diff -r 000000000000 -r 094583676ce7 IMPSengine/engsrv/src/impscspsession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IMPSengine/engsrv/src/impscspsession.cpp Thu Dec 17 08:41:52 2009 +0200 @@ -0,0 +1,3805 @@ +/* +* Copyright (c) 2004 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: Session for IMPS. +* +* +*/ + + +// INCLUDE FILES +#include +#include +#include "impsserver.h" +#include "impssession.h" +#include "impssubsession.h" +#include "impscspsession.h" +#include "impsfields.h" +#include "impsutils.h" +#include "impserrors.h" +#include "impstimer.h" +#include "impssendreceive.h" +#include "impsservices.h" +#include "impscommonenums.h" +#include "impssdatautils.h" +#include "impsmessageinterpreterapi.h" +#include "impsdataaccessor.h" +#include "impsdigestbytes.h" +#include "impsvariant.h" +#include "impsalivemanager.h" +#include "impsactivecirmonitor.h" +#include "ImpsVariantAPI.h" +#include "impstidqueue.h" +#include "impsactivecirmonitor.h" + +#ifdef LOCAL_IMPS +#ifndef _FAKE_RESPONSE +#define _FAKE_RESPONSE +#endif +#endif + +#ifdef _FAKE_RESPONSE +#include "impssrvtestutils.h" +#endif + +// MACROS +#ifndef _DEBUG +#define _NO_IMPS_LOGGING_ +#endif + +// CONSTANTS +// Adative polling policy time increment +const TInt KImpsPollIncrement = 10; + +// ================= MEMBER FUNCTIONS ======================= + +CImpsCSPSession::CImpsCSPSession( CImpsServer& aServer, + TImpsSrvSettings& aSettings, + RFs& aFs, + CImpsVariant& aVariant, + TImpsCspVersion aVer ): + iServer( aServer ), + iCSPVersion( aVer ), + iFs( aFs ), + iVariant( aVariant ), + iTransactionList( _FOFF( CTransaction, iLink ) ), //lint !e413 + iRequestList( _FOFF( CReq, iLink ) ), //lint !e413 + iCSPState( EImpsCSPIdle ), + iPendingLogout( EFalse ), + iAliveMgr( NULL ), + iPollTime( KImpsPollTime ), + iPollWasRequested( EFalse ), + iUserId( NULL ), + iIntStatus ( EInternal_NOT_LOGGED ), + iMultiTrans( KImpsMultiTrans ), + iNegoExpiry( ), + iCirManager( NULL ), + iLogoutTID( KNullDesC ), + iConAllowed( ETrue ), + iPendingAlive( EFalse ), + iSAP( NULL ), + iIAP( 0 ), + iPollState( EImpsPollNone ), + iPollInResume( 0 ), + iPendingPDP( EImpsPDPPendNone ), // PDP: + iPendPDPLogout ( EFalse ), // PDP: + iTidSapHistory( NULL ), + iTidCliHistory( NULL ), + iTcpCIRError( EFalse ), + iCancelLogin ( EFalse ) + { + iCSPSessionId = KNullDesC; + iLogCID = KNullDesC; + iTempTid = KNullDesC; + iTempTid2 = KNullDesC; + iMsg = EImpsMessageNone; + iLoginPhase = 1; + iKey1 = NULL; + iKey2 = NULL; + iSettings = aSettings; + } + +// Create and start a new server. + +CImpsCSPSession* CImpsCSPSession::NewL( CImpsServer& aServer, + TImpsSrvSettings& aSettings, + RFs& aFs, + CImpsVariant& aVariant, + TImpsCspVersion aVer ) + { +#ifndef _NO_IMPS_LOGGING_ + if ( aVer == EImpsCspVersion11 ) + { + CImpsClientLogger::Log( _L( "CSPSession: NewL rel200542.2+ WV 1.1" ) ); + } + else + { + CImpsClientLogger::Log( _L( "CSPSession: NewL rel200542.2+ WV 1.2" ) ); + } +#endif + + CImpsCSPSession* self = new ( ELeave ) CImpsCSPSession( aServer, + aSettings, aFs, aVariant, aVer ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CImpsCSPSession::~CImpsCSPSession() + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DESTRUCTOR csp=%d **" ), ( TInt )this ); +#endif + // deallocate all memory + DeleteTransactions(); + DeleteRequests(); + + delete iTransportOut; + + delete iCirManager; + delete iReceiver2; + delete iAllMessages; + delete iRcv; + delete iSnd; + + delete iIdleTimer; + delete iAliveMgr; + + delete iSendQ; + + delete iTCPAddr; + delete iLogPwd; + delete iLogTid; + delete iKey1; + delete iKey2; + delete iUserId; + + delete iSAP; + + if ( iDecoder ) + { + iDecoder->Destroy(); + } + if ( iEncoder ) + { + iEncoder->Destroy(); + } + + delete iPDPIdleTimer; + delete iPDPOpenTimer; + delete iTidSapHistory; + delete iTidCliHistory; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::Destroy() +// ----------------------------------------------------------------------------- +void CImpsCSPSession::Destroy() + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: Destroy csp=%d" ), ( TInt )this ); +#endif + // You MUST delete ip-cir entity before conn-manager entity. + // refer to ImpsIpCirWatcherApi.h. + delete iCirManager; + iCirManager = NULL; + iReceiver2->Destroy(); + delete iReceiver2; + iReceiver2 = NULL; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::ConstructL() +// ----------------------------------------------------------------------------- +void CImpsCSPSession::ConstructL() + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: ConstructL begins csp=%d **" ), ( TInt )this ); +#endif + + iTransportOut = CBufFlat::NewL( KImpsStreamSize / 2 ); + iTransportOut->ResizeL( KImpsStreamSize ); + + iDecoder = NewDecoderL( this ); + iEncoder = NewEncoderL(); + + iTidSapHistory = CImpsTidQueue::NewL(); + iTidCliHistory = CImpsTidQueue::NewL(); + + iSnd = CImpsFields::NewL(); + iRcv = CImpsFields::NewL(); + iIdleTimer = new ( ELeave ) CImpsIdleTimer( *this, CActive::EPriorityStandard ); + iPDPIdleTimer = new ( ELeave ) CImpsPDPIdleTimer( *this, CActive::EPriorityStandard ); + iPDPOpenTimer = new ( ELeave ) CImpsPDPOpenTimer( *this, CActive::EPriorityStandard ); + iAliveMgr = CImpsAliveManager::NewL( *this ); + + iSendQ = new ( ELeave ) CImpsSendQueued( * this, CActive::EPriorityStandard ); + + // Just initialize undefined address + iTCPAddr = HBufC::NewL( 1 ); + *iTCPAddr = KNullDesC; + + TPtrC8 myMime = iEncoder->MimeType(); + iReceiver2 = CImpsSendReceive2::NewL( + iFs, *this, *iTransportOut, myMime ); + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession:ConstructL ends" ) ); +#endif + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::CloseAll() +// CImpsServer::CloseEngine calls this. TransportStatus handles the callback. +// ----------------------------------------------------------------------------- +void CImpsCSPSession::CloseAll( ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CloseAll %d csp=%d" ), ( TInt )this ); +#endif + + NewState( EImpsCSPShuttingDown ); + + if ( iIdleTimer ) + { + iIdleTimer->Stop( ); + } + iPollState = EImpsPollNone; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); +#endif + + if ( iAliveMgr ) + { + iAliveMgr->StopTimer( ); + } + + if ( iSendQ ) + { + iSendQ->Cancel( ); + } + + if ( iCirManager ) + { + iCirManager->CloseCh( 0xF ); + delete iCirManager; + iCirManager = NULL; + } + + // Close the transport + if ( iReceiver2 ) + { + iReceiver2->CloseTr( ); + } + // TransportStatus handles rest of shut down activities + } + + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::ClosePDP +// called by - CImpsPDPIdleTimer +// ClosePDP method needed to close PDP-context. +// ----------------------------------------------------------------------------- +void CImpsCSPSession::ClosePDP() + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: ClosePDP" ) ); +#endif + + if ( iPollState != EImpsPollCIR ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: ClosePDP IGNORED iPollState = %d****" ), + iPollState ); +#endif + return; + } + if ( IsPDPIdle() ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: ClosePDP PDP already IDLE ****" ) ); +#endif + if ( iCSPState == EImpsCSPOnLineIdleEnd ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: ClosePDP -> EImpsPDPPendClose" ) ); +#endif + // set pending close request if PDP is opening + iPendingPDP = EImpsPDPPendClose; + } + return; + } + + NewState( EImpsCSPOnLineIdleStart ); + + // This does not close WAP-SMS-CIR + if ( iCirManager ) + { + iCirManager->CloseCh( 0xF ); + delete iCirManager; + iCirManager = NULL; + } + + // Close the transport + if ( iReceiver2 ) + { + iReceiver2->ClosePDP( ); + } + // TransportStatus handles rest of shut down activities + } + + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::OpenPDP +// Called by LogoutL, SendAliveL, SendDataL, TransportStatus, SendAllQueued +// Called by CIRMessageL directly and by the CImpsPDPTimer class too. +// OpenPDP method needed to re-open PDP-context +// ----------------------------------------------------------------------------- +TInt CImpsCSPSession::OpenPDP() + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: OpenPDP" ) ); +#endif + if ( !IsPDPIdle() ) + { + // Nothing to do +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: OpenPDP IGNORED - not idle" ) ); +#endif + return KErrAlreadyExists; + } + else if ( iCSPState == EImpsCSPOnLineIdleEnd ) + { + // already opening +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: OpenPDP IGNORED - EImpsCSPOnLineIdleEnd" ) ); +#endif + return KErrNotReady; + } + else if ( iCSPState == EImpsCSPOnLineIdleStart ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: OpenPDP -> EImpsPDPPendOpen" ) ); +#endif + iPendingPDP = EImpsPDPPendOpen; + return KErrNone; + } + + NewState( EImpsCSPOnLineIdleEnd ); + TRAPD( errx, iReceiver2->OpenPDPL( SAP(), iIAP ) ); + if ( errx ) + { + NewState( EImpsCSPOnLineIdle ); + // Does not matter which error code is returned. Used in Logout only + // to start internal logout routines. +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: openpdp E1 ****" ) ); +#endif + return KErrGeneral; + } + return KErrNone; + // TransportStatus/transportError handles rest of open activities + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::LoginL +// ----------------------------------------------------------------------------- +TPtrC CImpsCSPSession::LoginL( + const TDesC& aUser, + const TDesC& aPassword, + const TDesC& aClientId, + const TDesC& aSAP, + TUint32 aAP, + const TDesC& aKey1, + const TDesC& aKey2, + TTime aLoginExpiry, + TBool aReactive ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: LoginL state=%d csp=%d" ), iCSPState, ( TInt )this ); +#endif + + // AOL Login + if ( aKey1.Length() && aKey2.Length() ) + { + // this should be the case anyway + iSettings.iFourWayLogin = ETrue; + delete iKey1; + iKey1 = NULL; + iKey1 = aKey1.AllocL(); + delete iKey2; + iKey2 = NULL; + iKey2 = aKey2.AllocL(); + } + TPtrC tid ( KNullDesC ); + + delete iSAP; + iSAP = NULL; + iSAP = aSAP.AllocL(); + iIAP = aAP; + + iPendingAlive = EFalse; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPendingAlive->F" ) ); +#endif + + if ( iCSPState >= EImpsCSPLogged ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: Login when logged ***" ) ); +#endif + User::Leave( KImpsErrorAlreadyLogged ); + } + else if ( iCSPState == EImpsCSPDisconnecting ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: Login when CSP logging out ***" ) ); +#endif + User::Leave( KErrNotReady ); + } + // Check that no active CSP session exists + // This should not happen before login + else if ( iReceiver2->NbrOfPending() >= KImpsMaxPending || + iCSPState == EImpsCSPLogging ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: Login when busy ***" ) ); +#endif + User::Leave( KErrNotReady ); + } + // Close old connections if any in re-login case (wrong psw first time e.g.) + // The pending logout response is handled above, not here. + else if ( iReceiver2->isConnected() ) + { + // These are for re-login without logout after an error response + NewState( EImpsCSPIdle ); + iPollState = EImpsPollNone; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); + CImpsClientLogger::Log( _L( "CSPSession: err: transport was connected ***" ) ); +#endif + iAliveMgr->StopTimer(); + iSendQ->Cancel(); + iIntStatus = EInternal_NOT_LOGGED; + iReceiver2->CloseTr(); + User::Leave( KErrNotReady ); + } + + // aPassword cannot be NULL + delete iLogPwd; + iLogPwd = NULL; + delete iUserId; + iUserId = NULL; + iLogPwd = aPassword.AllocL(); + iUserId = aUser.AllocL(); + iLogCID = aClientId; + iLogoutTID = KNullDesC; + iNegoExpiry = aLoginExpiry; + iReactive = aReactive; + TImpsSrvUtils::InitializeServices( iServices, iReactive ); + + // Make a login request + iSnd->Reset(); + tid.Set( GenerateTid() ); + iSnd->SetTidL( tid ); + iSnd->SetMessageType( EImpsLoginReq ); + // Session type is OUTBAND + iSnd->SetSessionTypeL( EImpsOutband ); + + TImpsDataAccessor myAccess( iSnd ); + CImpsKey* myKey = CImpsKey::NewLC(); // <<< myKey + + iAliveTime = iSettings.iAliveTime; + + if ( iSettings.iFourWayLogin == EFalse ) + { + TImpsSDataUtils::CreateLoginReqL( + myKey, + &myAccess, + aUser, + iLogCID, + LogPwd(), + GenerateCookie(), + iAliveTime ); + // set this, that response goes to the right place + iLoginPhase = 2; + } + else + { + TImpsDigestSchema aSchema = EImpsMD5; + TImpsSDataUtils::CreateLoginReqPhaseOneL( + myKey, + &myAccess, + aUser, + iLogCID, + aSchema, + GenerateCookie(), + iAliveTime ); + // just to be sure + iLoginPhase = 1; + } + + // Add TImpsTransactionMode now + myKey->Reset(); + TImpsSDataUtils::AddValuesFromArrayL( + myKey, + KTransModeElements, + sizeof( KTransModeElements ) / + sizeof( KTransModeElements[0] ) ); + myAccess.StoreIntegerL( myKey, EImpsRequest ); + CleanupStack::PopAndDestroy( 1 ); // >>> myKey + + // Save login id for error handling purposes + iTempTid2 = tid; + + // Set WV version + iSnd->SetCspVersion( iCSPVersion ); + + // Encode login request + iEncoder->EncodeMessageL( myAccess, *iTransportOut ); + iLastSent = EImpsLoginReq; + + delete iLogTid; + iLogTid = NULL; + iLogTid = tid.AllocL(); + + // This does not leave immediately if network is not available + NewState( EImpsCSPLogging ); + TRAPD( errx, iReceiver2->OpenL( tid, iSettings.iXmlLog, aSAP, aAP ) ); + if ( errx ) + { + // In rare situations the previous call may leave + NewState( EImpsCSPIdle ); + User::Leave( errx ); + } + + // iReceiver callback handles the rest of the login method. + // This handles interrupted logout request as well as shut down interrupt + + iMsg = EImpsMessageNone; + + return tid; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::LogoutL +// Notice that subsession class prevents calling this in certain +// situations, if not iLogged or not pending login operation. +// Therefore shut down situation is not handled here. +// ----------------------------------------------------------------------------- +TPtrC CImpsCSPSession::LogoutL( TBool aCancel ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: LogoutL state=%d cancel=%d csp=%d" ), iCSPState, + aCancel, ( TInt )this ); +#endif + + if ( iCSPState == EImpsCSPIdle ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: LogoutL LEAVES KImpsErrorNotLogged" ) ); +#endif + iPendingPDP = EImpsPDPPendNone; + iPendPDPLogout = EFalse; + User::Leave( KImpsErrorNotLogged ); + } + + if ( iCancelLogin && aCancel ) + { + // cancel login already requested! + return TPtrC(); + } + + // Make a logout request (encode) + TPtrC tid; + tid.Set( GenerateTid() ); + iLogoutTID = tid; + // Use iLogoutTID when loggin out later after PDP-open + // Check if PDP is closed and start to re-open it here (Logout) + if ( IsPDPIdle() ) + { + // check this flag when PDP has been re-opened + iPendPDPLogout = ETrue; + if ( iCSPState == EImpsCSPOnLineIdle ) + { + // E1: error handling; return boolean to speed up error handling + // E2: fix: + if ( OpenPDP() ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: Ex2 OpenPDP FAILS ****" ) ); +#endif + DoLogout(); + } + return tid; + } + } + + if ( iCSPState != EImpsCSPLogging ) + { + // Clear buffers from old stuff + DeleteRequests(); + DeleteTransactions(); + // Send Logout primitive and set state to EImpsCSPDisconnecting. + TRAPD( errx, DoSendLogoutL( tid ) ); + if ( errx ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendLogoutL error %d ***" ), errx ); +#endif + // Do logout routines immediately if transport gives an error + DoLogout(); + // The following error code is handled in a special way in + // client session classes. + User::Leave( KImpsErrorTerminalOffLine ); + } + } + else // LoggingIn + { + if ( !aCancel ) + { + iPendingLogout = ETrue; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPendingLogout->TRUE ***" ) ); +#endif + } + else + { + iCancelLogin = ETrue; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iCancelLogin->TRUE ***" ) ); +#endif + } + // Logout must not ever fail so this must not leave. + StartLoginCancel( ); + } + + return tid; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::CirMessageL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::CirMessageL( + const TDesC8& aCookie ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CirMessageL csp=%d" ), ( TInt )this ); +#endif + + // if CIR is not negotiated then ignore + if ( ( iSettings.iUDPWAPCIR != 2 && iSettings.iSMSWAPCIR != 2 && + iSettings.iTCPSCIR != 2 && iSettings.iUDPSCIR != 2 ) || + !IsNegotiated() ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CirMessage IGNORED" ) ); +#endif + return; + } + + // check session cookie but not CSP-version. + // CIR syntax: WVCI + + TPtrC8 cookie = aCookie.Left( 4 ); + if ( cookie.CompareF( _L8( "WVCI" ) ) ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CirMessage SYNTAX ERROR" ) ); +#endif + User::Leave( KErrArgument ); + } + + cookie.Set( aCookie ); + // Find if the cookie exists in this push body + if ( cookie.Find( iCookie8 ) == KErrNotFound ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CirMessage COOKIE ERROR" ) ); +#endif + User::Leave( KImpsErrorUnauthorized ); + } + + // reset PDP idle timer when CIR received + iPDPIdleTimer->Reset(); + + // If PDP-context is idle or shutting down then set pending open request. + if ( IsPDPIdle() ) + { + if ( iCSPState == EImpsCSPOnLineIdle || + iCSPState == EImpsCSPOnLineIdleStart ) + { + iPendingPDP = EImpsPDPPendOpen; + } + if ( !iPollInResume ) + { + iPollInResume = 1; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollInResume %d" ), + iPollInResume ); +#endif + } + // This is a fix for cases when GPRS bearer event has not been received +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CIR -> openPDP ****" ) ); +#endif + OpenPDP(); + iPDPOpenTimer->Start( KImpsPDPRetryOpenTime ); + } + + // Send the actual Poll message + else if ( iIntStatus == EInternal_ON_LINE ) // && !PDPIdle + { + TRAPD( errPoll, SendPollL() ); + if ( errPoll && !iPollInResume ) + { + iPollInResume = 1; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollInResume %d" ), iPollInResume ); +#endif + } + } + else // NOT ON_LINE && !PDPIdle + { + // WAP SMS CIR causes OFF-LINE and therefore has to wait ON-LINE + iPollState = EImpsPollPending; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); +#endif + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::SendDataL +// ----------------------------------------------------------------------------- +TPtrC CImpsCSPSession::SendDataL( + CImpsFields* aFields, TInt aExpiry, TBool& aOwnerCh ) + { + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SendDataL begins csp=%d" ), ( TInt )this ); +#endif + + // reset PDP idle timer + iPDPIdleTimer->Reset(); + + aOwnerCh = EFalse; + + // generate TID + CImpsFields* fields = aFields; + TPtrC tid; + tid.Set( GenerateTid() ); + fields->SetTidL( tid ); + // Insert CSP Session-id + fields->SetSessionIdL( iCSPSessionId ); + // Session-type + fields->SetSessionTypeL( EImpsInband ); + + TImpsDataAccessor myAccess( fields ); + CImpsKey* myKey = CImpsKey::NewLC(); // <<< myKey + + // Add TImpsTransactionMode now + myKey->Reset(); + TImpsSDataUtils::AddValuesFromArrayL( + myKey, + KTransModeElements, + sizeof( KTransModeElements ) / + sizeof( KTransModeElements[0] ) ); + myAccess.StoreIntegerL( myKey, EImpsRequest ); + + // API supports deliver method and thus do not overwrite it here anymore + + CleanupStack::PopAndDestroy( 1 ); // >>> myKey + + // We have to check if queued messages exist + TBool queuedMsg = EFalse; + queuedMsg = RequestExist(); + + // if PDP-idle then queue request + start to open PDP + TInt nbrPend = iReceiver2->NbrOfPending(); + if ( nbrPend >= KImpsMaxPending || + iIntStatus != EInternal_ON_LINE || + iTr >= iMultiTrans || + queuedMsg || + IsPDPIdle() ) + { + // Transport adapter is busy so queue the request + QueueClientRequestL( fields, aExpiry ); + aOwnerCh = ETrue; + if ( iCSPState == EImpsCSPOnLineIdle ) + { + // Try to open PDP only once, don't start open PDP timer. + // The request will expiry if this fails anyway and it's + // a task of application to retry sending of this message. + OpenPDP( ); + } + else if ( iCSPState == EImpsCSPOnLineIdleStart || + iCSPState == EImpsCSPOnLineIdle ) + { + iPendingPDP = EImpsPDPPendOpen; + + /* Notice: + Thus CImpsConnManager DLL + does not give bearer event for GPRS resume in all situations + it is better to try to open the connection always. + */ + OpenPDP(); + } + + else if ( queuedMsg ) + { + // This must not leave because of the error is not message specific + SendAllQueued(); + } + } + else + { + // Message sending should be possible without PDP open + DoSendSingleL( + &myAccess, tid, ( TImpsMessageType ) fields->MessageType() ); + } + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SendData ends" ) ); +#endif + + return tid; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::TransportResponseL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::TransportResponseL( HBufC8** aDataPtr ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: TransportResponseL csp=%d" ), ( TInt )this ); +#endif + + HBufC8* rawData = *aDataPtr; + + // reset PDP idle timer + iPDPIdleTimer->Reset(); + + SendAllQueued(); + + TInt myError = KErrNone; + // Handle pending logout here + if ( iPendingLogout || iCancelLogin ) + { + DoPendingLogout(); + return; + } + + if ( rawData == NULL || rawData->Des().Length() == 0 ) + { + // SAP did not send anything in the response + iLastReceived = 0; + // Increase adaptive polling time if necessary + if ( iLastSent == EImpsPolling ) + { + IncreasePollTime(); + } + return; + } + + if ( iLastSent != EImpsKeepAliveReq ) + { + // Reset poll timer + ResetPollTime(); + } + + if ( iRcv ) + { + iRcv->Reset(); + } + else + { + // QueueTidL may have leaved and this is NULL + iRcv = CImpsFields::NewL(); + } + + CImpsDataAccessor* myAccess = CImpsDataAccessor::NewLC( iRcv ); // <<< + + TInt retCode = KErrNone; + +// ----------- NORMAL CASE ------------------------- +#ifndef _FAKE_RESPONSE + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: Gonna to call Decode" ) ); +#endif + // Decode to iRcv + iDecoder->DecodeMessageL( *myAccess, aDataPtr ); + retCode = iRcv->ResponseStatusL(); + // Decode errors cancel this method and error are + // reported to client by expiry timers. + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: Decoded status = %d" ), iRcv->Status() ); + CImpsClientLogger::Log( _L( "CSPSession: Decoded ResponseStatus = %d" ), + retCode ); +#endif + +// ----------- NORMAL CASE ENDS ------------------------- + +// ----------- TEST CASE ------------------------- +#endif // ifndef _FAKE_RESPONSE + +#ifdef _FAKE_RESPONSE + TImpsSrvTestUtils tests( *this, iFs ); + tests.MakeFakeResponseL( myAccess, aDataPtr ); +#endif +// ----------- TEST CASE ENDS ------------------------- + + // Message successfully received from SAP + // Session-id check + if ( iRcv->SessionTypeL() == EImpsInband ) + { + TPtrC sesId = iRcv->SessionIdL(); + // This is case sensitive + if ( sesId.Length( ) > 0 && sesId.Compare( iCSPSessionId ) ) + { + // Invalid session id + User::Leave( KImpsErrorSID ); + } + } + + // KeepAlive handling + iAliveMgr->CheckResp( retCode ); + + // --------------------------------- + // check if multiTrans messages + // --------------------------------- + TInt trs = myAccess->NbrOfTransactionsL( ); + if ( trs < 1 ) + { + // If no transaction content then it is handled as encode error + myError = KImpsErrorDecode; + } + else if ( trs == 1 ) + { + // regular case, one transaction content in a transport messages + // Update internal data structure (CImpsFields) +#ifndef _FAKE_RESPONSE + if ( !( myAccess->GetTransactionL( 0, NULL ) ) ) + { + // internal error + myError = KErrCorrupt; + } +#endif + } + + // ---------------------------------- + // checking multiTrans messages ends + // ---------------------------------- + + // If error then stop further progress of transport response + if ( myError ) + { + User::Leave( myError ); + } + + // Check if PollRequest was requested in incoming transport message + if ( iRcv->PollL() ) + { + iPollWasRequested = ETrue; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollWasRequested->T in msg" ) ); +#endif + } + else + { + iPollWasRequested = EFalse; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollWasRequested->F in msg" ) ); +#endif + } + + if ( trs > 1 ) + { + delete iAllMessages; + iAllMessages = iRcv; + iRcv = CImpsFields::NewL(); + } + else + { + // paranoid about memory leaks + delete iAllMessages; + iAllMessages = NULL; + } + + // --------------------------------- + // Send each new message to sessions + // --------------------------------- + for ( TInt i = 0; i < trs; i ++ ) + { + + if ( trs == 1 ) + { + // No need for split + } + else + { + // Data accessor points to the original iRcv (allMessages) + iRcv->Reset(); +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: MULTI-TRANS nbr=%d" ), i ); +#endif + if ( !( myAccess->GetTransactionL( i, iRcv ) ) ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: Error with MultiTrans" ) ); +#endif + // error, continue + continue; + } + } + + iLastReceived = iRcv->MessageType(); + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: TransportResponse msg = 0x%x" ), + iLastReceived ); +#endif + + // Check if csp Session startup routines needed + // TID is case sensitive + if ( ( iCSPState == EImpsCSPLogging || iCSPState == EImpsCSPNegotiation ) && + ( iRcv->MessageType() == EImpsLoginRes || + iRcv->MessageType() == EImpsClientCapabilityRes || + iRcv->MessageType() == EImpsServiceRes || + ( iRcv->MessageType() == EImpsStatus && + !iRcv->TidL().Compare( iTempTid2 ) ) ) ) + { + SessionStartupL( iRcv ); + } + // Sent events to all sub-sessions interested in this type of event + // This also handles login-resposes and removes the login-req from + // queues. + if ( iRcv->MessageType() != 0 && + iRcv->MessageType() != EImpsClientCapabilityRes && + iRcv->MessageType() != EImpsServiceRes && + iLoginPhase != 2 ) + { + RouteMessageL(); + } + } // for + + // CIR-error-flag check in WV 1.2. + // WV 1.1 messages returns always EFalse. + // Check this flag only if TCP/IP CIR channel is negotiated. + if ( !iTcpCIRError && iSettings.TCPSCIR() == 2 && IsLogged() ) + { + // Close and re-open TCP/IP CIR if CIR flag is on. + TInt erx = KErrNone; + TRAP( erx, iTcpCIRError = TImpsSDataUtils::GetCIRL( myAccess ) ); + // iTcpCIRError is reset in CirChOpened() + if ( iTcpCIRError ) + { + if ( iCirManager ) + { + iCirManager->CloseCh( KImpsCirTcp ); + } + TRAP( erx, DoStartIpCIRL() ); + } + } + + CleanupStack::PopAndDestroy( 1 ); // >>> myAccess + + delete iAllMessages; + iAllMessages = NULL; + + SendAllQueued(); + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: TransportResponse ends" ) ); +#endif + + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::TransportErrorL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::TransportErrorL( + const TDesC& aTID, + TInt aError ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: TransportError err=%d tid=%S csp=%d" ), aError, &aTID, ( TInt )this ); +#endif + + TImpsCSPState origCSP = iCSPState; + // reset PDP idle timer + iPDPIdleTimer->Reset(); + + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + + + // Handle pending logout here + // CSP destroyer is started finally + if ( iPendingLogout || iCancelLogin ) + { + NewState( EImpsCSPDisconnecting ); + DoPendingLogout(); + return; + } + + // Do not let the PDP start up again if it has just shut down. + if ( origCSP == EImpsCSPOnLineIdleEnd && aTID.Length() == 0 && + aError == KImpsErrorNoIAP ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DON'T START UP PDP AGAIN ****" ) ); +#endif + if ( iPollState > EImpsPollAdaptive ) + { + iPollState = EImpsPollCIR; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); +#endif + } + ResetPollTime(); + iPendingAlive = EFalse; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPendingAlive->F" ) ); +#endif + NewState( EImpsCSPOnLineIdle ); + + // KeepAlive handling + iAliveMgr->CheckError( aTID ); + + // Discard all the current requests + // We change the error code for UI. + // First we have to check if there is Logout request so that + // it is completed with OK status! + if ( LogoutTID().Length() ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: Err: Discard logout ****" ) ); +#endif + // This is for normal logout response error, i.e. no pending logout nor login-cancel. + iServer.DiscardLogout( LogoutTID(), csp ); + DoLogout(); + } + iServer.DiscardRequests( EImpsEventAll, KImpsErrorBearerSuspended, csp, this ); + return; + } + + // Let's call this to be sure that new messages are sent + SendAllQueued(); + + // Reset poll timer to resume from error case + ResetPollTime(); + + TInt myErr = KErrNone; + + if ( iRcv ) + { + iRcv->Reset(); + } + else + { + // QueueTidL may have leaved and this is NULL + iRcv = CImpsFields::NewL(); + } + + // This ensures that login gets a response in 4-way login later phase + if ( origCSP == EImpsCSPLogging && !LogTid().CompareF( aTID ) ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: Special LogTid ****" ) ); +#endif + // Route response to a requestion client and later below do logout. + iRcv->SetTidL( LogTid() ); + } + else + { + iRcv->SetTidL( aTID ); + } + iRcv->SetMessageType( EImpsStatus ); + iRcv->SetStatus( aError ); + TRAP( myErr, RouteMessageL( ) ); + + // KeepAlive handling + iAliveMgr->CheckError( aTID ); + + if ( origCSP == EImpsCSPLogging ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: Ex ****" ) ); +#endif + DoLogout(); + } + // If RouteMessage has not done internal logout then let's do it here + else if ( origCSP == EImpsCSPDisconnecting ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: E6 ****" ) ); +#endif + // Message type is used in subsession to prevent sending logout event twice + iServer.DiscardLogout( iLogoutTID, csp ); + DoLogout(); + } + + return; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::RouteMessageL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::RouteMessageL( ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL begins csp=%d" ), ( TInt )this ); +#endif + + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + + // ***************************************************** + // First check keep alive reponses + // ***************************************************** + + TInt32 resstatus = iRcv->ResponseStatusL(); + + // KeepAlive time may be reset on fly + if ( iRcv->MessageType() == EImpsKeepAliveRes ) + { + if ( resstatus != KImpsStatusOk ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL ends 1" ) ); +#endif + return; + } + // get new KeepAlive time if any + TInt newTime = 0; + TImpsDataAccessor myAc( iRcv ); + if ( TImpsSDataUtils::GetKeepAliveL( &myAc, newTime ) ) + { + iAliveTime = newTime; + iAliveMgr->StartTimer( iAliveTime ); +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "Server: new AliveTime %d" ), iAliveTime ); +#endif + } + // Keep alive response does not cause events to clients +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL ends 2" ) ); +#endif + return; + } + + // ************************************************************* + // Ignore informational messages from server status code 100-199 + // ************************************************************* + if ( resstatus >= 100 && resstatus < 200 ) + { + iTr--; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: 100-200 iTr = %d" ), iTr ); + CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL ends 3" ) ); +#endif + return; + } + + // ************************************************************* + // Harmonize WV 1.1 and WV 1.2 logout responses + // ************************************************************* + TImpsLogoutTrans logoutRsp = IsLogoutResp( iRcv ); + + // ***************************************************** + // Handle regular request + // ***************************************************** + + // Check requests + TBool someFound = EFalse; + TBool notOrphan = EFalse; + TInt error = 0; + // The following sends logout reponse to a requesting client + TRAP( error, iServer.CheckRequestsL ( iRcv, someFound, csp ) ); + + if ( someFound ) + { + // Message was response to our request, login phase has not + // increased this counter, that's why if statement here + TrMinus(); + } + else if ( iRcv->MessageType() != EImpsDisconnect ) + { + // Check that SAP initiated TID is not sent to clients already. + if ( ValidateTid( ETrue ) ) + { + // Notifications check. + notOrphan = iServer.CheckNotifications( iRcv, csp ); + } + } + + // Check error that means cancelled CSP session + // notice: fullfill the list of serious erros + if ( logoutRsp != EImpsLogoutNone || + resstatus == 600 || resstatus == 601 || resstatus == 604 ) + { + TInt myOpId = 0; + if ( logoutRsp == EImpsLogoutSAP ) + { + // Detect SAP initiated logout. disconnect primitive and + // TID not matching to our own logout TID. + myOpId = KImpsNullId; + } + // Both logout callback events and Status change events + // are sent here in logout. + DoLogoutNow( myOpId ); +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL ends 4" ) ); +#endif + return; + } + + // No reason to do this: + // if ( someFound ) notOrphan = ETrue; + + // If the message was not a response to our TID then it was SAP originated + // Update pending transaction queue + if ( ( iRcv->MessageType() != EImpsDisconnect ) && + ( iRcv->MessageType() != EImpsMessageNone ) && + ( iRcv->MessageType() != EImpsStatus ) && + ( !someFound ) + ) + { + // Make SAP response to wait actions + QueueTidL( !notOrphan ); + } + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: RouteMessageL ends 5" ) ); +#endif + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::GetNextMessageL +// Called by SendReceive2 +// ----------------------------------------------------------------------------- +void CImpsCSPSession::GetNextMessageL( ) + { + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: GetNextMessageL begins" ) ); +#endif + + // Use this to generate response for SAP intiated transactions + iSnd->Reset(); + + // Rejected, nothing to send + if ( !IsLogged() ) + { + return; + } + + // Send next buffered user request if any + // search. Not immediately, but via active object scheduler + SendAllQueued(); + + iLastSent = 0; + return; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::CheckExpiry +// ----------------------------------------------------------------------------- +void CImpsCSPSession::CheckExpiry( + TImpsEventType aType, const TTime aExpiry ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CheckExpiry begins" ) ); +#endif + + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + + // Login negotiation phase is a special case. + // Access timer handles that. + // Because of there may be messages not initiated by + // API methods, server must check special time-out variable iNegoExpiry. + // Internal iRequestList cannot be used for that purpose + // because of requests are deleted after transport has + // got them succesfully, but we are not satisfied until get response. + + if ( IsLogged() && !IsNegotiated() && iNegoExpiry < aExpiry ) + { + // Expired negotiation in session startup negotiation + TInt errorCode = KErrTimedOut; + switch ( iMsg ) + { + case EImpsClientCapabilityReq: + errorCode = KImpsErrorCapabilities; + break; + case EImpsServiceReq: + errorCode = KImpsErrorServices; + break; + default: + break; + } + iServer.SendErrorEvent( EImpsEventServerLogin, errorCode, 0, csp ); + // goto to NOT_LOGGED + DoLogout(); + } + else if ( iCSPState == EImpsCSPDisconnecting && iNegoExpiry < aExpiry ) + { + if ( iCancelLogin || iPendingLogout ) + { + DoPendingLogout(); + } + else + { + iServer.DiscardLogout( LogoutTID(), csp ); + // goto to NOT_LOGGED + DoLogout(); + } + } + else if ( iCSPState == EImpsCSPLogging && iNegoExpiry < aExpiry ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CheckExpiry in EImpsCSPLogging ***" ) ); +#endif + iServer.DiscardRequests( aType, aExpiry, csp, this ); + DoLogout(); + } + else + { + // Regular mode. + // Go through all sessions (each having an own request list) + // The following ends up calling CancelTrans and there + // we can check if login or logout is expired and change the + // iCSPState. + iServer.DiscardRequests( aType, aExpiry, csp, this ); + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::SessionStartupL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::SessionStartupL( CImpsFields* aFields ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL begins csp=%d" ), ( TInt )this ); +#endif + + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + TInt errx = KErrNone; + TrMinus(); + + // check if error for 2-way login + if ( ( !IsLogged() ) && + ( + aFields->MessageType() == EImpsLoginRes || + aFields->MessageType() == EImpsStatus ) && + aFields->ResponseStatusL() != KImpsStatusOk && + !iSettings.iFourWayLogin + ) + { + // RouteMessageL handles errors if iLoginPhase != 2 + // iLoginPhase starts from 2 in 2-way login + // See LoginL method + NewState( EImpsCSPIdle ); + iReceiver2->CloseTr(); + return; + } + + // Login response, 4-way login phase one + // ************************************* + if ( aFields->MessageType() == EImpsLoginRes && + aFields->Status() == KErrNone && + ( aFields->ResponseStatusL() == KImpsStatusOk || + aFields->ResponseStatusL() == 401 ) && + iLoginPhase == 1 ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL 4-login phase one" ) ); +#endif + iLoginPhase++; + TRAP( errx, HandleLoginResponseL( aFields ) ); + if ( errx ) + { + iServer.DiscardRequest( LogTid(), EImpsEventServerLogin, errx, csp ); + NewState( EImpsCSPIdle ); + } + return; + } // LOGIN RESPONSE1 + + // Login response, 4-way login phase two or 2-way login + // **************************************************** + // save session id if received + if ( aFields->MessageType() == EImpsLoginRes && + aFields->Status() == KErrNone && + aFields->ResponseStatusL() == KImpsStatusOk && + iLoginPhase == 2 ) + { + iLoginPhase++; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL 4-login phase two" ) ); +#endif + TImpsDataAccessor myAc( aFields ); + + TPtrC newId; + TImpsSDataUtils::GetLoginSessionIDL( &myAc, newId ); + // protect us against illegal data from SAP + if ( newId.Length() > KImpsMaxSID ) + { + User::Leave( KErrCorrupt ); + } + iCSPSessionId = newId; + + // get TimeToLive + TInt newTime( 0 ); + if ( TImpsSDataUtils::GetKeepAliveL( &myAc, newTime ) ) + { + iAliveTime = newTime; + } + + NewState( EImpsCSPLogged ); + // This is next message to be sent + iMsg = EImpsClientCapabilityReq; + + // KeepAlive timer started when logged in + iAliveMgr->StartTimer( iAliveTime ); + // Start polling timer with a static value to be sure that + // something is received if SAP happened to send an empty response. + // After capability negotiation a proper value is set for polling timer. + iPollState = EImpsPollAdaptive; + iIdleTimer->Start( iSettings.iMaxPollTime ); +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); + CImpsClientLogger::Log( _L( "CSPSession: PollTime %d" ), iSettings.iMaxPollTime ); + CImpsClientLogger::Log( _L( "CSPSession: AliveTime %d" ), iAliveTime ); +#endif + + // Let's send Client Capability request + TRAP( errx, DoSendClientCapabilityReqL() ); + if ( errx ) + { + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + iServer.SendErrorEvent( EImpsEventServerLogin, + KImpsErrorCapabilities, 0, csp ); + } + return; + } // LOGIN RESPONSE + + + // Client capability response + // *************************** + if ( aFields->MessageType() == EImpsClientCapabilityRes && + aFields->Status() == KErrNone && + IsLogged() ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL ClientCapabality" ) ); +#endif + TRAP( errx, HandleClientCapabilityResL ( aFields ) ); + if ( errx ) + { + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + iServer.SendErrorEvent( EImpsEventServerLogin, KImpsErrorCapabilities, 0, csp ); + NewState( EImpsCSPLogged ); + } + // Let's send Service Negotiation request + TRAP( errx, DoSendServiceNegotiationReqL () ); + if ( errx ) + { + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + iServer.SendErrorEvent( EImpsEventServerLogin, KImpsErrorServices, 0, csp ); + NewState( EImpsCSPLogged ); + } + return; + } + + // Service Negotiation response + // **************************** + if ( aFields->MessageType() == EImpsServiceRes && + aFields->Status() == KErrNone && + IsLogged() ) + { + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL ServiceRes" ) ); +#endif + iTempTid2 = KNullDesC; + + if ( aFields->MessageType() == EImpsServiceRes ) + { + TImpsDataAccessor myAccess( aFields ); + // Calculate agreed features and functions + TImpsSrvUtils::DiscardServicesL( + &myAccess, + &iServices ); + } + + // WV engine state in ON_LINE now + iIntStatus = EInternal_ON_LINE; + NewState( EImpsCSPOnLine ); + iMsg = EImpsMessageNone; + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: status ON_LINE" ) ); +#endif + // Send events to clients + iServer.TransportStatus( EInternal_ON_LINE, this ); + + // Start PDP idle time if WAP-SMS-CIR is negotiated as only CIR channel. + if ( iSettings.iSMSWAPCIR == 2 || + iSettings.iUDPWAPCIR == 2 || + iSettings.iTCPSCIR == 2 || + iSettings.iUDPSCIR == 2 ) + { + // goto CIR-polling-mode + iPollState = EImpsPollCIR; + iPollTime = iSettings.CIRModePollTime(); + iIdleTimer->Start( iPollTime ); +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); + CImpsClientLogger::Log( _L( "CSPSession: iPollTime %d" ), iPollTime ); +#endif + } + if ( iSettings.iSMSWAPCIR == 2 ) + { + // PDP Idle timer closes PDP-context + iPDPIdleTimer->Start( iSettings.PDPExpiryTime() ); + } + + TInt errxy = KErrNone; + TRAP( errxy, DoStartIpCIRL() ); + } + + // Error handling in negotiation phase AND FOR 4-WAY-LOGIN + // ******************************************************** + if ( ( aFields->Status() != KErrNone ) || + ( aFields->ResponseStatusL() != KImpsStatusOk && + aFields->ResponseStatusL() != 0 ) ) + { + TInt errorCode = KErrNone; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL Error handling %d" ), iMsg ); +#endif + switch ( iMsg ) + { + case EImpsClientCapabilityReq: + errorCode = KImpsErrorCapabilities; + break; + case EImpsServiceReq: + errorCode = KImpsErrorServices; + break; + default: + break; + } + if ( errorCode ) + { + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + iServer.SendErrorEvent( EImpsEventServerLogin, errorCode, 0, csp ); + // We assume that an application will call logout in this case + // and thus we do not close PDP here. + } + else + { + // RouteMessageL handles errors if iLoginPhase != 2 + NewState( EImpsCSPIdle ); + // routeMessaegL does not close PDP context so let't do it now + iReceiver2->CloseTr(); + } + } +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SessionStartupL ends" ) ); +#endif + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoSendClientCapabilityReqL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DoSendClientCapabilityReqL () + { + CImpsFields* tempFields = CImpsFields::NewL(); + CleanupStack::PushL( tempFields ); // <<< tempFields + tempFields->SetMessageType( EImpsClientCapabilityReq ); + tempFields->SetSessionTypeL( EImpsInband ); + iTempTid2 = GenerateTid(); + TImpsDataAccessor myAccess( tempFields ); + + iMultiTrans = iSettings.iMultiTrans; + iPollTime = iSettings.iPollTime; + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: MaxParserSize=%d" ), iSettings.MaximumParserSize() ); + CImpsClientLogger::Log( _L( "CSPSession: MaxMessageSize=%d" ), iSettings.MaximumMessageSize() ); +#endif + + TImpsSDataUtils::CreateClientCapabilityReqL( + &myAccess, + iCSPSessionId, + iTempTid2, + iLogCID, + iMultiTrans, + iPollTime, + iSettings ); + // Put Client Capability request into queue to wait sending + // Do not copy but add this instance. + // Negotiation phase expiry time is saved in iNegoExpiry so does not + // matter what we set here. + iMsg = EImpsClientCapabilityReq; + QueueClientRequestL( tempFields, 0, EFalse ); + SendAllQueued(); + CleanupStack::Pop( 1 ); // tempFields >>> + iNegoExpiry = iServer.ExpiryTime( EImpsEventServerLogin ); + NewState( EImpsCSPNegotiation ); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoSendServiceNegotiationReqL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DoSendServiceNegotiationReqL() + { + iMsg = EImpsServiceReq; + CImpsFields* tempFields = CImpsFields::NewL(); + CleanupStack::PushL( tempFields ); // <<< tempfields + tempFields->SetMessageType( EImpsServiceReq ); + tempFields->SetSessionTypeL( EImpsInband ); + iTempTid2 = GenerateTid(); + TImpsDataAccessor myAcc( tempFields ); + + // Initialize the iServices again (in case of re-login) + TImpsSrvUtils::InitializeServices( iServices, iReactive ); + TImpsSDataUtils::CreateServiceRequestL( + &myAcc, + iServices, + iCSPSessionId, + iTempTid2, + iLogCID, + iReactive ); + + // Put Service Negotiation request into queue to wait sending. + // Negotiation phase expiry time is saved in iNegoExpiry so does not + // matter what we set here. + QueueClientRequestL( tempFields, 0, EFalse ); + SendAllQueued(); + CleanupStack::Pop( 1 ); // >>> tempFields + iNegoExpiry = iServer.ExpiryTime( EImpsEventServerLogin ); + NewState( EImpsCSPNegotiation ); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::HandleLoginResponseL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::HandleLoginResponseL ( CImpsFields* aFields ) + { + // protect us against illegal data from SAP + TImpsDataAccessor myAc( aFields ); + + TPtrC newId; + TImpsSDataUtils::GetLoginSessionIDL( &myAc, newId ); + if ( newId.Length() > KImpsMaxSID ) + { + User::Leave( KErrCorrupt ); + } + iCSPSessionId = newId; + + TDesC8* nonce = NULL; + CImpsKey* myKey = CImpsKey::NewLC(); + myKey->AddL( EImpsKeySession ); + myKey->AddL( EImpsKeyTransaction ); + myKey->AddL( EImpsKeyTransactionContent ); + myKey->AddL( EImpsKeyLogin_Response ); + myKey->AddL( EImpsKeyDigestSchema ); + TInt schema; + TBool sendPwd = myAc.RestoreIntegerL( myKey, schema ); + if ( sendPwd ) + { + if ( schema == EImpsPWD ) + { + // Now we have to send the PWD + sendPwd = ETrue; + } + else + sendPwd = EFalse; + } + myKey->PopL(); + myKey->AddL( EImpsKeyNonce ); + ( void )myAc.RestoreDesc8L( myKey, nonce ); + TInt newTime( 0 ); + if ( TImpsSDataUtils::GetKeepAliveL( &myAc, newTime ) ) + { + iAliveTime = newTime; + } + + TImpsSDataUtils::SetResultStatusL( myKey, &myAc, KImpsStatusOk ); + + CleanupStack::PopAndDestroy( 1 ); + CImpsFields* tempFields = CImpsFields::NewL(); + CleanupStack::PushL( tempFields ); + tempFields->SetMessageType( EImpsLoginReq ); + iTempTid2 = LogTid(); + + TImpsDataAccessor myAcc( tempFields ); + + TImpsSDataUtils::CreateLoginReqPhaseTwoL( + sendPwd, + &myAcc, + iCSPSessionId, + LogTid(), + UserId(), + iLogCID, + LogPwd(), + nonce, + iCookie, + iAliveTime, + iKey1, + iKey2 ); + + iMsg = EImpsMessageNone; + + // Send 2nd login phase request + // Login expiry time is saved in iNegoExpiry so no need to calculate it here. + QueueClientRequestL( tempFields, 0, EFalse ); + SendAllQueued(); + + CleanupStack::Pop( 1 ); + delete iKey1; // not needed anymore + iKey1 = NULL; + delete iKey2; // not needed anymore + iKey2 = NULL; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::HandleClientCapabilityResL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::HandleClientCapabilityResL ( CImpsFields* aFields ) + { + iTempTid2 = KNullDesC; + + TImpsDataAccessor myAccess( aFields ); + CImpsKey* myKey = CImpsKey::NewLC(); // <<< myKey + + const TImpsContent* myContent = KClientCapabilityResElements; + TImpsSDataUtils::AddValuesFromArrayL( + myKey, + myContent, + sizeof( KClientCapabilityResElements ) / + sizeof( KClientCapabilityResElements[0] ) ); + + + // WV CSP versions are not fully compatible + if ( iCSPVersion == EImpsCspVersion11 ) + { + // WV 1.1 code + // CapabilityList element + myKey->AddL( CREATEKEY( EImpsKeyCapabilityList, 0 ) ); + + // We are interested in supported CIR methods, TCP/IP CIR addresses + // and polltime. + // SupportedBearer is ignored because of we support HTTP only.´ + // WV 1.1 specific ClientID is ignored too. + // AcceptedContentType not in a response based on + // Corrigenda Catalog for WV ver 1.1 + } + else + { + // WV 1.2 code + // AgreedCapabilityList element + myKey->AddL( CREATEKEY( EImpsKeyAgreedCapabilityList, 0 ) ); + + // We are interested in supported CIR methods, TCP/IP CIR addresses + // and polltime. + // SupportedBearer is ignored because of we support HTTP only. + // CIRURL is ignored too because of it is for HTTP CIR binding only + // that is not supported by this sw. + // + } + + // ServerPollMin + myKey->AddL( CREATEKEY( EImpsKeyServerPollMin, 0 ) ); + TInt myInt; + if ( myAccess.RestoreIntegerL( myKey, myInt ) ) + { + if ( myInt > iPollTime ) + { + iPollTime = myInt; + } + } + // Save new minimum polling time value in settings + iSettings.iPollTime = iPollTime; + + // Reset polling timer, ServerPollMin is optional, but if we do not get + // new value then we start to us our own suggestion + iPollState = EImpsPollAdaptive; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: PollTime %d" ), iPollTime ); + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); +#endif + iIdleTimer->Start( iPollTime ); + + // MultiTrans response + myKey->ReplaceLastL( CREATEKEY( EImpsKeyMultiTrans, 0 ) ); + if ( myAccess.RestoreIntegerL( myKey, myInt ) ) + { + iMultiTrans = myInt; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: new iMultiTrans %d" ), iMultiTrans ); +#endif + } + + myKey->PopL(); + + // SupportedCIRMethod update + iSettings.SetCirBindingsL( &myAccess, myKey ); + + // TCPAddress + TDesC* myPtr; + myKey->AddL( CREATEKEY( EImpsKeyTCPAddress, 0 ) ); + if ( myAccess.RestoreDescL( myKey, myPtr ) ) + { + HBufC* newAttrib = myPtr->AllocL(); + delete iTCPAddr; + iTCPAddr = newAttrib; + } + + // TCPPort + myKey->ReplaceLastL( CREATEKEY( EImpsKeyTCPPort, 0 ) ); + if ( myAccess.RestoreIntegerL( myKey, myInt ) ) + { + iTCPPort = ( TUint )myInt; + } + + CleanupStack::PopAndDestroy( 1 ); // >>> mKey + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::SendPollL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::SendPollL() + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SendPollL csp=%d" ), ( TInt )this ); +#endif + + TInt orig = iPollInResume; + iPollInResume = 0; + + if ( iIntStatus != EInternal_ON_LINE || IsPDPIdle() ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SendPollL IGNORED" ) ); +#endif + iPollInResume = 2; + User::Leave( KErrNotReady ); + } + + // Create Poll request + iSnd->Reset(); + iSnd->SetSessionTypeL( EImpsInband ); + iSnd->SetMessageType( EImpsPolling ); + iSnd->SetSessionIdL( iCSPSessionId ); + CImpsDataAccessor* myAccess = CImpsDataAccessor::NewLC( iSnd ); // <<< + CImpsKey* myKey = CImpsKey::NewLC(); // <<< + // Add TImpsTransactionMode now + myKey->Reset(); + TImpsSDataUtils::AddValuesFromArrayL( + myKey, + KTransModeElements, + sizeof( KTransModeElements ) / + sizeof( KTransModeElements[0] ) ); + myAccess->StoreIntegerL( myKey, EImpsRequest ); + myKey->Reset(); + TImpsSDataUtils::AddValuesFromArrayL( + myKey, + KTransContentElements, + sizeof( KTransContentElements ) / + sizeof( KTransContentElements[0] ) ); + myKey->AddL( CREATEKEY( EImpsKeyPolling_Request, 0 ) ); + myAccess->StoreEmptyL( myKey ); + + // Send + iTempTid = KNullDesC; + iSnd->SetTidL( iTempTid ); + + iPollWasRequested = EFalse; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollWasRequested->F in SendPollL" ) ); +#endif + + if ( orig >= 1 ) + { + iPollInResume = 2; + } + DoSendSingleL( myAccess, iTempTid, EImpsPolling, KImpsPollTO ); + iPollInResume = 0; + + CleanupStack::PopAndDestroy( 2 ); // >> myKey, myAccess + } + + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::SendAliveL +// ----------------------------------------------------------------------------- +TPtrC CImpsCSPSession::SendAliveL( ) + { + return DoSendAliveL(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::SendAliveInResume +// ----------------------------------------------------------------------------- +void CImpsCSPSession::SendAliveInResume( ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SendAliveInResume iPendingAlive->T" ) ); +#endif + iPendingAlive = ETrue; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoSendAliveL +// ----------------------------------------------------------------------------- +TPtrC CImpsCSPSession::DoSendAliveL( ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendAliveL csp=%d" ), ( TInt )this ); +#endif + + // send poll request. Do not update Transaction queue + iSnd->Reset(); + iSnd->SetSessionTypeL( EImpsInband ); + iSnd->SetMessageType( EImpsKeepAliveReq ); + iSnd->SetSessionIdL( iCSPSessionId ); + + // Set TID + TPtrC tid; + tid.Set( GenerateTid() ); + iSnd->SetTidL( tid ); + + // Add KeepAlive + CImpsDataAccessor* myAc = CImpsDataAccessor::NewLC( iSnd ); // <<< myAc + CImpsKey* myk = CImpsKey::NewLC(); // <<< myk + TImpsSDataUtils::AddValuesFromArrayL( + myk, + KKeepAliveReq, + sizeof( KKeepAliveReq ) / + sizeof( KKeepAliveReq[0] ) ); + myAc->StoreEmptyL( myk ); + // Add Transaction mode + myk->Reset(); + TImpsSDataUtils::AddValuesFromArrayL( + myk, + KTransModeElements, + sizeof( KTransModeElements ) / + sizeof( KTransModeElements[0] ) ); + myAc->StoreIntegerL( myk, EImpsRequest ); + + if ( IsPDPIdle() ) // PDP idle-> start to open + { + iPendingAlive = ETrue; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPendingAlive->T" ) ); +#endif + if ( iCSPState == EImpsCSPOnLineIdle ) + { + OpenPDP(); + } + else if ( iCSPState == EImpsCSPOnLineIdleStart ) + { + iPendingPDP = EImpsPDPPendOpen; + } +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendAliveL POSTPONED ***" ) ); +#endif + } + else if ( iIntStatus != EInternal_ON_LINE ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendAliveL IGNORED" ) ); +#endif + iSnd->Reset(); + User::Leave( KImpsGeneralError ); + } + else + { + DoSendSingleL( myAc, iTempTid, EImpsKeepAliveReq, KImpsKeepATO ); + iPendingAlive = EFalse; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPendingAlive->F" ) ); +#endif + } + + CleanupStack::PopAndDestroy( 2 ); // >>> myk myAc + + return iTempTid; + } + + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::SendAllQueued +// ----------------------------------------------------------------------------- +void CImpsCSPSession::SendAllQueued() + { + // Actually this does not send all messages at once but one by one. + // iSendQ calls DoSendAllQueued that calls (in most cases) + // this again and so on until no more valid messages found! + // DoSendAllQueued handles SAP initiated requests in same way. + if ( RequestExist() || SapReqExist() || iPendingAlive || + iPollState == EImpsPollExtWait || iPollInResume == 1 || + iPollWasRequested ) + { + if ( !IsPDPIdle() ) + { + iSendQ->Send(); + } + else if ( iCSPState == EImpsCSPOnLineIdle ) + { + iPollState = EImpsPollCIR; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); +#endif + } + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::CreateSapResponse +// ----------------------------------------------------------------------------- +TImpsSAPResStatus CImpsCSPSession::CreateSapResponse() + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CreateSapResponse begins csp=%d" ), ( TInt )this ); +#endif + + TImpsSAPResStatus ret( EImpsSAPNone ); + TInt err = KErrNone; + // Check if pending SAP initiated CSP transactions exists + TDblQueIter iter2 ( iTransactionList ); + iter2.SetToFirst(); + if ( iter2 ) + { + ret = EImpsSAPMore; + CTransaction* trans = iter2; + // Get first + iter2++; + CImpsFields* fields = trans->iFields; + TInt messageType = fields->MessageType(); + + // Try to get actual message type + if ( messageType == EImpsPureData ) + { + TRAP( err, TImpsDataAccessor temp ( fields ); + messageType = TImpsSDataUtils::GetPureMessageTypeL( &temp ) ); + } + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CreateSapResponse messageType=%x" ), messageType ); +#endif + // Here we have a list of supported push messages, i.e. + // SAP initiated transactions. + // Other pushed messages are not supported! + // Notice: add new methods as needed + // Disconnect is a special case handled before this method call + if ( messageType == EImpsNewMessage || + messageType == EImpsLeaveGroupRes || + messageType == EImpsInviteUserReq || + messageType == EImpsInviteRes || + messageType == EImpsCancelInviteUserReq || + messageType == EImpsPresenceNotification || + messageType == EImpsGroupChangeNotice || + messageType == EImpsPresenceAuthReq || + messageType == EImpsDeliveryReportReq + ) + { + // This also tries to send a SAP initiated transaction response once immediately + TRAP( err, DoMakeSapResponseL( trans ) ); + if ( !err ) + { + iPollInResume = 0; + } + // Last request handled. + if ( !iter2 ) + { + ret = EImpsSAPLast; + iPollInResume = 0; + + // All the WV servers do not work according to WV specs and they seems to need + // to get a Poll request instead for SAP initiated transactions, therefore the + // extra polling is needed. + err = KErrNone; + TBool polli ( EFalse ); + TRAP( err, polli = fields->PollL() ) + if ( polli ) + { + iPollWasRequested = ETrue; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollWasRequested->T in CreateSapResponse" ) ); +#endif + } + } + +#ifndef _NO_IMPS_LOGGING_ + if ( err ) + { + CImpsClientLogger::Log( _L( "CSPSession: DoMakeSapResponseL ERROR %d" ), err ); + } + +#endif + } + + // Transaction is deleted. If the response has failed the WV server should send + // the transaction again. Timer limit is not implemented in terminal side here. + trans->Destroy(); + + } // if (iter2) +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CreateSapResponse returns %d" ), ret ); +#endif + return ret; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoSendAllQueuedL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DoSendAllQueuedL() + { + + TInt errx = KErrNone; + + // Handle login phase specials first + // --------------------------------- + if ( iLoginPhase != 2 ) + { + if ( !IsLogged() || !iReceiver2->isConnected() || + ( iReceiver2->NbrOfPending() >= KImpsMaxPending ) || + IsPDPIdle() ) // no reason to try if PDP is not open + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendAllQueuedL IGNORED" ) ); +#endif + return; + } + } + + // Pending Alive messages and pending Poll messages + // ------------------------------------------------- + if ( iPendingAlive ) + { + // Pending Alive overrides pending Poll + iPendingAlive = EFalse; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPendingAlive->F" ) ); +#endif + iPollInResume = 0; + iAliveMgr->SendKeepAlive( EFalse ); + SendAllQueued(); + return; + } + else if ( iPollState == EImpsPollExtWait ) + { + iPollState = EImpsPollCIR; + iPollTime = iSettings.CIRModePollTime(); + iIdleTimer->Start( iPollTime ); +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); + CImpsClientLogger::Log( _L( "CSPSession: iPollTime %d" ), iPollTime ); +#endif + errx = KErrNone; + TRAP( errx, SendPollL() ); + // If Polling fails then try again + if ( errx && !iPollInResume ) + { + iPollInResume = 1; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollInResume %d" ), iPollInResume ); +#endif + } + + SendAllQueued(); + return; + } + + // Reqular cases + // -------------------------- + CReq* request = NULL; + + if ( iTr < iMultiTrans ) + { + // Try to send terminal initiated request + request = GiveNextRequestL(); + + // Block messages in negotiation phase + if ( request && request->iFields ) + { + TInt msgType = request->iFields->MessageType(); + if ( iIntStatus != EInternal_ON_LINE && + ( msgType != EImpsKeepAliveReq && + msgType != EImpsClientCapabilityReq && + msgType != EImpsServiceReq && + msgType != EImpsLoginReq && + msgType != EImpsLogoutReq ) ) + + { + request = NULL; + } + } + + if ( request ) + { + iPollInResume = 0; + // Send next buffered user request if any + // search. Not immediately, but via active object scheduler + SendAllQueued(); + + CImpsFields* fields = request->iFields; + errx = KErrNone; + TRAP( errx, DoSendNextBufferedL( fields ) ); + // Delete the client request + request->Destroy(); + } // if request + } + + if ( !request ) + { + // Check if SAP initiated message instead of terminal initiated one. + // This sends data and calls SendAllQueued if needed. + // comment: SAP responses should not exists in PDP-idle state + + // CreateSapResponse not only create the response but also tries to send it.. + TImpsSAPResStatus sapr = CreateSapResponse(); + if ( ( sapr != EImpsSAPMore ) && + ( iPollWasRequested || iPollInResume == 1 ) && + ( IsLogged() ) ) + { + errx = KErrNone; + // If Poll fails then re-try polling when GPRS resumes + TRAP( errx, SendPollL() ); + if ( errx && !iPollInResume ) + { + iPollInResume = 1; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: iPollInResume %d" ), iPollInResume ); +#endif + } + } + else if ( sapr == EImpsSAPMore ) + { + SendAllQueued(); + } + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::CancelTrans +// client subsession calls this when request expires +// ----------------------------------------------------------------------------- +void CImpsCSPSession::CancelTrans( const TDesC& aTID ) + { + DeleteRequest( aTID ); + // CancelTrans does not cause callback. + iReceiver2->CancelTrans( aTID ); + TrMinus(); + // Check if login-req expires and change CSP state + if ( iCSPState == EImpsCSPLogging && !aTID.Compare( LogTid() ) ) + { + NewState( EImpsCSPIdle ); + CancelData(); + } + + SendAllQueued(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::GenerateTid +// ----------------------------------------------------------------------------- +TPtrC CImpsCSPSession::GenerateTid( ) + { + // iCounter++; + // TInt tidNbr = iCounter; + TInt tidNbr = iServer.TidSeed(); + iTempTid = KNullDesC; + iTempTid = _L( "nok" ); + iTempTid.AppendFormat( _L( "%d" ), tidNbr ); + return iTempTid; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::GenerateCookie +// ----------------------------------------------------------------------------- +TPtrC CImpsCSPSession::GenerateCookie( ) + { + TTime myTime; + myTime.HomeTime(); + const TInt64& seed = myTime.Int64(); + TUint low = I64LOW( seed ); + TUint high = I64HIGH( seed ); + TInt64 seed2 MAKE_TINT64( high, low ); + iCookie = KNullDesC; + iCookie = _L( "wv:nokia." ); +#ifndef _FAKE_RESPONSE + TInt tidNbr = Math::Rand( seed2 ); + iCookie.AppendFormat( _L( "%d" ), tidNbr ); +#else + iCookie.AppendFormat( _L( "%d" ), 12345 ); +#endif + // copy to 8-bit buffer for CIR + iCookie8.Copy( iCookie ); + return iCookie; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoLogout +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DoLogout( ) + { + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoLogout" ) ); +#endif + DoLogoutNow( 0 ); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoLogoutNow +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DoLogoutNow( TInt aOpId ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoLogoutNow opid=%d, log=%d csp=%d" ), + aOpId, IsLogged(), ( TInt )this ); +#endif + + // save old status for this method + TBool oldLogged = IsLogged(); + TImpsCSPState oldState = iCSPState; + NewState( EImpsCSPIdle ); + + iAliveMgr->StopTimer(); + iIdleTimer->Stop(); + // stop PDP idle timer in logout routines + iPDPIdleTimer->Stop( ); + iPDPOpenTimer->Stop( ); + iPollState = EImpsPollNone; + iPendingPDP = EImpsPDPPendNone; + iPendPDPLogout = EFalse; + iPollWasRequested = EFalse; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d iPollWasRequested->F in logout" ), iPollState ); +#endif + + // Reset settings for further logins + ResetSession(); + + iSendQ->Cancel(); + + // Reset local variables + iIntStatus = EInternal_NOT_LOGGED; + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: status NOT_LOGGED" ) ); +#endif + + // Clean own queues + DeleteRequests(); + DeleteTransactions(); + iTidSapHistory->DeleteAll(); + iTidCliHistory->DeleteAll(); + + // Close ip cir +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CLOSE IP-CIR CHANNEL" ) ); +#endif + if ( iCirManager ) + { + // Close all cir bindings + iCirManager->CloseCh( 0xF ); + } + + // Cancel the HTTP transport in logout +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CANCEL TRANSPORT IN DOLOGOUT" ) ); +#endif + CancelData(); + + // Clean server core and send logout and status events there. + // We first detect if this is really CSP disconnect situation. + TBool cspDisconnect = ( oldLogged || oldState == EImpsCSPDisconnecting ) ? + ETrue : EFalse ; + iServer.DoLogoutSrv( aOpId, cspDisconnect, this ); + + delete iSAP; + iSAP = NULL; + iIAP = 0; + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CLOSE TRANSPORT SOON..." ) ); +#endif + if ( iReceiver2->Close2() == KErrCancel ) + { + // Start to delete this session asynchronously + // if there is nothing to close. + iServer.TransportStatus( EInternal_NO_IAP, this ); + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::CancelData +// server CloseSession calls this +// ----------------------------------------------------------------------------- +void CImpsCSPSession::CancelData( ) + { + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CancelData csp=%d" ), ( TInt )this ); +#endif + // Cancel the HTTP transport now, no callback + iReceiver2->Cancel(); + // Must reset variables because if new Login request mey be + // received before WV Engine is shut down and CloseEngine() called. + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::QueueClientRequestL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::QueueClientRequestL( + CImpsFields* aFields, + TInt aExpiry, + TBool aLast ) + { + // Check if subsession specific expiry time needed + CReq* req = new ( ELeave ) CReq( aFields ); + if ( !aExpiry ) + { + req->iExpiry = iServer.ExpiryTime( ( TImpsMessageType ) aFields->MessageType() ); + } + else + { + req->iExpiry = iServer.ExpiryTime( aExpiry ); + } + + // Put request into queue in a right place, + if ( aLast ) + { + iRequestList.AddLast( *req ); + } + else + { + iRequestList.AddFirst( *req ); + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::QueueTidL +// This resets iRcv! +// ----------------------------------------------------------------------------- +void CImpsCSPSession::QueueTidL( TBool aOrphan ) + { + + if ( !ValidateTid( EFalse ) ) + { + // TID is already responded to SAP + return; + } + + TPtrC tid; + TImpsDataAccessor myAccess( iRcv ); + TImpsDataUtils::GetTransactionIDL( &myAccess, tid ); + + if ( tid.Length() > 0 ) + { + + // Add new Sap initiated transaction to queue + CTransaction* trans = new ( ELeave ) CTransaction( + aOrphan, + tid, // tid + iRcv->SessionIdL(), // session-id + ( TImpsMessageType ) iRcv->MessageType(), + iRcv ); + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: QUEUE SAP TID=%S csp=%d" ), + &( trans->iTID ), ( TInt )this ); //lint !e525 +#endif + + iTransactionList.AddLast( *trans ); + iRcv = NULL; + iRcv = CImpsFields::NewL(); + iRcv->Reset(); + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::ValidateTid +// Validate SAP initiated TID +// ----------------------------------------------------------------------------- +TBool CImpsCSPSession::ValidateTid( TBool aClientHistory ) + { + + // The requesting entity may resend the request message using the same + // transaction identifier. The responding entity should + // guarantee that the requested operation or data is carried out only once, + // even if multiple request messages with the same transaction identifier + // are received. + + // Check that TID has not already sent to clients or has not responded to SAP. + + TPtrC tid; + TImpsDataAccessor myAccess( iRcv ); + TInt errx = KErrNone; + TRAP( errx, TImpsDataUtils::GetTransactionIDL( &myAccess, tid ) ); + + if ( tid.Length() > 0 ) + { + if ( aClientHistory && iTidCliHistory->TidFound( tid ) ) + { + // TID has sent to clients +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: already received TID=%S ***" ), &tid ); +#endif + return EFalse; + } + else if ( aClientHistory /* && !iTidCliHistory->TidFound( tid )*/ ) + { + // Save TId into client history + iTidCliHistory->Add( tid ); + } + else if ( !aClientHistory && iTidSapHistory->TidFound( tid ) ) + { + // TID has already responded to SAP + // TID-SAP-history has been updated when the transport response is sent + // successfully to SAP (i.e. no transport error) +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: already responded TID=%S ***" ), &tid ); +#endif + return EFalse; + } + } + return ETrue; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DiscardTid +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DiscardTid( const TDesC& aTid ) + { + // Delete buffered transaction + TDblQueIter rIter( iTransactionList ); + rIter.SetToFirst(); + while ( rIter ) + { + CTransaction* trans = rIter; + rIter++; + if ( !trans->iTID.Compare( aTid ) ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DiscardTid deletes a request " ) ); +#endif + trans->Destroy(); + return; + } + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DeleteTransactions +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DeleteTransactions() + { + // Delete all buffered transactions + TDblQueIter rIter( iTransactionList ); + + rIter.SetToFirst(); + + while ( rIter ) + { + CTransaction* trans = rIter; + rIter++; + trans->Destroy(); + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DeleteRequests +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DeleteRequests() + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DeleteRequests csp=%d" ), ( TInt )this ); +#endif + // Delete all buffered transaction requests + TDblQueIter rIter( iRequestList ); + rIter.SetToFirst(); + + while ( rIter ) + { + CReq* req = rIter; + rIter++; + req->Destroy(); + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DeleteRequest +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DeleteRequest( const TDesC& aTID ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DeleteRequest tid=%S csp=%d" ), &aTID, ( TInt )this ); +#endif + // Delete buffered transaction request + TInt errx = KErrNone; + TPtrC p( KNullDesC ); + + TDblQueIter rIter( iRequestList ); + rIter.SetToFirst(); + + while ( rIter ) + { + CReq* req = rIter; + rIter++; + TRAP( errx, p.Set( req->iFields->TidL() ) ); + if ( !p.Compare( aTID ) ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DeleteRequest MATCH tid=%S csp=%d" ), &aTID, ( TInt )this ); +#endif + req->Destroy(); + + } + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::RequestExist +// ----------------------------------------------------------------------------- +TBool CImpsCSPSession::RequestExist() + { + // Check buffered transactions + TDblQueIter rIter( iRequestList ); + + rIter.SetToFirst(); + + if ( rIter ) + { + return ETrue; + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::SapReqExist +// ----------------------------------------------------------------------------- +TBool CImpsCSPSession::SapReqExist() + { + TDblQueIter iter2 ( iTransactionList ); + iter2.SetToFirst(); + if ( iter2 ) + { + return ETrue; + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoSendNextBufferedL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DoSendNextBufferedL( CImpsFields* aFields ) + { + TImpsDataAccessor myAccess( aFields ); + TRAPD( err, DoSendSingleL( &myAccess, aFields->TidL(), + ( TImpsMessageType )aFields->MessageType() ) ); + if ( err ) + { + // send an error event +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendSingleL ERROR=%d csp=%d" ), err, ( TInt )this ); +#endif + iSnd->Reset(); + iSnd->SetStatus( err ); + iSnd->SetTidL( aFields->TidL() ); + TBool someFound; + // This sends error event to the right client session + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + iServer.CheckRequestsL( iSnd, someFound, csp ); + } + } + +// --------------------------------------------------------- +// CImpsCSPSession::TransportStatus +// --------------------------------------------------------- +// +void CImpsCSPSession::TransportStatus( + EImpsInternalStatus aConnectionState ) + { + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: TransportStatus=%d old=%d state=%d csp=%d" ), + ( TInt ) aConnectionState, iIntStatus, iCSPState, ( TInt )this ); +#endif + + TInt errx = KErrNone; + TRAP( errx, DoTransportStatusL ( aConnectionState ) ); + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: TransportStatus ends" ) ); +#endif + + } + +// --------------------------------------------------------- +// CImpsCSPSession::DoTransportStatusL +// --------------------------------------------------------- +// +void CImpsCSPSession::DoTransportStatusL( + EImpsInternalStatus aConnectionState ) + { + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + EImpsInternalStatus oldStatus = iIntStatus; + + // If there is pending logout request then the login is cancelled and + // logout performed immediately. + if ( iPendingLogout || iCancelLogin ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: ex3 iPendingLogout->F *****" ) ); +#endif + iPendingLogout = EFalse; + if ( iCSPState == EImpsCSPLogging ) + { + // This sends first a login response + iServer.DiscardRequest( LogTid(), EImpsEventServerLogin, KErrCancel, csp ); + // Special case where login is cancelled + if ( aConnectionState == EInternal_NO_IAP ) + { + iServer.DiscardLogout( LogoutTID(), csp ); + // below rest of activities are done + } + } + } + + // ********************************************* + // PDP idle situations handled first + if ( IsPDPIdle() ) + { + if ( aConnectionState == EInternal_NO_IAP ) + { + NewState( EImpsCSPOnLineIdle ); + // In a rare situation there is pending PDP open request + // received when PDP is closing down. + if ( iPendingPDP == EImpsPDPPendOpen ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPendingLogout->F in NO_IAP ***" ) ); +#endif + iPendingPDP = EImpsPDPPendNone; + OpenPDP(); + } + return; + } + else if ( aConnectionState == EInternal_IAP_OPEN ) + { + // PDP re-open completes here. + NewState( EImpsCSPOnLine ); + if ( iPendingPDP == EImpsPDPPendOpen ) + { + iPendingPDP = EImpsPDPPendNone; + } + // pending logout if PDP-context has been opened for Logout msg + if ( iPendPDPLogout ) + { + iPendPDPLogout = EFalse; + iPendingPDP = EImpsPDPPendNone; + TRAPD( errx, DoSendLogoutL( LogoutTID() ) ); + if ( errx ) + { + // E5: Typically Bearer Suspended error with bad luck +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: E5 ****" ) ); +#endif + DoLogout(); + } + } + else + { + // Send all queued reqular requests to transport +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: Normal PDP open ***" ) ); +#endif + iPollInResume = 1; + // ********************************************************* + // Notice: we assume that GPRS is resumed in this case even + // if ConnManager DLL cannot provide us such an information + // in all cases. + iIntStatus = EInternal_ON_LINE; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: status ON_LINE" ) ); +#endif + // start ip-cir-channels if not running + TInt errxy = KErrNone; + TRAP( errxy, DoStartIpCIRL() ); + } + // Send all queued requests to transport + SendAllQueued(); + } + } + + // ********************************************* + // NO PDP IDLE STARTS HERE + else if ( aConnectionState == EInternal_ON_LINE && IsNegotiated() ) + { + iIntStatus = EInternal_ON_LINE; + // we assume that old messages are in a bit heaven + iTr = 0; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: status ON_LINE" ) ); +#endif + if ( iPollState == EImpsPollPending ) + { + iPollState = EImpsPollExtWait; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); +#endif + } + + // This makes poll to be sent if no other requests + iPollInResume = 1; + + // pending logout if PDP-context has been opened for Logout msg + if ( iPendPDPLogout ) + { + iPendPDPLogout = EFalse; + DoSendLogoutL( LogoutTID() ); + } + else + { + SendAllQueued(); + // start ip-cir-channels if not running + TInt errxy = KErrNone; + TRAP( errxy, DoStartIpCIRL() ); + } + } + else if ( aConnectionState == EInternal_ON_LINE && !IsNegotiated() ) + { + iIntStatus = EInternal_NOT_LOGGED; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: status NOT_LOGGED" ) ); +#endif + if ( IsLogged() ) + { + // Rare situation where GPRS resume is taken place in negotiation phase. + // iAliveMgr->SendKeepAlive( EFalse ); + SendAllQueued(); + } + } + else if ( aConnectionState == EInternal_OFF_LINE && + oldStatus == EInternal_ON_LINE ) + { + iIntStatus = EInternal_OFF_LINE; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: status OFF_LINE" ) ); +#endif + } + else if ( iCSPState == EImpsCSPLogging && + ( aConnectionState == EInternal_NO_IAP || + aConnectionState == EInternal_NO_IAP_AUTH ) ) + { + // Discard request immediately in this case + // This sends first a login response +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: Login cancelled" ) ); +#endif + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + iServer.DiscardRequest( LogTid(), EImpsEventServerLogin, KImpsErrorBearerSuspended, csp ); + DoLogout(); + } + else if ( aConnectionState == EInternal_NO_IAP ) + { + if ( IsNegotiated() ) + { + // Check if no WAP SMS CIR negotiated then do logout. + // Otherwise close PDP connection only + if ( iSettings.iSMSWAPCIR == 2 ) // WAP CIR + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: PDP LOST SMS-CIR ***" ) ); +#endif + NewState( EImpsCSPOnLineIdle ); + if ( iPendingPDP == EImpsPDPPendClose ) + { + iPendingPDP = EImpsPDPPendNone; + ClosePDP(); + } + return; + } + else // no WAP CIR + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: PDP LOST NO-SMS-CIR ***" ) ); +#endif + DoLogout(); + } + } + else + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: err: PDP LOST NOT-NEGOTIATED ***" ) ); +#endif + if ( !IsLogged() ) + { + iIntStatus = EInternal_NOT_LOGGED; + // This causes DoLogout call from CImpsServer. + iServer.TransportStatus( EInternal_NO_IAP, this ); + NewState( EImpsCSPIdle ); + return; + } + else + // PDP can be lost in negotiation phase. Then we do internal + // logout. + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: LOGGED BUT NOT-NEGOTIATED -> Logout ***" ) ); +#endif + DoLogout(); + } + } + } + else if ( aConnectionState == EInternal_NO_IAP_AUTH ) + { + // Handle authorative bearer-lost situation here and + // make CSP logout +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: NO_IAP_AUTH ***" ) ); +#endif + iIntStatus = EInternal_NOT_LOGGED; + DoLogout(); + } + + // Call server's TransportStatus only if this is a state change from + // LOGGED->NOT_LOGGED. + // NOT_LOGGED event clears the client session CSP identification data and + // thus it must not be called in vain.. + if ( iIntStatus == EInternal_NOT_LOGGED && oldStatus != EInternal_NOT_LOGGED ) + { + iServer.TransportStatus( iIntStatus, this ); + } + } + +// --------------------------------------------------------- +// CImpsCSPSession::CirChOpened +// --------------------------------------------------------- +// +void CImpsCSPSession::CirChOpened( ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CirChOpened" ) ); +#endif + iTcpCIRError = EFalse; + } + +// --------------------------------------------------------- +// CImpsCSPSession::CirChError +// --------------------------------------------------------- +// +void CImpsCSPSession::CirChError( ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: CirChError csp=%d" ), ( TInt )this ); +#endif + delete iCirManager; + iCirManager = NULL; + // start poll mode again + if ( IsLogged() ) + { + iPollTime = iSettings.iPollTime; + iPollState = EImpsPollAdaptive; + iIdleTimer->Start( iPollTime ); + iPDPIdleTimer->Stop(); +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iPollState %d" ), iPollState ); + CImpsClientLogger::Log( _L( "CSPSession: iPollTime %d" ), iPollTime ); +#endif + } + } + +// --------------------------------------------------------- +// CImpsCSPSession::SetConnAllowed +// --------------------------------------------------------- +// +void CImpsCSPSession::SetConnAllowed( TBool aParam ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: SetConnAllowed %d" ), aParam ); +#endif + iConAllowed = aParam; + // Logout CSP session on behalf of user if terminal connection is not allowed. + if ( !aParam ) + { + // It's important that data channel is started to close first and after + // that internal CSP disconnect is done. + iReceiver2->CloseTr( ); + DoLogout( ); + } + } + +// --------------------------------------------------------- +// CImpsCSPSession::DoSendSingleL +// aAc connot be null +// --------------------------------------------------------- +// +void CImpsCSPSession::DoSendSingleL( + MImpsDataAccessor* aAc, + const TDesC& aTID, + TImpsMessageType aMsgType, + TInt aExpiryTime ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendSingle messagetype = 0x%x csp=%d" ), + aMsgType, ( TInt )this ); +#endif + + // Set the WV 1.2 version if needed, WV 1.1 is the default + if ( iCSPVersion == EImpsCspVersion12 ) + { + CImpsFields* f = aAc->GetImpsFields(); + f->SetCspVersion( EImpsCspVersion12 ); + } + + // Encode the message + iEncoder->EncodeMessageL( *aAc, *iTransportOut ); + + // Send to the transport module +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendSingle message encoded = 0x%x" ), aMsgType ); +#endif + + // reset PDP idle timer + iPDPIdleTimer->Reset(); + + iReceiver2->SendAndWaitL( aTID, aExpiryTime ); + iLastSent = aMsgType; + + // Notice: Maintain this list of non terminal originated + // transactions, send by terminal to SAP. + if ( !( aMsgType == EImpsPolling || aMsgType == EImpsKeepAliveReq || + aMsgType == EImpsStatus || aMsgType == EImpsMessageDelivered ) ) + { + iTr++; +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendSingle iTr = %d" ), iTr ); +#endif + } + // Anything except Poll and KeepAlive request resets Poll Timer. + if ( !( aMsgType == EImpsPolling || aMsgType == EImpsKeepAliveReq ) ) + { + ResetPollTime( ); + } + +#ifdef _FAKE_RESPONSE + iTestMsgTid = aTID; +#endif + } +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoSendLogoutL +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DoSendLogoutL( const TDesC& aTID ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendLogoutL csp=%d" ), ( TInt )this ); +#endif + + // Check if the transport is halted + if ( iReceiver2->NbrOfPending() >= KImpsMaxPending ) + { + User::Leave( KErrInUse ); + } + + NewState( EImpsCSPDisconnecting ); + // Set expiry time for logout. + // In case of Login-csncel expiry time is not overwritten, but it + // is the original login expiry time. + // Otherwise clint session would expire first and the user client would get + // normal time-out error, but we want that the user gets OK response. + if ( !iCancelLogin ) + { + iNegoExpiry = iServer.ExpiryTime( EImpsEventServerLogin ); + } + + // Make a logout request (encode) + iSnd->Reset(); + + // Insert CSP Session-id + iSnd->SetSessionIdL( iCSPSessionId ); + iSnd->SetTidL( aTID ); + iSnd->SetMessageType( EImpsLogoutReq ); + + // Session type is inband + iSnd->SetSessionTypeL( EImpsInband ); + + TImpsDataAccessor myAc( iSnd ); + CImpsKey* myKey = CImpsKey::NewLC(); // <<< myKey + + // Add TImpsTransactionMode + TImpsSDataUtils::AddValuesFromArrayL( + myKey, + KTransModeElements, + sizeof( KTransModeElements ) / + sizeof( KTransModeElements[0] ) ); + myAc.StoreIntegerL( myKey, EImpsRequest ); + myKey->Reset(); + TImpsSDataUtils::AddValuesFromArrayL( + myKey, + KTransContentElements, + sizeof( KTransContentElements ) / + sizeof( KTransContentElements[0] ) ); + myKey->AddL( CREATEKEY( EImpsKeyLogout_Request, 0 ) ); + myAc.StoreEmptyL( myKey ); + + CleanupStack::PopAndDestroy( 1 ); // >>> myKey + + DoSendSingleL( &myAc, aTID, EImpsLogoutReq ); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoMakeSapResponseL +// ----------------------------------------------------------------------------- +// +void CImpsCSPSession::DoMakeSapResponseL( CTransaction* aTrans ) + { + TPtrC tid; + CImpsFields* fields = aTrans->iFields; + tid.Set( aTrans->iTID ); + TInt messageType = fields->MessageType(); + + TInt responseType = EImpsStatus; + // Copy values from the new message to a response + iSnd->Reset(); + iSnd->SetSessionIdL( fields->SessionIdL() ); + iSnd->SetTidL( fields->TidL() ); + iSnd->SetSessionTypeL( EImpsInband ); + +#ifndef _NO_IMPS_LOGGING_ + TPtrC tid2; + tid2.Set( fields->TidL() ); + CImpsClientLogger::Log( _L( "CSPSession: MakeSAPresp SAP TID=%S" ), &( tid2 ) );//lint !e525 +#endif + + CImpsDataAccessor* myAccess = CImpsDataAccessor::NewL( iSnd ); + CleanupStack::PushL( myAccess ); // << myAccess + CImpsKey* myKey = CImpsKey::NewLC(); // <<< myKey + + CImpsDataAccessor* myAcRcv = CImpsDataAccessor::NewL( fields ); + CleanupStack::PushL( myAcRcv ); // << myAcRcv + + TPtrC myId; + + switch ( messageType ) + { + case EImpsNewMessage: + responseType = EImpsMessageDelivered; + iSnd->SetMessageType( responseType ); + // Get messageId from received message + TImpsSDataUtils::GetNewMessageIdL( myKey, myAcRcv, myId ); + // ... and copy data to outgoing response + TImpsSDataUtils::SetMessageDeliveredIdL( + myKey, myAccess, myId ); + break; + default: + iSnd->SetMessageType( responseType ); + TImpsSDataUtils::SetResultStatusL( myKey, myAccess, KImpsStatusOk ); + break; + } + + CleanupStack::PopAndDestroy( 1 ); // >> myAcRcv + + // Add TImpsTransactionMode now + myKey->Reset(); + TImpsSDataUtils::AddValuesFromArrayL( + myKey, + KTransModeElements, + sizeof( KTransModeElements ) / + sizeof( KTransModeElements[0] ) ); + myAccess->StoreIntegerL( myKey, EImpsResponse ); + CleanupStack::PopAndDestroy( 1 ); // >>> myKey + + // ------------------------------------------- + // Handle orphan message + if ( aTrans->iOrphan ) + { + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + TRAPD( errx, iServer.HandleOrphanL( aTrans->iFields, csp ) ); + if ( !errx ) + { + // ownership of the msg is in CImpsServer now + aTrans->iFields = NULL; + } + } + // ------------------------------------------- + + // DoSendSingleL leaves if GPRS suspended, + // so don't delete entry too early + DoSendSingleL( myAccess, tid, ( TImpsMessageType )responseType ); + + + // Save TID into tid-sap-history so that we so not send the response twicw + // even if SAP would send the transaction multiple times. + iTidSapHistory->Add( tid ); + + CleanupStack::PopAndDestroy( 1 ); // >> myAccess + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoStartIpCIRL +// ----------------------------------------------------------------------------- +// +void CImpsCSPSession::DoStartIpCIRL() + { + // Start ip-cir-watcher + if ( iVariant.IsFeatureSupportedL( EIpCirStandalone ) && + iSettings.iTCPSCIR == 2 || iSettings.iUDPSCIR == 2 ) + { + // Check which CIR bindings are negotiated for CSP session + TUint ipChannels = 0; + if ( iSettings.iTCPSCIR == 2 ) + { + ipChannels = KImpsCirTcp; + } + if ( iSettings.iUDPSCIR == 2 ) + { + ipChannels = ipChannels | KImpsCirUdp; + } +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: Starting ip-cir-watcher %d" ), + ipChannels ); +#endif + iCSPSessionId8.Copy( iCSPSessionId ); + if ( !iCirManager ) + { + iCirManager = CImpsCirManager::NewL( *this, + CActive::EPriorityStandard ); + } + iCirManager->OpenChL( ipChannels, iReceiver2->ConnManagerHandleL(), + iTCPPort, *iTCPAddr, iCSPSessionId8 ); + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::IncreasePollTime +// ----------------------------------------------------------------------------- +// +void CImpsCSPSession::IncreasePollTime() + { + // Increase poll timer. Two modes; CIR Mode and other modes. + if ( iPollState == EImpsPollCIR ) + { + ResetPollTime(); + } + else if ( iPollTime < iSettings.iMaxPollTime && iIdleTimer->IsActive() ) + { + iPollTime += KImpsPollIncrement; + iIdleTimer->Start( iPollTime ); +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: PollTime increased to %d" ), iPollTime ); +#endif + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::ResetPollTime +// ----------------------------------------------------------------------------- +// +void CImpsCSPSession::ResetPollTime() + { + // Reset poll timer. Two modes; CIR Mode and other modes. + if ( iPollState == EImpsPollCIR ) + { + if ( iPollTime != iSettings.CIRModePollTime() ) + { + iPollTime = iSettings.CIRModePollTime(); + iIdleTimer->Start( iPollTime ); +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: PollTime reset %d" ), iPollTime ); +#endif + } + } + else if ( iPollTime > iSettings.iPollTime && iIdleTimer->IsActive() ) + { + iPollTime = iSettings.iPollTime; + iIdleTimer->Start( iPollTime ); +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: PollTime reset %d" ), iPollTime ); +#endif + } + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::IsLogged +// ----------------------------------------------------------------------------- +// +TBool CImpsCSPSession::IsLogged( ) + { + return DoIsLogged(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::IsPendingLogin +// ----------------------------------------------------------------------------- +// +TBool CImpsCSPSession::IsPendingLogin() + { + return iCSPState == EImpsCSPLogging ? ETrue : EFalse; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::IsNegotiated +// ----------------------------------------------------------------------------- +// +TBool CImpsCSPSession::IsNegotiated( ) + { + return DoIsNegotiated(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::Servicses +// ----------------------------------------------------------------------------- +// +TImpsServices* CImpsCSPSession::Services( ) + { + return &iServices; //lint !e1536 this pointer must be used with care + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::IsShuttingDown +// ----------------------------------------------------------------------------- +// +TBool CImpsCSPSession::IsShuttingDown( ) + { + return DoIsShuttingDown(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::IsLogging +// ----------------------------------------------------------------------------- +// +TBool CImpsCSPSession::IsLogging( ) + { + return DoIsLogging(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::UserId +// ----------------------------------------------------------------------------- +// +TPtrC CImpsCSPSession::UserId( ) + { + return DoUserId(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::SAP +// ----------------------------------------------------------------------------- +// +TPtrC CImpsCSPSession::SAP( ) + { + return DoSAP(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::SID +// ----------------------------------------------------------------------------- +// +TPtrC CImpsCSPSession::SID( ) + { + return iCSPSessionId; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::Password +// ----------------------------------------------------------------------------- +// +TPtrC CImpsCSPSession::Password( ) + { + return LogPwd(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::GiveNextRequestL +// ----------------------------------------------------------------------------- +CReq* CImpsCSPSession::GiveNextRequestL() + { + +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: GiveNextRequestL begins" ) ); +#endif + // If logginOff then this should be logout request + TDblQueIter iter ( iRequestList ); + iter.SetToFirst(); + + while ( iter ) + { + CReq* request = iter; + // Get first and check if it is expired + iter++; + + TTime myTime; + myTime.HomeTime(); + if ( request->iExpiry < myTime ) + { + // session is asked to discard request from its structures + // Check TID match +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "Server: EXPIRED entry to be removed" ) ); +#endif + TImpsMessageType msgType = ( TImpsMessageType ) request->iFields->MessageType(); + TImpsEventType myType = impsService( &iVariant, msgType ); + // expired request is destroyed in client sessions too. + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + iServer.DiscardRequest( request->iFields->TidL(), myType, KErrTimedOut, csp ); + + // expired entry is deleted + request->Destroy(); + TrMinus(); + + // We want to push new messages from queued + SendAllQueued(); + + } // expired + else + { + return request; + } + } + + return ( CReq* )NULL; + } + + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::NewState +// ----------------------------------------------------------------------------- +void CImpsCSPSession::NewState( TImpsCSPState aNew ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: NewState old=%d new=%d csp=%d" ), + iCSPState, aNew, ( TInt )this ); +#endif + // In EImpsCSPDisconnecting iLogTid is still needed fore cancel-login + if ( iCSPState >= EImpsCSPLogging && aNew < EImpsCSPDisconnecting ) + { + delete iLogTid; + iLogTid = NULL; + } + if ( aNew == EImpsCSPIdle ) + { + iTr = 0; + iCookie = KNullDesC; + iCookie8 = KNullDesC8; + iCSPSessionId = KNullDesC; + iCSPSessionId8 = KNullDesC8; + iLoginPhase = 1; + } + else if ( aNew <= EImpsCSPOnLine ) + { + // PDP is opened sucessfully or CSP login not done or logging out. + iPDPOpenTimer->Stop(); + } + iCSPState = aNew; + } + + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::TrMinus +// ----------------------------------------------------------------------------- +void CImpsCSPSession::TrMinus() + { + if ( iTr > 0 ) + { + iTr--; + } +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: iTr=%d csp=%d" ), iTr, ( TInt )this ); +#endif + } + + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::ResetSession +// ----------------------------------------------------------------------------- +void CImpsCSPSession::ResetSession() + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: ResetSession csp=%d" ), ( TInt )this ); +#endif + // This is not needed since CSP session entity is not re-cycled? + iSettings.iUDPWAPCIR = 1; + iSettings.iSMSWAPCIR = 1; + iSettings.iTCPSCIR = 1; + iSettings.iUDPSCIR = 1; + iSettings.iPollTime = KImpsPollTime; + } + + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::MaxParserSize +// ----------------------------------------------------------------------------- +TInt CImpsCSPSession::MaxParserSize() + { + return iServer.Settings()->MaximumParserSize(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::MaxParserSize +// ----------------------------------------------------------------------------- +TInt CImpsCSPSession::MaxMessageSize() + { + return iServer.Settings()->MaximumMessageSize(); + } + +// ----------------------------------------------------------------------------- +// CTransaction::CTransaction +// ----------------------------------------------------------------------------- + +CTransaction::CTransaction( + TBool aOrphan, + const TDesC& aTID, + const TDesC& aSessionId, + TImpsMessageType aMessageType, + CImpsFields* aFields ) : + iMessageType( aMessageType ), + iFields ( aFields ), + iOrphan ( aOrphan ) + { + iTID = aTID; + iSessionId = aSessionId; + } + +CTransaction::~CTransaction() + { + + } //lint !e1540 iFields freed in Destroy + +void CTransaction::Destroy() + { + iLink.Deque(); + delete iFields; + iFields = NULL; + delete this; + } + + +// ----------------------------------------------------------------------------- +// CReq::CReq +// ----------------------------------------------------------------------------- + +CReq::CReq( CImpsFields* aFields ) : + iFields( aFields ) + {} + +CReq::~CReq() + { + + } //lint !e1540 iFields freed in Destroy + +void CReq::Destroy() + { + delete iFields; + iFields = NULL; + iLink.Deque(); + delete this; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::IsLogoutResp() +// aFields must not be NULL +// ----------------------------------------------------------------------------- +TImpsLogoutTrans CImpsCSPSession::IsLogoutResp( CImpsFields* aFields ) + { + TImpsLogoutTrans ret = EImpsLogoutNone; + + // set pointers to received TID and to current pending Logout-request TID + TPtrC recId; + TPtrC logoutTid; + logoutTid.Set( LogoutTID() ); + TRAPD( errxy, recId.Set( aFields->TidL() ) ); + if ( errxy ) + { + return ret; + } + + // Check if current logout transaction TID matches with received message. + if ( iCSPState == EImpsCSPDisconnecting && + !logoutTid.Length() || ( logoutTid.Length() && !recId.Compare( logoutTid ) ) ) // NOTE + { + if ( aFields->MessageType() == EImpsDisconnect ) + { + // WV 1.1 logout response + ret = EImpsLogoutTerminal; + } + else if ( aFields->MessageType() == EImpsStatus ) + { + // WV 1.2 logout response + ret = EImpsLogoutTerminal; + } + } + else if ( aFields->MessageType() == EImpsDisconnect ) + { + // SAP initiated CSP disconnect + ret = EImpsLogoutSAP; + } +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: IsLogoutResp returns %d csp=%d" ), + ret, ( TInt )this ); +#endif + return ret; + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::StartLoginCancel() +// ----------------------------------------------------------------------------- +void CImpsCSPSession::StartLoginCancel( ) + { + // Cancel login transaction, either login+logout or login+cancelLogin. + // DoPendingLogout() is called later to complete the client requests. + if ( iReceiver2->CancelLoginTrans( LogTid() ) ) + { + // Generate CSP Logout transaction + // Clear buffers from old stuff + DeleteRequests(); + DeleteTransactions(); + // Send Logout primitive and set state to EImpsCSPDisconnecting. + TRAPD( errx, DoSendLogoutL( LogoutTID() ) ); + if ( errx ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoSendLogoutL 2 error %d ***" ), errx ); +#endif + } + else + { + // If CSP Logout transaction is sent then we wait TransportResponseL or + // TransportErrorL callback methods to be called later. + return; + } + } + // Start to send events to clients if CSP Disconnect transaction is not sent. + DoPendingLogout(); + } + +// ----------------------------------------------------------------------------- +// CImpsCSPSession::DoPendingLogout() +// ----------------------------------------------------------------------------- +void CImpsCSPSession::DoPendingLogout( ) + { +#ifndef _NO_IMPS_LOGGING_ + CImpsClientLogger::Log( _L( "CSPSession: DoPendingLogout ***" ) ); +#endif + // Send critical response events to client sessions and start to logout + // internally this CSP session entity. + TImpsSessIdent csp( iCSPSessionId, DoSAP(), DoUserId() ); + if ( iPendingLogout ) + { + // Send login response for pending request first + iServer.DiscardRequest( LogTid(), EImpsEventServerLogin, KErrCancel, csp ); + // Send logout response, that is always successful + iServer.DiscardLogout( LogoutTID(), csp ); + } + + if ( iCancelLogin ) + { + // Send cancel-login response to client + iServer.DiscardRequest( LogTid(), EImpsEventServerLogin, KErrNone, csp ); + } + + iPendingLogout = EFalse; + iCancelLogin = EFalse; + DoLogout(); + } + +// End of File