messagingfw/msgsrvnstore/server/src/MCLENTRY.CPP
changeset 0 8e480a14352b
child 31 b9e74fff3740
child 34 b66b8f3a7fd8
--- /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);
+	}
+