messagingfw/wappushfw/SISLContentHandlers/src/CSIContentHandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 18 Jan 2010 20:36:02 +0200
changeset 0 8e480a14352b
permissions -rw-r--r--
Revision: 201001 Kit: 201003

// Copyright (c) 2001-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:
//

// Local includes
//
#include "CSIContentHandler.h"

// System includes
//
#include  <push/sislpushmsgutils.h>
#include <push/csipushmsgentry.h>
#include <escapeutils.h>
#include <msvids.h>
#include <inetprottextutils.h>

// SI string tables.
#include "sitagstable.h"
#include "siattributetable.h"
#include "siattributevaluetable.h"


const TInt KValidUTCLength = 20;


#if defined(_DEBUG)
_LIT(KErrPushMsgNull,	"NULL CPushMessage");
#endif

// Constants
_LIT(KReserved, "Reserved");

void CSIContentHandler::CPushHandlerBase_Reserved1()
	{
	User::Panic(KReserved, KErrNotSupported);
	}

void CSIContentHandler::CPushHandlerBase_Reserved2()
	{
	User::Panic(KReserved, KErrNotSupported);
	}

/**
 * The SL Content handler private constructor.
 * Index number : ESIContentHandlerIndex 
 */ 
CSIContentHandler::CSIContentHandler()
: CContentHandlerBase(), iPushMsgAction(KErrNotFound), iExpiresTime(Time::NullTTime()), iCreatedTime(Time::NullTTime()), iValidDate(ETrue)
	{
	}

/**
 *  This will complete initialization of the object
 */
void CSIContentHandler::ConstructL()
	{
	iWapPushUtils = CSISLPushMsgUtils::NewL();
	CActiveScheduler::Add(this);
	}

/**
 * Static Factory Construction
 *
 * Version of NewL which leaves nothing
 * on the cleanup stack
 */
