pimappservices/calendarvcalplugin/src/agnversit.cpp
changeset 0 f979ecb2b13e
--- /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;
+	}