pushmtm/Plugins/PushContentHandler/CSIContentHandler.cpp
branchRCL_3
changeset 69 4455192101e4
parent 65 8e6fa1719340
equal deleted inserted replaced
65:8e6fa1719340 69:4455192101e4
     1 /*
       
     2 * Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Implementation of CSIContentHandler.
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 // INCLUDE FILES
       
    21 
       
    22 #include "CSIContentHandler.h"
       
    23 #include "PushMtmUtil.h"
       
    24 #include "PushMtmSettings.h"
       
    25 #include "PushMtmLog.h"
       
    26 #include "PushMtmUiDef.h"
       
    27 #include "StringResourceReader.h"
       
    28 #include "PushContentHandlerPanic.h"
       
    29 #include "si_dict.h"
       
    30 #include "PushContentHandlerUtils.h"
       
    31 #include <push/CSIPushMsgEntry.h>
       
    32 #include <msvids.h>
       
    33 #include <PushMtmUi.rsg>
       
    34 #include <nw_dom_node.h>
       
    35 #include <nw_dom_document.h>
       
    36 #include <nw_dom_element.h>
       
    37 #include <nw_dom_text.h>
       
    38 #include <nw_wbxml_dictionary.h>
       
    39 #include <THttpFields.h>
       
    40 
       
    41 // CONSTANTS
       
    42 
       
    43 // si attributes / elements
       
    44 _LIT8( KSi,          "si" );
       
    45 _LIT8( KIndication,  "indication" );
       
    46 _LIT8( KHrefAttrib,  "href" );
       
    47 _LIT8( KSiIdAttrib,  "si-id" );
       
    48 _LIT8( KCreatedAttrib,   "created" );
       
    49 _LIT8( KExpiresAttrib,   "si-expires" );
       
    50 _LIT8( KActionAttrib,    "action" );
       
    51 
       
    52 // action attribute literals
       
    53 _LIT8( KDeleteAction,    "delete" );
       
    54 _LIT8( KSignalNone,      "signal-none" );
       
    55 _LIT8( KSignalLow,       "signal-low" );
       
    56 _LIT8( KSignalMedium,    "signal-medium" );
       
    57 _LIT8( KSignalHigh,      "signal-high" );
       
    58 
       
    59 _LIT( KSiTextContentType, "text/vnd.wap.si" );
       
    60 
       
    61 const TInt KValidMaxEncodedDateTimeSize = 7;
       
    62 const TInt KValidUTCLength = 20; // YYYY-MM-DDTHH:MM:SSZ
       
    63 const TInt KValidUTCNumericals = 14;
       
    64 const TInt KValidUTCYearBlockLength = 4;
       
    65 const TInt KValidUTCOtherBlockLength = 2;
       
    66 const TUint8 KAsciiZeroCharCode = 0x30;
       
    67 
       
    68 const TInt KValidTTimeMonthStart = 4;
       
    69 const TInt KValidTTimeDayStart = 6;
       
    70 const TInt KValidTTimeHourStart = 8;
       
    71 const TInt KValidTTimeMinuteStart = 10;
       
    72 const TInt KValidTTimeSecondStart = 12;
       
    73 const TInt KValidTTimeBlockLength = 2;
       
    74 
       
    75 const TInt KValidTTimeLength = 14; // YYYYMMDDHHMMSS
       
    76 
       
    77 const TInt KNoOfDictArrays = 1;
       
    78 
       
    79 _LIT( KCharMinus, "-" );
       
    80 _LIT( KCharT, "T" );
       
    81 _LIT( KCharColon, ":" );
       
    82 _LIT( KCharZ, "Z" );
       
    83 
       
    84 /// Conversion buffer size.
       
    85 LOCAL_D const TInt KPushConversionBufferSize = 256;
       
    86 /// Zero width non-breaking space character.
       
    87 LOCAL_D const TUint16 KPushZeroWidthNbsp = 0xfeff;
       
    88 
       
    89 // ================= MEMBER FUNCTIONS =======================
       
    90 
       
    91 // ---------------------------------------------------------
       
    92 // CSIContentHandler::NewL
       
    93 // ---------------------------------------------------------
       
    94 //
       
    95 CSIContentHandler* CSIContentHandler::NewL()
       
    96 	{
       
    97     PUSHLOG_ENTERFN("CSIContentHandler::NewL")
       
    98 
       
    99 	CSIContentHandler* self = new (ELeave) CSIContentHandler;
       
   100 	CleanupStack::PushL( self );
       
   101 	self->ConstructL();
       
   102 	CleanupStack::Pop( self );
       
   103 
       
   104     PUSHLOG_LEAVEFN("CSIContentHandler::NewL")
       
   105 	return self;
       
   106 	}
       
   107 
       
   108 // ---------------------------------------------------------
       
   109 // CSIContentHandler::~CSIContentHandler
       
   110 // ---------------------------------------------------------
       
   111 //
       
   112 CSIContentHandler::~CSIContentHandler()
       
   113 	{
       
   114     PUSHLOG_ENTERFN("CSIContentHandler::~CSIContentHandler")
       
   115 
       
   116     Cancel();
       
   117 	delete iHrefBuf;
       
   118 	delete iSiIdBuf;
       
   119 	delete iData;
       
   120     delete iCharacterSetConverter;
       
   121     iCharacterSetConverter = NULL;
       
   122     delete iCharacterSetsAvailable;
       
   123     iCharacterSetsAvailable = NULL;
       
   124 
       
   125     PUSHLOG_LEAVEFN("CSIContentHandler::~CSIContentHandler")
       
   126 	}
       
   127 
       
   128 // ---------------------------------------------------------
       
   129 // CSIContentHandler::CSIContentHandler
       
   130 // ---------------------------------------------------------
       
   131 //
       
   132 CSIContentHandler::CSIContentHandler()
       
   133 :   CPushContentHandlerBase(),
       
   134     iSavedMsgId( KMsvNullIndexEntryId ),
       
   135     iPushMsgAction( KErrNotFound ),
       
   136     iExpiresTime( Time::NullTTime() ),
       
   137     iCreatedTime( Time::NullTTime() )
       
   138 	{
       
   139 	}
       
   140 
       
   141 // ---------------------------------------------------------
       
   142 // CSIContentHandler::ConstructL
       
   143 // ---------------------------------------------------------
       
   144 //
       
   145 void CSIContentHandler::ConstructL()
       
   146 	{
       
   147     PUSHLOG_ENTERFN("CSIContentHandler::ConstructL")
       
   148 
       
   149     CPushContentHandlerBase::ConstructL();
       
   150     // Added to Active Scheduler.
       
   151 
       
   152     PUSHLOG_LEAVEFN("CSIContentHandler::ConstructL")
       
   153     }
       
   154 
       
   155 // ---------------------------------------------------------
       
   156 // CSIContentHandler::CollectGarbageL
       
   157 // ---------------------------------------------------------
       
   158 //
       
   159 void CSIContentHandler::CollectGarbageL()
       
   160 	{
       
   161     PUSHLOG_ENTERFN("CSIContentHandler::CollectGarbageL")
       
   162 
       
   163     DoCollectGarbageL();
       
   164 
       
   165     //Ready.
       
   166     iState = EFilteringAndParsing;
       
   167 	IdleComplete();
       
   168 
       
   169     PUSHLOG_LEAVEFN("CSIContentHandler::CollectGarbageL")
       
   170     }
       
   171 
       
   172 // ---------------------------------------------------------
       
   173 // CSIContentHandler::ParsePushMsgL
       
   174 // Note that cXML parser dosn't do any validation!
       
   175 // ---------------------------------------------------------
       
   176 //
       
   177 void CSIContentHandler::ParsePushMsgL()
       
   178 	{
       
   179     PUSHLOG_ENTERFN("CSIContentHandler::ParsePushMsgL")
       
   180 
       
   181     TPtrC8 bodyPtr;
       
   182     iMessage->GetMessageBody( bodyPtr );
       
   183     // If there is no body in the message leave with an error
       
   184     if ( bodyPtr.Size() == 0 )
       
   185         {
       
   186         PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: Empty body")
       
   187         User::Leave( KErrCorrupt );
       
   188         }
       
   189 
       
   190     // Get content type. It will tell us wheather the msg body is encoded or
       
   191     // textual.
       
   192     TPtrC contentType;
       
   193 	iMessage->GetContentType( contentType );
       
   194     PUSHLOG_WRITE_FORMAT("CSIContentHandler::ParsePushMsgL: HTTP header - Content type <%S>",&contentType);
       
   195 
       
   196     /*
       
   197     TPtrC8 encodingPtr;
       
   198     TBool encodingFound = iMessage->GetHeaderField
       
   199                           ( EHttpContentEncoding, encodingPtr );
       
   200     #ifdef __TEST_LOG__
       
   201     TBuf<64> encodingBuf;
       
   202     encodingBuf.Copy( encodingPtr );
       
   203     PUSHLOG_WRITE_FORMAT(" HTTP header - Content encoding <%S>",&encodingBuf);
       
   204     #endif // __TEST_LOG__
       
   205     */
       
   206 
       
   207     // Add SI dictionary.
       
   208     NW_WBXML_Dictionary_t* dictArray[ KNoOfDictArrays ] =
       
   209         { (NW_WBXML_Dictionary_t*)&NW_SI_WBXMLDictionary };
       
   210 
       
   211     NW_Status_t stat = NW_STAT_SUCCESS;
       
   212 
       
   213     RWbxmlDictionary wbxmlDict;
       
   214     wbxmlDict.InitializeL( KNoOfDictArrays, dictArray );
       
   215     CleanupClosePushL<RWbxmlDictionary>( wbxmlDict );
       
   216 
       
   217     NW_TinyDom_Handle_t domHandle;
       
   218     NW_Byte* buffer = (NW_Byte*)bodyPtr.Ptr();
       
   219     NW_Int32 length = (NW_Int32)bodyPtr.Size();
       
   220     // Let's use the content type now.
       
   221     NW_Bool encoded = ( contentType.CompareF( KSiTextContentType ) == 0 ) ?
       
   222                                                          NW_FALSE : NW_TRUE;
       
   223     // SI public identifier.
       
   224     NW_Uint32 publicID = NW_SI_PublicId;
       
   225     NW_Bool extTNotStringTable = NW_FALSE;
       
   226     NW_DOM_NodeType_t type = 0;
       
   227     /**********************************
       
   228     *   Root of DOM
       
   229     ***********************************/
       
   230     CDocumentTreeOwner* docTreeOwner = new (ELeave) CDocumentTreeOwner;
       
   231     CleanupStack::PushL( docTreeOwner );
       
   232     NW_DOM_DocumentNode_t* domNode = NW_DOM_DocumentNode_BuildTree
       
   233         (
       
   234                             &domHandle,
       
   235                             buffer,
       
   236                             length,
       
   237                             encoded,
       
   238                             publicID,
       
   239                             extTNotStringTable
       
   240         );
       
   241 	if (!domNode)
       
   242 		{
       
   243 		PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: domNode is Null")
       
   244 		}
       
   245     User::LeaveIfNull( domNode );
       
   246 	PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: domNode is not Null") // to be deleted
       
   247     // Let domNode be on the Cleanup Stack.
       
   248     docTreeOwner->SetDocTree( domNode );
       
   249 
       
   250     // It must be a document node.
       
   251     type = NW_DOM_Node_getNodeType( domNode );
       
   252     if ( type != NW_DOM_DOCUMENT_NODE )
       
   253         {
       
   254         PUSHLOG_WRITE_FORMAT("CSIContentHandler::ParsePushMsgL: Not Document node <%d>",type)
       
   255         User::Leave( KErrArgument );
       
   256         }
       
   257 
       
   258     // Get character encoding (NW_Uint32)
       
   259     iCharEncoding = NW_DOM_DocumentNode_getCharacterEncoding( domNode );
       
   260     PUSHLOG_WRITE_FORMAT("CSIContentHandler::ParsePushMsgL: Doc char encoding <%x>",iCharEncoding)
       
   261 
       
   262     /**********************************
       
   263     *   ELEMENT si
       
   264     ***********************************/
       
   265     // Get the first element of the document that must be an si.
       
   266 	// first make sure if there any children in the dom tree, otherwise we will PANIC(in NW_DOM_DocumentNode_getDocumentElement) and crash WatcherMainThread.
       
   267 	TBool domNodeHasChildNodes = EFalse;
       
   268 	domNodeHasChildNodes = NW_DOM_Node_hasChildNodes( domNode );
       
   269 	PUSHLOG_WRITE_FORMAT("CSIContentHandler::ParsePushMsgL: check if Dom tree has <SI> node <%d>", domNodeHasChildNodes)
       
   270 	if (!domNodeHasChildNodes)
       
   271         {
       
   272         PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: No SI element present in the dom tree. Message corrupted.")
       
   273         User::Leave( KErrCorrupt );
       
   274         }
       
   275 
       
   276 	PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: before calling getDocumentElement")
       
   277     NW_DOM_ElementNode_t* siElement =
       
   278         NW_DOM_DocumentNode_getDocumentElement( domNode );
       
   279 	PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: after calling getDocumentElement")
       
   280 	if (!siElement)
       
   281 		{
       
   282 		PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: siElement is Null")
       
   283 		}
       
   284 	PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: siElement is not Null, before leaving")
       
   285     User::LeaveIfNull( siElement );
       
   286 	PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: siElement is not Null, after leaving if siElement is null")
       
   287 
       
   288     type = NW_DOM_Node_getNodeType( siElement );
       
   289 
       
   290     CStringOwner* stringOwner = new (ELeave) CStringOwner;
       
   291     CleanupStack::PushL( stringOwner );
       
   292 
       
   293     NW_String_t* name = NW_String_new();
       
   294     User::LeaveIfNull( name );
       
   295     // Let name be on the Cleanup Stack.
       
   296     stringOwner->SetString( name );
       
   297     stat = NW_DOM_Node_getNodeName( siElement, name );
       
   298     User::LeaveIfError( NwxStatusToErrCode( stat ) );
       
   299     NW_Byte*  nameBuf = NW_String_getStorage( name );
       
   300     NW_Uint16 nameLen = NW_String_getCharCount( name, iCharEncoding );
       
   301     TPtrC8 namePtr( nameBuf, nameLen );
       
   302 
       
   303     // Now comes the validity check.
       
   304     if ( type != NW_DOM_ELEMENT_NODE || namePtr.CompareF( KSi ) != 0 )
       
   305         {
       
   306         PUSHLOG_WRITE_FORMAT("CSIContentHandler::ParsePushMsgL: Not si element node <%d>",type)
       
   307         User::Leave( KErrArgument );
       
   308         }
       
   309 
       
   310     CleanupStack::PopAndDestroy( stringOwner ); // stringOwner
       
   311 
       
   312     /**********************************
       
   313     *   ELEMENT indication
       
   314     ***********************************/
       
   315     if ( NW_DOM_Node_hasChildNodes( siElement ) )
       
   316         {
       
   317         NW_DOM_Node_t* node = NW_DOM_Node_getFirstChild( siElement );
       
   318 		if (!node)
       
   319 			{
       
   320 			PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: no si child nodes!")
       
   321 			}
       
   322         User::LeaveIfNull( node );
       
   323 
       
   324         // Find the indication element.
       
   325         TBool indicationFound = EFalse;
       
   326         do {
       
   327             type = NW_DOM_Node_getNodeType( node );
       
   328 
       
   329             CStringOwner* stringOwner = new (ELeave) CStringOwner;
       
   330             CleanupStack::PushL( stringOwner );
       
   331 
       
   332             NW_String_t* name = NW_String_new();
       
   333             User::LeaveIfNull( name );
       
   334             stringOwner->SetString( name );
       
   335             stat = NW_DOM_Node_getNodeName( node, name );
       
   336 			PUSHLOG_WRITE_FORMAT("CSIContentHandler::ParsePushMsgL: getNodeName ErrCode: %d", NwxStatusToErrCode( stat ))
       
   337             User::LeaveIfError( NwxStatusToErrCode( stat ) );
       
   338             NW_Byte*  nameBuf = NW_String_getStorage( name );
       
   339             NW_Uint16 nameLen = NW_String_getCharCount( name,
       
   340                                                         iCharEncoding );
       
   341             TPtrC8 namePtr( nameBuf, nameLen );
       
   342 
       
   343             if ( type == NW_DOM_ELEMENT_NODE &&
       
   344                  namePtr.CompareF( KIndication ) == 0 )
       
   345                 {
       
   346                 // We found the indication element. Parse it.
       
   347                 PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: indication under si found.")
       
   348                 indicationFound = ETrue;
       
   349                 NW_DOM_ElementNode_t* indicationElement =
       
   350                     REINTERPRET_CAST( NW_DOM_ElementNode_t*, node );
       
   351                 ParseIndicationL( *indicationElement );
       
   352                 }
       
   353 
       
   354             CleanupStack::PopAndDestroy( stringOwner ); // stringOwner
       
   355 
       
   356             if ( !indicationFound )
       
   357                 {
       
   358                 // Iterate next.
       
   359                 node = NW_DOM_Node_getNextSibling( node );
       
   360                 if ( !node )
       
   361                     {
       
   362                     PUSHLOG_WRITE("CSIContentHandler::ParsePushMsgL: No more sibling.")
       
   363                     break;
       
   364                     }
       
   365                 }
       
   366 
       
   367             } while ( !indicationFound );
       
   368         }
       
   369 
       
   370     // Cleanup.
       
   371     CleanupStack::PopAndDestroy( 2, &wbxmlDict ); // docTreeOwner, wbxmlDict
       
   372 
       
   373     if ( !ActionFlag() )
       
   374         {
       
   375         // default if no action explicitly stated
       
   376         iPushMsgAction = CSIPushMsgEntry::ESIPushMsgSignalMedium;
       
   377         SetActionFlag( ETrue );
       
   378         PUSHLOG_WRITE_FORMAT("CSIContentHandler::ParsePushMsgL: Defaulting to ActionFlag: %d",iPushMsgAction)
       
   379         }
       
   380 
       
   381     iState = EProcessing;
       
   382 	IdleComplete();
       
   383 
       
   384     PUSHLOG_LEAVEFN("CSIContentHandler::ParsePushMsgL")
       
   385 	}
       
   386 
       
   387 // ---------------------------------------------------------
       
   388 // CSIContentHandler::ParseIndicationL
       
   389 // ---------------------------------------------------------
       
   390 //
       
   391 void CSIContentHandler::ParseIndicationL( NW_DOM_ElementNode_t& aIndication )
       
   392 	{
       
   393     PUSHLOG_ENTERFN("CSIContentHandler::ParseIndicationL")
       
   394 
       
   395     NW_Status_t stat = NW_STAT_SUCCESS;
       
   396     NW_DOM_NodeType_t type = 0;
       
   397 
       
   398     if ( NW_DOM_ElementNode_hasAttributes( &aIndication ) )
       
   399         {
       
   400         NW_DOM_AttributeListIterator_t attrIter;
       
   401         stat = NW_DOM_ElementNode_getAttributeListIterator
       
   402                              ( &aIndication, &attrIter );
       
   403 		PUSHLOG_WRITE_FORMAT("CSIContentHandler::ParseIndicationL: getAttribListIter ErrCode: %d", NwxStatusToErrCode( stat ))
       
   404         User::LeaveIfError( NwxStatusToErrCode( stat ) );
       
   405 
       
   406         NW_DOM_AttributeHandle_t attrHandle;
       
   407         while ( NW_DOM_AttributeListIterator_getNextAttribute
       
   408                 ( &attrIter, &attrHandle ) == NW_STAT_WBXML_ITERATE_MORE )
       
   409             {
       
   410             ParseIndAttributeL( attrHandle );
       
   411             }
       
   412         }
       
   413 
       
   414     /**********************************
       
   415     *   PCDATA of ELEMENT indication
       
   416     ***********************************/
       
   417     if ( NW_DOM_Node_hasChildNodes( &aIndication ) )
       
   418         {
       
   419         NW_DOM_TextNode_t* textNode =
       
   420             NW_DOM_Node_getFirstChild( &aIndication );
       
   421         User::LeaveIfNull( textNode );
       
   422 
       
   423         type = NW_DOM_Node_getNodeType( textNode );
       
   424         if ( type != NW_DOM_TEXT_NODE )
       
   425             {
       
   426             PUSHLOG_WRITE_FORMAT("CSIContentHandler::ParseIndicationL: Not text node <%d>",type)
       
   427             User::Leave( KErrArgument );
       
   428             }
       
   429 
       
   430         ParseTextL( *textNode );
       
   431         }
       
   432 
       
   433     PUSHLOG_LEAVEFN("CSIContentHandler::ParseIndicationL")
       
   434     }
       
   435 
       
   436 // ---------------------------------------------------------
       
   437 // CSIContentHandler::ParseIndAttributeL
       
   438 // ---------------------------------------------------------
       
   439 //
       
   440 void CSIContentHandler::ParseIndAttributeL( NW_DOM_AttributeHandle_t&
       
   441                                             aAttrHandle )
       
   442 	{
       
   443     PUSHLOG_ENTERFN("CSIContentHandler::ParseIndAttributeL")
       
   444 
       
   445     NW_Status_t stat = NW_STAT_SUCCESS;
       
   446 
       
   447     CStringOwner* stringOwner = new (ELeave) CStringOwner;
       
   448     CleanupStack::PushL( stringOwner );
       
   449 
       
   450     NW_String_t* attrName = NW_String_new();
       
   451     User::LeaveIfNull( attrName );
       
   452     stringOwner->SetString( attrName );
       
   453 
       
   454     // Get the name of the attribute.
       
   455     stat = NW_DOM_AttributeHandle_getName( &aAttrHandle, attrName );
       
   456     User::LeaveIfError( NwxStatusToErrCode( stat ) );
       
   457     NW_Byte*  attrNameBuf = NW_String_getStorage( attrName );
       
   458     NW_Uint16 attrNameLen = NW_String_getCharCount( attrName, iCharEncoding );
       
   459     TPtrC8 attrNamePtr( attrNameBuf, attrNameLen );
       
   460 
       
   461     if ( attrNamePtr.CompareF( KCreatedAttrib ) == 0 )
       
   462         {
       
   463         if ( CreatedFlag() )
       
   464             {
       
   465             PUSHLOG_WRITE(" created redefinition")
       
   466             User::Leave( KErrCorrupt );
       
   467             }
       
   468         else
       
   469             {
       
   470             TBool gotDate = AttributeToTTimeL( aAttrHandle, iCreatedTime );
       
   471             SetCreatedFlag( gotDate );
       
   472             PUSHLOG_WRITE_FORMAT(" iCreatedTime set %d",gotDate?1:0)
       
   473             }
       
   474         }
       
   475     else if ( attrNamePtr.CompareF( KHrefAttrib ) == 0 )
       
   476         {
       
   477         if ( HrefFlag() )
       
   478             {
       
   479             PUSHLOG_WRITE(" href redefinition")
       
   480             User::Leave( KErrCorrupt );
       
   481             }
       
   482         else
       
   483             {
       
   484             CStringOwner* stringOwner = new (ELeave) CStringOwner;
       
   485             CleanupStack::PushL( stringOwner );
       
   486 
       
   487             NW_String_t* val = NW_String_new();
       
   488             User::LeaveIfNull( val );
       
   489             stringOwner->SetString( val );
       
   490             stat = NW_DOM_AttributeHandle_getValue( &aAttrHandle, val );
       
   491             if ( stat != NW_STAT_DOM_NO_STRING_RETURNED )
       
   492                 {
       
   493                 User::LeaveIfError( NwxStatusToErrCode( stat ) );
       
   494                 NW_Byte* storage = NW_String_getStorage( val );
       
   495                 NW_Uint16 length = NW_String_getCharCount( val,
       
   496                                                            iCharEncoding );
       
   497                 if ( length == 0 )
       
   498                     {
       
   499                     // Zero length href attribute is considered as missing.
       
   500                     PUSHLOG_WRITE(" Zero length HrefFlag");
       
   501                     }
       
   502                 else
       
   503                     {
       
   504                     TPtrC8 hrefPtr( storage, length );
       
   505                     HBufC* tempHrefBuf = HBufC::NewMaxL( length );
       
   506                     // No leavable after it!!! until...
       
   507                     tempHrefBuf->Des().Copy( hrefPtr );
       
   508                     iHrefBuf = tempHrefBuf; // ...until here.
       
   509                     SetHrefFlag( ETrue );
       
   510                     PUSHLOG_WRITE_FORMAT(" HrefFlag set <%S>",iHrefBuf);
       
   511                     }
       
   512                 }
       
   513 
       
   514             CleanupStack::PopAndDestroy( stringOwner ); // stringOwner
       
   515             }
       
   516         }
       
   517     else if ( attrNamePtr.CompareF( KExpiresAttrib ) == 0 )
       
   518         {
       
   519         if ( ExpiresFlag() )
       
   520             {
       
   521             PUSHLOG_WRITE(" expires redefinition")
       
   522             User::Leave( KErrCorrupt );
       
   523             }
       
   524         else
       
   525             {
       
   526             TBool gotDate = AttributeToTTimeL( aAttrHandle, iExpiresTime );
       
   527             SetExpiresFlag( gotDate );
       
   528             PUSHLOG_WRITE_FORMAT(" iExpiresTime set %d",gotDate?1:0)
       
   529             }
       
   530         }
       
   531     else if ( attrNamePtr.CompareF( KSiIdAttrib ) == 0 )
       
   532         {
       
   533         if ( SiIdFlag() )
       
   534             {
       
   535             PUSHLOG_WRITE(" si-id redefinition")
       
   536             User::Leave( KErrCorrupt );
       
   537             }
       
   538         else
       
   539             {
       
   540             // It is expected to be String.
       
   541             CStringOwner* stringOwner = new (ELeave) CStringOwner;
       
   542             CleanupStack::PushL( stringOwner );
       
   543 
       
   544             NW_String_t* val = NW_String_new();
       
   545             User::LeaveIfNull( val );
       
   546             stringOwner->SetString( val );
       
   547             stat = NW_DOM_AttributeHandle_getValue( &aAttrHandle, val );
       
   548             User::LeaveIfError( NwxStatusToErrCode( stat ) );
       
   549             NW_Byte* storage = NW_String_getStorage( val );
       
   550             NW_Uint16 length = NW_String_getCharCount( val, iCharEncoding );
       
   551             TPtrC8 siidPtr( storage, length );
       
   552 
       
   553             iSiIdBuf = HBufC::NewMaxL( siidPtr.Length() );
       
   554             iSiIdBuf->Des().Copy( siidPtr );
       
   555             SetSiIdFlag( ETrue );
       
   556             PUSHLOG_WRITE_FORMAT(" SiIdFlag set <%S>",iSiIdBuf)
       
   557 
       
   558             CleanupStack::PopAndDestroy( stringOwner ); // stringOwner
       
   559             }
       
   560         }
       
   561     else if ( attrNamePtr.CompareF( KActionAttrib ) == 0 )
       
   562         {
       
   563         if ( ActionFlag() )
       
   564             {
       
   565             PUSHLOG_WRITE(" action redefinition")
       
   566             User::Leave( KErrCorrupt );
       
   567             }
       
   568         else
       
   569             {
       
   570             // It is expected to be String.
       
   571             CStringOwner* stringOwner = new (ELeave) CStringOwner;
       
   572             CleanupStack::PushL( stringOwner );
       
   573 
       
   574             NW_String_t* val = NW_String_new();
       
   575             User::LeaveIfNull( val );
       
   576             stringOwner->SetString( val );
       
   577             stat = NW_DOM_AttributeHandle_getValue( &aAttrHandle, val );
       
   578             User::LeaveIfError( NwxStatusToErrCode( stat ) );
       
   579             NW_Byte* storage = NW_String_getStorage( val );
       
   580             NW_Uint16 length = NW_String_getCharCount( val, iCharEncoding );
       
   581             TPtrC8 actionPtr( storage, length );
       
   582 
       
   583             iPushMsgAction = ConvertActionString( actionPtr );
       
   584             SetActionFlag( ETrue );
       
   585             PUSHLOG_WRITE_FORMAT(" ActionFlag: %d",iPushMsgAction)
       
   586 
       
   587             CleanupStack::PopAndDestroy( stringOwner ); // stringOwner
       
   588             }
       
   589         }
       
   590     else
       
   591         {
       
   592         __ASSERT_DEBUG( EFalse,
       
   593             ContHandPanic( EPushContHandPanUnexpSiToken ) );
       
   594         }
       
   595 
       
   596     CleanupStack::PopAndDestroy( stringOwner ); // stringOwner
       
   597 
       
   598     PUSHLOG_LEAVEFN("CSIContentHandler::ParseIndAttributeL")
       
   599     }
       
   600 
       
   601 // ---------------------------------------------------------
       
   602 // CSIContentHandler::ParseTextL
       
   603 // ---------------------------------------------------------
       
   604 //
       
   605 void CSIContentHandler::ParseTextL( NW_DOM_TextNode_t& aTextNode )
       
   606 	{
       
   607     PUSHLOG_ENTERFN("CSIContentHandler::ParseTextL")
       
   608 
       
   609     if ( DataFlag() )
       
   610         {
       
   611         PUSHLOG_WRITE(" Data flag already set.")
       
   612         }
       
   613     else
       
   614         {
       
   615         CStringOwner* stringOwner = new (ELeave) CStringOwner;
       
   616         CleanupStack::PushL( stringOwner );
       
   617 
       
   618         NW_String_t* data = NW_String_new();
       
   619         User::LeaveIfNull( data );
       
   620         stringOwner->SetString( data );
       
   621         NW_Status_t stat = NW_STAT_SUCCESS;
       
   622         stat = NW_DOM_TextNode_getData( &aTextNode, data );
       
   623         User::LeaveIfError( NwxStatusToErrCode( stat ) );
       
   624 
       
   625         HBufC16* ucs2buffer = ConvertToUnicodeL( *data, iCharEncoding );
       
   626         // Be careful: ucs2buffer is not on the CleanupStack!
       
   627         __ASSERT_DEBUG( ucs2buffer != 0, ContHandPanic( EPushContHandPanNullUcs2Buf ) );
       
   628 
       
   629         TPtrC16 ucs2ptrC( *ucs2buffer );
       
   630         if ( ucs2ptrC.Length() == 0 )
       
   631             {
       
   632             // Zero length data is considered as nothing.
       
   633             PUSHLOG_WRITE(" Zero length Data");
       
   634             }
       
   635         else
       
   636             {
       
   637             PUSHLOG_WRITE_FORMAT(" Data: <%S>",&ucs2ptrC);
       
   638 
       
   639             #ifdef __TEST_LOG__
       
   640             // Write out each unicode character identifier
       
   641             TInt length = ucs2ptrC.Length();
       
   642             for (TInt logI=0;logI<length;logI++)
       
   643                 {
       
   644                 TBuf16<1> currChar;
       
   645                 currChar.Copy( ucs2ptrC.Mid( logI, /*aLength*/1 ) );
       
   646                 PUSHLOG_WRITE_FORMAT2(" 0x%x %S",currChar[0],&currChar);
       
   647                 }
       
   648             #endif // __TEST_LOG__
       
   649 
       
   650             iData = ucs2buffer; // Ownership transferred.
       
   651             ucs2buffer = NULL;
       
   652             SetDataFlag( ETrue );
       
   653             }
       
   654 
       
   655         CleanupStack::PopAndDestroy( stringOwner );
       
   656         }
       
   657 
       
   658     PUSHLOG_LEAVEFN("CSIContentHandler::ParseTextL")
       
   659     }
       
   660 
       
   661 // ---------------------------------------------------------
       
   662 // CSIContentHandler::ConvertToUnicodeL
       
   663 // ---------------------------------------------------------
       
   664 //
       
   665 HBufC16* CSIContentHandler::ConvertToUnicodeL( const TDesC8& aSrc, TUint aCharSetId )
       
   666 	{
       
   667     PUSHLOG_ENTERFN("CSIContentHandler::ConvertToUnicodeL");
       
   668 
       
   669     __ASSERT_DEBUG( aCharSetId != 0, ContHandPanic( EPushContHandPanNullCharSetId ) );
       
   670 
       
   671     InitialiseCharacterSetConverterL();
       
   672 
       
   673     HBufC16* ucs2buffer = NULL; // The return value.
       
   674     TBool resultOnStack = EFalse;
       
   675 
       
   676     #ifdef __TEST_LOG__
       
   677     // Write out the original 8-bit buffer
       
   678     TInt origiLength = aSrc.Length();
       
   679     for (TInt origiLogI=0;origiLogI<origiLength;origiLogI++)
       
   680         {
       
   681         TBuf16<1> currChar; // Only 16-bit buffer can be written out.
       
   682         currChar.Copy( aSrc.Mid( origiLogI, /*aLength*/1 ) );
       
   683         PUSHLOG_WRITE_FORMAT2(" 0x%x %S",currChar[0],&currChar);
       
   684         }
       
   685     #endif // __TEST_LOG__
       
   686 
       
   687     // Result
       
   688     HBufC16* buffer = HBufC16::NewLC( KPushConversionBufferSize );
       
   689     PUSHLOG_WRITE(" buffer allocated");
       
   690     TPtr16 ptr( buffer->Des() );
       
   691 
       
   692     // Prepare conversion for the given charset ID.
       
   693     RFs& fs = iMsvSession->FileSession();
       
   694     iCharacterSetConverter->PrepareToConvertToOrFromL
       
   695         ( aCharSetId, *iCharacterSetsAvailable, fs );
       
   696     PUSHLOG_WRITE(" PrepareToConvertToOrFromL OK");
       
   697 
       
   698     TInt state = 0;
       
   699     TInt remaining = iCharacterSetConverter->ConvertToUnicode( ptr, aSrc, state );
       
   700     PUSHLOG_WRITE_FORMAT(" remaining: %d",remaining);
       
   701     while ( remaining >= 0 )
       
   702         {
       
   703         if ( ucs2buffer == NULL )
       
   704             {
       
   705             ucs2buffer = HBufC::NewLC( ptr.Length() );
       
   706             resultOnStack = ETrue;
       
   707             }
       
   708         else
       
   709             {
       
   710             __ASSERT_DEBUG( resultOnStack,
       
   711                 ContHandPanic( EPushContHandPanSiResNotOnStack ) );
       
   712             // This may change the address of ucs2buffer so we need to put
       
   713             // it on the cleanup stack again!!
       
   714             ucs2buffer = ucs2buffer->ReAllocL
       
   715                 ( ucs2buffer->Length() + ptr.Length() );
       
   716             CleanupStack::Pop();    // old ucs2buffer
       
   717             CleanupStack::PushL( ucs2buffer );  // possibly new copy
       
   718             PUSHLOG_WRITE(" ucs2buffer reallocated");
       
   719             }
       
   720         TPtr16 ucs2ptr( ucs2buffer->Des() );
       
   721         ucs2ptr.Append( ptr );
       
   722         if ( remaining > 0 )
       
   723             {
       
   724             // Try to convert all remaining characters.
       
   725             ptr.Zero();
       
   726             remaining = iCharacterSetConverter->ConvertToUnicode
       
   727                 ( ptr, aSrc.Right( remaining ), state );
       
   728             PUSHLOG_WRITE_FORMAT(" remaining: %d",remaining);
       
   729             }
       
   730         else
       
   731             {
       
   732             PUSHLOG_WRITE(" break");
       
   733             break;
       
   734             }
       
   735         }
       
   736 
       
   737     if ( resultOnStack )
       
   738         {
       
   739         CleanupStack::Pop();    // ucs2buffer
       
   740         resultOnStack = EFalse;
       
   741         }
       
   742 
       
   743     // ucs2buffer is not on the CleanupStack!
       
   744 
       
   745     CleanupStack::PopAndDestroy( buffer ); // buffer
       
   746 
       
   747     if ( ucs2buffer == NULL )
       
   748         {
       
   749         PUSHLOG_WRITE(" NULL ucs2buffer - allocating an empty buf");
       
   750         ucs2buffer = KNullDesC().AllocL();
       
   751         }
       
   752     else
       
   753         {
       
   754         // Check if first character is a Zero-width nbsp.
       
   755         TPtrC16 ucs2ptrC( *ucs2buffer );
       
   756         if ( ucs2ptrC.Length() >= 1 && ucs2ptrC[0] == KPushZeroWidthNbsp )
       
   757             {
       
   758             // First character is a Zero-width NBSP. This character is used as
       
   759             // BOM in some encodings and should not be present at this point.
       
   760             // But we are tolerant and remove it.
       
   761             // (Not expecting big-endianness here.)
       
   762             HBufC16* temp = ucs2buffer;
       
   763             CleanupStack::PushL( temp );
       
   764             ucs2buffer = ucs2ptrC.Mid( 1 ).AllocL();
       
   765             CleanupStack::PopAndDestroy( temp ); // temp
       
   766             PUSHLOG_WRITE(" BOM removed");
       
   767             }
       
   768         else
       
   769             {
       
   770             PUSHLOG_WRITE(" No BOM");
       
   771             }
       
   772         }
       
   773 
       
   774 
       
   775     PUSHLOG_LEAVEFN("CSIContentHandler::ConvertToUnicodeL");
       
   776     return ucs2buffer;
       
   777     }
       
   778 
       
   779 // ---------------------------------------------------------
       
   780 // CSIContentHandler::ConvertToUnicodeL
       
   781 // ---------------------------------------------------------
       
   782 //
       
   783 HBufC16* CSIContentHandler::ConvertToUnicodeL
       
   784     ( NW_String_t& aString, NW_Uint32 aCharEncoding )
       
   785 	{
       
   786     PUSHLOG_ENTERFN("CSIContentHandler::ConvertToUnicodeL");
       
   787 
       
   788     /* As cXmlLibrary does, we support only the following charsets:
       
   789     #define HTTP_iso_10646_ucs_2        0x03E8
       
   790     #define HTTP_iso_8859_1             0x04
       
   791     #define HTTP_us_ascii               0x03
       
   792     #define HTTP_utf_8                  0x6A
       
   793     #define HTTP_utf_16                 1015
       
   794     */
       
   795     TUint id = 0;
       
   796     if ( aCharEncoding == HTTP_iso_10646_ucs_2 )
       
   797         {
       
   798         id = KCharacterSetIdentifierUcs2;
       
   799         PUSHLOG_WRITE(" KCharacterSetIdentifierUcs2")
       
   800         }
       
   801     else if ( aCharEncoding == HTTP_iso_8859_1 )
       
   802         {
       
   803         id = KCharacterSetIdentifierIso88591;
       
   804         PUSHLOG_WRITE(" KCharacterSetIdentifierIso88591")
       
   805         }
       
   806     else if ( aCharEncoding == HTTP_us_ascii )
       
   807         {
       
   808         id = KCharacterSetIdentifierAscii;
       
   809         PUSHLOG_WRITE(" KCharacterSetIdentifierAscii")
       
   810         }
       
   811     else if ( aCharEncoding == HTTP_utf_8 )
       
   812         {
       
   813         id = KCharacterSetIdentifierUtf8;
       
   814         PUSHLOG_WRITE(" KCharacterSetIdentifierUtf8")
       
   815         }
       
   816     else if ( aCharEncoding == HTTP_utf_16 ) // No such in CharConv.h
       
   817         {
       
   818         id = KCharacterSetIdentifierUcs2;
       
   819         PUSHLOG_WRITE(" KCharacterSetIdentifierUcs2")
       
   820         }
       
   821     else
       
   822         {
       
   823         id = KCharacterSetIdentifierUtf8; // Defaulting to UTF-8
       
   824         PUSHLOG_WRITE(" DEFAULTING to KCharacterSetIdentifierUtf8");
       
   825         }
       
   826 
       
   827     PUSHLOG_WRITE_FORMAT(" id: 0x%x",id);
       
   828     __ASSERT_DEBUG( id != 0, ContHandPanic( EPushContHandPanNullCharSetId ) );
       
   829 
       
   830     // Source
       
   831     PUSHLOG_WRITE_FORMAT(" Storage: 0x%x",NW_String_getStorage(&aString));
       
   832     PUSHLOG_WRITE_FORMAT(" Byte count: %d",NW_String_getByteCount(&aString)-1);
       
   833 
       
   834     // We will use NW_String_getByteCount(&aString)-1 as size, because
       
   835     // NW_String_getByteCount(&aString) includes NULL terminator.
       
   836     const TPtrC8 src( NW_String_getStorage(&aString),
       
   837                       NW_String_getByteCount(&aString)-1 );
       
   838     HBufC16* ucs2buffer = ConvertToUnicodeL( src, id );
       
   839 
       
   840     PUSHLOG_LEAVEFN("CSIContentHandler::ConvertToUnicodeL");
       
   841     return ucs2buffer;
       
   842     }
       
   843 
       
   844 // ---------------------------------------------------------
       
   845 // CSIContentHandler::InitialiseCharacterSetConverterL
       
   846 // ---------------------------------------------------------
       
   847 //
       
   848 void CSIContentHandler::InitialiseCharacterSetConverterL()
       
   849 	{
       
   850     PUSHLOG_ENTERFN("CSIContentHandler::InitialiseCharacterSetConverterL")
       
   851 
       
   852     iCharacterSetConverter = CCnvCharacterSetConverter::NewL();
       
   853 
       
   854     RFs& fs = iMsvSession->FileSession();
       
   855     iCharacterSetsAvailable =
       
   856         CCnvCharacterSetConverter::CreateArrayOfCharacterSetsAvailableL( fs );
       
   857 
       
   858     PUSHLOG_LEAVEFN("CSIContentHandler::InitialiseCharacterSetConverterL")
       
   859     }
       
   860 
       
   861 // ---------------------------------------------------------
       
   862 // CSIContentHandler::ConvertActionString
       
   863 // ---------------------------------------------------------
       
   864 //
       
   865 TUint CSIContentHandler::ConvertActionString
       
   866                          ( const TDesC8& aActionString ) const
       
   867 	{
       
   868 	const TInt KMatchFound = 0;
       
   869 
       
   870 	// set to default signal value (to rid ourselves of build warning)
       
   871 	TUint actionValue = CSIPushMsgEntry::ESIPushMsgSignalMedium;
       
   872 
       
   873 	if ( aActionString.Compare( KDeleteAction ) == KMatchFound )
       
   874         {
       
   875 		actionValue = CSIPushMsgEntry::ESIPushMsgDelete;
       
   876         }
       
   877 	else if ( aActionString.Compare( KSignalNone ) == KMatchFound )
       
   878         {
       
   879 		actionValue = CSIPushMsgEntry::ESIPushMsgSignalNone;
       
   880         }
       
   881 	else if ( aActionString.Compare( KSignalLow ) == KMatchFound )
       
   882         {
       
   883 		actionValue = CSIPushMsgEntry::ESIPushMsgSignalLow;
       
   884         }
       
   885 	else if ( aActionString.Compare( KSignalMedium ) == KMatchFound )
       
   886         {
       
   887 		actionValue = CSIPushMsgEntry::ESIPushMsgSignalMedium;
       
   888         }
       
   889 	else if ( aActionString.Compare( KSignalHigh ) == KMatchFound )
       
   890         {
       
   891 		actionValue = CSIPushMsgEntry::ESIPushMsgSignalHigh;
       
   892         }
       
   893 
       
   894 	return actionValue;
       
   895 	}
       
   896 
       
   897 // ---------------------------------------------------------
       
   898 // CSIContentHandler::SetSIPushMsgEntryFieldsL
       
   899 // ---------------------------------------------------------
       
   900 //
       
   901 void CSIContentHandler::SetSIPushMsgEntryFieldsL( CSIPushMsgEntry&
       
   902                                                   aSIPushMsgEntry )
       
   903 	{
       
   904     PUSHLOG_ENTERFN("CSIContentHandler::SetSIPushMsgEntryFieldsL")
       
   905 
       
   906 	if ( SiIdFlag() || HrefFlag() )
       
   907 		{
       
   908 		if ( SiIdFlag() && ( HrefFlag() == EFalse ) )
       
   909 			{
       
   910             // Message has only si-id but no href.
       
   911             aSIPushMsgEntry.SetIdL( *iSiIdBuf );
       
   912 			}
       
   913 		else if ( HrefFlag() && ( SiIdFlag() == EFalse ) )
       
   914 			{
       
   915             // If message has no si-id but does have a href, use href as si-id.
       
   916             aSIPushMsgEntry.SetIdL( *iHrefBuf );
       
   917             aSIPushMsgEntry.SetUrlL( *iHrefBuf );
       
   918 			}
       
   919 		else
       
   920             {
       
   921             // Use si-id and href as is.
       
   922             aSIPushMsgEntry.SetIdL( *iSiIdBuf );
       
   923             aSIPushMsgEntry.SetUrlL( *iHrefBuf );
       
   924             }
       
   925 		}
       
   926 
       
   927     __ASSERT_DEBUG( ActionFlag(),
       
   928                     ContHandPanic( EPushContHandPanUnspecSiAction ) );
       
   929 	if ( ActionFlag() )
       
   930         {
       
   931 		aSIPushMsgEntry.SetAction( iPushMsgAction );
       
   932         }
       
   933 	else // default if no action explicitly stated
       
   934         {
       
   935 		aSIPushMsgEntry.SetAction( CSIPushMsgEntry::ESIPushMsgSignalMedium );
       
   936         }
       
   937 
       
   938 	// uses default null time value if no explicit date set in message
       
   939 	aSIPushMsgEntry.SetCreated( iCreatedTime );
       
   940 	aSIPushMsgEntry.SetExpires( iExpiresTime );
       
   941 
       
   942 	// PCDATA (text) from message
       
   943 	if ( DataFlag() )
       
   944         {
       
   945 		aSIPushMsgEntry.SetTextL( *iData );
       
   946         }
       
   947 
       
   948 	TPtrC8 msgHeaderPtr;
       
   949 	iMessage->GetHeader( msgHeaderPtr );
       
   950 	aSIPushMsgEntry.SetHeaderL( msgHeaderPtr );
       
   951 
       
   952     // Get server address.
       
   953     TPtrC8 srvAddress;
       
   954     if ( iMessage->GetServerAddress( srvAddress ) )
       
   955         {
       
   956 	    aSIPushMsgEntry.SetFromL( srvAddress );
       
   957         }
       
   958 
       
   959     // First line in Inbox: TMsvEntry::iDetails.
       
   960     if ( srvAddress.Length() == 0 )
       
   961         {
       
   962         // Read from resource.
       
   963         HBufC* details =
       
   964             iStrRscReader->AllocReadResourceLC( R_PUSHMISC_UNK_SENDER );
       
   965         aSIPushMsgEntry.SetMsgDetailsL( *details );
       
   966         CleanupStack::PopAndDestroy( details );
       
   967         }
       
   968     else
       
   969         {
       
   970         // Convert the "From" information to the format required by the UI
       
   971         // spec and then decode it.
       
   972         HBufC* details = iWapPushUtils->ConvertDetailsL( srvAddress );
       
   973         CleanupStack::PushL( details );
       
   974         HBufC* convertedFrom =
       
   975             CPushMtmUtil::ConvertUriToDisplayFormL( *details );
       
   976         CleanupStack::PushL( convertedFrom );
       
   977         //
       
   978         aSIPushMsgEntry.SetMsgDetailsL( *convertedFrom );
       
   979         //
       
   980         CleanupStack::PopAndDestroy( 2, details ); // convertedFrom, details
       
   981         }
       
   982 
       
   983     // Second line in Inbox: TMsvEntry::iDescription.
       
   984 	if ( DataFlag() )
       
   985         {
       
   986         // Display SI message.
       
   987 		aSIPushMsgEntry.SetMsgDescriptionL( *iData );
       
   988         }
       
   989     else
       
   990         {
       
   991         // Display URL.
       
   992         __ASSERT_DEBUG( HrefFlag(),
       
   993                         ContHandPanic( EPushContHandPanUnspecSiHref ) );
       
   994         const TPtrC url = aSIPushMsgEntry.Url();
       
   995         HBufC* convertedUrl = CPushMtmUtil::ConvertUriToDisplayFormL( url );
       
   996         CleanupStack::PushL( convertedUrl );
       
   997         //
       
   998         aSIPushMsgEntry.SetMsgDescriptionL( *convertedUrl );
       
   999         //
       
  1000         CleanupStack::PopAndDestroy( convertedUrl ); // convertedUrl
       
  1001         }
       
  1002 
       
  1003     // ******** Push MTM specific processing *********
       
  1004 
       
  1005     /*
       
  1006     * Unfortunately in CPushMsgEntryBase there is no such functionality
       
  1007     * with which we can reach TMsvEntry as non-const, but we have to
       
  1008     * modify the entry's iMtmData2 member somehow. We can do it
       
  1009     * with either casting or with modifying and saving the entry
       
  1010     * manually after it has been saved by CSIPushMsgEntry. The latter
       
  1011     * solution is more expensive so we choose the first.
       
  1012     */
       
  1013     TMsvEntry& tEntry = CONST_CAST( TMsvEntry&, aSIPushMsgEntry.Entry() );
       
  1014     if ( HrefFlag() )
       
  1015         {
       
  1016         CPushMtmUtil::SetAttrs( tEntry, EPushMtmAttrHasHref );
       
  1017         }
       
  1018     else
       
  1019         {
       
  1020         CPushMtmUtil::ResetAttrs( tEntry, EPushMtmAttrHasHref );
       
  1021         }
       
  1022 
       
  1023     // *** Set the entry to unread and new state. ***
       
  1024 
       
  1025     tEntry.SetNew( ETrue );
       
  1026     tEntry.SetUnread( ETrue );
       
  1027 
       
  1028     PUSHLOG_LEAVEFN("CSIContentHandler::SetSIPushMsgEntryFieldsL")
       
  1029 	}
       
  1030 
       
  1031 // ---------------------------------------------------------
       
  1032 // CSIContentHandler::ProcessingPushMsgEntryL
       
  1033 // ---------------------------------------------------------
       
  1034 //
       
  1035 void CSIContentHandler::ProcessingPushMsgEntryL()
       
  1036 	{
       
  1037     PUSHLOG_ENTERFN("CSIContentHandler::ProcessingPushMsgEntryL")
       
  1038 
       
  1039 	TBool deletePushMsg( EFalse );
       
  1040 
       
  1041     __ASSERT_DEBUG( ActionFlag(),
       
  1042                     ContHandPanic( EPushContHandPanUnspecSiAction ) );
       
  1043 
       
  1044     // S60 requirement: if both the href and the message is empty then
       
  1045     // delete the msg.
       
  1046     if ( HrefFlag() == EFalse && DataFlag() == EFalse )
       
  1047         {
       
  1048         deletePushMsg = ETrue;
       
  1049         }
       
  1050 
       
  1051     // Expiration.
       
  1052     if ( !deletePushMsg && ExpiresFlag() )
       
  1053         {
       
  1054 	    TTime today;
       
  1055 	    today.UniversalTime();
       
  1056 #ifdef __TEST_LOG__
       
  1057         _LIT( KDateFormat, "%E%D%X%N%Y %1 %2 %3" );
       
  1058         _LIT( KTimeFormat, "%-B%:0%J%:1%T%:2%S%:3%+B" );
       
  1059         TBuf<32> dateHolder;
       
  1060         TBuf<32> timeHolder;
       
  1061         today.FormatL( dateHolder, KDateFormat );
       
  1062         today.FormatL( timeHolder, KTimeFormat );
       
  1063         PUSHLOG_WRITE_FORMAT(" now date: <%S>",&dateHolder)
       
  1064         PUSHLOG_WRITE_FORMAT(" now time: <%S>",&timeHolder)
       
  1065         iExpiresTime.FormatL( dateHolder, KDateFormat );
       
  1066         iExpiresTime.FormatL( timeHolder, KTimeFormat );
       
  1067         PUSHLOG_WRITE_FORMAT(" exp date: <%S>",&dateHolder)
       
  1068         PUSHLOG_WRITE_FORMAT(" exp time: <%S>",&timeHolder)
       
  1069 #endif // __TEST_LOG__
       
  1070 	    // check if message has expiry date before today's date
       
  1071 	    if ( iExpiresTime < today )
       
  1072 		    {
       
  1073             PUSHLOG_WRITE("CSIContentHandler already expired")
       
  1074 		    deletePushMsg = ETrue;
       
  1075 		    }
       
  1076         }
       
  1077 
       
  1078 	// An SI with the action attribute set to “delete” MUST have an
       
  1079     // explicitly assigned value for si-id.
       
  1080 	if ( !deletePushMsg && ActionFlag() )
       
  1081 		{
       
  1082 		if ( iPushMsgAction == CSIPushMsgEntry::ESIPushMsgDelete )
       
  1083             {
       
  1084             if ( !SiIdFlag() || ( SiIdFlag() && iSiIdBuf->Length() == 0 ) )
       
  1085                 {
       
  1086                 deletePushMsg = ETrue;
       
  1087                 }
       
  1088             }
       
  1089         }
       
  1090 
       
  1091     // Handling out of order delivery & Replacement.
       
  1092     TMsvId matchingEntryId = KMsvNullIndexEntryId;
       
  1093 
       
  1094     if ( !deletePushMsg && ( SiIdFlag() || HrefFlag() ) && CreatedFlag() )
       
  1095         {
       
  1096         deletePushMsg = HandleMsgOrderReceptionL( matchingEntryId );
       
  1097         }
       
  1098 
       
  1099     if ( !deletePushMsg && ActionFlag() )
       
  1100         {
       
  1101         // SI with action=signal-none must not be presented to the end-user.
       
  1102         // Note. In S60 signal-none behaves the same as delete: the
       
  1103         // message is discarded after processing it!
       
  1104         if ( iPushMsgAction == CSIPushMsgEntry::ESIPushMsgSignalNone )
       
  1105             {
       
  1106             deletePushMsg = ETrue;
       
  1107             }
       
  1108         // SI with action=delete must also be discarded.
       
  1109         else if ( iPushMsgAction == CSIPushMsgEntry::ESIPushMsgDelete )
       
  1110             {
       
  1111             deletePushMsg = ETrue;
       
  1112             }
       
  1113         }
       
  1114 
       
  1115 	// Store message if not marked for deletion.
       
  1116 	if ( !deletePushMsg )
       
  1117         {
       
  1118 		StoreSIMessageL( matchingEntryId );
       
  1119         }
       
  1120     else
       
  1121         {
       
  1122         // The new entry must be discarded.
       
  1123         // Delete the corresponding matching entry, too.
       
  1124         if ( matchingEntryId != KMsvNullIndexEntryId )
       
  1125             {
       
  1126             iWapPushUtils->DeleteEntryL( matchingEntryId );
       
  1127             }
       
  1128         }
       
  1129 
       
  1130 	iState = EDone;
       
  1131 	IdleComplete();
       
  1132 
       
  1133     PUSHLOG_LEAVEFN("CSIContentHandler::ProcessingPushMsgEntryL")
       
  1134 	}
       
  1135 
       
  1136 // ---------------------------------------------------------
       
  1137 // CSIContentHandler::StoreSIMessageL
       
  1138 // ---------------------------------------------------------
       
  1139 //
       
  1140 void CSIContentHandler::StoreSIMessageL( TMsvId aMatchingEntryId )
       
  1141 	{
       
  1142     PUSHLOG_ENTERFN("CSIContentHandler::StoreSIMessageL")
       
  1143 
       
  1144 	CSIPushMsgEntry* siEntry = CSIPushMsgEntry::NewL();
       
  1145 	CleanupStack::PushL( siEntry );
       
  1146 
       
  1147     if ( aMatchingEntryId != KMsvNullIndexEntryId )
       
  1148     {
       
  1149        PUSHLOG_WRITE("Matching SI found");
       
  1150        //Delete this old entry
       
  1151        iWapPushUtils->DeleteEntryL( aMatchingEntryId );
       
  1152     }
       
  1153 
       
  1154     SetSIPushMsgEntryFieldsL( *siEntry );
       
  1155     iSavedMsgId = siEntry->SaveL( *iMsvSession, KMsvGlobalInBoxIndexEntryId );
       
  1156 
       
  1157 #ifdef __TEST_LOG__
       
  1158         _LIT( KDateFormat, "%E%D%X%N%Y %1 %2 %3" );
       
  1159         _LIT( KTimeFormat, "%-B%:0%J%:1%T%:2%S%:3%+B" );
       
  1160         TBuf<32> dateHolder;
       
  1161         TBuf<32> timeHolder;
       
  1162         TTime recDateTime = siEntry->ReceivedDate();
       
  1163         recDateTime.FormatL( dateHolder, KDateFormat );
       
  1164         recDateTime.FormatL( timeHolder, KTimeFormat );
       
  1165         PUSHLOG_WRITE_FORMAT(" rec date: <%S>",&dateHolder)
       
  1166         PUSHLOG_WRITE_FORMAT(" rec time: <%S>",&timeHolder)
       
  1167 #endif // __TEST_LOG__
       
  1168 
       
  1169 	CleanupStack::PopAndDestroy( siEntry ); // siEntry
       
  1170 
       
  1171     PUSHLOG_LEAVEFN("CSIContentHandler::StoreSIMessageL")
       
  1172 	}
       
  1173 
       
  1174 // ---------------------------------------------------------
       
  1175 // CSIContentHandler::HandleMsgOrderReceptionL
       
  1176 // ---------------------------------------------------------
       
  1177 //
       
  1178 TBool CSIContentHandler::HandleMsgOrderReceptionL( TMsvId& aMatchingEntryId )
       
  1179 	{
       
  1180     PUSHLOG_ENTERFN("CSIContentHandler::HandleMsgOrderReceptionL")
       
  1181 
       
  1182     __ASSERT_DEBUG( ( SiIdFlag() || HrefFlag() ),
       
  1183             ContHandPanic( EPushContHandPanNoSiIdOrHrefAttr ) );
       
  1184     __ASSERT_DEBUG( CreatedFlag(),
       
  1185             ContHandPanic( EPushContHandPanNoCreatedAttr ) );
       
  1186 
       
  1187     CMsvEntrySelection* matchingIdList = NULL;
       
  1188 	TBool discardPushMsg( EFalse );
       
  1189 
       
  1190 	// Get list of matching stored SI messages.
       
  1191 	if ( SiIdFlag() && iSiIdBuf->Length() != 0 )
       
  1192         {
       
  1193 		matchingIdList = iWapPushUtils->FindSiIdLC( *iSiIdBuf );
       
  1194         }
       
  1195 	else // HrefFlag()
       
  1196         {
       
  1197         // Use href as si-id.
       
  1198 		matchingIdList = iWapPushUtils->FindSiIdLC( *iHrefBuf );
       
  1199         }
       
  1200     const TInt matchingListCount( matchingIdList->Count() );
       
  1201     // Note that the count can be greater than 1.
       
  1202 
       
  1203     PUSHLOG_WRITE_FORMAT("CSIContentHandler Count: %d",matchingListCount)
       
  1204 
       
  1205 	if ( 0 < matchingListCount && CreatedFlag() )
       
  1206 		{
       
  1207 		CSIPushMsgEntry* siEntry = CSIPushMsgEntry::NewL();
       
  1208 		CleanupStack::PushL( siEntry );
       
  1209 
       
  1210 		// Delete older stored messages and/or mark current message for
       
  1211         // deletion if same date or older than stored messages
       
  1212         TBool foundOneToBeReplaced = EFalse;
       
  1213 		for ( TInt count = 0; count < matchingListCount; ++count )
       
  1214 			{
       
  1215 			TMsvId matchingSiMsgEntryId( matchingIdList->At(count) );
       
  1216 
       
  1217             siEntry->RetrieveL( *iMsvSession, matchingSiMsgEntryId );
       
  1218 
       
  1219 			// Skip date comparisons if creation date not valid -
       
  1220             // SI without created attribute never gets replaced.
       
  1221 			TTime existingSiCreatedTime( siEntry->Created() );
       
  1222 
       
  1223 			if ( existingSiCreatedTime == Time::NullTTime() )
       
  1224                 {
       
  1225 				// continue;
       
  1226                 }
       
  1227             else
       
  1228                 {
       
  1229                 __ASSERT_DEBUG( !foundOneToBeReplaced,
       
  1230                                 ContHandPanic( EPushContHandPanTooManySi ) );
       
  1231                 if ( foundOneToBeReplaced )
       
  1232                     {
       
  1233                     PUSHLOG_WRITE(" Already found one")
       
  1234                     // Only one SI has to be found.
       
  1235                     // If the program runs into it, then make a
       
  1236                     // garbage collection to ensure consistency and
       
  1237                     // remove other messages found.
       
  1238                     iWapPushUtils->DeleteEntryL( matchingSiMsgEntryId );
       
  1239                     // After the 'for' only one SI is allowed that has created
       
  1240                     // attribute.
       
  1241                     }
       
  1242                 else
       
  1243                     {
       
  1244                     foundOneToBeReplaced = ETrue; // A match was found.
       
  1245                     // Check if received SI is newer than existing stored Si
       
  1246                     // (out of order).
       
  1247                     if ( iCreatedTime > existingSiCreatedTime )
       
  1248 	                    {
       
  1249                         PUSHLOG_WRITE(" Replacing...")
       
  1250                         // The new SI replaces the existing.
       
  1251                         aMatchingEntryId = matchingSiMsgEntryId;
       
  1252                         discardPushMsg = EFalse;
       
  1253 	                    }
       
  1254                     else if ( iCreatedTime <= existingSiCreatedTime )
       
  1255                         {
       
  1256                         PUSHLOG_WRITE(" Discarding...")
       
  1257                         // Received SI is older than existing stored Si.
       
  1258                         discardPushMsg = ETrue;
       
  1259                         }
       
  1260                     }
       
  1261                 }
       
  1262 			}
       
  1263 
       
  1264 		CleanupStack::PopAndDestroy( siEntry ); // siEntry
       
  1265 		}
       
  1266 
       
  1267 	CleanupStack::PopAndDestroy( matchingIdList ); // matchingIdList
       
  1268 
       
  1269     PUSHLOG_LEAVEFN("CSIContentHandler::HandleMsgOrderReceptionL")
       
  1270     return discardPushMsg;
       
  1271 	}
       
  1272 
       
  1273 // ---------------------------------------------------------
       
  1274 // CSIContentHandler::ConvertDateTimeL
       
  1275 // ---------------------------------------------------------
       
  1276 //
       
  1277 TBool CSIContentHandler::ConvertDateTimeL( const TDesC& aDateTime,
       
  1278                                            TTime& aConvertedDate ) const
       
  1279 	{
       
  1280     PUSHLOG_ENTERFN("CSIContentHandler::ConvertDateTimeL")
       
  1281 
       
  1282 	TTime convertedTime = Time::NullTTime();
       
  1283 	TBool convertedOK = EFalse;
       
  1284 
       
  1285     // check supplied descriptor is the correct length
       
  1286 	if ( aDateTime.Length() != KValidUTCLength )
       
  1287         {
       
  1288         PUSHLOG_WRITE_FORMAT(" invalid UTC length <%d>",aDateTime.Length())
       
  1289         User::Leave( KErrCorrupt );
       
  1290         }
       
  1291     else
       
  1292 		{
       
  1293 		TBuf<KValidUTCLength> str = aDateTime;
       
  1294         PUSHLOG_WRITE_FORMAT(" datetime str: <%S>",&str)
       
  1295 		if ( !IsValidUTCTime( str ) )
       
  1296             {
       
  1297             // The UTC time is invalid.
       
  1298             PUSHLOG_WRITE(" invalid UTC time")
       
  1299             User::Leave( KErrCorrupt );
       
  1300             }
       
  1301         else
       
  1302 			{
       
  1303             // Now 'str' is in format YYYYMMDD:HHMMSS
       
  1304 			// Adjust UTC time to zero offset TTime. Only month and day
       
  1305             // is effected.
       
  1306 			const TInt KFirstMonthChar = KValidTTimeMonthStart;
       
  1307 			const TInt KSecondMonthChar = KFirstMonthChar + 1;
       
  1308 			const TInt KFirstDayChar = KValidTTimeDayStart;
       
  1309 			const TInt KSecondDayChar = KFirstDayChar + 1;
       
  1310             // Month.
       
  1311 			// check for special case of month = 10 which becomes 09
       
  1312 			if ( str[KFirstMonthChar] == '1' && str[KSecondMonthChar] == '0' )
       
  1313 				{
       
  1314 				str[KFirstMonthChar] = '0';
       
  1315 				str[KSecondMonthChar] = '9';
       
  1316 				}
       
  1317 			else
       
  1318                 {
       
  1319 				// month value is either 11, 12 or less than 10, ie 1 - 9.
       
  1320 				// reduce day by one, eg 11 becomes 10, 12 becomes 11, 09 becomes 08
       
  1321 				str[KSecondMonthChar]--;
       
  1322                 }
       
  1323 
       
  1324             // Day.
       
  1325 			// check for special cases 10, 20, 30
       
  1326 			if ( str[KSecondDayChar] == '0' )
       
  1327 				{
       
  1328 				// reduce day by 1, ie 10 becomes 09, 20 becomes 19 ...
       
  1329 				str[KSecondDayChar] = '9';
       
  1330 				str[KFirstDayChar]--;
       
  1331 				}
       
  1332 			else
       
  1333                 {
       
  1334 				// day value is between 1 and 9 so reduce day by one
       
  1335 				// eg 29 becomes 28, 11 bcomes 10, 31 becomes 30
       
  1336 				str[KSecondDayChar]--;
       
  1337                 }
       
  1338 
       
  1339 			// string is now syntaxically correct, but Set() will return an
       
  1340             // error if it's semantically incorrect.
       
  1341             User::LeaveIfError( convertedTime.Set( str ) );
       
  1342 			convertedOK = ETrue;
       
  1343 			}
       
  1344 		}
       
  1345 
       
  1346     PUSHLOG_LEAVEFN("CSIContentHandler::ConvertDateTimeL")
       
  1347 	aConvertedDate = convertedTime;
       
  1348 	return convertedOK;
       
  1349 	}
       
  1350 
       
  1351 // ---------------------------------------------------------
       
  1352 // CSIContentHandler::ConvertOpaqueToUtcL
       
  1353 // ---------------------------------------------------------
       
  1354 //
       
  1355 HBufC* CSIContentHandler::ConvertOpaqueToUtcL( const TDesC8& aOpaque ) const
       
  1356 	{
       
  1357     PUSHLOG_ENTERFN("CSIContentHandler::ConvertOpaqueToUtcL")
       
  1358 
       
  1359     const TInt opaqueSize = aOpaque.Size();
       
  1360     if ( KValidMaxEncodedDateTimeSize < opaqueSize )
       
  1361         {
       
  1362         PUSHLOG_WRITE_FORMAT(" Bad OPAQUE size: <%d>",opaqueSize)
       
  1363         User::Leave( KErrCorrupt );
       
  1364         }
       
  1365 
       
  1366     HBufC* converted = HBufC::NewMaxLC( KValidUTCLength );
       
  1367     TPtr convertedPtr = converted->Des();
       
  1368     convertedPtr.SetLength( 0 ); // Reset.
       
  1369 
       
  1370     // Split up each opaque byte to two bytes.
       
  1371     TUint8 byte( 0x00 );
       
  1372     TUint8 high( 0x00 );
       
  1373     TUint8 low( 0x00 );
       
  1374     TInt i = 0;
       
  1375     for ( i = 0; i < opaqueSize; ++i )
       
  1376         {
       
  1377         byte = aOpaque[i];
       
  1378         high = (TUint8)( (byte & 0xF0) >> 4 );
       
  1379         low  = (TUint8)(  byte & 0x0F );
       
  1380         // Check high and low if they are in the range [0-9].
       
  1381         if ( 9 < high || 9 < low )
       
  1382             {
       
  1383             PUSHLOG_WRITE_FORMAT2(" Overflow: <%d, %d>",high,low)
       
  1384             User::Leave( KErrOverflow );
       
  1385             }
       
  1386         convertedPtr.Append( TChar(KAsciiZeroCharCode + high) );
       
  1387         convertedPtr.Append( TChar(KAsciiZeroCharCode + low) );
       
  1388         }
       
  1389 
       
  1390     // A valid UTC %Datetime contains 14 numerical characters and 6
       
  1391     // non-numerical: “1999-04-30T06:40:00Z”.
       
  1392     // So fill the remaining bytes with zeros.
       
  1393     for ( i = convertedPtr.Length(); i < KValidUTCNumericals; ++i )
       
  1394         {
       
  1395         convertedPtr.Append( TChar('0') );
       
  1396         }
       
  1397 
       
  1398     // Insert the necessary non-numerical boundary characters.
       
  1399     i = 0;
       
  1400     // Skip year and insert '-'. (Don't forget to increase i with 1 each time!)
       
  1401     i += KValidUTCYearBlockLength;
       
  1402     convertedPtr.Insert( i++, KCharMinus );
       
  1403     // Skip month and insert '-'.
       
  1404     i += KValidUTCOtherBlockLength;
       
  1405     convertedPtr.Insert( i++, KCharMinus );
       
  1406     // Skip day and insert 'T'.
       
  1407     i += KValidUTCOtherBlockLength;
       
  1408     convertedPtr.Insert( i++, KCharT );
       
  1409     // Skip hour and insert ':'.
       
  1410     i += KValidUTCOtherBlockLength;
       
  1411     convertedPtr.Insert( i++, KCharColon );
       
  1412     // Skip minute and insert ':'.
       
  1413     i += KValidUTCOtherBlockLength;
       
  1414     convertedPtr.Insert( i++, KCharColon );
       
  1415     // Skip second and insert 'Z'.
       
  1416     i += KValidUTCOtherBlockLength;
       
  1417     convertedPtr.Insert( i++, KCharZ );
       
  1418 
       
  1419     CleanupStack::Pop( converted ); // converted
       
  1420     PUSHLOG_LEAVEFN("CSIContentHandler::ConvertOpaqueToUtcL")
       
  1421 	return converted;
       
  1422 	}
       
  1423 
       
  1424 // ---------------------------------------------------------
       
  1425 // CSIContentHandler::IsValidUTCTime
       
  1426 // ---------------------------------------------------------
       
  1427 //
       
  1428 TBool CSIContentHandler::IsValidUTCTime( TDes& aDateTime ) const
       
  1429 	{
       
  1430     PUSHLOG_ENTERFN("CSIContentHandler::IsValidUTCTime")
       
  1431 
       
  1432     TBool isValid( ETrue ); // Return value.
       
  1433 
       
  1434     // Now aDateTime has to be in format YYYY-MM-DDTHH:MM:SSZ
       
  1435 
       
  1436     // check supplied descriptor is the correct length
       
  1437 	if ( aDateTime.Length() != KValidUTCLength )
       
  1438         {
       
  1439         PUSHLOG_WRITE_FORMAT(" invalid UTC length <%d>",aDateTime.Length())
       
  1440         isValid = EFalse;
       
  1441         }
       
  1442     else
       
  1443         {
       
  1444 	    // strip out formatting characters
       
  1445 	    TInt formatCharPos = 4;
       
  1446 	    aDateTime.Delete( formatCharPos, 1 );
       
  1447 	    // now move through two characters at a time and remove other chars
       
  1448 	    // to just leave digits
       
  1449 	    const TInt KRemainingFormatChars = 5;
       
  1450         TInt i( 0 );
       
  1451 	    for ( i = 0; i < KRemainingFormatChars; ++i )
       
  1452 		    {
       
  1453 		    formatCharPos += 2;
       
  1454 		    aDateTime.Delete( formatCharPos, 1 );
       
  1455 		    }
       
  1456 
       
  1457         // Now aDateTime has to be in format YYYYMMDDHHMMSS
       
  1458 
       
  1459         __ASSERT_DEBUG( aDateTime.Length() == KValidTTimeLength,
       
  1460                         ContHandPanic( EPushContHandPanBadTTimeLength ) );
       
  1461 
       
  1462         // now have UTC string stripped of format characters - check remaining
       
  1463         // characters are all digits - YYYYMMDDHHMMSS
       
  1464         TChar ch;
       
  1465         for ( i = 0; i < KValidTTimeLength; ++i )
       
  1466 		    {
       
  1467 		    ch = aDateTime[i];
       
  1468 		    if ( ch.IsDigit() == EFalse )
       
  1469                 {
       
  1470                 PUSHLOG_WRITE_FORMAT(" not digit <%d>",i)
       
  1471                 isValid = EFalse;
       
  1472                 }
       
  1473 		    }
       
  1474 
       
  1475         if ( isValid )
       
  1476             {
       
  1477             /*
       
  1478             In YYYYMMDDHHMMSS
       
  1479             YYYY = 4 digit year ("0000" ... "9999")
       
  1480             MM = 2 digit month ("01"=January, "02"=February ... "12"=December)
       
  1481             DD = 2 digit day ("01", "02" ... "31")
       
  1482             HH = 2 digit hour, 24-hour timekeeping system ("00" ... "23")
       
  1483             MM = 2 digit minute ("00" ... "59")
       
  1484             SS = 2 digit second ("00" ... "59")
       
  1485             */
       
  1486             TInt err;
       
  1487             TUint val;
       
  1488             // Do not check year. There are no restrictions.
       
  1489             // Check month.
       
  1490             TLex parser( aDateTime.Mid( KValidTTimeMonthStart,
       
  1491                                         KValidTTimeBlockLength ) );
       
  1492             err = parser.Val( val, EDecimal );
       
  1493             if ( err )
       
  1494                 {
       
  1495                 isValid = EFalse;
       
  1496                 PUSHLOG_WRITE_FORMAT(" parser err: <%d>",err)
       
  1497                 }
       
  1498             else
       
  1499                 {
       
  1500                 PUSHLOG_WRITE_FORMAT(" month: <%d>",val)
       
  1501                 if ( val < 1 || 12 < val )
       
  1502                     {
       
  1503                     isValid = EFalse;
       
  1504                     }
       
  1505                 }
       
  1506             // Check day.
       
  1507             if ( isValid )
       
  1508                 {
       
  1509                 parser = aDateTime.Mid( KValidTTimeDayStart,
       
  1510                                         KValidTTimeBlockLength );
       
  1511                 err = parser.Val( val, EDecimal );
       
  1512                 if ( err )
       
  1513                     {
       
  1514                     isValid = EFalse;
       
  1515                     PUSHLOG_WRITE_FORMAT(" parser err: <%d>",err)
       
  1516                     }
       
  1517                 else
       
  1518                     {
       
  1519                     PUSHLOG_WRITE_FORMAT(" day: <%d>",val)
       
  1520                     if ( val < 1 || 31 < val )
       
  1521                         {
       
  1522                         isValid = EFalse;
       
  1523                         }
       
  1524                     }
       
  1525                 }
       
  1526             // Check hour.
       
  1527             if ( isValid )
       
  1528                 {
       
  1529                 parser = aDateTime.Mid( KValidTTimeHourStart,
       
  1530                                         KValidTTimeBlockLength );
       
  1531                 err = parser.Val( val, EDecimal );
       
  1532                 if ( err )
       
  1533                     {
       
  1534                     isValid = EFalse;
       
  1535                     PUSHLOG_WRITE_FORMAT(" parser err: <%d>",err)
       
  1536                     }
       
  1537                 else
       
  1538                     {
       
  1539                     PUSHLOG_WRITE_FORMAT(" hour: <%d>",val)
       
  1540                     if ( 23 < val )
       
  1541                         {
       
  1542                         isValid = EFalse;
       
  1543                         }
       
  1544                     }
       
  1545                 }
       
  1546             // Check minute.
       
  1547             if ( isValid )
       
  1548                 {
       
  1549                 parser = aDateTime.Mid( KValidTTimeMinuteStart,
       
  1550                                         KValidTTimeBlockLength );
       
  1551                 err = parser.Val( val, EDecimal );
       
  1552                 if ( err )
       
  1553                     {
       
  1554                     isValid = EFalse;
       
  1555                     PUSHLOG_WRITE_FORMAT(" parser err: <%d>",err)
       
  1556                     }
       
  1557                 else
       
  1558                     {
       
  1559                     PUSHLOG_WRITE_FORMAT(" min: <%d>",val)
       
  1560                     if ( 59 < val )
       
  1561                         {
       
  1562                         isValid = EFalse;
       
  1563                         }
       
  1564                     }
       
  1565                 }
       
  1566             // Check second.
       
  1567             if ( isValid )
       
  1568                 {
       
  1569                 parser = aDateTime.Mid( KValidTTimeSecondStart,
       
  1570                                         KValidTTimeBlockLength );
       
  1571                 err = parser.Val( val, EDecimal );
       
  1572                 if ( err )
       
  1573                     {
       
  1574                     isValid = EFalse;
       
  1575                     PUSHLOG_WRITE_FORMAT(" parser err: <%d>",err)
       
  1576                     }
       
  1577                 else
       
  1578                     {
       
  1579                     PUSHLOG_WRITE_FORMAT(" sec: <%d>",val)
       
  1580                     if ( 59 < val )
       
  1581                         {
       
  1582                         isValid = EFalse;
       
  1583                         }
       
  1584                     }
       
  1585                 }
       
  1586 
       
  1587 	        // insert colon seperating date from time
       
  1588 	        const TInt KColonPosition = 8;
       
  1589 	        aDateTime.Insert( KColonPosition, KCharColon );
       
  1590 
       
  1591             // Now aDateTime has to be in format YYYYMMDD:HHMMSS
       
  1592             }
       
  1593         }
       
  1594 
       
  1595     PUSHLOG_LEAVEFN("CSIContentHandler::IsValidUTCTime")
       
  1596 	return isValid; // aDateTime contains a modified buffer.
       
  1597 	}
       
  1598 
       
  1599 // ---------------------------------------------------------
       
  1600 // CSIContentHandler::AttributeToTTimeL
       
  1601 // ---------------------------------------------------------
       
  1602 //
       
  1603 TBool CSIContentHandler::AttributeToTTimeL
       
  1604                         ( NW_DOM_AttributeHandle_t& aAttrHandle,
       
  1605                           TTime& aConvertedDate ) const
       
  1606     {
       
  1607     PUSHLOG_ENTERFN("CSIContentHandler::AttributeToTTimeL")
       
  1608 
       
  1609     TBool gotDate = EFalse;
       
  1610     NW_Status_t stat = NW_STAT_SUCCESS;
       
  1611     NW_DOM_AttrVal_t attrVal;
       
  1612 
       
  1613     // It is expected to be String or Opaque.
       
  1614     // It may be Opaque, to which we will need a NW_DOM_AttrVal_t structure.
       
  1615     stat = NW_DOM_AttributeHandle_getNextVal( &aAttrHandle, &attrVal );
       
  1616 
       
  1617     if ( stat != NW_STAT_WBXML_ITERATE_MORE )
       
  1618         {
       
  1619         User::LeaveIfError( NwxStatusToErrCode( stat ) );
       
  1620         }
       
  1621     else
       
  1622         {
       
  1623         NW_Uint16 valType = NW_DOM_AttrVal_getType( &attrVal );
       
  1624 
       
  1625         if ( valType == NW_DOM_ATTR_VAL_STRING )
       
  1626             {
       
  1627             CStringOwner* stringOwner = new (ELeave) CStringOwner;
       
  1628             CleanupStack::PushL( stringOwner );
       
  1629 
       
  1630             NW_String_t* val = NW_String_new();
       
  1631             User::LeaveIfNull( val );
       
  1632             stringOwner->SetString( val );
       
  1633             //
       
  1634             stat = NW_DOM_AttrVal_toString( &attrVal, val, iCharEncoding );
       
  1635             User::LeaveIfError( NwxStatusToErrCode( stat ) );
       
  1636             NW_Byte* storage = NW_String_getStorage( val );
       
  1637             NW_Uint16 length = NW_String_getCharCount( val, iCharEncoding );
       
  1638             TPtrC8 dataPtr( storage, length );
       
  1639             HBufC* dataBuf = HBufC::NewMaxLC( dataPtr.Length() );
       
  1640             dataBuf->Des().Copy( dataPtr );
       
  1641             gotDate = ConvertDateTimeL( *dataBuf, aConvertedDate );
       
  1642 
       
  1643             CleanupStack::PopAndDestroy( 2, stringOwner ); // dataBuf,
       
  1644                                                            // stringOwner
       
  1645             }
       
  1646         else if ( valType == NW_DOM_ATTR_VAL_OPAQUE )
       
  1647             {
       
  1648             NW_Uint32 len = 0;
       
  1649             NW_Byte* data = NW_DOM_AttrVal_getOpaque( &attrVal, &len );
       
  1650             User::LeaveIfNull( data );
       
  1651             TPtrC8 dataPtr( data, len );
       
  1652 
       
  1653             HBufC* dateTime = ConvertOpaqueToUtcL( dataPtr );
       
  1654             CleanupStack::PushL( dateTime );
       
  1655             gotDate = ConvertDateTimeL( *dateTime, aConvertedDate );
       
  1656             CleanupStack::PopAndDestroy( dateTime ); // dateTime
       
  1657             }
       
  1658         else
       
  1659             {
       
  1660             User::Leave( KErrNotSupported );
       
  1661             }
       
  1662         }
       
  1663 
       
  1664     PUSHLOG_LEAVEFN("CSIContentHandler::AttributeToTTimeL")
       
  1665     return gotDate; // aConvertedDate contains the result.
       
  1666     }
       
  1667 
       
  1668 // ---------------------------------------------------------
       
  1669 // CSIContentHandler::HandleMessageL
       
  1670 // ---------------------------------------------------------
       
  1671 //
       
  1672 void CSIContentHandler::HandleMessageL( CPushMessage* aPushMsg,
       
  1673                                         TRequestStatus& aStatus )
       
  1674 	{
       
  1675     PUSHLOG_ENTERFN("CSIContentHandler::HandleMessageL")
       
  1676 
       
  1677     __ASSERT_DEBUG( aPushMsg != NULL,
       
  1678                     ContHandPanic( EPushContHandPanMsgNull ) );
       
  1679 
       
  1680 #ifdef __TEST_LOG__
       
  1681     TPtrC8 bodyPtr;
       
  1682     aPushMsg->GetMessageBody( bodyPtr );
       
  1683     PUSHLOG_HEXDUMP( bodyPtr )
       
  1684 #endif // __TEST_LOG__
       
  1685 
       
  1686 	iMessage = aPushMsg;
       
  1687 	iAcknowledge = ETrue;
       
  1688 	SetConfirmationStatus( aStatus );
       
  1689 
       
  1690 	iState = EGarbageCollecting;
       
  1691 	IdleComplete();
       
  1692 
       
  1693     PUSHLOG_LEAVEFN("CSIContentHandler::HandleMessageL")
       
  1694 	}
       
  1695 
       
  1696 // ---------------------------------------------------------
       
  1697 // CSIContentHandler::HandleMessageL
       
  1698 // ---------------------------------------------------------
       
  1699 //
       
  1700 void CSIContentHandler::HandleMessageL( CPushMessage* aPushMsg )
       
  1701 	{
       
  1702     PUSHLOG_ENTERFN("CSIContentHandler::HandleMessageL")
       
  1703 
       
  1704     __ASSERT_DEBUG( aPushMsg != NULL,
       
  1705                     ContHandPanic( EPushContHandPanMsgNull ) );
       
  1706 
       
  1707 #ifdef __TEST_LOG__
       
  1708     TPtrC8 bodyPtr;
       
  1709     aPushMsg->GetMessageBody( bodyPtr );
       
  1710     PUSHLOG_HEXDUMP( bodyPtr )
       
  1711 #endif // __TEST_LOG__
       
  1712 
       
  1713     iAcknowledge = EFalse;
       
  1714 	iMessage = aPushMsg;
       
  1715 
       
  1716 	iState = EGarbageCollecting;
       
  1717 	IdleComplete();
       
  1718 
       
  1719     PUSHLOG_LEAVEFN("CSIContentHandler::HandleMessageL")
       
  1720 	}
       
  1721 
       
  1722 // ---------------------------------------------------------
       
  1723 // CSIContentHandler::CancelHandleMessage
       
  1724 // ---------------------------------------------------------
       
  1725 //
       
  1726 void CSIContentHandler::CancelHandleMessage()
       
  1727 	{
       
  1728     PUSHLOG_ENTERFN("CSIContentHandler::CancelHandleMessage")
       
  1729     Cancel();
       
  1730     PUSHLOG_LEAVEFN("CSIContentHandler::CancelHandleMessage")
       
  1731 	}
       
  1732 
       
  1733 // ---------------------------------------------------------
       
  1734 // CSIContentHandler::CPushHandlerBase_Reserved1
       
  1735 // ---------------------------------------------------------
       
  1736 //
       
  1737 void CSIContentHandler::CPushHandlerBase_Reserved1()
       
  1738     {
       
  1739     }
       
  1740 
       
  1741 // ---------------------------------------------------------
       
  1742 // CSIContentHandler::CPushHandlerBase_Reserved2
       
  1743 // ---------------------------------------------------------
       
  1744 //
       
  1745 void CSIContentHandler::CPushHandlerBase_Reserved2()
       
  1746     {
       
  1747     }
       
  1748 
       
  1749 // ---------------------------------------------------------
       
  1750 // CSIContentHandler::DoCancel
       
  1751 // ---------------------------------------------------------
       
  1752 //
       
  1753 void CSIContentHandler::DoCancel()
       
  1754 	{
       
  1755     PUSHLOG_ENTERFN("CSIContentHandler::DoCancel")
       
  1756 	Complete( KErrCancel );
       
  1757     PUSHLOG_LEAVEFN("CSIContentHandler::DoCancel")
       
  1758 	}
       
  1759 
       
  1760 // ---------------------------------------------------------
       
  1761 // CSIContentHandler::RunL
       
  1762 // ---------------------------------------------------------
       
  1763 //
       
  1764 void CSIContentHandler::RunL()
       
  1765 	{
       
  1766     // Handle errors in RunError().
       
  1767     PUSHLOG_WRITE_FORMAT("iStatus.Int(): %d",iStatus.Int())
       
  1768     User::LeaveIfError( iStatus.Int() );
       
  1769 
       
  1770 	// use active state machine routine to manage activites:
       
  1771 	switch ( iState )
       
  1772 		{
       
  1773 	    case EGarbageCollecting:
       
  1774             {
       
  1775 		    CollectGarbageL();
       
  1776 		    break;
       
  1777             }
       
  1778 	    case EFilteringAndParsing:
       
  1779             {
       
  1780             if ( !FilterPushMsgL() )
       
  1781                 {
       
  1782                 // It did not pass the filter. Done.
       
  1783 	            iState = EDone;
       
  1784 	            IdleComplete();
       
  1785                 }
       
  1786             else
       
  1787                 {
       
  1788                 // Continue.
       
  1789 		        TInt ret = KErrNone;
       
  1790 				PUSHLOG_WRITE("CSIContentHandler::RunL : before trapping parsing.")
       
  1791 				TRAP(ret, ParsePushMsgL());
       
  1792 				PUSHLOG_WRITE_FORMAT("CSIContentHandler::RunL : after trapping parsing. ret = %d", ret)
       
  1793 				if ( ret != KErrNone)
       
  1794 					{
       
  1795 					PUSHLOG_WRITE("CSIContentHandler::RunL : Parsing failed. discarding message.")
       
  1796 					iState = EDone;
       
  1797 					IdleComplete();
       
  1798 					}
       
  1799                 }
       
  1800 		    break;
       
  1801             }
       
  1802 	    case EProcessing:
       
  1803             {
       
  1804 		    ProcessingPushMsgEntryL();
       
  1805 		    break;
       
  1806             }
       
  1807 	    case EDone:
       
  1808             {
       
  1809             PUSHLOG_WRITE("CSIContentHandler EDone")
       
  1810 		    Complete( KErrNone );
       
  1811 		    break;
       
  1812             }
       
  1813 	    default:
       
  1814             {
       
  1815             // JIC.
       
  1816             PUSHLOG_WRITE("CSIContentHandler default Done")
       
  1817 		    Complete( KErrNone );
       
  1818 		    break;
       
  1819             }
       
  1820 		}
       
  1821 	}
       
  1822 
       
  1823 // ---------------------------------------------------------
       
  1824 // CSIContentHandler::RunError
       
  1825 // ---------------------------------------------------------
       
  1826 //
       
  1827 TInt CSIContentHandler::RunError( TInt aError )
       
  1828 	{
       
  1829     PUSHLOG_WRITE_FORMAT("CSIContentHandler::RunError: %d",aError)
       
  1830 
       
  1831 	iState = EDone;
       
  1832 	Complete( aError );
       
  1833 	return KErrNone;
       
  1834 	}
       
  1835