pimappservices/calendar/server/src/agsalarm.cpp
changeset 0 f979ecb2b13e
child 11 0f07cd1b5772
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappservices/calendar/server/src/agsalarm.cpp	Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,806 @@
+// 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 "agsalarm.h"
+#include "agmutil.h"
+#include "agssortinstance.h"
+#include "agmentry.h"
+#include "agsentrymodel.h"
+#include "agmtlsproxy.h"
+#include "agmdebug.h"
+#include "agsfilemanager.h"
+#include "agsmain.h"
+#include <centralrepository.h>
+#include <f32file.h>
+#include <txtetext.h>
+#include <tz.h>
+
+// This is used when the system time is put forward. All alarms within KSystemTimeChangeMaxDaysOld of 
+// the new/present time will be queued. If set to 1, and the time is put forward by 7 days then only
+// alarms within 1 day of the new time will be queued.
+// (Note: This may need to be changed to a TTime in the future if greater granularity is required.)
+const TInt KSystemTimeChangeMaxDaysOld = 1;
+
+// Maximum number of event alarms to be scheduled when the system time/date changes. Ideally there
+// shouldn't be a maximum but the existing API FindAndQueueNextFewAlarmsL takes has a
+// maximum parameter. This should be set to MAX_INT.
+// (Note: This is the same default value used in the method CAgnAlarm::FindAndQueueNextFewAlarmsL)
+const TInt KSystemTimeChangeMaxAlarmsQueued = 0xffff;
+
+
+// Central Repository Uid
+const TUid KUidCentralRepositoryAgenda = { 0x10003a5b };
+ 
+//Used for configuration of whether or not to notify missing alarms
+const TUint KKeyQueueMissingAlarm = 100;
+CAgnAlarm::CAgnAlarm(RASCliSession& aRASCliSession)
+    :iAlarmServer(aRASCliSession)
+    {
+    }
+CAgnAlarm* CAgnAlarm::NewL(CAgnEntryModel* aModel,MAgnAlarmServerTerminationCallBack* aCallBack)
+/** Allocates and constructs a CAgnAlarm object and makes a connection to 
+the alarm server.
+
+@internalAll
+@param aModel Pointer to the agenda model which the alarm server connection 
+is being set up for.
+@param aCallBack An optional alarm server termination callback provider. May be NULL.
+@return Pointer to the newly created alarm server interface object. */
+	{
+	CAgnAlarm* self = new (ELeave) CAgnAlarm(aModel->AgnServFile().Server().AlarmServer());
+	
+	CleanupStack::PushL(self);
+	self->ConstructL(aModel,aCallBack);
+	CleanupStack::Pop();
+	
+	return (self);
+	}
+
+void CAgnAlarm::DeleteAllAlarms()
+    {
+    // ignore any errors returned from this
+    TParsePtrC parser(iAlarm->AgnServFile().FileName());
+    TFileName fileName = parser.Drive();
+    fileName.Append(parser.NameAndExt());
+    iAlarmServer.AlarmDeleteByCalendarFile(fileName, EFuture|EExpired);
+    }
+
+void CAgnAlarm::ConstructL(CAgnEntryModel* aModel,MAgnAlarmServerTerminationCallBack* aCallBack)
+//
+// Construct CAgnAlarm
+//
+	{
+	iAlarm = CAgnAlarmActive::NewL(aModel,iAlarmServer);
+	iChangeObserver = CAgnAlarmServerChangeObserver::NewL(aCallBack,this);
+
+	iQueueAlarmsInPast = 1;
+	CRepository* repository = NULL;
+	TRAPD(err,  repository = CRepository::NewL(KUidCentralRepositoryAgenda));
+	if (err == KErrNone && repository)
+		{
+		CleanupStack::PushL(repository);
+		User::LeaveIfError(repository->Get(KKeyQueueMissingAlarm, iQueueAlarmsInPast));
+		CleanupStack::PopAndDestroy(repository);
+		}
+
+	iAlarm->SetQueueAlarmsInPast(iQueueAlarmsInPast);
+	}
+
+TBool CAgnAlarm::QueueAlarmsInPast()
+	{
+	return iQueueAlarmsInPast;
+	}
+	
+ CAgnAlarm::~CAgnAlarm()
+/** Frees all resources owned by the object, prior to its destruction, 
+and ends the session with the alarm server. 
+@internalAll
+*/
+	{
+	delete iAlarm;
+	delete iChangeObserver;
+	}
+
+void CAgnAlarm::OrphanAlarm()
+/** Orphans the session alarm. 
+
+This allows the alarm to be serviced after the session is closed. This 
+function should be called by the user of the model before closing an 
+agenda file. 
+
+@internalAll
+*/
+	{
+	iAlarm->OrphanAlarm();
+	}
+
+/** Finds the agenda model's next due alarm. 
+
+If a due alarm is found, it is set as the session alarm and queued 
+with the alarm server. 
+
+This function should be called by the client immediately after the CAgnAlarm object is created. 
+
+@internalAll
+@capability WriteUserData
+*/
+void CAgnAlarm::FindAndQueueNextAlarmL(TBool aSysTimeHasChanged)
+	{
+	iAlarm->FindAndQueueNextAlarmL(aSysTimeHasChanged);
+	}
+
+void CAgnAlarm::QueueNextAlarmL(CArrayFixFlat<TAgnSortInstance>*aAlarmedIds)
+	{
+	iAlarm->QueueNextAlarmL(aAlarmedIds);
+	}
+
+void CAgnAlarm::FindAndQueueNextFewAlarmsL(const TInt aMaxNumberOfAlarms,const TInt aMaxNumberOfDays)
+/** Finds the agenda model's next few alarms.
+
+If one or more due alarms are found, they are set as session alarms
+and queued with the alarm server.
+
+This method is no longer required by the client because the alarms are now queued
+by the agenda server once the last session is disconnected to it.
+
+@internalAll
+@param aMaxNumberOfAlarms The maximum number of alarms to be queued. The default 
+value is 10.
+@param aMaxNumberOfDays The maximum number of days to be scanned for alarms. 
+The default value is 31. */
+	{
+	iAlarm->FindAndQueueNextFewAlarmsL(aMaxNumberOfAlarms, aMaxNumberOfDays);
+	}
+
+
+void CAgnAlarm::FindAndQueueNextFewAlarmsL(const TTime& startTime,const TTime& endTime,const TInt aMaxNumberOfAlarms)
+/* Finds the agenda model's next few alarms.
+
+If one or more due alarms are found, they are set as session alarms
+and queued with the alarm server. 
+
+(Note: This method was added to handle system date/time changes. It is not currently exported, however
+ the less general version which takes aMaxNumberOfDays can be used for most purposes.  */
+	{
+	iAlarm->FindAndQueueNextFewAlarmsL(startTime,endTime,aMaxNumberOfAlarms);
+	}
+
+/* Gets the TAgnAlarmEntry struct 
+
+*/
+const TAgnAlarmEntry* CAgnAlarm::AlarmEntry() const
+	{
+	return ( iAlarm->CurrentAlarmEntry() );
+	}
+
+void CAgnAlarm::DeleteEntriesAlarmL(const TAgnEntryId& aEntryId)
+   //Removes all of an entry's alarms from the alarm server.
+   //First, obtain a list of alarms from the alarmserver.
+   //Compare aEntryInstanceId to the TAgnEntryId of the alarm in the queue.
+   //if they are the same then the alarm server is asked to remove the alarm from the queue.
+   	{
+   	RArray<TAlarmId> snoozedAlarmIds;
+   	CleanupClosePushL(snoozedAlarmIds);
+
+   	iAlarmServer.GetAlarmIdListForCategoryL(KUidAgendaModelAlarmCategory, snoozedAlarmIds);
+  	
+   	if( snoozedAlarmIds.Count() > 0 )
+   		{
+   		for( TInt i = 0; i < snoozedAlarmIds.Count(); ++i )
+	   		{
+	   		//get the info for this alarm id
+	  		TBuf8<sizeof(TAgnAlarmInfo)> alarmInfoBuf;
+	  		
+	   		iAlarmServer.GetAlarmData(snoozedAlarmIds[i],alarmInfoBuf);
+	   		
+	  		const TAgnAlarmInfo* alarmInfo = reinterpret_cast<const TAgnAlarmInfo*>(alarmInfoBuf.Ptr());
+	  		if ( alarmInfo->iEntryId == aEntryId )
+	   			{
+	   			iAlarmServer.AlarmNotificationCancelAndDequeue(snoozedAlarmIds[i]);
+	   			}
+	   		}
+   		}
+   		
+   	CleanupStack::PopAndDestroy(&snoozedAlarmIds);
+   	}
+#ifdef SYMBIAN_SYSTEM_STATE_MANAGEMENT
+void CAgnAlarm::DeleteAlarmsAndRequeueSessionAlarmL()
+	{
+	iAlarmServer.AlarmDeleteByCategory(KUidAgendaModelAlarmCategory, EFuture|EExpired);
+	FindAndQueueNextAlarmL(EFalse);
+	}
+#endif
+
+const CAgnServFile& CAgnAlarm::AgnServFile()
+    {
+    return iAlarm->AgnServFile();
+    }
+
+CAgnAlarmServerChangeObserver& CAgnAlarm::ChangeObserver()
+    {
+    return *iChangeObserver;
+    }
+
+CAgnAlarmActive* CAgnAlarmActive::NewL(CAgnEntryModel* aModel,RASCliSession& aAlarmServer)
+//
+// Create a CAgnAlarmActive object and connect to the alarm server.
+//
+	{
+
+	CAgnAlarmActive* self=new(ELeave)CAgnAlarmActive(EPriority,aAlarmServer);
+	
+	CleanupStack::PushL(self);
+	self->iAlarmList=new(ELeave)CArrayFixFlat<TAgnAlarmEntry>(EGranularity);
+	CleanupStack::Pop();
+	
+	self->iModel = aModel;
+	CActiveScheduler::Add(self);
+	
+	return ( self );
+	}
+
+CAgnAlarmActive::CAgnAlarmActive(TInt aPriority,RASCliSession& aAlarmServer) 
+//
+// Constructor
+//
+	: CActive(aPriority), iAlarmServer(aAlarmServer)
+	{
+	}
+
+
+void CAgnAlarmActive::OrphanAlarm()
+//
+// If there's currently an alarm queued with the alarm server then orphan it.
+//
+	{
+
+	if ( IsActive() )
+		{
+		// Changing the characteristics of the alarm from SessionSpecific to
+		// non-session specific means the alarm ownership is transferred from
+		// this session to the alarm server.
+		//
+		// Calling this completes the pending request with KErrCancel
+		TAlarmCharacteristicsFlags alarmCharacteristicsFlags;
+		iAlarmServer.GetAlarmCharacteristics(iAlarm.Id(), alarmCharacteristicsFlags);
+		alarmCharacteristicsFlags.Clear(EAlarmCharacteristicsSessionSpecific);
+		iAlarmServer.SetAlarmCharacteristics(iAlarm.Id(), alarmCharacteristicsFlags);
+		}
+		
+	Cancel();
+	}
+
+
+CAgnAlarmActive::~CAgnAlarmActive()
+//
+// If active then an alarm must be outstanding so create an orphan from it then cancel it.
+//
+	{
+	OrphanAlarm();
+	delete iAlarmList;
+	}
+
+
+void CAgnAlarmActive::RunL()
+//
+// The alarm server signals iRequestStatus in the following situations:
+//	- KErrNone when the alarm has expired
+//	- KErrCancel when the alarm has been canceled
+//
+	{
+
+	if ( iStatus == KErrNone ) 	// an alarm has expired
+		{
+		__ASSERT_DEBUG(iAlarmList->Count()>0, Panic(EAgmNoAlarmsInList)); // the alarm which has just gone off should be in the alarm list
+
+		if ( ++iAlarmListIndex < iAlarmList->Count() )
+		//	if there is another entry with the same alarm time as the one which has just gone off then
+		//  queue it with the alarm server (its time will now be in the past so it'll go off immediately)
+			{
+			const TAgnAlarmEntry& alarmEntry = (*iAlarmList)[iAlarmListIndex];
+			
+			// Create and queue an alarm with the Alarm Server
+			InitialiseAlarmL(iAlarm,alarmEntry,ETrue);
+			TAgnAlarmInfo alarmInfo;
+			GetAlarmInfoL(alarmEntry.iInstanceId, alarmInfo);
+
+			_DBGLOG_ALARM(AgmDebug::DebugLog("Alarm expired/cancelled. Queueing next alarm:");)
+			_DBGLOG_ALARM(AgmDebug::DebugLogAlarmL(alarmEntry);)
+
+			TPkgCAgnAlarmInfo pkgAgendaRef(alarmInfo);
+			SetActive();
+			iAlarmServer.AlarmAddWithNotification(iStatus, iAlarm, pkgAgendaRef);
+			
+			if ( iAlarm.Id() == KNullAlarmId )
+				{
+				User::Leave(KErrGeneral);
+				}
+			}
+		else
+			{
+			FindAndQueueNextAlarmL(EFalse);
+			}
+		}
+	else if( iStatus == KErrCancel )
+		{
+		DoCancel();
+		}
+	}
+
+
+TBool CAgnAlarmActive::AssignToL(TAgnAlarmEntry& aAlarmEntry, const TAgnSortInstance& aSortInstance)
+// assign data to the passed alarm entry
+// Used by QueueNextAlarmL and FindAndQueueNextFewAlarmsL
+
+	{
+	aAlarmEntry.iDueDateTimeLocal = aSortInstance.iStartTimeLocal;
+	
+	//to get text in this entry
+	CAgnEntry* entry = iModel->FetchEntryL(aSortInstance.SimpleEntry().EntryId());
+	if (! entry)
+		{
+		return EFalse;
+		}
+		
+	CleanupStack::PushL(entry);
+	
+	if ( entry->RptDef() && !entry->RptDef()->IsAnUnexceptedInstanceL(aSortInstance.InstanceDate()) )
+		{
+		// the entry should be not excepted
+		_DBGLOG_ALARM(AgmDebug::DebugLog("Alarm: PANIC - Invalid Instance: The entry should be not excepted"));
+		_DBGLOG_ALARM(AgmDebug::DebugLogEntryL(*entry, EDumpEntryAll);)
+		DBG_PANIC(EAgmErrInvalidInstance);
+		User::Leave(KErrNotFound);
+		}
+
+	TAgnCalendarTime instanceDate;
+	if (entry->TimeMode() == MAgnCalendarTimeMode::EFloating)
+		{
+		aAlarmEntry.iAlarmTime.SetFloatingL(aSortInstance.InstanceAlarmDateTime());
+		instanceDate.SetFloatingL(aSortInstance.InstanceDate());
+		}
+	else
+		{
+		aAlarmEntry.iAlarmTime.SetLocalL(aSortInstance.InstanceAlarmDateTime());
+		instanceDate.SetLocalL(aSortInstance.InstanceDate());
+		}
+	aAlarmEntry.iInstanceId.SetEntryId(entry->EntryId());
+	aAlarmEntry.iInstanceId.SetDate(instanceDate);
+	
+	if ( !entry->SummaryIsLoaded() )
+		{
+		entry->SetSummary(iModel->RestoreTextL(entry->SummaryStreamId()));
+		}
+
+	TInt len = entry->Summary().Length();
+	
+	if ( len > KMaxAlarmMessageLength )
+		{
+		len = KMaxAlarmMessageLength;
+		}
+		
+	aAlarmEntry.iMessage = KNullDesC;
+	
+	for ( TInt ii = 0; ii < len; ++ii )
+		{
+		TChar ch(entry->Summary()[ii]);
+		switch (ch)
+			{
+		case CEditableText::EParagraphDelimiter :
+		case CEditableText::ELineBreak :
+		case CEditableText::EPageBreak :
+		case CEditableText::ETabCharacter :
+		case CEditableText::ENonBreakingHyphen :
+		case CEditableText::EPotentialHyphen :
+		case CEditableText::ENonBreakingSpace :
+		case CEditableText::EPictureCharacter :
+			aAlarmEntry.iMessage.Append(CEditableText::ESpace);
+			continue;
+			}
+		aAlarmEntry.iMessage.Append(ch);
+		}
+
+	aAlarmEntry.iSound = entry->AlarmSoundName();
+	
+	CleanupStack::PopAndDestroy(); //entry
+	
+	return ETrue;
+	}
+
+/** Find the next due alarm(s) with same time and if at least one exists then queue it with the alarm server
+@capability WriteUserData
+*/
+void CAgnAlarmActive::FindAndQueueNextAlarmL(TBool aSysTimeHasChanged)
+	{
+	TTime now;
+	now.HomeTime();
+
+	// Certainly on WINS an alarm may expire a few seconds before it is due, the
+	// following ensures that the same alarm isn't queued twice
+	// If system time has been changed, we don't want to increase "now" to make sure
+	// that the alarm whoes due time same as "now" is found.
+	const TInt KAlarmCount = iAlarmList->Count();
+	if ( KAlarmCount && !aSysTimeHasChanged)
+		{
+		TTime lastAlarm = (*iAlarmList)[KAlarmCount-1].iAlarmTime.LocalL();
+		
+		if ( now < lastAlarm )
+			{
+			now += TTimeIntervalSeconds(1);
+			}
+		}
+
+	iAlarmList->Reset();
+	
+	CArrayFixFlat<TAgnSortInstance>* alarmedIds = new (ELeave) CArrayFixFlat<TAgnSortInstance>(2);
+	CleanupStack::PushL(alarmedIds);
+
+	iModel->NextAlarmForServerL(now, *alarmedIds);
+	QueueNextAlarmL(alarmedIds);
+	
+	CleanupStack::PopAndDestroy(alarmedIds);
+	}
+
+void CAgnAlarmActive::QueueNextAlarmL(CArrayFixFlat<TAgnSortInstance>* aAlarmedIds)
+// This function is only called by the server side since we want the alarm is queued in only server side
+	{
+	TTime now;
+	now.HomeTime();
+
+	// Certainly on WINS an alarm may expire a few seconds before it is due, the
+	// following ensures that the same alarm isn't queued twice
+	const TInt KAlarmCount = iAlarmList->Count();
+	if ( KAlarmCount )
+		{
+		TTime lastAlarm = (*iAlarmList)[KAlarmCount-1].iAlarmTime.LocalL();
+		
+		if ( now < lastAlarm )
+			{
+			now += TTimeIntervalSeconds(1);
+			}			
+		}
+
+	iAlarmList->Reset();
+	
+	for ( TInt ii = aAlarmedIds->Count() - 1; ii >= 0; --ii )
+		{
+		//create an alarmEntry
+		TAgnAlarmEntry alarmEntry;
+		
+		if (AssignToL(alarmEntry, (*aAlarmedIds)[ii]))
+			{
+			TKeyArrayFix key(_FOFF(TAgnAlarmEntry, iInstanceId), ECmpNormal8, sizeof(TAgnInstanceId));
+			iAlarmList->InsertIsqAllowDuplicatesL(alarmEntry, key);		
+			}
+		}
+
+	Cancel();
+	
+	if ( iAlarmList->Count() )
+	// Queue the first alarm in the alarm list
+		{
+		__ASSERT_DEBUG(IsAdded(), Panic(EAgmAgnAlarmActiveNotAdded));
+		iAlarmListIndex = 0;
+		const TAgnAlarmEntry& alarmEntry = (*iAlarmList)[0];
+
+		InitialiseAlarmL(iAlarm, alarmEntry, ETrue);
+
+		TAgnAlarmInfo alarmInfo;
+		GetAlarmInfoL(alarmEntry.iInstanceId, alarmInfo);
+
+		_DBGLOG_ALARM(AgmDebug::DebugLog("Queueing first alarm on list:");)
+		_DBGLOG_ALARM(AgmDebug::DebugLogAlarmL(alarmEntry);)
+
+		TPkgCAgnAlarmInfo pkgAgendaRef(alarmInfo);
+		SetActive();
+		iAlarmServer.AlarmAddWithNotification(iStatus, iAlarm, pkgAgendaRef);
+		
+		if ( iAlarm.Id() == KNullAlarmId )
+			{
+			User::Leave(KErrGeneral);
+			}
+		}
+	}
+
+void CAgnAlarmActive::InitialiseAlarmL(TASShdAlarm& aAlarm, const TAgnAlarmEntry& aEntryAlarm, TBool aIsSessionAlarm) 
+	{
+	aAlarm.Reset();
+	aAlarm.Message() = aEntryAlarm.iMessage;
+	aAlarm.Category() = KUidAgendaModelAlarmCategory;
+	aAlarm.SoundName() = aEntryAlarm.iSound;
+	aAlarm.DayOrTimed() = aEntryAlarm.iSessionType;
+
+	if (aEntryAlarm.iAlarmTime.TimeMode() == MAgnCalendarTimeMode::EFloating)
+		{
+		aAlarm.NextDueTime() = aEntryAlarm.iAlarmTime.LocalL();
+		}
+	else
+		{
+		aAlarm.SetUtcNextDueTime(aEntryAlarm.iAlarmTime.UtcL());
+		}
+
+	if ( aIsSessionAlarm )
+		{
+		aAlarm.Characteristics().Set(EAlarmCharacteristicsSessionSpecific);
+		}
+
+	if (!iQueueAlarmsInPast)
+		{
+		aAlarm.Characteristics().Set(EAlarmCharacteristicsDeQueueIfDueTimeInPast);
+		}
+	}
+
+void CAgnAlarmActive::FindAndQueueNextFewAlarmsL(const TInt aMaxNumberOfAlarms,const TInt aMaxNumberOfDays)
+	{
+	TTime now;
+	now.HomeTime();
+	
+	FindAndQueueNextFewAlarmsL(now,now+TTimeIntervalDays(aMaxNumberOfDays),aMaxNumberOfAlarms); 
+	}
+
+void CAgnAlarmActive::FindAndQueueNextFewAlarmsL(const TTime& aStartTime, const TTime& aEndTime, const TInt aMaxNumberOfAlarms)
+//
+// Find the next due alarm(s) and if at least one exists then queue it with the alarm server
+//
+	{
+	TTime currTime = aStartTime;
+
+	CArrayFixFlat<TAgnAlarmEntry>* alarmList = new (ELeave) CArrayFixFlat<TAgnAlarmEntry>(10);
+	CleanupStack::PushL(alarmList);
+	
+	// Certainly on WINS an alarm may expire a few seconds before it is due, the
+	// following ensures that the same alarm isn't queued twice
+	if ( iAlarmList->Count() )
+		{
+		TTime lastAlarm = ((*iAlarmList)[0]).iAlarmTime.LocalL();
+		
+		if ( currTime < lastAlarm )
+			{
+			currTime += TTimeIntervalSeconds(1);
+			}			
+		}
+
+	CArrayFixFlat<TAgnSortInstance>* alarmedIds = new(ELeave) CArrayFixFlat<TAgnSortInstance>(10);
+	CleanupStack::PushL(alarmedIds);
+
+	iModel->NextFewAlarmsForServerL(currTime, aEndTime, *alarmedIds, aMaxNumberOfAlarms);
+	
+	const TInt KAlarmedIdsCount = alarmedIds->Count();
+	
+	for ( TInt ii = 0; ii < KAlarmedIdsCount; ++ii )
+		{
+		//create an alarmEntry
+		TAgnAlarmEntry alarmEntry;
+		
+		if (AssignToL(alarmEntry, (*alarmedIds)[ii]))
+			{
+			TKeyArrayFix key(_FOFF(TAgnAlarmEntry, iAlarmTime), ECmpTInt64);//order by alarm time
+			alarmList->InsertIsqAllowDuplicatesL(alarmEntry, key);
+			}
+		}
+		
+	CleanupStack::PopAndDestroy(alarmedIds);
+
+	Cancel();
+
+	if(iStatus != KErrLocked)
+		{
+		TASShdAlarm alarm;
+		const TInt KCount = alarmList->Count();
+		for( TInt ii = 0; ii < KCount; ++ii )
+			{
+			const TAgnAlarmEntry& alarmEntry = (*alarmList)[ii];
+
+			InitialiseAlarmL(alarm, alarmEntry, EFalse);
+			
+			TAgnAlarmInfo alarmInfo;
+			GetAlarmInfoL(alarmEntry.iInstanceId, alarmInfo);
+			TPkgCAgnAlarmInfo pkgAgendaRef(alarmInfo);
+
+			_DBGLOG_ALARM(	AgmDebug::DebugLog("Queueing first alarm on list:");)
+			_DBGLOG_ALARM(AgmDebug::DebugLogAlarmL(alarmEntry);)
+
+			iAlarmServer.AlarmAdd(alarm, pkgAgendaRef);
+			}
+		}
+		
+	CleanupStack::PopAndDestroy(alarmList);
+	}
+
+// Get the TAgnAlarmEntry struct for the current entry or return NULL if not available
+const TAgnAlarmEntry* CAgnAlarmActive::CurrentAlarmEntry() const
+	{
+	if ( iAlarmList&&iAlarmList->Count() > 0 )
+		{
+		return ( &((*iAlarmList)[iAlarmListIndex]) );
+		}
+				
+	return ( NULL );
+	}
+ 
+void CAgnAlarmActive::DoCancel()
+//
+// Cancel the alarm
+//
+// DoCancel only gets called from Cancel(). It will only be called if the object is active - which means that
+// there should therefore be an alarm to cancel.
+	{
+	const TAlarmId KId = iAlarm.Id();
+	if ( KId != KNullAlarmId )
+		{
+		iAlarmServer.AlarmNotificationCancelAndDequeue(KId); // resulting signal is picked up in Cancel()
+		}
+	}
+
+void CAgnAlarmActive::GetAlarmInfoL(const TAgnInstanceId& aInstanceId, TAgnAlarmInfo& aAlarmInfo) const
+	{
+	aAlarmInfo.iEntryId = aInstanceId;
+	
+	aAlarmInfo.iTimeMode = aInstanceId.Date().TimeMode();
+	
+	if(aAlarmInfo.iTimeMode==MAgnCalendarTimeMode::EFloating)
+		{
+		aAlarmInfo.iInstanceTime = aInstanceId.Date().LocalL();
+		}
+	else
+		{
+		aAlarmInfo.iInstanceTime = aInstanceId.Date().UtcL();
+		}
+
+	aAlarmInfo.iAlarmCategory = KUidAgendaModelAlarmCategory;
+ 
+ 	//Remove path from the filename, leave only Drive:Filename.ext
+	TParsePtrC parser(iModel->FileName());
+	aAlarmInfo.iFileName = parser.Drive();
+	aAlarmInfo.iFileName.Append(parser.NameAndExt());
+
+	CAgnEntry* entry = iModel->FetchEntryL(aInstanceId);
+	__ASSERT_ALWAYS(entry, User::Leave(KErrNotFound)); // alarm has expired for entry which cannot be found or has been deleted
+
+	CleanupStack::PushL(entry);
+	
+	aAlarmInfo.iAgnUniqueId = entry->LocalUid();
+	
+	if(aInstanceId.Date().TimeMode()==MAgnCalendarTimeMode::EFloating)
+		{
+		aAlarmInfo.iRecurrenceId = entry->RecurrenceId().LocalL();
+		}
+	else
+		{
+		aAlarmInfo.iRecurrenceId = entry->RecurrenceId().UtcL();
+		}
+	aAlarmInfo.iGlobalIdentifier = iModel->GetEntryGuidL(*entry);
+	CleanupStack::PopAndDestroy(entry);
+	}
+	
+void CAgnAlarmActive::SetQueueAlarmsInPast(TBool aQueueAlarmsInPast)
+	{
+	iQueueAlarmsInPast = aQueueAlarmsInPast;	
+	}
+
+const CAgnServFile& CAgnAlarmActive::AgnServFile()
+    {
+    return iModel->AgnServFile();
+    }
+
+CAgnAlarmServerChangeObserver* CAgnAlarmServerChangeObserver::NewL(MAgnAlarmServerTerminationCallBack* aCallBack, CAgnAlarm* aOwningObject)
+//
+// Create a CAgnAlarmServerChangeObserver object
+//
+	{
+	CAgnAlarmServerChangeObserver* self = new(ELeave) CAgnAlarmServerChangeObserver(aCallBack, aOwningObject);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return (self);
+	}
+
+CAgnAlarmServerChangeObserver::CAgnAlarmServerChangeObserver(MAgnAlarmServerTerminationCallBack* aCallBack, CAgnAlarm* aOwningObject)
+//
+// C'tor
+//
+	:iCallBack(aCallBack), iOwningObject(aOwningObject)
+	{
+	}
+	
+void CAgnAlarmServerChangeObserver::ConstructL()
+	{
+	iTimeZoneConvertor = CAgnTlsProxy::CreateL(CAgnTlsProxy::TAgnTlsTzRulesType_Server);
+	}
+
+
+CAgnAlarmServerChangeObserver::~CAgnAlarmServerChangeObserver()
+//
+// D'tor
+//
+	{
+	delete iSystemId;
+	CAgnTlsProxy::Release(iTimeZoneConvertor);
+	}
+
+/**
+Filter notifications from the alarm server, if KErrServerTerminated is received then
+call the callback function
+*/
+void CAgnAlarmServerChangeObserver::HandleAlarmServerChangeL(TInt aChange)
+	{
+
+	if ( aChange == KErrServerTerminated )
+		{
+		if ( iCallBack )
+			{
+			iCallBack->AlarmServerTerminated();
+			}			
+		else if ( iUserRequestStatus )
+			{
+			User::RequestComplete(iUserRequestStatus,KErrServerTerminated);
+			iUserRequestStatus = NULL;
+			}
+		}
+	else // iStatus != KErrServerTerminated
+		{
+		if (aChange == EAlarmChangeEventSystemDateTimeChanged)
+			{
+			CTzId* newSysTime=iTimeZoneConvertor->TzServer().GetTimeZoneIdL();
+			if( iSystemId && (*iSystemId==*newSysTime) )//when locale changes, we will receive notification twice but we only act once.
+				{
+				delete newSysTime;
+				}
+			else
+				{
+				delete iSystemId;
+				iSystemId=newSysTime;
+				}
+				
+			const TAgnAlarmEntry* alarmEntry = iOwningObject->AlarmEntry();
+			TTime queuedEntryTime;
+
+			// INC045770: Alarms less than X days old should fire when the system time is put forward.
+			if ( alarmEntry && iOwningObject->QueueAlarmsInPast())
+				{
+				// Get the time of the currently scheduled alarm (serves as the old system time for our purposes.)
+				queuedEntryTime=alarmEntry->iAlarmTime.LocalL();
+				// sub 1st sec: FindAndQueue* adds 1 second to prevent scheduling an alarm twice.
+				// sub 2nd sec: Our sess alarm that has been cancelled needs to be aged 1 sec to get queued.
+				queuedEntryTime-=TTimeIntervalSeconds(2);  
+		
+				TTime now;
+				now.HomeTime();
+				TTimeIntervalDays delta = now.DaysFrom(queuedEntryTime);
+
+				// clock set forward X days or more after the session alarm; schedule all alarms within X days of the curr time.
+				if (delta >= TTimeIntervalDays(KSystemTimeChangeMaxDaysOld))
+					iOwningObject->FindAndQueueNextFewAlarmsL(now-TTimeIntervalDays(KSystemTimeChangeMaxDaysOld),now,KSystemTimeChangeMaxAlarmsQueued);
+				// clock set forward less than X days after sesion alarm, schedule all alarms between session alarm time and curr time
+				else if (delta >= TTimeIntervalDays(0))
+					iOwningObject->FindAndQueueNextFewAlarmsL(queuedEntryTime,now,KSystemTimeChangeMaxAlarmsQueued);				
+				// else system time has been put backwards (normal code path can handle this case)
+				}
+			// *always* schedule a session alarm when the time changes
+			iOwningObject->FindAndQueueNextAlarmL(ETrue);			
+			}
+		else if (aChange == EAlarmChangeEventRestoreCompleted ||
+                    aChange == EAlarmChangeEventRestoreFailed)
+		    {
+		    // The restore has finished so try to find and queue the next few alarms
+		    if (!iOwningObject->AgnServFile().IsLocked()
+                    && !iOwningObject->AgnServFile().IsBackupRestoreLock())
+                {
+                iOwningObject->FindAndQueueNextAlarmL(EFalse);
+                }		   
+		    }
+		}
+	}
+