pimappservices/calendarvcalplugin/src/agmvcalx.cpp
changeset 0 f979ecb2b13e
child 18 c198609911f9
child 65 12af337248b1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappservices/calendarvcalplugin/src/agmvcalx.cpp	Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,1682 @@
+// 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 <s32mem.h>
+#include <vtzrules.h>
+#include <utf.h>
+#include <tz.h>
+
+#include <calentry.h>
+#include <calcontent.h>
+#include <calrrule.h>
+#include <caluser.h>
+#include <calalarm.h>
+#include <calattachment.h>
+
+#include "agmvcal.h"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <vpropbinaryfile.h>
+#endif
+
+
+/** Specifies number of years backward from current year for which DAYLIGHT properties are exported.*/
+const TInt KDaylightPropertyYearsBackwards(2);
+
+/** Specifies number of years forward from current year, or the repeat start year, for which DAYLIGHT properties are exported.*/
+const TInt KDaylightPropertyYearsForwards(5);
+
+
+// Utility method to ensure proper cleanup in OOM 
+//
+void CAgendaEntryToVCalConverter::ResetAndDestroyArrayOfParams(TAny* aObject)
+	{
+	CArrayPtr<CParserParam>* array=reinterpret_cast<CArrayPtr<CParserParam>*>(aObject);
+	if (array)
+		{
+		array->ResetAndDestroy();
+		}
+	delete array;
+	}
+
+void CAgendaEntryToVCalConverter::ResetAndDestroyArrayOfVersitDateTime(TAny* aObject)
+	{
+	CArrayPtr<TVersitDateTime>* array=reinterpret_cast<CArrayPtr<TVersitDateTime>*>(aObject);
+	if (array)
+		{
+		array->ResetAndDestroy();
+		}
+	delete array;
+	}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *	Public
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Export agenda entry aEntry to the given parser
+//
+void CAgendaEntryToVCalConverter::ExportEntryL(CCalEntry* aEntry, CVersitParser& aParser)
+	{
+	CParserVCalEntity* entity = CParserVCalEntity::NewL();
+	CleanupStack::PushL(entity);
+
+	if (aEntry->EntryTypeL() == CCalEntry::ETodo)
+		{
+		entity->SetEntityNameL(KVersitVarTokenVTODO);
+		}
+	else
+		{
+		entity->SetEntityNameL(KVersitVarTokenVEVENT);
+		}
+
+	if ((aEntry->StartTimeL()).TimeMode() == TCalTime::EFloating)
+		{
+		iTimeType = TVersitDateTime::EIsMachineLocal;
+		iTimeFlag = TVersitDateTime::EExportLeaveAsLocalTime;
+		}
+	else 
+		{
+		iTimeType=TVersitDateTime::EIsUTC;
+		iTimeFlag=TVersitDateTime::EExportTimeZoneDesignator;
+		}
+
+	AddEntryPropertiesL(aEntry, *entity);
+	CleanupStack::Pop(); // entity
+	aParser.AddEntityL(entity); // takes ownership
+	}
+
+CAgendaEntryToVCalConverter::~CAgendaEntryToVCalConverter()
+	{
+	}
+	
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *	Private
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+	
+/** AddTzPropertyL()
+ *
+ *	Adds TZ property to aParser.
+ *
+ *	@param aParser		- a vCal entity or sub-entity (VEVENT or VTODO);
+ *	@param aStdOffset	- standard time zone offset from UTC in seconds.
+ */
+void CAgendaEntryToVCalConverter::AddTzPropertyL(CVersitParser& aParser, 
+												 TTimeIntervalSeconds aStdOffsetInSeconds)
+	{
+	if (!iAddedTzProperty)
+		{
+		CParserPropertyValue* vValue = new (ELeave) CParserPropertyValueTimeZone(aStdOffsetInSeconds);
+		CleanupStack::PushL(vValue);
+
+		CParserProperty* vProp = CParserProperty::NewL(*vValue, KVersitTokenTZ, NULL); 
+		CleanupStack::Pop(vValue);
+
+		aParser.AddPropertyL(vProp);
+		}
+	iAddedTzProperty = ETrue;
+	}
+
+
+/** MapToRelativeTime()
+ *
+ *	Provides mapping between iTimeReference of TVTzActualisedRule and iRelativeTime of TVersitDateTime. 
+ *
+ *	CTzRules::AddActualisedRulesL() guarantees that TVTzActualisedRule is always UTC or 
+ *	local(ETzWallTimeReference), and is never STD. The func maps everything to 
+ *	TVersitDateTime::EIsMachineLocal, unless iTimeReference is ETzUtcTimeReference, which is mapped
+ *  to TVersitDateTime::EIsUTC.
+ *
+ *	This is local helper function.
+ *	Used exclusively by CAgendaEntryToVCalConverter::AddTimeZonePropertiesL() to export DAYLIGHT properties.
+ */
+static inline TVersitDateTime::TRelativeTime MapToRelativeTime(TTzTimeReference& aTzTimeRef)
+	{
+	return (aTzTimeRef==ETzUtcTimeReference) ? (TVersitDateTime::EIsUTC) : (TVersitDateTime::EIsMachineLocal);
+	}
+
+/*	AddDaylightPropertyL()
+ *
+ *	Export a DAYLIGHT property to describe the daylight saving period and its offset.
+ *	There can be more than one DAYLIGHT property for a year (depenging on number of DST rules for the year).  
+ *	Time designators (i.e EST, EDT) are not exported.
+ *
+ *	@param aParser		- a vCal entity or sub-entity (VEVENT or VTODO);
+ *	@param aOffsetInSeconds	 - offset in seconds from UTC (i.e. STD + DST) for the period when the 
+ 					 	  daylight saving rule is in effect, 
+ 						  for instance, for time zone "Vancouver/America (PST)" aOffsetInSeconds is
+ 						  -480*60=-28800 secs in winter time, and -420*60=-25200 secs when DST is observed; 
+ *	@param aStartTime	- exact time when a rule starts (usually 02:00:00 local time);
+ *	@param aEndTime		- time when rule ends (usually 03:00:00 local time).
+ */
+void CAgendaEntryToVCalConverter::AddDaylightPropertyL(CVersitParser& aParser, 
+													   TTimeIntervalSeconds aOffsetInSeconds,
+													   TTimeWithReference aStartTime,
+													   TTimeWithReference aEndTime)
+	{
+	TVersitDateTime* vStartTime = new(ELeave) TVersitDateTime(aStartTime.iTime.DateTime(),
+															  MapToRelativeTime(aStartTime.iTimeReference));
+	CleanupStack::PushL(vStartTime);
+
+	TVersitDateTime* vEndTime = new (ELeave) TVersitDateTime(aEndTime.iTime.DateTime(),
+															  MapToRelativeTime(aEndTime.iTimeReference));
+	CleanupStack::PushL(vEndTime);
+
+	CVersitDaylight* vDaylight = CVersitDaylight::NewL(ETrue, 
+													  aOffsetInSeconds, 
+													  vStartTime, 
+													  vEndTime, 
+													  KNullDesC(), 
+													  KNullDesC());
+	
+	CleanupStack::Pop(vEndTime);   // CVersitDaylight takes ownership.
+	CleanupStack::Pop(vStartTime); // CVersitDaylight takes ownership.
+
+	CleanupStack::PushL(vDaylight);
+	CParserPropertyValue* vValue = new (ELeave) CParserPropertyValueDaylight(vDaylight);
+	CleanupStack::Pop(vDaylight);
+
+	CleanupStack::PushL(vValue);
+	CParserProperty* vProp = CParserProperty::NewL(*vValue, KVersitTokenDAYLIGHT, NULL); 
+	CleanupStack::Pop(vValue);
+
+	aParser.AddPropertyL(vProp);
+	}
+
+
+/**	Adds DAYLIGHT properties for a range of years from aStartYear to aEndYear inclusive to 
+ *	a vCalendar entity (aParser).
+ *	
+ *	@param aParser		- a vCalendar object where properties added
+ *	@param aRules		- time zone rules used to retrieve DST information
+ *	@param aRepeatStartTime		- start of entry range, including the repeat rule
+ *	@param aRepeatEndTime		- end of entry range, including the repeat rule
+ *
+ */
+void CAgendaEntryToVCalConverter::AddDaylightPropertiesL(CVersitParser& aParser, const CTzRules* aRules, TInt aStdOffset, TTime aRepeatStartTime, TTime aRepeatEndTime)
+	{
+	const TInt KRepeatStartYear = aRepeatStartTime.DateTime().Year();
+	const TInt KRepeatEndYear = aRepeatEndTime.DateTime().Year();
+	
+ 	// actualise the rules starting a year before our period of interest
+	CVTzActualisedRules* actRules = CVTzActualisedRules::NewL(KRepeatStartYear - 1, KRepeatEndYear + 1);
+	
+	if (actRules)
+		{
+		CleanupStack::PushL(actRules);
+		aRules->GetActualisedRulesL(*actRules);
+		
+		TTime now;
+		now.HomeTime();
+		const TInt KThisYear = now.DateTime().Year();
+		
+		// Set up the time range for exported DAYLIGHT properties
+		const TInt KRangeBeginYear(Max(KThisYear - KDaylightPropertyYearsBackwards, KRepeatStartYear));
+		const TInt KRangeEndYear(Min(Max(KThisYear + KDaylightPropertyYearsForwards, KRepeatStartYear + KDaylightPropertyYearsForwards), KRepeatEndYear + 1));
+		const TTime KRangeBeginTime(TDateTime(KRangeBeginYear, EJanuary, 0, 0, 0, 0, 0));
+		const TTime KRangeEndTime(TDateTime(KRangeEndYear, EJanuary, 0, 0, 0, 0, 0));
+		
+		const TInt KRulesCount(actRules->Count());
+		for (TInt i(0) ; i < KRulesCount - 1 ; ++i)
+			{
+			TVTzActualisedRule& actRule = (*actRules)[i];
+			
+			if (aStdOffset < actRule.iNewOffset)		// work with DST rules only
+				{
+				// End time of a rule is start time of the next rule
+				TVTzActualisedRule& actRuleNext = (*actRules)[i+1];
+				
+				TTimeWithReference ruleStart(TTimeWithReference(actRule.iTimeOfChange, actRule.iTimeReference));
+				TTimeWithReference ruleEnd(TTimeWithReference(actRuleNext.iTimeOfChange, actRuleNext.iTimeReference));
+				
+				TTime ruleStartTime = ruleStart.iTime;
+				TTime ruleEndTime = ruleEnd.iTime;
+				
+				if (actRule.iTimeReference == ETzStdTimeReference)
+					{
+					ruleStartTime -= TTimeIntervalMinutes(aRules->InitialStdTimeOffset());
+					}
+				else if (actRule.iTimeReference == ETzWallTimeReference)
+					{
+					ruleStartTime -= TTimeIntervalMinutes(actRule.iNewOffset);
+					}						
+
+				if (actRule.iTimeReference == ETzStdTimeReference)
+					{
+					ruleEndTime -= TTimeIntervalMinutes(aRules->InitialStdTimeOffset());
+					}
+				else if (actRule.iTimeReference == ETzWallTimeReference)
+					{
+					ruleEndTime -= TTimeIntervalMinutes(actRule.iNewOffset);
+					}	
+				
+				// Export rule if the first instance occours when dst is on
+				// or if the rule covers the range defined above
+				if ( (aRepeatStartTime >= ruleStartTime) && (aRepeatStartTime <= ruleEndTime) || (ruleEndTime >= KRangeBeginTime) && (ruleStartTime <= KRangeEndTime) )
+					{
+					// Export DAYLIGHT property for concrete DST rule
+					AddDaylightPropertyL(aParser, actRule.iNewOffset * 60, ruleStart, ruleEnd);
+					}
+				}
+			}
+		CleanupStack::PopAndDestroy(actRules);
+		}
+	}
+
+void CAgendaEntryToVCalConverter::NextVCalendarL()
+	{
+	iAddedTzProperty = EFalse;
+	}
+
+/**	CAgendaEntryToVCalConverter::AddTimeZonePropertiesL()
+ *	 	
+ *	Adds TZ and DAYLIGHT properties to a vCalendar entity. 
+ *
+ *	@param aEntry 	- an agenda entry which supplies timezone and tz rules information 
+ *						(has to have a repeat definition, otherwise function will do nothing);
+ *	@param aParser	- a vCalendar object to which the properties are added. 
+ *	
+ *	aParser can be 1) a vCalendar object (also referrred to as "vCalendar entity"), 
+ *		as well as 2) a vEvent or vTodo objects (also referred to as "vCalendar sub-entities").
+ *	
+ *	TZ and DAYLIGHT properties (as per vCalendar v1.0 spec) apply to the vCalendar object as a whole; UNLESS 
+ *	overriden by a property within the scope of an event or todo entity.
+ *	
+ *	@internalComponent
+ */
+void CAgendaEntryToVCalConverter::AddTimeZonePropertiesL(CVersitParser& aParser, CCalEntry* aEntry)
+	{
+	TCalRRule rrule;
+	
+  	if (aEntry->GetRRuleL(rrule) && aEntry->StartTimeL().TimeMode() != TCalTime::EFloating)
+		{
+		// Only export the TZ property when the entry is repeating.
+		// Do not export TZ rules for floating entry.
+		CTzRules* rules = aEntry->TzRulesL();
+		
+		if (rules)
+			{
+    		CleanupStack::PushL( rules );
+
+            // find the standard offset for this time zone
+            // which is the lowest offset from the rules for the entry's repeat range
+            CVTzActualisedRules* actRules = CVTzActualisedRules::NewL(rrule.DtStart().TimeUtcL().DateTime().Year() - 1, rrule.Until().TimeUtcL().DateTime().Year() + 1);
+        	CleanupStack::PushL(actRules);
+        	rules->GetActualisedRulesL(*actRules);
+        	
+        	TInt stdOffset(KMaxTInt);
+        	
+        	const TInt KRulesCount = actRules->Count();
+        	for (TInt i(0) ; i < KRulesCount ; ++i)
+        		{
+        		if ((*actRules)[i].iNewOffset < stdOffset)
+        			{
+        			stdOffset = (*actRules)[i].iNewOffset;
+        			}
+        		}
+        	
+        	if (stdOffset == KMaxTInt)
+        		{
+        		// there were no offsets found so use the current system utc offset
+        		stdOffset = (User::UTCOffset().Int() / 60);
+        		}
+        	
+        	CleanupStack::PopAndDestroy(actRules);
+			AddTzPropertyL(aParser, stdOffset * 60);
+			AddDaylightPropertiesL(aParser, rules, stdOffset, rrule.DtStart().TimeUtcL(), rrule.Until().TimeUtcL());
+            
+			CleanupStack::PopAndDestroy(rules);	
+			}
+		}
+	}
+
+// This function specifies the ordering of the vCalendar properties as exported by Versit.
+//
+// The UID property should be the first property. 
+//
+// The following three properties of a vCalendar should be DESCRIPTION, DTSTART and DTEND for appointments, 
+// anniversaries & events. To-do entries should have DESCRIPTION and DUE as the following two properties.
+// This is to assist processing by Connectivity (as requested by Time Technology)
+//
+void CAgendaEntryToVCalConverter::AddEntryPropertiesL(CCalEntry* aEntry, CVersitParser& aParser)
+	{
+	// UID 
+
+	HBufC* guid16 = HBufC::NewLC(aEntry->UidL().Length());
+	TPtr ptr16 = guid16->Des();
+	CnvUtfConverter::ConvertToUnicodeFromUtf8(ptr16, aEntry->UidL());
+	AddDesPropertyL(aParser, KVersitTokenUID, guid16->Des());
+	CleanupStack::PopAndDestroy(guid16);
+		
+	// CAgnEntry::RichTextL()	=> SUMMARY 
+	// CAgnEntry::NotesTextL()	=> DESCRIPTION 
+
+	if (aEntry->DescriptionL().Length() > 0)
+		{
+		AddDesPropertyL(aParser, KVersitTokenDESCRIPTION, aEntry->DescriptionL());					
+		}
+		
+	if (aEntry->SummaryL().Length() > 0)
+		{
+		AddDesPropertyL(aParser, KVersitTokenSUMMARY, aEntry->SummaryL());
+		}
+
+	// Add DTSTART and DTEND (or DUE, PRIORITY and todo list information for to-do items), then add X-EPOCAGENDAENTRYTYPE
+	switch (aEntry->EntryTypeL())
+		{
+		case CCalEntry::EAppt:
+			{
+			AddEventPropertiesL(aParser, aEntry);
+			AddDesPropertyL(aParser, KVCalToken8ENTRYTYPE, KVCalTokenTypeAPPT);	
+			break;
+			}
+		case CCalEntry::EReminder:
+			{
+			AddEventPropertiesL(aParser, aEntry);
+			AddDesPropertyL(aParser, KVCalToken8ENTRYTYPE, KVCalTokenTypeREMINDER);	
+			break;
+			}
+		case CCalEntry::EAnniv:
+			{
+			AddEventPropertiesL(aParser, aEntry);
+			AddDesPropertyL(aParser, KVCalToken8ENTRYTYPE, KVCalTokenTypeANNIV);
+			break;
+			}
+		case CCalEntry::EEvent:
+			{
+			AddEventPropertiesL(aParser, aEntry);
+			AddDesPropertyL(aParser, KVCalToken8ENTRYTYPE, KVCalTokenTypeEVENT);
+			break;
+			}
+		case CCalEntry::ETodo:
+			{
+			AddTodoPropertiesL(aParser, aEntry);
+			AddDesPropertyL(aParser, KVCalToken8ENTRYTYPE, KVCalTokenTypeTODO);
+			break;
+			}
+		default: break;
+		}
+
+	// Class
+	CCalEntry::TReplicationStatus status = aEntry->ReplicationStatusL();
+	switch(status)
+		{
+		case CCalEntry::EOpen:
+			AddDesPropertyL(aParser, KVersitTokenCLASS, KVCalTokenPUBLIC);
+			break;
+		case CCalEntry::EPrivate:
+			AddDesPropertyL(aParser, KVersitTokenCLASS, KVCalTokenPRIVATE);
+			break;
+		case CCalEntry::ERestricted:
+			AddDesPropertyL(aParser, KVersitTokenCLASS, KVCalTokenCONFIDENTIAL);
+			break;
+		}
+
+	// Location
+	const TDesC& location = aEntry->LocationL();
+	if (location.Length() != 0)
+		{
+		AddDesPropertyL(aParser, KVersitTokenLOCATION, location);
+		}
+
+	// DTSTAMP
+	TCalTime dTStamp = aEntry->DTStampL();
+		
+   	if ( dTStamp.TimeUtcL() != Time::NullTTime() )
+      	{	
+		AddDateTimePropertyL(aParser, KVersitTokenXDTSTAMP, dTStamp.TimeUtcL(), TVersitDateTime::EIsUTC, iTimeFlag);
+      	}
+	
+	// Sequence Number
+	AddIntegerPropertyL(aParser, KVersitTokenSEQUENCE, aEntry->SequenceNumberL());
+
+	//X-Method property
+	CCalEntry::TMethod methodStatus = aEntry->MethodL();
+	TPtrC methodStr;
+	switch(methodStatus)
+		{
+		case  CCalEntry::EMethodNone:
+			methodStr.Set(KVCalTokenMethodStatusENone);
+			break;
+		case CCalEntry::EMethodPublish:
+			methodStr.Set(KVCalTokenMethodStatusEPublish);
+			break;
+		case CCalEntry::EMethodRequest:
+			methodStr.Set(KVCalTokenMethodStatusERequest);
+			break;
+		case CCalEntry::EMethodReply:
+			methodStr.Set(KVCalTokenMethodStatusEReply);
+			break;
+		case CCalEntry::EMethodAdd:
+			methodStr.Set(KVCalTokenMethodStatusEAdd);
+			break;
+		case CCalEntry::EMethodCancel:
+			methodStr.Set(KVCalTokenMethodStatusECancel);
+			break;
+		case CCalEntry::EMethodRefresh:
+			methodStr.Set(KVCalTokenMethodStatusERefresh);
+			break;
+		case CCalEntry::EMethodCounter:
+			methodStr.Set(KVCalTokenMethodStatusECounter);
+			break;
+		case CCalEntry::EMethodDeclineCounter:
+			methodStr.Set(KVCalTokenMethodStatusEDeclineCounter);
+			break;	
+		default:
+			User::Leave(KErrArgument);	
+		}
+
+	AddDesPropertyL(aParser, KVersitTokenXMETHOD, methodStr);
+	// X-Recurrence-ID
+	TCalTime recurrenceDate = aEntry->RecurrenceIdL();
+	
+	if (recurrenceDate.TimeUtcL() != Time::NullTTime())
+		{
+		TTime recId;
+		if(iTimeType==TVersitDateTime::EIsUTC)
+			{
+			recId = recurrenceDate.TimeUtcL();
+			}
+		else
+			{
+			recId = recurrenceDate.TimeLocalL();
+			}
+		AddDateTimePropertyL(aParser, KVersitTokenXRECURRENCEID, recId, iTimeType, iTimeFlag);	
+		}
+		
+	// Attendees
+	RPointerArray<CCalAttendee> attendees = aEntry->AttendeesL();
+
+	TInt count=attendees.Count();
+	CCalUser* phoneowner=aEntry->PhoneOwnerL();
+	for (TInt ii=0; ii<count; ii++)
+		{
+		if(phoneowner==attendees[ii])
+			{
+			AddAttendeePropertyL(aParser, attendees[ii],ETrue, EFalse);
+			}
+		else
+			{
+			AddAttendeePropertyL(aParser, attendees[ii],EFalse, EFalse);
+			}
+		
+		}
+
+	CCalUser* organizer=aEntry->OrganizerL();
+	if(organizer)
+		{
+		if(phoneowner==organizer)
+			{
+			AddAttendeePropertyL(aParser, organizer,ETrue, ETrue);
+			}
+		else
+			{
+			AddAttendeePropertyL(aParser, organizer,EFalse, ETrue);
+			}
+		}
+
+	// Recurrence details
+	TCalRRule rule;
+	TBool isrepeat = aEntry->GetRRuleL(rule);
+	if (isrepeat)
+		{
+		CTzRules* repeatRule = aEntry->TzRulesL();
+		CleanupStack::PushL(repeatRule);
+		AddRepeatPropertiesL(aParser, rule, repeatRule);
+		CleanupStack::PopAndDestroy(repeatRule);
+		}
+		
+	// RDates
+	RArray<TCalTime>rdates;
+	CleanupClosePushL(rdates);
+	aEntry->GetRDatesL(rdates);
+
+	if (rdates.Count()>0)
+		{
+		AddRDatePropertyL(aParser, rdates);
+		isrepeat = ETrue;
+		}
+		
+	CleanupStack::PopAndDestroy(&rdates);
+
+	if (isrepeat)
+		{
+		// Recurrence Exception details
+		RArray<TCalTime> exceptions;
+		CleanupClosePushL(exceptions);
+		aEntry->GetExceptionDatesL(exceptions);
+
+		if (exceptions.Count()>0)
+			{
+			AddRepeatExceptionPropertiesL(aParser, exceptions);
+			}
+		CleanupStack::PopAndDestroy(&exceptions);
+		}
+		
+	// Alarm
+	CCalAlarm* alarm = aEntry->AlarmL();
+	if (alarm)
+		{
+		TCalTime alarmOrigin;
+		CleanupStack::PushL(alarm);
+		if(aEntry->EntryTypeL()==CCalEntry::ETodo && (aEntry->EndTimeL()).TimeUtcL()!=Time::NullTTime())
+			{
+			alarmOrigin = aEntry->EndTimeL();
+			}
+		else
+			{
+			alarmOrigin = aEntry->StartTimeL();
+			}
+		
+		TTime alarmtime;
+		if (aEntry->StartTimeL().TimeMode() != TCalTime::EFloating)
+			{
+			alarmtime = alarmOrigin.TimeUtcL() - TTimeIntervalMinutes(alarm->TimeOffset());
+			}
+		else
+			{
+			alarmtime = alarmOrigin.TimeLocalL() - TTimeIntervalMinutes(alarm->TimeOffset());
+			}
+		AddAlarmPropertyL(aParser, KVersitTokenAALARM, alarmtime, alarm->AlarmSoundNameL());
+		
+
+		CCalContent* alarmAction = alarm->AlarmAction();
+		if (alarmAction != NULL)
+			{
+			AddExtendedAlarmPropertyL(aParser, KVersitTokenXALARM, *alarmAction);
+			}
+		CleanupStack::PopAndDestroy(alarm);
+		}
+
+	// Add Last Changed Date
+	AddDateTimePropertyL(aParser, KVersitTokenLASTMODIFIED, (aEntry->LastModifiedDateL()).TimeUtcL(), TVersitDateTime::EIsUTC, iTimeFlag);
+
+	// Category Support
+	const RPointerArray<CCalCategory>& categories = aEntry->CategoryListL();
+
+	if (categories.Count()>0)
+		{
+		AddCategoryPropertyL(aParser, categories);
+		}
+
+	// ADDITION FOR VERSIT COMPLIANCE 
+	// Merged priorities into one place - ToDo priority was previously in AddTodoPropertiesL()
+	TInt priority = aEntry->PriorityL();
+	AddIntegerPropertyL(aParser, KVersitTokenPRIORITY, priority);
+	if (aEntry->EntryTypeL() != CCalEntry::ETodo)
+		{
+		AddStatusPropertyL(aParser, aEntry);
+		}
+	AddIntegerPropertyL(aParser, KVersitTokenXLOCALUID, aEntry->LocalUidL());
+	AddIntegerPropertyL(aParser, KVersitTokenTRANSP, aEntry->TimeTransparencyL());
+	
+	// Add GEO
+	CCalGeoValue* geoValue = aEntry->GeoValueL();
+	
+	// Check that the GEO values are not NULL
+	if(geoValue)
+		{
+		CleanupStack::PushL(geoValue);
+		
+		TReal geoLatitude;
+		TReal geoLongitude;
+		
+		// Extract latitude and longitude values
+		// Check if it returns EFalse
+		geoValue->GetLatLong(geoLatitude,geoLongitude);
+		
+		// Convert the geo values from numbers to string
+		// Create GEO string buffer to be constructed from a latitude, delimiter and a longitude value
+		TBuf<KGEOMaxWidthOfGeoValue*2+1> geoString;
+		TBuf<KGEOMaxWidthOfGeoValue> geoLatString;
+		TBuf<KGEOMaxWidthOfGeoValue> geoLongString;
+		
+		// Maximum width of a GEO value and max number of decimal places
+		TRealFormat geoFormat(KGEOMaxWidthOfGeoValue,KCalGEOMaxDecimalPlaces);
+		
+		_LIT(KGeoStringFormat,"%S%c%S");
+		
+		// Ensure correct conversion from stored numeric values to descriptors
+		if((geoLatString.Num(geoLatitude,geoFormat)>0) && (geoLongString.Num(geoLongitude,geoFormat)>0))
+			{
+			geoString.AppendFormat(KGeoStringFormat,&geoLatString,KVersitTokenCommaVal,&geoLongString);
+			
+			// Add the GEO property
+			AddDesPropertyL(aParser,KVersitTokenGEO,geoString);
+			}
+		
+		CleanupStack::PopAndDestroy(geoValue);
+		}
+		
+	TUint attachCount = aEntry->AttachmentCountL();
+	for(TInt ii = 0; ii<attachCount; ++ii)
+		{
+		CCalAttachment* attach = aEntry->AttachmentL(ii);
+		AddAttachmentPropertyL(aParser, *attach);
+		}
+	}
+
+
+// Add appointment properties to parser
+//
+void CAgendaEntryToVCalConverter::AddEventPropertiesL(CVersitParser& aParser, CCalEntry* aEntry)
+	{
+	//If this is an untimed appt the start time will be the default start time
+ 	//If the alarm time is *after* this time we need to move the start time to the alarm time
+	TTime startTime; 
+	TTime endTime; 
+	if((aEntry->StartTimeL()).TimeMode() == TCalTime::EFloating )
+		{
+		startTime = (aEntry->StartTimeL()).TimeLocalL();
+		if(aEntry->EntryTypeL()==CCalEntry::EReminder)
+			{
+			endTime = startTime;
+			}
+		else
+			{
+			endTime =(aEntry->EndTimeL()).TimeLocalL();
+			}
+
+		}
+	else 	
+		{
+		startTime = (aEntry->StartTimeL()).TimeUtcL();
+		if(aEntry->EntryTypeL()==CCalEntry::EReminder)
+			{
+			endTime = startTime;
+			}
+		else
+			{
+			endTime = (aEntry->EndTimeL()).TimeUtcL();
+			}
+
+		}
+	
+	iStartTime=startTime.DateTime();
+
+
+	AddDateTimePropertyL(aParser, KVersitTokenDTSTART, startTime, iTimeType, iTimeFlag);
+	AddDateTimePropertyL(aParser, KVersitTokenDTEND, endTime, iTimeType, iTimeFlag);
+	}
+
+// Add todo properties
+//
+void CAgendaEntryToVCalConverter::AddTodoPropertiesL(CVersitParser& aParser, CCalEntry* aEntry)
+	{
+	TBool isUtc = ETrue;
+	if ((aEntry->EndTimeL()).TimeUtcL() != Time::NullTTime())
+		{
+		if ((aEntry->StartTimeL()).TimeMode() == TCalTime::EFloating)
+			{
+			isUtc = EFalse;
+			AddDateTimePropertyL(aParser, KVersitTokenDUE, (aEntry->EndTimeL()).TimeLocalL(), iTimeType, iTimeFlag);
+			}
+		else
+			{
+			AddDateTimePropertyL(aParser, KVersitTokenDUE, (aEntry->EndTimeL()).TimeUtcL(), iTimeType, iTimeFlag);
+			}
+		}
+
+	// Add todo name list is now done with rest of category implementation	
+	TTime startDate; 
+	
+	if (isUtc)
+		{
+		startDate = aEntry->StartTimeL().TimeUtcL();
+		}
+	else
+		{
+		startDate = aEntry->StartTimeL().TimeLocalL();
+		}
+	iStartTime=startDate.DateTime();
+	
+	// We have already checked the start and end times so we do not need 
+	// further checks here. After discussion with MV.
+	if (startDate != Time::NullTTime())
+		{
+		AddDateTimePropertyL(aParser, KVersitTokenDTSTART, startDate, iTimeType, iTimeFlag);
+		}
+
+	// Is the entry completed - if so export completed date/time and COMPLETED status
+	if ((aEntry->CompletedTimeL()).TimeUtcL() != Time::NullTTime())
+		{
+		AddDateTimePropertyL(aParser,KVCalTokenCOMPLETED, (aEntry->CompletedTimeL()).TimeUtcL(), TVersitDateTime::EIsUTC, iTimeFlag);
+		AddDesPropertyL(aParser, KVCalTokenSTATUS, KVCalStatusCOMPLETED);
+		}
+	else
+		{
+		if (aEntry->StatusL()==CCalEntry::ETodoCompleted)
+			{
+			// If entry status is COMPLETED, ensure COMPLETED date is exported too
+			if ((aEntry->EndTimeL()).TimeUtcL()!= Time::NullTTime())
+				{
+				aEntry->SetCompletedL(ETrue,aEntry->EndTimeL());
+				}
+			else
+				{
+				//No valid due date, set the completed date to the today's date
+				TTime today;
+				today.UniversalTime();
+				TCalTime caltime;
+				caltime.SetTimeUtcL(today);
+				aEntry->SetCompletedL(ETrue, caltime);
+				}
+			AddDateTimePropertyL(aParser,KVCalTokenCOMPLETED, (aEntry->CompletedTimeL()).TimeUtcL(), TVersitDateTime::EIsUTC, iTimeFlag);
+			AddDesPropertyL(aParser, KVCalTokenSTATUS, KVCalStatusCOMPLETED);
+			}
+		else
+			{
+			// Entry is not completed and doesn't have status==Completed
+			// So, add status property as normal
+			AddStatusPropertyL(aParser,aEntry);
+			}
+
+		}
+		
+	}
+
+// Construct an integer property
+//
+void CAgendaEntryToVCalConverter::AddIntegerPropertyL(CVersitParser& aParser, const TDesC8& aToken, TCalLocalUid aInt)
+	{
+	CParserPropertyValue* value = new(ELeave)CParserPropertyValueInt(aInt);
+	CleanupStack::PushL(value);
+	CParserProperty* prop = CParserProperty::NewL(*value, aToken, NULL); 
+	CleanupStack::Pop(value);	
+	// Add to the parser
+	aParser.AddPropertyL(prop);
+	}
+
+void CAgendaEntryToVCalConverter::AddDateTimePropertyL(CVersitParser& aParser, const TDesC8& aToken, const TTime& aTime, const TVersitDateTime::TRelativeTime aRelativeTime, TVersitDateTime::TVersitDateTimeFlags aTimeFlag)
+	{
+	// Construct a date-time property
+	TVersitDateTime* versitDateTime = new(ELeave)TVersitDateTime(aTime.DateTime(), aRelativeTime);
+	CleanupStack::PushL(versitDateTime);
+	CParserPropertyValue* value = new(ELeave)CParserPropertyValueDateTime(versitDateTime);
+	CleanupStack::Pop(versitDateTime);
+	versitDateTime->SetFlag(aTimeFlag);
+	
+	CleanupStack::PushL(value);
+	CParserProperty* prop = CParserProperty::NewL(*value, aToken, NULL);
+	CleanupStack::Pop(value);
+	// Add to the parser
+	aParser.AddPropertyL(prop);
+
+	}
+
+void CAgendaEntryToVCalConverter::AddDesPropertyL(CVersitParser& aParser, const TDesC8& aToken, const TDesC& aDes)
+	{
+	HBufC* buf=AgnConvertUtil::EncodeL(aDes,KUidEtextToText);
+	CleanupStack::PushL(buf);
+	CParserPropertyValue* value = CParserPropertyValueHBufC::NewL(buf->Des());
+	CleanupStack::PopAndDestroy(buf);
+	CleanupStack::PushL(value);
+	CParserProperty* prop = CParserProperty::NewL(*value, aToken, NULL);
+	CleanupStack::Pop(value);
+	// Add to the parser
+	aParser.AddPropertyL(prop);
+	}
+
+void CAgendaEntryToVCalConverter::AddAlarmPropertyL(CVersitParser& aParser, const TDesC8& aToken, const TTime& aAlarmTime, const TDesC& aAlarmName)
+	{
+	// Create an array of paramaters for this property
+	CArrayPtr<CParserParam>* arrayOfParams = new(ELeave)CArrayPtrFlat<CParserParam>(4);
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroyArrayOfParams,arrayOfParams));
+
+	CParserParam* typeParam = CParserParam::NewL(KVCalToken8TYPE, KNullDesC8);
+	CleanupStack::PushL(typeParam);
+	typeParam->SetValueL(KVCalValue8EPOCSOUND);
+	arrayOfParams->AppendL(typeParam); // takes ownership
+	CleanupStack::Pop(typeParam);
+
+	// Construct a date-time property
+	
+	TVersitDateTime* versitDateTime = new(ELeave)TVersitDateTime(aAlarmTime.DateTime(), iTimeType);
+	CleanupStack::PushL(versitDateTime);
+
+	CVersitAlarm* alarm = CVersitAlarm::NewL(versitDateTime, NULL, 0, aAlarmName, TPtrC());
+	CleanupStack::Pop(versitDateTime);
+	versitDateTime->SetFlag(iTimeFlag);
+	CleanupStack::PushL(alarm);
+	CParserPropertyValue* value = new(ELeave)CParserPropertyValueAlarm(alarm);
+	CleanupStack::Pop(alarm);
+	CleanupStack::PushL(value);
+
+	CParserProperty* prop = CParserProperty::NewL(*value, aToken, arrayOfParams);
+	CleanupStack::Pop(2,arrayOfParams); // value, arrayOfParams
+
+	// Add to the parser
+	aParser.AddPropertyL(prop);
+	}
+
+void CAgendaEntryToVCalConverter::AddExtendedAlarmPropertyL(CVersitParser& aParser, const TDesC8& aToken, const CCalContent& aAlarmAction)
+	{
+	// Create an array of parameters for this property
+	CArrayPtr<CParserParam>* arrayOfParams = new(ELeave)CArrayPtrFlat<CParserParam>(4);
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroyArrayOfParams,arrayOfParams));
+	
+	// Create content disposition parameter
+	CParserParam* dispositionParam = CParserParam::NewL(KVersitTokenVALUE, KNullDesC8);
+	CleanupStack::PushL(dispositionParam);
+	CCalContent::TDisposition disposition = aAlarmAction.Disposition();
+	switch (disposition)
+		{
+		case CCalContent::EDispositionUrl:
+			{
+			dispositionParam->SetValueL(KVCalContentValueUrl);
+			break;
+			}
+		case CCalContent::EDispositionInline:
+			{
+			dispositionParam->SetValueL(KVCalContentValueInline);
+			break;
+			}
+		default:
+			{
+			// In the default case, the property is unsupported. So we'll clean up
+			// and then return
+			CleanupStack::PopAndDestroy(2); //arrayOfParams, dispositionParam
+			return;
+			}
+		}
+	arrayOfParams->AppendL(dispositionParam); // takes ownership
+	CleanupStack::Pop(dispositionParam);
+
+	// Create content MIME type parameter
+	CParserParam* mimeTypeParam = CParserParam::NewL(KVersitTokenCONTENTTYPE, KNullDesC8);
+	CleanupStack::PushL(mimeTypeParam);
+	TPtrC8 mimeType(aAlarmAction.MimeType());
+	mimeTypeParam->SetValueL(mimeType);
+  	arrayOfParams->AppendL(mimeTypeParam);
+  	CleanupStack::Pop(mimeTypeParam);
+  	
+  	
+	// Construct X-EPOC-ALARM property and initialise with parameters and content
+	CVersitExtendedAlarm* alarm = CVersitExtendedAlarm::NewL(aAlarmAction.Content(), aAlarmAction.MimeType(), static_cast<CVersitExtendedAlarm::TDisposition>(aAlarmAction.Disposition()));
+	CleanupStack::PushL(alarm);
+	CParserPropertyValue* value = new(ELeave)CParserPropertyValueExtendedAlarm(alarm);
+	CleanupStack::Pop(alarm);
+	CleanupStack::PushL(value);
+	CParserProperty* prop = CParserProperty::NewL(*value, aToken, arrayOfParams);
+	CleanupStack::Pop(2,arrayOfParams); // value, arrayOfParams
+
+	// Add to the parser
+	aParser.AddPropertyL(prop); // takes ownership of prop
+	}
+
+void CAgendaEntryToVCalConverter::AddAttachmentPropertyL(CVersitParser& aParser, CCalAttachment& aAttachment)
+	{
+	// Create an array of parameters for this property
+	CArrayPtr<CParserParam>* arrayOfParams = new(ELeave)CArrayPtrFlat<CParserParam>(4);
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroyArrayOfParams,arrayOfParams));
+	
+	// Create value parameter
+	CParserParam* valueType = CParserParam::NewL(KVersitTokenVALUE, KNullDesC8);
+	CleanupStack::PushL(valueType);
+	CCalAttachment::TType type = aAttachment.Type();
+	TBool exportBinaryData = EFalse;
+	switch (type)
+		{
+		case CCalAttachment::EUri:
+			{
+			valueType->SetValueL(KVCalContentValueUrl);
+			break;
+			}
+		case CCalAttachment::EFile:
+			{
+			if (aAttachment.FileAttachment()->ContentId().Length() > 0)
+				{
+				valueType->SetValueL(KVCalContentValueContentId);
+				}
+			else if (aAttachment.IsAttributeSet(CCalAttachment::EExportInline))
+				{
+				valueType->SetValueL(KVCalContentValueInline);
+				exportBinaryData = ETrue;
+				}
+			break;
+			}
+		default:
+			// Do nothing. In this case the value will not be set
+			break;
+		}
+	if (valueType->Value().Length() == 0)
+		{
+		// The property is unsupported. So we'll clean up and then return
+		CleanupStack::PopAndDestroy(2, arrayOfParams); //arrayOfParams, valueType
+		return;
+		}
+	arrayOfParams->AppendL(valueType); // takes ownership
+	CleanupStack::Pop(valueType);
+
+	// Create content MIME type parameter
+	TPtrC8 mimeType(aAttachment.MimeType());
+	if(mimeType != KNullDesC8)
+		{
+		CParserParam* mimeTypeParam = CParserParam::NewL(KVersitAttachMimeType, mimeType);
+		CleanupStack::PushL(mimeTypeParam);
+	  	arrayOfParams->AppendL(mimeTypeParam);
+	  	CleanupStack::Pop(mimeTypeParam);
+		}
+  
+  	const TPtrC fileName(aAttachment.Label());
+  	if(fileName != KNullDesC)
+  		{
+		HBufC8* filenameUtf8 = HBufC8::NewLC(2 * fileName.Length()); // need room to convert from 16 bit to 8 bit (x2)
+		TPtr8 pfileName(filenameUtf8->Des());
+		User::LeaveIfError(CnvUtfConverter::ConvertFromUnicodeToUtf8(pfileName, fileName));					 
+		CParserParam* fileNameParameter = CParserParam::NewL(KVersitAttachLabel, pfileName);
+		CleanupStack::PopAndDestroy(filenameUtf8);  
+		CleanupStack::PushL(fileNameParameter);
+	  	arrayOfParams->AppendL(fileNameParameter);
+	  	CleanupStack::Pop(fileNameParameter);
+  		}
+	 	// Create File Date parameter
+	TTime lastModifiedFileTime = Time::NullTTime();
+	if (aAttachment.FileAttachment())
+		{
+		lastModifiedFileTime = aAttachment.FileAttachment()->LastModifiedTimeUtc();
+		}
+	if(lastModifiedFileTime != Time::NullTTime())
+		{
+		_LIT(KStringFormat, "%F%Y%M%DT%H%T%SZ"); // locale-independent formatting YYMMDD"T"HHMMSS"Z" (day,month,year,hour,minute,second)
+		TBuf<KMaxTimeStringSize> dateString;
+		lastModifiedFileTime.FormatL(dateString,KStringFormat);
+		TBuf8<KMaxTimeStringSize> dateString8;
+		dateString8.Copy(dateString);
+		CParserParam* fileDate = CParserParam::NewL(KVCalAttachFileDate, dateString8);
+		CleanupStack::PushL(fileDate);
+	  	arrayOfParams->AppendL(fileDate);
+	  	CleanupStack::Pop(fileDate);
+		}
+	  	
+  	CParserPropertyValue* propertyValue = NULL;
+
+ 	if (exportBinaryData)
+ 		{
+ 		RFile file;
+	 	TRAPD(err,aAttachment.FileAttachment()->FetchFileHandleL(file));
+		if(err == KErrNone)
+			{
+			CleanupClosePushL(file);
+			propertyValue = CParserPropertyValueBinaryFile::NewL(file);
+			CleanupStack::PopAndDestroy(&file);
+			}
+		else if(err == KErrArgument)
+			{//FetchFileHandleL leaves with KErrArgument if there is no file handle has been set, eg. the entry hasn't been saved to Calendar file which isn't common user case
+			TRAP(err, aAttachment.FileAttachment()->LoadBinaryDataL());
+
+			if(err != KErrNone)
+				{//The user can keep synching if, e.g. it is out of memory, or the attachment file is on a drive where the media has been removed, or the attachment has been deleted from the calendar store by other clients.
+				CleanupStack::PopAndDestroy(arrayOfParams);	
+				return;
+				}
+
+			propertyValue = CParserPropertyValueBinary::NewL(aAttachment.Value());
+			}
+		else
+			{
+			User::Leave(err);
+			}
+		}
+ 	else 
+ 		{
+ 		TPtrC8 attach8;
+ 		if (type == CCalAttachment::EFile)
+ 			{
+ 			attach8.Set(aAttachment.FileAttachment()->ContentId());	
+ 			}
+ 		else
+ 			{
+ 			attach8.Set(aAttachment.Value());	
+ 			}
+ 		
+ 		HBufC* attach16 = HBufC::NewLC(attach8.Length());
+		attach16->Des().Copy(attach8);
+ 		propertyValue = CParserPropertyValueHBufC::NewL(attach16->Des());
+		CleanupStack::PopAndDestroy(attach16);		
+  		}
+	CleanupStack::PushL(propertyValue);
+	CParserProperty* property = CParserProperty::NewL(*propertyValue, KVersitTokenATTACH, arrayOfParams);
+	aParser.AddPropertyL(property);
+	CleanupStack::Pop(2,arrayOfParams);		// propertyValue, arrayOfParams
+	}
+
+void CAgendaEntryToVCalConverter::AddAttendeeParameterL(CArrayPtr<CParserParam>* aArrayOfParams, CCalAttendee* aAttendee)
+	{
+	// Create an array of paramaters for this property
+	CParserParam* expectParam = CParserParam::NewL(KVCalAttendee8EXPECT, KNullDesC8);
+	CleanupStack::PushL(expectParam);
+	switch (aAttendee->VCalExpect())
+		{
+		case CCalAttendee::EVCalFyi:
+			expectParam->SetValueL(KVCalAttendeeExpect8FYI);
+			break;
+		case CCalAttendee::EVCalRequire:
+			expectParam->SetValueL(KVCalAttendeeExpect8REQUIRE);
+			break;
+		case CCalAttendee::EVCalRequest:
+			expectParam->SetValueL(KVCalAttendeeExpect8REQUEST);
+			break;
+		case CCalAttendee::EVCalImmediate:
+			expectParam->SetValueL(KVCalAttendeeExpect8IMMEDIATE);
+			break;
+		default:
+			break;
+		}
+	aArrayOfParams->AppendL(expectParam); // takes ownership
+	CleanupStack::Pop(expectParam); 
+	
+	CParserParam* rsvpParam = CParserParam::NewL(KVCalAttendee8RSVP, KNullDesC8);
+	CleanupStack::PushL(rsvpParam);
+	switch (aAttendee->ResponseRequested())
+		{
+		case ETrue:
+			rsvpParam->SetValueL(KVCalAttendeeRsvp8YES);
+			break;
+		case EFalse:
+			rsvpParam->SetValueL(KVCalAttendeeRsvp8NO);
+			break;
+		default:
+			break;
+		}
+	aArrayOfParams->AppendL(rsvpParam); // takes ownership
+	CleanupStack::Pop(rsvpParam); 
+	
+	CParserParam* calroleParam = CParserParam::NewL(KICalAttendeeCalRole8, KNullDesC8);
+	CleanupStack::PushL(calroleParam);
+	
+	CParserParam* vcalroleParam = CParserParam::NewL(KICalAttendeeCalRole8, KNullDesC8);
+	CleanupStack::PushL(vcalroleParam);
+	
+	switch (aAttendee->RoleL())
+		{
+		case CCalAttendee::EChair:
+			calroleParam->SetValueL(KICalAttendeeCalRole8CHAIR);
+			break;
+		case CCalAttendee::EReqParticipant:
+			calroleParam->SetValueL(KICalAttendeeCalRole8REQUIRED);
+			break;
+		case CCalAttendee::EOptParticipant: 
+			calroleParam->SetValueL(KICalAttendeeCalRole8OPTIONAL);
+			break;
+		case CCalAttendee::ENonParticipant:
+			calroleParam->SetValueL(KICalAttendeeCalRole8NONPARTICIPANT);
+			break;
+			
+		case CCalAttendee::EVCalAttendee:
+			vcalroleParam->SetValueL(KVCalAttendeeRole8ATTENDEE);
+			break;
+		case CCalAttendee::EVCalDelegate:
+			vcalroleParam->SetValueL(KVCalAttendeeRole8DELEGATE);
+			break;
+		case CCalAttendee::EVCalOwner:
+			vcalroleParam->SetValueL(KVCalAttendeeRole8OWNER);
+			break;
+		default:
+			break;
+		}
+	if (calroleParam->Value().Length() > 0)
+		{
+		aArrayOfParams->AppendL(calroleParam); // takes ownership
+		CleanupStack::PopAndDestroy(vcalroleParam); // delete the vCal role as it is not used
+		CleanupStack::Pop(calroleParam);
+		}
+	else
+		{
+		aArrayOfParams->AppendL(vcalroleParam); // takes ownership
+		CleanupStack::Pop(vcalroleParam);
+		CleanupStack::PopAndDestroy(calroleParam); // delete the iCal role as it is not used
+		}
+	
+	CParserParam* calStatusParam = CParserParam::NewL(KICalAttendeeCalStatus8, KNullDesC8);
+	CleanupStack::PushL(calStatusParam);
+	
+	CParserParam* vcalStatusParam = CParserParam::NewL(KVCalAttendee8STATUS, KNullDesC8);
+	CleanupStack::PushL(vcalStatusParam);
+	
+	switch (aAttendee->StatusL())
+		{
+		case CCalAttendee::EAccepted:
+			calStatusParam->SetValueL(KVCalAttendeeStatus8ACCEPTED);
+			vcalStatusParam->SetValueL(KVCalAttendeeStatus8ACCEPTED);
+			break;
+		case CCalAttendee::ENeedsAction:
+			calStatusParam->SetValueL(KICalAttendeeCalStatus8NEEDSACTION);
+			vcalStatusParam->SetValueL(KVCalAttendeeStatus8NEEDSACTION);
+			break;
+		case CCalAttendee::ETentative:
+			calStatusParam->SetValueL(KVCalAttendeeStatus8TENTATIVE);
+			vcalStatusParam->SetValueL(KVCalAttendeeStatus8TENTATIVE);
+			break;
+		case CCalAttendee::EConfirmed:
+			calStatusParam->SetValueL(KVCalAttendeeStatus8CONFIRMED);
+			vcalStatusParam->SetValueL(KVCalAttendeeStatus8CONFIRMED);
+			break;
+		case CCalAttendee::EDeclined:
+			calStatusParam->SetValueL(KVCalAttendeeStatus8DECLINED);
+			vcalStatusParam->SetValueL(KVCalAttendeeStatus8DECLINED);
+			break;
+		case CCalAttendee::ECompleted:
+			calStatusParam->SetValueL(KVCalAttendeeStatus8COMPLETED);
+			vcalStatusParam->SetValueL(KVCalAttendeeStatus8COMPLETED);
+			break;
+		case CCalAttendee::EDelegated:
+			calStatusParam->SetValueL(KVCalAttendeeStatus8DELEGATED);
+			vcalStatusParam->SetValueL(KVCalAttendeeStatus8DELEGATED);
+			break;
+		case CCalAttendee::EInProcess:
+			calStatusParam->SetValueL(KICalAttendeeCalStatus8INPROCESS);
+			break;
+		case CCalAttendee::EVCalSent:
+			vcalStatusParam->SetValueL(KVCalAttendeeStatus8SENT);
+			break;
+		case CCalAttendee::EVCalXReceived:
+			vcalStatusParam->SetValueL(KVCalAttendeeStatus8XDASHRECEIVED);
+			break;
+		default:
+			break;
+		}
+	
+	if (vcalStatusParam->Value().Length() > 0)
+		{
+		aArrayOfParams->AppendL(vcalStatusParam); // takes ownership
+		CleanupStack::Pop(vcalStatusParam);
+		}
+	else
+		{
+		CleanupStack::PopAndDestroy(vcalStatusParam); 
+		}
+		
+	if (calStatusParam->Value().Length() > 0)
+		{
+		aArrayOfParams->AppendL(calStatusParam); // takes ownership
+		CleanupStack::Pop(calStatusParam); 
+		}
+	else
+		{
+		CleanupStack::PopAndDestroy(calStatusParam); 
+		}
+	}
+
+void CAgendaEntryToVCalConverter::AddAttendeePropertyL(CVersitParser& aParser, CCalUser* aAttendee, TBool isPhoneOwner, TBool isOrganizer)
+	{
+	CArrayPtr<CParserParam>* arrayOfParams = new(ELeave)CArrayPtrFlat<CParserParam>(9);
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroyArrayOfParams,arrayOfParams));
+
+	if( aAttendee->SentBy() != KNullDesC)
+		{
+		CParserParam* sentByParam = CParserParam::NewL(KICalAttendeeSentBy8, aAttendee->SentBy());
+		CleanupStack::PushL(sentByParam);
+		arrayOfParams->AppendL(sentByParam);
+		CleanupStack::Pop(sentByParam);	
+		}	
+
+	if( aAttendee->CommonName() != KNullDesC)
+		{
+		CParserParam* commonNameParam = CParserParam::NewL(KICalAttendeeCommonName8, aAttendee->CommonName());
+		CleanupStack::PushL(commonNameParam);
+		arrayOfParams->AppendL(commonNameParam);	// takes ownership
+		CleanupStack::Pop(commonNameParam);	
+		}
+	
+	if(isPhoneOwner)
+		{
+		CParserParam* phoneOwnerParam = CParserParam::NewL(KICalAttendee8XDASHPHONEOWNER, KNullDesC8);
+		CleanupStack::PushL(phoneOwnerParam);
+		arrayOfParams->AppendL(phoneOwnerParam);	// takes ownership
+		CleanupStack::Pop(phoneOwnerParam);			
+		}
+		
+	if (isOrganizer)
+		{
+		CParserParam* organizerParam = CParserParam::NewL(KVCalAttendee8ROLE, KVCalAttendeeRole8ORGANIZER);
+		CleanupStack::PushL(organizerParam);
+		arrayOfParams->AppendL(organizerParam);	// takes ownership
+		CleanupStack::Pop(organizerParam);
+		}
+	else
+		{
+		// these properties are not supported in CCalUser so don't need to be exported for an organizer
+		AddAttendeeParameterL(arrayOfParams,static_cast<CCalAttendee*>(aAttendee));
+		}
+				
+	CParserPropertyValue* value = CParserPropertyValueHBufC::NewL(aAttendee->Address());
+	CleanupStack::PushL(value);
+	CParserProperty* prop = CParserProperty::NewL(*value, KVersitTokenATTENDEE, arrayOfParams);
+	// Add to the parser
+	aParser.AddPropertyL(prop);
+	CleanupStack::Pop(2,arrayOfParams);		// value, arrayOfParams
+	}
+
+
+
+void CAgendaEntryToVCalConverter::AddRepeatPropertiesL(CVersitParser& aParser, TCalRRule& aRpt, CTzRules* aEntryTzRule)
+	{
+	CVersitRecurrence* recurrence = NULL;
+	TCalRRule::TType rType = aRpt.Type();
+
+	TVersitDateTime* endTime = NULL;
+	TUint duration = 0;
+	if (aRpt.Count() != 0)
+		{
+		TTime untilTime;
+		if(aEntryTzRule)
+			{
+			untilTime = aRpt.Until().TimeUtcL();
+			//convert utc to repeat local
+			aEntryTzRule->ConvertToLocalL(untilTime);
+			}
+		else
+			{//use system local
+			untilTime = aRpt.Until().TimeLocalL();
+			}
+		TDateTime end=untilTime.DateTime();
+		endTime = new(ELeave) TVersitDateTime(end, TVersitDateTime::EIsVCardLocal);
+		endTime->SetFlag(TVersitDateTime::EExportLeaveAsLocalTime);
+ 		duration = aRpt.Count();
+		}
+	CleanupStack::PushL(endTime);
+
+	switch (aRpt.Type())
+		{
+		// Daily Repeat
+		case TCalRRule::EDaily:
+			recurrence = new(ELeave)CVersitRecurrenceDaily(aRpt.Interval(), duration, endTime);
+			break;
+		// Weekly Repeat
+		case TCalRRule::EWeekly:
+			recurrence = CreateWeeklyRepeatL(aRpt, duration, endTime);
+			break;
+		// Monthly By Days Repeat
+		case TCalRRule::EMonthly:
+			recurrence = CreateMonthlyRepeatL(aRpt, duration, endTime);
+			break;
+		// Yearly By Day Repeat
+		case TCalRRule::EYearly:
+			recurrence = CreateYearlyRepeatL(aRpt, duration, endTime);
+			break;
+		default:
+			delete endTime;
+			break;
+		}
+	CleanupStack::Pop();	// endTime (owned by recurrence)
+
+	if (recurrence)
+		{
+		CleanupStack::PushL(recurrence);
+		CParserPropertyValue* value = new(ELeave)CParserPropertyValueRecurrence(recurrence);	// takes ownership
+		CleanupStack::Pop();		// recurrence
+		CleanupStack::PushL(value);
+		CParserProperty* prop = CParserProperty::NewL(*value, KVersitTokenRRULE, NULL);
+		CleanupStack::Pop(value);
+
+		// Add to the parser
+		aParser.AddPropertyL(prop);
+		}
+	}
+
+CVersitRecurrence* CAgendaEntryToVCalConverter::CreateWeeklyRepeatL(TCalRRule& aRpt,TInt aDuration, TVersitDateTime* aEndTime)
+	{
+	// Convert the agenda weekly repeat to a versit recurrence
+
+	CWeekDayArray* dayArray = new(ELeave)CWeekDayArray();
+	CleanupStack::PushL(dayArray);
+	dayArray->iArray = new(ELeave)CArrayFixFlat<TDay>(1);
+
+	// Iterate through the days to check which days are set
+	RArray<TDay> daysinweek;
+	CleanupClosePushL(daysinweek);
+	aRpt.GetByDayL(daysinweek);
+	TInt count=daysinweek.Count();
+	for (TInt ii=0; ii<count; ++ii)
+		{
+		dayArray->iArray->AppendL(daysinweek[ii]);
+		}
+	CleanupStack::PopAndDestroy(&daysinweek);
+	CVersitRecurrence* recurrence = new(ELeave)CVersitRecurrenceWeekly(aRpt.Interval(), aDuration, aEndTime, dayArray); // takes ownership
+	CleanupStack::Pop(dayArray);
+
+	return recurrence;
+	}
+	
+CVersitRecurrence* CAgendaEntryToVCalConverter::CreateMonthlyRepeatL(TCalRRule& aRpt, TInt aDuration, TVersitDateTime* aEndTime)
+	{
+	// Convert Agenda Monthly By Days repeat to a versit recurrence
+	RArray<TCalRRule::TDayOfMonth> days;
+	aRpt.GetByDayL(days);
+	TInt count=days.Count();
+	if(count>0)	
+		{//e.g. every Monday of first week and every Friday of the third week.
+		CleanupClosePushL(days);
+		CArrayPtrFlat<CVersitRecurrenceMonthlyByPos::CMonthPosition>* monthPositions = new(ELeave)CArrayPtrFlat<CVersitRecurrenceMonthlyByPos::CMonthPosition>(1);
+		CleanupStack::PushL(monthPositions);
+
+		// Iterate through the five weeks for the month
+		// (First,Second,Third,Fourth,Last)
+				
+		for (TInt ii=0; ii<count; ++ii)
+			{
+			CVersitRecurrenceMonthlyByPos::CMonthPosition* monthPos = new(ELeave)CVersitRecurrenceMonthlyByPos::CMonthPosition();
+			CleanupStack::PushL(monthPos);
+			
+			TInt8 weekNo = days[ii].WeekInMonth();
+			if(weekNo>0)
+				{
+				monthPos->iSign = CVersitRecurrenceMonthlyByPos::CMonthPosition::EWeeksFromStartOfMonth;
+				monthPos->iWeekNo = weekNo;	
+				}
+			else
+				{
+				monthPos->iSign = CVersitRecurrenceMonthlyByPos::CMonthPosition::EWeeksFromEndOfMonth;
+				monthPos->iWeekNo = Abs(weekNo);
+				}
+			monthPos->iArrayOfWeekDays = new(ELeave)CWeekDayArray();
+			monthPos->iArrayOfWeekDays->iArray = new(ELeave)CArrayFixFlat<TDay>(1);
+			monthPos->iArrayOfWeekDays->iArray->AppendL(days[ii].Day());
+			monthPositions->AppendL(monthPos);
+			CleanupStack::Pop();		// monthPos;
+			}
+
+		CVersitRecurrence* recurrence = new(ELeave)CVersitRecurrenceMonthlyByPos(aRpt.Interval(), aDuration, aEndTime, monthPositions);
+		CleanupStack::Pop();	// monthPositions (owned by recurrence)
+		CleanupStack::PopAndDestroy(&days);
+		return recurrence;
+		}
+	else
+		{
+		RArray<TInt> dayofmonth;
+		aRpt.GetByMonthDayL(dayofmonth);
+		TInt count=dayofmonth.Count();
+		if(count>0)
+			{
+			CleanupClosePushL(dayofmonth);
+			CArrayFixFlat<TInt>* dayList = new(ELeave)CArrayFixFlat<TInt>(1);
+			CleanupStack::PushL(dayList);
+
+			// Iterate through each day in the month
+
+			for (TInt ii=0; ii<count; ++ii)
+				{
+				dayList->AppendL(dayofmonth[ii]+1);  // add 1, since 0 means 1st
+				}
+
+			CVersitRecurrence* recurrence = new(ELeave)CVersitRecurrenceMonthlyByDay(aRpt.Interval(), aDuration, aEndTime, dayList, NULL, EFalse);
+
+			CleanupStack::Pop();		// dayList;
+			
+			CleanupStack::PopAndDestroy(&dayofmonth);
+			return recurrence;
+			}
+		}
+	return NULL;
+	}
+
+CVersitRecurrence* CAgendaEntryToVCalConverter::CreateYearlyRepeatL(TCalRRule& aRpt, TInt aDuration, TVersitDateTime* aEndTime)
+	{
+	// Convert Agenda Yearly By Days repeat to a versit recurrence
+
+	// There is no vCal equivalent of a yearly 'by day' repeat,
+	// e.g. repeat on the first monday of october,
+	// so a monthly repeat with an interval of 12* the yearly repeat
+	// is used instead
+	RArray<TCalRRule::TDayOfMonth> days;
+	aRpt.GetByDayL(days);
+	TInt count=days.Count();
+	if(count>0)
+		{
+		CleanupClosePushL(days);
+		CArrayPtrFlat<CVersitRecurrenceMonthlyByPos::CMonthPosition>* monthPositions = new(ELeave)CArrayPtrFlat<CVersitRecurrenceMonthlyByPos::CMonthPosition>(1);
+		CleanupStack::PushL(monthPositions);
+
+		// Iterate through the five weeks for the month
+		// (First,Second,Third,Fourth,Last)
+				
+		for (TInt ii=0; ii<count; ++ii)
+			{
+			CVersitRecurrenceMonthlyByPos::CMonthPosition* monthPos = new(ELeave)CVersitRecurrenceMonthlyByPos::CMonthPosition();
+			CleanupStack::PushL(monthPos);
+			monthPos->iSign = CVersitRecurrenceMonthlyByPos::CMonthPosition::EWeeksFromStartOfMonth;
+			monthPos->iWeekNo = days[ii].WeekInMonth(); // iWeekNo goes from 1-5
+		
+			monthPos->iArrayOfWeekDays = new(ELeave)CWeekDayArray();
+			monthPos->iArrayOfWeekDays->iArray = new(ELeave)CArrayFixFlat<TDay>(1);
+			monthPos->iArrayOfWeekDays->iArray->AppendL(days[ii].Day());
+			monthPositions->AppendL(monthPos);
+			CleanupStack::Pop();		// monthPos;
+			}
+		// Interval * 12, since we really want is to repeat yearly
+		CVersitRecurrence* recurrence = new(ELeave)CVersitRecurrenceMonthlyByPos(aRpt.Interval() * 12, aDuration, aEndTime, monthPositions);
+		CleanupStack::Pop();	// monthPositions (owned by recurrence)
+		CleanupStack::PopAndDestroy(&days);//close the array
+
+		return recurrence;
+		}
+	else
+		{
+		CArrayFixFlat<TMonth>* monthList = new(ELeave)CArrayFixFlat<TMonth>(1);
+		CleanupStack::PushL(monthList);
+		monthList->AppendL(aRpt.DtStart().TimeLocalL().DateTime().Month());
+		CVersitRecurrence* recurrence = new(ELeave)CVersitRecurrenceYearlyByMonth(aRpt.Interval(), aDuration, aEndTime, monthList);
+		CleanupStack::Pop();	// monthList
+		return recurrence;
+		}
+	}
+
+void CAgendaEntryToVCalConverter::AddRDatePropertyL(CVersitParser& aParser, RArray<TCalTime>& aRdates)
+	{
+	CArrayPtrFlat<TVersitDateTime>* dateList = new (ELeave) CArrayPtrFlat<TVersitDateTime>(4);
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroyArrayOfVersitDateTime,dateList));
+	
+	const TInt KCount(aRdates.Count());
+
+	for (TInt i = 0; i < KCount; ++i)
+		{
+		TCalTime sporadicDate = aRdates[i];
+		TDateTime rDate;
+		if (iTimeType == TVersitDateTime::EIsUTC)
+			{
+			rDate=sporadicDate.TimeUtcL().DateTime();
+			}
+		else
+			{
+			rDate=sporadicDate.TimeLocalL().DateTime();
+			}
+		
+		// Construct a versit date-time property	
+		TVersitDateTime* versitDateTime = new(ELeave) TVersitDateTime(rDate, iTimeType);
+		CleanupStack::PushL(versitDateTime);
+		versitDateTime->SetFlag(iTimeFlag);	
+		dateList->AppendL(versitDateTime);
+		CleanupStack::Pop(); // versitDateTime
+		}
+	
+	CParserPropertyValue* value = new(ELeave)CParserPropertyValueMultiDateTime(dateList);
+	CleanupStack::Pop(dateList);
+	CleanupStack::PushL(value);
+	
+	CParserProperty* property = CParserProperty::NewL(*value, KVersitTokenRDATE, NULL);
+	CleanupStack::Pop(value);
+	
+	// Add to the parser
+	aParser.AddPropertyL(property);//aParser takes the ownership
+	}
+
+// Exception property
+//
+void CAgendaEntryToVCalConverter::AddRepeatExceptionPropertiesL(CVersitParser& aParser, RArray<TCalTime>& aExceptions)
+	{
+	CArrayPtrFlat<TVersitDateTime>* dateList = new(ELeave)CArrayPtrFlat<TVersitDateTime>(1);
+	CleanupStack::PushL(TCleanupItem(ResetAndDestroyArrayOfVersitDateTime, dateList));
+	
+	TInt size = aExceptions.Count();
+
+	for (TInt count=0; count<size; count++)
+		{
+		TCalTime exception = aExceptions[count];
+		
+		TDateTime date;
+		if (iTimeType == TVersitDateTime::EIsUTC)
+			{
+			date = exception.TimeUtcL().DateTime();
+			}
+		else
+			{
+			date = exception.TimeLocalL().DateTime();
+			}
+
+		// Construct a date-time property
+
+		TVersitDateTime* versitDateTime = new(ELeave) TVersitDateTime(date, iTimeType);
+ 		versitDateTime->SetFlag(iTimeFlag);
+ 		CleanupStack::PushL(versitDateTime);
+		dateList->AppendL(versitDateTime);
+		CleanupStack::Pop(); // versitDateTime 
+		}
+
+	CParserPropertyValue* value = new(ELeave)CParserPropertyValueMultiDateTime(dateList);
+	CleanupStack::Pop();		// dateList
+
+	CleanupStack::PushL(value);
+	CParserProperty* prop = CParserProperty::NewL(*value, KVersitTokenEXDATE, NULL);
+	CleanupStack::Pop(value);
+	// Add to the parser
+	aParser.AddPropertyL(prop);
+	}
+
+// Creates a stream dictionary, from an embedded store and a stream ID 
+//
+CStreamDictionary* CAgendaEntryToVCalConverter::CreateDictionaryLC(CEmbeddedStore& aEmbeddedStore, TStreamId& aId)
+	{
+	CStreamDictionary* dictionary = CStreamDictionary::NewLC();
+	RStoreReadStream dicStream;
+	dicStream.OpenLC(aEmbeddedStore, aId);
+	dicStream >> *dictionary;
+	CleanupStack::PopAndDestroy(); //dicStream
+	return dictionary;
+	}
+
+
+// The vCalendar CATEGORIES property has multiple property values so the property values
+// are stored in an array.
+//
+// The categories of the entry are iterated through, and each category is added as a 
+// property value to the array. 
+//
+void CAgendaEntryToVCalConverter::AddCategoryPropertyL(CVersitParser& aParser, const RPointerArray<CCalCategory>& aCategories)
+	{
+	CDesCArrayFlat* desArray = new(ELeave) CDesCArrayFlat(4);
+	CleanupStack::PushL(desArray);
+
+	TInt categories = aCategories.Count();
+	for (TInt count=0; count<categories; count++)
+		{
+		CCalCategory* category = aCategories[count];
+		switch (category->Category())
+			{
+		case CCalCategory::ECalAppointment:
+				desArray->AppendL(KVCalCategoriesAPPOINTMENT);
+				break;
+		case CCalCategory::ECalBusiness:
+				desArray->AppendL(KVCalCategoriesBUSINESS);
+				break;
+		case CCalCategory::ECalEducation:
+				desArray->AppendL(KVCalCategoriesEDUCATION);
+				break;
+		case CCalCategory::ECalHoliday:
+				desArray->AppendL(KVCalCategoriesHOLIDAY);
+				break;
+		case CCalCategory::ECalMeeting:
+				desArray->AppendL(KVCalCategoriesMEETING);
+				break;
+		case CCalCategory::ECalMiscellaneous:
+				desArray->AppendL(KVCalCategoriesMISCELLANEOUS);
+				break;
+		case CCalCategory::ECalPersonal:
+				desArray->AppendL(KVCalCategoriesPERSONAL);
+				break;
+		case CCalCategory::ECalPhoneCall:
+				desArray->AppendL(KVCalCategoriesPHONECALL);
+				break;
+		case CCalCategory::ECalSickDay:
+				desArray->AppendL(KVCalCategoriesSICKDAY);
+				break;
+		case CCalCategory::ECalSpecialOccasion:
+				desArray->AppendL(KVCalCategoriesSPECIALOCCASION);
+				break;
+		case CCalCategory::ECalTravel:
+				desArray->AppendL(KVCalCategoriesTRAVEL);
+				break;
+		case CCalCategory::ECalVacation:
+				desArray->AppendL(KVCalCategoriesVACATION);
+				break;
+		case CCalCategory::ECalExtended:
+				desArray->AppendL(category->ExtendedCategoryName());
+				break;
+		default:
+				break;
+			}
+		}
+
+    CParserPropertyValue* value = new (ELeave) CParserPropertyValueCDesCArray(desArray);
+	CleanupStack::Pop(); //desArray
+	
+	CleanupStack::PushL(value); 
+	CParserProperty* prop = CParserProperty::NewL(*value, KVersitTokenCATEGORIES, NULL);
+	CleanupStack::Pop(value); 
+	// Add to the parser
+	aParser.AddPropertyL(prop);
+	}
+
+/**
+ * Checks the status value and adds the appropriate status value to the export list 
+ * held by the versit parser. 
+ */
+void CAgendaEntryToVCalConverter::AddStatusPropertyL(CVersitParser& aParser, CCalEntry* aEntry)
+	{
+	switch(aEntry->StatusL())
+		{
+		case CCalEntry::ETodoInProcess:
+		case CCalEntry::EVCalAccepted:
+			AddDesPropertyL(aParser, KVCalTokenSTATUS, KVCalStatusACCEPTED);			
+			break;
+		case CCalEntry::ETodoNeedsAction:
+		case CCalEntry::EVCalNeedsAction:
+			AddDesPropertyL(aParser, KVCalTokenSTATUS, KVCalStatusNEEDSACTION);			
+			break;
+		case CCalEntry::ETodoCompleted:
+			AddDesPropertyL(aParser, KVCalTokenSTATUS, KVCalStatusCOMPLETED);			
+			break;
+			
+		case CCalEntry::EConfirmed:
+			AddDesPropertyL(aParser, KVCalTokenSTATUS, KVCalStatusCONFIRMED);			
+			break;
+		case CCalEntry::ECancelled:
+		case CCalEntry::EVCalDeclined:
+			AddDesPropertyL(aParser, KVCalTokenSTATUS, KVCalStatusDECLINED);			
+			break;
+		case CCalEntry::ETentative:
+			AddDesPropertyL(aParser, KVCalTokenSTATUS, KVCalStatusTENTATIVE);			
+			break;
+		case CCalEntry::EVCalSent:
+			AddDesPropertyL(aParser, KVCalTokenSTATUS, KVCalStatusSENT);			
+			break;
+		case CCalEntry::EVCalDelegated:
+			AddDesPropertyL(aParser, KVCalTokenSTATUS, KVCalStatusDELEGATED);			
+			break;
+		}
+
+	}
+
+
+