--- /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;
+ }
+
+ }
+
+
+