--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pimappservices/calendarvcalplugin/src/agnversit.cpp Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,1021 @@
+// 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 "agnversit.h"
+#include <vtzrules.h>
+#include <ecom/implementationproxy.h>
+#include <calrrule.h>
+#include <calentry.h>
+#include <caldataformat.h>
+
+/**
+@internalComponent
+*/
+template<class T> void CalCleanup<T>::PushResetAndDestroyL(T& aRef)
+ {
+ CleanupStack::PushL(TCleanupItem(ResetAndDestroy, &aRef));
+ }
+
+/**
+@internalComponent
+*/
+template<class T> void CalCleanup<T>::PushResetL(T& aRef)
+ {
+ CleanupStack::PushL(TCleanupItem(Reset, &aRef));
+ }
+
+/**
+@internalComponent
+*/
+template <class T> void CalCleanup<T>::ResetAndDestroy(TAny* aPtr)
+ {
+ T* self = static_cast<T*>(aPtr);
+ if (self)
+ {
+ self->ResetAndDestroy();
+ }
+ }
+
+/**
+@internalComponent
+*/
+template <class T> void CalCleanup<T>::Reset(TAny* aPtr)
+ {
+ T self = static_cast<T>(aPtr);
+ if (self)
+ {
+ self->Reset();
+ }
+ }
+
+/** Global function for ease of use of CalCleanup template class
+@internalComponent
+*/
+template<class T> void CleanupResetAndDestroyPushL(T& aRef)
+ {
+ CalCleanup<T>::PushResetAndDestroyL(aRef);
+ }
+
+/** Global function for ease of use of CalCleanup template class
+@internalComponent
+*/
+template<class T> void CleanupResetPushL(T& aRef)
+ {
+ CalCleanup<T>::PushResetL(aRef);
+ }
+
+
+/**
+ * Imports a <code>vCalendar</code> consisting of one or more
+ * <code>vCalendar</code> entities.
+ *
+ * The <code>vCalendar</code> is read from the read stream specified and
+ * its entities are converted into EPOC agenda entries and returned in
+ * the array <code>aEntryArray</code>.
+ *
+ * @param "RReadStream& aReadStream"
+ * The read stream which contains the
+ * <code>vCalendar</code>.
+ * @param "CArrayPtr<CCalEntry>* aEntryArray"
+ * On return, a list of the agenda entries which were
+ * imported from the <code>vCalendar</code>. The list
+ * contains the <code>vEvents</code> followed by the
+ * <code>vTodos</code>.
+ */
+void CAgnVCalConverter::ImportVCalL(TInt aFlags, RReadStream& aReadStream, RPointerArray<CCalEntry>& aEntryArray)
+
+ {
+ // Create a new converter object
+ CVCalToAgendaEntryConverter* converter = new(ELeave)CVCalToAgendaEntryConverter();
+ CleanupStack::PushL(converter);
+
+ // Create a parser to internalize the entries
+ CParserVCal* vCal = CParserVCal::NewL();
+ CleanupStack::PushL(vCal);
+
+ // Japan uses SHIFT-JIS as the default charset contrary to
+ // the vCalendar Specification which says that the default
+ // charset should be US-ASCII.
+ // In order to provide interoperability with this market
+ // segment, allow a flag to override the default charset in versit.
+ if(aFlags & KCalDataExchangeDefaultShiftJIS)
+ {
+ vCal->SetDefaultCharSet(Versit::EShiftJISCharSet);
+ vCal->SetFlags(CVersitParser::EUseDefaultCharSetForAllProperties);
+ }
+ vCal->InternalizeL(aReadStream);
+
+
+ // Set the time zone converter. iTzConverter may be NULL if the optional
+ // time zone conversion service is not available. In this case all imported times
+ // will be exported as local time.
+ if (iTzConnected)
+ {
+ converter->SetTzConverter(&iTzServer);
+ }
+
+ if (aFlags & KCalDataExchangeImportStatusAsVCalendar)
+ {
+ converter->SetImportVCalendarValues(ETrue);
+ }
+ else
+ {
+ converter->SetImportVCalendarValues(ETrue);
+ }
+
+ converter->SetTzRules(ImportTzRulesL(*vCal)); // converter takes ownership of rules collection.
+
+ CArrayPtr<CVersitParser>* entities = vCal->ArrayOfEntities(EFalse); //doesn't take ownership
+ if (entities)
+ {
+ TInt count = entities->Count();
+ for (TInt i=0; i<count; i++)
+ {
+ CVersitParser& parser = *((*entities)[i]);
+ converter->ImportVCalL(parser, aEntryArray);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(vCal);
+ CleanupStack::PopAndDestroy(converter);
+ }
+
+
+/**
+ * Exports a list of agenda entries as multiple vCalendar entities to the
+ * write stream specified.
+ *
+ * The entries are exported either as vTodos, if they are to-dos,
+ * otherwise as vEvents
+ *
+ * @param "RWriteStream& aWriteStream"
+ * The stream to which the agenda entries should be
+ * externalised as vCalendar entities.
+ * @param "CArrayPtr<CCalEntry>* aEntryArray"
+ * Pointer to the array of agenda entries.
+ * @param "const Versit::TVersitCharSet aCharSet"
+ * The character encoding type
+ */
+void CAgnVCalConverter::ExportVCalL(RWriteStream& aWriteStream, const RPointerArray<CCalEntry>& aEntryArray, const Versit::TVersitCharSet aCharSet)
+
+ {
+ if(aEntryArray.Count()>0)
+ {
+ iCharSet = aCharSet;
+ // Create a new converter object
+ if(!iExportConverter)
+ {
+ iExportConverter = new(ELeave)CAgendaEntryToVCalConverter;
+ }
+ iEntryArray = const_cast<RPointerArray<CCalEntry>*>(&aEntryArray);
+ // Set the time zone converter. iTzConverter may be NULL if the optional
+ // time zone conversion service is not available. In this case all times will
+ // be exported as local time.
+ if (iTzConnected)
+ {
+ iExportConverter->SetTzConverter(&iTzServer);
+ }
+
+ ExportEntryBySameTzL(aWriteStream);
+ }
+ }
+
+void CAgnVCalConverter::ExportEntryBySameTzL(RWriteStream& aWriteStream)
+ {//To export entries into a serveral vCal according to their tz rules
+ if(!iSametzEntries)
+ {
+ iSametzEntries = new (ELeave) RPointerArray<CCalEntry>(4);
+ }
+
+ iSametzEntries->Reset();
+ InitialiseSameTzEntryArrayL();
+ //Find entries which belong to the first tz
+ FindSameTzEntryL(*iSametzEntries);
+ CParserVCal* vCal = NULL;
+ //Expoet entries by grouping them into different tz rules
+ while(iSametzEntries->Count()>0)
+ {//Pull entries with the same time zone in the same array and export them
+ vCal = CParserVCal::NewL(); // takes ownership of entrylist
+ CleanupStack::PushL(vCal);
+ vCal->SetDefaultCharSet(iCharSet);
+ ConvertEntryToVCalAndExportL(vCal, *iSametzEntries, aWriteStream);
+ CleanupStack::PopAndDestroy(vCal);
+ iSametzEntries->Reset();
+ FindSameTzEntryL(*iSametzEntries);//this result in fill in iSametzEntries with same tz rule and remove the their indexes from iEntryIndexToExport
+ }
+
+ if(iEntryIndexToExport.Count()>0)
+ {
+ //Export the rest of entryies(those are entries without tz informations)
+ ExportEntryWithoutTzRuleL(aWriteStream);
+ }
+ }
+
+void CAgnVCalConverter::ExportEntryWithoutTzRuleL(RWriteStream& aWriteStream)
+ {//This function only should be called when all entries in iEntryIndexToExport are either no-repeating or floating entry
+ CParserVCal* vCal = CParserVCal::NewL(); // takes ownership of entrylist
+ CleanupStack::PushL(vCal);
+ vCal->SetDefaultCharSet(iCharSet);
+ const TInt KCount = iEntryIndexToExport.Count();
+ for (TInt ii = 0; ii < KCount; ++ii)
+ {
+ CCalEntry* entry = (*iEntryArray)[iEntryIndexToExport[ii]];
+ if (entry)
+ {
+ TCalRRule rule;
+ __ASSERT_DEBUG(!(entry->GetRRuleL(rule)) || entry->StartTimeL().TimeMode() == TCalTime::EFloating, User::Invariant());
+ iExportConverter->ExportEntryL(entry, *vCal);
+ }
+ }
+ vCal->ExternalizeL(aWriteStream);
+ CleanupStack::PopAndDestroy(vCal);
+ }
+
+void CAgnVCalConverter::ConvertEntryToVCalAndExportL(CParserVCal* aVcal, const RPointerArray<CCalEntry>& aEntryArray, RWriteStream& aWriteStream)
+ {
+ iExportConverter->NextVCalendarL();
+ TInt count = aEntryArray.Count();
+
+ for (TInt ii = 0; ii < count; ii++)
+ {
+ CCalEntry* entry = aEntryArray[ii];
+ if (entry)
+ {
+ iExportConverter->AddTimeZonePropertiesL(*aVcal, entry);
+ iExportConverter->ExportEntryL(entry, *aVcal);
+ }
+ }
+
+ aVcal->ExternalizeL(aWriteStream);
+ }
+
+void CAgnVCalConverter::ImportVCalAsyncL(TInt aFlags, RReadStream& aReadStream,
+ RPointerArray<CCalEntry>& aEntryArray, MCalDataExchangeCallBack& aObserver)
+ {
+ // Create a new converter object
+ if(iAsyncState!=EIdle)
+ {
+ User::Leave(KErrInUse);
+ }
+
+ iImportConverter = new (ELeave) CVCalToAgendaEntryConverter();
+ iVCalArray = new (ELeave) RPointerArray<CParserVCal>();
+
+ // Read all the entries in the file. The parser will only read one.
+ iTotalNumEntry = 0;
+ TInt errcode = KErrNone;
+ while (errcode != KErrEof)
+ {
+ // Create a parser to internalize the entries
+ CParserVCal* vCal = CParserVCal::NewL();
+ CleanupStack::PushL(vCal);
+ // Japan uses SHIFT-JIS as the default charset contrary to
+ // the vCalendar Specification which says that the default
+ // charset should be US-ASCII.
+ // In order to provide interoperability with this market
+ // segment, allow a flag to override the default charset in versit.
+ if(aFlags & KCalDataExchangeDefaultShiftJIS)
+ {
+ vCal->SetDefaultCharSet(Versit::EShiftJISCharSet);
+ vCal->SetFlags(CVersitParser::EUseDefaultCharSetForAllProperties);
+ }
+ TRAP( errcode, vCal->InternalizeL(aReadStream) );
+ if (errcode ==KErrNone)
+ {
+ CArrayPtr<CVersitParser>* entities = vCal->ArrayOfEntities(EFalse);
+ TInt numEntry = entities->Count();
+ if(numEntry>0)
+ {
+ iVCalArray->AppendL(vCal);
+ CleanupStack::Pop(vCal);
+ iTotalNumEntry += numEntry;
+ }
+ }
+ else if (errcode ==KErrEof)
+ {
+ CleanupStack::PopAndDestroy(vCal);
+ }
+ else
+ {
+ User::LeaveIfError( errcode );
+ }
+ }
+
+
+ // Set the time zone converter. iTzConverter may be NULL if the optional
+ // time zone conversion service is not available. In this case all imported times
+ // will be exported as local time.
+ if (iTzConnected)
+ {
+ iImportConverter->SetTzConverter(&iTzServer);
+ }
+
+ iEntryArray = &aEntryArray;
+ iTotalCounter = 0;
+ iSameTzCounter = 0;
+ iObserver = &aObserver;
+ iAsyncState = EImporting;
+ iMaxNumEntryInStep = iObserver->NumberOfEntriesToHandleAtOnce();
+ if(iTotalNumEntry > 0)
+ {
+ CTzRules* tzRule = ImportTzRulesL(*((*iVCalArray)[0]));
+ iImportConverter->SetTzRules(tzRule); // converter takes ownership of rules collection.
+ }
+ iImportExportActive->Start();
+ }
+
+void CAgnVCalConverter::FindSameTzEntryL(RPointerArray<CCalEntry>& aSameTzEntry)
+ {
+ //Fill in aSameTzEntry with those entries with the same tz rule in iEntryArray
+ //Remove the index of the entry from iEntryIndexToExport
+ //Note that the order of the entries being exported has to be maintained
+ CCalEntry* firstEntrywithTz = NULL;
+ for (TInt ii = 0; ii < iEntryIndexToExport.Count(); ++ii)
+ {
+ TCalRRule repeatrule;//temp veraible
+ CCalEntry* entry = (*iEntryArray)[iEntryIndexToExport[ii]];
+ if(entry->GetRRuleL(repeatrule) && entry->StartTimeL().TimeMode() != TCalTime::EFloating)
+ {//Otherwise time zone info is not needed to export
+ if(firstEntrywithTz)
+ {
+ CTzRules* rules1 = entry->TzRulesL();
+ CleanupStack::PushL(rules1);
+
+ CTzRules* rules2 = firstEntrywithTz->TzRulesL();
+ CleanupStack::PushL(rules2);
+
+ if (rules1 && rules2 && rules1->IsEqualTo(*rules2))
+ {
+ //compare the time zone to see if it is the same as the "firstEntrywithTz"
+ aSameTzEntry.AppendL(entry);
+ iEntryIndexToExport.Remove(ii);
+ --ii;
+ }
+ CleanupStack::PopAndDestroy(rules2);
+ CleanupStack::PopAndDestroy(rules1);
+ }
+ else
+ {
+ firstEntrywithTz = entry;
+ aSameTzEntry.AppendL(entry);
+ iEntryIndexToExport.Remove(ii);
+ --ii;
+ }
+ }
+ }
+ }
+
+void CAgnVCalConverter::FindEntryWithoutTzRuleL(RPointerArray<CCalEntry>& aSameTzEntry)
+ {
+ // This functions should be only used for asynchronous exporting (use ExportEntryWithoutTzRuleL if it is for synchronous exporting)
+ for (TInt ii = 0; ii< iEntryIndexToExport.Count(); ++ii)
+ {//Pull those entries which do not need to export tz together (either non-repeating or floating entry)
+ TCalRRule rule;
+ CCalEntry* entry = (*iEntryArray)[iEntryIndexToExport[ii]];
+ if(!entry->GetRRuleL(rule) || entry->StartTimeL().TimeMode() == TCalTime::EFloating)
+ {
+ aSameTzEntry.AppendL((*iEntryArray)[iEntryIndexToExport[ii]]);
+ iEntryIndexToExport.Remove(ii);
+ --ii;
+ }
+ }
+ }
+
+void CAgnVCalConverter::ExportVCalAsyncL(RWriteStream& aWriteStream, RPointerArray<CCalEntry>& aEntryArray, MCalDataExchangeCallBack& aObserver, const Versit::TVersitCharSet aCharSet)
+ {
+ if(iAsyncState!=EIdle)
+ {
+ User::Leave(KErrInUse);
+ }
+
+ iEntryArray = &aEntryArray;
+
+ // Create a new converter object
+ if(!iExportConverter)
+ {
+ iExportConverter = new(ELeave)CAgendaEntryToVCalConverter;
+ }
+
+ // Set the time zone converter. iTzConverter may be NULL if the optional
+ // time zone conversion service is not available. In this case all times will
+ // be exported as local time.
+ if (iTzConnected)
+ {
+ iExportConverter->SetTzConverter(&iTzServer);
+ }
+
+ if(!iSametzEntries)
+ {
+ iSametzEntries = new(ELeave) RPointerArray<CCalEntry>;
+ }
+ iCharSet = aCharSet;
+ iSametzEntries->Reset();
+ InitialiseSameTzEntryArrayL();
+
+ iVCal = CParserVCal::NewL();
+ iVCal->SetDefaultCharSet(iCharSet);
+
+ iTotalNumEntry = iEntryArray->Count();
+ iTotalCounter = 0;
+ iSameTzCounter = 0;
+ iObserver = &aObserver;
+ iAsyncState = EExporting;
+ iWriteStream = &aWriteStream;
+ iMaxNumEntryInStep = iObserver->NumberOfEntriesToHandleAtOnce();
+
+ FindSameTzEntryL(*iSametzEntries);
+ if(iSametzEntries->Count()==0)
+ {
+ FindEntryWithoutTzRuleL(*iSametzEntries);
+ __ASSERT_DEBUG(iEntryIndexToExport.Count()==0, User::Invariant());
+ }
+ iExportConverter->NextVCalendarL();
+ iImportExportActive->Start();
+ }
+
+void CAgnVCalConverter::InitialiseSameTzEntryArrayL()
+ {// Initialise the the array with the indexes of each element in iEntryArray
+ iEntryIndexToExport.Reset();
+ const TInt KCount = iEntryArray->Count();
+ for (TInt ii = 0; ii<KCount; ++ii)
+ {
+ iEntryIndexToExport.AppendL(ii);
+ }
+ }
+
+void CCalImportExportActive::RunL()
+ {
+ switch (iConverter.AsyncState())
+ {
+ case CAgnVCalConverter::EImporting:
+ iConverter.NextImportStepL();
+ break;
+ case CAgnVCalConverter::EExporting:
+ iConverter.NextExportStepL();
+ break;
+ default:
+ case CAgnVCalConverter::EIdle:
+ Panic(EAgnVersitPanicImportExportFailure);
+ break;
+ }
+ }
+
+CAgnVCalConverter::TState CAgnVCalConverter::AsyncState() const
+ {
+ return iAsyncState;
+ }
+
+void CAgnVCalConverter::CheckCompletion()
+ {
+ if (iTotalCounter == iTotalNumEntry)
+ {
+ iObserver->Completed();
+ CancelImportExport();
+ }
+ else
+ {
+ iObserver->Progress((iTotalCounter * 100) / iTotalNumEntry);
+ iImportExportActive->Start();
+ }
+ }
+
+void CAgnVCalConverter::NextImportStepL()
+ {
+ if(iTotalNumEntry>0)
+ {
+ CArrayPtr<CVersitParser>* entities = (*iVCalArray)[0]->ArrayOfEntities(EFalse); //doesn't take ownership
+ TInt numSameTzEntry = entities->Count();
+ TInt count = ((numSameTzEntry - iSameTzCounter) > iMaxNumEntryInStep)?iMaxNumEntryInStep:(numSameTzEntry - iSameTzCounter);
+ RPointerArray<CCalEntry> importedEntries;
+ CleanupResetAndDestroyPushL(importedEntries);
+
+ for (TInt i = 0; i < count; i++)
+ {
+ CVersitParser& parser = *((*entities)[i + iSameTzCounter ]);
+ iImportConverter->ImportVCalL(parser, importedEntries);
+ for (TInt j = 0; j < importedEntries.Count(); j++)
+ {
+ iEntryArray->AppendL((importedEntries)[j]);
+ }
+ importedEntries.Reset();
+ }
+
+ CleanupStack::PopAndDestroy();//importedEntries
+ iTotalCounter += count;
+ iSameTzCounter += count;
+
+ if(iSameTzCounter == numSameTzEntry)
+ {//Convert the next vCal into entries
+ delete (*iVCalArray)[0];
+ iVCalArray->Remove(0);
+
+ if(iVCalArray->Count()>0)
+ {
+ CTzRules* tzRule = ImportTzRulesL(*((*iVCalArray)[0]));
+ iImportConverter->SetTzRules(tzRule); // converter takes ownership of rules collection.
+ iSameTzCounter = 0;
+ }
+ }
+ }
+
+ CheckCompletion();
+ }
+
+void CAgnVCalConverter::NextExportStepL()
+ {
+ if(iTotalNumEntry>0)
+ {
+ TInt numSameTzEntry = iSametzEntries->Count();
+ //decide how many entries to export in this step
+ TInt count = ((numSameTzEntry - iSameTzCounter) > iMaxNumEntryInStep)?iMaxNumEntryInStep:(numSameTzEntry - iSameTzCounter);
+ for (TInt i = 0; i < count; i++)
+ {
+ CCalEntry* entry = (*iSametzEntries)[i + iSameTzCounter];
+ if (entry)
+ {
+ iExportConverter->AddTimeZonePropertiesL(*iVCal, entry);
+ iExportConverter->ExportEntryL(entry, *iVCal);
+ }
+ }
+
+ iTotalCounter += count;
+ iSameTzCounter += count;
+
+ if (iSameTzCounter == numSameTzEntry)
+ {//Add time zone property
+ iExportConverter->NextVCalendarL();
+ //calling AddTimeZone Properties for all entries
+ //iExportConverter->AddTimeZonePropertiesL(*iVCal, (*iSametzEntries)[0]);
+ iVCal->ExternalizeL(*iWriteStream);
+ delete iVCal;
+ iVCal = NULL;
+ //Find out next group entries which are in the same time zone
+ if(iEntryIndexToExport.Count()>0)
+ {
+ iVCal = CParserVCal::NewL();
+ iVCal->SetDefaultCharSet(iCharSet);
+ iSametzEntries->Reset();
+ FindSameTzEntryL(*iSametzEntries);
+ if(iSametzEntries->Count()==0)
+ {
+ FindEntryWithoutTzRuleL(*iSametzEntries);
+ }
+ iSameTzCounter = 0;
+ }
+ }
+ }
+ CheckCompletion();
+ }
+
+void CAgnVCalConverter::CancelImportExport(TInt aError)
+/**
+ * This function destroys import/export convertor objects and resets async state.
+ * @param "TInt aError"
+ * Error during operation passed to the observer.
+ */
+ {
+ // Propagate in case of error
+ if(aError != KErrNone)
+ {
+ iObserver->Progress(aError);
+ iObserver->Completed();
+ }
+
+ delete iImportConverter;
+ iImportConverter = NULL;
+ delete iExportConverter;
+ iExportConverter = NULL;
+ delete iVCal;
+ iVCal = NULL;
+ if(iVCalArray)
+ {
+ iVCalArray->ResetAndDestroy();
+ }
+ delete iVCalArray;
+ iVCalArray = NULL;
+ iAsyncState = EIdle;
+ }
+/**
+ * Provides indication of validity of Daylight property during import
+ *
+ * At the moment, this means the following are all true:
+ * 1) start year is not earlier than 1900
+ * 2) end year is not later than 2100
+ * 3) end year is not earlier than start year
+ *
+ * @param aDaylightProperty The property to be validated.
+ *
+ * @return ETrue if aDaylightProperty satisfies above conditions. EFalse otherwise.
+ */
+TBool CAgnVCalConverter::ValidDaylightProperty(CParserProperty& aDaylightProperty) const
+ {
+ CParserPropertyValue* propertyValue = aDaylightProperty.Value();
+
+ if (propertyValue)
+ {
+ CVersitDaylight* checkProperty = static_cast<CParserPropertyValueDaylight*>(propertyValue)->Value();
+
+ if (checkProperty && checkProperty->iSavings)
+ {
+ TInt startYear = checkProperty->iStartTime->iDateTime.Year();
+ TInt endYear = checkProperty->iEndTime->iDateTime.Year();
+ TTime minDateTime = TCalTime::MinTime();
+ TTime maxDateTime = TCalTime::MaxTime();
+
+ return ( (startYear >= minDateTime.DateTime().Year()) &&
+ (endYear <= maxDateTime.DateTime().Year()) &&
+ (endYear >= startYear) );
+ }
+ }
+
+ return EFalse;
+ }
+
+/**
+ * Creates a collection of rules that describes a set UTC offsets and when they
+ * should be applied to local times within entities observed by the "home"
+ * system that created the vCalendar object.
+ *
+ * @param aCalParser A handle to the vCalendar parser.
+ *
+ * @return The time zone rules collection, NULL if no rules can be created.
+ */
+CTzRules* CAgnVCalConverter::ImportTzRulesL(CParserVCal& aCalParser) const
+ {
+ TBool acceptable = EFalse;
+ TTimeIntervalMinutes stdOffset = StandardTimeOffsetL(aCalParser);
+
+ // access properties but don't take ownership
+ CArrayPtr<CParserProperty>* daylightProperties =
+ aCalParser.PropertyL(KVersitTokenDAYLIGHT, TUid::Uid(KVersitPropertyDaylightUid), EFalse);
+
+ if (daylightProperties)
+ {
+ // check for an acceptable daylight property
+ // if there are none, treat this vCal as if it has no daylight properties at all
+ const TInt KCount = daylightProperties->Count();
+ for (TInt i = 0; i < KCount && ! acceptable; i++)
+ {
+ if (ValidDaylightProperty(*daylightProperties->At(i)))
+ {
+ acceptable = ETrue;
+ }
+ }
+
+ delete daylightProperties;
+ daylightProperties = NULL;
+ }
+
+ // Need either a TZ property or at least one acceptable DAYLIGHT property
+ // before TZ rules can be generated
+
+ if ((stdOffset.Int() == KMaxTInt) && acceptable)
+ {
+ // no TZ property supplied, but a DAYLIGHT property is useable
+ // set initial TZ offset to 0
+ stdOffset = 0;
+ }
+
+ CTzRules* rules = NULL;
+ // if TZ offset is set, we have something to process
+ if (stdOffset.Int() != KMaxTInt)
+ {
+ rules = DaylightRulesL(aCalParser, stdOffset);
+ rules->SetInitialStdTimeOffset(stdOffset.Int());
+ }
+ return rules;
+ }
+
+static TInt CompareDaylightProperties(const CParserProperty& aLeftProperty, const CParserProperty& aRightProperty)
+ {
+ CParserPropertyValueDaylight* leftValue = static_cast<CParserPropertyValueDaylight*>(aLeftProperty.Value());
+ CParserPropertyValueDaylight* rightValue = static_cast<CParserPropertyValueDaylight*>(aRightProperty.Value());
+
+ if (leftValue->Value()->iStartTimeSortKey >= rightValue->Value()->iStartTimeSortKey)
+ return 1;
+ return -1;
+ }
+
+/**
+ * Creates a collection of rules that describes a set of UTC offsets and when they
+ * should be applied to local times within entities observed by the "home"
+ * system that created the vCalendar object.
+ *
+ * @param aCalParser A handle to the vCalendar parser.
+ * @param aStdOffset The standard time UTC offset. Specify TTimeIntervalMinutes(KMaxTInt) if not known.
+ * @return The time zone rules collection, NULL if no rules can be created.
+ */
+CTzRules* CAgnVCalConverter::DaylightRulesL(CParserVCal& aCalParser, TTimeIntervalMinutes aStdOffset) const
+ {
+ __ASSERT_DEBUG(aStdOffset.Int() != KMaxTInt, User::Invariant());
+
+ CTzRules* rules = CTzRules::NewL(0, KMaxTUint);
+ CleanupStack::PushL(rules);
+
+ // get properties but don't take ownership of the elements of the array
+ CArrayPtr<CParserProperty>* daylightProperties = aCalParser.PropertyL(KVersitTokenDAYLIGHT, TUid::Uid(KVersitPropertyDaylightUid), EFalse);
+
+ TTime nextRuleStart = Time::MinTTime(); // start of the next std rule
+ TTzTimeReference nextRuleTimeRef = ETzUtcTimeReference;
+
+ TInt prevRuleOffset = aStdOffset.Int();
+
+ if (daylightProperties != NULL)
+ {
+ CleanupStack::PushL(daylightProperties);
+ // re-order the daylight properties
+ TLinearOrder<CParserProperty> daylightPropertySort(CompareDaylightProperties);
+ RPointerArray<CParserProperty> newDaylightPropArray;
+ TInt i;
+ for (i = 0; i < daylightProperties->Count(); i++)
+ {
+ // insert only valid imported properties
+ if (ValidDaylightProperty(*daylightProperties->At(i)))
+ {
+ TInt err = newDaylightPropArray.InsertInOrder(daylightProperties->At(i), daylightPropertySort);
+ if (err != KErrAlreadyExists)
+ {
+ User::LeaveIfError(err);
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy(daylightProperties);
+
+ CVersitDaylight* daylightProperty = NULL;
+ TInt n = newDaylightPropArray.Count();
+
+ // For each DAYLIGHT property, create a standard time rule prior to the
+ // daylight saving time period, and then create the daylight savings rule
+ // following on from the standard time period.
+ for (i = 0; i < n; ++i)
+ {
+ daylightProperty = static_cast<CParserPropertyValueDaylight*>(newDaylightPropArray[i]->Value())->Value();
+
+ if (daylightProperty && daylightProperty->iSavings)
+ {
+ TTime dstStartTime(daylightProperty->iStartTime->iDateTime);
+ TTime dstEndTime(daylightProperty->iEndTime->iDateTime);
+ TInt dstOffset = daylightProperty->iOffset.Int() / 60; // Convert seconds to minutes.
+
+ // standard time rule (STD)
+ TTzRule stdRule = TzRuleL(prevRuleOffset, // old offset, minutes
+ aStdOffset, // new offset (=STD offset), minutes
+ nextRuleStart, // from the end of prev rule
+ dstStartTime-TTimeIntervalSeconds(1)); // to DST start time less 1sec
+ // (e.g. 01:59:59)
+ // daylight saving time rule (DST)
+ TTzRule dstRule = TzRuleL(aStdOffset, // old offset (=STD offset), minutes
+ dstOffset, // new offset (=DST offset), minutes
+ dstStartTime, // start
+ dstEndTime); // end time
+
+ prevRuleOffset = dstOffset;
+
+ // 01:59:00->02:00:00; 01:59:59->02:00:00; 02:00:00->02:00:00; 01:29:59->01:30:00
+ nextRuleStart = dstEndTime;
+ nextRuleStart.RoundUpToNextMinute();
+ if (nextRuleStart.DateTime().Minute()%10==9) nextRuleStart+=TTimeIntervalMinutes(1);
+
+ // time references
+ stdRule.iFrom.iTimeReference = nextRuleTimeRef;
+ stdRule.iTimeReference = nextRuleTimeRef;
+ if (daylightProperty->iStartTime->iRelativeTime!=TVersitDateTime::EIsUTC)
+ {
+ stdRule.iTo.iTimeReference = ETzWallTimeReference;
+ dstRule.iFrom.iTimeReference = ETzWallTimeReference;
+ dstRule.iTimeReference = ETzWallTimeReference;
+ }
+ if (daylightProperty->iEndTime->iRelativeTime!=TVersitDateTime::EIsUTC)
+ {
+ nextRuleTimeRef = ETzWallTimeReference;
+ dstRule.iTo.iTimeReference = ETzWallTimeReference;
+ }
+ else
+ {
+ nextRuleTimeRef = ETzUtcTimeReference;
+ }
+
+ rules->AddRuleL(stdRule); // add STD rule
+ rules->AddRuleL(dstRule); // add DST rule
+ }
+ }
+ newDaylightPropArray.Reset();
+ }
+
+ // Create a standard time rule after the last daylight saving period.
+ TTzRule lastStdRule = TzRuleL(prevRuleOffset, aStdOffset, nextRuleStart, Time::MaxTTime());
+ lastStdRule.iFrom.iTimeReference = nextRuleTimeRef;
+ lastStdRule.iTimeReference = nextRuleTimeRef;
+ rules->AddRuleL(lastStdRule);
+ CleanupStack::Pop(rules);
+
+ return rules;
+ }
+
+
+/**
+ * Creates a rule that stores the UTC offset and when it should be
+ * applied to local times within entities specified by the "home"
+ * system that created the vCalendar object.
+ *
+ * @param aOldTzOffset The UTC offset (minutes since midnight) before the rule applies.
+ * @param aNewTzOffset The UTC offset (minutes since midnight) when the rule applies.
+ * @param aStartTime The time from when the rule applies.
+ * @param aEndTime The time to when the rule applies.
+ */
+TTzRule CAgnVCalConverter::TzRuleL(TTimeIntervalMinutes aOldTzOffset, TTimeIntervalMinutes aNewTzOffset, TTime aStartTime, TTime aEndTime) const
+ {
+ TTzRule rule;
+
+ // There needs to be better boundary checking when converting from TTime to TUInt...
+ // Ideally, the rule should accept TTimes.
+
+ if (aStartTime != Time::MinTTime())
+ {
+ rule.iFrom.iTime = aStartTime;
+ // rule.iFrom.iTimeReference defaults to ETzUtcTimeReference
+ rule.iMonth = aStartTime.DateTime().Month();
+ rule.iDayOfMonth = aStartTime.DateTime().Day();
+ rule.iTimeOfChange = aStartTime.DateTime().Hour() * 60 + aStartTime.DateTime().Minute();
+ }
+
+ if (aEndTime == Time::MaxTTime())
+ {
+ rule.iTo = TTimeWithReference::Max();
+ // rule.iTo.iTimeReference defaults to ETzUtcTimeReference
+ }
+ else
+ {
+ rule.iTo = aEndTime;
+ // rule.iTo.iTimeReference defaults to ETzUtcTimeReference
+ }
+
+ rule.iOldLocalTimeOffset = aOldTzOffset.Int();
+ rule.iNewLocalTimeOffset = aNewTzOffset.Int();
+ rule.iDayRule = ETzFixedDate;
+ rule.iTimeReference = ETzUtcTimeReference;
+
+ return rule;
+ }
+
+
+/**
+ * The TZ property represents the standard time zone of the
+ * "home" system that created the vCalendar object. If there are
+ * more than one TZ properties, then only the first TZ property value
+ * is returned.
+ *
+ * @param aCalParser A handle to the vCalendar parser.
+ * @return TTimeIntervalMinutes(KMaxTInt) if there is no TZ property, TZ property value otherwise.
+ */
+TTimeIntervalMinutes CAgnVCalConverter::StandardTimeOffsetL(CParserVCal& aCalParser) const
+ {
+ // get properties but don't take ownership of the elements of the array
+ CArrayPtr<CParserProperty>* tzCollection = aCalParser.PropertyL(KVersitTokenTZ, TUid::Uid(KVersitPropertyTimeZoneUid), EFalse);
+
+ if (tzCollection == NULL)
+ return TTimeIntervalMinutes(KMaxTInt);
+
+ CleanupStack::PushL(tzCollection);
+ TTimeIntervalSeconds stdTime = static_cast<CParserPropertyValueTimeZone*>((*tzCollection)[0]->Value())->Value();
+ CleanupStack::PopAndDestroy(tzCollection);
+
+ return TTimeIntervalMinutes(stdTime.Int() / 60);
+ }
+
+/**
+ * This function destroys the TAgnVCalConverter object created by the gate function,
+ * and the CTzConverter object if it exists
+ */
+CAgnVCalConverter::~CAgnVCalConverter()
+ {
+ delete iImportConverter;
+
+ if (iVCalArray)
+ {
+ iVCalArray->ResetAndDestroy();
+ }
+ delete iVCalArray;
+
+ delete iImportExportActive;
+ delete iExportConverter;
+
+ iTzServer.Close();
+ if(iSametzEntries)
+ {
+ iSametzEntries->Close();
+ delete iSametzEntries;
+ }
+
+ iEntryIndexToExport.Close();
+ }
+
+/**
+ * Standard 2-phase construction
+ */
+CAgnVCalConverter* CAgnVCalConverter::NewL()
+ {
+ CAgnVCalConverter* self = new (ELeave) CAgnVCalConverter;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+
+// Export the implementation collection function
+const TImplementationProxy ImplementationTable[] =
+ {
+ IMPLEMENTATION_PROXY_ENTRY(0x102035F6, CAgnVCalConverter::NewL)
+ };
+
+EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
+ {
+ aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
+ return ImplementationTable;
+ }
+
+
+
+void CAgnVCalConverter::ConstructL()
+ {
+ iTzConnected = EFalse;
+ // Timezone conversion library is not guaranteed to be available.
+ // If it is not available, then AgnVersit will ignore DST rules
+ // and default to its previous behaviour
+ const TInt result = iTzServer.Connect();
+ if (result == KErrNone)
+ {
+ iTzConnected = ETrue;
+ }
+ else if (result != KErrNotFound)
+ {
+ User::Leave(result);
+ }
+ iImportExportActive = new (ELeave) CCalImportExportActive(*this);
+ iAsyncState = EIdle;
+ }
+
+/**
+ * Panic the thread with AGNVERSIT as the category
+ *
+ * @param aPanic Panic number
+ */
+void Panic(TAgnVersitPanic aPanic)
+ {
+ _LIT(KAgnVersitPanicCategory,"AGNVERSIT");
+ User::Panic(KAgnVersitPanicCategory,aPanic);
+ }
+
+/**
+ * Standard Epoc32 Dll Entry point
+ */
+
+
+// Active object to control asynchronous import / export
+CCalImportExportActive::CCalImportExportActive(CAgnVCalConverter& aConverter) :
+ CActive(EPriorityLow), iConverter(aConverter)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CCalImportExportActive::~CCalImportExportActive()
+ {
+ Cancel();
+ }
+
+void CCalImportExportActive::Start()
+ {
+ if (!IsActive())
+ {
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, KErrNone);
+ SetActive();
+ }
+ }
+
+
+void CCalImportExportActive::DoCancel()
+ {
+ iConverter.CancelImportExport();
+ }
+
+TInt CCalImportExportActive::RunError(TInt aError)
+ {
+ // Propogate error
+ iConverter.CancelImportExport(aError);
+ return KErrNone;
+ }