pimappservices/calendar/server/src/agsentrymodel.cpp
changeset 0 f979ecb2b13e
child 12 38571fd2a704
child 45 b6db4fd4947b
equal deleted inserted replaced
-1:000000000000 0:f979ecb2b13e
       
     1 // Copyright (c) 1997-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 #include "agsentrymodel.h"
       
    17 
       
    18 #include "agsalarm.h"
       
    19 #include "agsasyncdelete.h"
       
    20 #include "agsattachmentindex.h"
       
    21 #include "agscategoryindex.h"
       
    22 #include "agscategorylist.h"
       
    23 #include "agsentrymanager.h"
       
    24 #include "agmentry.h"
       
    25 #include "agsextractor.h"
       
    26 #include "agsfileconverter.h"
       
    27 #include "agsiterator.h"
       
    28 #include "agsstreamidset.h"
       
    29 #include "agssort.h"
       
    30 #include "agmutil.h"
       
    31 #include "agmattendee.h"
       
    32 #include "agmcategory.h"
       
    33 #include "agssortinstance.h"
       
    34 #include "agsindex.h"
       
    35 #include "agmcontent.h"
       
    36 #include "agsfilemanager.h"
       
    37 #include "agsmain.h"
       
    38 #include "agssess.h"
       
    39 #include "agstzruleindex.h"
       
    40 #include <calnotification.h>
       
    41 #include "agsinstanceiterator.h"
       
    42 
       
    43 #include "agmdebug.h"
       
    44 
       
    45 #include <e32math.h>
       
    46 #include <e32property.h>
       
    47 #include <s32file.h>
       
    48 
       
    49 
       
    50 // Compact threshold dependent on the number of operations
       
    51 const TInt KCompactOperationsThreshold = 32;
       
    52 
       
    53 /** This is called when opening an agenda file
       
    54 @internalComponent
       
    55  */
       
    56 CAgnEntryModel* CAgnEntryModel::NewL(CAgnServFile* aAgnServerFile)
       
    57 	{
       
    58 	CAgnEntryModel* self = new (ELeave) CAgnEntryModel();
       
    59 	
       
    60 	CleanupStack::PushL(self);
       
    61 	self->ConstructL(aAgnServerFile);
       
    62 	CleanupStack::Pop();
       
    63 	
       
    64 	return (self);
       
    65 	}
       
    66 
       
    67 /** Constructs a CAgnEntryModel object
       
    68 @internalComponent
       
    69  */
       
    70 void CAgnEntryModel::ConstructL(CAgnServFile* aAgnServerFile)
       
    71 
       
    72 	{
       
    73 	iUpdateAlarm = ETrue;
       
    74 	iModelStreamIdSet = CAgnModelStreamIdSet::NewL();
       
    75 	iEntryManager = CAgnEntryManager::NewL();
       
    76 	iNextLocalUidValue = 1;
       
    77 	iNextAttachmentUid = 1;
       
    78 
       
    79 	if ( aAgnServerFile )
       
    80 		{//When opening a file
       
    81 		iAgnServerFile = aAgnServerFile;
       
    82 		iSimpleEntryTable = CAgnSimpleEntryTable::NewL(*this);
       
    83         iExtractor = new (ELeave) TAgnInstanceExtractor(*iSimpleEntryTable);
       
    84 		iCategoryIndex = CAgnCategoryIndex::NewL();
       
    85 		iAttachmentIndex = new (ELeave) CAgnAttachmentIndex;
       
    86 		CreateAlarmForServerL();
       
    87 		}
       
    88 	iIndexFileIsDirty = ETrue; 	// for safety assume that the index
       
    89 					// file is out of date. We can correct this
       
    90 					// when we read the file
       
    91 
       
    92 	iIndexFileIsPresent = ETrue; // Assume the index file is present. 
       
    93 	                             // First attempt to read it will update this
       
    94 	                             // if it is not there.
       
    95 	iTzRuleIndex = NULL;
       
    96 	}
       
    97 
       
    98 /** 
       
    99 Frees all resources owned by the agenda model, prior to its destruction. 
       
   100 
       
   101 @internalComponent
       
   102 @capability None
       
   103 */
       
   104 CAgnEntryModel::~CAgnEntryModel()
       
   105 	{
       
   106 	ResetRollback();
       
   107 	delete iCategoryIndex;
       
   108 	delete iAttachmentIndex;
       
   109 	delete iTzRuleIndex;
       
   110 	delete iExtractor;	
       
   111 	delete iSimpleEntryTable;
       
   112 	delete iAlarm;
       
   113 	delete iModelStreamIdSet;
       
   114 	delete iEntryManager;
       
   115 	delete iCalConverter;
       
   116 	}
       
   117 
       
   118 const CAgnServFile& CAgnEntryModel::AgnServFile()
       
   119 	{
       
   120 	return *iAgnServerFile;
       
   121 	}
       
   122 
       
   123 /** Load up the stream network
       
   124  */
       
   125 void CAgnEntryModel::DoOpenL(const TStreamId& aModelStreamId)
       
   126 	{
       
   127 	delete iCalConverter;
       
   128 	iCalConverter = NULL;
       
   129 	
       
   130 	// Check if a calendar converter is needed (old version file)
       
   131 	//
       
   132 	TAgnVersion fileVersion;
       
   133 	CalCommon::TCalFileVersionSupport status;
       
   134 	iAgnServerFile->GetFileVersionSupportStatusL(fileVersion,status);
       
   135 
       
   136 	if ( status == CalCommon::EFileNeedsConverting )
       
   137 		{
       
   138 		if ( iAgnServerFile->IsReadOnly() )
       
   139 			{
       
   140 			User::Leave(KErrAccessDenied);
       
   141 			}
       
   142 
       
   143 		iCalConverter = CalFileVersionUtils::CreateConverterL(fileVersion, *iAgnServerFile);
       
   144 		iModelStreamIdSet->LoadL(StreamStore(), aModelStreamId, *iCalConverter);
       
   145 		}
       
   146 	else
       
   147 		{
       
   148 		iTzRuleIndex = CAgnTzRuleIndex::NewL(*iAgnServerFile->Dictionary(), *iAgnServerFile->StoreL());
       
   149 		iModelStreamIdSet->LoadL(StreamStore(), aModelStreamId);
       
   150 		//If the Calendar file needs to be converted, CheckTzDbModificationL should be called after the file conversion is completed (in method LoadNewStreamStoreL). 
       
   151 		TAgnVersion curVersion = CalFileVersionUtils::CurrentFileVersion();
       
   152 		if(status == CalCommon::EFileIsCurrentVersion && !(fileVersion == curVersion))
       
   153 			{
       
   154 			//access to here means the format of index file has been changed but not to the rest
       
   155 			//Changing the index file format does not cause DC but we need to ignore the old index files
       
   156 			iIndexFileIsDirty = EFalse;
       
   157 			iIndexFileIsPresent = EFalse;
       
   158 			// Mark the existing index file as dirty and delete them.
       
   159 			// Trap the leave to keep things running, but there is nothing
       
   160 			// we can do if the file can't be deleted.
       
   161 			TRAP_IGNORE(MarkIndexFileAsDirtyL());
       
   162 			
       
   163 			//Change the version of file to be current version.
       
   164 			TRAP_IGNORE(iModelStreamIdSet->ChangeFileVersionL(StreamStore(), aModelStreamId, curVersion));
       
   165 			}
       
   166 		}
       
   167 	
       
   168 	GetFileIdL();
       
   169 	InternalizeNextUidValuesL();
       
   170 	InternalizeEntryManagerL();
       
   171 	}
       
   172 
       
   173 void CAgnEntryModel::CheckTzDbModificationL()
       
   174 	{
       
   175 	if(iTzRuleIndex)
       
   176 		{
       
   177 		iTzRuleIndex->CheckTzDbModificationL(*iAgnServerFile);
       
   178 		}
       
   179 	}
       
   180 
       
   181 /** Opens an existing model store, whose root ID is aModelStreamId in the store aStore.
       
   182 
       
   183 @capability None
       
   184 @param aStore The store in which the model's data is stored.
       
   185 @param aId The root stream ID of the store aStore.
       
   186 
       
   187 @internalComponent
       
   188 */
       
   189 void CAgnEntryModel::OpenL(CStreamStore& aStore, const TStreamId& aModelStreamId) 
       
   190 	{	
       
   191 	Reset();
       
   192 	
       
   193 	iEntryManager->SetStore(aStore);
       
   194 	DoOpenL(aModelStreamId);
       
   195 	}
       
   196 
       
   197 TStreamId CAgnEntryModel::CreateL(CStreamStore& aStore) 
       
   198 	{
       
   199 	Reset();
       
   200 
       
   201 	iEntryManager->SetStore(aStore);
       
   202 
       
   203 	TStreamId headStreamId = iModelStreamIdSet->CreateL(aStore, CalFileVersionUtils::CurrentFileVersion());
       
   204 
       
   205 	// save the next unique id value to the store
       
   206 	iNextLocalUidValue = 1;
       
   207 	iNextAttachmentUid = 1;
       
   208 	ExternalizeNextUidValuesL();
       
   209 
       
   210 	// save the entry store object to the store
       
   211 	ExternalizeEntryManagerL();
       
   212 	
       
   213 	TTime creationDate; 
       
   214 	creationDate.UniversalTime();
       
   215 	iFileId = creationDate.Int64();
       
   216 	TInt threeDidgit=Math::Random() % 1000;
       
   217 	iFileId = iFileId - threeDidgit;// Ensure the file ID is unique even when two files have been created at the same time.
       
   218 	ExternalizeFileIdL(aStore, iModelStreamIdSet->FileInformationStreamId());
       
   219 	StreamStore().CommitL();
       
   220 
       
   221 	return (headStreamId);
       
   222 	}
       
   223 
       
   224 void CAgnEntryModel::ExternalizeFileIdL(CStreamStore& aStore, const TStreamId& aStreamId) const
       
   225 	{
       
   226 	RStoreWriteStream out;
       
   227 	// save file id
       
   228 	out.ReplaceLC(aStore, aStreamId);
       
   229 	out << iFileId;
       
   230 	out.CommitL();
       
   231 	CleanupStack::PopAndDestroy(); //out
       
   232 	}
       
   233 
       
   234 /**
       
   235 Adds aEntry to the store and returns its resulting entry id.
       
   236 @capability None
       
   237 */
       
   238 TAgnEntryId CAgnEntryModel::DoAddEntryL(CAgnEntry& aEntry)
       
   239 	{
       
   240 	// If local UID is not set or if it's already used, then the entry is assigned a new local uid.
       
   241 	TBool useNextLocalUid = EFalse;
       
   242 	if (aEntry.LocalUid() == 0 || iSimpleEntryTable->GetEntry(aEntry.LocalUid()) != NULL)
       
   243 		{
       
   244 		useNextLocalUid = ETrue;
       
   245         while (iSimpleEntryTable->GetEntry(++iNextLocalUidValue) != NULL)
       
   246             {
       
   247             }
       
   248        	aEntry.SetLocalUid(iNextLocalUidValue);
       
   249 		}
       
   250 
       
   251 	TAgnEntryId nullId;
       
   252 	aEntry.SetEntryId(nullId);
       
   253 
       
   254 	StoreExternalAttributesL(aEntry);
       
   255 	
       
   256 	CopyAttachmentFileToDifferentPlaceL(aEntry);
       
   257 
       
   258 	//Add the tz rules in the entry to tz rule index before it is stored in entry manager.
       
   259 	if(iTzRuleIndex)
       
   260 		{
       
   261 		iTzRuleIndex->AddTzRuleL(aEntry);
       
   262 		}
       
   263 	
       
   264 	TStreamId newStreamId = iEntryManager->AddEntryL(aEntry);
       
   265 	if ( newStreamId != KNullStreamId )
       
   266 		{
       
   267 		iModelStreamIdSet->EntryStreamIdSet().AddL(newStreamId);
       
   268 		}
       
   269 	
       
   270 	TAgnEntryId entryId = aEntry.EntryId();
       
   271 	
       
   272 	if ( useNextLocalUid )
       
   273 		{
       
   274 		ExternalizeNextUidValuesL();			
       
   275 		}
       
   276 	
       
   277 	iEntryManager->StoreBuffersL();
       
   278 	ExternalizeEntryManagerL();
       
   279 	
       
   280 	UpdateIndexL(aEntry, NULL, EAdd);
       
   281 
       
   282 	// Don't commit on add. CommitL is called from CalInterimAPI after a number have been added.
       
   283 		
       
   284 	return (entryId);
       
   285 	}
       
   286 
       
   287 //It could copy the attachment to a different drive if it is the same as the existing one but with a different drive name
       
   288 //or, it could copy the attachment form a different calendar file folder.
       
   289 void CAgnEntryModel::CopyAttachmentFileToDifferentPlaceL(CAgnEntry& aEntry)
       
   290     {
       
   291     const TInt KAttachCount = aEntry.AttachmentCount();
       
   292     for (TInt ii = 0; ii < KAttachCount; ++ii)
       
   293         {
       
   294         CAgnAttachment& attach = aEntry.Attachment(ii);
       
   295         if (attach.Uid() && attach.Type() == CCalContent::EDispositionInline)
       
   296             {
       
   297             CAgnAttachmentFile* attachFile = static_cast<CAgnAttachmentFile*>(&attach);
       
   298             if(IsAttachmentFileFromSameSessionL(attachFile->FileName()))
       
   299                 {
       
   300                 const TDesC& existFileName = iAttachmentIndex->FileName(attach.Uid());
       
   301                 if(existFileName != KNullDesC())
       
   302                     {//There exists an attachment with same uid 
       
   303                     TDriveName oldDrive = existFileName.Left(2);
       
   304                     TDriveName newDrive = attachFile->Drive();
       
   305                     if(oldDrive.CompareF(newDrive) != 0)//drive is different
       
   306                         {
       
   307                     //Copy file to a new drive with the same name
       
   308                         HBufC* newfileName = existFileName.AllocLC();
       
   309                         newfileName->Des().Replace(0,2,newDrive);
       
   310                         iAgnServerFile->CopyFileL(existFileName, newfileName->Des());
       
   311                         attachFile->SetFileNameL(*newfileName);
       
   312                         CleanupStack::PopAndDestroy(newfileName);
       
   313                         }
       
   314                     }
       
   315                 }
       
   316             else if (iAgnServerFile->FileExistsL(attachFile->FileName())) 
       
   317                 { //Attachment has been copied from a different calendar session
       
   318                 TParsePtrC parseOriginalFile(attachFile->FileName()); 
       
   319                 HBufC* fileName = GenerateFilenameLC(parseOriginalFile.Drive(), parseOriginalFile.NameAndExt());
       
   320                 iAgnServerFile->CopyFileL(attachFile->FileName(), fileName->Des());
       
   321                 attachFile->SetFileNameL(fileName->Des());
       
   322                 CleanupStack::PopAndDestroy(fileName);
       
   323                 attachFile->SetUid(iNextAttachmentUid++);
       
   324                 }
       
   325             }
       
   326         }
       
   327     }
       
   328 //Find out if the attachment is copied from a different server session
       
   329 TBool CAgnEntryModel::IsAttachmentFileFromSameSessionL(const TDesC& aAttachmentFile)
       
   330     {
       
   331     TBool ret = ETrue;
       
   332     if(aAttachmentFile.FindF(iAgnServerFile->PrivatePath()) != KErrNotFound)
       
   333 
       
   334         {//The file name is something, for example,
       
   335         //c:\private\private\10003a5c\calendar_filename_a\0\attachmentfilename
       
   336         //We need to find out the calendar name where the attachment belongs to see if it is the same file as the current Calendar file. 
       
   337         TInt lengthPath = iAgnServerFile->PrivatePath().Length();
       
   338         const TInt lengthDrive = 2;
       
   339         //tempRemovedPath1 =  calendar_filename_a\0\attachmentfilename
       
   340         TPtrC tempRemovedPath1(aAttachmentFile.Mid(lengthPath + lengthDrive));
       
   341         //tempRemovedPath2 =  calendar_filename_a
       
   342         TPtrC tempRemovedPath2(tempRemovedPath1.Left(tempRemovedPath1.Locate('\\')));
       
   343         //calName = calendar_filename
       
   344         TPtrC calName(tempRemovedPath2.Left(tempRemovedPath2.LocateReverse('_')));
       
   345         TParsePtrC parseFile(iAgnServerFile->FileName()); 
       
   346         if(calName.CompareF(parseFile.NameAndExt()) != 0)
       
   347             {
       
   348             ret = EFalse;
       
   349             }
       
   350         }
       
   351     return ret;
       
   352     }
       
   353 
       
   354 // aEntry is the entry that has been changed. If the change is an update, then aOriginalEntry gives 
       
   355 // details about the original entry.
       
   356 void CAgnEntryModel::NotifyChangeL(const CAgnServerSession& aSession, CAgnEntry* aEntry, 
       
   357 									 MCalChangeCallBack2::TChangeType aChangeType, CAgnInstanceInfo* aOriginalEntry)
       
   358 	{
       
   359 	TAgnChange change;
       
   360 	change.iOperationType = aChangeType;
       
   361 	
       
   362 	if ( aEntry )
       
   363 		{
       
   364 		change.iEntryType = aEntry->Type();
       
   365 		change.iEntryId = aEntry->LocalUid();
       
   366 		change.iRepeatRule = aEntry->RptDef();
       
   367 		change.iStartTimeOfEntryUtc = aEntry->StartTime().UtcL();
       
   368 		change.iEndTimeOfEntryUtc = aEntry->ValidToTimeLocalL();
       
   369 			
       
   370 		if ( aOriginalEntry )
       
   371 			{
       
   372 			change.iOriginalRepeatRule = aOriginalEntry->RptDef();
       
   373 			change.iOriginalStartTimeUtc = aOriginalEntry->StartTimeUtc();
       
   374 			change.iOriginalEndTimeUtc = aOriginalEntry->EndTimeUtc();
       
   375 			}
       
   376 		else
       
   377 			{
       
   378 			change.iOriginalRepeatRule = NULL;
       
   379 			change.iOriginalStartTimeUtc = Time::NullTTime();
       
   380 			change.iOriginalEndTimeUtc = Time::NullTTime();
       
   381 			}
       
   382 		}
       
   383 	else
       
   384 		{
       
   385 		change.iEntryType = CCalEntry::EAppt;
       
   386 		change.iEntryId = 0;
       
   387 		change.iStartTimeOfEntryUtc = Time::NullTTime();
       
   388 		change.iEndTimeOfEntryUtc = Time::NullTTime();
       
   389 		change.iRepeatRule = NULL;
       
   390 		change.iOriginalStartTimeUtc = Time::NullTTime();
       
   391 		change.iOriginalEndTimeUtc = Time::NullTTime();
       
   392 		change.iOriginalRepeatRule = NULL;
       
   393 		}
       
   394 	
       
   395 	change.iSession = const_cast<CAgnServerSession*>(&aSession);
       
   396 	GetFileIdL();
       
   397 	change.iFileId = iFileId;
       
   398 	NotifySessionsOfChangeL(change);
       
   399 	}
       
   400 
       
   401 void CAgnEntryModel::NotifySessionsOfChangeL(const TAgnChange& aChange)
       
   402 	{
       
   403 	RPointerArray<CAgnServerSession> sessions;
       
   404 	CleanupClosePushL(sessions);
       
   405 	iAgnServerFile->Server().FetchSessionsL(sessions);
       
   406 	const TInt count = sessions.Count();
       
   407 	for ( TInt i = 0; i < count; ++i )
       
   408 		{
       
   409 		sessions[i]->AddChangeL(aChange);
       
   410 		}
       
   411 	CleanupStack::PopAndDestroy(&sessions); // sessions.Close()
       
   412 	}
       
   413 
       
   414 void CAgnEntryModel::NotifyPublishAndSubscribeL(TAgnChangeFilter& aChangeFilter)
       
   415 	{
       
   416 	// if publish and subcribe is enabled...	
       
   417 	if ( aChangeFilter.PubSubEnabled() )
       
   418 		{
       
   419 		// ...get and set the Publish and Subscribe data
       
   420 		TCalPubSubData calPubSubData;
       
   421 		calPubSubData.iFileNameHash = iAgnServerFile->FileNameHash();
       
   422 		calPubSubData.iTimeOfChangeUtc.UniversalTime(); 
       
   423 		
       
   424 		TPckgBuf<TCalPubSubData> calBuf(calPubSubData);
       
   425 		
       
   426 		// publish the update
       
   427 		if ( aChangeFilter.TodoChanged() )
       
   428 			{
       
   429 			User::LeaveIfError(RProperty::Set(KCalPubSubCategory, ECalPubSubTodoNotification, calBuf));
       
   430 			}
       
   431 		else
       
   432 			{
       
   433 			User::LeaveIfError(RProperty::Set(KCalPubSubCategory, ECalPubSubEventNotification, calBuf));
       
   434 			}
       
   435 		
       
   436 		aChangeFilter.SetPubSubChange(TAgnChangeFilter::ENoChange);
       
   437 		}
       
   438 	}
       
   439 
       
   440 /**
       
   441 Add a entry to the file. This function decides whether a new entry should be added or if an existing entry 
       
   442 should be replaced. It also handles the adding of child entries.
       
   443 @internalComponent
       
   444 @return the TAgnEntryId of the newly added entry.
       
   445 @param aEntry The entry being stored.
       
   446 @param aChangeFilter Specifies the notification filter for the session adding the entry.
       
   447 @leave KErrArgument If aEntry is a parent but contains a recurrence Id.
       
   448 @leave KErrNotFound If aEntry is a child entry whose parent entry doesn't exist in the calendar store.
       
   449 @leave KErrArgument If aEntry is a child entry with a different time mode (fixed / floating) to its parent entry.
       
   450 */
       
   451 TAgnEntryId CAgnEntryModel::StoreL(CAgnEntry& aEntry, TAgnChangeFilter* aChangeFilter)
       
   452 	{
       
   453 	iChangeFilter = aChangeFilter;
       
   454 	TAgnEntryId returnId;
       
   455 
       
   456 	if ( aEntry.GsDataType() == CGsData::EParent )
       
   457 		{
       
   458 		_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Entry to be stored is a parent");)
       
   459 		_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Checking if an entry with the same GUID already exists");)
       
   460 		
       
   461 		// it is a parent entry
       
   462 		CAgnEntry* existingEntryToReplace = FetchEntryL(aEntry.Guid());
       
   463 
       
   464 		if (existingEntryToReplace == NULL && aEntry.LocalUid() != 0)
       
   465 			{
       
   466 			//This is used for the case when sync a updated entry from remote sync server.
       
   467 			//Some servers may filter out GUID assigned by client and only info we can get
       
   468 			//to update a entry is by using its local ID.
       
   469 			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Attempting to fetch using localUid to fetch the entry from the server");)
       
   470 			existingEntryToReplace = FetchEntryL(aEntry.LocalUid());
       
   471 			}
       
   472 				
       
   473 		if ( existingEntryToReplace)
       
   474 			{
       
   475 			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: An entry with the same GUID already exists");)
       
   476 
       
   477 			CleanupStack::PushL(existingEntryToReplace);
       
   478 			if (existingEntryToReplace->Type() == aEntry.Type())
       
   479 				{
       
   480 				_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Existing entry type matches incoming entry's type");)
       
   481 
       
   482 				// if this entry is the same type as the existing entry, update the existing entry
       
   483 				aEntry.SetEntryId(existingEntryToReplace->EntryId());
       
   484 				aEntry.SetLocalUid(existingEntryToReplace->LocalUid());
       
   485 				
       
   486 				_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Setting Ids using the existing entry: LocalUid= %d, EntryId= %d", aEntry.LocalUid(),aEntry.EntryId().Value());)
       
   487 				
       
   488 			        const RArray<TGsChildRefData>& KChildIds = existingEntryToReplace->ChildIds();
       
   489 			        const TInt KCount = KChildIds.Count();
       
   490 			        for ( TInt ii = 0; ii < KCount; ++ii )
       
   491 			            {
       
   492 			            aEntry.AddChildIdL(KChildIds[ii]);
       
   493 			            }
       
   494 
       
   495 				aEntry.SetLastModifiedDate();
       
   496 	
       
   497 				UpdateEntryL(aEntry, iChangeFilter, ETrue);
       
   498 
       
   499 				returnId = aEntry.EntryId();
       
   500 				}
       
   501 			else 
       
   502 				{
       
   503 				_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Existing entry types is different to incoming entry's type");)
       
   504 				_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Delete the existing entry and add the incoming entry as a new one");)
       
   505 				
       
   506 				// if the entry is a different type, delete the old entry and add the new one 
       
   507 				DeleteEntryL(*existingEntryToReplace, ETrue, iChangeFilter);
       
   508 				returnId = AddEntryL(aEntry);
       
   509 				}
       
   510 
       
   511 			CleanupStack::PopAndDestroy(existingEntryToReplace);
       
   512 			}
       
   513 		else
       
   514 			{
       
   515 			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Matching existing entry not found. Adding a new entry");)
       
   516 			returnId = AddEntryL(aEntry);
       
   517 			}
       
   518 		}
       
   519 	else
       
   520 		{
       
   521 		_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Entry to be stored is a child");)
       
   522 		//if this is a child entry, fetch the parent from the child's GUID (if present) or Local UID
       
   523 		CAgnEntry* parentEntry = NULL;
       
   524 		if ( aEntry.Guid() != KNullDesC8 )
       
   525 			{
       
   526 			parentEntry = FetchEntryL(aEntry.Guid());
       
   527 			}
       
   528 		else
       
   529 			{
       
   530 			parentEntry = FetchEntryL(aEntry.ParentId());
       
   531 			}
       
   532 		
       
   533 		if(parentEntry==NULL)
       
   534 			{
       
   535 			#if defined (__CAL_BASIC_LOGGING__) || (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING)
       
   536 				AgmDebug::DebugLog("StoreL: KErrNotFound: Parent entry with the GUID or localUid doesnt exist");	
       
   537 			#endif
       
   538 	
       
   539 			User::Leave(KErrNotFound);
       
   540 			}
       
   541 		
       
   542 		CleanupStack::PushL(parentEntry);
       
   543 
       
   544 		if ( parentEntry->TimeMode() != aEntry.TimeMode() ||  parentEntry->Type() != aEntry.Type() )
       
   545 			{
       
   546 			#if defined (__CAL_BASIC_LOGGING__) || (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
       
   547 				AgmDebug::DebugLog("StoreL: KErrArgument: Child entry with different time mode or type from the parent entry is not allowed");
       
   548 			#endif
       
   549 			
       
   550 			// don't allow a child entry to be different time mode or type from the parent entry
       
   551 			User::Leave(KErrArgument);
       
   552 			}
       
   553 		
       
   554 		if ( ! aEntry.RecurrenceId().IsSet())
       
   555 			{
       
   556 			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Recurrence ID not set on the incoming entry. Setting it using the parent");)
       
   557 			aEntry.SetRecurrenceIdFromParentL(*parentEntry);
       
   558 			}
       
   559 		
       
   560 		// We allow only repeating parents to have children that attempt to change a parent 
       
   561 		// schedule.(If the user's intention is to modify a non-repeating parent, the entire
       
   562 		// parent should be replaced with a new entry).
       
   563 		const CAgnRptDef* KParentRptDef = parentEntry->RptDef();
       
   564 		
       
   565 		if(KParentRptDef==NULL)
       
   566 			{
       
   567 			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Parent is not repeating. Only repeating parents are allowed to have children");)
       
   568 			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: If the user's intention is to modify a non-repeating parent, the entire parent should be replaced with a new entry");)
       
   569 		
       
   570 			User::Leave(KErrArgument);
       
   571 			}
       
   572 				
       
   573 		if ( aEntry.RptDef() )
       
   574 			{
       
   575 			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Incoming entry is a repeating child entry");)
       
   576 			returnId = AddRepeatingChildEntryUpdateParentRuleL(*parentEntry, aEntry);
       
   577 			}
       
   578 		else	
       
   579 			{	
       
   580 			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Incoming entry is a non-repeating child entry");)
       
   581 			returnId = AddNonRepeatingChildEntryUpdateParentExceptionsL(*parentEntry, aEntry);						
       
   582 			}
       
   583 		
       
   584 		CleanupStack::PopAndDestroy(parentEntry);
       
   585 		}
       
   586 		_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Entry added successfully");)
       
   587 		_DBGLOG_ENTRY(AgmDebug::DebugLogEntryL(aEntry, EDumpEntryAll);)
       
   588 
       
   589 	return (returnId);
       
   590 	}
       
   591 
       
   592 TStreamId CAgnEntryModel::WriteDescriptorToStreamL(const TDesC& aString)
       
   593 	{
       
   594 	if (aString.Length() > 0)
       
   595 		{
       
   596 		RStoreWriteStream out;
       
   597 		TStreamId id = out.CreateLC(StreamStore());
       
   598 		out.WriteUint32L(aString.Length());
       
   599 		out << aString;
       
   600 		out.CommitL();
       
   601 		CleanupStack::PopAndDestroy(); //out
       
   602 		return id;
       
   603 		}
       
   604 	return KNullStreamId;
       
   605 	}
       
   606 
       
   607 /** 
       
   608 Store those entry properties which are stored in a separate stream: summary, description, alarm action.
       
   609 @capability WriteUserData
       
   610 */
       
   611 void CAgnEntryModel::StoreExternalAttributesL(CAgnEntry& aEntry)
       
   612 	{
       
   613 	TStreamId id = WriteDescriptorToStreamL(aEntry.Description());
       
   614 	aEntry.SetDescriptionStreamId(id);
       
   615 	
       
   616 	id = WriteDescriptorToStreamL(aEntry.Summary());
       
   617 	aEntry.SetSummaryStreamId(id);
       
   618 
       
   619 	if ( aEntry.AlarmAction() )
       
   620 		{
       
   621 		RStoreWriteStream out;
       
   622 		id = out.CreateLC(StreamStore());
       
   623 		out << *aEntry.AlarmAction();
       
   624 		out.CommitL();
       
   625 		CleanupStack::PopAndDestroy(); //out
       
   626 		aEntry.SetAlarmActionStreamId(id);
       
   627 		}
       
   628 	}
       
   629 
       
   630 void CAgnEntryModel::DeleteExternalAttributesL(CAgnEntry& aEntry)
       
   631 	{
       
   632 	if ( aEntry.DescriptionStreamId() != KNullStreamId )
       
   633 		{
       
   634 		StreamStore().DeleteL(aEntry.DescriptionStreamId());
       
   635 		aEntry.SetDescriptionStreamId(KNullStreamId);
       
   636 		}
       
   637 
       
   638 	if ( aEntry.SummaryStreamId() != KNullStreamId )
       
   639 		{
       
   640 		StreamStore().DeleteL(aEntry.SummaryStreamId());
       
   641 		aEntry.SetSummaryStreamId(KNullStreamId);
       
   642 		}
       
   643 
       
   644 	if ( aEntry.AlarmActionStreamId() != KNullStreamId )
       
   645 		{
       
   646 		StreamStore().DeleteL(aEntry.AlarmActionStreamId());
       
   647 		aEntry.SetAlarmActionStreamId(KNullStreamId);
       
   648 		}
       
   649 	}
       
   650 
       
   651 void CAgnEntryModel::UpdateExternalAttributesL(CAgnEntry& aEntry)
       
   652 	{
       
   653 	// 3 scenarios where we do something for updating notes text
       
   654 	TStreamId id = KNullStreamId;
       
   655 
       
   656 	switch ( aEntry.DescriptionChange() )
       
   657 		{
       
   658 		case CAgnEntry::EAgnDataDeleted:
       
   659 			DeleteTextStreamL(aEntry.DescriptionStreamId());
       
   660 			aEntry.SetDescriptionStreamId(KNullStreamId);
       
   661 			break;
       
   662 
       
   663 		case CAgnEntry::EAgnDataAdded:
       
   664 			id = StoreTextL(aEntry.Description());
       
   665 			aEntry.SetDescriptionStreamId(id);
       
   666 			break;
       
   667 
       
   668 		case CAgnEntry::EAgnDataUpdated:
       
   669 			UpdateTextL(aEntry.Description(), aEntry.DescriptionStreamId());
       
   670 			break;
       
   671 
       
   672 		default://no changes
       
   673 			break;
       
   674 		}
       
   675 
       
   676 	// 3 scenarios where we do something for updating summary text
       
   677 	switch ( aEntry.SummaryChange() )
       
   678 		{
       
   679 		case CAgnEntry::EAgnDataDeleted:
       
   680 			DeleteTextStreamL(aEntry.SummaryStreamId());
       
   681 			aEntry.SetSummaryStreamId(KNullStreamId);
       
   682 			break;
       
   683 
       
   684 		case CAgnEntry::EAgnDataAdded:
       
   685 			id = StoreTextL(aEntry.Summary());
       
   686 			aEntry.SetSummaryStreamId(id);
       
   687 			break;
       
   688 
       
   689 		case CAgnEntry::EAgnDataUpdated:
       
   690 			UpdateTextL(aEntry.Summary(), aEntry.SummaryStreamId());
       
   691 			break;
       
   692 
       
   693 		default://no changes
       
   694 			break;
       
   695 		}
       
   696 
       
   697 	// 3 scenarios where we do something for updating alarm action
       
   698 	switch ( aEntry.AlarmActionChange() )
       
   699 		{
       
   700 		case CAgnEntry::EAgnDataDeleted:
       
   701 			DeleteAlarmActionStreamL(aEntry.AlarmActionStreamId());
       
   702 			aEntry.SetAlarmActionStreamId(KNullStreamId);
       
   703 			break;
       
   704 
       
   705 		case CAgnEntry::EAgnDataAdded:
       
   706 			id = StoreAlarmActionL(*(aEntry.AlarmAction()));
       
   707 			aEntry.SetAlarmActionStreamId(id);
       
   708 			break;
       
   709 
       
   710 		case CAgnEntry::EAgnDataUpdated:
       
   711 			UpdateAlarmActionL(*(aEntry.AlarmAction()), aEntry.AlarmActionStreamId());
       
   712 			break;
       
   713 
       
   714 		default://no changes
       
   715 			break;
       
   716 		}
       
   717 	}
       
   718 
       
   719 
       
   720 TAgnEntryId CAgnEntryModel::AddEntryL(CAgnEntry& aEntry)
       
   721 	{
       
   722 	TAgnEntryId id;
       
   723 
       
   724 	id = DoAddEntryL(aEntry);
       
   725 
       
   726 	NotifyingL(MCalChangeCallBack2::EChangeAdd, aEntry, NULL);
       
   727 
       
   728 	if (iUpdateAlarm && aEntry.HasAlarm())
       
   729 		{
       
   730 		iAlarm->FindAndQueueNextAlarmL(EFalse);
       
   731 		}
       
   732 		
       
   733 	return (id);
       
   734 	}
       
   735 
       
   736 
       
   737 // Update all the indexes which are in RAM after an entry operation (add, update, delete)
       
   738 void CAgnEntryModel::UpdateIndexL(CAgnEntry& aEntry, CAgnEntry* aOldEntry, TUpdateIndex aUpdateIndex)
       
   739 	{
       
   740 	// set guid hash before adding / updating an entry in the GUID hash index
       
   741 	if ( aEntry.GsDataType() == CGsData::EParent && ! aEntry.GuidHash() )
       
   742 		{
       
   743 		aEntry.SetGuidHash( GenerateHash8L(aEntry.Guid()) );
       
   744 		if ( aOldEntry )
       
   745 			{
       
   746 			aOldEntry->SetGuidHash( aEntry.GuidHash() );					
       
   747 			}				
       
   748 		}	
       
   749 	
       
   750  	switch( aUpdateIndex )
       
   751  		{
       
   752  		case EAdd:
       
   753 			{
       
   754 			AppendRollbackArrayL(aEntry, ETrue);
       
   755 
       
   756 			AddEntryToIndexesL(aEntry);
       
   757 			}
       
   758  			break;
       
   759 
       
   760  		case EDelete:
       
   761  			{
       
   762 			AppendRollbackArrayL(aEntry, EFalse);
       
   763 
       
   764 			iSimpleEntryTable->DeleteEntry(aEntry.EntryId()); 				
       
   765 
       
   766  			iCategoryIndex->DeleteEntryL(aEntry.EntryId());
       
   767  			iAttachmentIndex->DeleteEntryL(aEntry);
       
   768  			} 			
       
   769  			break;
       
   770  
       
   771  		case EUpdate:
       
   772 			{
       
   773 			__ASSERT_ALWAYS(aOldEntry, Panic(EAgmErrUpdateInvalid));
       
   774 			AppendRollbackArrayL(*aOldEntry, EFalse);
       
   775 			iSimpleEntryTable->DeleteEntry(aOldEntry->EntryId());
       
   776 			
       
   777 			AppendRollbackArrayL(aEntry, ETrue);
       
   778 			
       
   779 			AddEntryToIndexesL(aEntry);
       
   780 			}
       
   781  			break;
       
   782  			
       
   783  		case EBuildIndex:
       
   784  			{
       
   785 			AppendRollbackArrayL(aEntry, ETrue);
       
   786 			
       
   787 			if(iTzRuleIndex)
       
   788 				{
       
   789 				iTzRuleIndex->FetchTzRuleL(aEntry);
       
   790 				}
       
   791 			AddEntryToIndexesL(aEntry);
       
   792 			}
       
   793  			break;
       
   794  			
       
   795  		default:
       
   796  			Panic(EAgmErrInvalidIndexUpdate);
       
   797  			break;
       
   798  		}
       
   799  		// Increment the operations counter which triggers compacting upon reaching a threshold
       
   800  	++iOperationsCounter;
       
   801 	}
       
   802 
       
   803 // Add an entry to all indexes in RAM
       
   804 void CAgnEntryModel::AddEntryToIndexesL(CAgnEntry& aEntry)
       
   805 	{
       
   806 	aEntry.SetCollectionId(iAgnServerFile->CollectionId());
       
   807 	iSimpleEntryTable->AddEntryL(aEntry);
       
   808 
       
   809 	iAgnServerFile->CategoryList().AddEntryL(aEntry);
       
   810 	iCategoryIndex->UpdateEntryL(aEntry.EntryId(), aEntry);
       
   811 	iAttachmentIndex->AddEntryL(aEntry);
       
   812 	}
       
   813 
       
   814 /**
       
   815 Returns true if the entry is found to have any children which are repeating.
       
   816 @internalComponent
       
   817 @return TBool.
       
   818 @param aEntry The entry.
       
   819 */
       
   820 TBool CAgnEntryModel::EntryHasRepeatingChildrenL(const CAgnEntry& aParentEntry)
       
   821 	{
       
   822 	const RArray<TGsChildRefData>& KChildIds = aParentEntry.ChildIds();
       
   823 
       
   824 	const TInt KIdCount = KChildIds.Count();
       
   825 	
       
   826 	TBool repeatingChildExists = EFalse;
       
   827 	
       
   828 	for ( TInt pos = 0; ! repeatingChildExists && pos < KIdCount; ++pos )
       
   829 		{
       
   830 		CAgnEntry* childOfParentEntry = FetchEntryL(KChildIds[pos].ChildId());
       
   831 		if (childOfParentEntry)
       
   832 			{
       
   833 			repeatingChildExists = (childOfParentEntry && childOfParentEntry->RptDef());
       
   834 
       
   835 			delete childOfParentEntry;
       
   836 			}
       
   837 		}
       
   838 
       
   839 	return (repeatingChildExists);
       
   840 	}
       
   841 
       
   842 /**
       
   843 Deletes any non-repeating children within a specified range. This is called when adding a repeating child entry to 
       
   844 delete existing non-repeating child entries - those that appear either before or after the repeating child entry's recurrence ID,
       
   845 depending on the recurrence range.
       
   846 @internalComponent
       
   847 @param aParentEntry The parent entry
       
   848 @param aRecId Indicates the recurrence ID of the repeating child entry
       
   849 @param aRange Indicates "this and prior" or "this and future" to delete child entries on one side of the recurrence ID.
       
   850 */
       
   851 void CAgnEntryModel::DeleteNonRepeatingChildrenOutsideRangeL(const CAgnEntry& aParentEntry, const TAgnCalendarTime& aRecId, CalCommon::TRecurrenceRange aRange)
       
   852 	{
       
   853 	const RArray<TGsChildRefData>& KChildIds = aParentEntry.ChildIds();
       
   854 
       
   855 	const TInt KCount(KChildIds.Count());
       
   856 	
       
   857 	for ( TInt i = 0; i < KCount; ++i )
       
   858 		{
       
   859 		// Check if any child falls outside parent's rpt rule
       
   860 		if ( (aRecId > KChildIds[i].RecurrenceId() && aRange == CalCommon::EThisAndPrior) ||
       
   861 		     (aRecId < KChildIds[i].RecurrenceId() && aRange == CalCommon::EThisAndFuture) )
       
   862 			{
       
   863 			// Remove child if it is non-repeating
       
   864 			TCalLocalUid chIdRemove(KChildIds[i].ChildId());
       
   865 			CAgnEntry* chIdEntry = FetchEntryL(chIdRemove);
       
   866 			if (chIdEntry)
       
   867 				{
       
   868 				CleanupStack::PushL(chIdEntry);
       
   869 				
       
   870 				__ASSERT_ALWAYS( ! chIdEntry->RptDef(), Panic(EAgmErrAddingSecondRepeatingChildEntry));
       
   871 				DeleteEntryL(*chIdEntry, ETrue, iChangeFilter);
       
   872 					
       
   873 				CleanupStack::PopAndDestroy(chIdEntry);
       
   874 				}
       
   875 			}
       
   876 		}
       
   877 	}
       
   878 
       
   879 /**
       
   880 Adds a repeating child to a repeating parent, and performs the necessary adjustments to the parent's repeat rule.
       
   881 The explanation of how the parent's rpt rule is trimmed is given in the code comments.
       
   882 @internalComponent
       
   883 @param aParentEntry The parent entry
       
   884 @param aRepeatingChild The child to be added
       
   885 @leave KErrArgument If either aParentEntry or aRepeatingChild are non-repeating
       
   886 @leave KErrArgument If aRepeatingChild's RecurrenceId is aParentEntry's first or last instance
       
   887 @leave KErrNotSupported If aRepeatingChild's Range is ECurrentInstance
       
   888 @leave KErrArgument If aRepeatingChild's Range is an unexpected value
       
   889 */
       
   890 TAgnEntryId CAgnEntryModel::AddRepeatingChildEntryUpdateParentRuleL(CAgnEntry& aParentEntry, CAgnEntry& aRepeatingChild)
       
   891 	{
       
   892 	// Ensure both parent and child are repeating
       
   893 	__ASSERT_ALWAYS((aRepeatingChild.RptDef() && aParentEntry.RptDef()), User::Leave(KErrArgument));
       
   894 	TAgnCalendarTime childRecId = aRepeatingChild.RecurrenceId();
       
   895 	
       
   896 	TAgnEntryId retId;
       
   897 	
       
   898 	CAgnRptDef* parentRptDef = aParentEntry.RptDef();
       
   899 	
       
   900 	TTime recIdLocal(childRecId.LocalL());
       
   901     TDateTime recIdLocalDateTime(recIdLocal.DateTime());
       
   902     	
       
   903 	CalCommon::TRecurrenceRange range = aRepeatingChild.RecurrenceRange();
       
   904 
       
   905 	if(range == CalCommon::EThisOnly)
       
   906 		{
       
   907 		// if the range specified is EThisOnly, attempt to recalculate the recurrence range 
       
   908 		// so that the maximum number of "overlapping" entries (schedules running concurrently in the 
       
   909 		// parent and child) is removed	
       
   910 		TTime dtStartLocal = aParentEntry.StartTime().LocalL();
       
   911 		TDateTime dtStartLocalDateTime =(dtStartLocal.DateTime()); 
       
   912 	 	if (dtStartLocalDateTime.Year() == recIdLocalDateTime.Year() && 
       
   913            dtStartLocalDateTime.Month() == recIdLocalDateTime.Month() && 
       
   914            dtStartLocalDateTime.Day() == recIdLocalDateTime.Day())
       
   915 			{
       
   916 			// Check whether the recurrence ID of the child is of the same day as the 
       
   917             // first instance of the parent.  If so, assume range is ThisAndPrior
       
   918             // to avoid the parent repeating rule being completely trimmed.
       
   919             //
       
   920             // Note: It is possible that this is a previously trimmed parent, as a result of 
       
   921             //       the trimming, completely embedded by the child.  Therefore, no rejection of 
       
   922             //       such child/parent range is performed to ensure an Import->Export->Import will 
       
   923             //       not be failed.  In the rare occurrence where the child entry completely embeds
       
   924             //       the parent entry and has RecID on the same day as start/end of parent entry, it will 
       
   925             //       be allowed through.
       
   926 			range = CalCommon::EThisAndPrior;
       
   927 			}
       
   928 		else 
       
   929 			{
       
   930 			TTime dtUntilLocal = parentRptDef->LastInstanceL().LocalL();
       
   931 			
       
   932 			TDateTime dtUntilLocalDateTime =(dtUntilLocal.DateTime()); 
       
   933 			if (dtUntilLocalDateTime.Year() == recIdLocalDateTime.Year() && 
       
   934                 dtUntilLocalDateTime.Month() == recIdLocalDateTime.Month() && 
       
   935                 dtUntilLocalDateTime.Day() == recIdLocalDateTime.Day())
       
   936 	  			{
       
   937  	 			// Check whether the recurrence ID of the child is of the same day as the 
       
   938                 // last instance of the parent. If so, assume range is ThisAndFuture
       
   939                 // instances to avoid the parent repeating rule being completely trimmed.                
       
   940                 //
       
   941                 // Note: It is possible that this is a previously trimmed parent, as a result of 
       
   942                 //       the trimming, completely embedded by the child.  Therefore, no rejection of 
       
   943                 //       such child/parent range is performed to ensure an Import->Export->Import will 
       
   944                 //       not be failed.  In the rare occurrence where the child entry completely 
       
   945                 //       embeds the parent entry and has RecID on the same day as start/end of parent 
       
   946                 //       entry, it will be allowed through.
       
   947 				range = CalCommon::EThisAndFuture;
       
   948 				}
       
   949 			else
       
   950 				{
       
   951 				// Reject the child entry if it completely alters the parent entry.  This should be done by 
       
   952     			// replacing the parent schedule instead.
       
   953     			//
       
   954     			// An exception is when the parent entry's start/end date is the same as the RecID.  That
       
   955     			// could be the result of the parent being previously trimmed.
       
   956 				__ASSERT_ALWAYS(parentRptDef->LastInstanceL() > aRepeatingChild.RptDef()->LastInstanceL() ||
       
   957 				              aRepeatingChild.RptDef()->FirstInstanceL() > aParentEntry.StartTime(),
       
   958                               User::Leave(KErrArgument));
       
   959    				// if the RecId is neither at the start/end of the parent's rpt range, 
       
   960     			// then base on the distance of the beginning & end of the child recurreance range 
       
   961     			// from the RecId, determine if the range should be assumed as ThisAndFuture 
       
   962     			// or a ThisAndPrior scenario.
       
   963     			// 
       
   964     			// As this usage is most likely ThisAndFuture, so even if the distance from 
       
   965     			// beginning & end of the child repeat range is the same, assume CurrentAndFuture.                                
       
   966 				TTimeIntervalDays afterRecurrence = (aRepeatingChild.RptDef()->LastInstanceL().UtcL()).DaysFrom(childRecId.UtcL());
       
   967 				TTimeIntervalDays beforeRecurrence = childRecId.UtcL().DaysFrom(aRepeatingChild.RptDef()->FirstInstanceL().UtcL());
       
   968 				range = (afterRecurrence >= beforeRecurrence) ?
       
   969 							CalCommon::EThisAndFuture : CalCommon::EThisAndPrior;
       
   970 				}
       
   971 			}
       
   972 		aRepeatingChild.SetRecurrenceRangeL(range);
       
   973 		}
       
   974 
       
   975 	// Trim parent's repeat rule to fall in line with the new child entry,
       
   976 	// and deal with any exceptions and sporadic dates that fall within the
       
   977 	// affected period.
       
   978 
       
   979 	switch (range)
       
   980 		{
       
   981 		case CalCommon::EThisAndFuture:
       
   982 			{
       
   983 			// Reject if RecurrenceId falls on 1st instance of parent's (original) rpt rule
       
   984 			// If the User's intention is to modify the entire parent schedule, they should replace the
       
   985 			// existing parent with a new parent entry (by submitting an entry with no RecId specified).
       
   986 			TTime firstInstanceParentUtc(Time::NullTTime());
       
   987 			parentRptDef->NudgeNextInstanceUtcL(aParentEntry.StartTime().UtcL(), firstInstanceParentUtc);
       
   988 
       
   989 			// Ensure child's RecurrenceId is not the parent's first instance.
       
   990 			__ASSERT_ALWAYS(childRecId.UtcL() > firstInstanceParentUtc, User::Leave(KErrArgument));
       
   991 
       
   992 			// Store child entry
       
   993 			retId = AddChildEntryL(aRepeatingChild, aParentEntry);
       
   994 			childRecId = aRepeatingChild.RecurrenceId(); // recurrence ID may have been updated if it was an imported rec ID with no time
       
   995 			
       
   996 			// Set parent's rpt-rule end date to child's RecId (already verified RecId points to a genuine instance on the parent).
       
   997 			if (parentRptDef->RRule())
       
   998 				{
       
   999 				parentRptDef->SetUntilTime(childRecId);
       
  1000 				}
       
  1001 			}
       
  1002 			break;
       
  1003 
       
  1004 		case CalCommon::EThisAndPrior:
       
  1005 			{						
       
  1006 			// Reject if RecurrenceId falls on last instance of parent's (original) rpt rule
       
  1007 			// If the User's intention is to modify the entire parent schedule, they should replace the
       
  1008 			// existing parent with a new parent entry (by submitting an entry with no RecId specified).
       
  1009 			TTime lastInstanceParentUtc(Time::NullTTime());
       
  1010 			parentRptDef->NudgePreviousInstanceUtcL(parentRptDef->LastInstanceL().UtcL(), lastInstanceParentUtc);
       
  1011 			
       
  1012 			// Ensure child's RecurrenceId is not the parent's last instance.
       
  1013 			__ASSERT_ALWAYS(childRecId.UtcL() < lastInstanceParentUtc, User::Leave(KErrArgument));
       
  1014 			
       
  1015 			// Store child entry 
       
  1016 			retId = AddChildEntryL(aRepeatingChild, aParentEntry);
       
  1017 			childRecId = aRepeatingChild.RecurrenceId(); // recurrence ID may have been updated if it was an imported rec ID with no time
       
  1018 
       
  1019 			// Move parent's start time to child's RecId (already verified RecId points to a genuine instance on the parent).
       
  1020 			aParentEntry.MoveStartTimeLocalL(childRecId.LocalL());
       
  1021 			}
       
  1022 			break;
       
  1023 
       
  1024 		default:
       
  1025 			{
       
  1026 			User::Leave(KErrArgument);	
       
  1027 			}
       
  1028 			break;
       
  1029 		}
       
  1030 	
       
  1031 	// add an exception to the parent on the child's recurrence ID
       
  1032 	aParentEntry.RptDef()->AddExceptionL(childRecId);
       
  1033 	
       
  1034 	// Remove any exceptions on the parent that fall in the discarded range
       
  1035 	aParentEntry.RptDef()->PruneExceptionsL();
       
  1036 
       
  1037 	// Remove any sporadic dates on the parent that fall in the discarded range
       
  1038 	aParentEntry.PruneRDatesL(childRecId, range);
       
  1039 		
       
  1040 	// Commit parent to store
       
  1041 	aParentEntry.SetLastModifiedDate();
       
  1042 	UpdateEntryL(aParentEntry, iChangeFilter, EFalse);
       
  1043 	
       
  1044 	// Delete any non-repeating children that fall in the discarded range
       
  1045 	DeleteNonRepeatingChildrenOutsideRangeL(aParentEntry, childRecId, range);
       
  1046 	
       
  1047 	return (retId);
       
  1048 	}
       
  1049 	
       
  1050 
       
  1051 /**
       
  1052 Adds a non-repeating child to a repeating parent, and then adds an exception to the parent's exception
       
  1053 list for the occurrence given by the child's RecId.
       
  1054 @internalComponent
       
  1055 @param aParentEntry The parent entry
       
  1056 @param aNonRepeatingChild The child to be added
       
  1057 @leave KErrArgument If parent entry does not have a repeat definition
       
  1058 */
       
  1059 TAgnEntryId CAgnEntryModel::AddNonRepeatingChildEntryUpdateParentExceptionsL(CAgnEntry& aParentEntry, CAgnEntry& aNonRepeatingChild)
       
  1060 	{
       
  1061 	const TInt KNumchildrenBefore = aParentEntry.ChildIds().Count();
       
  1062 	// Add\Update children entry
       
  1063 	TAgnEntryId retId = AddChildEntryL(aNonRepeatingChild, aParentEntry);
       
  1064 	const TInt KNumchildrenAfter = aParentEntry.ChildIds().Count();
       
  1065 	
       
  1066 	TBool addexception = !aParentEntry.RptDef()->FindException(aNonRepeatingChild.RecurrenceId());
       
  1067 	if ( KNumchildrenAfter > KNumchildrenBefore || addexception )
       
  1068 		{
       
  1069 		//only add exception and update parent if a child has been added otherwise a existing child has been updated.
       
  1070 		aParentEntry.RptDef()->AddExceptionL(aNonRepeatingChild.RecurrenceId());
       
  1071 		aParentEntry.SetLastModifiedDate();
       
  1072 		UpdateEntryL(aParentEntry, iChangeFilter, EFalse);
       
  1073 		}
       
  1074 	
       
  1075 	return (retId);
       
  1076 	}
       
  1077 
       
  1078 
       
  1079 TAgnEntryId CAgnEntryModel::AddChildEntryL(CAgnEntry& aChild, CAgnEntry& aParent)
       
  1080 	{
       
  1081   	TAgnCalendarTime entryRecId = aChild.RecurrenceId();
       
  1082  	CAgnRptDef* parentRptDef = aParent.RptDef();
       
  1083  	__ASSERT_ALWAYS(parentRptDef, Panic(EAgmErrAddingChildEntryToNonRepeatingParent));
       
  1084 		
       
  1085 	// Microsoft export recurrence id with date but no time. Test if current 
       
  1086 	// recurrenceId is an instance of parent entry so that when the time is 
       
  1087 	// not specified in recurrenceId we can find the right occurence from the parent.
       
  1088 	if ( ! parentRptDef->IsAnInstanceL(entryRecId.LocalL()) )
       
  1089 		{
       
  1090 		// If a midnight recurrence Id is not floating, and is not an instance of the parent entry, then
       
  1091 		// it means it is imported without the time and timezone information. Therefore, it has to be
       
  1092 		// converted to a correct UTC time here before nudging the instance.
       
  1093 		TDateTime recIdDateTime = entryRecId.UtcL().DateTime();
       
  1094 		if (recIdDateTime.Hour() == 0 && recIdDateTime.Minute() == 0 && 
       
  1095 			aChild.TimeMode() != MAgnCalendarTimeMode::EFloating)
       
  1096 			{
       
  1097 			entryRecId.SetUtcL(parentRptDef->ConvertFromRepeatLocalToUtcL(entryRecId.UtcL()));
       
  1098 			}
       
  1099 
       
  1100 		TTime actualInstanceTimeUtc;
       
  1101 		parentRptDef->NudgeNextInstanceUtcL(entryRecId.UtcL(), actualInstanceTimeUtc);
       
  1102 		// If recurrenceId is not an instance of the parent then nudge to next occurence if an instance can be found for the same date. 
       
  1103 		if ( actualInstanceTimeUtc != Time::NullTTime() )
       
  1104 			{
       
  1105 			const TTime KActualInstanceTimeRptLocal = parentRptDef->ConvertFromUtcToRepeatLocalL(actualInstanceTimeUtc);
       
  1106 			const TTime KRecurrenceIdRptLocal = parentRptDef->ConvertFromUtcToRepeatLocalL(entryRecId.UtcL());
       
  1107 			
       
  1108 			const TDateTime KActualInstanceDateTimeRptLocal = KActualInstanceTimeRptLocal.DateTime();
       
  1109 			const TDateTime KRecurrenceIdDateTimeRptLocal = KRecurrenceIdRptLocal.DateTime();
       
  1110 			
       
  1111 			// Only change recurrenceId if nudged date is the same as the recurrenceId date
       
  1112 			if ( KRecurrenceIdDateTimeRptLocal.Year() == KActualInstanceDateTimeRptLocal.Year() &&
       
  1113 				 KRecurrenceIdDateTimeRptLocal.Month() == KActualInstanceDateTimeRptLocal.Month() &&
       
  1114 				 KRecurrenceIdDateTimeRptLocal.Day() == KActualInstanceDateTimeRptLocal.Day() )
       
  1115 				{
       
  1116 				if (aParent.TimeMode() == MAgnCalendarTimeMode::EFloating)
       
  1117 					{
       
  1118 					entryRecId.SetFloatingL(KActualInstanceTimeRptLocal);
       
  1119 					}
       
  1120 				else
       
  1121 					{
       
  1122 					entryRecId.SetUtcL(actualInstanceTimeUtc);
       
  1123 					}
       
  1124 				aChild.UpdateRecurrenceIdL(entryRecId);
       
  1125 				}
       
  1126 			else
       
  1127 				{
       
  1128 				User::Leave(KErrNotFound); // If leave occurs here then there is no event found for given day by recurrenceId
       
  1129 				}
       
  1130 			}
       
  1131 		else
       
  1132 			{
       
  1133 			User::Leave(KErrNotFound); // leave occurs here because the next instance cannot be found
       
  1134 			}
       
  1135 		}
       
  1136 	
       
  1137 	aChild.SetParentId(aParent.LocalUid());
       
  1138 // First check if the same child entry already exists in the store (one with the same RecId).
       
  1139 	// If so we delete it and replace it with the new child.
       
  1140 	// This allows the client to 'update' a child entry without having to destroy the entire
       
  1141 	// associated set.
       
  1142 
       
  1143 	CAgnEntry* existingChildEntry = FetchEntryL(aParent.Guid(), entryRecId);
       
  1144 
       
  1145 	TAgnEntryId retId;
       
  1146 	TBool addChild(ETrue);
       
  1147 
       
  1148 	if ( existingChildEntry )
       
  1149 		{			
       
  1150 		CleanupStack::PushL(existingChildEntry);
       
  1151 		if ( existingChildEntry->Type() == aChild.Type() )
       
  1152 			{// Update existing child entry
       
  1153 			aChild.SetLocalUid(existingChildEntry->LocalUid());
       
  1154 			aChild.SetEntryId(existingChildEntry->EntryId());
       
  1155 			UpdateEntryL(aChild, iChangeFilter, EFalse);
       
  1156 			retId = aChild.EntryId();
       
  1157 			addChild = EFalse;
       
  1158 			}
       
  1159 		else
       
  1160 			{
       
  1161 			// Delete existing child entry
       
  1162 			aChild.SetLocalUid(existingChildEntry->LocalUid());
       
  1163 			DeleteEntryL(*existingChildEntry, EFalse, iChangeFilter);
       
  1164 			}
       
  1165 		CleanupStack::PopAndDestroy(existingChildEntry);
       
  1166 		}
       
  1167 
       
  1168 	if ( addChild )
       
  1169 		{
       
  1170 		if ( aChild.RptDef() )
       
  1171 			{
       
  1172 			// Check there are no other repeating childs on this parent.
       
  1173 			// (Limit to only ONE rpt rule change to a parent entry)
       
  1174 			__ASSERT_ALWAYS(!EntryHasRepeatingChildrenL(aParent), User::Leave(KErrNotSupported));
       
  1175 			}
       
  1176 
       
  1177 		// add the new child entry
       
  1178 		retId = AddEntryL(aChild);
       
  1179 			
       
  1180 		// Add the occurrence given by the RecId to the parent's Exception List.
       
  1181 		TGsChildRefData child(aChild.LocalUid(), entryRecId);
       
  1182 		aParent.AddChildIdL(child);
       
  1183 		}
       
  1184 
       
  1185 	return (retId);
       
  1186 	}
       
  1187 
       
  1188 
       
  1189 CAgnEntry* CAgnEntryModel::FetchEntryL(const TDesC8& aGuid) const	
       
  1190  	{
       
  1191  	#ifdef __CAL_VERBOSE_LOGGING__
       
  1192  		{
       
  1193  		TBuf<KMaxGuidBufLength> guidBuf;
       
  1194 		guidBuf.Copy(aGuid);
       
  1195 		AgmDebug::DebugLog("FetchEntryL: Fetching entry with GUID='%S'",&guidBuf);
       
  1196 		}
       
  1197 	#endif
       
  1198 	
       
  1199  	RArray<TAgnEntryId> candidateMatches;
       
  1200  	CleanupClosePushL(candidateMatches);
       
  1201  	
       
  1202 	iSimpleEntryTable->FindByHashL(GenerateHash8L(aGuid), candidateMatches);
       
  1203  	
       
  1204 	CAgnEntry* entry = NULL;
       
  1205  	const TInt KCount = candidateMatches.Count();
       
  1206  	
       
  1207  	for ( TInt i = 0; i < KCount; ++i )
       
  1208  		{
       
  1209 		CAgnEntry* candidateEntry = FetchEntryL(candidateMatches[i]);
       
  1210 		__ASSERT_ALWAYS(candidateEntry, User::Leave(KErrNotFound)); // entry table contains an entry not in the store
       
  1211 		
       
  1212 		CleanupStack::PushL(candidateEntry);
       
  1213 		
       
  1214 		if ( candidateEntry->Guid() == aGuid )
       
  1215 			{
       
  1216 			entry = candidateEntry;
       
  1217 			CleanupStack::Pop(candidateEntry);
       
  1218 			break;
       
  1219 			}
       
  1220 
       
  1221 		CleanupStack::PopAndDestroy(candidateEntry);
       
  1222  		}
       
  1223  		
       
  1224  	CleanupStack::PopAndDestroy(); //candidateMatches.Close();
       
  1225  
       
  1226 	return (entry);
       
  1227  	}
       
  1228 
       
  1229 
       
  1230 CAgnEntry* CAgnEntryModel::FindChildFromParentL(const CAgnEntry& aParent, const TAgnCalendarTime& aRecurrenceId)	const
       
  1231 	{
       
  1232 	CAgnEntry* returnEntry = NULL;
       
  1233 	
       
  1234 	// Get Child ids
       
  1235 	const RArray<TGsChildRefData>& KChildIds = aParent.ChildIds();
       
  1236 
       
  1237 	// Check if we have a match amongst the children of this parent
       
  1238 	const TInt KCount = KChildIds.Count();
       
  1239 
       
  1240 	for ( TInt pos = 0; pos < KCount; ++pos )
       
  1241 		{
       
  1242 		const TGsChildRefData& KChildData = KChildIds[pos];
       
  1243 		
       
  1244 		if ( KChildData.RecurrenceId() == aRecurrenceId )
       
  1245 			{
       
  1246 			returnEntry = FetchEntryL(KChildData.ChildId());
       
  1247 
       
  1248 			break;
       
  1249 			}
       
  1250 		}
       
  1251 	
       
  1252 	return (returnEntry);
       
  1253 	}
       
  1254 
       
  1255 /** Save the contents of iNextLocalUidValue and iNextAttachmentUid to the store
       
  1256 @internalComponent
       
  1257 */
       
  1258 void CAgnEntryModel::ExternalizeNextUidValuesL() const
       
  1259 	{
       
  1260 	ExternalizeNextUidValuesL(StreamStore(), iModelStreamIdSet->NextLocalUidValueStreamId());
       
  1261 	}
       
  1262 
       
  1263 void CAgnEntryModel::ExternalizeNextUidValuesL(CStreamStore& aStreamStore, const TStreamId& aStreamId) const
       
  1264 	{
       
  1265 	RStoreWriteStream stream;
       
  1266 
       
  1267 	stream.ReplaceLC(aStreamStore, aStreamId);
       
  1268 	stream.WriteUint32L(iNextLocalUidValue);
       
  1269 	stream.WriteUint32L(iNextAttachmentUid);
       
  1270 
       
  1271 	stream.CommitL();
       
  1272 
       
  1273 	CleanupStack::PopAndDestroy();
       
  1274 	}
       
  1275 
       
  1276 void CAgnEntryModel::InternalizeNextUidValuesL()
       
  1277 	{
       
  1278 	RStoreReadStream in;
       
  1279 	in.OpenLC(StreamStore(), iModelStreamIdSet->NextLocalUidValueStreamId());
       
  1280 	if (iCalConverter)
       
  1281 		{
       
  1282 		iCalConverter->InternalizeNextUidValuesL(in);
       
  1283 		}
       
  1284 	else
       
  1285 		{
       
  1286 		iNextLocalUidValue = in.ReadUint32L();
       
  1287 		iNextAttachmentUid = in.ReadUint32L();
       
  1288 		}
       
  1289 
       
  1290 	CleanupStack::PopAndDestroy(&in);
       
  1291 	}
       
  1292 	
       
  1293 /** Sets whether or not to use buffered deletion.
       
  1294 
       
  1295 Buffered deletion means that when entries are deleted they are only 
       
  1296 marked as being deleted in the internal memory buffer and the file 
       
  1297 is not updated until either every entry in the buffer is marked as being 
       
  1298 deleted or a commit/flush is called.
       
  1299 @param aSetting ETrue for buffered deletion, EFalse for non-buffered deletion.
       
  1300 @capability None
       
  1301 */
       
  1302 void CAgnEntryModel::SetBufferedDeleting(TBool aSetting)
       
  1303 	{ 
       
  1304 	iEntryManager->SetBufferedDeleting(aSetting); 
       
  1305 	}
       
  1306 
       
  1307 /**
       
  1308 Flush out the entry store
       
  1309 */
       
  1310 void CAgnEntryModel::FlushL()
       
  1311 	{
       
  1312 	iEntryManager->FlushBuffersL();
       
  1313 	}
       
  1314 
       
  1315 /** Resets any file specific data before opening a new calendar file.
       
  1316 @internalAll
       
  1317 */
       
  1318 void CAgnEntryModel::Reset()
       
  1319 	{
       
  1320 	iFileId = 0;
       
  1321 	
       
  1322 	if (iModelStreamIdSet)
       
  1323 		{
       
  1324 		iModelStreamIdSet->Reset();
       
  1325 		}
       
  1326 	
       
  1327 	if (iEntryManager)
       
  1328 		{
       
  1329 		iEntryManager->Reset();
       
  1330 		}
       
  1331 		
       
  1332 	if (iSimpleEntryTable)
       
  1333 		{
       
  1334 		iSimpleEntryTable->Reset();
       
  1335 		}
       
  1336 	}
       
  1337 
       
  1338 /** Save the entry manager and its data to the store
       
  1339 @internalAll
       
  1340 */
       
  1341 void CAgnEntryModel::ExternalizeEntryManagerL() const
       
  1342 	{
       
  1343 	RStoreWriteStream stream;
       
  1344 	stream.ReplaceLC(StreamStore(),iModelStreamIdSet->EntryManagerStreamId());
       
  1345 	stream << *iEntryManager;
       
  1346 	stream.CommitL();
       
  1347 	CleanupStack::PopAndDestroy();
       
  1348 	}
       
  1349 
       
  1350 void CAgnEntryModel::InternalizeEntryManagerL()
       
  1351 	{
       
  1352 	RStoreReadStream in;
       
  1353 	in.OpenLC(StreamStore(), iModelStreamIdSet->EntryManagerStreamId());
       
  1354 	in >> *iEntryManager;
       
  1355 
       
  1356 	// Sanity Check here. If the entry stream set is empty, then the store stream ids should
       
  1357 	// all be zero - reset them here to ensure that if the file has been partially corrupted, we can
       
  1358 	// recover from this.
       
  1359 	if ( iModelStreamIdSet->EntryStreamIdSet().Count() == 0 )
       
  1360 		{
       
  1361 		iEntryManager->Reset();
       
  1362 		}
       
  1363 
       
  1364 	CleanupStack::PopAndDestroy(&in);
       
  1365 	}
       
  1366 
       
  1367 void CAgnEntryModel::ResetIndexes()
       
  1368 	{
       
  1369 	// Reset indexes, returns EFalse if file is empty
       
  1370 	iSimpleEntryTable->Reset();
       
  1371 	iCategoryIndex->Reset();
       
  1372 	iAttachmentIndex->Reset();
       
  1373 	iModelStreamIdSet->EntryStreamIdSet().ResetIteratorToStart();
       
  1374 	if (iModelStreamIdSet->EntryStreamIdSet().Count() == 0)
       
  1375 		{
       
  1376 		iNumStreamsProcessed = 0;
       
  1377 		}
       
  1378 	}
       
  1379 
       
  1380 // This method is used for generating a filename for the index file from the
       
  1381 // calendar filename. 
       
  1382 TBool CAgnEntryModel::GenerateIndexFileName(TFileName& aFileName) 
       
  1383 	{
       
  1384 	aFileName = FileName();
       
  1385 	if ((aFileName.Length() + KIdxFilePostFixLength) > KMaxFileName)
       
  1386 		{
       
  1387 		iIndexFileIsDirty = ETrue;
       
  1388 		iIndexFileIsPresent = EFalse;
       
  1389 		return EFalse;
       
  1390 		}
       
  1391 	aFileName.Append(KIdxFilePostFix);
       
  1392 	return ETrue;
       
  1393 	}
       
  1394 
       
  1395 
       
  1396 // This method marks the index file as dirty (i.e. out of sync with the indices 
       
  1397 // in RAM) by deleting it. A flag is kept internally to allow us to know that the
       
  1398 // file needs to be rebuilt and to no try to delete the file more than once.
       
  1399 void CAgnEntryModel::MarkIndexFileAsDirtyL()
       
  1400 	{
       
  1401 	if (iIndexFileIsDirty)
       
  1402 		{
       
  1403 		return; // the file is already marked as dirty
       
  1404 		}
       
  1405 		
       
  1406 	TFileName idxfilename;
       
  1407 	if (!GenerateIndexFileName(idxfilename))
       
  1408 		{
       
  1409 		User::Leave(KErrBadName);
       
  1410 		}
       
  1411 	
       
  1412 	TInt connectErr = iFs.Connect();
       
  1413 	User::LeaveIfError(connectErr);
       
  1414 	
       
  1415 	iFs.Delete(idxfilename); // ignore return as there is nothing we can do with it
       
  1416 	
       
  1417 	iIndexFileIsDirty = ETrue;
       
  1418 	}
       
  1419 	
       
  1420 // This method allows clients of the model to determine if the index file is
       
  1421 // dirty and therefore in need of being rewritten with the current data.
       
  1422 TBool CAgnEntryModel::IsIndexFileDirty() const
       
  1423 	{
       
  1424 	return iIndexFileIsDirty;
       
  1425 	}
       
  1426 
       
  1427 TCalCollectionId CAgnEntryModel::CollectionId() const
       
  1428 	{
       
  1429 	return iAgnServerFile->CollectionId();
       
  1430 	}
       
  1431 
       
  1432 // This method reads the indices from the index file.
       
  1433 // It returns:
       
  1434 //		ETrue - indices successfully read from file
       
  1435 //      EFalse - indices not read from file (file may be missing, or there
       
  1436 //				 may have been errors trying to read the file.
       
  1437 // It Leaves when any of the index InternalizeL functions Leave.
       
  1438 // Overall description:
       
  1439 //		1. Attempt to open the file
       
  1440 //		2. If file is present InternalizeL all indices and return true
       
  1441 //		4. If no file, or errors in opening or streaming return false
       
  1442 TBool CAgnEntryModel::LoadIndexFileL()
       
  1443 	{
       
  1444 	TFileName idxfilename;
       
  1445 	if (!GenerateIndexFileName(idxfilename))
       
  1446 		{
       
  1447 		User::Leave(KErrBadName);
       
  1448 		}
       
  1449 	
       
  1450 	TInt connectErr = iFs.Connect();
       
  1451 	User::LeaveIfError(connectErr);
       
  1452 	
       
  1453 	RFile idxFile;
       
  1454 	TInt errReadIdx = idxFile.Open(iFs, idxfilename, EFileRead);
       
  1455 	CleanupClosePushL(idxFile);
       
  1456 	
       
  1457 	if (errReadIdx == KErrNone)    // we have a file
       
  1458 		{
       
  1459 		RFileReadStream idxStream;
       
  1460 		idxStream.Attach(idxFile);
       
  1461 		CleanupClosePushL(idxStream);
       
  1462 		
       
  1463 		TInt internalizeErr = KErrNone;
       
  1464 		
       
  1465 		TRAP(internalizeErr, iSimpleEntryTable->InternalizeL(idxStream, iTzRuleIndex));
       
  1466 		if (internalizeErr != KErrNone)
       
  1467 			{
       
  1468 			// clear any entries that may have been added to the table
       
  1469 			// before leaving
       
  1470 			iSimpleEntryTable->Reset();
       
  1471 			User::Leave(internalizeErr);
       
  1472 			}
       
  1473 		TRAP(internalizeErr, iCategoryIndex->InternalizeL(idxStream));
       
  1474 		if (internalizeErr != KErrNone)
       
  1475 			{
       
  1476 			// clear any entries in this index or the entry table
       
  1477 			// before leaving
       
  1478 			iSimpleEntryTable->Reset();
       
  1479 			iCategoryIndex->Reset();
       
  1480 			User::Leave(internalizeErr);
       
  1481 			}
       
  1482 		TRAP(internalizeErr, iAttachmentIndex->InternalizeL(idxStream));
       
  1483 		if (internalizeErr !=KErrNone)
       
  1484 			{
       
  1485 			// clear any entries in this index, the category index
       
  1486 			// and the entry table before leaving
       
  1487 			iAttachmentIndex->Reset();
       
  1488 			iSimpleEntryTable->Reset();
       
  1489 			iCategoryIndex->Reset();
       
  1490 			User::Leave(internalizeErr);
       
  1491 			}
       
  1492 
       
  1493 		CleanupStack::PopAndDestroy(2); //idxStream, idxFile
       
  1494 		iIndexFileIsDirty = EFalse;
       
  1495 		return ETrue;  // we have successfully read the index file
       
  1496 		}
       
  1497 	else if (errReadIdx == KErrNotFound)
       
  1498 		{
       
  1499 		CleanupStack::PopAndDestroy(); // idxFile
       
  1500 		iIndexFileIsDirty = ETrue;  // the index file needs to be created/updated
       
  1501 		iIndexFileIsPresent = EFalse; 	// so we won't try to find the file every time
       
  1502 										// DoBuildIndexL() is called
       
  1503 		return EFalse; // no file to read
       
  1504 		}
       
  1505 		
       
  1506 	// if we get here, then there was an error reading the file for some
       
  1507 	// reason other than it not being present. We'll mark it as DIRTY (i.e. delete it).
       
  1508 	// MarkIndexFileAsDirtyL will try to delete the file if errors occur.
       
  1509 	CleanupStack::PopAndDestroy(&idxFile);
       
  1510 	MarkIndexFileAsDirtyL();
       
  1511 	iIndexFileIsPresent = EFalse;	
       
  1512 	return EFalse;
       
  1513 	}
       
  1514 
       
  1515 
       
  1516 // This method attempts to save all indices to the index file.
       
  1517 // If any errors are encountered it will Leave.
       
  1518 // Clients of this method should TRAP the Leave and possibly
       
  1519 // mark the file as dirty or try to delete it.
       
  1520 void CAgnEntryModel::SaveIndexFileL()
       
  1521 	{
       
  1522 	TFileName idxfilename;
       
  1523 	if (!GenerateIndexFileName(idxfilename))
       
  1524 		{
       
  1525 		User::Leave(KErrBadName);
       
  1526 		}
       
  1527 	TInt connectErr = iFs.Connect();
       
  1528 	User::LeaveIfError(connectErr);
       
  1529 
       
  1530 	RFile idxFile;
       
  1531 	TInt errWriteIdx = idxFile.Replace(iFs, idxfilename, EFileWrite);
       
  1532 	User::LeaveIfError(errWriteIdx);
       
  1533 	CleanupClosePushL(idxFile);
       
  1534 	
       
  1535 	
       
  1536 	RFileWriteStream idxStream;
       
  1537 	idxStream.Attach(idxFile);
       
  1538 	CleanupClosePushL(idxStream);
       
  1539 
       
  1540 	iSimpleEntryTable->ExternalizeL(idxStream);
       
  1541 	iCategoryIndex->ExternalizeL(idxStream);
       
  1542 	iAttachmentIndex->ExternalizeL(idxStream);
       
  1543 
       
  1544 	CleanupStack::PopAndDestroy(2); //idxStream, idxFile
       
  1545 	
       
  1546 	iIndexFileIsDirty = EFalse;
       
  1547 	}
       
  1548 	
       
  1549 TBool CAgnEntryModel::DoLoadIndexFile()
       
  1550 	{
       
  1551 	// Check to see if we have a valid index file that we can read
       
  1552 	TBool readPassed = EFalse;
       
  1553 	TRAPD(idxErr, readPassed = LoadIndexFileL());
       
  1554 	if ((readPassed) && (idxErr == KErrNone))
       
  1555 		{
       
  1556 		// We successfully read the prebuilt index.
       
  1557 		return ETrue;   
       
  1558 		}
       
  1559 	else
       
  1560 		{
       
  1561 		// something bad happened to the index file
       
  1562 		// we need to delete it because it couldn't be read
       
  1563 		// To ensure that it is deleted we need to mark the index 
       
  1564 		// file as "not dirty".
       
  1565 		iIndexFileIsDirty = EFalse;
       
  1566 		iIndexFileIsPresent = EFalse;
       
  1567 		// trap the leave to keep things running, but there is nothing
       
  1568 		// we can do if the file can't be deleted.
       
  1569 		TRAP_IGNORE(MarkIndexFileAsDirtyL());
       
  1570 		}
       
  1571 	return EFalse;
       
  1572 	}
       
  1573 
       
  1574 
       
  1575 TInt CAgnEntryModel::DoIndexBuildStepL()
       
  1576 	{
       
  1577 	// Check to see if we have a valid index file that we can read
       
  1578 	// before trying to build all the indices.
       
  1579 	
       
  1580 	if (iIndexFileIsPresent)
       
  1581 		{
       
  1582 		if (DoLoadIndexFile())
       
  1583 			{
       
  1584 			// We successfully read the prebuilt index.
       
  1585 			// There is no need to go any further.
       
  1586 			// The 0 below indicates that there is nothing left to do.
       
  1587 			return KAgnPercentageComplete;   
       
  1588 			}
       
  1589 		}
       
  1590 	// otherwise, there is no file or the file is dirty (out of sync), 
       
  1591 	// continue to build indexes
       
  1592 	
       
  1593 	TInt retVal = 0;
       
  1594 
       
  1595 	FOREVER
       
  1596 		{
       
  1597 		TStreamId streamId(0);
       
  1598 
       
  1599 		if ( ! iModelStreamIdSet->EntryStreamIdSet().At(streamId) ) // returns value in streamId
       
  1600 			{
       
  1601 			retVal = KAgnPercentageComplete; // indicate completion if not more streams
       
  1602 			break;
       
  1603 			}
       
  1604 
       
  1605 		RStoreReadStream in;
       
  1606 		in.OpenLC(StreamStore(), streamId);
       
  1607 		
       
  1608 		in.ReadInt8L();		// discard buffer type information
       
  1609 		
       
  1610 		if ( iCalConverter )
       
  1611 			{
       
  1612 			// Read entry from a calendar file whose
       
  1613 			// version is not the current one.
       
  1614 			
       
  1615 			iCalConverter->InternalizeEntriesL(in);
       
  1616 			}
       
  1617 		else
       
  1618 			{	
       
  1619 			// Read entry from a calendar file - current version
       
  1620 			const TUint8 KCount = in.ReadUint8L();
       
  1621 			
       
  1622 			CAgnEntry* entry = NULL;	
       
  1623 			for ( TInt ii = 0; ii < KCount; ++ii )
       
  1624 				{
       
  1625 				entry =	CAgnEntry::NewL(in);
       
  1626 				CleanupStack::PushL(entry);
       
  1627 				
       
  1628 				UpdateIndexL(*entry, NULL, EBuildIndex);
       
  1629 				CleanupStack::PopAndDestroy(entry);
       
  1630 				}
       
  1631 			}
       
  1632 
       
  1633 		CleanupStack::PopAndDestroy();		// in
       
  1634 
       
  1635 		iSimpleEntryTable->Commit();
       
  1636 
       
  1637 		if ( ! iModelStreamIdSet->EntryStreamIdSet().Next() )
       
  1638 		 	{
       
  1639 		 	retVal = KAgnPercentageComplete; // no more streams to process
       
  1640 			break;
       
  1641 			}
       
  1642 
       
  1643 		// check iNumStreamsProcessed is valid - this number is used to calculate percentage complete
       
  1644 		++iNumStreamsProcessed;
       
  1645 		__ASSERT_ALWAYS(iNumStreamsProcessed <= iModelStreamIdSet->EntryStreamIdSet().Count(), User::Leave(KErrCorrupt));
       
  1646 
       
  1647 		// After every second stream is processed, calculate the percentage complete and return
       
  1648 		if ( iNumStreamsProcessed % 2 == 0 )
       
  1649 			{
       
  1650 			// coverity[check_return] coverity[unchecked_value]
       
  1651 			TInt percentage = (iNumStreamsProcessed * KAgnPercentageComplete) / iModelStreamIdSet->EntryStreamIdSet().Count();
       
  1652 			retVal = (percentage < 1 ? 1 : percentage); // percentage complete must be at least 1 (returning 0 indicates index building complete)
       
  1653 			break;
       
  1654 			}
       
  1655 		}
       
  1656 
       
  1657 	if (retVal == KAgnPercentageComplete)
       
  1658 		{
       
  1659 		// A return value of 0 indicates that the indexes have been
       
  1660 		// completely built. We will save them to file now so that
       
  1661 		// no future errors will cause this information to need to 
       
  1662 		// be built again.
       
  1663 		TRAPD (saveErr, SaveIndexFileL());
       
  1664 		if (saveErr != KErrNone)
       
  1665 			{
       
  1666 			// We couldn't save the index file, so we'll mark it as dirty
       
  1667 			TRAPD(ignore,MarkIndexFileAsDirtyL());
       
  1668 			User::LeaveIfError(ignore);			
       
  1669 			}
       
  1670 		}
       
  1671 	
       
  1672 	return (retVal);
       
  1673 	}
       
  1674 
       
  1675 
       
  1676 void CAgnEntryModel::BuildIndexCompleteL()
       
  1677 	{
       
  1678 	if ( iCalConverter )
       
  1679 		{
       
  1680 		RestoreCategoriesL();
       
  1681 		iCalConverter->CompleteConversionL();
       
  1682 		delete iCalConverter;
       
  1683 		iCalConverter = NULL;
       
  1684 		}
       
  1685 		
       
  1686 	CreateAlarmForServerL();
       
  1687 	iAlarm->DeleteAllAlarms();
       
  1688 	iAlarm->FindAndQueueNextAlarmL(EFalse);
       
  1689 	}
       
  1690 
       
  1691  
       
  1692 TInt CAgnEntryModel::MatchExactText(const TDesC& aTextField, const TDesC& aSearchText)
       
  1693 	{
       
  1694 	return aTextField.Match(aSearchText);
       
  1695 	}
       
  1696 
       
  1697 TInt CAgnEntryModel::MatchFoldedText(const TDesC& aTextField, const TDesC& aSearchText)
       
  1698 	{
       
  1699 	return aTextField.MatchC(aSearchText);
       
  1700 	}
       
  1701 
       
  1702 TBool CAgnEntryModel::MatchSearchTextL(MatchTextFnPtr aMatchTextFunction, CAgnEntry& aEntry, const TDesC& aSearchText, const TAgnFilter& aFilter)
       
  1703 	{ 
       
  1704 	// always search summary
       
  1705 	TInt pos = aMatchTextFunction(aEntry.Summary(), aSearchText);
       
  1706 
       
  1707 	if ( pos == KErrNotFound && aFilter.IsEntryLocationSearched() )
       
  1708 		{
       
  1709 		pos = aMatchTextFunction(aEntry.Location(), aSearchText);
       
  1710 		}
       
  1711 	if ( pos == KErrNotFound && aFilter.IsEntryDescriptionSearched() )
       
  1712 		{
       
  1713 		pos = aMatchTextFunction(aEntry.Description(), aSearchText);
       
  1714 		}
       
  1715 
       
  1716 	CAgnAttendee* organizer = aEntry.Organizer();
       
  1717 	const TInt KNumAttendees = aEntry.AttendeeCount();
       
  1718 
       
  1719 	if ( organizer && pos == KErrNotFound )
       
  1720 		{
       
  1721 		if ( aFilter.IsOrganizerAddressSearched() )
       
  1722 			{
       
  1723 			pos = aMatchTextFunction(organizer->Address(), aSearchText);
       
  1724 			}
       
  1725 		if ( pos == KErrNotFound && aFilter.IsOrganizerSentByAddressSearched() )
       
  1726 			{
       
  1727 			pos = aMatchTextFunction(organizer->SentBy(), aSearchText);
       
  1728 			}
       
  1729 		if ( pos == KErrNotFound && aFilter.IsOrganizerCommonNameSearched() )
       
  1730 			{
       
  1731 			pos = aMatchTextFunction(organizer->CommonName(), aSearchText);
       
  1732 			}
       
  1733 		}
       
  1734 		
       
  1735 	for ( TInt i = 0; pos == KErrNotFound && i < KNumAttendees; ++i)
       
  1736 		{
       
  1737 		CAgnAttendee& attendee = aEntry.FetchAttendee(i);
       
  1738 
       
  1739 		if ( aFilter.IsAttendeeAddressSearched() )
       
  1740 			{
       
  1741 			pos = aMatchTextFunction(attendee.Address(), aSearchText);
       
  1742 			}
       
  1743 		if ( pos == KErrNotFound && aFilter.IsAttendeeSentByAddressSearched() )
       
  1744 			{
       
  1745 			pos = aMatchTextFunction(attendee.SentBy(), aSearchText);
       
  1746 			}
       
  1747 		if ( pos == KErrNotFound && aFilter.IsAttendeeCommonNameSearched() )
       
  1748 			{
       
  1749 			pos = aMatchTextFunction(attendee.CommonName(), aSearchText);
       
  1750 			}
       
  1751 		}
       
  1752 
       
  1753 	return (pos >= 0);
       
  1754 	}
       
  1755 
       
  1756 TBool CAgnEntryModel::MatchFullEntryL(const TAgnEntryId& aEntryId, const TFindInstanceParams& aSearchParams)
       
  1757 	{
       
  1758 	TBool match(ETrue);
       
  1759 	if(aSearchParams.iSearchString.Length() > 0)
       
  1760 		{
       
  1761 		CAgnEntry* entry = FetchEntryL(aEntryId);
       
  1762 		__ASSERT_ALWAYS(entry, User::Leave(KErrNotFound));
       
  1763 
       
  1764 		CleanupStack::PushL(entry);
       
  1765 		if(!MatchSearchTextL(*entry, aSearchParams.iSearchString, aSearchParams.iFilter))
       
  1766 			{
       
  1767 			match = EFalse;
       
  1768 			}
       
  1769 		CleanupStack::PopAndDestroy(entry);
       
  1770 		}
       
  1771 	return match;
       
  1772 	}
       
  1773 
       
  1774 TBool CAgnEntryModel::MatchSearchTextL(CAgnEntry& aEntry, const TDesC& aSearchText, const TAgnFilter& aFilter)
       
  1775 	{
       
  1776 	TBool matchText = ETrue;
       
  1777 	
       
  1778 	if ( aSearchText.Length() > 0 )
       
  1779 		{
       
  1780 		TBuf<256> searchString;
       
  1781 		_LIT(KWildCard, "*");
       
  1782 		searchString.Append(KWildCard);
       
  1783 		searchString.Append(aSearchText);
       
  1784 		searchString.Append(KWildCard);
       
  1785 		
       
  1786 		if ( aEntry.Summary() == KNullDesC && aEntry.SummaryStreamId() != KNullStreamId )
       
  1787 			{
       
  1788 			HBufC* summary = RestoreTextL(aEntry.SummaryStreamId());
       
  1789 			aEntry.SetSummary(summary);			
       
  1790 			}
       
  1791 			
       
  1792 		// load description if required
       
  1793 		if ( aEntry.Description() == KNullDesC && aEntry.DescriptionStreamId() != KNullStreamId && aFilter.IsEntryDescriptionSearched() )
       
  1794 			{
       
  1795 			HBufC* description = RestoreTextL(aEntry.DescriptionStreamId());
       
  1796 			aEntry.SetDescription(description);			
       
  1797 			}
       
  1798 
       
  1799 		MatchTextFnPtr matchFn = &MatchFoldedText;
       
  1800 		if ( aFilter.IsExactTextOnlySearch() )
       
  1801  			{
       
  1802  			matchFn = &MatchExactText;
       
  1803  			}
       
  1804  		
       
  1805  		matchText = MatchSearchTextL(matchFn, aEntry, searchString, aFilter);
       
  1806 		}
       
  1807 		
       
  1808 	return (matchText);
       
  1809 	}
       
  1810 
       
  1811 void CAgnEntryModel::FindInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aParameters)
       
  1812 	{
       
  1813 	iExtractor->FindInstancesL(aInstances, aParameters);
       
  1814 	
       
  1815 #if defined (__CAL_INSTANCE_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
       
  1816 	LogInstanceSearchL(aParameters, aInstances);
       
  1817 #endif	
       
  1818 	}
       
  1819 
       
  1820 void CAgnEntryModel::LogInstanceSearchL(const TFindInstanceParams& aParameters, const CArrayFix<TAgnSortInstance>& aInstances) const
       
  1821 	{
       
  1822 	TAgnFilter iFilter;
       
  1823 	TTime dbgStartTime;
       
  1824 	TTime iEndTime;
       
  1825 	TBuf<KAgnMaxSearchStringLength> iSearchString;
       
  1826 	
       
  1827 	TAgnFilter debugFilter = aParameters.iFilter;
       
  1828 	
       
  1829 	TBuf<64> filterBuf;
       
  1830 	
       
  1831 	if (debugFilter.AreTimedApptsIncluded() && 
       
  1832 		debugFilter.AreRemindersIncluded() &&
       
  1833 		debugFilter.AreEventsIncluded() && 
       
  1834 		debugFilter.AreAnnivsIncluded() && 
       
  1835 		debugFilter.AreCompletedTodosIncluded() && 
       
  1836 		debugFilter.AreIncompletedTodosIncluded() )
       
  1837 		{
       
  1838 		filterBuf.Copy(_L("All entries"));
       
  1839 		}
       
  1840 	else
       
  1841 		{
       
  1842 		if (debugFilter.AreTimedApptsIncluded())
       
  1843 			{
       
  1844 			filterBuf.Append(_L("Appts,"));
       
  1845 			}
       
  1846 		if (debugFilter.AreRemindersIncluded())
       
  1847 			{
       
  1848 			filterBuf.Append(_L("Reminders,"));
       
  1849 			}
       
  1850 		if (debugFilter.AreEventsIncluded())
       
  1851 			{
       
  1852 			filterBuf.Append(_L("Events,"));
       
  1853 			}
       
  1854 		if (debugFilter.AreAnnivsIncluded())
       
  1855 			{
       
  1856 			filterBuf.Append(_L("Annivs,"));
       
  1857 			}
       
  1858 		if (debugFilter.AreCompletedTodosIncluded() && debugFilter.AreIncompletedTodosIncluded())
       
  1859 			{
       
  1860 			filterBuf.Append(_L("TODOs,"));
       
  1861 			}
       
  1862 		else if (debugFilter.AreIncompletedTodosIncluded())
       
  1863 			{
       
  1864 			filterBuf.Append(_L("Incomplete TODOs,"));
       
  1865 			}
       
  1866 		else if (debugFilter.AreCompletedTodosIncluded())
       
  1867 			{
       
  1868 			filterBuf.Append(_L("Complete TODOs,"));
       
  1869 			}
       
  1870 		}
       
  1871 	
       
  1872 	if (aParameters.iSearchString.Length() > 0)
       
  1873 		{
       
  1874 		TBuf<KAgnMaxSearchStringLength> searchBuf;
       
  1875 		searchBuf.Copy(aParameters.iSearchString);
       
  1876 		AgmDebug::DebugLog("Searching for text %S", &searchBuf);
       
  1877 		}
       
  1878 	
       
  1879 	TBuf<KMinTTimeStrLength> startTimeBuf;
       
  1880 	TBuf<KMinTTimeStrLength> endTimeBuf;
       
  1881 	
       
  1882 	AgmDebug::TTimeStrL(aParameters.iRangeStart.LocalL(),startTimeBuf);
       
  1883 	AgmDebug::TTimeStrL(aParameters.iRangeEnd.LocalL(),endTimeBuf);
       
  1884 	
       
  1885 	const TInt KInstanceCount(aInstances.Count());
       
  1886 	
       
  1887 	AgmDebug::DebugLog("FindInstancesL: Range: Start - %S, End - %S, Filter '%S'", &startTimeBuf, &endTimeBuf, &filterBuf);
       
  1888 	AgmDebug::DebugLog("Found %d instances", KInstanceCount);
       
  1889 	
       
  1890 	for ( TInt i = 0; i < KInstanceCount; ++i )
       
  1891 		{
       
  1892 		TBuf<KMinTTimeStrLength> instanceTimeBuf;
       
  1893 		AgmDebug::TTimeStrL(aInstances[i].InstanceIdL().Date().LocalL(), instanceTimeBuf);
       
  1894 		AgmDebug::DebugLog("Found instance: %S", &instanceTimeBuf);
       
  1895 		}
       
  1896 
       
  1897 	}
       
  1898 
       
  1899 void CAgnEntryModel::CreateAlarmForServerL()
       
  1900 	{
       
  1901 	if ( ! iAlarm )
       
  1902 		{
       
  1903 		iAlarm = CAgnAlarm::NewL(this, NULL);
       
  1904 		}
       
  1905 	}
       
  1906 
       
  1907 /**
       
  1908 Get list of ids of alarmed entries in the next 60 days.
       
  1909 FindInstanceL is used to find instances of alarmed entries.
       
  1910 */
       
  1911 void CAgnEntryModel::NextAlarmForServerL(const TTime& aNow, CArrayFixFlat<TAgnSortInstance>& aAlarmedIds)
       
  1912 	{
       
  1913 	if ( ! AgnDateTime::IsValidAgendaTTime(aNow) || ! iSimpleEntryTable || iAgnServerFile->IsFileDisabled())
       
  1914 		{
       
  1915 		return;
       
  1916 		}
       
  1917 	
       
  1918 	CArrayFixSeg<TAgnSortInstance>* dayInfoList = new(ELeave) CArrayFixSeg<TAgnSortInstance>(4);
       
  1919 	CleanupStack::PushL(dayInfoList);
       
  1920 
       
  1921 	TFindInstanceParams searchParams;
       
  1922 	searchParams.iUndatedTodoTimeLocal = aNow;
       
  1923     searchParams.iFilter = TAgnFilter(CalCommon::EIncludeAppts|CalCommon::EIncludeReminder|CalCommon::EIncludeEvents|
       
  1924 										CalCommon::EIncludeAnnivs|CalCommon::EIncludeIncompletedTodos|CalCommon::EIncludeAlarmedOnly, CalCommon::EFoldedTextSearch);
       
  1925     searchParams.iSearchString = KNullDesC();
       
  1926     searchParams.iRangeStart.SetLocalL(AgnDateTime::ResetToMidnight(aNow) - TTimeIntervalDays(1)); // alarms can be up to 24 hours after start time so check this
       
  1927     searchParams.iRangeEnd.SetLocalL(aNow + TTimeIntervalDays(2));
       
  1928         
       
  1929 	iExtractor->FindInstancesL(*dayInfoList, searchParams);
       
  1930 	TAgnDaySortKey sortKey(AgnDateTime::MaxDate(), searchParams.iUndatedTodoTimeLocal);
       
  1931 	dayInfoList->Sort(sortKey);
       
  1932 
       
  1933 	
       
  1934     searchParams.iFilter = TAgnFilter(CalCommon::EIncludeAppts|CalCommon::EIncludeReminder|CalCommon::EIncludeEvents|
       
  1935 			CalCommon::EIncludeAnnivs|CalCommon::EIncludeIncompletedTodos|CalCommon::EIncludeAlarmedOnly|
       
  1936 			CalCommon::EIncludeRptsNextInstanceOnly, CalCommon::EFoldedTextSearch);
       
  1937 	
       
  1938 	// check the next month if no alarmed instances found
       
  1939 	const TTime KLimit = aNow + TTimeIntervalDays(60);
       
  1940 
       
  1941 	while ( dayInfoList->Count() == 0 && searchParams.iRangeStart.LocalL() < KLimit )
       
  1942  		{
       
  1943 	    searchParams.iRangeStart.SetLocalL(searchParams.iRangeEnd.LocalL());
       
  1944 	    searchParams.iRangeEnd.SetLocalL(searchParams.iRangeStart.LocalL() + TTimeIntervalDays(10));
       
  1945 	    
       
  1946 	    iExtractor->FindInstancesL(*dayInfoList, searchParams);
       
  1947 	    TAgnDaySortKey sortKey1(AgnDateTime::MaxDate(), searchParams.iUndatedTodoTimeLocal);
       
  1948 		dayInfoList->Sort(sortKey1);
       
  1949 		}
       
  1950 
       
  1951 	UpdateAlarmListL(aAlarmedIds, *dayInfoList, aNow);
       
  1952 
       
  1953 	CleanupStack::PopAndDestroy(); //dayInfoList 
       
  1954 	}
       
  1955 
       
  1956 /**
       
  1957 Examine the contents of aDayInfoList and see if the any of the contained alarm instances should be added to
       
  1958 or replace the contents of aAlarmedIds
       
  1959 @internalComponent
       
  1960 */
       
  1961 
       
  1962 void CAgnEntryModel::UpdateAlarmListL(CArrayFixFlat<TAgnSortInstance>& aAlarmedIds,CArrayFixSeg<TAgnSortInstance>& aDayInfoList, const TTime& aNow)
       
  1963 	{
       
  1964 	TTime nextAlarmLocal(AgnDateTime::MaxDate());
       
  1965 	
       
  1966 	for ( TInt ii = aDayInfoList.Count() - 1; ii >= 0; --ii )
       
  1967 		{
       
  1968 		TAgnSortInstance sortInstance = aDayInfoList[ii];
       
  1969 		
       
  1970 		if ( sortInstance.SimpleEntry().Type() == CCalEntry::ETodo || sortInstance.iStartTimeLocal >= AgnDateTime::ResetToMidnight(aNow) )
       
  1971 			{
       
  1972 			TTime alarmTimeLocal(sortInstance.InstanceAlarmDateTime());
       
  1973 	
       
  1974 			if ( alarmTimeLocal <= aNow && sortInstance.SimpleEntry().RptDef() )
       
  1975 				{				
       
  1976 				TTime nextInstance;
       
  1977 				
       
  1978 				while ( sortInstance.SimpleEntry().RptDef()->NudgeNextInstanceL(sortInstance.InstanceDate(), nextInstance, ETrue) && nextInstance <= aNow)
       
  1979 					{
       
  1980 					sortInstance.SetL(nextInstance, aNow);
       
  1981 									
       
  1982 					if ( sortInstance.iStartTimeLocal < AgnDateTime::MaxDate() )
       
  1983 						{
       
  1984 						alarmTimeLocal = sortInstance.InstanceAlarmDateTime();
       
  1985 						}
       
  1986 					}
       
  1987 				}
       
  1988 						
       
  1989 			if ( AgnDateTime::IsValidAgendaTTime(alarmTimeLocal) )
       
  1990 				{
       
  1991 				if ( alarmTimeLocal > aNow && alarmTimeLocal < nextAlarmLocal )
       
  1992 					{
       
  1993 					aAlarmedIds.Reset();
       
  1994 					aAlarmedIds.AppendL(sortInstance);
       
  1995 					nextAlarmLocal = alarmTimeLocal;
       
  1996 					}
       
  1997 				else
       
  1998 					{
       
  1999 					if ( alarmTimeLocal == nextAlarmLocal )
       
  2000 						{
       
  2001 						aAlarmedIds.AppendL(sortInstance);
       
  2002 						}
       
  2003 					}
       
  2004 				}
       
  2005 			}
       
  2006 		}
       
  2007 	}
       
  2008 
       
  2009 /** Schedules a list of alarms whose dateTime meets the following criteria:
       
  2010 alarmTime >= aCurrentTime AND alarmTime <= aCurrentTime + 30 days
       
  2011 @internalComponent
       
  2012 */
       
  2013  void CAgnEntryModel::NextFewAlarmsForServerL(const TTime& aStartDateTime,const TTime& aEndDateTime,
       
  2014 											 CArrayFixFlat<TAgnSortInstance>& aAlarmedIds,const TInt aMaxNumberOfAlarms)
       
  2015 	{
       
  2016 	if(iAgnServerFile->IsFileDisabled())
       
  2017 	    {
       
  2018 	    return;
       
  2019 	    }
       
  2020 	if ( AgnDateTime::IsValidAgendaTTime(aStartDateTime) && AgnDateTime::IsValidAgendaTTime(aEndDateTime) &&
       
  2021 		 aEndDateTime>=aStartDateTime )
       
  2022 		{					
       
  2023 		CArrayFixSeg<TAgnSortInstance>* dayInfoList = new(ELeave) CArrayFixSeg<TAgnSortInstance>(4);
       
  2024 		CleanupStack::PushL(dayInfoList);
       
  2025 
       
  2026 		TFindInstanceParams searchParams;
       
  2027 		searchParams.iUndatedTodoTimeLocal = searchParams.iRangeStart.LocalL();
       
  2028 	    searchParams.iFilter = TAgnFilter(CalCommon::EIncludeAppts|CalCommon::EIncludeReminder|CalCommon::EIncludeEvents|
       
  2029 											CalCommon::EIncludeAnnivs|CalCommon::EIncludeIncompletedTodos|CalCommon::EIncludeAlarmedOnly|
       
  2030 											CalCommon::EIncludeRptsNextInstanceOnly, CalCommon::EFoldedTextSearch);
       
  2031 	    searchParams.iSearchString = KNullDesC();
       
  2032 	    searchParams.iRangeStart.SetLocalL(aStartDateTime - TTimeIntervalDays(1)); // alarms can be up to 24 hours after start time so check this
       
  2033 	    searchParams.iRangeEnd.SetLocalL(aEndDateTime);
       
  2034 	    
       
  2035 		iExtractor->FindInstancesL(*dayInfoList, searchParams);
       
  2036 		TAgnAlarmSortKey aKey;
       
  2037 		dayInfoList->Sort(aKey);
       
  2038 
       
  2039 		AddToAlarmListL(aAlarmedIds, *dayInfoList, aStartDateTime, aEndDateTime, aMaxNumberOfAlarms);
       
  2040 
       
  2041 		CleanupStack::PopAndDestroy(dayInfoList);
       
  2042 		}
       
  2043 	}
       
  2044 
       
  2045 
       
  2046 void CAgnEntryModel::AddToAlarmListL(CArrayFixFlat<TAgnSortInstance>& aAlarmedIds,CArrayFixSeg<TAgnSortInstance>& aDayInfoList, const TTime& aStartDateTime,
       
  2047 									 const TTime& aEndDateTime,const TInt )
       
  2048 //
       
  2049 // Examine the contents of aDayInfoList add to aAlarmedIds
       
  2050 //
       
  2051 	{
       
  2052 	const TInt KDayListCount(aDayInfoList.Count());
       
  2053 	for (TInt i = 0; i < KDayListCount; ++i)
       
  2054 		{
       
  2055  		const TAgnSortInstance KSortInstance = aDayInfoList[i];
       
  2056  		const TTime KAlarmInstance(KSortInstance.InstanceAlarmDateTime());
       
  2057 
       
  2058 		if (KAlarmInstance > aStartDateTime && KAlarmInstance <= aEndDateTime)
       
  2059 			{
       
  2060 			aAlarmedIds.AppendL(KSortInstance);						
       
  2061 			}
       
  2062  		}
       
  2063 	}
       
  2064 
       
  2065 void CAgnEntryModel::FindAndQueueNextFewAlarmsL()
       
  2066 	{
       
  2067 	if ( iAlarm )
       
  2068 		{
       
  2069 		iAlarm->FindAndQueueNextFewAlarmsL();
       
  2070 		}
       
  2071 	}
       
  2072 
       
  2073 #ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
       
  2074 void CAgnEntryModel::DeleteAlarmsAndRequeueSessionAlarmL()
       
  2075 	{
       
  2076 	if ( iAlarm )
       
  2077 		{
       
  2078 		iAlarm->DeleteAlarmsAndRequeueSessionAlarmL();
       
  2079 		}
       
  2080 	}
       
  2081 #endif
       
  2082 
       
  2083 /**
       
  2084 Return next time (from aStartDate) on which an instance exists
       
  2085 @internalComponent
       
  2086 */
       
  2087 void CAgnEntryModel::NextPossibleInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aSearchParams) const
       
  2088 	{
       
  2089 	iExtractor->NextPossibleInstancesL(aInstances, aSearchParams);
       
  2090 	}
       
  2091 /**
       
  2092 Return previous time (from aStartDate) on which an instance exists
       
  2093 @internalComponent
       
  2094 */
       
  2095 void CAgnEntryModel::PreviousPossibleInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aSearchParams) const
       
  2096 	{
       
  2097 	iExtractor->PreviousPossibleInstancesL(aInstances, aSearchParams);
       
  2098 	}
       
  2099 
       
  2100 
       
  2101 // Place the uids of entries that have a last changed data greater than aDate and which meet the selection
       
  2102 // criteria specified in aFilter into the aUids array.
       
  2103 //
       
  2104 void CAgnEntryModel::GetEntryUidsSinceDateL(const TTime& aTime, RArray<TCalLocalUid>& aUniqueIdList)
       
  2105 	{
       
  2106 	iSimpleEntryTable->FindByLastModifiedDateUtcL(aTime, aUniqueIdList);		
       
  2107 	}
       
  2108 
       
  2109 
       
  2110 /**
       
  2111 Get the file ID of the currently open Agenda file.  
       
  2112 This is unique to the file.
       
  2113 @capability None
       
  2114 */
       
  2115 const TInt64& CAgnEntryModel::GetFileIdL()
       
  2116 	{
       
  2117 	if ( iFileId == 0 )
       
  2118 		{
       
  2119 		RStoreReadStream in;
       
  2120 		in.OpenLC(StreamStore(),iModelStreamIdSet->FileInformationStreamId());
       
  2121 		TInt64 fileId=0;
       
  2122 		in >> fileId;
       
  2123 		CleanupStack::PopAndDestroy(); //in
       
  2124 		iFileId = fileId;
       
  2125 		}
       
  2126 		
       
  2127 	return iFileId;
       
  2128 	}
       
  2129 
       
  2130 
       
  2131 HBufC* CAgnEntryModel::RestoreTextL(const TStreamId& aStream)
       
  2132 	{
       
  2133 	CStreamStore& store = StreamStore();
       
  2134 	RStoreReadStream in;
       
  2135 	in.OpenLC(store, aStream);
       
  2136 	TInt textLength = in.ReadUint32L();
       
  2137 	HBufC* text = HBufC::NewL(in, textLength);
       
  2138 	CleanupStack::PopAndDestroy(); //in
       
  2139 	return text;
       
  2140 	}
       
  2141 
       
  2142 TStreamId CAgnEntryModel::StoreTextL(const TDesC& aText)
       
  2143 	{
       
  2144 	CStreamStore& store = StreamStore();
       
  2145 	RStoreWriteStream out;
       
  2146 	TStreamId id = out.CreateLC(store);
       
  2147 	out.WriteUint32L(aText.Length());
       
  2148 	out << aText;
       
  2149 	out.CommitL();
       
  2150 	CleanupStack::PopAndDestroy(); //out
       
  2151 	return id;
       
  2152 	}
       
  2153 
       
  2154 /*
       
  2155  * Updates the notes text stored in the specified stream. Null Descriptors are expected to be 
       
  2156  * handled client side
       
  2157  */
       
  2158 void CAgnEntryModel::UpdateTextL(const TDesC& aText, const TStreamId& aStream)
       
  2159 	{
       
  2160 	__ASSERT_DEBUG(aText.Length() != 0, Panic(EAgmNullDescriptor));
       
  2161 
       
  2162 	CStreamStore& store = StreamStore();
       
  2163 	RStoreWriteStream out;
       
  2164 	out.ReplaceLC(store, aStream);
       
  2165 	out.WriteUint32L(aText.Length());
       
  2166 	out << aText;
       
  2167 	out.CommitL();
       
  2168 	CleanupStack::PopAndDestroy(); //out
       
  2169 	}
       
  2170 
       
  2171 /*
       
  2172  * Deletes the specified stream holding notes data.
       
  2173  * 
       
  2174  */
       
  2175 void CAgnEntryModel::DeleteTextStreamL(const TStreamId& aStream)
       
  2176 	{
       
  2177 	StreamStore().DeleteL(aStream);
       
  2178 	}	
       
  2179 	
       
  2180 	
       
  2181 CAgnContent* CAgnEntryModel::RestoreAlarmActionL(const TStreamId& aStream)
       
  2182 	{
       
  2183 	CStreamStore& store = StreamStore();
       
  2184 	RStoreReadStream in;
       
  2185 	in.OpenLC(store, aStream);
       
  2186 
       
  2187 	CAgnContent* alarmAction = new (ELeave) CAgnContent;
       
  2188 	CleanupStack::PushL(alarmAction);
       
  2189 	in >> *alarmAction;
       
  2190 	CleanupStack::Pop(alarmAction);
       
  2191 
       
  2192 	CleanupStack::PopAndDestroy(); //in
       
  2193 	return alarmAction;
       
  2194 	}
       
  2195 
       
  2196 
       
  2197 TStreamId CAgnEntryModel::StoreAlarmActionL(const CAgnContent& aAlarmAction)
       
  2198 	{
       
  2199 	CStreamStore& store = StreamStore();
       
  2200 	RStoreWriteStream out;
       
  2201 	TStreamId id = out.CreateLC(store);
       
  2202 	out << aAlarmAction;
       
  2203 	out.CommitL();
       
  2204 	CleanupStack::PopAndDestroy(); //out
       
  2205 
       
  2206 	return id;
       
  2207 	}
       
  2208 
       
  2209 /*
       
  2210  * Updates the rich alarm data stored in the specified stream.  
       
  2211  */
       
  2212 void CAgnEntryModel::UpdateAlarmActionL(const CAgnContent& aAlarmAction, const TStreamId& aStream)
       
  2213 	{
       
  2214 	CStreamStore& store = StreamStore();
       
  2215 	RStoreWriteStream out;
       
  2216 	out.ReplaceLC(store, aStream);
       
  2217 	out << aAlarmAction;
       
  2218 	out.CommitL();
       
  2219 	CleanupStack::PopAndDestroy(); //out
       
  2220 	}
       
  2221 
       
  2222 /*
       
  2223  * Deletes the specified stream holding rich alarm data.
       
  2224  * 
       
  2225  */
       
  2226 void CAgnEntryModel::DeleteAlarmActionStreamL(const TStreamId& aStream)
       
  2227 	{
       
  2228 	StreamStore().DeleteL(aStream);
       
  2229 	}
       
  2230 
       
  2231 const TDesC& CAgnEntryModel::FileName() const
       
  2232 	{
       
  2233 	return iAgnServerFile->FileName();
       
  2234 	}
       
  2235 
       
  2236 void CAgnEntryModel::SetUpdateAlarmL(TBool aUpdateAlarm)
       
  2237 	{
       
  2238 	iUpdateAlarm = aUpdateAlarm;
       
  2239 	
       
  2240 	if ( iUpdateAlarm )
       
  2241 		{
       
  2242 		iAlarm->FindAndQueueNextAlarmL(EFalse);
       
  2243 		}
       
  2244 	}
       
  2245 
       
  2246 
       
  2247 /** Commits any changes both to file and internally that have occurred to the model. 
       
  2248 
       
  2249 This function does not empty the buffers. Call FlushL to do that.
       
  2250 @capability None
       
  2251 */
       
  2252 void CAgnEntryModel::DoCommitL()
       
  2253 	{ 
       
  2254 	
       
  2255 	if(!AgnServFile().IsBackupRestoreLock())
       
  2256 		{
       
  2257 		iModelStreamIdSet->CommitL(StreamStore());
       
  2258 		StreamStore().CommitL();
       
  2259 		iSimpleEntryTable->Commit();
       
  2260 		iAttachmentIndex->CommitL(*iAgnServerFile);
       
  2261 		}
       
  2262 	
       
  2263 	// Trigger compacting after a certain number of operations on the model
       
  2264 	if(iOperationsCounter >= KCompactOperationsThreshold)
       
  2265 		{
       
  2266 		// Initiate synchronous compact
       
  2267 		iAgnServerFile->CompactFileL();
       
  2268 		// Reset operations counter
       
  2269 		iOperationsCounter=0;
       
  2270 		}
       
  2271 	}
       
  2272 
       
  2273 // Commits all changes to file.
       
  2274 void CAgnEntryModel::CommitL()
       
  2275 	{
       
  2276 	DoCommitL();
       
  2277 	ResetRollback();
       
  2278 	}
       
  2279 
       
  2280 // Called after multiple entries have been deleted.
       
  2281 // This can fail at any time and must roll back, so notification cannot happen until the changes are committed to file.
       
  2282 // This function does the commits then notifies, using the rollback array to find which entries have been deleted.
       
  2283 void CAgnEntryModel::CommitAndNotifyDeletesL(TAgnChangeFilter& aChangeFilter)
       
  2284 	{
       
  2285 	DoCommitL();
       
  2286 	iChangeFilter = &aChangeFilter;
       
  2287 
       
  2288 	const TInt KDeleteCount = iDeleteRollbackArray.Count();
       
  2289 	for (TInt i = 0; i < KDeleteCount; ++i)
       
  2290 		{
       
  2291 		CAgnEntry* deletedEntry = iDeleteRollbackArray[i];
       
  2292 		NotifyingL(MCalChangeCallBack2::EChangeDelete, *deletedEntry, NULL);
       
  2293 		
       
  2294 		if(iTzRuleIndex)
       
  2295 			{
       
  2296 			//Remove the tz rule from tz rule index
       
  2297 			//we have to do it after CAgnEntryModel::NotifyingL that is indirectly using the
       
  2298 			//tz rule in aEntry.
       
  2299 			iTzRuleIndex->RemoveTzRuleL(*deletedEntry);
       
  2300 			}
       
  2301 		}
       
  2302 
       
  2303 	StreamStore().CommitL();
       
  2304 	ResetRollback();
       
  2305 	}
       
  2306 
       
  2307 // Add an entry to a rollback array. 
       
  2308 // If aAdd is ETrue it is added to the add rollback array (for add operations)
       
  2309 // If aAdd is EFalse it is added to the delete rollback array (for delete operations)
       
  2310 void CAgnEntryModel::AppendRollbackArrayL(const CAgnEntry& aEntry, TBool aAdd)
       
  2311 	{
       
  2312 	if ( aAdd )
       
  2313 		{
       
  2314 		iAddRollbackArray.AppendL(aEntry.EntryId());
       
  2315 		}
       
  2316 	else
       
  2317 		{
       
  2318 		CAgnEntry* entryCopy = aEntry.CloneL();
       
  2319 		CleanupStack::PushL(entryCopy);
       
  2320 		iDeleteRollbackArray.AppendL(entryCopy);
       
  2321 		CleanupStack::Pop(entryCopy);
       
  2322 		}
       
  2323 	}
       
  2324 
       
  2325 // Reset rollback arrays
       
  2326 void CAgnEntryModel::ResetRollback()
       
  2327 	{
       
  2328 	iAddRollbackArray.Reset();
       
  2329 	iDeleteRollbackArray.ResetAndDestroy();
       
  2330 	}
       
  2331 
       
  2332 /**
       
  2333 Rollback indexes in RAM. This is done by deleting all added entries and re-adding all deleted entries
       
  2334 @internalComponent
       
  2335 */
       
  2336 void CAgnEntryModel::RollbackIndexesL()
       
  2337 	{
       
  2338 	// delete all added entries
       
  2339 	for ( TInt ii = iAddRollbackArray.Count() - 1; ii >= 0; --ii )
       
  2340 		{
       
  2341 		const TAgnEntryId& KEntryIdToDelete = iAddRollbackArray[ii];
       
  2342 		
       
  2343 		CAgnSimpleEntry* entryToDelete = iSimpleEntryTable->GetEntry(KEntryIdToDelete);
       
  2344 		if(entryToDelete != NULL)
       
  2345 			{
       
  2346 			iSimpleEntryTable->DeleteEntry(KEntryIdToDelete);
       
  2347 			}
       
  2348 		
       
  2349 		iAddRollbackArray.Remove(ii);
       
  2350 		}
       
  2351 
       
  2352 	iAddRollbackArray.Reset();
       
  2353 	
       
  2354 	if(iTzRuleIndex)
       
  2355 		{
       
  2356 		//Rollback the reference count of tz rules in tz rule index
       
  2357 		TRAPD(ret, iTzRuleIndex->RollBackL());
       
  2358 		if(ret != KErrNotReady)
       
  2359 			{
       
  2360 			User::LeaveIfError(ret);
       
  2361 			}
       
  2362 		}
       
  2363 
       
  2364 	// re-add all deleted entries
       
  2365 	for ( TInt ii = iDeleteRollbackArray.Count() - 1; ii >= 0; --ii )
       
  2366 		{
       
  2367 		CAgnEntry* entryToAdd = iDeleteRollbackArray[ii];
       
  2368 
       
  2369 		// Check the entry has a guid hash
       
  2370 		if ( entryToAdd->GsDataType() == CGsData::EParent && ! entryToAdd->GuidHash() )
       
  2371 			{
       
  2372 			entryToAdd->SetGuidHash( GenerateHash8L(entryToAdd->Guid()) );
       
  2373 			}	
       
  2374 
       
  2375 		// If the entry has already been added, delete it to prevent an error from re-adding the same entry.
       
  2376 		// This can happen if the delete operation fails at a certain point.
       
  2377 		const TAgnEntryId& KEntryIdToAdd = entryToAdd->EntryId();
       
  2378 		if (iSimpleEntryTable->GetEntry(KEntryIdToAdd))
       
  2379 			{
       
  2380 			iSimpleEntryTable->DeleteEntry(KEntryIdToAdd);
       
  2381 			}
       
  2382 		
       
  2383 		if(iTzRuleIndex)
       
  2384 			{
       
  2385 			//Fetch back the tz rule
       
  2386 			iTzRuleIndex->FetchTzRuleL(*entryToAdd);
       
  2387 			}
       
  2388 		
       
  2389 		// re-add the entry
       
  2390 		AddEntryToIndexesL(*entryToAdd);
       
  2391 		
       
  2392 		iDeleteRollbackArray.Remove(ii);
       
  2393 		delete entryToAdd;
       
  2394 		}
       
  2395 
       
  2396 	iDeleteRollbackArray.Reset();
       
  2397 	
       
  2398 	iAttachmentIndex->Rollback();
       
  2399 	}
       
  2400 	
       
  2401 /** Reverts the model to the state it was in after CommitL() or RollbackL() was 
       
  2402 last called. This reverts changes to the file and to the indexes held in RAM.
       
  2403 
       
  2404 This means that it deletes all entries which have been added, and reinstates 
       
  2405 all entries which have been deleted.
       
  2406 
       
  2407 Note that this function is only called when an operation has failed. After this function is complete, there will be a leave in the place where 
       
  2408 Rollback was called.
       
  2409 	
       
  2410 @internalComponent
       
  2411 */
       
  2412 void CAgnEntryModel::Rollback()
       
  2413 	{
       
  2414 	iEntryManager->Reset();
       
  2415 
       
  2416 	StreamStore().Revert();
       
  2417 
       
  2418 	TRAPD(ret,iModelStreamIdSet->RollbackL());
       
  2419 	__ASSERT_DEBUG(ret==KErrNone, Panic(EAgmErrRollbackFailed));
       
  2420 
       
  2421 	TRAP(ret,RollbackIndexesL());
       
  2422 	}
       
  2423 
       
  2424 
       
  2425 void CAgnEntryModel::NotifyingL(MCalChangeCallBack2::TChangeType aChangeType, CAgnEntry& aEntry, CAgnInstanceInfo* aOriginalEntry)
       
  2426 	{
       
  2427 	if ( iChangeFilter )
       
  2428 		{
       
  2429 		if ( iChangeFilter->ChangeBroadcastEnabled() )
       
  2430 			{
       
  2431 			NotifyChangeL((iChangeFilter->Session()), &aEntry, aChangeType, aOriginalEntry);
       
  2432 			}
       
  2433 		else
       
  2434 			{
       
  2435 			iChangeFilter->SetChangeMadeWhileDisabled(ETrue);
       
  2436 			}
       
  2437 
       
  2438 		if ( aEntry.Type() == CCalEntry::ETodo )
       
  2439 			{
       
  2440 			iChangeFilter->SetPubSubChange(TAgnChangeFilter::ETodoChanged);
       
  2441 			}
       
  2442 		else
       
  2443 			{
       
  2444 			iChangeFilter->SetPubSubChange(TAgnChangeFilter::EEventChanged);
       
  2445 			}
       
  2446 
       
  2447 		NotifyPublishAndSubscribeL(*iChangeFilter);
       
  2448 		}
       
  2449 	}
       
  2450 
       
  2451 /*
       
  2452 Delete aEntry from the store. If it has a positive replicated count however then mark it as having
       
  2453 been deleted and update it instead.
       
  2454 @capability WriteUserData
       
  2455 @capability ReadUserData
       
  2456 */
       
  2457 void CAgnEntryModel::DeleteEntryL(CAgnEntry& aEntry, TBool aCascadeDelete, TAgnChangeFilter* aChangeFilter)
       
  2458 	{
       
  2459 	#if defined (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
       
  2460 		{
       
  2461 		TBuf<KMaxGuidBufLength> guidBuf;
       
  2462 		guidBuf.Copy(aEntry.Guid());
       
  2463 		AgmDebug::DebugLog("DeleteEntryL: Deleting entry with local UID=%d, GUID=%S", aEntry.LocalUid(), &guidBuf);
       
  2464 		}
       
  2465 	#endif
       
  2466 
       
  2467 	iChangeFilter = aChangeFilter;
       
  2468 	
       
  2469 	if ( aCascadeDelete )
       
  2470 		{
       
  2471 		if ( aEntry.GsDataType() == CGsData::EParent )
       
  2472 			{
       
  2473 			_DBGLOG_ENTRY(AgmDebug::DebugLog("DeleteEntryL: Deleting children");)
       
  2474 			
       
  2475 			DeleteChildrenL(aEntry);
       
  2476 			}
       
  2477 		else
       
  2478 			{
       
  2479 			_DBGLOG_ENTRY(AgmDebug::DebugLog("DeleteEntryL: Updating Parent");)
       
  2480 			UpdateParentL(aEntry);
       
  2481 			}
       
  2482 		}
       
  2483 
       
  2484 	DoDeleteEntryL(aEntry);
       
  2485 	
       
  2486 	NotifyingL(MCalChangeCallBack2::EChangeDelete,aEntry, NULL);
       
  2487 
       
  2488 	if ( iUpdateAlarm && aEntry.HasAlarm() )
       
  2489 		{
       
  2490 		iAlarm->FindAndQueueNextAlarmL(EFalse);
       
  2491 		iAlarm->DeleteEntriesAlarmL(aEntry.EntryId());	
       
  2492 		}
       
  2493 	
       
  2494 	if(iChangeFilter && iTzRuleIndex)
       
  2495 		{
       
  2496 		//Remove the tz rule from tz rule index
       
  2497 		//we have to do it after CAgnEntryModel::NotifyingL that is indirectly using the
       
  2498 		//tz rule in aEntry.
       
  2499 		iTzRuleIndex->RemoveTzRuleL(aEntry);
       
  2500 		}
       
  2501 	}
       
  2502 
       
  2503 
       
  2504 void CAgnEntryModel::DeleteChildrenL(CAgnEntry& aParent)
       
  2505 	{//Get Child ids
       
  2506 	__ASSERT_DEBUG(aParent.GsDataType() == CGsData::EParent, Panic(EAgmErrNotParentEntry));
       
  2507 	
       
  2508 	CAgnEntry* parent = FetchEntryL(aParent.EntryId());
       
  2509 	if (parent != NULL)
       
  2510 		{
       
  2511 		CleanupStack::PushL(parent);
       
  2512 		
       
  2513 		const RArray<TGsChildRefData>& KIds = parent->ChildIds();
       
  2514 		// delete each child entry 
       
  2515 		for ( TInt i = KIds.Count() - 1; i >= 0; --i )
       
  2516 			{
       
  2517 			const TCalLocalUid& KChildId = KIds[i].ChildId();
       
  2518 			CAgnEntry* childEntry = FetchEntryL(KChildId);  // pass flag so as not to tell parent  
       
  2519 			if (childEntry)
       
  2520 				{
       
  2521 				CleanupStack::PushL(childEntry);
       
  2522 
       
  2523 				DeleteEntryL(*childEntry, EFalse, iChangeFilter); // don't propogate the delete back to this parent
       
  2524 
       
  2525 				CleanupStack::PopAndDestroy(childEntry);
       
  2526 				}
       
  2527 			
       
  2528 			aParent.RemoveChildId(KChildId);
       
  2529 			}
       
  2530 		
       
  2531 		CleanupStack::PopAndDestroy(parent);
       
  2532 		}
       
  2533 	}
       
  2534 
       
  2535 
       
  2536 void CAgnEntryModel::UpdateParentL(CAgnEntry& aChild)
       
  2537 	{
       
  2538 	// It should be used in server side so that the notification of updating a parent is not sent
       
  2539 	__ASSERT_DEBUG(aChild.GsDataType() == CGsData::EChild, Panic(EAgmErrNotChildEntry));
       
  2540 
       
  2541 	// get parent and update
       
  2542 	CAgnEntry* parentEntry = FetchEntryL(aChild.ParentId());
       
  2543 	__ASSERT_ALWAYS(parentEntry, User::Leave(KErrNotFound));
       
  2544 	CleanupStack::PushL(parentEntry);
       
  2545 
       
  2546 	parentEntry->RemoveChildId(aChild.LocalUid());
       
  2547 
       
  2548 	UpdateEntryL(*parentEntry, iChangeFilter, EFalse);
       
  2549 
       
  2550 	CleanupStack::PopAndDestroy(parentEntry);	
       
  2551 	}
       
  2552 
       
  2553 
       
  2554 /**
       
  2555 Delete aEntry from the store. If the entry is a todo then its id is removed from its
       
  2556 todo list.
       
  2557 */
       
  2558 void CAgnEntryModel::DoDeleteEntryL(CAgnEntry& aEntry)
       
  2559 	{
       
  2560 	DeleteExternalAttributesL(aEntry);
       
  2561 	
       
  2562 	TAgnEntryId id = aEntry.EntryId();
       
  2563 	TStreamId streamId = iEntryManager->DeleteEntryL(id);
       
  2564 
       
  2565 	if ( streamId != KNullStreamId )
       
  2566 		{
       
  2567 		__ASSERT_DEBUG(streamId == aEntry.EntryId().StreamId(), Panic(EAgmErrWrongEntryDeleted));
       
  2568 		StreamStore().DeleteL(streamId);
       
  2569 		iModelStreamIdSet->EntryStreamIdSet().DeleteL(streamId);
       
  2570 		}
       
  2571 	
       
  2572 	if ( ! iEntryManager->BufferedDeleting() || iEntryManager->BufferHasBeenStored() ) // during tidying only commit when the buffer has been written
       
  2573 		{
       
  2574 		iEntryManager->StoreBuffersL();
       
  2575 		ExternalizeEntryManagerL();
       
  2576 		// Don't commit on delete. CommitL is called from CalInterimAPI after a number have been added.
       
  2577 		}
       
  2578 	
       
  2579 	UpdateIndexL(aEntry, NULL, EDelete);
       
  2580 	}
       
  2581 
       
  2582 
       
  2583 TBool CAgnEntryModel::EntryHasNoChildrenAndNoValidInstancesL(CAgnEntry& aEntry) const
       
  2584 	{
       
  2585 	TInt instances(1);
       
  2586 	TInt exceptions(0);
       
  2587 	if ( aEntry.RptDef() )
       
  2588 		{
       
  2589 		// Purely based on repeat rule, does not include exceptions' count
       
  2590 		instances = aEntry.RptDef()->InstanceCountL();
       
  2591 		const RArray<TAgnCalendarTime>* KExceptionList = aEntry.RptDef()->Exceptions();
       
  2592 		if (KExceptionList)
       
  2593 			{
       
  2594 			exceptions += KExceptionList->Count();
       
  2595 			}
       
  2596 		
       
  2597 		__ASSERT_ALWAYS(instances >= exceptions, User::Leave(KErrCorrupt));
       
  2598 		}
       
  2599 	
       
  2600 	TBool entryHasNoChild = ((aEntry.GsDataType() == CGsData::EChild) || aEntry.ChildIds().Count() == 0);
       
  2601 	return (entryHasNoChild && instances == exceptions);
       
  2602 	}
       
  2603 
       
  2604 /*
       
  2605 @capability ReadUserData
       
  2606 @capability WriteUserData
       
  2607 */
       
  2608 void CAgnEntryModel::UpdateEntryL(CAgnEntry& aEntry, TAgnChangeFilter* aChangeFilter, TBool aDeleteChildren)
       
  2609 	{
       
  2610 	TAgnEntryId originalId = aEntry.EntryId();
       
  2611 	
       
  2612 	if (originalId.IsNullId()) 
       
  2613 		{
       
  2614 		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: EntryId is null. Must be a newly created entry");)
       
  2615 		
       
  2616 		// Only parent entries can be updated
       
  2617 		if(aEntry.GsDataType() != CGsData::EParent)
       
  2618 			{
       
  2619 			_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: KErrArgument: Only parent entries can be updated");)
       
  2620 			User::Leave(KErrArgument);
       
  2621 			}
       
  2622 
       
  2623 		RPointerArray<CAgnEntry> entriesWithThisGuid;
       
  2624 		CleanupResetAndDestroyPushL(entriesWithThisGuid);
       
  2625 		FetchEntriesL(aEntry.Guid(), entriesWithThisGuid);
       
  2626 		
       
  2627 		// Only an existing entry with the same guid can be updated
       
  2628 		if(entriesWithThisGuid.Count() == 0)
       
  2629 			{
       
  2630 			_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: KErrNotFound: Only an existing entry with the same guid can be updated");)
       
  2631 			User::Leave(KErrNotFound);
       
  2632 			}
       
  2633 		
       
  2634 		CAgnEntry* existingParent = entriesWithThisGuid[0];
       
  2635 		aEntry.SetLocalUid(existingParent->LocalUid());
       
  2636 		aEntry.SetEntryId(existingParent->EntryId());
       
  2637 		originalId = existingParent->EntryId();
       
  2638 		
       
  2639 		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: Setting Ids: LocalUid - %d, EntryId - %d", aEntry.LocalUid(),aEntry.EntryId().Value());)
       
  2640 		CleanupStack::PopAndDestroy(&entriesWithThisGuid);
       
  2641 		}
       
  2642 		
       
  2643 	//client server calls needs to be updated
       
  2644 	iChangeFilter = aChangeFilter;
       
  2645 	
       
  2646 	if (EntryHasNoChildrenAndNoValidInstancesL(aEntry))
       
  2647 		{
       
  2648 		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: Deleting invalid entry - No children and no valid instances");)
       
  2649 		DeleteEntryL(aEntry, EFalse, iChangeFilter);
       
  2650 		return;
       
  2651 		}
       
  2652 	
       
  2653 	if ( aDeleteChildren )
       
  2654 		{
       
  2655 		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: Deleting children");)
       
  2656 		DeleteChildrenL(aEntry);
       
  2657 		}
       
  2658 	
       
  2659 	CAgnEntry* oldEntry = FetchEntryL(originalId);
       
  2660 	__ASSERT_DEBUG(oldEntry, User::Leave(KErrNotFound));
       
  2661 	CleanupStack::PushL(oldEntry);
       
  2662 	TBool hadAlarm = EFalse;
       
  2663 	if ( oldEntry )
       
  2664 		{
       
  2665 		hadAlarm = oldEntry->HasAlarm();
       
  2666 		}
       
  2667 	
       
  2668 	CAgnInstanceInfo* instanceInfoBefore = CAgnInstanceInfo::NewLC(*oldEntry);
       
  2669 
       
  2670 	TRAPD(ret, DoUpdateEntryL(aEntry, oldEntry));
       
  2671 
       
  2672 	if ( ret != KErrNone )
       
  2673 		{
       
  2674 		aEntry.SetEntryId(originalId);
       
  2675 		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: DoUpdateEntryL failed: Leaving with error - %d",ret);)
       
  2676 		User::Leave(ret);
       
  2677 		}
       
  2678 
       
  2679 	NotifyingL(MCalChangeCallBack2::EChangeModify, aEntry, instanceInfoBefore);
       
  2680 	
       
  2681 	CleanupStack::PopAndDestroy(instanceInfoBefore);
       
  2682 	CleanupStack::PopAndDestroy(oldEntry);
       
  2683 	
       
  2684 	// Delete the old alarm and if a new alarm exists it will be added by findAndQueue
       
  2685 	// If a todo is completed or an event updated, while alarm is snoozed, 
       
  2686 	// then the snoozed alarm has to be deleted separately, and deletion is not handled by findAndQueue
       
  2687 	if (hadAlarm)
       
  2688 		{
       
  2689 		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: Deleting the alarm on the existing entry");)
       
  2690 
       
  2691 		iAlarm->DeleteEntriesAlarmL(aEntry.EntryId());
       
  2692 		}
       
  2693 	if (iUpdateAlarm && aEntry.HasAlarm())
       
  2694 		{
       
  2695 		iAlarm->FindAndQueueNextAlarmL(EFalse);
       
  2696 		}
       
  2697 	}
       
  2698 
       
  2699 /** Update an entry in the store. 
       
  2700 @capability ReadUserData
       
  2701 */
       
  2702 void CAgnEntryModel::DoUpdateEntryL(CAgnEntry& aEntry, CAgnEntry* aOldEntry)
       
  2703 	{
       
  2704 	TStreamId newStreamId;
       
  2705 	UpdateExternalAttributesL(aEntry);
       
  2706 
       
  2707 	if (aOldEntry)
       
  2708 		{
       
  2709 		DoUpdateAttachmentsL(aEntry, *aOldEntry);
       
  2710 		}
       
  2711 	
       
  2712 	if(iTzRuleIndex)
       
  2713 		{
       
  2714 		__ASSERT_DEBUG(aOldEntry, Panic(EAgmErrNullPointer));
       
  2715 		iTzRuleIndex->UpdateTzRuleL(*aOldEntry, aEntry);
       
  2716 		}
       
  2717 	
       
  2718 	TStreamId oldStreamId = iEntryManager->UpdateEntryL(aEntry, newStreamId);
       
  2719 
       
  2720 	if ( oldStreamId != KNullStreamId )
       
  2721 		{
       
  2722 		StreamStore().DeleteL(oldStreamId);
       
  2723 		iModelStreamIdSet->EntryStreamIdSet().DeleteL(oldStreamId);
       
  2724 		}
       
  2725 
       
  2726 	if ( newStreamId != KNullStreamId )
       
  2727 		{
       
  2728 		iModelStreamIdSet->EntryStreamIdSet().AddL(newStreamId);			
       
  2729 		}
       
  2730 
       
  2731 	iEntryManager->StoreBuffersL();
       
  2732 	ExternalizeEntryManagerL();
       
  2733 	
       
  2734 	UpdateIndexL(aEntry, aOldEntry, EUpdate);
       
  2735 	}
       
  2736 
       
  2737 // Called when an entry is updated
       
  2738 // This compares the new entry with the old one to see if any attachments have changed drive (by calling CCalAttachmentFile::SetDrive).
       
  2739 void CAgnEntryModel::DoUpdateAttachmentsL(CAgnEntry& aNewEntry, CAgnEntry& aOldEntry)
       
  2740 	{//This method will move the attachment to a different drive if it has been reset by the user.
       
  2741 	const TInt KOldAttachmentCount = aOldEntry.AttachmentCount();
       
  2742 	const TInt KNewAttachmentCount = aNewEntry.AttachmentCount();
       
  2743 	
       
  2744 	for (TInt oldEntryIndex = 0; oldEntryIndex < KOldAttachmentCount; ++oldEntryIndex)
       
  2745 		{
       
  2746 		CAgnAttachment& oldAttach = aOldEntry.Attachment(oldEntryIndex);
       
  2747 		if (oldAttach.Type() == CCalContent::EDispositionInline && oldAttach.Uid() != 0)
       
  2748 			{
       
  2749 			CAgnAttachmentFile& oldAttachFile = static_cast<CAgnAttachmentFile&>(oldAttach);
       
  2750 			TDriveName oldDrive = oldAttachFile.Drive();
       
  2751 			
       
  2752 			for (TInt newEntryIndex = 0; newEntryIndex < KNewAttachmentCount; ++newEntryIndex)
       
  2753 				{
       
  2754 				CAgnAttachmentFile& newAttachFile = static_cast<CAgnAttachmentFile&>(aNewEntry.Attachment(newEntryIndex));
       
  2755 				if (newAttachFile.Uid() == oldAttach.Uid() && newAttachFile.Drive() != oldDrive)
       
  2756 					{
       
  2757 					HBufC* newfilename = oldAttachFile.FileName().AllocLC();
       
  2758 					newfilename->Des().Replace(0,2,newAttachFile.Drive());
       
  2759 					iAgnServerFile->MoveFileL(oldAttachFile.FileName(), newfilename->Des());
       
  2760 					CleanupStack::PopAndDestroy(newfilename);
       
  2761 
       
  2762 					break;
       
  2763 					}
       
  2764 				}
       
  2765 			}
       
  2766 		}
       
  2767 	}
       
  2768 
       
  2769 void CAgnEntryModel::MoveAttachmentToDriveL(CAgnAttachmentFile& aOldFileAttachment, CAgnAttachmentFile& aNewFileAttachment)
       
  2770 	{
       
  2771 	TParsePtrC parse(aOldFileAttachment.FileName());
       
  2772 	HBufC* fileName = GenerateFilenameLC(aNewFileAttachment.Drive(), parse.NameAndExt());
       
  2773 	TPtr pFilename(fileName->Des());
       
  2774 	iAgnServerFile->MoveFileL(aOldFileAttachment.FileName(), pFilename);
       
  2775 	aNewFileAttachment.SetFileNameL(*fileName);
       
  2776 	CleanupStack::PopAndDestroy(fileName);
       
  2777 		
       
  2778 	#if defined (__CAL_ATTACH_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
       
  2779 		HBufC8* attachId = aNewFileAttachment.ContentId().AllocLC();
       
  2780 		AgmDebug::DebugLog("Moving attachment to drive: Old filename: %S to New filename with drive: %S", &aOldFileAttachment.FileName(), &pFilename);
       
  2781 		AgmDebug::DebugLog("Attachment: UId - %S, Old filename size - %d, New filename size - %d", attachId, aOldFileAttachment.Size(), aNewFileAttachment.Size());
       
  2782 		CleanupStack::PopAndDestroy(attachId);
       
  2783 	#endif
       
  2784 	}
       
  2785 
       
  2786 const CAgnSimpleEntry* CAgnEntryModel::GetSimpleEntryFromIndexes(const TAgnEntryId& aEntryId)
       
  2787 	{
       
  2788 	return iSimpleEntryTable->GetEntry(aEntryId);
       
  2789 	}
       
  2790 
       
  2791 const CAgnSimpleEntry* CAgnEntryModel::GetSimpleEntryFromIndexes(TCalLocalUid aUniqueId)
       
  2792 	{
       
  2793 	return iSimpleEntryTable->GetEntry(aUniqueId);
       
  2794 	}
       
  2795 
       
  2796 /** 
       
  2797 Gets an entry based on its entry ID.
       
  2798 
       
  2799 @internalComponent
       
  2800 @capability ReadUserData
       
  2801 @param aId The entry ID of the entry to retrieve.
       
  2802 @return Pointer to the entry. 
       
  2803 */
       
  2804 CAgnEntry* CAgnEntryModel::FetchEntryL(const TAgnEntryId& aId) const
       
  2805 	{
       
  2806 	CAgnEntry* entry = iEntryManager->FetchEntryL(aId);
       
  2807 	if (entry)
       
  2808 		{
       
  2809 		CleanupStack::PushL(entry);
       
  2810 
       
  2811 		if(iTzRuleIndex)
       
  2812 			{
       
  2813 			iTzRuleIndex->FetchTzRuleL(*entry);
       
  2814 			}
       
  2815 		
       
  2816 		_DBGLOG_ENTRY(AgmDebug::DebugLog("FetchEntryL: Fetched entry with Stream Id %d, Partial Id %d",aId.Value(), aId.PartialId());)
       
  2817 
       
  2818 		if ( entry->GsDataType() == CGsData::EChild )
       
  2819 			{
       
  2820 			_DBGLOG_ENTRY(AgmDebug::DebugLog("FetchEntryL: Entry fetched is a child entry, Parent Id - %d", entry->ParentId());)
       
  2821 			
       
  2822 			// if a child entry has been fetched, get the recurrence ID and range stored with the parent
       
  2823 			CAgnEntry* parent = FetchEntryL(entry->ParentId());
       
  2824 
       
  2825 			__ASSERT_ALWAYS(parent, User::Leave(KErrCorrupt)); // child without parent entry in DB!
       
  2826 			CleanupStack::PushL(parent);
       
  2827 			
       
  2828 			entry->SetRecurrenceIdFromParentL(*parent);
       
  2829 			
       
  2830 			CleanupStack::PopAndDestroy(parent);
       
  2831 			}
       
  2832 
       
  2833 		_DBGLOG_ENTRY(AgmDebug::DebugLogEntryL(*entry, EDumpEntryAll);)
       
  2834 		CleanupStack::Pop(entry);
       
  2835 		}
       
  2836 	return (entry);
       
  2837 	}
       
  2838 
       
  2839 /** 
       
  2840 Gets an entry based on its unique ID.
       
  2841 
       
  2842 @internalComponent
       
  2843 @capability ReadUserData
       
  2844 @param aId The unique ID of the entry to retrieve.
       
  2845 @return Pointer to the entry. 
       
  2846 */
       
  2847 CAgnEntry* CAgnEntryModel::FetchEntryL(TCalLocalUid aUniqueId) const
       
  2848 	{
       
  2849 	_DBGLOG_ENTRY(AgmDebug::DebugLog("FetchEntryL: Attempting to fetch simple entry with LocalUid='%d'", aUniqueId);)
       
  2850 	
       
  2851 	// find entry in indexes to get the entry ID
       
  2852 	CAgnSimpleEntry* simpleEntry = iSimpleEntryTable->GetEntry(aUniqueId);
       
  2853 	CAgnEntry* entry = NULL;
       
  2854 	
       
  2855 	if ( simpleEntry )
       
  2856 		{
       
  2857 		_DBGLOG_ENTRY(AgmDebug::DebugLog("FetchEntryL: Entry found, fetching the full entry with Local ID %d",simpleEntry->EntryId().Value());)
       
  2858 		
       
  2859 		// fetch the full entry from the entry ID
       
  2860 		entry = FetchEntryL(simpleEntry->EntryId());			
       
  2861 		}
       
  2862 	#if defined (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
       
  2863 	else
       
  2864 		{
       
  2865 		AgmDebug::DebugLog("FetchEntryL: Entry not found");
       
  2866 		}
       
  2867 	#endif
       
  2868 
       
  2869 	
       
  2870 	return ( entry );
       
  2871 	}
       
  2872 
       
  2873 /** 
       
  2874 Gets entries based on GUID.
       
  2875 
       
  2876 @internalComponent
       
  2877 @capability ReadUserData
       
  2878 @param aGuid The GUID of the entry to retrieve
       
  2879 @param aList The list of CAgnEntry objects
       
  2880 */
       
  2881 void CAgnEntryModel::FetchEntriesL(const TDesC8& aGuid, RPointerArray<CAgnEntry>& aList) const
       
  2882 	{
       
  2883 	CAgnEntry* parentEntry = FetchEntryL(aGuid);
       
  2884 	
       
  2885 	#if defined (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
       
  2886 		TBuf<KMaxGuidBufLength> guidBuf;
       
  2887 		guidBuf.Copy(aGuid);
       
  2888 		AgmDebug::DebugLog("FetchEntriesL:  Using GUID='%S'", &guidBuf);
       
  2889 	#endif
       
  2890 
       
  2891 	if ( parentEntry )
       
  2892 		{
       
  2893 		#if defined (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
       
  2894 			TBuf<KMaxGuidBufLength> guidBuf;
       
  2895 			guidBuf.Copy(aGuid);
       
  2896 			AgmDebug::DebugLog("FetchEntriesL: Found a parent entry with GUID='%S'", &guidBuf);
       
  2897 		#endif
       
  2898 
       
  2899 		CleanupStack::PushL(parentEntry);
       
  2900 		aList.AppendL(parentEntry);
       
  2901 		CleanupStack::Pop(parentEntry);
       
  2902 		
       
  2903 		// Fetch the children and add them to the array
       
  2904 		const RArray<TGsChildRefData>& KIds = parentEntry->ChildIds();
       
  2905 		
       
  2906 		const TInt KCount = KIds.Count();
       
  2907 		
       
  2908 		_DBGLOG_ENTRY(AgmDebug::DebugLog("FetchEntriesL: Parent entry has %d child(ren)", KCount);)
       
  2909 
       
  2910 		for ( TInt i = 0; i < KCount; ++i )
       
  2911 			{
       
  2912 			CAgnEntry* childEntry = FetchEntryL(KIds[i].ChildId());  // pass flag so as not to tell parent to update its child list 
       
  2913 			if (childEntry)
       
  2914 				{
       
  2915 				CleanupStack::PushL(childEntry);
       
  2916 				aList.AppendL(childEntry);
       
  2917 				CleanupStack::Pop(childEntry);
       
  2918 				}
       
  2919 			}
       
  2920 		}  // parentEntry
       
  2921 	}
       
  2922 
       
  2923 
       
  2924 CAgnEntry* CAgnEntryModel::FetchEntryL(const TDesC8& aGuid, const TAgnCalendarTime& aRecurrenceId) const	
       
  2925 	{
       
  2926 	CAgnEntry* returnEntry = NULL;
       
  2927 	CAgnEntry* parentEntry = FetchEntryL(aGuid);
       
  2928 	
       
  2929 	if ( parentEntry )
       
  2930 		{
       
  2931 		CleanupStack::PushL(parentEntry);
       
  2932 		returnEntry = FindChildFromParentL(*parentEntry, aRecurrenceId); 
       
  2933 		CleanupStack::PopAndDestroy(parentEntry);  	
       
  2934 		}
       
  2935 		
       
  2936 	return returnEntry;
       
  2937 	}
       
  2938 
       
  2939 TBool CAgnEntryModel::AreIndexesBuilt() const
       
  2940 	{
       
  2941 	if (iAgnServerFile)
       
  2942 		{
       
  2943 		return iAgnServerFile->AreIndexesBuilt();
       
  2944 		}
       
  2945 	return EFalse;
       
  2946 	}
       
  2947 
       
  2948 
       
  2949 void CAgnEntryModel::RestoreCategoriesL()
       
  2950 	{
       
  2951 	if ( iCalConverter )
       
  2952 		{
       
  2953 		iCalConverter->InternalizeCategoriesL();
       
  2954 		}
       
  2955 	}
       
  2956 
       
  2957 void CAgnEntryModel::OpenAttachmentFileL(RFile& aFile, TInt aAttachmentUid) const
       
  2958 	{
       
  2959 	const CAgnAttachmentIndexItem* const item = iAttachmentIndex->Attachment(aAttachmentUid);
       
  2960 	// item is owned by iAttachmentIndex
       
  2961 	
       
  2962 	if ( item )
       
  2963 		{
       
  2964 		iAgnServerFile->OpenFileL(aFile, item->FileName());
       
  2965 		}
       
  2966 	else
       
  2967 		{
       
  2968 		User::Leave(KErrNotFound);
       
  2969 		}
       
  2970 	}
       
  2971 
       
  2972 
       
  2973 void CAgnEntryModel::CreateNewFileL(RFile& aFile, const TDesC& aFileName)
       
  2974 	{
       
  2975 	iAgnServerFile->CreateNewFileL(aFile, aFileName);
       
  2976 	}
       
  2977 
       
  2978 // Called when a binary data attachment is stored. 
       
  2979 // At this stage, a new file has been created, and the file handle returned to the client.
       
  2980 // The data is written to file from the client side, then this function is called to update the metadata of the entry containing the attachment.
       
  2981 void CAgnEntryModel::UpdateAttachmentDetailsL(TCalLocalUid aLocalUid, TInt aAttachmentIndex, const TDesC& aFileName, TInt aAttachmentSize)
       
  2982 	{
       
  2983 	_DBGLOG_ATTACH(AgmDebug::DebugLog("UpdateAttachmentDetailsL: Local Uid %d, Attachment Index %d, FileName %S, Attachment Size %d", aLocalUid, aAttachmentIndex, &aFileName, aAttachmentSize);)
       
  2984 	
       
  2985 	CAgnEntry* entry = FetchEntryL(aLocalUid);
       
  2986 	
       
  2987 	if ( entry )
       
  2988 		{
       
  2989 		CleanupStack::PushL(entry);
       
  2990 		
       
  2991 		CAgnAttachmentFile* attachment = static_cast<CAgnAttachmentFile*>(&entry->Attachment(aAttachmentIndex));
       
  2992 
       
  2993 		if ( attachment && attachment->FileName().Length() <= KMaxDriveName)
       
  2994 			{
       
  2995 			attachment->SetFileNameL(aFileName);
       
  2996 			attachment->SetSize(aAttachmentSize);
       
  2997 			attachment->SetUid(iNextAttachmentUid);
       
  2998 			++iNextAttachmentUid;
       
  2999 			UpdateEntryL(*entry, NULL, EFalse);
       
  3000 			
       
  3001 			ExternalizeNextUidValuesL();
       
  3002 			}
       
  3003 			
       
  3004 		CleanupStack::PopAndDestroy(entry);
       
  3005 		}
       
  3006 	}
       
  3007 
       
  3008 TInt CAgnEntryModel::TransferFileFromClientL(RFile& aAttachfileHandle, CAgnAttachmentFile& aAttachFile, CAgnEntry& aEntry, TBool aIsSameDrive)
       
  3009 	{
       
  3010 	RBuf originalFileName;
       
  3011 	originalFileName.CreateL(KMaxFileName);
       
  3012 	CleanupClosePushL(originalFileName);
       
  3013 	aAttachfileHandle.FullName(originalFileName);
       
  3014 	TInt size;
       
  3015 	User::LeaveIfError(aAttachfileHandle.Size(size));
       
  3016 				
       
  3017 	// Generate  attachment filename
       
  3018 	
       
  3019 	TParsePtrC parseOriginalFile(originalFileName); 
       
  3020 	HBufC* fileName = GenerateFilenameLC(aAttachFile.FileName(), parseOriginalFile.NameAndExt());
       
  3021 	TPtr attachFilename(fileName->Des());
       
  3022 		
       
  3023 	_DBGLOG_ATTACH(AgmDebug::DebugLog("TransferFileFromClientL: Transferring file from: %S of size %d to %S", &originalFileName, size, &attachFilename);)
       
  3024 	if(aIsSameDrive)
       
  3025 		{
       
  3026 		User::LeaveIfError(aAttachfileHandle.Rename(attachFilename)); // move the file to calendar area
       
  3027 		}
       
  3028 	else
       
  3029 		{
       
  3030 		aAttachfileHandle.Close();
       
  3031  		iAgnServerFile->MoveFileL(originalFileName, attachFilename);			
       
  3032 		}
       
  3033 	aAttachFile.SetFileNameL(attachFilename);
       
  3034 	aAttachFile.SetSize(size);
       
  3035 	aAttachFile.SetUid(iNextAttachmentUid++);
       
  3036 	
       
  3037 	// Don't call UpdateEntryL as we only need to update the Calendar db file
       
  3038 	TRAPD(err, UpdateEntryL(aEntry, NULL, EFalse));
       
  3039 	if (err != KErrNone)
       
  3040 		{
       
  3041 		// if the entry failed to update, move the attachment back
       
  3042 		if (aIsSameDrive)
       
  3043 			{
       
  3044 			User::LeaveIfError(aAttachfileHandle.Rename(originalFileName));	
       
  3045 			}
       
  3046 		else
       
  3047 			{
       
  3048 			iAgnServerFile->MoveFileL(fileName->Des(), originalFileName);		
       
  3049 			}	
       
  3050 		User::Leave(err);
       
  3051 		}
       
  3052 
       
  3053 	CleanupStack::PopAndDestroy(2, &originalFileName);
       
  3054 	ExternalizeNextUidValuesL();
       
  3055 	return iNextAttachmentUid-1;
       
  3056 	}
       
  3057 TInt CAgnEntryModel::MoveFileToServerL(TCalLocalUid aLocalUid, TInt aAttachmentIndex)
       
  3058 	{
       
  3059 	TInt ret = 0;
       
  3060 	TRAPD(err, ret = DoMoveFileToServerL(aLocalUid, aAttachmentIndex));
       
  3061 	if(err != KErrNone)	
       
  3062 		{
       
  3063 		iAttachmentFileHandle.Close();
       
  3064 		User::Leave(err);	
       
  3065 		}
       
  3066 	return ret;
       
  3067 	}
       
  3068 	
       
  3069 TInt CAgnEntryModel::DoMoveFileToServerL(TCalLocalUid aLocalUid, TInt aAttachmentIndex)
       
  3070 	{
       
  3071 	_DBGLOG_ATTACH(AgmDebug::DebugLog("DoMoveFileToServerL: Local Uid %d, Attachment Index %d", aLocalUid, aAttachmentIndex);)
       
  3072 	
       
  3073 	TCalAttachmentUid attachUid(0);
       
  3074 
       
  3075 	CAgnEntry* entry = FetchEntryL(aLocalUid);
       
  3076 	__ASSERT_ALWAYS(entry, User::Leave(KErrCorrupt));
       
  3077 	CleanupStack::PushL(entry);
       
  3078 
       
  3079 	CAgnAttachment& attach = entry->Attachment(aAttachmentIndex);
       
  3080 	__ASSERT_ALWAYS(attach.Type() == CCalContent::EDispositionInline, User::Leave(KErrCorrupt));
       
  3081 
       
  3082 	CAgnAttachmentFile& attachFile = static_cast<CAgnAttachmentFile&>(attach);
       
  3083 	__ASSERT_ALWAYS(attachFile.Drive().CompareF(KDefaultAttachmentDrive()),User::Leave(KErrCorrupt) );//Drive is the default one
       
  3084 
       
  3085 	attachUid = TransferFileFromClientL(iAttachmentFileHandle,attachFile, *entry, EFalse);
       
  3086 
       
  3087 	CleanupStack::PopAndDestroy(entry);
       
  3088 	return attachUid;
       
  3089 	}
       
  3090 	
       
  3091 TInt CAgnEntryModel::TransferAttachmentFileToServerL(RFile& aFile, TCalLocalUid aLocalUid, TInt aAttachmentIndex)
       
  3092 	{
       
  3093 	_DBGLOG_ATTACH(AgmDebug::DebugLog("TransferAttachmentFileToServerL: Local Uid %d, Attachment Index %d", aLocalUid, aAttachmentIndex);)
       
  3094 	
       
  3095 	TCalAttachmentUid attachUid(0);
       
  3096 	CAgnEntry* entry = FetchEntryL(aLocalUid);
       
  3097 	__ASSERT_ALWAYS(entry, User::Leave(KErrCorrupt));
       
  3098 	CleanupStack::PushL(entry);
       
  3099 
       
  3100 	CAgnAttachment& attach = entry->Attachment(aAttachmentIndex);
       
  3101 	__ASSERT_ALWAYS(attach.Type() == CCalContent::EDispositionInline, User::Leave(KErrCorrupt));
       
  3102 
       
  3103 	CAgnAttachmentFile& attachFile = static_cast<CAgnAttachmentFile&>(attach);
       
  3104 
       
  3105 	if(!attachFile.Drive().CompareF(KDefaultAttachmentDrive()))//Drive is the default one
       
  3106 		{
       
  3107 		attachUid = TransferFileFromClientL(aFile, attachFile, *entry, ETrue);
       
  3108 		}
       
  3109 	else
       
  3110 		{//Client need to close the handle in order to move the original file to the drive specified.
       
  3111 		User::LeaveIfError(iAttachmentFileHandle.Duplicate(aFile));	
       
  3112 		}
       
  3113 
       
  3114 	CleanupStack::PopAndDestroy(entry);
       
  3115 	return attachUid;
       
  3116 	}
       
  3117 
       
  3118 // Generate a filename for an attachment on the specified drive.
       
  3119 HBufC* CAgnEntryModel::GenerateFilenameLC(const TDesC& aDrive, const TDesC& aFileName)
       
  3120 	{
       
  3121 	_LIT(KCalDirectory, "\\");
       
  3122 	
       
  3123 	// file name is "X:\\private\\10003a5b\\calendarfilename_a\\Y\\filename"
       
  3124 	// where X is the drive specified (KDefaultAttachmentDrive if none is set)
       
  3125 	// and Y is the folder number calculated from the attachment ID
       
  3126 	const TInt KNumberOfAttachmentsPerFolder = 32;
       
  3127 	//Restricting the Attachemnt folder name length to 2 chars, where it allows to add max0-99 folders
       
  3128 	//by considering the KMaxFileName Length is allowed 220 Chars	
       
  3129 	const TInt KMaxNumOfAttachmentFolders = 100;
       
  3130 	// 8 to cover attachment folder name and trailing number if there exists a same file name
       
  3131 	const TInt KExtraFileNameLength = 8;
       
  3132 	TInt fileNameLength = iAgnServerFile->FileName().Length() + KExtraFileNameLength  + aFileName.Length();
       
  3133 	TPtrC fileNamePtr (aFileName);
       
  3134 	if(fileNameLength > KMaxFileName)
       
  3135 	    {
       
  3136 	    const TInt KMinFileNameLength = 8;
       
  3137 	    fileNameLength = iAgnServerFile->FileName().Length() + KExtraFileNameLength +  KMinFileNameLength;
       
  3138 	    if(fileNameLength > KMaxFileName)
       
  3139 	        {
       
  3140 	        User::Leave(KErrBadName);
       
  3141 	        }
       
  3142 	    else
       
  3143 	        {
       
  3144 	        fileNamePtr.Set(aFileName.Left(KMinFileNameLength - 2));//save 2 for trailling number
       
  3145 	        }
       
  3146 	    }
       
  3147 	HBufC* fileName = HBufC::NewLC(fileNameLength);
       
  3148 	TPtr folderNamePtr = fileName->Des();
       
  3149 	iAgnServerFile->GetAttachmentFolderNameL(folderNamePtr);
       
  3150 	
       
  3151 	// if the drive has been set already, set it on the filename
       
  3152 	if ( aDrive.Length() >= 1 )
       
  3153 		{
       
  3154 		folderNamePtr.Replace(0, 1, aDrive.Left(1));
       
  3155 		}
       
  3156 	else
       
  3157 		{
       
  3158 		folderNamePtr.Replace(0, 1, KDefaultAttachmentDrive().Left(1));
       
  3159 		}
       
  3160 	
       
  3161 	const TInt KFolderNumber = iNextAttachmentUid / KNumberOfAttachmentsPerFolder;
       
  3162 	if (KFolderNumber >= KMaxNumOfAttachmentFolders)
       
  3163 		{
       
  3164 		User::LeaveIfError(KErrDirFull);
       
  3165 		}
       
  3166 	folderNamePtr.AppendNum(KFolderNumber);
       
  3167 	folderNamePtr.Append(KCalDirectory);
       
  3168     TPtr fullFileNamePtr(folderNamePtr);
       
  3169 	fullFileNamePtr.Append(fileNamePtr);	
       
  3170 	TBool uniqueFilenameGenerated = EFalse;
       
  3171 	TInt count = 0;
       
  3172 	while ( ! uniqueFilenameGenerated )
       
  3173 	    {
       
  3174 	    if ( !iAgnServerFile->FileExistsL(fullFileNamePtr) )
       
  3175             {
       
  3176             uniqueFilenameGenerated = ETrue;
       
  3177             }
       
  3178 	    else
       
  3179 	        {
       
  3180 	        TParsePtrC parse(fileNamePtr);
       
  3181 	        fullFileNamePtr = folderNamePtr;
       
  3182 	        fullFileNamePtr.Append(parse.Name());
       
  3183 	        fullFileNamePtr.AppendNum(count++);
       
  3184 	        fullFileNamePtr.Append(parse.Ext());
       
  3185 	        }
       
  3186 	    }
       
  3187 	
       
  3188 	iAgnServerFile->CreateDirL(fullFileNamePtr);
       
  3189 	return fileName;
       
  3190 	}
       
  3191 
       
  3192 // Generate a filename for an attachment on the specified drive.
       
  3193 HBufC* CAgnEntryModel::GenerateRandomFilenameLC(const TDesC& aDrive)
       
  3194     {
       
  3195     _LIT(KCalDirectory, "\\");
       
  3196     
       
  3197     // file name is "X:\\private\\10003a5b\\calendarfilename_a\\Y\\filename"
       
  3198     // where X is the drive specified (KDefaultAttachmentDrive if none is set)
       
  3199     // and Y is the folder number calculated from the attachment ID
       
  3200     const TInt KNumberOfAttachmentsPerFolder = 32;
       
  3201     const TInt KNumCharsInFileName = 8; 
       
  3202     //Restricting the Attachemnt folder name length to 2 chars, where it allows to add max0-99 folders
       
  3203     //by considering the KMaxFileName Length is allowed 220 Chars   
       
  3204     const TInt KMaxNumOfAttachmentFolders = 100;
       
  3205 
       
  3206     // 16 to cover attachment folder name and extension - could be 'foldername\\888\\filename.xxx'
       
  3207     const TInt KFileNameLength = iAgnServerFile->FileName().Length() + 32 + KNumCharsInFileName;
       
  3208     
       
  3209     HBufC* fileName = HBufC::NewLC(KFileNameLength);
       
  3210     TPtr fileNamePtr = fileName->Des();
       
  3211     
       
  3212     iAgnServerFile->GetAttachmentFolderNameL(fileNamePtr);
       
  3213     
       
  3214     // if the drive has been set already, set it on the filename
       
  3215     if ( aDrive.Length() >= 1 )
       
  3216         {
       
  3217         fileNamePtr.Replace(0, 1, aDrive.Left(1));
       
  3218         }
       
  3219     else
       
  3220         {
       
  3221         fileNamePtr.Replace(0, 1, KDefaultAttachmentDrive().Left(1));
       
  3222         }
       
  3223     
       
  3224     const TInt KFolderNumber = iNextAttachmentUid / KNumberOfAttachmentsPerFolder;
       
  3225     if (KFolderNumber >= KMaxNumOfAttachmentFolders)
       
  3226         {
       
  3227         User::LeaveIfError(KErrDirFull);
       
  3228         }
       
  3229     fileNamePtr.AppendNum(KFolderNumber);
       
  3230     fileNamePtr.Append(KCalDirectory);
       
  3231     
       
  3232     TBool uniqueFilenameGenerated = EFalse;
       
  3233     
       
  3234     TTime time;
       
  3235     time.UniversalTime();
       
  3236     TInt64 seed = time.Int64() + iNextAttachmentUid;
       
  3237     
       
  3238     while ( ! uniqueFilenameGenerated )
       
  3239         {
       
  3240         // Generate a random filename
       
  3241         for ( TInt i = 0; i < KNumCharsInFileName; ++i, ++seed )
       
  3242             {
       
  3243             TChar randomChar = (Math::Rand(seed) % 26) + 'a';
       
  3244             fileNamePtr.Append(randomChar);
       
  3245             }
       
  3246 
       
  3247         // check that there is not an existing filename with the same name (very unlikely!)
       
  3248         if ( iAgnServerFile->FileExistsL(fileNamePtr) )
       
  3249             {
       
  3250             // Remove this file name from the descriptor if the file exists already, and generate a new name
       
  3251             fileNamePtr.SetLength(fileNamePtr.Length() - KNumCharsInFileName);
       
  3252             }
       
  3253         else
       
  3254             {
       
  3255             uniqueFilenameGenerated = ETrue;
       
  3256             }
       
  3257         }
       
  3258     
       
  3259     iAgnServerFile->CreateDirL(fileNamePtr);
       
  3260     return fileName;
       
  3261     }
       
  3262 
       
  3263 const RArray<TCalLocalUid>* CAgnEntryModel::GetEntriesWithAttachment(TCalAttachmentUid aAttachmentUid) const
       
  3264 	{
       
  3265 	_DBGLOG_ATTACH(AgmDebug::DebugLog("GetEntriesWithAttachment: Attachment Uid %d", aAttachmentUid);)
       
  3266 	
       
  3267 	const CAgnAttachmentIndexItem* const item = iAttachmentIndex->Attachment(aAttachmentUid);
       
  3268 	
       
  3269 	if ( item && item->Entries().Count())
       
  3270 		{
       
  3271 		return &item->Entries();
       
  3272 		}
       
  3273 		
       
  3274 	return NULL;
       
  3275 	}
       
  3276 
       
  3277 
       
  3278 void CAgnEntryModel::GetSortedAttachmentsL(RArray<TCalAttachmentUid>& aAttachmentIds, CCalAttachmentManager::TSortOrder aSortType)
       
  3279 	{
       
  3280 	RPointerArray<CAgnAttachmentIndexItem> sortedAttachments;
       
  3281 	CleanupClosePushL(sortedAttachments);
       
  3282 	iAttachmentIndex->GetSortedIndexL(aSortType, sortedAttachments);
       
  3283 
       
  3284 	const TInt KAttachmentCount = sortedAttachments.Count();
       
  3285 	for ( TInt i = 0; i < KAttachmentCount; ++i)
       
  3286 		{
       
  3287 		aAttachmentIds.AppendL(sortedAttachments[i]->Uid());
       
  3288 		}
       
  3289 
       
  3290 	CleanupStack::PopAndDestroy(&sortedAttachments); 
       
  3291 	}
       
  3292 
       
  3293 
       
  3294 CAgnAttachment* CAgnEntryModel::FetchAttachmentByIdL(TCalAttachmentUid aAttachUid)
       
  3295 	{
       
  3296 	_DBGLOG_ATTACH(AgmDebug::DebugLog("FetchAttachmentByIdL: Attachment Uid %d", aAttachUid);)
       
  3297 	
       
  3298 	const CAgnAttachmentIndexItem* const item = iAttachmentIndex->Attachment(aAttachUid);
       
  3299 	CAgnAttachment* attachmentToWrite = NULL;
       
  3300 	
       
  3301 	if ( item )
       
  3302 		{
       
  3303 		const RArray<TCalLocalUid>& KEntries = item->Entries();
       
  3304 
       
  3305 		if ( KEntries.Count() == 0 )
       
  3306 			{
       
  3307 			// corrupt index - remove the attachment and return NULL
       
  3308 			iAttachmentIndex->RemoveAttachment(aAttachUid);
       
  3309 			}
       
  3310 		else
       
  3311 			{
       
  3312 			const TCalLocalUid& Kid = KEntries[0];
       
  3313 			CAgnEntry* entry = FetchEntryL(Kid);
       
  3314 
       
  3315 			if ( entry )
       
  3316 				{
       
  3317 				CleanupStack::PushL(entry);
       
  3318 
       
  3319 				for ( TInt i = 0; i < entry->AttachmentCount(); ++i )
       
  3320 					{
       
  3321 					if ( entry->Attachment(i).Uid() == aAttachUid )
       
  3322 						{
       
  3323 						attachmentToWrite = AttachmentFactory::CloneL(entry->Attachment(i));
       
  3324 
       
  3325 						break;
       
  3326 						}
       
  3327 					}
       
  3328 
       
  3329 				CleanupStack::PopAndDestroy(entry);
       
  3330 				}
       
  3331 			}
       
  3332 		}
       
  3333 
       
  3334 	return attachmentToWrite;
       
  3335 	}
       
  3336 
       
  3337 const TDesC8& CAgnEntryModel::GetEntryGuidL(CAgnEntry& aEntry) const
       
  3338 	{
       
  3339 	if(aEntry.Guid() == KNullDesC8)
       
  3340 		{//it is a child and its uid has not been loaded
       
  3341 		CAgnEntry* parentEntry = FetchEntryL(aEntry.ParentId());
       
  3342 		__ASSERT_DEBUG(parentEntry, Panic(EAgmErrChildWithoutParent));
       
  3343 		if(parentEntry)
       
  3344 			{
       
  3345 			CleanupStack::PushL(parentEntry);
       
  3346 			HBufC8* guidHbuf = parentEntry->Guid().AllocL();
       
  3347 			CleanupStack::PopAndDestroy(parentEntry);	
       
  3348 			aEntry.SetGuid(guidHbuf);
       
  3349 			}
       
  3350 		}
       
  3351 	return aEntry.Guid();
       
  3352 	}
       
  3353 
       
  3354 
       
  3355 /**
       
  3356 Returns A reference to the stream store in which the model's data is stored. 
       
  3357 @internalComponent
       
  3358 */
       
  3359 CStreamStore& CAgnEntryModel::StreamStore() const
       
  3360 	{
       
  3361 	return iEntryManager->StreamStore();
       
  3362 	}
       
  3363 
       
  3364 CCalAsyncDelete* CAgnEntryModel::CreateAsyncDeleteL(TAgnChangeFilter& aChangeFilter)
       
  3365 	{
       
  3366 	return CCalAsyncDelete::NewL(*this, aChangeFilter, *iSimpleEntryTable);
       
  3367 	}
       
  3368 
       
  3369 void CAgnEntryModel::LoadNewStreamStoreL(CStreamStore& aStore, const TStreamId& aModelStreamId, CAgnEntryManager& aEntryManager, CAgnTzRuleIndex& aTzRuleIndex)
       
  3370 	{
       
  3371 	iEntryManager->SetStore(aStore);
       
  3372 
       
  3373 	iEntryManager->CopyStreamIds(aEntryManager);
       
  3374 	iModelStreamIdSet->LoadL(aStore, aModelStreamId);
       
  3375 	
       
  3376 	if(iTzRuleIndex)
       
  3377 		{
       
  3378 		delete iTzRuleIndex; 
       
  3379 		}
       
  3380 	
       
  3381 	iTzRuleIndex = &aTzRuleIndex;
       
  3382 	iTzRuleIndex->CheckTzDbModificationL(*iAgnServerFile);
       
  3383 	}
       
  3384 
       
  3385 TBool CAgnEntryModel::StreamsAreEmpty() const
       
  3386 	{
       
  3387 	return (iModelStreamIdSet->EntryStreamIdSet().Count() == 0);
       
  3388 	}
       
  3389 
       
  3390 TAgnEntryIter* CAgnEntryModel::CreateEntryIterL() const
       
  3391 	{
       
  3392 	return new (ELeave) TAgnEntryIter(iModelStreamIdSet->EntryStreamIdSet(), *iEntryManager);
       
  3393 	}
       
  3394 
       
  3395 CAgnCategoryIndex& CAgnEntryModel::CategoryIndex() const
       
  3396 /** Gets the category index.
       
  3397 
       
  3398 @return The agenda model category index object. */
       
  3399 	{
       
  3400 	return ( *iCategoryIndex );
       
  3401 	}
       
  3402 
       
  3403 TTime CAgnEntryModel::TzRulesLastModifiedDateL()
       
  3404 	{
       
  3405 	return iTzRuleIndex->TzRulesLastModifiedDateL();
       
  3406 	}
       
  3407 
       
  3408 void CAgnEntryModel::HandleTzRulesChangeL(const TTime& aTime)
       
  3409     {
       
  3410     iTzRuleIndex->HandleTzRulesChangeL(aTime);
       
  3411     }
       
  3412 
       
  3413 CAgnAlarm& CAgnEntryModel::Alarm()
       
  3414     {
       
  3415     return *iAlarm;
       
  3416 	}