--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IMPSengine/engsrv/src/impssubsession.cpp Thu Dec 17 08:41:52 2009 +0200
@@ -0,0 +1,2366 @@
+/*
+* Copyright (c) 2003 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: Class for imps sub session.
+*
+*
+*/
+
+
+// INCLUDE FILES
+#include "impsserver.h"
+#include "impsutils.h"
+#include "impssession.h"
+#include "impsfields.h"
+#include "impserrors.h"
+#include "impstimer.h"
+#include "impssdatautils.h"
+#include "impspacked.h"
+#include "impssubsession.h"
+#include "impstdataaccessor.h"
+#include "impsmessageinterpreterapi.h"
+#include "impsliterals.h"
+#include "ImpsVariantAPI.h"
+
+#ifdef _FAKE_RESPONSE
+#include "impssrvtestutils.h"
+#endif
+
+// MACROS
+#ifndef _DEBUG
+#define _NO_IMPS_LOGGING_
+#endif
+
+
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+// C++ default constructor can NOT contain any code, that
+// might leave.
+//
+CImpsSubSession::CImpsSubSession( )
+ : iEventList( _FOFF( CWvEvent, iLink ) ), //lint !e413
+ iRequestList( _FOFF( CRequest, iLink ) ), //lint !e413
+ iStatusObserver( EFalse ),
+ iDetailedError( EFalse ),
+ iLastEvent( EImpsMessageNone ),
+ iExpiryTime( 0 )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: CREATE subses=%d" ), ( TInt )this );
+#endif
+ }
+
+// Destructor
+// Session destructor calls this
+CImpsSubSession::~CImpsSubSession()
+ {
+ DeleteAllRequests();
+ DeleteAllEvents();
+ delete iVariant;
+
+ // complete event msg
+ CompleteEventMsg( KErrCancel );
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DELETE subses=%d" ), ( TInt )this );
+#endif
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::NewL()
+// ---------------------------------------------------------
+CImpsSubSession* CImpsSubSession::NewL(
+ CImpsSession* aSession,
+ TImpsEventType aType,
+ const RMessage2 aMessage )
+ {
+ CImpsSubSession* self = new ( ELeave ) CImpsSubSession();
+ // CleanupStack::PushL( self );
+ // Close method has to be called since this is derived from CObject.
+ CleanupClosePushL( *self );
+ self->ConstructL( aSession, aType, aMessage );
+ CleanupStack::Pop();
+ return self;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::ConstructL()
+// ---------------------------------------------------------
+void CImpsSubSession::ConstructL(
+ CImpsSession* aSession,
+ TImpsEventType aType,
+ const RMessage2 aMessage )
+ {
+ iServiceType = aType;
+ iSession = aSession;
+ TInt msg = aMessage.Function();
+
+ // get bit mask in an upper byte
+ TInt flags = ( msg >> 16 );
+
+ iOOMErr.Reset();
+
+#ifdef _FAKE_RESPONSE
+ // **********************************
+ // MODULE TEST for auxiliary classes
+
+ TImpsSrvTestUtils::TestOOMList();
+
+ // **********************************
+#endif
+
+ iHandleNew = ( flags & KImpsReqHandleNew ) ? ETrue : EFalse;
+ iVariant = CImpsVariant::NewLC( );
+ CleanupStack::Pop( ); // >> iVariant
+ // default value used ubtil client request to change it.
+ iExpiryTime = Server()->ExpirySeconds( iServiceType );
+ }
+
+// -----------------------------------------------------------------------------
+// CImpsSubSession::Unregister()
+// -----------------------------------------------------------------------------
+void CImpsSubSession::Unregister()
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: Unregister subses=%d h=%d type=%d" ),
+ ( TInt )this, Handle(), ( TInt )iServiceType );
+#endif
+ iCanceled = ETrue;
+ DeleteAllRequests();
+
+ // Complete new message observer
+ CompleteEventMsg( KErrCancel );
+
+ ( void ) DeleteAllEvents();
+ }
+
+// -----------------------------------------------------------------------------
+// CImpsSubSession::DeleteSub()
+// -----------------------------------------------------------------------------
+void CImpsSubSession::DeleteSub()
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DeleteSub subses=%d type=%d" ), ( TInt )this, ( TInt )iServiceType );
+#endif
+ // Calculate new expiry timer value
+ Server()->ResetExpiryTimer( iExpiryTime );
+ // Delete this entity
+ RMessage2 myMsg( Message() );
+ iSession->DeleteSubSession( myMsg.Int3() );
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::AssignIdL()
+// ---------------------------------------------------------
+void CImpsSubSession::AssignIdL( TImpsSessIdent aCSP )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: AssignIdL subses=%d" ), ( TInt )this );
+#endif
+ // create an event for each orphan message
+ CImpsFields* msg = NULL;
+ msg = Server()->NextOrphanLC( iSession->ApplicationId(), iServiceType, aCSP );
+ while ( msg )
+ {
+ SendEvent( msg, 0, EImpsServNone, EImpsMessageNone );
+ CleanupStack::PopAndDestroy();
+ msg = Server()->NextOrphanLC( iSession->ApplicationId(), iServiceType, aCSP );
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::HandleAllOrphans()
+// ---------------------------------------------------------
+void CImpsSubSession::HandleAllOrphans( TImpsSessIdent aCSP )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: HandleAllOrphans subses=%d" ), ( TInt )this );
+#endif
+ TInt err = KErrNone;
+ TRAP( err, AssignIdL( aCSP ) );
+ }
+
+// -----------------------------------------------------------------------------
+// CImpsSubSession::DeleteAllEvents()
+// -----------------------------------------------------------------------------
+TInt CImpsSubSession::DeleteAllEvents( )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DeleteAllEvents subses=%d" ), ( TInt )this );
+#endif
+
+ TInt ret = 0;
+
+ // Reset OOM_LIST too
+ iOOMErr.Reset();
+
+ // Delete all buffered events from this client,
+
+ TDblQueIter<CWvEvent> rIter( iEventList );
+
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CWvEvent* event = rIter;
+ rIter++;
+ if ( event->iSent )
+ {
+ ret++;
+ }
+ event->Destroy();
+ }
+
+ return ret;
+ }
+
+// -----------------------------------------------------------------------------
+// CImpsSubSession::DeleteAllRequests()
+// -----------------------------------------------------------------------------
+void CImpsSubSession::DeleteAllRequests( )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DeleteAllRequests" ) );
+#endif
+ // Delete all buffered requests from this client.
+
+ TDblQueIter<CRequest> rIter( iRequestList );
+
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CRequest* requ = rIter;
+ rIter++;
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DeleteAllRequests TID=%S" ), &( requ->iTID ) );
+#endif
+ requ->Destroy();
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::LoginL()
+// ---------------------------------------------------------
+void CImpsSubSession::LoginL( TBool aReactive )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: LoginL begins reactive=%d subses=%d" ),
+ aReactive, ( TInt )this );
+#endif
+
+ // OPID
+ RMessage2 myMsg( Message() );
+ TInt opId = myMsg.Int1();
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: Login opid=%d" ), opId );
+#endif
+
+ // Read PACKED ARRAY
+ CDesCArrayFlat* tempArr = new ( ELeave )CDesCArrayFlat( 7 );
+ CleanupStack::PushL( tempArr ); // << tempArr
+
+ HBufC8* stream = *StreamBufAddr();
+ if ( iSession->ReadBuffer8L( 0, stream ) )
+ {
+ HBufC8** stream2 = StreamBufAddr();
+ *stream2 = stream;
+ }
+ TImpsPackedEntity packedMessage( stream );
+ const TUint8* pS = stream->Ptr();
+ packedMessage.DoUnpackArrayL( pS, tempArr );
+
+ __ASSERT_DEBUG(
+ tempArr->MdcaCount() == 7,
+ User::Panic( KImpsPanicCategory,
+ EImpsCorrupted ) );
+ TPtrC tid;
+ TPtrC tempUser = tempArr->MdcaPoint( 0 );
+ TPtrC tempPassword = tempArr->MdcaPoint( 1 );
+ TPtrC tempCliId = tempArr->MdcaPoint( 2 );
+ TPtrC tempSAP = tempArr->MdcaPoint( 3 );
+ TPtrC key1 = tempArr->MdcaPoint( 4 );
+ TPtrC key2 = tempArr->MdcaPoint( 5 );
+ TPtrC ap = tempArr->MdcaPoint( 6 );
+
+ // convert AP back
+ TLex lex;
+ TUint32 myAp;
+ lex.Assign( ap );
+ lex.Val( myAp, EDecimal );
+
+ // Multi: update session's user-id and SAP.
+ iSession->SetUserIdL( tempUser );
+ iSession->SetSAPL( tempSAP );
+
+ TImpsSessIdent csp( KNullDesC, tempSAP, tempUser );
+ TPtrC p;
+ if ( Server()->IsLogged( csp, &p ) )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: CSP already logged ín subses=%d" ), ( TInt )this );
+#endif
+ // check password: if it does not match then return an error.
+ if ( p.CompareF( tempPassword ) )
+ {
+ User::Leave( KImpsErrorUnauthorized );
+ }
+
+ // Update session SID and other CSP identification data.
+ iSession->ModifySIDL( Server()->SID( csp ) );
+ iSession->SetSAPL( tempSAP );
+ iSession->SetUserIdL( tempUser );
+
+ // multi: Share existing CSP session
+ // Send callback reponse to a client
+ // Complete the open asyncronous request first and
+ // after that send login event (callback).
+ iSession->CompleteMe( KErrNone );
+ SendLoginEvent( KErrNone, opId );
+ if ( Server()->IsNegotiated( csp ) )
+ {
+ // On-line event too if CSP is negotiated.
+ // Must sent via Session to all subsessions
+ iSession->SendEvent( EInternal_ON_LINE );
+ // Check orphan messages because of IM subsessions
+ // may be registered before login request,
+ // Create an event for each orphan message
+ Server()->HandleAllOrphans();
+ }
+ tempArr->Reset();
+ CleanupStack::PopAndDestroy( 1 ); // >> tempArr
+ return;
+ }
+
+
+ // Save login expiry time and give it to CSP session too.
+ TTime loginExpiry = Server()->ExpiryTime( iExpiryTime );
+
+ tid.Set( Server()->LoginL( tempUser, tempPassword, tempCliId,
+ tempSAP, myAp, key1, key2, this, loginExpiry, aReactive ) );
+
+ tempArr->Reset();
+ CleanupStack::PopAndDestroy( 1 ); // >> tempArr
+
+ // Update request queue
+ // Add request into queue
+ CRequest* request = new ( ELeave ) CRequest(
+ tid, // tid
+ opId, // op-id
+ EImpsServWVLogin,
+ loginExpiry,
+ EImpsLoginReq
+ );
+
+ iRequestList.AddLast( *request );
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: LoginL ends TID=%S" ), &tid );
+#endif
+
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::LogoutL()
+// ---------------------------------------------------------
+TPtrC CImpsSubSession::LogoutL( TImpsSessIdent aCSP, TBool aCancel )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: LogoutL begins subses=%d" ), ( TInt )this );
+#endif
+
+ RMessage2 myMsg( Message() );
+ TInt opId = myMsg.Int0();
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: Logout opid=%d" ), opId );
+#endif
+
+ TPtrC tid;
+
+ // Login-cancel.
+ if ( aCancel )
+ {
+ // Check that request still exists, if not then leave KErrNotFound
+ TBool found( EFalse );
+ TDblQueIter<CRequest> requestIter( iRequestList );
+ requestIter.SetToFirst();
+ while ( requestIter )
+ {
+ CRequest* request = requestIter;
+ requestIter++;
+ if ( request->iOpId == opId )
+ {
+ found = ETrue;
+ break;
+ }
+ }
+ if ( !found )
+ {
+ User::Leave( KErrNotFound );
+ }
+ }
+
+ // Send logout request forward to CSP session entity
+ TRAPD( errL, tid.Set( iSession->Server()->LogoutL( aCancel, aCSP ) ) );
+
+ // If canceling login operation then client needs to get only one callback method call,
+ // so do not save new CRequest entity then. The CSP session entity will call later
+ // SendEvent to respond to the cancelled login operation if there is something
+ // to cancel.
+ if ( aCancel )
+ {
+ if ( errL )
+ {
+ // If the previous request leaves then there is nothing to cancel.
+ // Therefore delete the login request entity now and verify that CSP entity
+ // clear the particular transaction data,
+ CancelTrans( myMsg, aCSP );
+ User::Leave( errL );
+ }
+ // CSPSession will call back later and delete the request and send a response
+ // event to cancel request when everyting is clear regarding cancel of login
+ // transaction..
+ return TPtrC();
+ }
+ if ( errL == KImpsErrorTerminalOffLine )
+ {
+ // Logout requested in such a situation where Logout request is
+ // not needed nor not possible to be sent to SAP server.
+ // We have to generate a response here
+ // because of Logout must not fail in client API.
+ SendLogoutEvent( KErrNone, opId );
+ // Send NOT_LOGGED events to subhandles
+ iSession->SendEvent( EInternal_NOT_LOGGED );
+ return TPtrC();
+ }
+ else if ( errL )
+ {
+ // Unexpeted error situation
+ User::Leave( errL );
+ }
+
+ // Add request into request queue
+ CRequest* request = new ( ELeave ) CRequest(
+ tid,
+ opId,
+ EImpsServWVLogout,
+ Server()->ExpiryTime( iExpiryTime ),
+ EImpsLogoutReq
+ );
+ iRequestList.AddLast( *request );
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: LogoutL ends with tid=%S" ), &tid );
+#endif
+ return tid;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::Message()
+// ---------------------------------------------------------
+// return message - get it from session
+const RMessagePtr2 CImpsSubSession::Message() const
+ {
+ return iSession->Message();
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::Server()
+// ---------------------------------------------------------
+// return message - get it from session
+CImpsServer* CImpsSubSession::Server()
+ {
+ return iSession->Server();
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoSendStatusEvent()
+// ---------------------------------------------------------
+void CImpsSubSession::DoSendStatusEvent( CWvEvent& aEvent )
+ {
+
+ // Status event is lighter than a regular event in a sense that
+ // it does not write data to client thread, but updates iStatus
+ // of the handler active object in a client thread only.
+ if ( iEventMsg.IsNull() )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DoSendStatusEvent NULL MSG subses=%d" ),
+ ( TInt )this );
+#endif
+ return;
+ }
+
+ TInt newStatus = ConvertStatusCode( ( EImpsInternalStatus )aEvent.iAux );
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DoSendStatusEvent stat=%d subses=%d" ),
+ newStatus, ( TInt )this );
+#endif
+ CompleteEventMsg( newStatus );
+
+ aEvent.iSent = ETrue;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::SendEvent()
+// ---------------------------------------------------------
+void CImpsSubSession::SendEvent(
+ CImpsFields *aFields,
+ TInt aOpId,
+ TImpsServRequest aRequestType,
+ TImpsMessageType aReqMsgType )
+ {
+
+ TInt memErr = KErrNone;
+ // It is possible that the cancel request from client is not
+ // complete and this session entity is still waiting deletion.
+ if ( iCanceled )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log(
+ _L( "SubSession: SendEvent cancelled subses=%d ****" ), ( TInt )this );
+#endif
+ return;
+ }
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: SendEvent begins" ) );
+#endif
+
+
+ TDblQueIter<CWvEvent> eventIter( iEventList );
+
+ // Check if too many events waiting
+ CWvEvent* event = NULL;
+
+ // check if there is unhandled events for this session
+ TBool thisFirst = ( NbrEvents() > 0 || iOOMErr.Exists() ) ? EFalse : ETrue;
+
+ // Split GroupChangeNotice up to three parts for
+ // HandleNewUsersL, HandleLeftUsersL and HandleGroupProperties
+ if ( aFields->MessageType() == EImpsGroupChangeNotice )
+ {
+ TRAP( memErr, DoSplitGroupChangeL( aOpId, aRequestType, aFields ) );
+ }
+ else
+ {
+ TRAP( memErr, DoCreateEventL( aOpId, aRequestType, aReqMsgType, aFields ) );
+ }
+
+ // Now the event is ready to be sent.
+ // Send the event to client thread if this is first one
+ if ( thisFirst && !memErr )
+ {
+ // This should be a new event just created
+ eventIter.SetToFirst();
+ event = eventIter;
+ __ASSERT_DEBUG(
+ !event->iSent,
+ User::Panic( KImpsPanicCategory,
+ EImpsCorrupted ) );
+ // Select between base event and EventBody
+ DoSendBaseEvent( *event );
+ }
+ // Notice: CSP negotiation requests (client capabilities and service
+ // negotiaion) are internal for CSP class entity and they are not
+ // originated from client. Thus corresponding negotiation phase
+ // errors are not guaranted to be sent to a client in OOM situation.
+ // In those cases the aOpId is NULL.
+ //
+ else if ( memErr && aOpId )
+ {
+ // send/store OOM error message ( KErrNoMemory, aOpId )
+ iOOMErr.StoreOOM( aOpId );
+ if ( thisFirst )
+ {
+ ( void )SendOOMError();
+ }
+ }
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: SendEvent ends" ) );
+#endif
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::SendEvent()
+// Lighter version for engine status event
+// Notice: CSP status changes are guaranted to
+// to be sent to a client in OOM situation too.
+// ---------------------------------------------------------
+void CImpsSubSession::SendEvent(
+ EImpsInternalStatus aStatus )
+ {
+
+ // It is possible that the cancel request from client is not
+ // complete and this session entity is still waiting deletion.
+ if ( iCanceled || !iStatusObserver )
+ {
+ return;
+ }
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: SendEvent (status) subses=%d" ), ( TInt )this );
+#endif
+
+ // check if there is unhandled events for this session
+ TBool thisFirst = ( NbrEvents() > 0 || iOOMErr.Exists() ) ? EFalse : ETrue;
+
+ // Prefer reqular event queue then OOM error queue in order
+ // to save the logical order of events.
+ TRAPD( memErr, DoCreateEventL( aStatus ) );
+
+ if ( thisFirst && !memErr )
+ {
+ TDblQueIter<CWvEvent> eventIter( iEventList );
+ CWvEvent* event = NULL;
+ // This should be a new event just created
+ eventIter.SetToFirst();
+ event = eventIter;
+ __ASSERT_DEBUG(
+ !event->iSent,
+ User::Panic( KImpsPanicCategory,
+ EImpsCorrupted ) );
+ // Send the event immediately
+ DoSendStatusEvent( *event );
+ }
+
+ else if ( memErr )
+ {
+ // send/store OOM error message ( status, aOpId )
+ TInt retCode = ConvertStatusCode( aStatus );
+ iOOMErr.StoreOOM( retCode );
+ if ( thisFirst )
+ {
+ ( void )SendOOMError();
+ }
+ }
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: SendEvent ends" ) );
+#endif
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoSendBaseEvent()
+// ---------------------------------------------------------
+void CImpsSubSession::DoSendBaseEvent( CWvEvent& aEvent )
+ {
+ TInt bufSize = EventMsgBufSize();
+ TInt messageLength = aEvent.iPackedMessage ?
+ aEvent.iPackedMessage->Length() : 0;
+ if ( bufSize > 0 && bufSize >= messageLength )
+ {
+ // Message body can be sent immediately.
+ // This sends message headers too.
+ DoSendEventBody( aEvent );
+ }
+ else
+ {
+ // No message body or client is asked to increase the buffer
+ DoSendEventHeader( aEvent );
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoSendEventHeader()
+// ---------------------------------------------------------
+void CImpsSubSession::DoSendEventHeader( CWvEvent& aEvent )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DoSendEventHeader type=%d subses=%d" ),
+ aEvent.iType, ( TInt )this );
+#endif
+ RMessagePtr2 ptrMsg = EventMsg();
+ if ( ptrMsg.IsNull() )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DoSendEventHeader NULL MSG subses=%d" ),
+ ( TInt )this );
+#endif
+ return;
+ }
+ // Create the header information
+
+ TBuf < sizeof( SImpsEventData ) >
+ eventBuf( sizeof( SImpsEventData ) );
+
+ SImpsEventData* eventData =
+ ( SImpsEventData* )eventBuf.Ptr();
+
+ DoCreateEventIPC( aEvent, eventData );
+
+ // Write the message header to client thread via a message.
+ TInt err = KErrNone;
+
+
+ err = DoWriteEventHeaders( ptrMsg, eventBuf );
+
+ // We use NotifyHandler status parameter to pass the size of the
+ // packed message!
+ TInt messageLength = aEvent.iPackedMessage ?
+ aEvent.iPackedMessage->Length() : 0;
+ if ( err == KErrNone )
+ {
+ err = messageLength;
+ }
+
+ // Signal event handler in a client thread
+ CompleteEventMsg( err );
+
+ aEvent.iSent = ETrue;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoSendEventBody()
+// ---------------------------------------------------------
+void CImpsSubSession::DoSendEventBody( CWvEvent& aEvent )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DoSendEventBody type=%d subses=%d" ),
+ aEvent.iType, ( TInt )this );
+#endif
+
+ RMessagePtr2 ptrMsg = EventMsg();
+ if ( ptrMsg.IsNull() )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DoSendEventBody NULL MSG subses=%d" ),
+ ( TInt )this );
+#endif
+ return;
+ }
+
+ // This writes both headers and body.
+ // This increases the robustenss and thre client thread do not need
+ // to store data between these transactions, because of it receives
+ // all the necessary data at once.
+
+ TBuf < sizeof( SImpsEventData ) >
+ eventBuf( sizeof( SImpsEventData ) );
+
+ SImpsEventData* eventData =
+ ( SImpsEventData* )eventBuf.Ptr();
+
+ DoCreateEventIPC( aEvent, eventData );
+ eventData->iMessageBody = ( aEvent.iPackedMessage ? ETrue : EFalse );
+
+ // Write the message header to client thread via a message.
+ TInt err = KErrNone;
+ err = DoWriteEventHeaders( ptrMsg, eventBuf );
+
+ if ( !err )
+ {
+ // Write the message body
+ err = DoWriteEventBody( ptrMsg, aEvent );
+ // We use NotifyHandler status parameter to pass the size of the
+ // packed message!
+ TInt messageLength = aEvent.iPackedMessage ?
+ aEvent.iPackedMessage->Length() : 0;
+ if ( err == KErrNone )
+ {
+ err = messageLength;
+ }
+ }
+
+ // Signal event handler in a client thread
+ CompleteEventMsg( err );
+
+ aEvent.iSent = ETrue;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::SendLogoutEvent
+// ---------------------------------------------------------
+void CImpsSubSession::SendLogoutEvent( TInt aRespStatus, TInt aOpId )
+ {
+ // transfer CSP error code if any
+ if ( aRespStatus > 0 )
+ {
+ aRespStatus = ErrorCode( aRespStatus );
+ }
+
+ // check session type first and filter sending
+ // of the same logout twice
+ if ( iServiceType != EImpsEventServerLogin ||
+ ( iLastEvent == EImpsDisconnect && aOpId == 0 ) )
+ {
+ return;
+ }
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: SendLogoutEvent in action subses=%d" ),
+ ( TInt )this );
+#endif
+
+ TDblQueIter<CWvEvent> eventIter( iEventList );
+ CWvEvent* event = NULL;
+
+ // check if there is unhandled events for this session
+ TBool thisFirst = ( NbrEvents() > 0 || iOOMErr.Exists() ) ? EFalse : ETrue;
+
+ // Let this behave like real SAP initiated Disconnect primitive
+ TRAPD( memErr, DoCreateEventL( aOpId, aRespStatus,
+ EImpsMessageNone, EImpsDisconnect, EImpsServWVLogout ) );
+ // Since WV 1,2 logout messages may be either disconnect or Status,
+ // harmomize them here in order to avoid sending logout message
+ // with opid=actual_id and opid=0.
+ iLastEvent = EImpsDisconnect;
+
+ // Now the event is ready to be sent.
+ // Send the event to client thread if this is first one
+ if ( thisFirst && !memErr )
+ {
+ // This should be a new event just created
+ eventIter.SetToFirst();
+ event = eventIter;
+ __ASSERT_DEBUG(
+ !event->iSent,
+ User::Panic( KImpsPanicCategory,
+ EImpsCorrupted ) );
+ // Logout event does not contain body in this case
+ DoSendEventHeader( *event );
+ }
+ else if ( memErr && aOpId )
+ {
+ // send/store OOM error message ( KErrNoMemory, aOpId )
+ iOOMErr.StoreOOM( aOpId );
+ if ( thisFirst )
+ {
+ ( void )SendOOMError();
+ }
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::SendLoginEvent
+// Multi: new method to generate events when CSP session
+// already exists
+// ---------------------------------------------------------
+void CImpsSubSession::SendLoginEvent( TInt aRespStatus, TInt aOpId )
+ {
+ // transfer CSP error code if any
+ if ( aRespStatus > 0 )
+ {
+ aRespStatus = ErrorCode( aRespStatus );
+ }
+
+ // check session type first and filter sending
+ // of the same logout twice
+ if ( iServiceType != EImpsEventServerLogin )
+ {
+ return;
+ }
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: SendLoginEvent in action subses=%d" ),
+ ( TInt )this );
+#endif
+
+ TDblQueIter<CWvEvent> eventIter( iEventList );
+ CWvEvent* event = NULL;
+
+ // check if there is unhandled events for this session
+ TBool thisFirst = ( NbrEvents() > 0 || iOOMErr.Exists() ) ? EFalse : ETrue;
+
+ // Let this behave like real SAP initiated Disconnect primitive
+ TRAPD( memErr, DoCreateEventL( aOpId, aRespStatus,
+ EImpsMessageNone, EImpsLoginRes, EImpsServWVLogin ) );
+
+ // Now the event is ready to be sent.
+ // Send the event to client thread if this is first one
+ if ( thisFirst && !memErr )
+ {
+ // This should be a new event just created
+ eventIter.SetToFirst();
+ event = eventIter;
+ __ASSERT_DEBUG(
+ !event->iSent,
+ User::Panic( KImpsPanicCategory,
+ EImpsCorrupted ) );
+ // Logout event does not contain body in this case
+ DoSendEventHeader( *event );
+ }
+ else if ( memErr && aOpId )
+ {
+ // send/store OOM error message ( KErrNoMemory, aOpId )
+ iOOMErr.StoreOOM( aOpId );
+ if ( thisFirst )
+ {
+ ( void )SendOOMError();
+ }
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::SendOOMError
+// ---------------------------------------------------------
+TBool CImpsSubSession::SendOOMError( )
+ {
+
+ if ( iEventMsg.IsNull() )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log(
+ _L( "SubSession: SendOOMError NULL MSG subses=%d" ), ( TInt )this );
+#endif
+ return EFalse;
+ }
+
+ TInt opId = iOOMErr.GetOOM();
+ if ( opId != 0 )
+ {
+ if ( opId > 0 )
+ {
+ CompleteEventMsg( KImpsOOMReply | opId );
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log(
+ _L( "SubSession: SendOOMError completes opid=%d ****" ), opId );
+#endif
+ }
+ else
+ {
+ // Status change special error code etc
+ CompleteEventMsg( opId );
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log(
+ _L( "SubSession: SendOOMError completes status=%d ****" ), opId );
+#endif
+ }
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::SendPrimitiveL()
+// ---------------------------------------------------------
+void CImpsSubSession::SendPrimitiveL( TInt aFunction, TImpsSessIdent aCSP )
+ {
+ RMessage2 myMsg( Message() );
+ TInt opId = myMsg.Int1();
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: SendPrimitiveL begins %d opid=%d" ),
+ aFunction, opId );
+#endif
+
+ switch ( aFunction )
+ {
+ case EImpsServWVSendOnly:
+ case EImpsServBlock:
+ // Check availability of the service in general
+ TImpsSrvUtils::CheckServiceL( EIMFeat,
+ Server()->Services( aCSP ) );
+ break;
+ case EImpsServGroup:
+ TImpsSrvUtils::CheckServiceL( EGroupFeat,
+ Server()->Services( aCSP ) );
+ break;
+ case EImpsServPres:
+ TImpsSrvUtils::CheckServiceL( EPresenceFeat,
+ Server()->Services( aCSP ) );
+ break;
+ case EImpsServFundSearch:
+ case EImpsServFundInvite:
+ TImpsSrvUtils::CheckServiceL( EFundamentalFeat,
+ Server()->Services( aCSP ) );
+ break;
+ default:
+ break;
+ }
+ // Get data to iFields
+ GetWVDataL();
+
+ TImpsMessageType myMesType = ( TImpsMessageType ) ImpsFields()->MessageType();
+
+ // Check primitive if this is pure subsession
+ // Discard anything that does not belong to presence service
+ if ( iServiceType == EImpsEventPresencePure &&
+ impsService( iVariant, TImpsMessageType( myMesType ) ) != EImpsEventPresence )
+ {
+ User::Leave( KImpsErrorUnknownMessageType );
+ }
+
+ // Add sender if it is empty in new IM message
+ if ( aFunction == EImpsServWVSendOnly )
+ {
+ TPtrC sender;
+ TPtrC group;
+ CImpsKey* myKey = CImpsKey::NewLC(); // <<< myKey
+ TImpsSDataUtils::AddValuesFromArrayL(
+ myKey,
+ KSendMessageElements,
+ sizeof( KSendMessageElements ) /
+ sizeof( KSendMessageElements[0] ) );
+ myKey->AddL( CREATEKEY( EImpsKeyMessageInfo, 0 ) );
+ TImpsDataAccessor myAc( ImpsFields() );
+ TImpsSDataUtils::GetSenderL( myKey, &myAc, sender, group );
+ if ( sender.Length() == 0 )
+ {
+ TPtrC userId = iSession->UserId();
+ // Set Sender( User( UserID )) if sender not specified
+ // in client API
+ // Notice: Here we could add assigned clientID if wanted so.
+ TImpsSDataUtils::SetSenderL(
+ myKey,
+ &myAc,
+ &userId,
+ NULL );
+ }
+
+ TPtrC applicationID( iSession->ApplicationId() );
+ if ( applicationID.Length() != 0 )
+ {
+ // insert the ExtBlock
+ myKey->PopL( 3 );
+ myKey->AddL( CREATEKEY( EImpsKeyExtBlock, 0 ) );
+ myKey->AddL( CREATEKEY( EImpsKeyAPIClient, 0 ) );
+ myAc.StoreDescL( myKey, applicationID );
+ }
+
+
+ CleanupStack::PopAndDestroy( 1 ); // >>> myKey
+
+ }
+
+ TPtrC tid;
+
+ // Send data may in certain situation change iFields,
+ // so copy data address to safe.
+ tid.Set( Server()->SendDataL( this, aCSP ) );
+
+ // Add request into queue
+ CRequest* request = new ( ELeave ) CRequest(
+ tid, // tid
+ opId, // op-id
+ ( TImpsServRequest )aFunction,
+ Server()->ExpiryTime( iExpiryTime ),
+ myMesType );
+ iRequestList.AddLast( *request );
+
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::SendGetBlockedL()
+// This is for IM GetBlocked, only ID received from client
+// ---------------------------------------------------------
+void CImpsSubSession::SendGetBlockedL( TImpsSessIdent aCSP )
+ {
+
+ RMessage2 myMsg( Message() );
+ TInt opId = myMsg.Int1();
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: SendGetBlockedL opid=%d" ), opId );
+#endif
+
+ // Check availability of the service in general
+ TImpsSrvUtils::CheckServiceL( EIMFeat, Server()->Services( aCSP ) );
+
+ // Generate the stuff. Server thread finalizes the message adding
+ // session-id etc
+
+ ImpsFields()->Reset();
+ ImpsFields()->SetMessageType( EImpsGetBlockedListReq );
+
+ CImpsDataAccessor* myAc = CImpsDataAccessor::NewL( ImpsFields() );
+ CleanupStack::PushL( myAc ); // <<< myAc
+ CImpsKey* myKey = CImpsKey::NewLC(); // <<< myKey
+
+ TImpsSDataUtils::AddValuesFromArrayL(
+ myKey,
+ KTransContentElements,
+ sizeof( KTransContentElements ) /
+ sizeof( KTransContentElements[0] ) );
+ myKey->AddL( CREATEKEY( EImpsKeyGetBlockedList_Request, 0 ) );
+ myAc->StoreEmptyL( myKey );
+
+ TPtrC tid;
+
+ // Send data may in certain situation change iFields,
+ // so copy data to safe.
+ tid.Set( Server()->SendDataL( this, aCSP ) );
+
+ // Update request queue
+ // Add request into queue
+ CRequest* request = new ( ELeave ) CRequest(
+ tid, // tid
+ opId, // op-id
+ EImpsServGetBlocked,
+ Server()->ExpiryTime( iExpiryTime ),
+ EImpsGetBlockedListReq );
+ iRequestList.AddLast( *request );
+
+ CleanupStack::PopAndDestroy( 2 ); // >>> myAc, myKey
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoNextEvent()
+// ---------------------------------------------------------
+void CImpsSubSession::DoNextEvent()
+ {
+
+ // check OOM_LIST first
+ iOOMErr.RemoveOOM();
+ TInt errId = SendOOMError();
+ if ( errId )
+ {
+ return;
+ }
+
+ // Delete the event that was sent and send next
+ TDblQueIter<CWvEvent> eventIter( iEventList );
+ eventIter.SetToFirst();
+
+ while ( eventIter )
+ {
+ CWvEvent* event = eventIter;
+ eventIter++;
+
+ if ( event->iSent )
+ {
+ event->Destroy();
+ }
+ else
+ {
+ if ( event->iRequestType != EImpsServStatusReg )
+ {
+ DoSendBaseEvent( *event );
+ }
+ else
+ {
+ DoSendStatusEvent( *event );
+ }
+ // Only one event at a time is possible
+ break;
+ }
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoEventBodyL()
+// ---------------------------------------------------------
+void CImpsSubSession::DoEventBodyL()
+ {
+ // Check that the first event (headers) in the queue
+ // is sent
+ TDblQueIter<CWvEvent> eventIter( iEventList );
+ eventIter.SetToFirst();
+ CWvEvent* event = eventIter;
+ if ( !event || !event->iSent )
+ {
+ // This ensures that if the synchronization between client-server
+ // is lost the next messages are handled because of the
+ // client asks next event after this error.
+ User::Leave( KImpsGeneralError );
+ }
+
+ // Write the body to the client thread
+ DoSendEventBody( *event );
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DiscardRequests()
+// Expiry detection
+// ---------------------------------------------------------
+void CImpsSubSession::DiscardRequests(
+ TTime aExpiryTime,
+ TImpsEventType aServiceType,
+ MImpsCSPSession* aSess )
+ {
+
+ // It is possible that the cancel request from client is not
+ // complete and this session entity is still waiting deletion.
+ if ( iCanceled )
+ {
+ return;
+ }
+
+ if ( !( aServiceType & iServiceType ) )
+ {
+ return;
+ }
+
+ // check if there is unhandled events for this session
+ TBool thisFirst = ( NbrEvents() > 0 || iOOMErr.Exists() ) ? EFalse : ETrue;
+
+ TDblQueIter<CRequest> requestIter( iRequestList );
+ requestIter.SetToFirst();
+ while ( requestIter )
+ {
+ CRequest* request = requestIter;
+ requestIter++;
+ if ( request->iExpiry < aExpiryTime )
+ {
+ // expired entry found
+ // Create error event for UI API
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log(
+ _L( "SubSession: Entry EXPIRED type=%d subses=%d" ),
+ request->iRequestType, ( TInt )this );
+#endif
+ // Delete the message from server queues if not send
+ Server()->CancelTrans( request->iTID, aSess );
+ // Create event for client
+ TRAPD( memErr, DoCreateEventL(
+ request->iOpId,
+ KErrTimedOut,
+ request->iMessageType ) );
+
+ // store OOM error message if necessary ( KErrNoMemory, aOpId )
+ if ( memErr )
+ {
+ iOOMErr.StoreOOM( request->iOpId );
+ }
+
+ // Send an event if this is first
+ if ( thisFirst )
+ {
+ DoNextEvent();
+ thisFirst = EFalse;
+ }
+ // delete request from queue
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log(
+ _L( "SubSession: DiscardRequests TID=%S" ), &( request->iTID ) ); //lint !e525
+#endif
+ request->Destroy();
+ }
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DiscardRequests()
+// Discrad all requests
+// ---------------------------------------------------------
+void CImpsSubSession::DiscardRequests(
+ TInt aError,
+ TImpsEventType aServiceType,
+ MImpsCSPSession* aSess )
+ {
+
+ // It is possible that the cancel request from client is not
+ // complete and this session entity is still waiting deletion.
+ if ( iCanceled )
+ {
+ return;
+ }
+
+ if ( !( aServiceType & iServiceType ) )
+ {
+ return;
+ }
+
+ // check if there is unhandled events for this session
+ TBool thisFirst = ( NbrEvents() > 0 || iOOMErr.Exists() ) ? EFalse : ETrue;
+
+ TDblQueIter<CRequest> requestIter( iRequestList );
+ requestIter.SetToFirst();
+ while ( requestIter )
+ {
+ CRequest* request = requestIter;
+ requestIter++;
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log(
+ _L( "SubSession: Entry DISCARDED type=%d subses=%d" ),
+ request->iRequestType, ( TInt )this );
+#endif
+ // Delete the message from server queues if not send
+ Server()->CancelTrans( request->iTID, aSess );
+ // Create event for client
+ TRAPD( memErr, DoCreateEventL(
+ request->iOpId,
+ aError,
+ request->iMessageType ) );
+
+ if ( memErr )
+ {
+ iOOMErr.StoreOOM( request->iOpId );
+ }
+
+ // Try to send event if this is first
+ if ( thisFirst )
+ {
+ DoNextEvent();
+ thisFirst = EFalse;
+ }
+ // delete request from queue
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log(
+ _L( "SubSession: DiscardRequests TID=%S" ), &( request->iTID ) ); //lint !e525
+#endif
+ request->Destroy();
+
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DiscardRequest()
+// Discard a single request
+// ---------------------------------------------------------
+TBool CImpsSubSession::DiscardRequest(
+ const TDesC& aTid,
+ TImpsEventType aServiceType,
+ TInt aCode )
+ {
+
+ // It is possible that the cancel request from client is not
+ // complete and this session entity is still waiting deletion.
+ if ( iCanceled )
+ {
+ return EFalse;
+ }
+
+ TBool ret( EFalse );
+ if ( aServiceType != iServiceType )
+ {
+ return ret;
+ }
+
+ // check if there is unhandled events for this session
+ TBool thisFirst = ( NbrEvents() > 0 || iOOMErr.Exists() ) ? EFalse : ETrue;
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DiscardRequest subses=%d" ), ( TInt )this );
+#endif
+
+ TDblQueIter<CRequest> requestIter( iRequestList );
+ requestIter.SetToFirst();
+ while ( requestIter )
+ {
+ CRequest* request = requestIter;
+ requestIter++;
+ if ( !request->iTID.Compare( aTid ) )
+ {
+ // entry found
+ // Create error event for UI API
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: entry DISCARDED" ) );
+#endif
+ TRAPD( memErr, DoCreateEventL( request->iOpId,
+ aCode,
+ request->iMessageType ) );
+
+ if ( memErr )
+ {
+ // store OOM error message ( KErrNoMemory, aOpId )
+ iOOMErr.StoreOOM( request->iOpId );
+ }
+
+ // The following is NOT called because of server has called this.
+ // Server()->CancelTrans( request->iTID );
+ // delete request from queue
+ request->Destroy();
+ ret = ETrue;
+ break;
+ }
+ }
+
+ // Send the new event only if no old events in queue
+ if ( ret && thisFirst )
+ {
+ DoNextEvent();
+ }
+
+ return ret;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::CheckNotification()
+// ---------------------------------------------------------
+TBool CImpsSubSession::CheckNotification( CImpsFields* aFields )
+ {
+
+ TBool ret ( EFalse );
+ TRAPD( errx, ( ret = DoCheckNotificationL( aFields ) ) );
+ if ( ret && !errx )
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoCheckNotificationL()
+// Notice: MessageNotifiction not supported.
+// ---------------------------------------------------------
+TBool CImpsSubSession::DoCheckNotificationL( CImpsFields* aFields )
+ {
+
+ // It is possible that the cancel request from client is not
+ // complete and this session entity is still waiting deletion.
+ if ( iCanceled )
+ {
+ return EFalse;
+ }
+
+ // Filter new messages out if necessary
+ if ( !iHandleNew )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: new msg FILTERED OUT" ) );
+#endif
+ return EFalse;
+ }
+
+ TImpsDataAccessor myAc( aFields );
+ TPtrC msgContentType;
+ TBool retVal = EFalse;
+ TInt messageType = aFields->MessageType();
+
+ // Handle SAP initiated transactions here.
+ //
+ switch ( this->iServiceType )
+ {
+ case EImpsEventMessage:
+ if ( messageType == EImpsNewMessage )
+ {
+ retVal = ETrue;
+ // Checking the ApplicationID
+ // Consider client-id routing if media type is ok
+ /*
+ * 1) Get the ApplicationID from the message
+ * 2) Get the ApplicationID from the corresponding session
+ * ownClientId = iSession->ApplicationID();
+ * 3) if ownClientId == messageClientId -> retVal = ETrue,
+ * this includes the case when both are empty
+ * 4) otherwise retVal = EFalse
+ */
+ TPtrC messageAppID; // The recipient's ApplicationID
+
+ TImpsSDataUtils::GetApplicationIDL( &myAc, messageAppID );
+
+ if ( !messageAppID.Compare( iSession->ApplicationId() ) )
+ {
+ // The ClientIDs are matching
+ retVal = ETrue;
+ }
+ else
+ {
+ retVal = EFalse;
+ }
+ }
+ else if ( messageType == EImpsDeliveryReportReq )
+ {
+ retVal = ETrue;
+ }
+ break;
+ case EImpsEventServerLogin:
+ if ( messageType == EImpsDisconnect )
+ {
+ retVal = ETrue;
+ }
+ break;
+ case EImpsEventGroup:
+ if ( messageType == EImpsLeaveGroupRes ||
+ messageType == EImpsGroupChangeNotice )
+ {
+ retVal = ETrue;
+ }
+ break;
+ case EImpsEventCommon:
+ if ( messageType == EImpsInviteUserReq ||
+ messageType == EImpsInviteRes ||
+ messageType == EImpsCancelInviteUserReq )
+ {
+ retVal = ETrue;
+ }
+ break;
+ case EImpsEventPresence:
+ case EImpsEventPresencePure:
+ if ( messageType == EImpsPresenceNotification ||
+ messageType == EImpsPresenceAuthReq ||
+ messageType == EImpsPureData )
+ {
+ retVal = ETrue;
+ }
+ break;
+ default:
+ retVal = EFalse;
+ break;
+ }
+
+ return retVal;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::CheckRequests()
+// ---------------------------------------------------------
+TBool CImpsSubSession::CheckRequests(
+ const TDesC& aTid,
+ TInt& aOpId,
+ TImpsServRequest& aRequestType,
+ TImpsMessageType& aReqMsgType )
+ {
+ // It is possible that the cancel request from client is not
+ // complete and this session entity is still waiting deletion.
+ if ( iCanceled )
+ {
+ return EFalse;
+ }
+
+ aRequestType = EImpsServNone;
+ aReqMsgType = EImpsMessageNone;
+
+ TDblQueIter<CRequest> requestIter( iRequestList );
+
+ requestIter.SetToFirst();
+
+ while ( requestIter )
+ {
+ CRequest* request = requestIter;
+ requestIter++;
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: CheckRequests subses=%d aTID=%S reg.TID=%S" ),
+ ( TInt )this, &aTid, &request->iTID );
+#endif
+
+ if ( !request->iTID.Compare( aTid ) )
+ {
+ aOpId = request->iOpId;
+ aRequestType = request->iRequestType;
+ aReqMsgType = request->iMessageType;
+ return ETrue;
+ }
+ }
+
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CImpsSubSession::DeleteRequest
+// -----------------------------------------------------------------------------
+TBool CImpsSubSession::DeleteRequest( TInt aOpId )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DeleteRequest opid=%d, subses=%d" ), aOpId, ( TInt )this );
+#endif
+ // Delete one buffered requests from this client,
+ TDblQueIter<CRequest> rIter( iRequestList );
+
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CRequest* requ = rIter;
+ rIter++;
+ if ( requ->iOpId == aOpId )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DeleteRequest TID=%S" ), &( requ->iTID ) ); //lint !e525
+#endif
+ requ->Destroy();
+ return ETrue;
+ }
+ }
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: DeleteRequest failed" ) );
+#endif
+ return EFalse;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::NextEventL()
+// ---------------------------------------------------------
+void CImpsSubSession::NextEventL( const RMessage2& aMsg )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: NextEventL begins subses=%d" ), ( TInt )this );
+#endif
+ if ( iCanceled )
+ {
+ User::Leave( KErrCancel );
+ }
+ StoreEventMsg( aMsg );
+ DoNextEvent();
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::SendEventBodyL()
+// ---------------------------------------------------------
+void CImpsSubSession::SendEventBodyL( const RMessage2& aMsg )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: SendEventBodyL subses=%d" ), ( TInt )this );
+#endif
+ if ( iCanceled )
+ {
+ User::Leave( KErrCancel );
+ }
+
+ StoreEventMsg( aMsg );
+ DoEventBodyL();
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoCreateEventL
+// ---------------------------------------------------------
+void CImpsSubSession::DoCreateEventL(
+ TInt aOpId,
+ TImpsServRequest aRequestType,
+ TImpsMessageType aReqMesType,
+ CImpsFields* aFields )
+ {
+
+#ifdef _DEBUG
+ TInt rate = 0;
+ if ( !rate )
+ {
+ __UHEAP_RESET;
+ }
+ else
+ {
+ __UHEAP_FAILNEXT( rate );
+ }
+#endif
+
+ // Create an event
+ CWvEvent* myEvent = new ( ELeave ) CWvEvent( iServiceType );
+ CleanupStack::PushL( myEvent ); // <<< myEvent
+ myEvent->iOpCode = aOpId;
+ myEvent->iStatus = aFields->Status();
+ myEvent->iRequestType = aRequestType;
+ myEvent->iMessageType = ( TImpsMessageType )aFields->MessageType();
+ myEvent->iReqMesType = aReqMesType;
+
+ // convert CSP error code if any
+ TInt32 resstatus = aFields->ResponseStatusL();
+ if ( resstatus != KImpsStatusOk &&
+ resstatus != KErrNone )
+ {
+ myEvent->iStatus = ErrorCode( resstatus );
+ }
+
+ TImpsMessageType msgType = ( TImpsMessageType )myEvent->iMessageType;
+
+ // *********************************************************
+ // Handle pure client responses in different way
+ // In that case XML-formatted response needed in a client
+ if ( iServiceType == EImpsEventPresencePure )
+ {
+ if ( msgType == EImpsStatus ||
+ impsService( iVariant, TImpsMessageType( msgType ) ) == EImpsEventPresence )
+ {
+ myEvent->iMessageType = EImpsPureData;
+ msgType = EImpsPureData;
+ }
+ }
+ //*********************************************************/
+
+ // List of responses having serialized CImpsFields
+ // Notice: Check this list if new methods in API presented
+ if ( // im client
+ msgType == EImpsNewMessage ||
+ msgType == EImpsGetBlockedListRes ||
+ msgType == EImpsSendMessageRes ||
+ msgType == EImpsDeliveryReportReq ||
+ // group client
+ msgType == EImpsJoinGroupRes ||
+ msgType == EImpsLeaveGroupRes ||
+ msgType == EImpsGroupMembersRes ||
+ msgType == EImpsGroupPropertiesRes ||
+ msgType == EImpsGroupRejectListRes ||
+ msgType == EImpsNewUsers ||
+ msgType == EImpsLeftUsers ||
+ msgType == EImpsGroupChangeNotice ||
+ // Pure data
+ msgType == EImpsPureData ||
+ // fundamental
+ impsService( iVariant, TImpsMessageType( msgType ) ) == EImpsEventCommon ||
+ // presence
+ impsService( iVariant, TImpsMessageType( msgType ) ) == EImpsEventPresence )
+ // access service has nothing to pack in responses
+ {
+ HBufC8* dataBuffer = NULL;
+ TRAPD( errx, ( dataBuffer = HBufC8::NewL( aFields->Size() ) ) );
+ if ( errx )
+ {
+ myEvent->iStatus = errx;
+ myEvent->iPackedMessage = NULL;
+ }
+ else
+ {
+ TImpsPackedEntity packed( dataBuffer );
+ // Check data length if enough
+ User::LeaveIfError ( packed.PackEntity( *aFields ) );
+ myEvent->iPackedMessage = dataBuffer;
+ }
+ }
+
+ // detailed error data code in special format
+ // notice: avoid to pack in vain
+ if ( msgType == EImpsStatus && iDetailedError )
+ {
+ HBufC8* dataBuffer = HBufC8::NewLC( aFields->Size() );
+ TImpsPackedEntity packed( dataBuffer );
+ // Check data length if enough
+ User::LeaveIfError ( packed.PackEntity( *aFields ) );
+ myEvent->iPackedMessage = dataBuffer;
+ CleanupStack::Pop(); // dataBuffer
+ }
+
+ // list of responses having one byte response
+ if ( aFields->MessageType() == EImpsSubsGroupNoticeRes )
+ {
+ CImpsKey* myKey = CImpsKey::NewLC(); // <<< myKey
+ CImpsDataAccessor* myAc = CImpsDataAccessor::NewL( aFields );
+ CleanupStack::PushL( myAc ); // <<< myAc
+ TBool groupNotice = TImpsSDataUtils::SubGroupNoticeResponseL(
+ myKey,
+ myAc );
+ myEvent->iAux = groupNotice;
+ CleanupStack::PopAndDestroy( 2 ); // >>> myKey, myAc
+ }
+
+ // New event created succesfully
+ CleanupStack::Pop( 1 ); // >>> myEvent
+ // Since WV 1,2 logout messages may be either disconnect or Status,
+ // harmomize them here in order to avoid sending logout message
+ // with opid=actual_id and opid=0.
+ if ( aRequestType == EImpsServWVLogout )
+ {
+ iLastEvent = EImpsDisconnect;
+ }
+ else
+ {
+ iLastEvent = myEvent->iMessageType;
+ }
+ iEventList.AddLast( *myEvent );
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoCreateEventL
+// This creates wv engine online status event
+// ---------------------------------------------------------
+void CImpsSubSession::DoCreateEventL(
+ EImpsInternalStatus aStatus )
+ {
+#ifdef _DEBUG
+ TInt rate = 0;
+ if ( !rate )
+ {
+ __UHEAP_RESET;
+ }
+ else
+ {
+ __UHEAP_FAILNEXT( rate );
+ }
+#endif
+ // Create an event
+ CWvEvent* myEvent = new ( ELeave ) CWvEvent( iServiceType );
+ // No need for CleanupStack, no leave before inserted to queue
+ myEvent->iOpCode = 0;
+ myEvent->iStatus = KErrNone;
+ myEvent->iRequestType = EImpsServStatusReg;
+ myEvent->iMessageType = EImpsMessageNone;
+ myEvent->iReqMesType = 0;
+ myEvent->iAux = aStatus;
+
+ // New event created succesfully
+ iEventList.AddLast( *myEvent );
+
+ // Notice: this does not update iLastEvent
+ }
+
+// ---------------------------------------------------------
+// CImpSsubSession::DoCreateEventL
+// This creates wv engine expiry events and other internal messages
+// ---------------------------------------------------------
+void CImpsSubSession::DoCreateEventL(
+ TInt aOpCode,
+ TInt aStatus,
+ TImpsMessageType aReqMesType,
+ TImpsMessageType aRcvMesType,
+ TImpsServRequest aReqType )
+ {
+#ifdef _DEBUG
+ TInt rate = 0;
+ if ( !rate )
+ {
+ __UHEAP_RESET;
+ }
+ else
+ {
+ __UHEAP_FAILNEXT( rate );
+ }
+#endif
+ // Create an event
+ CWvEvent* myEvent = new ( ELeave ) CWvEvent( iServiceType );
+ // No need for CleanupStack, no leave before inserted to queue
+ myEvent->iOpCode = aOpCode;
+ myEvent->iStatus = aStatus;
+ myEvent->iMessageType = aRcvMesType;
+ myEvent->iReqMesType = aReqMesType;
+ myEvent->iRequestType = aReqType;
+
+ // New event created succesfully
+ iLastEvent = myEvent->iMessageType;
+ iEventList.AddLast( *myEvent );
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoSplitGroupChangeL
+// ---------------------------------------------------------
+void CImpsSubSession::DoSplitGroupChangeL(
+ TInt aOpId,
+ TImpsServRequest aRequestType,
+ CImpsFields* aFields )
+ {
+
+ CImpsKey* myKey = CImpsKey::NewLC(); // <<< myKey
+ CImpsDataAccessor* myAc = CImpsDataAccessor::NewL( aFields );
+ CleanupStack::PushL( myAc ); // myAc
+
+ TImpsSDataUtils::AddValuesFromArrayL(
+ myKey,
+ KTransContentElements,
+ sizeof( KTransContentElements ) /
+ sizeof( KTransContentElements[0] ) );
+ myKey->AddL( CREATEKEY( EImpsKeyGroupChangeNotice, 0 ) );
+
+ // First get GroupId
+ TDesC* pId; // for GroupID
+ myKey->AddL( CREATEKEY( EImpsKeyGroupID, 0 ) );
+ if ( myAc->RestoreDescL( myKey, pId ) )
+ {
+ myKey->PopL();
+ }
+ else
+ {
+ // This means illegal data from transport.
+ User::Leave( EImpsCorrupted );
+ }
+
+ // Search if new users
+ myKey->AddL( CREATEKEY( EImpsKeyJoined, 0 ) );
+ if ( myAc->CheckBranchExistenceL( myKey ) )
+ {
+ CImpsFields* newFields = CImpsFields::NewL();
+ CleanupStack::PushL( newFields ); // <<< newFields
+
+ // Copy message type etc important
+ newFields->SetStatus( aFields->Status( ) );
+
+ // set special internal message type
+ newFields->SetMessageType( EImpsNewUsers );
+
+ // Copy data, only Joined users list
+ CImpsDataAccessor* myAc2 = CImpsDataAccessor::NewLC( newFields );
+ TImpsDataUtils::CopyNewUsersL( *myAc, *myAc2 );
+
+ // Add Group Id
+ myKey->ReplaceLastL( CREATEKEY( EImpsKeyGroupID, 0 ) );
+ myAc2->StoreDescL( myKey, *pId );
+ // Make a request entity into queue
+ DoCreateEventL( aOpId, aRequestType, EImpsMessageNone, newFields );
+
+ CleanupStack::PopAndDestroy( 2 ); // >>> myAc2, newFields
+ }
+
+ // Search if LeftUsers
+ myKey->ReplaceLastL( CREATEKEY( EImpsKeyLeft, 0 ) );
+ if ( myAc->CheckBranchExistenceL( myKey ) )
+ {
+ CImpsFields* newFields = CImpsFields::NewL();
+ CleanupStack::PushL( newFields ); // <<< newFields
+
+ // Copy message type etc important
+ newFields->SetStatus( aFields->Status( ) );
+
+ // set special internal message type
+ newFields->SetMessageType( EImpsLeftUsers );
+
+ // Copy data, only Left users list
+ CImpsDataAccessor* myAc2 = CImpsDataAccessor::NewLC( newFields );
+ TImpsDataUtils::CopyLeftUsersL( *myAc, *myAc2 );
+
+ // Add Group Id
+ myKey->ReplaceLastL( CREATEKEY( EImpsKeyGroupID, 0 ) );
+ myAc2->StoreDescL( myKey, *pId );
+
+ // Make a request entity into queue
+ DoCreateEventL( aOpId, aRequestType, EImpsMessageNone, newFields );
+
+ CleanupStack::PopAndDestroy( 2 ); // >>> myAc2, newFields
+ }
+
+ CImpsFields* newFields = CImpsFields::NewL();
+ CleanupStack::PushL( newFields ); // <<< newFields
+
+ // Copy message type etc important
+ newFields->SetStatus( aFields->Status( ) );
+
+ // set special internal message type
+ newFields->SetMessageType( EImpsGroupChangeNotice );
+
+ // Search if GroupProperties
+ CImpsDataAccessor* myAc2 = CImpsDataAccessor::NewLC( newFields );
+ myKey->ReplaceLastL( CREATEKEY( EImpsKeyGroupProperties, 0 ) );
+ if ( myAc->CheckBranchExistenceL( myKey ) )
+ {
+ TImpsDataUtils::CopyGroupPropertiesL( *myAc, *myAc2 );
+ }
+ // Search if ownproperties
+ myKey->ReplaceLastL( CREATEKEY( EImpsKeyOwnProperties, 0 ) );
+ if ( myAc->CheckBranchExistenceL( myKey ) )
+ {
+ TImpsDataUtils::CopyOwnPropertiesL( *myAc, *myAc2 );
+ }
+
+ // Add Group Id
+ myKey->ReplaceLastL( CREATEKEY( EImpsKeyGroupID, 0 ) );
+ myAc2->StoreDescL( myKey, *pId );
+
+ // Make a request entity into queue
+ DoCreateEventL( aOpId, aRequestType, EImpsMessageNone, newFields );
+
+ CleanupStack::PopAndDestroy( 4 ); // >>> myAc2, newFields
+ // myKey, myAc
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::NbrEvents
+// ---------------------------------------------------------
+TInt CImpsSubSession::NbrEvents()
+ {
+ TDblQueIter<CWvEvent> eventIter( iEventList );
+ CWvEvent* event = NULL;
+ TInt counter = 0;
+
+ eventIter.SetToFirst();
+ event = eventIter;
+ while ( event )
+ {
+ counter++;
+ eventIter++;
+ event = eventIter;
+ }
+
+ return counter;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::GetWVDataL()
+// Generic data converter from packed data to internal data structure.
+// ---------------------------------------------------------
+void CImpsSubSession::GetWVDataL()
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: GetWVDataL begins" ) );
+#endif
+
+ // serialized message is always in ptr0
+ HBufC8* stream = *StreamBufAddr();
+ if ( iSession->ReadBuffer8L( 0, stream ) )
+ {
+ HBufC8** stream2 = StreamBufAddr();
+ *stream2 = stream;
+ }
+ ImpsFields()->Reset();
+ TImpsPackedEntity packedMessage( *StreamBufAddr() );
+ packedMessage.UnpackEntityL( *ImpsFields() );
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "Session: GetWVDataL ends" ) );
+#endif
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::ErrorCode
+// ---------------------------------------------------------
+TInt CImpsSubSession::ErrorCode( TInt aCSPError )
+ {
+
+ if ( aCSPError >= 100 && aCSPError <= 999 )
+ {
+ // Convert the error code if valid input value
+ return KImpsGeneralError - aCSPError;
+ }
+ // This means illagel data from transport.
+ return KImpsErrorValidate;
+
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoCreateEventIPC
+// ---------------------------------------------------------
+void CImpsSubSession::DoCreateEventIPC(
+ CWvEvent& aEvent, SImpsEventData* aData )
+ {
+ // Set pointers to the data
+ aData->iOpCode = aEvent.iOpCode;
+ aData->iMessageType = aEvent.iMessageType;
+ aData->iRequestType = ( TInt ) aEvent.iRequestType;
+ aData->iStatus = aEvent.iStatus;
+ aData->iMessageBody = EFalse;
+ aData->iReqMesType = aEvent.iReqMesType;
+ // this is not used in all cases but let's write it every time
+ aData->iAux = aEvent.iAux;
+
+ // Make a special change for Logout SAP errors to hide the error code
+ if ( iServiceType == EImpsEventServerLogin &&
+ aEvent.iRequestType == EImpsServWVLogout &&
+ aEvent.iStatus < ( Imps_ERROR_BASE - 200 ) )
+ {
+ aData->iStatus = KErrNone;
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L
+ ( "SubSession: DoCreateEventIPC converts LOGOUT code" ) );
+#endif
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoWriteEventHeaders
+// ---------------------------------------------------------
+TInt CImpsSubSession::DoWriteEventHeaders(
+ RMessagePtr2 aMsg, const TDes& aData )
+ {
+
+ TInt err = KErrNone;
+
+ TPtrC ptr( aData );
+
+ err = aMsg.Write( 0, ptr );
+
+ __ASSERT_DEBUG( err != KErrBadDescriptor,
+ aMsg.Panic( KImpsPanicCategory, EImpsCorrupted ) );
+
+#ifndef _NO_IMPS_LOGGING_
+ SImpsEventData* eventData = ( SImpsEventData* )aData.Ptr();
+ CImpsClientLogger::Log( _L(
+ "SubSession: DoWriteEventHeaders opid=%d msg=0x%x status=%d err=%d subses=%d" ),
+ eventData->iOpCode, eventData->iMessageType, eventData->iStatus, err, ( TInt )this );
+#endif
+
+ return err;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::DoWriteEventBody
+// ---------------------------------------------------------
+TInt CImpsSubSession::DoWriteEventBody(
+ RMessagePtr2 aMsg, CWvEvent& aEvent )
+ {
+ // Write message body
+ TPtrC8 ptr8( KNullDesC8 );
+ if ( aEvent.iPackedMessage )
+ {
+ ptr8.Set( aEvent.iPackedMessage->Des() );
+ }
+ TInt mLen = aMsg.GetDesMaxLength( 1 );
+ __ASSERT_DEBUG( mLen != KErrBadDescriptor,
+ aMsg.Panic( KImpsPanicCategory, EImpsCorrupted ) );
+ __ASSERT_DEBUG( mLen >= ptr8.Length(),
+ aMsg.Panic( KImpsPanicCategory, EImpsCorrupted ) );
+ if ( mLen < ptr8.Length() )
+ {
+ // This is an error situation in a client side
+ return KErrBadHandle;
+ }
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: EventMsg.Write2 subses=%d" ), ( TInt )this );
+ TTime testTime1;
+ testTime1.HomeTime();
+#endif
+
+ TInt err = aMsg.Write( 1, ptr8 );
+ __ASSERT_DEBUG( err != KErrBadDescriptor,
+ aMsg.Panic( KImpsPanicCategory, EImpsCorrupted ) );
+
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L(
+ "SubSession: DoWriteEventBody opid=%d msg=0x%x status=%d err=%d" ),
+ aEvent.iOpCode, aEvent.iMessageType, aEvent.iStatus, err );
+#endif
+
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::StoreEventMsg
+// ---------------------------------------------------------
+void CImpsSubSession::StoreEventMsg( RMessagePtr2 aMsg )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ RMessage2 myMsg( aMsg );
+ CImpsClientLogger::Log( _L( "SubSession: StoreEventMsg subses=%d bufSize=%d" ), ( TInt )this, myMsg.Int2() );
+#endif
+ iEventMsg = aMsg;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::CompleteEventMsg
+// ---------------------------------------------------------
+void CImpsSubSession::CompleteEventMsg( TInt aStatus )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: CompleteEventMsg size=%d subses=%d" ), aStatus, ( TInt )this );
+#endif
+ if ( iEventMsg.IsNull() )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: CompleteEventMsg NULL MSG subses=%d" ), ( TInt )this );
+#endif
+ return;
+ }
+ iEventMsg.Complete( aStatus );
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::EventMsgBufSize
+// ---------------------------------------------------------
+TInt CImpsSubSession::EventMsgBufSize( ) const
+ {
+ if ( iEventMsg.IsNull() )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: EventMsgBufSize NULL MSG subses=%d" ), ( TInt )this );
+#endif
+ return 0;
+ }
+ RMessage2 myMsg( iEventMsg );
+ return myMsg.Int2();
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::ConvertStatusCode
+// ---------------------------------------------------------
+TInt CImpsSubSession::ConvertStatusCode( EImpsInternalStatus aStatus ) const
+ {
+ TInt newStatus = KImpsOnlineStatus;
+ if ( aStatus == EInternal_OFF_LINE )
+ {
+ // This is not supported in client API anymore, so this is an error code.
+ newStatus = KImpsOfflineStatus;
+ }
+ else if ( aStatus == EInternal_NOT_LOGGED )
+ {
+ newStatus = KImpsNotLoggedStatus;
+ }
+ else if ( aStatus == EInternal_NO_IAP )
+ {
+ newStatus = KImpsNoIapStatus;
+ }
+ else if ( aStatus == EInternal_SHUTTING_DOWN )
+ {
+ newStatus = KImpsErrorShuttingDown;
+ }
+ return newStatus;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::CancelTrans
+// ---------------------------------------------------------
+TBool CImpsSubSession::CancelTrans(
+ RMessagePtr2 aMsg, TImpsSessIdent aCSP )
+ {
+ // Get operation id from client request messages
+ RMessage2 myMsg( aMsg );
+ TInt opid = myMsg.Int0();
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: CancelTransL opid=%d subses=%d" ), opid, ( TInt )this );
+#endif
+
+ TBuf<KImpsMaxTID> myTid;
+
+ // delete the request
+ // If there is no such opid then return an error code
+ TBool found( EFalse );
+ TDblQueIter<CRequest> requestIter( iRequestList );
+ requestIter.SetToFirst();
+ while ( requestIter )
+ {
+ CRequest* request = requestIter;
+ requestIter++;
+ if ( request->iOpId == opid )
+ {
+ myTid = request->iTID;
+ // entry found and deleted
+ request->Destroy();
+ found = ETrue;
+ break;
+ }
+ }
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: CancelTransL returns %d" ), found );
+#endif
+ if ( found )
+ {
+ // ok, the session cancels the transport and completes the request
+ Server()->CancelTrans( myTid, aCSP );
+ }
+ return found;
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::SetExpiryTime
+// ---------------------------------------------------------
+void CImpsSubSession::SetExpiryTime( RMessagePtr2 aMsg )
+ {
+ RMessage2 myMsg( aMsg );
+ TInt time = myMsg.Int0();
+ SetExpiryTime( time );
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::SetExpiryTime
+// ---------------------------------------------------------
+void CImpsSubSession::SetExpiryTime( TInt aVal )
+ {
+ if ( aVal > 0 )
+ {
+#ifndef _NO_IMPS_LOGGING_
+ CImpsClientLogger::Log( _L( "SubSession: SetExpiryTime %d" ), aVal );
+#endif
+ iExpiryTime = aVal;
+ Server()->SetExpiryTimer( aVal, EFalse );
+ }
+ }
+
+// ---------------------------------------------------------
+// CImpsSubSession::ExpiryTime
+// ---------------------------------------------------------
+TInt CImpsSubSession::ExpiryTime( )
+ {
+ return iExpiryTime;
+ }
+
+// ---------------------------------------------------------
+// TImpsOOMErrors::StoreOOM
+// ---------------------------------------------------------
+void TImpsOOMErrors::StoreOOM( TInt aOpCode )
+ {
+ // FIFO, a ring buffer
+ iOOMList[iW].SetOpId( aOpCode );
+ TInt newW = ( iW + 1 ) % KImpsMaxBuffered;
+ if ( newW != iR )
+ {
+ // overflow, don't increase the index.
+ // the last free write cell is re-used as needed
+ iW = newW;
+ }
+ }
+
+// ---------------------------------------------------------
+// ImpsOOMErrors::GetOOM
+// ---------------------------------------------------------
+TInt TImpsOOMErrors::GetOOM()
+ {
+ if ( iR != iW )
+ {
+ iOOMList[iR].SetAsSent();
+ return iOOMList[iR].OpId();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+// ---------------------------------------------------------
+// ImpsOOMErrors::RemoveOOM
+// ---------------------------------------------------------
+TInt TImpsOOMErrors::RemoveOOM()
+ {
+ if ( iR != iW && iOOMList[iR].IsSent() )
+ {
+ TInt ret = iOOMList[iR].OpId();
+ iR = ( ++iR ) % KImpsMaxBuffered;
+ return ret;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+// ---------------------------------------------------------
+// ImpsOOMErrors::Exists
+// ---------------------------------------------------------
+TBool TImpsOOMErrors::Exists()
+ {
+ if ( iR != iW /*&& !iOOMList[iR].IsSent()*/ )
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+
+// ---------------------------------------------------------
+// TImpsOOMErrors::Reset
+// ---------------------------------------------------------
+void TImpsOOMErrors::Reset()
+ {
+ iR = 0;
+ iW = 0;
+ }
+
+// ---------------------------------------------------------
+// TImpsOOMError::TImpsOOMError
+// ---------------------------------------------------------
+TImpsOOMError::TImpsOOMError()
+ {
+ iOpId = 0;
+ iSent = EFalse;
+ }
+
+// ---------------------------------------------------------
+// TImpsOOMError::SetOpId
+// ---------------------------------------------------------
+void TImpsOOMError::SetOpId( TInt aOpId )
+ {
+ iOpId = aOpId;
+ iSent = EFalse;
+ }
+
+// ---------------------------------------------------------
+// TImpsOOMError::OpId
+// ---------------------------------------------------------
+TInt TImpsOOMError::OpId()
+ {
+ return iOpId;
+ }
+
+// ---------------------------------------------------------
+// TImpsOOMError::SetAsSent
+// ---------------------------------------------------------
+void TImpsOOMError::SetAsSent( )
+ {
+ iSent = ETrue;
+ }
+
+// ---------------------------------------------------------
+// TImpsOOMError::IsSent
+// ---------------------------------------------------------
+TBool TImpsOOMError::IsSent( )
+ {
+ return iSent;
+ }
+
+
+// End of File