messagingfw/msgsrvnstore/server/src/MCLENTRY.CPP
changeset 0 8e480a14352b
child 31 b9e74fff3740
child 34 b66b8f3a7fd8
equal deleted inserted replaced
-1:000000000000 0:8e480a14352b
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #ifdef _DEBUG
       
    17 #undef _NO_SESSION_LOGGING_
       
    18 #endif
       
    19 
       
    20 #include <s32std.h>
       
    21 #include <txtrich.h>
       
    22 #include "MSVIDS.H"
       
    23 #include "MSVUIDS.H"
       
    24 
       
    25 #include "MSVAPI.H"
       
    26 #include "MSVCOP.H"
       
    27 #include "MCLENTRY.H"
       
    28 #include "MSVPANIC.H"
       
    29 #include "MSVUTILS.H"
       
    30 
       
    31 #include <mmsvstoremanager.h>
       
    32 
       
    33 const TInt KMsvClientEntryArrayGranuality=8;
       
    34 const TInt KMsvEntryObserverArrayGranuality=4;
       
    35 const TInt KMsvMtmListGranularity=8;
       
    36 
       
    37 //**********************************
       
    38 // CMsvClientEntry
       
    39 //**********************************
       
    40 
       
    41 // static 
       
    42 CMsvClientEntry* CMsvClientEntry::NewLC(const TMsvEntry& aEntry, TMsvClientEntryType aType)
       
    43 	{
       
    44 	CMsvClientEntry* self = new(ELeave) CMsvClientEntry(aEntry, aType);
       
    45 	CleanupStack::PushL(self);
       
    46 	self->ConstructL();
       
    47 	return self;
       
    48 	}
       
    49 
       
    50 
       
    51 CMsvClientEntry::CMsvClientEntry(const TMsvEntry& aEntry, TMsvClientEntryType aType)
       
    52 :iEntry(aEntry), iType(aType)
       
    53 	{
       
    54 	__DECLARE_NAME(_S("CMsvClientEntry"));
       
    55 	}
       
    56 
       
    57 
       
    58 CMsvClientEntry::~CMsvClientEntry()
       
    59 	{
       
    60 	delete iDescription;
       
    61 	delete iDetails;
       
    62 	}
       
    63 
       
    64 void CMsvClientEntry::ConstructL()
       
    65 	{
       
    66 	iDescription = HBufC::NewL(iEntry.iDescription.Length());
       
    67 	iDescription->Des().Copy(iEntry.iDescription);
       
    68 	iEntry.iDescription.Set(iDescription->Des());
       
    69 	iDetails = HBufC::NewL(iEntry.iDetails.Length());
       
    70 	iDetails->Des().Copy(iEntry.iDetails);
       
    71 	iEntry.iDetails.Set(iDetails->Des());
       
    72 	}
       
    73 
       
    74 
       
    75 
       
    76 
       
    77 //**********************************
       
    78 // CMsvEntry
       
    79 //**********************************
       
    80 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
    81 
       
    82 EXPORT_C CMsvEntry* CMsvEntry::NewL(CMsvSession& aMsvSession, TMsvId aMsvId, const TMsvSelectionOrdering& aOrdering, TBool aChildrenOfAvailableDrives)
       
    83 /** Creates a new CMsvEntry for the specified entry ID. 
       
    84 
       
    85 Note that this function does not create a new entry, but simply a new object 
       
    86 to access an existing entry. To create a new entry, use CreateL().
       
    87 
       
    88 @param aMsvSession The client’s Message Server session 
       
    89 @param aMsvId ID of the entry to access 
       
    90 @param aSortType  The initial sort order of children of the entry, for example, 
       
    91 when returned by ChildrenL(). The order can be changed later by SetSortTypeL().
       
    92 @param aChildrenOfAvailableDrives Indicates whether children from all available drives are 
       
    93 to be fetched during construction of this entry. However, a value of true is valid only
       
    94 if aMsvId is one of the standard folders, i.e. Inbox, Outbox, Drafts, Sent or Deleted.
       
    95 
       
    96 @return If the function succeeds, this is a pointer to a newly allocated and initialised object. 
       
    97 @leave KErrNotFound The requested entry does not exist.
       
    98 @leave KErrNoMemory A memory allocation failed.
       
    99 @leave KErrArgument aChildrenOfAvailableDrives is set to true and the requested entry is not 
       
   100 one of the standard folders, i.e. Inbox, Outbox, Drafts, Sent or Deleted.
       
   101 */
       
   102     {
       
   103     CMsvEntry* self = new(ELeave) CMsvEntry(aMsvSession, aOrdering, aChildrenOfAvailableDrives);
       
   104     CleanupStack::PushL(self);
       
   105     self->ConstructL(aMsvId);
       
   106     CleanupStack::Pop();
       
   107     return self;
       
   108     }
       
   109 
       
   110 
       
   111 CMsvEntry::CMsvEntry(CMsvSession& aMsvSession, const TMsvSelectionOrdering& aOrdering, TBool aChildrenOfAvailableDrives)
       
   112 :iState(EValid), iMsvSession(aMsvSession), iOrdering(aOrdering), iChildrenOfAvailableDrives(aChildrenOfAvailableDrives)
       
   113     {
       
   114     __DECLARE_NAME(_S("CMsvEntry"));
       
   115     }
       
   116 
       
   117 
       
   118 EXPORT_C void CMsvEntry::SetStandardFolderEntryL(TMsvId aId)
       
   119 //
       
   120 // Changes the context to another entry
       
   121 // If the function leaves, the context is unchanged
       
   122 //
       
   123 /** Sets the context to the specified entry while also fetching
       
   124 children from all available drives. This function can be used to
       
   125 set the context to only the standard folders i.e. Inbox, Outbox,
       
   126 Drafts, Sent or Deleted.
       
   127 
       
   128 If the function leaves, the context is unchanged.
       
   129 
       
   130 @param aId ID of the message entry which is to become the new context 
       
   131 @leave KErrNotFound aId could not be found in the index.
       
   132 @leave KErrArgument aId is not one of the standard folders, i.e. Inbox,
       
   133 Outbox, Drafts, Sent or Deleted folders.
       
   134 */
       
   135     {
       
   136     __ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreLeftOpen));
       
   137 
       
   138     if (aId==iEntryPtr->Id() && iState==EValid)
       
   139         return;
       
   140     
       
   141     SetEntryNoCheckL(aId, ETrue);
       
   142     }
       
   143 
       
   144 
       
   145 
       
   146 #endif           // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   147 
       
   148 
       
   149 EXPORT_C CMsvEntry* CMsvEntry::NewL(CMsvSession& aMsvSession, TMsvId aMsvId, const TMsvSelectionOrdering& aOrdering)
       
   150 //
       
   151 //
       
   152 //
       
   153 /** Creates a new CMsvEntry for the specified entry ID. 
       
   154 
       
   155 Note that this function does not create a new entry, but simply a new object 
       
   156 to access an existing entry. To create a new entry, use CreateL().
       
   157 
       
   158 @param aMsvSession The client’s Message Server session 
       
   159 @param aMsvId ID of the entry to access 
       
   160 @param aSortType  The initial sort order of children of the entry, for example, 
       
   161 when returned by ChildrenL(). The order can be changed later by SetSortTypeL(). 
       
   162 @return If the function succeeds, this is a pointer to a newly allocated and initialised object. 
       
   163 @leave KErrNotFound The requested entry does not exist 
       
   164 @leave KErrNoMemory A memory allocation failed 
       
   165 */
       
   166 	{
       
   167 	CMsvEntry* self = new(ELeave) CMsvEntry(aMsvSession, aOrdering);
       
   168 	CleanupStack::PushL(self);
       
   169 	self->ConstructL(aMsvId);
       
   170 	CleanupStack::Pop();
       
   171 	return self;
       
   172 	}
       
   173 
       
   174 
       
   175 CMsvEntry::CMsvEntry(CMsvSession& aMsvSession, const TMsvSelectionOrdering& aOrdering)
       
   176 :iState(EValid), iMsvSession(aMsvSession), iOrdering(aOrdering)
       
   177 //
       
   178 //
       
   179 //
       
   180 	{
       
   181 	__DECLARE_NAME(_S("CMsvEntry"));
       
   182 	}
       
   183 
       
   184 
       
   185 EXPORT_C CMsvEntry::~CMsvEntry()
       
   186 //
       
   187 //
       
   188 //
       
   189 /** Destructor. 
       
   190 
       
   191 This cleans up the object. CMsvEntry objects must be deleted by client applications 
       
   192 when they are no longer required. Note that deleting a CMsvEntry object does 
       
   193 not delete the context, simply the immediate means of accessing it. */
       
   194 	{
       
   195 	__ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreLeftOpenOnDestruction2));
       
   196 
       
   197 	if (iOberserverAdded)
       
   198 		iMsvSession.RemoveObserver(*this);
       
   199 
       
   200 	if (iEntries)
       
   201 		iEntries->ResetAndDestroy();
       
   202 
       
   203 	delete iEntries;
       
   204 	delete iSortedChildren;
       
   205 	delete iObservers;
       
   206 	delete iMtmList;
       
   207 	}
       
   208 
       
   209 void CMsvEntry::ConstructL(TMsvId aId)
       
   210 //
       
   211 //
       
   212 //
       
   213 	{
       
   214 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   215     if(iChildrenOfAvailableDrives && !MsvUtils::IsStandardId(aId))
       
   216         {
       
   217         User::Leave(KErrArgument);
       
   218         }
       
   219 #endif
       
   220 	iEntries = new (ELeave) CArrayPtrFlat<CMsvClientEntry>(KMsvClientEntryArrayGranuality);
       
   221 	iMtmList = new(ELeave) CArrayFixFlat<TUid>(KMsvMtmListGranularity);
       
   222 	iSortedChildren = CMsvEntryArray::NewL(*iMtmList);
       
   223 
       
   224 	// get the required entry from the server
       
   225 	CMsvClientEntry* cEntry = DoGetEntryLC(aId, iOwningService);
       
   226 	cEntry->SetType(EMsvClientContext);
       
   227 	iEntries->AppendL(cEntry);
       
   228 	CleanupStack::Pop(); // cEntry
       
   229 	iEntryPtr = &iEntries->At(0)->Entry();
       
   230 
       
   231 	// get the children
       
   232 	DoGetChildrenL();
       
   233 
       
   234 	// Get the notification sequence number
       
   235 	iNotifySequence = iMsvSession.Session().NotifySequenceL();
       
   236 
       
   237 	// get the event notifications from the server
       
   238 	iMsvSession.AddObserverL(*this);
       
   239 	iOberserverAdded=ETrue;
       
   240 
       
   241 #ifndef _NO_SESSION_LOGGING_
       
   242 	Log(_L("Constructed CMsvEntry on entry %x"), aId); 
       
   243 #endif
       
   244 	}
       
   245 
       
   246 #ifndef _NO_SESSION_LOGGING_
       
   247 void CMsvEntry::Log(TRefByValue<const TDesC> aFmt, ...)
       
   248 	{
       
   249 	VA_LIST list;
       
   250 	VA_START(list, aFmt);
       
   251 
       
   252 	// Generate the text
       
   253 	TBuf<256> buf;
       
   254 	buf.FormatList(aFmt, list);
       
   255 
       
   256 	// Write to file
       
   257 	_LIT(KFormatFile, "CMsvEntry %x: %S");
       
   258 	iMsvSession.iLog.WriteFormat(KFormatFile, this, &buf);
       
   259 
       
   260 	// Write to serial
       
   261 #ifndef _NO_SESSION_LOGGING_SERIAL_
       
   262 	_LIT(KFormatSerial, "MSGS: CMsvEntry %x: %S");
       
   263 	RDebug::Print(KFormatSerial, this, &buf);
       
   264 #endif
       
   265 	}
       
   266 #endif
       
   267 
       
   268 CMsvClientEntry* CMsvEntry::DoGetEntryLC(TMsvId aId, TMsvId& aOwningService)
       
   269 //
       
   270 // Gets the entry data from the server and create a CMsvClientEntry around it
       
   271 //
       
   272 	{
       
   273 	TMsvEntry tEntry;
       
   274 	User::LeaveIfError(iMsvSession.Session().GetEntry(aId, aOwningService, tEntry));
       
   275 	if (tEntry.iType==KUidMsvRootEntry)
       
   276 		aOwningService=aId;
       
   277 	return CMsvClientEntry::NewLC(tEntry, EMsvClientNull);
       
   278 	}
       
   279 
       
   280 
       
   281 
       
   282 void CMsvEntry::DoGetChildrenL()
       
   283 //
       
   284 // Gets the children of the context and places them in the entries array
       
   285 // The sorted children pointer array is implicited sorted, as the entries are retrieved
       
   286 // from the server with the current sort order
       
   287 //
       
   288 	{
       
   289 	__ASSERT_DEBUG(iEntries->Count()==1, PanicServer(EMsvChildEntriesExist1));
       
   290 	__ASSERT_DEBUG(iSortedChildren->Count()==0, PanicServer(EMsvChildEntriesExist2));
       
   291 
       
   292 	// get the children from the server - using only the visible flag
       
   293 	TMsvSelectionOrdering order(KMsvNoGrouping, EMsvSortByNone, iOrdering.ShowInvisibleEntries());
       
   294 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   295     // If child entries from all drives in the device are to be fetched.
       
   296     if(iChildrenOfAvailableDrives)
       
   297         {
       
   298 		User::LeaveIfError(iMsvSession.Session().GetChildrenAll(iEntryPtr->Id(), *iEntries, order));
       
   299 		}
       
   300 	else
       
   301 #endif
       
   302         {
       
   303         User::LeaveIfError(iMsvSession.Session().GetChildren(iEntryPtr->Id(), *iEntries, order));
       
   304 		}
       
   305 	
       
   306 	// add the children to the sorted pointer list - current context is the first entry
       
   307 	TInt totalCount=iEntries->Count();
       
   308 	for (TInt count=1; count<totalCount; count++)
       
   309 		iSortedChildren->AppendL(&iEntries->At(count)->Entry());
       
   310 
       
   311 	// sort the children
       
   312 	iSortedChildren->SortL(iOrdering);
       
   313 	}
       
   314 
       
   315 
       
   316 EXPORT_C void CMsvEntry::SetEntryL(TMsvId aId)
       
   317 //
       
   318 // Changes the context to another entry
       
   319 // If the function leaves, the context is unchanged
       
   320 //
       
   321 /** Sets the context to the specified entry. 
       
   322 
       
   323 If the function leaves, the context is unchanged.
       
   324 
       
   325 @param aId ID of the message entry which is to become the new context 
       
   326 @leave KErrNotFound aId could not be found in the index */
       
   327 	{
       
   328 	__ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreLeftOpen));
       
   329 
       
   330 	if (aId==iEntryPtr->Id() && iState==EValid)
       
   331 		return;
       
   332 	
       
   333  	SetEntryNoCheckL(aId);
       
   334 	}
       
   335 
       
   336 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   337 EXPORT_C void CMsvEntry::SetEntryNoCheckL(TMsvId aId, TBool aChildrenOfAvailableDrives /* DEFAULT=EFalse*/)
       
   338 //
       
   339 // Changes the context to another entry
       
   340 // If the function leaves, the context is unchanged
       
   341 // The function does not check for when the context is already on
       
   342 // the given TMsvId.
       
   343 //
       
   344 /** Sets the context to the specified entry.
       
   345 Children from all available drives will be fetched depending on the value of
       
   346 aChildrenOfAvailableDrives.
       
   347 
       
   348 If the function leaves, the context is unchanged.
       
   349 
       
   350 @internalTechnology
       
   351 @param aId ID of the message entry which is to become the new context
       
   352 @param aChildrenOfAvailableDrives Indicates whether children from all available drives are to
       
   353 be fetched during construction of this entry. However, a value of true is valid only
       
   354 if aMsvId is one among TMsvId's of Inbox, Outbox, Drafts, Sent or Deleted folders.
       
   355 @leave KErrNotFound aMsvId could not be found in the index 
       
   356 @leave KErrArgument aChildrenOfAvailableDrives is set to true and the requested entry is not
       
   357 one of the standard folders, i.e. Inbox, Outbox, Drafts, Sent or Deleted. */
       
   358     {
       
   359     __ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreLeftOpen));
       
   360 
       
   361     if(aChildrenOfAvailableDrives && !MsvUtils::IsStandardId(aId))
       
   362         {
       
   363         User::Leave(KErrArgument);
       
   364         }
       
   365 
       
   366     // create new entry array
       
   367     CArrayPtrFlat<CMsvClientEntry>* newEntries = new (ELeave) CArrayPtrFlat<CMsvClientEntry>(KMsvClientEntryArrayGranuality);
       
   368     CleanupStack::PushL(newEntries);
       
   369 
       
   370     // get the new context and place in array
       
   371     TMsvId newOwningService;
       
   372     CMsvClientEntry* cEntry = DoGetEntryLC(aId, newOwningService);
       
   373     cEntry->SetType(EMsvClientContext);
       
   374     newEntries->AppendL(cEntry);
       
   375     // create new children array
       
   376     CMsvEntryArray* newSortedChildren = CMsvEntryArray::NewL(*iMtmList);
       
   377 
       
   378     // keep the old arrays
       
   379     CArrayPtrFlat<CMsvClientEntry>* oldEntries = iEntries;
       
   380     CMsvEntryArray* oldSortedChildren = iSortedChildren;
       
   381 
       
   382     TBool oldFlag = iChildrenOfAvailableDrives;
       
   383     iChildrenOfAvailableDrives = aChildrenOfAvailableDrives;
       
   384 
       
   385     // use new arrays
       
   386     CleanupStack::Pop(2); // cEntry, newEntries
       
   387     iEntries = newEntries;
       
   388     iSortedChildren = newSortedChildren;
       
   389     iEntryPtr = &iEntries->At(0)->Entry();
       
   390 
       
   391     // get the children and sort accordingly
       
   392     TRAPD(leave, DoGetChildrenL(); iNotifySequence = iMsvSession.Session().NotifySequenceL());
       
   393 
       
   394     if (leave)
       
   395         {
       
   396 #ifndef _NO_SESSION_LOGGING_
       
   397         Log(_L("Failed to SetEntryL to %x with %d"), aId, leave); 
       
   398 #endif
       
   399 
       
   400         // reset the old context
       
   401         iChildrenOfAvailableDrives = oldFlag;
       
   402 
       
   403         iEntries = oldEntries;
       
   404         iSortedChildren = oldSortedChildren;
       
   405         iEntryPtr = &iEntries->At(0)->Entry();
       
   406         // cleanup
       
   407         newEntries->ResetAndDestroy();
       
   408         delete newEntries;
       
   409         delete newSortedChildren;
       
   410         // propogate leave
       
   411         User::Leave(leave);
       
   412         }
       
   413     else
       
   414         {
       
   415 #ifndef _NO_SESSION_LOGGING_
       
   416         Log(_L("SetEntryL to %x, sequence %d"), aId, iNotifySequence); 
       
   417 #endif
       
   418 
       
   419         // set the new owning service
       
   420         iOwningService = newOwningService;
       
   421         // delete the old context
       
   422         oldEntries->ResetAndDestroy();
       
   423         delete oldEntries;
       
   424         delete oldSortedChildren;
       
   425         // make sure the state is marked as valid
       
   426         iState = EValid;
       
   427         }
       
   428     }
       
   429 #else   //#define SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT
       
   430 
       
   431 EXPORT_C void CMsvEntry::SetEntryNoCheckL(TMsvId aId)
       
   432 //
       
   433 // Changes the context to another entry
       
   434 // If the function leaves, the context is unchanged
       
   435 // The function does not check for when the context is already on
       
   436 // the given TMsvId.
       
   437 //
       
   438 /** Sets the context to the specified entry. 
       
   439 
       
   440 If the function leaves, the context is unchanged.
       
   441 
       
   442 @internalTechnology
       
   443 @param aId ID of the message entry which is to become the new context 
       
   444 @leave KErrNotFound aMsvId could not be found in the index */
       
   445 	{
       
   446 	__ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreLeftOpen));
       
   447 
       
   448 	// create new entry array
       
   449 	CArrayPtrFlat<CMsvClientEntry>* newEntries = new (ELeave) CArrayPtrFlat<CMsvClientEntry>(KMsvClientEntryArrayGranuality);
       
   450 	CleanupStack::PushL(newEntries);
       
   451 
       
   452 	// get the new context and place in array
       
   453 	TMsvId newOwningService;
       
   454 	CMsvClientEntry* cEntry = DoGetEntryLC(aId, newOwningService);
       
   455 	cEntry->SetType(EMsvClientContext);
       
   456 	newEntries->AppendL(cEntry);
       
   457 	// create new children array
       
   458 	CMsvEntryArray* newSortedChildren = CMsvEntryArray::NewL(*iMtmList);
       
   459 
       
   460 	// keep the old arrays
       
   461 	CArrayPtrFlat<CMsvClientEntry>* oldEntries = iEntries;
       
   462 	CMsvEntryArray* oldSortedChildren = iSortedChildren;
       
   463 
       
   464 	// use new arrays
       
   465 	CleanupStack::Pop(2); // cEntry, newEntries
       
   466 	iEntries = newEntries;
       
   467 	iSortedChildren = newSortedChildren;
       
   468 	iEntryPtr = &iEntries->At(0)->Entry();
       
   469 
       
   470 	// get the children and sort accordingly
       
   471 	TRAPD(leave, DoGetChildrenL(); iNotifySequence = iMsvSession.Session().NotifySequenceL());
       
   472 
       
   473 	if (leave)
       
   474 		{
       
   475 #ifndef _NO_SESSION_LOGGING_
       
   476 		Log(_L("Failed to SetEntryL to %x with %d"), aId, leave); 
       
   477 #endif
       
   478 
       
   479 		// reset the old context
       
   480 		iEntries = oldEntries;
       
   481 		iSortedChildren = oldSortedChildren;
       
   482 		iEntryPtr = &iEntries->At(0)->Entry();
       
   483 		// cleanup
       
   484 		newEntries->ResetAndDestroy();
       
   485 		delete newEntries;
       
   486 		delete newSortedChildren;
       
   487 		// propogate leave
       
   488 		User::Leave(leave);
       
   489 		}
       
   490 	else
       
   491 		{
       
   492 #ifndef _NO_SESSION_LOGGING_
       
   493 		Log(_L("SetEntryL to %x, sequence %d"), aId, iNotifySequence); 
       
   494 #endif
       
   495 
       
   496 		// set the new owning service
       
   497 		iOwningService = newOwningService;
       
   498 		// delete the old context
       
   499 		oldEntries->ResetAndDestroy();
       
   500 		delete oldEntries;
       
   501 		delete oldSortedChildren;
       
   502 		// make sure the state is marked as valid
       
   503 		iState = EValid;
       
   504 		}
       
   505 	}
       
   506 #endif
       
   507 /**
       
   508 Creates a new child entry owned by the context asynchronously.
       
   509 
       
   510 Note that all session observers are notified when a new entry is created with 
       
   511 an EMsvEntriesCreated event (see TMsvSessionEvent). CMsvEntry objects are 
       
   512 such session observers themselves. When the object receives such a session 
       
   513 notification, it calls all registered entry observers with a TMsvEntryEvent 
       
   514 event EMsvNewChildren, passing in the ID of the new child.
       
   515 
       
   516 If aEntry is not a service entry, then the context must not be set to the root entry and iServiceId field must be defined .
       
   517 If aEntry is a service entry, then the context must be set to the root entry.
       
   518 
       
   519 The returned CMsvOperation object completes when creation is complete.
       
   520 
       
   521 @param	aEntry
       
   522 Index entry value for the new entry 
       
   523 
       
   524 @param	aStatus
       
   525 The request status to be completed when the operation has finished 
       
   526 
       
   527 @leave	KErrArgument aEntry is invalid 
       
   528 
       
   529 @return 
       
   530 The operation object controlling the create command. 
       
   531 */
       
   532 EXPORT_C CMsvOperation* CMsvEntry::CreateL(const TMsvEntry& aEntry, TRequestStatus& aStatus)
       
   533 	{
       
   534 	return CreateL(aEntry, RProcess().SecureId(), aStatus);
       
   535 	}
       
   536 	
       
   537 /**
       
   538 Creates a new child entry owned by the context asynchronously. Sets the owner of 
       
   539 the created entry to process specified by the supplied ID.
       
   540 
       
   541 Note that all session observers are notified when a new entry is created with 
       
   542 an EMsvEntriesCreated event (see TMsvSessionEvent). CMsvEntry objects are 
       
   543 such session observers themselves. When the object receives such a session 
       
   544 notification, it calls all registered entry observers with a TMsvEntryEvent 
       
   545 event EMsvNewChildren, passing in the ID of the new child.
       
   546 
       
   547 If aEntry is not a service entry, then the context must not be set to the root entry and iServiceId field must be defined .
       
   548 If aEntry is a service entry, then the context must be set to the root entry.
       
   549 
       
   550 The returned CMsvOperation object completes when creation is complete.
       
   551 
       
   552 @param	aEntry
       
   553 Index entry value for the new entry 
       
   554 
       
   555 @param	aOwnerId
       
   556 The ID of process that owns the created entry.
       
   557 
       
   558 @param	aStatus
       
   559 The request status to be completed when the operation has finished 
       
   560 
       
   561 @leave 	KErrArgument aEntry is invalid 
       
   562 
       
   563 @return 
       
   564 The operation object controlling the create command. 
       
   565 */
       
   566 EXPORT_C CMsvOperation* CMsvEntry::CreateL(const TMsvEntry& aEntry, TSecureId aOwnerId, TRequestStatus& aStatus)
       
   567 	{
       
   568 #ifndef _NO_SESSION_LOGGING_
       
   569 	Log(_L("Asynchronous CreateL")); 
       
   570 #endif
       
   571 
       
   572 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
   573 
       
   574 	TMsvEntry entry=aEntry;
       
   575 	entry.SetParent(iEntryPtr->Id());
       
   576 
       
   577 	__ASSERT_DEBUG(MsvUtils::ValidEntry(entry, ETrue), PanicServer(EMsvCreatingInvalidEntry));
       
   578 	if (!MsvUtils::ValidEntry(entry, ETrue))
       
   579 		User::Leave(KErrArgument);
       
   580 
       
   581 	CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
       
   582 	CleanupStack::PushL(operation);
       
   583 	User::LeaveIfError(iMsvSession.Session().OperationMtmL(iEntryPtr->Id(), operation->iMtm, operation->iService));
       
   584 	iMsvSession.Session().CreateEntryL(entry, operation->Id(), aOwnerId, operation->iStatus);
       
   585 	operation->Start();
       
   586 	CleanupStack::Pop(); // operation
       
   587 	return operation;
       
   588 	}
       
   589 	
       
   590 
       
   591 /** 
       
   592 Creates a new child entry owned by the context synchronously. 
       
   593 
       
   594 Note that all session observers are notified when a new entry is created with 
       
   595 an EMsvEntriesCreated event (see TMsvSessionEvent). CMsvEntry objects are 
       
   596 such session observers themselves. When the object receives such a session 
       
   597 notification, it calls all registered entry observers with a TMsvEntryEvent 
       
   598 event EMsvNewChildren, passing in the ID of the new child.
       
   599 
       
   600 If aEntry is not a service entry, then the context must not be set to the root entry and iServiceId field must be defined .
       
   601 If aEntry is a service entry, then the context must be set to the root entry.
       
   602 
       
   603 This function can only be used on local entries.
       
   604 
       
   605 @param	aEntry
       
   606 Index entry value for the new entry 
       
   607 
       
   608 @leave	KErrArgument aEntry is invalid
       
   609 */
       
   610 EXPORT_C void CMsvEntry::CreateL(TMsvEntry& aEntry)
       
   611 	{
       
   612 	CreateL(aEntry, RProcess().SecureId());
       
   613 	}
       
   614 	
       
   615 /** 
       
   616 Creates a new child entry owned by the context synchronously. Sets the owner of 
       
   617 the created entry to process specified by the supplied ID. 
       
   618 
       
   619 Note that all session observers are notified when a new entry is created with 
       
   620 an EMsvEntriesCreated event (see TMsvSessionEvent). CMsvEntry objects are 
       
   621 such session observers themselves. When the object receives such a session 
       
   622 notification, it calls all registered entry observers with a TMsvEntryEvent 
       
   623 event EMsvNewChildren, passing in the ID of the new child.
       
   624 
       
   625 If aEntry is not a service entry, then the context must not be set to the root entry and iServiceId field must be defined .
       
   626 If aEntry is a service entry, then the context must be set to the root entry.
       
   627 
       
   628 This function can only be used on local entries.
       
   629 
       
   630 @param	aEntry
       
   631 Index entry value for the new entry
       
   632 
       
   633 @param	aOwnerId
       
   634 The ID of process that owns the created entry.
       
   635 
       
   636 @leave	KErrArgument aEntry is invalid
       
   637 */
       
   638 EXPORT_C void CMsvEntry::CreateL(TMsvEntry& aEntry, TSecureId aOwnerId)
       
   639 	{
       
   640 #ifndef _NO_SESSION_LOGGING_
       
   641 	Log(_L("Synchronous CreateL")); 
       
   642 #endif
       
   643 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService));
       
   644 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
   645 
       
   646 	TMsvEntry entry=aEntry;
       
   647 	entry.SetParent(iEntryPtr->Id());
       
   648 
       
   649 	__ASSERT_DEBUG(MsvUtils::ValidEntry(entry, ETrue), PanicServer(EMsvCreatingInvalidEntry));
       
   650 	if (!MsvUtils::ValidEntry(entry, ETrue))
       
   651 		User::Leave(KErrArgument);
       
   652 
       
   653 	CMsvEntryArray* newSortedChildren = NULL;
       
   654 	CMsvClientEntry* cEntry = NULL;
       
   655 
       
   656 	TBool addEntry = entry.Visible() || iOrdering.ShowInvisibleEntries();
       
   657 	if (addEntry)
       
   658 		{
       
   659 		// Create what may be the new child entry if nothing goes wrong
       
   660 		cEntry = CMsvClientEntry::NewLC(entry, EMsvClientChild);
       
   661 
       
   662 		// Reserve space for the new entry for later
       
   663 		iEntries->SetReserveL(iEntries->Count() + 1);
       
   664 
       
   665 		newSortedChildren = CMsvEntryArray::NewLC(*iMtmList);
       
   666 
       
   667 		// add the children to the sorted pointer list - current context is the first entry
       
   668 		TInt totalCount=iEntries->Count();
       
   669 		for (TInt count=1; count<totalCount; count++)
       
   670 			newSortedChildren->AppendL(&iEntries->At(count)->Entry());
       
   671 
       
   672 		// We've created a new sorted child list now so we won't leave later
       
   673 		newSortedChildren->AppendL(&cEntry->Entry());
       
   674 		newSortedChildren->SortL(iOrdering);
       
   675 		}
       
   676 
       
   677 	TInt id = iMsvSession.OperationId();
       
   678 	iMsvSession.Session().CreateEntryL(entry, id, aOwnerId);
       
   679 	iMsvSession.CheckDrive();
       
   680 
       
   681     TPckgBuf<TMsvLocalOperationProgress> progressPack;
       
   682 	User::LeaveIfError(iMsvSession.Session().OperationCompletion(id, progressPack));
       
   683 	User::LeaveIfError(progressPack().iError);
       
   684 
       
   685 	// Can't leave after here
       
   686 
       
   687 	if (addEntry)
       
   688 		{
       
   689 		CleanupStack::Pop(); // newSortedChildren
       
   690 		delete iSortedChildren;
       
   691 		iSortedChildren = newSortedChildren;
       
   692 
       
   693 		CleanupStack::Pop(); // cEntry
       
   694 		iEntries->AppendL(cEntry); // Will not leave because we've reserved space earlier
       
   695 		cEntry->SetId(progressPack().iId);
       
   696 
       
   697 		TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
       
   698 		ptr->SetOwner(ETrue);
       
   699 		}
       
   700 
       
   701 	aEntry.SetParent(iEntryPtr->Id());
       
   702 	aEntry.SetId(progressPack().iId);
       
   703 
       
   704 	// If the entry is a service its service Id is the same as its Id
       
   705 	// Otherwise it must be a local entry
       
   706 	// We don't allow synchronous creation of remote entries
       
   707 	TMsvId serviceId = aEntry.Id();
       
   708 
       
   709 	aEntry.iServiceId = (aEntry.iType == KUidMsvServiceEntry) ? serviceId : KMsvLocalServiceIndexEntryId;
       
   710 	}
       
   711 
       
   712 /** 
       
   713 Sets the context's index entry to the specified values. The returned CMsvOperation 
       
   714 object completes when the change is complete.
       
   715 
       
   716 It is important to note that the state of the context is undefined until the 
       
   717 observer of the entry has been informed that the entry has been changed, or 
       
   718 the operation is completed with an error. If the function leaves, the context 
       
   719 is unchanged.
       
   720 
       
   721 @param	aEntry 
       
   722 The new index entry values for the context
       
   723 
       
   724 @param	aStatus 
       
   725 The request status to be completed when the operation has finished 
       
   726 
       
   727 @leave KErrAccessDenied The entry is locked by another client 
       
   728 
       
   729 @leave KErrArgument aEntry is invalid or the ID specified in aEntry is not 
       
   730 the same as the context ID 
       
   731 
       
   732 @leave KErrNoMemory The operation could not be created or passed to the server 
       
   733 
       
   734 @return
       
   735 An operation object controlling the change command
       
   736 */
       
   737 EXPORT_C CMsvOperation* CMsvEntry::ChangeL(const TMsvEntry& aEntry, TRequestStatus& aStatus)
       
   738 	{
       
   739 	return ChangeL(aEntry, RProcess().SecureId(), aStatus);
       
   740 	}
       
   741 
       
   742 /** 
       
   743 Sets the context's index entry to the specified values. The returned CMsvOperation 
       
   744 object completes when the change is complete. Sets the owner of the changed entry 
       
   745 to process specified by the supplied ID. 
       
   746 
       
   747 It is important to note that the state of the context is undefined until the 
       
   748 observer of the entry has been informed that the entry has been changed, or 
       
   749 the operation is completed with an error. If the function leaves, the context 
       
   750 is unchanged.
       
   751 
       
   752 @param	aEntry 
       
   753 The new index entry values for the context
       
   754 
       
   755 @param	aOwnerId
       
   756 The ID of process that owns the changed entry.
       
   757 
       
   758 @param	aStatus 
       
   759 The request status to be completed when the operation has finished 
       
   760 
       
   761 @leave KErrAccessDenied The entry is locked by another client 
       
   762 
       
   763 @leave KErrArgument aEntry is invalid or the ID specified in aEntry is not 
       
   764 the same as the context ID 
       
   765 
       
   766 @leave KErrNoMemory The operation could not be created or passed to the server 
       
   767 
       
   768 @return
       
   769 An operation object controlling the change command
       
   770 */
       
   771 EXPORT_C CMsvOperation* CMsvEntry::ChangeL(const TMsvEntry& aEntry, TSecureId aOwnerId, TRequestStatus& aStatus)
       
   772 	{
       
   773 #ifndef _NO_SESSION_LOGGING_
       
   774 	Log(_L("Asynchronous ChangeL to %x"), aEntry.Id()); 
       
   775 #endif
       
   776 
       
   777 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext, PanicServer(EMsvEntryAlreadyChangingContext));
       
   778 	__ASSERT_DEBUG(aEntry.Id()==iEntryPtr->Id(), PanicServer(EMsvChangingEntryNotContext));
       
   779 	__ASSERT_DEBUG(MsvUtils::ValidEntry(aEntry), PanicServer(EMsvChangingToInvalidEntry));
       
   780 
       
   781 	// can only change the current context
       
   782 	if (aEntry.Id()!=iEntryPtr->Id() || aEntry.Parent()!=iEntryPtr->Parent() || !MsvUtils::ValidEntry(aEntry))
       
   783 		User::Leave(KErrArgument);
       
   784 
       
   785 	// cannot change standard folders
       
   786 	if (iEntryPtr->StandardFolder())
       
   787 		User::Leave(KErrAccessDenied);
       
   788 
       
   789 	// create the operation
       
   790 	CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
       
   791 	CleanupStack::PushL(operation);
       
   792 	if (iEntryPtr->iType==KUidMsvServiceEntry)
       
   793 		{
       
   794 		operation->iMtm = KUidMsvLocalServiceMtm;
       
   795 		operation->iService = KMsvLocalServiceIndexEntryId;
       
   796 		}
       
   797 	else
       
   798 		User::LeaveIfError(iMsvSession.Session().OperationMtmL(iEntryPtr->Id(), operation->iMtm, operation->iService));
       
   799 	
       
   800 	// check that no other entries are type EMsvClientChangedContext
       
   801 	TInt count=iEntries->Count();
       
   802 	while (count--)
       
   803 		{
       
   804 		if (iEntries->At(count)->Type() == EMsvClientChangedContext)
       
   805 			{
       
   806 			delete iEntries->At(count);
       
   807 			iEntries->Delete(count);
       
   808 			}
       
   809 		}
       
   810 
       
   811 	// create local copy of entry
       
   812 	TMsvEntry entry=aEntry;
       
   813 
       
   814 	// check the hidden flags are correct
       
   815 	entry.SetOwner(iEntryPtr->Owner());
       
   816 	entry.SetDeleted(iEntryPtr->Deleted());
       
   817 
       
   818 	// store the new context for after the operation has completed
       
   819 	CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(entry, EMsvClientChangedContext);
       
   820 	if (iEntries->Count()==1)
       
   821 		iEntries->AppendL(cEntry);
       
   822 	else
       
   823 		iEntries->InsertL(1, cEntry);
       
   824 
       
   825 	// start the change operation
       
   826 	TRAPD(leave, iMsvSession.Session().ChangeEntryL(entry, operation->Id(), aOwnerId, operation->iStatus)); 
       
   827 	if (leave)
       
   828 		{
       
   829 		iEntries->Delete(1);
       
   830 		CleanupStack::PopAndDestroy(); // operation	& cEntry
       
   831 		User::Leave(leave);
       
   832 		}
       
   833 
       
   834 	operation->Start();
       
   835 	iState = EInvalidChangingContext;
       
   836 	CleanupStack::Pop(2); // operation and cEntry
       
   837 	return operation;
       
   838 	}
       
   839 
       
   840 /** 
       
   841 Sets the context's index entry to the specified values. The function is performed 
       
   842 synchronously.
       
   843 
       
   844 This function can only be used on local entries.
       
   845 
       
   846 @param	aEntry 
       
   847 The new index entry values for the context 
       
   848 
       
   849 @leave KErrAccessDenied The entry is locked by another client 
       
   850 
       
   851 @leave KErrArgument aEntry is invalid or the ID specified in aEntry is not 
       
   852 the same as the context ID 
       
   853 
       
   854 @leave KErrNoMemory The operation could not be created or passed to the server
       
   855 */
       
   856 EXPORT_C void CMsvEntry::ChangeL(const TMsvEntry& aEntry)
       
   857 	{
       
   858 	ChangeL(aEntry, RProcess().SecureId());
       
   859 	}
       
   860 
       
   861 /** 
       
   862 Sets the context's index entry to the specified values. The function is performed 
       
   863 synchronously. Sets the owner of the changed entry to process specified by the 
       
   864 supplied ID. 
       
   865 
       
   866 This function can only be used on local entries.
       
   867 
       
   868 @param	aEntry 
       
   869 The new index entry values for the context 
       
   870 
       
   871 @param	aOwnerId
       
   872 The ID of process that owns the changed entry.
       
   873 
       
   874 @leave KErrAccessDenied The entry is locked by another client 
       
   875 
       
   876 @leave KErrArgument aEntry is invalid or the ID specified in aEntry is not 
       
   877 the same as the context ID 
       
   878 
       
   879 @leave KErrNoMemory The operation could not be created or passed to the server
       
   880 */
       
   881 EXPORT_C void CMsvEntry::ChangeL(const TMsvEntry& aEntry, TSecureId aOwnerId)
       
   882 	{
       
   883 #ifndef _NO_SESSION_LOGGING_
       
   884 	Log(_L("Synchronous ChangeL to %x"), aEntry.Id()); 
       
   885 #endif
       
   886 
       
   887 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext, PanicServer(EMsvEntryAlreadyChangingContext));
       
   888 	__ASSERT_DEBUG(aEntry.Id()==iEntryPtr->Id(), PanicServer(EMsvChangingEntryNotContext));
       
   889 	__ASSERT_DEBUG(MsvUtils::ValidEntry(aEntry), PanicServer(EMsvChangingToInvalidEntry));
       
   890 
       
   891 	// can only change the current context
       
   892 	if (aEntry.Id()!=iEntryPtr->Id() || aEntry.Parent()!=iEntryPtr->Parent() || !MsvUtils::ValidEntry(aEntry))
       
   893 		User::Leave(KErrArgument);
       
   894 
       
   895 	// cannot change standard folders
       
   896 	if (iEntryPtr->StandardFolder())
       
   897 		User::Leave(KErrAccessDenied);
       
   898 
       
   899 	// create local copy of entry
       
   900 	TMsvEntry entry=aEntry;
       
   901 
       
   902 	// check the hidden flags are correct
       
   903 	entry.SetOwner(iEntryPtr->Owner());
       
   904 	entry.SetDeleted(iEntryPtr->Deleted());
       
   905 
       
   906 	// store the new context for after the operation has completed
       
   907 	CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(entry, EMsvClientContext);
       
   908 
       
   909 	TInt id = iMsvSession.OperationId();
       
   910 	iMsvSession.Session().ChangeEntryL(aEntry, id, aOwnerId); 
       
   911 
       
   912     TPckgBuf<TMsvLocalOperationProgress> progressPack;
       
   913 	User::LeaveIfError(iMsvSession.Session().OperationCompletion(id, progressPack));
       
   914 	User::LeaveIfError(progressPack().iError);
       
   915 
       
   916 	// Cannot leave after this
       
   917 	delete iEntries->At(0);
       
   918 	CleanupStack::Pop(); // cEntry
       
   919 	iEntries->At(0) = cEntry;
       
   920 	iEntryPtr = &iEntries->At(0)->Entry();
       
   921 	}
       
   922 
       
   923 
       
   924 EXPORT_C CMsvOperation* CMsvEntry::DeleteL(TMsvId aId, TRequestStatus& aStatus)
       
   925 //
       
   926 // Deletes a child of the context
       
   927 //
       
   928 	/** Deletes a child entry of the context asynchronously.
       
   929 	
       
   930 	The delete works recursively through all the descendants. If a child or any 
       
   931 	descendant is locked by another client or any store or file is open, then 
       
   932 	that child will not be deleted. Any files and stores associated with the entry 
       
   933 	are deleted.
       
   934 	
       
   935 	The returned CMsvOperation object completes when deletion is complete.
       
   936 	
       
   937 	
       
   938 	@param aId ID of entry to be deleted 
       
   939 	@param aStatus The request status to be completed when the operation has finished 
       
   940 	
       
   941 	@leave KErrNotFound The specified entry was not a child of the context 
       
   942 	@leave KErrNotSupported If deleting entries from non-current drive
       
   943 	@return The operation object controlling the deletion command */
       
   944 	{
       
   945 #ifndef _NO_SESSION_LOGGING_
       
   946 	Log(_L("Asynchronous DeleteL, entry %x"), aId); 
       
   947 #endif
       
   948 
       
   949 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
   950 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
   951 	CleanupStack::PushL(selection);
       
   952 	selection->AppendL(aId);
       
   953 	CMsvOperation* operation = DoDeleteL(*selection, aStatus);
       
   954 	CleanupStack::PopAndDestroy(); // selection
       
   955 	return operation;
       
   956 	}
       
   957 
       
   958 
       
   959 
       
   960 EXPORT_C CMsvOperation* CMsvEntry::DeleteL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
       
   961 //
       
   962 // Deletes a selection containing children of the context
       
   963 //
       
   964 /** Deletes child entries of the context asynchronously. 
       
   965 
       
   966 The delete works recursively through all the descendants. If a child or any 
       
   967 descendant is locked by another client or any store or file is open, then 
       
   968 that child will not be deleted. Any files and stores associated with the entries 
       
   969 are deleted.
       
   970 
       
   971 The returned CMsvOperation object completes when deletion is complete.
       
   972 
       
   973 @param aSelection List of ID of the entries to be deleted 
       
   974 @param aStatus The request status to be completed when the operation has finished 
       
   975 
       
   976 @leave KErrNotFound A specified entry was not a child of the context 
       
   977 @leave KErrNotSupported If deleting entries from non-current drive
       
   978 @return The operation object controlling the deletion command */
       
   979 	{
       
   980 #ifndef _NO_SESSION_LOGGING_
       
   981 	Log(_L("Asynchronous DeleteL with selection of %d entries"), aSelection.Count()); 
       
   982 #endif
       
   983 
       
   984 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
   985 	return DoDeleteL(aSelection, aStatus);
       
   986 	}
       
   987 
       
   988 
       
   989 
       
   990 CMsvOperation* CMsvEntry::DoDeleteL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
       
   991 //
       
   992 //
       
   993 //
       
   994 	{
       
   995 	__ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
   996 	
       
   997 	if (!AreChildren(aSelection))
       
   998 		User::Leave(KErrNotFound);
       
   999 
       
  1000 	CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
       
  1001 	CleanupStack::PushL(operation);
       
  1002 	if (iEntryPtr->iType==KUidMsvRootEntry)
       
  1003 		{
       
  1004 		// we must be deleting services - so it is a local operation
       
  1005 		operation->iMtm = KUidMsvLocalServiceMtm;
       
  1006 		operation->iService = KMsvLocalServiceIndexEntryId;
       
  1007 		}
       
  1008 	else
       
  1009 		User::LeaveIfError(iMsvSession.Session().OperationMtmL(aSelection.At(0), operation->iMtm, operation->iService));
       
  1010 
       
  1011 #if defined(_DEBUG)
       
  1012 	// check other entries in selection are consistent and are not read only
       
  1013 	TInt dCount = aSelection.Count();
       
  1014 	while (dCount--)
       
  1015 		{
       
  1016 		if (iEntryPtr->iType!=KUidMsvRootEntry)
       
  1017 			{
       
  1018 				TMsvId service;
       
  1019 				TUid mtm;
       
  1020 				TInt error = iMsvSession.Session().OperationMtmL(aSelection.At(dCount), mtm, service);
       
  1021 				__ASSERT_DEBUG(error==KErrNone || error==KErrNotFound, PanicServer(EMsvNonConsistentDeleteSelection));
       
  1022 				__ASSERT_DEBUG(mtm==operation->iMtm, PanicServer(EMsvNonConsistentDeleteSelection));
       
  1023 				__ASSERT_DEBUG(service==operation->iService, PanicServer(EMsvNonConsistentDeleteSelection));
       
  1024 			}
       
  1025 		TMsvEntry dEntry;
       
  1026 		TMsvId dService;
       
  1027 		if (iMsvSession.Session().GetEntry(aSelection.At(dCount), dService, dEntry)==KErrNone)
       
  1028 			{
       
  1029 			__ASSERT_DEBUG(dService==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && dService==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && dService==aSelection.At(dCount)), PanicServer(EMsvDeletingEntryDifferentOwningService));
       
  1030 			}
       
  1031 		}
       
  1032 #endif
       
  1033 	
       
  1034 	iMsvSession.Session().DeleteEntriesL(aSelection, operation->Id(), operation->iStatus);
       
  1035 	operation->Start();
       
  1036 	CleanupStack::Pop(); // operation
       
  1037 	return operation;
       
  1038 	}
       
  1039 
       
  1040 EXPORT_C void CMsvEntry::DeleteL(TMsvId aId)
       
  1041 /** Deletes a child entry of the context synchronously. 
       
  1042 
       
  1043 The delete works recursively through all the descendants. If a child or any descendant is locked by another 
       
  1044 client or any store or file is open, then that child will not be deleted. Any files and stores associated 
       
  1045 with the entry are deleted.
       
  1046 
       
  1047 This function can only be used on local entries.
       
  1048 
       
  1049 @param aId ID of entry to be deleted
       
  1050 @leave KErrNotFound The specified entry was not a child of the context
       
  1051 @leave KErrNotSupported If deleting entries from non-current drive
       
  1052 */
       
  1053 	{
       
  1054 #ifndef _NO_SESSION_LOGGING_
       
  1055 	Log(_L("Synchronous DeleteL, entry %x"), aId); 
       
  1056 #endif
       
  1057 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1058 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1059 	
       
  1060 	User::LeaveIfError(CMsvEntry::DeleteOneL(aId));
       
  1061 	}
       
  1062 
       
  1063 EXPORT_C void CMsvEntry::DeleteL(const CMsvEntrySelection& aSelection, TMsvLocalOperationProgress& aProgress)
       
  1064 /** Deletes child entries of the context synchronously. 
       
  1065 
       
  1066 The delete works recursively through all the descendants. If a child or any 
       
  1067 descendant is locked by another client or any store or file is open, then 
       
  1068 that child will not be deleted. Any files and stores associated with the entries 
       
  1069 are deleted.
       
  1070 
       
  1071 @param aSelection List of ID of the entries to be deleted 
       
  1072 @param aProgress Progress information for the delete operation
       
  1073 @leave KErrNotFound A specified entry was not a child of the context 
       
  1074 @leave KErrNotSupported If deleting entries from non-current drive */
       
  1075 	{
       
  1076 #ifndef _NO_SESSION_LOGGING_
       
  1077 	Log(_L("Synchronous DeleteL with selection of %d entries"), aSelection.Count()); 
       
  1078 #endif
       
  1079 
       
  1080 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1081 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1082 	__ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
  1083 
       
  1084 	if (!AreChildren(aSelection))
       
  1085 		User::Leave(KErrNotFound);
       
  1086 
       
  1087 	aProgress.iTotalNumberOfEntries=aSelection.Count();
       
  1088 	aProgress.iNumberCompleted=0;
       
  1089 	aProgress.iNumberRemaining=aProgress.iTotalNumberOfEntries;
       
  1090 	aProgress.iError=KErrNone;
       
  1091 
       
  1092 	TInt count=aProgress.iTotalNumberOfEntries;
       
  1093 	while(count--)
       
  1094 		{
       
  1095 		aProgress.iId=aSelection.At(count);
       
  1096 		TInt err=DeleteOneL(aProgress.iId);
       
  1097 		aProgress.iNumberRemaining--;
       
  1098 		if(err==KErrNone)
       
  1099 			aProgress.iNumberCompleted++;
       
  1100 		else
       
  1101 			{
       
  1102 			aProgress.iError=err;
       
  1103 			aProgress.iNumberFailed++;
       
  1104 			}
       
  1105 		}
       
  1106 	}
       
  1107 
       
  1108 
       
  1109 TInt CMsvEntry::DeleteOneL(TMsvId aMsvId)
       
  1110 	{
       
  1111 	CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
       
  1112 	CleanupStack::PushL(selection);
       
  1113 	selection->AppendL(aMsvId);
       
  1114 	TInt opid = iMsvSession.OperationId();
       
  1115 	iMsvSession.Session().DeleteEntriesL(*selection, opid);
       
  1116 
       
  1117 	TMsvLocalOperationProgress progress;
       
  1118 	TPckg<TMsvLocalOperationProgress> progressPack(progress);
       
  1119     User::LeaveIfError(iMsvSession.Session().OperationCompletion(opid, progressPack));
       
  1120 	
       
  1121 	if(progress.iError==KErrNone)
       
  1122 		{
       
  1123 		TMsvId id = selection->At(0);
       
  1124 		TInt ii = iSortedChildren->Count();
       
  1125 		while (ii--)
       
  1126 			{
       
  1127 			if (iSortedChildren->At(ii)->Id() == id)
       
  1128 				{
       
  1129 				iSortedChildren->Delete(ii);
       
  1130 				break;
       
  1131 				}
       
  1132 			}
       
  1133 
       
  1134 		ii = iEntries->Count();
       
  1135 		while (ii--)
       
  1136 			{
       
  1137 			if (iEntries->At(ii)->Entry().Id() == id)
       
  1138 				{
       
  1139 				delete iEntries->At(ii);
       
  1140 				iEntries->Delete(ii);
       
  1141 				break;
       
  1142 				}
       
  1143 			}
       
  1144 		// Reset the owner flag
       
  1145 		if (Count() == 0)
       
  1146 			{
       
  1147 			TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
       
  1148 			ptr->SetOwner(EFalse);
       
  1149 			}		
       
  1150 		}
       
  1151 	CleanupStack::PopAndDestroy(selection);
       
  1152 	return(progress.iError);
       
  1153 	}
       
  1154 
       
  1155 
       
  1156 
       
  1157 
       
  1158 EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenL() const
       
  1159 //
       
  1160 // Gets a selection containing the children of the context
       
  1161 //
       
  1162 /** Gets a selection containing the IDs of all the context children. If the entry 
       
  1163 has no children, the selection is empty.
       
  1164 
       
  1165 The calling function is responsible for the deletion of the returned CMsvEntrySelection. 
       
  1166 
       
  1167 @leave KErrNoMemory Not enough memory to create the selection 
       
  1168 @return A selection containing the ID of all children of the context */
       
  1169 	{
       
  1170 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1171 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1172 	CleanupStack::PushL(selection);
       
  1173 	TInt totalCount=iSortedChildren->Count();
       
  1174 	for (TInt count=0; count<totalCount; count++)
       
  1175 		{
       
  1176 		selection->AppendL(iSortedChildren->At(count)->Id());
       
  1177 		}
       
  1178 	CleanupStack::Pop(); // selection
       
  1179 	return selection;
       
  1180 	}
       
  1181 
       
  1182 EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenWithServiceL(TMsvId aServiceId) const
       
  1183 //
       
  1184 // Gets a selection containing the children of the context which use the service
       
  1185 //
       
  1186 /** Gets a selection containing the IDs of all the context children filtered by message service.
       
  1187 i.e. the index entry's iServiceId field equals aId.
       
  1188 
       
  1189 If the entry has no such children, the selection is empty.
       
  1190 
       
  1191 The calling function is responsible for the deletion of the returned CMsvEntrySelection.
       
  1192 @return	List of IDs of all children of the context meeting the criterion		
       
  1193 @param aServiceId Service by which to filter
       
  1194 @leave KErrNoMemory Not enough memory to create the selection 
       
  1195 */
       
  1196 	{
       
  1197 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1198 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1199 	CleanupStack::PushL(selection);
       
  1200 	TInt totalCount=iSortedChildren->Count();
       
  1201 	for (TInt count=0; count<totalCount; count++)
       
  1202 		{
       
  1203 		if (iSortedChildren->At(count)->iServiceId==aServiceId)
       
  1204 			{
       
  1205 			selection->AppendL(iSortedChildren->At(count)->Id());
       
  1206 			}
       
  1207 		}
       
  1208 	CleanupStack::Pop(); // selection
       
  1209 	return selection;
       
  1210 	}
       
  1211 
       
  1212 EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenWithMtmL(TUid aMtm) const
       
  1213 //
       
  1214 // Gets a selection containing the children of the context which use the same MTM
       
  1215 //
       
  1216 /** Gets a selection containing the IDs of all the context children filtered by 
       
  1217 MTM type. i.e. the index entry's iMtm field equals aMtm.
       
  1218 
       
  1219 If the entry has no such children, the selection is empty.
       
  1220 
       
  1221 The calling function is responsible for the deletion of the returned CMsvEntrySelection. 
       
  1222 
       
  1223 @param aMtm MTM type by which to filter 
       
  1224 @leave KErrNoMemory Not enough memory to create the selection 
       
  1225 @return A selection containing the ID of all children of the context meeting 
       
  1226 the criterion */
       
  1227 	{
       
  1228 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1229 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1230 	CleanupStack::PushL(selection);
       
  1231 	TInt totalCount=iSortedChildren->Count();
       
  1232 	for (TInt count=0; count<totalCount; count++)
       
  1233 		{
       
  1234 		if (iSortedChildren->At(count)->iMtm==aMtm)
       
  1235 			{
       
  1236 			selection->AppendL(iSortedChildren->At(count)->Id());
       
  1237 			}
       
  1238 		}
       
  1239 	CleanupStack::Pop(); // selection
       
  1240 	return selection;
       
  1241 	}
       
  1242 
       
  1243 EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenWithTypeL(TUid aType) const
       
  1244 //
       
  1245 // Gets a selection containing the children of the context which are the same type
       
  1246 //
       
  1247 /** Gets a selection containing the IDs of all the context children filtered by 
       
  1248 entry type. i.e. is the entry a folder, a message, etc.
       
  1249 
       
  1250 If the entry has no such children, the selection is empty.
       
  1251 
       
  1252 The calling function is responsible for the deletion of the returned CMsvEntrySelection. 
       
  1253 
       
  1254 
       
  1255 @param aType Entry type by which to filter. 
       
  1256 @leave KErrNoMemory Not enough memory to create the selection 
       
  1257 @return A selection containing the ID of all children of the context meeting 
       
  1258 the criterion */
       
  1259 	{
       
  1260 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1261 
       
  1262 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1263 	CleanupStack::PushL(selection);
       
  1264 	TInt totalCount=iSortedChildren->Count();
       
  1265 	for (TInt count=0; count<totalCount; count++)
       
  1266 		{
       
  1267 		if (iSortedChildren->At(count)->iType==aType)
       
  1268 			{
       
  1269 			selection->AppendL(iSortedChildren->At(count)->Id());
       
  1270 			}
       
  1271 		}
       
  1272 	CleanupStack::Pop(); // selection
       
  1273 	return selection;
       
  1274 	}
       
  1275 
       
  1276 
       
  1277 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1278 /**
       
  1279  * ChildrenOfAvailableDrivesL()
       
  1280  *
       
  1281  * @param None.
       
  1282  * @return CMsvEntrySelection List of child ids from all available drives.
       
  1283  * @leave KErrArgument If the function is used for a TMsvId other than that 
       
  1284  * of standard folders, i.e. Inbox, Outbox, Drafts, Sent or Deleted.
       
  1285  * @leave KErrNoMemory Not enough memory to create the selection.
       
  1286  * 
       
  1287  * Gets a selection containing the child Id's from all drives currently present
       
  1288  * in the server preferred drive list.
       
  1289  * The function must be used only if the context is set to one of the standard folders,
       
  1290  * i.e. Inbox, Outbox, Drafts, Sent or Deleted.
       
  1291  * 
       
  1292  * The calling function is responsible for the deletion of the returned CMsvEntrySelection.
       
  1293  *
       
  1294  @publishedAll
       
  1295  @released
       
  1296  */ 
       
  1297 EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenOfAvailableDrivesL() const
       
  1298     {
       
  1299     __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1300 
       
  1301     if(!iChildrenOfAvailableDrives)
       
  1302         {
       
  1303 		User::Leave(KErrArgument);		
       
  1304 		}
       
  1305 
       
  1306     CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1307 	CleanupStack::PushL(selection);
       
  1308 
       
  1309     TInt totalCount = iSortedChildren->Count();
       
  1310 	for (TInt count=0; count<totalCount; count++)
       
  1311 		{
       
  1312 		selection->AppendL(iSortedChildren->At(count)->Id());
       
  1313 		}
       
  1314 	CleanupStack::Pop(); // selection
       
  1315 	return selection;
       
  1316 	}
       
  1317 #endif			// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1318 
       
  1319 	
       
  1320 
       
  1321 EXPORT_C const TMsvEntry& CMsvEntry::operator[](TInt aIndex) const
       
  1322 //
       
  1323 // Returns the data for a child, zero index with the current sort order
       
  1324 //
       
  1325 /** Gets the index entry of the child at the position specified by the array index. 
       
  1326 The child entries of the context can be considered as a zero-based array, 
       
  1327 with entries sorted according to the current sort order. 
       
  1328 
       
  1329 Note:
       
  1330 
       
  1331 The function panics with E32USER-CBase 21 if aIndex was out of range.
       
  1332 
       
  1333 @param aIndex Array index 
       
  1334 @return Index entry for the specified child. Valid for in-range values of aIndex. */
       
  1335 	{
       
  1336 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1337 	return *iSortedChildren->At(aIndex);
       
  1338 	}
       
  1339 
       
  1340 
       
  1341 EXPORT_C CMsvEntry* CMsvEntry::ChildEntryL(TMsvId aId) const
       
  1342 //
       
  1343 // Returns a new entry with the child as the context
       
  1344 //
       
  1345 /** Gets a new CMsvEntry object with its context set to the child entry ID. aMsvId 
       
  1346 must specify a child of the current context.
       
  1347 
       
  1348 The CMsvEntry object must be deleted by the client application when it is 
       
  1349 no longer required. 
       
  1350 
       
  1351 @param aId ID of a child entry 
       
  1352 @leave KErrNotFound aMsvId does not specify a child of the context 
       
  1353 @return CMsvEntry object with its context set to child entry */
       
  1354 	{
       
  1355 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1356 	if (!IsAChild(aId))
       
  1357 		User::Leave(KErrNotFound);
       
  1358 	return CMsvEntry::NewL(iMsvSession, aId, iOrdering);
       
  1359 	}
       
  1360 
       
  1361 
       
  1362 EXPORT_C const TMsvEntry& CMsvEntry::ChildDataL(TMsvId aId) const
       
  1363 //
       
  1364 // Returns the data for a child with the aId
       
  1365 //
       
  1366 /** Gets the index entry of context's child with the specified ID.
       
  1367 
       
  1368 @param aId ID of the child 
       
  1369 @leave KErrNotFound No child exists with that ID 
       
  1370 @return Index entry for the specified child. Valid for in-range values of aIndex. */
       
  1371 	{
       
  1372 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1373 
       
  1374 	TInt count=iSortedChildren->Count();
       
  1375 	while (count--)
       
  1376 		{
       
  1377 		if (iSortedChildren->At(count)->Id()==aId)
       
  1378 			break;
       
  1379 		}
       
  1380 	User::LeaveIfError(count); // will be -1 (KErrNotFound)
       
  1381 	return *iSortedChildren->At(count);
       
  1382 	}
       
  1383 
       
  1384 
       
  1385 EXPORT_C CMsvStore* CMsvEntry::ReadStoreL()
       
  1386 //
       
  1387 // Return store for the current context which is opened for read only
       
  1388 //
       
  1389 /** Obtains the message store for the current context with read-only access. 
       
  1390 
       
  1391 Multiple clients can read from a store simultaneously. If another client is already 
       
  1392 writing to the store, the function leaves with KErrAccessDenied. 
       
  1393 
       
  1394 The returned CMsvStore must be deleted when it is no longer required. 
       
  1395 
       
  1396 @leave KErrNoMemory Not enough memory to open store 
       
  1397 @leave KErrAccessDenied Another client is currently writing to the store 
       
  1398 @leave KErrNotFound There is no store associated with this entry 
       
  1399 @return Context's message store open for read-only access */
       
  1400 	{
       
  1401 #ifndef _NO_SESSION_LOGGING_
       
  1402 	Log(_L("ReadStoreL for entry %x"), iEntryPtr->Id()); 
       
  1403 #endif
       
  1404 
       
  1405 	__ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreAlreadyOpen));
       
  1406 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1407 	User::LeaveIfError(iMsvSession.Session().ReadStore(iEntryPtr->Id()));
       
  1408 
       
  1409 	// open the store
       
  1410 	TInt err =0;
       
  1411 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
       
  1412 		TRAP(err, iStore = CMsvStore::OpenForReadL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id(), this->Entry().iMtm));	
       
  1413 #else
       
  1414 		TRAP(err, iStore = CMsvStore::OpenForReadL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id()));			
       
  1415 #endif
       
  1416 	if (err != KErrNone)
       
  1417 		{
       
  1418 		iMsvSession.Session().DecStoreReaderCount(iEntryPtr->Id()); // error ignored
       
  1419 		User::Leave(err);
       
  1420 		}
       
  1421 	return iStore;
       
  1422 	}
       
  1423 
       
  1424 
       
  1425 EXPORT_C CMsvStore* CMsvEntry::EditStoreL()
       
  1426 //
       
  1427 // Return store for the current context which can be writen to
       
  1428 //
       
  1429 /** Gets the message store for the current context with read-write access. 
       
  1430 
       
  1431 Only one client can edit a message store at one time. If another client is 
       
  1432 already writing to the store, KErrAccessDenied is returned. Other clients 
       
  1433 can be reading the store. 
       
  1434 
       
  1435 If the message store does not exist when EditStore() is called, a new message 
       
  1436 store is created. 
       
  1437 
       
  1438 The returned CMsvStore must be deleted when it is no longer required. 
       
  1439 
       
  1440 @leave KErrAccessDenied Store is locked by another process or the entry is 
       
  1441 read only 
       
  1442 @leave KErrNoMemory Not enough memory to open the store 
       
  1443 @return Context's message store open for read-write access */
       
  1444 	{
       
  1445 #ifndef _NO_SESSION_LOGGING_
       
  1446 	Log(_L("EditStoreL for entry %x"), iEntryPtr->Id()); 
       
  1447 #endif
       
  1448 
       
  1449 	__ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreAlreadyOpen));
       
  1450 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1451 	
       
  1452 	if (iEntryPtr->ReadOnly())
       
  1453 		User::Leave(KErrAccessDenied);
       
  1454 
       
  1455 	User::LeaveIfError(iMsvSession.Session().LockStore(iEntryPtr->Id()));
       
  1456 
       
  1457 	// open the store
       
  1458 	TInt error = 0;
       
  1459 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)	
       
  1460 		TRAP(error,  iStore = CMsvStore::OpenForWriteL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id(), this->Entry().iMtm));
       
  1461 #else
       
  1462 		TRAP(error,  iStore = CMsvStore::OpenForWriteL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id()));
       
  1463 #endif
       
  1464 	if (error)
       
  1465 		{
       
  1466 		iMsvSession.Session().ReleaseStore(iEntryPtr->Id()); // error ignored
       
  1467 		User::Leave(error);		
       
  1468 		}
       
  1469 
       
  1470 	return iStore;
       
  1471 	}
       
  1472 
       
  1473 
       
  1474 
       
  1475 void CMsvEntry::HandleStoreEvent(MMsvStoreObserver::TMsvStoreEvent aEvent, TMsvId /*aId*/)
       
  1476 //
       
  1477 //
       
  1478 //
       
  1479 	{
       
  1480 	switch (aEvent)
       
  1481 		{
       
  1482 		case EMsvEditStoreClosed:
       
  1483 			iMsvSession.Session().ReleaseStore(iEntryPtr->Id()); // error ignored
       
  1484 			iStore=NULL;
       
  1485 			break;
       
  1486 		case EMsvReadStoreClosed:
       
  1487 			iMsvSession.Session().DecStoreReaderCount(iEntryPtr->Id()); // error ignored
       
  1488 			iStore=NULL;
       
  1489 			break;
       
  1490 		default:
       
  1491 			__ASSERT_DEBUG(EFalse, PanicServer(EMsvUnknownStoreEvent3));
       
  1492 		}
       
  1493 
       
  1494 	}
       
  1495 
       
  1496 
       
  1497 EXPORT_C CMsvOperation* CMsvEntry::MoveL(TMsvId aMsvId, TMsvId aTargetId, TRequestStatus& aStatus)
       
  1498 //
       
  1499 // Move a single child to another parent
       
  1500 //
       
  1501 /** Moves, asynchronously, a child of the context to become an entry owned by the target entry. 
       
  1502 
       
  1503 All descendants will be moved as well. Any files and stores associated with 
       
  1504 the entry are also moved.
       
  1505 
       
  1506 The returned CMsvOperation object completes when moving is complete.
       
  1507 
       
  1508 @param aMsvId The ID of the entry to be moved 
       
  1509 @param aTargetId The ID of the entry to own the moved entries 
       
  1510 @param aStatus The request status to be completed when the operation has finished 
       
  1511 
       
  1512 @leave KErrNoMemory The operation could not be created or passed to the server 
       
  1513 @leave KErrNotFound An entry was not a child of the context 
       
  1514 @return The operation object controlling the move command. */
       
  1515 	{
       
  1516 #ifndef _NO_SESSION_LOGGING_
       
  1517 	Log(_L("Asynchronous MoveL %x to %x"), aMsvId, aTargetId); 
       
  1518 #endif
       
  1519 
       
  1520 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1521 	CleanupStack::PushL(selection);
       
  1522 	selection->AppendL(aMsvId);
       
  1523 	CMsvOperation* operation = MoveL(*selection, aTargetId, aStatus);
       
  1524 	CleanupStack::PopAndDestroy(); // selection
       
  1525 	return operation;
       
  1526 	}
       
  1527 
       
  1528 
       
  1529 TInt CMsvEntry::MoveOneL(TMsvId aMsvId, TMsvId aTargetId)
       
  1530 	{
       
  1531 	CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
       
  1532 	CleanupStack::PushL(selection);
       
  1533 	selection->AppendL(aMsvId);
       
  1534 	TInt opid = iMsvSession.OperationId();
       
  1535 	iMsvSession.Session().MoveEntriesL(*selection, aTargetId, opid);
       
  1536 
       
  1537 	TMsvLocalOperationProgress progress;
       
  1538 	TPckg<TMsvLocalOperationProgress> progressPack(progress);
       
  1539     User::LeaveIfError(iMsvSession.Session().OperationCompletion(opid, progressPack));
       
  1540 	
       
  1541 	if(progress.iError==KErrNone)
       
  1542 		{
       
  1543 		TMsvId id = selection->At(0);
       
  1544 		TInt ii = iSortedChildren->Count();
       
  1545 		while (ii--)
       
  1546 			{
       
  1547 			if (iSortedChildren->At(ii)->Id() == id)
       
  1548 				{
       
  1549 				iSortedChildren->Delete(ii);
       
  1550 				break;
       
  1551 				}
       
  1552 			}
       
  1553 
       
  1554 		ii = iEntries->Count();
       
  1555 		while (ii--)
       
  1556 			{
       
  1557 			if (iEntries->At(ii)->Entry().Id() == id)
       
  1558 				{
       
  1559 				delete iEntries->At(ii);
       
  1560 				iEntries->Delete(ii);
       
  1561 				break;
       
  1562 				}
       
  1563 			}
       
  1564 		// Reset the owner flag
       
  1565 		if (Count() == 0)
       
  1566 			{
       
  1567 			TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
       
  1568 			ptr->SetOwner(EFalse);
       
  1569 			}		
       
  1570 		}
       
  1571 	CleanupStack::PopAndDestroy(selection);
       
  1572 	return(progress.iError);
       
  1573 	}
       
  1574 
       
  1575 /** Moves, synchronously, a child of the context to become an entry owned by the target entry. 
       
  1576 
       
  1577 All descendants will be moved as well. Any files and stores associated with 
       
  1578 the entry are also moved.
       
  1579 
       
  1580 @param aMsvId The ID of the entry to be moved 
       
  1581 @param aTargetId The ID of the entry to own the moved entries 
       
  1582 
       
  1583 @leave KErrNoMemory 
       
  1584 @leave KErrNotFound An entry was not a child of the context 
       
  1585 */
       
  1586 EXPORT_C void CMsvEntry::MoveL(TMsvId aMsvId, TMsvId aTargetId)
       
  1587 //
       
  1588 // Move a single child to another parent
       
  1589 //
       
  1590 	{
       
  1591 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1592 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1593 	__ASSERT_DEBUG(aTargetId!=iEntryPtr->Id(), PanicServer(EMsvMovingEntryToSameParent));
       
  1594 
       
  1595 #ifndef _NO_SESSION_LOGGING_
       
  1596 	Log(_L("Synchronous MoveL %x to %x"), aMsvId, aTargetId); 
       
  1597 #endif
       
  1598 	User::LeaveIfError(MoveOneL(aMsvId,aTargetId));
       
  1599 	}
       
  1600 
       
  1601 
       
  1602 /** Moves, synchronously, children of the context to become entries owned by the target entry. 
       
  1603 
       
  1604 All descendants will be moved as well. Any files and stores associated with 
       
  1605 the entries are also moved.
       
  1606 
       
  1607 @param aSelection List of IDs of the entries to be moved 
       
  1608 @param aTargetId The ID of the entry to own the moved entires 
       
  1609 @param aProgress On return, records the outcome of the move 
       
  1610 
       
  1611 @leave KErrNoMemory 
       
  1612 @leave KErrNotFound An entry was not a child of the context 
       
  1613 */
       
  1614 EXPORT_C void CMsvEntry::MoveL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TMsvLocalOperationProgress& aProgress)
       
  1615 //
       
  1616 // Move a selection of children to another parent
       
  1617 //
       
  1618 	{
       
  1619 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1620 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1621 	__ASSERT_DEBUG(aTargetId!=iEntryPtr->Id(), PanicServer(EMsvMovingEntryToSameParent));
       
  1622 	__ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
  1623 
       
  1624 
       
  1625 #ifndef _NO_SESSION_LOGGING_
       
  1626 	Log(_L("Synchronous MoveL with selection of %d entries to %x"), aSelection.Count(),aTargetId); 
       
  1627 #endif
       
  1628 
       
  1629 	aProgress.iTotalNumberOfEntries=aSelection.Count();
       
  1630 	aProgress.iNumberCompleted=0;
       
  1631 	aProgress.iNumberRemaining=aProgress.iTotalNumberOfEntries;
       
  1632 	aProgress.iError=KErrNone;
       
  1633 
       
  1634 	TInt count=aProgress.iTotalNumberOfEntries;
       
  1635 	while(count--)
       
  1636 		{
       
  1637 		aProgress.iId=aSelection.At(count);
       
  1638 		TInt err=MoveOneL(aProgress.iId,aTargetId);
       
  1639 		aProgress.iNumberRemaining--;
       
  1640 		if(err==KErrNone)
       
  1641 			aProgress.iNumberCompleted++;
       
  1642 		else
       
  1643 			{
       
  1644 			aProgress.iError=err;
       
  1645 			aProgress.iNumberFailed++;
       
  1646 			}
       
  1647 		}
       
  1648 	}
       
  1649 
       
  1650 
       
  1651 
       
  1652 
       
  1653 
       
  1654 
       
  1655 EXPORT_C CMsvOperation* CMsvEntry::MoveL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TRequestStatus& aStatus)
       
  1656 //
       
  1657 // Move a selection of children to another parent
       
  1658 //
       
  1659 /** Moves, asynchronously, children of the context to become entries owned by the target entry. 
       
  1660 
       
  1661 All descendants will be moved as well. Any files and stores associated with 
       
  1662 the entries are also moved.
       
  1663 
       
  1664 The returned CMsvOperation object completes when moving is complete.
       
  1665 
       
  1666 @param aSelection List of IDs of the entries to be moved 
       
  1667 @param aTargetId The ID of the entry to own the moved entires 
       
  1668 @param aStatus The request status to be completed when the operation has finished 
       
  1669 
       
  1670 @leave KErrNoMemory The operation could not be created or passed to the server 
       
  1671 @leave KErrNotFound An entry was not a child of the context 
       
  1672 @return The operation object controlling the move command. */
       
  1673 	{
       
  1674 #ifndef _NO_SESSION_LOGGING_
       
  1675 	Log(_L("Asynchronous MoveL of selection of %d entries to %x"), aSelection.Count(), aTargetId); 
       
  1676 #endif
       
  1677 
       
  1678 	__ASSERT_DEBUG(aTargetId!=iEntryPtr->Id(), PanicServer(EMsvMovingEntryToSameParent));
       
  1679 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1680 	if (!AreChildren(aSelection))
       
  1681 		User::Leave(KErrNotFound);
       
  1682 	CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
       
  1683 	CleanupStack::PushL(operation);
       
  1684 	User::LeaveIfError(iMsvSession.Session().OperationMtmL(aSelection.At(0), aTargetId, operation->iMtm, operation->iService));
       
  1685 
       
  1686 #if defined(_DEBUG)
       
  1687 	// check other entries in selection are consistent and are not read only
       
  1688 	TInt dCount = aSelection.Count();
       
  1689 	while (dCount--)
       
  1690 		{
       
  1691 		TMsvId service;
       
  1692 		TUid mtm;
       
  1693 		TInt error = iMsvSession.Session().OperationMtmL(aSelection.At(dCount), aTargetId, mtm, service);
       
  1694 		__ASSERT_DEBUG(error==KErrNone || error==KErrNotFound, PanicServer(EMsvMulitpleMtmsForMoveCommand));
       
  1695 		__ASSERT_DEBUG(mtm==operation->iMtm, PanicServer(EMsvMulitpleMtmsForMoveCommand));
       
  1696 		__ASSERT_DEBUG(service==operation->iService, PanicServer(EMsvMulitpleMtmsForMoveCommand));
       
  1697 		TMsvEntry dEntry;
       
  1698 		TMsvId dService;
       
  1699 		if (iMsvSession.Session().GetEntry(aSelection.At(dCount), dService, dEntry)==KErrNone)
       
  1700 			__ASSERT_DEBUG(dService==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && dService==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==aSelection.At(dCount)), PanicServer(EMsvMovingEntryDifferentOwningService));
       
  1701 		}
       
  1702 #endif
       
  1703 
       
  1704 	iMsvSession.Session().MoveEntriesL(aSelection, aTargetId, operation->Id(), operation->iStatus);
       
  1705 	operation->Start();
       
  1706 	CleanupStack::Pop(); // operation
       
  1707 	return operation;
       
  1708 	}
       
  1709 
       
  1710 
       
  1711 EXPORT_C CMsvOperation* CMsvEntry::CopyL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TRequestStatus& aStatus)
       
  1712 //
       
  1713 // Copy a selection ocf children to another parent
       
  1714 //
       
  1715 /** Creates, asynchronously. copies of children of the context as new entries owned by the specified 
       
  1716 target ID.
       
  1717 
       
  1718 All descendants will be copied as well. Any files and stores associated with 
       
  1719 the entries are also copied.
       
  1720 
       
  1721 The returned CMsvOperation object completes when copying is complete.
       
  1722 
       
  1723 @param aSelection List of IDs of the entries to be copied 
       
  1724 @param aTargetId The ID of the entry to own the copies 
       
  1725 @param aStatus The request status to be completed when the operation has finished 
       
  1726 
       
  1727 @leave KErrNoMemory The operation could not be created or passed to the server 
       
  1728 @leave KErrNotFound An entry was not a child of the context 
       
  1729 @return The operation object controlling the copy command. */
       
  1730 	{
       
  1731 #ifndef _NO_SESSION_LOGGING_
       
  1732 	Log(_L("Asynchronous CopyL of selection of %d entries to %x"), aSelection.Count(), aTargetId); 
       
  1733 #endif
       
  1734 
       
  1735 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1736 	if (!AreChildren(aSelection))
       
  1737 		User::Leave(KErrNotFound);
       
  1738 	CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
       
  1739 	CleanupStack::PushL(operation);
       
  1740 	User::LeaveIfError(iMsvSession.Session().OperationMtmL(aSelection.At(0), aTargetId, operation->iMtm, operation->iService)); 
       
  1741 
       
  1742 #if defined(_DEBUG)
       
  1743 	// check other entries in selection are consistent 
       
  1744 	TInt dCount = aSelection.Count();
       
  1745 	while (dCount--)
       
  1746 		{
       
  1747 		TMsvId service;
       
  1748 		TUid mtm;
       
  1749 		TInt error = iMsvSession.Session().OperationMtmL(aSelection.At(dCount), aTargetId, mtm, service);
       
  1750 		__ASSERT_DEBUG(error==KErrNone || error==KErrNotFound, PanicServer(EMsvMulitpleMtmsForCopyCommand));
       
  1751 		__ASSERT_DEBUG(mtm==operation->iMtm, PanicServer(EMsvMulitpleMtmsForCopyCommand));
       
  1752 		__ASSERT_DEBUG(service==operation->iService, PanicServer(EMsvMulitpleMtmsForCopyCommand));
       
  1753 		TMsvEntry dEntry;
       
  1754 		TMsvId dService;
       
  1755 		if (iMsvSession.Session().GetEntry(aSelection.At(dCount), dService, dEntry)==KErrNone)
       
  1756 			__ASSERT_DEBUG(dService==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && dService==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==aSelection.At(dCount)), PanicServer(EMsvCopyingEntryDifferentOwningService));
       
  1757 		}
       
  1758 #endif
       
  1759 
       
  1760 	iMsvSession.Session().CopyEntriesL(aSelection, aTargetId, operation->Id(), operation->iStatus);
       
  1761 	operation->Start();
       
  1762 	CleanupStack::Pop(); // operation
       
  1763 	return operation;
       
  1764 	}
       
  1765 
       
  1766 EXPORT_C CMsvOperation* CMsvEntry::CopyL(TMsvId aMsvId, TMsvId aTargetId, TRequestStatus& aStatus)
       
  1767 //
       
  1768 // Copy a single entry to another parent
       
  1769 //
       
  1770 /** Creates, asynchronously, a copy of a child of the context as a new entry owned by the specified 
       
  1771 target ID.
       
  1772 
       
  1773 All descendants will be copied as well. Any files and stores associated with 
       
  1774 the entry are also copied.
       
  1775 
       
  1776 The returned CMsvOperation object completes when copying is complete.
       
  1777 
       
  1778 @param aMsvId The ID of the entry to be copied 
       
  1779 @param aTargetId The ID of the entry to own the copy 
       
  1780 @param aStatus The request status to be completed when the operation has finished 
       
  1781 
       
  1782 @leave KErrNoMemory The operation could not be created or passed to the server 
       
  1783 @leave KErrNotFound An entry was not a child of the context 
       
  1784 @return The operation object controlling the copy command. */
       
  1785 	{
       
  1786 #ifndef _NO_SESSION_LOGGING_
       
  1787 	Log(_L("Asynchronous CopyL of entry %x to %x"), aMsvId, aTargetId); 
       
  1788 #endif
       
  1789 
       
  1790 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1791 	CleanupStack::PushL(selection);
       
  1792 	selection->AppendL(aMsvId);
       
  1793 	CMsvOperation* operation = CopyL(*selection, aTargetId, aStatus);
       
  1794 	CleanupStack::PopAndDestroy(); // selection
       
  1795 	return operation;
       
  1796 	}
       
  1797 
       
  1798 
       
  1799 TInt CMsvEntry::CopyOneL(TMsvId aMsvId, TMsvId aTargetId)
       
  1800 	{
       
  1801 
       
  1802 	CMsvEntryArray* newSortedChildren = NULL;
       
  1803 	CMsvClientEntry *toadd=NULL;
       
  1804 
       
  1805 	
       
  1806 	if(aTargetId==iEntryPtr->Id())
       
  1807 		{
       
  1808 		const TMsvEntry &entry=ChildDataL(aMsvId);
       
  1809 		if (entry.Visible() || iOrdering.ShowInvisibleEntries())
       
  1810 			{
       
  1811 			// Create what may be the new child entry if nothing goes wrong
       
  1812 			toadd = CMsvClientEntry::NewLC(entry, EMsvClientChild);
       
  1813 
       
  1814 			// Reserve space for the new entry for later
       
  1815 			iEntries->SetReserveL(iEntries->Count() + 1);
       
  1816 
       
  1817 			newSortedChildren = CMsvEntryArray::NewLC(*iMtmList);
       
  1818 
       
  1819 			// add the children to the sorted pointer list - current context is the first entry
       
  1820 			TInt totalCount=iEntries->Count();
       
  1821 			for (TInt count=1; count<totalCount; count++)
       
  1822 				newSortedChildren->AppendL(&iEntries->At(count)->Entry());
       
  1823 
       
  1824 			// We've created a new sorted child list now so we won't leave later
       
  1825 			newSortedChildren->AppendL(&toadd->Entry());
       
  1826 			newSortedChildren->SortL(iOrdering);
       
  1827 			}
       
  1828 		}
       
  1829 
       
  1830 	CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
       
  1831 	CleanupStack::PushL(selection);
       
  1832 	selection->AppendL(aMsvId);
       
  1833 	TInt opid = iMsvSession.OperationId();
       
  1834 	iMsvSession.Session().CopyEntriesL(*selection, aTargetId, opid);
       
  1835 
       
  1836 	TMsvLocalOperationProgress progress;
       
  1837 	TPckg<TMsvLocalOperationProgress> progressPack(progress);
       
  1838     User::LeaveIfError(iMsvSession.Session().OperationCompletion(opid, progressPack));
       
  1839 
       
  1840 	CleanupStack::PopAndDestroy(selection);
       
  1841 
       
  1842 	// can't leave after this point
       
  1843 	if(newSortedChildren!=NULL) CleanupStack::Pop(newSortedChildren);
       
  1844 	if(toadd!=NULL) CleanupStack::Pop(toadd);
       
  1845 	if(newSortedChildren!=NULL && progress.iError==KErrNone)
       
  1846 		{
       
  1847 		delete iSortedChildren;
       
  1848 		iSortedChildren=newSortedChildren;
       
  1849 		newSortedChildren=NULL;
       
  1850 		toadd->SetId(progress.iId);
       
  1851 		// Will not leave because we've reserved space earlier
       
  1852 		iEntries->AppendL(toadd);
       
  1853 		toadd=NULL;
       
  1854 		}
       
  1855 	delete newSortedChildren;
       
  1856 	delete toadd;
       
  1857 	return(progress.iError);
       
  1858 	}
       
  1859 
       
  1860 EXPORT_C void CMsvEntry::CopyL(TMsvId aMsvId, TMsvId aTargetId)
       
  1861 //
       
  1862 // Copy a single child to another parent (or duplicate)
       
  1863 //
       
  1864 /** Creates, synchronously, a copy of a child of the context as a new entry owned by the specified target ID.
       
  1865 
       
  1866 @param aMsvId The ID of the entry to be copied
       
  1867 @param aTargetId The ID of the entry to own the copy
       
  1868 */
       
  1869 	{	
       
  1870 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1871 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1872 #ifndef _NO_SESSION_LOGGING_
       
  1873 	Log(_L("Synchronous CopyL %x to %x"), aMsvId, aTargetId); 
       
  1874 #endif
       
  1875 	User::LeaveIfError(CopyOneL(aMsvId,aTargetId));
       
  1876 	}
       
  1877 
       
  1878 
       
  1879 /** Creates, synchronously. copies of children of the context as new entries owned by the specified 
       
  1880 target ID.
       
  1881 
       
  1882 All descendants will be copied as well. Any files and stores associated with 
       
  1883 the entries are also copied.
       
  1884 
       
  1885 @param aSelection List of IDs of the entries to be copied 
       
  1886 @param aTargetId The ID of the entry to own the copies 
       
  1887 @param aProgress On return, records the outcome of the copy 
       
  1888 
       
  1889 @leave KErrNoMemory 
       
  1890 @leave KErrNotFound An entry was not a child of the context 
       
  1891 */
       
  1892 EXPORT_C void CMsvEntry::CopyL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TMsvLocalOperationProgress& aProgress)
       
  1893 //
       
  1894 // Copy a selection to another parent (or duplicate)
       
  1895 //
       
  1896 	{
       
  1897 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1898 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1899 	__ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
  1900 
       
  1901 #ifndef _NO_SESSION_LOGGING_
       
  1902 	Log(_L("Synchronous CopyL with selection of %d entries to %x"), aSelection.Count(),aTargetId); 
       
  1903 #endif
       
  1904 
       
  1905 
       
  1906 	aProgress.iTotalNumberOfEntries=aSelection.Count();
       
  1907 	aProgress.iNumberCompleted=0;
       
  1908 	aProgress.iNumberRemaining=aProgress.iTotalNumberOfEntries;
       
  1909 	aProgress.iError=KErrNone;
       
  1910 
       
  1911 	TInt count=aProgress.iTotalNumberOfEntries;
       
  1912 	while(count--)
       
  1913 		{
       
  1914 		aProgress.iId=aSelection.At(count);
       
  1915 		TInt err=CopyOneL(aProgress.iId,aTargetId);
       
  1916 		aProgress.iNumberRemaining--;
       
  1917 		if(err==KErrNone)
       
  1918 			aProgress.iNumberCompleted++;
       
  1919 		else
       
  1920 			{
       
  1921 			aProgress.iError=err;
       
  1922 			aProgress.iNumberFailed++;
       
  1923 			}
       
  1924 		}
       
  1925 	}
       
  1926 
       
  1927 
       
  1928 
       
  1929 
       
  1930 
       
  1931 EXPORT_C void CMsvEntry::AddObserverL(MMsvEntryObserver& aObserver)
       
  1932 //
       
  1933 // Adds an observer to this entry
       
  1934 // If the function leaves, the observer was not appended
       
  1935 // 
       
  1936 /** Registers an observer for the object. 
       
  1937 
       
  1938 CMsvEntry objects can call back observer objects that implement the MMsvEntryObserver 
       
  1939 interface when certain events occur. Any number of observers can be registered.
       
  1940 
       
  1941 Observers are called primarily when the context changes state or contents. 
       
  1942 For details, see MMsvEntryObserver::TMsvEntryEvent.
       
  1943 
       
  1944 @param aObserver The observer to be registered for events 
       
  1945 @leave KErrNoMemory Not enough memory to register the observer */
       
  1946 	{
       
  1947 	if (iObservers==NULL)
       
  1948 		iObservers=new(ELeave) CArrayPtrFlat<MMsvEntryObserver> (KMsvEntryObserverArrayGranuality);
       
  1949 	iObservers->AppendL(&aObserver);
       
  1950 
       
  1951 #ifndef _NO_SESSION_LOGGING_
       
  1952 	Log(_L("Observer %d added"), iObservers->Count()); 
       
  1953 #endif
       
  1954 	}
       
  1955 
       
  1956 
       
  1957 EXPORT_C void CMsvEntry::RemoveObserver(MMsvEntryObserver& aObserver)
       
  1958 //
       
  1959 // Removes an observer of the entry
       
  1960 //
       
  1961 /** Unregisters an observer previously registered with AddObserverL(). 
       
  1962 
       
  1963 @param aObserver A reference to an observer to be unregistered for events */
       
  1964 	{
       
  1965 	__ASSERT_DEBUG(iObservers, PanicServer(EMsvEntryUnknownObserver));
       
  1966 	if (iObservers)
       
  1967 		{
       
  1968 		TInt count=iObservers->Count();
       
  1969 		while (count--)
       
  1970 			{
       
  1971 			if (iObservers->At(count)==&aObserver)
       
  1972 				{
       
  1973 #ifndef _NO_SESSION_LOGGING_
       
  1974 				Log(_L("Observer %d removed"), count + 1); 
       
  1975 #endif
       
  1976 				iObservers->Delete(count);
       
  1977 				if (iObservers->Count()==0)
       
  1978 					{
       
  1979 					delete iObservers;
       
  1980 					iObservers=NULL;
       
  1981 					}
       
  1982 				return;
       
  1983 				}
       
  1984 			}
       
  1985 		__ASSERT_DEBUG(count>=0, PanicServer(EMsvEntryUnknownObserver));
       
  1986 		}
       
  1987 	}
       
  1988 
       
  1989 
       
  1990 void CMsvEntry::NotifyAllObserversL(MMsvEntryObserver::TMsvEntryEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3)
       
  1991 //
       
  1992 // Notifies all observers of the event affecting the context
       
  1993 //
       
  1994 	{
       
  1995 	if (iObservers==NULL)
       
  1996 		return;
       
  1997 	TInt count=iObservers->Count();
       
  1998 	while (count--)
       
  1999 		iObservers->At(count)->HandleEntryEventL(aEvent,aArg1,aArg2,aArg3);	
       
  2000 	}
       
  2001 
       
  2002 
       
  2003 void CMsvEntry::HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3)
       
  2004 //
       
  2005 // Is informed of all the session events
       
  2006 // This are filtered to find the events relating to the context
       
  2007 //
       
  2008 	{
       
  2009 	// Check the notification sequence and ignore if neccessary
       
  2010 	if (iNotifySequence >= iMsvSession.iNotifySequence)
       
  2011 		{
       
  2012 #ifndef _NO_SESSION_LOGGING_
       
  2013 		Log(_L("Ignoring notification, %d >= %d"), iNotifySequence, iMsvSession.iNotifySequence); 
       
  2014 #endif
       
  2015 		return;
       
  2016 		}
       
  2017 
       
  2018 	switch (aEvent)
       
  2019 		{
       
  2020 		case EMsvEntriesChanged:
       
  2021 			{
       
  2022 			CMsvEntrySelection* selection = (CMsvEntrySelection*) aArg1;
       
  2023 			if (iEntryPtr->Id() == selection->At(0))
       
  2024 				ContextChangedL(MMsvEntryObserver::EMsvEntryChanged);
       
  2025 			else if (iEntryPtr->Id()==*(TMsvId*) aArg2)
       
  2026 				ChildrenChangedL(*selection);
       
  2027 			break;
       
  2028 			}
       
  2029 		case EMsvEntriesCreated:
       
  2030 			if (*(TMsvId*) aArg2==iEntryPtr->Id())
       
  2031 				NewChildrenL(*(CMsvEntrySelection*) aArg1);
       
  2032 			else
       
  2033 				CheckNewGrandchildrenL(*(TMsvId*) aArg2);
       
  2034 			break;
       
  2035 		case EMsvEntriesDeleted:
       
  2036 			{
       
  2037 			CMsvEntrySelection* selection = (CMsvEntrySelection*) aArg1;
       
  2038 			if (*(TMsvId*) aArg2==iEntryPtr->Id())
       
  2039 				DeletedChildrenL(*selection);
       
  2040 			else
       
  2041 				{
       
  2042 				// check if we have been deleted
       
  2043 				TInt index=selection->Find(iEntryPtr->Id());
       
  2044 				if (index!=KErrNotFound)
       
  2045 					{
       
  2046 					iState = EInvalidDeletedContext;
       
  2047 					NotifyAllObserversL(MMsvEntryObserver::EMsvEntryDeleted, NULL, NULL, NULL);
       
  2048 					}
       
  2049 				else
       
  2050 					CheckDeletedGrandchildrenL(*(TMsvId*) aArg2);
       
  2051 				}
       
  2052 			break;
       
  2053 			}
       
  2054 		case EMsvEntriesMoved:
       
  2055 			if (*(TMsvId*) aArg3==iEntryPtr->Parent())
       
  2056 				CheckIfContextMovedL(*(CMsvEntrySelection*) aArg1);
       
  2057 			if (*(TMsvId*) aArg2==iEntryPtr->Id())
       
  2058 				NewChildrenL(*(CMsvEntrySelection*) aArg1);
       
  2059 			else if (*(TMsvId*) aArg3==iEntryPtr->Id())
       
  2060 				DeletedChildrenL(*(CMsvEntrySelection*) aArg1);
       
  2061 			else
       
  2062 				{
       
  2063 				CheckNewGrandchildrenL(*(TMsvId*) aArg2);
       
  2064 				CheckDeletedGrandchildrenL(*(TMsvId*) aArg3);
       
  2065 				}
       
  2066 			break;
       
  2067 		case EMsvMediaChanged:
       
  2068 			{
       
  2069 			TRAPD(error, HandleMediaChangeL());			
       
  2070 			if (error)
       
  2071 				{
       
  2072 				// An error occurred or this is a non standard entry
       
  2073 				// in which case the media has changed so this entry is not accessible
       
  2074 				// Just mark the entry as invalid - there is nothing else we can do!
       
  2075 				iState = EInvalidOldContext;
       
  2076 				NotifyAllObserversL(MMsvEntryObserver::EMsvContextInvalid, (TAny*)&error, NULL, NULL);
       
  2077 				}
       
  2078 			break;
       
  2079 			}
       
  2080 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2081 		case EMsvRefreshMessageView:
       
  2082 			{
       
  2083 			// A drive/disk has been added/removed.
       
  2084 			if(iEntryPtr->StandardFolder())
       
  2085 				{
       
  2086 				SetEntryNoCheckL(iEntryPtr->Id(), iChildrenOfAvailableDrives);
       
  2087 				}
       
  2088 			break;
       
  2089 			}
       
  2090 #endif
       
  2091 		default:
       
  2092 			break;
       
  2093 		}
       
  2094 	}
       
  2095 
       
  2096 void CMsvEntry::HandleMediaChangeL()
       
  2097 	{
       
  2098 	// If this is not a standard entry there is nothing we can do
       
  2099 	if (!iEntryPtr->StandardFolder())
       
  2100 		User::Leave(KMsvMediaChanged);
       
  2101 
       
  2102 	// This is a standard folder so it will exist on all media
       
  2103 	// Refresh the entry and child list - if this fails mark the entry as invalid
       
  2104 	// Otherwise the context will be told that everything has changed
       
  2105 	CMsvEntrySelection* oldChildren = new(ELeave)CMsvEntrySelection;
       
  2106 	CleanupStack::PushL(oldChildren);
       
  2107 
       
  2108 	// Get list of old children
       
  2109 	TInt count = iSortedChildren->Count();
       
  2110 	while(count--)
       
  2111 		oldChildren->AppendL(iSortedChildren->At(count)->Id());
       
  2112 
       
  2113 	// Refresh the context
       
  2114 	iState = EInvalidOldContext;
       
  2115 
       
  2116 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2117 	if(iChildrenOfAvailableDrives)
       
  2118 		{
       
  2119 		SetStandardFolderEntryL(iEntryPtr->Id());
       
  2120 		}
       
  2121 	else
       
  2122 #endif
       
  2123 		{
       
  2124 		SetEntryL(iEntryPtr->Id());
       
  2125 		}
       
  2126 	CMsvEntrySelection* newChildren = new(ELeave)CMsvEntrySelection;
       
  2127 	CleanupStack::PushL(newChildren);
       
  2128 
       
  2129 	// Get list of new children
       
  2130 	count = iSortedChildren->Count();
       
  2131 	while(count--)
       
  2132 		newChildren->AppendL(iSortedChildren->At(count)->Id());
       
  2133 
       
  2134 	// Tell the context about the children that have effectively been deleted and created
       
  2135 	if (oldChildren->Count())
       
  2136 		NotifyAllObserversL(MMsvEntryObserver::EMsvDeletedChildren, (TAny*)oldChildren, NULL, NULL);
       
  2137 	if (newChildren->Count())
       
  2138 		NotifyAllObserversL(MMsvEntryObserver::EMsvNewChildren, (TAny*)newChildren, NULL, NULL);
       
  2139 
       
  2140 	// Tell the context that it might have changed
       
  2141 	NotifyAllObserversL(MMsvEntryObserver::EMsvEntryChanged, NULL, NULL, NULL);
       
  2142 
       
  2143 	CleanupStack::PopAndDestroy(2); // newChildren, oldChildren
       
  2144 	}
       
  2145 
       
  2146 void CMsvEntry::CheckIfContextMovedL(const CMsvEntrySelection& aSelection)
       
  2147 //
       
  2148 // Some of the contexts parents children have moved, have to check if the context was one of them
       
  2149 //
       
  2150 	{
       
  2151 	TInt index=aSelection.Find(iEntryPtr->Id());
       
  2152 	if (index!=KErrNotFound)
       
  2153 		ContextChangedL(MMsvEntryObserver::EMsvEntryMoved);
       
  2154 	}
       
  2155 
       
  2156 
       
  2157 void CMsvEntry::ContextChangedL(MMsvEntryObserver::TMsvEntryEvent aEvent)
       
  2158 //
       
  2159 // The context has ben changed, spo we need to get the enw version
       
  2160 //
       
  2161 	{
       
  2162 #ifndef _NO_SESSION_LOGGING_
       
  2163 	Log(_L("Context changed")); 
       
  2164 #endif
       
  2165 
       
  2166 	if (iEntries->Count()>1 && iEntries->At(1)->Type()==EMsvClientChangedContext)
       
  2167 		{
       
  2168 		// we changed the entry, so get the new conext from the entry list
       
  2169 		// delete the old entry context (the new one is at position 1)
       
  2170 		delete iEntries->At(0);
       
  2171 		iEntries->Delete(0);
       
  2172 		}
       
  2173 	else
       
  2174 		{
       
  2175 		// someone else changed the context, so we have to update
       
  2176 		CMsvClientEntry* cEntry=NULL;
       
  2177 		TMsvId owningService=KMsvNullIndexEntryId;
       
  2178 		TRAPD(error, {cEntry = DoGetEntryLC(iEntryPtr->Id(), owningService); CleanupStack::Pop();});
       
  2179 		if (error==KErrNone)
       
  2180 			{
       
  2181 			if(iEntries->Count() != 0)
       
  2182 				{
       
  2183 				delete iEntries->At(0);
       
  2184 				iEntries->At(0) = cEntry;
       
  2185 				}
       
  2186 			else
       
  2187 				{
       
  2188 				iEntries->AppendL(cEntry); 	
       
  2189 				}
       
  2190 			iOwningService = owningService;
       
  2191 			}
       
  2192 		else
       
  2193 			{
       
  2194 			iState = EInvalidOldContext;
       
  2195 			NotifyAllObserversL(MMsvEntryObserver::EMsvContextInvalid, (TAny*)&error, NULL, NULL);
       
  2196 			return;
       
  2197 			}
       
  2198 		}
       
  2199 
       
  2200 	iEntries->At(0)->SetType(EMsvClientContext);
       
  2201 	iEntryPtr = &iEntries->At(0)->Entry();
       
  2202 	iState = EValid;
       
  2203 
       
  2204 	// notify all observers
       
  2205 	NotifyAllObserversL(aEvent, NULL, NULL, NULL);
       
  2206 	}
       
  2207 
       
  2208 
       
  2209 
       
  2210 void CMsvEntry::NewChildrenL(const CMsvEntrySelection& aSelection)
       
  2211 //
       
  2212 // New children have been created
       
  2213 //
       
  2214 	{
       
  2215 #ifndef _NO_SESSION_LOGGING_
       
  2216 	Log(_L("New children")); 
       
  2217 #endif
       
  2218 
       
  2219 	CMsvEntrySelection* newChildren = DoGetNewChildrenL(aSelection);
       
  2220 	CleanupStack::PushL(newChildren);
       
  2221 	if (newChildren->Count())
       
  2222 		{
       
  2223 		TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
       
  2224 		ptr->SetOwner(ETrue);
       
  2225 		NotifyAllObserversL(MMsvEntryObserver::EMsvNewChildren, (TAny*)newChildren, NULL, NULL);
       
  2226 		}
       
  2227 	CleanupStack::PopAndDestroy(); // newChildren
       
  2228 	}
       
  2229 
       
  2230 
       
  2231 CMsvEntrySelection* CMsvEntry::DoGetNewChildrenL(const CMsvEntrySelection& aSelection)
       
  2232 //
       
  2233 // New children have been created
       
  2234 //
       
  2235 	{
       
  2236 	CMsvEntrySelection* newChildren = aSelection.CopyLC();
       
  2237 	TInt count=aSelection.Count();
       
  2238 	while (count--)
       
  2239 		{
       
  2240 		// check if we already have this child
       
  2241 		if (IsAChild(aSelection.At(count)))
       
  2242 			{
       
  2243 			newChildren->Delete(count);
       
  2244 			continue;
       
  2245 			}
       
  2246 
       
  2247 		// get the new child data and add to to the list
       
  2248 		TMsvEntry tEntry;
       
  2249 		TMsvId service;
       
  2250 		TInt error=iMsvSession.Session().GetEntry(aSelection.At(count), service, tEntry);
       
  2251 		if(error!=KErrNotFound) User::LeaveIfError(error);
       
  2252 		
       
  2253 		if (error == KErrNone && (tEntry.Visible() || iOrdering.ShowInvisibleEntries()))
       
  2254 			{
       
  2255 			__ASSERT_DEBUG(service==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && service==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==(aSelection.At(count))), PanicServer(EMsvNewChildDifferentOwningService));
       
  2256 
       
  2257 			CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(tEntry, EMsvClientNull);
       
  2258 			cEntry->SetType(EMsvClientChild);
       
  2259 			iEntries->AppendL(cEntry);
       
  2260 			CleanupStack::Pop(); // cEntry
       
  2261 			// resort the children
       
  2262 			iSortedChildren->AppendL(&cEntry->Entry());
       
  2263 			}
       
  2264 		else
       
  2265 			newChildren->Delete(count);
       
  2266 		}
       
  2267 	
       
  2268 	if (newChildren->Count())
       
  2269 		iSortedChildren->SortL(iOrdering);
       
  2270 	CleanupStack::Pop(); // newChildren
       
  2271 	return newChildren;
       
  2272 	}
       
  2273 
       
  2274 
       
  2275 void CMsvEntry::CheckNewGrandchildrenL(TMsvId aId)
       
  2276 //
       
  2277 //
       
  2278 //
       
  2279 	{
       
  2280 	TInt count=iEntries->Count();
       
  2281 	while (count--)
       
  2282 		{
       
  2283 		if (iEntries->At(count)->Entry().Id()==aId && !iEntries->At(count)->Entry().Owner())
       
  2284 			{
       
  2285 			iEntries->At(count)->SetOwnerFlag(ETrue);
       
  2286 			NotifyChildChangedL(aId);
       
  2287 			break;
       
  2288 			}
       
  2289 		}
       
  2290 	}
       
  2291 
       
  2292 
       
  2293 void CMsvEntry::CheckDeletedGrandchildrenL(TMsvId aId)
       
  2294 //
       
  2295 //
       
  2296 //
       
  2297 	{
       
  2298 	TInt count=iEntries->Count();
       
  2299 	while (count--)
       
  2300 		{
       
  2301 		if (iEntries->At(count)->Entry().Id()==aId)
       
  2302 			{
       
  2303 			TMsvEntry entry;
       
  2304 			TMsvId service;
       
  2305 			TInt error = iMsvSession.Session().GetEntry(aId, service, entry);
       
  2306 			__ASSERT_DEBUG(error || service==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && service==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==aId), PanicServer(EMsvDeletedGrandChildDifferentOwningService));
       
  2307 			if (error)
       
  2308 				NotifyAllObserversL(MMsvEntryObserver::EMsvChildrenInvalid, (TAny*)&error, NULL, NULL);
       
  2309 			else if (!entry.Owner())
       
  2310 				{
       
  2311 				iEntries->At(count)->SetOwnerFlag(EFalse);
       
  2312 				NotifyChildChangedL(aId);
       
  2313 				}
       
  2314 			break;
       
  2315 			}
       
  2316 		}
       
  2317 	}
       
  2318 
       
  2319 
       
  2320 void CMsvEntry::NotifyChildChangedL(TMsvId aId)
       
  2321 //
       
  2322 //
       
  2323 //
       
  2324 	{
       
  2325 	CMsvEntrySelection* selection = DoMakeSelectionL(aId);
       
  2326 	CleanupStack::PushL(selection);
       
  2327 	NotifyAllObserversL(MMsvEntryObserver::EMsvChildrenChanged, (TAny*)selection, NULL, NULL);
       
  2328 	CleanupStack::PopAndDestroy(); // selection
       
  2329 	}
       
  2330 
       
  2331 
       
  2332 CMsvEntrySelection* CMsvEntry::DoMakeSelectionL(TMsvId aId)
       
  2333 //
       
  2334 //
       
  2335 //
       
  2336 	{
       
  2337 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  2338 	CleanupStack::PushL(selection);
       
  2339 	selection->AppendL(aId);
       
  2340 	CleanupStack::Pop(); // selection
       
  2341 	return selection;
       
  2342 	}
       
  2343 
       
  2344 
       
  2345 void CMsvEntry::ChildrenChangedL(const CMsvEntrySelection& aSelection)
       
  2346 //
       
  2347 // Children have been changed
       
  2348 //
       
  2349 	{
       
  2350 #ifndef _NO_SESSION_LOGGING_
       
  2351 	Log(_L("Children changed")); 
       
  2352 #endif
       
  2353 
       
  2354 	CMsvEntrySelection* changedChildren = new(ELeave) CMsvEntrySelection;
       
  2355 	CleanupStack::PushL(changedChildren);
       
  2356 	CMsvEntrySelection* newChildren = new(ELeave) CMsvEntrySelection;
       
  2357 	CleanupStack::PushL(newChildren);
       
  2358 	CMsvEntrySelection* deletedChildren = new(ELeave) CMsvEntrySelection;
       
  2359 	CleanupStack::PushL(deletedChildren);
       
  2360 
       
  2361 	TInt count=aSelection.Count();
       
  2362 	while (count--)
       
  2363 		{
       
  2364 		// get the changed child data
       
  2365 		TMsvId id = aSelection.At(count);
       
  2366 		TMsvEntry tEntry;
       
  2367 		TMsvId service;
       
  2368 
       
  2369 		// find the child in the sorted list
       
  2370 		TInt pos=iSortedChildren->Count();
       
  2371 		while (pos--)
       
  2372 			if (iSortedChildren->At(pos)->Id()==id)
       
  2373 				break;
       
  2374 
       
  2375 		TInt error = iMsvSession.Session().GetEntry(id, service, tEntry);
       
  2376 		if (error == KErrNotFound)
       
  2377 			{
       
  2378 			if (pos >= 0)
       
  2379 				{
       
  2380 				// The child has been deleted by the server
       
  2381 				DeleteChild(pos);
       
  2382 				deletedChildren->AppendL(id);
       
  2383 				}
       
  2384 			}
       
  2385 		else
       
  2386 			{
       
  2387 			User::LeaveIfError(error);
       
  2388 			__ASSERT_DEBUG(service==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && service==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==id), PanicServer(EMsvChangedChildHasDifferentOwningService));
       
  2389 
       
  2390 			if ( pos!=KErrNotFound  )
       
  2391 				{
       
  2392 				// replace it, if showing all children or its was and still is visible
       
  2393 				if (iOrdering.ShowInvisibleEntries() || tEntry.Visible())
       
  2394 					{
       
  2395 					ReplaceChildL(pos, tEntry);
       
  2396 					changedChildren->AppendL(id);
       
  2397 					continue;
       
  2398 					}
       
  2399 				}
       
  2400 
       
  2401 			if ( pos==KErrNotFound )
       
  2402 				{
       
  2403 				if (tEntry.Visible())
       
  2404 					{
       
  2405 					// the child has just been made visible so add it to our sorted list
       
  2406 					CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(tEntry, EMsvClientChild);
       
  2407 					iEntries->AppendL(cEntry);
       
  2408 					CleanupStack::Pop(); // cEntry
       
  2409 					iSortedChildren->AppendL(&cEntry->Entry());
       
  2410 					newChildren->AppendL(id);		
       
  2411 					}				
       
  2412 				}
       
  2413 			else if (!tEntry.Visible())
       
  2414 				{
       
  2415 				DeleteChild(pos);
       
  2416 				deletedChildren->AppendL(id);
       
  2417 				}
       
  2418 			}
       
  2419 		}
       
  2420 	
       
  2421 	// resort the children
       
  2422 	if (changedChildren->Count() || newChildren->Count() || deletedChildren->Count())
       
  2423 		{
       
  2424 		iSortedChildren->SortL(iOrdering);
       
  2425 		// notify the observers
       
  2426 		if (changedChildren->Count())
       
  2427 			NotifyAllObserversL(MMsvEntryObserver::EMsvChildrenChanged, (TAny*)changedChildren, NULL, NULL);
       
  2428 		if (newChildren->Count())
       
  2429 			NotifyAllObserversL(MMsvEntryObserver::EMsvNewChildren, (TAny*)newChildren, NULL, NULL);
       
  2430 		if (deletedChildren->Count())
       
  2431 			NotifyAllObserversL(MMsvEntryObserver::EMsvDeletedChildren, (TAny*)deletedChildren, NULL, NULL);
       
  2432 		}
       
  2433 
       
  2434 	CleanupStack::PopAndDestroy(3); // changedChildren, newChildren, deletedChildren
       
  2435 	}
       
  2436 
       
  2437 void CMsvEntry::DeleteChild(TInt aPosition)
       
  2438 	{
       
  2439 	TMsvId id = iSortedChildren->At(aPosition)->Id();
       
  2440 	iSortedChildren->Delete(aPosition);
       
  2441 	TInt ii=iEntries->Count();
       
  2442 	while (ii--)
       
  2443 		if (iEntries->At(ii)->Entry().Id()==id)
       
  2444 			{
       
  2445 			__ASSERT_DEBUG(iEntries->At(ii)->Type()==EMsvClientChild, PanicServer(EMsvNonChildDeleted));
       
  2446 			delete iEntries->At(ii);
       
  2447 			iEntries->Delete(ii);
       
  2448 			break;
       
  2449 			}
       
  2450 	__ASSERT_DEBUG(ii!=KErrNotFound, PanicServer(EMsvChangedChildNotFound1));
       
  2451 	}
       
  2452 
       
  2453 void CMsvEntry::ReplaceChildL(TInt aPosition, const TMsvEntry& aEntry)
       
  2454 //
       
  2455 //
       
  2456 //
       
  2457 	{
       
  2458 	CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(aEntry, EMsvClientChild);
       
  2459 			
       
  2460 	TInt ii=iEntries->Count();
       
  2461 	while (ii--)
       
  2462 		{
       
  2463 		if (iEntries->At(ii)->Entry().Id()==aEntry.Id())
       
  2464 			{
       
  2465 			__ASSERT_DEBUG(iEntries->At(ii)->Type()==EMsvClientChild, PanicServer(EMsvNonChildDeleted));
       
  2466 			delete iEntries->At(ii);
       
  2467 			iEntries->At(ii) = cEntry;
       
  2468 			iSortedChildren->At(aPosition) = &cEntry->Entry();
       
  2469 			break;
       
  2470 			}
       
  2471 		}
       
  2472 	__ASSERT_DEBUG(ii!=KErrNotFound, PanicServer(EMsvChangedChildNotFound1));
       
  2473 
       
  2474 	CleanupStack::Pop(); // cEntry
       
  2475 	}
       
  2476 
       
  2477 
       
  2478 
       
  2479 void CMsvEntry::DeletedChildrenL(const CMsvEntrySelection& aSelection)
       
  2480 //
       
  2481 // Some of the children have been deleted
       
  2482 //
       
  2483 	{
       
  2484 #ifndef _NO_SESSION_LOGGING_
       
  2485 	Log(_L("Deleted children")); 
       
  2486 #endif
       
  2487 
       
  2488 	CMsvEntrySelection* deletedChildren = aSelection.CopyL();
       
  2489 	CleanupStack::PushL(deletedChildren);
       
  2490 
       
  2491 	TInt count=aSelection.Count();
       
  2492 	while (count--)
       
  2493 		{
       
  2494 		TMsvId id = aSelection.At(count);
       
  2495 		TInt ii=iSortedChildren->Count();
       
  2496 		while (ii--)
       
  2497 			{
       
  2498 			if (iSortedChildren->At(ii)->Id()==id)
       
  2499 				{
       
  2500 				iSortedChildren->Delete(ii);
       
  2501 				break;
       
  2502 				}
       
  2503 			}
       
  2504 		if (ii==KErrNotFound)
       
  2505 			deletedChildren->Delete(count);
       
  2506 		else
       
  2507 			{
       
  2508 			ii=iEntries->Count();
       
  2509 			while (ii--)
       
  2510 				{
       
  2511 				if (iEntries->At(ii)->Entry().Id()==id)
       
  2512 					{
       
  2513 					__ASSERT_DEBUG(iEntries->At(ii)->Type()==EMsvClientChild, PanicServer(EMsvNonChildDeleted));
       
  2514 					delete iEntries->At(ii);
       
  2515 					iEntries->Delete(ii);
       
  2516 					break;
       
  2517 					}
       
  2518 				__ASSERT_DEBUG(ii!=KErrNotFound, PanicServer(EMsvDeletedChildNotInMainList));
       
  2519 				}
       
  2520 			}
       
  2521 		}
       
  2522 
       
  2523 	// notify all observers
       
  2524 	if (deletedChildren->Count())
       
  2525 		{
       
  2526 		// reset the owner flag
       
  2527 		if (Count()==0)
       
  2528 			{
       
  2529 			TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
       
  2530 			ptr->SetOwner(EFalse);
       
  2531 			}
       
  2532 
       
  2533 		NotifyAllObserversL(MMsvEntryObserver::EMsvDeletedChildren, (TAny*)deletedChildren, NULL, NULL);
       
  2534 		}
       
  2535 
       
  2536 	CleanupStack::PopAndDestroy(); // deletedChildren
       
  2537 	}
       
  2538 
       
  2539 
       
  2540 CMsvEntryArray* CMsvEntry::GetNewSortedListL(const TMsvSelectionOrdering& aOrdering, const CArrayFix<TUid>& aMtmList)
       
  2541 //
       
  2542 // Gets a new sorted list for new order and mtm list
       
  2543 // The entries should have the correct visiblity
       
  2544 //
       
  2545 	{
       
  2546 	CMsvEntryArray* newSortedChildren = CMsvEntryArray::NewLC(aMtmList);
       
  2547 	if (iSortedChildren->Count())
       
  2548 		{
       
  2549 //		newSortedChildren->InsertL(0, &iSortedChildren->At(0), iSortedChildren->Count());
       
  2550 //		newSortedChildren->SortL(aOrdering);
       
  2551 		TInt count=1;
       
  2552 		if (iEntries->At(count)->Type()!=EMsvClientChild)
       
  2553 			count++;
       
  2554 		TInt totalCount=iEntries->Count();
       
  2555 		for (; count<totalCount; count++)
       
  2556 			newSortedChildren->AppendL(&iEntries->At(count)->Entry());
       
  2557 		newSortedChildren->SortL(aOrdering);
       
  2558 		}
       
  2559 	CleanupStack::Pop(); // newSortedChildren
       
  2560 	return newSortedChildren;
       
  2561 	}
       
  2562 
       
  2563 
       
  2564 EXPORT_C void CMsvEntry::SetSortTypeL(const TMsvSelectionOrdering& aOrdering)
       
  2565 //
       
  2566 // Sets the sort type
       
  2567 // If this leaves the sort type has not been changed
       
  2568 //
       
  2569 /** Sets the sort order that is used when listing children, for example with ChildrenL().
       
  2570 
       
  2571 If the function leaves, the sort order is unchanged.
       
  2572 
       
  2573 @param aOrdering Sort order to use 
       
  2574 @leave KErrNoMemory Insufficient memory to resort the entries */
       
  2575 	{
       
  2576 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  2577 
       
  2578 #ifndef _NO_SESSION_LOGGING_
       
  2579 		Log(_L("Sort order changed, sorting %x, invisible %d"), aOrdering.Sorting(), aOrdering.ShowInvisibleEntries()); 
       
  2580 #endif
       
  2581 
       
  2582 	if (aOrdering.ShowInvisibleEntries()==iOrdering.ShowInvisibleEntries())
       
  2583 		{
       
  2584 		// just resort the current list of children
       
  2585 		CMsvEntryArray* newSortedChildren = GetNewSortedListL(aOrdering, *iMtmList);
       
  2586 		delete iSortedChildren;
       
  2587 		iSortedChildren = newSortedChildren;
       
  2588 		iOrdering = aOrdering;
       
  2589 		}
       
  2590 	else if (!aOrdering.ShowInvisibleEntries())
       
  2591 		{
       
  2592 		// resort the current list
       
  2593 		CMsvEntryArray* newSortedChildren = GetNewSortedListL(aOrdering, *iMtmList);
       
  2594 		delete iSortedChildren;
       
  2595 		iSortedChildren = newSortedChildren;
       
  2596 		iOrdering = aOrdering;
       
  2597 		// remove the invisible entries from sort list
       
  2598 		TInt count = iSortedChildren->Count();
       
  2599 		while (count--)
       
  2600 			if (!iSortedChildren->At(count)->Visible())
       
  2601 				iSortedChildren->Delete(count);
       
  2602 		// remove the invisible children from main list
       
  2603 		count = iEntries->Count();
       
  2604 		while (count-->=1)
       
  2605 			if (!iEntries->At(count)->Entry().Visible())
       
  2606 			{
       
  2607 			delete iEntries->At(count);
       
  2608 			iEntries->Delete(count);
       
  2609 			}
       
  2610 		}
       
  2611 	else
       
  2612 		{
       
  2613 		// keep old variable
       
  2614 		CArrayPtrFlat<CMsvClientEntry>* oldEntries = iEntries;
       
  2615 		iEntries=NULL;
       
  2616 		CMsvEntryArray* oldSortedChildren = iSortedChildren;
       
  2617 		iSortedChildren=NULL;
       
  2618 		TMsvSelectionOrdering oldOrder = iOrdering;	
       
  2619 		
       
  2620 		iOrdering = aOrdering;
       
  2621 		TRAPD(leave, DoSortTypeL(oldEntries->At(0)));
       
  2622 
       
  2623 		if (leave)
       
  2624 			{
       
  2625 			// we left, the function may have created a new iEntries,
       
  2626 			// if iEntries has been created we need to delete all the elements
       
  2627 			// except the first one, that is used in the old list
       
  2628 			// then delete iEntries, and put back the old one.
       
  2629 
       
  2630 			if(iEntries!=NULL)
       
  2631 				{
       
  2632 				if(iEntries->Count()!=0) 
       
  2633 					iEntries->Delete(0);
       
  2634 				iEntries->ResetAndDestroy();
       
  2635 				delete iEntries;
       
  2636 				}
       
  2637 			iEntries = oldEntries;
       
  2638 
       
  2639 			// iSortedChildren doesn't own the children so just delete the new one.
       
  2640 			// and put the old one back.
       
  2641 			delete iSortedChildren;
       
  2642 			iSortedChildren = oldSortedChildren;
       
  2643 			iOrdering = oldOrder;
       
  2644 			User::Leave(leave);
       
  2645 			}
       
  2646 		else
       
  2647 			{
       
  2648 			oldEntries->Delete(0); // the object is used in new list
       
  2649 			oldEntries->ResetAndDestroy();
       
  2650 			delete oldEntries;
       
  2651 			delete oldSortedChildren;
       
  2652 			}
       
  2653 		}
       
  2654 	}
       
  2655 
       
  2656 
       
  2657 
       
  2658 void CMsvEntry::DoSortTypeL(CMsvClientEntry* aContext)
       
  2659 //
       
  2660 // 
       
  2661 //
       
  2662 	{
       
  2663 	iEntries = new(ELeave) CArrayPtrFlat<CMsvClientEntry>(KMsvClientEntryArrayGranuality);
       
  2664 	iEntries->AppendL(aContext);
       
  2665 
       
  2666 	iSortedChildren = CMsvEntryArray::NewL(*iMtmList);
       
  2667 
       
  2668 	DoGetChildrenL();
       
  2669 	}
       
  2670 
       
  2671 
       
  2672 
       
  2673 EXPORT_C void CMsvEntry::SetMtmListL(const CArrayFix<TUid>& aMtmList)
       
  2674 //
       
  2675 // Sets the mtm list
       
  2676 // If this leaves the mtm list has not been changed
       
  2677 //
       
  2678 /** Sets the MTM order to the specified sort order. When children of an entry are 
       
  2679 sorted, entries belonging to the same MTM type can be grouped together. 
       
  2680 
       
  2681 MTM grouping can be switched on or off through setting the appropriate TMsvSelectionOrdering 
       
  2682 value by SetSortTypeL(). 
       
  2683 
       
  2684 If the function leaves, the sort order is unchanged.
       
  2685 
       
  2686 @param aMtmList The order of MTMs to use for sorting 
       
  2687 @leave KErrNoMemory Insufficient memory to resort the entries */
       
  2688 	{
       
  2689 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  2690 
       
  2691 	// create new mtm list
       
  2692 	CArrayFixFlat<TUid>* mtmList = new(ELeave)CArrayFixFlat<TUid>(KMsvMtmListGranularity);
       
  2693 	CleanupStack::PushL(mtmList);
       
  2694 	mtmList->InsertL(0, &aMtmList.At(0), aMtmList.Count());
       
  2695 
       
  2696 	// create new sorted children list
       
  2697 	CMsvEntryArray* newSortedChildren = GetNewSortedListL(iOrdering, *mtmList);
       
  2698 	
       
  2699 	// install the new sorted children array
       
  2700 	delete iSortedChildren;
       
  2701 	delete iMtmList;
       
  2702 	iSortedChildren = newSortedChildren;
       
  2703 	iMtmList = mtmList;
       
  2704 	
       
  2705 	CleanupStack::Pop(); // mtmList
       
  2706 	}
       
  2707 
       
  2708 
       
  2709 TBool CMsvEntry::IsAChild(TMsvId aId) const
       
  2710 //
       
  2711 // Returns true if the entry is a child
       
  2712 //
       
  2713 	{
       
  2714 	TInt count=iSortedChildren->Count();
       
  2715 	while (count--)
       
  2716 		{
       
  2717 		if (iSortedChildren->At(count)->Id()==aId)
       
  2718 			return ETrue;
       
  2719 		}
       
  2720 	return EFalse;
       
  2721 	}
       
  2722 
       
  2723 TBool CMsvEntry::AreChildren(const CMsvEntrySelection& aSelection) const
       
  2724 //
       
  2725 // Returns true if all the entries are children
       
  2726 //
       
  2727 	{
       
  2728 	TInt count = aSelection.Count();
       
  2729 	while (count--)
       
  2730 		{
       
  2731 		if (!IsAChild(aSelection.At(count)))
       
  2732 			{
       
  2733 			return EFalse;
       
  2734 			}
       
  2735 		}
       
  2736 	return ETrue;
       
  2737 	}
       
  2738 
       
  2739 
       
  2740 EXPORT_C TBool CMsvEntry::HasStoreL() const
       
  2741 /** Checks if the context has an associated message store.
       
  2742 
       
  2743 @return ETrue: entry has a message store EFalse: entry does not have a message 
       
  2744 store */
       
  2745 	{
       
  2746 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
       
  2747 	if(iMsvSession.StoreManager().DoesAnyStoreExists(iEntryPtr->Id(), this->Entry().iMtm))
       
  2748 		return ETrue;
       
  2749 	else
       
  2750 		return iMsvSession.StoreManager().FileStoreExistsL(iEntryPtr->Id());
       
  2751 #else
       
  2752 	return iMsvSession.StoreManager().FileStoreExistsL(iEntryPtr->Id());
       
  2753 #endif
       
  2754 	}
       
  2755 
       
  2756 /** Sets or clears multiple fields in a selection of children of the context.
       
  2757 
       
  2758 Fields to change are specified using a bitmask of TMsvAttribute values. Possible 
       
  2759 fields that can be changed using this function are the PC synchronisation, Visibility, 
       
  2760 Pending Deletion, Read, In-preparation, Connected, and New flags. 
       
  2761 
       
  2762 @param aSelection The entries to change
       
  2763 @param aSetAttributes A bitmask of the fields to set
       
  2764 @param aClearAttributes A bitmask of the fields to clear
       
  2765 @leave KErrNotFound An entry was not a child of the context
       
  2766 @see CMsvSession::ChangeAttributesL() 
       
  2767 */
       
  2768 EXPORT_C void CMsvEntry::ChangeAttributesL(const CMsvEntrySelection& aSelection, TUint aSetAttributes, TUint aClearAttributes)
       
  2769 	{
       
  2770 #ifndef _NO_SESSION_LOGGING_
       
  2771 	Log(_L("ChangeAttributesL")); 
       
  2772 #endif
       
  2773 
       
  2774 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  2775 	__ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
  2776 
       
  2777 	if (!AreChildren(aSelection))
       
  2778 		User::Leave(KErrNotFound);
       
  2779 
       
  2780 	iMsvSession.Session().ChangeAttributesL(aSelection, aSetAttributes, aClearAttributes);
       
  2781 	}
       
  2782