pimappservices/calendar/server/src/agsentrymodel.cpp
changeset 0 f979ecb2b13e
child 12 38571fd2a704
child 45 b6db4fd4947b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappservices/calendar/server/src/agsentrymodel.cpp	Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,3416 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "agsentrymodel.h"
+
+#include "agsalarm.h"
+#include "agsasyncdelete.h"
+#include "agsattachmentindex.h"
+#include "agscategoryindex.h"
+#include "agscategorylist.h"
+#include "agsentrymanager.h"
+#include "agmentry.h"
+#include "agsextractor.h"
+#include "agsfileconverter.h"
+#include "agsiterator.h"
+#include "agsstreamidset.h"
+#include "agssort.h"
+#include "agmutil.h"
+#include "agmattendee.h"
+#include "agmcategory.h"
+#include "agssortinstance.h"
+#include "agsindex.h"
+#include "agmcontent.h"
+#include "agsfilemanager.h"
+#include "agsmain.h"
+#include "agssess.h"
+#include "agstzruleindex.h"
+#include <calnotification.h>
+#include "agsinstanceiterator.h"
+
+#include "agmdebug.h"
+
+#include <e32math.h>
+#include <e32property.h>
+#include <s32file.h>
+
+
+// Compact threshold dependent on the number of operations
+const TInt KCompactOperationsThreshold = 32;
+
+/** This is called when opening an agenda file
+@internalComponent
+ */
+CAgnEntryModel* CAgnEntryModel::NewL(CAgnServFile* aAgnServerFile)
+	{
+	CAgnEntryModel* self = new (ELeave) CAgnEntryModel();
+	
+	CleanupStack::PushL(self);
+	self->ConstructL(aAgnServerFile);
+	CleanupStack::Pop();
+	
+	return (self);
+	}
+
+/** Constructs a CAgnEntryModel object
+@internalComponent
+ */
+void CAgnEntryModel::ConstructL(CAgnServFile* aAgnServerFile)
+
+	{
+	iUpdateAlarm = ETrue;
+	iModelStreamIdSet = CAgnModelStreamIdSet::NewL();
+	iEntryManager = CAgnEntryManager::NewL();
+	iNextLocalUidValue = 1;
+	iNextAttachmentUid = 1;
+
+	if ( aAgnServerFile )
+		{//When opening a file
+		iAgnServerFile = aAgnServerFile;
+		iSimpleEntryTable = CAgnSimpleEntryTable::NewL(*this);
+        iExtractor = new (ELeave) TAgnInstanceExtractor(*iSimpleEntryTable);
+		iCategoryIndex = CAgnCategoryIndex::NewL();
+		iAttachmentIndex = new (ELeave) CAgnAttachmentIndex;
+		CreateAlarmForServerL();
+		}
+	iIndexFileIsDirty = ETrue; 	// for safety assume that the index
+					// file is out of date. We can correct this
+					// when we read the file
+
+	iIndexFileIsPresent = ETrue; // Assume the index file is present. 
+	                             // First attempt to read it will update this
+	                             // if it is not there.
+	iTzRuleIndex = NULL;
+	}
+
+/** 
+Frees all resources owned by the agenda model, prior to its destruction. 
+
+@internalComponent
+@capability None
+*/
+CAgnEntryModel::~CAgnEntryModel()
+	{
+	ResetRollback();
+	delete iCategoryIndex;
+	delete iAttachmentIndex;
+	delete iTzRuleIndex;
+	delete iExtractor;	
+	delete iSimpleEntryTable;
+	delete iAlarm;
+	delete iModelStreamIdSet;
+	delete iEntryManager;
+	delete iCalConverter;
+	}
+
+const CAgnServFile& CAgnEntryModel::AgnServFile()
+	{
+	return *iAgnServerFile;
+	}
+
+/** Load up the stream network
+ */
+void CAgnEntryModel::DoOpenL(const TStreamId& aModelStreamId)
+	{
+	delete iCalConverter;
+	iCalConverter = NULL;
+	
+	// Check if a calendar converter is needed (old version file)
+	//
+	TAgnVersion fileVersion;
+	CalCommon::TCalFileVersionSupport status;
+	iAgnServerFile->GetFileVersionSupportStatusL(fileVersion,status);
+
+	if ( status == CalCommon::EFileNeedsConverting )
+		{
+		if ( iAgnServerFile->IsReadOnly() )
+			{
+			User::Leave(KErrAccessDenied);
+			}
+
+		iCalConverter = CalFileVersionUtils::CreateConverterL(fileVersion, *iAgnServerFile);
+		iModelStreamIdSet->LoadL(StreamStore(), aModelStreamId, *iCalConverter);
+		}
+	else
+		{
+		iTzRuleIndex = CAgnTzRuleIndex::NewL(*iAgnServerFile->Dictionary(), *iAgnServerFile->StoreL());
+		iModelStreamIdSet->LoadL(StreamStore(), aModelStreamId);
+		//If the Calendar file needs to be converted, CheckTzDbModificationL should be called after the file conversion is completed (in method LoadNewStreamStoreL). 
+		TAgnVersion curVersion = CalFileVersionUtils::CurrentFileVersion();
+		if(status == CalCommon::EFileIsCurrentVersion && !(fileVersion == curVersion))
+			{
+			//access to here means the format of index file has been changed but not to the rest
+			//Changing the index file format does not cause DC but we need to ignore the old index files
+			iIndexFileIsDirty = EFalse;
+			iIndexFileIsPresent = EFalse;
+			// Mark the existing index file as dirty and delete them.
+			// Trap the leave to keep things running, but there is nothing
+			// we can do if the file can't be deleted.
+			TRAP_IGNORE(MarkIndexFileAsDirtyL());
+			
+			//Change the version of file to be current version.
+			TRAP_IGNORE(iModelStreamIdSet->ChangeFileVersionL(StreamStore(), aModelStreamId, curVersion));
+			}
+		}
+	
+	GetFileIdL();
+	InternalizeNextUidValuesL();
+	InternalizeEntryManagerL();
+	}
+
+void CAgnEntryModel::CheckTzDbModificationL()
+	{
+	if(iTzRuleIndex)
+		{
+		iTzRuleIndex->CheckTzDbModificationL(*iAgnServerFile);
+		}
+	}
+
+/** Opens an existing model store, whose root ID is aModelStreamId in the store aStore.
+
+@capability None
+@param aStore The store in which the model's data is stored.
+@param aId The root stream ID of the store aStore.
+
+@internalComponent
+*/
+void CAgnEntryModel::OpenL(CStreamStore& aStore, const TStreamId& aModelStreamId) 
+	{	
+	Reset();
+	
+	iEntryManager->SetStore(aStore);
+	DoOpenL(aModelStreamId);
+	}
+
+TStreamId CAgnEntryModel::CreateL(CStreamStore& aStore) 
+	{
+	Reset();
+
+	iEntryManager->SetStore(aStore);
+
+	TStreamId headStreamId = iModelStreamIdSet->CreateL(aStore, CalFileVersionUtils::CurrentFileVersion());
+
+	// save the next unique id value to the store
+	iNextLocalUidValue = 1;
+	iNextAttachmentUid = 1;
+	ExternalizeNextUidValuesL();
+
+	// save the entry store object to the store
+	ExternalizeEntryManagerL();
+	
+	TTime creationDate; 
+	creationDate.UniversalTime();
+	iFileId = creationDate.Int64();
+	TInt threeDidgit=Math::Random() % 1000;
+	iFileId = iFileId - threeDidgit;// Ensure the file ID is unique even when two files have been created at the same time.
+	ExternalizeFileIdL(aStore, iModelStreamIdSet->FileInformationStreamId());
+	StreamStore().CommitL();
+
+	return (headStreamId);
+	}
+
+void CAgnEntryModel::ExternalizeFileIdL(CStreamStore& aStore, const TStreamId& aStreamId) const
+	{
+	RStoreWriteStream out;
+	// save file id
+	out.ReplaceLC(aStore, aStreamId);
+	out << iFileId;
+	out.CommitL();
+	CleanupStack::PopAndDestroy(); //out
+	}
+
+/**
+Adds aEntry to the store and returns its resulting entry id.
+@capability None
+*/
+TAgnEntryId CAgnEntryModel::DoAddEntryL(CAgnEntry& aEntry)
+	{
+	// If local UID is not set or if it's already used, then the entry is assigned a new local uid.
+	TBool useNextLocalUid = EFalse;
+	if (aEntry.LocalUid() == 0 || iSimpleEntryTable->GetEntry(aEntry.LocalUid()) != NULL)
+		{
+		useNextLocalUid = ETrue;
+        while (iSimpleEntryTable->GetEntry(++iNextLocalUidValue) != NULL)
+            {
+            }
+       	aEntry.SetLocalUid(iNextLocalUidValue);
+		}
+
+	TAgnEntryId nullId;
+	aEntry.SetEntryId(nullId);
+
+	StoreExternalAttributesL(aEntry);
+	
+	CopyAttachmentFileToDifferentPlaceL(aEntry);
+
+	//Add the tz rules in the entry to tz rule index before it is stored in entry manager.
+	if(iTzRuleIndex)
+		{
+		iTzRuleIndex->AddTzRuleL(aEntry);
+		}
+	
+	TStreamId newStreamId = iEntryManager->AddEntryL(aEntry);
+	if ( newStreamId != KNullStreamId )
+		{
+		iModelStreamIdSet->EntryStreamIdSet().AddL(newStreamId);
+		}
+	
+	TAgnEntryId entryId = aEntry.EntryId();
+	
+	if ( useNextLocalUid )
+		{
+		ExternalizeNextUidValuesL();			
+		}
+	
+	iEntryManager->StoreBuffersL();
+	ExternalizeEntryManagerL();
+	
+	UpdateIndexL(aEntry, NULL, EAdd);
+
+	// Don't commit on add. CommitL is called from CalInterimAPI after a number have been added.
+		
+	return (entryId);
+	}
+
+//It could copy the attachment to a different drive if it is the same as the existing one but with a different drive name
+//or, it could copy the attachment form a different calendar file folder.
+void CAgnEntryModel::CopyAttachmentFileToDifferentPlaceL(CAgnEntry& aEntry)
+    {
+    const TInt KAttachCount = aEntry.AttachmentCount();
+    for (TInt ii = 0; ii < KAttachCount; ++ii)
+        {
+        CAgnAttachment& attach = aEntry.Attachment(ii);
+        if (attach.Uid() && attach.Type() == CCalContent::EDispositionInline)
+            {
+            CAgnAttachmentFile* attachFile = static_cast<CAgnAttachmentFile*>(&attach);
+            if(IsAttachmentFileFromSameSessionL(attachFile->FileName()))
+                {
+                const TDesC& existFileName = iAttachmentIndex->FileName(attach.Uid());
+                if(existFileName != KNullDesC())
+                    {//There exists an attachment with same uid 
+                    TDriveName oldDrive = existFileName.Left(2);
+                    TDriveName newDrive = attachFile->Drive();
+                    if(oldDrive.CompareF(newDrive) != 0)//drive is different
+                        {
+                    //Copy file to a new drive with the same name
+                        HBufC* newfileName = existFileName.AllocLC();
+                        newfileName->Des().Replace(0,2,newDrive);
+                        iAgnServerFile->CopyFileL(existFileName, newfileName->Des());
+                        attachFile->SetFileNameL(*newfileName);
+                        CleanupStack::PopAndDestroy(newfileName);
+                        }
+                    }
+                }
+            else if (iAgnServerFile->FileExistsL(attachFile->FileName())) 
+                { //Attachment has been copied from a different calendar session
+                TParsePtrC parseOriginalFile(attachFile->FileName()); 
+                HBufC* fileName = GenerateFilenameLC(parseOriginalFile.Drive(), parseOriginalFile.NameAndExt());
+                iAgnServerFile->CopyFileL(attachFile->FileName(), fileName->Des());
+                attachFile->SetFileNameL(fileName->Des());
+                CleanupStack::PopAndDestroy(fileName);
+                attachFile->SetUid(iNextAttachmentUid++);
+                }
+            }
+        }
+    }
+//Find out if the attachment is copied from a different server session
+TBool CAgnEntryModel::IsAttachmentFileFromSameSessionL(const TDesC& aAttachmentFile)
+    {
+    TBool ret = ETrue;
+    if(aAttachmentFile.FindF(iAgnServerFile->PrivatePath()) != KErrNotFound)
+
+        {//The file name is something, for example,
+        //c:\private\private\10003a5c\calendar_filename_a\0\attachmentfilename
+        //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. 
+        TInt lengthPath = iAgnServerFile->PrivatePath().Length();
+        const TInt lengthDrive = 2;
+        //tempRemovedPath1 =  calendar_filename_a\0\attachmentfilename
+        TPtrC tempRemovedPath1(aAttachmentFile.Mid(lengthPath + lengthDrive));
+        //tempRemovedPath2 =  calendar_filename_a
+        TPtrC tempRemovedPath2(tempRemovedPath1.Left(tempRemovedPath1.Locate('\\')));
+        //calName = calendar_filename
+        TPtrC calName(tempRemovedPath2.Left(tempRemovedPath2.LocateReverse('_')));
+        TParsePtrC parseFile(iAgnServerFile->FileName()); 
+        if(calName.CompareF(parseFile.NameAndExt()) != 0)
+            {
+            ret = EFalse;
+            }
+        }
+    return ret;
+    }
+
+// aEntry is the entry that has been changed. If the change is an update, then aOriginalEntry gives 
+// details about the original entry.
+void CAgnEntryModel::NotifyChangeL(const CAgnServerSession& aSession, CAgnEntry* aEntry, 
+									 MCalChangeCallBack2::TChangeType aChangeType, CAgnInstanceInfo* aOriginalEntry)
+	{
+	TAgnChange change;
+	change.iOperationType = aChangeType;
+	
+	if ( aEntry )
+		{
+		change.iEntryType = aEntry->Type();
+		change.iEntryId = aEntry->LocalUid();
+		change.iRepeatRule = aEntry->RptDef();
+		change.iStartTimeOfEntryUtc = aEntry->StartTime().UtcL();
+		change.iEndTimeOfEntryUtc = aEntry->ValidToTimeLocalL();
+			
+		if ( aOriginalEntry )
+			{
+			change.iOriginalRepeatRule = aOriginalEntry->RptDef();
+			change.iOriginalStartTimeUtc = aOriginalEntry->StartTimeUtc();
+			change.iOriginalEndTimeUtc = aOriginalEntry->EndTimeUtc();
+			}
+		else
+			{
+			change.iOriginalRepeatRule = NULL;
+			change.iOriginalStartTimeUtc = Time::NullTTime();
+			change.iOriginalEndTimeUtc = Time::NullTTime();
+			}
+		}
+	else
+		{
+		change.iEntryType = CCalEntry::EAppt;
+		change.iEntryId = 0;
+		change.iStartTimeOfEntryUtc = Time::NullTTime();
+		change.iEndTimeOfEntryUtc = Time::NullTTime();
+		change.iRepeatRule = NULL;
+		change.iOriginalStartTimeUtc = Time::NullTTime();
+		change.iOriginalEndTimeUtc = Time::NullTTime();
+		change.iOriginalRepeatRule = NULL;
+		}
+	
+	change.iSession = const_cast<CAgnServerSession*>(&aSession);
+	GetFileIdL();
+	change.iFileId = iFileId;
+	NotifySessionsOfChangeL(change);
+	}
+
+void CAgnEntryModel::NotifySessionsOfChangeL(const TAgnChange& aChange)
+	{
+	RPointerArray<CAgnServerSession> sessions;
+	CleanupClosePushL(sessions);
+	iAgnServerFile->Server().FetchSessionsL(sessions);
+	const TInt count = sessions.Count();
+	for ( TInt i = 0; i < count; ++i )
+		{
+		sessions[i]->AddChangeL(aChange);
+		}
+	CleanupStack::PopAndDestroy(&sessions); // sessions.Close()
+	}
+
+void CAgnEntryModel::NotifyPublishAndSubscribeL(TAgnChangeFilter& aChangeFilter)
+	{
+	// if publish and subcribe is enabled...	
+	if ( aChangeFilter.PubSubEnabled() )
+		{
+		// ...get and set the Publish and Subscribe data
+		TCalPubSubData calPubSubData;
+		calPubSubData.iFileNameHash = iAgnServerFile->FileNameHash();
+		calPubSubData.iTimeOfChangeUtc.UniversalTime(); 
+		
+		TPckgBuf<TCalPubSubData> calBuf(calPubSubData);
+		
+		// publish the update
+		if ( aChangeFilter.TodoChanged() )
+			{
+			User::LeaveIfError(RProperty::Set(KCalPubSubCategory, ECalPubSubTodoNotification, calBuf));
+			}
+		else
+			{
+			User::LeaveIfError(RProperty::Set(KCalPubSubCategory, ECalPubSubEventNotification, calBuf));
+			}
+		
+		aChangeFilter.SetPubSubChange(TAgnChangeFilter::ENoChange);
+		}
+	}
+
+/**
+Add a entry to the file. This function decides whether a new entry should be added or if an existing entry 
+should be replaced. It also handles the adding of child entries.
+@internalComponent
+@return the TAgnEntryId of the newly added entry.
+@param aEntry The entry being stored.
+@param aChangeFilter Specifies the notification filter for the session adding the entry.
+@leave KErrArgument If aEntry is a parent but contains a recurrence Id.
+@leave KErrNotFound If aEntry is a child entry whose parent entry doesn't exist in the calendar store.
+@leave KErrArgument If aEntry is a child entry with a different time mode (fixed / floating) to its parent entry.
+*/
+TAgnEntryId CAgnEntryModel::StoreL(CAgnEntry& aEntry, TAgnChangeFilter* aChangeFilter)
+	{
+	iChangeFilter = aChangeFilter;
+	TAgnEntryId returnId;
+
+	if ( aEntry.GsDataType() == CGsData::EParent )
+		{
+		_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Entry to be stored is a parent");)
+		_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Checking if an entry with the same GUID already exists");)
+		
+		// it is a parent entry
+		CAgnEntry* existingEntryToReplace = FetchEntryL(aEntry.Guid());
+
+		if (existingEntryToReplace == NULL && aEntry.LocalUid() != 0)
+			{
+			//This is used for the case when sync a updated entry from remote sync server.
+			//Some servers may filter out GUID assigned by client and only info we can get
+			//to update a entry is by using its local ID.
+			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Attempting to fetch using localUid to fetch the entry from the server");)
+			existingEntryToReplace = FetchEntryL(aEntry.LocalUid());
+			}
+				
+		if ( existingEntryToReplace)
+			{
+			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: An entry with the same GUID already exists");)
+
+			CleanupStack::PushL(existingEntryToReplace);
+			if (existingEntryToReplace->Type() == aEntry.Type())
+				{
+				_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Existing entry type matches incoming entry's type");)
+
+				// if this entry is the same type as the existing entry, update the existing entry
+				aEntry.SetEntryId(existingEntryToReplace->EntryId());
+				aEntry.SetLocalUid(existingEntryToReplace->LocalUid());
+				
+				_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Setting Ids using the existing entry: LocalUid= %d, EntryId= %d", aEntry.LocalUid(),aEntry.EntryId().Value());)
+				
+			        const RArray<TGsChildRefData>& KChildIds = existingEntryToReplace->ChildIds();
+			        const TInt KCount = KChildIds.Count();
+			        for ( TInt ii = 0; ii < KCount; ++ii )
+			            {
+			            aEntry.AddChildIdL(KChildIds[ii]);
+			            }
+
+				aEntry.SetLastModifiedDate();
+	
+				UpdateEntryL(aEntry, iChangeFilter, ETrue);
+
+				returnId = aEntry.EntryId();
+				}
+			else 
+				{
+				_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Existing entry types is different to incoming entry's type");)
+				_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Delete the existing entry and add the incoming entry as a new one");)
+				
+				// if the entry is a different type, delete the old entry and add the new one 
+				DeleteEntryL(*existingEntryToReplace, ETrue, iChangeFilter);
+				returnId = AddEntryL(aEntry);
+				}
+
+			CleanupStack::PopAndDestroy(existingEntryToReplace);
+			}
+		else
+			{
+			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Matching existing entry not found. Adding a new entry");)
+			returnId = AddEntryL(aEntry);
+			}
+		}
+	else
+		{
+		_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Entry to be stored is a child");)
+		//if this is a child entry, fetch the parent from the child's GUID (if present) or Local UID
+		CAgnEntry* parentEntry = NULL;
+		if ( aEntry.Guid() != KNullDesC8 )
+			{
+			parentEntry = FetchEntryL(aEntry.Guid());
+			}
+		else
+			{
+			parentEntry = FetchEntryL(aEntry.ParentId());
+			}
+		
+		if(parentEntry==NULL)
+			{
+			#if defined (__CAL_BASIC_LOGGING__) || (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING)
+				AgmDebug::DebugLog("StoreL: KErrNotFound: Parent entry with the GUID or localUid doesnt exist");	
+			#endif
+	
+			User::Leave(KErrNotFound);
+			}
+		
+		CleanupStack::PushL(parentEntry);
+
+		if ( parentEntry->TimeMode() != aEntry.TimeMode() ||  parentEntry->Type() != aEntry.Type() )
+			{
+			#if defined (__CAL_BASIC_LOGGING__) || (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
+				AgmDebug::DebugLog("StoreL: KErrArgument: Child entry with different time mode or type from the parent entry is not allowed");
+			#endif
+			
+			// don't allow a child entry to be different time mode or type from the parent entry
+			User::Leave(KErrArgument);
+			}
+		
+		if ( ! aEntry.RecurrenceId().IsSet())
+			{
+			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Recurrence ID not set on the incoming entry. Setting it using the parent");)
+			aEntry.SetRecurrenceIdFromParentL(*parentEntry);
+			}
+		
+		// We allow only repeating parents to have children that attempt to change a parent 
+		// schedule.(If the user's intention is to modify a non-repeating parent, the entire
+		// parent should be replaced with a new entry).
+		const CAgnRptDef* KParentRptDef = parentEntry->RptDef();
+		
+		if(KParentRptDef==NULL)
+			{
+			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Parent is not repeating. Only repeating parents are allowed to have children");)
+			_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");)
+		
+			User::Leave(KErrArgument);
+			}
+				
+		if ( aEntry.RptDef() )
+			{
+			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Incoming entry is a repeating child entry");)
+			returnId = AddRepeatingChildEntryUpdateParentRuleL(*parentEntry, aEntry);
+			}
+		else	
+			{	
+			_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Incoming entry is a non-repeating child entry");)
+			returnId = AddNonRepeatingChildEntryUpdateParentExceptionsL(*parentEntry, aEntry);						
+			}
+		
+		CleanupStack::PopAndDestroy(parentEntry);
+		}
+		_DBGLOG_VERBOSE(AgmDebug::DebugLog("StoreL: Entry added successfully");)
+		_DBGLOG_ENTRY(AgmDebug::DebugLogEntryL(aEntry, EDumpEntryAll);)
+
+	return (returnId);
+	}
+
+TStreamId CAgnEntryModel::WriteDescriptorToStreamL(const TDesC& aString)
+	{
+	if (aString.Length() > 0)
+		{
+		RStoreWriteStream out;
+		TStreamId id = out.CreateLC(StreamStore());
+		out.WriteUint32L(aString.Length());
+		out << aString;
+		out.CommitL();
+		CleanupStack::PopAndDestroy(); //out
+		return id;
+		}
+	return KNullStreamId;
+	}
+
+/** 
+Store those entry properties which are stored in a separate stream: summary, description, alarm action.
+@capability WriteUserData
+*/
+void CAgnEntryModel::StoreExternalAttributesL(CAgnEntry& aEntry)
+	{
+	TStreamId id = WriteDescriptorToStreamL(aEntry.Description());
+	aEntry.SetDescriptionStreamId(id);
+	
+	id = WriteDescriptorToStreamL(aEntry.Summary());
+	aEntry.SetSummaryStreamId(id);
+
+	if ( aEntry.AlarmAction() )
+		{
+		RStoreWriteStream out;
+		id = out.CreateLC(StreamStore());
+		out << *aEntry.AlarmAction();
+		out.CommitL();
+		CleanupStack::PopAndDestroy(); //out
+		aEntry.SetAlarmActionStreamId(id);
+		}
+	}
+
+void CAgnEntryModel::DeleteExternalAttributesL(CAgnEntry& aEntry)
+	{
+	if ( aEntry.DescriptionStreamId() != KNullStreamId )
+		{
+		StreamStore().DeleteL(aEntry.DescriptionStreamId());
+		aEntry.SetDescriptionStreamId(KNullStreamId);
+		}
+
+	if ( aEntry.SummaryStreamId() != KNullStreamId )
+		{
+		StreamStore().DeleteL(aEntry.SummaryStreamId());
+		aEntry.SetSummaryStreamId(KNullStreamId);
+		}
+
+	if ( aEntry.AlarmActionStreamId() != KNullStreamId )
+		{
+		StreamStore().DeleteL(aEntry.AlarmActionStreamId());
+		aEntry.SetAlarmActionStreamId(KNullStreamId);
+		}
+	}
+
+void CAgnEntryModel::UpdateExternalAttributesL(CAgnEntry& aEntry)
+	{
+	// 3 scenarios where we do something for updating notes text
+	TStreamId id = KNullStreamId;
+
+	switch ( aEntry.DescriptionChange() )
+		{
+		case CAgnEntry::EAgnDataDeleted:
+			DeleteTextStreamL(aEntry.DescriptionStreamId());
+			aEntry.SetDescriptionStreamId(KNullStreamId);
+			break;
+
+		case CAgnEntry::EAgnDataAdded:
+			id = StoreTextL(aEntry.Description());
+			aEntry.SetDescriptionStreamId(id);
+			break;
+
+		case CAgnEntry::EAgnDataUpdated:
+			UpdateTextL(aEntry.Description(), aEntry.DescriptionStreamId());
+			break;
+
+		default://no changes
+			break;
+		}
+
+	// 3 scenarios where we do something for updating summary text
+	switch ( aEntry.SummaryChange() )
+		{
+		case CAgnEntry::EAgnDataDeleted:
+			DeleteTextStreamL(aEntry.SummaryStreamId());
+			aEntry.SetSummaryStreamId(KNullStreamId);
+			break;
+
+		case CAgnEntry::EAgnDataAdded:
+			id = StoreTextL(aEntry.Summary());
+			aEntry.SetSummaryStreamId(id);
+			break;
+
+		case CAgnEntry::EAgnDataUpdated:
+			UpdateTextL(aEntry.Summary(), aEntry.SummaryStreamId());
+			break;
+
+		default://no changes
+			break;
+		}
+
+	// 3 scenarios where we do something for updating alarm action
+	switch ( aEntry.AlarmActionChange() )
+		{
+		case CAgnEntry::EAgnDataDeleted:
+			DeleteAlarmActionStreamL(aEntry.AlarmActionStreamId());
+			aEntry.SetAlarmActionStreamId(KNullStreamId);
+			break;
+
+		case CAgnEntry::EAgnDataAdded:
+			id = StoreAlarmActionL(*(aEntry.AlarmAction()));
+			aEntry.SetAlarmActionStreamId(id);
+			break;
+
+		case CAgnEntry::EAgnDataUpdated:
+			UpdateAlarmActionL(*(aEntry.AlarmAction()), aEntry.AlarmActionStreamId());
+			break;
+
+		default://no changes
+			break;
+		}
+	}
+
+
+TAgnEntryId CAgnEntryModel::AddEntryL(CAgnEntry& aEntry)
+	{
+	TAgnEntryId id;
+
+	id = DoAddEntryL(aEntry);
+
+	NotifyingL(MCalChangeCallBack2::EChangeAdd, aEntry, NULL);
+
+	if (iUpdateAlarm && aEntry.HasAlarm())
+		{
+		iAlarm->FindAndQueueNextAlarmL(EFalse);
+		}
+		
+	return (id);
+	}
+
+
+// Update all the indexes which are in RAM after an entry operation (add, update, delete)
+void CAgnEntryModel::UpdateIndexL(CAgnEntry& aEntry, CAgnEntry* aOldEntry, TUpdateIndex aUpdateIndex)
+	{
+	// set guid hash before adding / updating an entry in the GUID hash index
+	if ( aEntry.GsDataType() == CGsData::EParent && ! aEntry.GuidHash() )
+		{
+		aEntry.SetGuidHash( GenerateHash8L(aEntry.Guid()) );
+		if ( aOldEntry )
+			{
+			aOldEntry->SetGuidHash( aEntry.GuidHash() );					
+			}				
+		}	
+	
+ 	switch( aUpdateIndex )
+ 		{
+ 		case EAdd:
+			{
+			AppendRollbackArrayL(aEntry, ETrue);
+
+			AddEntryToIndexesL(aEntry);
+			}
+ 			break;
+
+ 		case EDelete:
+ 			{
+			AppendRollbackArrayL(aEntry, EFalse);
+
+			iSimpleEntryTable->DeleteEntry(aEntry.EntryId()); 				
+
+ 			iCategoryIndex->DeleteEntryL(aEntry.EntryId());
+ 			iAttachmentIndex->DeleteEntryL(aEntry);
+ 			} 			
+ 			break;
+ 
+ 		case EUpdate:
+			{
+			__ASSERT_ALWAYS(aOldEntry, Panic(EAgmErrUpdateInvalid));
+			AppendRollbackArrayL(*aOldEntry, EFalse);
+			iSimpleEntryTable->DeleteEntry(aOldEntry->EntryId());
+			
+			AppendRollbackArrayL(aEntry, ETrue);
+			
+			AddEntryToIndexesL(aEntry);
+			}
+ 			break;
+ 			
+ 		case EBuildIndex:
+ 			{
+			AppendRollbackArrayL(aEntry, ETrue);
+			
+			if(iTzRuleIndex)
+				{
+				iTzRuleIndex->FetchTzRuleL(aEntry);
+				}
+			AddEntryToIndexesL(aEntry);
+			}
+ 			break;
+ 			
+ 		default:
+ 			Panic(EAgmErrInvalidIndexUpdate);
+ 			break;
+ 		}
+ 		// Increment the operations counter which triggers compacting upon reaching a threshold
+ 	++iOperationsCounter;
+	}
+
+// Add an entry to all indexes in RAM
+void CAgnEntryModel::AddEntryToIndexesL(CAgnEntry& aEntry)
+	{
+	aEntry.SetCollectionId(iAgnServerFile->CollectionId());
+	iSimpleEntryTable->AddEntryL(aEntry);
+
+	iAgnServerFile->CategoryList().AddEntryL(aEntry);
+	iCategoryIndex->UpdateEntryL(aEntry.EntryId(), aEntry);
+	iAttachmentIndex->AddEntryL(aEntry);
+	}
+
+/**
+Returns true if the entry is found to have any children which are repeating.
+@internalComponent
+@return TBool.
+@param aEntry The entry.
+*/
+TBool CAgnEntryModel::EntryHasRepeatingChildrenL(const CAgnEntry& aParentEntry)
+	{
+	const RArray<TGsChildRefData>& KChildIds = aParentEntry.ChildIds();
+
+	const TInt KIdCount = KChildIds.Count();
+	
+	TBool repeatingChildExists = EFalse;
+	
+	for ( TInt pos = 0; ! repeatingChildExists && pos < KIdCount; ++pos )
+		{
+		CAgnEntry* childOfParentEntry = FetchEntryL(KChildIds[pos].ChildId());
+		if (childOfParentEntry)
+			{
+			repeatingChildExists = (childOfParentEntry && childOfParentEntry->RptDef());
+
+			delete childOfParentEntry;
+			}
+		}
+
+	return (repeatingChildExists);
+	}
+
+/**
+Deletes any non-repeating children within a specified range. This is called when adding a repeating child entry to 
+delete existing non-repeating child entries - those that appear either before or after the repeating child entry's recurrence ID,
+depending on the recurrence range.
+@internalComponent
+@param aParentEntry The parent entry
+@param aRecId Indicates the recurrence ID of the repeating child entry
+@param aRange Indicates "this and prior" or "this and future" to delete child entries on one side of the recurrence ID.
+*/
+void CAgnEntryModel::DeleteNonRepeatingChildrenOutsideRangeL(const CAgnEntry& aParentEntry, const TAgnCalendarTime& aRecId, CalCommon::TRecurrenceRange aRange)
+	{
+	const RArray<TGsChildRefData>& KChildIds = aParentEntry.ChildIds();
+
+	const TInt KCount(KChildIds.Count());
+	
+	for ( TInt i = 0; i < KCount; ++i )
+		{
+		// Check if any child falls outside parent's rpt rule
+		if ( (aRecId > KChildIds[i].RecurrenceId() && aRange == CalCommon::EThisAndPrior) ||
+		     (aRecId < KChildIds[i].RecurrenceId() && aRange == CalCommon::EThisAndFuture) )
+			{
+			// Remove child if it is non-repeating
+			TCalLocalUid chIdRemove(KChildIds[i].ChildId());
+			CAgnEntry* chIdEntry = FetchEntryL(chIdRemove);
+			if (chIdEntry)
+				{
+				CleanupStack::PushL(chIdEntry);
+				
+				__ASSERT_ALWAYS( ! chIdEntry->RptDef(), Panic(EAgmErrAddingSecondRepeatingChildEntry));
+				DeleteEntryL(*chIdEntry, ETrue, iChangeFilter);
+					
+				CleanupStack::PopAndDestroy(chIdEntry);
+				}
+			}
+		}
+	}
+
+/**
+Adds a repeating child to a repeating parent, and performs the necessary adjustments to the parent's repeat rule.
+The explanation of how the parent's rpt rule is trimmed is given in the code comments.
+@internalComponent
+@param aParentEntry The parent entry
+@param aRepeatingChild The child to be added
+@leave KErrArgument If either aParentEntry or aRepeatingChild are non-repeating
+@leave KErrArgument If aRepeatingChild's RecurrenceId is aParentEntry's first or last instance
+@leave KErrNotSupported If aRepeatingChild's Range is ECurrentInstance
+@leave KErrArgument If aRepeatingChild's Range is an unexpected value
+*/
+TAgnEntryId CAgnEntryModel::AddRepeatingChildEntryUpdateParentRuleL(CAgnEntry& aParentEntry, CAgnEntry& aRepeatingChild)
+	{
+	// Ensure both parent and child are repeating
+	__ASSERT_ALWAYS((aRepeatingChild.RptDef() && aParentEntry.RptDef()), User::Leave(KErrArgument));
+	TAgnCalendarTime childRecId = aRepeatingChild.RecurrenceId();
+	
+	TAgnEntryId retId;
+	
+	CAgnRptDef* parentRptDef = aParentEntry.RptDef();
+	
+	TTime recIdLocal(childRecId.LocalL());
+    TDateTime recIdLocalDateTime(recIdLocal.DateTime());
+    	
+	CalCommon::TRecurrenceRange range = aRepeatingChild.RecurrenceRange();
+
+	if(range == CalCommon::EThisOnly)
+		{
+		// if the range specified is EThisOnly, attempt to recalculate the recurrence range 
+		// so that the maximum number of "overlapping" entries (schedules running concurrently in the 
+		// parent and child) is removed	
+		TTime dtStartLocal = aParentEntry.StartTime().LocalL();
+		TDateTime dtStartLocalDateTime =(dtStartLocal.DateTime()); 
+	 	if (dtStartLocalDateTime.Year() == recIdLocalDateTime.Year() && 
+           dtStartLocalDateTime.Month() == recIdLocalDateTime.Month() && 
+           dtStartLocalDateTime.Day() == recIdLocalDateTime.Day())
+			{
+			// Check whether the recurrence ID of the child is of the same day as the 
+            // first instance of the parent.  If so, assume range is ThisAndPrior
+            // to avoid the parent repeating rule being completely trimmed.
+            //
+            // Note: It is possible that this is a previously trimmed parent, as a result of 
+            //       the trimming, completely embedded by the child.  Therefore, no rejection of 
+            //       such child/parent range is performed to ensure an Import->Export->Import will 
+            //       not be failed.  In the rare occurrence where the child entry completely embeds
+            //       the parent entry and has RecID on the same day as start/end of parent entry, it will 
+            //       be allowed through.
+			range = CalCommon::EThisAndPrior;
+			}
+		else 
+			{
+			TTime dtUntilLocal = parentRptDef->LastInstanceL().LocalL();
+			
+			TDateTime dtUntilLocalDateTime =(dtUntilLocal.DateTime()); 
+			if (dtUntilLocalDateTime.Year() == recIdLocalDateTime.Year() && 
+                dtUntilLocalDateTime.Month() == recIdLocalDateTime.Month() && 
+                dtUntilLocalDateTime.Day() == recIdLocalDateTime.Day())
+	  			{
+ 	 			// Check whether the recurrence ID of the child is of the same day as the 
+                // last instance of the parent. If so, assume range is ThisAndFuture
+                // instances to avoid the parent repeating rule being completely trimmed.                
+                //
+                // Note: It is possible that this is a previously trimmed parent, as a result of 
+                //       the trimming, completely embedded by the child.  Therefore, no rejection of 
+                //       such child/parent range is performed to ensure an Import->Export->Import will 
+                //       not be failed.  In the rare occurrence where the child entry completely 
+                //       embeds the parent entry and has RecID on the same day as start/end of parent 
+                //       entry, it will be allowed through.
+				range = CalCommon::EThisAndFuture;
+				}
+			else
+				{
+				// Reject the child entry if it completely alters the parent entry.  This should be done by 
+    			// replacing the parent schedule instead.
+    			//
+    			// An exception is when the parent entry's start/end date is the same as the RecID.  That
+    			// could be the result of the parent being previously trimmed.
+				__ASSERT_ALWAYS(parentRptDef->LastInstanceL() > aRepeatingChild.RptDef()->LastInstanceL() ||
+				              aRepeatingChild.RptDef()->FirstInstanceL() > aParentEntry.StartTime(),
+                              User::Leave(KErrArgument));
+   				// if the RecId is neither at the start/end of the parent's rpt range, 
+    			// then base on the distance of the beginning & end of the child recurreance range 
+    			// from the RecId, determine if the range should be assumed as ThisAndFuture 
+    			// or a ThisAndPrior scenario.
+    			// 
+    			// As this usage is most likely ThisAndFuture, so even if the distance from 
+    			// beginning & end of the child repeat range is the same, assume CurrentAndFuture.                                
+				TTimeIntervalDays afterRecurrence = (aRepeatingChild.RptDef()->LastInstanceL().UtcL()).DaysFrom(childRecId.UtcL());
+				TTimeIntervalDays beforeRecurrence = childRecId.UtcL().DaysFrom(aRepeatingChild.RptDef()->FirstInstanceL().UtcL());
+				range = (afterRecurrence >= beforeRecurrence) ?
+							CalCommon::EThisAndFuture : CalCommon::EThisAndPrior;
+				}
+			}
+		aRepeatingChild.SetRecurrenceRangeL(range);
+		}
+
+	// Trim parent's repeat rule to fall in line with the new child entry,
+	// and deal with any exceptions and sporadic dates that fall within the
+	// affected period.
+
+	switch (range)
+		{
+		case CalCommon::EThisAndFuture:
+			{
+			// Reject if RecurrenceId falls on 1st instance of parent's (original) rpt rule
+			// If the User's intention is to modify the entire parent schedule, they should replace the
+			// existing parent with a new parent entry (by submitting an entry with no RecId specified).
+			TTime firstInstanceParentUtc(Time::NullTTime());
+			parentRptDef->NudgeNextInstanceUtcL(aParentEntry.StartTime().UtcL(), firstInstanceParentUtc);
+
+			// Ensure child's RecurrenceId is not the parent's first instance.
+			__ASSERT_ALWAYS(childRecId.UtcL() > firstInstanceParentUtc, User::Leave(KErrArgument));
+
+			// Store child entry
+			retId = AddChildEntryL(aRepeatingChild, aParentEntry);
+			childRecId = aRepeatingChild.RecurrenceId(); // recurrence ID may have been updated if it was an imported rec ID with no time
+			
+			// Set parent's rpt-rule end date to child's RecId (already verified RecId points to a genuine instance on the parent).
+			if (parentRptDef->RRule())
+				{
+				parentRptDef->SetUntilTime(childRecId);
+				}
+			}
+			break;
+
+		case CalCommon::EThisAndPrior:
+			{						
+			// Reject if RecurrenceId falls on last instance of parent's (original) rpt rule
+			// If the User's intention is to modify the entire parent schedule, they should replace the
+			// existing parent with a new parent entry (by submitting an entry with no RecId specified).
+			TTime lastInstanceParentUtc(Time::NullTTime());
+			parentRptDef->NudgePreviousInstanceUtcL(parentRptDef->LastInstanceL().UtcL(), lastInstanceParentUtc);
+			
+			// Ensure child's RecurrenceId is not the parent's last instance.
+			__ASSERT_ALWAYS(childRecId.UtcL() < lastInstanceParentUtc, User::Leave(KErrArgument));
+			
+			// Store child entry 
+			retId = AddChildEntryL(aRepeatingChild, aParentEntry);
+			childRecId = aRepeatingChild.RecurrenceId(); // recurrence ID may have been updated if it was an imported rec ID with no time
+
+			// Move parent's start time to child's RecId (already verified RecId points to a genuine instance on the parent).
+			aParentEntry.MoveStartTimeLocalL(childRecId.LocalL());
+			}
+			break;
+
+		default:
+			{
+			User::Leave(KErrArgument);	
+			}
+			break;
+		}
+	
+	// add an exception to the parent on the child's recurrence ID
+	aParentEntry.RptDef()->AddExceptionL(childRecId);
+	
+	// Remove any exceptions on the parent that fall in the discarded range
+	aParentEntry.RptDef()->PruneExceptionsL();
+
+	// Remove any sporadic dates on the parent that fall in the discarded range
+	aParentEntry.PruneRDatesL(childRecId, range);
+		
+	// Commit parent to store
+	aParentEntry.SetLastModifiedDate();
+	UpdateEntryL(aParentEntry, iChangeFilter, EFalse);
+	
+	// Delete any non-repeating children that fall in the discarded range
+	DeleteNonRepeatingChildrenOutsideRangeL(aParentEntry, childRecId, range);
+	
+	return (retId);
+	}
+	
+
+/**
+Adds a non-repeating child to a repeating parent, and then adds an exception to the parent's exception
+list for the occurrence given by the child's RecId.
+@internalComponent
+@param aParentEntry The parent entry
+@param aNonRepeatingChild The child to be added
+@leave KErrArgument If parent entry does not have a repeat definition
+*/
+TAgnEntryId CAgnEntryModel::AddNonRepeatingChildEntryUpdateParentExceptionsL(CAgnEntry& aParentEntry, CAgnEntry& aNonRepeatingChild)
+	{
+	const TInt KNumchildrenBefore = aParentEntry.ChildIds().Count();
+	// Add\Update children entry
+	TAgnEntryId retId = AddChildEntryL(aNonRepeatingChild, aParentEntry);
+	const TInt KNumchildrenAfter = aParentEntry.ChildIds().Count();
+	
+	TBool addexception = !aParentEntry.RptDef()->FindException(aNonRepeatingChild.RecurrenceId());
+	if ( KNumchildrenAfter > KNumchildrenBefore || addexception )
+		{
+		//only add exception and update parent if a child has been added otherwise a existing child has been updated.
+		aParentEntry.RptDef()->AddExceptionL(aNonRepeatingChild.RecurrenceId());
+		aParentEntry.SetLastModifiedDate();
+		UpdateEntryL(aParentEntry, iChangeFilter, EFalse);
+		}
+	
+	return (retId);
+	}
+
+
+TAgnEntryId CAgnEntryModel::AddChildEntryL(CAgnEntry& aChild, CAgnEntry& aParent)
+	{
+  	TAgnCalendarTime entryRecId = aChild.RecurrenceId();
+ 	CAgnRptDef* parentRptDef = aParent.RptDef();
+ 	__ASSERT_ALWAYS(parentRptDef, Panic(EAgmErrAddingChildEntryToNonRepeatingParent));
+		
+	// Microsoft export recurrence id with date but no time. Test if current 
+	// recurrenceId is an instance of parent entry so that when the time is 
+	// not specified in recurrenceId we can find the right occurence from the parent.
+	if ( ! parentRptDef->IsAnInstanceL(entryRecId.LocalL()) )
+		{
+		// If a midnight recurrence Id is not floating, and is not an instance of the parent entry, then
+		// it means it is imported without the time and timezone information. Therefore, it has to be
+		// converted to a correct UTC time here before nudging the instance.
+		TDateTime recIdDateTime = entryRecId.UtcL().DateTime();
+		if (recIdDateTime.Hour() == 0 && recIdDateTime.Minute() == 0 && 
+			aChild.TimeMode() != MAgnCalendarTimeMode::EFloating)
+			{
+			entryRecId.SetUtcL(parentRptDef->ConvertFromRepeatLocalToUtcL(entryRecId.UtcL()));
+			}
+
+		TTime actualInstanceTimeUtc;
+		parentRptDef->NudgeNextInstanceUtcL(entryRecId.UtcL(), actualInstanceTimeUtc);
+		// If recurrenceId is not an instance of the parent then nudge to next occurence if an instance can be found for the same date. 
+		if ( actualInstanceTimeUtc != Time::NullTTime() )
+			{
+			const TTime KActualInstanceTimeRptLocal = parentRptDef->ConvertFromUtcToRepeatLocalL(actualInstanceTimeUtc);
+			const TTime KRecurrenceIdRptLocal = parentRptDef->ConvertFromUtcToRepeatLocalL(entryRecId.UtcL());
+			
+			const TDateTime KActualInstanceDateTimeRptLocal = KActualInstanceTimeRptLocal.DateTime();
+			const TDateTime KRecurrenceIdDateTimeRptLocal = KRecurrenceIdRptLocal.DateTime();
+			
+			// Only change recurrenceId if nudged date is the same as the recurrenceId date
+			if ( KRecurrenceIdDateTimeRptLocal.Year() == KActualInstanceDateTimeRptLocal.Year() &&
+				 KRecurrenceIdDateTimeRptLocal.Month() == KActualInstanceDateTimeRptLocal.Month() &&
+				 KRecurrenceIdDateTimeRptLocal.Day() == KActualInstanceDateTimeRptLocal.Day() )
+				{
+				if (aParent.TimeMode() == MAgnCalendarTimeMode::EFloating)
+					{
+					entryRecId.SetFloatingL(KActualInstanceTimeRptLocal);
+					}
+				else
+					{
+					entryRecId.SetUtcL(actualInstanceTimeUtc);
+					}
+				aChild.UpdateRecurrenceIdL(entryRecId);
+				}
+			else
+				{
+				User::Leave(KErrNotFound); // If leave occurs here then there is no event found for given day by recurrenceId
+				}
+			}
+		else
+			{
+			User::Leave(KErrNotFound); // leave occurs here because the next instance cannot be found
+			}
+		}
+	
+	aChild.SetParentId(aParent.LocalUid());
+// First check if the same child entry already exists in the store (one with the same RecId).
+	// If so we delete it and replace it with the new child.
+	// This allows the client to 'update' a child entry without having to destroy the entire
+	// associated set.
+
+	CAgnEntry* existingChildEntry = FetchEntryL(aParent.Guid(), entryRecId);
+
+	TAgnEntryId retId;
+	TBool addChild(ETrue);
+
+	if ( existingChildEntry )
+		{			
+		CleanupStack::PushL(existingChildEntry);
+		if ( existingChildEntry->Type() == aChild.Type() )
+			{// Update existing child entry
+			aChild.SetLocalUid(existingChildEntry->LocalUid());
+			aChild.SetEntryId(existingChildEntry->EntryId());
+			UpdateEntryL(aChild, iChangeFilter, EFalse);
+			retId = aChild.EntryId();
+			addChild = EFalse;
+			}
+		else
+			{
+			// Delete existing child entry
+			aChild.SetLocalUid(existingChildEntry->LocalUid());
+			DeleteEntryL(*existingChildEntry, EFalse, iChangeFilter);
+			}
+		CleanupStack::PopAndDestroy(existingChildEntry);
+		}
+
+	if ( addChild )
+		{
+		if ( aChild.RptDef() )
+			{
+			// Check there are no other repeating childs on this parent.
+			// (Limit to only ONE rpt rule change to a parent entry)
+			__ASSERT_ALWAYS(!EntryHasRepeatingChildrenL(aParent), User::Leave(KErrNotSupported));
+			}
+
+		// add the new child entry
+		retId = AddEntryL(aChild);
+			
+		// Add the occurrence given by the RecId to the parent's Exception List.
+		TGsChildRefData child(aChild.LocalUid(), entryRecId);
+		aParent.AddChildIdL(child);
+		}
+
+	return (retId);
+	}
+
+
+CAgnEntry* CAgnEntryModel::FetchEntryL(const TDesC8& aGuid) const	
+ 	{
+ 	#ifdef __CAL_VERBOSE_LOGGING__
+ 		{
+ 		TBuf<KMaxGuidBufLength> guidBuf;
+		guidBuf.Copy(aGuid);
+		AgmDebug::DebugLog("FetchEntryL: Fetching entry with GUID='%S'",&guidBuf);
+		}
+	#endif
+	
+ 	RArray<TAgnEntryId> candidateMatches;
+ 	CleanupClosePushL(candidateMatches);
+ 	
+	iSimpleEntryTable->FindByHashL(GenerateHash8L(aGuid), candidateMatches);
+ 	
+	CAgnEntry* entry = NULL;
+ 	const TInt KCount = candidateMatches.Count();
+ 	
+ 	for ( TInt i = 0; i < KCount; ++i )
+ 		{
+		CAgnEntry* candidateEntry = FetchEntryL(candidateMatches[i]);
+		__ASSERT_ALWAYS(candidateEntry, User::Leave(KErrNotFound)); // entry table contains an entry not in the store
+		
+		CleanupStack::PushL(candidateEntry);
+		
+		if ( candidateEntry->Guid() == aGuid )
+			{
+			entry = candidateEntry;
+			CleanupStack::Pop(candidateEntry);
+			break;
+			}
+
+		CleanupStack::PopAndDestroy(candidateEntry);
+ 		}
+ 		
+ 	CleanupStack::PopAndDestroy(); //candidateMatches.Close();
+ 
+	return (entry);
+ 	}
+
+
+CAgnEntry* CAgnEntryModel::FindChildFromParentL(const CAgnEntry& aParent, const TAgnCalendarTime& aRecurrenceId)	const
+	{
+	CAgnEntry* returnEntry = NULL;
+	
+	// Get Child ids
+	const RArray<TGsChildRefData>& KChildIds = aParent.ChildIds();
+
+	// Check if we have a match amongst the children of this parent
+	const TInt KCount = KChildIds.Count();
+
+	for ( TInt pos = 0; pos < KCount; ++pos )
+		{
+		const TGsChildRefData& KChildData = KChildIds[pos];
+		
+		if ( KChildData.RecurrenceId() == aRecurrenceId )
+			{
+			returnEntry = FetchEntryL(KChildData.ChildId());
+
+			break;
+			}
+		}
+	
+	return (returnEntry);
+	}
+
+/** Save the contents of iNextLocalUidValue and iNextAttachmentUid to the store
+@internalComponent
+*/
+void CAgnEntryModel::ExternalizeNextUidValuesL() const
+	{
+	ExternalizeNextUidValuesL(StreamStore(), iModelStreamIdSet->NextLocalUidValueStreamId());
+	}
+
+void CAgnEntryModel::ExternalizeNextUidValuesL(CStreamStore& aStreamStore, const TStreamId& aStreamId) const
+	{
+	RStoreWriteStream stream;
+
+	stream.ReplaceLC(aStreamStore, aStreamId);
+	stream.WriteUint32L(iNextLocalUidValue);
+	stream.WriteUint32L(iNextAttachmentUid);
+
+	stream.CommitL();
+
+	CleanupStack::PopAndDestroy();
+	}
+
+void CAgnEntryModel::InternalizeNextUidValuesL()
+	{
+	RStoreReadStream in;
+	in.OpenLC(StreamStore(), iModelStreamIdSet->NextLocalUidValueStreamId());
+	if (iCalConverter)
+		{
+		iCalConverter->InternalizeNextUidValuesL(in);
+		}
+	else
+		{
+		iNextLocalUidValue = in.ReadUint32L();
+		iNextAttachmentUid = in.ReadUint32L();
+		}
+
+	CleanupStack::PopAndDestroy(&in);
+	}
+	
+/** Sets whether or not to use buffered deletion.
+
+Buffered deletion means that when entries are deleted they are only 
+marked as being deleted in the internal memory buffer and the file 
+is not updated until either every entry in the buffer is marked as being 
+deleted or a commit/flush is called.
+@param aSetting ETrue for buffered deletion, EFalse for non-buffered deletion.
+@capability None
+*/
+void CAgnEntryModel::SetBufferedDeleting(TBool aSetting)
+	{ 
+	iEntryManager->SetBufferedDeleting(aSetting); 
+	}
+
+/**
+Flush out the entry store
+*/
+void CAgnEntryModel::FlushL()
+	{
+	iEntryManager->FlushBuffersL();
+	}
+
+/** Resets any file specific data before opening a new calendar file.
+@internalAll
+*/
+void CAgnEntryModel::Reset()
+	{
+	iFileId = 0;
+	
+	if (iModelStreamIdSet)
+		{
+		iModelStreamIdSet->Reset();
+		}
+	
+	if (iEntryManager)
+		{
+		iEntryManager->Reset();
+		}
+		
+	if (iSimpleEntryTable)
+		{
+		iSimpleEntryTable->Reset();
+		}
+	}
+
+/** Save the entry manager and its data to the store
+@internalAll
+*/
+void CAgnEntryModel::ExternalizeEntryManagerL() const
+	{
+	RStoreWriteStream stream;
+	stream.ReplaceLC(StreamStore(),iModelStreamIdSet->EntryManagerStreamId());
+	stream << *iEntryManager;
+	stream.CommitL();
+	CleanupStack::PopAndDestroy();
+	}
+
+void CAgnEntryModel::InternalizeEntryManagerL()
+	{
+	RStoreReadStream in;
+	in.OpenLC(StreamStore(), iModelStreamIdSet->EntryManagerStreamId());
+	in >> *iEntryManager;
+
+	// Sanity Check here. If the entry stream set is empty, then the store stream ids should
+	// all be zero - reset them here to ensure that if the file has been partially corrupted, we can
+	// recover from this.
+	if ( iModelStreamIdSet->EntryStreamIdSet().Count() == 0 )
+		{
+		iEntryManager->Reset();
+		}
+
+	CleanupStack::PopAndDestroy(&in);
+	}
+
+void CAgnEntryModel::ResetIndexes()
+	{
+	// Reset indexes, returns EFalse if file is empty
+	iSimpleEntryTable->Reset();
+	iCategoryIndex->Reset();
+	iAttachmentIndex->Reset();
+	iModelStreamIdSet->EntryStreamIdSet().ResetIteratorToStart();
+	if (iModelStreamIdSet->EntryStreamIdSet().Count() == 0)
+		{
+		iNumStreamsProcessed = 0;
+		}
+	}
+
+// This method is used for generating a filename for the index file from the
+// calendar filename. 
+TBool CAgnEntryModel::GenerateIndexFileName(TFileName& aFileName) 
+	{
+	aFileName = FileName();
+	if ((aFileName.Length() + KIdxFilePostFixLength) > KMaxFileName)
+		{
+		iIndexFileIsDirty = ETrue;
+		iIndexFileIsPresent = EFalse;
+		return EFalse;
+		}
+	aFileName.Append(KIdxFilePostFix);
+	return ETrue;
+	}
+
+
+// This method marks the index file as dirty (i.e. out of sync with the indices 
+// in RAM) by deleting it. A flag is kept internally to allow us to know that the
+// file needs to be rebuilt and to no try to delete the file more than once.
+void CAgnEntryModel::MarkIndexFileAsDirtyL()
+	{
+	if (iIndexFileIsDirty)
+		{
+		return; // the file is already marked as dirty
+		}
+		
+	TFileName idxfilename;
+	if (!GenerateIndexFileName(idxfilename))
+		{
+		User::Leave(KErrBadName);
+		}
+	
+	TInt connectErr = iFs.Connect();
+	User::LeaveIfError(connectErr);
+	
+	iFs.Delete(idxfilename); // ignore return as there is nothing we can do with it
+	
+	iIndexFileIsDirty = ETrue;
+	}
+	
+// This method allows clients of the model to determine if the index file is
+// dirty and therefore in need of being rewritten with the current data.
+TBool CAgnEntryModel::IsIndexFileDirty() const
+	{
+	return iIndexFileIsDirty;
+	}
+
+TCalCollectionId CAgnEntryModel::CollectionId() const
+	{
+	return iAgnServerFile->CollectionId();
+	}
+
+// This method reads the indices from the index file.
+// It returns:
+//		ETrue - indices successfully read from file
+//      EFalse - indices not read from file (file may be missing, or there
+//				 may have been errors trying to read the file.
+// It Leaves when any of the index InternalizeL functions Leave.
+// Overall description:
+//		1. Attempt to open the file
+//		2. If file is present InternalizeL all indices and return true
+//		4. If no file, or errors in opening or streaming return false
+TBool CAgnEntryModel::LoadIndexFileL()
+	{
+	TFileName idxfilename;
+	if (!GenerateIndexFileName(idxfilename))
+		{
+		User::Leave(KErrBadName);
+		}
+	
+	TInt connectErr = iFs.Connect();
+	User::LeaveIfError(connectErr);
+	
+	RFile idxFile;
+	TInt errReadIdx = idxFile.Open(iFs, idxfilename, EFileRead);
+	CleanupClosePushL(idxFile);
+	
+	if (errReadIdx == KErrNone)    // we have a file
+		{
+		RFileReadStream idxStream;
+		idxStream.Attach(idxFile);
+		CleanupClosePushL(idxStream);
+		
+		TInt internalizeErr = KErrNone;
+		
+		TRAP(internalizeErr, iSimpleEntryTable->InternalizeL(idxStream, iTzRuleIndex));
+		if (internalizeErr != KErrNone)
+			{
+			// clear any entries that may have been added to the table
+			// before leaving
+			iSimpleEntryTable->Reset();
+			User::Leave(internalizeErr);
+			}
+		TRAP(internalizeErr, iCategoryIndex->InternalizeL(idxStream));
+		if (internalizeErr != KErrNone)
+			{
+			// clear any entries in this index or the entry table
+			// before leaving
+			iSimpleEntryTable->Reset();
+			iCategoryIndex->Reset();
+			User::Leave(internalizeErr);
+			}
+		TRAP(internalizeErr, iAttachmentIndex->InternalizeL(idxStream));
+		if (internalizeErr !=KErrNone)
+			{
+			// clear any entries in this index, the category index
+			// and the entry table before leaving
+			iAttachmentIndex->Reset();
+			iSimpleEntryTable->Reset();
+			iCategoryIndex->Reset();
+			User::Leave(internalizeErr);
+			}
+
+		CleanupStack::PopAndDestroy(2); //idxStream, idxFile
+		iIndexFileIsDirty = EFalse;
+		return ETrue;  // we have successfully read the index file
+		}
+	else if (errReadIdx == KErrNotFound)
+		{
+		CleanupStack::PopAndDestroy(); // idxFile
+		iIndexFileIsDirty = ETrue;  // the index file needs to be created/updated
+		iIndexFileIsPresent = EFalse; 	// so we won't try to find the file every time
+										// DoBuildIndexL() is called
+		return EFalse; // no file to read
+		}
+		
+	// if we get here, then there was an error reading the file for some
+	// reason other than it not being present. We'll mark it as DIRTY (i.e. delete it).
+	// MarkIndexFileAsDirtyL will try to delete the file if errors occur.
+	CleanupStack::PopAndDestroy(&idxFile);
+	MarkIndexFileAsDirtyL();
+	iIndexFileIsPresent = EFalse;	
+	return EFalse;
+	}
+
+
+// This method attempts to save all indices to the index file.
+// If any errors are encountered it will Leave.
+// Clients of this method should TRAP the Leave and possibly
+// mark the file as dirty or try to delete it.
+void CAgnEntryModel::SaveIndexFileL()
+	{
+	TFileName idxfilename;
+	if (!GenerateIndexFileName(idxfilename))
+		{
+		User::Leave(KErrBadName);
+		}
+	TInt connectErr = iFs.Connect();
+	User::LeaveIfError(connectErr);
+
+	RFile idxFile;
+	TInt errWriteIdx = idxFile.Replace(iFs, idxfilename, EFileWrite);
+	User::LeaveIfError(errWriteIdx);
+	CleanupClosePushL(idxFile);
+	
+	
+	RFileWriteStream idxStream;
+	idxStream.Attach(idxFile);
+	CleanupClosePushL(idxStream);
+
+	iSimpleEntryTable->ExternalizeL(idxStream);
+	iCategoryIndex->ExternalizeL(idxStream);
+	iAttachmentIndex->ExternalizeL(idxStream);
+
+	CleanupStack::PopAndDestroy(2); //idxStream, idxFile
+	
+	iIndexFileIsDirty = EFalse;
+	}
+	
+TBool CAgnEntryModel::DoLoadIndexFile()
+	{
+	// Check to see if we have a valid index file that we can read
+	TBool readPassed = EFalse;
+	TRAPD(idxErr, readPassed = LoadIndexFileL());
+	if ((readPassed) && (idxErr == KErrNone))
+		{
+		// We successfully read the prebuilt index.
+		return ETrue;   
+		}
+	else
+		{
+		// something bad happened to the index file
+		// we need to delete it because it couldn't be read
+		// To ensure that it is deleted we need to mark the index 
+		// file as "not dirty".
+		iIndexFileIsDirty = EFalse;
+		iIndexFileIsPresent = EFalse;
+		// trap the leave to keep things running, but there is nothing
+		// we can do if the file can't be deleted.
+		TRAP_IGNORE(MarkIndexFileAsDirtyL());
+		}
+	return EFalse;
+	}
+
+
+TInt CAgnEntryModel::DoIndexBuildStepL()
+	{
+	// Check to see if we have a valid index file that we can read
+	// before trying to build all the indices.
+	
+	if (iIndexFileIsPresent)
+		{
+		if (DoLoadIndexFile())
+			{
+			// We successfully read the prebuilt index.
+			// There is no need to go any further.
+			// The 0 below indicates that there is nothing left to do.
+			return KAgnPercentageComplete;   
+			}
+		}
+	// otherwise, there is no file or the file is dirty (out of sync), 
+	// continue to build indexes
+	
+	TInt retVal = 0;
+
+	FOREVER
+		{
+		TStreamId streamId(0);
+
+		if ( ! iModelStreamIdSet->EntryStreamIdSet().At(streamId) ) // returns value in streamId
+			{
+			retVal = KAgnPercentageComplete; // indicate completion if not more streams
+			break;
+			}
+
+		RStoreReadStream in;
+		in.OpenLC(StreamStore(), streamId);
+		
+		in.ReadInt8L();		// discard buffer type information
+		
+		if ( iCalConverter )
+			{
+			// Read entry from a calendar file whose
+			// version is not the current one.
+			
+			iCalConverter->InternalizeEntriesL(in);
+			}
+		else
+			{	
+			// Read entry from a calendar file - current version
+			const TUint8 KCount = in.ReadUint8L();
+			
+			CAgnEntry* entry = NULL;	
+			for ( TInt ii = 0; ii < KCount; ++ii )
+				{
+				entry =	CAgnEntry::NewL(in);
+				CleanupStack::PushL(entry);
+				
+				UpdateIndexL(*entry, NULL, EBuildIndex);
+				CleanupStack::PopAndDestroy(entry);
+				}
+			}
+
+		CleanupStack::PopAndDestroy();		// in
+
+		iSimpleEntryTable->Commit();
+
+		if ( ! iModelStreamIdSet->EntryStreamIdSet().Next() )
+		 	{
+		 	retVal = KAgnPercentageComplete; // no more streams to process
+			break;
+			}
+
+		// check iNumStreamsProcessed is valid - this number is used to calculate percentage complete
+		++iNumStreamsProcessed;
+		__ASSERT_ALWAYS(iNumStreamsProcessed <= iModelStreamIdSet->EntryStreamIdSet().Count(), User::Leave(KErrCorrupt));
+
+		// After every second stream is processed, calculate the percentage complete and return
+		if ( iNumStreamsProcessed % 2 == 0 )
+			{
+			// coverity[check_return] coverity[unchecked_value]
+			TInt percentage = (iNumStreamsProcessed * KAgnPercentageComplete) / iModelStreamIdSet->EntryStreamIdSet().Count();
+			retVal = (percentage < 1 ? 1 : percentage); // percentage complete must be at least 1 (returning 0 indicates index building complete)
+			break;
+			}
+		}
+
+	if (retVal == KAgnPercentageComplete)
+		{
+		// A return value of 0 indicates that the indexes have been
+		// completely built. We will save them to file now so that
+		// no future errors will cause this information to need to 
+		// be built again.
+		TRAPD (saveErr, SaveIndexFileL());
+		if (saveErr != KErrNone)
+			{
+			// We couldn't save the index file, so we'll mark it as dirty
+			TRAPD(ignore,MarkIndexFileAsDirtyL());
+			User::LeaveIfError(ignore);			
+			}
+		}
+	
+	return (retVal);
+	}
+
+
+void CAgnEntryModel::BuildIndexCompleteL()
+	{
+	if ( iCalConverter )
+		{
+		RestoreCategoriesL();
+		iCalConverter->CompleteConversionL();
+		delete iCalConverter;
+		iCalConverter = NULL;
+		}
+		
+	CreateAlarmForServerL();
+	iAlarm->DeleteAllAlarms();
+	iAlarm->FindAndQueueNextAlarmL(EFalse);
+	}
+
+ 
+TInt CAgnEntryModel::MatchExactText(const TDesC& aTextField, const TDesC& aSearchText)
+	{
+	return aTextField.Match(aSearchText);
+	}
+
+TInt CAgnEntryModel::MatchFoldedText(const TDesC& aTextField, const TDesC& aSearchText)
+	{
+	return aTextField.MatchC(aSearchText);
+	}
+
+TBool CAgnEntryModel::MatchSearchTextL(MatchTextFnPtr aMatchTextFunction, CAgnEntry& aEntry, const TDesC& aSearchText, const TAgnFilter& aFilter)
+	{ 
+	// always search summary
+	TInt pos = aMatchTextFunction(aEntry.Summary(), aSearchText);
+
+	if ( pos == KErrNotFound && aFilter.IsEntryLocationSearched() )
+		{
+		pos = aMatchTextFunction(aEntry.Location(), aSearchText);
+		}
+	if ( pos == KErrNotFound && aFilter.IsEntryDescriptionSearched() )
+		{
+		pos = aMatchTextFunction(aEntry.Description(), aSearchText);
+		}
+
+	CAgnAttendee* organizer = aEntry.Organizer();
+	const TInt KNumAttendees = aEntry.AttendeeCount();
+
+	if ( organizer && pos == KErrNotFound )
+		{
+		if ( aFilter.IsOrganizerAddressSearched() )
+			{
+			pos = aMatchTextFunction(organizer->Address(), aSearchText);
+			}
+		if ( pos == KErrNotFound && aFilter.IsOrganizerSentByAddressSearched() )
+			{
+			pos = aMatchTextFunction(organizer->SentBy(), aSearchText);
+			}
+		if ( pos == KErrNotFound && aFilter.IsOrganizerCommonNameSearched() )
+			{
+			pos = aMatchTextFunction(organizer->CommonName(), aSearchText);
+			}
+		}
+		
+	for ( TInt i = 0; pos == KErrNotFound && i < KNumAttendees; ++i)
+		{
+		CAgnAttendee& attendee = aEntry.FetchAttendee(i);
+
+		if ( aFilter.IsAttendeeAddressSearched() )
+			{
+			pos = aMatchTextFunction(attendee.Address(), aSearchText);
+			}
+		if ( pos == KErrNotFound && aFilter.IsAttendeeSentByAddressSearched() )
+			{
+			pos = aMatchTextFunction(attendee.SentBy(), aSearchText);
+			}
+		if ( pos == KErrNotFound && aFilter.IsAttendeeCommonNameSearched() )
+			{
+			pos = aMatchTextFunction(attendee.CommonName(), aSearchText);
+			}
+		}
+
+	return (pos >= 0);
+	}
+
+TBool CAgnEntryModel::MatchFullEntryL(const TAgnEntryId& aEntryId, const TFindInstanceParams& aSearchParams)
+	{
+	TBool match(ETrue);
+	if(aSearchParams.iSearchString.Length() > 0)
+		{
+		CAgnEntry* entry = FetchEntryL(aEntryId);
+		__ASSERT_ALWAYS(entry, User::Leave(KErrNotFound));
+
+		CleanupStack::PushL(entry);
+		if(!MatchSearchTextL(*entry, aSearchParams.iSearchString, aSearchParams.iFilter))
+			{
+			match = EFalse;
+			}
+		CleanupStack::PopAndDestroy(entry);
+		}
+	return match;
+	}
+
+TBool CAgnEntryModel::MatchSearchTextL(CAgnEntry& aEntry, const TDesC& aSearchText, const TAgnFilter& aFilter)
+	{
+	TBool matchText = ETrue;
+	
+	if ( aSearchText.Length() > 0 )
+		{
+		TBuf<256> searchString;
+		_LIT(KWildCard, "*");
+		searchString.Append(KWildCard);
+		searchString.Append(aSearchText);
+		searchString.Append(KWildCard);
+		
+		if ( aEntry.Summary() == KNullDesC && aEntry.SummaryStreamId() != KNullStreamId )
+			{
+			HBufC* summary = RestoreTextL(aEntry.SummaryStreamId());
+			aEntry.SetSummary(summary);			
+			}
+			
+		// load description if required
+		if ( aEntry.Description() == KNullDesC && aEntry.DescriptionStreamId() != KNullStreamId && aFilter.IsEntryDescriptionSearched() )
+			{
+			HBufC* description = RestoreTextL(aEntry.DescriptionStreamId());
+			aEntry.SetDescription(description);			
+			}
+
+		MatchTextFnPtr matchFn = &MatchFoldedText;
+		if ( aFilter.IsExactTextOnlySearch() )
+ 			{
+ 			matchFn = &MatchExactText;
+ 			}
+ 		
+ 		matchText = MatchSearchTextL(matchFn, aEntry, searchString, aFilter);
+		}
+		
+	return (matchText);
+	}
+
+void CAgnEntryModel::FindInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aParameters)
+	{
+	iExtractor->FindInstancesL(aInstances, aParameters);
+	
+#if defined (__CAL_INSTANCE_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
+	LogInstanceSearchL(aParameters, aInstances);
+#endif	
+	}
+
+void CAgnEntryModel::LogInstanceSearchL(const TFindInstanceParams& aParameters, const CArrayFix<TAgnSortInstance>& aInstances) const
+	{
+	TAgnFilter iFilter;
+	TTime dbgStartTime;
+	TTime iEndTime;
+	TBuf<KAgnMaxSearchStringLength> iSearchString;
+	
+	TAgnFilter debugFilter = aParameters.iFilter;
+	
+	TBuf<64> filterBuf;
+	
+	if (debugFilter.AreTimedApptsIncluded() && 
+		debugFilter.AreRemindersIncluded() &&
+		debugFilter.AreEventsIncluded() && 
+		debugFilter.AreAnnivsIncluded() && 
+		debugFilter.AreCompletedTodosIncluded() && 
+		debugFilter.AreIncompletedTodosIncluded() )
+		{
+		filterBuf.Copy(_L("All entries"));
+		}
+	else
+		{
+		if (debugFilter.AreTimedApptsIncluded())
+			{
+			filterBuf.Append(_L("Appts,"));
+			}
+		if (debugFilter.AreRemindersIncluded())
+			{
+			filterBuf.Append(_L("Reminders,"));
+			}
+		if (debugFilter.AreEventsIncluded())
+			{
+			filterBuf.Append(_L("Events,"));
+			}
+		if (debugFilter.AreAnnivsIncluded())
+			{
+			filterBuf.Append(_L("Annivs,"));
+			}
+		if (debugFilter.AreCompletedTodosIncluded() && debugFilter.AreIncompletedTodosIncluded())
+			{
+			filterBuf.Append(_L("TODOs,"));
+			}
+		else if (debugFilter.AreIncompletedTodosIncluded())
+			{
+			filterBuf.Append(_L("Incomplete TODOs,"));
+			}
+		else if (debugFilter.AreCompletedTodosIncluded())
+			{
+			filterBuf.Append(_L("Complete TODOs,"));
+			}
+		}
+	
+	if (aParameters.iSearchString.Length() > 0)
+		{
+		TBuf<KAgnMaxSearchStringLength> searchBuf;
+		searchBuf.Copy(aParameters.iSearchString);
+		AgmDebug::DebugLog("Searching for text %S", &searchBuf);
+		}
+	
+	TBuf<KMinTTimeStrLength> startTimeBuf;
+	TBuf<KMinTTimeStrLength> endTimeBuf;
+	
+	AgmDebug::TTimeStrL(aParameters.iRangeStart.LocalL(),startTimeBuf);
+	AgmDebug::TTimeStrL(aParameters.iRangeEnd.LocalL(),endTimeBuf);
+	
+	const TInt KInstanceCount(aInstances.Count());
+	
+	AgmDebug::DebugLog("FindInstancesL: Range: Start - %S, End - %S, Filter '%S'", &startTimeBuf, &endTimeBuf, &filterBuf);
+	AgmDebug::DebugLog("Found %d instances", KInstanceCount);
+	
+	for ( TInt i = 0; i < KInstanceCount; ++i )
+		{
+		TBuf<KMinTTimeStrLength> instanceTimeBuf;
+		AgmDebug::TTimeStrL(aInstances[i].InstanceIdL().Date().LocalL(), instanceTimeBuf);
+		AgmDebug::DebugLog("Found instance: %S", &instanceTimeBuf);
+		}
+
+	}
+
+void CAgnEntryModel::CreateAlarmForServerL()
+	{
+	if ( ! iAlarm )
+		{
+		iAlarm = CAgnAlarm::NewL(this, NULL);
+		}
+	}
+
+/**
+Get list of ids of alarmed entries in the next 60 days.
+FindInstanceL is used to find instances of alarmed entries.
+*/
+void CAgnEntryModel::NextAlarmForServerL(const TTime& aNow, CArrayFixFlat<TAgnSortInstance>& aAlarmedIds)
+	{
+	if ( ! AgnDateTime::IsValidAgendaTTime(aNow) || ! iSimpleEntryTable || iAgnServerFile->IsFileDisabled())
+		{
+		return;
+		}
+	
+	CArrayFixSeg<TAgnSortInstance>* dayInfoList = new(ELeave) CArrayFixSeg<TAgnSortInstance>(4);
+	CleanupStack::PushL(dayInfoList);
+
+	TFindInstanceParams searchParams;
+	searchParams.iUndatedTodoTimeLocal = aNow;
+    searchParams.iFilter = TAgnFilter(CalCommon::EIncludeAppts|CalCommon::EIncludeReminder|CalCommon::EIncludeEvents|
+										CalCommon::EIncludeAnnivs|CalCommon::EIncludeIncompletedTodos|CalCommon::EIncludeAlarmedOnly, CalCommon::EFoldedTextSearch);
+    searchParams.iSearchString = KNullDesC();
+    searchParams.iRangeStart.SetLocalL(AgnDateTime::ResetToMidnight(aNow) - TTimeIntervalDays(1)); // alarms can be up to 24 hours after start time so check this
+    searchParams.iRangeEnd.SetLocalL(aNow + TTimeIntervalDays(2));
+        
+	iExtractor->FindInstancesL(*dayInfoList, searchParams);
+	TAgnDaySortKey sortKey(AgnDateTime::MaxDate(), searchParams.iUndatedTodoTimeLocal);
+	dayInfoList->Sort(sortKey);
+
+	
+    searchParams.iFilter = TAgnFilter(CalCommon::EIncludeAppts|CalCommon::EIncludeReminder|CalCommon::EIncludeEvents|
+			CalCommon::EIncludeAnnivs|CalCommon::EIncludeIncompletedTodos|CalCommon::EIncludeAlarmedOnly|
+			CalCommon::EIncludeRptsNextInstanceOnly, CalCommon::EFoldedTextSearch);
+	
+	// check the next month if no alarmed instances found
+	const TTime KLimit = aNow + TTimeIntervalDays(60);
+
+	while ( dayInfoList->Count() == 0 && searchParams.iRangeStart.LocalL() < KLimit )
+ 		{
+	    searchParams.iRangeStart.SetLocalL(searchParams.iRangeEnd.LocalL());
+	    searchParams.iRangeEnd.SetLocalL(searchParams.iRangeStart.LocalL() + TTimeIntervalDays(10));
+	    
+	    iExtractor->FindInstancesL(*dayInfoList, searchParams);
+	    TAgnDaySortKey sortKey1(AgnDateTime::MaxDate(), searchParams.iUndatedTodoTimeLocal);
+		dayInfoList->Sort(sortKey1);
+		}
+
+	UpdateAlarmListL(aAlarmedIds, *dayInfoList, aNow);
+
+	CleanupStack::PopAndDestroy(); //dayInfoList 
+	}
+
+/**
+Examine the contents of aDayInfoList and see if the any of the contained alarm instances should be added to
+or replace the contents of aAlarmedIds
+@internalComponent
+*/
+
+void CAgnEntryModel::UpdateAlarmListL(CArrayFixFlat<TAgnSortInstance>& aAlarmedIds,CArrayFixSeg<TAgnSortInstance>& aDayInfoList, const TTime& aNow)
+	{
+	TTime nextAlarmLocal(AgnDateTime::MaxDate());
+	
+	for ( TInt ii = aDayInfoList.Count() - 1; ii >= 0; --ii )
+		{
+		TAgnSortInstance sortInstance = aDayInfoList[ii];
+		
+		if ( sortInstance.SimpleEntry().Type() == CCalEntry::ETodo || sortInstance.iStartTimeLocal >= AgnDateTime::ResetToMidnight(aNow) )
+			{
+			TTime alarmTimeLocal(sortInstance.InstanceAlarmDateTime());
+	
+			if ( alarmTimeLocal <= aNow && sortInstance.SimpleEntry().RptDef() )
+				{				
+				TTime nextInstance;
+				
+				while ( sortInstance.SimpleEntry().RptDef()->NudgeNextInstanceL(sortInstance.InstanceDate(), nextInstance, ETrue) && nextInstance <= aNow)
+					{
+					sortInstance.SetL(nextInstance, aNow);
+									
+					if ( sortInstance.iStartTimeLocal < AgnDateTime::MaxDate() )
+						{
+						alarmTimeLocal = sortInstance.InstanceAlarmDateTime();
+						}
+					}
+				}
+						
+			if ( AgnDateTime::IsValidAgendaTTime(alarmTimeLocal) )
+				{
+				if ( alarmTimeLocal > aNow && alarmTimeLocal < nextAlarmLocal )
+					{
+					aAlarmedIds.Reset();
+					aAlarmedIds.AppendL(sortInstance);
+					nextAlarmLocal = alarmTimeLocal;
+					}
+				else
+					{
+					if ( alarmTimeLocal == nextAlarmLocal )
+						{
+						aAlarmedIds.AppendL(sortInstance);
+						}
+					}
+				}
+			}
+		}
+	}
+
+/** Schedules a list of alarms whose dateTime meets the following criteria:
+alarmTime >= aCurrentTime AND alarmTime <= aCurrentTime + 30 days
+@internalComponent
+*/
+ void CAgnEntryModel::NextFewAlarmsForServerL(const TTime& aStartDateTime,const TTime& aEndDateTime,
+											 CArrayFixFlat<TAgnSortInstance>& aAlarmedIds,const TInt aMaxNumberOfAlarms)
+	{
+	if(iAgnServerFile->IsFileDisabled())
+	    {
+	    return;
+	    }
+	if ( AgnDateTime::IsValidAgendaTTime(aStartDateTime) && AgnDateTime::IsValidAgendaTTime(aEndDateTime) &&
+		 aEndDateTime>=aStartDateTime )
+		{					
+		CArrayFixSeg<TAgnSortInstance>* dayInfoList = new(ELeave) CArrayFixSeg<TAgnSortInstance>(4);
+		CleanupStack::PushL(dayInfoList);
+
+		TFindInstanceParams searchParams;
+		searchParams.iUndatedTodoTimeLocal = searchParams.iRangeStart.LocalL();
+	    searchParams.iFilter = TAgnFilter(CalCommon::EIncludeAppts|CalCommon::EIncludeReminder|CalCommon::EIncludeEvents|
+											CalCommon::EIncludeAnnivs|CalCommon::EIncludeIncompletedTodos|CalCommon::EIncludeAlarmedOnly|
+											CalCommon::EIncludeRptsNextInstanceOnly, CalCommon::EFoldedTextSearch);
+	    searchParams.iSearchString = KNullDesC();
+	    searchParams.iRangeStart.SetLocalL(aStartDateTime - TTimeIntervalDays(1)); // alarms can be up to 24 hours after start time so check this
+	    searchParams.iRangeEnd.SetLocalL(aEndDateTime);
+	    
+		iExtractor->FindInstancesL(*dayInfoList, searchParams);
+		TAgnAlarmSortKey aKey;
+		dayInfoList->Sort(aKey);
+
+		AddToAlarmListL(aAlarmedIds, *dayInfoList, aStartDateTime, aEndDateTime, aMaxNumberOfAlarms);
+
+		CleanupStack::PopAndDestroy(dayInfoList);
+		}
+	}
+
+
+void CAgnEntryModel::AddToAlarmListL(CArrayFixFlat<TAgnSortInstance>& aAlarmedIds,CArrayFixSeg<TAgnSortInstance>& aDayInfoList, const TTime& aStartDateTime,
+									 const TTime& aEndDateTime,const TInt )
+//
+// Examine the contents of aDayInfoList add to aAlarmedIds
+//
+	{
+	const TInt KDayListCount(aDayInfoList.Count());
+	for (TInt i = 0; i < KDayListCount; ++i)
+		{
+ 		const TAgnSortInstance KSortInstance = aDayInfoList[i];
+ 		const TTime KAlarmInstance(KSortInstance.InstanceAlarmDateTime());
+
+		if (KAlarmInstance > aStartDateTime && KAlarmInstance <= aEndDateTime)
+			{
+			aAlarmedIds.AppendL(KSortInstance);						
+			}
+ 		}
+	}
+
+void CAgnEntryModel::FindAndQueueNextFewAlarmsL()
+	{
+	if ( iAlarm )
+		{
+		iAlarm->FindAndQueueNextFewAlarmsL();
+		}
+	}
+
+#ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
+void CAgnEntryModel::DeleteAlarmsAndRequeueSessionAlarmL()
+	{
+	if ( iAlarm )
+		{
+		iAlarm->DeleteAlarmsAndRequeueSessionAlarmL();
+		}
+	}
+#endif
+
+/**
+Return next time (from aStartDate) on which an instance exists
+@internalComponent
+*/
+void CAgnEntryModel::NextPossibleInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aSearchParams) const
+	{
+	iExtractor->NextPossibleInstancesL(aInstances, aSearchParams);
+	}
+/**
+Return previous time (from aStartDate) on which an instance exists
+@internalComponent
+*/
+void CAgnEntryModel::PreviousPossibleInstancesL(CArrayFix<TAgnSortInstance>& aInstances, const TFindInstanceParams& aSearchParams) const
+	{
+	iExtractor->PreviousPossibleInstancesL(aInstances, aSearchParams);
+	}
+
+
+// Place the uids of entries that have a last changed data greater than aDate and which meet the selection
+// criteria specified in aFilter into the aUids array.
+//
+void CAgnEntryModel::GetEntryUidsSinceDateL(const TTime& aTime, RArray<TCalLocalUid>& aUniqueIdList)
+	{
+	iSimpleEntryTable->FindByLastModifiedDateUtcL(aTime, aUniqueIdList);		
+	}
+
+
+/**
+Get the file ID of the currently open Agenda file.  
+This is unique to the file.
+@capability None
+*/
+const TInt64& CAgnEntryModel::GetFileIdL()
+	{
+	if ( iFileId == 0 )
+		{
+		RStoreReadStream in;
+		in.OpenLC(StreamStore(),iModelStreamIdSet->FileInformationStreamId());
+		TInt64 fileId=0;
+		in >> fileId;
+		CleanupStack::PopAndDestroy(); //in
+		iFileId = fileId;
+		}
+		
+	return iFileId;
+	}
+
+
+HBufC* CAgnEntryModel::RestoreTextL(const TStreamId& aStream)
+	{
+	CStreamStore& store = StreamStore();
+	RStoreReadStream in;
+	in.OpenLC(store, aStream);
+	TInt textLength = in.ReadUint32L();
+	HBufC* text = HBufC::NewL(in, textLength);
+	CleanupStack::PopAndDestroy(); //in
+	return text;
+	}
+
+TStreamId CAgnEntryModel::StoreTextL(const TDesC& aText)
+	{
+	CStreamStore& store = StreamStore();
+	RStoreWriteStream out;
+	TStreamId id = out.CreateLC(store);
+	out.WriteUint32L(aText.Length());
+	out << aText;
+	out.CommitL();
+	CleanupStack::PopAndDestroy(); //out
+	return id;
+	}
+
+/*
+ * Updates the notes text stored in the specified stream. Null Descriptors are expected to be 
+ * handled client side
+ */
+void CAgnEntryModel::UpdateTextL(const TDesC& aText, const TStreamId& aStream)
+	{
+	__ASSERT_DEBUG(aText.Length() != 0, Panic(EAgmNullDescriptor));
+
+	CStreamStore& store = StreamStore();
+	RStoreWriteStream out;
+	out.ReplaceLC(store, aStream);
+	out.WriteUint32L(aText.Length());
+	out << aText;
+	out.CommitL();
+	CleanupStack::PopAndDestroy(); //out
+	}
+
+/*
+ * Deletes the specified stream holding notes data.
+ * 
+ */
+void CAgnEntryModel::DeleteTextStreamL(const TStreamId& aStream)
+	{
+	StreamStore().DeleteL(aStream);
+	}	
+	
+	
+CAgnContent* CAgnEntryModel::RestoreAlarmActionL(const TStreamId& aStream)
+	{
+	CStreamStore& store = StreamStore();
+	RStoreReadStream in;
+	in.OpenLC(store, aStream);
+
+	CAgnContent* alarmAction = new (ELeave) CAgnContent;
+	CleanupStack::PushL(alarmAction);
+	in >> *alarmAction;
+	CleanupStack::Pop(alarmAction);
+
+	CleanupStack::PopAndDestroy(); //in
+	return alarmAction;
+	}
+
+
+TStreamId CAgnEntryModel::StoreAlarmActionL(const CAgnContent& aAlarmAction)
+	{
+	CStreamStore& store = StreamStore();
+	RStoreWriteStream out;
+	TStreamId id = out.CreateLC(store);
+	out << aAlarmAction;
+	out.CommitL();
+	CleanupStack::PopAndDestroy(); //out
+
+	return id;
+	}
+
+/*
+ * Updates the rich alarm data stored in the specified stream.  
+ */
+void CAgnEntryModel::UpdateAlarmActionL(const CAgnContent& aAlarmAction, const TStreamId& aStream)
+	{
+	CStreamStore& store = StreamStore();
+	RStoreWriteStream out;
+	out.ReplaceLC(store, aStream);
+	out << aAlarmAction;
+	out.CommitL();
+	CleanupStack::PopAndDestroy(); //out
+	}
+
+/*
+ * Deletes the specified stream holding rich alarm data.
+ * 
+ */
+void CAgnEntryModel::DeleteAlarmActionStreamL(const TStreamId& aStream)
+	{
+	StreamStore().DeleteL(aStream);
+	}
+
+const TDesC& CAgnEntryModel::FileName() const
+	{
+	return iAgnServerFile->FileName();
+	}
+
+void CAgnEntryModel::SetUpdateAlarmL(TBool aUpdateAlarm)
+	{
+	iUpdateAlarm = aUpdateAlarm;
+	
+	if ( iUpdateAlarm )
+		{
+		iAlarm->FindAndQueueNextAlarmL(EFalse);
+		}
+	}
+
+
+/** Commits any changes both to file and internally that have occurred to the model. 
+
+This function does not empty the buffers. Call FlushL to do that.
+@capability None
+*/
+void CAgnEntryModel::DoCommitL()
+	{ 
+	
+	if(!AgnServFile().IsBackupRestoreLock())
+		{
+		iModelStreamIdSet->CommitL(StreamStore());
+		StreamStore().CommitL();
+		iSimpleEntryTable->Commit();
+		iAttachmentIndex->CommitL(*iAgnServerFile);
+		}
+	
+	// Trigger compacting after a certain number of operations on the model
+	if(iOperationsCounter >= KCompactOperationsThreshold)
+		{
+		// Initiate synchronous compact
+		iAgnServerFile->CompactFileL();
+		// Reset operations counter
+		iOperationsCounter=0;
+		}
+	}
+
+// Commits all changes to file.
+void CAgnEntryModel::CommitL()
+	{
+	DoCommitL();
+	ResetRollback();
+	}
+
+// Called after multiple entries have been deleted.
+// This can fail at any time and must roll back, so notification cannot happen until the changes are committed to file.
+// This function does the commits then notifies, using the rollback array to find which entries have been deleted.
+void CAgnEntryModel::CommitAndNotifyDeletesL(TAgnChangeFilter& aChangeFilter)
+	{
+	DoCommitL();
+	iChangeFilter = &aChangeFilter;
+
+	const TInt KDeleteCount = iDeleteRollbackArray.Count();
+	for (TInt i = 0; i < KDeleteCount; ++i)
+		{
+		CAgnEntry* deletedEntry = iDeleteRollbackArray[i];
+		NotifyingL(MCalChangeCallBack2::EChangeDelete, *deletedEntry, NULL);
+		
+		if(iTzRuleIndex)
+			{
+			//Remove the tz rule from tz rule index
+			//we have to do it after CAgnEntryModel::NotifyingL that is indirectly using the
+			//tz rule in aEntry.
+			iTzRuleIndex->RemoveTzRuleL(*deletedEntry);
+			}
+		}
+
+	StreamStore().CommitL();
+	ResetRollback();
+	}
+
+// Add an entry to a rollback array. 
+// If aAdd is ETrue it is added to the add rollback array (for add operations)
+// If aAdd is EFalse it is added to the delete rollback array (for delete operations)
+void CAgnEntryModel::AppendRollbackArrayL(const CAgnEntry& aEntry, TBool aAdd)
+	{
+	if ( aAdd )
+		{
+		iAddRollbackArray.AppendL(aEntry.EntryId());
+		}
+	else
+		{
+		CAgnEntry* entryCopy = aEntry.CloneL();
+		CleanupStack::PushL(entryCopy);
+		iDeleteRollbackArray.AppendL(entryCopy);
+		CleanupStack::Pop(entryCopy);
+		}
+	}
+
+// Reset rollback arrays
+void CAgnEntryModel::ResetRollback()
+	{
+	iAddRollbackArray.Reset();
+	iDeleteRollbackArray.ResetAndDestroy();
+	}
+
+/**
+Rollback indexes in RAM. This is done by deleting all added entries and re-adding all deleted entries
+@internalComponent
+*/
+void CAgnEntryModel::RollbackIndexesL()
+	{
+	// delete all added entries
+	for ( TInt ii = iAddRollbackArray.Count() - 1; ii >= 0; --ii )
+		{
+		const TAgnEntryId& KEntryIdToDelete = iAddRollbackArray[ii];
+		
+		CAgnSimpleEntry* entryToDelete = iSimpleEntryTable->GetEntry(KEntryIdToDelete);
+		if(entryToDelete != NULL)
+			{
+			iSimpleEntryTable->DeleteEntry(KEntryIdToDelete);
+			}
+		
+		iAddRollbackArray.Remove(ii);
+		}
+
+	iAddRollbackArray.Reset();
+	
+	if(iTzRuleIndex)
+		{
+		//Rollback the reference count of tz rules in tz rule index
+		TRAPD(ret, iTzRuleIndex->RollBackL());
+		if(ret != KErrNotReady)
+			{
+			User::LeaveIfError(ret);
+			}
+		}
+
+	// re-add all deleted entries
+	for ( TInt ii = iDeleteRollbackArray.Count() - 1; ii >= 0; --ii )
+		{
+		CAgnEntry* entryToAdd = iDeleteRollbackArray[ii];
+
+		// Check the entry has a guid hash
+		if ( entryToAdd->GsDataType() == CGsData::EParent && ! entryToAdd->GuidHash() )
+			{
+			entryToAdd->SetGuidHash( GenerateHash8L(entryToAdd->Guid()) );
+			}	
+
+		// If the entry has already been added, delete it to prevent an error from re-adding the same entry.
+		// This can happen if the delete operation fails at a certain point.
+		const TAgnEntryId& KEntryIdToAdd = entryToAdd->EntryId();
+		if (iSimpleEntryTable->GetEntry(KEntryIdToAdd))
+			{
+			iSimpleEntryTable->DeleteEntry(KEntryIdToAdd);
+			}
+		
+		if(iTzRuleIndex)
+			{
+			//Fetch back the tz rule
+			iTzRuleIndex->FetchTzRuleL(*entryToAdd);
+			}
+		
+		// re-add the entry
+		AddEntryToIndexesL(*entryToAdd);
+		
+		iDeleteRollbackArray.Remove(ii);
+		delete entryToAdd;
+		}
+
+	iDeleteRollbackArray.Reset();
+	
+	iAttachmentIndex->Rollback();
+	}
+	
+/** Reverts the model to the state it was in after CommitL() or RollbackL() was 
+last called. This reverts changes to the file and to the indexes held in RAM.
+
+This means that it deletes all entries which have been added, and reinstates 
+all entries which have been deleted.
+
+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 
+Rollback was called.
+	
+@internalComponent
+*/
+void CAgnEntryModel::Rollback()
+	{
+	iEntryManager->Reset();
+
+	StreamStore().Revert();
+
+	TRAPD(ret,iModelStreamIdSet->RollbackL());
+	__ASSERT_DEBUG(ret==KErrNone, Panic(EAgmErrRollbackFailed));
+
+	TRAP(ret,RollbackIndexesL());
+	}
+
+
+void CAgnEntryModel::NotifyingL(MCalChangeCallBack2::TChangeType aChangeType, CAgnEntry& aEntry, CAgnInstanceInfo* aOriginalEntry)
+	{
+	if ( iChangeFilter )
+		{
+		if ( iChangeFilter->ChangeBroadcastEnabled() )
+			{
+			NotifyChangeL((iChangeFilter->Session()), &aEntry, aChangeType, aOriginalEntry);
+			}
+		else
+			{
+			iChangeFilter->SetChangeMadeWhileDisabled(ETrue);
+			}
+
+		if ( aEntry.Type() == CCalEntry::ETodo )
+			{
+			iChangeFilter->SetPubSubChange(TAgnChangeFilter::ETodoChanged);
+			}
+		else
+			{
+			iChangeFilter->SetPubSubChange(TAgnChangeFilter::EEventChanged);
+			}
+
+		NotifyPublishAndSubscribeL(*iChangeFilter);
+		}
+	}
+
+/*
+Delete aEntry from the store. If it has a positive replicated count however then mark it as having
+been deleted and update it instead.
+@capability WriteUserData
+@capability ReadUserData
+*/
+void CAgnEntryModel::DeleteEntryL(CAgnEntry& aEntry, TBool aCascadeDelete, TAgnChangeFilter* aChangeFilter)
+	{
+	#if defined (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
+		{
+		TBuf<KMaxGuidBufLength> guidBuf;
+		guidBuf.Copy(aEntry.Guid());
+		AgmDebug::DebugLog("DeleteEntryL: Deleting entry with local UID=%d, GUID=%S", aEntry.LocalUid(), &guidBuf);
+		}
+	#endif
+
+	iChangeFilter = aChangeFilter;
+	
+	if ( aCascadeDelete )
+		{
+		if ( aEntry.GsDataType() == CGsData::EParent )
+			{
+			_DBGLOG_ENTRY(AgmDebug::DebugLog("DeleteEntryL: Deleting children");)
+			
+			DeleteChildrenL(aEntry);
+			}
+		else
+			{
+			_DBGLOG_ENTRY(AgmDebug::DebugLog("DeleteEntryL: Updating Parent");)
+			UpdateParentL(aEntry);
+			}
+		}
+
+	DoDeleteEntryL(aEntry);
+	
+	NotifyingL(MCalChangeCallBack2::EChangeDelete,aEntry, NULL);
+
+	if ( iUpdateAlarm && aEntry.HasAlarm() )
+		{
+		iAlarm->FindAndQueueNextAlarmL(EFalse);
+		iAlarm->DeleteEntriesAlarmL(aEntry.EntryId());	
+		}
+	
+	if(iChangeFilter && iTzRuleIndex)
+		{
+		//Remove the tz rule from tz rule index
+		//we have to do it after CAgnEntryModel::NotifyingL that is indirectly using the
+		//tz rule in aEntry.
+		iTzRuleIndex->RemoveTzRuleL(aEntry);
+		}
+	}
+
+
+void CAgnEntryModel::DeleteChildrenL(CAgnEntry& aParent)
+	{//Get Child ids
+	__ASSERT_DEBUG(aParent.GsDataType() == CGsData::EParent, Panic(EAgmErrNotParentEntry));
+	
+	CAgnEntry* parent = FetchEntryL(aParent.EntryId());
+	if (parent != NULL)
+		{
+		CleanupStack::PushL(parent);
+		
+		const RArray<TGsChildRefData>& KIds = parent->ChildIds();
+		// delete each child entry 
+		for ( TInt i = KIds.Count() - 1; i >= 0; --i )
+			{
+			const TCalLocalUid& KChildId = KIds[i].ChildId();
+			CAgnEntry* childEntry = FetchEntryL(KChildId);  // pass flag so as not to tell parent  
+			if (childEntry)
+				{
+				CleanupStack::PushL(childEntry);
+
+				DeleteEntryL(*childEntry, EFalse, iChangeFilter); // don't propogate the delete back to this parent
+
+				CleanupStack::PopAndDestroy(childEntry);
+				}
+			
+			aParent.RemoveChildId(KChildId);
+			}
+		
+		CleanupStack::PopAndDestroy(parent);
+		}
+	}
+
+
+void CAgnEntryModel::UpdateParentL(CAgnEntry& aChild)
+	{
+	// It should be used in server side so that the notification of updating a parent is not sent
+	__ASSERT_DEBUG(aChild.GsDataType() == CGsData::EChild, Panic(EAgmErrNotChildEntry));
+
+	// get parent and update
+	CAgnEntry* parentEntry = FetchEntryL(aChild.ParentId());
+	__ASSERT_ALWAYS(parentEntry, User::Leave(KErrNotFound));
+	CleanupStack::PushL(parentEntry);
+
+	parentEntry->RemoveChildId(aChild.LocalUid());
+
+	UpdateEntryL(*parentEntry, iChangeFilter, EFalse);
+
+	CleanupStack::PopAndDestroy(parentEntry);	
+	}
+
+
+/**
+Delete aEntry from the store. If the entry is a todo then its id is removed from its
+todo list.
+*/
+void CAgnEntryModel::DoDeleteEntryL(CAgnEntry& aEntry)
+	{
+	DeleteExternalAttributesL(aEntry);
+	
+	TAgnEntryId id = aEntry.EntryId();
+	TStreamId streamId = iEntryManager->DeleteEntryL(id);
+
+	if ( streamId != KNullStreamId )
+		{
+		__ASSERT_DEBUG(streamId == aEntry.EntryId().StreamId(), Panic(EAgmErrWrongEntryDeleted));
+		StreamStore().DeleteL(streamId);
+		iModelStreamIdSet->EntryStreamIdSet().DeleteL(streamId);
+		}
+	
+	if ( ! iEntryManager->BufferedDeleting() || iEntryManager->BufferHasBeenStored() ) // during tidying only commit when the buffer has been written
+		{
+		iEntryManager->StoreBuffersL();
+		ExternalizeEntryManagerL();
+		// Don't commit on delete. CommitL is called from CalInterimAPI after a number have been added.
+		}
+	
+	UpdateIndexL(aEntry, NULL, EDelete);
+	}
+
+
+TBool CAgnEntryModel::EntryHasNoChildrenAndNoValidInstancesL(CAgnEntry& aEntry) const
+	{
+	TInt instances(1);
+	TInt exceptions(0);
+	if ( aEntry.RptDef() )
+		{
+		// Purely based on repeat rule, does not include exceptions' count
+		instances = aEntry.RptDef()->InstanceCountL();
+		const RArray<TAgnCalendarTime>* KExceptionList = aEntry.RptDef()->Exceptions();
+		if (KExceptionList)
+			{
+			exceptions += KExceptionList->Count();
+			}
+		
+		__ASSERT_ALWAYS(instances >= exceptions, User::Leave(KErrCorrupt));
+		}
+	
+	TBool entryHasNoChild = ((aEntry.GsDataType() == CGsData::EChild) || aEntry.ChildIds().Count() == 0);
+	return (entryHasNoChild && instances == exceptions);
+	}
+
+/*
+@capability ReadUserData
+@capability WriteUserData
+*/
+void CAgnEntryModel::UpdateEntryL(CAgnEntry& aEntry, TAgnChangeFilter* aChangeFilter, TBool aDeleteChildren)
+	{
+	TAgnEntryId originalId = aEntry.EntryId();
+	
+	if (originalId.IsNullId()) 
+		{
+		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: EntryId is null. Must be a newly created entry");)
+		
+		// Only parent entries can be updated
+		if(aEntry.GsDataType() != CGsData::EParent)
+			{
+			_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: KErrArgument: Only parent entries can be updated");)
+			User::Leave(KErrArgument);
+			}
+
+		RPointerArray<CAgnEntry> entriesWithThisGuid;
+		CleanupResetAndDestroyPushL(entriesWithThisGuid);
+		FetchEntriesL(aEntry.Guid(), entriesWithThisGuid);
+		
+		// Only an existing entry with the same guid can be updated
+		if(entriesWithThisGuid.Count() == 0)
+			{
+			_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: KErrNotFound: Only an existing entry with the same guid can be updated");)
+			User::Leave(KErrNotFound);
+			}
+		
+		CAgnEntry* existingParent = entriesWithThisGuid[0];
+		aEntry.SetLocalUid(existingParent->LocalUid());
+		aEntry.SetEntryId(existingParent->EntryId());
+		originalId = existingParent->EntryId();
+		
+		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: Setting Ids: LocalUid - %d, EntryId - %d", aEntry.LocalUid(),aEntry.EntryId().Value());)
+		CleanupStack::PopAndDestroy(&entriesWithThisGuid);
+		}
+		
+	//client server calls needs to be updated
+	iChangeFilter = aChangeFilter;
+	
+	if (EntryHasNoChildrenAndNoValidInstancesL(aEntry))
+		{
+		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: Deleting invalid entry - No children and no valid instances");)
+		DeleteEntryL(aEntry, EFalse, iChangeFilter);
+		return;
+		}
+	
+	if ( aDeleteChildren )
+		{
+		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: Deleting children");)
+		DeleteChildrenL(aEntry);
+		}
+	
+	CAgnEntry* oldEntry = FetchEntryL(originalId);
+	__ASSERT_DEBUG(oldEntry, User::Leave(KErrNotFound));
+	CleanupStack::PushL(oldEntry);
+	TBool hadAlarm = EFalse;
+	if ( oldEntry )
+		{
+		hadAlarm = oldEntry->HasAlarm();
+		}
+	
+	CAgnInstanceInfo* instanceInfoBefore = CAgnInstanceInfo::NewLC(*oldEntry);
+
+	TRAPD(ret, DoUpdateEntryL(aEntry, oldEntry));
+
+	if ( ret != KErrNone )
+		{
+		aEntry.SetEntryId(originalId);
+		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: DoUpdateEntryL failed: Leaving with error - %d",ret);)
+		User::Leave(ret);
+		}
+
+	NotifyingL(MCalChangeCallBack2::EChangeModify, aEntry, instanceInfoBefore);
+	
+	CleanupStack::PopAndDestroy(instanceInfoBefore);
+	CleanupStack::PopAndDestroy(oldEntry);
+	
+	// Delete the old alarm and if a new alarm exists it will be added by findAndQueue
+	// If a todo is completed or an event updated, while alarm is snoozed, 
+	// then the snoozed alarm has to be deleted separately, and deletion is not handled by findAndQueue
+	if (hadAlarm)
+		{
+		_DBGLOG_ENTRY(AgmDebug::DebugLog("UpdateEntryL: Deleting the alarm on the existing entry");)
+
+		iAlarm->DeleteEntriesAlarmL(aEntry.EntryId());
+		}
+	if (iUpdateAlarm && aEntry.HasAlarm())
+		{
+		iAlarm->FindAndQueueNextAlarmL(EFalse);
+		}
+	}
+
+/** Update an entry in the store. 
+@capability ReadUserData
+*/
+void CAgnEntryModel::DoUpdateEntryL(CAgnEntry& aEntry, CAgnEntry* aOldEntry)
+	{
+	TStreamId newStreamId;
+	UpdateExternalAttributesL(aEntry);
+
+	if (aOldEntry)
+		{
+		DoUpdateAttachmentsL(aEntry, *aOldEntry);
+		}
+	
+	if(iTzRuleIndex)
+		{
+		__ASSERT_DEBUG(aOldEntry, Panic(EAgmErrNullPointer));
+		iTzRuleIndex->UpdateTzRuleL(*aOldEntry, aEntry);
+		}
+	
+	TStreamId oldStreamId = iEntryManager->UpdateEntryL(aEntry, newStreamId);
+
+	if ( oldStreamId != KNullStreamId )
+		{
+		StreamStore().DeleteL(oldStreamId);
+		iModelStreamIdSet->EntryStreamIdSet().DeleteL(oldStreamId);
+		}
+
+	if ( newStreamId != KNullStreamId )
+		{
+		iModelStreamIdSet->EntryStreamIdSet().AddL(newStreamId);			
+		}
+
+	iEntryManager->StoreBuffersL();
+	ExternalizeEntryManagerL();
+	
+	UpdateIndexL(aEntry, aOldEntry, EUpdate);
+	}
+
+// Called when an entry is updated
+// This compares the new entry with the old one to see if any attachments have changed drive (by calling CCalAttachmentFile::SetDrive).
+void CAgnEntryModel::DoUpdateAttachmentsL(CAgnEntry& aNewEntry, CAgnEntry& aOldEntry)
+	{//This method will move the attachment to a different drive if it has been reset by the user.
+	const TInt KOldAttachmentCount = aOldEntry.AttachmentCount();
+	const TInt KNewAttachmentCount = aNewEntry.AttachmentCount();
+	
+	for (TInt oldEntryIndex = 0; oldEntryIndex < KOldAttachmentCount; ++oldEntryIndex)
+		{
+		CAgnAttachment& oldAttach = aOldEntry.Attachment(oldEntryIndex);
+		if (oldAttach.Type() == CCalContent::EDispositionInline && oldAttach.Uid() != 0)
+			{
+			CAgnAttachmentFile& oldAttachFile = static_cast<CAgnAttachmentFile&>(oldAttach);
+			TDriveName oldDrive = oldAttachFile.Drive();
+			
+			for (TInt newEntryIndex = 0; newEntryIndex < KNewAttachmentCount; ++newEntryIndex)
+				{
+				CAgnAttachmentFile& newAttachFile = static_cast<CAgnAttachmentFile&>(aNewEntry.Attachment(newEntryIndex));
+				if (newAttachFile.Uid() == oldAttach.Uid() && newAttachFile.Drive() != oldDrive)
+					{
+					HBufC* newfilename = oldAttachFile.FileName().AllocLC();
+					newfilename->Des().Replace(0,2,newAttachFile.Drive());
+					iAgnServerFile->MoveFileL(oldAttachFile.FileName(), newfilename->Des());
+					CleanupStack::PopAndDestroy(newfilename);
+
+					break;
+					}
+				}
+			}
+		}
+	}
+
+void CAgnEntryModel::MoveAttachmentToDriveL(CAgnAttachmentFile& aOldFileAttachment, CAgnAttachmentFile& aNewFileAttachment)
+	{
+	TParsePtrC parse(aOldFileAttachment.FileName());
+	HBufC* fileName = GenerateFilenameLC(aNewFileAttachment.Drive(), parse.NameAndExt());
+	TPtr pFilename(fileName->Des());
+	iAgnServerFile->MoveFileL(aOldFileAttachment.FileName(), pFilename);
+	aNewFileAttachment.SetFileNameL(*fileName);
+	CleanupStack::PopAndDestroy(fileName);
+		
+	#if defined (__CAL_ATTACH_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
+		HBufC8* attachId = aNewFileAttachment.ContentId().AllocLC();
+		AgmDebug::DebugLog("Moving attachment to drive: Old filename: %S to New filename with drive: %S", &aOldFileAttachment.FileName(), &pFilename);
+		AgmDebug::DebugLog("Attachment: UId - %S, Old filename size - %d, New filename size - %d", attachId, aOldFileAttachment.Size(), aNewFileAttachment.Size());
+		CleanupStack::PopAndDestroy(attachId);
+	#endif
+	}
+
+const CAgnSimpleEntry* CAgnEntryModel::GetSimpleEntryFromIndexes(const TAgnEntryId& aEntryId)
+	{
+	return iSimpleEntryTable->GetEntry(aEntryId);
+	}
+
+const CAgnSimpleEntry* CAgnEntryModel::GetSimpleEntryFromIndexes(TCalLocalUid aUniqueId)
+	{
+	return iSimpleEntryTable->GetEntry(aUniqueId);
+	}
+
+/** 
+Gets an entry based on its entry ID.
+
+@internalComponent
+@capability ReadUserData
+@param aId The entry ID of the entry to retrieve.
+@return Pointer to the entry. 
+*/
+CAgnEntry* CAgnEntryModel::FetchEntryL(const TAgnEntryId& aId) const
+	{
+	CAgnEntry* entry = iEntryManager->FetchEntryL(aId);
+	if (entry)
+		{
+		CleanupStack::PushL(entry);
+
+		if(iTzRuleIndex)
+			{
+			iTzRuleIndex->FetchTzRuleL(*entry);
+			}
+		
+		_DBGLOG_ENTRY(AgmDebug::DebugLog("FetchEntryL: Fetched entry with Stream Id %d, Partial Id %d",aId.Value(), aId.PartialId());)
+
+		if ( entry->GsDataType() == CGsData::EChild )
+			{
+			_DBGLOG_ENTRY(AgmDebug::DebugLog("FetchEntryL: Entry fetched is a child entry, Parent Id - %d", entry->ParentId());)
+			
+			// if a child entry has been fetched, get the recurrence ID and range stored with the parent
+			CAgnEntry* parent = FetchEntryL(entry->ParentId());
+
+			__ASSERT_ALWAYS(parent, User::Leave(KErrCorrupt)); // child without parent entry in DB!
+			CleanupStack::PushL(parent);
+			
+			entry->SetRecurrenceIdFromParentL(*parent);
+			
+			CleanupStack::PopAndDestroy(parent);
+			}
+
+		_DBGLOG_ENTRY(AgmDebug::DebugLogEntryL(*entry, EDumpEntryAll);)
+		CleanupStack::Pop(entry);
+		}
+	return (entry);
+	}
+
+/** 
+Gets an entry based on its unique ID.
+
+@internalComponent
+@capability ReadUserData
+@param aId The unique ID of the entry to retrieve.
+@return Pointer to the entry. 
+*/
+CAgnEntry* CAgnEntryModel::FetchEntryL(TCalLocalUid aUniqueId) const
+	{
+	_DBGLOG_ENTRY(AgmDebug::DebugLog("FetchEntryL: Attempting to fetch simple entry with LocalUid='%d'", aUniqueId);)
+	
+	// find entry in indexes to get the entry ID
+	CAgnSimpleEntry* simpleEntry = iSimpleEntryTable->GetEntry(aUniqueId);
+	CAgnEntry* entry = NULL;
+	
+	if ( simpleEntry )
+		{
+		_DBGLOG_ENTRY(AgmDebug::DebugLog("FetchEntryL: Entry found, fetching the full entry with Local ID %d",simpleEntry->EntryId().Value());)
+		
+		// fetch the full entry from the entry ID
+		entry = FetchEntryL(simpleEntry->EntryId());			
+		}
+	#if defined (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
+	else
+		{
+		AgmDebug::DebugLog("FetchEntryL: Entry not found");
+		}
+	#endif
+
+	
+	return ( entry );
+	}
+
+/** 
+Gets entries based on GUID.
+
+@internalComponent
+@capability ReadUserData
+@param aGuid The GUID of the entry to retrieve
+@param aList The list of CAgnEntry objects
+*/
+void CAgnEntryModel::FetchEntriesL(const TDesC8& aGuid, RPointerArray<CAgnEntry>& aList) const
+	{
+	CAgnEntry* parentEntry = FetchEntryL(aGuid);
+	
+	#if defined (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
+		TBuf<KMaxGuidBufLength> guidBuf;
+		guidBuf.Copy(aGuid);
+		AgmDebug::DebugLog("FetchEntriesL:  Using GUID='%S'", &guidBuf);
+	#endif
+
+	if ( parentEntry )
+		{
+		#if defined (__CAL_ENTRY_LOGGING__) || (__CAL_VERBOSE_LOGGING__)
+			TBuf<KMaxGuidBufLength> guidBuf;
+			guidBuf.Copy(aGuid);
+			AgmDebug::DebugLog("FetchEntriesL: Found a parent entry with GUID='%S'", &guidBuf);
+		#endif
+
+		CleanupStack::PushL(parentEntry);
+		aList.AppendL(parentEntry);
+		CleanupStack::Pop(parentEntry);
+		
+		// Fetch the children and add them to the array
+		const RArray<TGsChildRefData>& KIds = parentEntry->ChildIds();
+		
+		const TInt KCount = KIds.Count();
+		
+		_DBGLOG_ENTRY(AgmDebug::DebugLog("FetchEntriesL: Parent entry has %d child(ren)", KCount);)
+
+		for ( TInt i = 0; i < KCount; ++i )
+			{
+			CAgnEntry* childEntry = FetchEntryL(KIds[i].ChildId());  // pass flag so as not to tell parent to update its child list 
+			if (childEntry)
+				{
+				CleanupStack::PushL(childEntry);
+				aList.AppendL(childEntry);
+				CleanupStack::Pop(childEntry);
+				}
+			}
+		}  // parentEntry
+	}
+
+
+CAgnEntry* CAgnEntryModel::FetchEntryL(const TDesC8& aGuid, const TAgnCalendarTime& aRecurrenceId) const	
+	{
+	CAgnEntry* returnEntry = NULL;
+	CAgnEntry* parentEntry = FetchEntryL(aGuid);
+	
+	if ( parentEntry )
+		{
+		CleanupStack::PushL(parentEntry);
+		returnEntry = FindChildFromParentL(*parentEntry, aRecurrenceId); 
+		CleanupStack::PopAndDestroy(parentEntry);  	
+		}
+		
+	return returnEntry;
+	}
+
+TBool CAgnEntryModel::AreIndexesBuilt() const
+	{
+	if (iAgnServerFile)
+		{
+		return iAgnServerFile->AreIndexesBuilt();
+		}
+	return EFalse;
+	}
+
+
+void CAgnEntryModel::RestoreCategoriesL()
+	{
+	if ( iCalConverter )
+		{
+		iCalConverter->InternalizeCategoriesL();
+		}
+	}
+
+void CAgnEntryModel::OpenAttachmentFileL(RFile& aFile, TInt aAttachmentUid) const
+	{
+	const CAgnAttachmentIndexItem* const item = iAttachmentIndex->Attachment(aAttachmentUid);
+	// item is owned by iAttachmentIndex
+	
+	if ( item )
+		{
+		iAgnServerFile->OpenFileL(aFile, item->FileName());
+		}
+	else
+		{
+		User::Leave(KErrNotFound);
+		}
+	}
+
+
+void CAgnEntryModel::CreateNewFileL(RFile& aFile, const TDesC& aFileName)
+	{
+	iAgnServerFile->CreateNewFileL(aFile, aFileName);
+	}
+
+// Called when a binary data attachment is stored. 
+// At this stage, a new file has been created, and the file handle returned to the client.
+// 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.
+void CAgnEntryModel::UpdateAttachmentDetailsL(TCalLocalUid aLocalUid, TInt aAttachmentIndex, const TDesC& aFileName, TInt aAttachmentSize)
+	{
+	_DBGLOG_ATTACH(AgmDebug::DebugLog("UpdateAttachmentDetailsL: Local Uid %d, Attachment Index %d, FileName %S, Attachment Size %d", aLocalUid, aAttachmentIndex, &aFileName, aAttachmentSize);)
+	
+	CAgnEntry* entry = FetchEntryL(aLocalUid);
+	
+	if ( entry )
+		{
+		CleanupStack::PushL(entry);
+		
+		CAgnAttachmentFile* attachment = static_cast<CAgnAttachmentFile*>(&entry->Attachment(aAttachmentIndex));
+
+		if ( attachment && attachment->FileName().Length() <= KMaxDriveName)
+			{
+			attachment->SetFileNameL(aFileName);
+			attachment->SetSize(aAttachmentSize);
+			attachment->SetUid(iNextAttachmentUid);
+			++iNextAttachmentUid;
+			UpdateEntryL(*entry, NULL, EFalse);
+			
+			ExternalizeNextUidValuesL();
+			}
+			
+		CleanupStack::PopAndDestroy(entry);
+		}
+	}
+
+TInt CAgnEntryModel::TransferFileFromClientL(RFile& aAttachfileHandle, CAgnAttachmentFile& aAttachFile, CAgnEntry& aEntry, TBool aIsSameDrive)
+	{
+	RBuf originalFileName;
+	originalFileName.CreateL(KMaxFileName);
+	CleanupClosePushL(originalFileName);
+	aAttachfileHandle.FullName(originalFileName);
+	TInt size;
+	User::LeaveIfError(aAttachfileHandle.Size(size));
+				
+	// Generate  attachment filename
+	
+	TParsePtrC parseOriginalFile(originalFileName); 
+	HBufC* fileName = GenerateFilenameLC(aAttachFile.FileName(), parseOriginalFile.NameAndExt());
+	TPtr attachFilename(fileName->Des());
+		
+	_DBGLOG_ATTACH(AgmDebug::DebugLog("TransferFileFromClientL: Transferring file from: %S of size %d to %S", &originalFileName, size, &attachFilename);)
+	if(aIsSameDrive)
+		{
+		User::LeaveIfError(aAttachfileHandle.Rename(attachFilename)); // move the file to calendar area
+		}
+	else
+		{
+		aAttachfileHandle.Close();
+ 		iAgnServerFile->MoveFileL(originalFileName, attachFilename);			
+		}
+	aAttachFile.SetFileNameL(attachFilename);
+	aAttachFile.SetSize(size);
+	aAttachFile.SetUid(iNextAttachmentUid++);
+	
+	// Don't call UpdateEntryL as we only need to update the Calendar db file
+	TRAPD(err, UpdateEntryL(aEntry, NULL, EFalse));
+	if (err != KErrNone)
+		{
+		// if the entry failed to update, move the attachment back
+		if (aIsSameDrive)
+			{
+			User::LeaveIfError(aAttachfileHandle.Rename(originalFileName));	
+			}
+		else
+			{
+			iAgnServerFile->MoveFileL(fileName->Des(), originalFileName);		
+			}	
+		User::Leave(err);
+		}
+
+	CleanupStack::PopAndDestroy(2, &originalFileName);
+	ExternalizeNextUidValuesL();
+	return iNextAttachmentUid-1;
+	}
+TInt CAgnEntryModel::MoveFileToServerL(TCalLocalUid aLocalUid, TInt aAttachmentIndex)
+	{
+	TInt ret = 0;
+	TRAPD(err, ret = DoMoveFileToServerL(aLocalUid, aAttachmentIndex));
+	if(err != KErrNone)	
+		{
+		iAttachmentFileHandle.Close();
+		User::Leave(err);	
+		}
+	return ret;
+	}
+	
+TInt CAgnEntryModel::DoMoveFileToServerL(TCalLocalUid aLocalUid, TInt aAttachmentIndex)
+	{
+	_DBGLOG_ATTACH(AgmDebug::DebugLog("DoMoveFileToServerL: Local Uid %d, Attachment Index %d", aLocalUid, aAttachmentIndex);)
+	
+	TCalAttachmentUid attachUid(0);
+
+	CAgnEntry* entry = FetchEntryL(aLocalUid);
+	__ASSERT_ALWAYS(entry, User::Leave(KErrCorrupt));
+	CleanupStack::PushL(entry);
+
+	CAgnAttachment& attach = entry->Attachment(aAttachmentIndex);
+	__ASSERT_ALWAYS(attach.Type() == CCalContent::EDispositionInline, User::Leave(KErrCorrupt));
+
+	CAgnAttachmentFile& attachFile = static_cast<CAgnAttachmentFile&>(attach);
+	__ASSERT_ALWAYS(attachFile.Drive().CompareF(KDefaultAttachmentDrive()),User::Leave(KErrCorrupt) );//Drive is the default one
+
+	attachUid = TransferFileFromClientL(iAttachmentFileHandle,attachFile, *entry, EFalse);
+
+	CleanupStack::PopAndDestroy(entry);
+	return attachUid;
+	}
+	
+TInt CAgnEntryModel::TransferAttachmentFileToServerL(RFile& aFile, TCalLocalUid aLocalUid, TInt aAttachmentIndex)
+	{
+	_DBGLOG_ATTACH(AgmDebug::DebugLog("TransferAttachmentFileToServerL: Local Uid %d, Attachment Index %d", aLocalUid, aAttachmentIndex);)
+	
+	TCalAttachmentUid attachUid(0);
+	CAgnEntry* entry = FetchEntryL(aLocalUid);
+	__ASSERT_ALWAYS(entry, User::Leave(KErrCorrupt));
+	CleanupStack::PushL(entry);
+
+	CAgnAttachment& attach = entry->Attachment(aAttachmentIndex);
+	__ASSERT_ALWAYS(attach.Type() == CCalContent::EDispositionInline, User::Leave(KErrCorrupt));
+
+	CAgnAttachmentFile& attachFile = static_cast<CAgnAttachmentFile&>(attach);
+
+	if(!attachFile.Drive().CompareF(KDefaultAttachmentDrive()))//Drive is the default one
+		{
+		attachUid = TransferFileFromClientL(aFile, attachFile, *entry, ETrue);
+		}
+	else
+		{//Client need to close the handle in order to move the original file to the drive specified.
+		User::LeaveIfError(iAttachmentFileHandle.Duplicate(aFile));	
+		}
+
+	CleanupStack::PopAndDestroy(entry);
+	return attachUid;
+	}
+
+// Generate a filename for an attachment on the specified drive.
+HBufC* CAgnEntryModel::GenerateFilenameLC(const TDesC& aDrive, const TDesC& aFileName)
+	{
+	_LIT(KCalDirectory, "\\");
+	
+	// file name is "X:\\private\\10003a5b\\calendarfilename_a\\Y\\filename"
+	// where X is the drive specified (KDefaultAttachmentDrive if none is set)
+	// and Y is the folder number calculated from the attachment ID
+	const TInt KNumberOfAttachmentsPerFolder = 32;
+	//Restricting the Attachemnt folder name length to 2 chars, where it allows to add max0-99 folders
+	//by considering the KMaxFileName Length is allowed 220 Chars	
+	const TInt KMaxNumOfAttachmentFolders = 100;
+	// 8 to cover attachment folder name and trailing number if there exists a same file name
+	const TInt KExtraFileNameLength = 8;
+	TInt fileNameLength = iAgnServerFile->FileName().Length() + KExtraFileNameLength  + aFileName.Length();
+	TPtrC fileNamePtr (aFileName);
+	if(fileNameLength > KMaxFileName)
+	    {
+	    const TInt KMinFileNameLength = 8;
+	    fileNameLength = iAgnServerFile->FileName().Length() + KExtraFileNameLength +  KMinFileNameLength;
+	    if(fileNameLength > KMaxFileName)
+	        {
+	        User::Leave(KErrBadName);
+	        }
+	    else
+	        {
+	        fileNamePtr.Set(aFileName.Left(KMinFileNameLength - 2));//save 2 for trailling number
+	        }
+	    }
+	HBufC* fileName = HBufC::NewLC(fileNameLength);
+	TPtr folderNamePtr = fileName->Des();
+	iAgnServerFile->GetAttachmentFolderNameL(folderNamePtr);
+	
+	// if the drive has been set already, set it on the filename
+	if ( aDrive.Length() >= 1 )
+		{
+		folderNamePtr.Replace(0, 1, aDrive.Left(1));
+		}
+	else
+		{
+		folderNamePtr.Replace(0, 1, KDefaultAttachmentDrive().Left(1));
+		}
+	
+	const TInt KFolderNumber = iNextAttachmentUid / KNumberOfAttachmentsPerFolder;
+	if (KFolderNumber >= KMaxNumOfAttachmentFolders)
+		{
+		User::LeaveIfError(KErrDirFull);
+		}
+	folderNamePtr.AppendNum(KFolderNumber);
+	folderNamePtr.Append(KCalDirectory);
+    TPtr fullFileNamePtr(folderNamePtr);
+	fullFileNamePtr.Append(fileNamePtr);	
+	TBool uniqueFilenameGenerated = EFalse;
+	TInt count = 0;
+	while ( ! uniqueFilenameGenerated )
+	    {
+	    if ( !iAgnServerFile->FileExistsL(fullFileNamePtr) )
+            {
+            uniqueFilenameGenerated = ETrue;
+            }
+	    else
+	        {
+	        TParsePtrC parse(fileNamePtr);
+	        fullFileNamePtr = folderNamePtr;
+	        fullFileNamePtr.Append(parse.Name());
+	        fullFileNamePtr.AppendNum(count++);
+	        fullFileNamePtr.Append(parse.Ext());
+	        }
+	    }
+	
+	iAgnServerFile->CreateDirL(fullFileNamePtr);
+	return fileName;
+	}
+
+// Generate a filename for an attachment on the specified drive.
+HBufC* CAgnEntryModel::GenerateRandomFilenameLC(const TDesC& aDrive)
+    {
+    _LIT(KCalDirectory, "\\");
+    
+    // file name is "X:\\private\\10003a5b\\calendarfilename_a\\Y\\filename"
+    // where X is the drive specified (KDefaultAttachmentDrive if none is set)
+    // and Y is the folder number calculated from the attachment ID
+    const TInt KNumberOfAttachmentsPerFolder = 32;
+    const TInt KNumCharsInFileName = 8; 
+    //Restricting the Attachemnt folder name length to 2 chars, where it allows to add max0-99 folders
+    //by considering the KMaxFileName Length is allowed 220 Chars   
+    const TInt KMaxNumOfAttachmentFolders = 100;
+
+    // 16 to cover attachment folder name and extension - could be 'foldername\\888\\filename.xxx'
+    const TInt KFileNameLength = iAgnServerFile->FileName().Length() + 32 + KNumCharsInFileName;
+    
+    HBufC* fileName = HBufC::NewLC(KFileNameLength);
+    TPtr fileNamePtr = fileName->Des();
+    
+    iAgnServerFile->GetAttachmentFolderNameL(fileNamePtr);
+    
+    // if the drive has been set already, set it on the filename
+    if ( aDrive.Length() >= 1 )
+        {
+        fileNamePtr.Replace(0, 1, aDrive.Left(1));
+        }
+    else
+        {
+        fileNamePtr.Replace(0, 1, KDefaultAttachmentDrive().Left(1));
+        }
+    
+    const TInt KFolderNumber = iNextAttachmentUid / KNumberOfAttachmentsPerFolder;
+    if (KFolderNumber >= KMaxNumOfAttachmentFolders)
+        {
+        User::LeaveIfError(KErrDirFull);
+        }
+    fileNamePtr.AppendNum(KFolderNumber);
+    fileNamePtr.Append(KCalDirectory);
+    
+    TBool uniqueFilenameGenerated = EFalse;
+    
+    TTime time;
+    time.UniversalTime();
+    TInt64 seed = time.Int64() + iNextAttachmentUid;
+    
+    while ( ! uniqueFilenameGenerated )
+        {
+        // Generate a random filename
+        for ( TInt i = 0; i < KNumCharsInFileName; ++i, ++seed )
+            {
+            TChar randomChar = (Math::Rand(seed) % 26) + 'a';
+            fileNamePtr.Append(randomChar);
+            }
+
+        // check that there is not an existing filename with the same name (very unlikely!)
+        if ( iAgnServerFile->FileExistsL(fileNamePtr) )
+            {
+            // Remove this file name from the descriptor if the file exists already, and generate a new name
+            fileNamePtr.SetLength(fileNamePtr.Length() - KNumCharsInFileName);
+            }
+        else
+            {
+            uniqueFilenameGenerated = ETrue;
+            }
+        }
+    
+    iAgnServerFile->CreateDirL(fileNamePtr);
+    return fileName;
+    }
+
+const RArray<TCalLocalUid>* CAgnEntryModel::GetEntriesWithAttachment(TCalAttachmentUid aAttachmentUid) const
+	{
+	_DBGLOG_ATTACH(AgmDebug::DebugLog("GetEntriesWithAttachment: Attachment Uid %d", aAttachmentUid);)
+	
+	const CAgnAttachmentIndexItem* const item = iAttachmentIndex->Attachment(aAttachmentUid);
+	
+	if ( item && item->Entries().Count())
+		{
+		return &item->Entries();
+		}
+		
+	return NULL;
+	}
+
+
+void CAgnEntryModel::GetSortedAttachmentsL(RArray<TCalAttachmentUid>& aAttachmentIds, CCalAttachmentManager::TSortOrder aSortType)
+	{
+	RPointerArray<CAgnAttachmentIndexItem> sortedAttachments;
+	CleanupClosePushL(sortedAttachments);
+	iAttachmentIndex->GetSortedIndexL(aSortType, sortedAttachments);
+
+	const TInt KAttachmentCount = sortedAttachments.Count();
+	for ( TInt i = 0; i < KAttachmentCount; ++i)
+		{
+		aAttachmentIds.AppendL(sortedAttachments[i]->Uid());
+		}
+
+	CleanupStack::PopAndDestroy(&sortedAttachments); 
+	}
+
+
+CAgnAttachment* CAgnEntryModel::FetchAttachmentByIdL(TCalAttachmentUid aAttachUid)
+	{
+	_DBGLOG_ATTACH(AgmDebug::DebugLog("FetchAttachmentByIdL: Attachment Uid %d", aAttachUid);)
+	
+	const CAgnAttachmentIndexItem* const item = iAttachmentIndex->Attachment(aAttachUid);
+	CAgnAttachment* attachmentToWrite = NULL;
+	
+	if ( item )
+		{
+		const RArray<TCalLocalUid>& KEntries = item->Entries();
+
+		if ( KEntries.Count() == 0 )
+			{
+			// corrupt index - remove the attachment and return NULL
+			iAttachmentIndex->RemoveAttachment(aAttachUid);
+			}
+		else
+			{
+			const TCalLocalUid& Kid = KEntries[0];
+			CAgnEntry* entry = FetchEntryL(Kid);
+
+			if ( entry )
+				{
+				CleanupStack::PushL(entry);
+
+				for ( TInt i = 0; i < entry->AttachmentCount(); ++i )
+					{
+					if ( entry->Attachment(i).Uid() == aAttachUid )
+						{
+						attachmentToWrite = AttachmentFactory::CloneL(entry->Attachment(i));
+
+						break;
+						}
+					}
+
+				CleanupStack::PopAndDestroy(entry);
+				}
+			}
+		}
+
+	return attachmentToWrite;
+	}
+
+const TDesC8& CAgnEntryModel::GetEntryGuidL(CAgnEntry& aEntry) const
+	{
+	if(aEntry.Guid() == KNullDesC8)
+		{//it is a child and its uid has not been loaded
+		CAgnEntry* parentEntry = FetchEntryL(aEntry.ParentId());
+		__ASSERT_DEBUG(parentEntry, Panic(EAgmErrChildWithoutParent));
+		if(parentEntry)
+			{
+			CleanupStack::PushL(parentEntry);
+			HBufC8* guidHbuf = parentEntry->Guid().AllocL();
+			CleanupStack::PopAndDestroy(parentEntry);	
+			aEntry.SetGuid(guidHbuf);
+			}
+		}
+	return aEntry.Guid();
+	}
+
+
+/**
+Returns A reference to the stream store in which the model's data is stored. 
+@internalComponent
+*/
+CStreamStore& CAgnEntryModel::StreamStore() const
+	{
+	return iEntryManager->StreamStore();
+	}
+
+CCalAsyncDelete* CAgnEntryModel::CreateAsyncDeleteL(TAgnChangeFilter& aChangeFilter)
+	{
+	return CCalAsyncDelete::NewL(*this, aChangeFilter, *iSimpleEntryTable);
+	}
+
+void CAgnEntryModel::LoadNewStreamStoreL(CStreamStore& aStore, const TStreamId& aModelStreamId, CAgnEntryManager& aEntryManager, CAgnTzRuleIndex& aTzRuleIndex)
+	{
+	iEntryManager->SetStore(aStore);
+
+	iEntryManager->CopyStreamIds(aEntryManager);
+	iModelStreamIdSet->LoadL(aStore, aModelStreamId);
+	
+	if(iTzRuleIndex)
+		{
+		delete iTzRuleIndex; 
+		}
+	
+	iTzRuleIndex = &aTzRuleIndex;
+	iTzRuleIndex->CheckTzDbModificationL(*iAgnServerFile);
+	}
+
+TBool CAgnEntryModel::StreamsAreEmpty() const
+	{
+	return (iModelStreamIdSet->EntryStreamIdSet().Count() == 0);
+	}
+
+TAgnEntryIter* CAgnEntryModel::CreateEntryIterL() const
+	{
+	return new (ELeave) TAgnEntryIter(iModelStreamIdSet->EntryStreamIdSet(), *iEntryManager);
+	}
+
+CAgnCategoryIndex& CAgnEntryModel::CategoryIndex() const
+/** Gets the category index.
+
+@return The agenda model category index object. */
+	{
+	return ( *iCategoryIndex );
+	}
+
+TTime CAgnEntryModel::TzRulesLastModifiedDateL()
+	{
+	return iTzRuleIndex->TzRulesLastModifiedDateL();
+	}
+
+void CAgnEntryModel::HandleTzRulesChangeL(const TTime& aTime)
+    {
+    iTzRuleIndex->HandleTzRulesChangeL(aTime);
+    }
+
+CAgnAlarm& CAgnEntryModel::Alarm()
+    {
+    return *iAlarm;
+	}