calendarengines/agnversit2/src/AgnVersit2Exporter.cpp
changeset 0 f979ecb2b13e
equal deleted inserted replaced
-1:000000000000 0:f979ecb2b13e
       
     1 /*
       
     2 * Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   This file contains iCal exporter implementation.
       
    15 *                Converts symbian agenda entries to iCal data.
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 // Class include.
       
    22 #include "AgnVersit2Exporter.h"
       
    23 
       
    24 //debug
       
    25 #include "calendarengines_debug.h"
       
    26 
       
    27 // Agenda includes.
       
    28 #include <calalarm.h>					// CCalAlarm
       
    29 #include <calcategory.h>				// CCalCategory
       
    30 #include <calentry.h>					// CCalEntry
       
    31 #include <calrrule.h>					// TCalRRule
       
    32 #include <caluser.h>					// CCalUser
       
    33 #include <vtzrules.h>					// CVTzActualisedRules
       
    34 
       
    35 // Versit includes.
       
    36 #include "ICal.h"						// CICal
       
    37 #include "ICalComponent.h"				// CICalComponent
       
    38 #include "ICalKeyWords.h"				// Literals used during export
       
    39 #include "ICalProperty.h"				// CICalProperty
       
    40 #include "ICalValue.h"					// CICalValue
       
    41 #include "ICalBase.h"					// TICalMethod
       
    42 
       
    43 // AgnVersit2 includes.
       
    44 #include "AgnVersit2StringProvider.h"	// CAgnVersit2StringProvider
       
    45 #include "AgnExternalInterface.h"		// TAgnEntryExport
       
    46 
       
    47 // Constants for timezone RRULE
       
    48 _LIT(KRRuleFreqYearly, "FREQ=YEARLY;BYMONTH=");
       
    49 _LIT(KRRuleByMonthDay, ";BYMONTHDAY=");
       
    50 _LIT(KRRuleByDayPlus, ";BYDAY=+");
       
    51 _LIT(KRRuleByDayPlusOne, ";BYDAY=+1");
       
    52 _LIT(KRRuleByDayMinusOne, ";BYDAY=-1");
       
    53 
       
    54 //iCalendar version number
       
    55 _LIT(KICalVersionNumber,"2.0");
       
    56 
       
    57 
       
    58 // Maximum characters in a GEO value should be 11 = -NNN.NNNNNN
       
    59 const TUint KGEOMaxWidthOfGeoValue = 11;
       
    60 
       
    61 /** A semi-colon character. */
       
    62 const TUint KAgnVersitTokenSemiColonVal =';';
       
    63 
       
    64 // Constant integer values
       
    65 const TInt KMaxOffsetMinutes = 720; //12 hours * 60 minutes
       
    66 const TInt KMinOffsetMinutes = -720; //-12 hours * 60 minutes
       
    67 
       
    68 const TInt KSecondsInOneMinute = 60;
       
    69 const TInt KInitialRRuleLength = 150; //RRule line length
       
    70 const TInt KMaxBufLength = 80;	//Max time zone name length
       
    71 
       
    72 /**
       
    73 Constructs a new CAgnVersit2Exporter and returns it.
       
    74 @param aObserver Application interface for error reporting.
       
    75 @param aWriteStream Stream to write output to.
       
    76 @param aStringProvider localisable string resources
       
    77 @return The new CAgnVersit2Exporter
       
    78 @internalTechnology
       
    79 */
       
    80 CAgnVersit2Exporter* CAgnVersit2Exporter::NewL(CAgnVersit2StringProvider& aStringProvider)
       
    81 	{
       
    82 	TRACE_ENTRY_POINT;
       
    83 		
       
    84 	CAgnVersit2Exporter* self = CAgnVersit2Exporter::NewLC(aStringProvider);
       
    85 	CleanupStack::Pop(self);
       
    86 	
       
    87 	TRACE_EXIT_POINT;
       
    88 	return self;
       
    89 	}
       
    90 
       
    91 /**
       
    92 Constructs a new CAgnVersit2Exporter and returns it.
       
    93 A pointer to the new object is left on the cleanup stack.
       
    94 @param aObserver Application interface for error reporting.
       
    95 @param aWriteStream Stream to write output to.
       
    96 @param aStringProvider localisable string resources
       
    97 @return The new CAgnVersit2Exporter
       
    98 @internalTechnology
       
    99 */
       
   100 CAgnVersit2Exporter* CAgnVersit2Exporter::NewLC(CAgnVersit2StringProvider& aStringProvider)
       
   101 	{
       
   102 	TRACE_ENTRY_POINT;
       
   103 	
       
   104 	CAgnVersit2Exporter* self = new (ELeave) CAgnVersit2Exporter(aStringProvider);
       
   105 	CleanupStack::PushL(self);
       
   106 	self->ConstructL();
       
   107 	
       
   108 	TRACE_EXIT_POINT;
       
   109 	return self;
       
   110 	}
       
   111 
       
   112 /**
       
   113 Destructor.
       
   114 @internalTechnology
       
   115 */
       
   116 CAgnVersit2Exporter::~CAgnVersit2Exporter()
       
   117 	{
       
   118 	TRACE_ENTRY_POINT;
       
   119 	
       
   120 	iTzNameArray.ResetAndDestroy();
       
   121 	iTimeZoneArray.ResetAndDestroy();
       
   122 	
       
   123 	TRACE_EXIT_POINT;
       
   124 	}
       
   125 /**
       
   126 Exports an array of calendar entries to a single iCalendar
       
   127 @param aEntries array of entries to export.
       
   128 @param aFlags not used.
       
   129 @internalTechnology
       
   130 */
       
   131 void CAgnVersit2Exporter::ExportL( RPointerArray<CCalEntry>& aEntries,
       
   132                                    RWriteStream& aWriteStream,
       
   133                                    TUint aExportFlags,
       
   134                                    MAgnExportObserver& aObserver )
       
   135 	{
       
   136 	TRACE_ENTRY_POINT;
       
   137 	
       
   138 	//We are exporting more than one entry to a single iCalendar. 
       
   139 	//Clear the time zone arrays, otherwise if this function is called twice
       
   140 	//components in this iCalendar may reference timezone components in a preceding
       
   141 	//iCalendar.
       
   142 	iTzNameArray.ResetAndDestroy();
       
   143 	iTimeZoneArray.ResetAndDestroy();
       
   144 		
       
   145 	iExportProperties = aExportFlags;
       
   146 	iObserver = &aObserver;
       
   147 	ASSERT( aEntries.Count() > 0 );
       
   148 	CICal* cal = AddICalLC(*aEntries[0]);
       
   149 	
       
   150 	TInt entryCount = aEntries.Count();
       
   151 	
       
   152 	TRAPD(err,
       
   153 	
       
   154 		for (TInt x = 0; x < entryCount; ++x)
       
   155 			{
       
   156 			if (iExportProperties & KAgnExportTzRules)
       
   157 				{
       
   158 				AddTimezoneL(*cal, *aEntries[x]);
       
   159 				}
       
   160 			AddComponentL(*cal, *aEntries[x]);
       
   161 			}
       
   162 		); //End TRAP
       
   163 	
       
   164 	User::LeaveIfError(err);
       
   165 
       
   166 	cal->ExternalizeL(aWriteStream);
       
   167 	CleanupStack::PopAndDestroy(cal);
       
   168 	
       
   169 	TRACE_EXIT_POINT;
       
   170 	}
       
   171 	
       
   172 /**
       
   173 Exports a given calendar entry.
       
   174 @param aEntry entry to export.
       
   175 @param aFlags not used.
       
   176 @internalTechnology
       
   177 */
       
   178 void CAgnVersit2Exporter::ExportL( const CCalEntry& aEntry,
       
   179                                    RWriteStream& aWriteStream,
       
   180                                    TUint aExportFlags,
       
   181                                    MAgnExportObserver& aObserver )
       
   182 	{
       
   183 	TRACE_ENTRY_POINT;
       
   184 	
       
   185 	//If we are exporting a single iCalendar per entry, we want to include the timezone
       
   186 	//even if we have previously encountered it.  We do this by clearing the time zone 
       
   187 	//name array
       
   188 	iTzNameArray.ResetAndDestroy();
       
   189 	iTimeZoneArray.ResetAndDestroy();
       
   190 			
       
   191 	iExportProperties = aExportFlags;
       
   192 	iObserver = &aObserver;
       
   193 	CICal* cal = AddICalLC(aEntry);
       
   194 
       
   195 	TRAPD(err,
       
   196 		if (iExportProperties & KAgnExportTzRules)
       
   197 			{
       
   198 			AddTimezoneL(*cal, aEntry);
       
   199 			}
       
   200 			AddComponentL(*cal, aEntry);
       
   201 		);
       
   202 
       
   203 
       
   204 	User::LeaveIfError(err);
       
   205 
       
   206 	cal->ExternalizeL(aWriteStream);
       
   207 	CleanupStack::PopAndDestroy(cal);
       
   208 	
       
   209 	TRACE_EXIT_POINT;
       
   210 	}
       
   211 
       
   212 /**
       
   213 Constructor.
       
   214 @param aObserver Application interface for error reporting.
       
   215 @param aWriteStream Stream to write output to.
       
   216 @param aStringProvider localisable string resources
       
   217 @internalTechnology
       
   218 */
       
   219 CAgnVersit2Exporter::CAgnVersit2Exporter(CAgnVersit2StringProvider& aStringProvider) :
       
   220 	iStringProvider(aStringProvider)
       
   221 	{
       
   222 	TRACE_ENTRY_POINT;
       
   223 	TRACE_EXIT_POINT;
       
   224 	}
       
   225 
       
   226 /**
       
   227 Internal construction.
       
   228 @internalTechnology
       
   229 */
       
   230 void CAgnVersit2Exporter::ConstructL()
       
   231 	{
       
   232 	TRACE_ENTRY_POINT;
       
   233 	iTimezoneIndex = KErrNotFound;
       
   234 	
       
   235 	TRACE_EXIT_POINT;
       
   236 	}
       
   237 
       
   238 /**
       
   239 Creates a new CICal*, adds any properties and returns it. The new object is
       
   240 left on the cleanup stack.
       
   241 @code
       
   242 ICalendar components can have the following properties:
       
   243 	PRODID: This is fixed for all exports from this device.
       
   244 	VERSION: Should	only ever be 2.0 for iCalendar v1 (vCalendar 2).
       
   245 	METHOD: Member data from aEntry.
       
   246 @endcode
       
   247 @param aEntry entry to export.
       
   248 @return newly created CICal*.
       
   249 @internalTechnology
       
   250 */
       
   251 CICal* CAgnVersit2Exporter::AddICalLC(const CCalEntry& aEntry) const
       
   252 	{
       
   253 	TRACE_ENTRY_POINT;
       
   254 	
       
   255 	CICal* cal = CICal::NewLC();
       
   256 	cal->AddPropertyL(KICalProdId, iStringProvider.StringL(EICalProdIdValue));
       
   257 	cal->AddPropertyL(KICalVersion,KICalVersionNumber);
       
   258 
       
   259 	switch (aEntry.MethodL())
       
   260 		{
       
   261 		case CCalEntry::EMethodPublish :
       
   262 			cal->AddPropertyL(KICalMethod, KICalPublish);
       
   263 			cal->SetMethodL(CICal::EMethodPublish);
       
   264 			break;
       
   265 		case CCalEntry::EMethodRequest :
       
   266 			cal->AddPropertyL(KICalMethod, KICalRequest);
       
   267 			cal->SetMethodL(CICal::EMethodRequest);
       
   268 			break;
       
   269 		case CCalEntry::EMethodReply :
       
   270 			cal->AddPropertyL(KICalMethod, KICalReply);
       
   271 			cal->SetMethodL(CICal::EMethodReply);
       
   272 			break;
       
   273 		case CCalEntry::EMethodAdd :
       
   274 			cal->AddPropertyL(KICalMethod, KICalAdd);
       
   275 			cal->SetMethodL(CICal::EMethodAdd);
       
   276 			break;
       
   277 		case CCalEntry::EMethodCancel :
       
   278 			cal->AddPropertyL(KICalMethod, KICalCancel);
       
   279 			cal->SetMethodL(CICal::EMethodCancel);
       
   280 			break;
       
   281 		case CCalEntry::EMethodRefresh :
       
   282 			cal->AddPropertyL(KICalMethod, KICalRefresh);
       
   283 			cal->SetMethodL(CICal::EMethodRefresh);
       
   284 			break;
       
   285 		case CCalEntry::EMethodCounter :
       
   286 			cal->AddPropertyL(KICalMethod, KICalCounter);
       
   287 			cal->SetMethodL(CICal::EMethodCounter);
       
   288 			break;
       
   289 		case CCalEntry::EMethodDeclineCounter :
       
   290 			cal->AddPropertyL(KICalMethod, KICalDeclineCounter);
       
   291 			cal->SetMethodL(CICal::EMethodDeclineCounter);
       
   292 			break;
       
   293 		case CCalEntry::EMethodNone :
       
   294 			// fall through...
       
   295 		default :
       
   296 			//Add MEHTOD:PUBLISH as default if no method exists
       
   297 			//needed by outlook
       
   298 			cal->AddPropertyL(KICalMethod, KICalPublish);
       
   299 			cal->SetMethodL(CICal::EMethodPublish);
       
   300 			break;
       
   301 		}
       
   302 	
       
   303 	TRACE_EXIT_POINT;
       
   304 	return cal;
       
   305 	}
       
   306 
       
   307 
       
   308 //
       
   309 //     ADD COMPONENT METHODS
       
   310 //     =====================
       
   311 //
       
   312 
       
   313 /**
       
   314 Exports an agenda Anniversary to an iCalendar component.
       
   315 @param aAnniv component to add to.
       
   316 @param aEntry Entry containing information about the anniversary.
       
   317 @internalTechnology
       
   318 */
       
   319 void CAgnVersit2Exporter::AddAnnivL(CICalComponent& aAnniv, const CCalEntry& /*aEntry*/) const
       
   320 	{
       
   321 	TRACE_ENTRY_POINT;
       
   322 	
       
   323 	//Add 'X-PARAM' identifier
       
   324 	if (iExportProperties & KAgnExportXProp)
       
   325 		{
       
   326 		aAnniv.AddPropertyL( iStringProvider.StringL(EICalXParamType),
       
   327 		                     iStringProvider.StringL(EICalXParamAnniversary) );
       
   328 		}
       
   329 	
       
   330 	TRACE_EXIT_POINT;
       
   331 	}
       
   332 
       
   333 
       
   334 /**
       
   335 Adds an alarm to a component.
       
   336 @code
       
   337 
       
   338 RFC 2445 states that an alarm MUST have an ACTION and TRIGGER property. We can
       
   339 retrieve the trigger property value from the alarm offset, but Agenda does not
       
   340 support the ACTION property.
       
   341 
       
   342 An alarm is defined as:
       
   343 
       
   344 	"BEGIN" ":" "VALARM" CRLF
       
   345 	(audioprop / dispprop / emailprop / procprop)
       
   346 	"END" ":" "VALARM" CRLF
       
   347 
       
   348 where audioprop / dispprop / emailprop and procprop are all values of the
       
   349 ACTION property.
       
   350 
       
   351 An ACTION property value of AUDIO only requires an additional TRIGGER property,
       
   352 all other properties are optional.  To comply with RFC 2445, all alarms will be
       
   353 exported with the following property:
       
   354 
       
   355 	ACTION:AUDIO
       
   356 
       
   357 as to set ACTION to any other value would require more properties, which we do
       
   358 not have values for.
       
   359 
       
   360 @endcode
       
   361 @param aComponent Component to add the VALARM component to
       
   362 @param aEntry Entry to extract ALARM information from
       
   363 @internalTechnology
       
   364 */
       
   365 void CAgnVersit2Exporter::AddAlarmL(CICalComponent& aComponent, const CCalEntry& aEntry) const
       
   366 	{
       
   367 	TRACE_ENTRY_POINT;
       
   368 	
       
   369 	CCalAlarm* alarm = aEntry.AlarmL();
       
   370 	if (alarm)
       
   371 		{
       
   372 		CleanupStack::PushL(alarm);
       
   373 		CICalComponent& component = aComponent.AddComponentL(CICalBase::EICalAlarm);
       
   374 		CICalValue* triggerVal = CICalValue::NewLC();
       
   375 		triggerVal->SetDurationL(TTimeIntervalSeconds(-alarm->TimeOffset().Int() * KSecondsInOneMinute));
       
   376 		CleanupStack::Pop(triggerVal);
       
   377 		component.AddPropertyL(KICalTrigger, triggerVal); //Pass ownership
       
   378 		component.AddPropertyL(KICalAction, KICalAudio);
       
   379 		CleanupStack::PopAndDestroy(alarm);
       
   380 		}
       
   381 	
       
   382 	TRACE_EXIT_POINT;
       
   383 	}
       
   384 
       
   385 /**
       
   386 Adds an appointment to a component.
       
   387 @param aAppt Component to add the appointment to.
       
   388 @param aEntry Entry to extract the appointment information from.
       
   389 @internalTechnology
       
   390 */
       
   391 void CAgnVersit2Exporter::AddApptL(CICalComponent& aAppt, const CCalEntry& aEntry) const
       
   392 	{
       
   393 	TRACE_ENTRY_POINT;
       
   394 	
       
   395 	//Add 'DTEND' property
       
   396 	if (iExportProperties & KAgnExportDtEnd)
       
   397 		{
       
   398 		TCalTime time(aEntry.EndTimeL());
       
   399 		if (time.TimeUtcL() != Time::NullTTime())
       
   400 			{
       
   401 			AddDateTimePropertyL(aAppt, time, KICalDtend);
       
   402 			}
       
   403 		}
       
   404 		
       
   405 	if (iExportProperties & KAgnExportStatus)
       
   406 		{
       
   407 		//Add 'STATUS' property
       
   408 		switch (aEntry.StatusL())
       
   409 			{
       
   410 			//VEvent supports TENTATIVE, CONFIRMED, CANCELLED
       
   411 			case CCalEntry::ETentative:
       
   412 				aAppt.AddPropertyL(KICalStatus, KICalTentative);
       
   413 				break;
       
   414 			case CCalEntry::EConfirmed:
       
   415 				aAppt.AddPropertyL(KICalStatus, KICalConfirmed);
       
   416 				break;
       
   417 			case CCalEntry::ECancelled:
       
   418 				aAppt.AddPropertyL(KICalStatus, KICalCancelled);
       
   419 				break;
       
   420 			case CCalEntry::ETodoNeedsAction :	// not supported, fall through
       
   421 			case CCalEntry::ETodoCompleted :	// not supported, fall through
       
   422 			case CCalEntry::ETodoInProcess :	// not supported, fall through
       
   423 			default:
       
   424 				//Do not add a status property
       
   425 				break;
       
   426 			}
       
   427 		}
       
   428 			
       
   429 	//Add 'X-PARAM' identifier
       
   430 	if (iExportProperties & KAgnExportXProp)
       
   431 		{
       
   432 		aAppt.AddPropertyL( iStringProvider.StringL(EICalXParamType),
       
   433 		                    iStringProvider.StringL(EICalXParamAppointment) );
       
   434 		}
       
   435 	
       
   436 	TRACE_EXIT_POINT;
       
   437 	}
       
   438 
       
   439 /**
       
   440 Adds a component to aICal. The type of component added is determined by the
       
   441 value of aEntry.EntryTypeL(). Generic properties (valid in both VEVENT and
       
   442 VTODO components) are added first, followed by type specific properties.
       
   443 @param aICal CICal object to add the component to.
       
   444 @param aEntry CCalEntry containing information about the component.
       
   445 @internalTechnology
       
   446 */
       
   447 void CAgnVersit2Exporter::AddComponentL(CICal& aICal, const CCalEntry& aEntry) const
       
   448 	{
       
   449 	TRACE_ENTRY_POINT;
       
   450 	
       
   451 	//Add the  component
       
   452 	CICalBase::TICalComponentType type(CICalBase::EICalEvent);
       
   453 	switch (aEntry.EntryTypeL())
       
   454 		{
       
   455 		//The agenda types all map to an iCalendar 'VEVENT' component
       
   456 		case CCalEntry::EAppt :
       
   457 			// fall through...
       
   458 		case CCalEntry::EEvent :
       
   459 			// fall through...
       
   460 		case CCalEntry::EReminder :
       
   461 			// fall through...
       
   462 		case CCalEntry::EAnniv :
       
   463 			{
       
   464 			type = CICalBase::EICalEvent;
       
   465 			break;
       
   466 			}
       
   467 		case CCalEntry::ETodo :
       
   468 			{
       
   469 			type = CICalBase::EICalTodo;
       
   470 			break;
       
   471 			}
       
   472 		default :
       
   473 			User::Leave(KErrNotSupported); //For now at least
       
   474 			break;
       
   475 		}
       
   476 	CICalComponent& comp = aICal.AddComponentL(type);
       
   477 
       
   478 	//Add 'ATTENDEE' properties
       
   479 	if (iExportProperties & KAgnExportAttendee)
       
   480 		{
       
   481 		AddAttendeePropertiesL(comp, aEntry);
       
   482 		}
       
   483 
       
   484 	//Add 'ORGANIZER' property
       
   485 	if (iExportProperties & KAgnExportOrganizer)
       
   486 		{
       
   487 		AddOrganizerPropertyL(comp, aEntry);
       
   488 		}
       
   489 
       
   490 	//Add 'LOCATION' property.
       
   491 	if (iExportProperties & KAgnExportLocation)
       
   492 		{
       
   493 		AddTextPropertyL(comp, aEntry.LocationL(), KICalLocation);
       
   494 		}
       
   495 
       
   496 	//Outlook puts TRANSP here. The default value is 'OPAQUE'.
       
   497 
       
   498 	//Add 'SEQUENCE' property.  The default value is '0', so
       
   499 	//the property is only added if there is a value.
       
   500 	if (iExportProperties & KAgnExportSequence)
       
   501 		{
       
   502 		TInt sequence = aEntry.SequenceNumberL();
       
   503 		if (sequence != 0)
       
   504 			{
       
   505 			AddIntegerPropertyL(comp, aEntry.SequenceNumberL(), KICalSequence);
       
   506 			}
       
   507 		}
       
   508 
       
   509 	//Add 'UID' property
       
   510 	if (iExportProperties & KAgnExportUID)
       
   511 		{
       
   512 		CICalValue* uidVal = CICalValue::NewLC();
       
   513 		uidVal->SetBinaryL(aEntry.UidL());
       
   514 		CleanupStack::Pop(uidVal);
       
   515 		comp.AddPropertyL(KICalUid, uidVal); //Pass ownership
       
   516 		}
       
   517 
       
   518     //Time for DTSTAMP, CREATED and LAST-MODIFIED
       
   519 	TCalTime time;
       
   520 	
       
   521 	//Check if DTSTAMP exist
       
   522 	if( aEntry.DTStampL().TimeUtcL() != Time::NullTTime() )
       
   523 	    {
       
   524 	    time = aEntry.DTStampL();    
       
   525 	    }
       
   526 	else //If not use current time
       
   527 	    {
       
   528 	    TTime currentTime;
       
   529 	    currentTime.UniversalTime();
       
   530 	    time.SetTimeUtcL( currentTime );
       
   531 	    }
       
   532 	
       
   533 	//Add 'DTSTAMP' property
       
   534 	if (iExportProperties & KAgnExportDtStamp)
       
   535 		{
       
   536 		AddUtcDateTimePropertyL(comp, time.TimeUtcL(), KICalDtstamp);
       
   537 		}
       
   538 
       
   539 	//Add 'CATEGORIES' properties
       
   540 	if (iExportProperties & KAgnExportCategory)
       
   541 		{
       
   542 		AddCategoriesPropertyL(comp, aEntry);
       
   543 		}
       
   544 
       
   545 	//Add 'DESCRIPTION' property.
       
   546 	if (iExportProperties & KAgnExportDescription)
       
   547 		{
       
   548 		AddTextPropertyL(comp, aEntry.DescriptionL(), KICalDescription);
       
   549 		}
       
   550 
       
   551 	//Add 'SUMMARY' property
       
   552 	if (iExportProperties & KAgnExportSummary)
       
   553 		{
       
   554 		AddTextPropertyL(comp, aEntry.SummaryL(), KICalSummary);
       
   555 		}
       
   556 
       
   557 
       
   558 	//Add 'PRIORITY' property
       
   559 	if (iExportProperties & KAgnExportPriority)
       
   560 		{
       
   561 		TInt priority = aEntry.PriorityL();
       
   562 		
       
   563 		//Pirorites are saved always in vcal format
       
   564 		//so they are mapped the following way
       
   565 		//vCal 1 = iCal 1
       
   566 		//vCal 2 = iCal 5
       
   567 		//vCal 3 = iCal 9
       
   568 		if (priority != 0)	// Zero priority is default
       
   569 			{
       
   570 			if( priority == 1 )
       
   571 			    {
       
   572 			    }
       
   573 			
       
   574 			else if( priority == 2 )
       
   575 			    {
       
   576 			    priority = 5;
       
   577 			    }
       
   578 			
       
   579 			else
       
   580 			    {
       
   581 			    priority = 9;
       
   582 			    }
       
   583 			
       
   584 			AddIntegerPropertyL(comp, priority, KICalPriority);
       
   585 			}
       
   586 		}
       
   587 
       
   588 	//Add 'CLASS' property
       
   589 	if (iExportProperties & KAgnExportClass)
       
   590 		{
       
   591 		AddClassPropertyL(comp, aEntry);
       
   592 		}
       
   593     
       
   594     //Check if last modified date exist    
       
   595     if( aEntry.LastModifiedDateL().TimeUtcL() != Time::NullTTime() )
       
   596 	    {
       
   597 	    //update time with it otherwise set CREATED and LAST-MODIFIED to
       
   598 	    //current time
       
   599 	    time = aEntry.LastModifiedDateL();    
       
   600 	    }
       
   601 
       
   602 	//Add 'CREATED' property with current system time.
       
   603 	//time should be set to 'now' in UTC if not already.
       
   604 	if (iExportProperties & KAgnExportCreated)
       
   605 		{
       
   606 		AddUtcDateTimePropertyL(comp, time.TimeUtcL(), KICalCreated);
       
   607 		}
       
   608 
       
   609 	//Add 'LAST-MODIFIED' property
       
   610 	if (iExportProperties & KAgnExportLastModified)
       
   611 		{
       
   612 		AddUtcDateTimePropertyL(comp, time.TimeUtcL(), KICalLastmodified);
       
   613 		}
       
   614 
       
   615 	//Add 'RECURRENCE-ID' property
       
   616 	if (iExportProperties & KAgnExportRecurrenceId)
       
   617 		{
       
   618 		time = aEntry.RecurrenceIdL();
       
   619 		if (time.TimeUtcL() != Time::NullTTime())
       
   620 			{
       
   621 			CICalProperty& recurProp = AddDateTimePropertyL(comp, time, KICalRecurrenceId);
       
   622 			switch (aEntry.RecurrenceRangeL())
       
   623 				{
       
   624 				case CalCommon::EThisAndFuture:
       
   625 					{
       
   626 					recurProp.AddPropertyParamL(KICalRange,KICalThisAndFuture);
       
   627 					}
       
   628 				break;
       
   629 				case CalCommon::EThisAndPrior:
       
   630 					{
       
   631 					recurProp.AddPropertyParamL(KICalRange,KICalThisAndPrior);
       
   632 					}
       
   633 				break;
       
   634 				default:
       
   635 				break;
       
   636 				}
       
   637 
       
   638 			}
       
   639 		}
       
   640 
       
   641 	//Add 'EXDATE' properties
       
   642 	if (iExportProperties & KAgnExportExDate)
       
   643 		{
       
   644 		AddExceptionDatePropertyL(comp, aEntry);
       
   645 		}
       
   646 
       
   647 	//Add 'RDATE' property
       
   648 	if (iExportProperties & KAgnExportRDate)
       
   649 		{
       
   650 		AddRDatePropertyL(comp, aEntry);
       
   651 		}
       
   652 
       
   653 	//Add 'RRULE' property
       
   654 	if (iExportProperties & KAgnExportRRule)
       
   655 		{
       
   656 		AddRRulePropertyL(comp, aEntry);
       
   657 		}
       
   658 
       
   659 	//Add 'VALARM' component
       
   660 	if (iExportProperties & KAgnExportAlarm)
       
   661 		{
       
   662 		AddAlarmL(comp, aEntry);
       
   663 		}
       
   664 
       
   665 	//Add 'DTSTART' property
       
   666 	if (iExportProperties & KAgnExportDtStart)
       
   667 		{
       
   668 		time = aEntry.StartTimeL();
       
   669 		if (time.TimeUtcL() != Time::NullTTime())
       
   670 			{
       
   671 			AddDateTimePropertyL(comp, time, KICalDtstart);
       
   672 			}
       
   673 		}
       
   674 
       
   675 	//Add type specific properties
       
   676 	switch (aEntry.EntryTypeL())
       
   677 		{
       
   678 		case CCalEntry::EAppt:
       
   679 			AddApptL(comp, aEntry);
       
   680 			break;
       
   681 		case CCalEntry::EEvent:
       
   682 			AddEventL(comp, aEntry);
       
   683 			break;
       
   684 		case CCalEntry::EReminder:
       
   685 			AddReminderL(comp, aEntry);
       
   686 			break;
       
   687 		case CCalEntry::EAnniv:
       
   688 			AddAnnivL(comp, aEntry);
       
   689 			break;
       
   690 		case CCalEntry::ETodo:
       
   691 			AddTodoL(comp, aEntry);
       
   692 			break;
       
   693 		default:
       
   694 			//Nothing more to add
       
   695 			break;
       
   696 		}
       
   697 	
       
   698 	// Add GEO
       
   699     CCalGeoValue* geoValue = aEntry.GeoValueL();
       
   700     
       
   701     // Check that the GEO values are not NULL
       
   702     if(geoValue)
       
   703         {
       
   704         CleanupStack::PushL(geoValue);
       
   705         
       
   706         TReal geoLatitude;
       
   707         TReal geoLongitude;
       
   708         
       
   709         // Extract latitude and longitude values
       
   710         // Check if it returns EFalse
       
   711         geoValue->GetLatLong(geoLatitude,geoLongitude);
       
   712         
       
   713         // Convert the geo values from numbers to string
       
   714         // Create GEO string buffer to be constructed from a latitude, delimiter and a longitude value
       
   715         TBuf<KGEOMaxWidthOfGeoValue*2+1> geoString;
       
   716         TBuf<KGEOMaxWidthOfGeoValue> geoLatString;
       
   717         TBuf<KGEOMaxWidthOfGeoValue> geoLongString;
       
   718         
       
   719         // Maximum width of a GEO value and max number of decimal places
       
   720         TRealFormat geoFormat(KGEOMaxWidthOfGeoValue,KCalGEOMaxDecimalPlaces);
       
   721         
       
   722         _LIT(KGeoStringFormat,"%S%c%S");
       
   723         
       
   724         // Ensure correct conversion from stored numeric values to descriptors
       
   725         if((geoLatString.Num(geoLatitude,geoFormat)>0) && (geoLongString.Num(geoLongitude,geoFormat)>0))
       
   726             {
       
   727             geoString.AppendFormat(KGeoStringFormat,&geoLatString,KAgnVersitTokenSemiColonVal,&geoLongString);
       
   728             
       
   729             // Add the GEO property
       
   730             AddTextPropertyL(comp,geoString,KICalGeo);
       
   731             }
       
   732         
       
   733         CleanupStack::PopAndDestroy(geoValue);
       
   734         }
       
   735 	TRACE_EXIT_POINT;
       
   736 	}
       
   737 
       
   738 /**
       
   739 Adds the information stored in aEntry to aEvent
       
   740 @param aEvent CICalComponent& to add the agenda information to.
       
   741 @param aEntry CCalEntry& containing the agenda information to export.
       
   742 @internalTechnology
       
   743 */
       
   744 void CAgnVersit2Exporter::AddEventL(CICalComponent& aEvent, const CCalEntry& aEntry) const
       
   745 	{
       
   746 	TRACE_ENTRY_POINT;
       
   747 	
       
   748 	//Add 'DTEND' property
       
   749 	if (iExportProperties & KAgnExportDtEnd)
       
   750 		{
       
   751 		TCalTime time(aEntry.EndTimeL());
       
   752 		if (time.TimeUtcL() != Time::NullTTime())
       
   753 			{
       
   754 			AddDateTimePropertyL(aEvent, time, KICalDtend);
       
   755 			}
       
   756 		}
       
   757 
       
   758 	if (iExportProperties & KAgnExportStatus)
       
   759 		{
       
   760 		//Add 'STATUS' property
       
   761 		switch (aEntry.StatusL())
       
   762 			{
       
   763 			//VEvent supports TENTATIVE, CONFIRMED, CANCELLED
       
   764 			case CCalEntry::ETentative:
       
   765 				aEvent.AddPropertyL(KICalStatus, KICalTentative);
       
   766 				break;
       
   767 			case CCalEntry::EConfirmed:
       
   768 				aEvent.AddPropertyL(KICalStatus, KICalConfirmed);
       
   769 				break;
       
   770 			case CCalEntry::ECancelled:
       
   771 				aEvent.AddPropertyL(KICalStatus, KICalCancelled);
       
   772 				break;
       
   773 			case CCalEntry::ETodoNeedsAction :	// not supported, fall through
       
   774 			case CCalEntry::ETodoCompleted :	// not supported, fall through
       
   775 			case CCalEntry::ETodoInProcess :	// not supported, fall through
       
   776 			default:
       
   777 				//Do not add a status property
       
   778 				break;
       
   779 			}
       
   780 		}
       
   781 	//Add 'X-PARAM' identifier
       
   782 	if (iExportProperties & KAgnExportXProp)
       
   783 		{
       
   784 		aEvent.AddPropertyL( iStringProvider.StringL(EICalXParamType),
       
   785 		                     iStringProvider.StringL(EICalXParamEvent) );
       
   786 		}
       
   787 	
       
   788 	TRACE_EXIT_POINT;
       
   789 	}
       
   790 
       
   791 /**
       
   792 Adds an agenda-style Reminder to the specified component.
       
   793 @param aReminder Component to add the reminder to.
       
   794 @param aEntry CCalEntry containing details of the reminder.
       
   795 @internalTechnology
       
   796 */
       
   797 void CAgnVersit2Exporter::AddReminderL(CICalComponent& aReminder, const CCalEntry& /*aEntry*/) const
       
   798 	{
       
   799 	TRACE_ENTRY_POINT;
       
   800 	
       
   801 	//Add 'X-PARAM' identifier
       
   802 	if (iExportProperties & KAgnExportXProp)
       
   803 		{
       
   804 		aReminder.AddPropertyL( iStringProvider.StringL(EICalXParamType),
       
   805 		                        iStringProvider.StringL(EICalXParamReminder) );
       
   806 		}
       
   807 	
       
   808 	TRACE_EXIT_POINT;
       
   809 	}
       
   810 
       
   811 /**
       
   812 Adds a Timezone component to the specified CCalEntry.
       
   813 @param aICal CICal object to add the component to.
       
   814 @param aEntry CCalEntry containing information about the Timezone.
       
   815 @internalTechnology
       
   816 */
       
   817 void CAgnVersit2Exporter::AddTimezoneL(CICal& aICal, const CCalEntry& aEntry)
       
   818 	{
       
   819 	TRACE_ENTRY_POINT;
       
   820 	
       
   821 	iTimezoneIndex = KErrNotFound;
       
   822 	
       
   823 	CTzRules* tzRules = aEntry.TzRulesL();
       
   824 	CleanupStack::PushL(tzRules);
       
   825 
       
   826 	if (!tzRules || tzRules->Count() < 1)
       
   827 		{
       
   828 		CleanupStack::PopAndDestroy(tzRules);
       
   829 		return;
       
   830 		}
       
   831 
       
   832 	TInt minimumMinutes = KMaxOffsetMinutes;// TInts to store the maximum and minimum UTC offset
       
   833 	TInt maximumMinutes = KMinOffsetMinutes;// to get a human readable name for TZID
       
   834 	TInt count = tzRules->Count();
       
   835 	for (TInt i = 0; i < count; ++i)
       
   836 		{
       
   837 		TTzRule& singleRule = (*tzRules)[i];
       
   838 		if (singleRule.iNewLocalTimeOffset < minimumMinutes)
       
   839 			{
       
   840 			minimumMinutes = singleRule.iNewLocalTimeOffset;
       
   841 			}
       
   842 		if (singleRule.iNewLocalTimeOffset > maximumMinutes)
       
   843 			{
       
   844 			maximumMinutes = singleRule.iNewLocalTimeOffset;
       
   845 			}
       
   846 		if (singleRule.iOldLocalTimeOffset < minimumMinutes)
       
   847 			{
       
   848 			minimumMinutes = singleRule.iOldLocalTimeOffset;
       
   849 			}
       
   850 		if (singleRule.iOldLocalTimeOffset > maximumMinutes)
       
   851 			{
       
   852 			maximumMinutes = singleRule.iOldLocalTimeOffset;
       
   853 			}
       
   854 		}
       
   855 
       
   856 	// Now we've got the max and minimum values, store these in the TzId text field
       
   857 	// iTimeZoneName allocates a new HBufC, but either deletes it or transfers ownership
       
   858 	// to iTznamesArray
       
   859 	HBufC* timeZoneName = HBufC::NewLC(KMaxBufLength);
       
   860 	timeZoneName->Des().Copy(iStringProvider.StringL(EICalTzidUtc));
       
   861 
       
   862 	//Convert minutes to hours
       
   863 	const TInt KConversionMul = 10;
       
   864 	const TInt KConversionDiv = 6;
       
   865 	
       
   866 	// Number of digits to store time in
       
   867 	const TInt KTimeWidth = 4;
       
   868 
       
   869 	TInt minimumHours = minimumMinutes * KConversionMul / KConversionDiv; // convert to HHMM format
       
   870 	if (minimumHours < 0)
       
   871 		{
       
   872 		minimumHours =- minimumHours;
       
   873 		timeZoneName->Des().Append(iStringProvider.StringL(EICalTzidMinus));
       
   874 		}
       
   875 	else
       
   876 		{
       
   877 		timeZoneName->Des().Append(iStringProvider.StringL(EICalTzidPlus));
       
   878 		}
       
   879 	timeZoneName->Des().AppendNumFixedWidth(minimumHours, EDecimal, KTimeWidth);
       
   880 	timeZoneName->Des().Append(iStringProvider.StringL(EICalTzidStandard));
       
   881 
       
   882 	//Add a slash seperator
       
   883 	timeZoneName->Des().Append(iStringProvider.StringL(EICalTzidSlash));
       
   884 	timeZoneName->Des().Append(iStringProvider.StringL(EICalTzidUtc));
       
   885 
       
   886 	TInt maximumHours = maximumMinutes * KConversionMul / KConversionDiv; // convert to HHMM format
       
   887 	if (maximumHours < 0)
       
   888 		{
       
   889 		maximumHours =- maximumHours;
       
   890 		timeZoneName->Des().Append(iStringProvider.StringL(EICalTzidMinus));
       
   891 		}
       
   892 	else
       
   893 		{
       
   894 		timeZoneName->Des().Append(iStringProvider.StringL(EICalTzidPlus));
       
   895 		}
       
   896 	timeZoneName->Des().AppendNumFixedWidth(maximumHours, EDecimal, KTimeWidth);
       
   897 	timeZoneName->Des().Append(iStringProvider.StringL(EICalTzidDaylight));
       
   898 
       
   899 	// The time zone name should now read: "UTC +HHMM (Standard) / UTC +HHMM (Daylight)".
       
   900 	
       
   901 	// Check if we have already used this timezone in this iCal.  If we have,
       
   902 	// we reuse this string but don't output the timezone again.
       
   903 	TInt tzCount = iTzNameArray.Count();
       
   904 	for (TInt x = 0; x < tzCount; ++x)
       
   905 		{
       
   906 		if ((iTzNameArray[x])->CompareC(*timeZoneName) == 0)
       
   907 			{
       
   908 			//Already used this timezone
       
   909 			iTimezoneIndex = x;
       
   910 			CleanupStack::PopAndDestroy(timeZoneName);
       
   911 			CleanupStack::PopAndDestroy(tzRules);
       
   912 			return;
       
   913 			}
       
   914 		}
       
   915 
       
   916 	//Add the 'VTIMEZONE' component
       
   917 	CICalComponent& timezone = aICal.AddComponentL(CICalBase::EICalTimeZone);
       
   918 
       
   919 	timezone.AddPropertyL(KICalTzid, *timeZoneName);
       
   920 
       
   921 
       
   922 	for (TInt ii = 0; ii < count; ++ii)
       
   923 		{
       
   924 		TTzRule& singleRule = (*tzRules)[ii];
       
   925 
       
   926 		// Set the DAYLIGHT/STANDARD field based on whether the
       
   927 		// time zone rule shifts time forwards or backwards
       
   928 		CICalComponent& tzProp = singleRule.iNewLocalTimeOffset < singleRule.iOldLocalTimeOffset ?
       
   929 			timezone.AddComponentL(CICalBase::EICalStandard) :
       
   930 			timezone.AddComponentL(CICalBase::EICalDaylight);
       
   931 
       
   932 		//  -DTSTART (Required)
       
   933 		CICalValue* dtstart = CICalValue::NewLC();
       
   934 
       
   935 
       
   936 		TTime startTime = singleRule.iFrom.iTime;
       
   937         
       
   938         //Check whether the year is 0, if so set it to 1970
       
   939 		if( !startTime.DateTime().Year() )//Year == 0000
       
   940 		    {
       
   941 		    TDateTime dateTime = startTime.DateTime();
       
   942 		    dateTime.SetYear( 1970 );
       
   943 		    startTime = dateTime;
       
   944 		    }
       
   945 
       
   946 		// DTSTART in a VTIMEZONE must always be in local time (with no TZ identifier).
       
   947 		dtstart->SetDateTimeL(startTime,CICalValue::ESpecifiedTimeZone);
       
   948 
       
   949 		CleanupStack::Pop(dtstart);
       
   950 		tzProp.AddPropertyL(KICalDtstart, dtstart); //Pass ownership
       
   951 
       
   952 		//  -RRULE (optional)
       
   953 		CICalValue* tzRrule = CICalValue::NewLC();
       
   954 		HBufC* ruleText = HBufC::NewLC(KMaxBufLength);
       
   955 		ruleText->Des().Copy(KRRuleFreqYearly);
       
   956 
       
   957 		TInt monthNum = singleRule.iMonth + 1;
       
   958 
       
   959 		switch (singleRule.iDayRule)
       
   960 			{
       
   961 			case ETzFixedDate :
       
   962 				{
       
   963 				// e.g. 11th October
       
   964 				// Equivalent to FREQ=YEARLY;BYMONTH=?;BYMONTHDAY=?
       
   965 				// This won't get imported by Outlook, but it's the only way of exporting it.
       
   966 				// It can't be converted to a week of the month.
       
   967 				ruleText->Des().AppendNum(monthNum);
       
   968 				ruleText->Des().Append(KRRuleByMonthDay);
       
   969 				ruleText->Des().AppendNum(singleRule.iDayOfMonth);
       
   970 				break;
       
   971 				}
       
   972 			case ETzDayAfterDate :
       
   973 				{
       
   974 				// e.g. first Sunday after 8th October
       
   975 				// To get this to a format understood by Outlook, we have to convert the day of
       
   976 				// month into a week number. If the day of the month is greater than 21, the week
       
   977 				// could cover multiple months (and possibly years), so we export using BYMONTHDAY.
       
   978 				const TInt KLastPossibleDayOfMonth = 21;
       
   979 				if (singleRule.iDayOfMonth > KLastPossibleDayOfMonth)
       
   980 					{
       
   981 					// Equivalent to FREQ=YEARLY;BYMONTH=?;BYMONTHDAY=?;BYDAY=+1?
       
   982 					ruleText->Des().AppendNum(monthNum);
       
   983 					ruleText->Des().Append(KRRuleByMonthDay);
       
   984 					ruleText->Des().AppendNum(singleRule.iDayOfMonth);
       
   985 					ruleText->Des().Append(KRRuleByDayPlusOne);
       
   986 					ruleText->Des().Append(DayFromInt(singleRule.iDayOfWeek));
       
   987 					}
       
   988 				else
       
   989 					{
       
   990 					// Equivalent to FREQ=YEARLY;BYMONTH=?;BYDAY=+n?
       
   991 					ruleText->Des().AppendNum(monthNum);
       
   992 					ruleText->Des().Append(KRRuleByDayPlus);
       
   993 					ruleText->Des().AppendNum(WeekNumFromDayOfMonth(singleRule.iDayOfMonth));
       
   994 					ruleText->Des().Append(DayFromInt(singleRule.iDayOfWeek));
       
   995 					}
       
   996 				break;
       
   997 				}
       
   998 			case ETzDayBeforeDate :
       
   999 				{
       
  1000 				// e.g. Sunday before 8th October
       
  1001 				// To get this to a format understood by Outlook, we have to convert the day of
       
  1002 				// month into a week number. If the day of the month is less than 8, the week
       
  1003 				// could cover multiple months (and possibly years), so we export using BYMONTHDAY.
       
  1004 				const TInt KFirstPossibleDayOfMonth = 8;
       
  1005 				if (singleRule.iDayOfMonth < KFirstPossibleDayOfMonth)
       
  1006 					{
       
  1007 					// Equivalent to FREQ=YEARLY;BYMONTH=?;BYMONTHDAY=?;BYDAY=-1?
       
  1008 					ruleText->Des().AppendNum(monthNum);
       
  1009 					ruleText->Des().Append(KRRuleByMonthDay);
       
  1010 					ruleText->Des().AppendNum(singleRule.iDayOfMonth);
       
  1011 					ruleText->Des().Append(KRRuleByDayMinusOne);
       
  1012 					ruleText->Des().Append(DayFromInt(singleRule.iDayOfWeek));
       
  1013 					}
       
  1014 				else
       
  1015 					{
       
  1016 					// Equivalent to FREQ=YEARLY;BYMONTH=?;BYDAY=+n?
       
  1017 					ruleText->Des().AppendNum(monthNum);
       
  1018 					ruleText->Des().Append(KRRuleByDayPlus);
       
  1019 					ruleText->Des().AppendNum(WeekNumFromDayOfMonth(singleRule.iDayOfMonth));
       
  1020 					ruleText->Des().Append(DayFromInt(singleRule.iDayOfWeek));
       
  1021 					}
       
  1022 				break;
       
  1023 				}
       
  1024 			case ETzDayInLastWeekOfMonth :
       
  1025 				{
       
  1026 				// e.g. last Sunday in October
       
  1027 				// Equivalent to FREQ=YEARLY;BYMONTH=?;BYDAY=-1?
       
  1028 				ruleText->Des().AppendNum(monthNum);
       
  1029 				ruleText->Des().Append(KRRuleByDayMinusOne);
       
  1030 				ruleText->Des().Append(DayFromInt(singleRule.iDayOfWeek));
       
  1031 				break;
       
  1032 				}
       
  1033 			default :
       
  1034 				User::Leave(KErrCorrupt);
       
  1035 				break;
       
  1036 			}
       
  1037 		tzRrule->SetRecurrenceRuleL(*ruleText);
       
  1038 		CleanupStack::PopAndDestroy(ruleText);
       
  1039 		CleanupStack::Pop(tzRrule);
       
  1040 		tzProp.AddPropertyL(KICalRRule, tzRrule); //Pass ownership
       
  1041 
       
  1042 		//  -TZOFFSETFROM (Required)
       
  1043 		CICalValue* tzOffsetFrom = CICalValue::NewLC();
       
  1044 		tzOffsetFrom->SetUtcOffsetL(
       
  1045 		            TTimeIntervalSeconds(singleRule.iOldLocalTimeOffset * KSecondsInOneMinute) );
       
  1046 		CleanupStack::Pop(tzOffsetFrom);
       
  1047 		tzProp.AddPropertyL(KICalTzoffsetfrom, tzOffsetFrom); //Pass ownership
       
  1048 
       
  1049 		//  -TZOFFSETTO (Required)
       
  1050 		CICalValue* tzOffsetTo = CICalValue::NewLC();
       
  1051 		tzOffsetTo->SetUtcOffsetL(
       
  1052 		            TTimeIntervalSeconds(singleRule.iNewLocalTimeOffset * KSecondsInOneMinute) );
       
  1053 		CleanupStack::Pop(tzOffsetTo);
       
  1054 		tzProp.AddPropertyL(KICalTzoffsetto, tzOffsetTo); //Pass ownership
       
  1055 		}
       
  1056 		
       
  1057 	iTzNameArray.AppendL(timeZoneName); //Transfer ownership
       
  1058 	iTimeZoneArray.AppendL(tzRules);	//Transfer ownership
       
  1059 	
       
  1060 	iTimezoneIndex = iTimeZoneArray.Count() -1;
       
  1061 	CleanupStack::Pop(timeZoneName);
       
  1062 	CleanupStack::Pop(tzRules);
       
  1063 	
       
  1064 	TRACE_EXIT_POINT;
       
  1065 	}
       
  1066 
       
  1067 /**
       
  1068 Adds properties specific to VTODO to the specified component.
       
  1069 @param aTodo VTODO component to add properties to.
       
  1070 @param aEntry CCalEntry containing details of the TODO.
       
  1071 @internalTechnology
       
  1072 */
       
  1073 void CAgnVersit2Exporter::AddTodoL(CICalComponent& aTodo,const CCalEntry& aEntry) const
       
  1074 	{
       
  1075 	TRACE_ENTRY_POINT;
       
  1076 	
       
  1077 	TCalTime time(aEntry.EndTimeL());
       
  1078 
       
  1079 	if (iExportProperties & KAgnExportDtEnd)
       
  1080 		{
       
  1081 		if (time.TimeUtcL() != Time::NullTTime())
       
  1082 			{
       
  1083 			//Add 'DUE' property
       
  1084 			AddDateTimePropertyL(aTodo, time, KICalDue);
       
  1085 			}
       
  1086 		}
       
  1087 
       
  1088 	//Add 'COMPLETED' property
       
  1089 	if (iExportProperties & KAgnExportCompleted)
       
  1090 		{
       
  1091 		time = aEntry.CompletedTimeL();
       
  1092 		if (time.TimeUtcL() != Time::NullTTime())
       
  1093 			{
       
  1094 			//Add 'COMPLETED' property
       
  1095 			AddDateTimePropertyL(aTodo, time, KICalCompleted);
       
  1096 			}
       
  1097 		}
       
  1098 
       
  1099 	//Add 'STATUS' property
       
  1100 	if (iExportProperties & KAgnExportStatus)
       
  1101 		{
       
  1102 		switch (aEntry.StatusL())
       
  1103 			{
       
  1104 			//VTODO supports NEEDS_ACTION, COMPLETED, IN-PROCESS, CANCELLED
       
  1105 			case CCalEntry::ECancelled :
       
  1106 				aTodo.AddPropertyL(KICalStatus, KICalCancelled);
       
  1107 				break;
       
  1108 			case CCalEntry::ETodoNeedsAction :
       
  1109 				aTodo.AddPropertyL(KICalStatus, KICalNeedsAction);
       
  1110 				break;
       
  1111 			case CCalEntry::ETodoCompleted :
       
  1112 				aTodo.AddPropertyL(KICalStatus, KICalCompleted);
       
  1113 				break;
       
  1114 			case CCalEntry::ETodoInProcess :
       
  1115 				aTodo.AddPropertyL(KICalStatus, KICalInProcess);
       
  1116 				break;
       
  1117 			case CCalEntry::ETentative :	// not supported, fall through
       
  1118 			case CCalEntry::EConfirmed :	// not supported, fall through
       
  1119 			default :
       
  1120 				//Do not add a status property
       
  1121 				break;
       
  1122 			}
       
  1123 		}
       
  1124 	//Add 'X-PARAM' identifier
       
  1125 	if (iExportProperties & KAgnExportXProp)
       
  1126 		{
       
  1127 		aTodo.AddPropertyL( iStringProvider.StringL(EICalXParamType),
       
  1128 		                    iStringProvider.StringL(EICalXParamTodo) );
       
  1129 		}
       
  1130 	
       
  1131 	TRACE_EXIT_POINT;
       
  1132 	}
       
  1133 
       
  1134 
       
  1135 //
       
  1136 //     ADD PROPERTY FUNCTIONS
       
  1137 //     ======================
       
  1138 //
       
  1139 
       
  1140 /**
       
  1141 Adds 'ATTENDEE' properties to aComponent from aEntry
       
  1142 @param aComponent component to add the ATTENDEE property to
       
  1143 @param aEntry entry to extract ATTENDEE information from
       
  1144 @internalTechnology
       
  1145 */
       
  1146 void CAgnVersit2Exporter::AddAttendeePropertiesL( CICalComponent& aComponent,
       
  1147                                                   const CCalEntry& aEntry ) const
       
  1148 	{
       
  1149 	TRACE_ENTRY_POINT;
       
  1150 	
       
  1151 	const RPointerArray<CCalAttendee>& attendees = aEntry.AttendeesL();
       
  1152 	const TInt count = attendees.Count();
       
  1153 	CCalAttendee* attendee = NULL;
       
  1154 	CICalValue* val = NULL;
       
  1155 	for (TInt x = 0; x < count; ++x)
       
  1156 		{
       
  1157 		/** Can't add the following property parameters due to no equivalence:
       
  1158 		*   (";" dirparam) / (";" languageparam) / (";" cutypeparam) /
       
  1159 		*   (";"memberparam) / (";" deltoparam) / (";" delfromparam)
       
  1160 		*/
       
  1161 		attendee = attendees[x]; //Not taking ownership
       
  1162 		val = CICalValue::NewLC();
       
  1163 		val->SetTextL(attendee->Address());
       
  1164 
       
  1165 		//Add a property for each ATTENDEE
       
  1166 		CleanupStack::Pop(val);
       
  1167 		CICalProperty& attProp = aComponent.AddPropertyL(KICalAttendee, val); //Pass ownership
       
  1168 
       
  1169 		//Add 'CN' property parameter
       
  1170 		TPtrC commonName(attendee->CommonName());
       
  1171 		if (commonName.Length() > 0)
       
  1172 			{
       
  1173 			attProp.AddPropertyParamL(KICalCn, commonName);
       
  1174 			}
       
  1175 
       
  1176 		//Add 'ROLE' property parameter
       
  1177 		TPtrC roleName(RoleFromEnum(attendee->RoleL()));
       
  1178 		if (roleName.Length() > 0)
       
  1179 			{
       
  1180 			attProp.AddPropertyParamL(KICalRole, roleName);
       
  1181 			}
       
  1182 
       
  1183 		//Add 'RSVP' property parameter
       
  1184 		// Default is FALSE so don't add a value if this is the case
       
  1185 		if (attendee->ResponseRequested())
       
  1186 			{
       
  1187 			CICalValue* rsvpVal = CICalValue::NewLC();
       
  1188 			rsvpVal->SetBooleanL(ETrue);
       
  1189 			CleanupStack::Pop(rsvpVal);
       
  1190 			attProp.AddPropertyParamL(KICalRsvp, rsvpVal);
       
  1191 			}
       
  1192 
       
  1193 		//Add "SENT-BY" property parameter
       
  1194 		TPtrC sentBy(attendee->SentBy());
       
  1195 		if (sentBy.Length() > 0)
       
  1196 			{
       
  1197 			attProp.AddPropertyParamL(KICalSentBy, sentBy);
       
  1198 			}
       
  1199 
       
  1200 		//Add PARTSTAT property parameter
       
  1201 		TPtrC participationStatus(StatusFromEnum(attendee->StatusL()));
       
  1202 		if (participationStatus.Length() > 0)
       
  1203 			{
       
  1204 			attProp.AddPropertyParamL(KICalPartStat, participationStatus);
       
  1205 			}
       
  1206 		}
       
  1207 	
       
  1208 	TRACE_EXIT_POINT;
       
  1209 	}
       
  1210 
       
  1211 /**
       
  1212 Adds 'CATEGORY' properties to aComponent from aEntry
       
  1213 @param aComponent component to add the CATEGORY property to
       
  1214 @param aEntry entry to extract CATEGORY information from
       
  1215 @internalTechnology
       
  1216 */
       
  1217 void CAgnVersit2Exporter::AddCategoriesPropertyL( CICalComponent& aComponent,
       
  1218                                                   const CCalEntry& aEntry ) const
       
  1219 	{
       
  1220 	TRACE_ENTRY_POINT;
       
  1221 	
       
  1222 	//CategoryListL is not const so we need a non-const CalEntry to call it
       
  1223 	CCalEntry& nonConstEntry = const_cast<CCalEntry&>(aEntry);
       
  1224 	const RPointerArray<CCalCategory>& categories = nonConstEntry.CategoryListL();
       
  1225 	const TInt count = categories.Count();
       
  1226 	if (count)
       
  1227 		{
       
  1228 		CICalProperty& catProp =
       
  1229                 aComponent.AddPropertyL(KICalCategories, CategoryStringL(*categories[0]));
       
  1230 		for (TInt x = 1; x < count; ++x)
       
  1231 			{
       
  1232 			catProp.AddValueL(CategoryStringL(*categories[x]));
       
  1233 			}
       
  1234 		}
       
  1235 	
       
  1236 	TRACE_EXIT_POINT;
       
  1237 	}
       
  1238 
       
  1239 /**
       
  1240 Adds a CLASS property to the specified component
       
  1241 @param aComponent component to add the CLASS property to
       
  1242 @param aEntry entry to extract CLASS information from
       
  1243 @internalTechnology
       
  1244 */
       
  1245 void CAgnVersit2Exporter::AddClassPropertyL( CICalComponent& aComponent,
       
  1246                                              const CCalEntry& aEntry ) const
       
  1247 	{
       
  1248 	TRACE_ENTRY_POINT;
       
  1249 	
       
  1250 	CCalEntry::TReplicationStatus repStatus = aEntry.ReplicationStatusL();
       
  1251 	TPtrC status(ClassStringL(repStatus));
       
  1252 	if (status.Length() > 0)
       
  1253 		{
       
  1254 		// Only add the CLASS property if it is not the default, 'PUBLIC'.
       
  1255 		if (status.CompareF(KICalPublic) != 0)
       
  1256 			{
       
  1257 			aComponent.AddPropertyL(KICalClass, status);
       
  1258 			}
       
  1259 		}
       
  1260 	
       
  1261 	TRACE_EXIT_POINT;
       
  1262 	}
       
  1263 
       
  1264 /**
       
  1265 Adds 'EXDATE' property to aComponent from aEntry
       
  1266 @param aComponent component to add the EXDATE property to
       
  1267 @param aEntry entry to extract EXDATE information from
       
  1268 @internalTechnology
       
  1269 */
       
  1270 void CAgnVersit2Exporter::AddExceptionDatePropertyL( CICalComponent& aComponent,
       
  1271                                                      const CCalEntry& aEntry ) const
       
  1272 	{
       
  1273 	TRACE_ENTRY_POINT;
       
  1274 	
       
  1275 	RArray<TCalTime> exDates;
       
  1276 	CleanupClosePushL(exDates);
       
  1277 	aEntry.GetExceptionDatesL(exDates);
       
  1278 	const TInt count = exDates.Count();
       
  1279 	if (count)
       
  1280 		{
       
  1281 		CICalValue* val = CICalValue::NewLC();
       
  1282 		val->SetDateTimeL(exDates[0].TimeUtcL(), CICalValue::EUtcTime);
       
  1283 		CleanupStack::Pop(val);
       
  1284 		CICalProperty& prop = aComponent.AddPropertyL(KICalExdate, val); //Pass ownership
       
  1285 
       
  1286 		for (TInt x = 1; x < count; ++x)
       
  1287 			{
       
  1288 			val = CICalValue::NewLC();
       
  1289 			val->SetDateTimeL(exDates[x].TimeUtcL(), CICalValue::EUtcTime);
       
  1290 			CleanupStack::Pop(val);
       
  1291 			prop.AddValueL(val); //Pass ownership
       
  1292 			}
       
  1293 		}
       
  1294 	CleanupStack::PopAndDestroy(&exDates);
       
  1295 	
       
  1296 	TRACE_EXIT_POINT;
       
  1297 	}
       
  1298 
       
  1299 /**
       
  1300 Adds an integer value to a given component
       
  1301 @param aComponent component to add the integer value to
       
  1302 @param aInt integer to be added
       
  1303 @param aProperty current property
       
  1304 @internalTechnology
       
  1305 */
       
  1306 void CAgnVersit2Exporter::AddIntegerPropertyL( CICalComponent& aComponent,
       
  1307                                                TInt aInt,
       
  1308                                                const TDesC& aProperty ) const
       
  1309 	{
       
  1310 	TRACE_ENTRY_POINT;
       
  1311 	
       
  1312 	CICalValue* val = CICalValue::NewLC();
       
  1313 	val->SetIntegerL(aInt);
       
  1314 	CleanupStack::Pop(val);
       
  1315 	aComponent.AddPropertyL(aProperty, val); //Pass ownership
       
  1316 	
       
  1317 	TRACE_EXIT_POINT;
       
  1318 	}
       
  1319 
       
  1320 /**
       
  1321 Adds an 'ORGANIZER' property to aComponent from aEntry
       
  1322 @param aComponent component to add the ORGANIZER property to
       
  1323 @param aEntry entry to extract ORGANIZER information from
       
  1324 @internalTechnology
       
  1325 */
       
  1326 void CAgnVersit2Exporter::AddOrganizerPropertyL( CICalComponent& aComponent,
       
  1327                                                  const CCalEntry& aEntry ) const
       
  1328 	{
       
  1329 	TRACE_ENTRY_POINT;
       
  1330 	
       
  1331 	CCalUser* organizer = aEntry.OrganizerL();
       
  1332 
       
  1333 	if (organizer)
       
  1334 		{
       
  1335 		/** Can't add the following property parameters due to no equivalence:
       
  1336 		*	(";" dirparam) /  (";" languageparam)
       
  1337         */
       
  1338 		CICalValue* orgVal = CICalValue::NewLC();
       
  1339 		orgVal->SetTextL(organizer->Address());
       
  1340 		CleanupStack::Pop(orgVal);
       
  1341 		CICalProperty& orgProp = aComponent.AddPropertyL(KICalOrganizer, orgVal); //Pass ownership
       
  1342 		//Add 'CN' property parameter
       
  1343 		TPtrC commonName(organizer->CommonName());
       
  1344 		if (commonName.Length() > 0)
       
  1345 			{
       
  1346 			orgProp.AddPropertyParamL(KICalCn, commonName);
       
  1347 			}
       
  1348 
       
  1349 		//Add "SENT-BY" property parameter
       
  1350 		TPtrC sentBy(organizer->SentBy());
       
  1351 		if (sentBy.Length() > 0)
       
  1352 			{
       
  1353 			orgProp.AddPropertyParamL(KICalSentBy, commonName);
       
  1354 			}
       
  1355 		}
       
  1356 	
       
  1357 	TRACE_EXIT_POINT;
       
  1358 	}
       
  1359 
       
  1360 /**
       
  1361 Adds a text value to a given component
       
  1362 @param aComponent component to add the text value to
       
  1363 @param aText text to be added
       
  1364 @param aProperty current property
       
  1365 @internalTechnology
       
  1366 */
       
  1367 void CAgnVersit2Exporter::AddTextPropertyL( CICalComponent& aComponent,
       
  1368                                             const TDesC& aText,
       
  1369                                             const TDesC& aProperty ) const
       
  1370 	{
       
  1371 	TRACE_ENTRY_POINT;
       
  1372 	
       
  1373 	if (aText.Length() > 0)
       
  1374 		{
       
  1375 		aComponent.AddPropertyL(aProperty, aText);
       
  1376 		}
       
  1377 	
       
  1378 	TRACE_EXIT_POINT;
       
  1379 	}
       
  1380 
       
  1381 /**
       
  1382 Adds 'RDATE' property to aComponent from aEntry
       
  1383 @param aComponent component to add the RDATE property to
       
  1384 @param aEntry entry to extract RRULE information from
       
  1385 @internalTechnology
       
  1386 */
       
  1387 void CAgnVersit2Exporter::AddRDatePropertyL( CICalComponent& aComponent,
       
  1388                                              const CCalEntry& aEntry ) const
       
  1389 	{
       
  1390 	TRACE_ENTRY_POINT;
       
  1391 	
       
  1392 	RArray<TCalTime> rDates;
       
  1393 	CleanupClosePushL(rDates);
       
  1394 	aEntry.GetRDatesL(rDates);
       
  1395 	const TInt count = rDates.Count();
       
  1396 	if (count)
       
  1397 		{
       
  1398 		//Must create a property with a value
       
  1399 		CICalValue* val = CICalValue::NewLC();
       
  1400 		val->SetDateTimeL(rDates[0].TimeUtcL(), CICalValue::EUtcTime);
       
  1401 		CleanupStack::Pop(val);
       
  1402 		CICalProperty& prop = aComponent.AddPropertyL(KICalRdate, val); //Pass ownership
       
  1403 
       
  1404 		for (TInt x = 1; x < count; ++x)
       
  1405 			{
       
  1406 			val = CICalValue::NewLC();
       
  1407 			val->SetDateTimeL(rDates[x].TimeUtcL(), CICalValue::EUtcTime);
       
  1408 			CleanupStack::Pop(val);
       
  1409 			prop.AddValueL(val);
       
  1410 			}
       
  1411 		}
       
  1412 	CleanupStack::PopAndDestroy(&rDates);
       
  1413 	
       
  1414 	TRACE_EXIT_POINT;
       
  1415 	}
       
  1416 
       
  1417 /**
       
  1418 Adds 'EXDATE' property to aComponent from aEntry
       
  1419 @param aComponent component to add the EXDATE property to
       
  1420 @param aEntry entry to extract EXDATE information from
       
  1421 @internalTechnology
       
  1422 */
       
  1423 void CAgnVersit2Exporter::AddRRulePropertyL( CICalComponent& aComponent,
       
  1424                                              const CCalEntry& aEntry ) const
       
  1425 	{
       
  1426 	TRACE_ENTRY_POINT;
       
  1427 	
       
  1428 	TCalRRule rule;
       
  1429 	if (aEntry.GetRRuleL(rule))
       
  1430 		{
       
  1431 		HBufC* ruleVal = HBufC::NewLC(KInitialRRuleLength);
       
  1432 		TPtr ruleValPtr(ruleVal->Des());
       
  1433 		//Add 'FREQ'
       
  1434 		ruleValPtr.Append(KICalFreq);
       
  1435 		ruleValPtr.Append(KICalEquals);
       
  1436 		switch (rule.Type())
       
  1437 			{
       
  1438 			case TCalRRule::EDaily:
       
  1439 				ruleValPtr.Append(KICalDaily);
       
  1440 				break;
       
  1441 			case TCalRRule::EWeekly:
       
  1442 				ruleValPtr.Append(KICalWeekly);
       
  1443 				break;
       
  1444 			case TCalRRule::EMonthly:
       
  1445 				ruleValPtr.Append(KICalMonthly);
       
  1446 				break;
       
  1447 			case TCalRRule::EYearly:
       
  1448 				ruleValPtr.Append(KICalYearly);
       
  1449 				break;
       
  1450 			default:
       
  1451 				{
       
  1452 				User::Leave(KErrCorrupt);
       
  1453 				}
       
  1454 			}
       
  1455 
       
  1456 		// Add 'UNTIL' or 'COUNT'.  Not both.
       
  1457 		// Try UNTIL first as the COUNT implementation has issues.
       
  1458 		TCalTime untilTime = rule.Until();
       
  1459 
       
  1460 		if (untilTime.TimeUtcL() == TCalTime::MaxTime())
       
  1461 			{
       
  1462 			// "UNTIL" returns the maximum date that Agenda can handle, so let's assume that it
       
  1463 			// repeats "forever". In this case we do not export a value for either UNTIL or COUNT.
       
  1464 			// Do nothing...
       
  1465 			}
       
  1466 		else if (untilTime.TimeUtcL() != Time::NullTTime())
       
  1467 			{
       
  1468 			ruleValPtr.Append(KICalSemiColon);
       
  1469 			// Add the 'UNTIL'
       
  1470 			ruleValPtr.Append(KICalUntil);
       
  1471 			ruleValPtr.Append(KICalEquals);
       
  1472 			CICalValue* val = CICalValue::NewLC();
       
  1473 			// iCalendar spec states 'UNTIL' should be in UTC
       
  1474 			val->SetDateTimeL(untilTime.TimeUtcL(), CICalValue::EUtcTime);
       
  1475 			ruleValPtr.Append(val->TextL());
       
  1476 			CleanupStack::PopAndDestroy(val);
       
  1477 			}
       
  1478 		else
       
  1479 			{
       
  1480 			TInt countNum = rule.Count();
       
  1481 
       
  1482 			if (countNum != 0)
       
  1483 				{
       
  1484 				ruleValPtr.Append(KICalSemiColon);
       
  1485 				ruleValPtr.Append(KICalCount);
       
  1486 				ruleValPtr.Append(KICalEquals);
       
  1487 
       
  1488 				// APINOTE: COUNT seems to be divided by interval during aEntry.GetRRuleL call.
       
  1489 				// APINOTE: It also seems to be count left (from now) rather than count from DTSTART.
       
  1490 				// APINOTE: In either case UNTIL will always be valid with the current API, so COUNT will never be used.
       
  1491 				countNum *= rule.Interval();
       
  1492 				ruleValPtr.AppendNum(countNum);
       
  1493 				}
       
  1494 
       
  1495 			// Else neither is present event repeats forever.
       
  1496 			}
       
  1497 
       
  1498 		//Add 'INTERVAL' if present
       
  1499 		TInt interval = rule.Interval();
       
  1500 
       
  1501 		if (interval > 1)	// "1" is the default, so don't bother exporting it.
       
  1502 			{
       
  1503 			ruleValPtr.Append(KICalSemiColon);
       
  1504 			ruleValPtr.Append(KICalInterval);
       
  1505 			ruleValPtr.Append(KICalEquals);
       
  1506 			ruleValPtr.AppendNum(rule.Interval());
       
  1507 			}
       
  1508 
       
  1509 		//Add 'BYMONTHDAY' if present
       
  1510 		if(rule.Type() == TCalRRule::EMonthly)
       
  1511 			{
       
  1512 			RArray<TInt> monthDays;
       
  1513 			CleanupClosePushL(monthDays);
       
  1514 			rule.GetByMonthDayL(monthDays);
       
  1515 			TInt count = monthDays.Count();
       
  1516 
       
  1517 			if (count > 0)
       
  1518 				{
       
  1519 				ruleValPtr.Append(KICalSemiColon);
       
  1520 				ruleValPtr.Append(KICalByMonthDay);
       
  1521 				ruleValPtr.Append(KICalEquals);
       
  1522 
       
  1523 				for (TInt x = 0; x < count; ++x)
       
  1524 					{
       
  1525 					//Add 1 the month day ( 0 = 1).
       
  1526 					ruleValPtr.AppendNum( monthDays[x]  + 1 );
       
  1527 					if (x < count - 1)
       
  1528 						{
       
  1529 						ruleValPtr.Append(KICalComma);
       
  1530 						}
       
  1531 					}
       
  1532 
       
  1533 				}
       
  1534 			CleanupStack::PopAndDestroy(&monthDays);
       
  1535 			}
       
  1536 
       
  1537 		//Add 'WKST'.  Agenda only supports 'WKST' if 'FREQ=WEEKLY'
       
  1538 		if (rule.Type() == TCalRRule::EWeekly)
       
  1539 			{
       
  1540 			ruleValPtr.Append(KICalSemiColon);
       
  1541 			ruleValPtr.Append(KICalWkSt);
       
  1542 			ruleValPtr.Append(KICalEquals);
       
  1543 			ruleValPtr.Append(DayFromTDay(rule.WkSt()));
       
  1544 			}
       
  1545 
       
  1546 
       
  1547 		//Add 'BYDAY'
       
  1548 		if ( rule.Type() == TCalRRule::EYearly  ||
       
  1549 		     rule.Type() == TCalRRule::EMonthly ||
       
  1550 		     rule.Type() == TCalRRule::EWeekly )
       
  1551 			{
       
  1552 			RArray<TDay> days;
       
  1553 			CleanupClosePushL(days);
       
  1554 			RArray<TCalRRule::TDayOfMonth> daysOfMonth;
       
  1555 			CleanupClosePushL(daysOfMonth);
       
  1556 			rule.GetByDayL(days);
       
  1557 			rule.GetByDayL(daysOfMonth);
       
  1558 			TInt daysCount = days.Count();
       
  1559 			TInt daysOfMonthCount = daysOfMonth.Count();
       
  1560 
       
  1561 			if (daysCount > 0 || daysOfMonthCount > 0)
       
  1562 				{
       
  1563 				ruleValPtr.Append(KICalSemiColon);
       
  1564 				ruleValPtr.Append(KICalByDay);
       
  1565 				ruleValPtr.Append(KICalEquals);
       
  1566 				}
       
  1567 
       
  1568 			if (daysCount > 0)
       
  1569 				{
       
  1570 				for (TInt x = 0; x < daysCount; ++x)
       
  1571 					{
       
  1572 					ruleValPtr.Append(DayFromTDay(days[x]));
       
  1573 					if (x < daysCount - 1)
       
  1574 						{
       
  1575 						ruleValPtr.Append(KICalComma);
       
  1576 						}
       
  1577 					}
       
  1578 				}
       
  1579 			if (daysOfMonthCount > 0)
       
  1580 				{
       
  1581 				for (TInt x = 0; x < daysOfMonthCount; ++x)
       
  1582 					{
       
  1583 					ruleValPtr.AppendNum(daysOfMonth[x].WeekInMonth());
       
  1584 					ruleValPtr.Append(DayFromTDay(daysOfMonth[x].Day()));
       
  1585 					if (x < daysOfMonthCount - 1)
       
  1586 						{
       
  1587 						ruleValPtr.Append(KICalComma);
       
  1588 						}
       
  1589 					}
       
  1590 				}
       
  1591 			CleanupStack::PopAndDestroy(&daysOfMonth);
       
  1592 			CleanupStack::PopAndDestroy(&days);
       
  1593 			}
       
  1594 
       
  1595 
       
  1596 		//Add 'BYMONTH'. Agenda only supports 'BYMONTH' if 'FREQ=YEARLY'
       
  1597 		if (rule.Type() == TCalRRule::EYearly)
       
  1598 			{
       
  1599 			RArray<TMonth> theMonths;
       
  1600 			CleanupClosePushL(theMonths);
       
  1601 			rule.GetByMonthL(theMonths);
       
  1602 
       
  1603 			TInt monthsCount = theMonths.Count();
       
  1604 
       
  1605 			if (monthsCount > 0)
       
  1606 				{
       
  1607 				ruleValPtr.Append(KICalSemiColon);
       
  1608 				ruleValPtr.Append(KICalByMonth);
       
  1609 				ruleValPtr.Append(KICalEquals);
       
  1610 
       
  1611 				for (int i = 0; i < monthsCount; i++)
       
  1612 					{
       
  1613 					TInt monthNum = (TInt)(theMonths[i] + 1);	// TMonth is offset from 0
       
  1614 					ruleValPtr.AppendNum(monthNum);
       
  1615 					if (i < monthsCount - 1)
       
  1616 						{
       
  1617 						ruleValPtr.Append(KICalComma);
       
  1618 						}
       
  1619 					}
       
  1620 				}
       
  1621 			CleanupStack::PopAndDestroy(&theMonths);
       
  1622 			}
       
  1623 
       
  1624 		CICalValue* val = CICalValue::NewLC();
       
  1625 		val->SetTextL(ruleValPtr);
       
  1626 		CleanupStack::Pop(val);
       
  1627 		CICalProperty& prop = aComponent.AddPropertyL(KICalRRule,val); //Pass ownership
       
  1628 
       
  1629 		CleanupStack::PopAndDestroy(ruleVal);
       
  1630 		
       
  1631 		TRACE_EXIT_POINT;
       
  1632 		}
       
  1633 	}
       
  1634 
       
  1635 /**
       
  1636 Adds a date-time property to the passed component. Outputs in Local time if
       
  1637 possible, UTC otherwise.
       
  1638 @param aComponent component to add the property to.
       
  1639 @param aUtcTime time in UTC.
       
  1640 @param aProperty property to add.
       
  1641 @return property resulting from adding the date-time.
       
  1642 @internalTechnology
       
  1643 */
       
  1644 CICalProperty& CAgnVersit2Exporter::AddDateTimePropertyL(CICalComponent& aComponent,
       
  1645 	const TCalTime& aTime, const TDesC& aProperty) const
       
  1646 	{
       
  1647 	TRACE_ENTRY_POINT;
       
  1648 	
       
  1649 	// Check if we have a local time zone name - output in this timezone if we do
       
  1650 	if ((iTimezoneIndex != KErrNotFound) && (iTimezoneIndex < iTzNameArray.Count()))
       
  1651 		{
       
  1652 		CICalValue* val = CICalValue::NewLC();
       
  1653 		TTime timeCopy(aTime.TimeUtcL());
       
  1654 		ASSERT(iTimeZoneArray.Count() >= iTimezoneIndex + 1);
       
  1655 		iTimeZoneArray[iTimezoneIndex]->ConvertToLocalL(timeCopy);
       
  1656 		val->SetDateTimeL(timeCopy, CICalValue::ESpecifiedTimeZone);
       
  1657 		CleanupStack::Pop(val);
       
  1658 		CICalProperty& prop = aComponent.AddPropertyL(aProperty, val); //pass ownership of val
       
  1659 		prop.AddPropertyParamL(KICalTzid,*iTzNameArray[iTimezoneIndex]);
       
  1660 		
       
  1661 		TRACE_EXIT_POINT;
       
  1662 		return prop;
       
  1663 		}
       
  1664 	else if(aTime.TimeMode() == TCalTime::EFloating)
       
  1665 		{
       
  1666 		TRACE_EXIT_POINT;
       
  1667 		// If the CalTime was a floating time when it was created, output in floating time.
       
  1668 		return AddFloatingDateTimePropertyL(aComponent, aTime.TimeLocalL(), aProperty);
       
  1669 		}
       
  1670 	else
       
  1671 		{
       
  1672 		TRACE_EXIT_POINT;
       
  1673 		// Otherwise output in UTC
       
  1674 		return AddUtcDateTimePropertyL(aComponent, aTime.TimeUtcL(), aProperty);
       
  1675 		}
       
  1676 	}
       
  1677 
       
  1678 /**
       
  1679 Adds a date-time property to the passed component. Forces UTC.
       
  1680 @param aComponent component to add the property to.
       
  1681 @param aUtcTime time in UTC.
       
  1682 @param aProperty property to add.
       
  1683 @return property resulting from adding the date-time.
       
  1684 @internalTechnology
       
  1685 */
       
  1686 CICalProperty& CAgnVersit2Exporter::AddUtcDateTimePropertyL(CICalComponent& aComponent,
       
  1687 	const TTime& aUtcTime, const TDesC& aProperty) const
       
  1688 	{
       
  1689 	TRACE_ENTRY_POINT;
       
  1690 	
       
  1691 	CICalValue* val = CICalValue::NewLC();
       
  1692 	val->SetDateTimeL(aUtcTime,CICalValue::EUtcTime);
       
  1693 	CleanupStack::Pop(val);
       
  1694 	CICalProperty& prop = aComponent.AddPropertyL(aProperty, val); //pass ownership of val
       
  1695 	
       
  1696 	TRACE_EXIT_POINT;
       
  1697 	return prop;
       
  1698 	}
       
  1699 
       
  1700 /**
       
  1701 Adds a date-time property to the passed component. Forces floating.
       
  1702 @param aComponent component to add the property to.
       
  1703 @param aUtcTime time in floating time.
       
  1704 @param aProperty property to add.
       
  1705 @return property resulting from adding the date-time.
       
  1706 @internalTechnology
       
  1707 */
       
  1708 CICalProperty& CAgnVersit2Exporter::AddFloatingDateTimePropertyL(CICalComponent& aComponent,
       
  1709 	const TTime& aFloatingTime, const TDesC& aProperty) const
       
  1710 	{
       
  1711 	TRACE_ENTRY_POINT;
       
  1712 	
       
  1713 	CICalValue* val = CICalValue::NewLC();
       
  1714 	val->SetDateTimeL(aFloatingTime,CICalValue::EFloatingTime);
       
  1715 	CleanupStack::Pop(val);
       
  1716 	CICalProperty& prop = aComponent.AddPropertyL(aProperty, val); //pass ownership of val
       
  1717 	
       
  1718 	TRACE_EXIT_POINT;
       
  1719 	return prop;
       
  1720 	}
       
  1721 
       
  1722 
       
  1723 //
       
  1724 //     HELPER FUNCTIONS
       
  1725 //     ================
       
  1726 //
       
  1727 
       
  1728 /**
       
  1729 Helper function to convert between a CCalEntry::TReplicationStatus stored in
       
  1730 agenda and a spec-compliant descriptor
       
  1731 @param aStatus agenda representation of CLASS
       
  1732 @return Descriptor representation of CLASS
       
  1733 */
       
  1734 const TDesC& CAgnVersit2Exporter::ClassStringL(const CCalEntry::TReplicationStatus aStatus)
       
  1735 	{
       
  1736 	TRACE_ENTRY_POINT;
       
  1737 	
       
  1738 	switch (aStatus)
       
  1739 		{
       
  1740 		case CCalEntry::EOpen :
       
  1741 		    TRACE_EXIT_POINT;
       
  1742 			return KICalPublic;
       
  1743 		case CCalEntry::EPrivate :
       
  1744 		    TRACE_EXIT_POINT;
       
  1745 			return KICalPrivate;
       
  1746 		case CCalEntry::ERestricted :
       
  1747 		    TRACE_EXIT_POINT;
       
  1748 			return KICalConfidential;
       
  1749 		default :
       
  1750 			User::Leave(KErrCorrupt);
       
  1751 			break;
       
  1752 		}
       
  1753 
       
  1754     TRACE_EXIT_POINT;	    
       
  1755 	return KNullDesC;
       
  1756 	}
       
  1757 
       
  1758 /**
       
  1759 Helper function to convert between a category stored in agenda and a
       
  1760 spec-compliant descriptor
       
  1761 @param aCategory category to extract data from
       
  1762 @return Descriptor representation of category
       
  1763 @internalTechnology
       
  1764 */
       
  1765 const TDesC& CAgnVersit2Exporter::CategoryStringL(const CCalCategory& aCategory) const
       
  1766 	{
       
  1767 	TRACE_ENTRY_POINT;
       
  1768 	
       
  1769 	switch (aCategory.Category())
       
  1770 		{
       
  1771 		case CCalCategory::ECalAppointment :
       
  1772 		    TRACE_EXIT_POINT;
       
  1773 			return iStringProvider.StringL(EICalAppointment);
       
  1774 		case CCalCategory::ECalBusiness :
       
  1775 		    TRACE_EXIT_POINT;
       
  1776 			return iStringProvider.StringL(EICalBusiness);
       
  1777 		case CCalCategory::ECalEducation :
       
  1778 		    TRACE_EXIT_POINT;
       
  1779 			return iStringProvider.StringL(EICalEducation);
       
  1780 		case CCalCategory::ECalHoliday :
       
  1781 		    TRACE_EXIT_POINT;   
       
  1782 			return iStringProvider.StringL(EICalHoliday);
       
  1783 		case CCalCategory::ECalMeeting :
       
  1784 		    TRACE_EXIT_POINT;
       
  1785 			return iStringProvider.StringL(EICalMeeting);
       
  1786 		case CCalCategory::ECalMiscellaneous :
       
  1787 		    TRACE_EXIT_POINT;
       
  1788 			return iStringProvider.StringL(EICalMisc);
       
  1789 		case CCalCategory::ECalPersonal :
       
  1790 		    TRACE_EXIT_POINT;
       
  1791 			return iStringProvider.StringL(EICalPersonal);
       
  1792 		case CCalCategory::ECalPhoneCall :
       
  1793 		    TRACE_EXIT_POINT;
       
  1794 			return iStringProvider.StringL(EICalPhoneCall);
       
  1795 		case CCalCategory::ECalSickDay :
       
  1796 		    TRACE_EXIT_POINT;
       
  1797 			return iStringProvider.StringL(EICalSick);
       
  1798 		case CCalCategory::ECalSpecialOccasion :
       
  1799 		    TRACE_EXIT_POINT;
       
  1800 			return iStringProvider.StringL(EICalSpecial);
       
  1801 		case CCalCategory::ECalTravel :
       
  1802 		    TRACE_EXIT_POINT;
       
  1803 			return iStringProvider.StringL(EICalTravel);
       
  1804 		case CCalCategory::ECalVacation :
       
  1805 		    TRACE_EXIT_POINT;
       
  1806 			return iStringProvider.StringL(EICalVacation);
       
  1807 		case CCalCategory::ECalExtended :
       
  1808 		    TRACE_EXIT_POINT;
       
  1809 			return aCategory.ExtendedCategoryName();
       
  1810 		default :
       
  1811 			User::Leave(KErrCorrupt);
       
  1812 			break;
       
  1813 		}
       
  1814     
       
  1815     TRACE_EXIT_POINT;
       
  1816 	return KNullDesC;
       
  1817 	}
       
  1818 
       
  1819 /**
       
  1820 Converts from a TCalRole defined in CCalAttendee into a spec-compliant
       
  1821 descriptor.
       
  1822 @param aRole TCalRole enumeration to convert from.
       
  1823 @return Descriptor containing the equivalent text.
       
  1824 @internalTechnology
       
  1825 */
       
  1826 const TDesC& CAgnVersit2Exporter::RoleFromEnum(CCalAttendee::TCalRole aRole)
       
  1827 	{
       
  1828 	TRACE_ENTRY_POINT;
       
  1829 	
       
  1830 	switch (aRole)
       
  1831 		{
       
  1832 		case CCalAttendee::EReqParticipant :
       
  1833 		    TRACE_EXIT_POINT;
       
  1834 			return KICalReqParticipant;
       
  1835 		case CCalAttendee::EOptParticipant :
       
  1836 		    TRACE_EXIT_POINT;
       
  1837 			return KICalOptParticipant;
       
  1838 		case CCalAttendee::ENonParticipant :
       
  1839 		    TRACE_EXIT_POINT;
       
  1840 			return KICalNonParticipant;
       
  1841 		case CCalAttendee::EChair :
       
  1842 		    TRACE_EXIT_POINT;
       
  1843 			return KICalChair;
       
  1844 		default :
       
  1845 			break;
       
  1846 		}
       
  1847     
       
  1848     TRACE_EXIT_POINT;
       
  1849 	return KNullDesC;
       
  1850 	}
       
  1851 
       
  1852 /**
       
  1853 Converts from a TCalStatus defined in CCalAttendee into a spec-compliant descriptor.
       
  1854 @param aStatus TCalStatus enumeration to convert from.
       
  1855 @return Descriptor containing the equivalent text.
       
  1856 @internalTechnology
       
  1857 */
       
  1858 const TDesC& CAgnVersit2Exporter::StatusFromEnum(CCalAttendee::TCalStatus aStatus)
       
  1859 	{
       
  1860 	TRACE_ENTRY_POINT;
       
  1861 	
       
  1862 	switch (aStatus)
       
  1863 		{
       
  1864 		case CCalAttendee::EAccepted :
       
  1865 		    TRACE_EXIT_POINT;
       
  1866 			return KICalAccepted;
       
  1867 		case CCalAttendee::ETentative :
       
  1868 		    TRACE_EXIT_POINT;
       
  1869 			return KICalTentative;
       
  1870 		case CCalAttendee::EConfirmed :
       
  1871 		    TRACE_EXIT_POINT;
       
  1872 			return KICalConfirmed;
       
  1873 		case CCalAttendee::EDeclined :
       
  1874 		    TRACE_EXIT_POINT;
       
  1875 			return KICalDeclined;
       
  1876 		case CCalAttendee::ECompleted :
       
  1877 		    TRACE_EXIT_POINT;
       
  1878 			return KICalCompleted;
       
  1879 		case CCalAttendee::EDelegated :
       
  1880 		    TRACE_EXIT_POINT;
       
  1881 			return KICalDelegated;
       
  1882 		case CCalAttendee::EInProcess :
       
  1883 		    TRACE_EXIT_POINT;
       
  1884 			return KICalInProcess;
       
  1885 		case CCalAttendee::ENeedsAction :
       
  1886 		// Needs action is the default so fall through and set a null descriptor
       
  1887 		default :
       
  1888 			break;
       
  1889 		}
       
  1890     
       
  1891     TRACE_EXIT_POINT;
       
  1892 	return KNullDesC;
       
  1893 	}
       
  1894 
       
  1895 /**
       
  1896 Helper function to convert from a TUint8 as defined in vtzrules.h into a
       
  1897 spec-compliant descriptor, such as MO, TU etc.
       
  1898 @param aDayInt Day number to be converted.
       
  1899 @return Descriptor containing the converted day.
       
  1900 @internalTechnology
       
  1901 */
       
  1902 const TDesC& CAgnVersit2Exporter::DayFromInt(TUint8 aDayInt)
       
  1903 	{
       
  1904 	TRACE_ENTRY_POINT;
       
  1905 	
       
  1906 	switch (aDayInt)
       
  1907 		{
       
  1908 		case 0 :
       
  1909 		    TRACE_EXIT_POINT;
       
  1910 			return KICalMonday;
       
  1911 		case 1 :
       
  1912 		    TRACE_EXIT_POINT;
       
  1913 			return KICalTuesday;
       
  1914 		case 2 :
       
  1915 		    TRACE_EXIT_POINT;
       
  1916 			return KICalWednesday;
       
  1917 		case 3 :
       
  1918 		    TRACE_EXIT_POINT;
       
  1919 			return KICalThursday;
       
  1920 		case 4 :
       
  1921 		    TRACE_EXIT_POINT;
       
  1922 			return KICalFriday;
       
  1923 		case 5 :
       
  1924 		    TRACE_EXIT_POINT;
       
  1925 			return KICalSaturday;
       
  1926 		case 6 :
       
  1927 		    TRACE_EXIT_POINT;
       
  1928 			return KICalSunday;
       
  1929 		default :
       
  1930 			break;
       
  1931 		}
       
  1932     
       
  1933     TRACE_EXIT_POINT;
       
  1934 	return KNullDesC;
       
  1935 	}
       
  1936 
       
  1937 /**
       
  1938 Helper function to convert from a TDay into a spec-compliant descriptor, such
       
  1939 as MO, TU etc.
       
  1940 @param aDay TDay to be converted.
       
  1941 @return Descriptor containing the converted day.
       
  1942 @internalTechnology
       
  1943 */
       
  1944 const TDesC& CAgnVersit2Exporter::DayFromTDay(TDay aDay)
       
  1945 	{
       
  1946 	TRACE_ENTRY_POINT;
       
  1947 	
       
  1948 	switch (aDay)
       
  1949 		{
       
  1950 		case EMonday :
       
  1951 		    TRACE_EXIT_POINT;
       
  1952 			return KICalMonday;
       
  1953 		case ETuesday :
       
  1954 		    TRACE_EXIT_POINT;
       
  1955 			return KICalTuesday;
       
  1956 		case EWednesday :
       
  1957 		    TRACE_EXIT_POINT;
       
  1958 			return KICalWednesday;
       
  1959 		case EThursday :
       
  1960 		    TRACE_EXIT_POINT;
       
  1961 			return KICalThursday;
       
  1962 		case EFriday :
       
  1963 		    TRACE_EXIT_POINT;
       
  1964 			return KICalFriday;
       
  1965 		case ESaturday :
       
  1966 		    TRACE_EXIT_POINT;
       
  1967 			return KICalSaturday;
       
  1968 		case ESunday :
       
  1969 		    TRACE_EXIT_POINT;
       
  1970 			return KICalSunday;
       
  1971 		default :
       
  1972 			break;
       
  1973 		}
       
  1974 	
       
  1975 	TRACE_EXIT_POINT;
       
  1976 	return KNullDesC;
       
  1977 	}
       
  1978 
       
  1979 TInt CAgnVersit2Exporter::WeekNumFromDayOfMonth(TInt aDayOfMonth)
       
  1980 	{
       
  1981 	TRACE_ENTRY_POINT;
       
  1982 	
       
  1983 	TRACE_EXIT_POINT;
       
  1984 	return ((aDayOfMonth - 1) / 7) + 1;
       
  1985 	}
       
  1986 
       
  1987 //End of file.