diff -r 000000000000 -r b16258d2340f applayerprotocols/ftpengine/ftpprot/FTPPROT.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/applayerprotocols/ftpengine/ftpprot/FTPPROT.CPP Tue Feb 02 01:09:52 2010 +0200 @@ -0,0 +1,1146 @@ +// Copyright (c) 2003-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: +// FTP protocol engine +// Author: Philippe Gabriel +// Entry point in the DLL +// Implements the interface to the FTP protocol +// through FTP commands defined as per RFC 959 +// Drives the DTP and PI channels +// +// + +/** + @file FTPPROT.CPP + @internalComponent +*/ + +#include +#include +#include "DEBUG.H" +#include "PROTOCOL.H" +#include "PICHNL.H" +#include "ANSPARSE.H" +#include "PASVANS.H" +#include "DTPCHNL.H" +#include "SETERROR.H" + +// +// Definitions +// + +// +// Minterface Implementation +// + +void CFtpProtocolDerived::PIChannelOperationCompletion(const TPiOperationCompletion aCompletionStatus) +/** +Define the PIChannel callback notifiers +These notifiers are called from PIChannel, but the event source +can be quite different: +PIChannelOperationCompletion, PIChannelOperationError and PIChannelReset +come from an error signaled at the TCP/IP level +where PIChannelRcvNotification is called whenever the server sent us a message +*/ + { + switch (aCompletionStatus) + { + case MPIChannelNotifier::EPiConnectComplete: + FTPPROTDEBUG(_DBGFtpprot,_L("PIChannelNotifierClass::PIChannelOperationCompletion(EPiConnectComplete) called\n")); + // Get my IP address for future use + iPiChannel->GetLocalAddress(iLocalAddress); + // Get welcome message from server + iPiChannel->GetNextAnswer(iServerAnswerBuffer); + UpdateState(EPiChannelConnectComplete); + break; + case MPIChannelNotifier::EPiSendComplete: + FTPPROTDEBUG(_DBGFtpprot,_L("PIChannelNotifierClass::PIChannelOperationCompletion(EPiSendComplete) called\n")); + UpdateState(EPiChannelSendComplete); + break; + default: + FTPPROTDEBUG(_DBGFtpprot,_L("PIChannelNotifierClass::PIChannelOperationCompletion() called\n")); + break; + } + return; + } + +void CFtpProtocolDerived::PIChannelOperationError(const TPiOperationError aErrorStatus) + { + FTPPROTDEBUG(_DBGFtpprot,_L("PIChannelNotifier::PIChannelOperationError called\n")); + //Close DTP Channel + iDtpChannel->Disconnect(); + //Reset state + iState = EIdle; + switch (aErrorStatus) + { + case MPIChannelNotifier::EPiConnectionReset: + //ARGHH this is serious and not recoverable + // Notify upper layer + iNotifier->ErrorNotification(MFtpProtocolNotifier::EOpConnectionReset); + break; + case MPIChannelNotifier::EPiConnectFailed: + // Notify upper layer + iNotifier->ErrorNotification(MFtpProtocolNotifier::EOpConnectionFailed); + break; + default: + break; + } + return; + } + +void CFtpProtocolDerived::PIChannelRcvNotification(void) + { + // Must call upper level client before issuing another read, otherwise + // I lose my buffer + FTPPROTDEBUG(_DBGFtpprot,_L("PIChannelNotifier::PIChannelRcvNotification called\n")); + // At this point need to parse the incoming buffer to decide if + // more data is to be fetched + // 2 cases + // - 1 line message + // - multiline message + // Parse the buffer + // it may contain several answers + for(;;) + { + TBool answer; + // Parse an answer + answer = iFTPServerAnswerParser->Parse(iServerAnswerBuffer); + // If I'm performing a PASV + // Parse an address + if( iState == EPerformingPasv) + iFtpPASVAnswerParser->Parse(iServerAnswerBuffer, iRemoteAddress); + //Passes the server text to upper layer + iNotifier->ServerMessage(iServerAnswerBuffer.Left(iFTPServerAnswerParser->NChars())); + // Remove what's already parsed from buffer + iServerAnswerBuffer.Delete(0,iFTPServerAnswerParser->NChars()); + if(answer) + { + // if I parsed an answer succesfully, notify upper layer + // of answer code + UpdateState(EFtpCodeReply); + } + //If buffer empty, stop parsing + if(iServerAnswerBuffer.Length()==0) + break; + } + // Fetch next answer, if there's more to come + // PG 2808 Always fetch next, potential hanging on close bug here + //if (iState != EPerformingQuit) + // Get ready to fetch next answer from server + iPiChannel->GetNextAnswer(iServerAnswerBuffer); + return; + } + +void CFtpProtocolDerived::DTPChannelOperationCompletion(const TDtpOperationCompletion aCompletionStatus) +/** +Define the DTPChannel callback notifiers +Notify of normal completion of an operation +*/ + { + FTPPROTDEBUG(_DBGFtpprot,_L("CFtpProtocolDerived::DTPChannelOperationCompletion called ")); + switch(aCompletionStatus) + { + case MDTPChannelNotifier::EDtpAcceptComplete: + case MDTPChannelNotifier::EDtpConnectComplete: + FTPPROTDEBUG(_DBGFtpprot,_L("Connected \n")); + switch(iState) + { + case EPerformingList: + case EPerformingNlst: + case EPerformingRetr: + iDtpChannel->Recv(*iIOBuffer); + break; + case EPerformingStor: + case EPerformingStou: + iDtpChannel->Send(*iIOBuffer); + break; + } + break; + default: + break; + } + } + +void CFtpProtocolDerived::DTPChannelOperationError(const TDtpOperationError aErrorStatus) +/** +Notify of error performing an operation +*/ + { + FTPPROTDEBUG(_DBGFtpprot,_L("CFtpProtocolDerived::DTPChannelOperationError called\n")); + switch (aErrorStatus) + { + case MDTPChannelNotifier::EDtpConnectFailed: + // + iNotifier->ErrorNotification(MFtpProtocolNotifier::EXferNotInitialised); + break; + case MDTPChannelNotifier::EDtpRecvAborted: + case MDTPChannelNotifier::EDtpSendAborted: + switch(iState) + { + // Some bad behaved ftp server (microsoft) + // reset the DTP connection on abort + case EPerformingAbor: + UpdateState(EDtpChannelClosed); + break; + default: + //Close PI Channel + iPiChannel->Disconnect(); + //Reset state + iState = EIdle; + iNotifier->ErrorNotification(MFtpProtocolNotifier::EXferReset); + break; + } + break; + default: + // Cannot come here + __ASSERT_DEBUG(FALSE, User::Panic(_L("CFtpProtocolDerived"), 0)); + break; + } + return; + } + +void CFtpProtocolDerived::DTPChannelXferNotification(const TDtpOperationCompletion aCompletionStatus) +/** +Notify of reception +*/ + { + FTPPROTDEBUG(_DBGFtpprot,_L("CFtpProtocolDerived::DTPChannelRcvNotification called\n")); + // notify upper layer a packet is ready + switch(aCompletionStatus) + { + case MDTPChannelNotifier::EDtpRcvMoreData: + FTPPROTDEBUG(_DBGFtpprot,_L("EDtpRcvMoreData\n")); + iNotifier->ServerXFerNotification(MFtpProtocolNotifier::EPacketReceived); + break; + case MDTPChannelNotifier::EDtpSendEOFComplete: + FTPPROTDEBUG(_DBGFtpprot,_L("EDtpSendEOFComplete\n")); + UpdateState(EDtpChannelClosed); + break; + case MDTPChannelNotifier::EDtpRcvComplete: + FTPPROTDEBUG(_DBGFtpprot,_L("EDtpRecvEOFComplete\n")); + UpdateState(EDtpChannelClosed); + break; + case MDTPChannelNotifier::EDtpSendComplete: + FTPPROTDEBUG(_DBGFtpprot,_L("EDtpSendComplete\n")); + iNotifier->ServerXFerNotification(MFtpProtocolNotifier::EPacketSent); + break; + default: + FTPPROTDEBUG(_DBGFtpprot,_L("WARNING !!!!! Unrecognised event\n")); + break; + } + } + +void CFtpProtocolDerived::FTPResolverNotifier(const TFTPResolverNotificationCode aCompletionStatus) +/** +Resolver callback +*/ + { + FTPPROTDEBUG(_DBGFtpprot,_L("CFtpProtocolDerived::DFTPResolverNotifier called")); + __ASSERT_DEBUG(iState == ELookingUp, User::Panic(_L("CFtpProtocolDerived"), EPIPanicMegaOI)); + switch(aCompletionStatus) + { + case MFTPResolverNotifier::EDtpLookupComplete: + FTPPROTDEBUG(_DBGFtpprot,_L("EDtpLookupComplete\n")); + iState = EConnecting; + iResolver->SetAddress(iRemoteAddress); + Connect(iRemoteAddress); + break; + case MFTPResolverNotifier::EDtpLookupFailed: + FTPPROTDEBUG(_DBGFtpprot,_L("EDtpLookupFailed\n")); + // + iNotifier->ErrorNotification(MFtpProtocolNotifier::EHostNotFound); + iState = EIdle; + + break; + } + } + +void CFtpProtocolDerived::SetErrorNotifier(const TInt aError) +/** +Define the CFTPSetError callback notifier +*/ +{ + switch(aError) + { + case MFtpProtocolNotifier::ESocketError: + iNotifier->ErrorNotification(MFtpProtocolNotifier::ESocketError); + break; + case MFtpProtocolNotifier::EOpCanceled: + iNotifier->ErrorNotification(MFtpProtocolNotifier::EOpCanceled); + break; + default: + __ASSERT_DEBUG(FALSE, User::Panic(_L("CFtpProtocolDerived"), EPIPanicMegaOI)); + break; + } +} + +// +// FTP Private methods implementation +// + +void CFtpProtocolDerived::UpdateState(const TInternalEvents aEvent) + { +#if defined(__FTPPROTDEBUG__) + TBuf<4> debugBuffer; //Placeholder for the answer I got from the FTP server +#endif + FTPPROTDEBUG(_DBGFtpprot,_L("CFtpProtocolDerived::UpdateState\n")); + // Do some preprocessing according to the event + switch(aEvent) + { + case EFtpCodeReply: + // Called when an answer has been parsed + FTPPROTDEBUG(_DBGFtpprot,_L("CFtpProtocolDerived::UpdateState called aEvent==EFtpCodeReply\n")); + // Fetch the answer + iFTPServerAnswerParser->ServerAnswer(iAnswer); + //Display the answer for debug purpose +#if defined(__FTPPROTDEBUG__) + debugBuffer.Copy(iAnswer); + debugBuffer.Append(0); + FTPPROTDEBUG(_DBGFtpprot,_L("Parsed server answer: <")); + FTPPROTDEBUG(_DBGFtpprot,debugBuffer); + FTPPROTDEBUG(_DBGFtpprot,_L(">\n")); +#endif + // Check the answer to keep it in the allowed bounds + if((iAnswer[0]<'1') || (iAnswer[0]>'5')) + { + // Answer out of bounds + FTPPROTDEBUG(0xffff,_L("!!!!!!SERVER ANSWER OUT OF BOUND\n")); + } + break; + default: + break; + } + // Completion callback can only be sent when + // - PI Channel has been notified of success for the send operation + // - An answer has been received and parsed + // Accordingly, we bail out if any of these conditions is not + // completed yet + if (iAnswer.Length()<3) + { + FTPPROTDEBUG(_DBGFtpprot,_L("iAnswer.Length()<3\n")); + return; + } + if (iPiChannel->Busy()) + { + FTPPROTDEBUG(_DBGFtpprot,_L("iPiChannel->Busy()) \n")); + return; + } + // Execute the next sequence of operations depending on our current state + switch(iState) + { + // Simple commands as per FSM page 54 of RFC 959 + case EConnecting: + case EPerformingAllo: + case EPerformingDele: + case EPerformingCwd: + case EPerformingCdup: + case EPerformingSmnt: + case EPerformingHelp: + case EPerformingMode: + case EPerformingNoop: + case EPerformingSite: + case EPerformingPort: + case EPerformingSyst: + case EPerformingStat: + case EPerformingRmd: + case EPerformingMkd: + case EPerformingPwd: + case EPerformingStru: + case EPerformingType: + // Only allow a "2" answer + if (iAnswer[0]=='2') + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + else + iNotifier->ServerNegativeAnswerNotification(MFtpProtocolNotifier::EOpFailed); + break; + case EPerformingQuit: + // In any case close the PI Channel + iPiChannel->Disconnect(); + // Only allow a "2" answer + if (iAnswer[0]=='2') + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + else + iNotifier->ServerNegativeAnswerNotification(MFtpProtocolNotifier::EOpFailed); + break; + case EPerformingAbor: + // rfc says, I might get a 426 + // then I'll get a 2xx to ack the ABORT + // Just wait for a "2" + // Note: Not checking for error here + // If the server nack my abort, I'll hang and the user has to reset me + if (iAnswer[0]=='2') + { + // Check the DtpChannel has been closed + if(!iDtpChannel->Closed()) + { + FTPPROTDEBUG(_DBGFtpprot,_L("!iDtpChannel->Closed()\n")); + return; + } + // Channel closed and 2 answer - notify completion + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + } + else if (iAnswer[0]=='4') + // Assume that if the server acknowledged my abort + // request with a 4, it has already issued a FIN + // I just reset the connection, otherwise I might have to + // wait for a long time to flush the queud packets + iDtpChannel->Disconnect(); + break; + case EPerformingPasv: + // Only allow a "2" answer, verify we got a valid address to connect to + if ((iAnswer[0]=='2') && (iFtpPASVAnswerParser->Fetch(iFTPDTPAddress))) + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + else + iNotifier->ServerNegativeAnswerNotification(MFtpProtocolNotifier::EOpFailed); + break; + // Commands defined as per 1st FSM page 55 of RFC 959 + case EPerformingList: + case EPerformingNlst: + case EPerformingRetr: + case EPerformingStor: + case EPerformingStou: + // If We get an error close DTP channel, notify error and bail out + switch(iAnswer[0]) + { + case '1': + // Ignore a 1 answer + break; + case '2': + // Check the DtpChannel has been closed + if(!iDtpChannel->Closed()) + { + FTPPROTDEBUG(_DBGFtpprot,_L("!iDtpChannel->Closed()\n")); + return; + } + // Channel closed and 2 answer - notify completion + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + break; + case '3': + case '4': + case '5': + default: + // If something else than 1-5 it really screwed up!! + iDtpChannel->Disconnect(); + iNotifier->ServerNegativeAnswerNotification(MFtpProtocolNotifier::EOpFailed); + break; + } + break; + case EPerformingAppe: + case EPerformingRein: + // Not much to do, just ignore any "1" answer + if (iAnswer[0]=='1') + break; + if (iAnswer[0]=='2') + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + else + iNotifier->ServerNegativeAnswerNotification(MFtpProtocolNotifier::EOpFailed); + break; + // rename sequence defined as per 2nd FSM page 55 of RFC 959 + case EPerformingRnfr: + if (iAnswer[0]=='3') + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + else + iNotifier->ServerNegativeAnswerNotification(MFtpProtocolNotifier::EOpFailed); + break; + case EPerformingRnto: + if (iAnswer[0]=='2') + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + else + iNotifier->ServerNegativeAnswerNotification(MFtpProtocolNotifier::EOpFailed); + break; + // Rest sequence as defined per FSM page 56 of RFC 959 + case EPerformingRest: + if (iAnswer[0]=='3') + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + else + iNotifier->ServerNegativeAnswerNotification(MFtpProtocolNotifier::EOpFailed); + break; + // Login sequence as defined by FSM page 57 of RFC 959 + case EPerformingUser: + if ((iAnswer[0]=='3') || + (iAnswer[0]=='2')) // Slight divergence from the RFC here, but some servers + // allow disabling the passwd check and send back a 2 answer at this stage + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + else + iNotifier->ServerNegativeAnswerNotification(MFtpProtocolNotifier::EOpFailed); + break; + case EPerformingPass: + if (iAnswer[0]=='2') + iNotifier->ServerPositiveAnswerNotification(MFtpProtocolNotifier::EOpComplete); + else + iNotifier->ServerNegativeAnswerNotification(MFtpProtocolNotifier::EOpFailed); + break; + case EIdle: + // Can't be here in Idle state + __ASSERT_DEBUG(FALSE, User::Panic(_L("CFtpProtocolDerived"), EPIPanicMegaOI)); + break; + default: + // OOps, forgot something + __ASSERT_DEBUG(FALSE, User::Panic(_L("CFtpProtocolDerived"), 0)); + } + + + } +// +// FTP Command interface implementation +// + +void CFtpProtocolDerived::SendBuffer(TDes8* aBuffer) +/** +Set a buffer for reception and initiate reception +if the dtp channel is connected +*/ + { + iIOBuffer = aBuffer; + if(iDtpChannel->Connected()) + { + iDtpChannel->Send(*iIOBuffer); + } + } + +void CFtpProtocolDerived::SendEOF(void) +/** +Terminates the connection with the peer to mark the end of transfer. +*/ + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::SendEOF called\n")); + iDtpChannel->SendEOF(); + } + +void CFtpProtocolDerived::RecvBuffer(TDes8* aBuffer) +/** +Set a buffer for reception and initiate reception if the dtp channel is connected. +*/ + { + iIOBuffer = aBuffer; + if(iDtpChannel->Connected()) + { + iDtpChannel->Recv(*iIOBuffer); + } + } + +void CFtpProtocolDerived::Connect(TSockAddr& aNetAddr) +/** +Establish a connection: +*/ + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Connect called\n")); + iState = EConnecting; + iRemoteAddress = aNetAddr; + // Reset the last answer + iAnswer.Zero(); + if(!(iPiChannel->Connect(aNetAddr))) + // PiChannel could not open a socket + // Post an error + iCFTPSetError->SetError(MFtpProtocolNotifier::ESocketError); + } + +void CFtpProtocolDerived::Connect(const THostName& aServerName) + { + // DNS name + Connect(aServerName,DEFAULT_SERVER_PI_PORT); + } + +void CFtpProtocolDerived::Connect(const THostName& aServerName, const TUint aPort) + { + // DNS name + port + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Connect called\n")); + iState = ELookingUp; + // Reset the last answer + iAnswer.Zero(); + iRemoteAddress.SetPort(aPort); + iResolver->Lookup(aServerName); + } + +void CFtpProtocolDerived::User(const TDesC8& aParam) +/** +FTP commands, presented in the same order as RFC959: +*/ + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::User called\n")); + iFTPCmdBuffer = _L8("USER "); + iFTPCmdBuffer.Append(aParam); + iState = EPerformingUser; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Pass(const TDesC8& aParam) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Pass called\n")); + iFTPCmdBuffer = _L8("PASS "); + iFTPCmdBuffer.Append(aParam); + iState = EPerformingPass; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Acct(const TDesC8& /*aParam*/) + { + iState = EPerformingAcct; + } + +void CFtpProtocolDerived::Cwd(const TDesC8& aParam) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Cwd called\n")); + iFTPCmdBuffer = _L8("CWD "); + iFTPCmdBuffer.Append(aParam); + iState = EPerformingCwd; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Cdup(void) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Cdup called\n")); + iFTPCmdBuffer = _L8("CDUP"); + iState = EPerformingCdup; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Smnt(const TDesC8& /*aParam*/) + { + iState = EPerformingSmnt; + } + +void CFtpProtocolDerived::Quit(void) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Quit called\n")); + iFTPCmdBuffer = _L8("QUIT"); + iState = EPerformingQuit; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Rein(void) + { + iState = EPerformingRein; + } + +void CFtpProtocolDerived::Port(void) + {// Sets the DTP port to one allocated by ESOCK + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Port called\n")); + iState = EPerformingPort; + iPort = iDtpChannel->ListeningPort(); + if ( iPort ==0) + { + // Some socket operations failed, post an async error + iCFTPSetError->SetError(MFtpProtocolNotifier::ESocketError); + // and bail out + return; + } + if (iLocalAddress.Family() == KAfInet) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***Using PORT\n")); + BuildPORTCommand(); + } + else + { + __ASSERT_DEBUG(iLocalAddress.Family() == KAfInet6, User::Panic(_L("CFtpProtocolDerived"), EAddressFamily)); + FTPPROTDEBUG(_DBGFtpprot,_L("***Using EPRT\n")); + BuildEPRTCommand(); + } + //PG 12/08/1999 following won't build, flogger doesn't take TDes8 + //FTPPROTDEBUG(_DBGFtpprot,_L("Sending command -->")); + //FTPPROTDEBUG(_DBGFtpprot,iFTPCmdBuffer); + //FTPPROTDEBUG(_DBGFtpprot,_L("\n")); + // Set the PASV switch + iPASVMode = FALSE; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::BuildPORTCommand() + { + iFTPCmdBuffer = _L8("PORT "); + iFTPCmdBuffer.AppendNum(((iLocalAddress.Address())>>24), EDecimal); + iFTPCmdBuffer.Append(_L(",")); + iFTPCmdBuffer.AppendNum((((iLocalAddress.Address()) & 0xFF0000) >>16), EDecimal); + iFTPCmdBuffer.Append(_L(",")); + iFTPCmdBuffer.AppendNum((((iLocalAddress.Address()) & 0xFF00) >>8), EDecimal); + iFTPCmdBuffer.Append(_L(",")); + iFTPCmdBuffer.AppendNum(((iLocalAddress.Address()) & 0xFF), EDecimal); + iFTPCmdBuffer.Append(_L(",")); + iFTPCmdBuffer.AppendNum((((iPort) & 0xFF00) >>8), EDecimal); + iFTPCmdBuffer.Append(_L(",")); + iFTPCmdBuffer.AppendNum(((iPort) & 0xFF), EDecimal); + } + +void CFtpProtocolDerived::BuildEPRTCommand() + { + TBuf<39> addrBuf; + iLocalAddress.Output(addrBuf); + + iFTPCmdBuffer = _L8("EPRT "); + iFTPCmdBuffer.Append(_L("|2|")); + iFTPCmdBuffer.Append(addrBuf); + iFTPCmdBuffer.Append(_L("|")); + iFTPCmdBuffer.AppendNum(iPort, EDecimal); + iFTPCmdBuffer.Append(_L("|")); + } + +void CFtpProtocolDerived::Port(TUint /*aPort*/) + { + // Sets the DTP port to a specific one + } + +void CFtpProtocolDerived::Pasv(void) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Pasv called\n")); + if (iLocalAddress.Family() == KAfInet) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***Using PASV\n")); + iFTPCmdBuffer = _L8("PASV"); + } + else + { + FTPPROTDEBUG(_DBGFtpprot,_L("***Using EPSV\n")); + iFTPCmdBuffer = _L8("EPSV"); + } + + iState = EPerformingPasv; + // Reset the last answer + iAnswer.Zero(); + // Reset the Pasv Address Parser + iFtpPASVAnswerParser->Reset(); + // Set the bool switch + iPASVMode = TRUE; + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Type(const TDesC8& aParam) + { + iState = EPerformingType; + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Type called\n")); + iFTPCmdBuffer = _L8("TYPE "); + iFTPCmdBuffer.Append(aParam); + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Type(const TDesC8& /*aParam1*/, const TDesC8& /*aParam2*/) + { + iState = EPerformingType; + } + +void CFtpProtocolDerived::Stru(const TDesC8& /*aParam*/) + { + iState = EPerformingStru; + } + +void CFtpProtocolDerived::Mode(const TDesC8& /*aParam*/) + { + iState = EPerformingMode; + } + +void CFtpProtocolDerived::Retr(const TDesC8& aFileName) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Retr called\n")); + iFTPCmdBuffer = _L8("RETR "); + iFTPCmdBuffer.Append(aFileName); + iState = EPerformingRetr; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + if(iPASVMode) + { + if (!(iDtpChannel->Connect(iFTPDTPAddress))) + { + // Some socket operations failed, post an async error + iCFTPSetError->SetError(MFtpProtocolNotifier::ESocketError); + return; + } + + } + else + { + // For non passive mode accept server connection + iDtpChannel->Accept(); + } + } + +void CFtpProtocolDerived::Stor(const TDesC8& aFileName) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Stor called\n")); + iFTPCmdBuffer = _L8("STOR "); + iFTPCmdBuffer.Append(aFileName); + iState = EPerformingStor; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + if(iPASVMode) + { + if (!(iDtpChannel->Connect(iFTPDTPAddress))) + { + // Some socket operations failed, post an async error + iCFTPSetError->SetError(MFtpProtocolNotifier::ESocketError); + return; + } + } + else + { + // For non passive mode accept server connection + iDtpChannel->Accept(); + } + } + +void CFtpProtocolDerived::List(void) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::List called\n")); + iFTPCmdBuffer = _L8("LIST"); + iState = EPerformingList; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + if(iPASVMode) + { + if (!(iDtpChannel->Connect(iFTPDTPAddress))) + { + // Some socket operations failed, post an async error + iCFTPSetError->SetError(MFtpProtocolNotifier::ESocketError); + return; + } + } + else + { + // For non passive mode accept server connection + iDtpChannel->Accept(); + } + } + +void CFtpProtocolDerived::List(const TDesC8& aParam) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::List called\n")); + iFTPCmdBuffer = _L8("LIST "); + iFTPCmdBuffer.Append(aParam); + iState = EPerformingList; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + if(iPASVMode) + { + if (!(iDtpChannel->Connect(iFTPDTPAddress))) + { + // Some socket operations failed, post an async error + iCFTPSetError->SetError(MFtpProtocolNotifier::ESocketError); + return; + } + } + else + { + // For non passive mode accept server connection + iDtpChannel->Accept(); + } + } + +void CFtpProtocolDerived::Stou(void) + { + iState = EPerformingStou; + } + +void CFtpProtocolDerived::Appe(const TDesC8& /*aFileName*/) + { + iState = EPerformingAppe; + } + +void CFtpProtocolDerived::Allo(const TDesC8& /*aParam*/) + { + iState = EPerformingAllo; + } + +void CFtpProtocolDerived::Allo(const TDesC8& /*aParam1*/, const TDesC8& /*aParam2*/) + { + iState = EPerformingAllo; + } + +void CFtpProtocolDerived::Rest(const TDesC8& aParam) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Rest called\n")); + iFTPCmdBuffer = _L8("REST "); + iFTPCmdBuffer.Append(aParam); + iState = EPerformingRest; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Rnfr(const TDesC8& aFileName) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Rnfr called\n")); + iFTPCmdBuffer = _L8("RNFR "); + iFTPCmdBuffer.Append(aFileName); + iState = EPerformingRnfr; + // Reset the last answer + iAnswer.Zero(); + // Get ready to receive an answer +// iPiChannel->GetNextAnswer(iServerAnswerBuffer); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Rnto(const TDesC8& aFileName) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Rnto called\n")); + iFTPCmdBuffer = _L8("RNTO "); + iFTPCmdBuffer.Append(aFileName); + iState = EPerformingRnto; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Abor(void) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Abor called\n")); + iFTPCmdBuffer.Zero(); + iFTPCmdBuffer.Append(IAC); + iFTPCmdBuffer.Append(IP); + iFTPCmdBuffer.Append(IAC); + iFTPCmdBuffer.Append(SYNCH); + iFTPCmdBuffer.Append(_L8("ABOR")); + iState = EPerformingAbor; + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer,KSockWriteUrgent); + } + +void CFtpProtocolDerived::Dele(const TDesC8& aFileName) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Dele called\n")); + iFTPCmdBuffer = _L8("DELE "); + iFTPCmdBuffer.Append(aFileName); + iState = EPerformingDele; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Rmd(const TDesC8& aParam) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Rmd called\n")); + iFTPCmdBuffer = _L8("RMD "); + iFTPCmdBuffer.Append(aParam); + iState = EPerformingRmd; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Mkd(const TDesC8& aParam) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Mkd called\n")); + iFTPCmdBuffer = _L8("MKD "); + iFTPCmdBuffer.Append(aParam); + iState = EPerformingMkd; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Pwd(void) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Pwd called\n")); + iFTPCmdBuffer = _L8("PWD"); + iState = EPerformingPwd; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Nlst(void) + { + iState = EPerformingNlst; + } + +void CFtpProtocolDerived::Nlst(const TDesC8& /*aParam*/) + { + iState = EPerformingNlst; + } + +void CFtpProtocolDerived::Site(const TDesC8& /*aParam*/) + { + iState = EPerformingSite; + } + +void CFtpProtocolDerived::Syst(void) + { + iState = EPerformingSyst; + } + +void CFtpProtocolDerived::Stat(const TDesC8& /*aParam*/) + { + iState = EPerformingStat; + } + +void CFtpProtocolDerived::Stat(void) + { + iState = EPerformingStat; + } + +void CFtpProtocolDerived::Help(const TDesC8& /*aParam*/) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Help called\n")); + iFTPCmdBuffer = _L8("HELP"); + iState = EPerformingHelp; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Help(void) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Help called\n")); + iFTPCmdBuffer = _L8("HELP"); + iState = EPerformingHelp; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::Noop(void) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::Help called\n")); + iFTPCmdBuffer = _L8("NOOP"); + iState = EPerformingNoop; + // Reset the last answer + iAnswer.Zero(); + // Fire the command + iPiChannel->SendCommand(iFTPCmdBuffer); + } + +void CFtpProtocolDerived::UserCancel(void) + { + FTPPROTDEBUG(_DBGFtpprot,_L("***CFtpProtocolDerived::UserCancel called ")); + switch(iState) + { + case ELookingUp: + FTPPROTDEBUG(_DBGFtpprot,_L("State: ELookingUp\n")); + iResolver->Cancel(); + break; + case EConnecting: + FTPPROTDEBUG(_DBGFtpprot,_L("State: EConnecting\n")); + iPiChannel->Disconnect(); + break; + default: + FTPPROTDEBUG(_DBGFtpprot,_L("Do Nothing\n")); + break; + } + } + + +//Extensions: + +EXPORT_C TUint32 CFtpProtocol::GetVersion(void) +/** Gets the API version number. +* +* @return 32-bit number: with MAJOR_VERSION in the highest byte, +* MINOR_VERSION in the next byte, and BUILD_NUMBER in the lowest two bytes +* i.e. MAJOR 2, MINOR 0x34, BUILD 0x278 would be "ver 2.52, build 632". +*/ + { + return FTPPROTDLL_VERSION_NUMBER; + } + +EXPORT_C CFtpProtocol *CFtpProtocol::NewL( MFtpProtocolNotifier* aNotifier) +/** Allocates and constructs a new FTP engine object. +* +* @param aNotifier Client callback interface. +* The FTP engine calls this interface to pass server responses and +* status messages to the client. +* @return New FTP engine object. +*/ + { + return CFtpProtocolDerived::NewL(aNotifier); + } + +CFtpProtocolDerived *CFtpProtocolDerived::NewL( MFtpProtocolNotifier* aNotifier) + { + CFtpProtocolDerived* self = new (ELeave) CFtpProtocolDerived(aNotifier); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CFtpProtocolDerived::CFtpProtocolDerived(MFtpProtocolNotifier* aNotifier + ):iNotifier(aNotifier) + { + } + +void CFtpProtocolDerived::ConstructL(void) + { + InitCommL(); + iCFTPSetError = CFTPSetError::NewL(this); + iPiChannel = CPIChannel::NewL(this,iSockServ); + iDtpChannel = CDTPChannel::NewL(this,iCFTPSetError,iSockServ); + iResolver = CFTPResolver::NewL(this,iSockServ); + iFTPServerAnswerParser = new (ELeave) TFTPServerAnswerParser(); + iFtpPASVAnswerParser = new (ELeave) TFtpPASVAnswerParser(); + // Reset the last answer + iAnswer.Zero(); + } + +CFtpProtocol::~CFtpProtocol() +/** Destructor. */ + {} + +CFtpProtocolDerived::~CFtpProtocolDerived() + { + FTPPROTDEBUG(_DBGFtpprot,_L("CFtpProtocolDerived::~CFtpProtocolDerived called\n")); + delete iPiChannel; + delete iDtpChannel; + delete iResolver; + delete iCFTPSetError; + delete iFTPServerAnswerParser; + delete iFtpPASVAnswerParser; + iSockServ.Close(); + } + +void CFtpProtocolDerived::InitCommL(void) + { + // Initialise Comm modules + // When bootstrapping C32 we have to avoid the PhBkSyncServer being started, since + // it needs a different CommDB + _LIT(KPhbkSyncCMI, "phbsync.cmi"); + StartC32WithCMISuppressions(KPhbkSyncCMI); + // Open socket server + User::LeaveIfError(iSockServ.Connect()); + } +