--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/MCLENTRY.CPP Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,2782 @@
+// 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:
+//
+
+#ifdef _DEBUG
+#undef _NO_SESSION_LOGGING_
+#endif
+
+#include <s32std.h>
+#include <txtrich.h>
+#include "MSVIDS.H"
+#include "MSVUIDS.H"
+
+#include "MSVAPI.H"
+#include "MSVCOP.H"
+#include "MCLENTRY.H"
+#include "MSVPANIC.H"
+#include "MSVUTILS.H"
+
+#include <mmsvstoremanager.h>
+
+const TInt KMsvClientEntryArrayGranuality=8;
+const TInt KMsvEntryObserverArrayGranuality=4;
+const TInt KMsvMtmListGranularity=8;
+
+//**********************************
+// CMsvClientEntry
+//**********************************
+
+// static
+CMsvClientEntry* CMsvClientEntry::NewLC(const TMsvEntry& aEntry, TMsvClientEntryType aType)
+ {
+ CMsvClientEntry* self = new(ELeave) CMsvClientEntry(aEntry, aType);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+
+CMsvClientEntry::CMsvClientEntry(const TMsvEntry& aEntry, TMsvClientEntryType aType)
+:iEntry(aEntry), iType(aType)
+ {
+ __DECLARE_NAME(_S("CMsvClientEntry"));
+ }
+
+
+CMsvClientEntry::~CMsvClientEntry()
+ {
+ delete iDescription;
+ delete iDetails;
+ }
+
+void CMsvClientEntry::ConstructL()
+ {
+ iDescription = HBufC::NewL(iEntry.iDescription.Length());
+ iDescription->Des().Copy(iEntry.iDescription);
+ iEntry.iDescription.Set(iDescription->Des());
+ iDetails = HBufC::NewL(iEntry.iDetails.Length());
+ iDetails->Des().Copy(iEntry.iDetails);
+ iEntry.iDetails.Set(iDetails->Des());
+ }
+
+
+
+
+//**********************************
+// CMsvEntry
+//**********************************
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+EXPORT_C CMsvEntry* CMsvEntry::NewL(CMsvSession& aMsvSession, TMsvId aMsvId, const TMsvSelectionOrdering& aOrdering, TBool aChildrenOfAvailableDrives)
+/** Creates a new CMsvEntry for the specified entry ID.
+
+Note that this function does not create a new entry, but simply a new object
+to access an existing entry. To create a new entry, use CreateL().
+
+@param aMsvSession The client’s Message Server session
+@param aMsvId ID of the entry to access
+@param aSortType The initial sort order of children of the entry, for example,
+when returned by ChildrenL(). The order can be changed later by SetSortTypeL().
+@param aChildrenOfAvailableDrives Indicates whether children from all available drives are
+to be fetched during construction of this entry. However, a value of true is valid only
+if aMsvId is one of the standard folders, i.e. Inbox, Outbox, Drafts, Sent or Deleted.
+
+@return If the function succeeds, this is a pointer to a newly allocated and initialised object.
+@leave KErrNotFound The requested entry does not exist.
+@leave KErrNoMemory A memory allocation failed.
+@leave KErrArgument aChildrenOfAvailableDrives is set to true and the requested entry is not
+one of the standard folders, i.e. Inbox, Outbox, Drafts, Sent or Deleted.
+*/
+ {
+ CMsvEntry* self = new(ELeave) CMsvEntry(aMsvSession, aOrdering, aChildrenOfAvailableDrives);
+ CleanupStack::PushL(self);
+ self->ConstructL(aMsvId);
+ CleanupStack::Pop();
+ return self;
+ }
+
+
+CMsvEntry::CMsvEntry(CMsvSession& aMsvSession, const TMsvSelectionOrdering& aOrdering, TBool aChildrenOfAvailableDrives)
+:iState(EValid), iMsvSession(aMsvSession), iOrdering(aOrdering), iChildrenOfAvailableDrives(aChildrenOfAvailableDrives)
+ {
+ __DECLARE_NAME(_S("CMsvEntry"));
+ }
+
+
+EXPORT_C void CMsvEntry::SetStandardFolderEntryL(TMsvId aId)
+//
+// Changes the context to another entry
+// If the function leaves, the context is unchanged
+//
+/** Sets the context to the specified entry while also fetching
+children from all available drives. This function can be used to
+set the context to only the standard folders i.e. Inbox, Outbox,
+Drafts, Sent or Deleted.
+
+If the function leaves, the context is unchanged.
+
+@param aId ID of the message entry which is to become the new context
+@leave KErrNotFound aId could not be found in the index.
+@leave KErrArgument aId is not one of the standard folders, i.e. Inbox,
+Outbox, Drafts, Sent or Deleted folders.
+*/
+ {
+ __ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreLeftOpen));
+
+ if (aId==iEntryPtr->Id() && iState==EValid)
+ return;
+
+ SetEntryNoCheckL(aId, ETrue);
+ }
+
+
+
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+
+EXPORT_C CMsvEntry* CMsvEntry::NewL(CMsvSession& aMsvSession, TMsvId aMsvId, const TMsvSelectionOrdering& aOrdering)
+//
+//
+//
+/** Creates a new CMsvEntry for the specified entry ID.
+
+Note that this function does not create a new entry, but simply a new object
+to access an existing entry. To create a new entry, use CreateL().
+
+@param aMsvSession The client’s Message Server session
+@param aMsvId ID of the entry to access
+@param aSortType The initial sort order of children of the entry, for example,
+when returned by ChildrenL(). The order can be changed later by SetSortTypeL().
+@return If the function succeeds, this is a pointer to a newly allocated and initialised object.
+@leave KErrNotFound The requested entry does not exist
+@leave KErrNoMemory A memory allocation failed
+*/
+ {
+ CMsvEntry* self = new(ELeave) CMsvEntry(aMsvSession, aOrdering);
+ CleanupStack::PushL(self);
+ self->ConstructL(aMsvId);
+ CleanupStack::Pop();
+ return self;
+ }
+
+
+CMsvEntry::CMsvEntry(CMsvSession& aMsvSession, const TMsvSelectionOrdering& aOrdering)
+:iState(EValid), iMsvSession(aMsvSession), iOrdering(aOrdering)
+//
+//
+//
+ {
+ __DECLARE_NAME(_S("CMsvEntry"));
+ }
+
+
+EXPORT_C CMsvEntry::~CMsvEntry()
+//
+//
+//
+/** Destructor.
+
+This cleans up the object. CMsvEntry objects must be deleted by client applications
+when they are no longer required. Note that deleting a CMsvEntry object does
+not delete the context, simply the immediate means of accessing it. */
+ {
+ __ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreLeftOpenOnDestruction2));
+
+ if (iOberserverAdded)
+ iMsvSession.RemoveObserver(*this);
+
+ if (iEntries)
+ iEntries->ResetAndDestroy();
+
+ delete iEntries;
+ delete iSortedChildren;
+ delete iObservers;
+ delete iMtmList;
+ }
+
+void CMsvEntry::ConstructL(TMsvId aId)
+//
+//
+//
+ {
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ if(iChildrenOfAvailableDrives && !MsvUtils::IsStandardId(aId))
+ {
+ User::Leave(KErrArgument);
+ }
+#endif
+ iEntries = new (ELeave) CArrayPtrFlat<CMsvClientEntry>(KMsvClientEntryArrayGranuality);
+ iMtmList = new(ELeave) CArrayFixFlat<TUid>(KMsvMtmListGranularity);
+ iSortedChildren = CMsvEntryArray::NewL(*iMtmList);
+
+ // get the required entry from the server
+ CMsvClientEntry* cEntry = DoGetEntryLC(aId, iOwningService);
+ cEntry->SetType(EMsvClientContext);
+ iEntries->AppendL(cEntry);
+ CleanupStack::Pop(); // cEntry
+ iEntryPtr = &iEntries->At(0)->Entry();
+
+ // get the children
+ DoGetChildrenL();
+
+ // Get the notification sequence number
+ iNotifySequence = iMsvSession.Session().NotifySequenceL();
+
+ // get the event notifications from the server
+ iMsvSession.AddObserverL(*this);
+ iOberserverAdded=ETrue;
+
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Constructed CMsvEntry on entry %x"), aId);
+#endif
+ }
+
+#ifndef _NO_SESSION_LOGGING_
+void CMsvEntry::Log(TRefByValue<const TDesC> aFmt, ...)
+ {
+ VA_LIST list;
+ VA_START(list, aFmt);
+
+ // Generate the text
+ TBuf<256> buf;
+ buf.FormatList(aFmt, list);
+
+ // Write to file
+ _LIT(KFormatFile, "CMsvEntry %x: %S");
+ iMsvSession.iLog.WriteFormat(KFormatFile, this, &buf);
+
+ // Write to serial
+#ifndef _NO_SESSION_LOGGING_SERIAL_
+ _LIT(KFormatSerial, "MSGS: CMsvEntry %x: %S");
+ RDebug::Print(KFormatSerial, this, &buf);
+#endif
+ }
+#endif
+
+CMsvClientEntry* CMsvEntry::DoGetEntryLC(TMsvId aId, TMsvId& aOwningService)
+//
+// Gets the entry data from the server and create a CMsvClientEntry around it
+//
+ {
+ TMsvEntry tEntry;
+ User::LeaveIfError(iMsvSession.Session().GetEntry(aId, aOwningService, tEntry));
+ if (tEntry.iType==KUidMsvRootEntry)
+ aOwningService=aId;
+ return CMsvClientEntry::NewLC(tEntry, EMsvClientNull);
+ }
+
+
+
+void CMsvEntry::DoGetChildrenL()
+//
+// Gets the children of the context and places them in the entries array
+// The sorted children pointer array is implicited sorted, as the entries are retrieved
+// from the server with the current sort order
+//
+ {
+ __ASSERT_DEBUG(iEntries->Count()==1, PanicServer(EMsvChildEntriesExist1));
+ __ASSERT_DEBUG(iSortedChildren->Count()==0, PanicServer(EMsvChildEntriesExist2));
+
+ // get the children from the server - using only the visible flag
+ TMsvSelectionOrdering order(KMsvNoGrouping, EMsvSortByNone, iOrdering.ShowInvisibleEntries());
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ // If child entries from all drives in the device are to be fetched.
+ if(iChildrenOfAvailableDrives)
+ {
+ User::LeaveIfError(iMsvSession.Session().GetChildrenAll(iEntryPtr->Id(), *iEntries, order));
+ }
+ else
+#endif
+ {
+ User::LeaveIfError(iMsvSession.Session().GetChildren(iEntryPtr->Id(), *iEntries, order));
+ }
+
+ // add the children to the sorted pointer list - current context is the first entry
+ TInt totalCount=iEntries->Count();
+ for (TInt count=1; count<totalCount; count++)
+ iSortedChildren->AppendL(&iEntries->At(count)->Entry());
+
+ // sort the children
+ iSortedChildren->SortL(iOrdering);
+ }
+
+
+EXPORT_C void CMsvEntry::SetEntryL(TMsvId aId)
+//
+// Changes the context to another entry
+// If the function leaves, the context is unchanged
+//
+/** Sets the context to the specified entry.
+
+If the function leaves, the context is unchanged.
+
+@param aId ID of the message entry which is to become the new context
+@leave KErrNotFound aId could not be found in the index */
+ {
+ __ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreLeftOpen));
+
+ if (aId==iEntryPtr->Id() && iState==EValid)
+ return;
+
+ SetEntryNoCheckL(aId);
+ }
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+EXPORT_C void CMsvEntry::SetEntryNoCheckL(TMsvId aId, TBool aChildrenOfAvailableDrives /* DEFAULT=EFalse*/)
+//
+// Changes the context to another entry
+// If the function leaves, the context is unchanged
+// The function does not check for when the context is already on
+// the given TMsvId.
+//
+/** Sets the context to the specified entry.
+Children from all available drives will be fetched depending on the value of
+aChildrenOfAvailableDrives.
+
+If the function leaves, the context is unchanged.
+
+@internalTechnology
+@param aId ID of the message entry which is to become the new context
+@param aChildrenOfAvailableDrives Indicates whether children from all available drives are to
+be fetched during construction of this entry. However, a value of true is valid only
+if aMsvId is one among TMsvId's of Inbox, Outbox, Drafts, Sent or Deleted folders.
+@leave KErrNotFound aMsvId could not be found in the index
+@leave KErrArgument aChildrenOfAvailableDrives is set to true and the requested entry is not
+one of the standard folders, i.e. Inbox, Outbox, Drafts, Sent or Deleted. */
+ {
+ __ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreLeftOpen));
+
+ if(aChildrenOfAvailableDrives && !MsvUtils::IsStandardId(aId))
+ {
+ User::Leave(KErrArgument);
+ }
+
+ // create new entry array
+ CArrayPtrFlat<CMsvClientEntry>* newEntries = new (ELeave) CArrayPtrFlat<CMsvClientEntry>(KMsvClientEntryArrayGranuality);
+ CleanupStack::PushL(newEntries);
+
+ // get the new context and place in array
+ TMsvId newOwningService;
+ CMsvClientEntry* cEntry = DoGetEntryLC(aId, newOwningService);
+ cEntry->SetType(EMsvClientContext);
+ newEntries->AppendL(cEntry);
+ // create new children array
+ CMsvEntryArray* newSortedChildren = CMsvEntryArray::NewL(*iMtmList);
+
+ // keep the old arrays
+ CArrayPtrFlat<CMsvClientEntry>* oldEntries = iEntries;
+ CMsvEntryArray* oldSortedChildren = iSortedChildren;
+
+ TBool oldFlag = iChildrenOfAvailableDrives;
+ iChildrenOfAvailableDrives = aChildrenOfAvailableDrives;
+
+ // use new arrays
+ CleanupStack::Pop(2); // cEntry, newEntries
+ iEntries = newEntries;
+ iSortedChildren = newSortedChildren;
+ iEntryPtr = &iEntries->At(0)->Entry();
+
+ // get the children and sort accordingly
+ TRAPD(leave, DoGetChildrenL(); iNotifySequence = iMsvSession.Session().NotifySequenceL());
+
+ if (leave)
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Failed to SetEntryL to %x with %d"), aId, leave);
+#endif
+
+ // reset the old context
+ iChildrenOfAvailableDrives = oldFlag;
+
+ iEntries = oldEntries;
+ iSortedChildren = oldSortedChildren;
+ iEntryPtr = &iEntries->At(0)->Entry();
+ // cleanup
+ newEntries->ResetAndDestroy();
+ delete newEntries;
+ delete newSortedChildren;
+ // propogate leave
+ User::Leave(leave);
+ }
+ else
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("SetEntryL to %x, sequence %d"), aId, iNotifySequence);
+#endif
+
+ // set the new owning service
+ iOwningService = newOwningService;
+ // delete the old context
+ oldEntries->ResetAndDestroy();
+ delete oldEntries;
+ delete oldSortedChildren;
+ // make sure the state is marked as valid
+ iState = EValid;
+ }
+ }
+#else //#define SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT
+
+EXPORT_C void CMsvEntry::SetEntryNoCheckL(TMsvId aId)
+//
+// Changes the context to another entry
+// If the function leaves, the context is unchanged
+// The function does not check for when the context is already on
+// the given TMsvId.
+//
+/** Sets the context to the specified entry.
+
+If the function leaves, the context is unchanged.
+
+@internalTechnology
+@param aId ID of the message entry which is to become the new context
+@leave KErrNotFound aMsvId could not be found in the index */
+ {
+ __ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreLeftOpen));
+
+ // create new entry array
+ CArrayPtrFlat<CMsvClientEntry>* newEntries = new (ELeave) CArrayPtrFlat<CMsvClientEntry>(KMsvClientEntryArrayGranuality);
+ CleanupStack::PushL(newEntries);
+
+ // get the new context and place in array
+ TMsvId newOwningService;
+ CMsvClientEntry* cEntry = DoGetEntryLC(aId, newOwningService);
+ cEntry->SetType(EMsvClientContext);
+ newEntries->AppendL(cEntry);
+ // create new children array
+ CMsvEntryArray* newSortedChildren = CMsvEntryArray::NewL(*iMtmList);
+
+ // keep the old arrays
+ CArrayPtrFlat<CMsvClientEntry>* oldEntries = iEntries;
+ CMsvEntryArray* oldSortedChildren = iSortedChildren;
+
+ // use new arrays
+ CleanupStack::Pop(2); // cEntry, newEntries
+ iEntries = newEntries;
+ iSortedChildren = newSortedChildren;
+ iEntryPtr = &iEntries->At(0)->Entry();
+
+ // get the children and sort accordingly
+ TRAPD(leave, DoGetChildrenL(); iNotifySequence = iMsvSession.Session().NotifySequenceL());
+
+ if (leave)
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Failed to SetEntryL to %x with %d"), aId, leave);
+#endif
+
+ // reset the old context
+ iEntries = oldEntries;
+ iSortedChildren = oldSortedChildren;
+ iEntryPtr = &iEntries->At(0)->Entry();
+ // cleanup
+ newEntries->ResetAndDestroy();
+ delete newEntries;
+ delete newSortedChildren;
+ // propogate leave
+ User::Leave(leave);
+ }
+ else
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("SetEntryL to %x, sequence %d"), aId, iNotifySequence);
+#endif
+
+ // set the new owning service
+ iOwningService = newOwningService;
+ // delete the old context
+ oldEntries->ResetAndDestroy();
+ delete oldEntries;
+ delete oldSortedChildren;
+ // make sure the state is marked as valid
+ iState = EValid;
+ }
+ }
+#endif
+/**
+Creates a new child entry owned by the context asynchronously.
+
+Note that all session observers are notified when a new entry is created with
+an EMsvEntriesCreated event (see TMsvSessionEvent). CMsvEntry objects are
+such session observers themselves. When the object receives such a session
+notification, it calls all registered entry observers with a TMsvEntryEvent
+event EMsvNewChildren, passing in the ID of the new child.
+
+If aEntry is not a service entry, then the context must not be set to the root entry and iServiceId field must be defined .
+If aEntry is a service entry, then the context must be set to the root entry.
+
+The returned CMsvOperation object completes when creation is complete.
+
+@param aEntry
+Index entry value for the new entry
+
+@param aStatus
+The request status to be completed when the operation has finished
+
+@leave KErrArgument aEntry is invalid
+
+@return
+The operation object controlling the create command.
+*/
+EXPORT_C CMsvOperation* CMsvEntry::CreateL(const TMsvEntry& aEntry, TRequestStatus& aStatus)
+ {
+ return CreateL(aEntry, RProcess().SecureId(), aStatus);
+ }
+
+/**
+Creates a new child entry owned by the context asynchronously. Sets the owner of
+the created entry to process specified by the supplied ID.
+
+Note that all session observers are notified when a new entry is created with
+an EMsvEntriesCreated event (see TMsvSessionEvent). CMsvEntry objects are
+such session observers themselves. When the object receives such a session
+notification, it calls all registered entry observers with a TMsvEntryEvent
+event EMsvNewChildren, passing in the ID of the new child.
+
+If aEntry is not a service entry, then the context must not be set to the root entry and iServiceId field must be defined .
+If aEntry is a service entry, then the context must be set to the root entry.
+
+The returned CMsvOperation object completes when creation is complete.
+
+@param aEntry
+Index entry value for the new entry
+
+@param aOwnerId
+The ID of process that owns the created entry.
+
+@param aStatus
+The request status to be completed when the operation has finished
+
+@leave KErrArgument aEntry is invalid
+
+@return
+The operation object controlling the create command.
+*/
+EXPORT_C CMsvOperation* CMsvEntry::CreateL(const TMsvEntry& aEntry, TSecureId aOwnerId, TRequestStatus& aStatus)
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Asynchronous CreateL"));
+#endif
+
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+
+ TMsvEntry entry=aEntry;
+ entry.SetParent(iEntryPtr->Id());
+
+ __ASSERT_DEBUG(MsvUtils::ValidEntry(entry, ETrue), PanicServer(EMsvCreatingInvalidEntry));
+ if (!MsvUtils::ValidEntry(entry, ETrue))
+ User::Leave(KErrArgument);
+
+ CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
+ CleanupStack::PushL(operation);
+ User::LeaveIfError(iMsvSession.Session().OperationMtmL(iEntryPtr->Id(), operation->iMtm, operation->iService));
+ iMsvSession.Session().CreateEntryL(entry, operation->Id(), aOwnerId, operation->iStatus);
+ operation->Start();
+ CleanupStack::Pop(); // operation
+ return operation;
+ }
+
+
+/**
+Creates a new child entry owned by the context synchronously.
+
+Note that all session observers are notified when a new entry is created with
+an EMsvEntriesCreated event (see TMsvSessionEvent). CMsvEntry objects are
+such session observers themselves. When the object receives such a session
+notification, it calls all registered entry observers with a TMsvEntryEvent
+event EMsvNewChildren, passing in the ID of the new child.
+
+If aEntry is not a service entry, then the context must not be set to the root entry and iServiceId field must be defined .
+If aEntry is a service entry, then the context must be set to the root entry.
+
+This function can only be used on local entries.
+
+@param aEntry
+Index entry value for the new entry
+
+@leave KErrArgument aEntry is invalid
+*/
+EXPORT_C void CMsvEntry::CreateL(TMsvEntry& aEntry)
+ {
+ CreateL(aEntry, RProcess().SecureId());
+ }
+
+/**
+Creates a new child entry owned by the context synchronously. Sets the owner of
+the created entry to process specified by the supplied ID.
+
+Note that all session observers are notified when a new entry is created with
+an EMsvEntriesCreated event (see TMsvSessionEvent). CMsvEntry objects are
+such session observers themselves. When the object receives such a session
+notification, it calls all registered entry observers with a TMsvEntryEvent
+event EMsvNewChildren, passing in the ID of the new child.
+
+If aEntry is not a service entry, then the context must not be set to the root entry and iServiceId field must be defined .
+If aEntry is a service entry, then the context must be set to the root entry.
+
+This function can only be used on local entries.
+
+@param aEntry
+Index entry value for the new entry
+
+@param aOwnerId
+The ID of process that owns the created entry.
+
+@leave KErrArgument aEntry is invalid
+*/
+EXPORT_C void CMsvEntry::CreateL(TMsvEntry& aEntry, TSecureId aOwnerId)
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Synchronous CreateL"));
+#endif
+ __ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService));
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+
+ TMsvEntry entry=aEntry;
+ entry.SetParent(iEntryPtr->Id());
+
+ __ASSERT_DEBUG(MsvUtils::ValidEntry(entry, ETrue), PanicServer(EMsvCreatingInvalidEntry));
+ if (!MsvUtils::ValidEntry(entry, ETrue))
+ User::Leave(KErrArgument);
+
+ CMsvEntryArray* newSortedChildren = NULL;
+ CMsvClientEntry* cEntry = NULL;
+
+ TBool addEntry = entry.Visible() || iOrdering.ShowInvisibleEntries();
+ if (addEntry)
+ {
+ // Create what may be the new child entry if nothing goes wrong
+ cEntry = CMsvClientEntry::NewLC(entry, EMsvClientChild);
+
+ // Reserve space for the new entry for later
+ iEntries->SetReserveL(iEntries->Count() + 1);
+
+ newSortedChildren = CMsvEntryArray::NewLC(*iMtmList);
+
+ // add the children to the sorted pointer list - current context is the first entry
+ TInt totalCount=iEntries->Count();
+ for (TInt count=1; count<totalCount; count++)
+ newSortedChildren->AppendL(&iEntries->At(count)->Entry());
+
+ // We've created a new sorted child list now so we won't leave later
+ newSortedChildren->AppendL(&cEntry->Entry());
+ newSortedChildren->SortL(iOrdering);
+ }
+
+ TInt id = iMsvSession.OperationId();
+ iMsvSession.Session().CreateEntryL(entry, id, aOwnerId);
+ iMsvSession.CheckDrive();
+
+ TPckgBuf<TMsvLocalOperationProgress> progressPack;
+ User::LeaveIfError(iMsvSession.Session().OperationCompletion(id, progressPack));
+ User::LeaveIfError(progressPack().iError);
+
+ // Can't leave after here
+
+ if (addEntry)
+ {
+ CleanupStack::Pop(); // newSortedChildren
+ delete iSortedChildren;
+ iSortedChildren = newSortedChildren;
+
+ CleanupStack::Pop(); // cEntry
+ iEntries->AppendL(cEntry); // Will not leave because we've reserved space earlier
+ cEntry->SetId(progressPack().iId);
+
+ TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
+ ptr->SetOwner(ETrue);
+ }
+
+ aEntry.SetParent(iEntryPtr->Id());
+ aEntry.SetId(progressPack().iId);
+
+ // If the entry is a service its service Id is the same as its Id
+ // Otherwise it must be a local entry
+ // We don't allow synchronous creation of remote entries
+ TMsvId serviceId = aEntry.Id();
+
+ aEntry.iServiceId = (aEntry.iType == KUidMsvServiceEntry) ? serviceId : KMsvLocalServiceIndexEntryId;
+ }
+
+/**
+Sets the context's index entry to the specified values. The returned CMsvOperation
+object completes when the change is complete.
+
+It is important to note that the state of the context is undefined until the
+observer of the entry has been informed that the entry has been changed, or
+the operation is completed with an error. If the function leaves, the context
+is unchanged.
+
+@param aEntry
+The new index entry values for the context
+
+@param aStatus
+The request status to be completed when the operation has finished
+
+@leave KErrAccessDenied The entry is locked by another client
+
+@leave KErrArgument aEntry is invalid or the ID specified in aEntry is not
+the same as the context ID
+
+@leave KErrNoMemory The operation could not be created or passed to the server
+
+@return
+An operation object controlling the change command
+*/
+EXPORT_C CMsvOperation* CMsvEntry::ChangeL(const TMsvEntry& aEntry, TRequestStatus& aStatus)
+ {
+ return ChangeL(aEntry, RProcess().SecureId(), aStatus);
+ }
+
+/**
+Sets the context's index entry to the specified values. The returned CMsvOperation
+object completes when the change is complete. Sets the owner of the changed entry
+to process specified by the supplied ID.
+
+It is important to note that the state of the context is undefined until the
+observer of the entry has been informed that the entry has been changed, or
+the operation is completed with an error. If the function leaves, the context
+is unchanged.
+
+@param aEntry
+The new index entry values for the context
+
+@param aOwnerId
+The ID of process that owns the changed entry.
+
+@param aStatus
+The request status to be completed when the operation has finished
+
+@leave KErrAccessDenied The entry is locked by another client
+
+@leave KErrArgument aEntry is invalid or the ID specified in aEntry is not
+the same as the context ID
+
+@leave KErrNoMemory The operation could not be created or passed to the server
+
+@return
+An operation object controlling the change command
+*/
+EXPORT_C CMsvOperation* CMsvEntry::ChangeL(const TMsvEntry& aEntry, TSecureId aOwnerId, TRequestStatus& aStatus)
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Asynchronous ChangeL to %x"), aEntry.Id());
+#endif
+
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext, PanicServer(EMsvEntryAlreadyChangingContext));
+ __ASSERT_DEBUG(aEntry.Id()==iEntryPtr->Id(), PanicServer(EMsvChangingEntryNotContext));
+ __ASSERT_DEBUG(MsvUtils::ValidEntry(aEntry), PanicServer(EMsvChangingToInvalidEntry));
+
+ // can only change the current context
+ if (aEntry.Id()!=iEntryPtr->Id() || aEntry.Parent()!=iEntryPtr->Parent() || !MsvUtils::ValidEntry(aEntry))
+ User::Leave(KErrArgument);
+
+ // cannot change standard folders
+ if (iEntryPtr->StandardFolder())
+ User::Leave(KErrAccessDenied);
+
+ // create the operation
+ CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
+ CleanupStack::PushL(operation);
+ if (iEntryPtr->iType==KUidMsvServiceEntry)
+ {
+ operation->iMtm = KUidMsvLocalServiceMtm;
+ operation->iService = KMsvLocalServiceIndexEntryId;
+ }
+ else
+ User::LeaveIfError(iMsvSession.Session().OperationMtmL(iEntryPtr->Id(), operation->iMtm, operation->iService));
+
+ // check that no other entries are type EMsvClientChangedContext
+ TInt count=iEntries->Count();
+ while (count--)
+ {
+ if (iEntries->At(count)->Type() == EMsvClientChangedContext)
+ {
+ delete iEntries->At(count);
+ iEntries->Delete(count);
+ }
+ }
+
+ // create local copy of entry
+ TMsvEntry entry=aEntry;
+
+ // check the hidden flags are correct
+ entry.SetOwner(iEntryPtr->Owner());
+ entry.SetDeleted(iEntryPtr->Deleted());
+
+ // store the new context for after the operation has completed
+ CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(entry, EMsvClientChangedContext);
+ if (iEntries->Count()==1)
+ iEntries->AppendL(cEntry);
+ else
+ iEntries->InsertL(1, cEntry);
+
+ // start the change operation
+ TRAPD(leave, iMsvSession.Session().ChangeEntryL(entry, operation->Id(), aOwnerId, operation->iStatus));
+ if (leave)
+ {
+ iEntries->Delete(1);
+ CleanupStack::PopAndDestroy(); // operation & cEntry
+ User::Leave(leave);
+ }
+
+ operation->Start();
+ iState = EInvalidChangingContext;
+ CleanupStack::Pop(2); // operation and cEntry
+ return operation;
+ }
+
+/**
+Sets the context's index entry to the specified values. The function is performed
+synchronously.
+
+This function can only be used on local entries.
+
+@param aEntry
+The new index entry values for the context
+
+@leave KErrAccessDenied The entry is locked by another client
+
+@leave KErrArgument aEntry is invalid or the ID specified in aEntry is not
+the same as the context ID
+
+@leave KErrNoMemory The operation could not be created or passed to the server
+*/
+EXPORT_C void CMsvEntry::ChangeL(const TMsvEntry& aEntry)
+ {
+ ChangeL(aEntry, RProcess().SecureId());
+ }
+
+/**
+Sets the context's index entry to the specified values. The function is performed
+synchronously. Sets the owner of the changed entry to process specified by the
+supplied ID.
+
+This function can only be used on local entries.
+
+@param aEntry
+The new index entry values for the context
+
+@param aOwnerId
+The ID of process that owns the changed entry.
+
+@leave KErrAccessDenied The entry is locked by another client
+
+@leave KErrArgument aEntry is invalid or the ID specified in aEntry is not
+the same as the context ID
+
+@leave KErrNoMemory The operation could not be created or passed to the server
+*/
+EXPORT_C void CMsvEntry::ChangeL(const TMsvEntry& aEntry, TSecureId aOwnerId)
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Synchronous ChangeL to %x"), aEntry.Id());
+#endif
+
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext, PanicServer(EMsvEntryAlreadyChangingContext));
+ __ASSERT_DEBUG(aEntry.Id()==iEntryPtr->Id(), PanicServer(EMsvChangingEntryNotContext));
+ __ASSERT_DEBUG(MsvUtils::ValidEntry(aEntry), PanicServer(EMsvChangingToInvalidEntry));
+
+ // can only change the current context
+ if (aEntry.Id()!=iEntryPtr->Id() || aEntry.Parent()!=iEntryPtr->Parent() || !MsvUtils::ValidEntry(aEntry))
+ User::Leave(KErrArgument);
+
+ // cannot change standard folders
+ if (iEntryPtr->StandardFolder())
+ User::Leave(KErrAccessDenied);
+
+ // create local copy of entry
+ TMsvEntry entry=aEntry;
+
+ // check the hidden flags are correct
+ entry.SetOwner(iEntryPtr->Owner());
+ entry.SetDeleted(iEntryPtr->Deleted());
+
+ // store the new context for after the operation has completed
+ CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(entry, EMsvClientContext);
+
+ TInt id = iMsvSession.OperationId();
+ iMsvSession.Session().ChangeEntryL(aEntry, id, aOwnerId);
+
+ TPckgBuf<TMsvLocalOperationProgress> progressPack;
+ User::LeaveIfError(iMsvSession.Session().OperationCompletion(id, progressPack));
+ User::LeaveIfError(progressPack().iError);
+
+ // Cannot leave after this
+ delete iEntries->At(0);
+ CleanupStack::Pop(); // cEntry
+ iEntries->At(0) = cEntry;
+ iEntryPtr = &iEntries->At(0)->Entry();
+ }
+
+
+EXPORT_C CMsvOperation* CMsvEntry::DeleteL(TMsvId aId, TRequestStatus& aStatus)
+//
+// Deletes a child of the context
+//
+ /** Deletes a child entry of the context asynchronously.
+
+ The delete works recursively through all the descendants. If a child or any
+ descendant is locked by another client or any store or file is open, then
+ that child will not be deleted. Any files and stores associated with the entry
+ are deleted.
+
+ The returned CMsvOperation object completes when deletion is complete.
+
+
+ @param aId ID of entry to be deleted
+ @param aStatus The request status to be completed when the operation has finished
+
+ @leave KErrNotFound The specified entry was not a child of the context
+ @leave KErrNotSupported If deleting entries from non-current drive
+ @return The operation object controlling the deletion command */
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Asynchronous DeleteL, entry %x"), aId);
+#endif
+
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ selection->AppendL(aId);
+ CMsvOperation* operation = DoDeleteL(*selection, aStatus);
+ CleanupStack::PopAndDestroy(); // selection
+ return operation;
+ }
+
+
+
+EXPORT_C CMsvOperation* CMsvEntry::DeleteL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
+//
+// Deletes a selection containing children of the context
+//
+/** Deletes child entries of the context asynchronously.
+
+The delete works recursively through all the descendants. If a child or any
+descendant is locked by another client or any store or file is open, then
+that child will not be deleted. Any files and stores associated with the entries
+are deleted.
+
+The returned CMsvOperation object completes when deletion is complete.
+
+@param aSelection List of ID of the entries to be deleted
+@param aStatus The request status to be completed when the operation has finished
+
+@leave KErrNotFound A specified entry was not a child of the context
+@leave KErrNotSupported If deleting entries from non-current drive
+@return The operation object controlling the deletion command */
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Asynchronous DeleteL with selection of %d entries"), aSelection.Count());
+#endif
+
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ return DoDeleteL(aSelection, aStatus);
+ }
+
+
+
+CMsvOperation* CMsvEntry::DoDeleteL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
+//
+//
+//
+ {
+ __ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
+
+ if (!AreChildren(aSelection))
+ User::Leave(KErrNotFound);
+
+ CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
+ CleanupStack::PushL(operation);
+ if (iEntryPtr->iType==KUidMsvRootEntry)
+ {
+ // we must be deleting services - so it is a local operation
+ operation->iMtm = KUidMsvLocalServiceMtm;
+ operation->iService = KMsvLocalServiceIndexEntryId;
+ }
+ else
+ User::LeaveIfError(iMsvSession.Session().OperationMtmL(aSelection.At(0), operation->iMtm, operation->iService));
+
+#if defined(_DEBUG)
+ // check other entries in selection are consistent and are not read only
+ TInt dCount = aSelection.Count();
+ while (dCount--)
+ {
+ if (iEntryPtr->iType!=KUidMsvRootEntry)
+ {
+ TMsvId service;
+ TUid mtm;
+ TInt error = iMsvSession.Session().OperationMtmL(aSelection.At(dCount), mtm, service);
+ __ASSERT_DEBUG(error==KErrNone || error==KErrNotFound, PanicServer(EMsvNonConsistentDeleteSelection));
+ __ASSERT_DEBUG(mtm==operation->iMtm, PanicServer(EMsvNonConsistentDeleteSelection));
+ __ASSERT_DEBUG(service==operation->iService, PanicServer(EMsvNonConsistentDeleteSelection));
+ }
+ TMsvEntry dEntry;
+ TMsvId dService;
+ if (iMsvSession.Session().GetEntry(aSelection.At(dCount), dService, dEntry)==KErrNone)
+ {
+ __ASSERT_DEBUG(dService==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && dService==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && dService==aSelection.At(dCount)), PanicServer(EMsvDeletingEntryDifferentOwningService));
+ }
+ }
+#endif
+
+ iMsvSession.Session().DeleteEntriesL(aSelection, operation->Id(), operation->iStatus);
+ operation->Start();
+ CleanupStack::Pop(); // operation
+ return operation;
+ }
+
+EXPORT_C void CMsvEntry::DeleteL(TMsvId aId)
+/** Deletes a child entry of the context synchronously.
+
+The delete works recursively through all the descendants. If a child or any descendant is locked by another
+client or any store or file is open, then that child will not be deleted. Any files and stores associated
+with the entry are deleted.
+
+This function can only be used on local entries.
+
+@param aId ID of entry to be deleted
+@leave KErrNotFound The specified entry was not a child of the context
+@leave KErrNotSupported If deleting entries from non-current drive
+*/
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Synchronous DeleteL, entry %x"), aId);
+#endif
+ __ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+
+ User::LeaveIfError(CMsvEntry::DeleteOneL(aId));
+ }
+
+EXPORT_C void CMsvEntry::DeleteL(const CMsvEntrySelection& aSelection, TMsvLocalOperationProgress& aProgress)
+/** Deletes child entries of the context synchronously.
+
+The delete works recursively through all the descendants. If a child or any
+descendant is locked by another client or any store or file is open, then
+that child will not be deleted. Any files and stores associated with the entries
+are deleted.
+
+@param aSelection List of ID of the entries to be deleted
+@param aProgress Progress information for the delete operation
+@leave KErrNotFound A specified entry was not a child of the context
+@leave KErrNotSupported If deleting entries from non-current drive */
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Synchronous DeleteL with selection of %d entries"), aSelection.Count());
+#endif
+
+ __ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ __ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
+
+ if (!AreChildren(aSelection))
+ User::Leave(KErrNotFound);
+
+ aProgress.iTotalNumberOfEntries=aSelection.Count();
+ aProgress.iNumberCompleted=0;
+ aProgress.iNumberRemaining=aProgress.iTotalNumberOfEntries;
+ aProgress.iError=KErrNone;
+
+ TInt count=aProgress.iTotalNumberOfEntries;
+ while(count--)
+ {
+ aProgress.iId=aSelection.At(count);
+ TInt err=DeleteOneL(aProgress.iId);
+ aProgress.iNumberRemaining--;
+ if(err==KErrNone)
+ aProgress.iNumberCompleted++;
+ else
+ {
+ aProgress.iError=err;
+ aProgress.iNumberFailed++;
+ }
+ }
+ }
+
+
+TInt CMsvEntry::DeleteOneL(TMsvId aMsvId)
+ {
+ CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ selection->AppendL(aMsvId);
+ TInt opid = iMsvSession.OperationId();
+ iMsvSession.Session().DeleteEntriesL(*selection, opid);
+
+ TMsvLocalOperationProgress progress;
+ TPckg<TMsvLocalOperationProgress> progressPack(progress);
+ User::LeaveIfError(iMsvSession.Session().OperationCompletion(opid, progressPack));
+
+ if(progress.iError==KErrNone)
+ {
+ TMsvId id = selection->At(0);
+ TInt ii = iSortedChildren->Count();
+ while (ii--)
+ {
+ if (iSortedChildren->At(ii)->Id() == id)
+ {
+ iSortedChildren->Delete(ii);
+ break;
+ }
+ }
+
+ ii = iEntries->Count();
+ while (ii--)
+ {
+ if (iEntries->At(ii)->Entry().Id() == id)
+ {
+ delete iEntries->At(ii);
+ iEntries->Delete(ii);
+ break;
+ }
+ }
+ // Reset the owner flag
+ if (Count() == 0)
+ {
+ TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
+ ptr->SetOwner(EFalse);
+ }
+ }
+ CleanupStack::PopAndDestroy(selection);
+ return(progress.iError);
+ }
+
+
+
+
+EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenL() const
+//
+// Gets a selection containing the children of the context
+//
+/** Gets a selection containing the IDs of all the context children. If the entry
+has no children, the selection is empty.
+
+The calling function is responsible for the deletion of the returned CMsvEntrySelection.
+
+@leave KErrNoMemory Not enough memory to create the selection
+@return A selection containing the ID of all children of the context */
+ {
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ TInt totalCount=iSortedChildren->Count();
+ for (TInt count=0; count<totalCount; count++)
+ {
+ selection->AppendL(iSortedChildren->At(count)->Id());
+ }
+ CleanupStack::Pop(); // selection
+ return selection;
+ }
+
+EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenWithServiceL(TMsvId aServiceId) const
+//
+// Gets a selection containing the children of the context which use the service
+//
+/** Gets a selection containing the IDs of all the context children filtered by message service.
+i.e. the index entry's iServiceId field equals aId.
+
+If the entry has no such children, the selection is empty.
+
+The calling function is responsible for the deletion of the returned CMsvEntrySelection.
+@return List of IDs of all children of the context meeting the criterion
+@param aServiceId Service by which to filter
+@leave KErrNoMemory Not enough memory to create the selection
+*/
+ {
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ TInt totalCount=iSortedChildren->Count();
+ for (TInt count=0; count<totalCount; count++)
+ {
+ if (iSortedChildren->At(count)->iServiceId==aServiceId)
+ {
+ selection->AppendL(iSortedChildren->At(count)->Id());
+ }
+ }
+ CleanupStack::Pop(); // selection
+ return selection;
+ }
+
+EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenWithMtmL(TUid aMtm) const
+//
+// Gets a selection containing the children of the context which use the same MTM
+//
+/** Gets a selection containing the IDs of all the context children filtered by
+MTM type. i.e. the index entry's iMtm field equals aMtm.
+
+If the entry has no such children, the selection is empty.
+
+The calling function is responsible for the deletion of the returned CMsvEntrySelection.
+
+@param aMtm MTM type by which to filter
+@leave KErrNoMemory Not enough memory to create the selection
+@return A selection containing the ID of all children of the context meeting
+the criterion */
+ {
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ TInt totalCount=iSortedChildren->Count();
+ for (TInt count=0; count<totalCount; count++)
+ {
+ if (iSortedChildren->At(count)->iMtm==aMtm)
+ {
+ selection->AppendL(iSortedChildren->At(count)->Id());
+ }
+ }
+ CleanupStack::Pop(); // selection
+ return selection;
+ }
+
+EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenWithTypeL(TUid aType) const
+//
+// Gets a selection containing the children of the context which are the same type
+//
+/** Gets a selection containing the IDs of all the context children filtered by
+entry type. i.e. is the entry a folder, a message, etc.
+
+If the entry has no such children, the selection is empty.
+
+The calling function is responsible for the deletion of the returned CMsvEntrySelection.
+
+
+@param aType Entry type by which to filter.
+@leave KErrNoMemory Not enough memory to create the selection
+@return A selection containing the ID of all children of the context meeting
+the criterion */
+ {
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+
+ CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ TInt totalCount=iSortedChildren->Count();
+ for (TInt count=0; count<totalCount; count++)
+ {
+ if (iSortedChildren->At(count)->iType==aType)
+ {
+ selection->AppendL(iSortedChildren->At(count)->Id());
+ }
+ }
+ CleanupStack::Pop(); // selection
+ return selection;
+ }
+
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+/**
+ * ChildrenOfAvailableDrivesL()
+ *
+ * @param None.
+ * @return CMsvEntrySelection List of child ids from all available drives.
+ * @leave KErrArgument If the function is used for a TMsvId other than that
+ * of standard folders, i.e. Inbox, Outbox, Drafts, Sent or Deleted.
+ * @leave KErrNoMemory Not enough memory to create the selection.
+ *
+ * Gets a selection containing the child Id's from all drives currently present
+ * in the server preferred drive list.
+ * The function must be used only if the context is set to one of the standard folders,
+ * i.e. Inbox, Outbox, Drafts, Sent or Deleted.
+ *
+ * The calling function is responsible for the deletion of the returned CMsvEntrySelection.
+ *
+ @publishedAll
+ @released
+ */
+EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenOfAvailableDrivesL() const
+ {
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+
+ if(!iChildrenOfAvailableDrives)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+
+ TInt totalCount = iSortedChildren->Count();
+ for (TInt count=0; count<totalCount; count++)
+ {
+ selection->AppendL(iSortedChildren->At(count)->Id());
+ }
+ CleanupStack::Pop(); // selection
+ return selection;
+ }
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+
+
+EXPORT_C const TMsvEntry& CMsvEntry::operator[](TInt aIndex) const
+//
+// Returns the data for a child, zero index with the current sort order
+//
+/** Gets the index entry of the child at the position specified by the array index.
+The child entries of the context can be considered as a zero-based array,
+with entries sorted according to the current sort order.
+
+Note:
+
+The function panics with E32USER-CBase 21 if aIndex was out of range.
+
+@param aIndex Array index
+@return Index entry for the specified child. Valid for in-range values of aIndex. */
+ {
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ return *iSortedChildren->At(aIndex);
+ }
+
+
+EXPORT_C CMsvEntry* CMsvEntry::ChildEntryL(TMsvId aId) const
+//
+// Returns a new entry with the child as the context
+//
+/** Gets a new CMsvEntry object with its context set to the child entry ID. aMsvId
+must specify a child of the current context.
+
+The CMsvEntry object must be deleted by the client application when it is
+no longer required.
+
+@param aId ID of a child entry
+@leave KErrNotFound aMsvId does not specify a child of the context
+@return CMsvEntry object with its context set to child entry */
+ {
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ if (!IsAChild(aId))
+ User::Leave(KErrNotFound);
+ return CMsvEntry::NewL(iMsvSession, aId, iOrdering);
+ }
+
+
+EXPORT_C const TMsvEntry& CMsvEntry::ChildDataL(TMsvId aId) const
+//
+// Returns the data for a child with the aId
+//
+/** Gets the index entry of context's child with the specified ID.
+
+@param aId ID of the child
+@leave KErrNotFound No child exists with that ID
+@return Index entry for the specified child. Valid for in-range values of aIndex. */
+ {
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+
+ TInt count=iSortedChildren->Count();
+ while (count--)
+ {
+ if (iSortedChildren->At(count)->Id()==aId)
+ break;
+ }
+ User::LeaveIfError(count); // will be -1 (KErrNotFound)
+ return *iSortedChildren->At(count);
+ }
+
+
+EXPORT_C CMsvStore* CMsvEntry::ReadStoreL()
+//
+// Return store for the current context which is opened for read only
+//
+/** Obtains the message store for the current context with read-only access.
+
+Multiple clients can read from a store simultaneously. If another client is already
+writing to the store, the function leaves with KErrAccessDenied.
+
+The returned CMsvStore must be deleted when it is no longer required.
+
+@leave KErrNoMemory Not enough memory to open store
+@leave KErrAccessDenied Another client is currently writing to the store
+@leave KErrNotFound There is no store associated with this entry
+@return Context's message store open for read-only access */
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("ReadStoreL for entry %x"), iEntryPtr->Id());
+#endif
+
+ __ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreAlreadyOpen));
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ User::LeaveIfError(iMsvSession.Session().ReadStore(iEntryPtr->Id()));
+
+ // open the store
+ TInt err =0;
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+ TRAP(err, iStore = CMsvStore::OpenForReadL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id(), this->Entry().iMtm));
+#else
+ TRAP(err, iStore = CMsvStore::OpenForReadL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id()));
+#endif
+ if (err != KErrNone)
+ {
+ iMsvSession.Session().DecStoreReaderCount(iEntryPtr->Id()); // error ignored
+ User::Leave(err);
+ }
+ return iStore;
+ }
+
+
+EXPORT_C CMsvStore* CMsvEntry::EditStoreL()
+//
+// Return store for the current context which can be writen to
+//
+/** Gets the message store for the current context with read-write access.
+
+Only one client can edit a message store at one time. If another client is
+already writing to the store, KErrAccessDenied is returned. Other clients
+can be reading the store.
+
+If the message store does not exist when EditStore() is called, a new message
+store is created.
+
+The returned CMsvStore must be deleted when it is no longer required.
+
+@leave KErrAccessDenied Store is locked by another process or the entry is
+read only
+@leave KErrNoMemory Not enough memory to open the store
+@return Context's message store open for read-write access */
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("EditStoreL for entry %x"), iEntryPtr->Id());
+#endif
+
+ __ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreAlreadyOpen));
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+
+ if (iEntryPtr->ReadOnly())
+ User::Leave(KErrAccessDenied);
+
+ User::LeaveIfError(iMsvSession.Session().LockStore(iEntryPtr->Id()));
+
+ // open the store
+ TInt error = 0;
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+ TRAP(error, iStore = CMsvStore::OpenForWriteL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id(), this->Entry().iMtm));
+#else
+ TRAP(error, iStore = CMsvStore::OpenForWriteL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id()));
+#endif
+ if (error)
+ {
+ iMsvSession.Session().ReleaseStore(iEntryPtr->Id()); // error ignored
+ User::Leave(error);
+ }
+
+ return iStore;
+ }
+
+
+
+void CMsvEntry::HandleStoreEvent(MMsvStoreObserver::TMsvStoreEvent aEvent, TMsvId /*aId*/)
+//
+//
+//
+ {
+ switch (aEvent)
+ {
+ case EMsvEditStoreClosed:
+ iMsvSession.Session().ReleaseStore(iEntryPtr->Id()); // error ignored
+ iStore=NULL;
+ break;
+ case EMsvReadStoreClosed:
+ iMsvSession.Session().DecStoreReaderCount(iEntryPtr->Id()); // error ignored
+ iStore=NULL;
+ break;
+ default:
+ __ASSERT_DEBUG(EFalse, PanicServer(EMsvUnknownStoreEvent3));
+ }
+
+ }
+
+
+EXPORT_C CMsvOperation* CMsvEntry::MoveL(TMsvId aMsvId, TMsvId aTargetId, TRequestStatus& aStatus)
+//
+// Move a single child to another parent
+//
+/** Moves, asynchronously, a child of the context to become an entry owned by the target entry.
+
+All descendants will be moved as well. Any files and stores associated with
+the entry are also moved.
+
+The returned CMsvOperation object completes when moving is complete.
+
+@param aMsvId The ID of the entry to be moved
+@param aTargetId The ID of the entry to own the moved entries
+@param aStatus The request status to be completed when the operation has finished
+
+@leave KErrNoMemory The operation could not be created or passed to the server
+@leave KErrNotFound An entry was not a child of the context
+@return The operation object controlling the move command. */
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Asynchronous MoveL %x to %x"), aMsvId, aTargetId);
+#endif
+
+ CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ selection->AppendL(aMsvId);
+ CMsvOperation* operation = MoveL(*selection, aTargetId, aStatus);
+ CleanupStack::PopAndDestroy(); // selection
+ return operation;
+ }
+
+
+TInt CMsvEntry::MoveOneL(TMsvId aMsvId, TMsvId aTargetId)
+ {
+ CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ selection->AppendL(aMsvId);
+ TInt opid = iMsvSession.OperationId();
+ iMsvSession.Session().MoveEntriesL(*selection, aTargetId, opid);
+
+ TMsvLocalOperationProgress progress;
+ TPckg<TMsvLocalOperationProgress> progressPack(progress);
+ User::LeaveIfError(iMsvSession.Session().OperationCompletion(opid, progressPack));
+
+ if(progress.iError==KErrNone)
+ {
+ TMsvId id = selection->At(0);
+ TInt ii = iSortedChildren->Count();
+ while (ii--)
+ {
+ if (iSortedChildren->At(ii)->Id() == id)
+ {
+ iSortedChildren->Delete(ii);
+ break;
+ }
+ }
+
+ ii = iEntries->Count();
+ while (ii--)
+ {
+ if (iEntries->At(ii)->Entry().Id() == id)
+ {
+ delete iEntries->At(ii);
+ iEntries->Delete(ii);
+ break;
+ }
+ }
+ // Reset the owner flag
+ if (Count() == 0)
+ {
+ TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
+ ptr->SetOwner(EFalse);
+ }
+ }
+ CleanupStack::PopAndDestroy(selection);
+ return(progress.iError);
+ }
+
+/** Moves, synchronously, a child of the context to become an entry owned by the target entry.
+
+All descendants will be moved as well. Any files and stores associated with
+the entry are also moved.
+
+@param aMsvId The ID of the entry to be moved
+@param aTargetId The ID of the entry to own the moved entries
+
+@leave KErrNoMemory
+@leave KErrNotFound An entry was not a child of the context
+*/
+EXPORT_C void CMsvEntry::MoveL(TMsvId aMsvId, TMsvId aTargetId)
+//
+// Move a single child to another parent
+//
+ {
+ __ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ __ASSERT_DEBUG(aTargetId!=iEntryPtr->Id(), PanicServer(EMsvMovingEntryToSameParent));
+
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Synchronous MoveL %x to %x"), aMsvId, aTargetId);
+#endif
+ User::LeaveIfError(MoveOneL(aMsvId,aTargetId));
+ }
+
+
+/** Moves, synchronously, children of the context to become entries owned by the target entry.
+
+All descendants will be moved as well. Any files and stores associated with
+the entries are also moved.
+
+@param aSelection List of IDs of the entries to be moved
+@param aTargetId The ID of the entry to own the moved entires
+@param aProgress On return, records the outcome of the move
+
+@leave KErrNoMemory
+@leave KErrNotFound An entry was not a child of the context
+*/
+EXPORT_C void CMsvEntry::MoveL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TMsvLocalOperationProgress& aProgress)
+//
+// Move a selection of children to another parent
+//
+ {
+ __ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ __ASSERT_DEBUG(aTargetId!=iEntryPtr->Id(), PanicServer(EMsvMovingEntryToSameParent));
+ __ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
+
+
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Synchronous MoveL with selection of %d entries to %x"), aSelection.Count(),aTargetId);
+#endif
+
+ aProgress.iTotalNumberOfEntries=aSelection.Count();
+ aProgress.iNumberCompleted=0;
+ aProgress.iNumberRemaining=aProgress.iTotalNumberOfEntries;
+ aProgress.iError=KErrNone;
+
+ TInt count=aProgress.iTotalNumberOfEntries;
+ while(count--)
+ {
+ aProgress.iId=aSelection.At(count);
+ TInt err=MoveOneL(aProgress.iId,aTargetId);
+ aProgress.iNumberRemaining--;
+ if(err==KErrNone)
+ aProgress.iNumberCompleted++;
+ else
+ {
+ aProgress.iError=err;
+ aProgress.iNumberFailed++;
+ }
+ }
+ }
+
+
+
+
+
+
+EXPORT_C CMsvOperation* CMsvEntry::MoveL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TRequestStatus& aStatus)
+//
+// Move a selection of children to another parent
+//
+/** Moves, asynchronously, children of the context to become entries owned by the target entry.
+
+All descendants will be moved as well. Any files and stores associated with
+the entries are also moved.
+
+The returned CMsvOperation object completes when moving is complete.
+
+@param aSelection List of IDs of the entries to be moved
+@param aTargetId The ID of the entry to own the moved entires
+@param aStatus The request status to be completed when the operation has finished
+
+@leave KErrNoMemory The operation could not be created or passed to the server
+@leave KErrNotFound An entry was not a child of the context
+@return The operation object controlling the move command. */
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Asynchronous MoveL of selection of %d entries to %x"), aSelection.Count(), aTargetId);
+#endif
+
+ __ASSERT_DEBUG(aTargetId!=iEntryPtr->Id(), PanicServer(EMsvMovingEntryToSameParent));
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ if (!AreChildren(aSelection))
+ User::Leave(KErrNotFound);
+ CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
+ CleanupStack::PushL(operation);
+ User::LeaveIfError(iMsvSession.Session().OperationMtmL(aSelection.At(0), aTargetId, operation->iMtm, operation->iService));
+
+#if defined(_DEBUG)
+ // check other entries in selection are consistent and are not read only
+ TInt dCount = aSelection.Count();
+ while (dCount--)
+ {
+ TMsvId service;
+ TUid mtm;
+ TInt error = iMsvSession.Session().OperationMtmL(aSelection.At(dCount), aTargetId, mtm, service);
+ __ASSERT_DEBUG(error==KErrNone || error==KErrNotFound, PanicServer(EMsvMulitpleMtmsForMoveCommand));
+ __ASSERT_DEBUG(mtm==operation->iMtm, PanicServer(EMsvMulitpleMtmsForMoveCommand));
+ __ASSERT_DEBUG(service==operation->iService, PanicServer(EMsvMulitpleMtmsForMoveCommand));
+ TMsvEntry dEntry;
+ TMsvId dService;
+ if (iMsvSession.Session().GetEntry(aSelection.At(dCount), dService, dEntry)==KErrNone)
+ __ASSERT_DEBUG(dService==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && dService==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==aSelection.At(dCount)), PanicServer(EMsvMovingEntryDifferentOwningService));
+ }
+#endif
+
+ iMsvSession.Session().MoveEntriesL(aSelection, aTargetId, operation->Id(), operation->iStatus);
+ operation->Start();
+ CleanupStack::Pop(); // operation
+ return operation;
+ }
+
+
+EXPORT_C CMsvOperation* CMsvEntry::CopyL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TRequestStatus& aStatus)
+//
+// Copy a selection ocf children to another parent
+//
+/** Creates, asynchronously. copies of children of the context as new entries owned by the specified
+target ID.
+
+All descendants will be copied as well. Any files and stores associated with
+the entries are also copied.
+
+The returned CMsvOperation object completes when copying is complete.
+
+@param aSelection List of IDs of the entries to be copied
+@param aTargetId The ID of the entry to own the copies
+@param aStatus The request status to be completed when the operation has finished
+
+@leave KErrNoMemory The operation could not be created or passed to the server
+@leave KErrNotFound An entry was not a child of the context
+@return The operation object controlling the copy command. */
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Asynchronous CopyL of selection of %d entries to %x"), aSelection.Count(), aTargetId);
+#endif
+
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ if (!AreChildren(aSelection))
+ User::Leave(KErrNotFound);
+ CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
+ CleanupStack::PushL(operation);
+ User::LeaveIfError(iMsvSession.Session().OperationMtmL(aSelection.At(0), aTargetId, operation->iMtm, operation->iService));
+
+#if defined(_DEBUG)
+ // check other entries in selection are consistent
+ TInt dCount = aSelection.Count();
+ while (dCount--)
+ {
+ TMsvId service;
+ TUid mtm;
+ TInt error = iMsvSession.Session().OperationMtmL(aSelection.At(dCount), aTargetId, mtm, service);
+ __ASSERT_DEBUG(error==KErrNone || error==KErrNotFound, PanicServer(EMsvMulitpleMtmsForCopyCommand));
+ __ASSERT_DEBUG(mtm==operation->iMtm, PanicServer(EMsvMulitpleMtmsForCopyCommand));
+ __ASSERT_DEBUG(service==operation->iService, PanicServer(EMsvMulitpleMtmsForCopyCommand));
+ TMsvEntry dEntry;
+ TMsvId dService;
+ if (iMsvSession.Session().GetEntry(aSelection.At(dCount), dService, dEntry)==KErrNone)
+ __ASSERT_DEBUG(dService==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && dService==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==aSelection.At(dCount)), PanicServer(EMsvCopyingEntryDifferentOwningService));
+ }
+#endif
+
+ iMsvSession.Session().CopyEntriesL(aSelection, aTargetId, operation->Id(), operation->iStatus);
+ operation->Start();
+ CleanupStack::Pop(); // operation
+ return operation;
+ }
+
+EXPORT_C CMsvOperation* CMsvEntry::CopyL(TMsvId aMsvId, TMsvId aTargetId, TRequestStatus& aStatus)
+//
+// Copy a single entry to another parent
+//
+/** Creates, asynchronously, a copy of a child of the context as a new entry owned by the specified
+target ID.
+
+All descendants will be copied as well. Any files and stores associated with
+the entry are also copied.
+
+The returned CMsvOperation object completes when copying is complete.
+
+@param aMsvId The ID of the entry to be copied
+@param aTargetId The ID of the entry to own the copy
+@param aStatus The request status to be completed when the operation has finished
+
+@leave KErrNoMemory The operation could not be created or passed to the server
+@leave KErrNotFound An entry was not a child of the context
+@return The operation object controlling the copy command. */
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Asynchronous CopyL of entry %x to %x"), aMsvId, aTargetId);
+#endif
+
+ CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ selection->AppendL(aMsvId);
+ CMsvOperation* operation = CopyL(*selection, aTargetId, aStatus);
+ CleanupStack::PopAndDestroy(); // selection
+ return operation;
+ }
+
+
+TInt CMsvEntry::CopyOneL(TMsvId aMsvId, TMsvId aTargetId)
+ {
+
+ CMsvEntryArray* newSortedChildren = NULL;
+ CMsvClientEntry *toadd=NULL;
+
+
+ if(aTargetId==iEntryPtr->Id())
+ {
+ const TMsvEntry &entry=ChildDataL(aMsvId);
+ if (entry.Visible() || iOrdering.ShowInvisibleEntries())
+ {
+ // Create what may be the new child entry if nothing goes wrong
+ toadd = CMsvClientEntry::NewLC(entry, EMsvClientChild);
+
+ // Reserve space for the new entry for later
+ iEntries->SetReserveL(iEntries->Count() + 1);
+
+ newSortedChildren = CMsvEntryArray::NewLC(*iMtmList);
+
+ // add the children to the sorted pointer list - current context is the first entry
+ TInt totalCount=iEntries->Count();
+ for (TInt count=1; count<totalCount; count++)
+ newSortedChildren->AppendL(&iEntries->At(count)->Entry());
+
+ // We've created a new sorted child list now so we won't leave later
+ newSortedChildren->AppendL(&toadd->Entry());
+ newSortedChildren->SortL(iOrdering);
+ }
+ }
+
+ CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ selection->AppendL(aMsvId);
+ TInt opid = iMsvSession.OperationId();
+ iMsvSession.Session().CopyEntriesL(*selection, aTargetId, opid);
+
+ TMsvLocalOperationProgress progress;
+ TPckg<TMsvLocalOperationProgress> progressPack(progress);
+ User::LeaveIfError(iMsvSession.Session().OperationCompletion(opid, progressPack));
+
+ CleanupStack::PopAndDestroy(selection);
+
+ // can't leave after this point
+ if(newSortedChildren!=NULL) CleanupStack::Pop(newSortedChildren);
+ if(toadd!=NULL) CleanupStack::Pop(toadd);
+ if(newSortedChildren!=NULL && progress.iError==KErrNone)
+ {
+ delete iSortedChildren;
+ iSortedChildren=newSortedChildren;
+ newSortedChildren=NULL;
+ toadd->SetId(progress.iId);
+ // Will not leave because we've reserved space earlier
+ iEntries->AppendL(toadd);
+ toadd=NULL;
+ }
+ delete newSortedChildren;
+ delete toadd;
+ return(progress.iError);
+ }
+
+EXPORT_C void CMsvEntry::CopyL(TMsvId aMsvId, TMsvId aTargetId)
+//
+// Copy a single child to another parent (or duplicate)
+//
+/** Creates, synchronously, a copy of a child of the context as a new entry owned by the specified target ID.
+
+@param aMsvId The ID of the entry to be copied
+@param aTargetId The ID of the entry to own the copy
+*/
+ {
+ __ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Synchronous CopyL %x to %x"), aMsvId, aTargetId);
+#endif
+ User::LeaveIfError(CopyOneL(aMsvId,aTargetId));
+ }
+
+
+/** Creates, synchronously. copies of children of the context as new entries owned by the specified
+target ID.
+
+All descendants will be copied as well. Any files and stores associated with
+the entries are also copied.
+
+@param aSelection List of IDs of the entries to be copied
+@param aTargetId The ID of the entry to own the copies
+@param aProgress On return, records the outcome of the copy
+
+@leave KErrNoMemory
+@leave KErrNotFound An entry was not a child of the context
+*/
+EXPORT_C void CMsvEntry::CopyL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TMsvLocalOperationProgress& aProgress)
+//
+// Copy a selection to another parent (or duplicate)
+//
+ {
+ __ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ __ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
+
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Synchronous CopyL with selection of %d entries to %x"), aSelection.Count(),aTargetId);
+#endif
+
+
+ aProgress.iTotalNumberOfEntries=aSelection.Count();
+ aProgress.iNumberCompleted=0;
+ aProgress.iNumberRemaining=aProgress.iTotalNumberOfEntries;
+ aProgress.iError=KErrNone;
+
+ TInt count=aProgress.iTotalNumberOfEntries;
+ while(count--)
+ {
+ aProgress.iId=aSelection.At(count);
+ TInt err=CopyOneL(aProgress.iId,aTargetId);
+ aProgress.iNumberRemaining--;
+ if(err==KErrNone)
+ aProgress.iNumberCompleted++;
+ else
+ {
+ aProgress.iError=err;
+ aProgress.iNumberFailed++;
+ }
+ }
+ }
+
+
+
+
+
+EXPORT_C void CMsvEntry::AddObserverL(MMsvEntryObserver& aObserver)
+//
+// Adds an observer to this entry
+// If the function leaves, the observer was not appended
+//
+/** Registers an observer for the object.
+
+CMsvEntry objects can call back observer objects that implement the MMsvEntryObserver
+interface when certain events occur. Any number of observers can be registered.
+
+Observers are called primarily when the context changes state or contents.
+For details, see MMsvEntryObserver::TMsvEntryEvent.
+
+@param aObserver The observer to be registered for events
+@leave KErrNoMemory Not enough memory to register the observer */
+ {
+ if (iObservers==NULL)
+ iObservers=new(ELeave) CArrayPtrFlat<MMsvEntryObserver> (KMsvEntryObserverArrayGranuality);
+ iObservers->AppendL(&aObserver);
+
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Observer %d added"), iObservers->Count());
+#endif
+ }
+
+
+EXPORT_C void CMsvEntry::RemoveObserver(MMsvEntryObserver& aObserver)
+//
+// Removes an observer of the entry
+//
+/** Unregisters an observer previously registered with AddObserverL().
+
+@param aObserver A reference to an observer to be unregistered for events */
+ {
+ __ASSERT_DEBUG(iObservers, PanicServer(EMsvEntryUnknownObserver));
+ if (iObservers)
+ {
+ TInt count=iObservers->Count();
+ while (count--)
+ {
+ if (iObservers->At(count)==&aObserver)
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Observer %d removed"), count + 1);
+#endif
+ iObservers->Delete(count);
+ if (iObservers->Count()==0)
+ {
+ delete iObservers;
+ iObservers=NULL;
+ }
+ return;
+ }
+ }
+ __ASSERT_DEBUG(count>=0, PanicServer(EMsvEntryUnknownObserver));
+ }
+ }
+
+
+void CMsvEntry::NotifyAllObserversL(MMsvEntryObserver::TMsvEntryEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3)
+//
+// Notifies all observers of the event affecting the context
+//
+ {
+ if (iObservers==NULL)
+ return;
+ TInt count=iObservers->Count();
+ while (count--)
+ iObservers->At(count)->HandleEntryEventL(aEvent,aArg1,aArg2,aArg3);
+ }
+
+
+void CMsvEntry::HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3)
+//
+// Is informed of all the session events
+// This are filtered to find the events relating to the context
+//
+ {
+ // Check the notification sequence and ignore if neccessary
+ if (iNotifySequence >= iMsvSession.iNotifySequence)
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Ignoring notification, %d >= %d"), iNotifySequence, iMsvSession.iNotifySequence);
+#endif
+ return;
+ }
+
+ switch (aEvent)
+ {
+ case EMsvEntriesChanged:
+ {
+ CMsvEntrySelection* selection = (CMsvEntrySelection*) aArg1;
+ if (iEntryPtr->Id() == selection->At(0))
+ ContextChangedL(MMsvEntryObserver::EMsvEntryChanged);
+ else if (iEntryPtr->Id()==*(TMsvId*) aArg2)
+ ChildrenChangedL(*selection);
+ break;
+ }
+ case EMsvEntriesCreated:
+ if (*(TMsvId*) aArg2==iEntryPtr->Id())
+ NewChildrenL(*(CMsvEntrySelection*) aArg1);
+ else
+ CheckNewGrandchildrenL(*(TMsvId*) aArg2);
+ break;
+ case EMsvEntriesDeleted:
+ {
+ CMsvEntrySelection* selection = (CMsvEntrySelection*) aArg1;
+ if (*(TMsvId*) aArg2==iEntryPtr->Id())
+ DeletedChildrenL(*selection);
+ else
+ {
+ // check if we have been deleted
+ TInt index=selection->Find(iEntryPtr->Id());
+ if (index!=KErrNotFound)
+ {
+ iState = EInvalidDeletedContext;
+ NotifyAllObserversL(MMsvEntryObserver::EMsvEntryDeleted, NULL, NULL, NULL);
+ }
+ else
+ CheckDeletedGrandchildrenL(*(TMsvId*) aArg2);
+ }
+ break;
+ }
+ case EMsvEntriesMoved:
+ if (*(TMsvId*) aArg3==iEntryPtr->Parent())
+ CheckIfContextMovedL(*(CMsvEntrySelection*) aArg1);
+ if (*(TMsvId*) aArg2==iEntryPtr->Id())
+ NewChildrenL(*(CMsvEntrySelection*) aArg1);
+ else if (*(TMsvId*) aArg3==iEntryPtr->Id())
+ DeletedChildrenL(*(CMsvEntrySelection*) aArg1);
+ else
+ {
+ CheckNewGrandchildrenL(*(TMsvId*) aArg2);
+ CheckDeletedGrandchildrenL(*(TMsvId*) aArg3);
+ }
+ break;
+ case EMsvMediaChanged:
+ {
+ TRAPD(error, HandleMediaChangeL());
+ if (error)
+ {
+ // An error occurred or this is a non standard entry
+ // in which case the media has changed so this entry is not accessible
+ // Just mark the entry as invalid - there is nothing else we can do!
+ iState = EInvalidOldContext;
+ NotifyAllObserversL(MMsvEntryObserver::EMsvContextInvalid, (TAny*)&error, NULL, NULL);
+ }
+ break;
+ }
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ case EMsvRefreshMessageView:
+ {
+ // A drive/disk has been added/removed.
+ if(iEntryPtr->StandardFolder())
+ {
+ SetEntryNoCheckL(iEntryPtr->Id(), iChildrenOfAvailableDrives);
+ }
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+ }
+
+void CMsvEntry::HandleMediaChangeL()
+ {
+ // If this is not a standard entry there is nothing we can do
+ if (!iEntryPtr->StandardFolder())
+ User::Leave(KMsvMediaChanged);
+
+ // This is a standard folder so it will exist on all media
+ // Refresh the entry and child list - if this fails mark the entry as invalid
+ // Otherwise the context will be told that everything has changed
+ CMsvEntrySelection* oldChildren = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(oldChildren);
+
+ // Get list of old children
+ TInt count = iSortedChildren->Count();
+ while(count--)
+ oldChildren->AppendL(iSortedChildren->At(count)->Id());
+
+ // Refresh the context
+ iState = EInvalidOldContext;
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ if(iChildrenOfAvailableDrives)
+ {
+ SetStandardFolderEntryL(iEntryPtr->Id());
+ }
+ else
+#endif
+ {
+ SetEntryL(iEntryPtr->Id());
+ }
+ CMsvEntrySelection* newChildren = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(newChildren);
+
+ // Get list of new children
+ count = iSortedChildren->Count();
+ while(count--)
+ newChildren->AppendL(iSortedChildren->At(count)->Id());
+
+ // Tell the context about the children that have effectively been deleted and created
+ if (oldChildren->Count())
+ NotifyAllObserversL(MMsvEntryObserver::EMsvDeletedChildren, (TAny*)oldChildren, NULL, NULL);
+ if (newChildren->Count())
+ NotifyAllObserversL(MMsvEntryObserver::EMsvNewChildren, (TAny*)newChildren, NULL, NULL);
+
+ // Tell the context that it might have changed
+ NotifyAllObserversL(MMsvEntryObserver::EMsvEntryChanged, NULL, NULL, NULL);
+
+ CleanupStack::PopAndDestroy(2); // newChildren, oldChildren
+ }
+
+void CMsvEntry::CheckIfContextMovedL(const CMsvEntrySelection& aSelection)
+//
+// Some of the contexts parents children have moved, have to check if the context was one of them
+//
+ {
+ TInt index=aSelection.Find(iEntryPtr->Id());
+ if (index!=KErrNotFound)
+ ContextChangedL(MMsvEntryObserver::EMsvEntryMoved);
+ }
+
+
+void CMsvEntry::ContextChangedL(MMsvEntryObserver::TMsvEntryEvent aEvent)
+//
+// The context has ben changed, spo we need to get the enw version
+//
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Context changed"));
+#endif
+
+ if (iEntries->Count()>1 && iEntries->At(1)->Type()==EMsvClientChangedContext)
+ {
+ // we changed the entry, so get the new conext from the entry list
+ // delete the old entry context (the new one is at position 1)
+ delete iEntries->At(0);
+ iEntries->Delete(0);
+ }
+ else
+ {
+ // someone else changed the context, so we have to update
+ CMsvClientEntry* cEntry=NULL;
+ TMsvId owningService=KMsvNullIndexEntryId;
+ TRAPD(error, {cEntry = DoGetEntryLC(iEntryPtr->Id(), owningService); CleanupStack::Pop();});
+ if (error==KErrNone)
+ {
+ if(iEntries->Count() != 0)
+ {
+ delete iEntries->At(0);
+ iEntries->At(0) = cEntry;
+ }
+ else
+ {
+ iEntries->AppendL(cEntry);
+ }
+ iOwningService = owningService;
+ }
+ else
+ {
+ iState = EInvalidOldContext;
+ NotifyAllObserversL(MMsvEntryObserver::EMsvContextInvalid, (TAny*)&error, NULL, NULL);
+ return;
+ }
+ }
+
+ iEntries->At(0)->SetType(EMsvClientContext);
+ iEntryPtr = &iEntries->At(0)->Entry();
+ iState = EValid;
+
+ // notify all observers
+ NotifyAllObserversL(aEvent, NULL, NULL, NULL);
+ }
+
+
+
+void CMsvEntry::NewChildrenL(const CMsvEntrySelection& aSelection)
+//
+// New children have been created
+//
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("New children"));
+#endif
+
+ CMsvEntrySelection* newChildren = DoGetNewChildrenL(aSelection);
+ CleanupStack::PushL(newChildren);
+ if (newChildren->Count())
+ {
+ TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
+ ptr->SetOwner(ETrue);
+ NotifyAllObserversL(MMsvEntryObserver::EMsvNewChildren, (TAny*)newChildren, NULL, NULL);
+ }
+ CleanupStack::PopAndDestroy(); // newChildren
+ }
+
+
+CMsvEntrySelection* CMsvEntry::DoGetNewChildrenL(const CMsvEntrySelection& aSelection)
+//
+// New children have been created
+//
+ {
+ CMsvEntrySelection* newChildren = aSelection.CopyLC();
+ TInt count=aSelection.Count();
+ while (count--)
+ {
+ // check if we already have this child
+ if (IsAChild(aSelection.At(count)))
+ {
+ newChildren->Delete(count);
+ continue;
+ }
+
+ // get the new child data and add to to the list
+ TMsvEntry tEntry;
+ TMsvId service;
+ TInt error=iMsvSession.Session().GetEntry(aSelection.At(count), service, tEntry);
+ if(error!=KErrNotFound) User::LeaveIfError(error);
+
+ if (error == KErrNone && (tEntry.Visible() || iOrdering.ShowInvisibleEntries()))
+ {
+ __ASSERT_DEBUG(service==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && service==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==(aSelection.At(count))), PanicServer(EMsvNewChildDifferentOwningService));
+
+ CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(tEntry, EMsvClientNull);
+ cEntry->SetType(EMsvClientChild);
+ iEntries->AppendL(cEntry);
+ CleanupStack::Pop(); // cEntry
+ // resort the children
+ iSortedChildren->AppendL(&cEntry->Entry());
+ }
+ else
+ newChildren->Delete(count);
+ }
+
+ if (newChildren->Count())
+ iSortedChildren->SortL(iOrdering);
+ CleanupStack::Pop(); // newChildren
+ return newChildren;
+ }
+
+
+void CMsvEntry::CheckNewGrandchildrenL(TMsvId aId)
+//
+//
+//
+ {
+ TInt count=iEntries->Count();
+ while (count--)
+ {
+ if (iEntries->At(count)->Entry().Id()==aId && !iEntries->At(count)->Entry().Owner())
+ {
+ iEntries->At(count)->SetOwnerFlag(ETrue);
+ NotifyChildChangedL(aId);
+ break;
+ }
+ }
+ }
+
+
+void CMsvEntry::CheckDeletedGrandchildrenL(TMsvId aId)
+//
+//
+//
+ {
+ TInt count=iEntries->Count();
+ while (count--)
+ {
+ if (iEntries->At(count)->Entry().Id()==aId)
+ {
+ TMsvEntry entry;
+ TMsvId service;
+ TInt error = iMsvSession.Session().GetEntry(aId, service, entry);
+ __ASSERT_DEBUG(error || service==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && service==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==aId), PanicServer(EMsvDeletedGrandChildDifferentOwningService));
+ if (error)
+ NotifyAllObserversL(MMsvEntryObserver::EMsvChildrenInvalid, (TAny*)&error, NULL, NULL);
+ else if (!entry.Owner())
+ {
+ iEntries->At(count)->SetOwnerFlag(EFalse);
+ NotifyChildChangedL(aId);
+ }
+ break;
+ }
+ }
+ }
+
+
+void CMsvEntry::NotifyChildChangedL(TMsvId aId)
+//
+//
+//
+ {
+ CMsvEntrySelection* selection = DoMakeSelectionL(aId);
+ CleanupStack::PushL(selection);
+ NotifyAllObserversL(MMsvEntryObserver::EMsvChildrenChanged, (TAny*)selection, NULL, NULL);
+ CleanupStack::PopAndDestroy(); // selection
+ }
+
+
+CMsvEntrySelection* CMsvEntry::DoMakeSelectionL(TMsvId aId)
+//
+//
+//
+ {
+ CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ selection->AppendL(aId);
+ CleanupStack::Pop(); // selection
+ return selection;
+ }
+
+
+void CMsvEntry::ChildrenChangedL(const CMsvEntrySelection& aSelection)
+//
+// Children have been changed
+//
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Children changed"));
+#endif
+
+ CMsvEntrySelection* changedChildren = new(ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(changedChildren);
+ CMsvEntrySelection* newChildren = new(ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(newChildren);
+ CMsvEntrySelection* deletedChildren = new(ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(deletedChildren);
+
+ TInt count=aSelection.Count();
+ while (count--)
+ {
+ // get the changed child data
+ TMsvId id = aSelection.At(count);
+ TMsvEntry tEntry;
+ TMsvId service;
+
+ // find the child in the sorted list
+ TInt pos=iSortedChildren->Count();
+ while (pos--)
+ if (iSortedChildren->At(pos)->Id()==id)
+ break;
+
+ TInt error = iMsvSession.Session().GetEntry(id, service, tEntry);
+ if (error == KErrNotFound)
+ {
+ if (pos >= 0)
+ {
+ // The child has been deleted by the server
+ DeleteChild(pos);
+ deletedChildren->AppendL(id);
+ }
+ }
+ else
+ {
+ User::LeaveIfError(error);
+ __ASSERT_DEBUG(service==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && service==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==id), PanicServer(EMsvChangedChildHasDifferentOwningService));
+
+ if ( pos!=KErrNotFound )
+ {
+ // replace it, if showing all children or its was and still is visible
+ if (iOrdering.ShowInvisibleEntries() || tEntry.Visible())
+ {
+ ReplaceChildL(pos, tEntry);
+ changedChildren->AppendL(id);
+ continue;
+ }
+ }
+
+ if ( pos==KErrNotFound )
+ {
+ if (tEntry.Visible())
+ {
+ // the child has just been made visible so add it to our sorted list
+ CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(tEntry, EMsvClientChild);
+ iEntries->AppendL(cEntry);
+ CleanupStack::Pop(); // cEntry
+ iSortedChildren->AppendL(&cEntry->Entry());
+ newChildren->AppendL(id);
+ }
+ }
+ else if (!tEntry.Visible())
+ {
+ DeleteChild(pos);
+ deletedChildren->AppendL(id);
+ }
+ }
+ }
+
+ // resort the children
+ if (changedChildren->Count() || newChildren->Count() || deletedChildren->Count())
+ {
+ iSortedChildren->SortL(iOrdering);
+ // notify the observers
+ if (changedChildren->Count())
+ NotifyAllObserversL(MMsvEntryObserver::EMsvChildrenChanged, (TAny*)changedChildren, NULL, NULL);
+ if (newChildren->Count())
+ NotifyAllObserversL(MMsvEntryObserver::EMsvNewChildren, (TAny*)newChildren, NULL, NULL);
+ if (deletedChildren->Count())
+ NotifyAllObserversL(MMsvEntryObserver::EMsvDeletedChildren, (TAny*)deletedChildren, NULL, NULL);
+ }
+
+ CleanupStack::PopAndDestroy(3); // changedChildren, newChildren, deletedChildren
+ }
+
+void CMsvEntry::DeleteChild(TInt aPosition)
+ {
+ TMsvId id = iSortedChildren->At(aPosition)->Id();
+ iSortedChildren->Delete(aPosition);
+ TInt ii=iEntries->Count();
+ while (ii--)
+ if (iEntries->At(ii)->Entry().Id()==id)
+ {
+ __ASSERT_DEBUG(iEntries->At(ii)->Type()==EMsvClientChild, PanicServer(EMsvNonChildDeleted));
+ delete iEntries->At(ii);
+ iEntries->Delete(ii);
+ break;
+ }
+ __ASSERT_DEBUG(ii!=KErrNotFound, PanicServer(EMsvChangedChildNotFound1));
+ }
+
+void CMsvEntry::ReplaceChildL(TInt aPosition, const TMsvEntry& aEntry)
+//
+//
+//
+ {
+ CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(aEntry, EMsvClientChild);
+
+ TInt ii=iEntries->Count();
+ while (ii--)
+ {
+ if (iEntries->At(ii)->Entry().Id()==aEntry.Id())
+ {
+ __ASSERT_DEBUG(iEntries->At(ii)->Type()==EMsvClientChild, PanicServer(EMsvNonChildDeleted));
+ delete iEntries->At(ii);
+ iEntries->At(ii) = cEntry;
+ iSortedChildren->At(aPosition) = &cEntry->Entry();
+ break;
+ }
+ }
+ __ASSERT_DEBUG(ii!=KErrNotFound, PanicServer(EMsvChangedChildNotFound1));
+
+ CleanupStack::Pop(); // cEntry
+ }
+
+
+
+void CMsvEntry::DeletedChildrenL(const CMsvEntrySelection& aSelection)
+//
+// Some of the children have been deleted
+//
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Deleted children"));
+#endif
+
+ CMsvEntrySelection* deletedChildren = aSelection.CopyL();
+ CleanupStack::PushL(deletedChildren);
+
+ TInt count=aSelection.Count();
+ while (count--)
+ {
+ TMsvId id = aSelection.At(count);
+ TInt ii=iSortedChildren->Count();
+ while (ii--)
+ {
+ if (iSortedChildren->At(ii)->Id()==id)
+ {
+ iSortedChildren->Delete(ii);
+ break;
+ }
+ }
+ if (ii==KErrNotFound)
+ deletedChildren->Delete(count);
+ else
+ {
+ ii=iEntries->Count();
+ while (ii--)
+ {
+ if (iEntries->At(ii)->Entry().Id()==id)
+ {
+ __ASSERT_DEBUG(iEntries->At(ii)->Type()==EMsvClientChild, PanicServer(EMsvNonChildDeleted));
+ delete iEntries->At(ii);
+ iEntries->Delete(ii);
+ break;
+ }
+ __ASSERT_DEBUG(ii!=KErrNotFound, PanicServer(EMsvDeletedChildNotInMainList));
+ }
+ }
+ }
+
+ // notify all observers
+ if (deletedChildren->Count())
+ {
+ // reset the owner flag
+ if (Count()==0)
+ {
+ TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
+ ptr->SetOwner(EFalse);
+ }
+
+ NotifyAllObserversL(MMsvEntryObserver::EMsvDeletedChildren, (TAny*)deletedChildren, NULL, NULL);
+ }
+
+ CleanupStack::PopAndDestroy(); // deletedChildren
+ }
+
+
+CMsvEntryArray* CMsvEntry::GetNewSortedListL(const TMsvSelectionOrdering& aOrdering, const CArrayFix<TUid>& aMtmList)
+//
+// Gets a new sorted list for new order and mtm list
+// The entries should have the correct visiblity
+//
+ {
+ CMsvEntryArray* newSortedChildren = CMsvEntryArray::NewLC(aMtmList);
+ if (iSortedChildren->Count())
+ {
+// newSortedChildren->InsertL(0, &iSortedChildren->At(0), iSortedChildren->Count());
+// newSortedChildren->SortL(aOrdering);
+ TInt count=1;
+ if (iEntries->At(count)->Type()!=EMsvClientChild)
+ count++;
+ TInt totalCount=iEntries->Count();
+ for (; count<totalCount; count++)
+ newSortedChildren->AppendL(&iEntries->At(count)->Entry());
+ newSortedChildren->SortL(aOrdering);
+ }
+ CleanupStack::Pop(); // newSortedChildren
+ return newSortedChildren;
+ }
+
+
+EXPORT_C void CMsvEntry::SetSortTypeL(const TMsvSelectionOrdering& aOrdering)
+//
+// Sets the sort type
+// If this leaves the sort type has not been changed
+//
+/** Sets the sort order that is used when listing children, for example with ChildrenL().
+
+If the function leaves, the sort order is unchanged.
+
+@param aOrdering Sort order to use
+@leave KErrNoMemory Insufficient memory to resort the entries */
+ {
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("Sort order changed, sorting %x, invisible %d"), aOrdering.Sorting(), aOrdering.ShowInvisibleEntries());
+#endif
+
+ if (aOrdering.ShowInvisibleEntries()==iOrdering.ShowInvisibleEntries())
+ {
+ // just resort the current list of children
+ CMsvEntryArray* newSortedChildren = GetNewSortedListL(aOrdering, *iMtmList);
+ delete iSortedChildren;
+ iSortedChildren = newSortedChildren;
+ iOrdering = aOrdering;
+ }
+ else if (!aOrdering.ShowInvisibleEntries())
+ {
+ // resort the current list
+ CMsvEntryArray* newSortedChildren = GetNewSortedListL(aOrdering, *iMtmList);
+ delete iSortedChildren;
+ iSortedChildren = newSortedChildren;
+ iOrdering = aOrdering;
+ // remove the invisible entries from sort list
+ TInt count = iSortedChildren->Count();
+ while (count--)
+ if (!iSortedChildren->At(count)->Visible())
+ iSortedChildren->Delete(count);
+ // remove the invisible children from main list
+ count = iEntries->Count();
+ while (count-->=1)
+ if (!iEntries->At(count)->Entry().Visible())
+ {
+ delete iEntries->At(count);
+ iEntries->Delete(count);
+ }
+ }
+ else
+ {
+ // keep old variable
+ CArrayPtrFlat<CMsvClientEntry>* oldEntries = iEntries;
+ iEntries=NULL;
+ CMsvEntryArray* oldSortedChildren = iSortedChildren;
+ iSortedChildren=NULL;
+ TMsvSelectionOrdering oldOrder = iOrdering;
+
+ iOrdering = aOrdering;
+ TRAPD(leave, DoSortTypeL(oldEntries->At(0)));
+
+ if (leave)
+ {
+ // we left, the function may have created a new iEntries,
+ // if iEntries has been created we need to delete all the elements
+ // except the first one, that is used in the old list
+ // then delete iEntries, and put back the old one.
+
+ if(iEntries!=NULL)
+ {
+ if(iEntries->Count()!=0)
+ iEntries->Delete(0);
+ iEntries->ResetAndDestroy();
+ delete iEntries;
+ }
+ iEntries = oldEntries;
+
+ // iSortedChildren doesn't own the children so just delete the new one.
+ // and put the old one back.
+ delete iSortedChildren;
+ iSortedChildren = oldSortedChildren;
+ iOrdering = oldOrder;
+ User::Leave(leave);
+ }
+ else
+ {
+ oldEntries->Delete(0); // the object is used in new list
+ oldEntries->ResetAndDestroy();
+ delete oldEntries;
+ delete oldSortedChildren;
+ }
+ }
+ }
+
+
+
+void CMsvEntry::DoSortTypeL(CMsvClientEntry* aContext)
+//
+//
+//
+ {
+ iEntries = new(ELeave) CArrayPtrFlat<CMsvClientEntry>(KMsvClientEntryArrayGranuality);
+ iEntries->AppendL(aContext);
+
+ iSortedChildren = CMsvEntryArray::NewL(*iMtmList);
+
+ DoGetChildrenL();
+ }
+
+
+
+EXPORT_C void CMsvEntry::SetMtmListL(const CArrayFix<TUid>& aMtmList)
+//
+// Sets the mtm list
+// If this leaves the mtm list has not been changed
+//
+/** Sets the MTM order to the specified sort order. When children of an entry are
+sorted, entries belonging to the same MTM type can be grouped together.
+
+MTM grouping can be switched on or off through setting the appropriate TMsvSelectionOrdering
+value by SetSortTypeL().
+
+If the function leaves, the sort order is unchanged.
+
+@param aMtmList The order of MTMs to use for sorting
+@leave KErrNoMemory Insufficient memory to resort the entries */
+ {
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+
+ // create new mtm list
+ CArrayFixFlat<TUid>* mtmList = new(ELeave)CArrayFixFlat<TUid>(KMsvMtmListGranularity);
+ CleanupStack::PushL(mtmList);
+ mtmList->InsertL(0, &aMtmList.At(0), aMtmList.Count());
+
+ // create new sorted children list
+ CMsvEntryArray* newSortedChildren = GetNewSortedListL(iOrdering, *mtmList);
+
+ // install the new sorted children array
+ delete iSortedChildren;
+ delete iMtmList;
+ iSortedChildren = newSortedChildren;
+ iMtmList = mtmList;
+
+ CleanupStack::Pop(); // mtmList
+ }
+
+
+TBool CMsvEntry::IsAChild(TMsvId aId) const
+//
+// Returns true if the entry is a child
+//
+ {
+ TInt count=iSortedChildren->Count();
+ while (count--)
+ {
+ if (iSortedChildren->At(count)->Id()==aId)
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+TBool CMsvEntry::AreChildren(const CMsvEntrySelection& aSelection) const
+//
+// Returns true if all the entries are children
+//
+ {
+ TInt count = aSelection.Count();
+ while (count--)
+ {
+ if (!IsAChild(aSelection.At(count)))
+ {
+ return EFalse;
+ }
+ }
+ return ETrue;
+ }
+
+
+EXPORT_C TBool CMsvEntry::HasStoreL() const
+/** Checks if the context has an associated message store.
+
+@return ETrue: entry has a message store EFalse: entry does not have a message
+store */
+ {
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+ if(iMsvSession.StoreManager().DoesAnyStoreExists(iEntryPtr->Id(), this->Entry().iMtm))
+ return ETrue;
+ else
+ return iMsvSession.StoreManager().FileStoreExistsL(iEntryPtr->Id());
+#else
+ return iMsvSession.StoreManager().FileStoreExistsL(iEntryPtr->Id());
+#endif
+ }
+
+/** Sets or clears multiple fields in a selection of children of the context.
+
+Fields to change are specified using a bitmask of TMsvAttribute values. Possible
+fields that can be changed using this function are the PC synchronisation, Visibility,
+Pending Deletion, Read, In-preparation, Connected, and New flags.
+
+@param aSelection The entries to change
+@param aSetAttributes A bitmask of the fields to set
+@param aClearAttributes A bitmask of the fields to clear
+@leave KErrNotFound An entry was not a child of the context
+@see CMsvSession::ChangeAttributesL()
+*/
+EXPORT_C void CMsvEntry::ChangeAttributesL(const CMsvEntrySelection& aSelection, TUint aSetAttributes, TUint aClearAttributes)
+ {
+#ifndef _NO_SESSION_LOGGING_
+ Log(_L("ChangeAttributesL"));
+#endif
+
+ __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
+ __ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
+
+ if (!AreChildren(aSelection))
+ User::Leave(KErrNotFound);
+
+ iMsvSession.Session().ChangeAttributesL(aSelection, aSetAttributes, aClearAttributes);
+ }
+