--- /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 <es_sock.h>
+#include <c32comm.h>
+#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());
+ }
+