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