calendarengines/caleninterimutils/src/CalenInterimUtils2Impl.cpp
changeset 0 f979ecb2b13e
child 25 bf573002ff72
equal deleted inserted replaced
-1:000000000000 0:f979ecb2b13e
       
     1 /*
       
     2 * Copyright (c) 2005 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 class contains utility method implementation 
       
    15 *               related to usage of Calendar Interim API.
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 // ----------------------------------------------------------------------------
       
    21 // INCLUDE FILES
       
    22 // ----------------------------------------------------------------------------
       
    23 //
       
    24 #include "CalenInterimUtils2Impl.h"
       
    25 
       
    26 //debug
       
    27 #include "calendarengines_debug.h"
       
    28 
       
    29 #include <calentry.h>
       
    30 #include <caluser.h>
       
    31 #include <calentryview.h>
       
    32 #include <etelmm.h>
       
    33 #include <e32math.h>
       
    34 #include <calrrule.h>
       
    35 #include <cmrmailboxutils.h>
       
    36 #include <featmgr.h>
       
    37 #include <MeetingRequestUids.hrh>
       
    38 #include <ecom/ecom.h>
       
    39 #include <utf.h>
       
    40 #include <openssl/md5.h>
       
    41 #include <string.h>
       
    42 
       
    43 #include "CleanupResetAndDestroy.h"
       
    44 #include "RImplInfoPtrArrayOwn.inl"
       
    45 #include "CalenEcomWatcher.h"       // Watches for ECOM registry changes
       
    46 
       
    47 // CONSTANTS
       
    48 /// Unnamed namespace for local definitions
       
    49 namespace {
       
    50 
       
    51 #ifdef __WINSCW__
       
    52     _LIT( KEmulatorImei, "123456789012345" );
       
    53 #endif
       
    54 
       
    55     const TInt KImeiLength = 15; // 15 chars from left of imei
       
    56 
       
    57     const TInt KAsciiFirstNumber = 48;             // ASCII character 48 = '0'.
       
    58     const TInt KAsciiFirstLowercaseLetter = 97;    // ASCII character 97 = 'a'.
       
    59 
       
    60 }  // namespace
       
    61 
       
    62 // ----------------------------------------------------------------------------
       
    63 // MEMBER FUNCTIONS
       
    64 // ----------------------------------------------------------------------------
       
    65 //
       
    66 
       
    67 // -----------------------------------------------------------------------------
       
    68 // CCalenInterimUtils2Impl::NewL()
       
    69 // Creates and returns a new CCalenInterimUtils2Impl object.
       
    70 // (other items were commented in a header).
       
    71 // -----------------------------------------------------------------------------
       
    72 CCalenInterimUtils2Impl* CCalenInterimUtils2Impl::NewL()
       
    73     {
       
    74     TRACE_ENTRY_POINT;
       
    75     
       
    76     CCalenInterimUtils2Impl* self = new(ELeave) CCalenInterimUtils2Impl();
       
    77     CleanupStack::PushL(self);
       
    78     self->ConstructL();
       
    79     CleanupStack::Pop(self);
       
    80     
       
    81     TRACE_EXIT_POINT;
       
    82     return self;
       
    83     }
       
    84 
       
    85 // -----------------------------------------------------------------------------
       
    86 // CCalenInterimUtils2Impl::CCalenInterimUtils2Impl()
       
    87 // Default constructor
       
    88 // -----------------------------------------------------------------------------
       
    89 CCalenInterimUtils2Impl::CCalenInterimUtils2Impl()
       
    90     {
       
    91     TRACE_ENTRY_POINT;
       
    92 
       
    93     iMrEnabledCheck = ETrue;
       
    94     iMrEnabled = EFalse;
       
    95     
       
    96     TRACE_EXIT_POINT;
       
    97     }
       
    98 
       
    99 // -----------------------------------------------------------------------------
       
   100 // CCalenInterimUtils2Impl::ConstructL()
       
   101 // -----------------------------------------------------------------------------
       
   102 void CCalenInterimUtils2Impl::ConstructL()
       
   103     {
       
   104     TRACE_ENTRY_POINT;
       
   105 
       
   106     FeatureManager::InitializeLibL();
       
   107     // Only start the ecom watcher if the feature flags are on.
       
   108     if ((FeatureManager::FeatureSupported(KFeatureIdMeetingRequestEnabler)) || 
       
   109         (FeatureManager::FeatureSupported(KFeatureIdMeetingRequestSupport)) )
       
   110         {
       
   111         iEcomWatcher  = CCalenEComWatcher::NewL(*this);
       
   112         }
       
   113     
       
   114     TRACE_EXIT_POINT;
       
   115     }
       
   116 
       
   117 // -----------------------------------------------------------------------------
       
   118 // CCalenInterimUtils2Impl::~CCalenInterimUtils2Impl()
       
   119 // -----------------------------------------------------------------------------
       
   120 CCalenInterimUtils2Impl::~CCalenInterimUtils2Impl()
       
   121     {
       
   122     TRACE_ENTRY_POINT;
       
   123     
       
   124     delete iEcomWatcher;
       
   125 	FeatureManager::UnInitializeLib();
       
   126 	
       
   127 	TRACE_EXIT_POINT;
       
   128     }
       
   129 
       
   130 // ----------------------------------------------------------------------------
       
   131 // CCalenInterimUtils2Impl::PopulateChildFromParentL
       
   132 // ----------------------------------------------------------------------------
       
   133 void CCalenInterimUtils2Impl::PopulateChildFromParentL(CCalEntry& aChild, const CCalEntry& aParent)
       
   134     {
       
   135     TRACE_ENTRY_POINT;
       
   136 
       
   137     if ( aChild.DescriptionL() == KNullDesC )
       
   138         {
       
   139         aChild.SetDescriptionL( aParent.DescriptionL() );
       
   140         }
       
   141     if ( aChild.LocationL() == KNullDesC )
       
   142         {
       
   143         aChild.SetLocationL( aParent.LocationL() );
       
   144         }
       
   145     if ( aChild.PriorityL() == 0 )
       
   146         { // zero is undefined priority according to iCal spec.
       
   147         aChild.SetPriorityL( aParent.PriorityL() );
       
   148         }
       
   149     if ( aChild.SummaryL() == KNullDesC )
       
   150         {
       
   151         aChild.SetSummaryL( aParent.SummaryL() );
       
   152         }
       
   153     if ( aChild.StatusL() == CCalEntry::ENullStatus )
       
   154         {
       
   155         aChild.SetStatusL( aParent.StatusL() );
       
   156         }
       
   157     CCalAlarm* childAlarm = aChild.AlarmL();
       
   158     CCalAlarm* parentAlarm = aParent.AlarmL();
       
   159     
       
   160     CleanupStack::PushL(childAlarm);
       
   161     CleanupStack::PushL(parentAlarm);
       
   162     
       
   163     if( !childAlarm && parentAlarm )
       
   164         {
       
   165         aChild.SetAlarmL( parentAlarm);
       
   166         }
       
   167     
       
   168     CleanupStack::PopAndDestroy(childAlarm);
       
   169     CleanupStack::PopAndDestroy(parentAlarm);
       
   170 		
       
   171     if (aChild.ReplicationStatusL() != aParent.ReplicationStatusL())
       
   172         {
       
   173         aChild.SetReplicationStatusL(aParent.ReplicationStatusL());
       
   174         }
       
   175     if (aChild.MethodL() == CCalEntry::EMethodNone)
       
   176         {
       
   177         aChild.SetMethodL(aParent.MethodL());
       
   178         }
       
   179 
       
   180     if ( !aChild.OrganizerL() && aParent.OrganizerL() )
       
   181         {
       
   182         CCalUser* owner = CopyUserLC( *( aParent.OrganizerL() ) );
       
   183         aChild.SetOrganizerL( owner );
       
   184         CleanupStack::Pop(owner); // ownership transferred
       
   185         }
       
   186     
       
   187     PopulateAttendeeListL( aChild, aParent );
       
   188     
       
   189     TRACE_EXIT_POINT;
       
   190     // "Categories" property is omitted
       
   191     }
       
   192 
       
   193 // ----------------------------------------------------------------------------
       
   194 // CCalenInterimUtils2Impl::PopulateAttendeeListL
       
   195 // ----------------------------------------------------------------------------
       
   196 //
       
   197 void CCalenInterimUtils2Impl::PopulateAttendeeListL(
       
   198     CCalEntry& aChild,
       
   199     const CCalEntry& aParent )
       
   200     {
       
   201     TRACE_ENTRY_POINT;
       
   202     
       
   203     RPointerArray<CCalAttendee>& childAtt = aChild.AttendeesL();
       
   204     RPointerArray<CCalAttendee>& parentAtt = aParent.AttendeesL();
       
   205  
       
   206     CCalUser *po = NULL;
       
   207     if ( !aChild.PhoneOwnerL() )
       
   208         { // Phone owner is internal data, not part of ical protocol, it's
       
   209           // benefit is to avoid heavy "who am I?" resolving operation
       
   210         po = aParent.PhoneOwnerL();
       
   211         }
       
   212     TInt parentAttCount( parentAtt.Count() );
       
   213     if ( childAtt.Count() == 0 && parentAttCount > 0 )
       
   214         {
       
   215         for ( TInt i( 0 ); i < parentAttCount; ++i )
       
   216             {
       
   217             CCalAttendee* copy = CopyAttendeeLC( *( parentAtt[i] ) );
       
   218             aChild.AddAttendeeL( copy );
       
   219             CleanupStack::Pop(copy); // ownership transferred
       
   220             if(po == parentAtt[i])
       
   221                 {
       
   222                 aChild.SetPhoneOwnerL(copy);
       
   223 
       
   224                 }
       
   225             }
       
   226         }
       
   227     
       
   228     TRACE_EXIT_POINT;
       
   229     }
       
   230 
       
   231 // ----------------------------------------------------------------------------
       
   232 // CCalenInterimUtils2Impl::CopyAttendeeLC
       
   233 // ----------------------------------------------------------------------------
       
   234 //
       
   235 CCalAttendee* CCalenInterimUtils2Impl::CopyAttendeeLC(
       
   236     const CCalAttendee& aSource )
       
   237     {
       
   238     TRACE_ENTRY_POINT;
       
   239     
       
   240     CCalAttendee* copy = CCalAttendee::NewL( aSource.Address(),
       
   241                                              aSource.SentBy() );
       
   242     CleanupStack::PushL( copy );
       
   243     copy->SetCommonNameL( aSource.CommonName() );
       
   244     copy->SetRoleL( aSource.RoleL() );
       
   245     copy->SetStatusL( aSource.StatusL() );
       
   246     copy->SetResponseRequested( aSource.ResponseRequested() );
       
   247     
       
   248     TRACE_EXIT_POINT;
       
   249     return copy;
       
   250     }
       
   251 
       
   252 // ----------------------------------------------------------------------------
       
   253 // CCalenInterimUtils2Impl::CopyUserLC
       
   254 // ----------------------------------------------------------------------------
       
   255 //
       
   256 CCalUser* CCalenInterimUtils2Impl::CopyUserLC( const CCalUser& aSource )
       
   257     {
       
   258     TRACE_ENTRY_POINT;
       
   259     
       
   260     CCalUser* copy = CCalUser::NewL( aSource.Address(),
       
   261                                      aSource.SentBy() );
       
   262     CleanupStack::PushL( copy );
       
   263     copy->SetCommonNameL( aSource.CommonName() );
       
   264     
       
   265     TRACE_EXIT_POINT;
       
   266     return copy;
       
   267     }
       
   268 
       
   269 
       
   270 // ----------------------------------------------------------------------------
       
   271 // CCalenInterimUtils2Impl::GlobalUidL
       
   272 // ----------------------------------------------------------------------------
       
   273 //
       
   274 HBufC8* CCalenInterimUtils2Impl::GlobalUidL()
       
   275     {
       
   276     TRACE_ENTRY_POINT;
       
   277     
       
   278     // Loosely using UID generation algorithm from
       
   279     // http://www.webdav.org/specs/draft-leach-uuids-guids-01.txt
       
   280 
       
   281     // Number of 100ns ticks since Oct 15 1582.
       
   282     TInt64 timeStamp = GetTicksFromGregorianCalendarStartL();
       
   283 
       
   284     // This differs slightly from the spec in that the clock sequence is just a pseudo-random number.
       
   285        TUint32 clockSeq = Math::Random();
       
   286        // IMEI is read the first time this is called, and stored for subsequent calls.
       
   287        if(!iImeiNode)
       
   288            {
       
   289            iImeiNode = GetImeiAsNodeValueL();
       
   290            }
       
   291 
       
   292     HBufC8* resultBuf = DoCreateUidLC(clockSeq, timeStamp, iImeiNode);
       
   293     CleanupStack::Pop(resultBuf);
       
   294     
       
   295     TRACE_EXIT_POINT;
       
   296     return resultBuf;
       
   297     }
       
   298 
       
   299 // -----------------------------------------------------------------------------
       
   300 // CCalenInterimUtils2Impl::GetTicksFromGregorianCalendarStartL()
       
   301 // This function returns the number of 100ns ticks since 0:00 15th October 1582.
       
   302 // (other items were commented in a header).
       
   303 // -----------------------------------------------------------------------------
       
   304 //
       
   305 TInt64 CCalenInterimUtils2Impl::GetTicksFromGregorianCalendarStartL()
       
   306     {
       
   307     TRACE_ENTRY_POINT;
       
   308     
       
   309     TTime timeNow;
       
   310     timeNow.HomeTime();
       
   311     TDateTime gregorianStartDT(1582, EOctober, 15, 0, 0, 0, 0);
       
   312     TTime gregorianStart(gregorianStartDT);
       
   313     TTimeIntervalMicroSeconds msDifference = timeNow.MicroSecondsFrom(gregorianStart);
       
   314     
       
   315     TRACE_EXIT_POINT;
       
   316     return msDifference.Int64() * 10; // * 10 to convert from micro sec (==1000 ns) count to 100ns count.
       
   317     }
       
   318 
       
   319 // -----------------------------------------------------------------------------
       
   320 // CCalenInterimUtils2Impl::GetImeiAsNodeValueL()
       
   321 // Formats the IMEI returned from GetImeiL() into a 64-bit integer.
       
   322 // (other items were commented in a header).
       
   323 // -----------------------------------------------------------------------------
       
   324 //
       
   325 TInt64 CCalenInterimUtils2Impl::GetImeiAsNodeValueL()
       
   326     {
       
   327     TRACE_ENTRY_POINT;
       
   328     
       
   329     TBuf<RMobilePhone::KPhoneSerialNumberSize> serialNumber;
       
   330     GetImeiL( serialNumber );
       
   331 
       
   332     // Trim off all but the first KImeiLength digits.
       
   333     TLex lex( serialNumber.Left(KImeiLength) );
       
   334 
       
   335     TInt64 val;
       
   336     User::LeaveIfError(lex.Val(val));
       
   337     
       
   338     TRACE_EXIT_POINT;
       
   339     return val;
       
   340     }
       
   341 
       
   342 inline TUint8 LastFourBits(TUint8& aNum)
       
   343     {
       
   344     TRACE_ENTRY_POINT;
       
   345     
       
   346     // 00001111 b
       
   347     TRACE_EXIT_POINT;
       
   348     return aNum & 0x0F;
       
   349     }
       
   350 
       
   351 inline TUint8 FirstFourBits(TUint8& aNum)
       
   352     {
       
   353     TRACE_ENTRY_POINT;
       
   354     
       
   355     // 11110000 b
       
   356     TRACE_EXIT_POINT;
       
   357     return (aNum & 0xF0) >> 4;
       
   358     }
       
   359 
       
   360 // -----------------------------------------------------------------------------
       
   361 // CCalenInterimUtils2Impl::DoCreateUidLC()
       
   362 // Performs the work in creating a GUID.
       
   363 // (other items were commented in a header).
       
   364 // -----------------------------------------------------------------------------
       
   365 //
       
   366 HBufC8* CCalenInterimUtils2Impl::DoCreateUidLC( const TUint32& aClockSeq,
       
   367                                                const TUint64& aTimeStamp,
       
   368                                                const TUint64& aNodeValue )
       
   369     {
       
   370     TRACE_ENTRY_POINT;
       
   371     
       
   372     // The roast beef of the algorithm. Does all the shifting about as described in the web draft.
       
   373     TUint32 time_low = aTimeStamp & 0xFFFFFFFF;
       
   374     TUint16 time_mid = (aTimeStamp >> 32) & 0xFFFF;
       
   375     TUint16 time_high = (aTimeStamp >> 48) & 0x0FFF;
       
   376     time_high |= (1 << 12);
       
   377     TUint8 clock_seq_low = aClockSeq & 0xFF;
       
   378     TUint8 clock_seq_high = (aClockSeq & 0x3F00) >> 8;
       
   379     clock_seq_high |= 0x80;
       
   380 
       
   381     // Can't use RArray as that's set up for minimum 4 bytes per item.
       
   382     CArrayFixFlat<TUint8> *node = new (ELeave) CArrayFixFlat<TUint8>(6);
       
   383     CleanupStack::PushL(node);
       
   384 
       
   385     // The rest of the function is mapping the 64, 32 and 16 bit numbers to 8 bit numbers
       
   386     // while losing as little data as possible.
       
   387 
       
   388     TUint64 mask = 0xFF0000000000;
       
   389     for(TInt i=0; i<=6; ++i)
       
   390         {
       
   391         TInt64 temp = aNodeValue & mask;
       
   392         temp >>= ((5-i)*8);
       
   393         node->AppendL(temp);
       
   394         mask = mask >> 8;
       
   395         }
       
   396 
       
   397     TBuf8<16> rawOutput;
       
   398 
       
   399     rawOutput.Append( (time_low  & 0xFF000000) >> 24 );
       
   400     rawOutput.Append( (time_low  & 0x00FF0000) >> 16 );
       
   401     rawOutput.Append( (time_low  & 0x0000FF00) >> 8 );
       
   402     rawOutput.Append( (time_low  & 0x000000FF) );
       
   403 
       
   404     rawOutput.Append( (time_mid  & 0xFF00) >> 8 );
       
   405     rawOutput.Append( (time_mid  & 0x00FF) );
       
   406 
       
   407     rawOutput.Append( (time_high & 0xFF00) >> 8 );
       
   408     rawOutput.Append( (time_high & 0x00FF) );
       
   409 
       
   410     rawOutput.Append( clock_seq_low );
       
   411     rawOutput.Append( clock_seq_high );
       
   412 
       
   413     for(TInt i=0; i<6; ++i)
       
   414         {
       
   415         rawOutput.Append( node->At(i) );
       
   416         }
       
   417     CleanupStack::PopAndDestroy(); // node
       
   418     
       
   419     TUint8 digest[16];
       
   420     HBufC8* resultBuf = rawOutput.AllocLC();
       
   421     TPtr8 resultBufPtr = resultBuf->Des();
       
   422     TUint length = resultBufPtr.Length();
       
   423     
       
   424     // Create a new buffer to provide space for '\0'
       
   425     HBufC8* newBuf = HBufC8::NewLC( length + 1 );//+1 space for '\0'
       
   426     TPtr8 newBufPtr = newBuf->Des();
       
   427     newBufPtr.Copy(resultBufPtr);
       
   428     
       
   429     // Appends a zero terminator onto the end of this descriptor's data
       
   430     // and returns a pointer to the data.
       
   431     char* chPtrTemp = ( char*)newBufPtr.PtrZ();
       
   432     char* chPtr = ( char*) User::AllocL( length + 1 );
       
   433     strcpy( chPtr , chPtrTemp );
       
   434     
       
   435     //md5 context
       
   436     MD5_CTX* context = new MD5_CTX();
       
   437     //initialize the context
       
   438     MD5_Init(context);
       
   439     //Append a string to the message
       
   440     MD5_Update(context, chPtr, length );
       
   441     //Finish the message and return the digest.
       
   442     MD5_Final(digest, context );
       
   443     
       
   444     // Add the version field in the msb 4 bits. The value of version is 3.
       
   445     digest[6] = digest[6] & 0x0F;
       
   446     digest[6] |= (3 << 4);
       
   447     
       
   448     //Add the variant field in the msb 2 bits. The value of variant is 2.
       
   449     digest[9] = digest[9] & 0x3F;
       
   450     digest[9] |= 0x80;
       
   451     
       
   452     delete chPtr;
       
   453     delete context;
       
   454     CleanupStack::PopAndDestroy( newBuf );
       
   455     CleanupStack::PopAndDestroy( resultBuf );
       
   456     TBuf8<36> output;
       
   457     TInt i;
       
   458     for(i=0; i<16; ++i)
       
   459         {
       
   460         output.Append( ConvertToCharacterL( FirstFourBits( digest[i] ) ) ); 
       
   461         output.Append( ConvertToCharacterL( LastFourBits( digest[i] ) ) );
       
   462         if(i == 3 || i == 5 || i == 7 ||i == 9)
       
   463             {
       
   464             output.Append( '-' );
       
   465             }
       
   466         }
       
   467     HBufC8* md5ResultBuf = output.AllocLC();
       
   468     
       
   469     TRACE_EXIT_POINT;
       
   470     return md5ResultBuf;
       
   471     }
       
   472 
       
   473 // -----------------------------------------------------------------------------
       
   474 // CCalenInterimUtils2Impl::ConvertToCharacterL()
       
   475 // Converts from a number between 0-15 to a hexadecimal character representation.
       
   476 // 0-9, a-f
       
   477 // -----------------------------------------------------------------------------
       
   478 //
       
   479 TChar CCalenInterimUtils2Impl::ConvertToCharacterL(TUint8 aChar)
       
   480     {
       
   481     TRACE_ENTRY_POINT;
       
   482     
       
   483     if(aChar < 10)
       
   484         {
       
   485         // Convert to a digit.
       
   486         TRACE_EXIT_POINT;
       
   487         return TChar(aChar + KAsciiFirstNumber);
       
   488         }
       
   489     else if(aChar < 16)
       
   490         {
       
   491         // Convert to lower case character.
       
   492         TRACE_EXIT_POINT;
       
   493         return TChar(aChar - 10 + KAsciiFirstLowercaseLetter);
       
   494         }
       
   495 
       
   496     // This function should only be passed numbers between 0-15.
       
   497     User::Leave(KErrArgument);
       
   498     
       
   499     TRACE_EXIT_POINT;
       
   500     return TChar(KAsciiFirstLowercaseLetter); // Stops compiler warning.
       
   501     }
       
   502 
       
   503 // ----------------------------------------------------------------------------
       
   504 // CCalenInterimUtils2Impl::GetImeiL
       
   505 // Gets the IMEI of the device. On the emulator, this will return a fake IMEI.
       
   506 // (other items were commented in a header).
       
   507 // ----------------------------------------------------------------------------
       
   508 //
       
   509 void CCalenInterimUtils2Impl::GetImeiL( TDes& aImei )
       
   510     {
       
   511     TRACE_ENTRY_POINT;
       
   512     
       
   513     #ifndef __WINSCW__
       
   514 
       
   515     RTelServer telServer;
       
   516     User::LeaveIfError( telServer.Connect() );
       
   517     CleanupClosePushL(telServer);
       
   518 
       
   519     TInt numPhones = 0;
       
   520     User::LeaveIfError( telServer.EnumeratePhones(numPhones) );
       
   521     if(numPhones < 1)
       
   522         {
       
   523         User::Leave(KErrNotFound);
       
   524         }
       
   525     RTelServer::TPhoneInfo info;
       
   526     User::LeaveIfError( telServer.GetPhoneInfo(0, info) );
       
   527     RMobilePhone mobilePhone;
       
   528     User::LeaveIfError( mobilePhone.Open(telServer, info.iName) );
       
   529     CleanupClosePushL(mobilePhone);
       
   530 
       
   531     TUint32 identityCaps;
       
   532     User::LeaveIfError( mobilePhone.GetIdentityCaps( identityCaps ) );
       
   533 
       
   534     if ( identityCaps & RMobilePhone::KCapsGetSerialNumber )
       
   535         {
       
   536         TRequestStatus status;
       
   537         RMobilePhone::TMobilePhoneIdentityV1 mobilePhoneIdentity;
       
   538         mobilePhone.GetPhoneId( status, mobilePhoneIdentity );
       
   539         // Needs testing on target - May lock device
       
   540         User::WaitForRequest( status );
       
   541         User::LeaveIfError( status.Int() );
       
   542         aImei = mobilePhoneIdentity.iSerialNumber;
       
   543         }
       
   544     else
       
   545         {
       
   546         User::Leave(KErrNotSupported);
       
   547         }
       
   548 
       
   549     CleanupStack::PopAndDestroy(); // mobilePhone;
       
   550     CleanupStack::PopAndDestroy(); // telServer;
       
   551 
       
   552     #else
       
   553 
       
   554       // Return a fake IMEI when working on emulator
       
   555       aImei = KEmulatorImei;
       
   556 
       
   557     #endif // __WINSCW__
       
   558     
       
   559     TRACE_EXIT_POINT;
       
   560     }
       
   561 
       
   562 // -----------------------------------------------------------------------------
       
   563 // CCalenInterimUtils2Impl::MRViewersEnabledL()
       
   564 // Checks to see if Meeting Request Viewer functionality
       
   565 // is enabled and an implementation is available to use
       
   566 // (other items were commented in a header).
       
   567 // -----------------------------------------------------------------------------
       
   568 //
       
   569 TBool CCalenInterimUtils2Impl::MRViewersEnabledL(TBool aForceCheck)
       
   570     {
       
   571     TRACE_ENTRY_POINT;
       
   572     if( aForceCheck || iMrEnabledCheck )
       
   573         {
       
   574 		iMrEnabled = EFalse;
       
   575 		iMrEnabledCheck = EFalse;
       
   576 
       
   577         PIM_TRAPD_HANDLE( DoMRViewersEnabledL() );
       
   578         }
       
   579         
       
   580     TRACE_EXIT_POINT;
       
   581     return iMrEnabled;    
       
   582     }
       
   583 // -----------------------------------------------------------------------------
       
   584 // CCalenInterimUtils2Impl::DoMRViewersEnabledL()
       
   585 // Checks to see if Meeting Request Viewer functionality
       
   586 // is enabled and an implementation is available to use
       
   587 // (other items were commented in a header).
       
   588 // -----------------------------------------------------------------------------
       
   589 //
       
   590 void CCalenInterimUtils2Impl::DoMRViewersEnabledL()
       
   591     {
       
   592     TRACE_ENTRY_POINT;
       
   593 
       
   594     // We ignore any leaves because iMrEnabled and iMrEnabledCheck are already set to
       
   595     // EFalse, so if the function leaves it will return EFalse this time and any future
       
   596     // calls will not force a check (unless aForceCheck is ETrue).
       
   597     if (FeatureManager::FeatureSupported(KFeatureIdMeetingRequestSupport))
       
   598         {
       
   599         // Full meeting request solution
       
   600         // As long as we have at least one mailbox we can return true
       
   601         CMRMailboxUtils *mbUtils = CMRMailboxUtils::NewL();
       
   602         CleanupStack::PushL( mbUtils );
       
   603 
       
   604                 RArray<CMRMailboxUtils::TMailboxInfo> mailboxes;
       
   605                 CleanupClosePushL(mailboxes);
       
   606                 mbUtils->ListMailBoxesL(mailboxes);
       
   607                 if(mailboxes.Count() > 0)
       
   608                     {
       
   609                     iMrEnabled = ETrue; // && 1 mailbox
       
   610                     }
       
   611 
       
   612         CleanupStack::PopAndDestroy(); // mailboxes
       
   613         CleanupStack::PopAndDestroy(); // mbUtils
       
   614         }
       
   615      else
       
   616         {
       
   617         if (FeatureManager::FeatureSupported(KFeatureIdMeetingRequestEnabler))
       
   618             {
       
   619     		// Meeting request enablers solution
       
   620     		//Check for:
       
   621     		//	At least one mailbox exists on the terminal
       
   622     		//	At least one MRViewer implementation, with an id matching a mailbox,
       
   623     		    //	exists on the terminal
       
   624     		    //	At least one MRUtils implementation exists on the terminal
       
   625     		    CMRMailboxUtils *mbUtils = CMRMailboxUtils::NewL();
       
   626     		    CleanupStack::PushL( mbUtils );
       
   627 
       
   628                 RArray<CMRMailboxUtils::TMailboxInfo> mailboxes;
       
   629                 CleanupClosePushL(mailboxes);
       
   630 
       
   631                 mbUtils->ListMailBoxesL(mailboxes);
       
   632                 if(mailboxes.Count() > 0)
       
   633                     {
       
   634                     RImplInfoPtrArrayOwn implArray;
       
   635                      CleanupClosePushL( implArray );
       
   636 
       
   637                      //Check for a MRViewers Implementation
       
   638                      const TUid mrViewersIface = {KMRViewersInterfaceUID};
       
   639                      REComSession::ListImplementationsL(mrViewersIface, implArray );
       
   640                      if ( implArray.Count() > 0 )
       
   641                          {
       
   642                          // MRViewers implementations exist.  We need to see if any are
       
   643                          // associated with an existing mailbox
       
   644                          TBool mrImplMatchesMailbox = EFalse;
       
   645                          for (TInt i=0; i<implArray.Count(); ++i)
       
   646                              {
       
   647                              for(TInt j=0; j<mailboxes.Count(); ++j)
       
   648                                  {
       
   649                                  TBuf16<KMaxUidName> mbName;
       
   650                                  CnvUtfConverter::ConvertToUnicodeFromUtf8( mbName, implArray[i]->DataType() );
       
   651                                  if(mailboxes[j].iMtmUid.Name().CompareF(mbName) == 0)
       
   652                                      {
       
   653                                     mrImplMatchesMailbox = ETrue;
       
   654                                     //One match is enough for this decision to be true
       
   655                                     break;
       
   656                                     }
       
   657                                  }
       
   658                              if (mrImplMatchesMailbox)
       
   659                                  {
       
   660                                  break;
       
   661                                  }
       
   662                              }
       
   663 
       
   664                          // Reset the viewer implementation array.  This will be reused
       
   665                          // if we need to check for mr utils implementations
       
   666                          implArray.ResetAndDestroy();
       
   667 
       
   668                          if (mrImplMatchesMailbox)
       
   669                              {
       
   670                              // We have at least one MRViewer implementation with an associated
       
   671                              // mailbox.  Check for a matching MR utils implementation
       
   672                              const TUid mrUtilsIface = {KMRUtilsInterfaceUID};
       
   673                              REComSession::ListImplementationsL(mrUtilsIface, implArray );
       
   674                              if (implArray.Count() > 0)
       
   675                                  {
       
   676                                  // Meeting request functionality is available on this device
       
   677                                  iMrEnabled = ETrue;
       
   678                                  }
       
   679                              }
       
   680 
       
   681                          }
       
   682                       CleanupStack::PopAndDestroy(); // implArray
       
   683                       }
       
   684 
       
   685                 CleanupStack::PopAndDestroy(); // mailboxes
       
   686                 CleanupStack::PopAndDestroy(); // mbUtils
       
   687                 }            
       
   688             }
       
   689     }
       
   690 
       
   691 // -----------------------------------------------------------------------------
       
   692 // CCalenInterimUtils2Impl::HasTimeOrDateChangedL()
       
   693 // Checks to see if the date or time has changed from the given entry to the
       
   694 // entry with the same UID stored in the database. This function should only be
       
   695 // called on parent entries with a repeat.
       
   696 // (other items were commented in a header).
       
   697 // -----------------------------------------------------------------------------
       
   698 //
       
   699 TBool CCalenInterimUtils2Impl::HasTimeOrDateChangedL(const CCalEntry& aNewEntry, const CCalEntry& aOldEntry)
       
   700     {
       
   701     TRACE_ENTRY_POINT;
       
   702     
       
   703     TBool hasChanged = EFalse;
       
   704 
       
   705     if( aNewEntry.StartTimeL().TimeUtcL() != aOldEntry.StartTimeL().TimeUtcL() ||
       
   706         aNewEntry.EndTimeL().TimeUtcL()   != aOldEntry.EndTimeL().TimeUtcL())
       
   707         {
       
   708         hasChanged = ETrue;
       
   709         }
       
   710 
       
   711     TRACE_EXIT_POINT;
       
   712     return hasChanged;
       
   713     }
       
   714 
       
   715 // -----------------------------------------------------------------------------
       
   716 // CCalenInterimUtils2Impl::PrepareForStorageL()
       
   717 // Sets the last modified date of an entry, and if aEntry is a meeting request,
       
   718 // sets the phone owner if not previously set.
       
   719 // (other items were commented in a header).
       
   720 // -----------------------------------------------------------------------------
       
   721 //
       
   722 void CCalenInterimUtils2Impl::PrepareForStorageL( CCalEntry& aEntry )
       
   723     {
       
   724     TRACE_ENTRY_POINT;
       
   725 
       
   726     FeatureManager::InitializeLibL();
       
   727 
       
   728     aEntry.SetLastModifiedDateL();
       
   729 
       
   730     if (FeatureManager::FeatureSupported(KFeatureIdMeetingRequestEnabler) ||
       
   731         FeatureManager::FeatureSupported(KFeatureIdMeetingRequestSupport))
       
   732         {
       
   733         if( IsMeetingRequestL(aEntry) && aEntry.PhoneOwnerL() == NULL )
       
   734             {
       
   735             CMRMailboxUtils *mbUtils = CMRMailboxUtils::NewL();
       
   736             CleanupStack::PushL( mbUtils );
       
   737             mbUtils->SetPhoneOwnerL( aEntry );
       
   738             CleanupStack::PopAndDestroy(); // mbUtils
       
   739             }
       
   740         }
       
   741     FeatureManager::UnInitializeLib();
       
   742     
       
   743     TRACE_EXIT_POINT;
       
   744     }
       
   745 
       
   746 // -----------------------------------------------------------------------------
       
   747 // CCalenInterimUtils2Impl::SingleStoreL()
       
   748 // Calls CCalEntryView::StoreL() on the given entry. Puts the entry into an
       
   749 // RPointerArray, as CalInterimApi expects.
       
   750 // (other items were commented in a header).
       
   751 // -----------------------------------------------------------------------------
       
   752 //
       
   753 void CCalenInterimUtils2Impl::SingleStoreL( CCalEntryView& aEntryView,
       
   754                                       CCalEntry& aEntry )
       
   755     {
       
   756     TRACE_ENTRY_POINT;
       
   757 
       
   758     PrepareForStorageL( aEntry );
       
   759     TInt successCount=0;
       
   760     RPointerArray<CCalEntry> entries;
       
   761     CleanupClosePushL( entries );
       
   762     entries.Append( &aEntry );
       
   763     aEntryView.StoreL( entries, successCount );
       
   764     CleanupStack::PopAndDestroy( &entries );
       
   765     
       
   766     TRACE_EXIT_POINT;
       
   767     }
       
   768 
       
   769 // -----------------------------------------------------------------------------
       
   770 // CCalenInterimUtils2Impl::SingleUpdateL()
       
   771 // Calls CCalEntryView::UpdateL() on the given entry. Puts the entry into an
       
   772 // RPointerArray, as CalInterimApi expects.
       
   773 // (other items were commented in a header).
       
   774 // -----------------------------------------------------------------------------
       
   775 //
       
   776 void CCalenInterimUtils2Impl::SingleUpdateL( CCalEntryView& aEntryView,
       
   777                                        CCalEntry& aEntry )
       
   778     {
       
   779     TRACE_ENTRY_POINT;
       
   780     
       
   781     PrepareForStorageL( aEntry );
       
   782     TInt successCount=0;
       
   783     RPointerArray<CCalEntry> entries;
       
   784     CleanupClosePushL( entries );
       
   785     entries.Append( &aEntry );
       
   786     aEntryView.UpdateL( entries, successCount );
       
   787     CleanupStack::PopAndDestroy( &entries );
       
   788     
       
   789     TRACE_EXIT_POINT;
       
   790     }
       
   791 
       
   792 // -----------------------------------------------------------------------------
       
   793 // CCalenInterimUtils2Impl::FieldIsTheSameL()
       
   794 // Checks to see if the ONE given field is the same on one entry as another.
       
   795 // To check if more than one field is the same, call the function more than once
       
   796 // (other items were commented in a header).
       
   797 // -----------------------------------------------------------------------------
       
   798 //
       
   799 TBool CCalenInterimUtils2Impl::FieldIsTheSameL( CCalEntry& aEntryOne,
       
   800                                           CCalEntry& aEntryTwo,
       
   801                                           TDifferenceFlag aFlag)
       
   802     {
       
   803     TRACE_ENTRY_POINT;
       
   804     
       
   805     switch( aFlag )
       
   806         {
       
   807         case EEntryDifferentStartTimeAndEndTime:
       
   808             TRACE_EXIT_POINT;
       
   809             return      ( TimeOfDay( aEntryOne.StartTimeL().TimeUtcL() )
       
   810                         == TimeOfDay( aEntryTwo.StartTimeL().TimeUtcL() ))
       
   811                     &&  ( TimeOfDay( aEntryOne.EndTimeL().TimeUtcL() )
       
   812                         == TimeOfDay( aEntryTwo.EndTimeL().TimeUtcL() ) );
       
   813         case EEntryDifferentSummary:
       
   814             TRACE_EXIT_POINT;
       
   815             return aEntryOne.SummaryL() == aEntryTwo.SummaryL();
       
   816         case EEntryDifferentDescription:
       
   817             TRACE_EXIT_POINT;
       
   818             return aEntryOne.DescriptionL() == aEntryTwo.DescriptionL();
       
   819         case EEntryDifferentLocation:
       
   820             TRACE_EXIT_POINT;
       
   821             return aEntryOne.LocationL() == aEntryTwo.LocationL();
       
   822         default:
       
   823             _LIT(KCalenInterimUtils2Panic, "CCalenInterimUtils2");
       
   824             User::Panic(KCalenInterimUtils2Panic, KErrArgument);
       
   825         }
       
   826     TRACE_EXIT_POINT;
       
   827     return EFalse; // Never hit.
       
   828     }
       
   829 
       
   830 // -----------------------------------------------------------------------------
       
   831 // CCalenInterimUtils2Impl::CopyFieldL()
       
   832 // Copies ONE given field from aSrc to aDst. To copy more than one field,
       
   833 // call the function more than one time.
       
   834 // (other items were commented in a header).
       
   835 // -----------------------------------------------------------------------------
       
   836 //
       
   837 void CCalenInterimUtils2Impl::CopyFieldL( const CCalEntry& aSrc,
       
   838                                     CCalEntry& aDst,
       
   839                                     TDifferenceFlag aField )
       
   840     {
       
   841     TRACE_ENTRY_POINT;
       
   842 
       
   843     switch( aField )
       
   844         {
       
   845         case EEntryDifferentStartTimeAndEndTime:
       
   846             {
       
   847             // START TIME
       
   848             // Keep aDst's start date, but copy the start time (h/m/s) from aSrc to aDst.
       
   849             TTimeIntervalMinutes dtStartTimeOfDay = TimeOfDay( aSrc.StartTimeL().TimeUtcL() );
       
   850             TTime dtStartDay = BeginningOfDay( aDst.StartTimeL().TimeUtcL() );
       
   851 
       
   852             TCalTime startTime;
       
   853             startTime.SetTimeUtcL( dtStartDay + (TTimeIntervalMinutes)dtStartTimeOfDay );
       
   854 
       
   855 
       
   856             TTimeIntervalMinutes duration;
       
   857             aSrc.EndTimeL().TimeUtcL().MinutesFrom(aSrc.StartTimeL().TimeUtcL(), duration);
       
   858 
       
   859             // END TIME
       
   860             // Calculate the duration of aSrc, and make aDst endtime equal aDst startTime
       
   861             // + duration.  This will allow for events spanning multiple days.
       
   862             TCalTime endTime;
       
   863             endTime.SetTimeUtcL(startTime.TimeUtcL() + duration);
       
   864 
       
   865             aDst.SetStartAndEndTimeL(startTime, endTime);
       
   866 
       
   867             break;
       
   868             }
       
   869         case EEntryDifferentSummary:
       
   870             aDst.SetSummaryL(aSrc.SummaryL());
       
   871             break;
       
   872         case EEntryDifferentDescription:
       
   873             aDst.SetDescriptionL(aSrc.DescriptionL());
       
   874             break;
       
   875         case EEntryDifferentLocation:
       
   876             aDst.SetLocationL(aSrc.LocationL());
       
   877             break;
       
   878         default:
       
   879             _LIT(KCalenInterimUtils2Panic, "CCalenInterimUtils2");
       
   880             User::Panic(KCalenInterimUtils2Panic, KErrArgument);
       
   881         }
       
   882     
       
   883     TRACE_EXIT_POINT;
       
   884     }
       
   885 
       
   886 // -----------------------------------------------------------------------------
       
   887 // CCalenInterimUtils2Impl::CopyChildrenExceptionDataL()
       
   888 // For each exception, for each field, if the field is NOT the reason for the
       
   889 // entry being an exception, copy the new parent's field across to the exception
       
   890 // (other items were commented in a header).
       
   891 // -----------------------------------------------------------------------------
       
   892 //
       
   893 void CCalenInterimUtils2Impl::CopyChildrenExceptionDataL( CCalEntry& aEditedEntry,
       
   894                                                     RPointerArray<CCalEntry>& aOldEntries )
       
   895     {
       
   896     TRACE_ENTRY_POINT;
       
   897 
       
   898     // For each oldChild...
       
   899     for(TInt i=1; i<aOldEntries.Count(); ++i)
       
   900         {
       
   901         // For each field...
       
   902         for(TDifferenceFlag j=(TDifferenceFlag)1; j<EEntryDifferenceCount; j=(TDifferenceFlag)(j<<1))
       
   903             {
       
   904             // Where oldChild field == oldParent Field
       
   905             // and newParent field != oldParent Field...
       
   906             if( FieldIsTheSameL(*aOldEntries[i], *aOldEntries[0], j ) &&
       
   907                 !FieldIsTheSameL(aEditedEntry,  *aOldEntries[0], j ) )
       
   908                 {
       
   909                 // ...copy newParent field to oldChild.
       
   910                 CopyFieldL(aEditedEntry, *aOldEntries[i], j);
       
   911                 }
       
   912             }
       
   913         }
       
   914     
       
   915     TRACE_EXIT_POINT;
       
   916     }
       
   917 
       
   918 // -----------------------------------------------------------------------------
       
   919 // CCalenInterimUtils2Impl::StoreL()
       
   920 // Public exported function. Checks to see if the given entry should be entered
       
   921 // using StoreL() or UpdateL().
       
   922 // (other items were commented in a header).
       
   923 // -----------------------------------------------------------------------------
       
   924 //
       
   925 void CCalenInterimUtils2Impl::StoreL( CCalEntryView& aEntryView,
       
   926                                 CCalEntry& aEntry,
       
   927                                 TBool aCopyToChildren )
       
   928     {
       
   929     TRACE_ENTRY_POINT;
       
   930     
       
   931     if (!IsEntryRepeatingL(aEntry))
       
   932         {
       
   933         // This is not a repeating entry.  Technically we should make a
       
   934         // decision to see if we should be calling StoreL or UpdateL, but
       
   935         // the cost of all the checking required to determine this would 
       
   936         // be greater than the benefit of calling UpdateL if possible.
       
   937         // Just call StoreL, as ultimately it is a lighter call.
       
   938         SingleStoreL(aEntryView, aEntry);
       
   939         return;
       
   940         }
       
   941 
       
   942 
       
   943     // This entry is repeating. Does it have EXDATEs which could be due to children?
       
   944     RArray<TCalTime> exceptionDates;
       
   945     CleanupClosePushL( exceptionDates );
       
   946     aEntry.GetExceptionDatesL( exceptionDates );
       
   947     TInt exceptionCount = exceptionDates.Count();
       
   948     CleanupStack::PopAndDestroy( &exceptionDates );
       
   949 
       
   950     if( exceptionCount == 0 )
       
   951         {
       
   952         // No exception dates so do a StoreL().
       
   953         // We have no exceptions, so there are no children to re-store
       
   954         // Same logic as above applies, we call StoreL rather than check to 
       
   955         // see if we could have called UpdateL
       
   956         SingleStoreL( aEntryView, aEntry );
       
   957         return;
       
   958         } 
       
   959 
       
   960     //Is this a child entry?
       
   961     if(aEntry.RecurrenceIdL().TimeUtcL() != Time::NullTTime())
       
   962         {
       
   963         SingleStoreL( aEntryView, aEntry );
       
   964         return;
       
   965         }
       
   966 
       
   967     //Entry is not a child, but does it have any children?
       
   968 
       
   969     // Fetch array of entries associated with this UID.
       
   970     RPointerArray<CCalEntry> oldEntries;
       
   971     CleanupResetAndDestroyPushL(oldEntries);
       
   972     aEntryView.FetchL(aEntry.UidL(), oldEntries);
       
   973     TBool hasChildren = oldEntries.Count() > 0;
       
   974        
       
   975     if (oldEntries.Count() == 0)
       
   976         {
       
   977         //This is a new repeating entry, with exceptions
       
   978         //This must have come from an external application, as the 
       
   979         //calendar UI does not allow creation of this type of entry
       
   980         SingleStoreL(aEntryView, aEntry);
       
   981         }
       
   982         
       
   983     //Have the RRule or time fields changed
       
   984     else if(aCopyToChildren || HasTimeOrDateChangedL(*oldEntries[0], aEntry) 
       
   985         || HaveRepeatPropertiesChangedL(*oldEntries[0], aEntry))
       
   986         {
       
   987         if (hasChildren && aCopyToChildren)
       
   988             {
       
   989             CopyChildrenExceptionDataL( aEntry, oldEntries );
       
   990             }
       
   991         SingleStoreL(aEntryView, aEntry);
       
   992         
       
   993         if(hasChildren)
       
   994             {
       
   995             StoreEachChildEntryL( aEntryView, aEntry, oldEntries, !aCopyToChildren );
       
   996             }
       
   997         }
       
   998     else
       
   999         {
       
  1000         SingleUpdateL(aEntryView, aEntry);
       
  1001         }
       
  1002 
       
  1003     CleanupStack::PopAndDestroy( &oldEntries );
       
  1004     
       
  1005     TRACE_EXIT_POINT;
       
  1006     }
       
  1007 
       
  1008 // ---------------------------------------------------------
       
  1009 // GenerateRecurrenceIdFromEntryL
       
  1010 // Static helper function for StoreEachChildEntryL. Generates a TCalTime which is at the
       
  1011 // same TIME as aEntry but at the same DATE as aInstanceDate
       
  1012 // ---------------------------------------------------------
       
  1013 TCalTime GenerateRecurrenceIdFromEntryL( CCalEntry& aEntry, TCalTime aInstanceDate )
       
  1014     {
       
  1015     TRACE_ENTRY_POINT;
       
  1016     
       
  1017     TDateTime theTime = aEntry.StartTimeL().TimeUtcL().DateTime();
       
  1018     TDateTime theDate = aInstanceDate.TimeUtcL().DateTime();
       
  1019 
       
  1020     theTime.SetYear(theDate.Year());
       
  1021     theTime.SetMonth(theDate.Month());
       
  1022     theTime.SetDay(theDate.Day());
       
  1023 
       
  1024     TCalTime toRet;
       
  1025     toRet.SetTimeUtcL(theTime);
       
  1026     
       
  1027     TRACE_EXIT_POINT;
       
  1028     return toRet;
       
  1029     }
       
  1030 
       
  1031 // -----------------------------------------------------------------------------
       
  1032 // CCalenInterimUtils2Impl::StoreEachChildEntryL()
       
  1033 // Run through each of the given CCalEntries and call CCalEntryView::StoreL()
       
  1034 // on them. Any Leaves in StoreL are ignored to make sure all items get entered.
       
  1035 // (other items were commented in a header).
       
  1036 // -----------------------------------------------------------------------------
       
  1037 //
       
  1038 void CCalenInterimUtils2Impl::StoreEachChildEntryL( CCalEntryView &aEntryView,
       
  1039                                               CCalEntry &aEntry,
       
  1040                                               RPointerArray<CCalEntry> &aOldEntries,
       
  1041                                               TBool aResetLocalUid)
       
  1042     {
       
  1043     TRACE_ENTRY_POINT;
       
  1044     
       
  1045     // Start from 1 as we don't want to copy the old parent entry.
       
  1046     for(TInt i=1; i<aOldEntries.Count(); ++i)
       
  1047         {
       
  1048         if (aResetLocalUid)
       
  1049             {
       
  1050             // Reset the local UID of the exception.  When we store the exception, it will
       
  1051             // be added as a new entry rather than an update.
       
  1052             aOldEntries[i]->SetLocalUidL( TCalLocalUid( 0 ) );
       
  1053             }
       
  1054 
       
  1055         // The RecurrenceId of child (exception) entries should never be a null time by definition.
       
  1056         // The code below will attempt to generate a RecurrenceId from the start time of the
       
  1057         // exception if no RecurrenceId is found.  This should never actually happen, and
       
  1058         // will not work if the start time/start date is changed.  The if case below should remain
       
  1059         // until the Symbian defect fix for NULL RecurrenceIds is verified.
       
  1060 
       
  1061         if(aOldEntries[i]->RecurrenceIdL().TimeUtcL() == Time::NullTTime())
       
  1062             {
       
  1063             // This is being hit, but shouldn't be. Hence we create a new Recurrence ID.
       
  1064             // Without doing this, the SingleStoreL below fails with Agenda Model -35: No agenda server.
       
  1065             TCalTime recId = GenerateRecurrenceIdFromEntryL( aEntry, aOldEntries[i]->StartTimeL() );
       
  1066             CCalEntry *exception = CCalEntry::NewL( aOldEntries[i]->EntryTypeL(),
       
  1067                                                 aEntry.UidL().AllocL(),
       
  1068                                                 aOldEntries[i]->MethodL(),
       
  1069                                                 aOldEntries[i]->SequenceNumberL(),
       
  1070                                                 recId,
       
  1071                                                 aOldEntries[i]->RecurrenceRangeL() );
       
  1072             CleanupStack::PushL(exception);
       
  1073             exception->CopyFromL(*aOldEntries[i]);
       
  1074 
       
  1075             PIM_TRAPD_HANDLE( SingleStoreL(aEntryView, *exception) );
       
  1076             CleanupStack::PopAndDestroy(exception);
       
  1077             }
       
  1078         else
       
  1079             {
       
  1080             // If the start time of the series has been changed, the call below will
       
  1081             // leave with -1, and the child entries will be lost.  To prevent this
       
  1082             // we need to regenerate a new recurrence id for each child, create a copy
       
  1083             // of the child with the new recurrence id, and store that instead.
       
  1084             // Fixing this may cause issues with sync though, as some servers delete the
       
  1085             // children when changing the start time of the series anyway.
       
  1086             PIM_TRAPD_HANDLE( SingleStoreL(aEntryView, *aOldEntries[i]) );
       
  1087             }
       
  1088         }
       
  1089         
       
  1090     TRACE_EXIT_POINT;
       
  1091     }
       
  1092 
       
  1093 // -----------------------------------------------------------------------------
       
  1094 // CCalenInterimUtils2Impl::IsMeetingRequestL()
       
  1095 // Check to see if the given entry is a meeting request.
       
  1096 // (other items were commented in a header).
       
  1097 // -----------------------------------------------------------------------------
       
  1098 //
       
  1099 TBool CCalenInterimUtils2Impl::IsMeetingRequestL( CCalEntry& aEntry )
       
  1100     {
       
  1101     TRACE_ENTRY_POINT;
       
  1102     TRACE_EXIT_POINT;
       
  1103     return aEntry.EntryTypeL() == CCalEntry::EAppt
       
  1104         && aEntry.OrganizerL();
       
  1105     }
       
  1106 
       
  1107 // -----------------------------------------------------------------------------
       
  1108 // CCalenInterimUtils2Impl::IsEntryRepeatingL()
       
  1109 // Check to see if the given entry is a repeating
       
  1110 // (other items were commented in a header).
       
  1111 // -----------------------------------------------------------------------------
       
  1112 TBool CCalenInterimUtils2Impl::IsEntryRepeatingL(const CCalEntry& aEntry)
       
  1113     {
       
  1114     TRACE_ENTRY_POINT;
       
  1115     
       
  1116     TBool isRepeating = EFalse;
       
  1117     RArray<TCalTime> rdates;
       
  1118     CleanupClosePushL(rdates);
       
  1119     aEntry.GetRDatesL(rdates);
       
  1120     TBool isRDate = rdates.Count() > 0;
       
  1121     CleanupStack::PopAndDestroy(); // rdates
       
  1122 
       
  1123     TCalRRule newRule;
       
  1124 
       
  1125     if ((isRDate) || (aEntry.GetRRuleL(newRule) && newRule.Type() != TCalRRule::EInvalid ))
       
  1126         {
       
  1127         isRepeating = ETrue;
       
  1128         }
       
  1129     
       
  1130     TRACE_EXIT_POINT;
       
  1131     return isRepeating;
       
  1132     }
       
  1133 
       
  1134 // -----------------------------------------------------------------------------
       
  1135 // CCalenInterimUtils2Impl::HaveRepeatPropertiesChangedL()
       
  1136 // Check to see if the RRule or RDates have been modified.
       
  1137 // (other items were commented in a header).
       
  1138 // -----------------------------------------------------------------------------
       
  1139 TBool CCalenInterimUtils2Impl::HaveRepeatPropertiesChangedL(const CCalEntry& aNewEntry, const CCalEntry& aOldEntry)
       
  1140     {
       
  1141     TRACE_ENTRY_POINT;
       
  1142     
       
  1143     //Have the RRules Changed?
       
  1144     TCalRRule newEntryRule;
       
  1145     aNewEntry.GetRRuleL(newEntryRule);
       
  1146 
       
  1147     TCalRRule oldEntryRule;
       
  1148     aOldEntry.GetRRuleL(oldEntryRule);
       
  1149 
       
  1150     if ((newEntryRule.Type() != oldEntryRule.Type()) ||
       
  1151     (newEntryRule.DtStart().TimeUtcL() != oldEntryRule.DtStart().TimeUtcL()) ||
       
  1152     (newEntryRule.Until().TimeUtcL() != oldEntryRule.Until().TimeUtcL()) ||
       
  1153     (newEntryRule.Count() != oldEntryRule.Count()))
       
  1154         {
       
  1155         TRACE_EXIT_POINT;
       
  1156         return ETrue;
       
  1157         }
       
  1158 
       
  1159     // Did the RDates change?
       
  1160     TBool rDatesChanged = EFalse;
       
  1161     RArray<TCalTime> newRDates;
       
  1162     RArray<TCalTime> oldRDates;
       
  1163     CleanupClosePushL(newRDates);
       
  1164     CleanupClosePushL(oldRDates);
       
  1165     aNewEntry.GetRDatesL(newRDates);
       
  1166     aOldEntry.GetRDatesL(oldRDates);
       
  1167 
       
  1168     if (newRDates.Count() != oldRDates.Count())
       
  1169         {
       
  1170         rDatesChanged = ETrue;
       
  1171         }
       
  1172     else
       
  1173         {
       
  1174         for (TInt x = 0; x < newRDates.Count(); ++x)
       
  1175             {
       
  1176             if (newRDates[x].TimeUtcL() != oldRDates[x].TimeUtcL())
       
  1177                 {
       
  1178                 rDatesChanged = ETrue;
       
  1179                 break;
       
  1180                 }
       
  1181             }
       
  1182         }
       
  1183 
       
  1184     CleanupStack::PopAndDestroy(&oldRDates);
       
  1185     CleanupStack::PopAndDestroy(&newRDates);
       
  1186 
       
  1187     TRACE_EXIT_POINT;
       
  1188     return rDatesChanged;
       
  1189     }
       
  1190 
       
  1191 // -----------------------------------------------------------------------------
       
  1192 // CCalenInterimUtils2Impl::TimeOfDay
       
  1193 // Returns minimum time allowed, 1.1.1900 0:00 is min
       
  1194 // (other items were commented in a header).
       
  1195 // -----------------------------------------------------------------------------
       
  1196 TTimeIntervalMinutes CCalenInterimUtils2Impl::TimeOfDay( const TTime& aDateTime )
       
  1197     {
       
  1198     TRACE_ENTRY_POINT;
       
  1199     
       
  1200     TTime midnight = BeginningOfDay( aDateTime );
       
  1201     TTimeIntervalMinutes result;
       
  1202     aDateTime.MinutesFrom( midnight, result );
       
  1203     return result;
       
  1204     }
       
  1205 
       
  1206 // -----------------------------------------------------------------------------
       
  1207 // CCalenInterimUtils2Impl::BeginningOfDay
       
  1208 // ?implementation_description
       
  1209 // (other items were commented in a header).
       
  1210 // -----------------------------------------------------------------------------
       
  1211 TTime CCalenInterimUtils2Impl::BeginningOfDay(const TTime& aStartTime)
       
  1212     {
       
  1213     TRACE_ENTRY_POINT;
       
  1214 
       
  1215     TTime zero(TInt64(0));
       
  1216     
       
  1217     TRACE_EXIT_POINT;
       
  1218     return zero + aStartTime.DaysFrom(zero);
       
  1219     }
       
  1220 
       
  1221 // -----------------------------------------------------------------------------
       
  1222 // CCalenInterimUtils2Impl::EComChanged
       
  1223 // From MCalenEComChangeObserver, called by when the ecom registry is changed
       
  1224 // (other items were commented in a header).
       
  1225 // -----------------------------------------------------------------------------
       
  1226 //
       
  1227 void CCalenInterimUtils2Impl::EComChanged()
       
  1228     {
       
  1229     TRACE_ENTRY_POINT;
       
  1230 
       
  1231     TRAP_IGNORE(MRViewersEnabledL(ETrue));
       
  1232 
       
  1233     TRACE_EXIT_POINT;
       
  1234     }
       
  1235 
       
  1236 // End of file