meetingrequest/mrversit2/src/cesmricalvalue.cpp
changeset 0 8466d47a6819
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meetingrequest/mrversit2/src/cesmricalvalue.cpp	Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,1505 @@
+/*
+* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: This file implements class CESMRICalValue.
+*
+*/
+
+
+// Class include.
+#include "emailtrace.h"
+#include "cesmricalvalue.h" // CESMRICalValue
+
+//debug
+
+// User includes.
+#include "esmricalkeywords.h"       // Literals
+#include "cesmricalrulesegment.h"   // CESMRICalRuleSegment
+
+// Constants.
+
+namespace{
+// Maximum number of characters to use for storing TInt.
+// (The maximum number of characters for storing a decimal representation of
+// KMaxTInt, KMinTInt or even KMaxTUint is 10 on current implementations.
+// The maximum number of characters for storing a decimal representation of
+// KMaxTUint64 is 20, so using this for future proofing.)
+const TInt KICalTIntWidth = 20;
+
+// Width of "HHMMSS"
+const TInt KICalTimeWidth = 6;
+
+// Width of "YYYYMMDD"
+const TInt KICalDateWidth = 8;
+
+// Width of "YYYYMMDDTHHMMSS" (note the 'T' in the middle)
+const TInt KICalDateTimeWidth = KICalDateWidth + KICalTimeWidth + 1;
+
+// Width of a duration.
+const TInt KICalDurationWidth = 25;
+
+// Width of a short format UTC offset.
+const TInt KShortFormatUtcOffsetWidth = 5;  // The width of (e.g.) +1000.
+
+// Width of a long format UTC offset.
+const TInt KLongFormatUtcOffsetWidth = 7;   // The width of (e.g.) -013045.
+
+// Time constants.
+const TInt KICalSecondsPerMinute =     60;
+const TInt KICalSecondsPerHour   =   3600; // That is:      60*60;
+const TInt KICalSecondsPerDay    =  86400; // That is:   24*60*60;
+const TInt KICalSecondsPerWeek   = 604800; // That is: 7*24*60*60;
+
+// Time characters
+const TUint KICalUtcChar('Z');      // UTC time.
+const TUint KICalTimeChar('T');     // Date/time separator.
+const TUint KICalPeriodChar('/');   // Period separator.
+const TUint KICalMicroChar('.');    // Second/microsecond separator.
+const TUint KICalDurationChar('P'); // Duration.
+const TUint KICalWeekChar('W');     // Week.
+const TUint KICalDayChar('D');      // Day.
+const TUint KICalHourChar('H');     // Hour.
+const TUint KICalMinuteChar('M');   // Minute.
+const TUint KICalSecondChar('S');   // Second.
+const TUint KICalPositiveChar('+'); // Positive values.
+const TUint KICalNegativeChar('-'); // Negative values.
+
+// Date format.
+_LIT(KICalDateFormat, "%F%Y%M%D");
+}//namespace
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::NewL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CESMRICalValue* CESMRICalValue::NewL()
+    {
+    FUNC_LOG;
+
+    CESMRICalValue* self  = CESMRICalValue::NewLC();
+    CleanupStack::Pop(self);
+
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::NewLC
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CESMRICalValue* CESMRICalValue::NewLC()
+    {
+    FUNC_LOG;
+
+    CESMRICalValue* self  = new (ELeave) CESMRICalValue;
+    CleanupStack::PushL(self);
+    self->ConstructL();
+
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::~CESMRICalValue
+// ---------------------------------------------------------------------------
+//
+CESMRICalValue::~CESMRICalValue()
+    {
+    FUNC_LOG;
+    delete iValue;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::BinaryLC
+// ---------------------------------------------------------------------------
+//
+EXPORT_C HBufC8* CESMRICalValue::BinaryLC() const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+    HBufC8* buf = HBufC8::NewLC(iValue->Length());
+    buf->Des().Copy(*iValue);
+
+    return buf;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetBinaryL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetBinaryL(const TDesC8& aBuffer)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+    iValue = HBufC::NewL(aBuffer.Length());
+    iValue->Des().Copy(aBuffer);
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::BooleanL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TBool CESMRICalValue::BooleanL() const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+
+    if (iValue->Des() == KICalTrue)
+        {
+        return ETrue;
+        }
+    else if (iValue->Des() == KICalFalse)
+        {
+        return EFalse;
+        }
+
+    // Else...
+    User::Leave(KErrCorrupt);
+
+    return EFalse;  // Never reached.
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetBooleanL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetBooleanL(TBool aBool)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+
+    if (aBool) // ETrue
+        {
+        iValue = KICalTrue().AllocL();
+        }
+    else    // EFalse
+        {
+        iValue = KICalFalse().AllocL();
+        }
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetDateL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::GetDateL(TTime& aDate) const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+    GetDateFromValueL(aDate);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetDateL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetDateL(const TTime& aDate)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+    iValue = HBufC::NewL(KICalDateWidth);
+    AppendDateToValueL(aDate);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetTimeL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::GetTimeL(TTime& aTime, TTimeZoneType& aTzType) const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+    GetTimeFromValueL(aTime, aTzType);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetTimeL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetTimeL(const TTime& aTime, TTimeZoneType aTzType)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+
+    if (aTzType == EUtcTime)
+        {
+        iValue = HBufC::NewL(KICalTimeWidth + 1);
+        AppendTimeToValueL(aTime);
+        iValue->Des().Append(KICalUtcChar); // Append a 'Z' to signify UTC.
+        }
+    else if (aTzType == ESpecifiedTimeZone || aTzType == EFloatingTime)
+        {
+        iValue = HBufC::NewL(KICalTimeWidth);
+        AppendTimeToValueL(aTime);
+        }
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetDateTimeL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::GetDateTimeL(TTime& aDateTime, TTimeZoneType& aTzType, TInt aFirstCharacterNum) const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+
+    // The GetTimeFromValueL() function explicitly sets the TTime passed
+    // in, so create a new TTime for the date and merge with the time later.
+    TTime theDate;
+    GetDateFromValueL(theDate, aFirstCharacterNum);
+
+    // Only start looking for the time at character position KICalDateWidth
+    // plus one for the 'T' separator.
+    if (iValue->Length() > aFirstCharacterNum + KICalDateWidth + 1)
+        {
+        TTime theTime;
+        if ((*iValue)[aFirstCharacterNum + KICalDateWidth] != KICalDateTimeSeparator)
+            {
+            User::Leave(KErrCorrupt);
+            }
+
+        GetTimeFromValueL(theTime, aTzType, aFirstCharacterNum + KICalDateWidth + 1);
+
+        // Set the time component.
+        TDateTime dateValues(theDate.DateTime());
+        TDateTime combinedValues(theTime.DateTime());
+
+        // Set the date component.
+        combinedValues.SetYear(dateValues.Year());
+        combinedValues.SetMonth(dateValues.Month());
+        combinedValues.SetDay(dateValues.Day());
+
+        // Set the value to return.
+        aDateTime = TTime(combinedValues);
+        }
+    else
+        {
+        // There is no time component specified.  For compatibility with MS Outlook,
+        // which can export RECURRENCE-ID fields with no time component, we use
+        // a default time of '00:00'
+        aDateTime = theDate;
+        }
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetDateTimeL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetDateTimeL(const TTime& aDateTime, TTimeZoneType aTzType)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+
+    if (aTzType == EUtcTime)
+        {
+        iValue = HBufC::NewL(KICalDateTimeWidth + 1);
+        AppendDateToValueL(aDateTime);
+
+        iValue->Des().Append(KICalTimeChar);
+        AppendTimeToValueL(aDateTime);
+
+        iValue->Des().Append(KICalUtcChar); // For UTC Time.
+        }
+    else if (aTzType == ESpecifiedTimeZone || aTzType == EFloatingTime)
+        {
+        iValue = HBufC::NewL(KICalDateTimeWidth);
+        AppendDateToValueL(aDateTime);
+
+        iValue->Des().Append(KICalTimeChar);
+        AppendTimeToValueL(aDateTime);
+        }
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::DurationL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TTimeIntervalSeconds CESMRICalValue::DurationL() const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+    TTimeIntervalSeconds theTis;
+    GetTimeIntervalFromValueL(theTis);
+
+    return theTis;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetDurationL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetDurationL(TTimeIntervalSeconds aDuration)
+    {
+    FUNC_LOG;
+
+    // e.g. P15DT5H0M20S
+    PrepareValuePointer();
+
+    iValue = HBufC::NewL(KICalDurationWidth);
+    TInt durInt(aDuration.Int());
+
+    if (durInt < 0)
+        {
+        // First character is a '-' for negative values
+        iValue->Des().Append(KICalNegativeChar);
+
+        // Now we've set the sign, change the durInt to +ve
+        durInt =- durInt;
+        }
+
+    iValue->Des().Append(KICalDurationChar);
+
+    // Add day portion.
+    TInt numDays(durInt / KICalSecondsPerDay);
+    durInt -= (numDays * KICalSecondsPerDay);
+    iValue->Des().AppendNum(numDays);
+    iValue->Des().Append(KICalDayChar);
+    iValue->Des().Append(KICalTimeChar);
+
+    // Add hour portion.
+    TInt numHours(durInt / KICalSecondsPerHour);
+    durInt -= (numHours * KICalSecondsPerHour);
+    iValue->Des().AppendNum(numHours);
+    iValue->Des().Append(KICalHourChar);
+
+    // Add minute portion.
+    TInt numMinutes(durInt / KICalSecondsPerMinute);
+    durInt -= (numMinutes * KICalSecondsPerMinute);
+    iValue->Des().AppendNum(numMinutes);
+    iValue->Des().Append(KICalMinuteChar);
+
+    // Add second portion.
+    TInt numSeconds(durInt);
+    iValue->Des().AppendNum(numSeconds);
+    iValue->Des().Append(KICalSecondChar);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetFloatL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::GetFloatL(TReal& aFloat) const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+    TLex stringLex(iValue->Des());
+    User::LeaveIfError(stringLex.Val(aFloat));
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetFloatL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetFloatL(const TReal& aFloat)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+
+    iValue = HBufC::NewL(KDefaultRealWidth);
+    TRealFormat format;
+    iValue->Des().Num(aFloat, format);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::IntegerL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TInt CESMRICalValue::IntegerL() const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+
+    return ReadIntL(iValue->Des());
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetIntegerL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetIntegerL(TInt aInt)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+    iValue = HBufC::NewL(KICalTIntWidth);
+    iValue->Des().Num(aInt);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetPeriodL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::GetPeriodL(
+    TTime& aStartTime,
+    TTimeZoneType& aStartTzType,
+    TTime& aEndTime,
+    TTimeZoneType& aEndTzType) const
+    {
+    FUNC_LOG;
+
+    // Example :   19970101T180000Z/19970102T070000Z
+    // that is : yyyymmddThhmmss[Z]/yyyymmddThhmmss[Z]
+
+    // Example2:   19970101T180000Z/PT5H30M
+    // that is2: yyyymmddThhmmss[Z]/[+/-]P[lots of stuff]
+
+    // As the first part is always a date-time, get this out to start off with
+    GetDateTimeL(aStartTime, aStartTzType, 0);
+
+    // Next we need to get the position of the separator.
+    TInt charNumber(iValue->Des().Locate(KICalPeriodChar));
+    User::LeaveIfError(charNumber);
+
+    // If the character after the separator is a 'P', '+' or '-' the second part is a duration.
+    ++charNumber;
+    if (charNumber >= iValue->Length())
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    TChar theChar(iValue->Des()[charNumber]);
+
+    if ((theChar == KICalDurationChar) ||
+        (theChar == KICalPositiveChar) ||
+        (theChar == KICalNegativeChar))
+        {
+        // Call a function to change the duration into a TTime (date + time)
+        TTimeIntervalSeconds interval;
+        GetTimeIntervalFromValueL(interval, charNumber);
+
+        // Convert from this TimeInterval to a TTime
+        aEndTime = aStartTime;
+        aEndTime += interval;
+
+        // The timezone will be the same as the first.
+        aEndTzType = aStartTzType;
+        }
+    else // Presume it's a date-time
+        {
+        GetDateTimeL(aEndTime, aEndTzType, charNumber);
+        }
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetPeriodL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetPeriodL(
+    const TTime& aStartTime,
+    TTimeZoneType aStartTzType,
+    const TTime& aEndTime,
+    TTimeZoneType aEndTzType)
+    {
+    FUNC_LOG;
+
+    // Example:   19970101T180000Z/19970102T070000Z
+    // that is: yyyymmddThhmmss[Z]/yyyymmddThhmmss[Z]
+
+    PrepareValuePointer();
+
+    SetDateTimeL(aStartTime, aStartTzType);
+
+    if (aEndTzType == EUtcTime)
+        {
+        iValue->ReAllocL(iValue->Length() + 2 + KICalDateTimeWidth);
+        iValue->Des().Append(KICalPeriodChar);
+
+        AppendDateToValueL(aEndTime);
+        iValue->Des().Append(KICalTimeChar);
+
+        AppendTimeToValueL(aEndTime);
+        iValue->Des().Append(KICalUtcChar);
+        }
+    else if (aEndTzType == ESpecifiedTimeZone || aEndTzType == EFloatingTime)
+        {
+        iValue->ReAllocL(iValue->Length() + 1 + KICalDateTimeWidth);
+
+        iValue->Des().Append(KICalPeriodChar);
+        AppendDateToValueL(aEndTime);
+
+        iValue->Des().Append(KICalTimeChar);
+        AppendTimeToValueL(aEndTime);
+        }
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetDayL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::GetDayL(TDay& aDay, TInt& aPos) const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+
+    // Find the end of the numeric part.
+    _LIT(KICalDayNumeric, "-+0123456789");
+    TInt endNumeric(0);
+
+    while (endNumeric < iValue->Length())
+        {
+        if (KICalDayNumeric().Locate((*iValue)[endNumeric]) == KErrNotFound)
+            {
+            break;
+            }
+
+        ++endNumeric;
+        }
+
+    // Set the numeric part.
+    if (endNumeric != 0)
+        {
+        aPos = ReadIntL(iValue->Left(endNumeric));
+        }
+    else
+        {
+        aPos = 0;
+        }
+
+    // Set the day part.
+    HBufC* dayStrBuf = iValue->Mid(endNumeric).AllocLC();
+    TPtr dayStr( dayStrBuf->Des() );
+    dayStr.TrimLeft();
+
+    if (dayStr.CompareF(KICalMonday) == 0)
+        {
+        aDay = EMonday;
+        }
+    else if (dayStr.CompareF(KICalTuesday) == 0)
+        {
+        aDay = ETuesday;
+        }
+    else if (dayStr.CompareF(KICalWednesday) == 0)
+        {
+        aDay = EWednesday;
+        }
+    else if (dayStr.CompareF(KICalThursday) == 0)
+        {
+        aDay = EThursday;
+        }
+    else if (dayStr.CompareF(KICalFriday) == 0)
+        {
+        aDay = EFriday;
+        }
+    else if (dayStr.CompareF(KICalSaturday) == 0)
+        {
+        aDay = ESaturday;
+        }
+    else if (dayStr.CompareF(KICalSunday) == 0)
+        {
+        aDay = ESunday;
+        }
+    else
+        {
+        User::Leave(KErrCorrupt);   // Invalid day.
+        }
+
+    CleanupStack::PopAndDestroy( dayStrBuf );
+    dayStrBuf = NULL;
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetDayL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetDayL(TDay aDay, TInt aPos)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+
+    // Get the day as a descriptor.
+    TPtrC dayName;
+
+    switch (aDay)
+        {
+        case EMonday:
+            dayName.Set(KICalMonday());
+            break;
+        case ETuesday:
+            dayName.Set(KICalTuesday());
+            break;
+        case EWednesday:
+            dayName.Set(KICalWednesday());
+            break;
+        case EThursday:
+            dayName.Set(KICalThursday());
+            break;
+        case EFriday:
+            dayName.Set(KICalFriday());
+            break;
+        case ESaturday:
+            dayName.Set(KICalSaturday());
+            break;
+        case ESunday:
+            dayName.Set(KICalSunday());
+            break;
+        default:
+            User::Leave(KErrUnknown);
+            break;
+        }
+
+    // We need space for a number and a day name.
+    iValue = HBufC::NewL(KICalTIntWidth + dayName.Length());
+    iValue->Des().AppendNum(aPos);
+    iValue->Des().Append(dayName);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::MonthL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TMonth CESMRICalValue::MonthL() const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+
+    TInt num(IntegerL());
+
+    if ((num < 1) || (num > 12))
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    return static_cast<TMonth>(num - 1);
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetMonthL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetMonthL(TMonth aMonth)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+    SetIntegerL(aMonth + 1);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetRecurrenceRuleL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::GetRecurrenceRuleL(RPointerArray<CESMRICalRuleSegment>& aRuleSegmentArray) const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+
+    // Find the first semicolon:
+    TInt nextSemiColon(iValue->Locate(KICalSemiColonChar));
+
+    if (nextSemiColon == KErrNotFound)
+        {
+        // This means there is only one segment, pretend the semicolon exists at the end of the buffer
+        nextSemiColon = iValue->Length();
+        }
+
+    TUint charNum(0);
+
+    do
+        {
+        // Create a rule segment from characters charNum to nextSemiColon
+        CESMRICalRuleSegment* theRule = CESMRICalRuleSegment::NewLC(iValue->Mid(charNum, nextSemiColon - charNum));
+        User::LeaveIfError(aRuleSegmentArray.Append(theRule));  // Takes ownership.
+        CleanupStack::Pop(theRule);
+
+        // Put the character marker past the current semicolon
+        charNum = nextSemiColon + 1;
+
+        // We only want to check for any more semicolons in the area to the right of charNum.
+        // First check if there are ANY characters to the right of charNum
+        if (charNum < iValue->Length())
+            {
+            // Find the location of the next semi colon in this area.
+            nextSemiColon = iValue->Right(iValue->Length() - charNum).Locate(KICalSemiColonChar);
+
+            if (nextSemiColon != KErrNotFound)
+                {
+                // Set the semicolon to be in it's correct position, shifted to take into account the fact
+                // that we were only looking in the right part of the original descriptor.
+                nextSemiColon += charNum;
+                }
+            else
+                {
+                // There are no more semicolons, read in the last value and then exit the loop
+                nextSemiColon = iValue->Length();
+                }
+            }
+        }
+    while (charNum < iValue->Length());
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetRecurrenceRuleL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetRecurrenceRuleL(const TDesC& aRuleValue)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+    iValue = aRuleValue.AllocL();
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::TextL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C const TDesC& CESMRICalValue::TextL() const
+    {
+    FUNC_LOG;
+
+    CheckNullValueL();
+
+    return *iValue;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetTextL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetTextL(const TDesC& aText)
+    {
+    FUNC_LOG;
+
+    PrepareValuePointer();
+    iValue = aText.AllocL();
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::UtcOffsetL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TTimeIntervalSeconds CESMRICalValue::UtcOffsetL() const
+    {
+    FUNC_LOG;
+
+    // Format is (e.g.) +1000 (10 hours ahead) or -013045 (1.5 hours and 45 seconds behind).
+    CheckNullValueL();
+
+    const TInt length = iValue->Length();
+
+    if ((length != KLongFormatUtcOffsetWidth) && (length != KShortFormatUtcOffsetWidth))
+        {
+        // Invalid UTC Offset - we can't really test more than this, so the output may be garbage
+        User::Leave(KErrCorrupt);
+        }
+
+    // Get the value of the hour component.
+    TInt hours(ReadIntL(iValue->Des().Left(3)));    // '+' or '-' plus the hours component.
+
+    // Get the value of the minute component.
+    TInt minutes(ReadIntL(iValue->Des().Mid(3, 2)));    // The minutes component.
+
+    // Get the value of the (optional) second component.
+    TInt seconds(0);
+
+    if (length == KLongFormatUtcOffsetWidth)    // Long format.
+        {
+        seconds = ReadIntL(iValue->Des().Mid(5, 2));    // The second component.
+        }
+
+    // Convert to TTimeIntervalSeconds.
+    return TTimeIntervalSeconds((hours * KICalSecondsPerHour) + (minutes * KICalSecondsPerMinute) + seconds);
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::SetUtcOffsetL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CESMRICalValue::SetUtcOffsetL(TTimeIntervalSeconds aOffset)
+    {
+    FUNC_LOG;
+
+    // Format is (e.g.) +1000 (10 hours ahead) or -013045 (1.5 hours and 45 seconds behind).
+    PrepareValuePointer();
+
+    // Create a buffer long enough to hold the widest format.
+    iValue = HBufC::NewL(KLongFormatUtcOffsetWidth);
+
+    // Get the offset as an integer.
+    TInt offset(aOffset.Int());
+
+    // Set the sign.
+    if (offset < 0)
+        {
+        iValue->Des().Append(KICalNegativeChar);
+
+        // Set offset to positive for calculations.
+        offset =- offset;
+        }
+    else
+        {
+        iValue->Des().Append(KICalPositiveChar);
+        }
+
+    // Add hour portion.
+    TInt numHours(offset / KICalSecondsPerHour);
+    offset -= (numHours * KICalSecondsPerHour);
+    iValue->Des().AppendNumFixedWidth(numHours, EDecimal, 2);
+
+    // Add minute portion.
+    TInt numMinutes(offset / KICalSecondsPerMinute);
+    offset -= (numMinutes * KICalSecondsPerMinute);
+    iValue->Des().AppendNumFixedWidth(numMinutes, EDecimal, 2);
+
+    // Add second portion if necessary.
+    if (offset > 0)
+        {
+        iValue->Des().AppendNumFixedWidth(offset, EDecimal, 2);
+        }
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::CESMRICalValue
+// ---------------------------------------------------------------------------
+//
+CESMRICalValue::CESMRICalValue()
+    {
+    FUNC_LOG;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CESMRICalValue::ConstructL()
+    {
+    FUNC_LOG;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::CheckNullValueL
+// ---------------------------------------------------------------------------
+//
+/**
+Checks for a NULL value. Should be called before accessing iValue.
+@leave Leaves with KErrCorrupt if the value is NULL.
+@internalTechnology
+*/
+void CESMRICalValue::CheckNullValueL() const
+    {
+    FUNC_LOG;
+
+    if (!iValue)
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::PrepareValuePointer
+// ---------------------------------------------------------------------------
+//
+/**
+Prepares iValue pointer for writing. Deletes existing pointer if it exists.
+@internalTechnology
+*/
+void CESMRICalValue::PrepareValuePointer()
+    {
+    FUNC_LOG;
+
+    if (iValue)
+        {
+        delete iValue;
+        iValue = NULL;
+        }
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::ReadIntL
+// ---------------------------------------------------------------------------
+//
+/**
+Reads a TInt from the given descriptor.
+@param aDes The descriptor to convert
+@return The integer conversion.
+@leave Leaves if there is an error reading an integer.
+@internalTechnology
+*/
+TInt CESMRICalValue::ReadIntL(const TDesC& aDes) const
+    {
+    FUNC_LOG;
+
+    TLex stringLex(aDes);
+    TInt returnValue(0);
+    User::LeaveIfError(stringLex.Val(returnValue));
+
+    return returnValue;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::AppendDateToValueL
+// ---------------------------------------------------------------------------
+//
+/**
+Appends the date to iValue. Member iValue must be initialised before calling.
+@param aDate TTime to append to the value.
+@internalTechnology
+*/
+void CESMRICalValue::AppendDateToValueL(const TTime& aDate)
+    {
+    FUNC_LOG;
+
+    TBuf<KICalDateWidth> formattedDate;
+    aDate.FormatL(formattedDate, KICalDateFormat);
+    iValue->Des().Append(formattedDate);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetDateFromValueL
+// ---------------------------------------------------------------------------
+//
+/**
+Gets the date from iValue descriptor. Should be in the format YYYYMMDD
+@param aDate A modifiable reference returning a date.
+@param aFirstCharacterNum Skip this many characters at the start of the value.
+@leave Leaves with KErrCorrupt if the format of the value is not a valid date.
+@internalTechnology
+*/
+void CESMRICalValue::GetDateFromValueL(TTime& aDate, TInt aFirstCharacterNum) const
+    {
+    FUNC_LOG;
+
+    if (aFirstCharacterNum + KICalDateWidth > iValue->Length())
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    // Get the year as an int.
+    TInt year(ReadIntL(iValue->Des().Mid(aFirstCharacterNum, 4)));  // YYYYmmdd
+
+    if (year < 0)   // All positive years are valid
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    // Get the month as an int.
+    TInt month(ReadIntL(iValue->Mid(aFirstCharacterNum + 4, 2)));   // yyyMMdd
+
+    if ((month < 1) || (month > 12))
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    // Get the day as an int.
+    TInt day(ReadIntL(iValue->Mid(aFirstCharacterNum + 6, 2))); // yyyymmDD
+
+    if ((day < 1) || (day > Time::DaysInMonth(year, static_cast<TMonth>(month - 1))))   // Zero-offset month.
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    // Set the date from its component parts.
+    aDate = 0;
+    aDate += TTimeIntervalYears(year);
+    aDate += TTimeIntervalMonths(month - 1);    // Zero-offset.
+    aDate += TTimeIntervalDays(day - 1);        // Zero-offset.
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::AppendTimeToValueL
+// ---------------------------------------------------------------------------
+//
+/**
+Appends the time to iValue. Member iValue must be initialised before calling.
+@param aTime TTime to append to the value.
+@internalTechnology
+*/
+void CESMRICalValue::AppendTimeToValueL(const TTime& aTime)
+    {
+    FUNC_LOG;
+
+    // Format is HHMMSS followed optionally by a Z for UTC time.
+    // Note that the 'Z' is not appended here.
+    TDateTime fullTime(aTime.DateTime());
+
+    iValue->Des().AppendNumFixedWidth(fullTime.Hour(), EDecimal, 2);
+    iValue->Des().AppendNumFixedWidth(fullTime.Minute(), EDecimal, 2);
+    iValue->Des().AppendNumFixedWidth(fullTime.Second(), EDecimal, 2);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetTimeFromValueL
+// ---------------------------------------------------------------------------
+//
+/**
+Gets the time from iValue descriptor, starting from a pre-determined point.
+Should be in the format HHMMSS[Z]
+@param aTime TTime to store result of read in
+@param aTzType Enumeration showing whether the time represents local time (not
+supported), UTC or a custom time zone.
+@param aFirstCharacterNum The character number to start searching from.
+@leave Leaves with KErrCorrupt if the value does not hold a valid time.
+@internalTechnology
+*/
+void CESMRICalValue::GetTimeFromValueL(TTime& aTime, TTimeZoneType& aTzType, TInt aFirstCharacterNum) const
+    {
+    FUNC_LOG;
+
+    if (aFirstCharacterNum + KICalTimeWidth > iValue->Length())
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    // Create a new descriptor containing just the first KICalTimeWidth characters of iValue
+    // It's size is one larger as we will need to add a full stop (see below)
+    HBufC* formattedTime = HBufC::NewLC(iValue->Des().Mid(aFirstCharacterNum, KICalTimeWidth).Length() + 1);
+    *formattedTime = iValue->Des().Mid(aFirstCharacterNum, KICalTimeWidth);
+
+    // The only formatting needed is to append a full stop
+    formattedTime->Des().Append(KICalMicroChar);
+
+    if (aTime.Set(*formattedTime))
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    if ((iValue->Length() > (KICalTimeWidth + aFirstCharacterNum)) &&
+        (iValue->Des()[KICalTimeWidth + aFirstCharacterNum] == KICalUtcChar))
+        {
+        aTzType = EUtcTime;
+        }
+    else
+        {//DAVIDTODO:
+        // If there is no 'Z' character then assume that there
+        // is a specified time zone - EFloatingTime is not used.
+        aTzType = ESpecifiedTimeZone;
+        }
+
+    CleanupStack::PopAndDestroy(formattedTime);
+
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetTimeIntervalFromValueL
+// ---------------------------------------------------------------------------
+//
+/**
+Retrieves a time interval stored as a duration as per the RFC 2445
+specification.
+@param aTimeInterval TTimeIntervalSeconds to store the result in.
+@param aFirstCharacterNum The position in the value containing the first
+character of the duration.
+@leave Leaves with KErrCorrupt if the value does not hold a valid interval.
+@internalTechnology
+*/
+void CESMRICalValue::GetTimeIntervalFromValueL(TTimeIntervalSeconds& aTimeInterval, TInt aFirstCharacterNum) const
+    {
+    FUNC_LOG;
+
+    //     dur-value  = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
+    //     dur-date   = dur-day [dur-time]
+    //     dur-time   = "T" (dur-hour / dur-minute / dur-second)
+    //     dur-week   = 1*DIGIT "W"
+    //     dur-hour   = 1*DIGIT "H" [dur-minute]
+    //     dur-minute = 1*DIGIT "M" [dur-second]
+    //     dur-second = 1*DIGIT "S"
+    //     dur-day    = 1*DIGIT "D"
+
+    // Example: A duration of 15 days, 5 hours and 20 seconds would be:
+    //     P15DT5H0M20S
+    // A duration of 7 weeks would be:
+    //     P7W
+
+    TInt intervalMultiplier(1); // This variable sets the interval to be positive or negative.
+
+    // Length should be at least two.
+    if ((aFirstCharacterNum >= iValue->Length()) || (iValue->Length() < 2 + aFirstCharacterNum))
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    // Check that the first character is a 'P', '+' or '-' and adjust the interval accordingly.
+    TChar firstCharacter(iValue->Des()[aFirstCharacterNum]);
+
+    if (firstCharacter == KICalDurationChar)
+        {
+        intervalMultiplier = 1;
+        aFirstCharacterNum += 1; // Skip the "P"
+        }
+    else if (firstCharacter == KICalPositiveChar)
+        {
+        intervalMultiplier = 1;
+        aFirstCharacterNum += 2; // Skip the "+P"
+        }
+    else if (firstCharacter == KICalNegativeChar)
+        {
+        intervalMultiplier = -1;
+        aFirstCharacterNum += 2; // Skip the "-P"
+        }
+    else
+        {
+        User::Leave(KErrCorrupt);
+        }
+
+    // It can only contain a dur-date, or a dur-time, or a dur-week
+    TInt theInterval(0);
+    if (!GetDurDateL(theInterval, aFirstCharacterNum))
+        {
+        if (!GetDurTimeL(theInterval, aFirstCharacterNum))
+            {
+            if (!GetDurWeekL(theInterval, aFirstCharacterNum))
+                {
+                User::Leave(KErrCorrupt);
+                }
+            }
+        }
+
+    theInterval *= intervalMultiplier;
+
+    // Now we've done the multiply we can convert it into a TTimeIntervalSeconds
+    aTimeInterval = theInterval;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetDurDateL
+// ---------------------------------------------------------------------------
+//
+/**
+Reads in and converts a dur-day into a number of seconds
+@param aIntervalSecs Function adds number of seconds to this variable.
+@param aCurrentCharNumber Character number to start looking in the value.
+@return ETrue if the value could be interpreted as a dur-date, EFalse otherwise.
+@internalTechnology
+*/
+TBool CESMRICalValue::GetDurDateL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+    {
+    FUNC_LOG;
+
+    //  dur-date   = dur-day [dur-time]
+    //  dur-day    = 1*DIGIT "D"
+
+    if (aCurrentCharNumber >= iValue->Length())
+        {
+        return EFalse;
+        }
+
+    // Create a new TPtrC containing the data from iValue which we need.
+    TPtrC data(iValue->Mid(aCurrentCharNumber));
+
+    // Find the next 'D' in the descriptor.
+    TInt nextDPos(data.Locate(KICalDayChar));
+
+    // Check it exists
+    if (nextDPos != KErrNotFound)
+        {
+        // If character found, construct a number from currentCharNumber to nextDPos
+        TInt theNum(ReadIntL(data.Left(nextDPos)));
+
+        // Convert this time from days to seconds
+        theNum *= KICalSecondsPerDay;
+        aIntervalSecs += theNum;
+        aCurrentCharNumber += nextDPos + 1; // Extra increment to get past the 'D'
+
+        // Check if a dur-time follows. It's optional
+        // so we can ignore it's return value.
+        GetDurTimeL(aIntervalSecs, aCurrentCharNumber);
+        return ETrue;
+        }
+
+    // If no character found, return EFalse
+    return EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetDurTimeL
+// ---------------------------------------------------------------------------
+//
+/**
+Reads in and converts a dur-time into a number of seconds
+@param aIntervalSecs Function adds number of seconds to this variable.
+@param aCurrentCharNumber Character number to start looking in the value.
+@return ETrue if the value could be interpreted as a dur-time, EFalse otherwise.
+@leave Leaves with KErrCorrupt if the value does not hold a valid time.
+@internalTechnology
+*/
+TBool CESMRICalValue::GetDurTimeL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+    {
+    FUNC_LOG;
+
+    //  dur-time   = "T" (dur-hour / dur-minute / dur-second) e.g. T5H0M20S
+
+    if (aCurrentCharNumber >= iValue->Length())
+        {
+        return EFalse;
+        }
+
+    if (iValue->Des()[aCurrentCharNumber] == KICalTimeChar)
+        {
+        ++aCurrentCharNumber; // Increment to get past 'T'
+
+        if (!GetDurHourL(aIntervalSecs, aCurrentCharNumber))
+            {
+            if (!GetDurMinuteL(aIntervalSecs, aCurrentCharNumber))
+                {
+                if (!GetDurSecondL(aIntervalSecs, aCurrentCharNumber))
+                    {
+                    // We should not have read a 'T' and failed to match hour/minute/second
+                    User::Leave(KErrCorrupt);
+                    }
+                }
+            }
+        }
+    else
+        {
+        // First character is not a 'T', therefore value is not a dur-time
+        return EFalse;
+        }
+
+    return ETrue;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetDurHourL
+// ---------------------------------------------------------------------------
+//
+/**
+Reads in and converts a dur-hour into a number of seconds. There is no range
+check on the number of hours.
+@param aIntervalSecs Function adds number of seconds to this variable.
+@param aCurrentCharNumber Character number to start looking in the value.
+@return ETrue if the value could be interpreted as a dur-hour, EFalse otherwise.
+@internalTechnology
+*/
+TBool CESMRICalValue::GetDurHourL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+    {
+    FUNC_LOG;
+
+    //  dur-hour   = 1*DIGIT "H" [dur-minute]
+
+    if (aCurrentCharNumber >= iValue->Length())
+        {
+        return EFalse;
+        }
+
+    // Create a new TPtrC containing the data from iValue which we need
+    TPtrC data(iValue->Mid(aCurrentCharNumber));
+
+    // Find the next 'H' in the descriptor
+    TInt nextHPos(data.Locate(KICalHourChar));
+
+    // Check it exists
+    if (nextHPos != KErrNotFound)
+        {
+        // If character found, construct a number from currentCharNumber to nextHPos
+        TInt theNum(ReadIntL(data.Left(nextHPos)));
+
+        // Convert this time from hours to seconds
+        theNum *= KICalSecondsPerHour;
+
+        aIntervalSecs += theNum;
+        aCurrentCharNumber += nextHPos + 1; // Extra increment to get past 'H'
+
+        // Check if a dur-minute follows. It's optional
+        // so we can ignore it's return value.
+        GetDurMinuteL(aIntervalSecs,aCurrentCharNumber);
+        return ETrue;
+        }
+
+    // If no character found, return EFalse
+    return EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetDurMinuteL
+// ---------------------------------------------------------------------------
+//
+/**
+Reads in and converts a dur-minute into a number of seconds. There is no range
+check on the number of minutes.
+@param aIntervalSecs Function adds number of seconds to this variable.
+@param aCurrentCharNumber Character number to start looking in the value.
+@return ETrue if the value could be interpreted as a dur-minute, EFalse
+otherwise.
+@internalTechnology
+*/
+TBool CESMRICalValue::GetDurMinuteL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+    {
+    FUNC_LOG;
+
+    //  dur-minute = 1*DIGIT "M" [dur-second]
+
+    if (aCurrentCharNumber >= iValue->Length())
+        {
+        return EFalse;
+        }
+
+    // Create a new TPtrC containing the data from iValue which we need
+    TPtrC data(iValue->Mid(aCurrentCharNumber));
+
+    // Find the next 'M' in the descriptor
+    TInt nextMPos(data.Locate(KICalMinuteChar));
+
+    // Check it exists
+    if (nextMPos != KErrNotFound)
+        {
+        // If character found, construct a number from currentCharNumber to nextMPos
+        TInt theNum(ReadIntL(data.Left(nextMPos)));
+
+        // Convert this time from minutes to seconds
+        theNum *= KICalSecondsPerMinute;
+
+        aIntervalSecs += theNum;
+        aCurrentCharNumber += nextMPos + 1; // Extra increment to get past 'M'
+
+        // Check if a dur-second follows. It's optional
+        // so we can ignore it's return value.
+        GetDurSecondL(aIntervalSecs,aCurrentCharNumber);
+        return ETrue;
+        }
+
+    // If no character found, return EFalse
+    return EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetDurSecondL
+// ---------------------------------------------------------------------------
+//
+/**
+Reads in and converts a dur-second into a number of seconds. There is no range
+check on the number of seconds.
+@param aIntervalSecs Function adds number of seconds to this variable.
+@param aCurrentCharNumber Character number to start looking in the value.
+@return ETrue if the value could be interpreted as a dur-second, EFalse
+otherwise.
+@internalTechnology
+*/
+TBool CESMRICalValue::GetDurSecondL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+    {
+    FUNC_LOG;
+
+    //  dur-second = 1*DIGIT "S"
+
+    if (aCurrentCharNumber >= iValue->Length())
+        {
+        return EFalse;
+        }
+
+    // Create a new TPtrC containing the data from iValue which we need
+    TPtrC data(iValue->Mid(aCurrentCharNumber));
+
+    // Find the next 'S' in the descriptor
+    TInt nextSPos(data.Locate(KICalSecondChar));
+
+    // Check it exists
+    if (nextSPos != KErrNotFound)
+        {
+        // If character found, construct a number from currentCharNumber to nextSPos
+        TInt theNum(ReadIntL(data.Left(nextSPos)));
+
+        aIntervalSecs += theNum;
+        aCurrentCharNumber += nextSPos;
+
+        return ETrue;
+        }
+
+    // If no character found, return EFalse
+    return EFalse;
+    }
+
+// ---------------------------------------------------------------------------
+// CESMRICalValue::GetDurWeekL
+// ---------------------------------------------------------------------------
+//
+/**
+Reads in and converts a dur-week into a number of seconds
+@param aIntervalSecs Function adds number of seconds to this variable
+@param aCurrentCharNumber Character number to start looking in the value.
+@return ETrue if the value could be interpreted as a dur-week, EFalse
+otherwise.
+@internalTechnology
+*/
+TBool CESMRICalValue::GetDurWeekL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+    {
+    FUNC_LOG;
+
+    //  dur-week   = 1*DIGIT "W"
+
+    if (aCurrentCharNumber >= iValue->Length())
+        {
+        return EFalse;
+        }
+
+    // Create a new TPtrC containing the data from iValue which we need
+    TPtrC data(iValue->Mid(aCurrentCharNumber));
+
+    // Find the next 'W' in the descriptor
+    TInt nextWPos(data.Locate(KICalWeekChar));
+
+    // Check it exists
+    if (nextWPos != KErrNotFound)
+        {
+        // If character found, construct a number from currentCharNumber to nextWPos
+        TInt theNum(ReadIntL(data.Left(nextWPos)));
+
+        // Convert this time from weeks to seconds
+        theNum *= KICalSecondsPerWeek;
+
+        aIntervalSecs += theNum;
+        aCurrentCharNumber += nextWPos;
+
+        return ETrue;
+        }
+
+    // If no character found, return EFalse
+    return EFalse;
+    }
+
+
+// End of File
+
+
+