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