applayerprotocols/ftpengine/ftpprot/FTPPROT.CPP
changeset 0 b16258d2340f
--- /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());
+	}
+