// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).// All rights reserved.// This component and the accompanying materials are made available// under the terms of "Eclipse Public License v1.0"// which accompanies this distribution, and is available// at the URL "http://www.eclipse.org/legal/epl-v10.html".//// Initial Contributors:// Nokia Corporation - initial contribution.//// Contributors://// Description:// FTP protocol engine// Author: Philippe Gabriel// Implements objet controling the PI channel of the FTP protocol// Model the PI Channel as an FSM// Transitions between states are triggered by PI methods and events// coming from ESOCK// ///** @file PICHNL.CPP @internalComponent*///#include <in_sock.h>//#include <c32comm.h>#include "DEBUG.H"#include "PICHNL.H"#include "FTPPROT.H"#include <e32base.h>//#include <es_sock.h>//#include <nifman.h>//// Definitions//CPISocketRead::CPISocketRead(MPIChannelNotifier* aNotifier, CPIChannel* aPIChannel) : CActive(EPriorityStandard)/**CPISocketRead objectRead Write implementaion.*/ { iNotifier = aNotifier; iPIChannel = aPIChannel; };CPISocketRead* CPISocketRead::NewL(MPIChannelNotifier* aNotifier, CPIChannel* aPIChannel) { CPISocketRead* self = new(ELeave) CPISocketRead(aNotifier,aPIChannel); CleanupStack::PushL(self); self->ConstructL(); CleanupStack::Pop(); return self; };void CPISocketRead::ConstructL() { CActiveScheduler::Add(this); };void CPISocketRead::DoCancel() { FTPPROTDEBUG(_DBGPichnl,_L("CPISocketRead::DoCancel() called")); iSocket->CancelAll(); };void CPISocketRead::RunL() { FTPPROTDEBUG(_DBGPichnl,_L("CPISocketRead::RunL() called")); if (iStatus == KErrNone) { // Call our notifier iNotifier->PIChannelRcvNotification(); } else { // Uh!!! weird Cancel(); //Disconnect Pi Channel iPIChannel->Disconnect(); // Notify caller iNotifier->PIChannelOperationError(MPIChannelNotifier::EPiConnectionReset); } };void CPISocketRead::IssueRead(TDes8& aBuffer)/**Read Data from a Stream Socket */ { FTPPROTDEBUG(_DBGPichnl,_L("CPISocketRead::IssueRead() called\n")); if (this->IsActive()) return; iSocket->RecvOneOrMore(aBuffer, 0, iStatus,iRcvLen); SetActive(); FTPPROTDEBUG(_DBGPichnl,_L("CPISocketRead::IssueRead() recv triggered\n")); };CPIChannel::CPIChannel(MPIChannelNotifier* aNotifier) :CActive(CActive::EPriorityStandard) /**PI Channel object*/ { FTPPROTDEBUG(_DBGPichnl,_L("CPIChannel::CPIChannel called\n")); //Initialise State iPIChannelState = EPIChannelIdle; iNotifier = aNotifier; }CPIChannel* CPIChannel::NewL(MPIChannelNotifier* aNotifier, RSocketServ& aSockServ) { CPIChannel* self = new (ELeave) CPIChannel(aNotifier); CleanupStack::PushL(self); self->ConstructL(aSockServ); CleanupStack::Pop(); return self; } void CPIChannel::ConstructL(RSocketServ& aSockServ) { FTPPROTDEBUG(_DBGPichnl,_L("CPIChannel::ConstructL called\n")); iSockServ = aSockServ; iReceiver = CPISocketRead::NewL(iNotifier,this); CActiveScheduler::Add(this); } CPIChannel::~CPIChannel() { FTPPROTDEBUG(_DBGPichnl,_L("CPIChannel::~CPIChannel called\n")); //Abort receive if ( iReceiver ) { iReceiver->Cancel(); delete iReceiver; } }void CPIChannel::RunL() { FTPPROTDEBUG(_DBGPichnl,_L("Mytest::RunL activated for CPIChannel\n")); switch(iPIChannelState) { case EPIChannelIdle: // Cannot be activated in that state __ASSERT_DEBUG(FALSE, User::Panic(_L("CPIChannel"), EPIPanicOutOfState)); break; case EPIChannelConnecting: FTPPROTDEBUG(_DBGPichnl,_L("CPIChannel::RunL state: Connecting\n")); // Check result of connecting request switch (iStatus.Int()) { case KErrNone: // If succeed set state to EPIChannelConnected iPIChannelState = EPIChannelConnected; // Call notifier iNotifier->PIChannelOperationCompletion(MPIChannelNotifier::EPiConnectComplete); break; default: // Reset channel to Idle/disconnect socket Disconnect(); // Notify caller iNotifier->PIChannelOperationError(MPIChannelNotifier::EPiConnectFailed); break; } break; case EPIChannelDisconnecting: FTPPROTDEBUG(_DBGPichnl,_L("CPIChannel::RunL state: Connecting\n")); // Assume disconnect always work Disconnect(); // Notify caller iNotifier->PIChannelOperationCompletion(MPIChannelNotifier::EPiDisconnectComplete); break; case EPIChannelSending: FTPPROTDEBUG(_DBGPichnl,_L("CPIChannel::RunL state: EPIChannelSending\n")); // Check result of send request switch (iStatus.Int()) { case KErrNone: // If succeed set state to EPIChannelConnected iPIChannelState = EPIChannelConnected; // Call notifier iNotifier->PIChannelOperationCompletion(MPIChannelNotifier::EPiSendComplete); break; default: // Reset channel to Idle/disconnect socket Disconnect(); // Notify caller iNotifier->PIChannelOperationError(MPIChannelNotifier::EPiSendFailed); break; } break; default: __ASSERT_DEBUG(FALSE, User::Panic(_L("CPIChannel::RunL"), 0)); break; } }TBool CPIChannel::Connect(TSockAddr& aNetAddr)/**@return FALSE if a socket could not be openned Caller must check the result and post an error if appropriate*/ { // Check this is a valid state for this operation __ASSERT_DEBUG((iPIChannelState == EPIChannelIdle), User::Panic(_L("CPIChannel"), EPIPanicChannelConnected)); // Open a socket if(KErrNone != iPiSocket.Open(iSockServ, KAfInet, KSockStream, KProtocolInetTcp)) // Socket could not be openned, bail out return FALSE; // Give CPISocketRead the ref to my socket iReceiver->SetSocket(&iPiSocket); // Connect to peer iPiSocket.Connect(aNetAddr, iStatus); // Update state iPIChannelState = EPIChannelConnecting; // Activate the object SetActive(); // Everything's OK return TRUE; }void CPIChannel::GetLocalAddress(TInetAddr& aLocalAddr) { // get my local address // seems that LocalAddress function does not return // the IP address until you've connected to somewhere // hence I need this function to be called once the // connect has succeeded to discover my IP address iPiSocket.LocalName(aLocalAddr); }TBool CPIChannel::Busy(void) /**@return The state of DTP Channel*/ { return(iPIChannelState != EPIChannelConnected); }void CPIChannel::Disconnect(void) { FTPPROTDEBUG(_DBGPichnl,_L("CPIChannel::Disconnect called\n")); //Close PI socket iReceiver->Cancel(); Cancel(); iPiSocket.Close(); iPIChannelState = EPIChannelIdle; }void CPIChannel::SendCommand(TDes8& aCommand,TUint aSomeFlags,TBool aSendCRLF) { // If I'm not connected just return don't post error if(iPIChannelState == EPIChannelIdle) { FTPPROTDEBUG(_DBGPichnl,_L("!!!!!Not Connected - SendCommand not triggered\n")); return; } //__ASSERT_DEBUG(iPIChannelState != EPIChannelIdle, User::Panic(_L("CPIChannel"), EPIPanicChannelNotConnected)); // Update the state iPIChannelState = EPIChannelSending; // Add the Telnet terminator sequence // BIG BIG assumption here !! the buffer is big enough // but FtpProtocol is my friend I trust it if(aSendCRLF) { aCommand.Append(CR); aCommand.Append(LF); } // Send the command iPiSocket.Send(aCommand,aSomeFlags,iStatus); // Activate the object SetActive(); }void CPIChannel::GetNextAnswer(TDes8& aBuffer) { FTPPROTDEBUG(_DBGPichnl,_L("CPIChannel::GetNextAnswer called\n")); if(iPIChannelState != EPIChannelIdle) // Fetch the reply sent by the server iReceiver->IssueRead(aBuffer); }void CPIChannel::DoCancel(void) { FTPPROTDEBUG(_DBGPichnl,_L("CPIChannel::DoCancel called\n")); iReceiver->Cancel(); switch(iPIChannelState) { case EPIChannelConnecting: iPiSocket.CancelConnect(); iPiSocket.Close(); iPIChannelState = EPIChannelIdle; break; default: break; } }