// 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 <s32file.h>
#include <s32mem.h>
#include <bassnd.h>
#include <calentry.h>
#include <vtzrules.h>
#include "agnversit.h"
#include <utf.h>
#include <tz.h> //Conversion between local and UTC times
#include <calalarm.h>
#include <calcontent.h>
#include <calrrule.h>
#include <caluser.h>
#include <calattachment.h>
#include "agmvcal.h"
const TInt KCountDigits = 8;
_LIT(KDateStringFormat, "%F%D%M%Y%H%T%S%C"); // locale-independent formatting DDMMYYHHMMSSUUUUUU (day,month,year,hour,minute,second,usec
_LIT(KVersitTokenMailTo,"MAILTO:");
HBufC* AgnConvertUtil::EncodeL(const TDesC& aText,TUid aConversion)
{
HBufC8* text=HBufC8::NewLC(aText.Length()*2);
TPtr8 ptr = text->Des();
TInt i;
for (i=0; i < aText.Length(); i++)
{
ptr.Append(aText[i] & 0x00FF);
ptr.Append((aText[i] >> 8) & 0x00FF);
}
CCnaConverterList* convList=CCnaConverterList::NewLC();
CConverterBase* conv = convList->NewConverterL(aConversion);
if (!conv)
{
CleanupStack::PopAndDestroy(); // convList
User::Leave(KErrNotSupported);
}
CleanupStack::PushL(conv);
CBufFlat* decodeBuffer = CBufFlat::NewL(256);
CleanupStack::PushL(decodeBuffer);
CBufFlat* encodedBuffer = CBufFlat::NewL(256);
CleanupStack::PushL(encodedBuffer);
decodeBuffer->InsertL(0,ptr);
RBufReadStream readStream;
RBufWriteStream writeStream;
readStream.Open(*decodeBuffer);
writeStream.Open(*encodedBuffer);
conv->ConvertObjectL(readStream, writeStream);
readStream.Close();
TInt size=encodedBuffer->Size();
HBufC* writeBuf=HBufC::NewLC(size);
TPtr resulttext = writeBuf->Des();
for(i = 0; i < (size - 1); i += 2)
{
resulttext.Append((encodedBuffer->Ptr(0)[i + 1] << 8) |
encodedBuffer->Ptr(0)[i]);
}
writeStream.CommitL();
writeStream.Close();
CleanupStack::Pop(writeBuf); // writebuf
CleanupStack::PopAndDestroy(2,decodeBuffer); // buffers
CleanupStack::PopAndDestroy(2,convList); //conv+convList
CleanupStack::PopAndDestroy(text); //text
return (writeBuf);
}
// This method imports a vCalendar entity from aParser and returns a pointer to a CAgnEntry
// if successful or NULL if it wasn't possible to import the vCalendar. It reads the
// relevant properties from aParser entity and builds up a corresponding agenda entry.
// It allows to import vCal file without Summary and Description fields
void CVCalToAgendaEntryConverter::ImportVCalL(CVersitParser& aParser, RPointerArray<CCalEntry>& aEntryArray)
{
CCalEntry::TType entryType = GetEntryTypeL(aParser);
// Group Scheduling Data
//Import UID
HBufC* guid16 = ImportDesPropertyL(aParser, KVersitTokenUID);
if (!guid16) // non cal entry
{
// create our a UID based on the current time (UTC, microsecond precision)
TTime now;
now.UniversalTime();
TBuf<KMaxTimeStringSize+KCountDigits> dateString;
now.FormatL(dateString,KDateStringFormat);
TInt threeDidgit=Math::Random() % 1000;
dateString.Append(threeDidgit);
guid16 = dateString.AllocL();
}
CleanupStack::PushL(guid16);
// the UID is stored as an 8-bit descriptor, so convert from 16-bit to 8-bit
HBufC8* guid8= CnvUtfConverter::ConvertFromUnicodeToUtf8L(guid16->Des());
CleanupStack::PopAndDestroy(guid16);
CleanupStack::PushL(guid8);
// Import Sequence Number
TInt seqNumber;
// if no sequence number
if (!ImportIntegerPropertyL(aParser, KVersitTokenSEQUENCE, seqNumber))
{
seqNumber = 0;
}
// Import Method
CCalEntry::TMethod methodStatus(CCalEntry::EMethodNone);
HBufC* method = ImportDesPropertyL(aParser, KVersitTokenXMETHOD);
if (method)
{
CleanupStack::PushL(method);
if (*method == KVCalTokenMethodStatusENone)
{
methodStatus = CCalEntry::EMethodNone;
}
else if (*method == KVCalTokenMethodStatusEPublish)
{
methodStatus = CCalEntry::EMethodPublish;
}
else if (*method == KVCalTokenMethodStatusERequest)
{
methodStatus = CCalEntry::EMethodRequest;
}
else if (*method == KVCalTokenMethodStatusEReply)
{
methodStatus = CCalEntry::EMethodReply;
}
else if (*method == KVCalTokenMethodStatusEAdd)
{
methodStatus = CCalEntry::EMethodAdd;
}
else if (*method == KVCalTokenMethodStatusECancel)
{
methodStatus = CCalEntry::EMethodCancel;
}
else if (*method == KVCalTokenMethodStatusERefresh)
{
methodStatus = CCalEntry::EMethodRefresh;
}
else if (*method == KVCalTokenMethodStatusECounter)
{
methodStatus = CCalEntry::EMethodCounter;
}
else if (*method == KVCalTokenMethodStatusEDeclineCounter)
{
methodStatus = CCalEntry::EMethodDeclineCounter;
}
else
{
// do nothing if method is invalid - it will be None by default
}
CleanupStack::PopAndDestroy(method);
}
// Import X-Recurrence-Id
TVersitDateTime::TRelativeTime relativeTime = TVersitDateTime::EIsUTC;
TTime recurrenceId;
TBool isRecurrenceIdPresent = ImportDateTimePropertyL(aParser, KVersitTokenXRECURRENCEID, recurrenceId, relativeTime);
if (!isRecurrenceIdPresent)
{
iEntry = CCalEntry::NewL(entryType,guid8, methodStatus, seqNumber);
}
else
{
TCalTime caltime;
if(GetTimeModeL(aParser) == TCalTime::EFloating)
{
caltime.SetTimeLocalFloatingL(recurrenceId);
}
else
{
caltime.SetTimeUtcL(recurrenceId);
}
iEntry = CCalEntry::NewL(entryType,guid8, methodStatus, seqNumber, caltime, CalCommon::EThisOnly);
}
CleanupStack::Pop(guid8); // ownership was passed to calGSData
// Fill in the entry description from the SUMMARY property
// If this doesn't exist, use the DESCRIPTION property, and if this
// doesn't exist, return a NULL entry
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(KVersitTokenSUMMARY, TUid::Uid(KVersitPropertyHBufCUid), EFalse);
if (!properties)
{
// get properties but don't take ownership of the elements of the array
properties = aParser.PropertyL(KVersitTokenDESCRIPTION, TUid::Uid(KVersitPropertyHBufCUid), EFalse);
}
CleanupStack::PushL(properties);
// Use the value found from the Summary/Description
// Both Summary and Description are not found in imported vCal file
//then insert empty enties for summary and description
// these empty entries will be descarded while exporting vCal file
TPtrC summary;
if (properties)
{
summary.Set(static_cast<CParserPropertyValueHBufC*>((*properties)[0]->Value())->Value());
}
HBufC* summaryBuf = AgnConvertUtil::EncodeL(summary,KUidTextToEtextNoTrim);
CleanupStack::PushL(summaryBuf);
if (summaryBuf)
{
iEntry->SetSummaryL(*summaryBuf);
}
CleanupStack::PopAndDestroy(summaryBuf);
HBufC* description =ImportDesPropertyL(aParser,KVersitTokenDESCRIPTION);
CleanupStack::PushL(description);
if (description != NULL)
{
iEntry->SetDescriptionL(*description); // Takes ownership
}
CleanupStack::PopAndDestroy(description);
TBool validEntry = EFalse;
if (entryType == CCalEntry::ETodo)
{
validEntry = ImportTodoPropertiesL(aParser);
}
else
{
validEntry = ImportEventPropertiesL(aParser);
}
if (!validEntry)
{
CleanupStack::PopAndDestroy(properties);
delete iEntry;
iEntry = NULL;
return;
}
// Import CLASS property
HBufC* property=ImportDesPropertyL(aParser, KVersitTokenCLASS);
if (property)
{
CleanupStack::PushL(property);
if (*property == KVCalTokenPUBLIC)
iEntry->SetReplicationStatusL(CCalEntry::EOpen);
else if (*property == KVCalTokenPRIVATE)
iEntry->SetReplicationStatusL(CCalEntry::EPrivate);
else if (*property == KVCalTokenCONFIDENTIAL)
iEntry->SetReplicationStatusL(CCalEntry::ERestricted);
CleanupStack::PopAndDestroy(property);
}
// Import LOCATION property
property=ImportDesPropertyL(aParser, KVersitTokenLOCATION);
if (property)
{
CleanupStack::PushL(property);
iEntry->SetLocationL(*property);
CleanupStack::PopAndDestroy(property);
}
// Import DTSTAMP
TTime timeProperty;
if (ImportDateTimePropertyL(aParser, KVersitTokenXDTSTAMP, timeProperty, relativeTime))
{
TCalTime caltimeProperty;
caltimeProperty.SetTimeUtcL(timeProperty);
iEntry->SetDTStampL(caltimeProperty);
}
// Attendee property
ImportAttendeePropertiesL(aParser, KVersitTokenATTENDEE);
// Categories property
ImportCategoriesPropertyL(aParser, KVersitTokenCATEGORIES);
TInt localId;
if (ImportIntegerPropertyL(aParser, KVersitTokenXLOCALUID, localId))
{
iEntry->SetLocalUidL(localId);
}
// Additional stuff to comply with Versit Specs 1.0
// All entries have a priority not just ToDo's
// Todo Functionality merged into this code block
TInt priority;
if (ImportIntegerPropertyL(aParser, KVersitTokenPRIORITY, priority))
{
iEntry->SetPriorityL(priority);
}
// All entries have a status - will default to Needs Action if cannot be read
CCalEntry::TStatus entryStatus=CCalEntry::ENullStatus;
ImportStatusPropertyL(aParser, entryStatus);
//Now sync completed and ECompleted status to keep entry consistenty
if(entryType==CCalEntry::ETodo && (iEntry->CompletedTimeL().TimeUtcL()) != Time::NullTTime())
{
iEntry->SetCompletedL(ETrue, iEntry->CompletedTimeL());
}
iEntry->SetStatusL(entryStatus);
//Get last changed date from vcal
if (ImportDateTimePropertyL(aParser, KVersitTokenLASTMODIFIED, timeProperty, relativeTime))
{
if (iTzZone && (relativeTime == TVersitDateTime::EIsVCardLocal))
{
iTzZone->ConvertToUtcL(timeProperty);
}
TCalTime lastModifiedDate;
lastModifiedDate.SetTimeUtcL(timeProperty);
iEntry->SetLastModifiedDateL(lastModifiedDate);
}
else
{
iEntry->SetLastModifiedDateL(); //set changed date to now
}
TInt transp;
if (ImportIntegerPropertyL(aParser, KVersitTokenTRANSP, transp))
{
iEntry->SetTimeTransparencyL(static_cast<CCalEntry::TTransp>(transp));
}
ImportAttachmentPropertyL(aParser);
// Import GEO
HBufC* geoString=ImportDesPropertyL(aParser,KVersitTokenGEO);
if (geoString != NULL)
{
CleanupStack::PushL(geoString);
// Determine the position of the delimiter for extraction of the geo latitude and longitude values
TInt delimiterPos = geoString->Locate(KVersitTokenCommaVal);
if(delimiterPos!=KErrNotFound)
{
// Extract the latitude
TLex geoLatitudeLex(geoString->Left(delimiterPos));
// Extract the latitude by excluding the delimiter
TLex geoLongitudeLex(geoString->Right(geoString->Length()-(delimiterPos+1)));
TReal geoLatitude;
TReal geoLongitude;
if((geoLatitudeLex.Val(geoLatitude)==KErrNone) && (geoLongitudeLex.Val(geoLongitude)==KErrNone))
{
CCalGeoValue* importedGeoValue=CCalGeoValue::NewL();
CleanupStack::PushL(importedGeoValue);
TRAPD(err, importedGeoValue->SetLatLongL(geoLatitude,geoLongitude));
if(err==KErrNone)
{
iEntry->SetGeoValueL(*importedGeoValue);
}
CleanupStack::PopAndDestroy(importedGeoValue);
}
}
CleanupStack::PopAndDestroy(geoString);
}
CleanupStack::PopAndDestroy(properties);
aEntryArray.AppendL(iEntry); // takes ownership of entry
iEntry = NULL;
}
CVCalToAgendaEntryConverter::~CVCalToAgendaEntryConverter()
{
delete iEntry;
delete iTzZone;
}
void CVCalToAgendaEntryConverter::SetTzConverter(RTz* aTzConverter)
{
iTzConverter = aTzConverter;
}
void CVCalToAgendaEntryConverter::SetTzRules(CTzRules* aTzZone)
{
// this function should only ever be called once so this shouldn't be needed
if (iTzZone)
{
delete iTzZone;
iTzZone = NULL;
}
iTzZone = aTzZone;
}
TCalTime::TTimeMode CVCalToAgendaEntryConverter::GetTimeModeL(CVersitParser& aParser)
{
TTime dummyTime;
TVersitDateTime::TRelativeTime relativeTime;
if ( ! ImportDateTimePropertyL(aParser, KVersitTokenDTSTART, dummyTime, relativeTime))
{
if ( ! ImportDateTimePropertyL(aParser, KVersitTokenDTEND, dummyTime, relativeTime))
{
if ( ! ImportDateTimePropertyL(aParser, KVersitTokenDUE, dummyTime, relativeTime))
{
// no time
relativeTime = TVersitDateTime::EIsUTC;
}
}
}
if (iTzZone || relativeTime == TVersitDateTime::EIsUTC)
{
return TCalTime::EFixedUtc;
}
return TCalTime::EFloating;
}
// Try and find out which Epoc Agenda entry type this belongs to.
// At the moment, relies on having an 'X-EPOCAGENDAENTRYTYPE' field, and defaults to a appointment
// type if this isn't present.
// Maybe some heuristics should be used to try and ascertain which entry type is most appropriate
// e.g. if the entry has a yearly repeat, then maybe it should be an anniversary type.
//
// A call to this function resets iVcalTokenTypeReminder flag (unless the vCal entry is actually a Reminder).
//
CCalEntry::TType CVCalToAgendaEntryConverter::GetEntryTypeL(CVersitParser& aParser)
{
// If the entry type is a Todo, return immediately
if (aParser.EntityName()==KVersitVarTokenVTODO)
{
return CCalEntry::ETodo;
}
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(KVCalToken8XDASHENTRYTYPE, TUid::Uid(KVersitPropertyHBufCUid), EFalse);
if (properties)
{
TPtrC type = static_cast<CParserPropertyValueHBufC*>((*properties)[0]->Value())->Value();
delete properties;
if (type == KVCalTokenTypeAPPT)
{
return CCalEntry::EAppt;
}
if (type == KVCalTokenTypeEVENT)
{
return CCalEntry::EEvent;
}
if (type == KVCalTokenTypeANNIV)
{
return CCalEntry::EAnniv;
}
if (type == KVCalTokenTypeTODO)
{
return CCalEntry::ETodo;
}
if (type == KVCalTokenTypeREMINDER)
{
return CCalEntry::EReminder;
}
}
// return an appointment as default type
return (CCalEntry::EAppt);
}
TBool CVCalToAgendaEntryConverter::IsValidTime(const TTime& aTime)
{
if (aTime < TCalTime::MinTime() || aTime > TCalTime::MaxTime())
{
return EFalse;
}
return ETrue;
}
// Import Recurrence Dates property
//
void CVCalToAgendaEntryConverter::ImportRDatePropertyL(CVersitParser& aParser, const TDesC8& aToken)
{
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(aToken, TUid::Uid(KVersitPropertyMultiDateTimeUid), EFalse);
if (properties)
{
CleanupStack::PushL(properties);
CArrayPtr<TVersitDateTime>* rDates = static_cast<CParserPropertyValueMultiDateTime*>((*properties)[0]->Value())->Value();
if (rDates)
{
RArray<TCalTime>calrdates;
CleanupClosePushL(calrdates);
const TInt KSize = rDates->Count();
for (TInt count = 0; count < KSize; ++count)
{
TVersitDateTime* time = (*rDates)[count];
TTime timeProperty(time->iDateTime);
if (IsValidTime(timeProperty))
{
TVersitDateTime::TRelativeTime relativeTime = time->iRelativeTime;
if (iTzZone && (relativeTime == TVersitDateTime::EIsVCardLocal))
{
//Convert to utc time using imported TZ rules
iTzZone->ConvertToUtcL(timeProperty);
relativeTime = TVersitDateTime::EIsUTC;
}
TCalTime calrdate;
if (relativeTime == TVersitDateTime::EIsVCardLocal)
{
calrdate.SetTimeLocalFloatingL(timeProperty);
}
else
{
__ASSERT_DEBUG(relativeTime == TVersitDateTime::EIsUTC, Panic(EAgnVersitPanicWrongTimeType));
calrdate.SetTimeUtcL(timeProperty); //assume time as UTC for release build
}
calrdates.Append(calrdate);
}
}
iEntry->SetRDatesL(calrdates);
CleanupStack::PopAndDestroy();//close RArray
}
CleanupStack::PopAndDestroy(properties);
}
}
// Import the start and end dates of the vCalendar
// This method returns EFalse if there is no start date or end date, or if the start date
// is after the end date. If the start date is missing but an end date is present, the
// start date is set to the end date. If the end date is missing but there is a start
// date, the end date is set to the start date.
//
TBool CVCalToAgendaEntryConverter::GetStartAndEndDatesL(CVersitParser& aParser, TTime& aStartDate, TTime& aEndDate, TVersitDateTime::TRelativeTime& aRelativeTime)
{
TBool startValid = ETrue;
TBool endValid = ETrue;
if (!ImportDateTimePropertyL(aParser, KVersitTokenDTSTART, aStartDate,aRelativeTime))
{
startValid = EFalse;
}
TVersitDateTime::TRelativeTime relativeTime;
if (!ImportDateTimePropertyL(aParser, KVersitTokenDTEND, aEndDate, relativeTime))
{
endValid = EFalse;
}
if (!startValid && !endValid)
{
// Neither times exist, so return Invalid Entry
return EFalse;
}
if (startValid && !endValid)
{
// Start time but no end time
aEndDate = aStartDate;
}
else if (!startValid && endValid)
{
// End time but no start time
aStartDate = aEndDate;
aRelativeTime = relativeTime;
}
if (aStartDate>aEndDate)
return EFalse;
return ETrue;
}
// Import appointment properties
//
TBool CVCalToAgendaEntryConverter::ImportEventPropertiesL(CVersitParser& aParser)
{
TTime startDate;
TTime endDate;
TVersitDateTime::TRelativeTime relativeTime;
if (!GetStartAndEndDatesL(aParser, startDate, endDate, relativeTime))
{
return EFalse;
}
if(iEntry->EntryTypeL()==CCalEntry::EReminder)
{
endDate = startDate;
}
TCalTime caltimeStart;
TCalTime caltimeEnd;
if (relativeTime == TVersitDateTime::EIsVCardLocal)
{
caltimeStart.SetTimeLocalFloatingL(startDate);
caltimeEnd.SetTimeLocalFloatingL(endDate);
}
else
{
__ASSERT_DEBUG(relativeTime==TVersitDateTime::EIsUTC, Panic(EAgnVersitPanicWrongTimeType));
caltimeStart.SetTimeUtcL(startDate); //assume time as UTC for release build
caltimeEnd.SetTimeUtcL(endDate); //assume time as UTC for release build
}
if (startDate > endDate && endDate != Time::NullTTime())
{
return EFalse;
}
iEntry->SetStartAndEndTimeL(caltimeStart,caltimeEnd);
// Attempt to import alarm/repeat properties
ImportRepeatPropertyL(aParser, KVersitTokenRRULE, startDate, relativeTime);
ImportAlarmPropertyL(aParser, startDate, relativeTime);
return ETrue;
}
//
TBool CVCalToAgendaEntryConverter::ImportTodoPropertiesL(CVersitParser& aParser)
{
TVersitDateTime::TRelativeTime relativeTime;//EIsUTC is the default
TTime startDate = Time::NullTTime();
TTime endDate = Time::NullTTime();
if (!ImportDateTimePropertyL(aParser, KVersitTokenDUE, endDate, relativeTime))
{
if (!ImportDateTimePropertyL(aParser, KVersitTokenDTEND, endDate, relativeTime))
{
endDate = Time::NullTTime();
}
}
if ( ! ImportDateTimePropertyL(aParser, KVersitTokenDTSTART, startDate, relativeTime))
{
startDate = endDate;
}
if (startDate > endDate && endDate != Time::NullTTime())
{
return EFalse;
}
if (endDate == Time::NullTTime())
{
endDate = startDate;
}
else if (startDate == Time::NullTTime() || startDate > endDate)
{
startDate = endDate;
}
TTime completedDate;
if (ImportDateTimePropertyL(aParser, KVCalTokenCOMPLETED,completedDate, relativeTime))
{
TCalTime calcompletedDate;
calcompletedDate.SetTimeUtcL(completedDate);
iEntry->SetCompletedL(ETrue, calcompletedDate);
}
TCalTime caltimeStart;
TCalTime caltimeEnd;
if (relativeTime == TVersitDateTime::EIsUTC)
{
caltimeStart.SetTimeUtcL(startDate);
caltimeEnd.SetTimeUtcL(endDate);
}
else
{
caltimeStart.SetTimeLocalFloatingL(startDate);
caltimeEnd.SetTimeLocalFloatingL(endDate);
}
iEntry->SetStartAndEndTimeL(caltimeStart,caltimeEnd);
// Attempt to import alarm properties
ImportAlarmPropertyL(aParser, endDate, relativeTime);
// Attempt to import repeat properties
ImportRepeatPropertyL(aParser, KVersitTokenRRULE, endDate, relativeTime);
return ETrue;
}
// Import a date/time
// This method returns true if a date/time exists and is within the standard agenda date range
// If it doesn't exist or the date isn't valid this method returns EFalse.
//
TBool CVCalToAgendaEntryConverter::ImportDateTimePropertyL(CVersitParser& aParser, const TDesC8& aToken, TTime& aValue, TVersitDateTime::TRelativeTime& aRelativeTime)
{
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(aToken, TUid::Uid(KVersitPropertyDateTimeUid), EFalse);
if (properties)
{
CleanupStack::PushL(properties);
TVersitDateTime* time = static_cast<CParserPropertyValueDateTime*>((*properties)[0]->Value())->Value();
aValue = TTime(time->iDateTime);
TCalTime calTime;
if (IsValidTime(aValue))
{
aRelativeTime = time->iRelativeTime;
if (iTzZone && ( aRelativeTime== TVersitDateTime::EIsVCardLocal))
{
//Convert to utc time using imported TZ rules
iTzZone->ConvertToUtcL(aValue);
aRelativeTime = TVersitDateTime::EIsUTC;
}
CleanupStack::PopAndDestroy(properties);
return ETrue;
}
CleanupStack::PopAndDestroy(properties);
}
return EFalse;
}
// Import an integer property
//
TBool CVCalToAgendaEntryConverter::ImportIntegerPropertyL(CVersitParser& aParser, const TDesC8& aToken, TInt& aValue)
{
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(aToken, TUid::Uid(KVersitPropertyIntUid), EFalse);
if (properties)
{
aValue = static_cast<CParserPropertyValueInt*>((*properties)[0]->Value())->Value();
delete properties;
return ETrue;
}
else
{
// If there is no property available, return EFalse to signal that this property doesn't exist
return EFalse;
}
}
// Import a descriptor property
//
HBufC* CVCalToAgendaEntryConverter::ImportDesPropertyL(CVersitParser& aParser, const TDesC8& aToken)
{
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(aToken, TUid::Uid(KVersitPropertyHBufCUid), EFalse);
// If there is no property available, return NULL to signal that this property doesn't exist
HBufC* aHBufC = NULL;
if (properties)
{
CleanupStack::PushL(properties);
CParserPropertyValueHBufC* propertyValue = static_cast<CParserPropertyValueHBufC*>((*properties)[0]->Value());
aHBufC=propertyValue->TakeValueOwnership();
CleanupStack::PopAndDestroy(properties);
if (aHBufC)
{
CleanupStack::PushL(aHBufC);
HBufC* temp=AgnConvertUtil::EncodeL(aHBufC->Des(),KUidTextToEtextNoTrim);
CleanupStack::PopAndDestroy(aHBufC);
aHBufC=temp;
}
}
return aHBufC;
}
// Import an alarm property
//
TBool CVCalToAgendaEntryConverter::ImportAlarmPropertyL(CVersitParser& aParser, TTime& aEntryTime, TVersitDateTime::TRelativeTime& aRelativeTime)
{
// Get properties but don't take ownership of the elements of the array.
// Check if there is an AALARM first.
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(KVersitTokenAALARM,
TUid::Uid(KVCalPropertyAlarmUid), EFalse);
// If there is no AALARM then try with a DALARM. They are treated the same.
if (!properties)
{
properties = aParser.PropertyL(KVersitTokenDALARM,
TUid::Uid(KVCalPropertyAlarmUid), EFalse);
}
if (properties)
{
CleanupStack::PushL(properties);
CParserPropertyValueAlarm* alarmProperty = static_cast<CParserPropertyValueAlarm*>((*properties)[0]->Value());
CVersitAlarm* alarm = alarmProperty->Value();
if (!alarm->iRunTime)
{
CleanupStack::PopAndDestroy(properties);
return EFalse;
}
TTime alarmTime = TTime(alarm->iRunTime->iDateTime);
TVersitDateTime::TRelativeTime relativeTime = alarm->iRunTime->iRelativeTime;
if (iTzZone && (alarm->iRunTime->iRelativeTime == TVersitDateTime::EIsVCardLocal))
{
//Convert to utc time using imported TZ rules
iTzZone->ConvertToUtcL(alarmTime);
relativeTime = TVersitDateTime::EIsUTC;
}
if(aEntryTime==Time::NullTTime())
{//It is only possible if it is a undated doto entry, in which, the due time should be set before the alarm time is set
__ASSERT_DEBUG(iEntry->EntryTypeL()==CCalEntry::ETodo, Panic(EAgnVersitWrongAttribute));
aEntryTime = alarmTime;
aRelativeTime = relativeTime;
TCalTime endTime;
if (relativeTime==TVersitDateTime::EIsVCardLocal || relativeTime==TVersitDateTime::EIsMachineLocal)
{
endTime.SetTimeLocalFloatingL(aEntryTime);
}
else
{
__ASSERT_DEBUG(relativeTime==TVersitDateTime::EIsUTC, Panic(EAgnVersitPanicWrongTimeType));
endTime.SetTimeUtcL(aEntryTime);
}
iEntry->SetStartAndEndTimeL(iEntry->StartTimeL(), endTime);
}
TTimeIntervalMinutes minutes;
aEntryTime.MinutesFrom(alarmTime, minutes);
CCalAlarm* calalarm = CCalAlarm::NewL();
CleanupStack::PushL(calalarm);
const TInt KMinValidAlarmTime = -1440; // can have an alarm up to one day after an event
if(minutes.Int() >= KMinValidAlarmTime)
{
calalarm->SetTimeOffset(minutes);
}
else
{
// Alarm run-time is not valid - return EFalse since there is no valid alarm property
CleanupStack::PopAndDestroy(2,properties);
return EFalse;
}
HBufC* soundName=NULL;
// Check if the sound type is an Epoc Sound
CParserParam* param = ((*properties)[0])->Param(KVCalToken8TYPE);
if (param)
{
if (param->Value() == KVCalValue8EPOCSOUND)
{
soundName = alarm->iAudioContent;
if (soundName)
{
calalarm->SetAlarmSoundNameL(*soundName);
}
}
}
TBool hasExtenedAlarm = ImportExtendedAlarmPropertyL(calalarm, aParser, KVersitTokenXALARM);
if (!soundName && !hasExtenedAlarm)
{
TBaSystemSoundType type(KSystemSoundAlarmUID);
TBaSystemSoundInfo info;
RFs s;
User::LeaveIfError(s.Connect());
BaSystemSound::GetSound(s,type,info); //don't check err as info will always be filled in
s.Close();
calalarm->SetAlarmSoundNameL(info.FileName());
}
iEntry->SetAlarmL(calalarm);
CleanupStack::PopAndDestroy(2,properties);
return ETrue;
}
else
{
// If there is no property available, return EFalse to signal that this property doesn't exist
return EFalse;
}
}
// Import an extended alarm property (X-EPOCALARM) - containing the rich alarm data; it does not import the
// timing control parameters because the AALARM property would have been imported and written to the agenda
// model entry; no need to re-populate the timing controls since both audio sound and extended alarm share the
// same timing controls. The audio alarm timing controls override the rich alarm's timing controls (not used).
TBool CVCalToAgendaEntryConverter::ImportExtendedAlarmPropertyL(CCalAlarm* aAlarm, CVersitParser& aParser, const TDesC8& aToken )
{
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(aToken, TUid::Uid(KVCalPropertyExtendedAlarmUid), EFalse);
if (properties)
{
CleanupStack::PushL(properties);
CParserPropertyValueExtendedAlarm* extendedAlarmProperty = static_cast<CParserPropertyValueExtendedAlarm*>((*properties)[0]->Value());
CVersitExtendedAlarm* extendedAlarm = extendedAlarmProperty->Value();
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* audioAlarmProperties = aParser.PropertyL(KVersitTokenAALARM, TUid::Uid(KVCalPropertyAlarmUid), EFalse);
if (extendedAlarm && audioAlarmProperties)
{
CleanupStack::PushL(audioAlarmProperties);
// Convert X-EPOC-ALARM to alarm content and add to entry
CCalContent* alarmAction = CCalContent::NewL();
CleanupStack::PushL(alarmAction);
HBufC8* content = NULL;
if (extendedAlarm->iContent != NULL)
{
content = extendedAlarm->iContent->AllocL();
CleanupStack::PushL(content);
}
HBufC8* mimeType = NULL;
if (extendedAlarm->iMimeType != NULL)
{
mimeType = extendedAlarm->iMimeType->AllocL();
CleanupStack::PushL(mimeType);
}
alarmAction->SetContentL(content, mimeType, static_cast<CCalContent::TDisposition>(extendedAlarm->iDisposition)); //Takes ownership of content & mimeType
if (mimeType != NULL)
{
CleanupStack::Pop(mimeType);
}
if (content != NULL)
{
CleanupStack::Pop(content);
}
aAlarm->SetAlarmAction(alarmAction); // takes ownership of alarmAction
CleanupStack::Pop(alarmAction);
CleanupStack::PopAndDestroy(audioAlarmProperties);
CleanupStack::PopAndDestroy(properties);
return ETrue;
}
else
{
// If there is no rich alarm available, return EFalse to signal that this property doesn't exist
CleanupStack::PopAndDestroy(properties);
return EFalse;
}
}
else
{
// If there is no property available, return EFalse to signal that this property doesn't exist
return EFalse;
}
}
void CVCalToAgendaEntryConverter::ImportAttachmentPropertyL(CVersitParser& aParser)
{
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(KVersitTokenATTACH, KNullUid, EFalse);//We past KNullUid since we don't know whether it is a binary or URI - versit will have the informantion.
if (!properties)
{
return;
}
CleanupStack::PushL(properties);
const TInt KCount = properties->Count(); // no. of attachments
for (TInt i = 0; i < KCount; ++i)
{
CParserParam* attachValueType = (*properties)[i]->Param(KVersitTokenVALUE);
TPtrC8 valueType;
if(attachValueType && attachValueType->Value().Length() > 0)
{
valueType.Set(attachValueType->Value());
}
CCalAttachment* attachment = NULL;
if(!attachValueType || valueType == KVersitTokenINLINE || valueType == KVersitTokenBINARY)
{
CParserPropertyValueBinary* attachValueBinary = static_cast<CParserPropertyValueBinary*>((*properties)[i]->Value());
if (attachValueBinary)
{
CBufSeg* binary=(CBufSeg*)(attachValueBinary->Value());
const TInt KBinaryLength = binary->Size();
if(KBinaryLength>0)
{
HBufC8* bufValue = HBufC8::NewLC(KBinaryLength);
TPtr8 pBufValue = bufValue->Des();
binary->Read(0, pBufValue, KBinaryLength);
attachment = CCalAttachment::NewFileL(bufValue);
CleanupStack::Pop(bufValue);
}
}
}
else
{
CParserPropertyValueHBufC* attachValueDes = static_cast<CParserPropertyValueHBufC*>((*properties)[i]->Value());
if (attachValueDes && attachValueDes->Value().Length() > 0)
{
TPtrC des16Value = attachValueDes->Value();
HBufC8* buf8Value = HBufC8::NewLC(des16Value.Length());
buf8Value->Des().Copy(des16Value);
if ( ! valueType.Compare(KVCalContentValueContentId) || ! valueType.Compare(KVCalContentValueContentIdShort))
{
attachment = CCalAttachment::NewFileByContentIdL(*buf8Value);
}
else
{
attachment = CCalAttachment::NewUriL(*buf8Value);
}
CleanupStack::PopAndDestroy(buf8Value);
}
}
if (attachment)
{
CleanupStack::PushL(attachment);
//Set paramenters
CParserParam* mimeTypeParam = (*properties)[i]->Param(KVersitAttachMimeType);
if(mimeTypeParam && mimeTypeParam->Value().Length() > 0)
{
attachment->SetMimeTypeL(mimeTypeParam->Value());
}
CParserParam* attachName = (*properties)[i]->Param(KVersitAttachLabel);
if(attachName && attachName->Value().Length() > 0)
{
TPtrC8 attachnameNarror = attachName->Value();
HBufC* attachname16 = HBufC::NewLC(attachnameNarror.Length());
TPtr pattachname16 = attachname16->Des();
User::LeaveIfError(CnvUtfConverter::ConvertToUnicodeFromUtf8(pattachname16, attachnameNarror));
attachment->SetLabelL(*attachname16);
CleanupStack::PopAndDestroy(attachname16);
}
CParserParam* attachDate = (*properties)[i]->Param(KVCalAttachFileDate);
if(attachDate && attachment->FileAttachment() && attachDate->Value().Length() > 0)
{
TPtrC8 pAttachDate = attachDate->Value();
TBuf<KMaxTimeStringSize>date16;
date16.Copy(pAttachDate);
TVersitDateTime* datetime = aParser.DecodeDateTimeL(date16);
CleanupStack::PushL(datetime);
TTime fileTtime(datetime->iDateTime);
if(iTzZone && datetime->iRelativeTime != TVersitDateTime::EIsUTC)
{
iTzZone->ConvertToUtcL(fileTtime);
}
attachment->FileAttachment()->SetLastModifiedTimeUtc(fileTtime);
CleanupStack::PopAndDestroy(datetime);
}
iEntry->AddAttachmentL(*attachment);
CleanupStack::Pop(attachment);
}
}// for loop
CleanupStack::PopAndDestroy(properties);
}
// Import repeat property
//
void CVCalToAgendaEntryConverter::ImportRepeatPropertyL(CVersitParser& aParser, const TDesC8& aToken, const TTime& aRepeatTime, TVersitDateTime::TRelativeTime aRelativeTime)
{
if (aRepeatTime != Time::NullTTime())
{
ImportRepeatRuleL(aParser, aToken, aRepeatTime, aRelativeTime);
//check for RDates - this operation must be carried out after any rule has been imported
ImportRDatePropertyL(aParser, KVersitTokenRDATE);
ImportRepeatExceptionPropertiesL(aParser, KVersitTokenEXDATE);
}
}
// Repeat end date behaviour
// - If the repeat end date is within the agenda range it is set
// - If the repeat end date is greater than the maximum agenda date then the entry is set to repeat forever
// - If the repeat end date is less than the minimum agenda date then the entry is made non-repeating
//
// Current implementation follows these policies:
// 1) time mode of repeat always matches time mode of the entry:
// if entry's time mode is EFloating, then repeat's time mode is EFloating;
// if entry's time mode is EFixedUTC, then repeat's time mode is EFixedTimeZone.
// 2) time format of DTSTART determines time mode of the entry.
// if DTSTART is not valid, then time format of DTEND/DUE is used.
//
void CVCalToAgendaEntryConverter::ImportRepeatRuleL(CVersitParser& aParser, const TDesC8& aToken, const TTime& aStartDate, TVersitDateTime::TRelativeTime aRelativeTime)
{
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(aToken, TUid::Uid(KVCalPropertyRecurrenceUid), EFalse);
if (properties)
{
CleanupStack::PushL(properties);
CVersitRecurrence* recurrence = static_cast<CParserPropertyValueRecurrence*>((*properties)[0]->Value())->Value();
if (!recurrence)
{
CleanupStack::PopAndDestroy(properties);
return;
}
//Importing the start time of the repeating
//startTimeLoc & startTimeUtc will be same if it is floating entry or when iTzZone is not specified.
TTime startTimeLoc = aStartDate;
TTime startTimeUtc = aStartDate;
TBool isFloatingEntry = (!iTzZone && aRelativeTime != TVersitDateTime::EIsUTC);
if (iTzZone)
{
if (aRelativeTime == TVersitDateTime::EIsUTC)
{
iTzZone->ConvertToLocalL(startTimeLoc);
}
else
{
iTzZone->ConvertToUtcL(startTimeUtc);
}
}
TCalRRule repeat;
TCalTime calstart;
if (isFloatingEntry)
{
calstart.SetTimeLocalFloatingL(startTimeLoc);
}
else
{
calstart.SetTimeUtcL(startTimeUtc);
}
repeat.SetDtStart(calstart);
//Importing the recurrence of the repeating
switch(recurrence->iRepeatType)
{
case CVersitRecurrence::EDaily:
repeat.SetType(TCalRRule::EDaily);
break;
case CVersitRecurrence::EYearlyByMonth:
repeat.SetType(TCalRRule::EYearly);
break;
case CVersitRecurrence::EWeekly:
ImportWeeklyRepeatPropertiesL(static_cast<CVersitRecurrenceWeekly*>(recurrence), repeat, startTimeLoc.DayNoInWeek());
break;
case CVersitRecurrence::EMonthlyByPos:
ImportMonthlyByPosRepeatPropertiesL(static_cast<CVersitRecurrenceMonthlyByPos*>(recurrence), repeat, startTimeLoc);
break;
case CVersitRecurrence::EMonthlyByDay:
ImportMonthlyByDayRepeatPropertiesL(static_cast<CVersitRecurrenceMonthlyByDay*>(recurrence), repeat, startTimeLoc.DayNoInMonth());
break;
case CVersitRecurrence::EYearlyByDay:
// Not supported, since an event cannot repeat on the 100th day of a year, etc
// -- intentional drop through to default case --
default:
// Don't understand the repeat type,
// so cleanup and exit
CleanupStack::PopAndDestroy(properties);
return;
}
// We allow only TVersitDateTime::EIsUTC and EIsVCardLocal, because
// EIsMachineLocal is never returned by parser,and EIsCorrect is not used
__ASSERT_DEBUG(aRelativeTime == TVersitDateTime::EIsUTC ||
aRelativeTime == TVersitDateTime::EIsVCardLocal, Panic(EAgnVersitPanicWrongTimeType));
//Importing the until time of the repeating
TVersitDateTime* rptEndDate = recurrence->iEndDate;
TCalTime calUntil;
TBool isUntilTimeValid = EFalse;
if(!rptEndDate && recurrence->iDuration == 0)
{//If no until time has been set and the count is 0, the repeating is forever
calUntil.SetTimeUtcL(TCalTime::MaxTime());
repeat.SetCount(0);
isUntilTimeValid = ETrue;
}
else if(rptEndDate)
{//Set the until time
TDateTime untilDateTimeLoc = rptEndDate->iDateTime;
//Adjust the local repeating until time according to the local start time
if (!isFloatingEntry && iTzZone && rptEndDate->iRelativeTime == TVersitDateTime::EIsUTC)
{
TTime time(untilDateTimeLoc);//create a temp object of TTime
iTzZone->ConvertToLocalL(time);//convert the UTC until to local
untilDateTimeLoc = time.DateTime();// set the local until
}
untilDateTimeLoc.SetHour(startTimeLoc.DateTime().Hour());
untilDateTimeLoc.SetMinute(startTimeLoc.DateTime().Minute());
untilDateTimeLoc.SetSecond(startTimeLoc.DateTime().Second());
untilDateTimeLoc.SetMicroSecond(0);
isUntilTimeValid = ETrue;
if (isFloatingEntry)
{
if (TTime(untilDateTimeLoc) < TCalTime::MinTime())
{
isUntilTimeValid = EFalse;
}
else
{
if (TTime(untilDateTimeLoc) > TCalTime::MaxTime())
{
untilDateTimeLoc = TCalTime::MaxTime().DateTime();
}
calUntil.SetTimeLocalFloatingL(untilDateTimeLoc);
}
}
else
{
TTime untilUtc(untilDateTimeLoc);
if (iTzZone)
{
iTzZone->ConvertToUtcL(untilUtc);
}
if (untilUtc < TCalTime::MinTime())
{
isUntilTimeValid = EFalse;
}
else
{
if (untilUtc > TCalTime::MaxTime())
{
untilUtc = TCalTime::MaxTime().DateTime();
}
calUntil.SetTimeUtcL(untilUtc);
}
}
}
if (isUntilTimeValid)
{
repeat.SetUntil(calUntil);
}
if (recurrence->iDuration>0)
{
TInt instancesPerRepeat = CalculateInstancesPerRepeatL(repeat);
TInt count = recurrence->iDuration * instancesPerRepeat;
// it is possible to have both count and untiltime in an imported vcal
// we will import the shortest repeat of the two dates
if(repeat.Until().TimeLocalL() != Time::NullTTime())
{
TCalTime countUntilTime = iEntry->FindRptUntilTimeL(count);
if(countUntilTime.TimeLocalL() < repeat.Until().TimeLocalL())
{
// if until time is already set, it will be replaced
repeat.SetUntil(countUntilTime);
}
}
else
{
repeat.SetCount(count);
}
isUntilTimeValid = ETrue;
}
if (isUntilTimeValid)
{
//Importing the interval
repeat.SetInterval(recurrence->iInterval);
//Importing the repeating count
TRAPD(err, iEntry->SetRRuleL(repeat));
if (err != KErrArgument && err != KErrNotSupported)
{
User::LeaveIfError(err);
}
TCalRRule ruleGot;
if(iEntry->GetRRuleL(ruleGot))
{
if(iTzZone)
{
// If there are DAYLIGHT and TZ properties, use these rules when converting
// repeating dates to UTC for storage, otherwise the time zone device will be used
// instead.
iEntry->SetTzRulesL(*iTzZone);
}
}
}
CleanupStack::PopAndDestroy(properties);
}
}
TInt CVCalToAgendaEntryConverter::CalculateInstancesPerRepeatL(const TCalRRule& aRRule) const
{
TInt instancesPerRepeat = 1;
switch (aRRule.Type())
{
case TCalRRule::EWeekly:
{
RArray<TDay> wkdays;
CleanupClosePushL(wkdays);
aRRule.GetByDayL(wkdays);
instancesPerRepeat = wkdays.Count();
CleanupStack::PopAndDestroy(&wkdays);
}
break;
case TCalRRule::EMonthly:
{
RArray<TCalRRule::TDayOfMonth> monthdays;
CleanupClosePushL(monthdays);
aRRule.GetByDayL(monthdays);
instancesPerRepeat = monthdays.Count();
CleanupStack::PopAndDestroy(&monthdays);
if (instancesPerRepeat == 0)
{
RArray<TInt> monthdates;
CleanupClosePushL(monthdates);
aRRule.GetByMonthDayL(monthdates);
instancesPerRepeat = monthdates.Count();
CleanupStack::PopAndDestroy(&monthdates);
}
}
break;
case TCalRRule::EYearly:
{
RArray<TCalRRule::TDayOfMonth> yrdays;
CleanupClosePushL(yrdays);
aRRule.GetByDayL(yrdays);
instancesPerRepeat = yrdays.Count();
CleanupStack::PopAndDestroy(&yrdays);
if (instancesPerRepeat == 0)
{
RArray<TMonth> yrmonths;
CleanupClosePushL(yrmonths);
aRRule.GetByMonthL(yrmonths);
instancesPerRepeat = yrmonths.Count();
CleanupStack::PopAndDestroy(&yrmonths);
}
}
break;
case TCalRRule::EDaily:
default:
// do nothing
break;
}
if (instancesPerRepeat == 0)
{
instancesPerRepeat = 1;
}
return instancesPerRepeat;
}
void CVCalToAgendaEntryConverter::ImportWeeklyRepeatPropertiesL(CVersitRecurrenceWeekly* aRepeat, TCalRRule& aRpt, TDay aDefaultDayOfWeek)
{
aRpt.SetType(TCalRRule::EWeekly);
CWeekDayArray* weekdayArray = aRepeat->iArrayOfWeekDayOccurrences;
RArray<TDay> daysinweek;
CleanupClosePushL(daysinweek);
if (weekdayArray)
{
CArrayFix<TDay>* dayList = weekdayArray->iArray;
TInt size = dayList->Count();
for (TInt count=0; count<size; count++)
{
TDay day = (*dayList)[count];
daysinweek.AppendL(day);
}
}
else
{
daysinweek.AppendL(aDefaultDayOfWeek);
}
aRpt.SetByDay(daysinweek);
CleanupStack::PopAndDestroy();//close rarray
}
void CVCalToAgendaEntryConverter::ImportMonthlyByDayRepeatPropertiesL(CVersitRecurrenceMonthlyByDay* aRepeat, TCalRRule& aRpt, TInt aDefaultDayOfMonth)
{
aRpt.SetType(TCalRRule::EMonthly);
// Specify which dates to repeat on
// Only days from the start of the month are supported
CArrayFix<TInt>* dayList = aRepeat->iArrayOfOccurrencesInDaysFromStartOfMonth;
CArrayFix<TInt>* endDayList = aRepeat->iArrayOfOccurrencesInDaysFromEndOfMonth;
RArray<TInt> monthdays;
CleanupClosePushL(monthdays);
if (dayList)
{
TInt size = dayList->Count();
for (TInt count=0; count<size; count++)
{
TInt day = (*dayList)[count]-1;
// Set only valid dates
// 0 = the first day of a month, 30 = the 31st day of the month
if (day >= 0 && day <= 30)
{
monthdays.AppendL(day);
}
}
}
else if(endDayList)
{
TInt size = endDayList->Count();
for (TInt count=0;count<size;++count)
{
TInt day = (*endDayList)[count];
if(day==1)
{ //set 31st day in the monthlyByDates list as its the last day of the month
monthdays.AppendL(30);
break;
}
}
}
if(monthdays.Count()<1)
{
monthdays.AppendL(aDefaultDayOfMonth);
}
aRpt.SetByMonthDay(monthdays);
CleanupStack::PopAndDestroy();//close RArray
}
void CVCalToAgendaEntryConverter::ImportMonthlyByPosRepeatPropertiesL(CVersitRecurrenceMonthlyByPos* aRepeat, TCalRRule& aRpt, const TTime& aDate)
{
aRpt.SetType(TCalRRule::EMonthly);
TInt size = aRepeat->iMonthPositions->Count();
RArray<TCalRRule::TDayOfMonth> dayofmonthArray;
CleanupClosePushL(dayofmonthArray);
if (size > 0)
{
for (TInt count=0; count<size; count++)
{
CArrayFix<TDay>* dayList = (*(aRepeat->iMonthPositions))[count]->iArrayOfWeekDays->iArray;
TInt weekNo = (*(aRepeat->iMonthPositions))[count]->iWeekNo;
TInt sign = (*(aRepeat->iMonthPositions))[count]->iSign;
if (weekNo == 1 && sign == CVersitRecurrenceMonthlyByPos::CMonthPosition::EWeeksFromEndOfMonth)
{
// If the poisiton is in the last week of the month
weekNo = -1;
}
else if (weekNo > 5 || sign == CVersitRecurrenceMonthlyByPos::CMonthPosition::EWeeksFromEndOfMonth)
{
// We can't model this setting, so ignore it
continue;
}
// Now set the days for the week setting
TInt dayCount = dayList->Count();
for (TInt ii=0; ii<dayCount; ii++)
{
TDay day = (*dayList)[ii];
TCalRRule::TDayOfMonth monthday(day, weekNo);
dayofmonthArray.AppendL(monthday);
}
}
}
else
{
TDay day = aDate.DayNoInWeek();
TInt week = aDate.DayNoInMonth() / 7 + 1;
TCalRRule::TDayOfMonth monthday(day, week);
dayofmonthArray.AppendL(monthday);
}
aRpt.SetByDay(dayofmonthArray);
CleanupStack::PopAndDestroy();//close the RArray
}
void CVCalToAgendaEntryConverter::ImportRepeatExceptionPropertiesL(CVersitParser& aParser, const TDesC8& aToken)
{
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(aToken, TUid::Uid(KVersitPropertyMultiDateTimeUid), EFalse);
if (properties)
{
CleanupStack::PushL(properties);
CArrayPtr<TVersitDateTime>* exDates = static_cast<CParserPropertyValueMultiDateTime*>((*properties)[0]->Value())->Value();
if (exDates)
{
TInt size = exDates->Count();
RArray<TCalTime> exceptionlist;
CleanupClosePushL(exceptionlist);
for (TInt count=0; count<size; count++)
{
TCalTime exception;
TVersitDateTime* time = (*exDates)[count];
TTime timeProperty(time->iDateTime);
if (IsValidTime(timeProperty))
{
TVersitDateTime::TRelativeTime relativeTime = time->iRelativeTime;
if (iTzZone && (relativeTime == TVersitDateTime::EIsVCardLocal))
{
//Convert to utc time
iTzZone->ConvertToUtcL(timeProperty);
relativeTime = TVersitDateTime::EIsUTC;
}
if (iEntry->StartTimeL().TimeMode() == TCalTime::EFloating)
{
exception.SetTimeLocalFloatingL(timeProperty);
}
else
{
// the EXDATE is floating but the entry is UTC
exception.SetTimeUtcL(timeProperty);
}
exceptionlist.AppendL(exception);
}
}
iEntry->SetExceptionDatesL(exceptionlist);
CleanupStack::PopAndDestroy();//close the RArray
}
CleanupStack::PopAndDestroy(properties);
}
}
void CVCalToAgendaEntryConverter::ImportAttendeePropertiesL(CVersitParser& aParser, const TDesC8& aToken)
{
TBool mailto;
TInt propLen;
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(aToken, TUid::Uid(KVersitPropertyHBufCUid), EFalse);
CleanupStack::PushL(properties);
if (properties)
{
TInt size = properties->Count(); // no. of attendees
for (TInt count=0; count<size; count++)
{
CParserPropertyValueHBufC* attendeeProperty = static_cast<CParserPropertyValueHBufC*>((*properties)[count]->Value());
mailto = EFalse;
propLen = 0;
if (attendeeProperty->Value().FindF(KVersitTokenMailTo) == 0)
{
mailto = ETrue;
propLen = attendeeProperty->Value().Length() - KVersitTokenMailTo().Length();
}
CParserParam* sentBy = (*properties)[count]->Param(KICalAttendeeSentBy8);
CCalAttendee* attendee = NULL;
CCalUser* user = NULL;
CParserParam* role = (*properties)[count]->Param(KVCalAttendee8ROLE);
const TDesC& KAttendeeProperty = mailto ? attendeeProperty->Value().Right(propLen) : attendeeProperty->Value();
if (sentBy)
{
HBufC* sentByDesc = sentBy->ValueL();
CleanupStack::PushL(sentByDesc);
if (role && role->Value() == KVCalAttendeeRole8ORGANIZER)
{
user = CCalUser::NewL(KAttendeeProperty, *sentByDesc);
iEntry->SetOrganizerL(user);
}
else
{
attendee = CCalAttendee::NewL(KAttendeeProperty, *sentByDesc);
iEntry->AddAttendeeL(attendee);
}
CleanupStack::PopAndDestroy(sentByDesc);
}
else
{
if (role && role->Value() == KVCalAttendeeRole8ORGANIZER)
{
user = CCalUser::NewL(KAttendeeProperty);
iEntry->SetOrganizerL(user);
}
else
{
attendee = CCalAttendee::NewL(KAttendeeProperty);
iEntry->AddAttendeeL(attendee);
}
}
if (attendee)
{
CParserParam* calrole = (*properties)[count]->Param(KICalAttendeeCalRole8);
TBool roleSet = EFalse;
// Check for iCal roles values
if (calrole)
{
if(calrole->Value() == KICalAttendeeCalRole8CHAIR)
{
attendee->SetRoleL(CCalAttendee::EChair);
roleSet = ETrue;
}
else if(calrole->Value() == KICalAttendeeCalRole8REQUIRED)
{
attendee->SetRoleL(CCalAttendee::EReqParticipant);
roleSet = ETrue;
}
else if(calrole->Value() == KICalAttendeeCalRole8OPTIONAL)
{
attendee->SetRoleL(CCalAttendee::EOptParticipant);
roleSet = ETrue;
}
else if(calrole->Value() == KICalAttendeeCalRole8NONPARTICIPANT)
{
attendee->SetRoleL(CCalAttendee::ENonParticipant);
roleSet = ETrue;
}
}
if ( ! roleSet && role)
{
if (role->Value() == KVCalAttendeeRole8OWNER)
{
attendee->SetRoleL(CCalAttendee::EVCalOwner);
roleSet = ETrue;
}
else if (role->Value() == KVCalAttendeeRole8DELEGATE)
{
attendee->SetRoleL(CCalAttendee::EVCalDelegate);
roleSet = ETrue;
}
else if (role->Value() == KVCalAttendeeRole8ATTENDEE)
{
attendee->SetRoleL(CCalAttendee::EVCalAttendee);
roleSet = ETrue;
}
}
if ( ! roleSet)
{
attendee->SetRoleL(CCalAttendee::EReqParticipant);
}
// Check for vCal status values
CParserParam* calStatus = (*properties)[count]->Param(KICalAttendeeCalStatus8);
CParserParam* status = (*properties)[count]->Param(KVCalAttendee8STATUS);
if (calStatus)
{
if (calStatus->Value() == KVCalAttendeeStatus8ACCEPTED)
attendee->SetStatusL(CCalAttendee::EAccepted);
else if (calStatus->Value() == KVCalAttendeeStatus8NEEDSACTION)
attendee->SetStatusL(CCalAttendee::ENeedsAction);
else if (calStatus->Value() == KVCalAttendeeStatus8TENTATIVE)
attendee->SetStatusL(CCalAttendee::ETentative);
else if (calStatus->Value() == KVCalAttendeeStatus8CONFIRMED)
attendee->SetStatusL(CCalAttendee::EConfirmed);
else if (calStatus->Value() == KVCalAttendeeStatus8DECLINED)
attendee->SetStatusL(CCalAttendee::EDeclined);
else if (calStatus->Value() == KVCalAttendeeStatus8COMPLETED)
attendee->SetStatusL(CCalAttendee::ECompleted);
else if (calStatus->Value() == KVCalAttendeeStatus8DELEGATED)
attendee->SetStatusL(CCalAttendee::EDelegated);
else if (calStatus->Value() == KICalAttendeeCalStatus8INPROCESS)
attendee->SetStatusL(CCalAttendee::EInProcess);
}
else if (status)
{
if (status->Value() == KVCalAttendeeStatus8ACCEPTED)
attendee->SetStatusL(CCalAttendee::EAccepted);
else if (status->Value() == KVCalAttendeeStatus8NEEDSACTION)
attendee->SetStatusL(CCalAttendee::ENeedsAction);
else if (status->Value() == KVCalAttendeeStatus8SENT)
attendee->SetStatusL(CCalAttendee::EVCalSent);
else if (status->Value() == KVCalAttendeeStatus8XDASHRECEIVED)
attendee->SetStatusL(CCalAttendee::EVCalXReceived);
else if (status->Value() == KVCalAttendeeStatus8TENTATIVE)
attendee->SetStatusL(CCalAttendee::ETentative);
else if (status->Value() == KVCalAttendeeStatus8CONFIRMED)
attendee->SetStatusL(CCalAttendee::EConfirmed);
else if (status->Value() == KVCalAttendeeStatus8DECLINED)
attendee->SetStatusL(CCalAttendee::EDeclined);
else if (status->Value() == KVCalAttendeeStatus8COMPLETED)
attendee->SetStatusL(CCalAttendee::ECompleted);
else if (status->Value() == KVCalAttendeeStatus8DELEGATED)
attendee->SetStatusL(CCalAttendee::EDelegated);
}
// Check for RSVP parameter
CParserParam* rsvp = (*properties)[count]->Param(KVCalAttendee8RSVP);
if (rsvp)
{
if (rsvp->Value() == KVCalAttendeeRsvp8YES)
attendee->SetResponseRequested(ETrue);
else
attendee->SetResponseRequested(EFalse);
}
// Check for EXPECT parameter
CParserParam* expect = (*properties)[count]->Param(KVCalAttendee8EXPECT);
if (expect)
{
if (expect->Value() == KVCalAttendeeExpect8FYI)
attendee->SetVCalExpect(CCalAttendee::EVCalFyi);
else if (expect->Value() == KVCalAttendeeExpect8REQUIRE)
attendee->SetVCalExpect(CCalAttendee::EVCalRequire);
else if (expect->Value() == KVCalAttendeeExpect8REQUEST)
attendee->SetVCalExpect(CCalAttendee::EVCalRequest);
else if (expect->Value() == KVCalAttendeeExpect8IMMEDIATE)
attendee->SetVCalExpect(CCalAttendee::EVCalImmediate);
}
}
// Check for a common name
CParserParam* commonname = (*properties)[count]->Param(KICalAttendeeCommonName8);
if (commonname)
{
HBufC* commonNameDesC = commonname->ValueL();
CleanupStack::PushL(commonNameDesC);
if(user)
{
user->SetCommonNameL(*commonNameDesC);
}
else if (attendee)
{
attendee->SetCommonNameL(*commonNameDesC);
}
CleanupStack::PopAndDestroy(commonNameDesC);
}
//Set phone owner
CParserParam* phoneowner = (*properties)[count]->Param(KICalAttendee8XDASHPHONEOWNER);
if(phoneowner)
{
if(user)
{
iEntry->SetPhoneOwnerL(user);
}
else if (attendee)
{
iEntry->SetPhoneOwnerL(attendee);
}
}
}//for
}//if property
CleanupStack::PopAndDestroy(properties);
}
// Import the categories property
// For each category, try and match the name of the category with the standard category types.
// If this fails, the category is assumed to be an extended category type and the "X-" prefix
// is removed
//
void CVCalToAgendaEntryConverter::ImportCategoriesPropertyL(CVersitParser& aParser, const TDesC8& aToken)
{
// get properties but don't take ownership of the elements of the array
CArrayPtr<CParserProperty>* properties = aParser.PropertyL(aToken, TUid::Uid(KVersitPropertyCDesCArrayUid), EFalse);
if (properties)
{
CleanupStack::PushL(properties);
CDesCArray* categories = static_cast<CParserPropertyValueCDesCArray*>((*properties)[0]->Value())->Value();
for (TInt count=0; count < categories->Count(); count++)
{
TPtrC categoryName=categories->MdcaPoint(count);
CCalCategory* category = NULL;
//match category name to standard ones
CCalCategory::TCalCategoryType type = (CCalCategory::TCalCategoryType)(-1);
if (categoryName.CompareF(KVCalCategoriesAPPOINTMENT)==0)
{
type = CCalCategory::ECalAppointment;
}
else if(categoryName.CompareF(KVCalCategoriesBUSINESS)==0)
{
type = CCalCategory::ECalBusiness;
}
else if(categoryName.CompareF(KVCalCategoriesEDUCATION)==0)
{
type = CCalCategory::ECalEducation;
}
else if(categoryName.CompareF(KVCalCategoriesHOLIDAY)==0)
{
type = CCalCategory::ECalHoliday;
}
else if(categoryName.CompareF(KVCalCategoriesMEETING)==0)
{
type = CCalCategory::ECalMeeting;
}
else if(categoryName.CompareF(KVCalCategoriesMISCELLANEOUS)==0)
{
type = CCalCategory::ECalMiscellaneous;
}
else if(categoryName.CompareF(KVCalCategoriesPERSONAL)==0)
{
type = CCalCategory::ECalPersonal;
}
else if(categoryName.CompareF(KVCalCategoriesPHONECALL)==0)
{
type = CCalCategory::ECalPhoneCall;
}
else if(categoryName.CompareF(KVCalCategoriesSICKDAY)==0)
{
type = CCalCategory::ECalSickDay;
}
else if(categoryName.CompareF(KVCalCategoriesSPECIALOCCASION)==0)
{
type = CCalCategory::ECalSpecialOccasion;
}
else if(categoryName.CompareF(KVCalCategoriesTRAVEL)==0)
{
type = CCalCategory::ECalTravel;
}
else if(categoryName.CompareF(KVCalCategoriesVACATION)==0)
{
type = CCalCategory::ECalVacation;
}
if(type>-1)
{
category = CCalCategory::NewL(type);
}
else if(categoryName.Length() > 0)
{
if (categoryName.Find(KVCalTokenXDash) == 0)
{
categoryName.Set(categoryName.Right(categoryName.Length() - 2));
}
if(categoryName.Length() > 0)
{
category = CCalCategory::NewL(categoryName);
}
}
if(category)
{
// AddCategoryL() takes ownership at the end of the function call (after calling leaving functions)
iEntry->AddCategoryL(category);
}
}
CleanupStack::PopAndDestroy(properties);
}
}
// Utility method to ensure proper cleanup in OOM
//
void ResetAndDestroyArrayOfEntries(TAny* aObject)
{
CArrayPtrFlat<CCalEntry>* array=reinterpret_cast<CArrayPtrFlat<CCalEntry>*>(aObject);
if (array)
array->ResetAndDestroy();
delete array;
}
void CVCalToAgendaEntryConverter::SetImportVCalendarValues(TBool aImportVCalendar)
{
iImportVCalendarValues = aImportVCalendar;
}
void CVCalToAgendaEntryConverter::ImportStatusPropertyL(CVersitParser& aParser, CCalEntry::TStatus& aStatus)
{
if (iImportVCalendarValues)
{
ImportVCalStatusPropertyL(aParser, aStatus);
}
else
{
ImportICalStatusPropertyL(aParser, aStatus);
}
}
void CVCalToAgendaEntryConverter::ImportICalStatusPropertyL(CVersitParser& aParser, CCalEntry::TStatus& aStatus)
{
HBufC* property=ImportDesPropertyL(aParser, KVCalTokenSTATUS);
if (!property)
{
aStatus = CCalEntry::ENullStatus;
return;
}
// BB mapped according to CCalEntryImpl::StatusL() which should be reconsidered
if (property->Length() ==0) // Property value not found - use default setting
{
aStatus = CCalEntry::ENullStatus;
}
else if (property->CompareF(KVCalStatusNEEDSACTION) == 0)
{
if (iEntry->EntryTypeL()==CCalEntry::ETodo)
{
aStatus = CCalEntry::ETodoNeedsAction;
}
else
{
aStatus = CCalEntry::EConfirmed;
}
}
else if (property->CompareF(KVCalStatusSENT) ==0 || property->CompareF(KVCalStatusDELEGATED)==0 || property->CompareF(KVCalStatusCONFIRMED) ==0 || property->CompareF(KVCalStatusACCEPTED) == 0)
{
if (iEntry->EntryTypeL()==CCalEntry::ETodo)
{
aStatus = CCalEntry::ETodoInProcess;
}
else
{
aStatus = CCalEntry::EConfirmed;
}
}
else if (property->CompareF(KVCalStatusTENTATIVE)==0)
{
if (iEntry->EntryTypeL()==CCalEntry::ETodo)
{
aStatus = CCalEntry::ETodoNeedsAction;
}
else
{
aStatus = CCalEntry::ETentative;
}
}
else if (property->CompareF(KVCalStatusDECLINED)==0)
{
aStatus = CCalEntry::ECancelled;
}
else if (property->CompareF(KVCalStatusCOMPLETED)==0)
{
if(iEntry->EntryTypeL()==CCalEntry::ETodo)
{
aStatus = CCalEntry::ETodoCompleted;
}
else
{
aStatus = CCalEntry::EConfirmed;
}
}
else // No Match found so use the default
aStatus = CCalEntry::ENullStatus;
delete property;
}
void CVCalToAgendaEntryConverter::ImportVCalStatusPropertyL(CVersitParser& aParser, CCalEntry::TStatus& aStatus)
{
HBufC* property=ImportDesPropertyL(aParser, KVCalTokenSTATUS);
if (!property || property->Length() == 0)
{
aStatus = CCalEntry::ENullStatus;
}
else if (property->CompareF(KVCalStatusNEEDSACTION) == 0)
{
aStatus = CCalEntry::EVCalNeedsAction;
}
else if (property->CompareF(KVCalStatusSENT) == 0)
{
aStatus = CCalEntry::EVCalSent;
}
else if (property->CompareF(KVCalStatusDELEGATED)== 0)
{
aStatus = CCalEntry::EVCalDelegated;
}
else if (property->CompareF(KVCalStatusCONFIRMED) == 0 && iEntry->EntryTypeL() != CCalEntry::ETodo)
{
aStatus = CCalEntry::EConfirmed;
}
else if (property->CompareF(KVCalStatusACCEPTED) == 0)
{
aStatus = CCalEntry::EVCalAccepted;
}
else if (property->CompareF(KVCalStatusTENTATIVE)==0 && iEntry->EntryTypeL() != CCalEntry::ETodo)
{
aStatus = CCalEntry::ETentative;
}
else if (property->CompareF(KVCalStatusDECLINED)==0)
{
aStatus = CCalEntry::EVCalDeclined;
}
else if (property->CompareF(KVCalStatusCOMPLETED)==0 && iEntry->EntryTypeL() == CCalEntry::ETodo)
{
aStatus = CCalEntry::ETodoCompleted;
}
delete property;
}