diff -r 000000000000 -r 72b543305e3a email/pop3andsmtpmtm/servermtmutils/src/IMSK.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/pop3andsmtpmtm/servermtmutils/src/IMSK.CPP Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,1765 @@ +// Copyright (c) 1998-2009 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: +// + +#include "IMSK.H" +#include +#include "IMSKSCR.H" +#include "IMUTDLL.H" +#include "cimsocketidletimer.h" + +#include +#include + +#include +#include + +#include +#include + + +/************************************************************* +* Notes: +* +* GetIAPBearer won't work if a new bearer is added, +* it will return KImskUnknownBearer +* +*************************************************************/ + +_LIT8(KImCarriageReturn,"\r\n"); +_LIT(KSSLProtocol,"tls1.0"); +_LIT8(KNullSSLDomainName, ""); + +const TInt KImutMicroSecondsToMinutes = 60000000; +const TInt KImutMicroSecondsToSeconds = 1000000; + +#if defined(__IMSK_SIMULATION) +_LIT(KGPRSConfigFile, "c:\\logs\\email\\imutconf\\gprs.cfg"); +_LIT(KFailIAPConfigFile, "c:\\logs\\email\\imutconf\\iapfail.cfg"); +_LIT8(KStart, "start:"); +_LIT8(KDuration, "duration:"); +_LIT8(KRepeat, "repeat:"); +_LIT8(KLogGPRSSimSuspended, "GPRS simulated suspend (%d)"); +_LIT8(KLogGPRSSimUnSuspended, "GPRS returned from suspend"); +#endif // __IMSK_SIMULATION + +#ifndef _NO_MSG_LOGGING +#define __IMSK_LOGGING +#endif + +#if defined(__IMSK_LOGGING) +#define __LOG_IN(text) (iLog?iLog->AppendResponse(text):void(0)) +#define __LOG_COMMENT_OUT(text) (iLog?iLog->AppendComment(text):void(0)) +#define __LOG_OUT(text) (iLog?iLog->AppendOut(text):void(0)) +#define __LOG_ERR(text,err) (iLog?iLog->AppendError(text,err):void(0)) +#else +#define __LOG_IN(text) (void(0)) +#define __LOG_COMMENT_OUT(text) (void(0)) +#define __LOG_OUT(text) (void(0)) +#define __LOG_ERR(text,err) (void(0)) +#endif + + +#if defined(__IMSK_LOGGING) +// IMSK Logging +_LIT8(KLogResolveCompleted, "Resolve completed"); +_LIT8(KLogResolveQueued, "Resolve queued"); +_LIT8(KLogConnectQueued, "Connect queued on port "); +_LIT8(KLogConnectCompleted, "Connect completed"); +_LIT8(KLogSendReceiveCompleted, "SendReceive/Receiving completed"); +_LIT8(KLogSendReceiveBinaryCompleted, "SendReceive/ReceivingBinaryData completed"); +_LIT8(KLogServerConnectionError, "Server Connection error"); +_LIT8(KLogReadCancelled, "Read cancelled"); +_LIT8(KLogWriteCancelled, "Write cancelled"); +_LIT8(KLogOverridefailed, "Overide failed with"); +_LIT8(KLogTLSHandShake, "TLS handshake Started"); +_LIT8(KLogTLSHandShakeCompleted, "TLS handshake completed"); +_LIT8(KLogSocketClosed, "Closed socket"); +_LIT8(KLogTLSResponse, "SSL/TLS response should be '%S'"); +_LIT8(KLogSendReceiveTimedOut, "SendReceive has timed out"); + +#endif + +//*********************************************************************************************/ +//* */ +//* Construction/Destruction functions */ +//* */ +//*********************************************************************************************/ + +LOCAL_C void RequestComplete(TRequestStatus& aStatus,TInt aError) + { + TRequestStatus* pStatus=&aStatus; + User::RequestComplete(pStatus,aError); + } + +EXPORT_C CImTextServerSession *CImTextServerSession::NewL() + { + CImTextServerSession* self=new (ELeave) CImTextServerSession(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +/** +@internalTechnology +@released +*/ +EXPORT_C CImTextServerSession *CImTextServerSession::NewL(RSocketServ& aSocketServ, CImConnect& aConnect) + { + CImTextServerSession* self=new (ELeave) CImTextServerSession(aSocketServ, aConnect); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +/** +Factory constructor that allows setting of send and receive idle times. + +An idle time of zero implies that no timer should be set. + +@param aSendIdleTime +The idle time in minutes allowed for sending. A value of zero indicates that no timer +should be set. + +@param aReceiveIdleTime +The idle time in minutes allowed for receiving. A value of zero indicates that no timer +should be set. + +@return +A pointer to the newly created CImTextServerSession object. +*/ +EXPORT_C CImTextServerSession *CImTextServerSession::NewL(TInt aSendIdleTime, TInt aReceiveIdleTime) + { + CImTextServerSession* self=new (ELeave) CImTextServerSession(aSendIdleTime, aReceiveIdleTime); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +/** +@internalTechnology +@released +*/ +EXPORT_C CImTextServerSession* CImTextServerSession::NewL(TInt aSendIdleTime, TInt aReceiveIdleTime, RSocketServ& aSocketServ, CImConnect& aConnect) + { + CImTextServerSession* self=new (ELeave) CImTextServerSession(aSendIdleTime, aReceiveIdleTime, aSocketServ, aConnect); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CImTextServerSession::CImTextServerSession() + : CMsgActive(EActivePriorityHigh), + iState(EImClosed), + iPerformLogging(ETrue) + { + } + +CImTextServerSession::CImTextServerSession(RSocketServ& aSocketServ, CImConnect& aConnect) + : CMsgActive(EActivePriorityHigh), + iServ(aSocketServ), + iState(EImClosed), + iConnect(&aConnect), + iPerformLogging(ETrue), + iClientOwnsConnection(ETrue) + { + } + +/** +Constructor that allows setting of the send and receive idle times. + +An idle time of zero implies that no timer should be set. + +@param aSendIdleTime +The idle time in minutes allowed for sending. A value of zero indicates that no timer +should be set. + +@param aReceiveIdleTime +The idle time in minutes allowed for receiving. A value of zero indicates that no timer +should be set. +*/ +CImTextServerSession::CImTextServerSession(TInt aSendIdleTime, TInt aReceiveIdleTime) + : CMsgActive(EActivePriorityHigh), + iState(EImClosed), + iPerformLogging(ETrue), + iSendIdleTime(aSendIdleTime*KImutMicroSecondsToMinutes), + iReceiveIdleTime(aReceiveIdleTime*KImutMicroSecondsToMinutes),iPrimaryTextServerSession(NULL) + { + } + +CImTextServerSession::CImTextServerSession(TInt aSendIdleTime, TInt aReceiveIdleTime, RSocketServ& aSocketServ, CImConnect& aConnect) + : CMsgActive(EActivePriorityHigh), + iServ(aSocketServ), + iState(EImClosed), + iConnect(&aConnect), + iPerformLogging(ETrue), + iSendIdleTime(aSendIdleTime*KImutMicroSecondsToMinutes), + iReceiveIdleTime(aReceiveIdleTime*KImutMicroSecondsToMinutes), + iClientOwnsConnection(ETrue) + { + } + +// +// 2nd stage of construction +// +void CImTextServerSession::ConstructL() + { + iBuffer = HBufC8::NewL(KImMailMaxBufferSize*2 +2); + + if (!iClientOwnsConnection) + { + User::LeaveIfError(iServ.Connect()); + } + +#if defined(__IMSK_SIMULATION) + + // if gprs suspension file exists - use its contents to determine + // the the time to delay TCP/IP traffic + + User::LeaveIfError(iFs.Connect()); + TInt err = iGprsFile.Open(iFs,KGPRSConfigFile,EFileShareAny); + + if (err != KErrNone && err != KErrPathNotFound && err != KErrNotFound) + User::Leave(err); + + if (err == KErrNone) + { + iGprsConfigExists=ETrue; + // read the first delay period + ReadNextPeriod(); + + // get baseline time + if (SuspendPeriodSet()) + iLastSuspend.UniversalTime(); + + User::LeaveIfError(iSuspendTimer.CreateLocal()); + } + else + iGprsConfigExists=EFalse; +#endif // __IMSK_SIMULATION + + iSocketIdleTimer = CImSocketIdleTimer::NewL(*this); + CActiveScheduler::Add(this); + } + +// +// Destruction +// +CImTextServerSession::~CImTextServerSession() + { + Disconnect(); + delete iBuffer; + if (!iClientOwnsConnection) + { + delete iConnect; + iServ.Close(); + } + delete iSentData; + delete iTLSResponse; +#if defined(__IMSK_SIMULATION) + iGprsFile.Close(); + delete iSendData; + iFs.Close(); +#endif // __IMSK_SIMULATION + delete iSocketIdleTimer; + delete iSSLDomainName; + } + + +//*********************************************************************************************/ +//* */ +//* Connect/Disconnect functions */ +//* */ +//*********************************************************************************************/ + +// +// Queue a standard or wrapped SSL connect (depending on state of iWrappedSocket) assuming the +// socket is successfully opened- RunL called on completion +// + +void CImTextServerSession::QueueGenericConnectL(TRequestStatus &aStatus,const TDesC& anAddressDesc, TInt aPortNum, const CImIAPPreferences& aIAPPreferences, const TDesC8& aSSLDomainName) + { +#if defined(__IMSK_LOGGING) + CreateLogFile(aPortNum); // Attempt to create the log file +#endif + Queue(aStatus); + + iIAPPreferences=&aIAPPreferences; + iPortNum=aPortNum; + iAddressDesc.Set(anAddressDesc); + + delete iSSLDomainName; + iSSLDomainName = NULL; + if (aSSLDomainName.Length() > 0) + { + iSSLDomainName = aSSLDomainName.AllocL(); + } + else + { + iSSLDomainName = HBufC8::NewL(iAddressDesc.Length()); + TPtr8 addr8ptr = iSSLDomainName->Des(); + addr8ptr.Copy(iAddressDesc); + } + + __ASSERT_ALWAYS(iState==EImClosed,gPanic(EImskSocketOpen)); + + iState = EImDialUsingOverride; +#if defined(__IMSK_SCRIPTING) + if (!iScript) + OpenScriptFile(iPortNum); // open the relevant script file if it exists + + if(iScript) + RequestComplete(iStatus,KErrNone); + else +#endif //(__IMSK_SCRIPTING) + { + // If we are not using the clients connection, create our own one now + if (!iClientOwnsConnection) + { + delete iConnect; + iConnect = 0; + iConnect = CImConnect::NewL(*iIAPPreferences,*this); + } +#if defined(__IMSK_SIMULATION) + iConnect->SetIAPsToFail(ReadConfigNum(KFailIAPConfigFile)); +#endif //(__IMSK_SIMULATION) + + // if local textseversession is active, then connect the session using existing RConnection + if(iPrimaryTextServerSession) + { + // Attaching the existing RConnection. + iConnect->SecondaryStartL(iPrimaryTextServerSession); + // Queue the connection + DoQueueConnect(); + return; + } + else + { + // If we are using the clients connection then it should have already been + // started, so just self complete to keep the state machine going. If it is + // our own connection, start it now. + if (iClientOwnsConnection) + { + RequestComplete(iStatus, KErrNone); + } + else + { + iConnect->StartL(iStatus); + } + } + } + SetActive(); + } + +// +// Queue a connect assuming the socket is successfully opened- RunL called on completion +// + +EXPORT_C void CImTextServerSession::QueueConnectL(TRequestStatus &aStatus,const TDesC& anAddressDesc, TInt aPortNum, const CImIAPPreferences& aIAPPreferences, TBool /*aEnableTimeout*/) + { + iWrappedSocket=EFalse; + QueueGenericConnectL(aStatus, anAddressDesc, aPortNum, aIAPPreferences, KNullSSLDomainName); + } + +/** +Queue a connect on a socket assuming the socket is successfully opened. + +@param aStatus Asynchronous completion status +@param aAddressDesc Address of the server to connect to +@param aIAPPreferences IAP connection preferences to be used +@param aPortNum Port number eg. 993, 465, 995. +@param aSSLDomainName SSL domain name to use for the connection +@pre None +@post Connection is ready to send and receive data +@since 9.5 +*/ +EXPORT_C void CImTextServerSession::QueueConnectL(TRequestStatus &aStatus,const TDesC& anAddressDesc, TInt aPortNum, const CImIAPPreferences& aIAPPreferences, const TDesC8& aSSLDomainName) + { + iWrappedSocket=EFalse; + QueueGenericConnectL(aStatus, anAddressDesc, aPortNum, aIAPPreferences, aSSLDomainName); + } + +// +// Queue a wrapped SSL connect assuming the socket is successfully opened- RunL called on completion +// + +EXPORT_C void CImTextServerSession::SSLQueueConnectL(TRequestStatus &aStatus,const TDesC& anAddressDesc, TInt aPortNum, const CImIAPPreferences& aIAPPreferences, TBool /*aEnableTimeout*/) + { + iWrappedSocket=ETrue; + QueueGenericConnectL(aStatus, anAddressDesc, aPortNum, aIAPPreferences, KNullSSLDomainName); + } + +/** +Queue a wrapped SSL connect on a socket assuming the socket is successfully opened. + +@param aStatus Asynchronous completion status +@param aAddressDesc Address of the server to connect to +@param aIAPPreferences IAP connection preferences to be used +@param aPortNum Port number eg. 993, 465, 995. +@param aSSLDomainName SSL domain name to use for the connection +@pre None +@post Connection is ready to send and receive data +@since 9.5 +*/ +EXPORT_C void CImTextServerSession::SSLQueueConnectL(TRequestStatus &aStatus,const TDesC& anAddressDesc, TInt aPortNum, const CImIAPPreferences& aIAPPreferences, const TDesC8& aSSLDomainName) + { + iWrappedSocket=ETrue; + QueueGenericConnectL(aStatus, anAddressDesc, aPortNum, aIAPPreferences, aSSLDomainName); + } + +// +// Public socket disconnection +// +EXPORT_C void CImTextServerSession::Disconnect() + { + iIAPCached=EFalse; + Cancel(); + Close(); + } + + +EXPORT_C void CImTextServerSession::Disconnect(TRequestStatus& aStatus) + { + Disconnect(); + RequestComplete(aStatus,KErrNone); + } + + +//*********************************************************************************************/ +//* */ +//* Send/Recieve/Query functions */ +//* */ +//*********************************************************************************************/ + +// +// Async send functions +// +EXPORT_C void CImTextServerSession::Send(TRequestStatus &aStatus, const TDesC8& aDesc) + { + if (iState!=EImSendReceive) + { + RequestComplete(aStatus,KErrDisconnected); + return; + } + + iSendShortIdleTime = 0; + iReceiveShortIdleTime = 0; + + Queue(aStatus); + + iSendReceive=EImSending; + RealSend(aDesc); + } + +// +// Async send function, specifying short idle timeouts should be used. +// aIdleTime specifies the send and next receive timeout to be used in seconds +// +EXPORT_C void CImTextServerSession::SendWithTimeout(TRequestStatus &aStatus, TInt aIdleTime, const TDesC8& aDesc) + { + if (iState!=EImSendReceive) + { + RequestComplete(aStatus,KErrDisconnected); + return; + } + + iSendShortIdleTime = aIdleTime*KImutMicroSecondsToSeconds; + iReceiveShortIdleTime = aIdleTime*KImutMicroSecondsToSeconds; + + Queue(aStatus); + + iSendReceive=EImSending; + RealSend(aDesc); + } + +EXPORT_C void CImTextServerSession::SendQueueReceiveWithTimeout(TRequestStatus& aStatus, TInt aIdleTime, const TDesC8& aDesc) + { + if (iState!=EImSendReceive) + { + RequestComplete(aStatus, KErrDisconnected); + return; + } + + iSendShortIdleTime = aIdleTime*KImutMicroSecondsToSeconds; + iReceiveShortIdleTime = aIdleTime*KImutMicroSecondsToSeconds; + Queue(aStatus); + + iSendReceive=EImSendingQueueReceive; + RealSend(aDesc); + } + +// +// async. Send +// +EXPORT_C void CImTextServerSession::Send(TRequestStatus &aStatus, TRefByValue aFmt,...) + { + VA_LIST list; + VA_START(list,aFmt); + TBuf8<2*KImMailMaxBufferSize+2>aBuf; + aBuf.AppendFormatList(aFmt,list); + + Send(aStatus, aBuf); + } + + +// +// async Send and receive operation +// +EXPORT_C void CImTextServerSession::SendQueueReceive(TRequestStatus &aStatus, const TDesC8& aDesc) + { + if (iState!=EImSendReceive) + { + RequestComplete(aStatus,KErrDisconnected); + return; + } + + Queue(aStatus); + + iSendReceive=EImSendingQueueReceive; + + RealSend(aDesc); + } + + +// +// async. SendQueueRecieve +// +EXPORT_C void CImTextServerSession::SendQueueReceive(TRequestStatus &aStatus, TRefByValue aFmt,...) + { + VA_LIST list; + VA_START(list,aFmt); + TBuf8<2*KImMailMaxBufferSize+2>aBuf; + aBuf.AppendFormatList(aFmt,list); + + SendQueueReceive(aStatus, aBuf); + } + + + +// +// User queues a new request from the socket (unless there's a full line of data in buffer +// then signal user and there's no need to make a receive request) +// +EXPORT_C void CImTextServerSession::QueueReceiveNextTextLine(TRequestStatus& aStatus) + { + if (iState!=EImSendReceive) + { + RequestComplete(aStatus,KErrDisconnected); + return; + } + + iSendReceive=EImReceiving; + + + Queue(aStatus); + + // Is there already a full text line in the buffer (ie is there a CRLF?) + if(iBuffer->Find(KImCarriageReturn)==KErrNotFound) + { + RealReceive(iReceive); + return; + } + // force calling active object to terminate + Complete(KErrNone); + } + +// +// Return first full line of data received from socket to user +// +EXPORT_C TImLineType CImTextServerSession::GetCurrentTextLine(TDes8& aDesc) + { + __ASSERT_ALWAYS(this->IsActive()==EFalse,gPanic(EImskSocketStillActive)); + // we have two possibilites a CRLF term line or we've filled our buffer + TInt bufLength=aDesc.MaxLength(); + TPtr8 bufPtr=iBuffer->Des(); + + if(iBuffer->Length()==0) + { + aDesc.Zero(); + return EReceiveBufferEmpty; + } + + TInt crLfPos=iBuffer->Find(KImCarriageReturn); // need to update + if(crLfPos!=KErrNotFound) + { + if(crLfPosLength(),bufLength); + } + else + { + // gPanic coz this shouldn't happen + gPanic(EImskUnknownState); + } + aDesc=iBuffer->Left(bufLength); + bufPtr.Delete(0,bufLength); + + TInt left=iReceive.Length(); + if (left) + { + if (left>bufLength) + left=bufLength; + bufPtr.Append(iReceive.Left(left)); + iReceive.Delete(0,left); + } +#if defined(__IMSK_SCRIPTING) + if(iScript) + __LOG_IN(aDesc); +#endif + return iCurrentLineType; + } + + + +EXPORT_C void CImTextServerSession::ReceiveBinaryData(TRequestStatus& aStatus, TDes8& aDes, TInt aLen) + { + if (iState!=EImSendReceive) + { + RequestComplete(aStatus,KErrDisconnected); + return; + } + + + Queue(aStatus); + iSendReceive=EImReceivingBinaryData; + iLen=aLen; + RealReceive(aDes); + } + + +// Returns the IAP we are connecting/connected with in aIAP or returns an error code +EXPORT_C TInt CImTextServerSession::GetIAPValue(TUint32 &aIAP) + { + TInt err=KErrNone; + + if(iIAPCached) + // Return cached IAP value + { + aIAP=iCurrentIAPcache; + } + else + // IAP not yet cached + { +#if defined(__IMSK_SCRIPTING) + if (iScript) + { + aIAP = 0; + return KErrNotFound; + } + else +#endif //(__IMSK_SCRIPTING) + { + err = iConnect->GetIAPValue(aIAP); + if(err==KErrNone && !(iState == EImClosed || iState == EImDialUsingOverride)) + // Only cache if no error and connection is complete + { + iCurrentIAPcache=aIAP; + iIAPCached=ETrue; + } + } + } + + return(err); + } +//Returns the Name of the RConnection in use. +EXPORT_C TInt CImTextServerSession::GetRConnectionName(TName &aName) + { +#if defined(__IMSK_SCRIPTING) + if (iScript) + { + _LIT(KNull,""); + aName.Copy(KNull); + return KErrNotFound; + } + else +#endif //(__IMSK_SCRIPTING) + { + return (iConnect->GetRConnectionName(aName)); + } + } + +// Returns the bearer type we are connected to with in aBearer or returns an error code +EXPORT_C TInt CImTextServerSession::GetIAPBearer(TUint32 &aBearer) + { +#if defined(__IMSK_SCRIPTING) + if (iScript) + { + aBearer = 0; + return KErrNotFound; + } + else +#endif //(__IMSK_SCRIPTING) + { + return iConnect->GetIAPBearer(aBearer); + } + } + +// Returns the last socket activity timeout value for the connection +EXPORT_C TInt CImTextServerSession::GetLastSocketActivityTimeout(TUint32& aTimeout) + { +#if defined(__IMSK_SCRIPTING) + if (iScript) + { + aTimeout = 0; + return KErrNotFound; + } + else +#endif //(__IMSK_SCRIPTING) + { + return iConnect->GetLastSocketActivityTimeout(aTimeout); + } + } + +RSocketServ& CImTextServerSession::GetSocketServ() + { + return iServ; + } + +//*********************************************************************************************/ +//* */ +//* Other public functions */ +//* */ +//*********************************************************************************************/ + + +EXPORT_C const TDesC& CImTextServerSession::LocalName() + { + return iLocalName; // a text descriptor - containing the numeric IP address of this client, eg "194.255.242.34" + } + + +EXPORT_C void CImTextServerSession::LogText(const TDesC8& aDesc) + { + __LOG_COMMENT_OUT(aDesc); + } + + + +EXPORT_C void CImTextServerSession::PerformLogging(TBool aLogging) + { + iPerformLogging = aLogging; + } + + + +EXPORT_C void CImTextServerSession::LogError(const TDesC8& aDesc, const TInt aNumber) + { + __LOG_ERR(aDesc,aNumber); + } + + + + +EXPORT_C void CImTextServerSession::SetSSLTLSResponseL(const TDesC8& aDesc) + { + __ASSERT_ALWAYS( aDesc.Length(), gPanic(EImskNoTLSResponseString)); + iTLSResponse=aDesc.AllocL(); + if (iTLSResponse==NULL) + User::Leave(KErrNoMemory); + iReadTLSResponse=ETrue; +#if defined(__IMSK_LOGGING) + TBuf8<1024> buf; + buf.AppendFormat(KLogTLSResponse,&aDesc); + __LOG_COMMENT_OUT(buf); +#endif + } + + +void CImTextServerSession::SocketIdle() + { + __LOG_COMMENT_OUT(KLogSendReceiveTimedOut); + + // The socket has been idle too long - probably in a half open situation + // and server could well have disconnected the session and we'll never + // know about it. So disconnect and notify the observer. + iSocketIdleTimeSet=ETrue; + Disconnect(); + } + + +//*********************************************************************************************/ +//* */ +//* Private IMSK connect functions */ +//* */ +//*********************************************************************************************/ + + +// +// Queue a connect assuming the socket is successfully opened- RunL called on completion +// +void CImTextServerSession::ParseSSLTLSResponseL() + { + __LOG_COMMENT_OUT(*iBuffer); + if (iBuffer->Find(*iTLSResponse)==KErrNotFound) + { + __LOG_ERR(_L8("ParseSSLTLSResponseL failed with "),KImskSSLTLSNegotiateFailed); + Complete(KImskSSLTLSNegotiateFailed); + return; + } + delete iTLSResponse; //finished with TLSresponse. free the memory + iTLSResponse=NULL; + iReadTLSResponse=EFalse; + CreateSecureSocketL(); + } + +void CImTextServerSession::CreateSecureSocketL() + { +#if defined(__IMSK_SCRIPTING) + if (iScript) + { + iState=EImTLSHandShakeStarted; + RequestComplete(iStatus,KErrNone); + SetActive(); + __LOG_COMMENT_OUT(KLogTLSHandShake); + return; + } +#endif + iSecureSocket = CSecureSocket::NewL( iSocket, KSSLProtocol); + __ASSERT_DEBUG(iSSLDomainName, gPanic(EPanicNoSSLDomainName)); + if (iSSLDomainName) + { + User::LeaveIfError(iSecureSocket->SetOpt(KSoSSLDomainName, KSolInetSSL, *iSSLDomainName)); + } + iSecureSocket->StartClientHandshake( iStatus ); + iState=EImTLSHandShakeStarted; + SetActive(); + __LOG_COMMENT_OUT(KLogTLSHandShake); + } + +void CImTextServerSession::SocketConnect() + { + + iState=EImConnect; + +#if defined(__IMSK_SCRIPTING) + if (iScript) + { + SetActive(); + RequestComplete(iStatus,KErrNone); + } + else +#endif + { + __ASSERT_DEBUG(iScript==NULL,User::Invariant()); + + iHostResolver.Close(); + TInt err; + __ASSERT_ALWAYS(iPortNum>=0, gPanic(EImskInvalidPortNumber)); + + TSockAddr& addr=iHostent().iAddr; + addr.SetPort(iPortNum); + LogText(addr); + err=iSocket.Open(iServ,KAfInet,KSockStream, KProtocolInetTcp, iConnect->GetConnection()); + + if(err==KErrNone) + { + iSocket.Connect(addr,iStatus); + SetActive(); + return; + } + __LOG_ERR(KLogServerConnectionError,err); + Complete(err); + } + } + + +// called from DoRunL after a connection has been opened +void CImTextServerSession::DoQueueConnect() + { +#if defined(__IMSK_LOGGING) + if (!iLog) + CreateLogFile(iPortNum); // Attempt to create the log file +#endif + TInt err; +#if defined(__IMSK_SCRIPTING) + if (iScript) + { + iState=EImResolve; + RequestComplete(iStatus,KErrNone); + SetActive(); + return; + } + else +#endif + { + iState=EImResolve; + err = iHostResolver.Open(iServ, KAfInet, KProtocolInetTcp, iConnect->GetConnection()); + if(err==KErrNone) + { + iHostResolver.GetByName(iAddressDesc, iHostent,iStatus); + SetActive(); + __LOG_COMMENT_OUT(KLogResolveQueued); + return; + } + } + Complete(err); + } + + +// called from DoRunL after a socket has been connected to +void CImTextServerSession::DoConnectedToSocketL() + { +#if defined(__IMSK_SCRIPTING) + // Retrieve the local IP address of this client + if(!iScript) +#endif + { + TInetAddr address; + iSocket.LocalName(address); + address.Output(iLocalName); + } + + if(iWrappedSocket) + { + CreateSecureSocketL(); + } + else + { + iState=EImSendReceive; + iSendReceive=EImInactive; + TPtr8 bufPtr=iBuffer->Des(); + bufPtr.Zero(); + } + } + + +// +// Close all socket and resovler access. Restore to just created state. +// +void CImTextServerSession::Close() + { + iHostResolver.Close(); + if (iSecureSocket) + { + //Closing the Secure Connection & the Socket. + //Since the Socket is closed, Shutdown shouldn't be called again, so making iSocketIdelTimeSet=EFalse + iSecureSocket->Close(); + delete iSecureSocket; + iSecureSocket=NULL; + iSocketIdleTimeSet = EFalse; + } + else if(iSocketIdleTimeSet) + { + //For non Secure Socket, if idle time is set then shutdown the socket + // Shutdown should be called only once, so make iSocketIdelTimeSet=EFalse + iSocketIdleTimeSet=EFalse; + iSocket.Shutdown(RSocket::EImmediate, iStatus); + iState = EImSendReceiveTimedOut; + SetActive(); + return; + } + else + { + //For non Secure Socket, if idle time is not set then close the socket + iSocket.Close(); + } + + iState=EImClosed; + __LOG_COMMENT_OUT(KLogSocketClosed); +#if defined(__IMSK_SCRIPTING) + delete iScript; + iScript=NULL; +#endif +#if defined(__IMSK_LOGGING) + delete iLog; + iLog=NULL; +#endif + +#if defined(__IMSK_SIMULATION) + if (iGprsConfigExists) + { + // reset to begin of config file + iCfgFilePos = 0; + // read the first delay period + ReadNextPeriod(); + + if (SuspendPeriodSet()) + iLastSuspend.UniversalTime(); + } +#endif // __IMSK_SIMULATION + } + + +//*********************************************************************************************/ +//* */ +//* CActive private IMSK functions */ +//* */ +//*********************************************************************************************/ + + + +// +// Current request has completed - deal with it +// +void CImTextServerSession::DoRunL() + { + delete iSentData; + iSentData = 0; + + switch(iState) + { + case EImTLSHandShakeStarted: + __LOG_COMMENT_OUT(KLogTLSHandShakeCompleted); + iState=EImSendReceive; + iSendReceive=EImInactive; + iSecurityState=EImSecurityStateOn; + break; + case EImDialUsingOverride: + DoQueueConnect(); + break; + case EImResolve: // we have a internet connection + __LOG_COMMENT_OUT(KLogResolveCompleted); + __LOG_ERR(KLogConnectQueued,iPortNum); + + SocketConnect(); + break; + + case EImConnect: // we have a socket connected + __LOG_COMMENT_OUT(KLogConnectCompleted); + DoConnectedToSocketL(); + break; + + case EImSendReceive: + { + // Cancel the socket idle timer as the socket request has completed. + iSocketIdleTimer->Cancel(); + + if(iSendReceive==EImReceiving) + { + __LOG_COMMENT_OUT(KLogSendReceiveCompleted); + __LOG_IN(iReceive); + + + TPtr8 bufPtr=iBuffer->Des(); + TInt space=bufPtr.MaxLength()-bufPtr.Length(); + if(iReceive.Length()>space) + { + bufPtr.Append(iReceive.Left(space)); + iReceive.Delete(0,space); + iSendReceive=EImInactive; + iCurrentLineType=EReceiveBufferFull; + } + else + { + bufPtr.Append(iReceive); + iReceive.Zero(); + // search for a CRLF in iBuffer + if(iBuffer->Find(KImCarriageReturn)==KErrNotFound) + { + // Start up the socket idle timer. + if(iReceiveShortIdleTime.Int() > 0 ) + { + iSocketIdleTimer->After(iReceiveShortIdleTime); + iReceiveShortIdleTime = 0; + } + else if( iReceiveIdleTime.Int() > 0 ) + { + iSocketIdleTimer->After(iReceiveIdleTime); + } + + if (iSecurityState==EImSecurityStateOn) + iSecureSocket->RecvOneOrMore(iReceive,iStatus,iLen); + else + iSocket.RecvOneOrMore(iReceive,NULL,iStatus,iLen); + SetActive(); + } + else + { + iSendReceive=EImInactive; + iCurrentLineType=ECRLFTerminated; + if (iReadTLSResponse) + { + ParseSSLTLSResponseL(); + return; + } + } + } + } + else if (iSendReceive==EImReceivingBinaryData) + { + // just pass raw binary data straight back to caller without any processing + __LOG_COMMENT_OUT(KLogSendReceiveBinaryCompleted); + __LOG_IN(*iReceiveData); + } + else if(iSendReceive==EImSendingQueueReceive) + { + iSendReceive=EImReceiving; + // Is there already a full text line in the buffer (ie is there a CRLF?) + if(iBuffer->Find(KImCarriageReturn)==KErrNotFound) + { + RealReceive(iReceive); + return; + } + } + else if (iSendReceive==EImSending) + { + if (iReadTLSResponse) + { + iSendReceive=EImReceiving; + RealReceive(iReceive); + return; + } + Complete(KErrNone); + } +#if defined(__IMSK_SIMULATION) + else if(iSendReceive==EImSuspended) + { + __LOG_COMMENT_OUT(KLogGPRSSimUnSuspended); + + iSendReceive=iSuspendedState; + if(iSendReceive==EImSending || iSendReceive==EImSendingQueueReceive) + { + RealSend(*iSendData); + delete iSendData; + iSendData=NULL; + } + else + RealReceive(*iReceiveData); + } +#endif // __IMSK_SIMULATION + } + break; + case EImSendReceiveTimedOut: + { + iSocket.Close(); + iState=EImClosed; + Complete(KErrTimedOut); + break; + } + + default: + gPanic(EImskUnknownState); + } + + } + + +// +// Cancel connect/receive if one is currently occurring +// +void CImTextServerSession::DoCancel() + { + // clear out receive buffer if we cancel + TPtr8 bufPtr=iBuffer->Des(); + bufPtr.Zero(); + + switch(iState) + { + case EImResolve: + iHostResolver.Cancel(); + break; + case EImConnect: + iSocket.CancelConnect(); + break; + case EImSendReceive: + { +#if defined(__IMSK_SCRIPTING) + if (!iScript) +#endif + { + // Cancel the socket idle timer as the socket request is also being + // cancelled. + iSocketIdleTimer->Cancel(); + + if(iSendReceive==EImSending || iSendReceive==EImSendingQueueReceive) + { + __LOG_COMMENT_OUT(KLogWriteCancelled); + if (iSecurityState==EImSecurityStateOn) + iSecureSocket->CancelSend(); + else + iSocket.CancelSend(); + } + else if(iSendReceive==EImReceiving || iSendReceive==EImReceivingBinaryData) + { + __LOG_COMMENT_OUT(KLogReadCancelled); + if (iSecurityState==EImSecurityStateOn) + iSecureSocket->CancelRecv(); + else + iSocket.CancelRead(); + } + } +#if defined(__IMSK_SCRIPTING) + else + iScript->Cancel(); +#endif//__IMSK_SCRIPTING +#if defined(__IMSK_SIMULATION) + if(iSendReceive==EImSuspended) iSuspendTimer.Cancel(); +#endif//__IMSK_SIMULATION + } + break; + case EImTLSHandShakeStarted: + if (iSecureSocket) + { + iSecureSocket->CancelHandshake(); + } + break; + case EImClosed: + default: + break; + case EImDialUsingOverride: + if (iConnect) + iConnect->Cancel(); + break; + case EImSendReceiveTimedOut: + iSocket.CancelAll(); + iSocket.Close(); + iState=EImClosed; + break; + } + + delete iSentData; + iSentData = 0; + + if(!iSocketIdleTimeSet) + { + CMsgActive::DoCancel(); + } + } + +// +// If it all goes wrong +// +void CImTextServerSession::DoComplete(TInt& aStatusValue) + { + TInt status=aStatusValue; + // + // test for KErrEof returns from socket. This might indicate that there has been + // a TCPIP half close - with the remote end sending a FIN + // If this occurs as response to QUIT treat as a remote disconnection + // + if (iState==EImDialUsingOverride) + { + __LOG_ERR(KLogOverridefailed,aStatusValue); + Close(); + return; + } + if(status==KErrEof) + { + aStatusValue=KErrDisconnected; + Close(); + return; + } + // don't close the socket if the ide timer timed out, or if asynch operation was cancelled... + if((aStatusValue) && (aStatusValue!=KErrCancel) && (aStatusValue!=KErrTimedOut)) + { + // there was an error so no need to keep on running these timers... + if(iState==EImResolve) + { + if (aStatusValue==KErrNotFound) + aStatusValue=KImskErrorDNSNotFound; + + if (aStatusValue==KErrLocked) + aStatusValue=KImskErrorControlPanelLocked; + } + + if(iState!=EImClosed) + Close(); + } + + delete iSentData; + iSentData = 0; + } + + +//*********************************************************************************************/ +//* */ +//* Private IMSK send/receive functions */ +//* */ +//*********************************************************************************************/ + +// log & Send to a socket +void CImTextServerSession::RealSend(const TDesC8& aDesc) + { + // Cancel the socket idle timer as we are about to send some data + iSocketIdleTimer->Cancel(); + +#if defined(__IMSK_SIMULATION) + if(IsSuspended()) + { + iSuspendedState=iSendReceive; + iSendReceive=EImSuspended; + iSendData=aDesc.Alloc(); + if(iSendData==NULL) + { + TInt err=KErrNoMemory; + DoComplete(err); + } + SetAfterTimer(); + } + else +#endif + { + // Do the logging of the text if required + if (iPerformLogging) + __LOG_OUT(aDesc); + +#if defined(__IMSK_SCRIPTING) + if(iScript) + RequestComplete(iStatus,KErrNone); + else +#endif + { + if(iSecurityState==EImSecurityStateFailed) + RequestComplete(iStatus,KImskSecuritySettingsFailed); + else + { + iSentData = aDesc.Alloc(); + + if (iSentData==NULL) + RequestComplete(iStatus, KErrNoMemory); + else + { + // Start up the socket idle timer. + if( iSendShortIdleTime.Int() > 0 ) + { + iSocketIdleTimer->After(iSendShortIdleTime); + iSendShortIdleTime = 0; + } + else if( iSendIdleTime.Int() > 0 ) + { + iSocketIdleTimer->After(iSendIdleTime); + } + + if (iSecurityState==EImSecurityStateOn) + iSecureSocket->Send(*iSentData,iStatus); + else + iSocket.Write(*iSentData,iStatus); + } + } + } + } + SetActive(); + } + +// +// Queue a recieve from a socket +// +void CImTextServerSession::RealReceive(TDes8& aDesc) + { + // Cancel the socket idle timer as we are about to receive some data + iSocketIdleTimer->Cancel(); + + iReceiveData=&aDesc; +#if defined(__IMSK_SIMULATION) + if(IsSuspended()) + { + iSuspendedState=iSendReceive; + iSendReceive=EImSuspended; + SetAfterTimer(); + } + else +#endif + { +#if defined(__IMSK_SCRIPTING) + + if(iScript) + { + TPtr8 bufPtr=iBuffer->Des(); + iScript->RetrieveResponse(bufPtr, iStatus); + TInt bufLength = aDesc.MaxLength(); + aDesc=iBuffer->Left(bufLength); + bufPtr.Delete(0,bufLength); + } + else +#endif + { + if(iSecurityState==EImSecurityStateFailed) + RequestComplete(iStatus,KImskSecuritySettingsFailed); + else + { + // Start up the socket idle timer. + if(iReceiveShortIdleTime.Int() > 0 ) + { + iSocketIdleTimer->After(iReceiveShortIdleTime); + iReceiveShortIdleTime = 0; + } + else if( iReceiveIdleTime.Int() > 0 ) + { + iSocketIdleTimer->After(iReceiveIdleTime); + } + + if (iSecurityState==EImSecurityStateOn) + iSecureSocket->RecvOneOrMore(aDesc,iStatus,iLen); + else + iSocket.RecvOneOrMore(aDesc,NULL,iStatus,iLen); + } + } + } + SetActive(); + } + + + +//*********************************************************************************************/ +//* */ +//* Private logging/scripting/suspend functions */ +//* */ +//*********************************************************************************************/ + + + + +#if defined(__IMSK_LOGGING) +// +// Attempt to create a log file to record messages sent to/from socket +// +void CImTextServerSession::CreateLogFile(TInt aPortNum) + { + //attempt to create a log file + TRAP_IGNORE(iLog = CImLog::NewL(aPortNum)); + } +#endif + +#if defined(__IMSK_SCRIPTING) +// +// See if a script file exists for the type of session we're perforiming +// if it doesn't really try to connect +// if it does exits then load the iap and bearer we should pretend to be connected to +void CImTextServerSession::OpenScriptFile(TInt aPortNum) + { + TRAP_IGNORE(iScript=CImTextServerScript::NewL(aPortNum)); + } + +#endif + +#if defined(__IMSK_SIMULATION) + +// ************************************************************************* +// GPRS Suspend code +// ************************************************************************* +// +// Read next suspension time from configuration file gprs.cfg +// The tokens start:, duration: and repeat: are located and their +// values used to setup the next suspension period. +// NB, The tokens are assumed (must be) to be paired as follows: +// +// start: nn +// duration: nn +// +// or +// +// repeat: +// start: nn +// duration: nn +// +// or +// +// duration: nn (where start is assumed to be 0. + +void CImTextServerSession::ReadNextPeriod() + { + ResetSuspendPeriod(); + + // Read into the buffer + TBuf8<80> buffer; + + // Get the current file position + TInt pos; + TInt err; + + iGprsFile.Seek(ESeekStart, iCfgFilePos); + + // look for the tokens + + while (! SuspendPeriodSet()) + { + err = iGprsFile.Read(buffer); + + if (err != KErrNone) + { + ResetSuspendPeriod(); + return; + } + + // quit on eof + if (buffer.Length() == 0) + break; + + // Copy to the lfcr and then set the file pointer + // to the point after that... + pos = buffer.Find(KImCarriageReturn); + if (pos != KErrNotFound) + { + iCfgFilePos += pos + 2; + buffer.Delete(pos,buffer.Length()); + } + else + iCfgFilePos += buffer.Length(); + + iGprsFile.Seek(ESeekStart, iCfgFilePos); + + // check the line read in + buffer.TrimLeft(); + + if (buffer.FindF(KRepeat) != KErrNotFound) + { + iRepeat = ETrue; + } + else if (buffer.FindF(KStart) != KErrNotFound) + { + iStart = GetTokenValue(KStart.iTypeLength, buffer); + } + else if (buffer.FindF(KDuration) != KErrNotFound) + { + iDuration = GetTokenValue(KDuration.iTypeLength, buffer); + } + } + } + + + +TInt CImTextServerSession::ReadConfigNum(const TDesC& aName) + { + RFile configFile; + TInt err = configFile.Open(iFs,aName,EFileShareAny); + TInt toreturn=0; + if(err==KErrNone) + { + TBuf8<20> buffer; // we ignore more than 20 chars in the file + configFile.Read(buffer,20); + configFile.Close(); + + TLex8 lexical(buffer); + lexical.Val(toreturn); + } + return toreturn; + } + + + +TUint32 CImTextServerSession::GetTokenValue(TInt aTokenLen, const TPtrC8& aBuffer) + { + TUint32 num; + TInt i = aTokenLen; + + TBuf<70> value; + value.Copy(aBuffer); + + // remove leading token, space and tabs + while(i < value.Length()) + { + if (value[i] != ' ' && value[i] != '\t') + break; + i++; + } + value.Delete(0,i); + + TLex lex(value); + + if (lex.Val(num,EDecimal) != KErrNone) + num = 0; + + return num; + } + +// determine if we are in a suspension period based on the last +// time one took place. If we have passed over the last period +// get the next period from the config file. +TBool CImTextServerSession::IsSuspended() + { + if (iGprsConfigExists && SuspendPeriodSet()) + { + TTime now; + now.UniversalTime(); + + // suspend period has not yet started + if (now < iLastSuspend + iStart) + return EFalse; + + // we are in the suspend period + if (now < iLastSuspend + iStart + iDuration) + return ETrue; + + // we have moved out of the period so get the next one + // if not required to repeat the last + if (! iRepeat) + ReadNextPeriod(); + + // reset baseline time/send buffer len if one set + if (SuspendPeriodSet()) + { + iLastSuspend.UniversalTime(); + + // check for immediate start + if (iStart.Int() == 0) + return ETrue; + } + } + + return EFalse; + } + +// determine if a suspend period has been defined. +// start can be immediate. +TBool CImTextServerSession::SuspendPeriodSet() + { + return iStart.Int() >= 0 && iDuration.Int() != 0 ? ETrue : EFalse; + } + +void CImTextServerSession::ResetSuspendPeriod() + { + iStart = 0; + iDuration = 0; + iRepeat = EFalse; + } + + +// calls DoRunL after the delay period has expired +// NB, delay is expected to be < KMinTInt32 secs +// used to queue async calls +void CImTextServerSession::SetAfterTimer() + { + + { + TBuf8<1024> buf; + buf.Format(KLogGPRSSimSuspended,iDuration.Int()); + __LOG_COMMENT_OUT(buf); + } + TTime now; + + now.UniversalTime(); + + TTimeIntervalMicroSeconds usecs(TInt64(0)); + + TTime delayEnd = iLastSuspend + iStart + iDuration; + if (now <= delayEnd) + usecs=delayEnd.MicroSecondsFrom(now); + TInt64 delay=usecs.Int64()+500000; + iSuspendTimer.After(iStatus,I64INT(delay)); + } + + +#endif // __IMSK_SIMULATION + + + +// Depreciated functions - do not use. +EXPORT_C void CImTextServerSession::QueueConnect(TRequestStatus& ,const TDesC& , TInt , TBool ) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + } +EXPORT_C void CImTextServerSession::QueueConnect(TRequestStatus&,const TDesC&, TInt, TCallBack,const TUint32,TInt, TBool) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + } +EXPORT_C void CImTextServerSession::QueueConnect(TRequestStatus &,const TDesC& , TInt ,const TUint32 , TInt , TBool ) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + } +EXPORT_C void CImTextServerSession::QueueConnect(TRequestStatus& ,const TDesC& , TInt , TCallBack , TBool ) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + } +EXPORT_C void CImTextServerSession::QueueConnect(TRequestStatus& ,const TDesC& , TInt , TCallBack , const CImIAPPreferences& ,TInt , TBool ) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + } +EXPORT_C void CImTextServerSession::QueueConnect(TRequestStatus &,const TDesC& , TInt , const CImIAPPreferences& ,TInt , TBool ) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + } +EXPORT_C TInt CImTextServerSession::Send(const TDesC8& ) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + return 0; + } +EXPORT_C TInt CImTextServerSession::Send(TRefByValue,...) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + return 0; + } +EXPORT_C TInt CImTextServerSession::SendReceive(const TDesC8& ) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + return 0; + } +EXPORT_C TInt CImTextServerSession::Receive(TDes8&) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + return 0; + } +EXPORT_C void CImTextServerSession::Receive(TRequestStatus &, TDes8&) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + } + +EXPORT_C CImTextServerSession *CImTextServerSession::NewLC (TImOperationMode, RSocketServ &) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + return 0; + } +EXPORT_C CImTextServerSession *CImTextServerSession::NewL(RSocketServ &) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + return 0; + } + +EXPORT_C TInt CImTextServerSession::SetSecurity(TBool, TBool) + { + __ASSERT_ALWAYS(EFalse, gPanic(EImskNotSupported)); + return 0; + } + +/** + Intended Usage : Gets the stage of the connection process obtained from RConnection + @since 7.0s + @return The current connection stage from RConnection or a system-wide error code. + + */ +EXPORT_C TInt CImTextServerSession::GetConnectionStage() + { +#if defined(__IMSK_SCRIPTING) + if (iScript) + { + return KErrNotFound; + } + else +#endif //(__IMSK_SCRIPTING) + { + TNifProgress progress; + TInt err = iConnect->Progress(progress); + return (err == KErrNone) ? (progress.iStage) : (err); + } + } + +// Setting of PrimaryTextServerSession, Going to be set on the secondary session. +EXPORT_C void CImTextServerSession::SetPrimaryTextServerSession(CImTextServerSession* aPrimaryTextServerSession) + { + iPrimaryTextServerSession=aPrimaryTextServerSession; + } + +// Return of current Connection +CImConnect* CImTextServerSession::GetCImConnect() + { + return iConnect; + }