messagingfw/wappushfw/plugins/PushContentHandler/CSIAContentHandler.cpp
changeset 0 8e480a14352b
equal deleted inserted replaced
-1:000000000000 0:8e480a14352b
       
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <wapmessage.h>
       
    17 // Local includes
       
    18 //
       
    19 #include "csiacontenthandler.h"
       
    20 #include "clwatcher.h"
       
    21 
       
    22 // System includes
       
    23 //
       
    24 #include <commdb.h>
       
    25 #include "wapdecoder.h"
       
    26 #include <push/cwappushmsgutils.h>
       
    27 
       
    28 const TUid KSIADialogNotifierUid={0x100096f6}; //from WapPushSIADialogNotifier.h
       
    29 _LIT8(KWapPushCmdConnect,"Connect"); // from WapPushSIADialogNotifier.h
       
    30 
       
    31 #if defined(_DEBUG)
       
    32 _LIT(KErrPushMsgNull,	"NULL CPushMessage");
       
    33 #endif
       
    34 
       
    35 //comment out this line if testing without notifier
       
    36 #define _ASK_USER_TO_CONNECT
       
    37 
       
    38 //supported bearers for connection-oriented push
       
    39 const TUint8 KCSDBearer = 0x0A;
       
    40 const TUint8 KGPRSBearer = 0x0B;
       
    41 
       
    42 //bitmasks
       
    43 const TUint8 KPortFlagBitMask = 0x40;
       
    44 const TUint8 KBearerFlagBitMask = 0x80;
       
    45 const TUint8 KAddressLengthBitMask = 0x3F;
       
    46 
       
    47 // Constants
       
    48 _LIT(KReserved, "Reserved");
       
    49 
       
    50 void CSIAContentHandler::CPushHandlerBase_Reserved1()
       
    51 	{
       
    52 	User::Panic(KReserved, KErrNotSupported);
       
    53 	}
       
    54 
       
    55 void CSIAContentHandler::CPushHandlerBase_Reserved2()
       
    56 	{
       
    57 	User::Panic(KReserved, KErrNotSupported);
       
    58 	}
       
    59 
       
    60 /**
       
    61  * The SIA App handler private constructor
       
    62  * Index number : ESIAContentHandlerIndex 
       
    63  */ 
       
    64 CSIAContentHandler::CSIAContentHandler()
       
    65 : CContentHandlerBase()
       
    66 	{
       
    67 	}
       
    68 
       
    69 /**
       
    70  *  This will complete initialization of the object
       
    71  */
       
    72 void CSIAContentHandler::ConstructL()
       
    73 	{
       
    74 	iWapPushUtils = CWapPushMsgUtils::NewL();
       
    75 	iCommDb = CCommsDatabase::NewL(EDatabaseTypeIAP);
       
    76 	CActiveScheduler::Add(this);
       
    77 	}
       
    78 
       
    79 /**
       
    80  * Static Factory Construction
       
    81  *
       
    82  * Version of NewL which leaves nothing
       
    83  * on the cleanup stack
       
    84  */
       
    85 CSIAContentHandler* CSIAContentHandler::NewL()
       
    86 	{
       
    87 	CSIAContentHandler* self = new(ELeave) CSIAContentHandler;
       
    88 	CleanupStack::PushL(self);
       
    89 	self->ConstructL();
       
    90 	CleanupStack::Pop(self);
       
    91 	return self;
       
    92 	}
       
    93 
       
    94 /**
       
    95  * Default d'tor
       
    96  */
       
    97 CSIAContentHandler::~CSIAContentHandler()
       
    98 	{
       
    99 	__LOG_PTR_DEBUG("CSIAContentHandler:: Destructor Called");
       
   100 	delete iWapPushUtils;
       
   101 	delete iCommDb;
       
   102 	}
       
   103 
       
   104 /**
       
   105  * HandleMessage Async. Version
       
   106  *	Takes ownership of Push Message and sets self active to continue
       
   107  *	processing message.
       
   108  *	@param aPushMsg
       
   109  *		CPushMessage to process
       
   110  *	@param aStatus
       
   111  *		request status variable for use in asynchronous operations
       
   112  */
       
   113 void CSIAContentHandler::HandleMessageL(CPushMessage* aPushMsg, TRequestStatus& aStatus)
       
   114 	{
       
   115 	__LOG_PTR_DEBUG("CSIAContentHandler:: HandleMessage Async Func. Called");
       
   116 	__ASSERT_DEBUG( aPushMsg != NULL , User::Panic(KErrPushMsgNull, KErrNone));
       
   117 
       
   118 	iMessage = aPushMsg;
       
   119 	iAcknowledge = ETrue;
       
   120 	SetConfirmationStatus(aStatus);
       
   121 
       
   122 	iState=EParsing;
       
   123 	IdleComplete();
       
   124 	}
       
   125 
       
   126 /**
       
   127  *	Abort handling  
       
   128  */
       
   129 void CSIAContentHandler::CancelHandleMessage()
       
   130 	{
       
   131 	__LOG_PTR_DEBUG("CSIAContentHandler:: CancelHandleMessage Called");
       
   132 	Complete(KErrCancel);
       
   133 	}
       
   134 
       
   135 /**
       
   136  * HandleMessage Sync. Version
       
   137  *	Takes ownership of Push Message and sets self active to continue
       
   138  *	processing message.
       
   139  *	@param aPushMsg
       
   140  *		CPushMessage to process
       
   141  */
       
   142 void CSIAContentHandler::HandleMessageL(CPushMessage* aPushMsg)
       
   143 	{
       
   144 	__LOG_PTR_DEBUG("CSIAContentHandler:: HandleMessage Sync Func. Called");
       
   145 	__ASSERT_DEBUG( aPushMsg != NULL , User::Panic(KErrPushMsgNull, KErrNone));
       
   146 	
       
   147 	iAcknowledge = EFalse;
       
   148 	iMessage = aPushMsg;
       
   149 	
       
   150 	iState = EParsing;
       
   151 	IdleComplete();
       
   152 	}
       
   153 
       
   154 /**
       
   155  * Stop all actions and quit
       
   156  */
       
   157 void CSIAContentHandler::DoCancel()
       
   158 	{
       
   159 	 __LOG_PTR_DEBUG("CSIAContentHandler:: DoCancel Called");
       
   160 	
       
   161 #ifdef _ASK_USER_TO_CONNECT
       
   162 	//cancel notifier if appropriate
       
   163 	if (iState == EOpeningCOconn && iStatus.Int() == KErrNone)
       
   164 		 iNotifier.CancelNotifier(KSIADialogNotifierUid);
       
   165 #endif
       
   166 	
       
   167 	Complete(KErrCancel);
       
   168 	}
       
   169 
       
   170 /**	
       
   171  * Step through the various representative states for handling a message 
       
   172  * 1. Initial State - Parsing SIA Push Msg
       
   173  * 2. Make a CO connection
       
   174  * 3. Delete Content Handler Plugin Owner (i.e self)
       
   175  */
       
   176 void CSIAContentHandler::RunL()
       
   177 	{
       
   178 	__LOG_PTR_DEBUG("CSIAContentHandler:: RunL Called");
       
   179 	// use active state machine routine to manage activites:
       
   180 	switch(iState)
       
   181  		{
       
   182 	case EParsing:
       
   183 		ParsePushMsgL();
       
   184 		break;
       
   185 	case ERequestingConn:
       
   186 		RequestConnectionL();
       
   187 		break;
       
   188 	case EOpeningCOconn:
       
   189 		OpenConnectionL();
       
   190 		break;
       
   191 	case EDone:
       
   192  		Complete(KErrNone);
       
   193 		break;
       
   194 	default:
       
   195 		break;
       
   196 		}
       
   197 	}
       
   198 
       
   199 /**
       
   200  *	This is invoked when RunL Leaves with an error.
       
   201  *	Cleans up and returns.
       
   202  *	@param aError Error passed into this function
       
   203  */
       
   204 TInt CSIAContentHandler::RunError(TInt aError)
       
   205 	{
       
   206 	__LOG_PTR_DEBUG("CSIAContentHandler:: RunError Called"); 
       
   207 	iState=EDone;
       
   208 	Complete(aError);
       
   209 	return KErrNone;
       
   210 	}
       
   211 
       
   212 /**
       
   213  *	Retrieve SIA body, which is in octets, from within CPushMessage,
       
   214  *	parse it for a valid connection point.
       
   215  *	@leave KErrNotFound no valid connection point located
       
   216  *	@leave KErrCorrupt Will leave if the message body contains corrupted data
       
   217  */
       
   218 void CSIAContentHandler::ParsePushMsgL()
       
   219 	{
       
   220 	__LOG_PTR_DEBUG("CSIAContentHandler:: ParsePushMsgL Called");
       
   221 	
       
   222 	// get contact points list from message
       
   223 	ObtainContactPointsListL();
       
   224 	
       
   225 	// got a ContactList so now need to parse this and obtain a TPushConnPoint
       
   226 	TBool foundValidConnectionDetails = EFalse;
       
   227 	TBool moreContactPointsAvailable = ETrue;
       
   228 	// search iContactList for valid connection Point
       
   229 	while (!foundValidConnectionDetails && moreContactPointsAvailable)
       
   230 		{
       
   231 		if (RetrieveContactPoint())
       
   232 			foundValidConnectionDetails = ValidContactPointL();
       
   233 		if (foundValidConnectionDetails == EFalse)
       
   234 			moreContactPointsAvailable = iContactList.Length() > 1;
       
   235 		}
       
   236 	if (!foundValidConnectionDetails)
       
   237 		{
       
   238 		__LOG_PTR_DEBUG("CSIAContentHandler: No valid connection point located.");
       
   239 		User::Leave(KErrNotFound);
       
   240 		}
       
   241 	
       
   242 	// will leave if no connection possible
       
   243 	iState = ERequestingConn;
       
   244 	IdleComplete();
       
   245 	}
       
   246 
       
   247 /** 
       
   248  *	Retrieve contact point details from within SIA content body. This 
       
   249  *	method looks up the owned CPushMessage message body and gets a 
       
   250  *	pointer to it which it then parses to obtain the contact Points
       
   251  *	string only which it sets the iContactList pointer to.
       
   252  *	@leave KErrNotFound	Will leave if the contacts list can not be obtained
       
   253  *	@leave KErrCorrupt Will leave if the message body contains corrupted data
       
   254  */
       
   255 void CSIAContentHandler::ObtainContactPointsListL()
       
   256 	{
       
   257 	__LOG_PTR_DEBUG("CSIAContentHandler::ObtainContactPointsListL Called");
       
   258 	TPtrC8 rFieldValue;
       
   259 	TBool gotList = EFalse;
       
   260 	if (iMessage->GetMessageBody(rFieldValue))
       
   261 		{
       
   262 		TPtrC8 messageBodyPtr = rFieldValue;
       
   263 		TWapBinCodex::TUintvar rMultiByte;
       
   264 		TUint startpos = 1;
       
   265 		TWapBinCodex::ExtractUIntvarL(messageBodyPtr, startpos, rMultiByte);
       
   266 		TUint fieldSize = rMultiByte.iOctetSize;
       
   267 		TUint appIdFieldLength = rMultiByte.iValue;
       
   268 		TUint contactPointOffset = fieldSize + appIdFieldLength + startpos;
       
   269 		// now get Uintvar of ContactPointLen
       
   270 		TWapBinCodex::ExtractUIntvarL(messageBodyPtr, contactPointOffset, rMultiByte);
       
   271 		//actual Contact Points field starts after ContactPointLen uintvar
       
   272 		TUint contactPointLenSize = rMultiByte.iOctetSize;
       
   273 		TUint contactPointLen = rMultiByte.iValue;
       
   274 		TUint index = contactPointOffset + contactPointLenSize;
       
   275 		iContactList.Set(messageBodyPtr.Mid(index, contactPointLen));
       
   276 		if (iContactList.Length())
       
   277 			gotList = ETrue;
       
   278 		}
       
   279 	
       
   280 	// failed to parse the contact points list
       
   281 	if (!gotList)
       
   282 		{
       
   283 		__LOG_PTR_DEBUG("CSIAContentHandler: Invalid Message Body - unable to parse.");
       
   284 		User::Leave(KErrNotFound);
       
   285 		}
       
   286 	}
       
   287 
       
   288 /**
       
   289  *	Parse iContactList string for the first Contact Point.
       
   290  *	If found sets iContactPoint to retrieved point and
       
   291  *	removes this point from iContactList so that any further
       
   292  *	calls will start with the next unused Contact Point in the
       
   293  *	iContactList.
       
   294  *	@return TBool
       
   295  *		returns True if found a contact point
       
   296  *		returns False if no contact point found
       
   297  */
       
   298 TBool CSIAContentHandler::RetrieveContactPoint()
       
   299 	{
       
   300 	__LOG_PTR_DEBUG("CSIAContentHandler:: RetrieveContactPoint Called");
       
   301 	// ensure have the first byte at least which indicates bearer, port and address
       
   302 	// length of ContactPoint within list
       
   303 	if (iContactList.Length() > 1)
       
   304 		{
       
   305 		const TInt KFirstByte = 0;
       
   306 		TUint8 byte = iContactList[KFirstByte];
       
   307 		
       
   308 		// check for bit flags settings
       
   309 		TUint8 bearerFlagPresent = STATIC_CAST(TUint8, byte & KBearerFlagBitMask);
       
   310 		TUint8 portFlagPresent = STATIC_CAST(TUint8, byte & KPortFlagBitMask);
       
   311 
       
   312 		// get address length to calculate length of ContactPoint
       
   313 		TUint8 addressLength = STATIC_CAST(TUint8, byte & KAddressLengthBitMask);
       
   314 
       
   315 		TInt length = 1;
       
   316 		if (bearerFlagPresent)
       
   317 			length++;
       
   318 		if (portFlagPresent)
       
   319 			length += 2;
       
   320 		length += addressLength;
       
   321 
       
   322 		// check not going to access beyond List
       
   323 		if (length > iContactList.Length())
       
   324 			{
       
   325 			// avoid retrying same retrieval and exiting at this point
       
   326 			// set list length to zero as no contact points left in it
       
   327 			const TInt KZero = 0;
       
   328 			iContactList.Set(iContactList.Left(KZero));
       
   329 			return EFalse;
       
   330 			}
       
   331 		iContactPoint.Set(iContactList.Left(length));
       
   332 		// if contact list has no further data will be set to length of zero
       
   333 		TInt pos = length;
       
   334 		TInt count = iContactList.Length() - pos;
       
   335 		iContactList.Set(iContactList.Mid(pos, count));
       
   336 		return ETrue;
       
   337 		}
       
   338 	
       
   339 	return EFalse;
       
   340 	}
       
   341 
       
   342 /**
       
   343  *	Check the current retrieved Contact Point, contained in
       
   344  *	iContactPoint, to check that the connection details are
       
   345  *	valid for a connection-oriented Push session. If the
       
   346  *	iContactPoint passes the tests iConnPoint is set and 
       
   347  *	this value will be used for opening a connection.
       
   348  *	@return TBool
       
   349  *		Returns True if ContactPoint is valid
       
   350  *		retruns False if invalid contact point
       
   351  *	@leave CCommsDatabase::OpenViewMatchingTextLC
       
   352  *		CommDb methods can Leave - so just propogate
       
   353  *		as can't verfiy address and security.
       
   354  *	@leave CCommsDbTableView::ReadBoolL
       
   355  */
       
   356 TBool CSIAContentHandler::ValidContactPointL()
       
   357 	{
       
   358 	__LOG_PTR_DEBUG("CSIAContentHandler:: ValidContactPointL Called");
       
   359 
       
   360 	TBool valid = ETrue;
       
   361 	TUint index = 0;
       
   362 
       
   363 	// check first bit of first byte to see if bearer Type present 
       
   364 	TUint8 byte = iContactPoint[index];
       
   365 	index++;
       
   366 	// will be zero if flag not set - non-zero overwise
       
   367 	TUint8 bearerFlagPresent = STATIC_CAST(TUint8, byte & KBearerFlagBitMask);
       
   368 	TUint8 portFlagPresent = STATIC_CAST(TUint8, byte & KPortFlagBitMask);
       
   369 	// mask off 1st two bits to get the 6 bits representing address length
       
   370 	TUint8 addressLength = STATIC_CAST(TUint8, byte & KAddressLengthBitMask);
       
   371 
       
   372 	//check bearer type
       
   373 	if (bearerFlagPresent)
       
   374 		{
       
   375 		byte = iContactPoint[index];
       
   376 		index++;
       
   377 		if ((byte != KCSDBearer) && (byte != KGPRSBearer))
       
   378 			{
       
   379 			// unsupported bearer
       
   380 			__LOG_PTR_DEBUG("CSIAContentHandler: unsupported Bearer Type");
       
   381 			valid = EFalse;
       
   382 			return valid;
       
   383 			}
       
   384 		}
       
   385 
       
   386 	//set postion of the first byte of the port
       
   387 	TUint portStartByte = index; 
       
   388 	
       
   389 	// get address
       
   390 	if (portFlagPresent)
       
   391 		index += 2;
       
   392 	TPtrC8 address;
       
   393 	address.Set(iContactPoint.Mid(index, addressLength));
       
   394 
       
   395 	//Look up supplied address in commsdb. Leave possible from here on in... 
       
   396 	TPtrC KTableName(WAP_IP_BEARER);
       
   397 	TPtrC KColumnName(WAP_GATEWAY_ADDRESS);
       
   398 	TPtrC KSecurityCol(WAP_SECURITY);
       
   399 	CCommsDbTableView* table = iCommDb->OpenViewMatchingTextLC(KTableName, KColumnName, address); 
       
   400 	
       
   401 	TInt ret = table->GotoFirstRecord();
       
   402 	if (ret == KErrNone)	//address found
       
   403 		{
       
   404 		__LOG_PTR_DEBUG("CSIAContentHandler:: Commdb lookup");
       
   405 
       
   406 		// set port number, using the following logic:
       
   407 		// 1. if port number supplied, use it with an unsecure security setting
       
   408 		// 2. if no port supplied, use the default port for the security setting 
       
   409 		//    returned by the commsdb address lookup
       
   410 		TUint16 port;
       
   411 		if (portFlagPresent)
       
   412 			{
       
   413 			TUint8 portNumHighByte = iContactPoint[portStartByte];
       
   414 			TUint8 portNumlowByte = iContactPoint[portStartByte + 1];
       
   415 			port = STATIC_CAST(TUint16, ((portNumHighByte<<8)|portNumlowByte));
       
   416 			}
       
   417 		else
       
   418 			{
       
   419 			TBool secure;
       
   420 			table->ReadBoolL(KSecurityCol, secure);
       
   421 			 if (secure)
       
   422 				port = KPushPortSecure;
       
   423 			 else
       
   424 				port = KPushPortUnsecure;
       
   425 			}
       
   426 
       
   427 		//set connection point
       
   428 		iConnPoint.iHost = address;
       
   429 		iConnPoint.iPort = port;
       
   430 		}
       
   431 	else	//address lookup failed
       
   432 		{
       
   433 		valid = EFalse;
       
   434 		__LOG_PTR_DEBUG("CSIAContentHandler:: Commdb lookup failed");
       
   435 		}
       
   436 	CleanupStack::PopAndDestroy(); // table
       
   437 
       
   438 	// will only return true if not SMS and address in CommDB
       
   439 	return valid;
       
   440 	}
       
   441 
       
   442 /**
       
   443  *	Start Notifier to inform the user that an SIA request
       
   444  *  has been received and a connection-oriented session is
       
   445  *	required to be initiated.
       
   446  */
       
   447 void CSIAContentHandler::RequestConnectionL()
       
   448 	{
       
   449 	__LOG_PTR_DEBUG("CSIAContentHandler:: RequestConnectionL Called"); 
       
   450 	
       
   451 	iNotifierResponse.SetMax();
       
   452 
       
   453 #ifdef _ASK_USER_TO_CONNECT
       
   454 	User::LeaveIfError(iNotifier.Connect());
       
   455 	iNotifier.StartNotifierAndGetResponse(iStatus, KSIADialogNotifierUid, iConnPoint.iHost, iNotifierResponse);
       
   456 	iState=EOpeningCOconn;
       
   457 	SetActive();
       
   458 #else	//always connect case (notifier not started)
       
   459 	iNotifierResponse = KWapPushCmdConnect;
       
   460 	iState=EOpeningCOconn;
       
   461 	IdleComplete();
       
   462 #endif
       
   463 
       
   464 
       
   465 	}
       
   466 
       
   467 /**
       
   468  *	If user accepts connection request, call Connection Manager 
       
   469  *  with valid Connection Point to initiate connection-oriented 
       
   470  *	session. Handler has now finished and closes down leaving 
       
   471  *	connection manager to carry on.
       
   472  */
       
   473 void CSIAContentHandler::OpenConnectionL()
       
   474 	{
       
   475 	__LOG_PTR_DEBUG("CSIAContentHandler:: OpenConnectionL Called"); 
       
   476 	
       
   477 	//open connection if user accepted	
       
   478 	if ((iStatus.Int() == KErrNone) && (iNotifierResponse == KWapPushCmdConnect))
       
   479 		iManager->CMOpenConnectionL(iConnPoint);
       
   480 	
       
   481 	iState=EDone;
       
   482 	IdleComplete();
       
   483 	}