networkprotocolmodules/suplprotocolmodule/SuplProtocol/src/suplstatehandlerbase.cpp
changeset 36 b47902b73a93
parent 0 9cfd9a3ee49c
equal deleted inserted replaced
35:a2efdd544abf 36:b47902b73a93
       
     1 // Copyright (c) 2008-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 // This file provides the implementation of the base class for
       
    15 // protocol states used in the SUPL Protocol Module.
       
    16 // 
       
    17 //
       
    18 
       
    19 /**
       
    20  @file
       
    21  @internalTechnology
       
    22  @deprecated
       
    23 */
       
    24 
       
    25 #include "suplstatehandlerbase.h"
       
    26 #include "supldevloggermacros.h"
       
    27 #include "suplend.h"
       
    28 #include "suplgatewayinterface.h"
       
    29 
       
    30 /** Standard constructor.
       
    31 @param aMachine A reference to the parent state machine.
       
    32 */  
       
    33 CSuplStateHandlerBase::CSuplStateHandlerBase(CSuplFsmSessionBase& aMachine)
       
    34 : iMachine(aMachine)
       
    35 	{
       
    36 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::CSuplStateHandlerBase() Begin\n");
       
    37 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::CSuplStateHandlerBase() End\n");
       
    38 	}
       
    39 
       
    40 
       
    41 /** Standard destructor.
       
    42 */  
       
    43 CSuplStateHandlerBase::~CSuplStateHandlerBase()
       
    44 	{
       
    45 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::~CSuplStateHandlerBase() Begin\n");
       
    46 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::~CSuplStateHandlerBase() End\n");
       
    47 	}
       
    48 
       
    49 
       
    50 /**
       
    51 Utility method to retrieve the location Id in from the store
       
    52 @param Pointer to the location Id. Caller owns the heap object created.
       
    53 */
       
    54 TBool CSuplStateHandlerBase::BuildLocationIdL(CSuplLocationId*& aLocationId)
       
    55 {
       
    56 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::BuildLocationIdL() Begin\n");
       
    57 	TBool ret = EFalse;
       
    58 	CSuplLocationId* ptr = NULL;
       
    59 
       
    60 	//  Location ID is constructed with network information
       
    61 	// stored by the state machine.
       
    62 
       
    63 	RMobilePhone::TMobilePhoneNetworkInfoV1 networkInfo;
       
    64 	RMobilePhone::TMobilePhoneLocationAreaV1 locationArea;
       
    65 
       
    66 	if(iMachine.IsNetworkInfoAvailable())
       
    67 		{
       
    68 		iMachine.RetrieveStoredNetworkInfo(networkInfo, locationArea);
       
    69 		
       
    70 		switch(networkInfo.iMode)
       
    71 			{
       
    72 			case RMobilePhone::ENetworkModeGsm:
       
    73 				{
       
    74 				RMobilePhone::TMobilePhoneCellInfoV9 cellInfo;
       
    75 				ptr = CSuplLocationId::NewL(ESuplLocationTypeGsm);
       
    76 				aLocationId = ptr;
       
    77 				TLex(networkInfo.iCountryCode).Val(aLocationId->iGsmCellInfo->iRefMCC);
       
    78 				TLex(networkInfo.iNetworkId).Val(aLocationId->iGsmCellInfo->iRefMNC);
       
    79 				aLocationId->iGsmCellInfo->iRefLAC = locationArea.iAreaKnown?locationArea.iLocationAreaCode:0;
       
    80 				aLocationId->iGsmCellInfo->iRefCI  = locationArea.iCellId;
       
    81 				if(iMachine.RetrieveStoredCellInfo(cellInfo))
       
    82 					{
       
    83 					aLocationId->iGsmCellInfo->iTA = cellInfo.iTimingAdvance;			
       
    84 					}
       
    85 				ret = ETrue;
       
    86 				}
       
    87 			break;
       
    88 
       
    89 			case RMobilePhone::ENetworkModeWcdma:
       
    90 				ptr = CSuplLocationId::NewL(ESuplLocationTypeWcdma);
       
    91 				aLocationId = ptr;
       
    92 				TLex(networkInfo.iCountryCode).Val(aLocationId->iWcdmaCellInfo->iRefMCC);
       
    93 				TLex(networkInfo.iNetworkId).Val(aLocationId->iWcdmaCellInfo->iRefMNC);
       
    94 				aLocationId->iWcdmaCellInfo->iRefUC  = locationArea.iCellId;
       
    95 				ret = ETrue;
       
    96 			break;
       
    97 			
       
    98 			default: // only GSM and WCDMA networks are supported
       
    99 				ret = EFalse;
       
   100 			 break;
       
   101 			}
       
   102 
       
   103 		}
       
   104 		
       
   105 	if(ptr != NULL)
       
   106 		{
       
   107 		RMobilePhone::TMobilePhoneCellInfoV9 cellInfo;
       
   108 		if(iMachine.RetrieveStoredCellInfo(cellInfo))
       
   109 			{
       
   110 			switch(cellInfo.iStatus)
       
   111 				{
       
   112 				case RMobilePhone::ECellInfoStatusNotCurrent:
       
   113 					ptr->iStatus = ESuplLocStatusStale;
       
   114 					break;
       
   115 				case RMobilePhone::ECellInfoStatusCurrent:
       
   116 					ptr->iStatus = ESuplLocStatusCurrent;				
       
   117 					break;				
       
   118 				default:
       
   119 				case RMobilePhone::ECellInfoStatusUnknown:
       
   120 					ptr->iStatus = ESuplLocStatusUnknown;
       
   121 					break;	
       
   122 				}
       
   123 			}
       
   124 		else
       
   125 			{
       
   126 			ptr->iStatus = ESuplLocStatusCurrent;
       
   127 			}
       
   128 		}
       
   129 
       
   130 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::BuildLocationIdL() End\n");
       
   131 	return ret;	
       
   132 }
       
   133 
       
   134 /** Actions on entering state EStatePositioningInProgress
       
   135 Events conductive to (re)entering this state are a SUPL POS
       
   136 message received from the SLP or a request from the positioning
       
   137 state machine for sending a SUPL POS with a positining protocol
       
   138 payload.
       
   139 */
       
   140 TBool CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL()
       
   141 	{
       
   142 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() Begin\n");
       
   143 	TBool actionsTaken = EFalse;
       
   144 
       
   145 	// Check first if a positioning payload is available in the event
       
   146 	// store for sending out
       
   147 	const CSuplPosPayload* constPosPayload = iMachine.RetrievePosPayload();
       
   148 	CSuplPosPayload* posPayload = const_cast <CSuplPosPayload*> (constPosPayload);
       
   149 	if (posPayload)
       
   150 		{
       
   151 		ASSERT(iMachine.IsSessionConnected());
       
   152 
       
   153 		// Set payload in a SUPL POS 
       
   154 		CSuplPos* suplPos = CSuplPos::NewLC(ETrue);
       
   155 		suplPos->SetPosPayload(posPayload);
       
   156 
       
   157 		CSuplSessionId* msgId = iMachine.MessageSessionId();
       
   158 		
       
   159 		suplPos->SetSessionId(*msgId);
       
   160 		
       
   161 		CleanupStack::Pop(suplPos);
       
   162 		// Ask the Connection Manager to send the SUPL POS message
       
   163 		iMachine.Observer().ConnectionManager().SendMessage(suplPos, iMachine.SessionId().SessionNum());
       
   164 		
       
   165 		// If this was the last of the SUPL POS messages (positioning state machine
       
   166 		// has terminated), start the SUPL END timer.
       
   167 		if (iMachine.RetrievePositioningSessionEnded())
       
   168 			{
       
   169 			iMachine.StartSuplEndTimer();
       
   170 			}
       
   171 		
       
   172 		actionsTaken = ETrue;
       
   173 		}
       
   174 	else 
       
   175 		{
       
   176 		// There must be a SUPL POS in the event store
       
   177 		CSuplMessageBase* suplMessage = const_cast <CSuplMessageBase*> (iMachine.RetrieveSuplMessage());
       
   178 		ASSERT(suplMessage != NULL);
       
   179 		ASSERT(CSuplMessageBase::ESuplPos == suplMessage->MessageType());
       
   180 
       
   181 		if ((suplMessage != NULL) && (CSuplMessageBase::ESuplPos == suplMessage->MessageType()))
       
   182 			{
       
   183 			CSuplPos* suplPosMessage = static_cast <CSuplPos*>(suplMessage);
       
   184 
       
   185 			// make sure the session id matches the one received in earlier messages
       
   186 			CSuplSessionId *sessId = CSuplSessionId::NewLC();
       
   187 			suplPosMessage->GetSessionId(*sessId);
       
   188 			if (! ((*(iMachine.MessageSessionId())) == (*sessId)))
       
   189 				{
       
   190 				iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt,CSuplFsmSessionBase::EReasonInvalidSessId);
       
   191 				// Store received session Id for sending later in SUPL END as per SUPL specification
       
   192 				CleanupStack::Pop(sessId);
       
   193 				iMachine.SetMessageSessionId(sessId); // ownership transferred
       
   194 				delete suplPosMessage;
       
   195 				SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() End\n");
       
   196 				return actionsTaken;
       
   197 				}
       
   198 			else
       
   199 				{
       
   200 				CleanupStack::PopAndDestroy(sessId);
       
   201 				}
       
   202 			// Extract the payload
       
   203 			posPayload = suplPosMessage->PosPayload();
       
   204 			ASSERT(posPayload != NULL);
       
   205 			if (posPayload)
       
   206 				{
       
   207 				// send the payload to the positioning fsm
       
   208 				iMachine.PositioningFsm()->ProcessPositioningMessage(posPayload);
       
   209 				}
       
   210 
       
   211 			// Delete the SUPL POS message
       
   212 			delete suplPosMessage;
       
   213 			actionsTaken = ETrue;			
       
   214 			}
       
   215 		}
       
   216 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositioningInProgressStateL() End\n");
       
   217 	return actionsTaken;
       
   218 	}
       
   219 
       
   220 /** Actions on entering state EStatePositionReceived
       
   221 This method extracts a position from a SUPL END message and
       
   222 sends it to LBS.
       
   223 */
       
   224 TBool CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL()
       
   225 	{
       
   226 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() Begin\n");
       
   227 	TBool actionsTaken = EFalse;
       
   228 
       
   229 	// Extract the position from the SUPL END in the event store and send to
       
   230 	// LBS in a ProcessLocationUpdate method
       
   231 	TPosition position;
       
   232 
       
   233 	// There must be a SUPL END in the store
       
   234 	CSuplMessageBase* suplMessage = const_cast <CSuplMessageBase*> (iMachine.RetrieveSuplMessage());
       
   235 	
       
   236 	ASSERT(suplMessage != NULL);
       
   237 	ASSERT(CSuplMessageBase::ESuplEnd == suplMessage->MessageType());
       
   238 
       
   239 	if ((suplMessage != NULL) && (CSuplMessageBase::ESuplEnd == suplMessage->MessageType()))
       
   240 		{
       
   241 		
       
   242  		CSuplEnd* suplEndPtr = static_cast <CSuplEnd*>(suplMessage);
       
   243  		
       
   244  		// make sure the session id matches the one received in earlier messages
       
   245 		CSuplSessionId *sessId = CSuplSessionId::NewLC();
       
   246 		suplEndPtr->GetSessionId(*sessId);
       
   247 		
       
   248 		// Compare only the SET session ID as this may be the first message we get from
       
   249 		// the SLP and the SLP session ID is not yet known.
       
   250 		CSuplSetSessionId* receivedSetSessId = (*(iMachine.MessageSessionId())).iSetSessionId;
       
   251 		CSuplSetSessionId* storedSetSessId = (*sessId).iSetSessionId;
       
   252 		if (! ((*receivedSetSessId)== (*storedSetSessId)))
       
   253 			{
       
   254 			iMachine.CancelMachine(CSuplFsmSessionBase::ECancelSuplProt,CSuplFsmSessionBase::EReasonInvalidSessId);
       
   255 			// Store received session Id for sending later in SUPL END as per SUPL specification
       
   256 			CleanupStack::Pop(sessId);
       
   257 			iMachine.SetMessageSessionId(sessId); // ownership transferred
       
   258 			delete suplEndPtr;
       
   259 			SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() End\n");
       
   260 			return actionsTaken;
       
   261 			}
       
   262 		else
       
   263 			{
       
   264 			CleanupStack::PopAndDestroy(sessId);
       
   265 			}
       
   266  
       
   267 		// There must be a position in the SUPL END
       
   268 		ASSERT(suplEndPtr->PositionPresent());
       
   269 		if (suplEndPtr->PositionPresent())
       
   270 			{
       
   271  			suplEndPtr->GetPosition(position);
       
   272  			
       
   273 			// Use position to build a TPositionInfo object
       
   274 			// and send it to LBS
       
   275 			TPositionInfo pos;
       
   276 			pos.SetPosition(position);
       
   277 			const TPositionModuleId id = {KSuplv1UidValue};
       
   278 			pos.SetModuleId(id);
       
   279 			pos.SetUpdateType(EPositionUpdateGeneral);
       
   280 			pos.SetPositionModeReason(EPositionModeReasonNone);
       
   281 			
       
   282 			// If the position has been received and no positioning session
       
   283 			// has taken place, then the position is the reference location
       
   284 			// calculated based on cell-id.
       
   285 			if (!iMachine.PosSessionConducted())
       
   286 				{
       
   287 				pos.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork);	
       
   288 				}
       
   289 			else
       
   290 				{
       
   291 				// Position calculated in Terminal Assisted mode unless the 
       
   292 				// SUPL END has an error code, in which case the position is
       
   293 				// the reference location.
       
   294 				if(suplEndPtr->StatusCodePresent())
       
   295 					{
       
   296 					pos.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork);	
       
   297 					}					
       
   298 				else
       
   299 					{
       
   300 					pos.SetPositionMode(TPositionModuleInfo::ETechnologyNetwork | TPositionModuleInfo::ETechnologyAssisted);
       
   301 					}
       
   302 				}
       
   303 
       
   304 			iMachine.Observer().Gateway().NetworkLocationInd(iMachine.LbsSessionId(), pos);
       
   305  
       
   306 			actionsTaken = ETrue;
       
   307 			}
       
   308 			
       
   309 		// SUPL POS message no longer needed
       
   310 		delete suplEndPtr;
       
   311 		}
       
   312 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromPositionReceivedStateL() End\n");
       
   313 	return actionsTaken;
       
   314 	}
       
   315 
       
   316 
       
   317 /** Actions on entering state EStateSuplSessionEnded
       
   318 
       
   319 Send a SUPL END message to the SUPL server. This state is reached
       
   320 after the state machine was cancelled for some reason.
       
   321 */
       
   322 TBool CSuplStateHandlerBase::EntryActionsFromSuplSessionEndedStateL()
       
   323 	{
       
   324 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromSuplSessionEndedStateL() Begin\n");
       
   325 	TBool verRequired = EFalse;
       
   326 	TBool statusCodeRequired = ETrue;
       
   327 	// Send a SUPL END to the SLP. Most likely reason to be here is 
       
   328 	// that the machine is cancelling due to explicit client cancel, a
       
   329 	// client privacy rejection, an error or a timeout. If so, the
       
   330 	// cancel source and reason can be taken from the event store.
       
   331 	//
       
   332 	// The only other use case where we end up in here is for MTLRs
       
   333 	// where the SUPL INIT has specified "no Position".
       
   334 	
       
   335 	
       
   336 	// Take cancel source and reason from the event store
       
   337 	CSuplFsmSessionBase::TCancelSource source;
       
   338 	CSuplFsmSessionBase::TCancelReason reason;
       
   339 	iMachine.RetrieveCancelInfo(source,reason);
       
   340 		
       
   341 	// work out the reason code to set in a SUPL END
       
   342 	TSuplStatusCode statusCode = ESuplStatusUnspecified;
       
   343 	switch (source)
       
   344 		{
       
   345 		case CSuplFsmSessionBase::ECancelNone:
       
   346 			// Not here after a cancel...assuming
       
   347 			// there has been a SUPL INIT with "no position"
       
   348 			// and we are here to send a SUPL END with privacy 
       
   349 			// acceptance.
       
   350 
       
   351 			verRequired = ETrue;
       
   352 			statusCodeRequired = ETrue;
       
   353 			statusCode = ESuplStatusConsentGrantedByUser;
       
   354 
       
   355 			break;
       
   356 		case CSuplFsmSessionBase::ECancelNetwork:
       
   357 			
       
   358 			switch (reason)
       
   359 				{
       
   360 				case CSuplFsmSessionBase::EReasonInsuficcientSecurity:
       
   361 					// no matching supl status code
       
   362 					statusCode = ESuplStatusUnspecified;
       
   363 					break;
       
   364 				// Since the connection manager performs the decoding
       
   365 				// of received SUPL messages, all of the errors in decoding
       
   366 				// show as having ECancelNetwork source, hence:
       
   367 				case CSuplFsmSessionBase::EReasonParsingError:
       
   368 					statusCode = ESuplStatusProtocolError;
       
   369 					break;
       
   370 				case CSuplFsmSessionBase::EReasonDataMissing:
       
   371 					statusCode = ESuplStatusDataMissing;
       
   372 					break;
       
   373 				case CSuplFsmSessionBase::EReasonUnexpectedDataValue:
       
   374 					statusCode = ESuplStatusUnexpectedDataValue;
       
   375 					break;
       
   376 				default:
       
   377 					statusCode = ESuplStatusUnspecified;
       
   378 					break;
       
   379 				}
       
   380 			break;
       
   381 
       
   382 		case CSuplFsmSessionBase::ECancelPosProt:
       
   383 			statusCode = ESuplStatusPosMethodFailure;
       
   384 			break;
       
   385 
       
   386 		case CSuplFsmSessionBase::ECancelSuplProt:
       
   387 			switch (reason)
       
   388 				{
       
   389 				case CSuplFsmSessionBase::EReasonMethodMismatch:
       
   390 					statusCode = ESuplStatusPosMethodMismatch;
       
   391 					break;			
       
   392 				case CSuplFsmSessionBase::EReasonInvalidSessId:
       
   393 					statusCode = ESuplStatusInvalidSessionId;
       
   394 					break;
       
   395 				case CSuplFsmSessionBase::EReasonUnexpectedMessage:
       
   396 					statusCode = ESuplStatusUnexpectedMessage;
       
   397 					break;
       
   398 				default:
       
   399 					statusCode = ESuplStatusUnspecified;
       
   400 					break;
       
   401 				}
       
   402 			break;		
       
   403 
       
   404 		case CSuplFsmSessionBase::ECancelClient:
       
   405 			// no matching status code in SUPL
       
   406 			if (CSuplFsmSessionBase:: EReasonPrivacyRejected == reason)
       
   407 				{
       
   408 				statusCode = ESuplStatusConsentDeniedByUser;
       
   409 				verRequired = ETrue;					
       
   410 				}
       
   411 			else if (CSuplFsmSessionBase::EReasonFutilePosCalc == reason)
       
   412 				{
       
   413 				statusCode = ESuplStatusPosMethodFailure;
       
   414 				}
       
   415 			else 
       
   416 				{
       
   417 				statusCode = ESuplStatusUnspecified;	
       
   418 				}
       
   419 			break;
       
   420 
       
   421 		case CSuplFsmSessionBase::ECancelClosing:
       
   422 		default:
       
   423 			//No other source of cancel should result in this method being called
       
   424 			ASSERT(EFalse);
       
   425 			break;
       
   426 		}
       
   427 	
       
   428 	// Build and send a SUPL END 
       
   429 	CSuplEnd* suplEndPtr = CSuplEnd::NewLC(ETrue);
       
   430  
       
   431  	if (statusCodeRequired)
       
   432 	 	{
       
   433 		suplEndPtr->SetStatusCode(statusCode);	 		
       
   434 	 	}
       
   435 	
       
   436 	if (verRequired)
       
   437 		{
       
   438 		// Set the Ver field in SUPL END
       
   439 		TBuf8<8> ver;
       
   440 		iMachine.RetrieveVer(ver);
       
   441 		User::LeaveIfError(suplEndPtr->SetVer(ver));
       
   442 		}
       
   443 	
       
   444 	// Set the session Id
       
   445 	CSuplSessionId* msgId = iMachine.MessageSessionId();
       
   446 	suplEndPtr->SetSessionId(*msgId);	
       
   447 	
       
   448 	CleanupStack::Pop(suplEndPtr);
       
   449 	iMachine.Observer().ConnectionManager().SendMessage(suplEndPtr, iMachine.SessionId().SessionNum());
       
   450 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromSuplSessionEndedStateL() End\n");
       
   451 	return ETrue;
       
   452 	}
       
   453 
       
   454 
       
   455 /** Actions on entering state EStateLbsSessionEnded
       
   456 
       
   457 This method informs LBS that the session has ended.
       
   458 */
       
   459 TBool CSuplStateHandlerBase::EntryActionsFromLbsSessionEndedStateL()
       
   460 	{
       
   461 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromLbsSessionEndedStateL() Begin\n");
       
   462 	TBool actionsTaken = EFalse;
       
   463 	
       
   464 	TInt sessionCompletionReason = KErrNone; // reason sent to LBS
       
   465 
       
   466 	// Check the event store to see in the completion reason
       
   467 	// has to be different from KErrNone
       
   468 	// Take cancel source and reason from the event store.
       
   469 	//
       
   470 	CSuplFsmSessionBase::TCancelSource cancelSource;
       
   471 	CSuplFsmSessionBase::TCancelReason cancelReason;
       
   472 	iMachine.RetrieveCancelInfo(cancelSource,cancelReason);
       
   473 	
       
   474 	if (cancelSource != CSuplFsmSessionBase::ECancelNone)
       
   475 		{
       
   476 		// Session was cancelled.  Error code is KErrCancel
       
   477 		// except if network connection is down (KErrDisconnected).
       
   478 		if ((cancelSource == CSuplFsmSessionBase::ECancelNetwork)
       
   479 			&& (cancelReason == CSuplFsmSessionBase::EReasonDisconnected))
       
   480 			{
       
   481 			sessionCompletionReason = KErrDisconnected;
       
   482 			}
       
   483 		else
       
   484 			{
       
   485 			sessionCompletionReason = KErrCancel;
       
   486 			}
       
   487 		actionsTaken = ETrue;
       
   488 		}
       
   489 		
       
   490 	// Check if the session was terminated after an unexpected 
       
   491 	// SUPL END or a SUPL END with reason code indicating an error
       
   492 	else if (iMachine.IsUnexpectedSuplEndStored())
       
   493 		{
       
   494 		// Complete with KErrPositionProtocolErr
       
   495 		sessionCompletionReason = KErrPositionProtocolErr;
       
   496 		actionsTaken = ETrue;
       
   497 		}
       
   498 	else
       
   499 		{
       
   500 		// If the session has not been cancelled, there could be a
       
   501 		// SUPL END message in the store (there won't be one if the
       
   502 		// SUPL END carried position information as it is dealt with
       
   503 		// in a previous state).
       
   504 		const CSuplMessageBase* suplEnd = iMachine.RetrieveSuplMessage();
       
   505 
       
   506 		if ((suplEnd != NULL) && (CSuplMessageBase::ESuplEnd == (const_cast <CSuplMessageBase*>(suplEnd))->MessageType()))
       
   507 			{
       
   508 			delete suplEnd;
       
   509 			}
       
   510 			
       
   511 		sessionCompletionReason = KErrNone;
       
   512 		actionsTaken = ETrue;
       
   513 		}
       
   514 
       
   515 	if (actionsTaken)
       
   516 		{
       
   517 		iMachine.Observer().Gateway().SessionCompleteInd(iMachine.LbsSessionId(), sessionCompletionReason);
       
   518 		}
       
   519 	iMachine.SetSessionInProgress(EFalse);
       
   520 	SUPLLOG(ELogP1, "CSuplStateHandlerBase::EntryActionsFromLbsSessionEndedStateL() End\n");
       
   521 	return actionsTaken;
       
   522 	}
       
   523 
       
   524 
       
   525 /** Utility method to convert a numeric string to Binary Coded Decimal string
       
   526 
       
   527 Taken from section 8.3 of the OMA SUPL document UserPlane Location Protocol OMA-TS-ULP-V1-0-20070615-A
       
   528 The BCD string is stored in an 8 octet buffer with 2 digits per octet.
       
   529 Each digit is encoded 0000 to 1001 ( 0 to 9).
       
   530 Bits 8765 of octet n encoding digit 2n
       
   531 Bits 4321 of octet n encoding digit 2(n-1)+1
       
   532 Unused digits in the string are filled with 0xFF
       
   533 
       
   534 */
       
   535 void CSuplStateHandlerBase::ConvertToBcd(TDes8& aBcdString)
       
   536 	{
       
   537 	
       
   538 	const TUint8 KMaxBcdStringLength = 8;
       
   539 	const TUint8 fillBuffer[KMaxBcdStringLength] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
       
   540 	
       
   541 	TBool LeastSignificantNibble(ETrue);
       
   542 	TInt OctetCount = 0;
       
   543 	TChar nextChar;
       
   544 	TUint8 nextOctet = 0;
       
   545 	TLex lexString(*iMachine.Msisdn());
       
   546 	
       
   547 	aBcdString.Zero();
       
   548 	while (!lexString.Eos())
       
   549 		{
       
   550 		nextChar = lexString.Get();
       
   551 		if (nextChar.IsDigit())  // ignore any non-numeric characters
       
   552 			{
       
   553 			if (LeastSignificantNibble)
       
   554 				{
       
   555 				nextOctet = nextChar.GetNumericValue(); //store digit in L.S. nibble
       
   556 				LeastSignificantNibble = EFalse;
       
   557 				}
       
   558 			else
       
   559 				{
       
   560 				nextOctet |= (nextChar.GetNumericValue()<<4); //store digit in M.S. nibble
       
   561 				aBcdString.Append(nextOctet);
       
   562 				OctetCount++;
       
   563 				LeastSignificantNibble = ETrue;
       
   564 				}
       
   565 			}
       
   566 		}
       
   567 	
       
   568 	// All of the decimal string has been converted - deal with an half filled octet
       
   569 	if (!LeastSignificantNibble)
       
   570 		{
       
   571 		nextOctet |= 0xF0;
       
   572 		aBcdString.Append(nextOctet);
       
   573 		OctetCount++;
       
   574 		}
       
   575 	
       
   576 	// Fill remainder of string with 0xFF values
       
   577 	aBcdString.Append(fillBuffer, (KMaxBcdStringLength-OctetCount));
       
   578 	
       
   579 	}
       
   580