|
1 // Copyright (c) 1998-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 #include <e32base.h> |
|
18 |
|
19 #include "MSVIDS.H" |
|
20 |
|
21 #include "MSVDELET.H" |
|
22 #include "MSVSERV.H" |
|
23 #include "MSVPANIC.H" |
|
24 #include "MSVUTILS.H" |
|
25 #include "msvindexadapter.h" |
|
26 #include "msventryfreepool.h" |
|
27 |
|
28 // static |
|
29 CMsvDelete* CMsvDelete::NewL(CMsvServer& aServer) |
|
30 // |
|
31 // |
|
32 // |
|
33 { |
|
34 CMsvDelete* self = new(ELeave) CMsvDelete(aServer); |
|
35 CleanupStack::PushL(self); |
|
36 self->ConstructL(); |
|
37 CleanupStack::Pop(); |
|
38 return self; |
|
39 } |
|
40 |
|
41 |
|
42 CMsvDelete::CMsvDelete(CMsvServer& aServer) |
|
43 : CActive(EPriorityStandard), iServer(aServer), iLockedIndex(-2) |
|
44 // |
|
45 // |
|
46 // |
|
47 { |
|
48 } |
|
49 |
|
50 |
|
51 void CMsvDelete::ConstructL() |
|
52 // |
|
53 // |
|
54 // |
|
55 { |
|
56 iFileMan = CFileMan::NewL(iServer.FileSession()); |
|
57 iDescendents = new(ELeave)CMsvEntrySelection; |
|
58 CActiveScheduler::Add(this); |
|
59 } |
|
60 |
|
61 |
|
62 CMsvDelete::~CMsvDelete() |
|
63 // |
|
64 // |
|
65 // |
|
66 { |
|
67 Cancel(); |
|
68 delete iDescendents; |
|
69 delete iFileMan; |
|
70 iDeleteArray.Close(); |
|
71 } |
|
72 |
|
73 void CMsvDelete::StartL(TMsvId aId, CMsvEntrySelection& aDeletedEntries, CMsvEntrySelection& aMovedEntries, TRequestStatus& aObserverStatus, TBool aPCSyncOverride) |
|
74 // |
|
75 // |
|
76 // |
|
77 { |
|
78 DoStartL(aId, aDeletedEntries, aMovedEntries, aPCSyncOverride); |
|
79 |
|
80 iStatus = KRequestPending; |
|
81 TRequestStatus* st=&iStatus; |
|
82 User::RequestComplete(st, KErrNone); |
|
83 SetActive(); |
|
84 // |
|
85 iObserverStatus = &aObserverStatus; |
|
86 *iObserverStatus = KRequestPending; |
|
87 } |
|
88 |
|
89 void CMsvDelete::StartL(TMsvId aId, CMsvEntrySelection& aDeletedEntries, CMsvEntrySelection& aMovedEntries, TBool aPCSyncOverride) |
|
90 // |
|
91 // |
|
92 // |
|
93 { |
|
94 DoStartL(aId, aDeletedEntries, aMovedEntries, aPCSyncOverride); |
|
95 |
|
96 // the state machine from RunL |
|
97 while (iState!=ECompleted) |
|
98 { |
|
99 switch (iState) |
|
100 { |
|
101 case ECheck: |
|
102 TRAP(iError, CheckEntriesL()); |
|
103 if (iError) |
|
104 iState=ECompleted; |
|
105 break; |
|
106 case EFiles: |
|
107 TRAPD(leave, DeleteFilesL()); |
|
108 if (leave) |
|
109 { |
|
110 iError=leave; |
|
111 iState=ECompleted; |
|
112 } |
|
113 break; |
|
114 case EIndex: |
|
115 DeleteAllIndexEntries(); |
|
116 iState=ECompleted; |
|
117 break; |
|
118 case EIndexIndividually: |
|
119 DeleteIndividualIndexEntries(); |
|
120 iState=ECompleted; |
|
121 break; |
|
122 default: |
|
123 __ASSERT_DEBUG(EFalse, PanicServer(EMsvDeleteBadState2)); |
|
124 } |
|
125 } |
|
126 |
|
127 // completion code |
|
128 iDeletionIndex=0; |
|
129 |
|
130 User::LeaveIfError(iError); |
|
131 } |
|
132 |
|
133 void CMsvDelete::DoStartL(TMsvId aId, CMsvEntrySelection& aDeletedEntries, CMsvEntrySelection& aMovedEntries, TBool aPCSyncOverride) |
|
134 // |
|
135 // |
|
136 // |
|
137 { |
|
138 // Fail now if the index says it's not available |
|
139 User::LeaveIfError(iServer.IndexAdapter().ErrorState()); |
|
140 iId = aId; |
|
141 iPCSyncOverride = aPCSyncOverride; |
|
142 |
|
143 // Let's not support deletion of entries from non-current drive. |
|
144 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT) |
|
145 if(GetDriveId(iId) != KCurrentDriveId) |
|
146 { |
|
147 User::Leave(KErrNotSupported); |
|
148 } |
|
149 #endif |
|
150 |
|
151 // get the expanded selection |
|
152 iDescendents->Reset(); |
|
153 iDescendents->AppendL(iId); |
|
154 User::LeaveIfError(iServer.IndexAdapter().ExpandSelectionRecursively(*iDescendents)); |
|
155 // make sure all deleted entries can be stored |
|
156 iDeletedEntries = &aDeletedEntries; |
|
157 iDeletedEntries->SetReserveL(iDescendents->Count()); |
|
158 iMovedEntries = &aMovedEntries; |
|
159 iMovedEntries->SetReserveL(iDescendents->Count()); |
|
160 |
|
161 // check if the entry is a service then set up PC override |
|
162 TMsvEntry* entry; |
|
163 User::LeaveIfError(iServer.IndexAdapter().GetEntry(aId, entry)); |
|
164 if (entry->iType==KUidMsvServiceEntry) |
|
165 iPCSyncOverride=ETrue; |
|
166 |
|
167 iState = ECheck; |
|
168 } |
|
169 |
|
170 void CMsvDelete::DoCancel() |
|
171 // |
|
172 // |
|
173 // |
|
174 { |
|
175 // need to remove the index entries for any already deleted |
|
176 if (iState==EFiles || iState==EIndex || iState==EIndexIndividually) |
|
177 iPCSynced ? DeleteIndividualIndexEntries() : DeleteAllIndexEntries(); |
|
178 Complete(KErrCancel); |
|
179 } |
|
180 |
|
181 |
|
182 |
|
183 void CMsvDelete::RunL() |
|
184 // |
|
185 // |
|
186 // |
|
187 { |
|
188 TInt error = iStatus.Int(); |
|
189 if (error==KErrNone) |
|
190 TRAP(error, DoRunL()); |
|
191 if (error) |
|
192 Complete(error); |
|
193 } |
|
194 |
|
195 |
|
196 void CMsvDelete::DoRunL() |
|
197 // |
|
198 // |
|
199 // |
|
200 { |
|
201 switch (iState) |
|
202 { |
|
203 case EFiles: |
|
204 DeleteFilesL(); |
|
205 break; |
|
206 case ECheck: |
|
207 CheckEntriesL(); |
|
208 break; |
|
209 case EIndex: |
|
210 DeleteAllIndexEntries(); |
|
211 Complete(iError); |
|
212 return; |
|
213 case EIndexIndividually: |
|
214 DeleteIndividualIndexEntries(); |
|
215 Complete(iError); |
|
216 return; |
|
217 default: |
|
218 __ASSERT_DEBUG(EFalse, PanicServer(EMsvDeleteBadState)); |
|
219 } |
|
220 iStatus = KRequestPending; |
|
221 TRequestStatus* st=&iStatus; |
|
222 User::RequestComplete(st, KErrNone); |
|
223 SetActive(); |
|
224 } |
|
225 |
|
226 |
|
227 void CMsvDelete::CheckEntriesL() |
|
228 // |
|
229 // |
|
230 // |
|
231 { |
|
232 iLockedIndex = iDescendents->Count(); |
|
233 while (iLockedIndex) |
|
234 { |
|
235 TMsvId id = iDescendents->At(iLockedIndex-1); |
|
236 |
|
237 // lock the entry |
|
238 User::LeaveIfError(iServer.IndexAdapter().IsEntryOrStoreLocked(id)); |
|
239 iLockedIndex--; |
|
240 |
|
241 // check noone is reading the store (reading the store now doesn't |
|
242 // keep the file open, therefore we can't rely on checking the file to stop |
|
243 // deleting while reading |
|
244 TBool reading=EFalse; |
|
245 User::LeaveIfError(iServer.IndexAdapter().IsStoreReadingLocked(id,reading)); |
|
246 if(reading) User::Leave(KErrInUse); |
|
247 |
|
248 |
|
249 // get the entry |
|
250 TMsvEntry entry; |
|
251 User::LeaveIfError(iServer.IndexAdapter().GetEntryNoCache(id, &entry)); |
|
252 TMsvDelete deleteEntry(entry.Id(), entry.Owner(), entry.PcSyncCount(), entry.iType, entry.Complete()); |
|
253 iDeleteArray.AppendL(deleteEntry); |
|
254 |
|
255 // check if any entries have been synced and not been overridden |
|
256 if (!iPCSyncOverride && entry.PcSyncCount()) |
|
257 iPCSynced=ETrue; |
|
258 |
|
259 // cannot delete standard folders |
|
260 if (entry.StandardFolder()) |
|
261 User::Leave(KErrAccessDenied); |
|
262 |
|
263 // check the store |
|
264 TFileName filename; |
|
265 iServer.GetEntryName(id, filename, EFalse); |
|
266 TBool open; |
|
267 TInt error = iServer.FileSession().IsFileOpen(filename, open); |
|
268 if (error!=KErrNone && error!=KErrNotFound && error!=KErrPathNotFound) |
|
269 User::Leave(error); |
|
270 if (error==KErrNone && open) |
|
271 User::Leave(KErrInUse); |
|
272 |
|
273 // check any files |
|
274 CDir* dir; |
|
275 error = iServer.GetFileDirectoryListing(id, filename, dir); |
|
276 if (error==KErrNone) |
|
277 { |
|
278 CleanupStack::PushL(dir); |
|
279 User::LeaveIfError(iServer.FileSession().SetSessionPath(filename)); |
|
280 TInt fCount=dir->Count(); |
|
281 if (fCount--) |
|
282 { |
|
283 TBool open; |
|
284 TInt error = iServer.FileSession().IsFileOpen((*dir)[fCount].iName, open); |
|
285 if (error!=KErrNone && error!=KErrNotFound && error!=KErrPathNotFound) |
|
286 User::Leave(error); |
|
287 if (error==KErrNone && open) |
|
288 User::Leave(KErrInUse); |
|
289 if ((*dir)[fCount].IsReadOnly()) |
|
290 User::LeaveIfError(iServer.FileSession().SetAtt((*dir)[fCount].iName, 0, KEntryAttReadOnly)); |
|
291 } |
|
292 CleanupStack::PopAndDestroy(); // dir |
|
293 } |
|
294 else if (error!=KErrPathNotFound) |
|
295 User::Leave(error); |
|
296 } |
|
297 iState = EFiles; |
|
298 } |
|
299 |
|
300 |
|
301 void CMsvDelete::DeleteFilesL() |
|
302 // |
|
303 // |
|
304 // |
|
305 { |
|
306 TFileName filename; |
|
307 TMsvId id = iDescendents->At(iDeletionIndex++); |
|
308 |
|
309 // delete the binary files |
|
310 CDir* dir=NULL; |
|
311 TBool partiallyDeleted=EFalse; |
|
312 TInt error = iServer.GetFileDirectoryListing(id, filename, dir); |
|
313 if (error==KErrNone) |
|
314 { |
|
315 User::LeaveIfError(iServer.FileSession().SetSessionPath(filename)); |
|
316 // remove any files |
|
317 TInt fCount=dir->Count(); |
|
318 while (fCount--) |
|
319 { |
|
320 error = iServer.FileSession().Delete((*dir)[fCount].iName); |
|
321 if (error==KErrNone) |
|
322 partiallyDeleted=ETrue; |
|
323 else if (error!=KErrNotFound && error!=KErrPathNotFound) |
|
324 goto failed; |
|
325 } |
|
326 |
|
327 // remove the directory |
|
328 error = iServer.FileSession().RmDir(filename); |
|
329 if (error==KErrNone) |
|
330 partiallyDeleted=ETrue; |
|
331 else if (error!=KErrNotFound && error!=KErrPathNotFound) |
|
332 goto failed; |
|
333 } |
|
334 else if (error!=KErrPathNotFound && error!=KErrNotFound) |
|
335 goto failed; |
|
336 |
|
337 // delete the store |
|
338 iServer.GetEntryName(id, filename, EFalse); // error ignore as entry exists |
|
339 error = iServer.FileSession().Delete(filename); |
|
340 // Try to delete the (single digit) parent folder if it is empty. E.g.: "...\00001001_S\9\" |
|
341 iServer.FileSession().RmDir(filename); // ignore error |
|
342 if (error==KErrNone) |
|
343 partiallyDeleted=ETrue; |
|
344 else if (error!=KErrNotFound && error!=KErrPathNotFound) |
|
345 goto failed; |
|
346 |
|
347 |
|
348 filename.Append(KMsvUtilsNewExtension); // try and make sure that a temporary store file |
|
349 iServer.FileSession().Delete(filename); // hasn't been left behind by CMsvCachedStore |
|
350 // but ignore the error as we can't do anything about it |
|
351 |
|
352 // for the last entry, check if it a service and move to next state |
|
353 if (iDeletionIndex==iDescendents->Count()) |
|
354 { |
|
355 // get the entry and check whether it is a service |
|
356 TBool serviceType =EFalse; |
|
357 TInt deleteArrayCount = iDeleteArray.Count(); |
|
358 for(TInt i =0; i < deleteArrayCount; ++i) |
|
359 { |
|
360 if(iDeleteArray[i].iEntryId == id) |
|
361 { |
|
362 if(iDeleteArray[i].iType == KUidMsvServiceEntry) |
|
363 { |
|
364 serviceType = ETrue; |
|
365 } |
|
366 break; |
|
367 } |
|
368 } |
|
369 if(serviceType) |
|
370 { |
|
371 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT) |
|
372 iServer.Context().MessageFolder(GetDriveId(id), filename); |
|
373 MsvUtils::ConstructEntryName(UnmaskTMsvId(id), id, filename, MsvUtils::EPath); |
|
374 #else |
|
375 filename = iServer.Context().MessageFolder(); |
|
376 MsvUtils::ConstructEntryName(id, id, filename, MsvUtils::EPath); |
|
377 #endif |
|
378 error = iFileMan->RmDir(filename); |
|
379 if (error && error!=KErrPathNotFound && error!=KErrNotFound) |
|
380 goto failed; |
|
381 } |
|
382 // we have completed all the deletion, move onto next state |
|
383 iState = iPCSynced ? EIndexIndividually : EIndex; |
|
384 } |
|
385 |
|
386 // deletion was successful |
|
387 iDeletedEntries->AppendL(id); // will not leave, space has been reserved |
|
388 iMovedEntries->AppendL(id); // will not leave, space has been reserved |
|
389 delete dir; |
|
390 return; |
|
391 |
|
392 failed: |
|
393 if (partiallyDeleted) |
|
394 { |
|
395 TMsvEntry* entry=NULL; |
|
396 TBool complete =EFalse; |
|
397 for(TInt i =0; i< iDeleteArray.Count(); ++i) |
|
398 { |
|
399 if(iDeleteArray[i].iEntryId == id) |
|
400 { |
|
401 if(iDeleteArray[i].iIsComplete) |
|
402 { |
|
403 iServer.IndexAdapter().GetEntry(id, entry); |
|
404 if(entry) |
|
405 { |
|
406 complete = ETrue; |
|
407 } |
|
408 } |
|
409 break; |
|
410 } |
|
411 } |
|
412 |
|
413 if(complete) |
|
414 { |
|
415 // mark as imcomplete |
|
416 TMsvEntry icmpEntry=*entry; |
|
417 icmpEntry.SetComplete(EFalse); |
|
418 iServer.IndexAdapter().LockEntry(id); |
|
419 iServer.IndexAdapter().ChangeEntry(icmpEntry, KMsvServerId, EFalse); // ignore error |
|
420 iServer.IndexAdapter().ReleaseEntry(id); |
|
421 } |
|
422 } |
|
423 |
|
424 // we have failed, move onto next state |
|
425 iState = iPCSynced ? EIndexIndividually : EIndex; |
|
426 iError=error; |
|
427 delete dir; |
|
428 } |
|
429 |
|
430 |
|
431 |
|
432 void CMsvDelete::DeleteAllIndexEntries() |
|
433 // |
|
434 // |
|
435 // |
|
436 { |
|
437 iMovedEntries->Reset(); |
|
438 |
|
439 if (iDeletedEntries->Count()==0) |
|
440 return; |
|
441 |
|
442 // delete the entries |
|
443 TInt error = KErrNone; |
|
444 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) |
|
445 TMsvEntry* entry = NULL; |
|
446 TInt deleteIndex = 0; |
|
447 while(deleteIndex < iDeletedEntries->Count()) |
|
448 { |
|
449 iServer.IndexAdapter().GetEntry(iDeletedEntries->At(deleteIndex), entry); |
|
450 if(entry==NULL) |
|
451 { |
|
452 iDeletedEntries->Delete(deleteIndex); |
|
453 continue; |
|
454 } |
|
455 |
|
456 // If there's a DB store, delete any header entries associated with the entry. |
|
457 TRAP(error, iServer.MessageDBAdapter().DeleteHeaderEntryL(entry->iMtm, entry->iId)); |
|
458 if(KErrNotFound == error) // Ignore entry not found case |
|
459 error = KErrNone; |
|
460 |
|
461 if(error) |
|
462 iDeletedEntries->Delete(deleteIndex); |
|
463 else |
|
464 ++deleteIndex; |
|
465 } |
|
466 #endif |
|
467 if(!error) // Looks awkward inside the macro above.. |
|
468 error = iServer.IndexAdapter().DeleteSelectionUsingTransaction(*iDeletedEntries); |
|
469 |
|
470 if (error && iError==KErrNone) |
|
471 iError=error; |
|
472 } |
|
473 |
|
474 |
|
475 void CMsvDelete::DeleteIndividualIndexEntries() |
|
476 // |
|
477 // |
|
478 // |
|
479 { |
|
480 if (iDeletedEntries->Count()==0) |
|
481 return; |
|
482 |
|
483 TInt moveIndex=0; |
|
484 TInt deleteIndex=0; |
|
485 iServer.IndexAdapter().BeginTransaction(); |
|
486 |
|
487 while(deleteIndex < iDeletedEntries->Count()) |
|
488 { |
|
489 // get the entry |
|
490 TMsvEntry* entry=NULL; |
|
491 iServer.IndexAdapter().GetEntry(iDeletedEntries->At(deleteIndex), entry); |
|
492 if(entry==NULL) |
|
493 { |
|
494 iDeletedEntries->Delete(deleteIndex); |
|
495 iMovedEntries->Delete(moveIndex); |
|
496 continue; |
|
497 } |
|
498 |
|
499 TInt error = KErrNone; |
|
500 if(!entry->Owner()) |
|
501 { |
|
502 // either delete the entry, or move it to the deleted folder |
|
503 if(entry->PcSyncCount()==0) |
|
504 { // Deleting the entry.. |
|
505 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB) |
|
506 // If there's a DB store, delete any header entries associated with the entry. |
|
507 TRAP(error, iServer.MessageDBAdapter().DeleteHeaderEntryL(entry->iMtm, entry->iId)); |
|
508 if(KErrNotFound == error) // Ignore entry not found case |
|
509 error = KErrNone; |
|
510 #endif |
|
511 if(!error) // Looks awkward inside the macro above.. |
|
512 error = iServer.IndexAdapter().ForceDeleteEntry(entry->Id()); |
|
513 |
|
514 if (error) |
|
515 iDeletedEntries->Delete(deleteIndex); |
|
516 else |
|
517 deleteIndex++; |
|
518 iMovedEntries->Delete(moveIndex); |
|
519 } |
|
520 else |
|
521 { // Moving the entry.. |
|
522 TMsvEntry deletedEntry(*entry); |
|
523 // this should be removed and CMsvDelete made a friend of TMsvEntry |
|
524 deletedEntry.iDetails.Set(TPtrC()); |
|
525 deletedEntry.iDescription.Set(TPtrC()); |
|
526 deletedEntry.SetDeleted(ETrue); |
|
527 deletedEntry.SetVisible(EFalse); |
|
528 deletedEntry.SetParent(KMsvDeletedEntryFolderEntryId); |
|
529 |
|
530 TMsvId backUpEntryId = entry->Id(); |
|
531 iServer.IndexAdapter().LockEntry(backUpEntryId); |
|
532 error = iServer.IndexAdapter().ChangeEntry(deletedEntry, KMsvServerId, EFalse); |
|
533 iServer.IndexAdapter().ReleaseEntry(backUpEntryId); |
|
534 if (error) |
|
535 iMovedEntries->Delete(moveIndex); |
|
536 else |
|
537 moveIndex++; |
|
538 iDeletedEntries->Delete(deleteIndex); |
|
539 } |
|
540 } |
|
541 else |
|
542 error = KErrAccessDenied; |
|
543 |
|
544 if (error && iError==KErrNone) |
|
545 iError=error; |
|
546 } |
|
547 |
|
548 iServer.IndexAdapter().CommitTransaction(); |
|
549 } |
|
550 |
|
551 |
|
552 |
|
553 void CMsvDelete::Complete(TInt aError) |
|
554 // |
|
555 // |
|
556 // |
|
557 { |
|
558 User::RequestComplete(iObserverStatus, aError); |
|
559 iState=ECompleted; |
|
560 iDeletionIndex=0; |
|
561 } |