CSIContentHandler* CSIContentHandler::NewL()
	{
	CSIContentHandler* self = new(ELeave) CSIContentHandler;
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

/**
 * Default d'tor
 */
CSIContentHandler::~CSIContentHandler()
	{
	__LOG_PTR_DEBUG("CSIContentHandler:: Destructor Called"); 
	delete iHrefBuf;
	delete iSiIdBuf;
	delete iData;
	delete iWapPushUtils;
	}

/**
 * HandleMessage Async. Version
 *	Takes ownership of Push Message and sets self active to continue
 *	processing message.
 *	@param aPushMsg
 *		CPushMessage to process
 *	@param aStatus
 *		request status variable for use in asynchronous operations
 */
void CSIContentHandler::HandleMessageL(CPushMessage* aPushMsg, TRequestStatus& aStatus)
	{
	__LOG_PTR_DEBUG("CSIContentHandler:: HandleMessage Async Func. Called"); 
	__ASSERT_DEBUG( aPushMsg != NULL, User::Panic(KErrPushMsgNull, KErrNone));

	iMessage = aPushMsg;
	iAcknowledge = ETrue;
	SetConfirmationStatus(aStatus);

	iState= EParsing;
	IdleComplete();
	}

/**
 * HandleMessage Sync. Version
 *	Takes ownership of Push Message and sets self active to continue
 *	processing message.
 *
 *	Initial State: Set data members then go to the next state 
 *	@param aPushMsg
 *		CPushMessage to process
 */
void CSIContentHandler::HandleMessageL(CPushMessage* aPushMsg)
	{
	__LOG_PTR_DEBUG("CSIContentHandler:: HandleMessage Sync Func. Called");
	__ASSERT_DEBUG( aPushMsg != NULL, User::Panic(KErrPushMsgNull, KErrNone));
	
	iAcknowledge = EFalse;
	iMessage = aPushMsg;

	iState =EParsing;
	IdleComplete();
	}

/** 
 *	Parse the SI message from XML to its component parts which are held
 *	in the document tree. This tree is then examined and the attributes
 *	read and recorded for later reference. Once parsed the parser and tree
 *	are deleted as no longer required.
 *	@leave KErrNotFound
 *		indicates general processing error and to abandon processing
 *	@leave KErrCorrupt
 *		there is no body in the message
 *	@leave TDesC::AllocL
 
 */
void CSIContentHandler::ParsePushMsgL()
	{
	__LOG_PTR_DEBUG("CSIContentHandler:: ParsePushMsgL. Called"); 

	CMessageParser* myParser = CMessageParser::NewL ( *iMessage, 
													*this, 
													&sitagstable::Table,
													&siattributetable::Table,
													&siattributevaluetable::Table );
	CleanupStack::PushL ( myParser );
	
	myParser->ParseMessageL ();

	User::LeaveIfError ( myParser->LastError() );

	CleanupStack::PopAndDestroy ( myParser );

	if (iData)
	{
	( iData->Des() ).TrimLeft ();
	( iData->Des() ).TrimRight ();		
	}
	iState = EProcessing;
	IdleComplete();
	}

	// Return value NULL indicates failed conversion!
	// Ownership of the resulting string is passed up to caller.
	HBufC16* CSIContentHandler::FormatDateStringL(const TDesC& aData)
	{
	const TInt KDateTimePart = 7;
	enum TDateTimeParts {EYearTop, EYearBot, EMon, EDay, EHour, EMin, ESec};
	TInt dateData[KDateTimePart];	
	
	for (TInt i = 0; i < KDateTimePart; i++)
		dateData[i] = 0;
	
	TInt offSet = 0;
	TInt dataLen = aData.Length();
	

	while (offSet < KDateTimePart && dataLen > 0)
		{
		dateData[offSet] = aData[offSet];
		offSet++;
		dataLen--;
		}

		_LIT(KDateFormat,"%2x%02x-%02x-%02xT%02x:%02x:%02xZ");
		const TInt KDateFormatLen = 20;
		
		TBuf16<KDateFormatLen> dateBuf;
		dateBuf.Format(KDateFormat, dateData[EYearTop], 
								dateData[EYearBot], 
								dateData[EMon], 
								dateData[EDay], 
								dateData[EHour], 
								dateData[EMin], 
								dateData[ESec]);
	return( dateBuf.AllocL() );	
}
		

/** 
 *	Convert UTC date time into native TTime format. Method can not leave
 *	and traps any leaves from ValidateUTCTimeL.
 *	@param aDateTime
 *			the UTC string representing the date and time
 *	@param aConvertedDate
 *			member date variable passed in to accept converted UTC date as TTime varaible
 *	@return TBool
 *			indicates if conversion successful (ETrue) or conversion failed (EFalse)
 */
TBool CSIContentHandler::ConvertDateTimeL(const TDesC& aDateTime, TTime &aConvertedDate)
	{
	TTime convertedTime = Time::NullTTime();
	TBool convertedOK = EFalse;

	HBufC* dateTime = NULL;
	if (aDateTime.Length() == KValidUTCLength) //check supplied descriptor is the correct length
		{		
		dateTime = aDateTime.AllocLC ();
		}
	else
		{
		// Convert to UTC string
		dateTime = FormatDateStringL ( aDateTime );
		CleanupStack::PushL ( dateTime );		
		}
		
	TBuf<20> str = dateTime->Des();
	if (IsValidUTCTime(str))
		{
		// adjust UTC time to zero offset TTime
		const TInt KFirstMonthChar = 4;
		const TInt KSecondMonthChar = KFirstMonthChar + 1;
		const TInt KFirstDayChar = 6;
		const TInt KSecondDayChar = KFirstDayChar + 1;
		// check for special case of month = 10 which becomes 09
		if (str[KFirstMonthChar]=='1' && str[KSecondMonthChar] == '0')
			{
			str[KFirstMonthChar]='0';
			str[KSecondMonthChar]='9';
			}
		else
			// month value is either 11, 12 or less than 10, ie 1 - 9.
			// reduce day by one, eg 11 becomes 10, 12 becomes 11, 09 becomes 08
			str[KSecondMonthChar]-- ; 
		
		// check for special cases 10, 20, 30
		if (str[KSecondDayChar] == '0')
			{
			// reduce day by 1, ie 10 becomes 09, 20 becomes 19 ...
			str[KSecondDayChar] = '9';
			str[KFirstDayChar]--;
			}
		else
			// day value is between 1 and 9 so reduce day by one
			// eg 29 becomes 28, 11 bcomes 10, 31 becomes 30
			str[KSecondDayChar]--;
		
		// string is now syntaxically correct and year will be not be negative
		// so no errors will occur here and will now have a valid TTime
		convertedTime.Set(str);
		convertedOK = ETrue;
		}	
	
	aConvertedDate = convertedTime;
	CleanupStack::PopAndDestroy ( dateTime );
	if(!convertedOK)
	   {
	   iValidDate = EFalse;
	   }
	return convertedOK;
	}

/**
 *	Check given UTC time string conforms to expected format:
 *	YYYY-MM-DDTHH:MM:SSZ and strip out formatting characters
 *	then validate the remaining characters are all digits.
 *	If validated then add TTime formating character so final
 *	string returned will be of the format YYYYMMDD:HHMMSS.
 *	@param aDateTime
 *		UTC string which is validated and returned
 *	@return boolean 
 *		indicates if given date is valid (ETrue)
 *		or not (EFalse)
 */
TBool CSIContentHandler::IsValidUTCTime(TDes& aDateTime)
	{
	// strip out formatting characters
	TInt formatCharPos = 4;
	aDateTime.Delete(formatCharPos, 1); 
	// now move through two characters at a time and remove other chars 
	// to just leave digits
	TInt KRemainingFormatChars = 5;
	for (TInt i = 0 ; i < KRemainingFormatChars; i++)
		{
		formatCharPos += 2;
		aDateTime.Delete(formatCharPos, 1);
		}
	
	// check string now the right TTime length
	const TInt KValidTTimeLength = 14;
	if (aDateTime.Length() != KValidTTimeLength)
		return EFalse;

	// now have UTC string stripped of format characters - check remaining characters are
	// all digits - YYYYMMDDHHMMSS
	TChar ch;
	for (TInt x = 0; x < KValidTTimeLength; x++)
		{
		ch = aDateTime[x];
		if (ch.IsDigit() == EFalse)
			return EFalse;
		}
	
	TInt err = ValidateDateTime( aDateTime );
	if(!err)   
	return EFalse;

	// insert colon seperating date from time
	_LIT(colon, ":");
	const TInt KColonPosition = 8;
	aDateTime.Insert(KColonPosition, colon);
	return ETrue;
	}

/**
 * Validate date and time to check whether date and time values lie 
 * within the valid range
 *	@param aDateTime
 *		UTC string which is validated 
 *	@return boolean 
 *		indicates if given date and time is valid (ETrue)
 *		or not (EFalse)
 */
TBool CSIContentHandler::ValidateDateTime(TDes& aDateTime)
    {
	TPtrC ptr(aDateTime);
	TPtrC yr;
	yr.Set(ptr.Left(4));	   
	TInt yearInt;
	InetProtTextUtils::ConvertDescriptorToInt(yr,yearInt);
	   
	TPtrC month;
	month.Set(ptr.Mid(4));
	TPtrC mon;
	mon.Set(month.Left(2));
	TInt monthInt;
	InetProtTextUtils::ConvertDescriptorToInt(mon,monthInt);
	   
	TPtrC day;
	day.Set(month.Mid(2));
    TPtrC dy;
	dy.Set(day.Left(2));
	TInt dayInt;
	InetProtTextUtils::ConvertDescriptorToInt(dy,dayInt);
	   
	TPtrC hour;
    hour.Set(day.Mid(2));
    TPtrC hr;
    hr.Set(hour.Left(2));
	TInt hourInt;
    InetProtTextUtils::ConvertDescriptorToInt(hr,hourInt);
	   
	TPtrC minute;
	minute.Set(hour.Mid(2));
	TPtrC min;
	min.Set(minute.Left(2));
	TInt minInt;
    InetProtTextUtils::ConvertDescriptorToInt(min,minInt);
	   
    TPtrC second;
	second.Set(minute.Mid(2));
	TPtrC sec;
	sec.Set(second.Left(2));
	TInt secInt;
	InetProtTextUtils::ConvertDescriptorToInt(sec,secInt);
	    
		
	if ( monthInt == 1 ||  monthInt == 3 || monthInt == 5 || monthInt == 7
		 || monthInt == 8 || monthInt == 10 || monthInt == 12)
         {
         if (!(dayInt <= 31))
	         return EFalse;	
         }	 
    else if (monthInt == 04 ||  monthInt == 06 || monthInt == 9 || monthInt == 11)
             {
             if (!(dayInt <= 30))
	             return EFalse;
	         }
    else if (monthInt == 02)
             {
             if (Time::IsLeapYear(yearInt))
                 {
                 if (!(dayInt <= 29))
	                 return EFalse;		                  
	             }
	         else if (!(dayInt <= 28))	                  
	                  return EFalse;
	         }	                 
    else 
       {
       return EFalse;
       }
  
    if ( !(hourInt <= 23 && minInt <= 59 && secInt <= 59))
        return EFalse;
    
    return ETrue;
    }

/** 
 *	Convert the action string to a representative numeric value to facilitate 
 *	storing the message in the wap push utils.
 *	@param aActionString
 *		the attribute value indicating the action level eg 'signal-high'
 *	@return TUint
 *		a value representing the action type (as defined in PushEntry.h)
 */
TUint CSIContentHandler::ConvertActionString(const RString& aActionString)
	{
	// set to default signal value (to rid ourselves of build warning)
	TUint actionValue = CSIPushMsgEntry::ESIPushMsgSignalMedium;	
	switch ( aActionString.Index ( siattributevaluetable::Table ) )
		{
		case siattributevaluetable::EAction1:
		actionValue = CSIPushMsgEntry::ESIPushMsgSignalNone;
		break;
		case siattributevaluetable::EAction2:
		actionValue = CSIPushMsgEntry::ESIPushMsgSignalLow;
		break;
		case siattributevaluetable::EAction3:
 		actionValue = CSIPushMsgEntry::ESIPushMsgSignalMedium;
		break;
		case siattributevaluetable::EAction4:
 		actionValue = CSIPushMsgEntry::ESIPushMsgSignalHigh;
		break;		
		case siattributevaluetable::EAction5:
		actionValue = CSIPushMsgEntry::ESIPushMsgDelete;
		break;						
		default:
		User::Invariant ();
		}
	return actionValue;
	}

/** 
 *	Handles message reception and processes the received message following 
 *	the flow of actions detailed in 7.2 Reception 
 *	[WAP Service Indication 08-Nov-1999]
 *		1. check if received message is expired 
 *		2. if received message is an older version of stored SI,
 *			or is the same age - discard received message 
 *		3. if message is more recent version than stored SI - delete stored SI
 *		4. if message actioned to delete, and has Si Id set, then delete it 
 *			and any stored messages with same id
 *	finally if received message not set to deleted or discarded - store it
 */
void CSIContentHandler::ProcessingPushMsgEntryL()
	{
	__LOG_PTR_DEBUG("CSIContentHandler:: ProcessingPushMsgEntryL. called");
	TBool deletePushMsg = EFalse;
	
	// 1. Expiration
	TTime today;
	today.UniversalTime();
	// check if message has expiry date before today's date
	if (ExpiresFlag() && iExpiresTime < today)
		{
		deletePushMsg = ETrue;
		__LOG_PTR_DEBUG("CSIContentHandler: ProcessingPushMsgEntryL: Expired msg (1)");
		}
	
	// 2. handling out of order delivery & 
	// 3. replacement
	else if (SiIdFlag() || HrefFlag())
		deletePushMsg = HandleMsgOrderReceptionL();

	// 4. deletion
	if (!deletePushMsg && ActionFlag())
		{
		// check if action = delete and SiId value is set before can delete
		if ((iPushMsgAction == CSIPushMsgEntry::ESIPushMsgDelete) && (SiIdFlag())) 
			{
			__LOG_PTR_DEBUG("CSIContentHandler: ProcessingPushMsgEntryL: delete msg (4)");
			
			// delete msg and any matching messages (with same si-id)
			__LOG_PTR_DEBUG("CWapPushMsgUtils: FindSiIdLC  called");
			CMsvEntrySelection* matchingIdList = iWapPushUtils->FindSiIdLC(*iSiIdBuf);
			TInt matchingListCount = matchingIdList->Count();
			for (TInt count = 0; count < matchingListCount; count++)
				{
				TMsvId matchingSiMsgEntryId = matchingIdList->At(count);
				if (matchingSiMsgEntryId)
					{
					__LOG_PTR_DEBUG("CWapPushMsgUtils: DeleteEntryNowL called");
					iWapPushUtils->DeleteEntryNowL(matchingSiMsgEntryId);
					}
				}
			CleanupStack::PopAndDestroy(); // matchingIdList
			deletePushMsg = ETrue;
			}
		}

	// store message if not marked for deletion and date/time is valid
	if (!deletePushMsg && iValidDate)
		StoreSIMessageL();
	// Reset the flag to ETrue for next message
	iValidDate = ETrue;

	iState = EDone;
	IdleComplete();
	}

/**
 *	Check received SI message against existing stored messages
 *	with the same si-id and update the message(s) according to
 *	the creation date (if specified).
 *	@return TBool
 *		ETrue - Received SI message older than stored match(es)
 *				and should be marked for deletion
 *		EFalse - Receieved SI message to be retained as newer
 *				therefore do not delete it
 */
TBool CSIContentHandler::HandleMsgOrderReceptionL()
	{
	CMsvEntrySelection* matchingIdList;
	TBool discardPushMsg = EFalse;

	__LOG_PTR_DEBUG("CSISLPushMsgUtils: FindSiIdLC called");
	// get list of matching stored SI messages 
	if (SiIdFlag())
		matchingIdList = iWapPushUtils->FindSiIdLC(*iSiIdBuf);
	else
		matchingIdList = iWapPushUtils->FindSiIdLC(*iHrefBuf);

	// check we have a creation date specified before checking against list of matches
	if (matchingIdList->Count() && CreatedFlag())
		{
		CSIPushMsgEntry* siEntry=GetSiEntryL();	
		CleanupStack::PushL(siEntry);
			
		// delete older stored messages and/or mark current message for deletion
		// if same date or older than stored messages
		TInt matchingListCount = matchingIdList->Count();
		for (TInt count = 0; count < matchingListCount; count++)
			{
			TMsvId matchingSiMsgEntryId = matchingIdList->At(count);
						
			__LOG_PTR_DEBUG("CSIPushMsgEntry: RetrieveL called");
			siEntry->RetrieveL(iWapPushUtils->Session(), matchingSiMsgEntryId);
		
			// skip date comparisons if creation date not valid
			TTime existingSiCreatedTime = siEntry->Created();
			if (existingSiCreatedTime == Time::NullTTime())
				continue;
			//check if received SI is newer than existing stored Si (out of order)
			if (iCreatedTime > existingSiCreatedTime) 
				{
				__LOG_PTR_DEBUG("CWapPushMsgUtils: DeleteEntryNowL called");
				iWapPushUtils->DeleteEntryNowL(matchingSiMsgEntryId);
				__LOG_PTR_DEBUG("CSIContentHandler: ProcessingPushMsgEntryL: delete stored msg (3)");
				}
			else if (iCreatedTime <= existingSiCreatedTime)
				// received SI older than existing stored Si (replacement)
				discardPushMsg = ETrue;
			}
		CleanupStack::PopAndDestroy(siEntry);
		}
		
	CleanupStack::PopAndDestroy(matchingIdList);
		
	if (discardPushMsg)
		{
		__LOG_PTR_DEBUG("CSIContentHandler: ProcessingPushMsgEntryL: discard msg (2)");
		}
	return discardPushMsg;
	}


/** 
 *	Save push message in message store.
 * 	Creates link to message service provided by wap push utils
 *	and uses this and the associated push entry class to save
 *	the push message.
 */
void CSIContentHandler::StoreSIMessageL() 
	{
	__LOG_PTR_DEBUG("CSIContentHandler:: StoreSiMessageL. called");

	CSIPushMsgEntry* siEntry=GetSiEntryL();
	CleanupStack::PushL(siEntry);
	SetSIPushMsgEntryFieldsL(*siEntry);
	
	TMsvId folderId;
	iWapPushUtils->GetPushMsgFolderIdL(folderId);

	__LOG_PTR_DEBUG("CSIPushMsgEntry::SaveL called");
	siEntry->SaveL(iWapPushUtils->Session(), folderId);
	
	CleanupStack::PopAndDestroy(siEntry);
	}


CSIPushMsgEntry* CSIContentHandler::GetSiEntryL()
	{
	TBool isInt;
	TPtrC8 appURI;
	TInt appID=0;
	iMessage->GetAppIdL(appURI, appID, isInt);
	CSIPushMsgEntry* siEntry=NULL;
	if (isInt)
		{
		siEntry = CSIPushMsgEntry::NewL(appID);
		}
	else
		{
		siEntry = CSIPushMsgEntry::NewL(appURI);
		}
	return siEntry;
	}

/** 
 *	Create SI entry fields prior to storing message. The saving of
 * 	certain push message attributes will be set to defaults if 
 *	information missing to facilitate message searching, storing 
 *	and retrieval.
 *	@param siEntry 
 *		entry represents message format to use when storing it
 */
void CSIContentHandler::SetSIPushMsgEntryFieldsL(CSIPushMsgEntry& aSIPushMsgEntry)
	{
	// if message has no si-id but does have a href - use href as si-id and
	// if message has a si-id but no href use si-id for href
	
	if (SiIdFlag() || HrefFlag())
		{
		if (SiIdFlag() && (HrefFlag() == EFalse))
			{
			aSIPushMsgEntry.SetIdL(*iSiIdBuf);
			aSIPushMsgEntry.SetUrlL(*iSiIdBuf);
			}
		else if (HrefFlag() && (SiIdFlag() == EFalse))
			{
			aSIPushMsgEntry.SetIdL(*iHrefBuf);
			aSIPushMsgEntry.SetUrlL(*iHrefBuf);
			}
		else
			{
			aSIPushMsgEntry.SetIdL(*iSiIdBuf);
			aSIPushMsgEntry.SetUrlL(*iHrefBuf);
			}
		}
	
	if (ActionFlag())
		aSIPushMsgEntry.SetAction(iPushMsgAction);
	else // default if no action explicitly stated
		aSIPushMsgEntry.SetAction(CSIPushMsgEntry::ESIPushMsgSignalMedium);
	
	// uses default null time value if no explicit date set in message
	aSIPushMsgEntry.SetCreated(iCreatedTime);
	aSIPushMsgEntry.SetExpires(iExpiresTime);
	
	// PCDATA (text) from message
	if (DataFlag())
		aSIPushMsgEntry.SetTextL(*iData);
	
	TPtrC8 msgHeaderPtr;
	iMessage->GetHeader(msgHeaderPtr);	
	aSIPushMsgEntry.SetHeaderL(msgHeaderPtr);
	
	TPtrC8 from;
	if (!iMessage->GetBinaryHeaderField(EHttpFrom, from) &&
		!iMessage->GetBinaryHeaderField(EHttpXWapInitiatorURI, from) &&
		!iMessage->GetBinaryHeaderField(EHttpContentLocation, from) )
		{
		from.Set(KNullDesC8);
		}
		aSIPushMsgEntry.SetFromL(from);
	
	if(iMessage->MessageAllowed())
		{
		aSIPushMsgEntry.SetTrusted(ETrue);
		}
	else
		{
		aSIPushMsgEntry.SetTrusted(EFalse);	
		}
		
	TPtrC8 serverAddress8;
	iMessage->GetServerAddress(serverAddress8);
	aSIPushMsgEntry.SetMsgOriginUriL(serverAddress8);
	}

/** 
 *	Same functionality as DoCancel()
 */
void CSIContentHandler::CancelHandleMessage()
	{
	__LOG_PTR_DEBUG("CSIContentHandler:: CancelHandleMessage called");
	Complete(KErrCancel);
	}

/** 
 *	Cancels the handling of the message and revokes the active status
 *	of the handler 
 */
void CSIContentHandler::DoCancel()
	{
	__LOG_PTR_DEBUG("CSIContentHandler:: DoCancel Called");
	Complete(KErrCancel);	
	}

/** 
 *	Step through the various representative states for handling a message 
 *	1. validate the message by parsing it against the relevant DTD
 *	2. process the message in accordance with the Reception rules
 *	3. finish up 
 */
void CSIContentHandler::RunL()
	{
	__LOG_PTR_DEBUG("CSIContentHandler:: RunL Called");
	// use active state machine routine to manage activites:
	switch (iState)
		{
	case EParsing : 
		ParsePushMsgL();
		break;
	case EProcessing:
		ProcessingPushMsgEntryL();
		break;
	case EDone:
		Complete(KErrNone);
		break;
	default:
		break;
		}
	}

/** 
 * CPluginActiveBase methods
 */
TInt CSIContentHandler::RunError(TInt aError)
	{
	__LOG_PTR_DEBUG("CSIContentHandler:: RunError Called"); 
	iState=EDone;
	Complete(aError);
	return KErrNone;
	}

void CSIContentHandler::HandleElementL ( const RString& aTag, const RString& aAttributeName, const RString& aAttributeValue )
	{
	__LOG_PTR_DEBUG( "CSIContentHandler:: HandleElementL Called" );
	
	const TDesC8& tag = aTag.DesC();
	iIndicationTagFound = EFalse;
	
	if ( aTag.Index ( sitagstable::Table ) == sitagstable::EIndication )
		{
		iIndicationTagFound = ETrue;
		}
	
	TBool gotDate = EFalse;	
	HBufC* des16 = EscapeUtils::ConvertToUnicodeFromUtf8L ( aAttributeValue.DesC() );	
	CleanupStack::PushL ( des16 );

	switch ( aAttributeName.Index ( siattributetable::Table ) )
		{
		case siattributetable::EAction1:
		case siattributetable::EAction2:
		case siattributetable::EAction3:		
		case siattributetable::EAction4:
		case siattributetable::EAction5:
		iPushMsgAction = ConvertActionString( aAttributeValue );
		SetActionFlag(ETrue);		
		break;
			
		case siattributetable::ECreated:
		gotDate = ConvertDateTimeL ( *des16, iCreatedTime );
		SetCreatedFlag(gotDate);
		break;
		
		case siattributetable::EHref:
		delete iHrefBuf;
		iHrefBuf = NULL;
		
		iHrefBuf = ( des16->Des() ).AllocL ();
		SetHrefFlag(ETrue);		
		break;

		case siattributetable::ESiExpires:
		gotDate  = ConvertDateTimeL ( *des16, iExpiresTime );
		SetExpiresFlag(gotDate);
		break;
		
		case siattributetable::ESiId:
		delete iSiIdBuf;
		iSiIdBuf = NULL;
		
		iSiIdBuf = ( des16->Des() ).AllocL (); 
		SetSiIdFlag(ETrue);
		break;
		
		case siattributetable::EClass:
		break;

		default:
		// Shouldn't come here.
		User::Invariant ();
		}

	CleanupStack::PopAndDestroy ( des16 );
	}

void CSIContentHandler::HandleContentL ( const TDesC8& aBytes )
	{	
	// We do handle content only if it is in indication tag.
	// else we reject the content.
	if ( !iIndicationTagFound )
		{
		return;
		}
	if ( iData )
		{
		HBufC* des16 = EscapeUtils::ConvertToUnicodeFromUtf8L ( aBytes );
		CleanupStack::PushL ( des16 );		
		
		TInt newDataLength = des16->Length ();
		TInt existingDataLength = iData->Length ();
				
		if ( ( newDataLength + existingDataLength ) > existingDataLength )
			{
			iData = iData->ReAllocL ( newDataLength + existingDataLength );
			}
			
		(iData->Des()).Append( *des16 );			
		
		CleanupStack::PopAndDestroy ( des16 );		
		}
	else
		{
		iData = EscapeUtils::ConvertToUnicodeFromUtf8L ( aBytes );
		}	
	SetDataFlag ( ETrue );
	}