calendarengines/versit2/src/ICalValue.cpp
changeset 0 f979ecb2b13e
child 16 55d60436f00b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/calendarengines/versit2/src/ICalValue.cpp	Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,1567 @@
+/*
+* Copyright (c) 2002-2004 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:   Implements the definition of CICalValue.
+*
+*/
+
+
+
+// Class include.
+#include "ICalValue.h"	// CICalValue
+
+//debug
+#include "calendarengines_debug.h"
+
+// User includes.
+#include "ICalKeyWords.h"		// Literals
+#include "ICalRuleSegment.h"	// CICalRuleSegment
+
+// Constants.
+
+// 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");
+	
+/**
+Static factory construction.
+@return A new CICalValue.
+@publishedPartner
+*/
+EXPORT_C CICalValue* CICalValue::NewL()
+	{
+	TRACE_ENTRY_POINT;
+	
+	CICalValue* self  = CICalValue::NewLC();
+	CleanupStack::Pop(self);
+	
+	TRACE_EXIT_POINT;
+	return self;
+	}
+
+/**
+Static factory construction.
+@return A new CICalValue.
+@publishedPartner
+*/
+EXPORT_C CICalValue* CICalValue::NewLC()
+	{
+	TRACE_ENTRY_POINT;
+	
+	CICalValue* self  = new (ELeave) CICalValue;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	
+	TRACE_EXIT_POINT;
+	return self;
+	}
+
+/**
+Destructor.
+@publishedPartner
+*/
+CICalValue::~CICalValue()
+	{
+	TRACE_ENTRY_POINT;
+	TRACE_EXIT_POINT;
+	delete iValue;
+	}
+
+/**
+Returns a copy of the value as an 8-bit string. User takes ownership of the
+returned descriptor, which is also left on the Cleanup Stack. Note that each
+16-bit word in the value is copied into a single 8-bit word in the returned
+descriptor and any values greater than 256 are set to the value '1'. This will
+not occur if the value was set using SetBinaryL().
+@return An 8-bit copy of the value.
+@publishedPartner
+*/
+EXPORT_C HBufC8* CICalValue::BinaryLC() const
+	{
+	TRACE_ENTRY_POINT;
+	
+	CheckNullValueL();
+	HBufC8* buf = HBufC8::NewLC(iValue->Length());
+	buf->Des().Copy(*iValue);
+	
+	TRACE_EXIT_POINT;
+	return buf;
+	}
+
+/**
+Stores an 8-bit buffer in the CICalValue. Each 8-bit value is stored within a
+16-bit value internally.
+@param aBuffer The 8-bit buffer to be stored.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetBinaryL(const TDesC8& aBuffer)
+	{
+	TRACE_ENTRY_POINT;
+	
+	PrepareValuePointer();
+	iValue = HBufC::NewL(aBuffer.Length());
+	iValue->Des().Copy(aBuffer);
+	}
+
+/**
+Returns the CICalValue as a TBool. Leaves if the value cannot be read as a TBool.
+@return TBool stored in the value.
+@leave KErrCorrupt if value is not a valid Boolean value.
+@publishedPartner
+*/
+EXPORT_C TBool CICalValue::BooleanL() const
+	{
+	TRACE_ENTRY_POINT;
+	
+	CheckNullValueL();
+	
+	if (iValue->Des() == KICalTrue)
+		{
+		TRACE_EXIT_POINT;
+		return ETrue;
+		}
+	else if (iValue->Des() == KICalFalse)
+		{
+		TRACE_EXIT_POINT;
+		return EFalse;
+		}
+	
+	// Else...
+	User::Leave(KErrCorrupt);
+	
+	TRACE_EXIT_POINT;
+	return EFalse;	// Never reached.
+	}
+
+/**
+Stores a TBool in the CICalValue.
+@param aBool TBool to be stored.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetBooleanL(TBool aBool)
+	{
+	TRACE_ENTRY_POINT;
+	
+	PrepareValuePointer();
+	
+	if (aBool) // ETrue
+		{
+		iValue = KICalTrue().AllocL();
+		}
+	else	// EFalse
+		{
+		iValue = KICalFalse().AllocL();
+		}
+		
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Returns the CICalValue as a date (TTime).
+@param aDate TTime to store the date in.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::GetDateL(TTime& aDate) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	CheckNullValueL();
+	GetDateFromValueL(aDate);
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Stores a date (TTime) as the value.
+@param aDate TTime to be stored.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetDateL(const TTime& aDate)
+	{
+	TRACE_ENTRY_POINT;
+	
+	PrepareValuePointer();
+	iValue = HBufC::NewL(KICalDateWidth);
+	AppendDateToValueL(aDate);
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Returns the CICalValue as a time (TTime).
+@param aTime TTime to store the time in.
+@param aTzType Enumeration showing whether the time represents local time (not
+supported), UTC or a custom time zone.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::GetTimeL(TTime& aTime, TTimeZoneType& aTzType) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	CheckNullValueL();
+	GetTimeFromValueL(aTime, aTzType);
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Stores a time (TTime) as the value.
+@param aTime TTime to be stored.
+@param aTzType Enumeration showing whether the time represents local time (not
+supported), UTC or a custom time zone.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetTimeL(const TTime& aTime, TTimeZoneType aTzType)
+	{
+	TRACE_ENTRY_POINT;
+	
+	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);
+		}
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Returns the CICalValue as a date/time (TTime).
+@param aDateTime TTime to store the date/time in.
+@param aTzType Enumeration showing whether the time represents local time (not
+supported), UTC or a custom time zone.
+@param aFirstCharacterNum Skip this many characters of the internal buffer
+@leave Leaves with KErrCorrupt if the value is not a valid date/time.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::GetDateTimeL(TTime& aDateTime, TTimeZoneType& aTzType, TInt aFirstCharacterNum) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	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;
+		}
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Stores a date/time (TTime) as the value.
+@param aDateTime TTime to be stored.
+@param aTzType Enumeration showing whether the time represents floating time,
+UTC or a custom time zone.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetDateTimeL(const TTime& aDateTime, TTimeZoneType aTzType)
+	{
+	TRACE_ENTRY_POINT;
+	
+	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);
+		}
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Returns the CICalValue as a Duration (TTimeIntervalSeconds).
+@return TTimeInterval containing the value's duration.
+@publishedPartner
+*/
+EXPORT_C TTimeIntervalSeconds CICalValue::DurationL() const
+	{
+	TRACE_ENTRY_POINT;
+	
+	CheckNullValueL();
+	TTimeIntervalSeconds theTis;
+	GetTimeIntervalFromValueL(theTis);
+	
+    TRACE_EXIT_POINT;
+	return theTis;
+	}
+
+/**
+Stores a Duration (TTimeIntervalSeconds) as the value.
+@param aDuration TTimeIntervalSeconds to be stored.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetDurationL(TTimeIntervalSeconds aDuration)
+	{
+	TRACE_ENTRY_POINT;
+	
+	// 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);
+	
+    TRACE_EXIT_POINT;
+	}
+
+/**
+Returns the CICalValue as a Float (TReal).
+@param aFloat The value to return.
+@leave Leaves if there is an error reading a float.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::GetFloatL(TReal& aFloat) const
+	{
+    TRACE_ENTRY_POINT;
+	
+	CheckNullValueL();
+	TLex stringLex(iValue->Des());
+	User::LeaveIfError(stringLex.Val(aFloat));
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Stores a float (TReal) as the value.
+@param aFloat The value to store.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetFloatL(const TReal& aFloat)
+	{
+	TRACE_ENTRY_POINT;
+	
+	PrepareValuePointer();
+
+	iValue = HBufC::NewL(KDefaultRealWidth);
+	TRealFormat format;
+	iValue->Des().Num(aFloat, format);
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Returns the CICalValue as an Integer.
+@return The integer requested.
+@publishedPartner
+*/
+EXPORT_C TInt CICalValue::IntegerL() const
+	{
+	TRACE_ENTRY_POINT;
+	
+	CheckNullValueL();
+	
+	TRACE_EXIT_POINT;
+	return ReadIntL(iValue->Des());
+	}
+
+/**
+Stores an Integer as the value.
+@param aInt The integer to be stored.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetIntegerL(TInt aInt)
+	{
+	TRACE_ENTRY_POINT;
+	
+	PrepareValuePointer();
+	iValue = HBufC::NewL(KICalTIntWidth);
+	iValue->Des().Num(aInt);
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Returns the CICalValue as a Period (two TTimes).
+@param aStartTime TTime marking the beginning of the period.
+@param aStartTzType Enumeration showing whether the start time represents local
+time (not supported), UTC or a custom time zone.
+@param aEndTime TTime marking the end of the period.
+@param aEndTzType Enumeration showing whether the end time represents local
+time (not supported), UTC or a custom time zone.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::GetPeriodL(
+	TTime& aStartTime, 
+	TTimeZoneType& aStartTzType, 
+	TTime& aEndTime, 
+	TTimeZoneType& aEndTzType) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	// 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);
+		}
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Stores a Period (two TTimes) as the value.
+@param aStartTime TTime to be stored containing the beginning of the period.
+@param aStartTzType Enumeration showing whether the start time represents local
+time (not supported), UTC or a custom time zone.
+@param aEndTime TTime to be stored containing the end of the period.
+@param aEndTzType Enumeration showing whether the end time represents local
+time (not supported), UTC or a custom time zone.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetPeriodL(
+	const TTime& aStartTime, 
+	TTimeZoneType aStartTzType, 
+	const TTime& aEndTime, 
+	TTimeZoneType aEndTzType)
+	{
+	TRACE_ENTRY_POINT;
+	
+	// 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);
+		}
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Returns the value as an enumerated day and position.
+@param aDay A modifiable reference to an enumerated day.
+@param aPos A modifiable reference to a position.
+@leave KErrCorrupt if the day part is invalid.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::GetDayL(TDay& aDay, TInt& aPos) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	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.
+	TPtrC dayStr(iValue->Mid(endNumeric));
+			
+	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.
+		}
+		
+	TRACE_EXIT_POINT;
+	}
+	
+/**
+Sets the value from an enumerated date and position.
+@param aDay The day to set.
+@param aPos The position to set.
+@leave Leaves with KErrUnknown if the value of aDay is not known.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetDayL(TDay aDay, TInt aPos)
+	{
+	TRACE_ENTRY_POINT;
+	
+	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);
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Gets the value as a month.
+@return The month set in the value.
+@leave Leaves with KErrCorrupt if the value is not a valid month.
+@publishedPartner
+*/
+EXPORT_C TMonth CICalValue::MonthL() const
+	{
+	TRACE_ENTRY_POINT;
+	
+	CheckNullValueL();
+	
+	TInt num(IntegerL());
+	
+	if ((num < 1) || (num > 12))
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+    TRACE_EXIT_POINT;
+	return static_cast<TMonth>(num - 1);
+	}
+
+/**
+Sets a month as the value.
+@param aMonth The month to set.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetMonthL(TMonth aMonth)
+	{
+	TRACE_ENTRY_POINT;
+	
+	PrepareValuePointer();
+	SetIntegerL(aMonth + 1);
+	
+    TRACE_EXIT_POINT;
+	}
+	
+/**
+Returns the value as an array of CICalRuleSegments. Assumes that all escaping
+has been previously removed.
+@param aRuleSegmentArray The array that the segments are appended to.
+@leave Leaves if there is an error adding a rule segment to the array.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::GetRecurrenceRuleL(RPointerArray<CICalRuleSegment>& aRuleSegmentArray) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	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
+		CICalRuleSegment* theRule = CICalRuleSegment::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());
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Sets a complete RRULE as a descriptor value. Note that this is no different
+than setting as text and is only supplied for symmetry.
+@param aRuleValue The descriptor containing the complete RRULE.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetRecurrenceRuleL(const TDesC& aRuleValue)
+	{
+	TRACE_ENTRY_POINT;
+	
+	PrepareValuePointer();
+	iValue = aRuleValue.AllocL();
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Returns the CICalValue as text.
+@return The value as text.
+@publishedPartner
+*/
+EXPORT_C const TDesC& CICalValue::TextL() const
+	{
+	TRACE_ENTRY_POINT;
+	
+	CheckNullValueL();
+	
+	TRACE_EXIT_POINT;
+	return *iValue;
+	}
+
+/**
+Stores text as the value.
+@param aText The text to be stored.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetTextL(const TDesC& aText)
+	{
+	TRACE_ENTRY_POINT;
+	
+	PrepareValuePointer();
+	iValue = aText.AllocL();
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Returns the CICalValue as a UTC Offset (TTimeIntervalSeconds).
+@return TTimeIntervalSeconds containing the offset.
+@leave Leaves with KErrCorrupt if the value is invalid.
+@publishedPartner
+*/
+EXPORT_C TTimeIntervalSeconds CICalValue::UtcOffsetL() const
+	{
+	TRACE_ENTRY_POINT;
+	
+	// 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.
+	TRACE_EXIT_POINT;
+	return TTimeIntervalSeconds((hours * KICalSecondsPerHour) + (minutes * KICalSecondsPerMinute) + seconds);
+	}
+
+/**
+Stores a UTC Offset (TTimeIntervalSeconds) as the value.
+@param aOffset TTimeInterval to set as the offset.
+@publishedPartner
+*/
+EXPORT_C void CICalValue::SetUtcOffsetL(TTimeIntervalSeconds aOffset)
+	{
+	TRACE_ENTRY_POINT;
+	
+	// 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);
+		}
+		
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Constructor.
+@internalTechnology
+*/
+CICalValue::CICalValue()
+	{
+	TRACE_ENTRY_POINT;
+	TRACE_EXIT_POINT;
+	}
+	
+/**
+Internal construction.
+@internalTechnology
+*/
+void CICalValue::ConstructL()
+	{
+	TRACE_ENTRY_POINT;
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Checks for a NULL value. Should be called before accessing iValue. 
+@leave Leaves with KErrCorrupt if the value is NULL.
+@internalTechnology
+*/
+void CICalValue::CheckNullValueL() const
+	{
+	TRACE_ENTRY_POINT;
+	
+	if (!iValue)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Prepares iValue pointer for writing. Deletes existing pointer if it exists.
+@internalTechnology
+*/
+void CICalValue::PrepareValuePointer()
+	{
+	TRACE_ENTRY_POINT;
+	
+	if (iValue)
+		{
+		delete iValue;
+		iValue = NULL;
+		}
+		
+	TRACE_EXIT_POINT;
+	}
+	
+/**
+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 CICalValue::ReadIntL(const TDesC& aDes) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	TLex stringLex(aDes);
+	TInt returnValue(0);
+	User::LeaveIfError(stringLex.Val(returnValue));
+	
+	TRACE_EXIT_POINT;
+	return returnValue;
+	}
+	
+/**
+Appends the date to iValue. Member iValue must be initialised before calling.
+@param aDate TTime to append to the value.
+@internalTechnology
+*/
+void CICalValue::AppendDateToValueL(const TTime& aDate)
+	{
+	TRACE_ENTRY_POINT;
+	
+	TBuf<KICalDateWidth> formattedDate;
+	aDate.FormatL(formattedDate, KICalDateFormat);
+	iValue->Des().Append(formattedDate);
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+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 CICalValue::GetDateFromValueL(TTime& aDate, TInt aFirstCharacterNum) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	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.
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+Appends the time to iValue. Member iValue must be initialised before calling.
+@param aTime TTime to append to the value.
+@internalTechnology
+*/
+void CICalValue::AppendTimeToValueL(const TTime& aTime)
+	{
+	TRACE_ENTRY_POINT;
+	
+	// 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);
+	
+	TRACE_EXIT_POINT;
+	}
+	
+/**
+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 CICalValue::GetTimeFromValueL(TTime& aTime, TTimeZoneType& aTzType, TInt aFirstCharacterNum) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	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);
+	
+	TRACE_EXIT_POINT;
+	}
+
+/**
+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 CICalValue::GetTimeIntervalFromValueL(TTimeIntervalSeconds& aTimeInterval, TInt aFirstCharacterNum) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	//     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;
+	TRACE_EXIT_POINT;
+	}
+
+/**
+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 CICalValue::GetDurDateL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	//	dur-date   = dur-day [dur-time]
+	//	dur-day    = 1*DIGIT "D"
+	
+	if (aCurrentCharNumber >= iValue->Length())
+		{
+		TRACE_EXIT_POINT;
+		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);
+		TRACE_EXIT_POINT;
+		return ETrue;
+		}
+
+	// If no character found, return EFalse
+	TRACE_EXIT_POINT;
+	return EFalse;
+	}
+
+/**
+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 CICalValue::GetDurTimeL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	//	dur-time   = "T" (dur-hour / dur-minute / dur-second) e.g. T5H0M20S
+
+	if (aCurrentCharNumber >= iValue->Length())
+		{
+		TRACE_EXIT_POINT;
+		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
+		TRACE_EXIT_POINT;
+		return EFalse;
+		}
+		
+	TRACE_EXIT_POINT;
+	return ETrue;
+	}
+	
+/**
+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 CICalValue::GetDurHourL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	//	dur-hour   = 1*DIGIT "H" [dur-minute]
+	
+	if (aCurrentCharNumber >= iValue->Length())
+		{
+		TRACE_EXIT_POINT;
+		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);
+		TRACE_EXIT_POINT;
+		return ETrue;
+		}
+
+	// If no character found, return EFalse
+	TRACE_EXIT_POINT;
+	return EFalse;
+	}
+
+/**
+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 CICalValue::GetDurMinuteL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	//	dur-minute = 1*DIGIT "M" [dur-second]
+
+	if (aCurrentCharNumber >= iValue->Length())
+		{
+		TRACE_EXIT_POINT;
+		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);
+		TRACE_EXIT_POINT;
+		return ETrue;
+		}
+
+	// If no character found, return EFalse
+	TRACE_EXIT_POINT;
+	return EFalse;
+	}
+		
+/**
+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 CICalValue::GetDurSecondL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	//	dur-second = 1*DIGIT "S"
+
+	if (aCurrentCharNumber >= iValue->Length())
+		{
+		TRACE_EXIT_POINT;
+		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;
+		
+		TRACE_EXIT_POINT;
+		return ETrue;
+		}
+
+	// If no character found, return EFalse
+	TRACE_EXIT_POINT;
+	return EFalse;
+	}
+
+/**
+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 CICalValue::GetDurWeekL(TInt& aIntervalSecs, TInt& aCurrentCharNumber) const
+	{
+	TRACE_ENTRY_POINT;
+	
+	//	dur-week   = 1*DIGIT "W"
+	
+	if (aCurrentCharNumber >= iValue->Length())
+		{
+		TRACE_EXIT_POINT;
+		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;
+		
+		TRACE_EXIT_POINT;
+		return ETrue;
+		}
+
+	// If no character found, return EFalse
+	TRACE_EXIT_POINT;
+	return EFalse;
+	}
+
+
+// End of File
+
+
+