messagingfw/msgsrvnstore/server/src/MCLENTRY.CPP
changeset 62 db3f5fa34ec7
equal deleted inserted replaced
60:9f5ae1728557 62:db3f5fa34ec7
       
     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 Update a selection of children to read or Unread asynchronously of the context. 
       
   925 The returned CMsvOperation object .
       
   926 
       
   927 @param	aSelection 
       
   928 The selectio of entry values for the context
       
   929 
       
   930 @param	aMark 
       
   931 True : Update selection to UnRead .
       
   932 False: Update selection to Read . 
       
   933 
       
   934 @param aStatus The request status to be completed when the operation has finished .
       
   935 
       
   936 @leave KErrAccessDenied The entry is locked by another client 
       
   937 
       
   938 @return
       
   939 An operation object controlling the change command
       
   940 */
       
   941 EXPORT_C CMsvOperation* CMsvEntry::ChangeL(const CMsvEntrySelection& aSelection,TBool aMark, TRequestStatus& aStatus)
       
   942      {
       
   943 #ifndef _NO_SESSION_LOGGING_
       
   944     Log(_L("Asynchronous ChangeL with selection of %d entries"), aSelection.Count()); 
       
   945 #endif
       
   946 
       
   947     __ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
   948 
       
   949 #if defined(_DEBUG)    
       
   950      
       
   951       TInt aCount = aSelection.Count();
       
   952       while (aCount--)
       
   953           {
       
   954           TMsvEntry aEntry;
       
   955           TMsvId aService;
       
   956           if (iMsvSession.Session().GetEntry(aSelection.At(aCount), aService, aEntry)==KErrNone)
       
   957               {
       
   958               __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext, PanicServer(EMsvEntryAlreadyChangingContext));
       
   959               __ASSERT_DEBUG(MsvUtils::ValidEntry(aEntry), PanicServer(EMsvChangingToInvalidEntry));
       
   960              
       
   961               // can only change the current context
       
   962               if (!MsvUtils::ValidEntry(aEntry))
       
   963                   User::Leave(KErrArgument);
       
   964               }
       
   965            }
       
   966 #endif
       
   967       // cannot change standard folders
       
   968       if (iEntryPtr->StandardFolder())
       
   969           User::Leave(KErrAccessDenied);
       
   970   
       
   971       //// create the operation
       
   972       CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
       
   973       CleanupStack::PushL(operation);
       
   974       User::LeaveIfError(iMsvSession.Session().OperationMtmL(aSelection.At(0), operation->iMtm, operation->iService)); 
       
   975    
       
   976       // start the change operation
       
   977 	  iMsvSession.Session().ChangeEntriesL(aSelection, aMark, operation->Id(), RProcess().SecureId(), operation->iStatus);
       
   978      
       
   979       operation->Start();
       
   980       iState = EInvalidChangingContext;
       
   981       CleanupStack::Pop(1); // operation 
       
   982       return operation; 
       
   983       }
       
   984 
       
   985 
       
   986 EXPORT_C CMsvOperation* CMsvEntry::DeleteL(TMsvId aId, TRequestStatus& aStatus)
       
   987 //
       
   988 // Deletes a child of the context
       
   989 //
       
   990 	/** Deletes a child entry of the context asynchronously.
       
   991 	
       
   992 	The delete works recursively through all the descendants. If a child or any 
       
   993 	descendant is locked by another client or any store or file is open, then 
       
   994 	that child will not be deleted. Any files and stores associated with the entry 
       
   995 	are deleted.
       
   996 	
       
   997 	The returned CMsvOperation object completes when deletion is complete.
       
   998 	
       
   999 	
       
  1000 	@param aId ID of entry to be deleted 
       
  1001 	@param aStatus The request status to be completed when the operation has finished 
       
  1002 	
       
  1003 	@leave KErrNotFound The specified entry was not a child of the context 
       
  1004 	@leave KErrNotSupported If deleting entries from non-current drive
       
  1005 	@return The operation object controlling the deletion command */
       
  1006 	{
       
  1007 #ifndef _NO_SESSION_LOGGING_
       
  1008 	Log(_L("Asynchronous DeleteL, entry %x"), aId); 
       
  1009 #endif
       
  1010 
       
  1011 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1012 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1013 	CleanupStack::PushL(selection);
       
  1014 	selection->AppendL(aId);
       
  1015 	CMsvOperation* operation = DoDeleteL(*selection, aStatus);
       
  1016 	CleanupStack::PopAndDestroy(); // selection
       
  1017 	return operation;
       
  1018 	}
       
  1019 
       
  1020 
       
  1021 
       
  1022 EXPORT_C CMsvOperation* CMsvEntry::DeleteL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
       
  1023 //
       
  1024 // Deletes a selection containing children of the context
       
  1025 //
       
  1026 /** Deletes child entries of the context asynchronously. 
       
  1027 
       
  1028 The delete works recursively through all the descendants. If a child or any 
       
  1029 descendant is locked by another client or any store or file is open, then 
       
  1030 that child will not be deleted. Any files and stores associated with the entries 
       
  1031 are deleted.
       
  1032 
       
  1033 The returned CMsvOperation object completes when deletion is complete.
       
  1034 
       
  1035 @param aSelection List of ID of the entries to be deleted 
       
  1036 @param aStatus The request status to be completed when the operation has finished 
       
  1037 
       
  1038 @leave KErrNotFound A specified entry was not a child of the context 
       
  1039 @leave KErrNotSupported If deleting entries from non-current drive
       
  1040 @return The operation object controlling the deletion command */
       
  1041 	{
       
  1042 #ifndef _NO_SESSION_LOGGING_
       
  1043 	Log(_L("Asynchronous DeleteL with selection of %d entries"), aSelection.Count()); 
       
  1044 #endif
       
  1045 
       
  1046 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1047 	return DoDeleteL(aSelection, aStatus);
       
  1048 	}
       
  1049 
       
  1050 
       
  1051 
       
  1052 CMsvOperation* CMsvEntry::DoDeleteL(const CMsvEntrySelection& aSelection, TRequestStatus& aStatus)
       
  1053 //
       
  1054 //
       
  1055 //
       
  1056 	{
       
  1057 	__ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
  1058 	
       
  1059 	if (!AreChildren(aSelection))
       
  1060 		User::Leave(KErrNotFound);
       
  1061 
       
  1062 	CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
       
  1063 	CleanupStack::PushL(operation);
       
  1064 	if (iEntryPtr->iType==KUidMsvRootEntry)
       
  1065 		{
       
  1066 		// we must be deleting services - so it is a local operation
       
  1067 		operation->iMtm = KUidMsvLocalServiceMtm;
       
  1068 		operation->iService = KMsvLocalServiceIndexEntryId;
       
  1069 		}
       
  1070 	else
       
  1071 		User::LeaveIfError(iMsvSession.Session().OperationMtmL(aSelection.At(0), operation->iMtm, operation->iService));
       
  1072 
       
  1073 #if defined(_DEBUG)
       
  1074 	// check other entries in selection are consistent and are not read only
       
  1075 	TInt dCount = aSelection.Count();
       
  1076 	while (dCount--)
       
  1077 		{
       
  1078 		if (iEntryPtr->iType!=KUidMsvRootEntry)
       
  1079 			{
       
  1080 				TMsvId service;
       
  1081 				TUid mtm;
       
  1082 				TInt error = iMsvSession.Session().OperationMtmL(aSelection.At(dCount), mtm, service);
       
  1083 				__ASSERT_DEBUG(error==KErrNone || error==KErrNotFound, PanicServer(EMsvNonConsistentDeleteSelection));
       
  1084 				__ASSERT_DEBUG(mtm==operation->iMtm, PanicServer(EMsvNonConsistentDeleteSelection));
       
  1085 				__ASSERT_DEBUG(service==operation->iService, PanicServer(EMsvNonConsistentDeleteSelection));
       
  1086 			}
       
  1087 		TMsvEntry dEntry;
       
  1088 		TMsvId dService;
       
  1089 		if (iMsvSession.Session().GetEntry(aSelection.At(dCount), dService, dEntry)==KErrNone)
       
  1090 			{
       
  1091 			__ASSERT_DEBUG(dService==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && dService==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && dService==aSelection.At(dCount)), PanicServer(EMsvDeletingEntryDifferentOwningService));
       
  1092 			}
       
  1093 		}
       
  1094 #endif
       
  1095 	
       
  1096 	iMsvSession.Session().DeleteEntriesL(aSelection, operation->Id(), operation->iStatus);
       
  1097 	operation->Start();
       
  1098 	CleanupStack::Pop(); // operation
       
  1099 	return operation;
       
  1100 	}
       
  1101 
       
  1102 EXPORT_C void CMsvEntry::DeleteL(TMsvId aId)
       
  1103 /** Deletes a child entry of the context synchronously. 
       
  1104 
       
  1105 The delete works recursively through all the descendants. If a child or any descendant is locked by another 
       
  1106 client or any store or file is open, then that child will not be deleted. Any files and stores associated 
       
  1107 with the entry are deleted.
       
  1108 
       
  1109 This function can only be used on local entries.
       
  1110 
       
  1111 @param aId ID of entry to be deleted
       
  1112 @leave KErrNotFound The specified entry was not a child of the context
       
  1113 @leave KErrNotSupported If deleting entries from non-current drive
       
  1114 */
       
  1115 	{
       
  1116 #ifndef _NO_SESSION_LOGGING_
       
  1117 	Log(_L("Synchronous DeleteL, entry %x"), aId); 
       
  1118 #endif
       
  1119 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1120 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1121 	
       
  1122 	User::LeaveIfError(CMsvEntry::DeleteOneL(aId));
       
  1123 	}
       
  1124 
       
  1125 EXPORT_C void CMsvEntry::DeleteL(const CMsvEntrySelection& aSelection, TMsvLocalOperationProgress& aProgress)
       
  1126 /** Deletes child entries of the context synchronously. 
       
  1127 
       
  1128 The delete works recursively through all the descendants. If a child or any 
       
  1129 descendant is locked by another client or any store or file is open, then 
       
  1130 that child will not be deleted. Any files and stores associated with the entries 
       
  1131 are deleted.
       
  1132 
       
  1133 @param aSelection List of ID of the entries to be deleted 
       
  1134 @param aProgress Progress information for the delete operation
       
  1135 @leave KErrNotFound A specified entry was not a child of the context 
       
  1136 @leave KErrNotSupported If deleting entries from non-current drive */
       
  1137 	{
       
  1138 #ifndef _NO_SESSION_LOGGING_
       
  1139 	Log(_L("Synchronous DeleteL with selection of %d entries"), aSelection.Count()); 
       
  1140 #endif
       
  1141 
       
  1142 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1143 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1144 	__ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
  1145 
       
  1146 	if (!AreChildren(aSelection))
       
  1147 		User::Leave(KErrNotFound);
       
  1148 
       
  1149 	aProgress.iTotalNumberOfEntries=aSelection.Count();
       
  1150 	aProgress.iNumberCompleted=0;
       
  1151 	aProgress.iNumberRemaining=aProgress.iTotalNumberOfEntries;
       
  1152 	aProgress.iError=KErrNone;
       
  1153 
       
  1154 	TInt count=aProgress.iTotalNumberOfEntries;
       
  1155 	while(count--)
       
  1156 		{
       
  1157 		aProgress.iId=aSelection.At(count);
       
  1158 		TInt err=DeleteOneL(aProgress.iId);
       
  1159 		aProgress.iNumberRemaining--;
       
  1160 		if(err==KErrNone)
       
  1161 			aProgress.iNumberCompleted++;
       
  1162 		else
       
  1163 			{
       
  1164 			aProgress.iError=err;
       
  1165 			aProgress.iNumberFailed++;
       
  1166 			}
       
  1167 		}
       
  1168 	}
       
  1169 
       
  1170 
       
  1171 TInt CMsvEntry::DeleteOneL(TMsvId aMsvId)
       
  1172 	{
       
  1173 	CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
       
  1174 	CleanupStack::PushL(selection);
       
  1175 	selection->AppendL(aMsvId);
       
  1176 	TInt opid = iMsvSession.OperationId();
       
  1177 	iMsvSession.Session().DeleteEntriesL(*selection, opid);
       
  1178 
       
  1179 	TMsvLocalOperationProgress progress;
       
  1180 	TPckg<TMsvLocalOperationProgress> progressPack(progress);
       
  1181     User::LeaveIfError(iMsvSession.Session().OperationCompletion(opid, progressPack));
       
  1182 	
       
  1183 	if(progress.iError==KErrNone)
       
  1184 		{
       
  1185 		TMsvId id = selection->At(0);
       
  1186 		TInt ii = iSortedChildren->Count();
       
  1187 		while (ii--)
       
  1188 			{
       
  1189 			if (iSortedChildren->At(ii)->Id() == id)
       
  1190 				{
       
  1191 				iSortedChildren->Delete(ii);
       
  1192 				break;
       
  1193 				}
       
  1194 			}
       
  1195 
       
  1196 		ii = iEntries->Count();
       
  1197 		while (ii--)
       
  1198 			{
       
  1199 			if (iEntries->At(ii)->Entry().Id() == id)
       
  1200 				{
       
  1201 				delete iEntries->At(ii);
       
  1202 				iEntries->Delete(ii);
       
  1203 				break;
       
  1204 				}
       
  1205 			}
       
  1206 		// Reset the owner flag
       
  1207 		if (Count() == 0)
       
  1208 			{
       
  1209 			TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
       
  1210 			ptr->SetOwner(EFalse);
       
  1211 			}		
       
  1212 		}
       
  1213 	CleanupStack::PopAndDestroy(selection);
       
  1214 	return(progress.iError);
       
  1215 	}
       
  1216 
       
  1217 
       
  1218 
       
  1219 
       
  1220 EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenL() const
       
  1221 //
       
  1222 // Gets a selection containing the children of the context
       
  1223 //
       
  1224 /** Gets a selection containing the IDs of all the context children. If the entry 
       
  1225 has no children, the selection is empty.
       
  1226 
       
  1227 The calling function is responsible for the deletion of the returned CMsvEntrySelection. 
       
  1228 
       
  1229 @leave KErrNoMemory Not enough memory to create the selection 
       
  1230 @return A selection containing the ID of all children of the context */
       
  1231 	{
       
  1232 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1233 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1234 	CleanupStack::PushL(selection);
       
  1235 	TInt totalCount=iSortedChildren->Count();
       
  1236 	for (TInt count=0; count<totalCount; count++)
       
  1237 		{
       
  1238 		selection->AppendL(iSortedChildren->At(count)->Id());
       
  1239 		}
       
  1240 	CleanupStack::Pop(); // selection
       
  1241 	return selection;
       
  1242 	}
       
  1243 
       
  1244 EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenWithServiceL(TMsvId aServiceId) const
       
  1245 //
       
  1246 // Gets a selection containing the children of the context which use the service
       
  1247 //
       
  1248 /** Gets a selection containing the IDs of all the context children filtered by message service.
       
  1249 i.e. the index entry's iServiceId field equals aId.
       
  1250 
       
  1251 If the entry has no such children, the selection is empty.
       
  1252 
       
  1253 The calling function is responsible for the deletion of the returned CMsvEntrySelection.
       
  1254 @return	List of IDs of all children of the context meeting the criterion		
       
  1255 @param aServiceId Service by which to filter
       
  1256 @leave KErrNoMemory Not enough memory to create the selection 
       
  1257 */
       
  1258 	{
       
  1259 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1260 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1261 	CleanupStack::PushL(selection);
       
  1262 	TInt totalCount=iSortedChildren->Count();
       
  1263 	for (TInt count=0; count<totalCount; count++)
       
  1264 		{
       
  1265 		if (iSortedChildren->At(count)->iServiceId==aServiceId)
       
  1266 			{
       
  1267 			selection->AppendL(iSortedChildren->At(count)->Id());
       
  1268 			}
       
  1269 		}
       
  1270 	CleanupStack::Pop(); // selection
       
  1271 	return selection;
       
  1272 	}
       
  1273 
       
  1274 EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenWithMtmL(TUid aMtm) const
       
  1275 //
       
  1276 // Gets a selection containing the children of the context which use the same MTM
       
  1277 //
       
  1278 /** Gets a selection containing the IDs of all the context children filtered by 
       
  1279 MTM type. i.e. the index entry's iMtm field equals aMtm.
       
  1280 
       
  1281 If the entry has no such children, the selection is empty.
       
  1282 
       
  1283 The calling function is responsible for the deletion of the returned CMsvEntrySelection. 
       
  1284 
       
  1285 @param aMtm MTM type by which to filter 
       
  1286 @leave KErrNoMemory Not enough memory to create the selection 
       
  1287 @return A selection containing the ID of all children of the context meeting 
       
  1288 the criterion */
       
  1289 	{
       
  1290 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1291 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1292 	CleanupStack::PushL(selection);
       
  1293 	TInt totalCount=iSortedChildren->Count();
       
  1294 	for (TInt count=0; count<totalCount; count++)
       
  1295 		{
       
  1296 		if (iSortedChildren->At(count)->iMtm==aMtm)
       
  1297 			{
       
  1298 			selection->AppendL(iSortedChildren->At(count)->Id());
       
  1299 			}
       
  1300 		}
       
  1301 	CleanupStack::Pop(); // selection
       
  1302 	return selection;
       
  1303 	}
       
  1304 
       
  1305 EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenWithTypeL(TUid aType) const
       
  1306 //
       
  1307 // Gets a selection containing the children of the context which are the same type
       
  1308 //
       
  1309 /** Gets a selection containing the IDs of all the context children filtered by 
       
  1310 entry type. i.e. is the entry a folder, a message, etc.
       
  1311 
       
  1312 If the entry has no such children, the selection is empty.
       
  1313 
       
  1314 The calling function is responsible for the deletion of the returned CMsvEntrySelection. 
       
  1315 
       
  1316 
       
  1317 @param aType Entry type by which to filter. 
       
  1318 @leave KErrNoMemory Not enough memory to create the selection 
       
  1319 @return A selection containing the ID of all children of the context meeting 
       
  1320 the criterion */
       
  1321 	{
       
  1322 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1323 
       
  1324 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1325 	CleanupStack::PushL(selection);
       
  1326 	TInt totalCount=iSortedChildren->Count();
       
  1327 	for (TInt count=0; count<totalCount; count++)
       
  1328 		{
       
  1329 		if (iSortedChildren->At(count)->iType==aType)
       
  1330 			{
       
  1331 			selection->AppendL(iSortedChildren->At(count)->Id());
       
  1332 			}
       
  1333 		}
       
  1334 	CleanupStack::Pop(); // selection
       
  1335 	return selection;
       
  1336 	}
       
  1337 
       
  1338 
       
  1339 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1340 /**
       
  1341  * ChildrenOfAvailableDrivesL()
       
  1342  *
       
  1343  * @param None.
       
  1344  * @return CMsvEntrySelection List of child ids from all available drives.
       
  1345  * @leave KErrArgument If the function is used for a TMsvId other than that 
       
  1346  * of standard folders, i.e. Inbox, Outbox, Drafts, Sent or Deleted.
       
  1347  * @leave KErrNoMemory Not enough memory to create the selection.
       
  1348  * 
       
  1349  * Gets a selection containing the child Id's from all drives currently present
       
  1350  * in the server preferred drive list.
       
  1351  * The function must be used only if the context is set to one of the standard folders,
       
  1352  * i.e. Inbox, Outbox, Drafts, Sent or Deleted.
       
  1353  * 
       
  1354  * The calling function is responsible for the deletion of the returned CMsvEntrySelection.
       
  1355  *
       
  1356  @publishedAll
       
  1357  @released
       
  1358  */ 
       
  1359 EXPORT_C CMsvEntrySelection* CMsvEntry::ChildrenOfAvailableDrivesL() const
       
  1360     {
       
  1361     __ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1362 
       
  1363     if(!iChildrenOfAvailableDrives)
       
  1364         {
       
  1365 		User::Leave(KErrArgument);		
       
  1366 		}
       
  1367 
       
  1368     CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1369 	CleanupStack::PushL(selection);
       
  1370 
       
  1371     TInt totalCount = iSortedChildren->Count();
       
  1372 	for (TInt count=0; count<totalCount; count++)
       
  1373 		{
       
  1374 		selection->AppendL(iSortedChildren->At(count)->Id());
       
  1375 		}
       
  1376 	CleanupStack::Pop(); // selection
       
  1377 	return selection;
       
  1378 	}
       
  1379 #endif			// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1380 
       
  1381 	
       
  1382 
       
  1383 EXPORT_C const TMsvEntry& CMsvEntry::operator[](TInt aIndex) const
       
  1384 //
       
  1385 // Returns the data for a child, zero index with the current sort order
       
  1386 //
       
  1387 /** Gets the index entry of the child at the position specified by the array index. 
       
  1388 The child entries of the context can be considered as a zero-based array, 
       
  1389 with entries sorted according to the current sort order. 
       
  1390 
       
  1391 Note:
       
  1392 
       
  1393 The function panics with E32USER-CBase 21 if aIndex was out of range.
       
  1394 
       
  1395 @param aIndex Array index 
       
  1396 @return Index entry for the specified child. Valid for in-range values of aIndex. */
       
  1397 	{
       
  1398 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1399 	return *iSortedChildren->At(aIndex);
       
  1400 	}
       
  1401 
       
  1402 
       
  1403 EXPORT_C CMsvEntry* CMsvEntry::ChildEntryL(TMsvId aId) const
       
  1404 //
       
  1405 // Returns a new entry with the child as the context
       
  1406 //
       
  1407 /** Gets a new CMsvEntry object with its context set to the child entry ID. aMsvId 
       
  1408 must specify a child of the current context.
       
  1409 
       
  1410 The CMsvEntry object must be deleted by the client application when it is 
       
  1411 no longer required. 
       
  1412 
       
  1413 @param aId ID of a child entry 
       
  1414 @leave KErrNotFound aMsvId does not specify a child of the context 
       
  1415 @return CMsvEntry object with its context set to child entry */
       
  1416 	{
       
  1417 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1418 	if (!IsAChild(aId))
       
  1419 		User::Leave(KErrNotFound);
       
  1420 	return CMsvEntry::NewL(iMsvSession, aId, iOrdering);
       
  1421 	}
       
  1422 
       
  1423 
       
  1424 EXPORT_C const TMsvEntry& CMsvEntry::ChildDataL(TMsvId aId) const
       
  1425 //
       
  1426 // Returns the data for a child with the aId
       
  1427 //
       
  1428 /** Gets the index entry of context's child with the specified ID.
       
  1429 
       
  1430 @param aId ID of the child 
       
  1431 @leave KErrNotFound No child exists with that ID 
       
  1432 @return Index entry for the specified child. Valid for in-range values of aIndex. */
       
  1433 	{
       
  1434 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1435 
       
  1436 	TInt count=iSortedChildren->Count();
       
  1437 	while (count--)
       
  1438 		{
       
  1439 		if (iSortedChildren->At(count)->Id()==aId)
       
  1440 			break;
       
  1441 		}
       
  1442 	User::LeaveIfError(count); // will be -1 (KErrNotFound)
       
  1443 	return *iSortedChildren->At(count);
       
  1444 	}
       
  1445 
       
  1446 
       
  1447 EXPORT_C CMsvStore* CMsvEntry::ReadStoreL()
       
  1448 //
       
  1449 // Return store for the current context which is opened for read only
       
  1450 //
       
  1451 /** Obtains the message store for the current context with read-only access. 
       
  1452 
       
  1453 Multiple clients can read from a store simultaneously. If another client is already 
       
  1454 writing to the store, the function leaves with KErrAccessDenied. 
       
  1455 
       
  1456 The returned CMsvStore must be deleted when it is no longer required. 
       
  1457 
       
  1458 @leave KErrNoMemory Not enough memory to open store 
       
  1459 @leave KErrAccessDenied Another client is currently writing to the store 
       
  1460 @leave KErrNotFound There is no store associated with this entry 
       
  1461 @return Context's message store open for read-only access */
       
  1462 	{
       
  1463 #ifndef _NO_SESSION_LOGGING_
       
  1464 	Log(_L("ReadStoreL for entry %x"), iEntryPtr->Id()); 
       
  1465 #endif
       
  1466 
       
  1467 	__ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreAlreadyOpen));
       
  1468 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1469 	User::LeaveIfError(iMsvSession.Session().ReadStore(iEntryPtr->Id()));
       
  1470 
       
  1471 	// open the store
       
  1472 	TInt err =0;
       
  1473 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
       
  1474 		TRAP(err, iStore = CMsvStore::OpenForReadL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id(), this->Entry().iMtm));	
       
  1475 #else
       
  1476 		TRAP(err, iStore = CMsvStore::OpenForReadL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id()));			
       
  1477 #endif
       
  1478 	if (err != KErrNone)
       
  1479 		{
       
  1480 		iMsvSession.Session().DecStoreReaderCount(iEntryPtr->Id()); // error ignored
       
  1481 		User::Leave(err);
       
  1482 		}
       
  1483 	return iStore;
       
  1484 	}
       
  1485 
       
  1486 
       
  1487 EXPORT_C CMsvStore* CMsvEntry::EditStoreL()
       
  1488 //
       
  1489 // Return store for the current context which can be writen to
       
  1490 //
       
  1491 /** Gets the message store for the current context with read-write access. 
       
  1492 
       
  1493 Only one client can edit a message store at one time. If another client is 
       
  1494 already writing to the store, KErrAccessDenied is returned. Other clients 
       
  1495 can be reading the store. 
       
  1496 
       
  1497 If the message store does not exist when EditStore() is called, a new message 
       
  1498 store is created. 
       
  1499 
       
  1500 The returned CMsvStore must be deleted when it is no longer required. 
       
  1501 
       
  1502 @leave KErrAccessDenied Store is locked by another process or the entry is 
       
  1503 read only 
       
  1504 @leave KErrNoMemory Not enough memory to open the store 
       
  1505 @return Context's message store open for read-write access */
       
  1506 	{
       
  1507 #ifndef _NO_SESSION_LOGGING_
       
  1508 	Log(_L("EditStoreL for entry %x"), iEntryPtr->Id()); 
       
  1509 #endif
       
  1510 
       
  1511 	__ASSERT_ALWAYS(iStore==NULL, PanicServer(EMsvStoreAlreadyOpen));
       
  1512 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1513 	
       
  1514 	if (iEntryPtr->ReadOnly())
       
  1515 		User::Leave(KErrAccessDenied);
       
  1516 
       
  1517 	User::LeaveIfError(iMsvSession.Session().LockStore(iEntryPtr->Id()));
       
  1518 
       
  1519 	// open the store
       
  1520 	TInt error = 0;
       
  1521 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)	
       
  1522 		TRAP(error,  iStore = CMsvStore::OpenForWriteL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id(), this->Entry().iMtm));
       
  1523 #else
       
  1524 		TRAP(error,  iStore = CMsvStore::OpenForWriteL(*this, iMsvSession.FileSession(), iMsvSession.StoreManager(), iEntryPtr->Id()));
       
  1525 #endif
       
  1526 	if (error)
       
  1527 		{
       
  1528 		iMsvSession.Session().ReleaseStore(iEntryPtr->Id()); // error ignored
       
  1529 		User::Leave(error);		
       
  1530 		}
       
  1531 
       
  1532 	return iStore;
       
  1533 	}
       
  1534 
       
  1535 
       
  1536 
       
  1537 void CMsvEntry::HandleStoreEvent(MMsvStoreObserver::TMsvStoreEvent aEvent, TMsvId /*aId*/)
       
  1538 //
       
  1539 //
       
  1540 //
       
  1541 	{
       
  1542 	switch (aEvent)
       
  1543 		{
       
  1544 		case EMsvEditStoreClosed:
       
  1545 			iMsvSession.Session().ReleaseStore(iEntryPtr->Id()); // error ignored
       
  1546 			iStore=NULL;
       
  1547 			break;
       
  1548 		case EMsvReadStoreClosed:
       
  1549 			iMsvSession.Session().DecStoreReaderCount(iEntryPtr->Id()); // error ignored
       
  1550 			iStore=NULL;
       
  1551 			break;
       
  1552 		default:
       
  1553 			__ASSERT_DEBUG(EFalse, PanicServer(EMsvUnknownStoreEvent3));
       
  1554 		}
       
  1555 
       
  1556 	}
       
  1557 
       
  1558 
       
  1559 EXPORT_C CMsvOperation* CMsvEntry::MoveL(TMsvId aMsvId, TMsvId aTargetId, TRequestStatus& aStatus)
       
  1560 //
       
  1561 // Move a single child to another parent
       
  1562 //
       
  1563 /** Moves, asynchronously, a child of the context to become an entry owned by the target entry. 
       
  1564 
       
  1565 All descendants will be moved as well. Any files and stores associated with 
       
  1566 the entry are also moved.
       
  1567 
       
  1568 The returned CMsvOperation object completes when moving is complete.
       
  1569 
       
  1570 @param aMsvId The ID of the entry to be moved 
       
  1571 @param aTargetId The ID of the entry to own the moved entries 
       
  1572 @param aStatus The request status to be completed when the operation has finished 
       
  1573 
       
  1574 @leave KErrNoMemory The operation could not be created or passed to the server 
       
  1575 @leave KErrNotFound An entry was not a child of the context 
       
  1576 @return The operation object controlling the move command. */
       
  1577 	{
       
  1578 #ifndef _NO_SESSION_LOGGING_
       
  1579 	Log(_L("Asynchronous MoveL %x to %x"), aMsvId, aTargetId); 
       
  1580 #endif
       
  1581 
       
  1582 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1583 	CleanupStack::PushL(selection);
       
  1584 	selection->AppendL(aMsvId);
       
  1585 	CMsvOperation* operation = MoveL(*selection, aTargetId, aStatus);
       
  1586 	CleanupStack::PopAndDestroy(); // selection
       
  1587 	return operation;
       
  1588 	}
       
  1589 
       
  1590 
       
  1591 TInt CMsvEntry::MoveOneL(TMsvId aMsvId, TMsvId aTargetId)
       
  1592 	{
       
  1593 	CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
       
  1594 	CleanupStack::PushL(selection);
       
  1595 	selection->AppendL(aMsvId);
       
  1596 	TInt opid = iMsvSession.OperationId();
       
  1597 	iMsvSession.Session().MoveEntriesL(*selection, aTargetId, opid);
       
  1598 
       
  1599 	TMsvLocalOperationProgress progress;
       
  1600 	TPckg<TMsvLocalOperationProgress> progressPack(progress);
       
  1601     User::LeaveIfError(iMsvSession.Session().OperationCompletion(opid, progressPack));
       
  1602 	
       
  1603 	if(progress.iError==KErrNone)
       
  1604 		{
       
  1605 		TMsvId id = selection->At(0);
       
  1606 		TInt ii = iSortedChildren->Count();
       
  1607 		while (ii--)
       
  1608 			{
       
  1609 			if (iSortedChildren->At(ii)->Id() == id)
       
  1610 				{
       
  1611 				iSortedChildren->Delete(ii);
       
  1612 				break;
       
  1613 				}
       
  1614 			}
       
  1615 
       
  1616 		ii = iEntries->Count();
       
  1617 		while (ii--)
       
  1618 			{
       
  1619 			if (iEntries->At(ii)->Entry().Id() == id)
       
  1620 				{
       
  1621 				delete iEntries->At(ii);
       
  1622 				iEntries->Delete(ii);
       
  1623 				break;
       
  1624 				}
       
  1625 			}
       
  1626 		// Reset the owner flag
       
  1627 		if (Count() == 0)
       
  1628 			{
       
  1629 			TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
       
  1630 			ptr->SetOwner(EFalse);
       
  1631 			}		
       
  1632 		}
       
  1633 	CleanupStack::PopAndDestroy(selection);
       
  1634 	return(progress.iError);
       
  1635 	}
       
  1636 
       
  1637 /** Moves, synchronously, a child of the context to become an entry owned by the target entry. 
       
  1638 
       
  1639 All descendants will be moved as well. Any files and stores associated with 
       
  1640 the entry are also moved.
       
  1641 
       
  1642 @param aMsvId The ID of the entry to be moved 
       
  1643 @param aTargetId The ID of the entry to own the moved entries 
       
  1644 
       
  1645 @leave KErrNoMemory 
       
  1646 @leave KErrNotFound An entry was not a child of the context 
       
  1647 */
       
  1648 EXPORT_C void CMsvEntry::MoveL(TMsvId aMsvId, TMsvId aTargetId)
       
  1649 //
       
  1650 // Move a single child to another parent
       
  1651 //
       
  1652 	{
       
  1653 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1654 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1655 	__ASSERT_DEBUG(aTargetId!=iEntryPtr->Id(), PanicServer(EMsvMovingEntryToSameParent));
       
  1656 
       
  1657 #ifndef _NO_SESSION_LOGGING_
       
  1658 	Log(_L("Synchronous MoveL %x to %x"), aMsvId, aTargetId); 
       
  1659 #endif
       
  1660 	User::LeaveIfError(MoveOneL(aMsvId,aTargetId));
       
  1661 	}
       
  1662 
       
  1663 
       
  1664 /** Moves, synchronously, children of the context to become entries owned by the target entry. 
       
  1665 
       
  1666 All descendants will be moved as well. Any files and stores associated with 
       
  1667 the entries are also moved.
       
  1668 
       
  1669 @param aSelection List of IDs of the entries to be moved 
       
  1670 @param aTargetId The ID of the entry to own the moved entires 
       
  1671 @param aProgress On return, records the outcome of the move 
       
  1672 
       
  1673 @leave KErrNoMemory 
       
  1674 @leave KErrNotFound An entry was not a child of the context 
       
  1675 */
       
  1676 EXPORT_C void CMsvEntry::MoveL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TMsvLocalOperationProgress& aProgress)
       
  1677 //
       
  1678 // Move a selection of children to another parent
       
  1679 //
       
  1680 	{
       
  1681 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1682 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1683 	__ASSERT_DEBUG(aTargetId!=iEntryPtr->Id(), PanicServer(EMsvMovingEntryToSameParent));
       
  1684 	__ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
  1685 
       
  1686 
       
  1687 #ifndef _NO_SESSION_LOGGING_
       
  1688 	Log(_L("Synchronous MoveL with selection of %d entries to %x"), aSelection.Count(),aTargetId); 
       
  1689 #endif
       
  1690 
       
  1691 	aProgress.iTotalNumberOfEntries=aSelection.Count();
       
  1692 	aProgress.iNumberCompleted=0;
       
  1693 	aProgress.iNumberRemaining=aProgress.iTotalNumberOfEntries;
       
  1694 	aProgress.iError=KErrNone;
       
  1695 
       
  1696 	TInt count=aProgress.iTotalNumberOfEntries;
       
  1697 	while(count--)
       
  1698 		{
       
  1699 		aProgress.iId=aSelection.At(count);
       
  1700 		TInt err=MoveOneL(aProgress.iId,aTargetId);
       
  1701 		aProgress.iNumberRemaining--;
       
  1702 		if(err==KErrNone)
       
  1703 			aProgress.iNumberCompleted++;
       
  1704 		else
       
  1705 			{
       
  1706 			aProgress.iError=err;
       
  1707 			aProgress.iNumberFailed++;
       
  1708 			}
       
  1709 		}
       
  1710 	}
       
  1711 
       
  1712 
       
  1713 
       
  1714 
       
  1715 
       
  1716 
       
  1717 EXPORT_C CMsvOperation* CMsvEntry::MoveL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TRequestStatus& aStatus)
       
  1718 //
       
  1719 // Move a selection of children to another parent
       
  1720 //
       
  1721 /** Moves, asynchronously, children of the context to become entries owned by the target entry. 
       
  1722 
       
  1723 All descendants will be moved as well. Any files and stores associated with 
       
  1724 the entries are also moved.
       
  1725 
       
  1726 The returned CMsvOperation object completes when moving is complete.
       
  1727 
       
  1728 @param aSelection List of IDs of the entries to be moved 
       
  1729 @param aTargetId The ID of the entry to own the moved entires 
       
  1730 @param aStatus The request status to be completed when the operation has finished 
       
  1731 
       
  1732 @leave KErrNoMemory The operation could not be created or passed to the server 
       
  1733 @leave KErrNotFound An entry was not a child of the context 
       
  1734 @return The operation object controlling the move command. */
       
  1735 	{
       
  1736 #ifndef _NO_SESSION_LOGGING_
       
  1737 	Log(_L("Asynchronous MoveL of selection of %d entries to %x"), aSelection.Count(), aTargetId); 
       
  1738 #endif
       
  1739 
       
  1740 	__ASSERT_DEBUG(aTargetId!=iEntryPtr->Id(), PanicServer(EMsvMovingEntryToSameParent));
       
  1741 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1742 	if (!AreChildren(aSelection))
       
  1743 		User::Leave(KErrNotFound);
       
  1744 	CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
       
  1745 	CleanupStack::PushL(operation);
       
  1746 	User::LeaveIfError(iMsvSession.Session().OperationMtmL(aSelection.At(0), aTargetId, operation->iMtm, operation->iService));
       
  1747 
       
  1748 #if defined(_DEBUG)
       
  1749 	// check other entries in selection are consistent and are not read only
       
  1750 	TInt dCount = aSelection.Count();
       
  1751 	while (dCount--)
       
  1752 		{
       
  1753 		TMsvId service;
       
  1754 		TUid mtm;
       
  1755 		TInt error = iMsvSession.Session().OperationMtmL(aSelection.At(dCount), aTargetId, mtm, service);
       
  1756 		__ASSERT_DEBUG(error==KErrNone || error==KErrNotFound, PanicServer(EMsvMulitpleMtmsForMoveCommand));
       
  1757 		__ASSERT_DEBUG(mtm==operation->iMtm, PanicServer(EMsvMulitpleMtmsForMoveCommand));
       
  1758 		__ASSERT_DEBUG(service==operation->iService, PanicServer(EMsvMulitpleMtmsForMoveCommand));
       
  1759 		TMsvEntry dEntry;
       
  1760 		TMsvId dService;
       
  1761 		if (iMsvSession.Session().GetEntry(aSelection.At(dCount), dService, dEntry)==KErrNone)
       
  1762 			__ASSERT_DEBUG(dService==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && dService==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==aSelection.At(dCount)), PanicServer(EMsvMovingEntryDifferentOwningService));
       
  1763 		}
       
  1764 #endif
       
  1765 
       
  1766 	iMsvSession.Session().MoveEntriesL(aSelection, aTargetId, operation->Id(), operation->iStatus);
       
  1767 	operation->Start();
       
  1768 	CleanupStack::Pop(); // operation
       
  1769 	return operation;
       
  1770 	}
       
  1771 
       
  1772 
       
  1773 EXPORT_C CMsvOperation* CMsvEntry::CopyL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TRequestStatus& aStatus)
       
  1774 //
       
  1775 // Copy a selection ocf children to another parent
       
  1776 //
       
  1777 /** Creates, asynchronously. copies of children of the context as new entries owned by the specified 
       
  1778 target ID.
       
  1779 
       
  1780 All descendants will be copied as well. Any files and stores associated with 
       
  1781 the entries are also copied.
       
  1782 
       
  1783 The returned CMsvOperation object completes when copying is complete.
       
  1784 
       
  1785 @param aSelection List of IDs of the entries to be copied 
       
  1786 @param aTargetId The ID of the entry to own the copies 
       
  1787 @param aStatus The request status to be completed when the operation has finished 
       
  1788 
       
  1789 @leave KErrNoMemory The operation could not be created or passed to the server 
       
  1790 @leave KErrNotFound An entry was not a child of the context 
       
  1791 @return The operation object controlling the copy command. */
       
  1792 	{
       
  1793 #ifndef _NO_SESSION_LOGGING_
       
  1794 	Log(_L("Asynchronous CopyL of selection of %d entries to %x"), aSelection.Count(), aTargetId); 
       
  1795 #endif
       
  1796 
       
  1797 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1798 	if (!AreChildren(aSelection))
       
  1799 		User::Leave(KErrNotFound);
       
  1800 	CMsvEntryOperation* operation = CMsvEntryOperation::NewL(iMsvSession, aStatus);
       
  1801 	CleanupStack::PushL(operation);
       
  1802 	User::LeaveIfError(iMsvSession.Session().OperationMtmL(aSelection.At(0), aTargetId, operation->iMtm, operation->iService)); 
       
  1803 
       
  1804 #if defined(_DEBUG)
       
  1805 	// check other entries in selection are consistent 
       
  1806 	TInt dCount = aSelection.Count();
       
  1807 	while (dCount--)
       
  1808 		{
       
  1809 		TMsvId service;
       
  1810 		TUid mtm;
       
  1811 		TInt error = iMsvSession.Session().OperationMtmL(aSelection.At(dCount), aTargetId, mtm, service);
       
  1812 		__ASSERT_DEBUG(error==KErrNone || error==KErrNotFound, PanicServer(EMsvMulitpleMtmsForCopyCommand));
       
  1813 		__ASSERT_DEBUG(mtm==operation->iMtm, PanicServer(EMsvMulitpleMtmsForCopyCommand));
       
  1814 		__ASSERT_DEBUG(service==operation->iService, PanicServer(EMsvMulitpleMtmsForCopyCommand));
       
  1815 		TMsvEntry dEntry;
       
  1816 		TMsvId dService;
       
  1817 		if (iMsvSession.Session().GetEntry(aSelection.At(dCount), dService, dEntry)==KErrNone)
       
  1818 			__ASSERT_DEBUG(dService==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && dService==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==aSelection.At(dCount)), PanicServer(EMsvCopyingEntryDifferentOwningService));
       
  1819 		}
       
  1820 #endif
       
  1821 
       
  1822 	iMsvSession.Session().CopyEntriesL(aSelection, aTargetId, operation->Id(), operation->iStatus);
       
  1823 	operation->Start();
       
  1824 	CleanupStack::Pop(); // operation
       
  1825 	return operation;
       
  1826 	}
       
  1827 
       
  1828 EXPORT_C CMsvOperation* CMsvEntry::CopyL(TMsvId aMsvId, TMsvId aTargetId, TRequestStatus& aStatus)
       
  1829 //
       
  1830 // Copy a single entry to another parent
       
  1831 //
       
  1832 /** Creates, asynchronously, a copy of a child of the context as a new entry owned by the specified 
       
  1833 target ID.
       
  1834 
       
  1835 All descendants will be copied as well. Any files and stores associated with 
       
  1836 the entry are also copied.
       
  1837 
       
  1838 The returned CMsvOperation object completes when copying is complete.
       
  1839 
       
  1840 @param aMsvId The ID of the entry to be copied 
       
  1841 @param aTargetId The ID of the entry to own the copy 
       
  1842 @param aStatus The request status to be completed when the operation has finished 
       
  1843 
       
  1844 @leave KErrNoMemory The operation could not be created or passed to the server 
       
  1845 @leave KErrNotFound An entry was not a child of the context 
       
  1846 @return The operation object controlling the copy command. */
       
  1847 	{
       
  1848 #ifndef _NO_SESSION_LOGGING_
       
  1849 	Log(_L("Asynchronous CopyL of entry %x to %x"), aMsvId, aTargetId); 
       
  1850 #endif
       
  1851 
       
  1852 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  1853 	CleanupStack::PushL(selection);
       
  1854 	selection->AppendL(aMsvId);
       
  1855 	CMsvOperation* operation = CopyL(*selection, aTargetId, aStatus);
       
  1856 	CleanupStack::PopAndDestroy(); // selection
       
  1857 	return operation;
       
  1858 	}
       
  1859 
       
  1860 
       
  1861 TInt CMsvEntry::CopyOneL(TMsvId aMsvId, TMsvId aTargetId)
       
  1862 	{
       
  1863 
       
  1864 	CMsvEntryArray* newSortedChildren = NULL;
       
  1865 	CMsvClientEntry *toadd=NULL;
       
  1866 
       
  1867 	
       
  1868 	if(aTargetId==iEntryPtr->Id())
       
  1869 		{
       
  1870 		const TMsvEntry &entry=ChildDataL(aMsvId);
       
  1871 		if (entry.Visible() || iOrdering.ShowInvisibleEntries())
       
  1872 			{
       
  1873 			// Create what may be the new child entry if nothing goes wrong
       
  1874 			toadd = CMsvClientEntry::NewLC(entry, EMsvClientChild);
       
  1875 
       
  1876 			// Reserve space for the new entry for later
       
  1877 			iEntries->SetReserveL(iEntries->Count() + 1);
       
  1878 
       
  1879 			newSortedChildren = CMsvEntryArray::NewLC(*iMtmList);
       
  1880 
       
  1881 			// add the children to the sorted pointer list - current context is the first entry
       
  1882 			TInt totalCount=iEntries->Count();
       
  1883 			for (TInt count=1; count<totalCount; count++)
       
  1884 				newSortedChildren->AppendL(&iEntries->At(count)->Entry());
       
  1885 
       
  1886 			// We've created a new sorted child list now so we won't leave later
       
  1887 			newSortedChildren->AppendL(&toadd->Entry());
       
  1888 			newSortedChildren->SortL(iOrdering);
       
  1889 			}
       
  1890 		}
       
  1891 
       
  1892 	CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
       
  1893 	CleanupStack::PushL(selection);
       
  1894 	selection->AppendL(aMsvId);
       
  1895 	TInt opid = iMsvSession.OperationId();
       
  1896 	iMsvSession.Session().CopyEntriesL(*selection, aTargetId, opid);
       
  1897 
       
  1898 	TMsvLocalOperationProgress progress;
       
  1899 	TPckg<TMsvLocalOperationProgress> progressPack(progress);
       
  1900     User::LeaveIfError(iMsvSession.Session().OperationCompletion(opid, progressPack));
       
  1901 
       
  1902 	CleanupStack::PopAndDestroy(selection);
       
  1903 
       
  1904 	// can't leave after this point
       
  1905 	if(newSortedChildren!=NULL) CleanupStack::Pop(newSortedChildren);
       
  1906 	if(toadd!=NULL) CleanupStack::Pop(toadd);
       
  1907 	if(newSortedChildren!=NULL && progress.iError==KErrNone)
       
  1908 		{
       
  1909 		delete iSortedChildren;
       
  1910 		iSortedChildren=newSortedChildren;
       
  1911 		newSortedChildren=NULL;
       
  1912 		toadd->SetId(progress.iId);
       
  1913 		// Will not leave because we've reserved space earlier
       
  1914 		iEntries->AppendL(toadd);
       
  1915 		toadd=NULL;
       
  1916 		}
       
  1917 	delete newSortedChildren;
       
  1918 	delete toadd;
       
  1919 	return(progress.iError);
       
  1920 	}
       
  1921 
       
  1922 EXPORT_C void CMsvEntry::CopyL(TMsvId aMsvId, TMsvId aTargetId)
       
  1923 //
       
  1924 // Copy a single child to another parent (or duplicate)
       
  1925 //
       
  1926 /** Creates, synchronously, a copy of a child of the context as a new entry owned by the specified target ID.
       
  1927 
       
  1928 @param aMsvId The ID of the entry to be copied
       
  1929 @param aTargetId The ID of the entry to own the copy
       
  1930 */
       
  1931 	{	
       
  1932 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1933 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1934 #ifndef _NO_SESSION_LOGGING_
       
  1935 	Log(_L("Synchronous CopyL %x to %x"), aMsvId, aTargetId); 
       
  1936 #endif
       
  1937 	User::LeaveIfError(CopyOneL(aMsvId,aTargetId));
       
  1938 	}
       
  1939 
       
  1940 
       
  1941 /** Creates, synchronously. copies of children of the context as new entries owned by the specified 
       
  1942 target ID.
       
  1943 
       
  1944 All descendants will be copied as well. Any files and stores associated with 
       
  1945 the entries are also copied.
       
  1946 
       
  1947 @param aSelection List of IDs of the entries to be copied 
       
  1948 @param aTargetId The ID of the entry to own the copies 
       
  1949 @param aProgress On return, records the outcome of the copy 
       
  1950 
       
  1951 @leave KErrNoMemory 
       
  1952 @leave KErrNotFound An entry was not a child of the context 
       
  1953 */
       
  1954 EXPORT_C void CMsvEntry::CopyL(const CMsvEntrySelection& aSelection, TMsvId aTargetId, TMsvLocalOperationProgress& aProgress)
       
  1955 //
       
  1956 // Copy a selection to another parent (or duplicate)
       
  1957 //
       
  1958 	{
       
  1959 	__ASSERT_ALWAYS(iOwningService == KMsvLocalServiceIndexEntryId || iOwningService == KMsvRootIndexEntryId, PanicServer(EMsvNotLocalService)); // Root as well?
       
  1960 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  1961 	__ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
  1962 
       
  1963 #ifndef _NO_SESSION_LOGGING_
       
  1964 	Log(_L("Synchronous CopyL with selection of %d entries to %x"), aSelection.Count(),aTargetId); 
       
  1965 #endif
       
  1966 
       
  1967 
       
  1968 	aProgress.iTotalNumberOfEntries=aSelection.Count();
       
  1969 	aProgress.iNumberCompleted=0;
       
  1970 	aProgress.iNumberRemaining=aProgress.iTotalNumberOfEntries;
       
  1971 	aProgress.iError=KErrNone;
       
  1972 
       
  1973 	TInt count=aProgress.iTotalNumberOfEntries;
       
  1974 	while(count--)
       
  1975 		{
       
  1976 		aProgress.iId=aSelection.At(count);
       
  1977 		TInt err=CopyOneL(aProgress.iId,aTargetId);
       
  1978 		aProgress.iNumberRemaining--;
       
  1979 		if(err==KErrNone)
       
  1980 			aProgress.iNumberCompleted++;
       
  1981 		else
       
  1982 			{
       
  1983 			aProgress.iError=err;
       
  1984 			aProgress.iNumberFailed++;
       
  1985 			}
       
  1986 		}
       
  1987 	}
       
  1988 
       
  1989 
       
  1990 
       
  1991 
       
  1992 
       
  1993 EXPORT_C void CMsvEntry::AddObserverL(MMsvEntryObserver& aObserver)
       
  1994 //
       
  1995 // Adds an observer to this entry
       
  1996 // If the function leaves, the observer was not appended
       
  1997 // 
       
  1998 /** Registers an observer for the object. 
       
  1999 
       
  2000 CMsvEntry objects can call back observer objects that implement the MMsvEntryObserver 
       
  2001 interface when certain events occur. Any number of observers can be registered.
       
  2002 
       
  2003 Observers are called primarily when the context changes state or contents. 
       
  2004 For details, see MMsvEntryObserver::TMsvEntryEvent.
       
  2005 
       
  2006 @param aObserver The observer to be registered for events 
       
  2007 @leave KErrNoMemory Not enough memory to register the observer */
       
  2008 	{
       
  2009 	if (iObservers==NULL)
       
  2010 		iObservers=new(ELeave) CArrayPtrFlat<MMsvEntryObserver> (KMsvEntryObserverArrayGranuality);
       
  2011 	iObservers->AppendL(&aObserver);
       
  2012 
       
  2013 #ifndef _NO_SESSION_LOGGING_
       
  2014 	Log(_L("Observer %d added"), iObservers->Count()); 
       
  2015 #endif
       
  2016 	}
       
  2017 
       
  2018 
       
  2019 EXPORT_C void CMsvEntry::RemoveObserver(MMsvEntryObserver& aObserver)
       
  2020 //
       
  2021 // Removes an observer of the entry
       
  2022 //
       
  2023 /** Unregisters an observer previously registered with AddObserverL(). 
       
  2024 
       
  2025 @param aObserver A reference to an observer to be unregistered for events */
       
  2026 	{
       
  2027 	__ASSERT_DEBUG(iObservers, PanicServer(EMsvEntryUnknownObserver));
       
  2028 	if (iObservers)
       
  2029 		{
       
  2030 		TInt count=iObservers->Count();
       
  2031 		while (count--)
       
  2032 			{
       
  2033 			if (iObservers->At(count)==&aObserver)
       
  2034 				{
       
  2035 #ifndef _NO_SESSION_LOGGING_
       
  2036 				Log(_L("Observer %d removed"), count + 1); 
       
  2037 #endif
       
  2038 				iObservers->Delete(count);
       
  2039 				if (iObservers->Count()==0)
       
  2040 					{
       
  2041 					delete iObservers;
       
  2042 					iObservers=NULL;
       
  2043 					}
       
  2044 				return;
       
  2045 				}
       
  2046 			}
       
  2047 		__ASSERT_DEBUG(count>=0, PanicServer(EMsvEntryUnknownObserver));
       
  2048 		}
       
  2049 	}
       
  2050 
       
  2051 
       
  2052 void CMsvEntry::NotifyAllObserversL(MMsvEntryObserver::TMsvEntryEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3)
       
  2053 //
       
  2054 // Notifies all observers of the event affecting the context
       
  2055 //
       
  2056 	{
       
  2057 	if (iObservers==NULL)
       
  2058 		return;
       
  2059 	TInt count=iObservers->Count();
       
  2060 	while (count--)
       
  2061 		iObservers->At(count)->HandleEntryEventL(aEvent,aArg1,aArg2,aArg3);	
       
  2062 	}
       
  2063 
       
  2064 
       
  2065 void CMsvEntry::HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3)
       
  2066 //
       
  2067 // Is informed of all the session events
       
  2068 // This are filtered to find the events relating to the context
       
  2069 //
       
  2070 	{
       
  2071 	// Check the notification sequence and ignore if neccessary
       
  2072 	if (iNotifySequence >= iMsvSession.iNotifySequence)
       
  2073 		{
       
  2074 #ifndef _NO_SESSION_LOGGING_
       
  2075 		Log(_L("Ignoring notification, %d >= %d"), iNotifySequence, iMsvSession.iNotifySequence); 
       
  2076 #endif
       
  2077 		return;
       
  2078 		}
       
  2079 
       
  2080 	switch (aEvent)
       
  2081 		{
       
  2082 		case EMsvEntriesChanged:
       
  2083 			{
       
  2084 			CMsvEntrySelection* selection = (CMsvEntrySelection*) aArg1;
       
  2085 			if (iEntryPtr->Id() == selection->At(0))
       
  2086 				ContextChangedL(MMsvEntryObserver::EMsvEntryChanged);
       
  2087 			else if (iEntryPtr->Id()==*(TMsvId*) aArg2)
       
  2088 				ChildrenChangedL(*selection);
       
  2089 			break;
       
  2090 			}
       
  2091 		case EMsvEntriesCreated:
       
  2092 			if (*(TMsvId*) aArg2==iEntryPtr->Id())
       
  2093 				NewChildrenL(*(CMsvEntrySelection*) aArg1);
       
  2094 			else
       
  2095 				CheckNewGrandchildrenL(*(TMsvId*) aArg2);
       
  2096 			break;
       
  2097 		case EMsvEntriesDeleted:
       
  2098 			{
       
  2099 			CMsvEntrySelection* selection = (CMsvEntrySelection*) aArg1;
       
  2100 			if (*(TMsvId*) aArg2==iEntryPtr->Id())
       
  2101 				DeletedChildrenL(*selection);
       
  2102 			else
       
  2103 				{
       
  2104 				// check if we have been deleted
       
  2105 				TInt index=selection->Find(iEntryPtr->Id());
       
  2106 				if (index!=KErrNotFound)
       
  2107 					{
       
  2108 					iState = EInvalidDeletedContext;
       
  2109 					NotifyAllObserversL(MMsvEntryObserver::EMsvEntryDeleted, NULL, NULL, NULL);
       
  2110 					}
       
  2111 				else
       
  2112 					CheckDeletedGrandchildrenL(*(TMsvId*) aArg2);
       
  2113 				}
       
  2114 			break;
       
  2115 			}
       
  2116 		case EMsvEntriesMoved:
       
  2117 			if (*(TMsvId*) aArg3==iEntryPtr->Parent())
       
  2118 				CheckIfContextMovedL(*(CMsvEntrySelection*) aArg1);
       
  2119 			if (*(TMsvId*) aArg2==iEntryPtr->Id())
       
  2120 				NewChildrenL(*(CMsvEntrySelection*) aArg1);
       
  2121 			else if (*(TMsvId*) aArg3==iEntryPtr->Id())
       
  2122 				DeletedChildrenL(*(CMsvEntrySelection*) aArg1);
       
  2123 			else
       
  2124 				{
       
  2125 				CheckNewGrandchildrenL(*(TMsvId*) aArg2);
       
  2126 				CheckDeletedGrandchildrenL(*(TMsvId*) aArg3);
       
  2127 				}
       
  2128 			break;
       
  2129 		case EMsvMediaChanged:
       
  2130 			{
       
  2131 			TRAPD(error, HandleMediaChangeL());			
       
  2132 			if (error)
       
  2133 				{
       
  2134 				// An error occurred or this is a non standard entry
       
  2135 				// in which case the media has changed so this entry is not accessible
       
  2136 				// Just mark the entry as invalid - there is nothing else we can do!
       
  2137 				iState = EInvalidOldContext;
       
  2138 				NotifyAllObserversL(MMsvEntryObserver::EMsvContextInvalid, (TAny*)&error, NULL, NULL);
       
  2139 				}
       
  2140 			break;
       
  2141 			}
       
  2142 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2143 		case EMsvRefreshMessageView:
       
  2144 			{
       
  2145 			// A drive/disk has been added/removed.
       
  2146 			if(iEntryPtr->StandardFolder())
       
  2147 				{
       
  2148 				SetEntryNoCheckL(iEntryPtr->Id(), iChildrenOfAvailableDrives);
       
  2149 				}
       
  2150 			break;
       
  2151 			}
       
  2152 #endif
       
  2153 		default:
       
  2154 			break;
       
  2155 		}
       
  2156 	}
       
  2157 
       
  2158 void CMsvEntry::HandleMediaChangeL()
       
  2159 	{
       
  2160 	// If this is not a standard entry there is nothing we can do
       
  2161 	if (!iEntryPtr->StandardFolder())
       
  2162 		User::Leave(KMsvMediaChanged);
       
  2163 
       
  2164 	// This is a standard folder so it will exist on all media
       
  2165 	// Refresh the entry and child list - if this fails mark the entry as invalid
       
  2166 	// Otherwise the context will be told that everything has changed
       
  2167 	CMsvEntrySelection* oldChildren = new(ELeave)CMsvEntrySelection;
       
  2168 	CleanupStack::PushL(oldChildren);
       
  2169 
       
  2170 	// Get list of old children
       
  2171 	TInt count = iSortedChildren->Count();
       
  2172 	while(count--)
       
  2173 		oldChildren->AppendL(iSortedChildren->At(count)->Id());
       
  2174 
       
  2175 	// Refresh the context
       
  2176 	iState = EInvalidOldContext;
       
  2177 
       
  2178 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2179 	if(iChildrenOfAvailableDrives)
       
  2180 		{
       
  2181 		SetStandardFolderEntryL(iEntryPtr->Id());
       
  2182 		}
       
  2183 	else
       
  2184 #endif
       
  2185 		{
       
  2186 		SetEntryL(iEntryPtr->Id());
       
  2187 		}
       
  2188 	CMsvEntrySelection* newChildren = new(ELeave)CMsvEntrySelection;
       
  2189 	CleanupStack::PushL(newChildren);
       
  2190 
       
  2191 	// Get list of new children
       
  2192 	count = iSortedChildren->Count();
       
  2193 	while(count--)
       
  2194 		newChildren->AppendL(iSortedChildren->At(count)->Id());
       
  2195 
       
  2196 	// Tell the context about the children that have effectively been deleted and created
       
  2197 	if (oldChildren->Count())
       
  2198 		NotifyAllObserversL(MMsvEntryObserver::EMsvDeletedChildren, (TAny*)oldChildren, NULL, NULL);
       
  2199 	if (newChildren->Count())
       
  2200 		NotifyAllObserversL(MMsvEntryObserver::EMsvNewChildren, (TAny*)newChildren, NULL, NULL);
       
  2201 
       
  2202 	// Tell the context that it might have changed
       
  2203 	NotifyAllObserversL(MMsvEntryObserver::EMsvEntryChanged, NULL, NULL, NULL);
       
  2204 
       
  2205 	CleanupStack::PopAndDestroy(2); // newChildren, oldChildren
       
  2206 	}
       
  2207 
       
  2208 void CMsvEntry::CheckIfContextMovedL(const CMsvEntrySelection& aSelection)
       
  2209 //
       
  2210 // Some of the contexts parents children have moved, have to check if the context was one of them
       
  2211 //
       
  2212 	{
       
  2213 	TInt index=aSelection.Find(iEntryPtr->Id());
       
  2214 	if (index!=KErrNotFound)
       
  2215 		ContextChangedL(MMsvEntryObserver::EMsvEntryMoved);
       
  2216 	}
       
  2217 
       
  2218 
       
  2219 void CMsvEntry::ContextChangedL(MMsvEntryObserver::TMsvEntryEvent aEvent)
       
  2220 //
       
  2221 // The context has ben changed, spo we need to get the enw version
       
  2222 //
       
  2223 	{
       
  2224 #ifndef _NO_SESSION_LOGGING_
       
  2225 	Log(_L("Context changed")); 
       
  2226 #endif
       
  2227 
       
  2228 	if (iEntries->Count()>1 && iEntries->At(1)->Type()==EMsvClientChangedContext)
       
  2229 		{
       
  2230 		// we changed the entry, so get the new conext from the entry list
       
  2231 		// delete the old entry context (the new one is at position 1)
       
  2232 		delete iEntries->At(0);
       
  2233 		iEntries->Delete(0);
       
  2234 		}
       
  2235 	else
       
  2236 		{
       
  2237 		// someone else changed the context, so we have to update
       
  2238 		CMsvClientEntry* cEntry=NULL;
       
  2239 		TMsvId owningService=KMsvNullIndexEntryId;
       
  2240 		TRAPD(error, {cEntry = DoGetEntryLC(iEntryPtr->Id(), owningService); CleanupStack::Pop();});
       
  2241 		if (error==KErrNone)
       
  2242 			{
       
  2243 			if(iEntries->Count() != 0)
       
  2244 				{
       
  2245 				delete iEntries->At(0);
       
  2246 				iEntries->At(0) = cEntry;
       
  2247 				}
       
  2248 			else
       
  2249 				{
       
  2250 				iEntries->AppendL(cEntry); 	
       
  2251 				}
       
  2252 			iOwningService = owningService;
       
  2253 			}
       
  2254 		else
       
  2255 			{
       
  2256 			iState = EInvalidOldContext;
       
  2257 			NotifyAllObserversL(MMsvEntryObserver::EMsvContextInvalid, (TAny*)&error, NULL, NULL);
       
  2258 			return;
       
  2259 			}
       
  2260 		}
       
  2261 
       
  2262 	iEntries->At(0)->SetType(EMsvClientContext);
       
  2263 	iEntryPtr = &iEntries->At(0)->Entry();
       
  2264 	iState = EValid;
       
  2265 
       
  2266 	// notify all observers
       
  2267 	NotifyAllObserversL(aEvent, NULL, NULL, NULL);
       
  2268 	}
       
  2269 
       
  2270 
       
  2271 
       
  2272 void CMsvEntry::NewChildrenL(const CMsvEntrySelection& aSelection)
       
  2273 //
       
  2274 // New children have been created
       
  2275 //
       
  2276 	{
       
  2277 #ifndef _NO_SESSION_LOGGING_
       
  2278 	Log(_L("New children")); 
       
  2279 #endif
       
  2280 
       
  2281 	CMsvEntrySelection* newChildren = DoGetNewChildrenL(aSelection);
       
  2282 	CleanupStack::PushL(newChildren);
       
  2283 	if (newChildren->Count())
       
  2284 		{
       
  2285 		TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
       
  2286 		ptr->SetOwner(ETrue);
       
  2287 		NotifyAllObserversL(MMsvEntryObserver::EMsvNewChildren, (TAny*)newChildren, NULL, NULL);
       
  2288 		}
       
  2289 	CleanupStack::PopAndDestroy(); // newChildren
       
  2290 	}
       
  2291 
       
  2292 
       
  2293 CMsvEntrySelection* CMsvEntry::DoGetNewChildrenL(const CMsvEntrySelection& aSelection)
       
  2294 //
       
  2295 // New children have been created
       
  2296 //
       
  2297 	{
       
  2298 	CMsvEntrySelection* newChildren = aSelection.CopyLC();
       
  2299 	TInt count=aSelection.Count();
       
  2300 	while (count--)
       
  2301 		{
       
  2302 		// check if we already have this child
       
  2303 		if (IsAChild(aSelection.At(count)))
       
  2304 			{
       
  2305 			newChildren->Delete(count);
       
  2306 			continue;
       
  2307 			}
       
  2308 
       
  2309 		// get the new child data and add to to the list
       
  2310 		TMsvEntry tEntry;
       
  2311 		TMsvId service;
       
  2312 		TInt error=iMsvSession.Session().GetEntry(aSelection.At(count), service, tEntry);
       
  2313 		if(error!=KErrNotFound) User::LeaveIfError(error);
       
  2314 		
       
  2315 		if (error == KErrNone && (tEntry.Visible() || iOrdering.ShowInvisibleEntries()))
       
  2316 			{
       
  2317 			__ASSERT_DEBUG(service==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && service==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==(aSelection.At(count))), PanicServer(EMsvNewChildDifferentOwningService));
       
  2318 
       
  2319 			CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(tEntry, EMsvClientNull);
       
  2320 			cEntry->SetType(EMsvClientChild);
       
  2321 			iEntries->AppendL(cEntry);
       
  2322 			CleanupStack::Pop(); // cEntry
       
  2323 			// resort the children
       
  2324 			iSortedChildren->AppendL(&cEntry->Entry());
       
  2325 			}
       
  2326 		else
       
  2327 			newChildren->Delete(count);
       
  2328 		}
       
  2329 	
       
  2330 	if (newChildren->Count())
       
  2331 		iSortedChildren->SortL(iOrdering);
       
  2332 	CleanupStack::Pop(); // newChildren
       
  2333 	return newChildren;
       
  2334 	}
       
  2335 
       
  2336 
       
  2337 void CMsvEntry::CheckNewGrandchildrenL(TMsvId aId)
       
  2338 //
       
  2339 //
       
  2340 //
       
  2341 	{
       
  2342 	TInt count=iEntries->Count();
       
  2343 	while (count--)
       
  2344 		{
       
  2345 		if (iEntries->At(count)->Entry().Id()==aId && !iEntries->At(count)->Entry().Owner())
       
  2346 			{
       
  2347 			iEntries->At(count)->SetOwnerFlag(ETrue);
       
  2348 			NotifyChildChangedL(aId);
       
  2349 			break;
       
  2350 			}
       
  2351 		}
       
  2352 	}
       
  2353 
       
  2354 
       
  2355 void CMsvEntry::CheckDeletedGrandchildrenL(TMsvId aId)
       
  2356 //
       
  2357 //
       
  2358 //
       
  2359 	{
       
  2360 	TInt count=iEntries->Count();
       
  2361 	while (count--)
       
  2362 		{
       
  2363 		if (iEntries->At(count)->Entry().Id()==aId)
       
  2364 			{
       
  2365 			TMsvEntry entry;
       
  2366 			TMsvId service;
       
  2367 			TInt error = iMsvSession.Session().GetEntry(aId, service, entry);
       
  2368 			__ASSERT_DEBUG(error || service==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && service==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==aId), PanicServer(EMsvDeletedGrandChildDifferentOwningService));
       
  2369 			if (error)
       
  2370 				NotifyAllObserversL(MMsvEntryObserver::EMsvChildrenInvalid, (TAny*)&error, NULL, NULL);
       
  2371 			else if (!entry.Owner())
       
  2372 				{
       
  2373 				iEntries->At(count)->SetOwnerFlag(EFalse);
       
  2374 				NotifyChildChangedL(aId);
       
  2375 				}
       
  2376 			break;
       
  2377 			}
       
  2378 		}
       
  2379 	}
       
  2380 
       
  2381 
       
  2382 void CMsvEntry::NotifyChildChangedL(TMsvId aId)
       
  2383 //
       
  2384 //
       
  2385 //
       
  2386 	{
       
  2387 	CMsvEntrySelection* selection = DoMakeSelectionL(aId);
       
  2388 	CleanupStack::PushL(selection);
       
  2389 	NotifyAllObserversL(MMsvEntryObserver::EMsvChildrenChanged, (TAny*)selection, NULL, NULL);
       
  2390 	CleanupStack::PopAndDestroy(); // selection
       
  2391 	}
       
  2392 
       
  2393 
       
  2394 CMsvEntrySelection* CMsvEntry::DoMakeSelectionL(TMsvId aId)
       
  2395 //
       
  2396 //
       
  2397 //
       
  2398 	{
       
  2399 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  2400 	CleanupStack::PushL(selection);
       
  2401 	selection->AppendL(aId);
       
  2402 	CleanupStack::Pop(); // selection
       
  2403 	return selection;
       
  2404 	}
       
  2405 
       
  2406 
       
  2407 void CMsvEntry::ChildrenChangedL(const CMsvEntrySelection& aSelection)
       
  2408 //
       
  2409 // Children have been changed
       
  2410 //
       
  2411 	{
       
  2412 #ifndef _NO_SESSION_LOGGING_
       
  2413 	Log(_L("Children changed")); 
       
  2414 #endif
       
  2415 
       
  2416 	CMsvEntrySelection* changedChildren = new(ELeave) CMsvEntrySelection;
       
  2417 	CleanupStack::PushL(changedChildren);
       
  2418 	CMsvEntrySelection* newChildren = new(ELeave) CMsvEntrySelection;
       
  2419 	CleanupStack::PushL(newChildren);
       
  2420 	CMsvEntrySelection* deletedChildren = new(ELeave) CMsvEntrySelection;
       
  2421 	CleanupStack::PushL(deletedChildren);
       
  2422 
       
  2423 	TInt count=aSelection.Count();
       
  2424 	while (count--)
       
  2425 		{
       
  2426 		// get the changed child data
       
  2427 		TMsvId id = aSelection.At(count);
       
  2428 		TMsvEntry tEntry;
       
  2429 		TMsvId service;
       
  2430 
       
  2431 		// find the child in the sorted list
       
  2432 		TInt pos=iSortedChildren->Count();
       
  2433 		while (pos--)
       
  2434 			if (iSortedChildren->At(pos)->Id()==id)
       
  2435 				break;
       
  2436 
       
  2437 		TInt error = iMsvSession.Session().GetEntry(id, service, tEntry);
       
  2438 		if (error == KErrNotFound)
       
  2439 			{
       
  2440 			if (pos >= 0)
       
  2441 				{
       
  2442 				// The child has been deleted by the server
       
  2443 				DeleteChild(pos);
       
  2444 				deletedChildren->AppendL(id);
       
  2445 				}
       
  2446 			}
       
  2447 		else
       
  2448 			{
       
  2449 			User::LeaveIfError(error);
       
  2450 			__ASSERT_DEBUG(service==iOwningService || (iEntryPtr->iType==KUidMsvServiceEntry && service==iEntryPtr->Id()) || (iEntryPtr->iType==KUidMsvRootEntry && service==id), PanicServer(EMsvChangedChildHasDifferentOwningService));
       
  2451 
       
  2452 			if ( pos!=KErrNotFound  )
       
  2453 				{
       
  2454 				// replace it, if showing all children or its was and still is visible
       
  2455 				if (iOrdering.ShowInvisibleEntries() || tEntry.Visible())
       
  2456 					{
       
  2457 					ReplaceChildL(pos, tEntry);
       
  2458 					changedChildren->AppendL(id);
       
  2459 					continue;
       
  2460 					}
       
  2461 				}
       
  2462 
       
  2463 			if ( pos==KErrNotFound )
       
  2464 				{
       
  2465 				if (tEntry.Visible())
       
  2466 					{
       
  2467 					// the child has just been made visible so add it to our sorted list
       
  2468 					CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(tEntry, EMsvClientChild);
       
  2469 					iEntries->AppendL(cEntry);
       
  2470 					CleanupStack::Pop(); // cEntry
       
  2471 					iSortedChildren->AppendL(&cEntry->Entry());
       
  2472 					newChildren->AppendL(id);		
       
  2473 					}				
       
  2474 				}
       
  2475 			else if (!tEntry.Visible())
       
  2476 				{
       
  2477 				DeleteChild(pos);
       
  2478 				deletedChildren->AppendL(id);
       
  2479 				}
       
  2480 			}
       
  2481 		}
       
  2482 	
       
  2483 	// resort the children
       
  2484 	if (changedChildren->Count() || newChildren->Count() || deletedChildren->Count())
       
  2485 		{
       
  2486 		iSortedChildren->SortL(iOrdering);
       
  2487 		// notify the observers
       
  2488 		if (changedChildren->Count())
       
  2489 			NotifyAllObserversL(MMsvEntryObserver::EMsvChildrenChanged, (TAny*)changedChildren, NULL, NULL);
       
  2490 		if (newChildren->Count())
       
  2491 			NotifyAllObserversL(MMsvEntryObserver::EMsvNewChildren, (TAny*)newChildren, NULL, NULL);
       
  2492 		if (deletedChildren->Count())
       
  2493 			NotifyAllObserversL(MMsvEntryObserver::EMsvDeletedChildren, (TAny*)deletedChildren, NULL, NULL);
       
  2494 		}
       
  2495 
       
  2496 	CleanupStack::PopAndDestroy(3); // changedChildren, newChildren, deletedChildren
       
  2497 	}
       
  2498 
       
  2499 void CMsvEntry::DeleteChild(TInt aPosition)
       
  2500 	{
       
  2501 	TMsvId id = iSortedChildren->At(aPosition)->Id();
       
  2502 	iSortedChildren->Delete(aPosition);
       
  2503 	TInt ii=iEntries->Count();
       
  2504 	while (ii--)
       
  2505 		if (iEntries->At(ii)->Entry().Id()==id)
       
  2506 			{
       
  2507 			__ASSERT_DEBUG(iEntries->At(ii)->Type()==EMsvClientChild, PanicServer(EMsvNonChildDeleted));
       
  2508 			delete iEntries->At(ii);
       
  2509 			iEntries->Delete(ii);
       
  2510 			break;
       
  2511 			}
       
  2512 	__ASSERT_DEBUG(ii!=KErrNotFound, PanicServer(EMsvChangedChildNotFound1));
       
  2513 	}
       
  2514 
       
  2515 void CMsvEntry::ReplaceChildL(TInt aPosition, const TMsvEntry& aEntry)
       
  2516 //
       
  2517 //
       
  2518 //
       
  2519 	{
       
  2520 	CMsvClientEntry* cEntry = CMsvClientEntry::NewLC(aEntry, EMsvClientChild);
       
  2521 			
       
  2522 	TInt ii=iEntries->Count();
       
  2523 	while (ii--)
       
  2524 		{
       
  2525 		if (iEntries->At(ii)->Entry().Id()==aEntry.Id())
       
  2526 			{
       
  2527 			__ASSERT_DEBUG(iEntries->At(ii)->Type()==EMsvClientChild, PanicServer(EMsvNonChildDeleted));
       
  2528 			delete iEntries->At(ii);
       
  2529 			iEntries->At(ii) = cEntry;
       
  2530 			iSortedChildren->At(aPosition) = &cEntry->Entry();
       
  2531 			break;
       
  2532 			}
       
  2533 		}
       
  2534 	__ASSERT_DEBUG(ii!=KErrNotFound, PanicServer(EMsvChangedChildNotFound1));
       
  2535 
       
  2536 	CleanupStack::Pop(); // cEntry
       
  2537 	}
       
  2538 
       
  2539 
       
  2540 
       
  2541 void CMsvEntry::DeletedChildrenL(const CMsvEntrySelection& aSelection)
       
  2542 //
       
  2543 // Some of the children have been deleted
       
  2544 //
       
  2545 	{
       
  2546 #ifndef _NO_SESSION_LOGGING_
       
  2547 	Log(_L("Deleted children")); 
       
  2548 #endif
       
  2549 
       
  2550 	CMsvEntrySelection* deletedChildren = aSelection.CopyL();
       
  2551 	CleanupStack::PushL(deletedChildren);
       
  2552 
       
  2553 	TInt count=aSelection.Count();
       
  2554 	while (count--)
       
  2555 		{
       
  2556 		TMsvId id = aSelection.At(count);
       
  2557 		TInt ii=iSortedChildren->Count();
       
  2558 		while (ii--)
       
  2559 			{
       
  2560 			if (iSortedChildren->At(ii)->Id()==id)
       
  2561 				{
       
  2562 				iSortedChildren->Delete(ii);
       
  2563 				break;
       
  2564 				}
       
  2565 			}
       
  2566 		if (ii==KErrNotFound)
       
  2567 			deletedChildren->Delete(count);
       
  2568 		else
       
  2569 			{
       
  2570 			ii=iEntries->Count();
       
  2571 			while (ii--)
       
  2572 				{
       
  2573 				if (iEntries->At(ii)->Entry().Id()==id)
       
  2574 					{
       
  2575 					__ASSERT_DEBUG(iEntries->At(ii)->Type()==EMsvClientChild, PanicServer(EMsvNonChildDeleted));
       
  2576 					delete iEntries->At(ii);
       
  2577 					iEntries->Delete(ii);
       
  2578 					break;
       
  2579 					}
       
  2580 				__ASSERT_DEBUG(ii!=KErrNotFound, PanicServer(EMsvDeletedChildNotInMainList));
       
  2581 				}
       
  2582 			}
       
  2583 		}
       
  2584 
       
  2585 	// notify all observers
       
  2586 	if (deletedChildren->Count())
       
  2587 		{
       
  2588 		// reset the owner flag
       
  2589 		if (Count()==0)
       
  2590 			{
       
  2591 			TMsvEntry* ptr = CONST_CAST(TMsvEntry*, iEntryPtr);
       
  2592 			ptr->SetOwner(EFalse);
       
  2593 			}
       
  2594 
       
  2595 		NotifyAllObserversL(MMsvEntryObserver::EMsvDeletedChildren, (TAny*)deletedChildren, NULL, NULL);
       
  2596 		}
       
  2597 
       
  2598 	CleanupStack::PopAndDestroy(); // deletedChildren
       
  2599 	}
       
  2600 
       
  2601 
       
  2602 CMsvEntryArray* CMsvEntry::GetNewSortedListL(const TMsvSelectionOrdering& aOrdering, const CArrayFix<TUid>& aMtmList)
       
  2603 //
       
  2604 // Gets a new sorted list for new order and mtm list
       
  2605 // The entries should have the correct visiblity
       
  2606 //
       
  2607 	{
       
  2608 	CMsvEntryArray* newSortedChildren = CMsvEntryArray::NewLC(aMtmList);
       
  2609 	if (iSortedChildren->Count())
       
  2610 		{
       
  2611 //		newSortedChildren->InsertL(0, &iSortedChildren->At(0), iSortedChildren->Count());
       
  2612 //		newSortedChildren->SortL(aOrdering);
       
  2613 		TInt count=1;
       
  2614 		if (iEntries->At(count)->Type()!=EMsvClientChild)
       
  2615 			count++;
       
  2616 		TInt totalCount=iEntries->Count();
       
  2617 		for (; count<totalCount; count++)
       
  2618 			newSortedChildren->AppendL(&iEntries->At(count)->Entry());
       
  2619 		newSortedChildren->SortL(aOrdering);
       
  2620 		}
       
  2621 	CleanupStack::Pop(); // newSortedChildren
       
  2622 	return newSortedChildren;
       
  2623 	}
       
  2624 
       
  2625 
       
  2626 EXPORT_C void CMsvEntry::SetSortTypeL(const TMsvSelectionOrdering& aOrdering)
       
  2627 //
       
  2628 // Sets the sort type
       
  2629 // If this leaves the sort type has not been changed
       
  2630 //
       
  2631 /** Sets the sort order that is used when listing children, for example with ChildrenL().
       
  2632 
       
  2633 If the function leaves, the sort order is unchanged.
       
  2634 
       
  2635 @param aOrdering Sort order to use 
       
  2636 @leave KErrNoMemory Insufficient memory to resort the entries */
       
  2637 	{
       
  2638 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  2639 
       
  2640 #ifndef _NO_SESSION_LOGGING_
       
  2641 		Log(_L("Sort order changed, sorting %x, invisible %d"), aOrdering.Sorting(), aOrdering.ShowInvisibleEntries()); 
       
  2642 #endif
       
  2643 
       
  2644 	if (aOrdering.ShowInvisibleEntries()==iOrdering.ShowInvisibleEntries())
       
  2645 		{
       
  2646 		// just resort the current list of children
       
  2647 		CMsvEntryArray* newSortedChildren = GetNewSortedListL(aOrdering, *iMtmList);
       
  2648 		delete iSortedChildren;
       
  2649 		iSortedChildren = newSortedChildren;
       
  2650 		iOrdering = aOrdering;
       
  2651 		}
       
  2652 	else if (!aOrdering.ShowInvisibleEntries())
       
  2653 		{
       
  2654 		// resort the current list
       
  2655 		CMsvEntryArray* newSortedChildren = GetNewSortedListL(aOrdering, *iMtmList);
       
  2656 		delete iSortedChildren;
       
  2657 		iSortedChildren = newSortedChildren;
       
  2658 		iOrdering = aOrdering;
       
  2659 		// remove the invisible entries from sort list
       
  2660 		TInt count = iSortedChildren->Count();
       
  2661 		while (count--)
       
  2662 			if (!iSortedChildren->At(count)->Visible())
       
  2663 				iSortedChildren->Delete(count);
       
  2664 		// remove the invisible children from main list
       
  2665 		count = iEntries->Count();
       
  2666 		while (count-->=1)
       
  2667 			if (!iEntries->At(count)->Entry().Visible())
       
  2668 			{
       
  2669 			delete iEntries->At(count);
       
  2670 			iEntries->Delete(count);
       
  2671 			}
       
  2672 		}
       
  2673 	else
       
  2674 		{
       
  2675 		// keep old variable
       
  2676 		CArrayPtrFlat<CMsvClientEntry>* oldEntries = iEntries;
       
  2677 		iEntries=NULL;
       
  2678 		CMsvEntryArray* oldSortedChildren = iSortedChildren;
       
  2679 		iSortedChildren=NULL;
       
  2680 		TMsvSelectionOrdering oldOrder = iOrdering;	
       
  2681 		
       
  2682 		iOrdering = aOrdering;
       
  2683 		TRAPD(leave, DoSortTypeL(oldEntries->At(0)));
       
  2684 
       
  2685 		if (leave)
       
  2686 			{
       
  2687 			// we left, the function may have created a new iEntries,
       
  2688 			// if iEntries has been created we need to delete all the elements
       
  2689 			// except the first one, that is used in the old list
       
  2690 			// then delete iEntries, and put back the old one.
       
  2691 
       
  2692 			if(iEntries!=NULL)
       
  2693 				{
       
  2694 				if(iEntries->Count()!=0) 
       
  2695 					iEntries->Delete(0);
       
  2696 				iEntries->ResetAndDestroy();
       
  2697 				delete iEntries;
       
  2698 				}
       
  2699 			iEntries = oldEntries;
       
  2700 
       
  2701 			// iSortedChildren doesn't own the children so just delete the new one.
       
  2702 			// and put the old one back.
       
  2703 			delete iSortedChildren;
       
  2704 			iSortedChildren = oldSortedChildren;
       
  2705 			iOrdering = oldOrder;
       
  2706 			User::Leave(leave);
       
  2707 			}
       
  2708 		else
       
  2709 			{
       
  2710 			oldEntries->Delete(0); // the object is used in new list
       
  2711 			oldEntries->ResetAndDestroy();
       
  2712 			delete oldEntries;
       
  2713 			delete oldSortedChildren;
       
  2714 			}
       
  2715 		}
       
  2716 	}
       
  2717 
       
  2718 
       
  2719 
       
  2720 void CMsvEntry::DoSortTypeL(CMsvClientEntry* aContext)
       
  2721 //
       
  2722 // 
       
  2723 //
       
  2724 	{
       
  2725 	iEntries = new(ELeave) CArrayPtrFlat<CMsvClientEntry>(KMsvClientEntryArrayGranuality);
       
  2726 	iEntries->AppendL(aContext);
       
  2727 
       
  2728 	iSortedChildren = CMsvEntryArray::NewL(*iMtmList);
       
  2729 
       
  2730 	DoGetChildrenL();
       
  2731 	}
       
  2732 
       
  2733 
       
  2734 
       
  2735 EXPORT_C void CMsvEntry::SetMtmListL(const CArrayFix<TUid>& aMtmList)
       
  2736 //
       
  2737 // Sets the mtm list
       
  2738 // If this leaves the mtm list has not been changed
       
  2739 //
       
  2740 /** Sets the MTM order to the specified sort order. When children of an entry are 
       
  2741 sorted, entries belonging to the same MTM type can be grouped together. 
       
  2742 
       
  2743 MTM grouping can be switched on or off through setting the appropriate TMsvSelectionOrdering 
       
  2744 value by SetSortTypeL(). 
       
  2745 
       
  2746 If the function leaves, the sort order is unchanged.
       
  2747 
       
  2748 @param aMtmList The order of MTMs to use for sorting 
       
  2749 @leave KErrNoMemory Insufficient memory to resort the entries */
       
  2750 	{
       
  2751 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  2752 
       
  2753 	// create new mtm list
       
  2754 	CArrayFixFlat<TUid>* mtmList = new(ELeave)CArrayFixFlat<TUid>(KMsvMtmListGranularity);
       
  2755 	CleanupStack::PushL(mtmList);
       
  2756 	mtmList->InsertL(0, &aMtmList.At(0), aMtmList.Count());
       
  2757 
       
  2758 	// create new sorted children list
       
  2759 	CMsvEntryArray* newSortedChildren = GetNewSortedListL(iOrdering, *mtmList);
       
  2760 	
       
  2761 	// install the new sorted children array
       
  2762 	delete iSortedChildren;
       
  2763 	delete iMtmList;
       
  2764 	iSortedChildren = newSortedChildren;
       
  2765 	iMtmList = mtmList;
       
  2766 	
       
  2767 	CleanupStack::Pop(); // mtmList
       
  2768 	}
       
  2769 
       
  2770 
       
  2771 TBool CMsvEntry::IsAChild(TMsvId aId) const
       
  2772 //
       
  2773 // Returns true if the entry is a child
       
  2774 //
       
  2775 	{
       
  2776 	TInt count=iSortedChildren->Count();
       
  2777 	while (count--)
       
  2778 		{
       
  2779 		if (iSortedChildren->At(count)->Id()==aId)
       
  2780 			return ETrue;
       
  2781 		}
       
  2782 	return EFalse;
       
  2783 	}
       
  2784 
       
  2785 TBool CMsvEntry::AreChildren(const CMsvEntrySelection& aSelection) const
       
  2786 //
       
  2787 // Returns true if all the entries are children
       
  2788 //
       
  2789 	{
       
  2790 	TInt count = aSelection.Count();
       
  2791 	if(!count)
       
  2792 	    {
       
  2793         return EFalse;
       
  2794 	    }
       
  2795 	else
       
  2796 	    {
       
  2797         while (count--)
       
  2798             {
       
  2799             if (!IsAChild(aSelection.At(count)))
       
  2800                 {
       
  2801                 return EFalse;
       
  2802                 }
       
  2803             }
       
  2804 	    }
       
  2805 	return ETrue;
       
  2806 	}
       
  2807 
       
  2808 
       
  2809 EXPORT_C TBool CMsvEntry::HasStoreL() const
       
  2810 /** Checks if the context has an associated message store.
       
  2811 
       
  2812 @return ETrue: entry has a message store EFalse: entry does not have a message 
       
  2813 store */
       
  2814 	{
       
  2815 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
       
  2816 	if(iMsvSession.StoreManager().DoesAnyStoreExists(iEntryPtr->Id(), this->Entry().iMtm))
       
  2817 		return ETrue;
       
  2818 	else
       
  2819 		return iMsvSession.StoreManager().FileStoreExistsL(iEntryPtr->Id());
       
  2820 #else
       
  2821 	return iMsvSession.StoreManager().FileStoreExistsL(iEntryPtr->Id());
       
  2822 #endif
       
  2823 	}
       
  2824 
       
  2825 /** Sets or clears multiple fields in a selection of children of the context.
       
  2826 
       
  2827 Fields to change are specified using a bitmask of TMsvAttribute values. Possible 
       
  2828 fields that can be changed using this function are the PC synchronisation, Visibility, 
       
  2829 Pending Deletion, Read, In-preparation, Connected, and New flags. 
       
  2830 
       
  2831 @param aSelection The entries to change
       
  2832 @param aSetAttributes A bitmask of the fields to set
       
  2833 @param aClearAttributes A bitmask of the fields to clear
       
  2834 @leave KErrNotFound An entry was not a child of the context
       
  2835 @see CMsvSession::ChangeAttributesL() 
       
  2836 */
       
  2837 EXPORT_C void CMsvEntry::ChangeAttributesL(const CMsvEntrySelection& aSelection, TUint aSetAttributes, TUint aClearAttributes)
       
  2838 	{
       
  2839 #ifndef _NO_SESSION_LOGGING_
       
  2840 	Log(_L("ChangeAttributesL")); 
       
  2841 #endif
       
  2842 
       
  2843 	__ASSERT_DEBUG(iState==EValid || iState==EInvalidDeletedContext || iState==EInvalidChangingContext, PanicServer(EMsvEntryStateUndetermined));
       
  2844 	__ASSERT_DEBUG(aSelection.Count(), PanicServer(EMsvEmptySelection));
       
  2845 
       
  2846 	if (!AreChildren(aSelection))
       
  2847 		User::Leave(KErrNotFound);
       
  2848 
       
  2849 	iMsvSession.Session().ChangeAttributesL(aSelection, aSetAttributes, aClearAttributes);
       
  2850 	}
       
  2851