hti/HtiServicePlugins/HtiFtpServicePlugin/src/HtiFtpServicePlugin.cpp
branchRCL_3
changeset 59 8ad140f3dd41
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hti/HtiServicePlugins/HtiFtpServicePlugin/src/HtiFtpServicePlugin.cpp	Wed Oct 13 16:17:58 2010 +0300
@@ -0,0 +1,2318 @@
+/*
+* Copyright (c) 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:  HtiFtpServicePlugin implementation
+*
+*/
+
+
+// INCLUDE FILES
+#include "HtiFtpServicePlugin.h"
+#include <HtiFtpBackupFakeBase.h>
+#include <HtiDispatcherInterface.h>
+#include <HtiLogging.h>
+
+#include <e32property.h>
+#include <hash.h>
+
+// CONSTANTS
+static const TUid KFtpServiceUid = { 0x1020DEC5 };
+_LIT( KBackslash, "\\" );
+_LIT( KRootPathFormat, "%c:\\" );
+_LIT( KHtiFtpBackupFakeDllName, "HtiFtpBackupFake.dll" );
+const static TInt KMinBufferSize = 1024;
+const static TUint8 KUnicodeMask = 0x1;
+const static TInt KFileSizeMsgSize = 5;
+
+//error description
+_LIT8( KErrDescrUnknownCmd, "unknown command" );
+_LIT8( KErrDescrNoSpace, "no disk space" );
+_LIT8( KErrDescrFailedRead, "failed read file" );
+_LIT8( KErrDescrFailedWrite, "failed write file" );
+_LIT8( KErrDescrFailedGetDir, "failed to read directory" );
+_LIT8( KErrDescrEmptyDirname, "directory name empty" );
+_LIT8( KErrDescrInvalidDirnameLength, "invalid directory name length" );
+_LIT8( KErrDescrEmptyFilename, "file name empty" );
+_LIT8( KErrDescrInvalidFilenameLength, "invalid file name length" );
+_LIT8( KErrDescrFailedMkDir, "failed create directory" );
+_LIT8( KErrDescrFailedRmDir, "failed remove directory" );
+_LIT8( KErrDescrFailedDeleFile, "failed delete file" );
+_LIT8( KErrDescrFailedRenameFile, "failed rename file" );
+_LIT8( KErrDescrFailedCopyFile, "failed copy file" );
+_LIT8( KErrDescrFailedMoveFile, "failed move file" );
+_LIT8( KErrDescrInvalidStorArgument, "invalid arguments" );
+_LIT8( KErrDescrFailedCreateFile, "invalid create file" );
+_LIT8( KErrDescrFailedOpenFile, "failed open file" );
+_LIT8( KErrDescrFailedCloseFile, "failed close file" );
+_LIT8( KErrDescrInvalidDataMessage, "invalid data message" );
+_LIT8( KErrDescrNoMemory, "no memory to send file" );
+_LIT8( KErrDescrNoCancel, "nothing to cancel" );
+_LIT8( KErrDescrBusy, "Busy" );
+_LIT8( KErrDescrFailedCopyTcb, "Failed to copy to Tcb directories" );
+_LIT8( KErrDescrInvalidForceArgs, "invalid arguments for setforce" );
+_LIT8( KErrDescrInvalidChecksumArgs, "invalid arguments for checksum" );
+_LIT8( KErrDescrInvalidFormatArgs, "invalid arguments for format" );
+_LIT8( KErrDescrInvalidDriveListArgs, "invalid arguments for drive list" );
+_LIT8( KErrDescrFailedFormat, "failed to format" );
+_LIT8( KErrDescrNotSupported, "command not supported" );
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// FORWARD DECLARATIONS
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+/**
+* CFtpHandlerAO implementation
+*/
+CFtpHandlerAO::CFtpHandlerAO( MFtpObserverAO* anObserver ):
+    CActive( EPriorityStandard ),
+    iObserver( anObserver ),
+    iCancelFileMan( EFalse )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+CFtpHandlerAO::~CFtpHandlerAO()
+    {
+    }
+
+void CFtpHandlerAO::Start()
+    {
+    SetActive();
+    }
+
+MFileManObserver::TControl CFtpHandlerAO::NotifyFileManStarted()
+    {
+    return iCancelFileMan?
+                MFileManObserver::EAbort :
+                MFileManObserver::EContinue;
+    }
+
+MFileManObserver::TControl CFtpHandlerAO::NotifyFileManOperation()
+    {
+    return iCancelFileMan?
+                MFileManObserver::ECancel :
+                MFileManObserver::EContinue;
+    }
+
+MFileManObserver::TControl CFtpHandlerAO::NotifyFileManEnded()
+    {
+    return iCancelFileMan?
+                MFileManObserver::EAbort :
+                MFileManObserver::EContinue;
+    }
+
+void CFtpHandlerAO::RunL()
+    {
+    iObserver->FtpComplete( iStatus.Int() );
+    }
+
+void CFtpHandlerAO::DoCancel()
+    {
+    iCancelFileMan = ETrue;
+    }
+
+CProcessLogonAO::CProcessLogonAO( MFtpObserverAO* anObserver ):
+    CActive( EPriorityStandard ),
+    iObserver( anObserver )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+CProcessLogonAO::~CProcessLogonAO()
+    {
+    Cancel();
+    iProcess.Close();
+    }
+
+void CProcessLogonAO::Start( const TDesC& aCmdLine )
+    {
+    TInt err = iProcess.Create( KHtiFileHlp, aCmdLine );
+
+    if ( err == KErrNone )
+        {
+        iProcess.Logon( iStatus );
+        //start HtiFileHlp.exe
+        iProcess.Resume();
+        }
+    else
+        {
+        TRequestStatus* pS = &iStatus;
+        User::RequestComplete( pS, err );
+        }
+    SetActive();
+    }
+
+void CProcessLogonAO::RunL()
+    {
+    iObserver->FtpComplete( iStatus.Int() );
+    }
+
+void CProcessLogonAO::DoCancel()
+    {
+    iProcess.LogonCancel( iStatus );
+    }
+
+// Create instance of concrete ECOM interface implementation
+CHtiFtpServicePlugin* CHtiFtpServicePlugin::NewL()
+    {
+    CHtiFtpServicePlugin* self = new (ELeave) CHtiFtpServicePlugin;
+    CleanupStack::PushL (self);
+    self->ConstructL();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// Constructor
+CHtiFtpServicePlugin::CHtiFtpServicePlugin():
+    iState( EIdle ),
+    iSendBuffer( NULL ),
+    iSendBufferDes( NULL, 0 ),
+    iHandlerAO( NULL ),
+    iProcessLogonAO( NULL )
+    {
+    }
+
+CHtiFtpServicePlugin::~CHtiFtpServicePlugin()
+    {
+    HTI_LOG_FUNC_IN("~CHtiFtpServicePlugin");
+    delete iSendBuffer;
+    delete iHandlerAO;
+    delete iProcessLogonAO;
+    delete iFileMan;
+    delete iBackupFake;
+    iBackupFakeLib.Close();
+    iFs.Close();
+    HTI_LOG_FUNC_OUT("~CHtiFtpServicePlugin");
+    }
+
+// Second phase construction.
+void CHtiFtpServicePlugin::ConstructL()
+    {
+    HTI_LOG_FUNC_IN("CHtiFtpServicePlugin::ConstructL");
+
+    User::LeaveIfError( iFs.Connect() );
+    iFileMan = CFileMan::NewL( iFs );
+
+    HTI_LOG_FUNC_OUT("CHtiFtpServicePlugin::ConstructL");
+    }
+
+void CHtiFtpServicePlugin::InitL()
+    {
+    if ( iDispatcher->GetFreeMemory() < KMinBufferSize )
+        {
+        User::Leave( KErrNoMemory );
+        }
+    // just guess
+
+    iBufferSize = iDispatcher->GetFreeMemory()/10;
+    iBufferSize = iBufferSize < KMinBufferSize ?
+                    KMinBufferSize :
+                    iBufferSize;
+    //test
+    iBufferSize = 3*KMinBufferSize;
+    }
+
+TInt CHtiFtpServicePlugin::SendControlMsg( TFtpCommand aCmd,
+                                           const TDesC8& aMsg  )
+    {
+    TInt err = KErrNone;
+    HBufC8* temp = NULL;
+    TRAP( err, temp = HBufC8::NewL( 1 + aMsg.Size() ) );
+    if ( err == KErrNone )
+        {
+        temp->Des().Append( aCmd );
+        temp->Des().Append( aMsg );
+        err = iDispatcher->DispatchOutgoingMessage( temp,
+                        KFtpServiceUid,
+                        EFalse,
+                        EHtiPriorityControl );
+        if ( err != KErrNone )
+            {
+            delete temp;
+            }
+        }
+    return err;
+    }
+
+inline TInt CHtiFtpServicePlugin::SendErrorMsg( TInt anError,
+                                                const TDesC8& aMsg )
+    {
+    SetBURFakeState( EFalse ); // errors ignored
+    return iDispatcher->DispatchOutgoingErrorMessage( anError,
+                                               aMsg,
+                                               KFtpServiceUid);
+    }
+
+TBool CHtiFtpServicePlugin::IsBusy()
+    {
+    return !( iState == EIdle || iState == EStorWait || iState == ERetrWait );
+    }
+
+void CHtiFtpServicePlugin::ProcessMessageL(const TDesC8& aMessage,
+                THtiMessagePriority aPriority)
+    {
+    HTI_LOG_FUNC_IN("CHtiFtpServicePlugin::ProcessMessage");
+
+    if ( IsBusy() )
+        {
+        //should not happend - service busy,deny request
+        User::Leave( KErrInUse );
+        }
+
+    switch ( aPriority )
+        {
+        case EHtiPriorityData:
+            {
+            HandleDataMessageL( aMessage );
+            }
+            break;
+        case EHtiPriorityControl:
+            {
+            if ( iState == EStorWait || iState == ERetrWait )
+                {
+                HandleCancelL( aMessage );
+                }
+            else
+                {
+                HandleControlMessageL( aMessage );
+                }
+            }
+            break;
+        default:
+            HTI_LOG_TEXT("Unknown priority");
+        }
+
+    HTI_LOG_FUNC_OUT("CHtiFtpServicePlugin::ProcessMessage");
+    }
+
+void CHtiFtpServicePlugin::HandleControlMessageL(const TDesC8& aMessage)
+    {
+    TInt err = KErrNone;
+
+    if ( aMessage.Length() > 0 )
+        {
+        TBool unicode = aMessage[0]&KUnicodeMask;
+        HTI_LOG_FORMAT("cmd %d", aMessage[0] );
+
+        switch ( aMessage[0] )
+            {
+            case EFtpSTOR:
+            case EFtpSTOR_u:
+                {
+                //receive file
+                //get filesize
+                if ( aMessage.Length() > 5 )
+                    {
+                    iFileSize = aMessage[1] +
+                                ( aMessage[2] << 8  ) +
+                                ( aMessage[3] << 16 ) +
+                                ( aMessage[4] << 24 );
+
+                    HTI_LOG_FORMAT( "Filesize %d", iFileSize );
+                    //get fileName
+                    if ( GetFileNameL( aMessage.Mid( 5 ),
+                                      unicode ) )
+                        {
+                        HandleReceiveFileL();
+                        }
+                    }
+                else
+                    {
+                    HTI_LOG_TEXT("no file size or file name");
+                    User::LeaveIfError( SendErrorMsg( KErrArgument,
+                                            KErrDescrInvalidStorArgument) );
+
+                    }
+                }
+                break;
+            case EFtpRETR:
+            case EFtpRETR_u:
+                {
+                //send file
+                //get fileName and size
+                if ( GetFileNameL( aMessage.Mid(1),
+                                   unicode ) )
+                    {
+                    HandleSendFileL();
+                    }
+                }
+                break;
+            case EFtpLIST:
+            case EFtpLIST_u:
+            case EFtpLISTSIZES:
+            case EFtpLISTSIZES_u:
+                {
+                if ( GetDirectoryL( aMessage.Mid( 1 ),
+                                   unicode ) )
+                    {
+                    HandleListL( unicode,
+                        ( KEntryAttHidden| KEntryAttSystem|KEntryAttNormal ),
+                        ( aMessage[0] == EFtpLISTSIZES ||
+                          aMessage[0] == EFtpLISTSIZES_u ) );
+                    }
+                }
+                break;
+            case EFtpListDetail:
+            case EFtpListDetail_u:
+                {
+                if ( GetDirectoryL( aMessage.Mid( 1 ),
+                                   unicode ) )
+                    {
+                    HandleListDetailL( unicode,
+                        KEntryAttHidden| KEntryAttSystem|KEntryAttNormal);
+                    }
+                }
+                break;
+            case EFtpLISTDIR:
+            case EFtpLISTDIR_u:
+                {
+                if ( GetDirectoryL( aMessage.Mid( 1 ),
+                                   unicode ) )
+                    {
+                    HandleListL( unicode,
+                                (KEntryAttMatchExclusive|
+                                KEntryAttHidden|KEntryAttSystem|
+                                KEntryAttDir), EFalse );
+                    }
+                }
+                break;
+            case EFtpListDirDetail:
+            case EFtpListDirDetail_u:
+                {
+                if ( GetDirectoryL( aMessage.Mid( 1 ),
+                                   unicode ) )
+                    {
+                    HandleListDetailL( unicode,
+                            KEntryAttMatchExclusive|KEntryAttHidden|
+                            KEntryAttSystem|KEntryAttDir);
+                    }
+                }
+                break;
+            case EFtpMKD:
+            case EFtpMKD_u:
+                {
+                if ( GetDirectoryL( aMessage.Mid( 1 ),
+                                   unicode ) )
+                    {
+                    if ( IsFileTcb( iFileName ) )
+                        {
+                        HandleTcbMkdL( iFileName );
+                        }
+                    else
+                        {
+                        err = iFs.MkDirAll( iFileName );
+                        if ( err == KErrNone || err == KErrAlreadyExists )
+                            {
+                            User::LeaveIfError( SendControlMsg( EFtpOK,
+                                                                KNullDesC8) );
+                            }
+                        else
+                            {
+                            User::LeaveIfError( SendErrorMsg( err,
+                                                        KErrDescrFailedMkDir ) );
+
+                            }
+                        }
+                    }
+                }
+                break;
+            case EFtpRMD:
+            case EFtpRMD_u:
+                {
+                if ( GetDirectoryL( aMessage.Mid( 1 ),
+                                   unicode ) )
+                    {
+                    if ( IsFileTcb( iFileName ) )
+                        {
+                        HandleTcbRmdL( iFileName );
+                        }
+                    else
+                        {
+                        delete iHandlerAO;
+                        iHandlerAO = NULL;
+
+                        iHandlerAO = new(ELeave) CFtpHandlerAO( this );
+                        err = iFileMan->RmDir( iFileName, iHandlerAO->iStatus );
+                        if ( err == KErrNone)
+                            {
+                            iState = ERmdBusy;
+                            iHandlerAO->Start();
+                            }
+                        else
+                            {
+                            delete iHandlerAO;
+                            iHandlerAO = NULL;
+                            User::LeaveIfError( SendErrorMsg( err,
+                                                        KErrDescrFailedRmDir ) );
+                            }
+                        }
+                    }
+                }
+                break;
+            case EFtpDELE:
+            case EFtpDELE_u:
+                {
+                if ( GetFileNameL( aMessage.Mid( 1 ),
+                                   unicode ) )
+                    {
+                    if ( IsFileTcb( iFileName ) )
+                        {
+                        HandleTcbDeleteL( iFileName );
+                        }
+                    else
+                        {
+                        HandleDeleteL( iFileName );
+                        }
+                    }
+                }
+                break;
+            case EFtpCANCEL:
+                {
+                User::LeaveIfError( SendErrorMsg( KErrArgument,
+                                                KErrDescrNoCancel ) );
+                }
+                break;
+            case EFtpSETFORCE:
+                {
+                if ( aMessage.Length() != 2 )
+                    {
+                    User::LeaveIfError( SendErrorMsg( KErrArgument,
+                                                KErrDescrInvalidForceArgs ) );
+                    }
+                else
+                    {
+                    if ( aMessage[1] )
+                        {
+                        // Setting forced operations on
+                        err = iBackupFakeLib.Load( KHtiFtpBackupFakeDllName );
+                        HTI_LOG_FORMAT( "BackupFake DLL load returned %d", err );
+                        if ( err == KErrNone && iBackupFakeLib.Type()[1] ==
+                                KHtiFtpBackupFakeInterfaceUid )
+                            {
+                            HTI_LOG_TEXT( "BackupFake DLL found" );
+                            TLibraryFunction entry = iBackupFakeLib.Lookup( 1 );
+                            if ( entry != NULL )
+                                {
+                                iBackupFake = ( CHtiFtpBackupFakeBase* ) entry();
+                                TRAP( err, iBackupFake->ConstructL( &iFs ) );
+                                }
+                            }
+                        if ( err == KErrNone )
+                            {
+                            SendControlMsg( EFtpOK, KNullDesC8 );
+                            }
+                        else
+                            {
+                            User::LeaveIfError( SendErrorMsg( KErrNotSupported,
+                                KErrDescrNotSupported ) );
+                            }
+                        }
+                    else
+                        {
+                        // Setting forced operations off
+                        delete iBackupFake;
+                        iBackupFake = NULL;
+                        iBackupFakeLib.Close();
+                        SendControlMsg( EFtpOK, KNullDesC8 );
+                        }
+                    }
+                }
+                break;
+            case EFtpCHECKSUM:
+            case EFtpCHECKSUM_u:
+                {
+                if ( aMessage.Length() < 3 )
+                    {
+                    User::LeaveIfError(
+                        SendErrorMsg( KErrArgument,
+                                      KErrDescrInvalidChecksumArgs ) );
+                    }
+                else if ( GetFileNameL( aMessage.Mid( 2 ), unicode ) )
+                    {
+                    HandleCheckSumCalcL( (TAlgorithm)aMessage[1], iFileName );
+                    }
+                }
+                break;
+            case EFtpFORMAT:
+                {
+                if ( aMessage.Length() != 3 )
+                    {
+                    User::LeaveIfError( SendErrorMsg( KErrArgument,
+                            KErrDescrInvalidFormatArgs ) );
+                    }
+                else
+                    {
+                    HandleFormat( aMessage[1], aMessage[2] );
+                    }
+                }
+                break;
+            case EFtpLISTDRIVES:
+            case EFtpLISTDRIVES_u:
+                {
+                if ( aMessage.Length() != 1 )
+                    {
+                    User::LeaveIfError( SendErrorMsg( KErrArgument,
+                        KErrDescrInvalidDriveListArgs ) );
+                    }
+                else
+                    {
+                    HandleListDrivesL( unicode );
+                    }
+                }
+                break;
+            case EFtpRENAME:
+            case EFtpRENAME_u:
+                {
+                HandleRenameL( aMessage, unicode );
+                }
+                break;
+            case EFtpCOPY:
+            case EFtpCOPY_u:
+                {
+                HandleCopyL( aMessage, unicode );
+                }
+                break;
+            case EFtpMOVE:
+            case EFtpMOVE_u:
+                {
+                HandleMoveL( aMessage, unicode );
+                }
+                break;
+            default:
+                {
+                //Error: unknown command
+                User::LeaveIfError( SendErrorMsg( KErrArgument,
+                                                KErrDescrUnknownCmd ) );
+                }
+            }
+        }
+    else
+        {
+        //error: empty request
+        User::LeaveIfError( SendErrorMsg( KErrArgument, KErrDescrUnknownCmd ) );
+        }
+    }
+
+void CHtiFtpServicePlugin::HandleDeleteL( const TDesC& aFilename )
+    {
+    HTI_LOG_FUNC_IN( "CHtiFtpServicePlugin::HandleDeleteL" );
+    delete iHandlerAO;
+    iHandlerAO = NULL;
+
+    iHandlerAO = new(ELeave) CFtpHandlerAO( this );
+    TInt err = iFileMan->Delete( aFilename, 0, iHandlerAO->iStatus );
+    if ( err == KErrNone)
+        {
+        iState = EDeleBusy;
+        iHandlerAO->Start();
+        }
+    else
+        {
+        HTI_LOG_FORMAT( "Delete failed %d", err );
+        delete iHandlerAO;
+        iHandlerAO = NULL;
+        User::LeaveIfError( SendErrorMsg( err,
+                                    KErrDescrFailedDeleFile ) );
+        }
+    HTI_LOG_FUNC_OUT( "CHtiFtpServicePlugin::HandleDeleteL" );
+    }
+
+void CHtiFtpServicePlugin::HandleRenameL( const TDesC8& aMessage, TBool aUnicode )
+    {
+    delete iHandlerAO;
+    iHandlerAO = NULL;
+
+    TInt originalLenngth = aMessage[1];
+
+    GetFileNameL( aMessage.Mid( 1, originalLenngth + 1 ), aUnicode );
+
+    //If last character is back slash remove it
+    RemoveEndBackslash(iFileName);
+
+    TFileName origName = iFileName;
+
+    TInt newNamePos = originalLenngth + 2 ;
+    TInt newNameLength = aMessage[newNamePos];
+    GetFileNameL( aMessage.Mid( newNamePos, newNameLength + 1 ), aUnicode );
+
+    RemoveEndBackslash( iFileName );
+
+    if ( IsFileTcb( origName ) || IsFileTcb( iFileName ) )
+        {
+        HandleTcbRenameL( origName, iFileName );
+        }
+    else
+        {
+        iHandlerAO = new ( ELeave ) CFtpHandlerAO( this );
+        TInt err = iFileMan->Rename( origName, iFileName,
+                    CFileMan::EOverWrite, iHandlerAO->iStatus );
+
+        if ( err == KErrNone )
+            {
+            iState = ERenameBusy;
+            iHandlerAO->Start();
+            }
+        else
+            {
+            HTI_LOG_FORMAT( "Rename failed %d", err );
+            delete iHandlerAO;
+            iHandlerAO = NULL;
+            User::LeaveIfError( SendErrorMsg(
+                    err, KErrDescrFailedRenameFile ) );
+            }
+        }
+
+    }
+
+void CHtiFtpServicePlugin::RemoveEndBackslash( TFileName& aFileName  )
+    {
+    //If last character is back slash remove it
+    if ( aFileName.Right( 1 ) == KBackslash )
+        {
+        aFileName.Delete( aFileName.Length() - 1, 1 );
+        }
+    }
+
+void CHtiFtpServicePlugin::HandleCopyL( const TDesC8& aMessage, TBool aUnicode )
+    {
+    delete iHandlerAO;
+    iHandlerAO = NULL;
+
+    TInt originalLenngth = aMessage[1];
+
+    GetFileNameL( aMessage.Mid( 1, originalLenngth + 1 ), aUnicode );
+    TFileName origName = iFileName;
+
+    TInt newNamePos = originalLenngth + 2 ;
+    TInt newNameLength = aMessage[newNamePos];
+    GetFileNameL( aMessage.Mid( newNamePos, newNameLength + 1 ), aUnicode );
+
+    TInt msglen = aMessage.Length();
+    TInt recurse = 1;
+    if(msglen>originalLenngth+newNameLength+3)        
+        {
+        recurse = aMessage[newNamePos+1+newNameLength];
+        }
+    
+    TInt err=0;
+    if ( IsFileTcb( origName ) || IsFileTcb( iFileName ) )
+        {
+        HandleTcbCopyL( origName, iFileName );
+        }
+    else{
+        iHandlerAO = new ( ELeave ) CFtpHandlerAO( this );
+        
+        if (recurse)
+            {
+            err = iFileMan->Copy( origName, iFileName,
+                ( CFileMan::EOverWrite | CFileMan::ERecurse ),
+                iHandlerAO->iStatus );
+            }
+        else
+            {
+            err = iFileMan->Copy( origName, iFileName,
+                ( CFileMan::EOverWrite ),
+                iHandlerAO->iStatus );
+            }
+
+        if ( err == KErrNone)
+            {
+            iState = ECopyBusy;
+            iHandlerAO->Start();
+            }
+        else
+            {
+            HTI_LOG_FORMAT( "Rename failed %d", err );
+            delete iHandlerAO;
+            iHandlerAO = NULL;
+            User::LeaveIfError( SendErrorMsg( err,
+                                        KErrDescrFailedCopyFile ) );
+            }
+        }
+    }
+
+void CHtiFtpServicePlugin::HandleMoveL( const TDesC8& aMessage, TBool aUnicode )
+    {
+    delete iHandlerAO;
+    iHandlerAO = NULL;
+
+    TInt originalLenngth = aMessage[1];
+
+    GetFileNameL( aMessage.Mid( 1, originalLenngth + 1 ), aUnicode );
+
+    RemoveEndBackslash( iFileName );
+
+    TFileName origName = iFileName;
+
+    TInt newNamePos = originalLenngth + 2 ;
+    TInt newNameLength = aMessage[newNamePos];
+    GetFileNameL( aMessage.Mid( newNamePos, newNameLength + 1 ), aUnicode );
+    // make sure destination ends with backslash - destination always directory
+    if ( iFileName.Right( 1 ) != KBackslash )
+        {
+        iFileName.Append( KBackslash );
+        }
+
+    if ( IsFileTcb( origName ) || IsFileTcb( iFileName ) )
+        {
+        HandleTcbMoveL( origName, iFileName );
+        }
+    else
+        {
+        iHandlerAO = new ( ELeave ) CFtpHandlerAO( this );
+        TInt err = iFileMan->Move( origName, iFileName,
+                ( CFileMan::EOverWrite | CFileMan::ERecurse ),
+                iHandlerAO->iStatus );
+
+        if ( err == KErrNone )
+            {
+            iState = EMoveBusy;
+            iHandlerAO->Start();
+            }
+        else
+            {
+            HTI_LOG_FORMAT( "Move failed %d", err );
+            delete iHandlerAO;
+            iHandlerAO = NULL;
+            User::LeaveIfError( SendErrorMsg( err,
+                                        KErrDescrFailedMoveFile ) );
+            }
+        }
+    }
+
+void CHtiFtpServicePlugin::HandleCancelL(const TDesC8& aMessage)
+    {
+
+    if ( aMessage.Length()>0 )
+        {
+        HTI_LOG_FORMAT("cmd %d", aMessage[0]);
+
+        if ( aMessage[0] == EFtpCANCEL )
+            {
+            //handle cancel
+            iFile.Close();
+
+            if ( iState == EStorWait )
+                {
+                iFs.Delete(iFileName);
+                }
+            else if ( iState == ERetrWait )
+                {
+                iDispatcher->RemoveMemoryObserver(this);
+
+                delete iSendBuffer;
+                iSendBuffer = NULL;
+                }
+            //other states filtered out before
+
+            delete iHandlerAO;
+            iHandlerAO = NULL;
+
+            iState = EIdle;
+
+            User::LeaveIfError( SendControlMsg( EFtpOK, KNullDesC8) );
+            }
+        else
+            {
+            User::LeaveIfError( SendErrorMsg( KErrServerBusy,
+                            KErrDescrBusy) );
+            }
+        }
+    else
+        {
+        //send err
+        User::LeaveIfError( SendErrorMsg( KErrArgument,
+                            KErrDescrUnknownCmd ) );
+        }
+    }
+
+void CHtiFtpServicePlugin::CopyUnicode( TDes& aTo, const TDesC8& aFrom )
+{
+    HTI_LOG_FUNC_IN("CHtiFtpServicePlugin::CopyUnicode");
+    TInt len = aFrom.Length()>>1;
+    aTo.SetLength( len );
+    for ( TInt i = 0; i < len; ++i )
+    {
+        aTo[i] = (TUint16)aFrom[i<<1] + (((TUint16)aFrom[(i<<1)+1])<<8);
+    }
+    HTI_LOG_FUNC_OUT("CHtiFtpServicePlugin::CopyUnicode");
+}
+
+TBool CHtiFtpServicePlugin::GetFileNameL( const TDesC8& aFilename,
+                                          TBool aToUnicode )
+    {
+    HTI_LOG_FUNC_IN("CHtiFtpServicePlugin::GetFileNameL");
+    if ( aFilename.Length() > 1 )
+        {
+        TInt length = aFilename[0];
+        TInt size = aToUnicode ? ( length * 2 ) : length;
+
+        if ( ( size + 1 ) == aFilename.Size() )
+            {
+            if ( aToUnicode )
+                {
+                //const TPtrC8 ptr = aFilename.Mid(1).Ptr();
+                //iFileName.Copy( (TUint16*)ptr, len );
+                CopyUnicode( iFileName, aFilename.Mid( 1 ) );
+                }
+            else
+                {
+                iFileName.Copy( aFilename.Mid( 1, length ) );
+                }
+
+            HTI_LOG_TEXT( "filename:" );
+            HTI_LOG_DES( iFileName );
+            return ETrue;
+            }
+        else
+            {
+            User::LeaveIfError( SendErrorMsg( KErrArgument,
+                                              KErrDescrInvalidFilenameLength ) );
+            }
+        }
+    else
+        {
+        User::LeaveIfError( SendErrorMsg( KErrArgument,
+                                          KErrDescrEmptyFilename ) );
+        }
+
+    HTI_LOG_FUNC_OUT("CHtiFtpServicePlugin::GetFileNameL");
+    return EFalse;
+    }
+
+TBool CHtiFtpServicePlugin::GetDirectoryL( const TDesC8& aDirname,
+                                           TBool aToUnicode )
+    {
+    HTI_LOG_FUNC_IN("CHtiFtpServicePlugin::GetDirectoryL");
+    if ( aDirname.Length() > 1 )
+        {
+        TInt len = aDirname[0];
+        TInt size = aToUnicode ? ( len * 2 ) : len;
+        if ( ( size + 1 ) == aDirname.Size() )
+            {
+            if ( aToUnicode )
+                {
+                //const TUint8* ptr = aDirname.Mid(1).Ptr();
+                //iFileName.Copy( (TUint16*)ptr, len );
+                CopyUnicode( iFileName, aDirname.Mid(1) );
+                }
+            else
+                {
+                iFileName.Copy( aDirname.Mid( 1, len ) );
+                }
+
+            HTI_LOG_TEXT( "dir:" );
+            HTI_LOG_DES( iFileName );
+            if ( iFileName.Right( 1 ) != KBackslash )
+                {
+                iFileName.Append( KBackslash );
+                }
+            HTI_LOG_FUNC_OUT("CHtiFtpServicePlugin::GetDirectoryL");
+            return ETrue;
+            }
+        else
+            {
+            User::LeaveIfError( SendErrorMsg( KErrArgument,
+                                              KErrDescrInvalidDirnameLength ) );
+            }
+        }
+    else
+        {
+        User::LeaveIfError( SendErrorMsg( KErrArgument,
+                                          KErrDescrEmptyDirname ) );
+        }
+
+    HTI_LOG_FUNC_OUT("CHtiFtpServicePlugin::GetDirectoryL");
+    return EFalse;
+    }
+
+void CHtiFtpServicePlugin::HandleListL( TBool aUnicodText,
+                                        TUint aReadingAtt, TBool aSizes )
+    {
+    HTI_LOG_FUNC_IN("HandleListL");
+    CDir* dir;
+    TInt err = iFs.GetDir( iFileName, aReadingAtt, ESortNone, dir );
+    if ( err != KErrNone )
+        {
+        User::LeaveIfError( SendErrorMsg( err, KErrDescrFailedGetDir ) );
+        return;
+        }
+
+    CleanupStack::PushL( dir );
+    //build list
+    delete iSendBuffer;
+    iSendBuffer = NULL;
+    TInt bufferLen = dir->Count()*KMaxFileName;
+    if ( aUnicodText )
+        {
+        bufferLen *= 2;
+        }
+    bufferLen += dir->Count();
+    if ( aSizes )
+        {
+        bufferLen += 4 * dir->Count();
+        }
+
+    iSendBuffer = HBufC8::NewL( bufferLen );
+    TInt dirNameLen = 0;
+    for ( TInt i = 0; i < dir->Count(); ++i)
+        {
+        dirNameLen = (*dir)[i].iName.Length();
+        iSendBuffer->Des().Append( dirNameLen );
+        if ( aUnicodText )
+            {
+            iSendBuffer->Des().Append( (TUint8*)((*dir)[i].iName.Ptr()),
+                                       dirNameLen*2 );
+            }
+        else
+            {
+            iSendBuffer->Des().Append( (*dir)[i].iName );
+            }
+        if ( aSizes )
+            {
+            TInt size = (*dir)[i].iSize;
+            iSendBuffer->Des().Append( (TUint8*)(&size), 4 );
+            }
+        }
+
+    err = iDispatcher->DispatchOutgoingMessage(iSendBuffer,
+                        KFtpServiceUid,
+                        EFalse,
+                        EHtiPriorityControl);
+
+    if (  err != KErrNone )
+        {
+        //wait for a memory
+        iState = EListBusy;
+        iDispatcher->AddMemoryObserver( this );
+        }
+    else
+        {
+        iSendBuffer = NULL;
+        }
+
+    CleanupStack::PopAndDestroy();//dir
+    HTI_LOG_FUNC_OUT("HandleListL");
+    }
+
+void CHtiFtpServicePlugin::HandleListDetailL( TBool aUnicodText, TUint aReadingAtt)
+    {
+    HTI_LOG_FUNC_IN("HandleListDetailL");
+    CDir* dir;
+    TInt err = iFs.GetDir( iFileName, aReadingAtt, ESortNone, dir );
+    if ( err != KErrNone )
+        {
+        User::LeaveIfError( SendErrorMsg( err, KErrDescrFailedGetDir ) );
+        return;
+        }
+
+    CleanupStack::PushL( dir );
+    //build list
+    delete iSendBuffer;
+    iSendBuffer = NULL;
+    TInt bufferLen = dir->Count()*KMaxFileName;
+    if ( aUnicodText )
+        {
+        bufferLen *= 2;
+        }
+    // 1 bytes for name length, 4 bytes for file size, 
+    // 6 bytes for date time, 3 bytes for attributes(hide, readonly and system)
+    bufferLen += (1 + 4 + 6 + 3) * dir->Count();
+
+    iSendBuffer = HBufC8::NewL( bufferLen );
+    TInt dirNameLen = 0;
+    for ( TInt i = 0; i < dir->Count(); ++i)
+        {
+        dirNameLen = (*dir)[i].iName.Length();
+        iSendBuffer->Des().Append( dirNameLen );
+        if ( aUnicodText )
+            {
+            iSendBuffer->Des().Append( (TUint8*)((*dir)[i].iName.Ptr()),
+                                       dirNameLen*2 );
+            }
+        else
+            {
+            iSendBuffer->Des().Append( (*dir)[i].iName );
+            }
+        TInt year = (*dir)[i].iModified.DateTime().Year();
+        iSendBuffer->Des().Append((TUint8*)(&year), 2 );
+        iSendBuffer->Des().Append( (*dir)[i].iModified.DateTime().Month()+1);
+        iSendBuffer->Des().Append( (*dir)[i].iModified.DateTime().Day()+1);
+        iSendBuffer->Des().Append( (*dir)[i].iModified.DateTime().Hour());
+        iSendBuffer->Des().Append( (*dir)[i].iModified.DateTime().Minute());
+        iSendBuffer->Des().Append( (*dir)[i].iModified.DateTime().Second());
+        iSendBuffer->Des().Append( (*dir)[i].IsHidden());
+        iSendBuffer->Des().Append( (*dir)[i].IsReadOnly());
+        iSendBuffer->Des().Append( (*dir)[i].IsSystem());
+        if((*dir)[i].IsDir() == EFalse)
+            {
+            TInt size = (*dir)[i].iSize;
+            iSendBuffer->Des().Append( (TUint8*)(&size), 4 );
+            }
+        }
+
+    err = iDispatcher->DispatchOutgoingMessage(iSendBuffer,
+                        KFtpServiceUid,
+                        EFalse,
+                        EHtiPriorityControl);
+
+    if (  err != KErrNone )
+        {
+        //wait for a memory
+        iState = EListBusy;
+        iDispatcher->AddMemoryObserver( this );
+        }
+    else
+        {
+        iSendBuffer = NULL;
+        }
+
+    CleanupStack::PopAndDestroy();//dir
+    HTI_LOG_FUNC_OUT("HandleListDetailL");
+    }
+
+void CHtiFtpServicePlugin::HandleDataMessageL( const TDesC8& aMessage )
+    {
+    switch ( iState )
+        {
+        case EStorWait:
+            {
+            iState = EStorBusy;
+            iCurrentOffset += aMessage.Size();
+
+            TInt anError = iFile.Write( aMessage );
+            if ( anError == KErrNone  )
+                {
+                HTI_LOG_FORMAT("received %d", iCurrentOffset);
+                if ( iCurrentOffset == iFileSize )
+                    {
+                    HTI_LOG_TEXT("receiving is over");
+                    //receiving is over
+                    TInt err = iFile.Flush();
+                    iFile.Close();
+                    iState = EIdle;
+                    if ( err != KErrNone )
+                        {
+                        //err
+                        HTI_LOG_TEXT("failed to close file");
+                        iFs.Delete(iFileName);
+                        SendErrorMsg( err, KErrDescrFailedCloseFile );
+                        }
+                    else
+                        {
+                        //if file should be copied to TCB
+                        //copy it to to TCB from temp location
+                        if ( IsFileTcb( iFileName ) )
+                            {
+                            HandleTcbCopyL( KTmpFileName, iFileName );
+                            }
+                        else
+                            {
+                            SetBURFakeState( EFalse );
+                            SendControlMsg( EFtpOK, KNullDesC8 );
+                            }
+                        }
+                    }
+                else
+                    {
+                    iState = EStorWait;
+                    }
+                }
+            else
+                {
+                HTI_LOG_FORMAT("error writing file %d", anError);
+                //abort operation and send err msg
+
+                iFile.Close();
+                iFs.Delete(iFileName);
+                iState = EIdle;
+                SendErrorMsg( anError, KErrDescrFailedWrite );
+                }
+            }
+            break;
+        default:
+            //do nothing
+            User::LeaveIfError( SendErrorMsg( KErrArgument,
+                                              KErrDescrInvalidDataMessage ) );
+            break;
+        }
+    }
+
+void CHtiFtpServicePlugin::HandleReceiveFileL()
+    {
+    HTI_LOG_FUNC_IN("HandleReceiveFileL");
+
+    // create file
+    TInt err = KErrNone;
+
+    //if file should be copied to TCB
+    //first copy it to temp location
+    if ( IsFileTcb( iFileName ) )
+        {
+        err = iFile.Replace( iFs, KTmpFileName, EFileWrite );
+        }
+        else
+        {
+        err = iFile.Replace(
+            iFs, iFileName, EFileWrite | EFileShareExclusive );
+        }
+
+    if ( err != KErrNone )
+        {
+        err = iFile.Replace(
+            iFs, iFileName, EFileWrite | EFileShareAny );
+        }
+
+    if ( err != KErrNone )
+        {
+        err = iFile.Replace(
+            iFs, iFileName, EFileWrite | EFileShareReadersOrWriters );
+        }
+
+    if ( err != KErrNone )
+        {
+        if ( SetBURFakeState( ETrue ) == KErrNone )
+            {
+            err = iFile.Replace(
+                iFs, iFileName, EFileWrite | EFileShareExclusive );
+            }
+        }
+
+    if ( err != KErrNone )
+        {
+        HTI_LOG_TEXT("failed create file");
+        SendErrorMsg( err, KErrDescrFailedCreateFile );
+        return;
+        }
+
+    //check that there is enough disk space
+    err = iFile.SetSize( iFileSize );
+    if ( err != KErrNone )
+        {
+        HTI_LOG_TEXT("not enough space");
+        SendErrorMsg( err, KErrDescrNoSpace );
+        iFile.Close();
+        iFs.Delete( iFileName );
+        return;
+        }
+
+    // init receiving byte counter
+    iCurrentOffset = 0;
+    iState = EStorWait;
+
+    //send ok and
+    User::LeaveIfError( SendControlMsg( EFtpOK, KNullDesC8 ) );
+    //...wait for data messages
+    HTI_LOG_FUNC_OUT("HandleReceiveFileL");
+    }
+
+void CHtiFtpServicePlugin::HandleSendFileL()
+    {
+    //open it
+    TInt err = iFile.Open( iFs, iFileName, EFileRead | EFileShareAny );
+
+    if ( err != KErrNone )
+        {
+        err = iFile.Open( iFs, iFileName, EFileRead | EFileShareReadersOnly );
+        }
+
+    if ( err != KErrNone )
+        {
+        err = iFile.Open( iFs, iFileName, EFileRead | EFileShareReadersOrWriters );
+        }
+
+    if ( err != KErrNone )
+        {
+        if ( SetBURFakeState( ETrue ) == KErrNone )
+            {
+            err = iFile.Open(
+                iFs, iFileName, EFileRead | EFileShareReadersOnly );
+            }
+        }
+
+    if ( err != KErrNone )
+        {
+        HTI_LOG_FORMAT("failed open file %d", err);
+        SendErrorMsg( err, KErrDescrFailedOpenFile );
+        return;
+        }
+
+    //send file size
+    err = iFile.Size( iFileSize );
+    if ( err != KErrNone )
+        {
+        HTI_LOG_TEXT("failed get filesize");
+        User::LeaveIfError( SendErrorMsg( err, KErrDescrFailedOpenFile ) );
+        }
+
+    TBuf8<KFileSizeMsgSize> fileSizeMsg;
+    fileSizeMsg.Append( (TUint8*)(&iFileSize), 4 );
+    User::LeaveIfError( SendControlMsg( EFtpFILESIZE, fileSizeMsg ) );
+
+    iCurrentOffset = 0;
+    //start sending
+    //always observe when sending
+    iDispatcher->AddMemoryObserver( this );
+
+    //create handler for following RFile::Write
+    delete iHandlerAO;
+    iHandlerAO = NULL;
+    iHandlerAO = new(ELeave) CFtpHandlerAO( this );
+
+    //start operation
+    ReadToBuffer();
+    }
+
+void CHtiFtpServicePlugin::ReadToBuffer()
+    {
+    HTI_LOG_FUNC_IN("ReadToBuffer");
+    //check that iHandlerAO valid
+    if ( iHandlerAO )
+        {
+        if ( !iHandlerAO->IsActive() )
+            {
+            //dispatch messages in the outgoing queue until run out of memory
+            TInt err;
+            //allocate memory and read from file
+            delete iSendBuffer;
+            iSendBuffer = NULL;
+
+            TRAP( err, iSendBuffer = HBufC8::NewL( iBufferSize ) );
+            if ( err == KErrNone )
+                {
+                HTI_LOG_TEXT("read file");
+                iState = ERetrBusy;
+                iSendBufferDes.Set( iSendBuffer->Des() );
+                iFile.Read( iSendBufferDes, iHandlerAO->iStatus  );
+                iHandlerAO->Start();
+                }
+            else
+                {
+                //go to idle state
+                HTI_LOG_TEXT("impossible to alloc mem");
+                iDispatcher->RemoveMemoryObserver( this );
+
+                delete iHandlerAO;
+                iHandlerAO = NULL;
+
+                iFile.Close();
+                iState = EIdle;
+                //try to send err message
+                SendErrorMsg( KErrNoMemory, KErrDescrNoMemory );
+                }
+            }
+        else
+            {
+            //error, ignore
+            HTI_LOG_TEXT("ERROR: Call ReadBuffer with active handler");
+            }
+        }
+    else
+        {
+        //error
+        HTI_LOG_TEXT("ERROR: Call ReadBuffer with no handler");
+        //go to idle
+        iState = EIdle;
+        }
+    HTI_LOG_FUNC_OUT("ReadToBuffer");
+    }
+
+void CHtiFtpServicePlugin::SendBuffer()
+    {
+    HTI_LOG_FUNC_IN("SendBuffer");
+    if ( iSendBuffer )
+        {
+        HTI_LOG_FORMAT("iCurrentOffset %d bytes", iCurrentOffset);
+        //send buffer
+        TInt err = iDispatcher->DispatchOutgoingMessage( iSendBuffer,
+                        KFtpServiceUid,
+                        EFalse,
+                        EHtiPriorityData);
+
+        if ( err == KErrNone )
+            {
+            HTI_LOG_TEXT("message was dispatched");
+            //message was dispatched
+            iSendBuffer = NULL;
+            //check do we have to continue
+            if ( iCurrentOffset >= iFileSize )
+                {
+                HTI_LOG_TEXT( "over sending" );
+
+                delete iHandlerAO;
+                iHandlerAO = NULL;
+
+                iFile.Close();
+                iState = EIdle;
+
+                iDispatcher->RemoveMemoryObserver( this );
+                SetBURFakeState( EFalse );
+                }
+            else
+                {
+                //read and send next package
+                ReadToBuffer();
+                }
+            }
+        else if ( err == KErrNoMemory )
+            {
+            //wait for memory
+            //observer should be active
+            iState = ERetrWait;
+            }
+        else if ( err != KErrNone )
+            {
+            HTI_LOG_FORMAT("error dispatching outgoing message %d", err );
+            //some err, abort operation
+            delete iSendBuffer;
+            iSendBuffer = NULL;
+
+            delete iHandlerAO;
+            iHandlerAO = NULL;
+
+            iFile.Close();
+
+            iState = EIdle;
+
+            iDispatcher->RemoveMemoryObserver( this );
+            SetBURFakeState( EFalse );
+            }
+        }
+    else
+        {
+        //really weird error, go to idle
+        HTI_LOG_TEXT("ERROR: SendBuffer with empty iSendBuffer");
+        iState = EIdle;
+        SetBURFakeState( EFalse );
+        }
+    HTI_LOG_FUNC_OUT("SendBuffer");
+    }
+
+void CHtiFtpServicePlugin::FtpComplete( TInt anError)
+    {
+    HTI_LOG_FUNC_IN("FtpComplete");
+    HTI_LOG_FORMAT("error %d", anError);
+
+    //NOTE: can't leave from here
+    switch ( iState )
+        {
+        case ERmdBusy:
+            {
+            //send OK message
+            if ( anError == KErrNone )
+                {
+                SendControlMsg( EFtpOK, KNullDesC8 );
+                }
+            else
+                {
+                SendErrorMsg( anError, KErrDescrFailedRmDir );
+                }
+            delete iHandlerAO;
+            iHandlerAO = NULL;
+
+            iState = EIdle;
+            }
+            break;
+        case EDeleBusy:
+            {
+            //send OK message
+            if ( anError == KErrNone )
+                {
+                SetBURFakeState( EFalse );
+                SendControlMsg( EFtpOK, KNullDesC8 );
+                }
+            else
+                {
+                if ( SetBURFakeState( ETrue ) != KErrNone )
+                    {
+                    // Force was not requested, not supported OR already tried.
+                    SendErrorMsg( anError, KErrDescrFailedDeleFile );
+                    }
+                else
+                    {
+                    // try delete again
+                    TRAPD( err, HandleDeleteL( iFileName ) );
+                    if ( err == KErrNone )
+                        {
+                        break;
+                        }
+                    else
+                        {
+                        SendErrorMsg( err, KErrDescrFailedDeleFile );
+                        }
+                    }
+                }
+            delete iHandlerAO;
+            iHandlerAO = NULL;
+
+            iState = EIdle;
+            }
+            break;
+        case ERenameBusy:
+            {
+            //send OK message
+            if ( anError == KErrNone )
+                {
+                SetBURFakeState( EFalse );
+                SendControlMsg( EFtpOK, KNullDesC8 );
+                }
+            else
+                {
+                SendErrorMsg( anError, KErrDescrFailedRenameFile );
+                }
+
+            delete iHandlerAO;
+            iHandlerAO = NULL;
+
+            iState = EIdle;
+            }
+            break;
+        case ECopyBusy:
+            {
+            //send OK message
+            if ( anError == KErrNone )
+                {
+                SetBURFakeState( EFalse );
+                SendControlMsg( EFtpOK, KNullDesC8 );
+                }
+            else
+                {
+                SendErrorMsg( anError, KErrDescrFailedCopyFile );
+                }
+
+            delete iHandlerAO;
+            iHandlerAO = NULL;
+
+            iState = EIdle;
+            }
+            break;
+        case EMoveBusy:
+            {
+            //send OK message
+            if ( anError == KErrNone )
+                {
+                SetBURFakeState( EFalse );
+                SendControlMsg( EFtpOK, KNullDesC8 );
+                }
+            else
+                {
+                SendErrorMsg( anError, KErrDescrFailedMoveFile );
+                }
+
+            delete iHandlerAO;
+            iHandlerAO = NULL;
+
+            iState = EIdle;
+            }
+            break;
+        case EMoveTcbBusy:
+            {
+            //send OK message
+            if ( anError == KErrNone )
+                {
+                SetBURFakeState( EFalse );
+                SendControlMsg( EFtpOK, KNullDesC8 );
+                }
+            else
+                {
+                SendErrorMsg( anError, KErrDescrFailedMoveFile );
+                }
+
+            delete iProcessLogonAO;
+            iProcessLogonAO = NULL;
+
+            iState = EIdle;
+            }
+            break;
+        case ERenameTcbBusy:
+            {
+            //send OK message
+            if ( anError == KErrNone )
+                {
+                SetBURFakeState( EFalse );
+                SendControlMsg( EFtpOK, KNullDesC8 );
+                }
+            else
+                {
+                SendErrorMsg( anError, KErrDescrFailedRenameFile );
+                }
+
+            delete iProcessLogonAO;
+            iProcessLogonAO = NULL;
+
+            iState = EIdle;
+            }
+            break;
+        case EDeleTcbBusy:
+            {
+            //send OK message
+            if ( anError == KErrNone )
+                {
+                SetBURFakeState( EFalse );
+                SendControlMsg( EFtpOK, KNullDesC8 );
+                }
+            else
+                {
+                if ( SetBURFakeState( ETrue ) != KErrNone )
+                    {
+                    // Force was not requested, not supported OR already tried.
+                    SendErrorMsg( anError, KErrDescrFailedDeleFile );
+                    }
+                else
+                    {
+                     // try delete again
+                    TRAPD( err, HandleTcbDeleteL( iFileName ) );
+                    if ( err == KErrNone )
+                        {
+                        break;
+                        }
+                    else
+                        {
+                        SendErrorMsg( err, KErrDescrFailedDeleFile );
+                        }
+                    }
+                }
+            delete iProcessLogonAO;
+            iProcessLogonAO = NULL;
+
+            iState = EIdle;
+            }
+            break;
+        case EMkdTcbBusy:
+            {
+            if ( anError == KErrNone || anError == KErrAlreadyExists )
+                {
+                SendControlMsg( EFtpOK, KNullDesC8);
+                }
+            else
+                {
+                SendErrorMsg( anError, KErrDescrFailedMkDir );
+                }
+            delete iProcessLogonAO;
+            iProcessLogonAO = NULL;
+
+            iState = EIdle;
+
+            }
+            break;
+        case ERmdTcbBusy:
+            {
+            if ( anError == KErrNone || anError == KErrAlreadyExists )
+                {
+                SendControlMsg( EFtpOK, KNullDesC8);
+                }
+            else
+                {
+                SendErrorMsg( anError, KErrDescrFailedRmDir );
+                }
+            delete iProcessLogonAO;
+            iProcessLogonAO = NULL;
+
+            iState = EIdle;
+
+            }
+            break;
+
+        case EStorBusy:
+            {
+            if ( anError == KErrNone  )
+                {
+                HTI_LOG_FORMAT("received %d", iCurrentOffset);
+                if ( iCurrentOffset == iFileSize )
+                    {
+                    HTI_LOG_TEXT("receiveing is over");
+                    //receiveing is over
+                    delete iHandlerAO;
+                    iHandlerAO = NULL;
+
+                    iState = EIdle;
+
+                    TInt err = iFile.Flush();
+                    iFile.Close();
+                    if ( err != KErrNone )
+                        {
+                        //err
+                        HTI_LOG_TEXT("failed to close file");
+                        iFs.Delete(iFileName);
+                        SendErrorMsg( err, KErrDescrFailedCloseFile );
+                        }
+                    else
+                        {
+                        //if file should be copied to TCB
+                        //copy it to to TCB from temp location
+                        if ( IsFileTcb( iFileName ) )
+                            {
+                            TRAP( err, HandleTcbCopyL(
+                                KTmpFileName, iFileName ) );
+                            if ( err != KErrNone )
+                                {
+                                SendErrorMsg( anError, KErrDescrFailedCopyTcb );
+                                iFs.Delete( KTmpFileName );
+                                delete iProcessLogonAO;
+                                iProcessLogonAO = NULL;
+                                iState = EIdle;
+                                }
+                            }
+                        else
+                            {
+                            SetBURFakeState( EFalse );
+                            SendControlMsg( EFtpOK, KNullDesC8 );
+                            }
+                        }
+                    }
+                else
+                    {
+                    iState = EStorWait;
+                    //busy state is over
+                    iDispatcher->Notify(KErrNone);
+                    }
+                }
+            else
+                {
+                HTI_LOG_FORMAT("error writing file %d", anError);
+                //abort operation and send err msg
+                delete iHandlerAO;
+                iHandlerAO = NULL;
+
+                iFile.Close();
+                iFs.Delete(iFileName);
+                iState = EIdle;
+                SendErrorMsg( anError, KErrDescrFailedWrite );
+                }
+            }
+            break;
+
+        case EStorTcbBusy:
+            {
+            if ( anError == KErrNone )
+                {
+                SetBURFakeState( EFalse );
+                SendControlMsg( EFtpOK, KNullDesC8 );
+                }
+            else
+                {
+                if ( SetBURFakeState( ETrue ) != KErrNone )
+                    {
+                    // Force was not requested, not supported OR already tried.
+                    HTI_LOG_FORMAT("error copy to tcb %d", anError);
+                    //abort operation and send err msg
+                    SendErrorMsg( anError, KErrDescrFailedCopyTcb );
+                    }
+                else
+                    {
+                    // try copy again
+                    TRAPD( err, HandleTcbCopyL( KTmpFileName, iFileName ) );
+                    if ( err == KErrNone )
+                        {
+                        break;
+                        // don't continue, this method will be called again
+                        // by the AO after copying is tried
+                        }
+                    else
+                        {
+                        SendErrorMsg( err, KErrDescrFailedCopyTcb );
+                        }
+                    }
+                }
+
+            //delete temp file
+            HTI_LOG_TEXT("delete tmp file");
+            TInt err = iFs.Delete(KTmpFileName);
+            if ( err != KErrNone )
+                {
+                HTI_LOG_FORMAT("error delete tmp file %d", err);
+                }
+
+            delete iProcessLogonAO;
+            iProcessLogonAO = NULL;
+            iState = EIdle;
+            }
+            break;
+
+        case ERetrBusy:
+            {
+            if ( anError == KErrNone )
+                {
+                HTI_LOG_FORMAT("read %d bytes", iSendBuffer->Size());
+                iCurrentOffset += iSendBuffer->Size();
+
+                SendBuffer();
+                }
+            else
+                {
+                HTI_LOG_FORMAT("failed read file %d", anError);
+                //error reading file
+                //abort operation and send err msg
+                delete iSendBuffer;
+                iSendBuffer = NULL;
+
+                delete iHandlerAO;
+                iHandlerAO = NULL;
+
+                iFile.Close();
+
+                iState = EIdle;
+                iDispatcher->RemoveMemoryObserver( this );
+
+                SendErrorMsg( anError, KErrDescrFailedRead );
+                }
+            }
+            break;
+        default:
+            {
+            //some error, should not be called
+            HTI_LOG_TEXT("invalid state for FtpComplete");
+            }
+        }
+    HTI_LOG_FUNC_OUT("FtpComplete");
+    }
+
+void CHtiFtpServicePlugin::NotifyMemoryChange( TInt aAvailableMemory )
+    {
+    HTI_LOG_FUNC_IN("NotifyMemoryChange");
+    switch ( iState )
+        {
+        case ERetrWait:
+            {
+            if ( iSendBuffer )
+                {
+                if ( aAvailableMemory >= iSendBuffer->Size() )
+                    {
+                    //continue sending
+                    SendBuffer();
+                    }
+                }
+            else
+                {//impossible
+                //nothing to send
+                //just reset
+                HTI_LOG_TEXT("invalid state for mem");
+
+                delete iHandlerAO;
+                iHandlerAO = NULL;
+                iFile.Close();
+                iDispatcher->RemoveMemoryObserver(this);
+                iState = EIdle;
+                }
+            }
+            break;
+        case EListBusy:
+            {
+            if ( iSendBuffer )
+                {
+                if ( aAvailableMemory >= iSendBuffer->Size() )
+                    {
+                    //send buffer
+                    TInt err = iDispatcher->DispatchOutgoingMessage(
+                                    iSendBuffer,
+                                    KFtpServiceUid,
+                                    EFalse,
+                                    EHtiPriorityData);
+                    if ( err != KErrNone )
+                        {
+                        //error, reset
+                        HTI_LOG_TEXT("failed to send LIST");
+                        delete iSendBuffer;
+                        }
+                    iSendBuffer = NULL;
+                    iDispatcher->RemoveMemoryObserver(this);
+                    iState = EIdle;
+                    }
+                }
+            else
+                {//impossible
+                //nothing to send
+                //just reset
+                HTI_LOG_TEXT("invalid state for mem");
+                iDispatcher->RemoveMemoryObserver(this);
+                iState = EIdle;
+                }
+            }
+            break;
+        default:
+            //some error, should not be called
+            HTI_LOG_TEXT("invalid state for mem");
+            //iDispatcher->RemoveMemoryObserver(this);
+            //iState = EIdle;
+        }
+    HTI_LOG_FUNC_OUT("NotifyMemoryChange");
+    }
+
+TBool CHtiFtpServicePlugin::IsFileTcb( const TDesC& aFilename )
+    {
+    return aFilename.FindF( KHtiTcbSys ) == KPathOffset ||
+           aFilename.FindF( KHtiTcbResource ) == KPathOffset;
+    }
+
+void CHtiFtpServicePlugin::HandleTcbDeleteL( const TDesC& aFilename )
+    {
+    HTI_LOG_FUNC_IN("HandleTcbDeleteL");
+    HBufC* cmdLine = HBufC::NewLC( aFilename.Length() + 2 );
+
+    //make command line "d|filename"
+    cmdLine->Des().Copy( KHtiFileHlpDeleteCmd );
+    cmdLine->Des().Append( KHtiFileHlpDelim );
+    cmdLine->Des().Append( aFilename );
+
+    HTI_LOG_DES( *cmdLine );
+
+    delete iProcessLogonAO;
+    iProcessLogonAO = NULL;
+
+    iProcessLogonAO = new(ELeave) CProcessLogonAO( this );
+    iProcessLogonAO->Start( *cmdLine );
+
+    iState = EDeleTcbBusy;
+
+    CleanupStack::PopAndDestroy( cmdLine );
+    HTI_LOG_FUNC_OUT("HandleTcbDeleteL");
+    }
+
+void CHtiFtpServicePlugin::HandleTcbCopyL( const TDesC& aFromFilename,
+                                           const TDesC& aToFilename )
+    {
+    HTI_LOG_FUNC_IN("HandleTcbCopyL");
+    HBufC* cmdLine = HBufC::NewLC( aFromFilename.Length() + aToFilename.Length() + 3 );
+
+    //make command line "c|fromfilename|tofilename"
+    cmdLine->Des().Copy( KHtiFileHlpCopyCmd );
+    cmdLine->Des().Append( KHtiFileHlpDelim );
+    cmdLine->Des().Append( aFromFilename );
+    cmdLine->Des().Append( KHtiFileHlpDelim );
+    cmdLine->Des().Append( aToFilename );
+
+    HTI_LOG_DES( *cmdLine );
+
+    delete iProcessLogonAO;
+    iProcessLogonAO = NULL;
+
+    iProcessLogonAO = new(ELeave) CProcessLogonAO( this );
+    iProcessLogonAO->Start( *cmdLine );
+
+    iState = EStorTcbBusy;
+
+    CleanupStack::PopAndDestroy( cmdLine );
+    HTI_LOG_FUNC_OUT("HandleTcbCopyL");
+    }
+
+void CHtiFtpServicePlugin::HandleTcbMkdL( const TDesC& aDirname )
+    {
+    HTI_LOG_FUNC_IN("HandleTcbMkdL");
+    HBufC* cmdLine = HBufC::NewLC( aDirname.Length() + 2 );
+
+    //make command line "m|dirname"
+    cmdLine->Des().Copy( KHtiFileHlpMkdCmd );
+    cmdLine->Des().Append( KHtiFileHlpDelim );
+    cmdLine->Des().Append( aDirname );
+
+    HTI_LOG_DES( *cmdLine );
+
+    delete iProcessLogonAO;
+    iProcessLogonAO = NULL;
+
+    iProcessLogonAO = new(ELeave) CProcessLogonAO( this );
+    iProcessLogonAO->Start(*cmdLine);
+
+    iState = EMkdTcbBusy;
+
+    CleanupStack::PopAndDestroy(cmdLine);
+    HTI_LOG_FUNC_OUT("HandleTcbMkdL");
+    }
+
+void CHtiFtpServicePlugin::HandleTcbRmdL( const TDesC& aDirname )
+    {
+    HTI_LOG_FUNC_IN("HandleTcbRmdL");
+    HBufC* cmdLine = HBufC::NewLC( aDirname.Length() + 2 );
+
+    //make command line "r|dirname"
+    cmdLine->Des().Copy( KHtiFileHlpRmdCmd );
+    cmdLine->Des().Append( KHtiFileHlpDelim );
+    cmdLine->Des().Append( aDirname );
+
+    HTI_LOG_DES( *cmdLine );
+
+    delete iProcessLogonAO;
+    iProcessLogonAO = NULL;
+
+    iProcessLogonAO = new ( ELeave ) CProcessLogonAO( this );
+    iProcessLogonAO->Start( *cmdLine );
+
+    iState = ERmdTcbBusy;
+
+    CleanupStack::PopAndDestroy( cmdLine );
+    HTI_LOG_FUNC_OUT("HandleTcbRmdL");
+    }
+
+void CHtiFtpServicePlugin::HandleTcbRenameL(
+        const TDesC& aTargetName, const TDesC& aDestName )
+    {
+    HTI_LOG_FUNC_IN("HandleTcbRenameL");
+    HBufC* cmdLine = HBufC::NewLC( aTargetName.Length() + 4 + aDestName.Length());
+
+    //make command line "r|dirname"
+    cmdLine->Des().Copy( KHtiFileHlpRenameCmd );
+    cmdLine->Des().Append( KHtiFileHlpDelim );
+    cmdLine->Des().Append( aTargetName );
+    cmdLine->Des().Append( KHtiFileHlpDelim );
+    cmdLine->Des().Append( aDestName );
+
+    HTI_LOG_DES( *cmdLine );
+
+    delete iProcessLogonAO;
+    iProcessLogonAO = NULL;
+
+    iProcessLogonAO = new ( ELeave ) CProcessLogonAO( this );
+    iProcessLogonAO->Start( *cmdLine );
+
+    iState = ERenameTcbBusy;
+
+    CleanupStack::PopAndDestroy( cmdLine );
+    HTI_LOG_FUNC_OUT("HandleTcbRenameL");
+    }
+
+void CHtiFtpServicePlugin::HandleTcbMoveL(
+        const TDesC& aTargetName, const TDesC& aDestName )
+    {
+    HTI_LOG_FUNC_IN("HandleTcbRenameL");
+    HBufC* cmdLine = HBufC::NewLC( aTargetName.Length() + 4 + aDestName.Length());
+
+    //make command line "r|dirname"
+    cmdLine->Des().Copy( KHtiFileHlpMoveCmd );
+    cmdLine->Des().Append( KHtiFileHlpDelim );
+    cmdLine->Des().Append( aTargetName );
+    cmdLine->Des().Append( KHtiFileHlpDelim );
+    cmdLine->Des().Append( aDestName );
+
+    HTI_LOG_DES( *cmdLine );
+
+    delete iProcessLogonAO;
+    iProcessLogonAO = NULL;
+
+    iProcessLogonAO = new ( ELeave ) CProcessLogonAO( this );
+    iProcessLogonAO->Start( *cmdLine );
+
+    iState = EMoveTcbBusy;
+
+    CleanupStack::PopAndDestroy( cmdLine );
+    HTI_LOG_FUNC_OUT("HandleTcbRenameL");
+    }
+
+TInt CHtiFtpServicePlugin::SetBURFakeState( TBool aOn )
+    {
+    HTI_LOG_FUNC_IN( "CHtiFtpServicePlugin::SetBURFakeStateL" );
+    TInt err = KErrNone;
+
+    if ( iBackupFake == NULL )
+        {
+        // Foreced operations not requested or not supported
+        err = KErrNotSupported;
+        }
+
+    else if ( aOn )
+        {
+        HTI_LOG_TEXT( "Calling ActivateBackup()" );
+        err = iBackupFake->ActivateBackup();
+        }
+
+    else
+        {
+        HTI_LOG_TEXT( "Calling DeactivateBackup()" );
+        err = iBackupFake->DeactivateBackup();
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiFtpServicePlugin::SetBURFakeStateL" );
+    return err;
+    }
+
+void CHtiFtpServicePlugin::HandleCheckSumCalcL( TAlgorithm aAlgorithm,
+                                                const TDesC& aFilename )
+    {
+    HTI_LOG_FUNC_IN( "CHtiFtpServicePlugin::HandleCheckSumCalcL" );
+
+    RFile file;
+    TInt err = file.Open( iFs, aFilename, EFileRead | EFileShareReadersOnly );
+    if ( err )
+        {
+        HTI_LOG_FORMAT( "Error opening file, err: %d", err );
+        SendErrorMsg( err, KErrDescrFailedOpenFile );
+        return;
+        }
+
+    CleanupClosePushL( file );
+    switch ( aAlgorithm )
+        {
+        case EMD5:
+            {
+            HTI_LOG_TEXT( "Using MD5 algorithm" );
+            const TInt KBufSize( 1024 );
+            TInt size = 0;
+            TInt offset = 0;
+
+            file.Size( size );
+
+            HBufC8* buf = HBufC8::NewMaxLC( KBufSize );
+            TPtr8 filePtr( buf->Des() );
+
+            CMD5* md5 = CMD5::NewL();
+            CleanupStack::PushL( md5 );
+
+            while ( offset < size - KBufSize )
+                {
+                User::LeaveIfError( file.Read( filePtr, KBufSize ) );
+                md5->Hash( filePtr );
+                offset += filePtr.Length();
+                }
+
+            file.Read( filePtr, size - offset );
+            filePtr.SetLength( size - offset );
+            md5->Hash( filePtr );
+
+            filePtr.Set( NULL, 0, 0 );
+            HBufC8* result = md5->Hash( filePtr ).AllocL();
+            CleanupStack::PushL( result );
+
+            HTI_LOG_TEXT( "Got following MD5:" );
+            HTI_LOG_DES( *result );
+
+            User::LeaveIfError(
+                iDispatcher->DispatchOutgoingMessage( result,
+                                                      KFtpServiceUid,
+                                                      EFalse,
+                                                      EHtiPriorityControl ) );
+            CleanupStack::Pop( result ); // do not delete, ownership transfered
+            CleanupStack::PopAndDestroy( 2 ); // md5, buf
+            break;
+            }
+
+        default:
+            {
+            HTI_LOG_FORMAT( "Invalid algorithm: %d", aAlgorithm );
+            SendErrorMsg( KErrNotFound, KErrDescrInvalidChecksumArgs );
+            break;
+            }
+        }
+    CleanupStack::PopAndDestroy(); // file
+
+    HTI_LOG_FUNC_OUT( "CHtiFtpServicePlugin::HandleCheckSumCalcL" );
+    }
+
+void CHtiFtpServicePlugin::HandleFormat( const TUint8 aDrive, const TUint8 aMode )
+    {
+    HTI_LOG_FUNC_IN( "CHtiFtpServicePlugin::HandleFormat" );
+
+    // Convert the format mode: in HTI protocol 0 means full format and 1
+    // (or anything else currently) means quick format
+    TUint formatMode = 0;
+    if ( aMode )
+        formatMode = ESpecialFormat | EQuickFormat;
+    else
+        formatMode = ESpecialFormat | EFullFormat;
+
+    // Create the drive name (drive letter and colon)
+    TDriveName drive;
+    drive.Append( aDrive );
+    drive.Append( _L( ":" ) );
+
+    // Check that HTI is not running from the drive that is to be formatted
+    RProcess thisProcess;
+    if ( thisProcess.FileName().FindF( drive ) == 0 )
+        {
+        HTI_LOG_FORMAT( "HTI running from drive %S cannot format", &drive );
+        SendErrorMsg( KErrInUse, KErrDescrFailedFormat );
+        HTI_LOG_FUNC_OUT( "CHtiFtpServicePlugin::HandleFormat" );
+        return;
+        }
+
+    // Activate backup/restore to close apps that might have files open.
+    // Ignore errors - try to format even if backup fake is not supported.
+    SetBURFakeState( ETrue );
+
+    // Start the format
+    HTI_LOG_FORMAT( "Starting to format drive %S", &drive );
+    HTI_LOG_FORMAT( "Format mode = %d", formatMode );
+    TInt remainingTracks = 0;
+    RFormat format;
+    TInt err = format.Open( iFs, drive, formatMode, remainingTracks );
+    if ( err == KErrNone )
+        {
+        HTI_LOG_FORMAT( "Formatting %d tracks", remainingTracks );
+        while ( remainingTracks && err == KErrNone )
+            {
+            err = format.Next( remainingTracks );
+            HTI_LOG_FORMAT( "Tracks remaining: %d", remainingTracks );
+            }
+        }
+    format.Close();
+
+    // Deactivate backup/restore - errors ignored.
+    SetBURFakeState( EFalse );
+
+    if ( err == KErrNone )
+        {
+        SendControlMsg( EFtpOK, KNullDesC8 );
+        }
+
+    else
+        {
+        SendErrorMsg( err, KErrDescrFailedFormat );
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiFtpServicePlugin::HandleFormat" );
+    }
+
+void CHtiFtpServicePlugin::HandleListDrivesL( TBool aUnicode )
+    {
+    HTI_LOG_FUNC_IN( "CHtiFtpServicePlugin::HandleListDrivesL" );
+    TInt driveCount = 0;
+    TDriveList driveList;
+
+    User::LeaveIfError( iFs.DriveList( driveList, KDriveAttAll ) );
+
+    // Buffer for the drive list that is returned
+    CBufFlat* driveListBuf = CBufFlat::NewL( 256 );
+    CleanupStack::PushL( driveListBuf );
+    TInt bufPos = 0;
+
+    for ( TInt i = 0; i < KMaxDrives; i++ )
+        {
+        if ( driveList[i] )
+            {
+            HTI_LOG_FORMAT( "Found drive number %d", i );
+            TVolumeInfo volInfo;
+            if ( iFs.Volume( volInfo, i ) == KErrNone )
+                {
+                driveCount++;
+                // root path with length byte
+                TChar driveLetter;
+                iFs.DriveToChar( i, driveLetter );
+                HTI_LOG_FORMAT( "Got volume info for drive %c",
+                        TUint( driveLetter ) );
+                TBuf<3> rootPathBuf;
+                rootPathBuf.AppendFormat( KRootPathFormat,
+                        TUint( driveLetter ) );
+                TBuf8<1> lengthBuf;
+                lengthBuf.Append( rootPathBuf.Length() );
+                TBuf8<6> rootPathBuf8;
+                if ( aUnicode )
+                    {
+                    rootPathBuf8.Append( ( TUint8* ) rootPathBuf.Ptr(),
+                            rootPathBuf.Length() * 2 );
+                    }
+                else
+                    {
+                    rootPathBuf8.Copy( rootPathBuf );
+                    }
+                driveListBuf->ExpandL( bufPos, rootPathBuf8.Length() + 1 );
+                driveListBuf->Write( bufPos, lengthBuf, 1 );
+                bufPos++;
+                driveListBuf->Write( bufPos, rootPathBuf8 );
+                bufPos += rootPathBuf8.Length();
+
+                // media type 1 byte
+                TBuf8<8> tmpBuf;
+                tmpBuf.Append( volInfo.iDrive.iType );
+                driveListBuf->ExpandL( bufPos, tmpBuf.Length() );
+                driveListBuf->Write( bufPos, tmpBuf );
+                bufPos += tmpBuf.Length();
+
+                // UID 4 bytes
+                tmpBuf.Copy( ( TUint8* ) ( &volInfo.iUniqueID ), 4 );
+                driveListBuf->ExpandL( bufPos, tmpBuf.Length() );
+                driveListBuf->Write( bufPos, tmpBuf );
+                bufPos += tmpBuf.Length();
+
+                // size 8 bytes
+                tmpBuf.Copy( ( TUint8* ) ( &volInfo.iSize ), 8 );
+                driveListBuf->ExpandL( bufPos, tmpBuf.Length() );
+                driveListBuf->Write( bufPos, tmpBuf );
+                bufPos += tmpBuf.Length();
+
+                // free space 8 bytes
+                tmpBuf.Copy( ( TUint8* ) ( &volInfo.iFree ), 8 );
+                driveListBuf->ExpandL( bufPos, tmpBuf.Length() );
+                driveListBuf->Write( bufPos, tmpBuf );
+                bufPos += tmpBuf.Length();
+
+                // name with length byte
+                HBufC8* driveNameBuf8 = NULL;
+                TInt driveNameLength = volInfo.iName.Length();
+                lengthBuf.Zero();
+                lengthBuf.Append( driveNameLength );
+                driveListBuf->ExpandL( bufPos, 1 );
+                driveListBuf->Write( bufPos, lengthBuf, 1 );
+                bufPos++;
+                if ( driveNameLength > 0 )
+                    {
+                    if ( aUnicode )
+                        {
+                        driveNameBuf8 = HBufC8::NewL( driveNameLength * 2 );
+                        driveNameBuf8->Des().Append(
+                                ( TUint8* ) volInfo.iName.Ptr(),
+                                driveNameLength * 2 );
+                        }
+                    else
+                        {
+                        driveNameBuf8 = HBufC8::NewL( driveNameLength );
+                        driveNameBuf8->Des().Append( volInfo.iName );
+                        }
+                    HTI_LOG_FORMAT( "Drive name: %S", &volInfo.iName );
+                    driveListBuf->ExpandL( bufPos, driveNameBuf8->Length() );
+                    driveListBuf->Write( bufPos, driveNameBuf8->Ptr(),
+                        driveNameBuf8->Length() );
+                    bufPos += driveNameBuf8->Length();
+                    delete driveNameBuf8;
+                    driveNameBuf8 = NULL;
+                    }
+                }
+            }
+        }
+
+    // All drives added - write number of drives to the beginning of buffer
+    TBuf8<1> countBuf;
+    countBuf.Append( ( TUint8* ) ( &driveCount ), 1 );
+    driveListBuf->InsertL( 0, countBuf, 1 );
+
+    // Make a copy of the buffer to iSendBuffer
+    delete iSendBuffer;
+    iSendBuffer = NULL;
+    iSendBuffer = driveListBuf->Ptr( 0 ).AllocL();
+    CleanupStack::PopAndDestroy(); // driveListBuf
+
+    // ...and send it away
+    TInt err = iDispatcher->DispatchOutgoingMessage(
+        iSendBuffer, KFtpServiceUid, EFalse, EHtiPriorityControl );
+
+    if (  err != KErrNone )
+        {
+        //wait for memory
+        iState = EListBusy;
+        iDispatcher->AddMemoryObserver( this );
+        }
+    else
+        {
+        iSendBuffer = NULL; // ownership transferred
+        }
+
+    HTI_LOG_FUNC_OUT( "CHtiFtpServicePlugin::HandleListDrivesL" );
+    }
+
+
+// End of File