diff -r 000000000000 -r f979ecb2b13e pimappservices/calendarvcalplugin/src/agmvcalx.cpp --- /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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "agmvcal.h" +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#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* array=reinterpret_cast*>(aObject); + if (array) + { + array->ResetAndDestroy(); + } + delete array; + } + +void CAgendaEntryToVCalConverter::ResetAndDestroyArrayOfVersitDateTime(TAny* aObject) + { + CArrayPtr* array=reinterpret_cast*>(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 attendees = aEntry->AttendeesL(); + + TInt count=attendees.Count(); + CCalUser* phoneowner=aEntry->PhoneOwnerL(); + for (TInt ii=0; iiOrganizerL(); + 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 + RArrayrdates; + CleanupClosePushL(rdates); + aEntry->GetRDatesL(rdates); + + if (rdates.Count()>0) + { + AddRDatePropertyL(aParser, rdates); + isrepeat = ETrue; + } + + CleanupStack::PopAndDestroy(&rdates); + + if (isrepeat) + { + // Recurrence Exception details + RArray 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& 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 geoString; + TBuf geoLatString; + TBuf 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; iiAttachmentL(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* arrayOfParams = new(ELeave)CArrayPtrFlat(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* arrayOfParams = new(ELeave)CArrayPtrFlat(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(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* arrayOfParams = new(ELeave)CArrayPtrFlat(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 dateString; + lastModifiedFileTime.FormatL(dateString,KStringFormat); + TBuf8 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* 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* arrayOfParams = new(ELeave)CArrayPtrFlat(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(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(1); + + // Iterate through the days to check which days are set + RArray daysinweek; + CleanupClosePushL(daysinweek); + aRpt.GetByDayL(daysinweek); + TInt count=daysinweek.Count(); + for (TInt ii=0; iiiArray->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 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* monthPositions = new(ELeave)CArrayPtrFlat(1); + CleanupStack::PushL(monthPositions); + + // Iterate through the five weeks for the month + // (First,Second,Third,Fourth,Last) + + for (TInt ii=0; ii0) + { + 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(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 dayofmonth; + aRpt.GetByMonthDayL(dayofmonth); + TInt count=dayofmonth.Count(); + if(count>0) + { + CleanupClosePushL(dayofmonth); + CArrayFixFlat* dayList = new(ELeave)CArrayFixFlat(1); + CleanupStack::PushL(dayList); + + // Iterate through each day in the month + + for (TInt ii=0; iiAppendL(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 days; + aRpt.GetByDayL(days); + TInt count=days.Count(); + if(count>0) + { + CleanupClosePushL(days); + CArrayPtrFlat* monthPositions = new(ELeave)CArrayPtrFlat(1); + CleanupStack::PushL(monthPositions); + + // Iterate through the five weeks for the month + // (First,Second,Third,Fourth,Last) + + for (TInt ii=0; iiiSign = CVersitRecurrenceMonthlyByPos::CMonthPosition::EWeeksFromStartOfMonth; + monthPos->iWeekNo = days[ii].WeekInMonth(); // iWeekNo goes from 1-5 + + monthPos->iArrayOfWeekDays = new(ELeave)CWeekDayArray(); + monthPos->iArrayOfWeekDays->iArray = new(ELeave)CArrayFixFlat(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* monthList = new(ELeave)CArrayFixFlat(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& aRdates) + { + CArrayPtrFlat* dateList = new (ELeave) CArrayPtrFlat(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& aExceptions) + { + CArrayPtrFlat* dateList = new(ELeave)CArrayPtrFlat(1); + CleanupStack::PushL(TCleanupItem(ResetAndDestroyArrayOfVersitDateTime, dateList)); + + TInt size = aExceptions.Count(); + + for (TInt count=0; countSetFlag(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& aCategories) + { + CDesCArrayFlat* desArray = new(ELeave) CDesCArrayFlat(4); + CleanupStack::PushL(desArray); + + TInt categories = aCategories.Count(); + for (TInt count=0; countCategory()) + { + 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; + } + + } + + +