|
1 // Copyright (c) 2007-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 /** |
|
18 HEADER FILES |
|
19 */ |
|
20 |
|
21 #include "cmsvconverterwaiter.h" |
|
22 #include "cmessageconvertermanager.h" |
|
23 |
|
24 //const |
|
25 const TUid KUidMsvIndexFile = {0x10003C6B}; |
|
26 |
|
27 static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy); |
|
28 // literals |
|
29 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE) |
|
30 _LIT(KMessagingDBName, "\\messaging.db"); |
|
31 #else |
|
32 _LIT(KMessagingDBName,"[1000484B]messaging.db"); |
|
33 #endif |
|
34 |
|
35 |
|
36 |
|
37 // static class initialiser |
|
38 CMsvConverterWaiter* CMsvConverterWaiter::iConverterWaiter = NULL; |
|
39 |
|
40 |
|
41 /** |
|
42 Instance() |
|
43 The function returns already created instance of |
|
44 this class to the caller. To create a new instance |
|
45 the caller should call InstanceL(). |
|
46 @return CMsvConverterWaiter* : An instance of converter waiter. |
|
47 */ |
|
48 CMsvConverterWaiter* CMsvConverterWaiter::Instance() |
|
49 { |
|
50 return iConverterWaiter; |
|
51 } |
|
52 |
|
53 /** |
|
54 InstanceL() |
|
55 Instatiates converter waiter object.It is responsible for initiating and completing |
|
56 message store conversion |
|
57 |
|
58 @param aServer: Message Server Object |
|
59 @return CMsvConverterWaiter* : An instance of converter waiter. |
|
60 */ |
|
61 CMsvConverterWaiter* CMsvConverterWaiter::InstanceL(CMsvServer* aServer) |
|
62 { |
|
63 if(iConverterWaiter == NULL) |
|
64 { |
|
65 CMsvConverterWaiter* self = new(ELeave)CMsvConverterWaiter(aServer); |
|
66 iConverterWaiter = self; |
|
67 } |
|
68 |
|
69 return iConverterWaiter; |
|
70 } |
|
71 |
|
72 /** |
|
73 ~CMsvConverterWaiter() |
|
74 |
|
75 @param None |
|
76 @return: None |
|
77 @internalComponent |
|
78 */ |
|
79 CMsvConverterWaiter::~CMsvConverterWaiter() |
|
80 { |
|
81 iConverterWaiter = NULL; |
|
82 Cancel(); |
|
83 iConverterQueue.Close(); |
|
84 iConverterThread.Close(); |
|
85 // Free the handle to the property |
|
86 iProperty.Close(); |
|
87 } |
|
88 |
|
89 /* |
|
90 CMsvConverterWaiter() |
|
91 Default constructor. Adds this active request into active scheduler queue. |
|
92 |
|
93 @param aServer: messaging server |
|
94 @param iActive: active object |
|
95 @internalComponent |
|
96 */ |
|
97 CMsvConverterWaiter::CMsvConverterWaiter(CMsvServer* aServer) |
|
98 : CActive(EPriorityLow),iServer(aServer) |
|
99 { |
|
100 CActiveScheduler::Add(this); |
|
101 } |
|
102 |
|
103 /** |
|
104 DoCancel() |
|
105 Stub Code |
|
106 |
|
107 @param : None |
|
108 @return: None |
|
109 */ |
|
110 void CMsvConverterWaiter::DoCancel() |
|
111 { |
|
112 } |
|
113 |
|
114 /** |
|
115 DefineProperty() |
|
116 Define the property and attached it. |
|
117 |
|
118 @param none. |
|
119 @return void. |
|
120 */ |
|
121 TInt CMsvConverterWaiter::DefineProperty() |
|
122 { |
|
123 // Define the property and create a handle to it |
|
124 TInt err = RProperty::Define(KMyPropertyCat, KMyPropertyName,RProperty::EInt,KAllowAllPolicy,KAllowAllPolicy); |
|
125 if(!err) |
|
126 { |
|
127 iProperty.Attach(KMyPropertyCat,KMyPropertyName,EOwnerThread); |
|
128 } |
|
129 return err; |
|
130 } |
|
131 |
|
132 /** |
|
133 PublishProperty() |
|
134 Publishing property. |
|
135 |
|
136 @param aValue : value will published. |
|
137 @return void. |
|
138 */ |
|
139 TInt CMsvConverterWaiter::PublishProperty(TInt aValue) |
|
140 { |
|
141 TInt err = iProperty.Set(aValue); |
|
142 return err; |
|
143 } |
|
144 |
|
145 |
|
146 /** |
|
147 RunL() |
|
148 Asynchronous request handler of an active object. |
|
149 Invoked when a notification is received from the converter thread. |
|
150 Upon succesful conversion, this removes the index file , drive from the queue and closes |
|
151 the converter thread. |
|
152 When the conversion is cancelled , it removes the partially converted database table fro headers |
|
153 and completes the conversion request with KErrCancel. |
|
154 |
|
155 @param None |
|
156 @return: None |
|
157 @internalComponent |
|
158 */ |
|
159 void CMsvConverterWaiter::RunL() |
|
160 { |
|
161 if(iStatus >= KErrNone) |
|
162 { |
|
163 //Update drive status for this drive. EMsvMessageStoreAvailableStatus |
|
164 iServer->UpdateDriveStatusL(TDriveUnit(iConverterQueue[0].iDriveNumber),EMsvMessageStoreAvailableStatus); |
|
165 |
|
166 //Close the existing handle to the thread |
|
167 |
|
168 |
|
169 //Complete this request |
|
170 Completed(KErrNone); |
|
171 iConverterThread.Close(); |
|
172 } |
|
173 else if(iStatus == KErrCancel) |
|
174 { |
|
175 // we would have published this property so we can safely delte it in case of cancel |
|
176 RProperty::Delete(KMyPropertyCat,KMyPropertyName); |
|
177 |
|
178 iConverterThread.Close(); |
|
179 |
|
180 // The previous conversion request failed |
|
181 Completed(iStatus.Int()); |
|
182 } |
|
183 else |
|
184 { |
|
185 // The previous conversion request failed |
|
186 iConverterThread.Close(); |
|
187 Completed(iStatus.Int()); |
|
188 } |
|
189 |
|
190 // start conversion for the next drive in the queue |
|
191 if(iConverterQueue.Count()) |
|
192 { |
|
193 StartMessageStoreConversionL(iConverterQueue[0].iMessage,ETrue); |
|
194 } |
|
195 } |
|
196 |
|
197 /** |
|
198 StartMessageStoreConversionL() |
|
199 Starts the message store conversion. |
|
200 Steps: |
|
201 1. validates the drive. |
|
202 2. Creates a RThread object for conversion. |
|
203 3. Logons to the created thread to receive notofications. |
|
204 4. Resumes the converter thread and starts message store conversion. |
|
205 5. Marks this request as active. |
|
206 |
|
207 @param aMessage: RMessage2 representing client request and containing request data. |
|
208 @param aQueuedRequest: Boolean flag specifying if the drive is queued. |
|
209 @return: None |
|
210 @internalComponent |
|
211 */ |
|
212 void CMsvConverterWaiter::StartMessageStoreConversionL(const RMessage2& aMessage,TBool aQueuedRequest) |
|
213 { |
|
214 _LIT(KConverterThread,"StartMessageStoreConversion"); |
|
215 |
|
216 TDriveNumber driveNumber = (TDriveNumber) aMessage.Int0(); |
|
217 TInt error = KErrNone; |
|
218 |
|
219 //This is a new request, we need to validate this. |
|
220 //Note : the drive is already validated if it is in the queue. |
|
221 if(!aQueuedRequest) |
|
222 { |
|
223 error = ValidateRequestedDriveL(driveNumber); |
|
224 } |
|
225 |
|
226 if(error == KErrNone) // if proper |
|
227 { |
|
228 if(!aQueuedRequest) // if it is not already queued |
|
229 { |
|
230 TConversionQueue request; |
|
231 request.iDriveNumber = driveNumber; |
|
232 request.iMessage = aMessage; |
|
233 iConverterQueue.Append(request); |
|
234 } |
|
235 |
|
236 iDriveNumber = driveNumber; |
|
237 TAny* conversionStatus = &iDriveNumber; |
|
238 |
|
239 TInt err = iConverterThread.Create(KConverterThread, &CMessageConverterManager::StartConversion,KDefaultStackSize*8,KMinHeapSize,0x8000000,conversionStatus,EOwnerThread); |
|
240 |
|
241 iStatus = KRequestPending; |
|
242 if(!err) |
|
243 { |
|
244 iConverterThread.Logon(iStatus); |
|
245 iConverterThread.Resume(); |
|
246 } |
|
247 // activate this request |
|
248 SetActive(); |
|
249 } |
|
250 else |
|
251 { |
|
252 // complete this request with the right error |
|
253 aMessage.Complete(error); |
|
254 } |
|
255 |
|
256 } |
|
257 |
|
258 /** |
|
259 QueueConversionRequestL() |
|
260 Queues conversion request for a drive. A drive is queued for conversion when conversion is |
|
261 currently in progress for a drive. |
|
262 |
|
263 @param aMessage: RMessage2 representing client request and containing request data. |
|
264 @return: None |
|
265 @internalComponent |
|
266 */ |
|
267 void CMsvConverterWaiter::QueueConversionRequestL(const RMessage2& aMessage) |
|
268 { |
|
269 TDriveNumber driveNumber = (TDriveNumber) aMessage.Int0(); |
|
270 |
|
271 TInt pos = 0; |
|
272 TBool found = EFalse; |
|
273 while(pos < iConverterQueue.Count()) |
|
274 { |
|
275 if(iConverterQueue[pos++].iDriveNumber == driveNumber )// drive not in the queue |
|
276 { |
|
277 found = ETrue; |
|
278 } |
|
279 } |
|
280 |
|
281 if(found) |
|
282 { |
|
283 aMessage.Complete(KErrAlreadyExists); |
|
284 } |
|
285 else |
|
286 { |
|
287 TInt error = ValidateRequestedDriveL(driveNumber); |
|
288 if(error == KErrNone) |
|
289 { |
|
290 //validation fine. Add this request |
|
291 TConversionQueue request; |
|
292 request.iDriveNumber = driveNumber; |
|
293 request.iMessage = aMessage; |
|
294 iConverterQueue.Append(request); |
|
295 } |
|
296 else |
|
297 { |
|
298 aMessage.Complete(error); |
|
299 } |
|
300 } |
|
301 } |
|
302 |
|
303 /** |
|
304 ValidateRequestedDriveL() |
|
305 Validates the message store in the requested drive. |
|
306 It checks for the following conditions. |
|
307 1) Drive is present in preferred drive list. |
|
308 2) The drive is already present in conversion Queue. |
|
309 3) Checks if the version 1 message store is present |
|
310 4) Identifies if version 0 message store is corrupt.. |
|
311 |
|
312 @param aDrive: Drive number. |
|
313 @return: None |
|
314 @internalComponent |
|
315 */ |
|
316 TInt CMsvConverterWaiter::ValidateRequestedDriveL(TDriveNumber aDrive) |
|
317 { |
|
318 // check if the drive is present in preferred drive list |
|
319 TInt error = ValidateDriveInPreferredDriveListL(aDrive); |
|
320 if(error != KErrNone) |
|
321 { |
|
322 return error; |
|
323 } |
|
324 |
|
325 // Check if Version 1 message store exists. |
|
326 TParse parse; |
|
327 TPtrC drive = TDriveUnit(aDrive).Name(); |
|
328 parse.Set(KMessagingDBName, &drive, NULL); |
|
329 TFileName dbFileName = parse.FullName(); |
|
330 |
|
331 // check version 1 message store |
|
332 RSqlDatabase temp; |
|
333 CleanupClosePushL(temp); |
|
334 |
|
335 error = temp.Open(dbFileName); |
|
336 |
|
337 temp.Close(); |
|
338 CleanupStack::PopAndDestroy(); // temp |
|
339 |
|
340 //Version 1 message store may be corrupt |
|
341 if(error == KSqlErrCorrupt ) |
|
342 { |
|
343 return error; |
|
344 } |
|
345 |
|
346 //version 1 does not exist, check version 0 is corrupt |
|
347 if(error == KErrNotFound) |
|
348 { |
|
349 TBuf<KMaxPath> filePath; |
|
350 TPtrC drive(TDriveUnit(aDrive).Name()); |
|
351 filePath.Append(drive); |
|
352 filePath.Append(KIndexFilePath); |
|
353 |
|
354 RFs ifsSession; |
|
355 User::LeaveIfError(ifsSession.Connect()); |
|
356 |
|
357 RFile file; |
|
358 TInt error = file.Open(ifsSession, filePath, EFileShareAny|EFileWrite); |
|
359 |
|
360 if(error==KErrNone) |
|
361 { |
|
362 CPermanentFileStore* iIndexStore = CPermanentFileStore::FromL(file); |
|
363 CleanupStack::PushL(iIndexStore); |
|
364 if (iIndexStore->Type() != TUidType(KPermanentFileStoreLayoutUid, KUidMsvIndexFile)) |
|
365 { |
|
366 User::Leave(KErrCorrupt); |
|
367 } |
|
368 CleanupStack::PopAndDestroy(); // iIndexStore |
|
369 } |
|
370 ifsSession.Close(); |
|
371 file.Close(); |
|
372 } |
|
373 return KErrNone; |
|
374 } |
|
375 |
|
376 /** |
|
377 isRunningMessageStoreConverter() |
|
378 Checks if converter waiter is active and waiting for completion of a conversion request. |
|
379 |
|
380 @param None |
|
381 @return: Boolean flag specifying if the conversion is in progress,i,e if this active object is busy. |
|
382 @internalComponent |
|
383 */ |
|
384 TBool CMsvConverterWaiter::isRunningMessageStoreConverter() |
|
385 { |
|
386 if( iStatus == KRequestPending ) |
|
387 { |
|
388 return ETrue; |
|
389 } |
|
390 else |
|
391 { |
|
392 return EFalse; |
|
393 } |
|
394 } |
|
395 |
|
396 /** |
|
397 CancelConversionL() |
|
398 Cancels conversion for a drive. |
|
399 Steps to cancel. |
|
400 1. Stop converter Thread. |
|
401 2. Remove the partially converted header table. |
|
402 3. Complete the asynchronous request for conversion of the drive. |
|
403 4. Remove The drive from the drive array. |
|
404 5. If more drives are found in the queue, than initiate conversion for the next drive. |
|
405 |
|
406 @param aMessage: RMessage2 representing client request and containing request data. |
|
407 @return None |
|
408 @internalComponent |
|
409 */ |
|
410 void CMsvConverterWaiter::CancelConversionL(const RMessage2& aMessage) |
|
411 { |
|
412 //Get the drive |
|
413 TDriveNumber driveNumber = (TDriveNumber) aMessage.Int0(); |
|
414 |
|
415 TInt pos = 0; |
|
416 TBool found = EFalse; |
|
417 while(pos < iConverterQueue.Count()) |
|
418 { |
|
419 if(iConverterQueue[pos].iDriveNumber == driveNumber) |
|
420 { |
|
421 found = ETrue; |
|
422 break; |
|
423 } |
|
424 else |
|
425 { |
|
426 pos++; |
|
427 } |
|
428 } |
|
429 |
|
430 if(pos == 0 && found)// this is the active request |
|
431 { |
|
432 // Define cancel property |
|
433 TInt err = DefineProperty(); |
|
434 if(err == KErrNone) |
|
435 { |
|
436 // published the property so that, conversion thread will releases the memory and return. |
|
437 PublishProperty(KErrCancel); |
|
438 aMessage.Complete(KErrNone); |
|
439 } |
|
440 else |
|
441 { |
|
442 aMessage.Complete(err); |
|
443 } |
|
444 } |
|
445 else if(found)// this drive is queued |
|
446 { |
|
447 aMessage.Complete(KErrNone); |
|
448 iConverterQueue[pos].iMessage.Complete(KErrCancel); |
|
449 iConverterQueue.Remove(pos); |
|
450 } |
|
451 else// invalid rive for cancellation |
|
452 { |
|
453 aMessage.Complete(KErrNotFound); |
|
454 } |
|
455 } |
|
456 |
|
457 /** |
|
458 GetConversionStatus() |
|
459 Returns conversion status for a drive. |
|
460 |
|
461 @param aMessage: RMessage handle. |
|
462 @return None |
|
463 @internalComponent |
|
464 */ |
|
465 void CMsvConverterWaiter::GetConversionStatus(const RMessage2& aMessage) |
|
466 { |
|
467 TDriveNumber driveNumber = (TDriveNumber) aMessage.Int0(); |
|
468 TInt pos = 0; |
|
469 TBool found = EFalse; |
|
470 while(pos < iConverterQueue.Count()) |
|
471 { |
|
472 if(iConverterQueue[pos++].iDriveNumber == driveNumber) |
|
473 { |
|
474 found = ETrue; |
|
475 } |
|
476 } |
|
477 if(found) |
|
478 { |
|
479 if (pos == 0) |
|
480 { |
|
481 aMessage.Complete(0); // This request is active |
|
482 } |
|
483 else |
|
484 { |
|
485 aMessage.Complete(1); // Drive is queued for conversion |
|
486 } |
|
487 } |
|
488 else |
|
489 { |
|
490 aMessage.Complete(-1); // drive not found |
|
491 } |
|
492 } |
|
493 |
|
494 |
|
495 /** |
|
496 Completed() |
|
497 Completes the asynchronous request for message store conversion for the completed drive. |
|
498 When conversion completes successfully, it gets notified of the completion. |
|
499 The active conversion is alwasys the first element on the conversion queue. |
|
500 Upon compeltion, the first element in the queue gets compeleted.and the drive is removed |
|
501 from the drive array. |
|
502 |
|
503 @param aStatus: MTM ID of the table. |
|
504 @return None |
|
505 @internalComponent |
|
506 */ |
|
507 void CMsvConverterWaiter::Completed(const TInt aStatus) |
|
508 { |
|
509 iConverterQueue[0].iMessage.Complete(aStatus); |
|
510 iConverterQueue.Remove(0); |
|
511 |
|
512 } |
|
513 |
|
514 /** |
|
515 ValidateDriveInPreferredDriveListL() |
|
516 Validates a drive by checking if it is present in preferred drive list and its ststus is |
|
517 EMsvMessageStoreNotSupportedStatus |
|
518 Also checks if the drive is already queued for conversion and as such is a duplicate request. |
|
519 |
|
520 @param aDrive: Drive number. |
|
521 @return None |
|
522 @internalComponent |
|
523 */ |
|
524 TInt CMsvConverterWaiter::ValidateDriveInPreferredDriveListL(TDriveNumber aDrive) |
|
525 { |
|
526 CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList(); |
|
527 RArray<TDriveNumber> driveNumList; |
|
528 CleanupClosePushL(driveNumList); |
|
529 TInt index; |
|
530 for(index=0; index<driveList->Count(); index++) |
|
531 { |
|
532 if(EMsvMessageStoreNotSupportedStatus == (*driveList)[index].status) |
|
533 { |
|
534 driveNumList.AppendL((*driveList)[index].driveNum); |
|
535 } |
|
536 } |
|
537 |
|
538 if( driveNumList.Find(aDrive) != KErrNotFound) |
|
539 { |
|
540 CleanupStack::PopAndDestroy(); // driveNumList |
|
541 return KErrNone; |
|
542 } |
|
543 CleanupStack::PopAndDestroy(); // driveNumList |
|
544 return KErrNotFound; |
|
545 } |