|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 /** |
|
17 @file |
|
18 @internalComponent |
|
19 @released |
|
20 */ |
|
21 |
|
22 #include "persistencelayerimpl.h" |
|
23 #include "clplcontactproperties.h" |
|
24 #include "cntfilesearch.h" |
|
25 #include <bautils.h> |
|
26 #include "persistencelayer.h" |
|
27 |
|
28 const TInt KDriveNameWidth = 2; // e.g. "C:" |
|
29 |
|
30 _LIT(KSqLiteFilePrefix, "SQLite__"); |
|
31 |
|
32 // Transaction constants (only used by CPplContactsFile) |
|
33 _LIT(KStartTransaction,"BEGIN TRANSACTION;"); |
|
34 _LIT(KCommitTransaction,"COMMIT;"); |
|
35 _LIT(KRollbackTransaction,"ROLLBACK;"); |
|
36 |
|
37 /** |
|
38 @SYMPatchable |
|
39 @publishedPartner |
|
40 @released |
|
41 |
|
42 Patchable optional constant that overrides the cache size of the Contacts model databases set in the |
|
43 SqlServer.cfg file in the SQL data cage. |
|
44 If this value is left at 0, the cache size from the SqlServer.cfg file is used. |
|
45 The cache size affects the size of the cache in Kb that opens and creates Contacts model files. |
|
46 See SQLite documentation for more details. |
|
47 |
|
48 The constant can be changed at ROM build time using patchdata OBY keyword. |
|
49 */ |
|
50 IMPORT_C extern const TInt KContactsModelSqliteDbCacheSize; |
|
51 |
|
52 const TInt KCacheDataSize = 8; // The size in chars of patchable constant 'KContactsModelSqliteDbCacheSize' passed in |
|
53 |
|
54 //configure string used to create and open sqlite database |
|
55 _LIT8(KSqliteCacheSize, "cache_size=%d"); |
|
56 |
|
57 /** |
|
58 CPplContactsFile NewL. |
|
59 */ |
|
60 CPplContactsFile* CPplContactsFile::NewL(CLplContactProperties& aProps, MContactDbObserver* aObserver) |
|
61 { |
|
62 CPplContactsFile* self = new (ELeave) CPplContactsFile(aProps, aObserver); |
|
63 CleanupStack::PushL(self); |
|
64 self->ConstructL(); |
|
65 CleanupStack::Pop(self); |
|
66 return self; |
|
67 } |
|
68 |
|
69 /** |
|
70 CPplContactsFile ConstructL. |
|
71 */ |
|
72 void CPplContactsFile::ConstructL() |
|
73 { |
|
74 iItemManager = CPplContactItemManager::NewL(iDatabase, *this, iContactProperties, iIccContactStore); |
|
75 iContactProperties.SetContactItemManagerL(*iItemManager); |
|
76 |
|
77 iConfigureStr = NULL; |
|
78 if(KContactsModelSqliteDbCacheSize > 0) |
|
79 { |
|
80 //Create configure string to be used when creating/opening database |
|
81 iConfigureStr = HBufC8::NewL(KSqliteCacheSize().Length() + KCacheDataSize); |
|
82 TPtr8 ptrConfigureStr = iConfigureStr->Des(); |
|
83 ptrConfigureStr.Format(KSqliteCacheSize(), KContactsModelSqliteDbCacheSize); |
|
84 } |
|
85 } |
|
86 |
|
87 |
|
88 /** |
|
89 CPplContactsFile constructor. |
|
90 */ |
|
91 CPplContactsFile::CPplContactsFile(CLplContactProperties& aProps, MContactDbObserver* aObserver) |
|
92 : |
|
93 iActive(EFalse), |
|
94 iDbObserver(aObserver), |
|
95 iContactProperties(aProps), |
|
96 iIccContactStore(aProps) |
|
97 { |
|
98 } |
|
99 |
|
100 /** |
|
101 CPplContactsFile destructor. |
|
102 */ |
|
103 CPplContactsFile::~CPplContactsFile() |
|
104 { |
|
105 Close(); |
|
106 delete iItemManager; |
|
107 delete iConfigureStr; |
|
108 } |
|
109 |
|
110 |
|
111 /** |
|
112 Set the database observer for event propagation. |
|
113 */ |
|
114 void CPplContactsFile::RegisterDbObserver(MContactDbObserver& aDbObserver) |
|
115 { |
|
116 iDbObserver = &aDbObserver; |
|
117 } |
|
118 |
|
119 /** |
|
120 Utility method used to construct physical path for a given file name |
|
121 |
|
122 @param aPhysicalFileName in/out paramter; file name to which physical path will be append |
|
123 @param aSecuredFileName secured file name |
|
124 */ |
|
125 void CPplContactsFile::GetPhysicalFileNameL(TDes& aPhysicalFileName, const TDesC& aSecuredFileName) |
|
126 { |
|
127 GetPhysicalPathL(aPhysicalFileName, aSecuredFileName); |
|
128 aPhysicalFileName.Append(KSqLiteFilePrefix); |
|
129 aPhysicalFileName.Append(aSecuredFileName.Right(aSecuredFileName.Length() - KDriveNameWidth)); |
|
130 } |
|
131 |
|
132 /** |
|
133 Utility method used to construct physical path for a given file name |
|
134 |
|
135 @param aPhysicalFileName in/out paramter; file name to which physical path will be append |
|
136 @param aSecuredFileName secured file name |
|
137 */ |
|
138 void CPplContactsFile::GetPhysicalPathL(TDes& aPhysicalFileName, const TDesC& aSecuredFileName) |
|
139 { |
|
140 const TUint16 KDriveDelimiter = ':'; |
|
141 |
|
142 // Check for the drive delimiter. |
|
143 __ASSERT_ALWAYS(aSecuredFileName.Length() > 2 && |
|
144 aSecuredFileName[1] == KDriveDelimiter, User::Leave(KErrBadName)); |
|
145 |
|
146 // Check for malformed file name (path included explicitly). |
|
147 __ASSERT_ALWAYS(aSecuredFileName.Locate('\\') == KErrNotFound, User::Leave(KErrBadName)); |
|
148 |
|
149 // Get the private path from the file session. |
|
150 const TInt KMaxPrivatePathLength = 32; |
|
151 TBuf<KMaxPrivatePathLength> privatePath; |
|
152 |
|
153 LocalFsL(); |
|
154 iLocalFs.PrivatePath(privatePath); |
|
155 |
|
156 aPhysicalFileName = aSecuredFileName.Left(KDriveNameWidth); |
|
157 |
|
158 // Set current drive. |
|
159 iDatabaseDrive = aPhysicalFileName; |
|
160 |
|
161 aPhysicalFileName.Append(privatePath); |
|
162 |
|
163 // Make sure private path exists. |
|
164 TInt err = iLocalFs.MkDirAll(aPhysicalFileName); |
|
165 if (err != KErrNone && err != KErrAlreadyExists) |
|
166 { |
|
167 User::Leave(err); |
|
168 } |
|
169 } |
|
170 |
|
171 /** |
|
172 Open the given database file. |
|
173 */ |
|
174 void CPplContactsFile::OpenL(const TDesC& aFileName, TBool aNotify) |
|
175 { |
|
176 // Contact databases are in the Contact model private directory. |
|
177 TFileName fileName; |
|
178 GetPhysicalFileNameL(fileName, aFileName); |
|
179 |
|
180 iDatabase.Close(); |
|
181 iDatabase.OpenL(fileName, iConfigureStr); |
|
182 |
|
183 iFileIsOpen = ETrue; |
|
184 GenerateNotificationEventL(aNotify); |
|
185 } |
|
186 |
|
187 /** |
|
188 Utility method used to generate EContactDbObserverEventTablesOpened event |
|
189 */ |
|
190 void CPplContactsFile::GenerateNotificationEventL(TBool aNotify) |
|
191 { |
|
192 #if defined(__PROFILE_DEBUG__) |
|
193 RDebug::Print(_L("[CNTMODEL] MTD: CPplContactsFile::GenerateNotificationEventL")); |
|
194 #endif |
|
195 |
|
196 // Generate an event - this event is generated if this was an explicit call from the |
|
197 // server to opentables or recover database - ie A call on the contactsDatabase API |
|
198 if (iDbObserver && aNotify) |
|
199 { |
|
200 TContactDbObserverEvent event; |
|
201 event.iType = EContactDbObserverEventTablesOpened; |
|
202 event.iContactId = 0; |
|
203 event.iConnectionId = 0; |
|
204 TRAP_IGNORE(iDbObserver->HandleDatabaseEventL(event)); |
|
205 } |
|
206 } |
|
207 |
|
208 |
|
209 /** |
|
210 Open the database tables (a state change, no action on file necessary). |
|
211 */ |
|
212 void CPplContactsFile::OpenTablesL(TBool aNotify) |
|
213 { |
|
214 // Do nothing but notify |
|
215 |
|
216 #if defined(__PROFILE_DEBUG__) |
|
217 _LIT(KMessage, "[CNTMODEL] MTD: CPplContactsFile::OpenTablesL"); |
|
218 RDebug::Print(KMessage); |
|
219 #endif |
|
220 |
|
221 iFileIsOpen = ETrue; |
|
222 GenerateNotificationEventL(aNotify); |
|
223 } |
|
224 |
|
225 |
|
226 /** |
|
227 Close the database tables leaving the iDatabase itself open. |
|
228 Despite the trailing 'L', this method cannot leave. |
|
229 */ |
|
230 void CPplContactsFile::CloseTablesL(TBool aNotify) |
|
231 { |
|
232 // Do nothing but notify |
|
233 |
|
234 if (iDbObserver && aNotify) // Observer is optional. |
|
235 { |
|
236 // Notify observers that table is closed. |
|
237 TContactDbObserverEvent event; |
|
238 event.iType = EContactDbObserverEventTablesClosed; |
|
239 event.iContactId = 0; |
|
240 event.iConnectionId = 0; |
|
241 TRAP_IGNORE(iDbObserver->HandleDatabaseEventL(event)); |
|
242 } |
|
243 } |
|
244 |
|
245 |
|
246 /** |
|
247 File cleanup class used if creating database and its tables leaves. |
|
248 */ |
|
249 class TFileCleanup |
|
250 { |
|
251 public: |
|
252 TFileCleanup(RSqlDatabase& aDb, RFs& aFs, const TDesC& aFileName) : iDb(aDb),iFs(aFs),iFileName(aFileName) {} |
|
253 static void Cleanup(TAny* aSelf) { STATIC_CAST(TFileCleanup*,aSelf)->DoCleanup(); } |
|
254 |
|
255 private: |
|
256 void DoCleanup() |
|
257 { |
|
258 iDb.Close(); |
|
259 (void)iFs.Delete(iFileName); |
|
260 } |
|
261 |
|
262 public: |
|
263 RSqlDatabase& iDb; |
|
264 RFs& iFs; |
|
265 const TDesC& iFileName; |
|
266 }; |
|
267 |
|
268 |
|
269 /** |
|
270 Create a new database. |
|
271 */ |
|
272 EXPORT_C void CPplContactsFile::CreateL(const TDesC& aFileName, TPlCreateMode aMode) |
|
273 { |
|
274 TFileName fileName; |
|
275 GetPhysicalFileNameL(fileName, aFileName); |
|
276 |
|
277 TUint attVal; |
|
278 LocalFsL(); |
|
279 TInt err = iLocalFs.Att(fileName, attVal); |
|
280 TBool fileExists = (err == KErrNone); |
|
281 |
|
282 if (fileExists) |
|
283 { |
|
284 switch (aMode) |
|
285 { |
|
286 case EPlLeaveIfExist: |
|
287 User::Leave(KErrAlreadyExists); |
|
288 break; |
|
289 |
|
290 case EPlOverwrite: |
|
291 err = iLocalFs.Delete(fileName); |
|
292 break; |
|
293 } |
|
294 } |
|
295 |
|
296 // If the database is not created propertly delete the database file using |
|
297 // the cleanup item. |
|
298 TFileCleanup cleanupData(iDatabase, iLocalFs, fileName); |
|
299 CleanupStack::PushL(TCleanupItem(TFileCleanup::Cleanup,&cleanupData)); |
|
300 |
|
301 if ((err != KErrNone) && (err != KErrNotFound)) |
|
302 { |
|
303 User::LeaveIfError(err); |
|
304 } |
|
305 |
|
306 User::LeaveIfError(iDatabase.Create(fileName, iConfigureStr)); |
|
307 iItemManager->CreateTablesL(); |
|
308 iContactProperties.SystemTemplateManager().RecreateSystemTemplateL(); |
|
309 |
|
310 CleanupStack::Pop(); // The TCleanupItem. |
|
311 |
|
312 iDatabase.Close(); |
|
313 } |
|
314 |
|
315 |
|
316 /** |
|
317 Delete the given database. |
|
318 */ |
|
319 void CPplContactsFile::DeleteL(const TDesC& aFileName) |
|
320 { |
|
321 TFileName fileName; |
|
322 GetPhysicalFileNameL(fileName, aFileName); |
|
323 |
|
324 User::LeaveIfError(iLocalFs.Delete(fileName)); |
|
325 iFileIsOpen = EFalse; |
|
326 } |
|
327 |
|
328 |
|
329 /** |
|
330 Get a list of the contacts database on the given drive. |
|
331 */ |
|
332 CDesCArray* CPplContactsFile::ListL(TDriveUnit* aDriveUnit) |
|
333 { |
|
334 LocalFsL(); |
|
335 return CCntFileScanner::ListFilesL(iLocalFs, aDriveUnit); |
|
336 } |
|
337 |
|
338 |
|
339 /** |
|
340 Close the database. |
|
341 */ |
|
342 void CPplContactsFile::Close(TBool aNotify) |
|
343 { |
|
344 iDatabase.Close(); |
|
345 iFileIsOpen = EFalse; |
|
346 |
|
347 REComSession::FinalClose(); // This line is necessary to make sure the plug-in is unloaded properly |
|
348 iLocalFs.Close(); //we now use a local File Session |
|
349 |
|
350 iIccContactStore.Close(); |
|
351 |
|
352 TRAP_IGNORE(CloseTablesL(aNotify) ); // CloseTablesL() cannot leave anyway but still |
|
353 // trap in case implementation changes later |
|
354 } |
|
355 |
|
356 |
|
357 /** |
|
358 Starts a new transaction if one is not currently active otherwise leave. |
|
359 */ |
|
360 void CPplContactsFile::StartTransactionL() |
|
361 { |
|
362 if (iActive) |
|
363 { |
|
364 User::Leave(KErrInUse); |
|
365 } |
|
366 User::LeaveIfError(iDatabase.Exec(KStartTransaction)); |
|
367 iIccContactStore.StartTransactionL(); |
|
368 iActive = ETrue; |
|
369 } |
|
370 |
|
371 |
|
372 /** |
|
373 Commit all changes made since the transaction was started. |
|
374 */ |
|
375 void CPplContactsFile::CommitCurrentTransactionL(TUint aSessionId) |
|
376 { |
|
377 |
|
378 if (!iActive) |
|
379 { |
|
380 User::Leave(KErrNotReady); |
|
381 } |
|
382 iIccContactStore.CommitCurrentTransactionL(aSessionId); |
|
383 User::LeaveIfError(iDatabase.Exec(KCommitTransaction)); |
|
384 iActive = EFalse; |
|
385 } |
|
386 |
|
387 |
|
388 /** |
|
389 Rollback all changes made since the active the transaction was started. |
|
390 */ |
|
391 void CPplContactsFile::RollbackCurrentTransactionL(TUint aSessionId) |
|
392 { |
|
393 // Check that the database is open before rolling back. |
|
394 if (iFileIsOpen && iActive) |
|
395 { |
|
396 iActive = EFalse; |
|
397 iIccContactStore.RollbackCurrentTransaction(aSessionId); |
|
398 User::LeaveIfError(iDatabase.Exec(KRollbackTransaction)); |
|
399 } |
|
400 } |
|
401 |
|
402 /** |
|
403 Gets the size of the database file in bytes. |
|
404 |
|
405 @return The size of the contact database. |
|
406 */ |
|
407 TInt CPplContactsFile::FileSize() const |
|
408 { |
|
409 return iDatabase.Size(); |
|
410 } |
|
411 |
|
412 |
|
413 /** |
|
414 Gets the current database drive. The database drive is the drive on which |
|
415 the default contact database is located. |
|
416 |
|
417 @param aDriveUnit On return, contains the database drive. |
|
418 */ |
|
419 void CPplContactsFile::DatabaseDrive(TDriveUnit& aDriveUnit) |
|
420 { |
|
421 aDriveUnit = iDatabaseDrive; |
|
422 } |
|
423 |
|
424 |
|
425 /** |
|
426 A static method to determine if a given Contacts database exists. |
|
427 |
|
428 @param aFileName The Contacts database to search for. |
|
429 |
|
430 @return ETrue if the Contacts database is found, EFalse otherwise. |
|
431 */ |
|
432 TBool CPplContactsFile::DatabaseExistsL(const TDesC& aFileName) |
|
433 { |
|
434 TFileName fileName; |
|
435 GetPhysicalFileNameL(fileName, aFileName); |
|
436 LocalFsL(); |
|
437 return BaflUtils::FileExists(iLocalFs, fileName); |
|
438 } |
|
439 |