--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/MSVDELET.CPP Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,561 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+
+#include <e32base.h>
+
+#include "MSVIDS.H"
+
+#include "MSVDELET.H"
+#include "MSVSERV.H"
+#include "MSVPANIC.H"
+#include "MSVUTILS.H"
+#include "msvindexadapter.h"
+#include "msventryfreepool.h"
+
+// static
+CMsvDelete* CMsvDelete::NewL(CMsvServer& aServer)
+//
+//
+//
+ {
+ CMsvDelete* self = new(ELeave) CMsvDelete(aServer);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+
+CMsvDelete::CMsvDelete(CMsvServer& aServer)
+: CActive(EPriorityStandard), iServer(aServer), iLockedIndex(-2)
+//
+//
+//
+ {
+ }
+
+
+void CMsvDelete::ConstructL()
+//
+//
+//
+ {
+ iFileMan = CFileMan::NewL(iServer.FileSession());
+ iDescendents = new(ELeave)CMsvEntrySelection;
+ CActiveScheduler::Add(this);
+ }
+
+
+CMsvDelete::~CMsvDelete()
+//
+//
+//
+ {
+ Cancel();
+ delete iDescendents;
+ delete iFileMan;
+ iDeleteArray.Close();
+ }
+
+void CMsvDelete::StartL(TMsvId aId, CMsvEntrySelection& aDeletedEntries, CMsvEntrySelection& aMovedEntries, TRequestStatus& aObserverStatus, TBool aPCSyncOverride)
+//
+//
+//
+ {
+ DoStartL(aId, aDeletedEntries, aMovedEntries, aPCSyncOverride);
+
+ iStatus = KRequestPending;
+ TRequestStatus* st=&iStatus;
+ User::RequestComplete(st, KErrNone);
+ SetActive();
+ //
+ iObserverStatus = &aObserverStatus;
+ *iObserverStatus = KRequestPending;
+ }
+
+void CMsvDelete::StartL(TMsvId aId, CMsvEntrySelection& aDeletedEntries, CMsvEntrySelection& aMovedEntries, TBool aPCSyncOverride)
+//
+//
+//
+ {
+ DoStartL(aId, aDeletedEntries, aMovedEntries, aPCSyncOverride);
+
+ // the state machine from RunL
+ while (iState!=ECompleted)
+ {
+ switch (iState)
+ {
+ case ECheck:
+ TRAP(iError, CheckEntriesL());
+ if (iError)
+ iState=ECompleted;
+ break;
+ case EFiles:
+ TRAPD(leave, DeleteFilesL());
+ if (leave)
+ {
+ iError=leave;
+ iState=ECompleted;
+ }
+ break;
+ case EIndex:
+ DeleteAllIndexEntries();
+ iState=ECompleted;
+ break;
+ case EIndexIndividually:
+ DeleteIndividualIndexEntries();
+ iState=ECompleted;
+ break;
+ default:
+ __ASSERT_DEBUG(EFalse, PanicServer(EMsvDeleteBadState2));
+ }
+ }
+
+ // completion code
+ iDeletionIndex=0;
+
+ User::LeaveIfError(iError);
+ }
+
+void CMsvDelete::DoStartL(TMsvId aId, CMsvEntrySelection& aDeletedEntries, CMsvEntrySelection& aMovedEntries, TBool aPCSyncOverride)
+//
+//
+//
+ {
+ // Fail now if the index says it's not available
+ User::LeaveIfError(iServer.IndexAdapter().ErrorState());
+ iId = aId;
+ iPCSyncOverride = aPCSyncOverride;
+
+ // Let's not support deletion of entries from non-current drive.
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ if(GetDriveId(iId) != KCurrentDriveId)
+ {
+ User::Leave(KErrNotSupported);
+ }
+#endif
+
+ // get the expanded selection
+ iDescendents->Reset();
+ iDescendents->AppendL(iId);
+ User::LeaveIfError(iServer.IndexAdapter().ExpandSelectionRecursively(*iDescendents));
+ // make sure all deleted entries can be stored
+ iDeletedEntries = &aDeletedEntries;
+ iDeletedEntries->SetReserveL(iDescendents->Count());
+ iMovedEntries = &aMovedEntries;
+ iMovedEntries->SetReserveL(iDescendents->Count());
+
+ // check if the entry is a service then set up PC override
+ TMsvEntry* entry;
+ User::LeaveIfError(iServer.IndexAdapter().GetEntry(aId, entry));
+ if (entry->iType==KUidMsvServiceEntry)
+ iPCSyncOverride=ETrue;
+
+ iState = ECheck;
+ }
+
+void CMsvDelete::DoCancel()
+//
+//
+//
+ {
+ // need to remove the index entries for any already deleted
+ if (iState==EFiles || iState==EIndex || iState==EIndexIndividually)
+ iPCSynced ? DeleteIndividualIndexEntries() : DeleteAllIndexEntries();
+ Complete(KErrCancel);
+ }
+
+
+
+void CMsvDelete::RunL()
+//
+//
+//
+ {
+ TInt error = iStatus.Int();
+ if (error==KErrNone)
+ TRAP(error, DoRunL());
+ if (error)
+ Complete(error);
+ }
+
+
+void CMsvDelete::DoRunL()
+//
+//
+//
+ {
+ switch (iState)
+ {
+ case EFiles:
+ DeleteFilesL();
+ break;
+ case ECheck:
+ CheckEntriesL();
+ break;
+ case EIndex:
+ DeleteAllIndexEntries();
+ Complete(iError);
+ return;
+ case EIndexIndividually:
+ DeleteIndividualIndexEntries();
+ Complete(iError);
+ return;
+ default:
+ __ASSERT_DEBUG(EFalse, PanicServer(EMsvDeleteBadState));
+ }
+ iStatus = KRequestPending;
+ TRequestStatus* st=&iStatus;
+ User::RequestComplete(st, KErrNone);
+ SetActive();
+ }
+
+
+void CMsvDelete::CheckEntriesL()
+//
+//
+//
+ {
+ iLockedIndex = iDescendents->Count();
+ while (iLockedIndex)
+ {
+ TMsvId id = iDescendents->At(iLockedIndex-1);
+
+ // lock the entry
+ User::LeaveIfError(iServer.IndexAdapter().IsEntryOrStoreLocked(id));
+ iLockedIndex--;
+
+ // check noone is reading the store (reading the store now doesn't
+ // keep the file open, therefore we can't rely on checking the file to stop
+ // deleting while reading
+ TBool reading=EFalse;
+ User::LeaveIfError(iServer.IndexAdapter().IsStoreReadingLocked(id,reading));
+ if(reading) User::Leave(KErrInUse);
+
+
+ // get the entry
+ TMsvEntry entry;
+ User::LeaveIfError(iServer.IndexAdapter().GetEntryNoCache(id, &entry));
+ TMsvDelete deleteEntry(entry.Id(), entry.Owner(), entry.PcSyncCount(), entry.iType, entry.Complete());
+ iDeleteArray.AppendL(deleteEntry);
+
+ // check if any entries have been synced and not been overridden
+ if (!iPCSyncOverride && entry.PcSyncCount())
+ iPCSynced=ETrue;
+
+ // cannot delete standard folders
+ if (entry.StandardFolder())
+ User::Leave(KErrAccessDenied);
+
+ // check the store
+ TFileName filename;
+ iServer.GetEntryName(id, filename, EFalse);
+ TBool open;
+ TInt error = iServer.FileSession().IsFileOpen(filename, open);
+ if (error!=KErrNone && error!=KErrNotFound && error!=KErrPathNotFound)
+ User::Leave(error);
+ if (error==KErrNone && open)
+ User::Leave(KErrInUse);
+
+ // check any files
+ CDir* dir;
+ error = iServer.GetFileDirectoryListing(id, filename, dir);
+ if (error==KErrNone)
+ {
+ CleanupStack::PushL(dir);
+ User::LeaveIfError(iServer.FileSession().SetSessionPath(filename));
+ TInt fCount=dir->Count();
+ if (fCount--)
+ {
+ TBool open;
+ TInt error = iServer.FileSession().IsFileOpen((*dir)[fCount].iName, open);
+ if (error!=KErrNone && error!=KErrNotFound && error!=KErrPathNotFound)
+ User::Leave(error);
+ if (error==KErrNone && open)
+ User::Leave(KErrInUse);
+ if ((*dir)[fCount].IsReadOnly())
+ User::LeaveIfError(iServer.FileSession().SetAtt((*dir)[fCount].iName, 0, KEntryAttReadOnly));
+ }
+ CleanupStack::PopAndDestroy(); // dir
+ }
+ else if (error!=KErrPathNotFound)
+ User::Leave(error);
+ }
+ iState = EFiles;
+ }
+
+
+void CMsvDelete::DeleteFilesL()
+//
+//
+//
+ {
+ TFileName filename;
+ TMsvId id = iDescendents->At(iDeletionIndex++);
+
+ // delete the binary files
+ CDir* dir=NULL;
+ TBool partiallyDeleted=EFalse;
+ TInt error = iServer.GetFileDirectoryListing(id, filename, dir);
+ if (error==KErrNone)
+ {
+ User::LeaveIfError(iServer.FileSession().SetSessionPath(filename));
+ // remove any files
+ TInt fCount=dir->Count();
+ while (fCount--)
+ {
+ error = iServer.FileSession().Delete((*dir)[fCount].iName);
+ if (error==KErrNone)
+ partiallyDeleted=ETrue;
+ else if (error!=KErrNotFound && error!=KErrPathNotFound)
+ goto failed;
+ }
+
+ // remove the directory
+ error = iServer.FileSession().RmDir(filename);
+ if (error==KErrNone)
+ partiallyDeleted=ETrue;
+ else if (error!=KErrNotFound && error!=KErrPathNotFound)
+ goto failed;
+ }
+ else if (error!=KErrPathNotFound && error!=KErrNotFound)
+ goto failed;
+
+ // delete the store
+ iServer.GetEntryName(id, filename, EFalse); // error ignore as entry exists
+ error = iServer.FileSession().Delete(filename);
+ // Try to delete the (single digit) parent folder if it is empty. E.g.: "...\00001001_S\9\"
+ iServer.FileSession().RmDir(filename); // ignore error
+ if (error==KErrNone)
+ partiallyDeleted=ETrue;
+ else if (error!=KErrNotFound && error!=KErrPathNotFound)
+ goto failed;
+
+
+ filename.Append(KMsvUtilsNewExtension); // try and make sure that a temporary store file
+ iServer.FileSession().Delete(filename); // hasn't been left behind by CMsvCachedStore
+ // but ignore the error as we can't do anything about it
+
+ // for the last entry, check if it a service and move to next state
+ if (iDeletionIndex==iDescendents->Count())
+ {
+ // get the entry and check whether it is a service
+ TBool serviceType =EFalse;
+ TInt deleteArrayCount = iDeleteArray.Count();
+ for(TInt i =0; i < deleteArrayCount; ++i)
+ {
+ if(iDeleteArray[i].iEntryId == id)
+ {
+ if(iDeleteArray[i].iType == KUidMsvServiceEntry)
+ {
+ serviceType = ETrue;
+ }
+ break;
+ }
+ }
+ if(serviceType)
+ {
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ iServer.Context().MessageFolder(GetDriveId(id), filename);
+ MsvUtils::ConstructEntryName(UnmaskTMsvId(id), id, filename, MsvUtils::EPath);
+#else
+ filename = iServer.Context().MessageFolder();
+ MsvUtils::ConstructEntryName(id, id, filename, MsvUtils::EPath);
+#endif
+ error = iFileMan->RmDir(filename);
+ if (error && error!=KErrPathNotFound && error!=KErrNotFound)
+ goto failed;
+ }
+ // we have completed all the deletion, move onto next state
+ iState = iPCSynced ? EIndexIndividually : EIndex;
+ }
+
+ // deletion was successful
+ iDeletedEntries->AppendL(id); // will not leave, space has been reserved
+ iMovedEntries->AppendL(id); // will not leave, space has been reserved
+ delete dir;
+ return;
+
+failed:
+ if (partiallyDeleted)
+ {
+ TMsvEntry* entry=NULL;
+ TBool complete =EFalse;
+ for(TInt i =0; i< iDeleteArray.Count(); ++i)
+ {
+ if(iDeleteArray[i].iEntryId == id)
+ {
+ if(iDeleteArray[i].iIsComplete)
+ {
+ iServer.IndexAdapter().GetEntry(id, entry);
+ if(entry)
+ {
+ complete = ETrue;
+ }
+ }
+ break;
+ }
+ }
+
+ if(complete)
+ {
+ // mark as imcomplete
+ TMsvEntry icmpEntry=*entry;
+ icmpEntry.SetComplete(EFalse);
+ iServer.IndexAdapter().LockEntry(id);
+ iServer.IndexAdapter().ChangeEntry(icmpEntry, KMsvServerId, EFalse); // ignore error
+ iServer.IndexAdapter().ReleaseEntry(id);
+ }
+ }
+
+ // we have failed, move onto next state
+ iState = iPCSynced ? EIndexIndividually : EIndex;
+ iError=error;
+ delete dir;
+ }
+
+
+
+void CMsvDelete::DeleteAllIndexEntries()
+//
+//
+//
+ {
+ iMovedEntries->Reset();
+
+ if (iDeletedEntries->Count()==0)
+ return;
+
+ // delete the entries
+ TInt error = KErrNone;
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+ TMsvEntry* entry = NULL;
+ TInt deleteIndex = 0;
+ while(deleteIndex < iDeletedEntries->Count())
+ {
+ iServer.IndexAdapter().GetEntry(iDeletedEntries->At(deleteIndex), entry);
+ if(entry==NULL)
+ {
+ iDeletedEntries->Delete(deleteIndex);
+ continue;
+ }
+
+ // If there's a DB store, delete any header entries associated with the entry.
+ TRAP(error, iServer.MessageDBAdapter().DeleteHeaderEntryL(entry->iMtm, entry->iId));
+ if(KErrNotFound == error) // Ignore entry not found case
+ error = KErrNone;
+
+ if(error)
+ iDeletedEntries->Delete(deleteIndex);
+ else
+ ++deleteIndex;
+ }
+#endif
+ if(!error) // Looks awkward inside the macro above..
+ error = iServer.IndexAdapter().DeleteSelectionUsingTransaction(*iDeletedEntries);
+
+ if (error && iError==KErrNone)
+ iError=error;
+ }
+
+
+void CMsvDelete::DeleteIndividualIndexEntries()
+//
+//
+//
+ {
+ if (iDeletedEntries->Count()==0)
+ return;
+
+ TInt moveIndex=0;
+ TInt deleteIndex=0;
+ iServer.IndexAdapter().BeginTransaction();
+
+ while(deleteIndex < iDeletedEntries->Count())
+ {
+ // get the entry
+ TMsvEntry* entry=NULL;
+ iServer.IndexAdapter().GetEntry(iDeletedEntries->At(deleteIndex), entry);
+ if(entry==NULL)
+ {
+ iDeletedEntries->Delete(deleteIndex);
+ iMovedEntries->Delete(moveIndex);
+ continue;
+ }
+
+ TInt error = KErrNone;
+ if(!entry->Owner())
+ {
+ // either delete the entry, or move it to the deleted folder
+ if(entry->PcSyncCount()==0)
+ { // Deleting the entry..
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+ // If there's a DB store, delete any header entries associated with the entry.
+ TRAP(error, iServer.MessageDBAdapter().DeleteHeaderEntryL(entry->iMtm, entry->iId));
+ if(KErrNotFound == error) // Ignore entry not found case
+ error = KErrNone;
+#endif
+ if(!error) // Looks awkward inside the macro above..
+ error = iServer.IndexAdapter().ForceDeleteEntry(entry->Id());
+
+ if (error)
+ iDeletedEntries->Delete(deleteIndex);
+ else
+ deleteIndex++;
+ iMovedEntries->Delete(moveIndex);
+ }
+ else
+ { // Moving the entry..
+ TMsvEntry deletedEntry(*entry);
+ // this should be removed and CMsvDelete made a friend of TMsvEntry
+ deletedEntry.iDetails.Set(TPtrC());
+ deletedEntry.iDescription.Set(TPtrC());
+ deletedEntry.SetDeleted(ETrue);
+ deletedEntry.SetVisible(EFalse);
+ deletedEntry.SetParent(KMsvDeletedEntryFolderEntryId);
+
+ TMsvId backUpEntryId = entry->Id();
+ iServer.IndexAdapter().LockEntry(backUpEntryId);
+ error = iServer.IndexAdapter().ChangeEntry(deletedEntry, KMsvServerId, EFalse);
+ iServer.IndexAdapter().ReleaseEntry(backUpEntryId);
+ if (error)
+ iMovedEntries->Delete(moveIndex);
+ else
+ moveIndex++;
+ iDeletedEntries->Delete(deleteIndex);
+ }
+ }
+ else
+ error = KErrAccessDenied;
+
+ if (error && iError==KErrNone)
+ iError=error;
+ }
+
+ iServer.IndexAdapter().CommitTransaction();
+ }
+
+
+
+void CMsvDelete::Complete(TInt aError)
+//
+//
+//
+ {
+ User::RequestComplete(iObserverStatus, aError);
+ iState=ECompleted;
+ iDeletionIndex=0;
+ }