pimappservices/calendarvcalplugin/src/agnversit.cpp
changeset 0 f979ecb2b13e
equal deleted inserted replaced
-1:000000000000 0:f979ecb2b13e
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "agnversit.h"
       
    17 #include <vtzrules.h>
       
    18 #include <ecom/implementationproxy.h>
       
    19 #include <calrrule.h>
       
    20 #include <calentry.h>
       
    21 #include <caldataformat.h>
       
    22 
       
    23 /**
       
    24 @internalComponent
       
    25 */
       
    26 template<class T> void CalCleanup<T>::PushResetAndDestroyL(T& aRef)
       
    27 	{
       
    28 	CleanupStack::PushL(TCleanupItem(ResetAndDestroy, &aRef));
       
    29 	}
       
    30 	
       
    31 /**
       
    32 @internalComponent
       
    33 */
       
    34 template<class T> void CalCleanup<T>::PushResetL(T& aRef)
       
    35 	{
       
    36 	CleanupStack::PushL(TCleanupItem(Reset, &aRef));
       
    37 	}
       
    38 
       
    39 /**
       
    40 @internalComponent
       
    41 */	
       
    42 template <class T> void CalCleanup<T>::ResetAndDestroy(TAny* aPtr)
       
    43 	{
       
    44 	T* self = static_cast<T*>(aPtr);
       
    45 	if (self)
       
    46 		{
       
    47 		self->ResetAndDestroy();
       
    48 		}
       
    49 	}
       
    50 	
       
    51 /**
       
    52 @internalComponent
       
    53 */	
       
    54 template <class T> void CalCleanup<T>::Reset(TAny* aPtr)
       
    55 	{
       
    56 	T self = static_cast<T>(aPtr);
       
    57 	if (self)
       
    58 		{
       
    59 		self->Reset();
       
    60 		}
       
    61 	}
       
    62 	
       
    63 /** Global function for ease of use of CalCleanup template class
       
    64 @internalComponent
       
    65 */
       
    66 template<class T> void CleanupResetAndDestroyPushL(T& aRef)
       
    67 	{
       
    68 	CalCleanup<T>::PushResetAndDestroyL(aRef);
       
    69 	}
       
    70 	
       
    71 /** Global function for ease of use of CalCleanup template class
       
    72 @internalComponent
       
    73 */
       
    74 template<class T> void CleanupResetPushL(T& aRef)
       
    75 	{
       
    76 	CalCleanup<T>::PushResetL(aRef);
       
    77 	}
       
    78 
       
    79 
       
    80 /**
       
    81  * Imports a <code>vCalendar</code> consisting of one or more
       
    82  * <code>vCalendar</code> entities.
       
    83  *
       
    84  * The <code>vCalendar</code> is read from the read stream specified and
       
    85  * its entities are converted into EPOC agenda entries and returned in
       
    86  * the array <code>aEntryArray</code>.
       
    87  *
       
    88  * @param     "RReadStream& aReadStream"
       
    89  *            The read stream which contains the
       
    90  *            <code>vCalendar</code>.
       
    91  * @param     "CArrayPtr<CCalEntry>* aEntryArray"
       
    92  *            On return, a list of the agenda entries which were
       
    93  *            imported from the <code>vCalendar</code>. The list
       
    94  *            contains the <code>vEvents</code> followed by the
       
    95  *            <code>vTodos</code>.
       
    96  */
       
    97 void CAgnVCalConverter::ImportVCalL(TInt aFlags, RReadStream& aReadStream, RPointerArray<CCalEntry>& aEntryArray)
       
    98 
       
    99 	{
       
   100 	// Create a new converter object
       
   101 	CVCalToAgendaEntryConverter* converter = new(ELeave)CVCalToAgendaEntryConverter();
       
   102 	CleanupStack::PushL(converter);
       
   103 
       
   104 	// Create a parser to internalize the entries
       
   105 	CParserVCal* vCal = CParserVCal::NewL();
       
   106 	CleanupStack::PushL(vCal);
       
   107 
       
   108 	// Japan uses SHIFT-JIS as the default charset contrary to 
       
   109 	// the vCalendar Specification which says that the default 
       
   110 	// charset should be US-ASCII. 
       
   111 	// In order to provide interoperability with this market
       
   112 	// segment, allow a flag to override the default charset in versit.
       
   113 	if(aFlags & KCalDataExchangeDefaultShiftJIS)
       
   114 	    {
       
   115 	    vCal->SetDefaultCharSet(Versit::EShiftJISCharSet);
       
   116 	    vCal->SetFlags(CVersitParser::EUseDefaultCharSetForAllProperties);
       
   117 	    }
       
   118 	vCal->InternalizeL(aReadStream);
       
   119 
       
   120 	
       
   121 	// Set the time zone converter.  iTzConverter may be NULL if the optional
       
   122 	// time zone conversion service is not available.  In this case all imported times 
       
   123 	// will be exported as local time.
       
   124 	if (iTzConnected)
       
   125 		{
       
   126 		converter->SetTzConverter(&iTzServer);
       
   127 		}
       
   128 	
       
   129 	if (aFlags & KCalDataExchangeImportStatusAsVCalendar)
       
   130 		{
       
   131 		converter->SetImportVCalendarValues(ETrue);
       
   132 		}
       
   133 	else
       
   134 		{
       
   135 		converter->SetImportVCalendarValues(ETrue);
       
   136 		}
       
   137 
       
   138 	converter->SetTzRules(ImportTzRulesL(*vCal)); // converter takes ownership of rules collection.
       
   139 	
       
   140 	CArrayPtr<CVersitParser>* entities = vCal->ArrayOfEntities(EFalse); //doesn't take ownership
       
   141 	if (entities)
       
   142 		{
       
   143 		TInt count = entities->Count();
       
   144 		for (TInt i=0; i<count; i++)
       
   145 			{
       
   146 			CVersitParser& parser = *((*entities)[i]);			
       
   147 			converter->ImportVCalL(parser, aEntryArray);
       
   148 			} 
       
   149 		}
       
   150 
       
   151 	CleanupStack::PopAndDestroy(vCal);
       
   152 	CleanupStack::PopAndDestroy(converter);
       
   153 	}
       
   154 
       
   155 
       
   156 /**
       
   157  * Exports a list of agenda entries as multiple vCalendar entities to the
       
   158  * write stream specified.
       
   159  *
       
   160  * The entries are exported either as vTodos, if they are to-dos,
       
   161  * otherwise as vEvents
       
   162  *
       
   163  * @param     "RWriteStream& aWriteStream"
       
   164  *            The stream to which the agenda entries should be
       
   165  *            externalised as vCalendar entities.
       
   166  * @param     "CArrayPtr<CCalEntry>* aEntryArray"
       
   167  *            Pointer to the array of agenda entries.
       
   168  * @param     "const Versit::TVersitCharSet aCharSet"
       
   169  *             The character encoding type
       
   170  */
       
   171 void CAgnVCalConverter::ExportVCalL(RWriteStream& aWriteStream, const RPointerArray<CCalEntry>& aEntryArray, const Versit::TVersitCharSet aCharSet)
       
   172 
       
   173 	{
       
   174 	if(aEntryArray.Count()>0)
       
   175 		{
       
   176 		iCharSet = aCharSet;
       
   177 		// Create a new converter object
       
   178 		if(!iExportConverter)
       
   179 			{
       
   180 			iExportConverter = new(ELeave)CAgendaEntryToVCalConverter;
       
   181 			}
       
   182 		iEntryArray = const_cast<RPointerArray<CCalEntry>*>(&aEntryArray);
       
   183 		// Set the time zone converter.  iTzConverter may be NULL if the optional
       
   184 		// time zone conversion service is not available.  In this case all times will 
       
   185 		// be exported as local time.
       
   186 		if (iTzConnected)
       
   187 			{
       
   188 			iExportConverter->SetTzConverter(&iTzServer);
       
   189 			}
       
   190 			
       
   191 		ExportEntryBySameTzL(aWriteStream);
       
   192 		}
       
   193 	}
       
   194 	
       
   195 void CAgnVCalConverter::ExportEntryBySameTzL(RWriteStream& aWriteStream)
       
   196 	{//To export entries into a serveral vCal according to their tz rules
       
   197 	if(!iSametzEntries)
       
   198 		{
       
   199 		iSametzEntries = new (ELeave) RPointerArray<CCalEntry>(4);
       
   200 		}
       
   201 		
       
   202 	iSametzEntries->Reset();
       
   203 	InitialiseSameTzEntryArrayL();
       
   204 	//Find entries which belong to the first tz
       
   205 	FindSameTzEntryL(*iSametzEntries);
       
   206 	CParserVCal* vCal = NULL;
       
   207 	//Expoet entries by grouping them into different tz rules 
       
   208 	while(iSametzEntries->Count()>0)
       
   209 		{//Pull entries with the same time zone in the same array and export them
       
   210 		vCal = CParserVCal::NewL(); // takes ownership of entrylist
       
   211 		CleanupStack::PushL(vCal);
       
   212 		vCal->SetDefaultCharSet(iCharSet);
       
   213 		ConvertEntryToVCalAndExportL(vCal, *iSametzEntries, aWriteStream);
       
   214 		CleanupStack::PopAndDestroy(vCal);
       
   215 		iSametzEntries->Reset();
       
   216 		FindSameTzEntryL(*iSametzEntries);//this result in fill in iSametzEntries with same tz rule and remove the their indexes from iEntryIndexToExport
       
   217 		}
       
   218 	
       
   219 	if(iEntryIndexToExport.Count()>0)
       
   220 		{
       
   221 		//Export the rest of entryies(those are entries without tz informations)
       
   222 		ExportEntryWithoutTzRuleL(aWriteStream);
       
   223 		}
       
   224 	}
       
   225 		
       
   226 void CAgnVCalConverter::ExportEntryWithoutTzRuleL(RWriteStream& aWriteStream)
       
   227 	{//This function only should be called when all entries in iEntryIndexToExport are either no-repeating or floating entry
       
   228 	CParserVCal* vCal = CParserVCal::NewL(); // takes ownership of entrylist
       
   229 	CleanupStack::PushL(vCal);
       
   230 	vCal->SetDefaultCharSet(iCharSet);
       
   231 	const TInt KCount = iEntryIndexToExport.Count();
       
   232 	for (TInt ii = 0; ii < KCount; ++ii)
       
   233 		{
       
   234 		CCalEntry* entry = (*iEntryArray)[iEntryIndexToExport[ii]];
       
   235 		if (entry)
       
   236 			{
       
   237 			TCalRRule rule;
       
   238 			__ASSERT_DEBUG(!(entry->GetRRuleL(rule)) || entry->StartTimeL().TimeMode() == TCalTime::EFloating, User::Invariant());
       
   239 			iExportConverter->ExportEntryL(entry, *vCal);
       
   240 			}
       
   241 		}
       
   242 	vCal->ExternalizeL(aWriteStream);
       
   243 	CleanupStack::PopAndDestroy(vCal);
       
   244 	}
       
   245 
       
   246 void CAgnVCalConverter::ConvertEntryToVCalAndExportL(CParserVCal* aVcal, const RPointerArray<CCalEntry>& aEntryArray, RWriteStream& aWriteStream)
       
   247 	{
       
   248 	iExportConverter->NextVCalendarL();
       
   249 	TInt count = aEntryArray.Count();
       
   250 
       
   251 	for (TInt ii = 0; ii < count; ii++)
       
   252 		{
       
   253 		CCalEntry* entry = aEntryArray[ii];
       
   254 		if (entry)
       
   255 			{
       
   256 			iExportConverter->AddTimeZonePropertiesL(*aVcal, entry);
       
   257 			iExportConverter->ExportEntryL(entry, *aVcal);
       
   258 			}
       
   259 		}
       
   260 	
       
   261 	aVcal->ExternalizeL(aWriteStream);
       
   262 	}
       
   263 	
       
   264 void CAgnVCalConverter::ImportVCalAsyncL(TInt aFlags, RReadStream& aReadStream, 
       
   265 		RPointerArray<CCalEntry>& aEntryArray, MCalDataExchangeCallBack& aObserver)
       
   266 	{
       
   267 	// Create a new converter object
       
   268 	if(iAsyncState!=EIdle)
       
   269 		{
       
   270 		User::Leave(KErrInUse);
       
   271 		}
       
   272 		
       
   273 	iImportConverter = new (ELeave) CVCalToAgendaEntryConverter();
       
   274 	iVCalArray = new (ELeave) RPointerArray<CParserVCal>();
       
   275 
       
   276 	// Read all the entries in the file. The parser will only read one.
       
   277 	iTotalNumEntry = 0;
       
   278 	TInt errcode = KErrNone;
       
   279 	while (errcode != KErrEof)
       
   280    	 	{
       
   281  		// Create a parser to internalize the entries
       
   282 		CParserVCal* vCal = CParserVCal::NewL();
       
   283 		CleanupStack::PushL(vCal);
       
   284 		// Japan uses SHIFT-JIS as the default charset contrary to 
       
   285 		// the vCalendar Specification which says that the default 
       
   286 		// charset should be US-ASCII. 
       
   287 		// In order to provide interoperability with this market
       
   288 		// segment, allow a flag to override the default charset in versit.
       
   289 		if(aFlags & KCalDataExchangeDefaultShiftJIS)
       
   290 		    {
       
   291 		    vCal->SetDefaultCharSet(Versit::EShiftJISCharSet);
       
   292 		    vCal->SetFlags(CVersitParser::EUseDefaultCharSetForAllProperties);
       
   293 		    }
       
   294   	 	TRAP( errcode, vCal->InternalizeL(aReadStream) );
       
   295   	 	if (errcode ==KErrNone)
       
   296   	 		{
       
   297   	 		CArrayPtr<CVersitParser>* entities = vCal->ArrayOfEntities(EFalse); 
       
   298   	 		TInt numEntry = entities->Count();
       
   299 	 		if(numEntry>0)
       
   300 	 			{
       
   301 	 			iVCalArray->AppendL(vCal);
       
   302 	 			CleanupStack::Pop(vCal);
       
   303 	 			iTotalNumEntry += numEntry;
       
   304 	 			}
       
   305   	 		}
       
   306   	 	else if (errcode ==KErrEof)
       
   307   	 		{
       
   308   	 		CleanupStack::PopAndDestroy(vCal);
       
   309   	 		}
       
   310 	  	else
       
   311 	  	 	{
       
   312 	  	 	User::LeaveIfError( errcode );
       
   313 	  	 	}
       
   314      	}
       
   315 
       
   316 
       
   317 	// Set the time zone converter.  iTzConverter may be NULL if the optional
       
   318 	// time zone conversion service is not available.  In this case all imported times 
       
   319 	// will be exported as local time.
       
   320 	if (iTzConnected)
       
   321 		{
       
   322 		iImportConverter->SetTzConverter(&iTzServer);
       
   323 		}
       
   324 
       
   325 	iEntryArray = &aEntryArray;
       
   326 	iTotalCounter = 0;
       
   327 	iSameTzCounter = 0;
       
   328 	iObserver = &aObserver;
       
   329 	iAsyncState = EImporting;
       
   330 	iMaxNumEntryInStep = iObserver->NumberOfEntriesToHandleAtOnce();
       
   331 	if(iTotalNumEntry > 0)
       
   332 		{
       
   333 		CTzRules* tzRule = ImportTzRulesL(*((*iVCalArray)[0]));
       
   334 		iImportConverter->SetTzRules(tzRule); // converter takes ownership of rules collection.
       
   335 		}
       
   336 	iImportExportActive->Start();
       
   337 	}
       
   338 	
       
   339 void CAgnVCalConverter::FindSameTzEntryL(RPointerArray<CCalEntry>& aSameTzEntry)
       
   340 	{
       
   341 	//Fill in aSameTzEntry with those entries with the same tz rule in iEntryArray
       
   342 	//Remove the index of the entry from iEntryIndexToExport
       
   343 	//Note that the order of the entries being exported has to be maintained 
       
   344 	CCalEntry* firstEntrywithTz = NULL;
       
   345 	for (TInt ii = 0; ii < iEntryIndexToExport.Count();  ++ii)
       
   346 		{
       
   347 		TCalRRule repeatrule;//temp veraible
       
   348 		CCalEntry* entry = (*iEntryArray)[iEntryIndexToExport[ii]];
       
   349 		if(entry->GetRRuleL(repeatrule) && entry->StartTimeL().TimeMode() != TCalTime::EFloating)
       
   350 			{//Otherwise time zone info is not needed to export
       
   351 			if(firstEntrywithTz)
       
   352 				{
       
   353 				CTzRules* rules1 = entry->TzRulesL();
       
   354 				CleanupStack::PushL(rules1);
       
   355 
       
   356 				CTzRules* rules2 = firstEntrywithTz->TzRulesL();
       
   357 				CleanupStack::PushL(rules2);
       
   358 				
       
   359 				if (rules1 && rules2 && rules1->IsEqualTo(*rules2))
       
   360 					{
       
   361 					//compare the time zone to see if it is the same as the "firstEntrywithTz"
       
   362 					aSameTzEntry.AppendL(entry);
       
   363 					iEntryIndexToExport.Remove(ii);
       
   364 					--ii;
       
   365 					}
       
   366 				CleanupStack::PopAndDestroy(rules2);
       
   367 				CleanupStack::PopAndDestroy(rules1);
       
   368 				}
       
   369 			else
       
   370 				{
       
   371 				firstEntrywithTz = entry;
       
   372 				aSameTzEntry.AppendL(entry);
       
   373 				iEntryIndexToExport.Remove(ii);
       
   374 				--ii;
       
   375 				}
       
   376 			}
       
   377 		}
       
   378 	}
       
   379 	
       
   380 void CAgnVCalConverter::FindEntryWithoutTzRuleL(RPointerArray<CCalEntry>& aSameTzEntry)
       
   381 	{
       
   382 	// This functions should be only used for asynchronous exporting (use ExportEntryWithoutTzRuleL if it is for synchronous exporting)
       
   383 	for (TInt ii = 0; ii< iEntryIndexToExport.Count();  ++ii)
       
   384 		{//Pull those entries which do not need to export tz together (either non-repeating or floating entry)
       
   385 		TCalRRule rule;
       
   386 		CCalEntry* entry = (*iEntryArray)[iEntryIndexToExport[ii]];
       
   387 		if(!entry->GetRRuleL(rule) || entry->StartTimeL().TimeMode() == TCalTime::EFloating)
       
   388 			{
       
   389 			aSameTzEntry.AppendL((*iEntryArray)[iEntryIndexToExport[ii]]);
       
   390 			iEntryIndexToExport.Remove(ii);
       
   391 			--ii;
       
   392 			}
       
   393 		}
       
   394 	}
       
   395 
       
   396 void CAgnVCalConverter::ExportVCalAsyncL(RWriteStream& aWriteStream, RPointerArray<CCalEntry>& aEntryArray, MCalDataExchangeCallBack& aObserver, const Versit::TVersitCharSet aCharSet)
       
   397 	{
       
   398 	if(iAsyncState!=EIdle)
       
   399 		{
       
   400 		User::Leave(KErrInUse);
       
   401 		}
       
   402 
       
   403 	iEntryArray = &aEntryArray;
       
   404 		
       
   405 	// Create a new converter object
       
   406 	if(!iExportConverter)
       
   407 		{
       
   408 		iExportConverter = new(ELeave)CAgendaEntryToVCalConverter;
       
   409 		}
       
   410 
       
   411 	// Set the time zone converter.  iTzConverter may be NULL if the optional
       
   412 	// time zone conversion service is not available.  In this case all times will 
       
   413 	// be exported as local time.
       
   414 	if (iTzConnected)
       
   415 		{
       
   416 		iExportConverter->SetTzConverter(&iTzServer);
       
   417 		}
       
   418 	
       
   419 	if(!iSametzEntries)
       
   420 		{
       
   421 		iSametzEntries = new(ELeave) RPointerArray<CCalEntry>;
       
   422 		}
       
   423 	iCharSet = aCharSet;
       
   424 	iSametzEntries->Reset();
       
   425 	InitialiseSameTzEntryArrayL();
       
   426 
       
   427 	iVCal = CParserVCal::NewL();
       
   428 	iVCal->SetDefaultCharSet(iCharSet);
       
   429 	
       
   430 	iTotalNumEntry = iEntryArray->Count();
       
   431 	iTotalCounter = 0;
       
   432 	iSameTzCounter = 0;
       
   433 	iObserver = &aObserver;
       
   434 	iAsyncState = EExporting;
       
   435 	iWriteStream = &aWriteStream;
       
   436 	iMaxNumEntryInStep = iObserver->NumberOfEntriesToHandleAtOnce();
       
   437 	
       
   438 	FindSameTzEntryL(*iSametzEntries);
       
   439 	if(iSametzEntries->Count()==0)
       
   440 		{
       
   441 		FindEntryWithoutTzRuleL(*iSametzEntries);
       
   442 		__ASSERT_DEBUG(iEntryIndexToExport.Count()==0, User::Invariant());
       
   443 		}
       
   444 	iExportConverter->NextVCalendarL();
       
   445 	iImportExportActive->Start();
       
   446 	}
       
   447 	
       
   448 void CAgnVCalConverter::InitialiseSameTzEntryArrayL()
       
   449 	{// Initialise the the array with the indexes of each element in iEntryArray
       
   450 	iEntryIndexToExport.Reset();
       
   451 	const TInt KCount = iEntryArray->Count();
       
   452 	for (TInt ii = 0; ii<KCount; ++ii)
       
   453 		{
       
   454 		iEntryIndexToExport.AppendL(ii);
       
   455 		}
       
   456 	}
       
   457 	
       
   458 void CCalImportExportActive::RunL()
       
   459 	{
       
   460 	switch (iConverter.AsyncState())
       
   461 		{
       
   462 		case CAgnVCalConverter::EImporting:
       
   463 			iConverter.NextImportStepL();
       
   464 			break;
       
   465 		case CAgnVCalConverter::EExporting:
       
   466 			iConverter.NextExportStepL();
       
   467 			break;
       
   468 		default:
       
   469 			case CAgnVCalConverter::EIdle:
       
   470 			Panic(EAgnVersitPanicImportExportFailure);
       
   471 			break;
       
   472 		}
       
   473 	}
       
   474 	
       
   475 CAgnVCalConverter::TState CAgnVCalConverter::AsyncState() const 
       
   476 	{
       
   477 	return iAsyncState;
       
   478 	}
       
   479 	
       
   480 void CAgnVCalConverter::CheckCompletion()
       
   481 	{
       
   482 	if (iTotalCounter == iTotalNumEntry)
       
   483 		{
       
   484 		iObserver->Completed();
       
   485 		CancelImportExport();
       
   486 		}
       
   487 	else
       
   488 		{
       
   489 		iObserver->Progress((iTotalCounter * 100) / iTotalNumEntry);
       
   490 		iImportExportActive->Start();
       
   491 		}
       
   492 	}
       
   493 	
       
   494 void CAgnVCalConverter::NextImportStepL()
       
   495 	{
       
   496 	if(iTotalNumEntry>0)
       
   497 		{
       
   498 		CArrayPtr<CVersitParser>* entities = (*iVCalArray)[0]->ArrayOfEntities(EFalse); //doesn't take ownership
       
   499 		TInt numSameTzEntry = entities->Count();
       
   500 		TInt count = ((numSameTzEntry - iSameTzCounter) > iMaxNumEntryInStep)?iMaxNumEntryInStep:(numSameTzEntry - iSameTzCounter); 
       
   501 		RPointerArray<CCalEntry> importedEntries;
       
   502 		CleanupResetAndDestroyPushL(importedEntries);
       
   503 
       
   504 		for (TInt i = 0; i < count; i++)
       
   505 			{
       
   506 			CVersitParser& parser = *((*entities)[i + iSameTzCounter ]);
       
   507 			iImportConverter->ImportVCalL(parser, importedEntries);
       
   508 			for (TInt j = 0; j < importedEntries.Count(); j++)
       
   509 				{
       
   510 				iEntryArray->AppendL((importedEntries)[j]);
       
   511 				}
       
   512 			importedEntries.Reset();
       
   513 			}
       
   514 			
       
   515 		CleanupStack::PopAndDestroy();//importedEntries
       
   516 		iTotalCounter  += count;
       
   517 		iSameTzCounter += count;
       
   518 
       
   519 		if(iSameTzCounter == numSameTzEntry)
       
   520 			{//Convert the next vCal into entries
       
   521 			delete (*iVCalArray)[0];
       
   522 			iVCalArray->Remove(0);
       
   523 		
       
   524 			if(iVCalArray->Count()>0)
       
   525 				{
       
   526 				CTzRules* tzRule = ImportTzRulesL(*((*iVCalArray)[0]));
       
   527 				iImportConverter->SetTzRules(tzRule); // converter takes ownership of rules collection.
       
   528 				iSameTzCounter = 0;
       
   529 				}
       
   530 			}
       
   531 		}
       
   532 		
       
   533 	CheckCompletion();
       
   534 	}
       
   535 	
       
   536 void CAgnVCalConverter::NextExportStepL()
       
   537 	{
       
   538 	if(iTotalNumEntry>0)
       
   539 		{
       
   540 		TInt numSameTzEntry = iSametzEntries->Count();
       
   541 		//decide how many entries to export in this step
       
   542 		TInt count = ((numSameTzEntry - iSameTzCounter) > iMaxNumEntryInStep)?iMaxNumEntryInStep:(numSameTzEntry - iSameTzCounter); 
       
   543 		for (TInt i = 0; i < count; i++)
       
   544 			{
       
   545 			CCalEntry* entry = (*iSametzEntries)[i + iSameTzCounter];
       
   546 			if (entry)
       
   547 				{
       
   548 				iExportConverter->AddTimeZonePropertiesL(*iVCal, entry);
       
   549 				iExportConverter->ExportEntryL(entry, *iVCal);
       
   550 				}
       
   551 			}
       
   552 			
       
   553 		iTotalCounter += count;
       
   554 		iSameTzCounter += count;
       
   555 
       
   556 		if (iSameTzCounter == numSameTzEntry)
       
   557 			{//Add time zone property 
       
   558 			iExportConverter->NextVCalendarL();
       
   559 			//calling AddTimeZone Properties for all entries
       
   560 			//iExportConverter->AddTimeZonePropertiesL(*iVCal, (*iSametzEntries)[0]);
       
   561 			iVCal->ExternalizeL(*iWriteStream);
       
   562 			delete iVCal;
       
   563 			iVCal = NULL;
       
   564 			//Find out next group entries which are in the same time zone
       
   565 			if(iEntryIndexToExport.Count()>0)
       
   566 				{
       
   567 				iVCal = CParserVCal::NewL();
       
   568 				iVCal->SetDefaultCharSet(iCharSet);
       
   569 				iSametzEntries->Reset();
       
   570 				FindSameTzEntryL(*iSametzEntries);
       
   571 				if(iSametzEntries->Count()==0)
       
   572 					{
       
   573 					FindEntryWithoutTzRuleL(*iSametzEntries);
       
   574 					}
       
   575 				iSameTzCounter = 0;
       
   576 				}
       
   577 			}
       
   578 		}
       
   579 	CheckCompletion();
       
   580 	}
       
   581 
       
   582 void CAgnVCalConverter::CancelImportExport(TInt aError)
       
   583 /**
       
   584  * This function destroys import/export convertor objects and resets async state.
       
   585  * @param "TInt aError"
       
   586  *        Error during operation passed to the observer.
       
   587  */
       
   588 	{
       
   589 	// Propagate in case of error
       
   590 	if(aError != KErrNone)
       
   591 		{
       
   592 		iObserver->Progress(aError);
       
   593 		iObserver->Completed();
       
   594 		}
       
   595 
       
   596 	delete iImportConverter;
       
   597 	iImportConverter = NULL;
       
   598 	delete iExportConverter;
       
   599 	iExportConverter = NULL;
       
   600 	delete iVCal;
       
   601 	iVCal = NULL;
       
   602 	if(iVCalArray)
       
   603 		{
       
   604 		iVCalArray->ResetAndDestroy();
       
   605 		}
       
   606 	delete iVCalArray;
       
   607 	iVCalArray = NULL;
       
   608 	iAsyncState = EIdle;
       
   609 	}
       
   610 /**
       
   611  * Provides indication of validity of Daylight property during import
       
   612  *
       
   613  * At the moment, this means the following are all true:
       
   614  *    1) start year is not earlier than 1900
       
   615  *    2) end year is not later than 2100
       
   616  *    3) end year is not earlier than start year
       
   617  *
       
   618  * @param aDaylightProperty The property to be validated.
       
   619  *
       
   620  * @return ETrue if aDaylightProperty satisfies above conditions. EFalse otherwise.
       
   621  */
       
   622 TBool CAgnVCalConverter::ValidDaylightProperty(CParserProperty& aDaylightProperty) const
       
   623     {		
       
   624     CParserPropertyValue* propertyValue = aDaylightProperty.Value();
       
   625  
       
   626     if (propertyValue)
       
   627        {
       
   628        CVersitDaylight* checkProperty = static_cast<CParserPropertyValueDaylight*>(propertyValue)->Value();
       
   629 
       
   630        if (checkProperty && checkProperty->iSavings) 
       
   631           {
       
   632           TInt startYear = checkProperty->iStartTime->iDateTime.Year();
       
   633           TInt endYear = checkProperty->iEndTime->iDateTime.Year();
       
   634           TTime minDateTime = TCalTime::MinTime();
       
   635           TTime maxDateTime = TCalTime::MaxTime();
       
   636           
       
   637           return ( (startYear	>= minDateTime.DateTime().Year()) &&
       
   638                    (endYear 	<= maxDateTime.DateTime().Year()) &&
       
   639                    (endYear 	>= startYear) );
       
   640           }
       
   641        }
       
   642  
       
   643     return EFalse;
       
   644     }
       
   645 
       
   646 /**
       
   647  * Creates a collection of rules that describes a set UTC offsets and when they 
       
   648  * should be applied to local times within entities observed by the "home" 
       
   649  * system that created the vCalendar object.
       
   650  *
       
   651  * @param aCalParser A handle to the vCalendar parser.
       
   652  *
       
   653  * @return The time zone rules collection, NULL if no rules can be created.
       
   654  */
       
   655 CTzRules* CAgnVCalConverter::ImportTzRulesL(CParserVCal& aCalParser) const
       
   656 	{
       
   657     TBool acceptable = EFalse;
       
   658 	TTimeIntervalMinutes stdOffset = StandardTimeOffsetL(aCalParser);
       
   659 
       
   660 	// access properties but don't take ownership
       
   661 	CArrayPtr<CParserProperty>* daylightProperties = 
       
   662     aCalParser.PropertyL(KVersitTokenDAYLIGHT, TUid::Uid(KVersitPropertyDaylightUid), EFalse);
       
   663 
       
   664     if (daylightProperties)
       
   665        {
       
   666        // check for an acceptable daylight property 
       
   667        // if there are none, treat this vCal as if it has no daylight properties at all
       
   668        const TInt KCount = daylightProperties->Count();
       
   669        for (TInt i = 0; i < KCount && ! acceptable; i++) 
       
   670            {	
       
   671            if (ValidDaylightProperty(*daylightProperties->At(i)))	
       
   672        		  {
       
   673               acceptable = ETrue;
       
   674               }
       
   675            }
       
   676 
       
   677        delete daylightProperties; 
       
   678        daylightProperties = NULL;
       
   679        }
       
   680         
       
   681     // Need either a TZ property or at least one acceptable DAYLIGHT property         
       
   682     // before TZ rules can be generated
       
   683 
       
   684 	if ((stdOffset.Int() == KMaxTInt) && acceptable) 
       
   685 	   {
       
   686        // no TZ property supplied, but a DAYLIGHT property is useable   
       
   687        // set initial TZ offset to 0
       
   688        stdOffset = 0;
       
   689        }
       
   690 
       
   691 	CTzRules* rules = NULL;
       
   692 	// if TZ offset is set, we have something to process
       
   693 	if (stdOffset.Int() != KMaxTInt)
       
   694 		{
       
   695 		rules = DaylightRulesL(aCalParser, stdOffset);
       
   696 		rules->SetInitialStdTimeOffset(stdOffset.Int());
       
   697 		}
       
   698 	return rules;
       
   699 	}
       
   700 
       
   701 static TInt CompareDaylightProperties(const CParserProperty& aLeftProperty, const CParserProperty& aRightProperty)
       
   702 	{
       
   703 	CParserPropertyValueDaylight* leftValue = static_cast<CParserPropertyValueDaylight*>(aLeftProperty.Value());
       
   704 	CParserPropertyValueDaylight* rightValue = static_cast<CParserPropertyValueDaylight*>(aRightProperty.Value());
       
   705 
       
   706 	if (leftValue->Value()->iStartTimeSortKey >= rightValue->Value()->iStartTimeSortKey)
       
   707 		return 1;
       
   708 	return -1;
       
   709 	}
       
   710 
       
   711 /**
       
   712  * Creates a collection of rules that describes a set of UTC offsets and when they 
       
   713  * should be applied to local times within entities observed by the "home" 
       
   714  * system that created the vCalendar object.
       
   715  *
       
   716  * @param aCalParser A handle to the vCalendar parser.
       
   717  * @param aStdOffset The standard time UTC offset.  Specify TTimeIntervalMinutes(KMaxTInt) if not known.
       
   718  * @return The time zone rules collection, NULL if no rules can be created.
       
   719  */
       
   720 CTzRules* CAgnVCalConverter::DaylightRulesL(CParserVCal& aCalParser, TTimeIntervalMinutes aStdOffset) const
       
   721 	{
       
   722 	__ASSERT_DEBUG(aStdOffset.Int() != KMaxTInt, User::Invariant());
       
   723 	
       
   724 	CTzRules* rules = CTzRules::NewL(0, KMaxTUint);
       
   725 	CleanupStack::PushL(rules);
       
   726 
       
   727 	// get properties but don't take ownership of the elements of the array
       
   728 	CArrayPtr<CParserProperty>* daylightProperties = aCalParser.PropertyL(KVersitTokenDAYLIGHT, TUid::Uid(KVersitPropertyDaylightUid), EFalse);
       
   729 	
       
   730 	TTime nextRuleStart = Time::MinTTime();	// start of the next std rule
       
   731 	TTzTimeReference nextRuleTimeRef = ETzUtcTimeReference;
       
   732 
       
   733 	TInt  prevRuleOffset = aStdOffset.Int();
       
   734 
       
   735 	if (daylightProperties != NULL)
       
   736 		{
       
   737 		CleanupStack::PushL(daylightProperties);
       
   738 		// re-order the daylight properties
       
   739 		TLinearOrder<CParserProperty> daylightPropertySort(CompareDaylightProperties);
       
   740 		RPointerArray<CParserProperty> newDaylightPropArray;
       
   741 		TInt i;
       
   742 		for (i = 0; i < daylightProperties->Count(); i++)
       
   743 			{
       
   744             // insert only valid imported properties 
       
   745             if (ValidDaylightProperty(*daylightProperties->At(i)))
       
   746                 {
       
   747   			    TInt err = newDaylightPropArray.InsertInOrder(daylightProperties->At(i), daylightPropertySort);
       
   748   			    if (err != KErrAlreadyExists)
       
   749   			    	{
       
   750   			    	User::LeaveIfError(err);
       
   751   			    	}
       
   752                 }
       
   753 			}
       
   754 		CleanupStack::PopAndDestroy(daylightProperties);
       
   755 
       
   756 		CVersitDaylight* daylightProperty = NULL;
       
   757 		TInt n = newDaylightPropArray.Count();
       
   758 		
       
   759 		// For each DAYLIGHT property, create a standard time rule prior to the
       
   760 		// daylight saving time period, and then create the daylight savings rule
       
   761 		// following on from the standard time period.
       
   762 		for (i = 0; i < n; ++i)	
       
   763 			{
       
   764 			daylightProperty = static_cast<CParserPropertyValueDaylight*>(newDaylightPropArray[i]->Value())->Value();
       
   765 			
       
   766 			if (daylightProperty && daylightProperty->iSavings)
       
   767 				{
       
   768 				TTime dstStartTime(daylightProperty->iStartTime->iDateTime);
       
   769 				TTime dstEndTime(daylightProperty->iEndTime->iDateTime);
       
   770 				TInt  dstOffset = daylightProperty->iOffset.Int() / 60; // Convert seconds to minutes.
       
   771 				
       
   772 				// standard time rule (STD)
       
   773 				TTzRule stdRule = TzRuleL(prevRuleOffset, 	// old offset, minutes
       
   774 							    		  aStdOffset, 		// new offset (=STD offset), minutes
       
   775 										  nextRuleStart,	// from the end of prev rule
       
   776 								dstStartTime-TTimeIntervalSeconds(1));	// to DST start time less 1sec
       
   777 																		// (e.g. 01:59:59)
       
   778 				// daylight saving time rule (DST)
       
   779 				TTzRule dstRule = TzRuleL(aStdOffset,		// old offset (=STD offset), minutes
       
   780 							    		  dstOffset,		// new offset (=DST offset), minutes
       
   781 							    		  dstStartTime, 	// start
       
   782 										  dstEndTime); 		// end time
       
   783 				
       
   784 				prevRuleOffset = dstOffset;				
       
   785 
       
   786 				// 01:59:00->02:00:00; 01:59:59->02:00:00; 02:00:00->02:00:00; 01:29:59->01:30:00
       
   787 				nextRuleStart = dstEndTime;
       
   788 				nextRuleStart.RoundUpToNextMinute();
       
   789 				if (nextRuleStart.DateTime().Minute()%10==9) nextRuleStart+=TTimeIntervalMinutes(1);
       
   790 
       
   791 				// time references
       
   792 				stdRule.iFrom.iTimeReference = nextRuleTimeRef;
       
   793 				stdRule.iTimeReference = nextRuleTimeRef;
       
   794 				if (daylightProperty->iStartTime->iRelativeTime!=TVersitDateTime::EIsUTC)
       
   795 					{
       
   796 					stdRule.iTo.iTimeReference = ETzWallTimeReference;
       
   797 					dstRule.iFrom.iTimeReference = ETzWallTimeReference;
       
   798 					dstRule.iTimeReference = ETzWallTimeReference;
       
   799 					}
       
   800 				if (daylightProperty->iEndTime->iRelativeTime!=TVersitDateTime::EIsUTC)
       
   801 					{
       
   802 					nextRuleTimeRef = ETzWallTimeReference;
       
   803 					dstRule.iTo.iTimeReference = ETzWallTimeReference;
       
   804 					}
       
   805 				else
       
   806 					{
       
   807 					nextRuleTimeRef = ETzUtcTimeReference;
       
   808 					}
       
   809 			
       
   810 				rules->AddRuleL(stdRule);	// add STD rule
       
   811 				rules->AddRuleL(dstRule);	// add DST rule
       
   812 				}
       
   813 			}
       
   814 		newDaylightPropArray.Reset();
       
   815 		}
       
   816 	
       
   817 	// Create a standard time rule after the last daylight saving period.
       
   818 	TTzRule lastStdRule = TzRuleL(prevRuleOffset, aStdOffset, nextRuleStart, Time::MaxTTime());
       
   819 	lastStdRule.iFrom.iTimeReference = nextRuleTimeRef;
       
   820 	lastStdRule.iTimeReference = nextRuleTimeRef;	
       
   821 	rules->AddRuleL(lastStdRule);
       
   822 	CleanupStack::Pop(rules);
       
   823 
       
   824 	return rules;
       
   825 	}
       
   826 	
       
   827 
       
   828 /**
       
   829  * Creates a rule that stores the UTC offset and when it should be
       
   830  * applied to local times within entities specified by the "home" 
       
   831  * system that created the vCalendar object.
       
   832  *
       
   833  * @param aOldTzOffset The UTC offset (minutes since midnight) before the rule applies.
       
   834  * @param aNewTzOffset The UTC offset (minutes since midnight) when the rule applies.
       
   835  * @param aStartTime   The time from when the rule applies.
       
   836  * @param aEndTime     The time to when the rule applies.
       
   837  */
       
   838 TTzRule CAgnVCalConverter::TzRuleL(TTimeIntervalMinutes aOldTzOffset, TTimeIntervalMinutes aNewTzOffset, TTime aStartTime, TTime aEndTime) const
       
   839 	{
       
   840 	TTzRule rule;
       
   841 
       
   842 	// There needs to be better boundary checking when converting from TTime to TUInt...
       
   843 	// Ideally, the rule should accept TTimes.
       
   844 	
       
   845 	if (aStartTime != Time::MinTTime())
       
   846 		{
       
   847 		rule.iFrom.iTime = aStartTime;
       
   848 		// rule.iFrom.iTimeReference defaults to ETzUtcTimeReference	
       
   849 		rule.iMonth = aStartTime.DateTime().Month();
       
   850 		rule.iDayOfMonth = aStartTime.DateTime().Day();
       
   851 		rule.iTimeOfChange = aStartTime.DateTime().Hour() * 60 + aStartTime.DateTime().Minute();
       
   852 		}
       
   853 	
       
   854 	if (aEndTime == Time::MaxTTime())
       
   855 		{
       
   856 		rule.iTo = TTimeWithReference::Max();
       
   857 		// rule.iTo.iTimeReference defaults to ETzUtcTimeReference
       
   858 		}
       
   859 	else
       
   860 		{
       
   861 		rule.iTo = aEndTime;
       
   862 		// rule.iTo.iTimeReference defaults to ETzUtcTimeReference
       
   863 		}
       
   864 
       
   865 	rule.iOldLocalTimeOffset = aOldTzOffset.Int();
       
   866 	rule.iNewLocalTimeOffset = aNewTzOffset.Int();
       
   867 	rule.iDayRule = ETzFixedDate;
       
   868 	rule.iTimeReference = ETzUtcTimeReference;
       
   869 
       
   870 	return rule;
       
   871 	}
       
   872 
       
   873 
       
   874 /**
       
   875  * The TZ property represents the standard time zone of the 
       
   876  * "home" system that created the vCalendar object.  If there are
       
   877  * more than one TZ properties, then only the first TZ property value
       
   878  * is returned.
       
   879  * 
       
   880  * @param  aCalParser A handle to the vCalendar parser.
       
   881  * @return TTimeIntervalMinutes(KMaxTInt) if there is no TZ property, TZ property value otherwise.
       
   882  */
       
   883 TTimeIntervalMinutes CAgnVCalConverter::StandardTimeOffsetL(CParserVCal& aCalParser) const
       
   884 	{
       
   885 	// get properties but don't take ownership of the elements of the array
       
   886 	CArrayPtr<CParserProperty>* tzCollection = aCalParser.PropertyL(KVersitTokenTZ, TUid::Uid(KVersitPropertyTimeZoneUid), EFalse);
       
   887 
       
   888 	if (tzCollection == NULL)
       
   889 		return TTimeIntervalMinutes(KMaxTInt);
       
   890 	
       
   891 	CleanupStack::PushL(tzCollection);
       
   892 	TTimeIntervalSeconds stdTime = static_cast<CParserPropertyValueTimeZone*>((*tzCollection)[0]->Value())->Value();
       
   893 	CleanupStack::PopAndDestroy(tzCollection);
       
   894 
       
   895 	return TTimeIntervalMinutes(stdTime.Int() / 60);
       
   896 	}
       
   897 	
       
   898 /**  
       
   899  * This function destroys the TAgnVCalConverter object created by the gate function,
       
   900  * and the CTzConverter object if it exists
       
   901  */
       
   902 CAgnVCalConverter::~CAgnVCalConverter()
       
   903 	{	
       
   904 	delete iImportConverter;
       
   905 	
       
   906 	if (iVCalArray)
       
   907 		{
       
   908 		iVCalArray->ResetAndDestroy();
       
   909 		}
       
   910 	delete iVCalArray;
       
   911 	
       
   912 	delete iImportExportActive;
       
   913 	delete iExportConverter;
       
   914 
       
   915 	iTzServer.Close();
       
   916 	if(iSametzEntries)
       
   917 		{
       
   918 		iSametzEntries->Close();
       
   919 		delete iSametzEntries;
       
   920 		}
       
   921 		
       
   922 	iEntryIndexToExport.Close();
       
   923 	}
       
   924 
       
   925 /**
       
   926  * Standard 2-phase construction
       
   927  */
       
   928 CAgnVCalConverter* CAgnVCalConverter::NewL()
       
   929    	{
       
   930    	CAgnVCalConverter* self = new (ELeave) CAgnVCalConverter;
       
   931    	CleanupStack::PushL(self);
       
   932    	self->ConstructL();
       
   933    	CleanupStack::Pop(self);
       
   934    	return self;
       
   935    	}
       
   936   
       
   937 
       
   938 
       
   939 // Export the implementation collection function
       
   940 const TImplementationProxy ImplementationTable[] = 
       
   941     {
       
   942     IMPLEMENTATION_PROXY_ENTRY(0x102035F6, CAgnVCalConverter::NewL)
       
   943     };
       
   944 
       
   945 EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
       
   946     {
       
   947     aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
       
   948     return ImplementationTable;
       
   949     }
       
   950   
       
   951 
       
   952 
       
   953 void CAgnVCalConverter::ConstructL()
       
   954 	{
       
   955 	iTzConnected = EFalse;
       
   956 	// Timezone conversion library is not guaranteed to be available.
       
   957 	// If it is not available, then AgnVersit will ignore DST rules
       
   958 	// and default to its previous behaviour
       
   959 	const TInt result = iTzServer.Connect();
       
   960 	if (result == KErrNone)
       
   961 		{
       
   962 		iTzConnected = ETrue;
       
   963 		}
       
   964 	else if (result != KErrNotFound)
       
   965 		{
       
   966 		User::Leave(result);
       
   967 		}
       
   968 	iImportExportActive = new (ELeave) CCalImportExportActive(*this);
       
   969 	iAsyncState = EIdle;
       
   970 	}
       
   971 	
       
   972 /**
       
   973  * Panic the thread with AGNVERSIT as the category
       
   974  * 
       
   975  * @param aPanic Panic number
       
   976  */
       
   977 void Panic(TAgnVersitPanic aPanic)
       
   978 	{
       
   979 	_LIT(KAgnVersitPanicCategory,"AGNVERSIT");
       
   980 	User::Panic(KAgnVersitPanicCategory,aPanic);
       
   981 	}
       
   982 
       
   983 /**
       
   984  * Standard Epoc32 Dll Entry point
       
   985  */
       
   986 
       
   987 
       
   988 // Active object to control asynchronous import / export
       
   989 CCalImportExportActive::CCalImportExportActive(CAgnVCalConverter& aConverter) :
       
   990 	CActive(EPriorityLow), iConverter(aConverter)
       
   991 	{
       
   992 	CActiveScheduler::Add(this);
       
   993 	}
       
   994 
       
   995 CCalImportExportActive::~CCalImportExportActive()
       
   996 	{
       
   997 	Cancel();
       
   998 	}
       
   999 	
       
  1000 void CCalImportExportActive::Start()
       
  1001 	{
       
  1002 	if (!IsActive())
       
  1003 		{
       
  1004 		TRequestStatus* status = &iStatus;
       
  1005 		User::RequestComplete(status, KErrNone);
       
  1006 		SetActive();
       
  1007 		}
       
  1008 	}
       
  1009 
       
  1010 
       
  1011 void CCalImportExportActive::DoCancel()
       
  1012 	{
       
  1013 	iConverter.CancelImportExport();
       
  1014 	}
       
  1015 
       
  1016 TInt CCalImportExportActive::RunError(TInt aError)
       
  1017 	{
       
  1018 	// Propogate error		
       
  1019 	iConverter.CancelImportExport(aError);
       
  1020 	return KErrNone;
       
  1021 	}