/***************************************************************************
                          msnftpconnection.cpp -  description
                             -------------------
    begin                : Tue 06 30 2005
    copyright            : (C) 2003 by Mike K. Bennett
                           (C) 2005 by Diederik van der Boor
    email                : mkb137b@hotmail.com
                           vdboor --at-- codingdomain.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "msnftpconnection.h"

#include "../kmessdebug.h"
#include "../currentaccount.h"

#include <qtimer.h>
#include <qiodevice.h>
#include <qfile.h>
#include <qstringlist.h>

#include <kdebug.h>
#include <kextsock.h>
#include <ksockaddr.h>
#include <klocale.h>

#ifdef KMESSDEBUG_MSNFTP
  #define KMESSDEBUG_MSNFTP_GENERAL
  // enabling KMESSDEBUG_MSNFTP_RECEIVING makes file transfer slow and inresponsive.
  #define KMESSDEBUG_MSNFTP_RECEIVING
#endif


// The constructor
MsnFtpConnection::MsnFtpConnection()
  : QObject(0, "MsnFtpConnection")
  , fileBytesRemaining_(0)
  , fileSize_(0)
  , inputStream_(0)
  , mode_(WAIT)
  , outputStream_(0)
  , server_(0)
  , serverPort_(-1)
  , socket_(0)
  , remainingBlockBytes_(0)
  , userCancelled_(false)
{

}



// The destructor
MsnFtpConnection::~MsnFtpConnection()
{
  // Close and clean up
  if(socket_ != 0 || server_ != 0)
  {
    closeConnection();
  }

#ifdef KMESSDEBUG_MSNFTP_GENERAL
  kdDebug() << "DESTROYED MsnFtpConnection" << endl;
#endif
}



// Cancel the transfer
void MsnFtpConnection::cancelTransfer(bool userCancelled)
{
#ifdef KMESSDEBUG_MSNFTP_GENERAL
  kdDebug() << "MsnFtpConnection::cancelTransfer - Cancelling." << endl;
#endif
#ifdef KMESSTEST
  ASSERT( isConnected() );
#endif

  userCancelled_ = userCancelled;

  if(mode_ == SEND_DATA)
  {
    // Fail the transfer
    mode_ = SEND_CANCEL;
  }
  else if(mode_ == RECEIVE_DATA)
  {
    mode_ = SEND_CCL;
  }
  else
  {
    mode_ = SEND_CCL;
  }
}



// Close the connection
void MsnFtpConnection::closeConnection()
{
#ifdef KMESSDEBUG_MSNFTP_GENERAL
  kdDebug() << "MsnFtpConnection - closing sockets" << endl;
#endif

  // Reset the current mode
  mode_ = WAIT;

  // Close and delete the socket
  if( socket_ != 0 )
  {
    socket_->flush();
    socket_->closeNow();
    delete socket_;
    socket_ = 0;
  }

  // Delete the server.
  if( server_ != 0 )
  {
    server_->closeNow();
    delete server_;
    server_ = 0;
  }
}



// Emit a cancel message
void MsnFtpConnection::emitCancelStatusMessage(bool contactCancelled)
{
#ifdef KMESSTEST
  // Assume that this is only used from slotWriteMessage()
  ASSERT( contactCancelled || mode_ == SEND_CANCEL || mode_ == SEND_CCL );
#endif

  if(userCancelled_)
  {
    // The user pressed the cancel button
    emit statusMessage( i18n("The transfer of %1 was cancelled."),         STATUS_CHAT_FAILED   );
    emit statusMessage( i18n("File transfer dialog message", "Cancelled"), STATUS_DIALOG_FAILED );
  }
  else if(contactCancelled)
  {
    // The contact pressed the cancel button
    // TODO: replace this with "The contact cancelled the filetransfer" with KMess 1.5
    emit statusMessage( i18n("The contact cancelled the session."), STATUS_CHAT_FAILED );
    emit statusMessage( i18n("The contact cancelled the session."), STATUS_DIALOG_FAILED );
  }
  else
  {
    // This class sent the "CCL" message in a response, because the contact sent bad data.
    emit statusMessage( i18n("The file transfer invitation was cancelled.  Bad data was received."), STATUS_CHAT_FAILED );
    emit statusMessage( i18n("File transfer dialog message", "Failed"),                              STATUS_DIALOG_FAILED );
  }
}



// Get the server port that will be used
int MsnFtpConnection::getLocalServerPort()
{
  if( serverPort_ < 0 )
  {
    // Get an available port

    // TODO: This is a bad default to return.
    // and it is no longer required, we could use a random port nowadays.
    // The old clients that had the "only port 6891" bug are no longer in use.
    serverPort_ = 6891;
  }

  return serverPort_;
}



// Return true if a connection is active
bool MsnFtpConnection::isConnected() const
{
  return (socket_ != 0 && socket_->socketStatus() == KExtendedSocket::connected);
}



// Connect to a host
bool MsnFtpConnection::openConnection(const QString &ipAddress, int port)
{
#ifdef KMESSDEBUG_MSNFTP_GENERAL
  kdDebug() << "MsnFtpConnection::openConnection - Connecting to " << ipAddress << " port " << port << "." << endl;
#endif

  // Configure the socket for asynchronous operation
  socket_ = new KExtendedSocket(ipAddress, port, KExtendedSocket::bufferedSocket );
  socket_->enableRead(true);
  socket_->enableWrite(true);
  socket_->setTimeout(10);
  connect( socket_, SIGNAL( readyRead()           ), this, SLOT( slotDataReceived()    ));
  connect( socket_, SIGNAL( readyWrite()          ), this, SLOT( slotWriteCommand()    ));
  connect( socket_, SIGNAL( connectionFailed(int) ), this, SLOT( slotSocketError(int)  ));

  // Connect the socket
  if(socket_->connect() != 0)
  {
    kdDebug() << "MsnFtpConnection::openConnection - WARNING - Couldn't connect new socket" << endl;
    return false;
  }

#ifdef KMESSDEBUG_MSNFTP_GENERAL
  kdDebug() << "MsnFtpConnection::openConnection - Connected with host" << endl;
#endif

  return true;
}



// Wait for an incoming connection
bool MsnFtpConnection::openServerPort()
{
#ifdef KMESSDEBUG_MSNFTP_GENERAL
  kdDebug() << "MsnFtpConnection::openServerPort - Creating server socket." << endl;
#endif
#ifdef KMESSTEST
  ASSERT( server_ == 0 );
#endif

  int  port;
  bool portSuccess;
  int  listenResult;

  // Create the server socket to the given port.
  server_ = new KExtendedSocket();
  server_->setSocketFlags( KExtendedSocket::noResolve | KExtendedSocket::passiveSocket );

  // Set the port
  port        = getLocalServerPort();
  portSuccess = server_->setPort(port);
  if(! portSuccess )
  {
    kdDebug() << "MsnFtpConnection - WARNING - Could not use port " << port << "." << endl;
    return false;
  }


  // Connect the server to signal when it is ready to accept a connection
  connect( server_, SIGNAL( readyAccept()          ),
           this,    SLOT  ( slotAcceptConnection() ) );


  // Put the socket in listen mode.
  listenResult = server_->listen(1);  // Refuse parallel connections
  if(listenResult != 0)
  {
    kdDebug() << "MsnFtpConnection - WARNING - Could not listen at port " << port << "." << endl;
    return false;
  }

  // The code continues with slotAcceptConnection()
  return true;
}



// Parse a command received from the contact
void MsnFtpConnection::parseCommand(const QStringList &command)
{
  if(command[0] == "VER")
  {
    if(mode_ == WAIT_VER)
    {
      // Server: Send version confirmation
      mode_ = SEND_VER2;
    }
    else
    {
      // Client: Got version confirmation
      mode_ = SEND_USR;
    }
  }
  else if(command[0] == "FIL")
  {
    // Client: Get file size
    fileSize_           = command[1].toULong();
    fileBytesRemaining_ = fileSize_;
    mode_               = SEND_TFR;
#ifdef KMESSDEBUG_MSNFTP_GENERAL
    kdDebug() << "MsnFtpConnection: There are " << fileBytesRemaining_ << " bytes to be received." << endl;
#endif
  }
  else if(command[0] == "USR")
  {
    // Server: Accept user login
    if(// command[1] == authHandle_ &&  // TODO: send the correct handle to MimeApplication classes (msnswitchboardconnection problem)
       command[2] == authCookie_)
    {
      // Send file size with next write
      mode_ = SEND_FIL;

      // We also know we have a good connection now.
      // Close the server so we can re-use the port later again.
      // (or we should keep it open all the time, and assign sockets to the correct msnftpconnection)
      if(server_ != 0)
      {
        server_->closeNow();
        delete server_;
        server_ = 0;
      }
    }
    else
    {
      kdDebug() << "MsnFtpConnection - WARNING - user authorisation was incorrect." << endl;
#ifdef KMESSDEBUG_MSNFTP_GENERAL
      kdDebug() << "MsnFtpConnection: expected " << authHandle_ << "/" << authCookie_
                                      << " got " << command[1]  << "/" << command[2] << "." << endl;
#endif
      cancelTransfer(false);
      // TODO: test it
    }
  }
  else if(command[0] == "TFR")
  {
    // Server: Initiate transfer
    if(mode_ == WAIT_TFR)
    {
      // Client was authorized,
      // WAIT_TFR is set set after SEND_FIL
      mode_ = SEND_DATA;

      // Update status
      emit statusMessage( i18n("Sending file %1"), STATUS_DIALOG );
    }
    else
    {
      // Never passed authorisation test
      kdDebug() << "MsnFtpConnection - WARNING - user authorisation was skipped by contact." << endl;
      cancelTransfer(false);
      // TODO: test it
    }
  }
  else if(command[0] == "BYE")
  {
    // Server: Got BYE from client
    closeConnection();
    emit transferComplete();
  }
  else if(command[0] == "CCL")
  {
    // Client/server: Got cancel from contact
    emitCancelStatusMessage(true);  // contact cancelled
    closeConnection();
    emit transferFailed();
  }
  else
  {
    kdDebug() << "File transfer got unhandled command " << command[0] << "." << endl;
    // Cancel, session is of no use now.
    cancelTransfer(false);
  }
}



// Handle the received file data
void MsnFtpConnection::parseReceivedFileData()
{
#ifdef KMESSTEST
  ASSERT( outputStream_ != 0);
  ASSERT( socket_       != 0);
#endif

  // After we give the TFR signal, the contact (server) sends all file data
  // Each data block has a 3-byte header, and could be received in fragments

  char          rawBlock[2050];
  unsigned char code;
  unsigned char byte1;
  unsigned char byte2;
  int           blockSize;
  int           noBytesRead;


  // Make sure we read all available bytes from the socket before returning
  do   // while(bytesAvailable > 0)
  {
    // If no block was started
    if(remainingBlockBytes_ <= 0)
    {
      // Start with a new data block

      code  = socket_->getch();  // First byte: 0=data, 1=control
      byte1 = socket_->getch();  // Next two bytes contain
      byte2 = socket_->getch();  // the data size

      if(code == 0)
      {
        // A data block was received

        // Merge the two bytes as integer
        // This is the block-size to expect
        remainingBlockBytes_ = (byte1 | byte2 << 8);

#ifdef KMESSDEBUG_MSNFTP_RECEIVING
        kdDebug() << "MsnFtpConnection::slotDataReceived - Receiving new block, size = " << remainingBlockBytes_ << "."
                  << "  socket bytes available: " << socket_->bytesAvailable() << "." << endl;
#endif
      }
      else if(code == 1)
      {
        // A control block was received
        if( byte1 == 0 && byte2 == 0 )
        {
          // The transfer was terminated by the sender.
          // TODO: better messages for KMess 1.5 (like "aborted by receiver" for the dialog, "the contact aborted the file transfer")
          emitCancelStatusMessage(true);
          mode_ = SEND_BYE;  // emits transferFailed()
          return;
        }
      }
      else
      {
        // Contact did not sent a valid block
        // At this point, the official client displays "corrupt file received".
        cancelTransfer(false);
        emit transferFailed();
        return;
      }
    }

    // If there is a block waiting
    if(remainingBlockBytes_ > 0)
    {
      // Determine max size to read (avoid buffer overflows!)
      blockSize = remainingBlockBytes_;
      if(blockSize > ((int) sizeof(rawBlock))) blockSize = sizeof(rawBlock);

      // Read the data block (usually 2045 bytes)
      noBytesRead = socket_->readBlock( rawBlock, blockSize );

      if(noBytesRead <= 0)
      {
#ifdef KMESSDEBUG_MSNFTP_GENERAL
        kdDebug() << "MsnFtpConnection::slotDataReceived - WARNING -"
                  << " Got read error " << noBytesRead
                  << " block size was " << blockSize  << endl;
#endif
        // Socket error, exit
//        cancelTransfer(false);
        return;
      }
      else
      {
        // Update the progress dialog
        fileBytesRemaining_  -= noBytesRead;
        remainingBlockBytes_ -= noBytesRead;
        emit transferProgess(fileSize_ - fileBytesRemaining_);

        // Add data to file
        outputStream_->writeBlock( rawBlock, noBytesRead );

#ifdef KMESSDEBUG_MSNFTP_RECEIVING
        kdDebug() << "MsnFtpConnection::slotDataReceived - " << noBytesRead << " bytes read.  "
                                                             << fileBytesRemaining_ << " bytes remaining." << endl;
#endif
      }


      // See if all data is received
      if(fileBytesRemaining_ <= 0)
      {
#ifdef KMESSDEBUG_MSNFTP_GENERAL
        kdDebug() << "MsnFtpConnection::slotDataReceived - Done receiving file data." << endl;
#endif
        mode_ = SEND_BYE;
        return;
      }
    }
  }
  while(socket_->bytesAvailable() > 0);
}



// Set the authentication parameters
void MsnFtpConnection::setAuthInfo(const QString authHandle, const QString authCookie)
{
  authHandle_ = authHandle;
  authCookie_ = authCookie;
}



// Send a file
bool MsnFtpConnection::sendFile(QFile *inputFile)
{
#ifdef KMESSTEST
  ASSERT( socket_ == 0 );
  ASSERT( authHandle_.length() > 0 );
  ASSERT( authCookie_.length() > 0 );
  ASSERT( inputFile != 0);
  ASSERT( inputFile->isOpen() && inputFile->isReadable() );
#endif

  // Prepare
  inputStream_        = inputFile;
  fileSize_           = inputStream_->size();
  fileBytesRemaining_ = fileSize_;
  mode_               = SEND_VER;

  // Start listing for the connection
  bool listening = openServerPort();
  if(listening)
  {
    // Success!
    QString externIp = CurrentAccount::instance()->getExternalIP();
    emit statusMessage( i18n("Awaiting connection at %1, port %2")
                        .arg(externIp) // not server_->localAddress()->nodeName() here
                        .arg(server_->localAddress()->serviceName()), STATUS_DIALOG );
  }
  else
  {
    // Failed!
    // TODO for KMess 1.5: replace this text with something like "Couldn't open a local port"
    emit statusMessage( i18n("The transfer of %1 failed.  Couldn't create a socket."),     STATUS_CHAT_FAILED);
    emit statusMessage( i18n("File transfer dialog message", "Couldn't create a socket."), STATUS_DIALOG_FAILED);
    emit transferFailed();
  }

  // The return code only indicates whether this object is listening,
  // it can be used to send network commands, but status messages are delivered with the signals
  return listening;
}



// Retrieve a file
bool MsnFtpConnection::retrieveFile(QFile *outputFile, const QString &ipAddress, const int port)
{
#ifdef KMESSTEST
  ASSERT( socket_    == 0 );
  ASSERT( authHandle_.length() > 0 );
  ASSERT( authCookie_.length() > 0 );
  ASSERT( outputFile != 0 );
  ASSERT( outputFile->isOpen() && outputFile->isWritable() );
#endif

  // Open the file
  outputStream_       = outputFile;
  fileSize_           = 0;    // is set by FIL command
  fileBytesRemaining_ = 999;  // dummy value for FIL command
  mode_               = SEND_VER;

  // Open the connection
  bool connected = openConnection(ipAddress, port);
  if(connected)
  {
    // Success!
    emit statusMessage( i18n("Initiating file transfer"), STATUS_DIALOG );
  }
  else
  {
    // Failed!
    emit statusMessage( i18n("The transfer of %1 failed.  A connection could not be made"),   STATUS_CHAT_FAILED );
    emit statusMessage( i18n("File transfer dialog message", "Unable to make a connection."), STATUS_DIALOG_FAILED );
    emit transferFailed();
  }

  // The return code only indicates whether this object has a connection,
  // it can be used to send network commands, but status messages are delivered with the signals
  return connected;
}



// Accept incoming connections on the socket.
void MsnFtpConnection::slotAcceptConnection()
{
#ifdef KMESSTEST
  ASSERT( socket_ == 0 );
#endif
#ifdef KMESSDEBUG_MSNFTP_GENERAL
  kdDebug() << "MsnFtpConnection - Accept a socket" << endl;
#endif

  if(socket_ != 0)
  {
    // Already accepted a connection, close server
#ifdef KMESSDEBUG_MSNFTP_GENERAL
    kdDebug() << "MsnFtpConnection - Already got a connection, rejecting this request" << endl;
#endif
    if(server_ != 0)
    {
      server_->closeNow();
      delete server_;
      server_ = 0;
    }
    return;
  }

  // Wait until a connection was established
  server_->setBlockingMode(true);
  int acceptResult = server_->accept(socket_);

  if(acceptResult == 0)
  {
    // Accept success
#ifdef KMESSDEBUG_MSNFTP_GENERAL
    kdDebug() << "MsnFtpConnection - Accept success" << endl;
#endif

    // Close the server, we don't need to anymore.
    server_->closeNow();
    delete server_;
    server_ = 0;

    // Prepare to receive VER command
    mode_ = WAIT_VER;

    // Configure the socket for asynchronous operation
    socket_->setBlockingMode(true);
    socket_->enableRead(true);
    socket_->enableWrite(true);
    socket_->setBufferSize(-1, -1);
    connect( socket_, SIGNAL( readyRead()           ), this, SLOT( slotDataReceived()    ));
    connect( socket_, SIGNAL( readyWrite()          ), this, SLOT( slotWriteCommand()    ));
    connect( socket_, SIGNAL( connectionFailed(int) ), this, SLOT( slotSocketError(int)  ));

    // Update the status message
    emit statusMessage( i18n("Connection established"), STATUS_DIALOG );
  }
  else
  {
#ifdef KMESSDEBUG_MSNFTP_GENERAL
    kdDebug() << "MsnFtpConnection - WARNING - Failed to accept incoming connection." << endl;
#endif
    // TODO: signal failure
  }
}



// This is called when data is received from the socket.
void MsnFtpConnection::slotDataReceived()
{
#ifdef KMESSTEST
  ASSERT( socket_ != 0 );
#endif

  char          rawBlock[255];
  int           blockSize;
  int           noBytesRead;
  QString       commandLine;
  QStringList   command;

  if(mode_ == RECEIVE_DATA)
  {
    // Session is in the data transfer stage
    parseReceivedFileData();
  }
  else
  {
    // In the command stage, parse the commands

    // Get number of available bytes
    blockSize = 500; // socket_->bytesAvailable() (always 0)
    if( blockSize >= (int) sizeof(rawBlock) )
    {
      // Safety net, shouldn't happen though
      blockSize = sizeof(rawBlock);
    }

    // Read all received data without buffering
    // This can't hurt, because MSNFTP is a stop-and-wait protocol.
    // It's not possible to receive multiple lines at once.
    noBytesRead = socket_->readBlock( rawBlock, blockSize );
    if(noBytesRead <= 0)
    {
      // Error code or buffer empty.
      return;
    }

    // Convert data block to UTF8 string
    commandLine = QString::fromUtf8( rawBlock, noBytesRead );

    // Strip the newline character
    if(commandLine.contains("\r\n"))
    {
      commandLine = commandLine.left(commandLine.find("\r\n"));
    }

    // Split command into separate fields
    command = QStringList::split(" ", commandLine);


#ifdef KMESSDEBUG_MSNFTP_GENERAL
    kdDebug() << "MsnFtpConnection <<< " << commandLine << endl;
#endif

    // Parse the command
    parseCommand( command );
  }
}



// This is called when there's an error in the socket.
void MsnFtpConnection::slotSocketError(int error)
{
  kdDebug() << "MsnFtpConnection - WARNING - Socket error " << error << "." << endl;
}



// The socket is ready for writing.  Write any outstanding commands.
void MsnFtpConnection::slotWriteCommand()
{
  switch(mode_)
  {
    case WAIT :
    {
      // Do nothing.  Wait for slotDataReceived()
      break;
    }
    case SEND_VER :
    {
      // Client: Send the version
      writeMessage("VER MSNFTP\r\n");
      mode_ = WAIT;  // Wait for server response (VER)
      break;
    }
    case SEND_USR :
    {
      // Client: Send authorisation
      writeMessage("USR " + authHandle_ + " " + authCookie_ + "\r\n");
      mode_ = WAIT;  // Wait for server response (FIL)
      break;
    }
    case SEND_TFR :
    {
      // Client: Send signal to start the transfer
      writeMessage("TFR\r\n");
      mode_ = RECEIVE_DATA;

      // Update the status
      emit statusMessage( i18n("Receiving file %1"), STATUS_DIALOG );

      break;
    }
    case RECEIVE_DATA :
    {
      // Client: Receiving data with slotDataReceived()
      break;
    }
    case SEND_BYE :
    {
      // Client: Send the bye
      QString message;
      writeMessage("BYE 16777989\r\n");
      mode_ = WAIT;

      // Update the status
      if(this->fileBytesRemaining_ == 0)
      {
        emit transferComplete();
      }
      else
      {
        emit transferFailed();
      }
      break;
    }
    case WAIT_VER :
    {
      // Server: waiting for client to send version, do nothing
      break;
    }
    case SEND_VER2 :
    {
      // Server: Waiting for VER, send VER back
      writeMessage("VER MSNFTP\r\n");
      mode_ = WAIT;  // Wait for client response (USR)
      break;
    }
    case SEND_FIL :
    {
      // Server: Waiting for USR, send FIL back
      writeMessage("FIL " + QString::number(fileSize_) + "\r\n");
      mode_ = WAIT_TFR;  // Wait for client response (TFR)
      break;
    }
    case WAIT_TFR :
    {
      // Server: Wait for TFR, do nothing
      break;
    }
    case SEND_DATA :
    {
      // Server: Send data
      writeFileData();
      break;
    }
    case SEND_CANCEL :
    {
      // Server: Cancel the transfer
      writeCancelData();

      // Update the status
      emitCancelStatusMessage(false);   // we send cancel, contact didn't

      // wait for contact to send BYE (and close afterwards)
      // TODO: use a timeout here
      break;
    }
    case SEND_CCL :
    {
      // Server/client: Send a CCL message to abort
      writeMessage("CCL\r\n");

      // Update the status
      emitCancelStatusMessage(false);   // we send cancel, contact didn't

      // contact should close the connection now.
      // TODO: use a timeout here
      mode_ = WAIT;
      emit transferFailed();   // for now, close manually
      break;
    }
  }
}



// Write a cancel data block
void MsnFtpConnection::writeCancelData()
{
#ifdef KMESSDEBUG_MSNFTP_GENERAL
  kdDebug() << "MsnFtpConnection - Cancelling transfer" << endl;
#endif

  // Send a new data block
  char out[3];
  out[0] = 0x01;
  out[1] = 0x00;
  out[2] = 0x00;
  socket_->writeBlock( out, 3 );
  mode_ = WAIT;
}



// Write more file data to the socket
void MsnFtpConnection::writeFileData()
{
#ifdef KMESSTEST
  ASSERT( inputStream_ != 0 );
  ASSERT( socket_      != 0 );
#endif

  int  noBytesRead;
  int  noBytesWritten;
  char rawBlock[2048];

  // Read a block from the file.
  noBytesRead = inputStream_->readBlock( rawBlock + 3, sizeof(rawBlock) - 3 );

  if(noBytesRead < 0)
  {
    // File read error
    writeCancelData();

    // Add status message
    userCancelled_ = false;
    emitCancelStatusMessage(false);

    // Wait for contact to quit
    mode_ = WAIT;
    return;
  }

#ifdef KMESSDEBUG_MSNFTP_GENERAL
  kdDebug() << "MsnFtpConnection::writeFileData - " << noBytesRead         << " bytes read.  "
                                                    << fileBytesRemaining_ << " bytes remaining."
                                                    << " connected=" << socket_->socketStatus() << endl;
#endif

  // Set the header
  rawBlock[0] = 0;
  rawBlock[1] = (noBytesRead & 0x00ff);
  rawBlock[2] = (noBytesRead & 0xff00) >> 8;

  // Update the progress
  fileBytesRemaining_ -= noBytesRead;
  emit transferProgess(fileSize_ - fileBytesRemaining_);

  // Write the data to the socket_
  noBytesWritten = socket_->writeBlock( rawBlock, noBytesRead + 3 );

#ifdef KMESSTEST
  ASSERT( noBytesWritten == (noBytesRead + 3));
#endif

  // See if we're done
  if(fileBytesRemaining_ <= 0 )
  {
    kdDebug() << "MsnFtpConnection::writeFileData - done transferring file." << endl;
    mode_ = WAIT;  // Wait for BYE
  }
}



// Write a message to the socket.
void MsnFtpConnection::writeMessage(QString message)
{
  unsigned int noBytesWritten;

  noBytesWritten = socket_->writeBlock( message.utf8().data(), message.utf8().length() );

#ifdef KMESSTEST
  ASSERT( noBytesWritten == message.utf8().length() );
#endif
#ifdef KMESSDEBUG_MSNFTP_GENERAL
  kdDebug() << "MsnFtpConnection: mode is " << mode_ << endl;
  kdDebug() << "MsnFtpConnection >>> " << message;
#endif
}


#include "msnftpconnection.moc"
