--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pushmtm/Plugins/PushContentHandler/CSLContentHandler.cpp Wed Sep 01 12:31:04 2010 +0100
@@ -0,0 +1,1221 @@
+/*
+* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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: Implementation of CSLContentHandler.
+*
+*/
+
+
+
+// INCLUDE FILES
+
+#include "CSLContentHandler.h"
+#include "PushMtmUtil.h"
+#include "PushMtmSettings.h"
+#include "PushAuthenticationUtilities.h"
+#include "PushMtmLog.h"
+#include "PushContentHandlerPanic.h"
+#include "PushMtmAutoFetchOperation.h"
+#include "PushMtmUiDef.h"
+#include "StringResourceReader.h"
+#include "sl_dict.h"
+#include "PushContentHandlerUtils.h"
+#include <push/cslpushmsgentry.h>
+#include <msvids.h>
+#include <apgtask.h>
+#include <apgcli.h>
+#include <w32std.h>
+#include <PushMtmUi.rsg>
+#include <nw_dom_node.h>
+#include <nw_dom_document.h>
+#include <nw_dom_element.h>
+#include <nw_dom_text.h>
+#include <nw_wbxml_dictionary.h>
+#include <nw_string_char.h>
+#include "PushMtmPrivateCRKeys.h"
+#include <centralrepository.h>
+
+// CONSTANTS
+
+// sl attributes / elements
+_LIT8( KSl, "sl" );
+_LIT8( KHref, "href" );
+_LIT8( KAction, "action" );
+
+// action attribute literals
+_LIT8( KExecHigh,"execute-high" );
+_LIT8( KExecLow, "execute-low" );
+_LIT8( KCache, "cache" );
+
+// Text SL MIME type
+_LIT( KSlTextContentType, "text/vnd.wap.sl" );
+
+// Browser command to fetch an URL. See Browser API Specification!
+_LIT( KBrowserCmdFetchUrl, "4 " );
+const TUid KBrowserAppUid = { 0x10008D39 };
+
+const TInt KNoOfDictArrays = 1;
+
+/// Autofetch time delay in seconds.
+const TInt KAutofetchDelayInSec = 5;
+
+// file monitored by browser
+_LIT( KPushMtmUrl, "c:\\system\\temp\\PushMtmUrl.txt" );
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ---------------------------------------------------------
+// CSLContentHandler::NewL
+// ---------------------------------------------------------
+//
+CSLContentHandler* CSLContentHandler::NewL()
+ {
+ CSLContentHandler* self = new (ELeave) CSLContentHandler;
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::~CSLContentHandler
+// ---------------------------------------------------------
+//
+CSLContentHandler::~CSLContentHandler()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::~CSLContentHandler")
+
+ Cancel();
+ delete iFetchOp;
+ delete iHrefBuf;
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::~CSLContentHandler")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::CSLContentHandler
+// ---------------------------------------------------------
+//
+CSLContentHandler::CSLContentHandler()
+: CPushContentHandlerBase(),
+ iSavedMsgId( KMsvNullIndexEntryId ),
+ iPushMsgAction( KErrNotFound ),
+ iSaveAsRead( EFalse )
+ {
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::ConstructL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::ConstructL()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::ConstructL")
+
+ CRepository* PushSL = CRepository::NewL( KCRUidPushMtm );
+ CleanupStack::PushL( PushSL );
+ User::LeaveIfError( PushSL->Get( KPushMtmServiceEnabled , iPushSLEnabled ) );
+ CleanupStack::PopAndDestroy( PushSL );
+
+ CPushContentHandlerBase::ConstructL();
+ // Added to Active Scheduler.
+ PUSHLOG_LEAVEFN("CSLContentHandler::ConstructL")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::CollectGarbageL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::CollectGarbageL()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::CollectGarbageL")
+
+ DoCollectGarbageL();
+
+ if(iPushSLEnabled)
+ iState = EFilteringAndParsing;
+ else
+ iState = EDone;
+
+ IdleComplete();
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::CollectGarbageL")
+ }
+
+
+// ---------------------------------------------------------
+// CSLContentHandler::ParsePushMsgL
+// Note that cXML parser dosn't do any validation!
+// ---------------------------------------------------------
+//
+void CSLContentHandler::ParsePushMsgL()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::ParsePushMsgL")
+
+ TPtrC8 bodyPtr;
+ iMessage->GetMessageBody( bodyPtr );
+ // If there is no body in the message leave with an error
+ if ( bodyPtr.Size() == 0 )
+ {
+ PUSHLOG_WRITE("CSLContentHandler::ParsePushMsgL: Empty body")
+ User::Leave( KErrCorrupt );
+ }
+
+ TPtrC contentType;
+ iMessage->GetContentType( contentType );
+ PUSHLOG_WRITE_FORMAT(" Content type <%S>",&contentType)
+
+ // Add SL dictionary.
+ NW_WBXML_Dictionary_t* dictArray[ KNoOfDictArrays ] =
+ { (NW_WBXML_Dictionary_t*)&NW_SL_WBXMLDictionary };
+
+ NW_Status_t stat = NW_STAT_SUCCESS;
+
+ RWbxmlDictionary wbxmlDict;
+ wbxmlDict.InitializeL( KNoOfDictArrays, dictArray );
+ CleanupClosePushL<RWbxmlDictionary>( wbxmlDict );
+
+ NW_TinyDom_Handle_t domHandle;
+ NW_Byte* buffer = (NW_Byte*)bodyPtr.Ptr();
+ NW_Int32 length = (NW_Int32)bodyPtr.Size();
+ NW_Bool encoded = ( contentType.CompareF( KSlTextContentType ) == 0 ) ?
+ NW_FALSE : NW_TRUE;
+ NW_Uint32 publicID = NW_SL_PublicId;
+ NW_Bool extTNotStringTable = NW_FALSE; // What is this?
+ NW_DOM_NodeType_t type = 0;
+ /**********************************
+ * Root of DOM
+ ***********************************/
+ CDocumentTreeOwner* docTreeOwner = new (ELeave) CDocumentTreeOwner;
+ CleanupStack::PushL( docTreeOwner );
+ NW_DOM_DocumentNode_t* domNode = NW_DOM_DocumentNode_BuildTree
+ (
+ &domHandle,
+ buffer,
+ length,
+ encoded,
+ publicID,
+ extTNotStringTable
+ );
+ if (!domNode)
+ {
+ PUSHLOG_WRITE("CSLContentHandler::ParsePushMsgL: domNode is Null")
+ }
+ User::LeaveIfNull( domNode );
+ docTreeOwner->SetDocTree( domNode );
+
+ type = NW_DOM_Node_getNodeType( domNode );
+ if ( type != NW_DOM_DOCUMENT_NODE )
+ {
+ PUSHLOG_WRITE_FORMAT("CSLContentHandler::ParsePushMsgL: Not Document node <%d>",type)
+ User::Leave( KErrArgument );
+ }
+
+ iCharEncoding = NW_DOM_DocumentNode_getCharacterEncoding( domNode );
+ PUSHLOG_WRITE_FORMAT("CSLContentHandler::ParsePushMsgL: Doc char encoding <%x>",iCharEncoding)
+
+ /**********************************
+ * ELEMENT sl
+ ***********************************/
+ // first make sure if there any children in the dom tree, otherwise we will PANIC(in NW_DOM_DocumentNode_getDocumentElement) and crash WatcherMainThread.
+ TBool domNodeHasChildNodes = EFalse;
+ domNodeHasChildNodes = NW_DOM_Node_hasChildNodes( domNode );
+ PUSHLOG_WRITE_FORMAT("CSLContentHandler::ParsePushMsgL: check if Dom tree has <SI> node <%d>", domNodeHasChildNodes)
+ if (!domNodeHasChildNodes)
+ {
+ PUSHLOG_WRITE("CSLContentHandler::ParsePushMsgL: No SL element present in the dom tree. Message corrupted.")
+ User::Leave( KErrCorrupt );
+ }
+
+ PUSHLOG_WRITE("CSLContentHandler::ParsePushMsgL: before calling getDocumentElement")
+ NW_DOM_ElementNode_t* slElement =
+ NW_DOM_DocumentNode_getDocumentElement( domNode );
+ if (!slElement)
+ {
+ PUSHLOG_WRITE("CSLContentHandler::ParsePushMsgL: slElement is Null")
+ }
+ User::LeaveIfNull( slElement );
+
+ type = NW_DOM_Node_getNodeType( slElement );
+
+ CStringOwner* stringOwner = new (ELeave) CStringOwner;
+ CleanupStack::PushL( stringOwner );
+
+ NW_String_t* name = NW_String_new();
+ User::LeaveIfNull( name );
+ stringOwner->SetString( name );
+ stat = NW_DOM_Node_getNodeName( slElement, name );
+ PUSHLOG_WRITE_FORMAT("CSLContentHandler::ParsePushMsgL: getNodeName ErrCode: %d", NwxStatusToErrCode( stat ))
+ User::LeaveIfError( NwxStatusToErrCode( stat ) );
+ NW_Byte* nameBuf = NW_String_getStorage( name );
+ NW_Uint16 nameLen = NW_String_getCharCount( name, iCharEncoding );
+ TPtrC8 namePtr( nameBuf, nameLen );
+
+ if ( type != NW_DOM_ELEMENT_NODE || namePtr.CompareF( KSl ) != 0 )
+ {
+ PUSHLOG_WRITE_FORMAT("CSLContentHandler::ParsePushMsgL: Not sl element node <%d>",type)
+ User::Leave( KErrArgument );
+ }
+
+ CleanupStack::PopAndDestroy( stringOwner ); // stringOwner
+
+ /**********************************
+ * Attributes of ELEMENT sl
+ ***********************************/
+ if ( NW_DOM_ElementNode_hasAttributes( slElement ) )
+ {
+ NW_DOM_AttributeListIterator_t attrIter;
+ stat = NW_DOM_ElementNode_getAttributeListIterator
+ ( slElement, &attrIter );
+ PUSHLOG_WRITE_FORMAT("CSLContentHandler::ParsePushMsgL: getAttribListIter ErrCode: %d", NwxStatusToErrCode( stat ))
+ User::LeaveIfError( NwxStatusToErrCode( stat ) );
+
+ NW_DOM_AttributeHandle_t attrHandle;
+ while( NW_DOM_AttributeListIterator_getNextAttribute
+ ( &attrIter, &attrHandle ) == NW_STAT_WBXML_ITERATE_MORE )
+ {
+ ParseSlAttributeL( attrHandle );
+ }
+ }
+
+ // Cleanup.
+ CleanupStack::PopAndDestroy( 2, &wbxmlDict ); // docTreeOwner, wbxmlDict
+
+ // if 'action' attribute not specified, the value 'execute-low' is used.
+ if ( !ActionFlag() )
+ {
+ iPushMsgAction = CSLPushMsgEntry::ESLPushMsgExecuteLow;
+ SetActionFlag( ETrue );
+ PUSHLOG_WRITE_FORMAT(" Defaulting to ActionFlag: %d",iPushMsgAction)
+ }
+
+ iState = EProcessing;
+ IdleComplete();
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::ParsePushMsgL")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::ParseSlAttributeL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::ParseSlAttributeL
+ ( NW_DOM_AttributeHandle_t& aAttrHandle )
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::ParseSlAttributeL")
+
+ NW_Status_t stat = NW_STAT_SUCCESS;
+
+ CStringOwner* attrNameOwner = new (ELeave) CStringOwner;
+ CleanupStack::PushL( attrNameOwner );
+
+ NW_String_t* attrName = NW_String_new();
+ User::LeaveIfNull( attrName );
+ attrNameOwner->SetString( attrName );
+
+ // Get the name of the attribute.
+ stat = NW_DOM_AttributeHandle_getName( &aAttrHandle, attrName );
+ User::LeaveIfError( NwxStatusToErrCode( stat ) );
+ NW_Byte* attrNameBuf = NW_String_getStorage( attrName );
+ NW_Uint16 attrNameLen = NW_String_getCharCount( attrName, iCharEncoding );
+ TPtrC8 attrNamePtr( attrNameBuf, attrNameLen );
+
+ if ( attrNamePtr.CompareF( KHref ) == 0 )
+ {
+ if ( !HrefFlag() )
+ {
+ HBufC* tempHrefBuf = NULL;
+
+ CStringOwner* valOwner = new (ELeave) CStringOwner;
+ CleanupStack::PushL( valOwner );
+
+ NW_String_t* val = NW_String_new();
+ User::LeaveIfNull( val );
+ valOwner->SetString( val );
+ stat = NW_DOM_AttributeHandle_getValue( &aAttrHandle, val );
+ if ( stat != NW_STAT_DOM_NO_STRING_RETURNED )
+ {
+ User::LeaveIfError( NwxStatusToErrCode( stat ) );
+ NW_Byte* storage = NW_String_getStorage( val );
+ NW_Uint16 length = NW_String_getCharCount( val, iCharEncoding );
+ TPtrC8 prefixPtr( storage, length );
+ tempHrefBuf = HBufC::NewMaxL( length );
+ // No leavable after it!!! until...
+ tempHrefBuf->Des().Copy( prefixPtr );
+ }
+
+ CleanupStack::PopAndDestroy( valOwner ); // valOwner
+
+ if ( tempHrefBuf )
+ {
+ if ( tempHrefBuf->Length() == 0 )
+ {
+ // Zero length Href is considered as nothing.
+ PUSHLOG_WRITE(" Zero length HrefFlag");
+ }
+ else
+ {
+ iHrefBuf = tempHrefBuf; // ...until here.
+ SetHrefFlag( ETrue );
+ PUSHLOG_WRITE_FORMAT(" HrefFlag set <%S>",iHrefBuf);
+ }
+ }
+ }
+ }
+ else if ( attrNamePtr.CompareF( KAction ) == 0 )
+ {
+ if ( !ActionFlag() )
+ {
+ CStringOwner* stringOwner = new (ELeave) CStringOwner;
+ CleanupStack::PushL( stringOwner );
+
+ NW_String_t* val = NW_String_new();
+ User::LeaveIfNull( val );
+ stringOwner->SetString( val );
+ stat = NW_DOM_AttributeHandle_getValue( &aAttrHandle, val );
+ User::LeaveIfError( NwxStatusToErrCode( stat ) );
+ NW_Byte* storage = NW_String_getStorage( val );
+ NW_Uint16 length = NW_String_getCharCount( val, iCharEncoding );
+ TPtrC8 actionPtr( storage, length );
+
+ iPushMsgAction = ConvertActionString( actionPtr );
+ SetActionFlag( ETrue );
+ PUSHLOG_WRITE_FORMAT(" ActionFlag: %d",iPushMsgAction)
+
+ CleanupStack::PopAndDestroy( stringOwner );
+ }
+ }
+ else
+ {
+ __ASSERT_DEBUG( EFalse,
+ ContHandPanic( EPushContHandPanUnexpSlToken ) );
+ }
+
+ CleanupStack::PopAndDestroy( attrNameOwner ); // attrNameOwner
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::ParseSlAttributeL")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::ConvertActionString
+// ---------------------------------------------------------
+//
+TUint CSLContentHandler::ConvertActionString
+ ( const TDesC8& aActionString ) const
+ {
+ const TInt KMatchFound = 0;
+
+ // if 'action' attribute not specified, the value 'execute-low' is used.
+ TUint actionValue = CSLPushMsgEntry::ESLPushMsgExecuteLow;
+
+ if ( aActionString.Compare( KExecHigh ) == KMatchFound )
+ {
+ actionValue = CSLPushMsgEntry::ESLPushMsgExecuteHigh;
+ }
+ else if ( aActionString.Compare( KExecLow ) == KMatchFound )
+ {
+ actionValue = CSLPushMsgEntry::ESLPushMsgExecuteLow;
+ }
+ else if ( aActionString.Compare( KCache ) == KMatchFound )
+ {
+ actionValue = CSLPushMsgEntry::ESLPushMsgExecuteCache;
+ }
+
+ return actionValue;
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::SetSlPushMsgEntryFieldsL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::SetSlPushMsgEntryFieldsL( CSLPushMsgEntry&
+ aSlPushMsgEntry ) const
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::SetSlPushMsgEntryFieldsL")
+
+ // Set URL and Action fields.
+ if ( HrefFlag() )
+ {
+ aSlPushMsgEntry.SetUrlL( *iHrefBuf );
+ }
+
+ __ASSERT_DEBUG( ActionFlag(),
+ ContHandPanic( EPushContHandPanUnspecSlAction ) );
+ if ( ActionFlag() )
+ {
+ aSlPushMsgEntry.SetAction( iPushMsgAction );
+ }
+ else // if not specified, the value 'execute-low' is used.
+ {
+ aSlPushMsgEntry.SetAction( CSLPushMsgEntry::ESLPushMsgExecuteLow );
+ }
+
+ // Set all the relevant header fields.
+ TPtrC8 msgHeaderPtr;
+ iMessage->GetHeader( msgHeaderPtr );
+ aSlPushMsgEntry.SetHeaderL( msgHeaderPtr );
+
+ // Get server address.
+ TPtrC8 srvAddress;
+ if ( iMessage->GetServerAddress( srvAddress ) )
+ {
+ aSlPushMsgEntry.SetFromL( srvAddress );
+ }
+
+ // First line in Inbox: TMsvEntry::iDetails.
+ if ( srvAddress.Length() == 0 )
+ {
+ // Read from resource.
+ HBufC* details =
+ iStrRscReader->AllocReadResourceLC( R_PUSHMISC_UNK_SENDER );
+ aSlPushMsgEntry.SetMsgDetailsL( *details );
+ CleanupStack::PopAndDestroy( details );
+ }
+ else
+ {
+ // Convert the "From" information to the format required by the UI
+ // spec and then decode it.
+ HBufC* details = iWapPushUtils->ConvertDetailsL( srvAddress );
+ CleanupStack::PushL( details );
+ HBufC* convertedFrom =
+ CPushMtmUtil::ConvertUriToDisplayFormL( *details );
+ CleanupStack::PushL( convertedFrom );
+ //
+ aSlPushMsgEntry.SetMsgDetailsL( *convertedFrom );
+ //
+ CleanupStack::PopAndDestroy( 2, details ); // convertedFrom, details
+ }
+
+ // Second line in Inbox: TMsvEntry::iDescription.
+ // Read from resource.
+ HBufC* description =
+ iStrRscReader->AllocReadResourceLC( R_PUSHMISC_INBOX_SERV_MSG );
+ aSlPushMsgEntry.SetMsgDescriptionL( *description );
+ CleanupStack::PopAndDestroy( description );
+
+ // ******** Push MTM specific processing *********
+
+ /*
+ * Unfortunately in CPushMsgEntryBase there is no such functionality
+ * with which we can reach TMsvEntry as non-const, but we have to
+ * modify the entry's iMtmData2 member somehow. We can do it
+ * with either casting or with modifying and saving the entry
+ * manually after it has been saved by CSLPushMsgEntry. The latter
+ * solution is more expensive so we choose the first.
+ */
+ TMsvEntry& tEntry = CONST_CAST( TMsvEntry&, aSlPushMsgEntry.Entry() );
+ if ( HrefFlag() )
+ {
+ CPushMtmUtil::SetAttrs( tEntry, EPushMtmAttrHasHref );
+ }
+ else
+ {
+ CPushMtmUtil::ResetAttrs( tEntry, EPushMtmAttrHasHref );
+ }
+
+ // Indication is required if the entry is saved as 'read' (delete &
+ // replacement notification). It can happen only in case of SL message.
+ // Otherwise the flag has to be cleared!
+ if ( !iSaveAsRead )
+ {
+ // Saving as unread & new.
+ tEntry.SetNew( ETrue );
+ tEntry.SetUnread( ETrue );
+ CPushMtmUtil::ResetAttrs( tEntry, EPushMtmReadButContentChanged );
+ }
+ else
+ {
+ // Saving as read.
+ tEntry.SetNew( EFalse );
+ tEntry.SetUnread( EFalse );
+ CPushMtmUtil::SetAttrs( tEntry, EPushMtmReadButContentChanged );
+ }
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::SetSlPushMsgEntryFieldsL")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::ProcessingPushMsgEntryL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::ProcessingPushMsgEntryL()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::ProcessingPushMsgEntryL")
+
+ TBool discardPushMsg( EFalse );
+
+ __ASSERT_DEBUG( ActionFlag(),
+ ContHandPanic( EPushContHandPanUnspecSlAction ) );
+
+ // S60 requirement: if the href is empty then delete (discard) the msg.
+ if ( HrefFlag() == EFalse )
+ {
+ PUSHLOG_WRITE(" No SL Href.")
+ discardPushMsg = ETrue;
+ }
+ else
+ {
+ __ASSERT_DEBUG( HrefFlag() && iHrefBuf,
+ ContHandPanic( EPushContHandPanUnspecSlHref ) );
+
+ // The message will not be discarded
+ discardPushMsg = EFalse;
+
+ CMsvEntrySelection* matchingUrlList = iWapPushUtils->FindUrlLC
+ ( *iHrefBuf, KUidWapPushMsgSL );
+ TInt matchingListCount = matchingUrlList->Count();
+ PUSHLOG_WRITE_FORMAT(" matchingListCount: %d",matchingListCount)
+
+ // Only one SL is allowed with the same Url, so leave the first and
+ // delete the others.
+ if ( 1 < matchingListCount )
+ {
+ for ( TInt count = 1; count < matchingListCount; ++count )
+ {
+ iWapPushUtils->DeleteEntryL( matchingUrlList->At(count) );
+ }
+ matchingListCount = 1; // Only one remains.
+ }
+
+ if ( 0 < matchingListCount )
+ {
+ // Find msg of the same href and discard it if it has a lower or
+ // the same action value.
+ CSLPushMsgEntry* matchingSl = CSLPushMsgEntry::NewL();
+ CleanupStack::PushL( matchingSl );
+
+ const TMsvId matchingId = matchingUrlList->At(0);
+ matchingSl->RetrieveL( *iMsvSession, matchingId );
+
+ if ( iPushMsgAction <= matchingSl->Action() )
+ {
+ PUSHLOG_WRITE(" SL: not higher action")
+ discardPushMsg = ETrue;
+ }
+
+ CleanupStack::PopAndDestroy( matchingSl ); // matchingSl,
+ }
+
+ CleanupStack::PopAndDestroy( matchingUrlList ); // matchingUrlList
+ }
+
+ if ( discardPushMsg )
+ {
+ // Nothing to do.
+ PUSHLOG_WRITE(" SL discarded.")
+ iState = EDone;
+ IdleComplete();
+ }
+ else
+ {
+ iState = HandleServiceInvocationL();
+ IdleComplete();
+ }
+
+ __ASSERT_DEBUG( iSavedMsgId == KMsvNullIndexEntryId,
+ ContHandPanic( EPushContHandPanSlMsgIdSet ) );
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::ProcessingPushMsgEntryL")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::HandleServiceInvocationL
+// ---------------------------------------------------------
+//
+TInt CSLContentHandler::HandleServiceInvocationL() const
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::HandleServiceInvocationL")
+
+ TInt nextState = ESavePushMsgEntry;
+
+ if ( iPushMsgAction == CSLPushMsgEntry::ESLPushMsgExecuteCache )
+ {
+ PUSHLOG_WRITE(" SL cache");
+ TBool isAuthenticated = TPushAuthenticationUtil::
+ AuthenticateMsgL( *iMtmSettings, *iMessage );
+ if ( !isAuthenticated )
+ {
+ PUSHLOG_WRITE(" Not authenticated");
+ // The message is placed to Inbox.
+ nextState = ESavePushMsgEntry;
+ }
+ else
+ {
+ // Authenticated. Fetch SL-cache.
+ nextState = EFetching;
+ }
+ }
+
+ else if ( iPushMsgAction == CSLPushMsgEntry::ESLPushMsgExecuteLow )
+ {
+ PUSHLOG_WRITE(" SL execute-low")
+ // It is independent from Automatic/Manual setting and WL
+ // authentication is not applied. The message is placed to Inbox
+ // for manual downloading.
+ nextState = ESavePushMsgEntry;
+ }
+
+ else // ESLPushMsgExecuteHigh
+ {
+ PUSHLOG_WRITE(" SL execute-high");
+ // If the settings is Manual or it does not pass the WL authentication
+ // then it is placed to Inbox for manual downloading.
+ // If the setting is Automatic and it passes the WL authentication,
+ // the Browser is started standalone to download the URL without any
+ // user interaction.
+ if ( iMtmSettings->ServiceLoadingType() ==
+ CPushMtmSettings::EManual )
+ {
+ PUSHLOG_WRITE(" Manual setting")
+ // The message is placed to Inbox.
+ nextState = ESavePushMsgEntry;
+ }
+ else // Automatic loading
+ {
+ PUSHLOG_WRITE(" Automatic setting");
+ // Authenticate the message.
+ TBool isAuthenticated = TPushAuthenticationUtil::
+ AuthenticateMsgL( *iMtmSettings, *iMessage );
+ if ( !isAuthenticated )
+ {
+ PUSHLOG_WRITE(" Not authenticated");
+ // The message is placed to Inbox.
+ nextState = ESavePushMsgEntry;
+ }
+ else
+ {
+ // Authenticated - start downloading.
+ nextState = EFetching;
+ }
+ }
+ }
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::HandleServiceInvocationL")
+ return nextState;
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::FetchPushMsgEntryL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::FetchPushMsgEntryL()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::FetchPushMsgEntryL")
+
+ __ASSERT_DEBUG( iSavedMsgId == KMsvNullIndexEntryId,
+ ContHandPanic( EPushContHandPanAlreadyInitialized ) );
+ __ASSERT_DEBUG( HrefFlag() && iHrefBuf,
+ ContHandPanic( EPushContHandPanUnspecSlHref ) );
+
+ /*
+ * In case of execute-high use the Browser to download the service.
+ * In case of cache use the fetch operation to download the service
+ * silently.
+ */
+
+ if ( iPushMsgAction == CSLPushMsgEntry::ESLPushMsgExecuteHigh )
+ {
+ PUSHLOG_WRITE(" Start Browser")
+ // Launch the Browser with the URI, then save the message.
+ // Trap errors. If Browser's launching fails, then save the
+ // message as 'unread'. In case of an error, it is not forwarded.
+ TRAPD( err, StartBrowserL() );
+ iState = ESavePushMsgEntry;
+ // Mark it 'read' after succesfull Browser startup.
+ iSaveAsRead = err ? EFalse : ETrue;
+ IdleComplete();
+ }
+ else if ( iPushMsgAction == CSLPushMsgEntry::ESLPushMsgExecuteCache )
+ {
+ // Fetch the service inside the content handler.
+ iStatus = KRequestPending;
+ SetActive();
+ __ASSERT_DEBUG( !iFetchOp,
+ ContHandPanic( EPushContHandPanFetchAlreadyInit ) );
+
+ iFetchOp = CPushMtmAutoFetchOperation::NewL( *iHrefBuf,
+ KAutofetchDelayInSec,
+ iStatus );
+ iFetchOp->StartL();
+ PUSHLOG_WRITE(" Fetch op started")
+ iState = EFetchCompleted; // Next state.
+ // Fetch completes it.
+ }
+ else
+ {
+ __ASSERT_DEBUG( EFalse,
+ ContHandPanic( EPushContHandPanBadActionValue ) );
+ User::Leave( KErrNotSupported );
+ }
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::FetchPushMsgEntryL")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::StartBrowserL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::StartBrowserL()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::StartBrowserL")
+
+ // Parameters are separated by space
+ // 1st parameter: type of the further parameters
+ // 2nd parameter: URL
+ //
+ HBufC* param = HBufC::NewLC( KBrowserCmdFetchUrl().Length() +
+ iHrefBuf->Length() );
+ TPtr paramPtr = param->Des();
+ paramPtr.Copy( KBrowserCmdFetchUrl );
+ paramPtr.Append( *iHrefBuf );
+
+ RWsSession wsSession;
+ User::LeaveIfError( wsSession.Connect() );
+ CleanupClosePushL<RWsSession>( wsSession );
+ TApaTaskList taskList( wsSession );
+ TApaTask task = taskList.FindApp( KBrowserAppUid );
+
+ if ( task.Exists() )
+ {
+ PUSHLOG_WRITE("CSLContentHandler Browser::SendMessage")
+
+ RFs rfs;
+ RFile file;
+ TPtrC8 param8Ptr;
+ // 8-bit buffer is required.
+ HBufC8* param8 = HBufC8::NewLC( param->Length() );
+ param8->Des().Copy( *param );
+ param8Ptr.Set(param8->Des());
+
+ // Open the file.
+ User::LeaveIfError(rfs.Connect());
+ CleanupClosePushL(rfs);
+
+ // Replace file if exists or Create file if not exist yet
+ User::LeaveIfError( file.Replace( rfs, KPushMtmUrl, EFileWrite | EFileShareExclusive ) );
+ CleanupClosePushL(file);
+
+ // Write to file
+ User::LeaveIfError( file.Write( param8Ptr ) );
+
+ // Clean up.
+ CleanupStack::PopAndDestroy(/*file*/);
+ CleanupStack::PopAndDestroy(/*rfs*/);
+ CleanupStack::PopAndDestroy( /*param8*/ );
+ }
+ else
+ {
+ PUSHLOG_WRITE("CSLContentHandler Browser::StartDocument")
+ RApaLsSession appArcSession;
+ User::LeaveIfError( appArcSession.Connect() );
+ CleanupClosePushL<RApaLsSession>( appArcSession );
+ TThreadId id;
+ User::LeaveIfError
+ (
+ appArcSession.StartDocument( *param, KBrowserAppUid, id )
+ );
+ CleanupStack::PopAndDestroy( &appArcSession );
+ }
+
+ CleanupStack::PopAndDestroy( &wsSession );
+ CleanupStack::PopAndDestroy( param );
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::StartBrowserL")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::FetchCompletedL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::FetchCompletedL()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::FetchCompletedL")
+
+ __ASSERT_DEBUG( iPushMsgAction == CSLPushMsgEntry::ESLPushMsgExecuteCache,
+ ContHandPanic( EPushContHandPanBadActionValue ) );
+ __ASSERT_DEBUG( iSavedMsgId == KMsvNullIndexEntryId,
+ ContHandPanic( EPushContHandPanAlreadyInitialized ) );
+ __ASSERT_DEBUG( iFetchOp, ContHandPanic( EPushContHandPanNoFetchOp ) );
+
+ const TInt fetchRes = iStatus.Int();
+ PUSHLOG_WRITE_FORMAT(" fetchRes <%d>",fetchRes)
+
+ if ( fetchRes != KErrNone )
+ {
+ // Downloading failed. Save the message.
+ iState = ESavePushMsgEntry;
+ }
+ else
+ {
+ // Silent fetching has completed successfully.
+ // The message should not be saved.
+ iState = EDone;
+ }
+
+ // Next state set. Complete.
+ IdleComplete();
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::FetchCompletedL")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::SavePushMsgEntryL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::SavePushMsgEntryL()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::SavePushMsgEntryL")
+
+ __ASSERT_DEBUG( ActionFlag(),
+ ContHandPanic( EPushContHandPanUnspecSlAction ) );
+ __ASSERT_DEBUG( HrefFlag() && iHrefBuf,
+ ContHandPanic( EPushContHandPanUnspecSlHref ) );
+ __ASSERT_DEBUG( iSavedMsgId == KMsvNullIndexEntryId,
+ ContHandPanic( EPushContHandPanAlreadyInitialized ) );
+
+ CMsvEntrySelection* matchingUrlList = iWapPushUtils->FindUrlLC
+ ( *iHrefBuf, KUidWapPushMsgSL );
+ TInt matchingListCount = matchingUrlList->Count();
+ PUSHLOG_WRITE_FORMAT(" matchingListCount: %d",matchingListCount)
+
+ // Only one SL is allowed with the same Url, so leave the first and
+ // delete the others.
+ __ASSERT_DEBUG( matchingListCount <= 1,
+ ContHandPanic( EPushContHandPanTooManySl ) );
+ if ( 1 < matchingListCount )
+ {
+ for ( TInt count = 1; count < matchingListCount; ++count )
+ {
+ iWapPushUtils->DeleteEntryL( matchingUrlList->At(count) );
+ }
+ matchingListCount = 1; // Only one remains.
+ }
+
+ TBool saveNewMsg = ETrue; // Save by default.
+ TMsvId matchingEntryId = KMsvNullIndexEntryId;
+
+ // Apply reception rules.
+ if ( matchingListCount == 0 )
+ {
+ // Nothing to do.
+ saveNewMsg = ETrue;
+ }
+ else
+ {
+ CSLPushMsgEntry* matchingSl = CSLPushMsgEntry::NewL();
+ CleanupStack::PushL( matchingSl );
+
+ matchingEntryId = matchingUrlList->At(0);
+ matchingSl->RetrieveL( *iMsvSession, matchingEntryId );
+
+ if ( iPushMsgAction <= matchingSl->Action() )
+ {
+ // Discard the new SL: it does not have higher
+ // action value as the existing.
+ PUSHLOG_WRITE(" SL not higher action - discarded")
+ saveNewMsg = EFalse;
+ }
+ else
+ {
+ // The new has greater action attribute.
+ // Update the old SL with the new data.
+ saveNewMsg = ETrue;
+ }
+
+ CleanupStack::PopAndDestroy( matchingSl ); // matchingSl
+ }
+
+ CleanupStack::PopAndDestroy( matchingUrlList ); // matchingUrlList
+
+ // Store message if not marked for deletion.
+ if ( saveNewMsg )
+ {
+ StoreSLMessageL( matchingEntryId );
+ }
+
+ iState = EDone;
+ IdleComplete();
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::SavePushMsgEntryL")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::StoreSLMessageL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::StoreSLMessageL( TMsvId aMatchingEntryId )
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::StoreSLMessageL")
+
+ CSLPushMsgEntry* slEntry = CSLPushMsgEntry::NewL();
+ CleanupStack::PushL( slEntry );
+
+ if ( aMatchingEntryId == KMsvNullIndexEntryId )
+ {
+ PUSHLOG_WRITE(" No matching SL")
+ // Save new to Inbox.
+ SetSlPushMsgEntryFieldsL( *slEntry );
+ iSavedMsgId =
+ slEntry->SaveL( *iMsvSession, KMsvGlobalInBoxIndexEntryId );
+ // Set the entry to read and *not* new state depending on iSaveAsRead.
+ if ( !iSaveAsRead )
+ {
+ // Do nothing SaveL saves it as unread.
+ }
+ else
+ {
+ // SaveL owerrides the read settings (iEntry.SetUnread(ETrue);)
+ // that we set in SetSlPushMsgEntryFieldsL, thus the read status
+ // has to be reset manually here:
+ iWapPushUtils->MarkServiceUnreadL( iSavedMsgId, EFalse );
+ }
+ }
+ else
+ {
+ PUSHLOG_WRITE(" Matching SL")
+ slEntry->RetrieveL( *iMsvSession, aMatchingEntryId );
+ SetSlPushMsgEntryFieldsL( *slEntry );
+
+ slEntry->UpdateL( *iMsvSession );
+ iSavedMsgId = aMatchingEntryId;
+ // Note that UpdateL does not change the read/unread status.
+
+ // Move the updated msg back to Inbox.
+ TMsvId parentId = slEntry->Entry().Parent();
+ if ( parentId != KMsvGlobalInBoxIndexEntryId )
+ {
+ PUSHLOG_WRITE(" Moving back to Inbox")
+ CMsvEntry* cParent = iMsvSession->GetEntryL( parentId );
+ CleanupStack::PushL( cParent );
+ cParent->MoveL( iSavedMsgId, KMsvGlobalInBoxIndexEntryId );
+ CleanupStack::PopAndDestroy( cParent ); // cParent
+ }
+ }
+
+#ifdef __TEST_LOG__
+ _LIT( KDateFormat, "%E%D%X%N%Y %1 %2 %3" );
+ _LIT( KTimeFormat, "%-B%:0%J%:1%T%:2%S%:3%+B" );
+ TBuf<32> dateHolder;
+ TBuf<32> timeHolder;
+ TTime recDateTime = slEntry->ReceivedDate();
+ recDateTime.FormatL( dateHolder, KDateFormat );
+ recDateTime.FormatL( timeHolder, KTimeFormat );
+ PUSHLOG_WRITE_FORMAT(" rec date: <%S>",&dateHolder)
+ PUSHLOG_WRITE_FORMAT(" rec time: <%S>",&timeHolder)
+#endif // __TEST_LOG__
+
+ CleanupStack::PopAndDestroy( slEntry ); // slEntry
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::StoreSLMessageL")
+ }
+
+
+// ---------------------------------------------------------
+// CSLContentHandler::HandleMessageL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::HandleMessageL( CPushMessage* aPushMsg,
+ TRequestStatus& aStatus )
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::HandleMessageL 2")
+
+ __ASSERT_DEBUG( aPushMsg != NULL,
+ ContHandPanic( EPushContHandPanMsgNull ) );
+
+#ifdef __TEST_LOG__
+ TPtrC8 bodyPtr;
+ aPushMsg->GetMessageBody( bodyPtr );
+ PUSHLOG_HEXDUMP( bodyPtr )
+#endif // __TEST_LOG__
+
+ iMessage = aPushMsg;
+ iAcknowledge = ETrue;
+ SetConfirmationStatus( aStatus );
+
+ iState = EGarbageCollecting;
+ IdleComplete();
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::HandleMessageL 2")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::HandleMessageL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::HandleMessageL( CPushMessage* aPushMsg )
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::HandleMessageL 1")
+
+ __ASSERT_DEBUG( aPushMsg != NULL,
+ ContHandPanic( EPushContHandPanMsgNull ) );
+
+#ifdef __TEST_LOG__
+ TPtrC8 bodyPtr;
+ aPushMsg->GetMessageBody( bodyPtr );
+ PUSHLOG_HEXDUMP( bodyPtr )
+#endif // __TEST_LOG__
+
+ iAcknowledge = EFalse;
+ iMessage = aPushMsg;
+
+ iState = EGarbageCollecting;
+ IdleComplete();
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::HandleMessageL 1")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::CancelHandleMessage
+// ---------------------------------------------------------
+//
+void CSLContentHandler::CancelHandleMessage()
+ {
+ Cancel();
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::CPushHandlerBase_Reserved1
+// ---------------------------------------------------------
+//
+void CSLContentHandler::CPushHandlerBase_Reserved1()
+ {
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::CPushHandlerBase_Reserved1
+// ---------------------------------------------------------
+//
+void CSLContentHandler::CPushHandlerBase_Reserved2()
+ {
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::DoCancel
+// ---------------------------------------------------------
+//
+void CSLContentHandler::DoCancel()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::DoCancel")
+ // TODO Cancel outstanding requests!
+ Complete( KErrCancel );
+ PUSHLOG_LEAVEFN("CSLContentHandler::DoCancel")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::RunL
+// ---------------------------------------------------------
+//
+void CSLContentHandler::RunL()
+ {
+ PUSHLOG_ENTERFN("CSLContentHandler::RunL")
+
+ // Handle errors in RunError().
+ PUSHLOG_WRITE_FORMAT(" iStatus.Int(): %d",iStatus.Int())
+
+ switch ( iState )
+ {
+ case EGarbageCollecting:
+ {
+ CollectGarbageL();
+ break;
+ }
+
+
+ case EFilteringAndParsing:
+ {
+ if(iPushSLEnabled)
+ {
+ if ( !FilterPushMsgL() )
+ {
+ // It did not pass the filter. Done.
+ iState = EDone;
+ IdleComplete();
+ }
+ else
+ {
+ // Continue.
+ TInt ret = KErrNone;
+ PUSHLOG_WRITE("CSLContentHandler::RunL : before trapping parsing.")
+ TRAP(ret, ParsePushMsgL());
+ PUSHLOG_WRITE_FORMAT("CSLContentHandler::RunL : after trapping parsing. ret = %d", ret)
+ if ( ret != KErrNone)
+ {
+ PUSHLOG_WRITE("CSLContentHandler::RunL : Parsing failed. discarding message.")
+ iState = EDone;
+ IdleComplete();
+ }
+ }
+ }
+ break;
+ }
+
+ case EProcessing:
+ {
+ if(iPushSLEnabled)
+ ProcessingPushMsgEntryL();
+ break;
+ }
+
+ case EFetching:
+ {
+ if(iPushSLEnabled)
+ FetchPushMsgEntryL();
+ break;
+ }
+
+ case EFetchCompleted:
+ {
+ if(iPushSLEnabled)
+ FetchCompletedL();
+ break;
+ }
+
+ case ESavePushMsgEntry:
+ {
+ if(iPushSLEnabled)
+ SavePushMsgEntryL();
+ break;
+ }
+
+
+ case EDone:
+ {
+ PUSHLOG_WRITE("CSLContentHandler EDone")
+ Complete( KErrNone );
+ break;
+ }
+ default:
+ {
+ // JIC.
+ PUSHLOG_WRITE("CSLContentHandler default EDone")
+ Complete( KErrNone );
+ break;
+ }
+ }
+
+ PUSHLOG_LEAVEFN("CSLContentHandler::RunL")
+ }
+
+// ---------------------------------------------------------
+// CSLContentHandler::RunError
+// ---------------------------------------------------------
+//
+TInt CSLContentHandler::RunError( TInt aError )
+ {
+ PUSHLOG_WRITE_FORMAT("CSLContentHandler::RunError: %d",aError)
+
+ iState = EDone;
+ Complete( aError );
+ return KErrNone;
+ }
+