--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/email/emailnotificationhandler/src/EMNXMLContentHandler.cpp Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,572 @@
+/*
+* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Extracts needed attributes from received EMN message.
+*
+*
+*/
+
+
+#include "EMNXMLContentHandler.h"
+#include "EMNLogging.h"
+
+// Used in compares
+_LIT8( KEmnElement, "emn" );
+_LIT8( KMailboxAttribute, "mailbox");
+_LIT8( KTimestampAttribute, "timestamp");
+
+// Used for parsing timestamp attribute's value from ASCII message.
+_LIT( KColonChar, ":" );
+_LIT( KDashChar, "-" );
+_LIT( KDateTimeSeparator, "T" );
+_LIT( KTimezoneSeparator, "Z" );
+
+// Received timestamp string length
+const TInt KEMNLengthOfRecvTimeStamp = 20;
+
+// Index of hour or minute in timestamp string
+const TInt KEMNTimestampIncHour = 5;
+const TInt KEMNTimestampIncHourMinute = 6;
+
+// Constants for getting first or last four bits from byte
+const TInt KEMNUpperBits = 4;
+const TInt KEMNLowerBits = 0xf;
+
+// Constants for date handling
+const TInt KEMNAtLeastDate = 4;
+const TInt KEMNIndexOfMilleniumAndCentury = 0;
+const TInt KEMNIndexOfDecadeAndYear = 1;
+const TInt KEMNIndexOfMonth = 2;
+const TInt KEMNIndexOfDay = 3;
+
+// Constants for time handling
+const TInt KEMNIndexOfHour = 4;
+const TInt KEMNIndexOfMinute = 5;
+
+using namespace Xml;
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::CEMNXMLContentHandler
+//-----------------------------------------------------------------------------
+CEMNXMLContentHandler::CEMNXMLContentHandler(
+ TEMNElement& aElement, TBool aIsAscii ) :
+ iElement( aElement ),
+ iIsAscii( aIsAscii ),
+ iFoundMailboxAttribute( EFalse )
+ {
+ KEMNLOGGER_WRITE("CEMNXMLContentHandler::CEMNXMLContentHandler()");
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::NewL
+//-----------------------------------------------------------------------------
+CEMNXMLContentHandler* CEMNXMLContentHandler::NewL(
+ TEMNElement& aElement,
+ TBool aIsAscii )
+ {
+ CEMNXMLContentHandler* self = NewLC( aElement, aIsAscii );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::NewLC
+//-----------------------------------------------------------------------------
+CEMNXMLContentHandler* CEMNXMLContentHandler::NewLC(
+ TEMNElement& aElement,
+ TBool aIsAscii )
+ {
+ CEMNXMLContentHandler* self =
+ new (ELeave) CEMNXMLContentHandler( aElement, aIsAscii );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::ConstructL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::ConstructL()
+ {
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::~CEMNXMLContentHandler
+//-----------------------------------------------------------------------------
+CEMNXMLContentHandler::~CEMNXMLContentHandler()
+ {
+ KEMNLOGGER_WRITE("CEMNXMLContentHandler::~CEMNXMLContentHandler()");
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnStartDocumentL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnStartDocumentL(
+ const RDocumentParameters& /*aDocParam*/,
+ TInt /*aErrorCode*/ )
+ {
+ KEMNLOGGER_WRITE("CEMNXMLContentHandler::OnStartDocumentL()");
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnEndDocumentL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnEndDocumentL( TInt /*aErrorCode*/ )
+ {
+ KEMNLOGGER_WRITE("<- EMN message data");
+
+ // This EMN message will be discarded if no mailbox attribute found.
+ if ( !iFoundMailboxAttribute )
+ {
+ KEMNLOGGER_WRITE("CEMNXMLContentHandler::OnEndDocumentL(): No mailbox attribute found, leaving.");
+ User::Leave( EEMNMissingMailboxAttribute );
+ }
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnStartElementL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnStartElementL(
+ const RTagInfo& aElement,
+ const RAttributeArray& aAttributes,
+ TInt aErrorCode )
+ {
+ KEMNLOGGER_WRITE("CEMNXMLContentHandler::OnStartElementL()");
+ KEMNLOGGER_WRITE("EMN message data ->");
+
+ // Element name
+ const TDesC8& localPart8 = aElement.LocalName().DesC();
+ KEMNLOGGER_WRITE_FORMAT8("<%s>", localPart8.Ptr() );
+
+ // Attribute(s) of emn element
+ if ( localPart8.Compare( KEmnElement ) == 0 ) // Is emn element
+ {
+ TInt attributeCount = aAttributes.Count();
+
+ for ( TInt n = 0; n < attributeCount; n++ )
+ {
+ const RAttribute& attribute = aAttributes[n];
+ const RTagInfo& nameInfo = attribute.Attribute();
+
+ const TDesC8& localPart8 = nameInfo.LocalName().DesC();
+ const TDesC8& prefix8 = nameInfo.Prefix().DesC();
+ const TDesC8& value8 = attribute.Value().DesC();
+
+ // Mailbox attribute is similar to both ascii and binary
+ if ( localPart8.Compare( KMailboxAttribute ) == 0)
+ {
+ KEMNLOGGER_WRITE_FORMAT8("mailbox=%s", value8.Ptr() );
+ // Read the whole value of mailbox attribute and copy that
+ // to iElement. Conversion happens from 8-bit to 16 bit
+ // unicode.
+ iElement.mailbox.Copy( value8.Left( KAOMailboxAttributeLength ) );
+ iFoundMailboxAttribute = ETrue;
+ }
+ // Timestamp attribute is in different form in ascii than in binary
+ // so we need to extract it with different methods.
+ else if ( localPart8.Compare( KTimestampAttribute ) == 0 )
+ {
+ KEMNLOGGER_WRITE_FORMAT8("timestamp=%s", value8.Ptr() );
+ // NOTE: Currently timestamp attribute is omitted.
+ /* This code branch will be commented out when there is some nice
+ use case for timestamp.
+ if ( iIsAscii )
+ {
+ HandleXMLAttributesL( localPart8, value8 );
+ }
+ else
+ {
+ HandleWBXMLAttributesL( localPart8, value8 );
+ }
+ */
+ }
+ // Something else than mailbox or timestamp attribute
+ else
+ {
+ KEMNLOGGER_WRITE_FORMAT28("Unknown attribute: %s=%s", localPart8.Ptr(), value8.Ptr() );
+ }
+ }
+ }
+ else // No emn element found
+ {
+ KEMNLOGGER_WRITE_FORMAT8("%s\">", localPart8.Ptr() );
+ User::Leave( EEMNMissingEMNElement );
+ }
+
+ User::LeaveIfError( aErrorCode );
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::HandleXMLAttributes
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::HandleXMLAttributesL(
+ const TDesC8& aAttributeName8,
+ const TDesC8& aAttributeValue8 )
+ {
+ // Currently only timestamp attribute is handled here. Mailbox attribute
+ // is same for both XML and WBXML.
+ if ( aAttributeName8.Compare( KTimestampAttribute ) == 0 )
+ {
+ iElement.timestamp = NULL;
+
+ TPtrC8 p8( aAttributeValue8.Ptr(), aAttributeValue8.Length() );
+ HBufC* tmpBuf = HBufC::NewLC( aAttributeValue8.Length() );
+ // Copies 8 bit to 16 bit and makes a new copy from heap
+ tmpBuf->Des().Copy( p8 );
+ TPtr ptr = tmpBuf->Des();
+
+ if ( ptr.Length() == KEMNLengthOfRecvTimeStamp )
+ {
+ // Parse received timestamp to be in a form, which can be set to TTime
+ // "2010-12-31T00:01:00Z" != YYYYMMDD:HHMMSS
+ TInt pos = ptr.Find( KColonChar );
+ while ( pos != KErrNotFound )
+ {
+ ptr.Delete( pos, 1 );
+ pos = ptr.Find( KColonChar );
+ }
+
+ // "2010-12-31T000100Z" != YYYYMMDD:HHMMSS
+ pos = ptr.Find( KDashChar );
+ while ( pos != KErrNotFound )
+ {
+ ptr.Delete( pos, 1 );
+ pos = ptr.Find( KDashChar );
+ }
+
+ // "20101231T000100Z" != YYYYMMDD:HHMMSS
+ pos = ptr.Find( KDateTimeSeparator );
+ while ( pos != KErrNotFound )
+ {
+ ptr.Replace( pos, 1, KColonChar );
+ pos = ptr.Find( KDateTimeSeparator );
+ }
+
+ // "20101231:000100Z" != YYYYMMDD:HHMMSS
+ pos = ptr.Find( KTimezoneSeparator );
+ while ( pos != KErrNotFound )
+ {
+ ptr.Delete( pos, 1 );
+ pos = ptr.Find( KTimezoneSeparator );
+ }
+
+ // "20101231:000100" == YYYYMMDD:HHMMSS, but day and month must be
+ // decreased by one, because those are offset from zero and we
+ // received them in offset from one.
+
+ /*
+ * if MM == 09 -> MM = 08
+ * if MM == 10 -> MM = 09
+ * if MM == 11 -> MM = 10
+ */
+ if ( ( ptr[4] == '1' ) && ( ptr[5] == '0' ) ) // CSI: 47 # see comments
+ {
+ ptr[4] = ( ptr[4] - 0x1 ); // 1 -> 0
+ ptr[5] = ( ptr[5] + 0x9 ); // 0 -> 9
+ }
+ else
+ {
+ ptr[5] = ( ptr[5] - 0x1 ); // n -> n-1
+ }
+
+ /*
+ * if DD == 09 -> DD = 08
+ * if DD == 13 -> DD = 12
+ * if DD == 28 -> DD = 27
+ * if DD == 31 -> DD = 30
+ * if DD == 10 -> DD = 09
+ * if DD == 20 -> DD = 19
+ * if DD == 30 -> DD = 29
+ */
+ if ( ( ( ptr[6] == '1' ) || // CSI: 47 # see comments
+ ( ptr[6] == '2' ) || // CSI: 47 # see comments
+ ( ptr[6] == '3' ) ) && ( ptr[7] ) == '0' ) // CSI: 47 # see comments
+ {
+ ptr[6] = ( ptr[6] - 0x1 ); // n -> n-1
+ ptr[7] = ( ptr[7] + 0x9 ); // 0 -> 9
+ }
+ else
+ {
+ ptr[7] = ( ptr[7] - 0x1 ); // n -> n-1
+ }
+
+ // Now the "20101231:000100" should be "20101130:000100"
+ // Make a TTime object from it.
+ TTime time;
+ TInt err = time.Set( ptr );
+ if ( err == KErrNone )
+ {
+ iElement.timestamp = time;
+ }
+ else
+ {
+ iElement.timestamp = NULL;
+ }
+ }
+
+ CleanupStack::PopAndDestroy( tmpBuf );
+ }
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::HandleWBXMLAttributes
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::HandleWBXMLAttributesL(
+ const TDesC8& aAttributeName8,
+ const TDesC8& aAttributeValue8 )
+ {
+ // Currently only timestamp attribute is handled here. Mailbox attribute
+ // is same for both XML and WBXML.
+ if ( aAttributeName8.Compare( KTimestampAttribute ) == 0 )
+ {
+ iElement.timestamp = NULL;
+
+ // Here is an example of received timestamp string: 20 05 11 12 13 14 01
+ // It is 12th of November 2005, 01:14:01 PM
+
+ // Timestamp length must be atleast 4. It means that at least year, month
+ // and day must be given, because those can't be zeros. Hour, minute and
+ // second can be zeros. But not all the Push Content GWs doesn't send those,
+ // so we must handle both situations.
+ TInt timestampLength = aAttributeValue8.Length();
+ if ( timestampLength >= KEMNAtLeastDate )
+ {
+ TDateTime datetime;
+ TInt err;
+ TInt temp1;
+ TInt temp2;
+
+ temp1 = aAttributeValue8[ KEMNIndexOfMilleniumAndCentury ];
+ temp2 = aAttributeValue8[ KEMNIndexOfDecadeAndYear ];
+
+ // Separately parse millenium, century, decade and year
+ TInt year =
+ ( ( temp1 >> KEMNUpperBits ) * 1000 ) + // CSI: 47 # see comments
+ ( ( temp1 & KEMNLowerBits ) * 100 ) + // CSI: 47 # see comments
+ ( ( temp2 >> KEMNUpperBits ) * 10 ) + // CSI: 47 # see comments
+ ( temp2 & KEMNLowerBits );
+
+ temp1 = aAttributeValue8[ KEMNIndexOfMonth ];
+ TInt month =
+ ( ( temp1 >> KEMNUpperBits ) * 10 ) + // CSI: 47 # see comments
+ ( temp1 & KEMNLowerBits );
+
+ temp1 = aAttributeValue8[ KEMNIndexOfDay ];
+ TInt day =
+ ( ( temp1 >> KEMNUpperBits ) * 10 ) + // CSI: 47 # see comments
+ ( temp1 & KEMNLowerBits );
+
+ err = datetime.SetYear( year );
+ if ( err != KErrNone )
+ {
+ User::Leave( EEMNInvalidYear );
+ }
+
+ err = datetime.SetMonth( static_cast<TMonth>( month - 1 ) );
+ if ( err != KErrNone )
+ {
+ User::Leave( EEMNInvalidMonth );
+ }
+
+ err = datetime.SetDay( day - 1 );
+ if ( err != KErrNone )
+ {
+ User::Leave( EEMNInvalidDay );
+ }
+
+ // There might not be hour, minute and second in EMN message
+ if ( timestampLength > KEMNAtLeastDate )
+ {
+ // At least hour
+ if ( timestampLength >= KEMNTimestampIncHour )
+ {
+ temp1 = aAttributeValue8[ KEMNIndexOfHour ];
+ TInt hour = ( ( temp1 >> KEMNUpperBits ) * 10 ) + // CSI: 47 # see comments
+ ( temp1 & KEMNLowerBits );
+
+ err = datetime.SetHour( hour );
+ if ( err != KErrNone )
+ {
+ User::Leave( EEMNInvalidHour );
+ }
+ }
+
+ // At least hour and minute
+ if ( timestampLength >= KEMNTimestampIncHourMinute )
+ {
+ temp1 = aAttributeValue8[ KEMNIndexOfMinute ];
+ TInt minute =
+ ( ( temp1 >> KEMNUpperBits ) * 10 ) + // CSI: 47 # see comments
+ ( temp1 & KEMNLowerBits );
+
+ err = datetime.SetMinute( minute );
+ if ( err != KErrNone )
+ {
+ User::Leave( EEMNInvalidMinute );
+ }
+ }
+ }
+ else
+ {
+ datetime.SetHour( 0 );
+ datetime.SetMinute( 0 );
+ }
+
+ // At this point, datetime should be well formed, so no need to do extra
+ // checks.
+ TTime time( datetime );
+
+ iElement.timestamp = time;
+ KEMNLOGGER_WRITE_DATETIME("timestamp=", time );
+ }
+ else
+ {
+ KEMNLOGGER_WRITE("Timestamp provided, but not valid ==> EMN discarded!" );
+ KEMNLOGGER_WRITE_FORMAT("Timestamp length was %d", aAttributeValue8.Length() );
+
+ // Timestamp attribute was found, but its format was not valid.
+ User::Leave( EEMNInvalidTimestampAttribute );
+ }
+ }
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::CEMNXMLContentHandler
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnEndElementL(
+ const RTagInfo& aElement,
+ TInt /*aErrorCode*/ )
+ {
+ const TDesC8& localPart8 = aElement.LocalName().DesC();
+ KEMNLOGGER_WRITE_FORMAT8("</%s>", localPart8.Ptr() );
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnContentL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnContentL(
+ const TDesC8& /*aData8*/,
+ TInt /*aErrorCode*/ )
+ {
+ // Content of an EMN message should always be empty.
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnStartPrefixMappingL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnStartPrefixMappingL(
+ const RString& /*aPrefix*/,
+ const RString& /*aUri*/,
+ TInt /*aErrorCode*/ )
+ {
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnEndPrefixMappingL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnEndPrefixMappingL(
+ const RString& /*aPrefix*/,
+ TInt /*aErrorCode*/ )
+ {
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnIgnorableWhiteSpaceL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnIgnorableWhiteSpaceL(
+ const TDesC8& /*aBytes*/,
+ TInt /*aErrorCode*/ )
+ {
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnSkippedEntityL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnSkippedEntityL(
+ const RString& /*aName*/,
+ TInt /*aErrorCode*/ )
+ {
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnProcessingInstructionL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnProcessingInstructionL(
+ const TDesC8& /* aTarget8*/,
+ const TDesC8& /*aData8*/,
+ TInt /*aErrorCode*/ )
+ {
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnExtensionL
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnExtensionL(
+ const RString& /*aData*/,
+ TInt /*aToken*/,
+ TInt /*aErrorCode*/ )
+ {
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::OnError
+//-----------------------------------------------------------------------------
+void CEMNXMLContentHandler::OnError( TInt __DEBUG_ONLY( aError ) )
+ {
+ KEMNLOGGER_WRITE_FORMAT("CEMNXMLContentHandler::OnError() aError = %d", aError );
+
+#ifdef _DEBUG
+ // No actions taken, if there is something wrong with elements or attributes
+ // in received EMN message. This is because OMA EMN spesification says that
+ // received message can be discarded if it is not valid or well-formed. This
+ // error handling is just for debugging purposes.
+ switch ( aError )
+ {
+ case EEMNMissingEMNElement:
+ KEMNLOGGER_WRITE("No EMN element found.");
+ break;
+
+ case EEMNMissingMailboxAttribute:
+ KEMNLOGGER_WRITE("Mailbox attribute not found.");
+ break;
+
+ case EEMNMissingTimestampAttribute:
+ KEMNLOGGER_WRITE("Timestamp attribute not found.");
+ break;
+
+ // Received timestamp attribute did not contain proper date and time.
+ case EEMNInvalidTimestampAttribute:
+
+ // Following errors indicates that values were not in acceptable ranges
+ case EEMNInvalidYear:
+ case EEMNInvalidMonth:
+ case EEMNInvalidDay:
+ case EEMNInvalidMinute:
+ case EEMNInvalidHour:
+ KEMNLOGGER_WRITE("Timestamp attribute found, but with invalid value.");
+ break;
+ default:
+ KEMNLOGGER_WRITE("Invalid error code, where we got it?.");
+ }
+#endif
+ }
+
+//-----------------------------------------------------------------------------
+// CEMNXMLContentHandler::GetExtendedInterface
+//-----------------------------------------------------------------------------
+TAny* CEMNXMLContentHandler::GetExtendedInterface( const TInt32 )
+ {
+ KEMNLOGGER_WRITE("CEMNXMLContentHandler::GetExtendedInterface()");
+ return NULL;
+ }
+