--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerprotocols/ftpengine/ftpsess/FTPSESS.CPP Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,1091 @@
+// 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:
+// EPOC32 FTP Engine header file
+// Author: Philippe Gabriel
+// Implements set of APIs simplyfying access to the FTP protocol
+//
+//
+
+/**
+ @file FTPSESS.CPP
+ @internalComponent
+*/
+
+#include <e32test.h>
+#include "SESSION.H"
+#include "DEBUG.H"
+
+//
+// Minterface Implementation
+//
+
+void CFTPSessionDerived::SetErrorNotifier(const TInt aError)
+/**
+Define the CFTPSetError callback notifier
+*/
+{
+ switch(aError)
+ {
+ case MFtpSessionNotifier::ESocketError:
+ iFtpSessionNotifier->ConnectionError((MFtpSessionNotifier::TOpComp)aError);
+ ErrorTransition(MFtpProtocolNotifier::EOpConnectionFailed);
+ break;
+ case MFtpSessionNotifier::EAlreadyConnected:
+ case MFtpSessionNotifier::ENotConnected:
+ iFtpSessionNotifier->ConnectionError((MFtpSessionNotifier::TOpComp)aError);
+ //No state transition in this case
+ break;
+ case MFtpSessionNotifier::EFileSystemError:
+ case MFtpSessionNotifier::EFileOpenFailure:
+ case MFtpSessionNotifier::EFileReadError:
+ case MFtpSessionNotifier::EFileWriteError:
+ case MFtpSessionNotifier::EFileAlreadyExist:
+ case MFtpSessionNotifier::EFileNotExist:
+ case MFtpSessionNotifier::EDirAlreadyExist:
+ case MFtpSessionNotifier::EDirNotExist:
+ iFtpSessionNotifier->LocalFileSystemError((MFtpSessionNotifier::TOpComp)aError);
+ ErrorTransition(MFtpProtocolNotifier::EOpFailed);
+ break;
+ case MFtpSessionNotifier::EOpCanceled:
+ iFtpSessionNotifier->Cancel();
+ ErrorTransition(MFtpProtocolNotifier::EOpCanceled);
+ break;
+ default:
+ // I forgot something
+ __ASSERT_DEBUG(FALSE, User::Panic(_L("CFTPSessionDerived::SetError"), 0));
+ break;
+ }
+}
+
+void CFTPSessionDerived::ErrorNotification(const TOpComp aStatus)
+{
+ switch(aStatus)
+ {
+ case MFtpProtocolNotifier::EOpConnectionReset:
+ // Total mayhem, irrecoverable
+ // We got a TCP RST
+ // Notify upper layer
+ iFtpSessionNotifier->ConnReset();
+ break;
+ case MFtpProtocolNotifier::EOpConnectionFailed:
+ __ASSERT_DEBUG(iState == EConnecting, User::Panic(_L("CFTPSessionDerived::ErrorNotification"), 0));
+ iFtpSessionNotifier->ConnectionError(MFtpSessionNotifier::EConnectionFailed);
+ break;
+ case MFtpProtocolNotifier::EXferReset:
+ __ASSERT_DEBUG((iState == EPerformingList)
+ ||(iState == ERetrieveFile)
+ ||(iState == EStoreFile)
+ ||(iState == EStoreFileSendEOF),
+ User::Panic(_L("CFTPSessionDerived::ErrorNotification"), 0));
+ iFtpSessionNotifier->RemoteFileSystemError(MFtpSessionNotifier::ERemoteFileSystemError);
+ break;
+ case MFtpProtocolNotifier::EXferNotInitialised:
+ __ASSERT_DEBUG((iState == EPerformingList)
+ ||(iState == ERetrieveFile)
+ ||(iState == EStoreFile)
+ ||(iState == EStoreFileSendEOF),
+ User::Panic(_L("CFTPSessionDerived::ServerNegativeAnswerNotification"), 0));
+ iFtpSessionNotifier->RemoteFileSystemError(MFtpSessionNotifier::ERemoteFileOpenFailure);
+ break;
+ case MFtpProtocolNotifier::EHostNotFound:
+ iFtpSessionNotifier->ConnectionError(MFtpSessionNotifier::EHostNotExist);
+ break;
+ case MFtpProtocolNotifier::EOpCanceled:
+ iFtpSessionNotifier->Cancel();
+ break;
+ default:
+ // I forgot something
+ __ASSERT_DEBUG(FALSE, User::Panic(_L("ErrorNotification::SetError"), 0));
+ iFtpSessionNotifier->EUnknownError();
+ break;
+ }
+ ErrorTransition(aStatus);
+}
+
+void CFTPSessionDerived::ServerMessage(const TDesC8& aMessage)
+{
+ iFtpSessionNotifier->ServerMessage(aMessage);
+}
+
+void CFTPSessionDerived::ServerNegativeAnswerNotification(const TOpComp /*aStatus*/)
+{
+ // Fetch the answer
+ iCFtpProtocol->FTPServerAnswer(iServerAnswer);
+ // Have to discriminate on the answer to send back a meaningfull error
+ // fetch a Lex object
+ TLex input(iServerAnswer);
+ TUint uintServerAnswer;
+ // Convert
+ input.Val(uintServerAnswer,EDecimal);
+ FTPPROTDEBUG1(_DBGFtpsess,_L("CFTPSessionDerived::ServerNegativeAnswerNotification Server converted answer:<%u>\n"),uintServerAnswer);
+ // Check the answer is within bounds
+ if ((uintServerAnswer<(TUint)100) || (uintServerAnswer>(TUint)599))
+ {
+ FTPPROTDEBUG2(0xffff,_L("!!!!!!!!!!!!!CFTPSessionDerived::ServerNegativeAnswerNotification Server answer:<%d> is out of bound\n"),iServerAnswer);
+ __ASSERT_DEBUG(FALSE, User::Panic(_L("CFTPSessionDerived::ServerNegativeAnswerNotification"), 0));
+ // Set it to a generic failure code
+ uintServerAnswer = 599;
+ }
+ // Check this is really an error
+ __ASSERT_DEBUG(uintServerAnswer>199, User::Panic(_L("CFTPSessionDerived::ServerNegativeAnswerNotification"), 0));
+ // Unfortunately servers do not seem to follow the RFC recommendation very well
+ // And the list of messages in RFC959 p40-42 is not reliable.
+ // All we can do is best guess, anything more appropriate need the user
+ // to read the text meesage sent back by the server
+ switch(iState)
+ {
+ // Intermediate State
+ case EConnecting:
+ // Assume server unreachable
+ iFtpSessionNotifier->ConnectionError(MFtpSessionNotifier::EConnectionFailed);
+ break;
+ case ELoginUser:
+ case ELoginPass:
+ // Assume login,pass invalid
+ iFtpSessionNotifier->ConnectionError(MFtpSessionNotifier::ELoginFailed);
+ break;
+ case ERenameFileFrom:
+ case ERenameFileTo:
+ // file not found or no access
+ iFtpSessionNotifier->RemoteFileSystemError(MFtpSessionNotifier::EPermissionDenied);
+ break;
+ case EPerformingPortForList:
+ case EPerformingPasvForList:
+ case EPerformingPortForRetrieve:
+ case EPerformingPasvForRetrieve:
+ case EPerformingPasvForStore:
+ case EPerformingPortForStore:
+ // What kind of error could we have following a port?
+ iFtpSessionNotifier->EUnknownError();
+ break;
+ case EPerformingRestForRetrieve:
+ // file not found or no access
+ iFtpSessionNotifier->RemoteFileSystemError(MFtpSessionNotifier::ERestartNotSupported);
+ break;
+ // Semi-Intermediate states
+ case EPerformingList:
+ case ERetrieveFile:
+ case EStoreFile:
+ iFtpSessionNotifier->RemoteFileSystemError(MFtpSessionNotifier::ERemoteFileSystemError);
+ break;
+ // Final States, call back notifier
+ case EConnected:
+ // Assume timeout
+ iFtpSessionNotifier->ConnectionError(MFtpSessionNotifier::ETimedOut);
+ break;
+ case EStoreFileSendEOF:
+ case EGetCurrentDirectory:
+ case EChangeDirectory:
+ case ECreateDirectory:
+ case EDeleteDirectory:
+ case EDeleteFile:
+ iFtpSessionNotifier->RemoteFileSystemError(MFtpSessionNotifier::EPermissionDenied);
+ break;
+ case EClosing:
+ // What kind of error could we have here?
+ iFtpSessionNotifier->EUnknownError();
+ break;
+ default:
+ // Invalid state
+ __ASSERT_DEBUG(FALSE, User::Panic(_L("CFTPSessionDerived::ServerNegativeAnswerNotification"), 0));
+ break;
+ }
+ ErrorTransition(MFtpProtocolNotifier::EOpFailed);
+}
+
+void CFTPSessionDerived::ServerXFerNotification(const TOpComp /*aStatus*/)
+{
+FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::ServerXFerNotification called - State:"));
+TDes8& currentBuf = iFileXferBuffer[iCurrentXferBuffer];
+iCurrentXferBuffer = !iCurrentXferBuffer; //swap buffers;
+
+ switch(iState)
+ {
+ // Semi-Intermediate states
+ case EPerformingList:
+ FTPPROTDEBUG(_DBGFtpsess,_L("EPerformingList \n"));
+ iFtpSessionNotifier->MoreData();
+ break;
+ case ERetrieveFile:
+ FTPPROTDEBUG(_DBGFtpsess,_L("ERetrieveFile \n"));
+ // Reissue the read request
+ iCFtpProtocol->RecvBuffer(&iFileXferBuffer[iCurrentXferBuffer]);
+ // Save packet in the open file
+ if(iFileOpErrorOccured || (KErrNone != iFile.Write(currentBuf)))
+ {
+ // Notify error
+ if(!iFileOpErrorOccured)
+ //1st time, notify
+ iFtpSessionNotifier->LocalFileSystemError(MFtpSessionNotifier::EFileWriteError);
+ iFileOpErrorOccured = TRUE;
+ // __ASSERT_DEBUG(fileOpReturn==KErrNone, User::Panic(_L("CFTPSessionDerived::ServerXFerNotification"), 0));
+ }
+ // Just to be sure
+ if(iFileOpErrorOccured || (KErrNone != iFile.Flush()))
+ {
+ // Notify error
+ if(!iFileOpErrorOccured)
+ //1st time, notify
+ iFtpSessionNotifier->LocalFileSystemError(MFtpSessionNotifier::EFileWriteError);
+ iFileOpErrorOccured = TRUE;
+ // __ASSERT_DEBUG(fileOpReturn==KErrNone, User::Panic(_L("CFTPSessionDerived::ServerXFerNotification"), 0));
+ }
+ // Call the Progress notifier
+ iFtpSessionNotifier->TransferProgress(currentBuf.Length());
+ break;
+ case EStoreFile:
+ FTPPROTDEBUG(_DBGFtpsess,_L("EStoreFile \n"));
+ // Call the Progress notifier
+ if((iFileOpErrorOccured || (currentBuf.Length() == 0)) && !iFirstRun)
+ {
+ // Send an EOF
+ iState = EStoreFileSendEOF;
+ iCFtpProtocol->SendEOF();
+ }
+ else {
+ // Reissue the Send request
+ iCFtpProtocol->SendBuffer(¤tBuf);
+ iFirstRun=EFalse;
+ }
+
+ iFtpSessionNotifier->TransferProgress(currentBuf.Length());
+
+ // Construct a packet from the open file
+ if(iFileOpErrorOccured || (KErrNone != iFile.Read(iFileXferBuffer[iCurrentXferBuffer])))
+ {
+ // Notify error
+ if(!iFileOpErrorOccured)
+ //1st time, notify
+ iFtpSessionNotifier->LocalFileSystemError(MFtpSessionNotifier::EFileWriteError);
+ iFileOpErrorOccured = ETrue;
+ }
+ break;
+ case EAbortingStore:
+ FTPPROTDEBUG(_DBGFtpsess,_L("EAbortingStore \n"));
+ // Shutdown the DTP channel
+ iCFtpProtocol->SendEOF();
+ break;
+ case EAbortingRetrieve:
+ case EAbortingList:
+ FTPPROTDEBUG(_DBGFtpsess,_L("EAbortingRetrieve - EAbortingList\n"));
+ // Reissue the read request to flush the recv buffer
+ iCFtpProtocol->RecvBuffer(¤tBuf);
+ break;
+ default:
+ FTPPROTDEBUG(_DBGFtpsess,_L("INVALID \n"));
+ // Invalid state
+ __ASSERT_DEBUG(FALSE, User::Panic(_L("CFtpProtocol::ServerXFerNotification"), 0));
+ break;
+ }
+}
+
+void CFTPSessionDerived::ServerPositiveAnswerNotification(const TOpComp /*aStatus*/)
+/**
+Define the CFtpProtocol callback notifiers
+*/
+{
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::ServerPositiveAnswerNotification called\n"));
+ // Fetch the answer
+ // PG 200898 Don't need the answer just now, maybe in the future
+ // iCFtpProtocol->FTPServerAnswer(iServerAnswer);
+ // Just do a normal transition
+ NormalTransition();
+}
+//
+// State Transition functions
+//
+
+void CFTPSessionDerived::NormalTransition(void)
+/**
+NormalTransition
+Called when an operation has been positively acknowledged
+and we progress to the next operation
+No input parameter, only operates on global member data
+*/
+{
+FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::NormalTransition called\n"));
+TBool loopAgain;
+ do
+ {
+ // Do Pre State update action
+ switch(iState)
+ {
+ case ERetrieveFile:
+ case EStoreFileSendEOF:
+ //Finished, replace the old local file with the temp one
+ //and delete the temp file
+ if(iTempStore)
+ {
+ iTempStore = FALSE;
+ if(iFs.Delete(iRenamedLocalFileName)!=KErrNone)
+ {
+ iCFTPSetError->SetError(MFtpSessionNotifier::EFileSystemError);
+ return;
+ }
+ }
+ iFile.Close();
+ break;
+ case EPerformingTypeForRetrieve:
+ case EPerformingTypeForStore:
+ iCurrentRepresentationType = iNewRepresentationType;
+ break;
+ case EAbortingStore:
+ case EAbortingRetrieve:
+ case EAbortingList:
+ iFtpSessionNotifier->Cancel();
+ break;
+ case EConnected:
+ // We should never get here
+ // BUT WE DO, reason is:
+ // during xfers, some ftp servers don't ack the abort
+ // where we (the client) enter an abort state and wait for the server to
+ // send us either
+ // 4 (xfer canceled) - 2 (abort ack)
+ // or just 2 (abort ack)
+ // but some lame servers send us:
+ // 2 (xfer finished) - 2 (abort ack)
+ // Don't report a completion to the client just bail out
+ return;
+ default:
+ break;
+ }
+ // Update the state
+ iState = UpdateState(iState,MFtpProtocolNotifier::EOpComplete);
+ // Do some action according to the new state
+ loopAgain = FALSE;
+ switch(iState)
+ {
+ // Intermediate State
+ // Don't callback notifier
+ case EInitiateListOperation:
+ case EInitiateRetrieveOperation:
+ case EInitiateStoreOperation:
+ // These are just a bunch of dummy states
+ // allowing to streamline the code a bit
+ loopAgain = TRUE;
+ break;
+ case ELoginUser:
+ iCFtpProtocol->User(iBuffer1);
+ break;
+ case ELoginPass:
+ iCFtpProtocol->Pass(iBuffer2);
+ break;
+ case ERenameFileTo:
+ iCFtpProtocol->Rnto(iBuffer1);
+ break;
+ case EPerformingTypeForRetrieve:
+ case EPerformingTypeForStore:
+ if(iNewRepresentationType != iCurrentRepresentationType)
+ {
+ // New type differs from the old, tell the server to change it
+ if(iNewRepresentationType == EASCII)
+ iCFtpProtocol->Type(_L8("A"));
+ else
+ iCFtpProtocol->Type(_L8("I"));
+ break;
+ }
+ else
+ // New type same as the old, do nothing
+ loopAgain = TRUE;
+ break;
+ case EPerformingPasvForList:
+ case EPerformingPasvForRetrieve:
+ case EPerformingPasvForStore:
+ iCFtpProtocol->Pasv();
+ break;
+ case EPerformingPortForList:
+ case EPerformingPortForRetrieve:
+ case EPerformingPortForStore:
+ iCFtpProtocol->Port();
+ break;
+ case EPerformingList:
+ // Set buffer
+ iCFtpProtocol->RecvBuffer(iFileList);
+ iCFtpProtocol->List(iBuffer1);
+ break;
+ case EPerformingRestForStore:
+ case EPerformingRestForRetrieve:
+ // Do I really need to send a restart?
+ if(iRESTOffset !=0 )
+ {
+ //Send a REST command
+ iBuffer2.Num(iRESTOffset,EDecimal);
+ // Reset immediately the RESTOffset
+ iRESTOffset = 0;
+ iCFtpProtocol->Rest(iBuffer2);
+ }
+ else
+ loopAgain = TRUE;
+ break;
+ case ERetrieveFile:
+ // Set buffer
+ iCFtpProtocol->RecvBuffer(&iFileXferBuffer[iCurrentXferBuffer]);
+ iCFtpProtocol->Retr(iBuffer1);
+ break;
+ case EStoreFile:
+ // Set buffer
+ iCFtpProtocol->Stor(iBuffer1);
+ // Construct a packet from the open file
+ iFileXferBuffer[iCurrentXferBuffer].SetLength(0);
+ iCurrentXferBuffer = !iCurrentXferBuffer;
+ iFile.Read(iFileXferBuffer[iCurrentXferBuffer]);
+ //Don't send yet, just bump the notifier
+ iFirstRun=ETrue;
+ ServerXFerNotification(EOpComplete);
+ break;
+ // Final States, call back notifier
+ case EConnected:
+ case EIdle:
+ iFtpSessionNotifier->Complete();
+ break;
+ default:
+ // Invalid state
+ __ASSERT_DEBUG(FALSE, User::Panic(_L("CFtpProtocol"), 0));
+ break;
+ }
+ }while(loopAgain);
+}
+
+void CFTPSessionDerived::ErrorTransition(const TOpComp aStatus)
+/**
+ErrorTransition
+Called when an operation has failed
+need to do some clearup
+and determine what the next state is gonna be
+*/
+{
+ // Close local file
+ iFile.Close();
+
+ if ( iTempStore )
+ {//rename orig file back iRenamedLocalFileName contains original file name as well
+ iTempStore = FALSE;
+ TBuf<256> fileName;
+ fileName.Copy( iRenamedLocalFileName.Ptr(), iRenamedLocalFileName.Length() - 1 );
+ iFs.Delete( fileName ); //just in case
+ iFs.Rename( iRenamedLocalFileName, fileName );
+ //should i report a possible error to anyone?
+ }
+ // Trust the lower layer to cleanup the connection mess
+ // just find out what the next state is
+ iState = UpdateState(iState,aStatus);
+}
+
+CFTPSessionDerived::TState CFTPSessionDerived::UpdateState(CFTPSessionDerived::TState aState,MFtpProtocolNotifier::TOpComp aStatus)
+ {
+ CFTPSessionDerived::TState returnValue;
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::UpdateState called\n"));
+ switch(aStatus)
+ {
+ case MFtpProtocolNotifier::EOpComplete:
+ switch(aState)
+ {
+ case EConnecting:
+ returnValue = ELoginUser;
+ break;
+ case ELoginUser:
+ returnValue = ELoginPass;
+ break;
+ case ERenameFileFrom:
+ returnValue = ERenameFileTo;
+ break;
+ case EInitiateListOperation:
+ if(iPASVMode)
+ returnValue = EPerformingPasvForList;
+ else
+ returnValue = EPerformingPortForList;
+ break;
+ case EInitiateRetrieveOperation:
+ returnValue = EPerformingTypeForRetrieve;
+ break;
+ case EInitiateStoreOperation:
+ returnValue = EPerformingTypeForStore;
+ break;
+ case EPerformingTypeForRetrieve:
+ if(iPASVMode)
+ returnValue = EPerformingPasvForRetrieve;
+ else
+ returnValue = EPerformingPortForRetrieve;
+ break;
+ case EPerformingTypeForStore:
+ if(iPASVMode)
+ returnValue = EPerformingPasvForStore;
+ else
+ returnValue = EPerformingPortForStore;
+ break;
+
+ case EPerformingPortForList:
+ case EPerformingPasvForList:
+ returnValue = EPerformingList;
+ break;
+ case EPerformingPortForRetrieve:
+ case EPerformingPasvForRetrieve:
+ returnValue = EPerformingRestForRetrieve;
+ break;
+ case EPerformingPortForStore:
+ case EPerformingPasvForStore:
+ returnValue = EPerformingRestForStore;
+ break;
+ case EPerformingRestForRetrieve:
+ returnValue = ERetrieveFile;
+ break;
+ case EPerformingRestForStore:
+ returnValue = EStoreFile;
+ break;
+ case ERetrieveFile:
+ case EStoreFileSendEOF:
+ case EPerformingList:
+ case ELoginPass:
+ case EGetCurrentDirectory:
+ case EChangeDirectory:
+ case ECreateDirectory:
+ case EDeleteDirectory:
+ case EDeleteFile:
+ case ERenameFileTo:
+ case EAbortingStore:
+ case EAbortingRetrieve:
+ case EAbortingList:
+ returnValue = EConnected;
+ break;
+ case EClosing:
+ returnValue = EIdle;
+ break;
+ default:
+ // Invalid state
+ __ASSERT_DEBUG(FALSE, User::Panic(_L("CFTPSessionDerived::UpdateState Bad State"), 0));
+ returnValue = EIdle;
+ break;
+ } // switch (aState)
+ break;
+ //Cancel
+ case MFtpProtocolNotifier::EOpCanceled:
+ switch(aState)
+ {
+ case EAbortingStore:
+ case EAbortingRetrieve:
+ case EAbortingList:
+ returnValue = EConnected;
+ break;
+ case EConnecting:
+ returnValue = EIdle;
+ break;
+ default:
+ //Otherwise don't change the state
+ returnValue = aState;
+ break;
+ }
+ break;
+ // Error statuses
+ case MFtpProtocolNotifier::EOpFailed:
+ // This means I got a Negative answer from the PI Channel
+ // hence PI Channel still there ==> still connected
+ returnValue = EConnected;
+ break;
+ case MFtpProtocolNotifier::EOpConnectionReset:
+ case MFtpProtocolNotifier::EOpConnectionFailed:
+ case MFtpProtocolNotifier::EHostNotFound:
+ //Simple massive errors
+ // No need to look at the state
+ returnValue = EIdle;
+ break;
+ case MFtpProtocolNotifier::EXferReset:
+ case MFtpProtocolNotifier::EXferNotInitialised:
+ returnValue = EConnected;
+ break;
+ case MFtpProtocolNotifier::ESocketError:
+ switch(aState)
+ {
+ // Socket error while connecting PI Channel
+ case EConnecting:
+ returnValue = EIdle;
+ break;
+ // else socket error while openning DTP Channel
+ default:
+ // Check the state is in the acceptable range
+ __ASSERT_DEBUG(
+ (aState == EPerformingPortForList)||
+ (aState == EPerformingList)||
+ (aState == EPerformingPortForRetrieve)||
+ (aState == ERetrieveFile)||
+ (aState == EPerformingPortForStore)||
+ (aState == EStoreFile)
+ , User::Panic(_L("CFTPSessionDerived::UpdateState Invalid State"), 0));
+ returnValue = EConnected;
+ break;
+ }
+ break;
+ default:
+ // Invalid status
+ __ASSERT_DEBUG(FALSE, User::Panic(_L("CFTPSessionDerived::UpdateState Bad Status"), 0));
+ returnValue = EIdle;
+ break;
+ } // switch (aStatus)
+ return returnValue;
+ }
+//
+// Creation, Destruction
+//
+
+CFTPSessionDerived::CFTPSessionDerived(
+ ):iState(EIdle),FileServerInitialised(FALSE)
+ ,iCurrentRepresentationType(EUninitialised),iRESTOffset(0)
+/**
+C++ constructor
+*/
+ {
+ }
+
+EXPORT_C CFTPSession* CFTPSession::NewL(MFtpSessionNotifier* aNotifier)
+/** Allocates and constructs a new FTP session object.
+*
+* @param aNotifier Callback interface to notify the client of the completion
+* of operations or to report errors. For each FTP session, the FTP client should
+* instantiate an object of this type.
+* @return New FTP session object */
+ {
+ return CFTPSessionDerived::NewL(aNotifier);
+ }
+
+CFTPSessionDerived* CFTPSessionDerived::NewL(MFtpSessionNotifier* aNotifier)
+ {
+ CFTPSessionDerived* self=new (ELeave) CFTPSessionDerived();
+ CleanupStack::PushL(self);
+ self->ConstructL(aNotifier);
+ CleanupStack::Pop();
+ return self;
+ }
+
+void CFTPSessionDerived::ConstructL(MFtpSessionNotifier* aNotifier)
+/**
+2nd phase construction
+*/
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::ConstructL called\n"));
+ iCFtpProtocol = CFtpProtocol::NewL(this);
+ iCFTPSetError = CFTPSetError::NewL(this);
+ User::LeaveIfError(iFs.Connect());
+ iFtpSessionNotifier = aNotifier;
+ }
+
+CFTPSession::~CFTPSession()
+/** Destructor. */
+ {}
+
+CFTPSessionDerived::~CFTPSessionDerived()
+/**
+Destruction
+*/
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::~CFTPSessionDerived() called\n"));
+ iFs.Close();
+ delete iCFtpProtocol;
+ delete iCFTPSetError;
+ }
+
+//
+// Interface
+//
+
+void CFTPSessionDerived::Connect( const TSockAddr& aNetAddr, //IP address
+ const TDesC8& aUserName,
+ const TDesC8& aPassword,
+ const TConnectionMode aConnectionMode)
+/**
+Establish a connection with a server:
+*/
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::Connect called\n"));
+ if(iState != EIdle)
+ {
+ // Already connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::EAlreadyConnected);
+ return;
+ }
+ iPASVMode = (aConnectionMode == Epassive);
+ iBuffer1 = aUserName;
+ iBuffer2 = aPassword;
+ iTInt1 = aConnectionMode;
+ iState = EConnecting;
+ iCFtpProtocol->Connect((TSockAddr&)aNetAddr);
+ }
+
+void CFTPSessionDerived::Connect(
+ const THostName& aServerName,
+ const TDesC8& aUserName,
+ const TDesC8& aPassword,
+ const TConnectionMode aConnectionMode,
+ const TUint aPort)
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::Connect called\n"));
+ if(iState != EIdle)
+ {
+ // Already connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::EAlreadyConnected);
+ return;
+ }
+ iPASVMode = (aConnectionMode == Epassive);
+ iBuffer1 = aUserName;
+ iBuffer2 = aPassword;
+ iTInt1 = aConnectionMode;
+ iState = EConnecting;
+ iCFtpProtocol->Connect(aServerName,aPort);
+ }
+
+void CFTPSessionDerived::Close()
+/**
+Close connection with a server
+*/
+ {
+ if(iState == EIdle)
+ {
+ // Not connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::ENotConnected);
+ return;
+ }
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::Close called\n"));
+ iState = EClosing;
+ iCFtpProtocol->Quit();
+ }
+
+void CFTPSessionDerived::Cancel()
+/**
+Cancel latest FTP operation
+*/
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::Cancel called\n"));
+ // Switch on current state
+ switch(iState)
+ {
+ // If I'm storing or recving files I need to negociate
+ // an abort with the server
+ case EStoreFile:
+ iState = EAbortingStore;
+ iCFtpProtocol->Abor();
+ iFile.Close();
+ break;
+ case ERetrieveFile:
+ iState = EAbortingRetrieve;
+ iCFtpProtocol->Abor();
+ iFile.Close();
+ break;
+ case EPerformingList:
+ iState = EAbortingList;
+ iCFtpProtocol->Abor();
+ break;
+ // Simpler states, no negociation with server
+ case EConnecting:
+ // Note: UserCancel is synchronous, hence need to trigger a
+ // notification myself
+ iCFtpProtocol->UserCancel();
+ iCFTPSetError->SetError(MFtpSessionNotifier::EOpCanceled);
+ break;
+ default:
+ // Cancel currently only implemented for store and receive
+ iCFTPSetError->SetError(MFtpSessionNotifier::EOpCanceled);
+ return;
+ }
+ }
+
+// Passes a marker object to store a position for an aborted transfer operation
+//void CFTPSessionDerived::SetMarker(TFTPRestartMarker& /*aTFTPRestartMarker*/)
+// {
+// FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::SetMarker called\n"));
+// FTPPROTDEBUG(_DBGFtpsess,_L("Not Implemented Yet -- Sorry\n"));
+// }
+
+void CFTPSessionDerived::Restart(const TUint aTFTPRestartOffset)
+/**
+Restart an aborted transfer operation
+*/
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::Restart called\n"));
+ iRESTOffset = aTFTPRestartOffset;
+ }
+
+void CFTPSessionDerived::Store(const TDesC& aLocalFileName,
+ const TDesC8& aNewRemoteFileName,
+ const TBool /*aOverwrite*/,
+ const RepresentationType aRepresentationType,
+ const TransferMode /*aTransferMode*/)
+/**
+Transfer APIs
+Store a file on the server
+*/
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::Store called\n"));
+ if(iState == EIdle)
+ {
+ // Not connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::ENotConnected);
+ return;
+ }
+ // Try to open the local file
+ if (iFile.Open(iFs, aLocalFileName, EFileRead|EFileShareReadersOnly) != KErrNone)
+ {
+ iCFTPSetError->SetError(MFtpSessionNotifier::EFileNotExist);
+ return;
+ }
+ debugInt =0;
+ iFileOpErrorOccured = FALSE;
+ iBuffer1 = aNewRemoteFileName;
+ iNewRepresentationType = aRepresentationType;
+ iState = EInitiateStoreOperation;
+ NormalTransition();
+ }
+
+void CFTPSessionDerived::Retrieve(const TDesC8& aRemoteFileName,
+ const TDesC& aNewLocalFileName,
+ const TOpenMode aOpenMode,
+ const RepresentationType aRepresentationType,
+ const TransferMode /*aTransferMode*/)
+/**
+Get a file from the server
+*/
+ {
+ TInt filepos;
+
+ //initialise the flag for indicating if the exisiting local file has been renamed
+ __ASSERT_DEBUG( iTempStore == FALSE, User::Panic(_L("CFTPSessionDerived::Retrieve"), 0) );
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::Retrieve called\n"));
+ TBuf<256> fileName =aNewLocalFileName;
+ TInt counter;
+ // Set the path to C:\ as pert of the defetc Fix DEF058464, to avoid getting
+ // files in C:\private\{uid} folder which is the expected behavior as part
+ // of the platform security.
+ iFs.SetSessionPath(_L("C:\\"));
+
+ if(iState == EIdle)
+ {
+ // Not connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::ENotConnected);
+ return;
+ }
+ // Added to test
+ iFs.SetSessionPath(_L("C:\\"));
+ // Try to open the local file
+ switch(aOpenMode)
+ {
+ case EOverwrite:
+ // In the local folder see if the remote file already exists
+ if(!iFile.Open(iFs, aNewLocalFileName, EFileWrite|EFileShareExclusive))
+ {
+ for(counter=1;counter<5;counter++)
+ {
+ //Create a different name for the existing local file
+ fileName.AppendNum(counter);
+
+ // change the existing local file name to the one created above (if possible)
+ // If renaming was succesful, then do the settings and start retrieving, else
+ // try a new name.
+ if(!iFile.Rename(fileName))
+ {
+ iRenamedLocalFileName = fileName;
+ break;
+ }
+ else
+ {
+ if(counter==4)
+ {
+ // all the 4 possible names are used.Use the last name
+ iFs.Delete(fileName);
+ if(iFile.Rename(fileName)!=KErrNone)
+ {
+ iCFTPSetError->SetError(MFtpSessionNotifier::EFileSystemError);
+ return;
+ }
+
+ iRenamedLocalFileName = fileName;
+ break;
+ }
+ fileName=aNewLocalFileName;
+ }
+ }
+ iFile.Close();
+ iTempStore= TRUE;
+ if(iFile.Replace(iFs,aNewLocalFileName,EFileWrite|EFileShareExclusive)!=KErrNone)
+ {
+ iCFTPSetError->SetError(MFtpSessionNotifier::EFileOpenFailure);
+ return;
+ }
+
+
+ }
+ else
+ {
+ if(iFile.Replace(iFs,aNewLocalFileName,EFileWrite|EFileShareExclusive)!=KErrNone)
+ {
+ iCFTPSetError->SetError(MFtpSessionNotifier::EFileOpenFailure);
+ return;
+ }
+ }
+ break;
+ case ENoOverwrite:
+ if (iFile.Create(iFs, aNewLocalFileName, EFileWrite|EFileShareExclusive) != KErrNone)
+ {
+ iCFTPSetError->SetError(MFtpSessionNotifier::EFileAlreadyExist);
+ return;
+ }
+ break;
+ case EExpand:
+ // Open file
+ if (iFile.Open(iFs, aNewLocalFileName, EFileWrite|EFileShareExclusive) != KErrNone)
+ {
+ iCFTPSetError->SetError(MFtpSessionNotifier::EFileNotExist);
+ return;
+ }
+ // Goto EOF
+ if (iFile.Seek(ESeekEnd,filepos) != KErrNone)
+ {
+ iFile.Close();
+ iCFTPSetError->SetError(MFtpSessionNotifier::EFileOpenFailure);
+ return;
+ }
+ break;
+ }
+ // Set up parameters
+ debugInt =0;
+ iFileOpErrorOccured = FALSE;
+ iBuffer1 = aRemoteFileName;
+ iNewRepresentationType = aRepresentationType;
+ iState = EInitiateRetrieveOperation;
+ NormalTransition();
+ }
+
+void CFTPSessionDerived::ChangeDirectory(const TDesC8& aDirectoryName)
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::ChangeDirectory called\n"));
+ if(iState == EIdle)
+ {
+ // Not connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::ENotConnected);
+ return;
+ }
+ iState = EGetCurrentDirectory;
+ iCFtpProtocol->Cwd(aDirectoryName);
+ }
+
+void CFTPSessionDerived::CreateDirectory(const TDesC8& aDirectoryName)
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::CreateDirectory called\n"));
+ if(iState == EIdle)
+ {
+ // Not connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::ENotConnected);
+ return;
+ }
+ iState = ECreateDirectory;
+ iCFtpProtocol->Mkd(aDirectoryName);
+ }
+
+void CFTPSessionDerived::DeleteDirectory(const TDesC8& aDirectoryName)
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::DeleteDirectory called\n"));
+ if(iState == EIdle)
+ {
+ // Not connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::ENotConnected);
+ return;
+ }
+ iState = EDeleteDirectory;
+ iCFtpProtocol->Rmd(aDirectoryName);
+ }
+
+void CFTPSessionDerived::GetCurrentDirectory()
+ {
+ // Result on the PI connection between quotes
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::GetCurrentDirectory called\n"));
+ if(iState == EIdle)
+ {
+ // Not connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::ENotConnected);
+ return;
+ }
+ iState = EGetCurrentDirectory;
+ iCFtpProtocol->Pwd();
+ }
+
+void CFTPSessionDerived::ListDirectory(const TDesC8& aDirectoryName,TDes8& aFileList)
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::ListDirectory called\n"));
+ if(iState == EIdle)
+ {
+ // Not connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::ENotConnected);
+ return;
+ }
+ if (iState != EPerformingList)
+ {
+ iBuffer1 = aDirectoryName;
+ iFileList = &aFileList;
+ iState = EInitiateListOperation;
+ NormalTransition();
+ }
+ else
+ {
+ // Set buffer
+ iCFtpProtocol->RecvBuffer(&aFileList);
+ }
+ }
+
+void CFTPSessionDerived::DeleteFile(const TDesC8& aFileName)
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::DeleteFile called\n"));
+ if(iState == EIdle)
+ {
+ // Not connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::ENotConnected);
+ return;
+ }
+ iState = EDeleteFile;
+ iCFtpProtocol->Dele(aFileName);
+ }
+
+void CFTPSessionDerived::RenameFile( const TDesC8& aRemoteFileName,
+ const TDesC8& aNewRemoteFileName)
+ {
+ FTPPROTDEBUG(_DBGFtpsess,_L("CFTPSessionDerived::RenameFile called\n"));
+ if(iState == EIdle)
+ {
+ // Not connected, BailOut
+ iCFTPSetError->SetError(MFtpSessionNotifier::ENotConnected);
+ return;
+ }
+ iState = ERenameFileFrom;
+ iBuffer1 = aNewRemoteFileName;
+ iCFtpProtocol->Rnfr(aRemoteFileName);
+ }
+
+EXPORT_C TUint32 CFTPSession::GetVersion(void)
+/** Gets API version information.
+*
+* The vesion information format is:
+*
+* @li byte 3: ftpsess dll major version
+* @li byte 2: ftpsess dll minor version
+* @li byte 1: ftpprot dll major version
+* @li byte 0: ftpprot dll minor version
+*
+* @return Version information */
+ {
+ TUint32 result;
+ result = FTPSESS_VERSION_NUMBER;
+ result = result<<16;
+ result = result | CFtpProtocol::GetVersion();
+ return result;
+ }
+
+//
+// DLL Entry point
+//
+