Logo Search packages:      
Sourcecode: kmess version File versions  Download package

msnconnection.cpp

/***************************************************************************
                          msnconnection.cpp  -  description
                             -------------------
    begin                : Thu Jan 23 2003
    copyright            : (C) 2003 by Mike K. Bennett
    email                : mkb137b@hotmail.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 "msnconnection.h"

#include <qregexp.h>
#include <qtimer.h>
#include <qmutex.h>
#include <qvaluelist.h>

#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>

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

#ifdef KMESSDEBUG_CONNECTION // Area-specific debug statements
  #define KMESSDEBUG_CONNECTION_GENERAL
  #define KMESSDEBUG_CONNECTION_SOCKET
#endif

/**
 * @brief The constructor
 *
 * Initializes the sockets, buffers and ping timer.
 *
 * @param  name  The Qt object name.
 */
00045 MsnConnection::MsnConnection( const char *name )
: QObject(0, name),
   currentAccount_(0),
   ack_(0),
   disconnected_(false),
   initialized_(false),
   missedPings_(0),
   sendPings_(false),
   writeLocked_(false)
{
  // Create the socket
  socket_ = new KExtendedSocket();

  // Connect it up and set some defaults
  socket_->setSocketFlags( KExtendedSocket::bufferedSocket );
  socket_->enableRead( true );
  socket_->setTimeout( 30   );

  connect( socket_, SIGNAL(         readyRead()    ),
           this,    SLOT  (      dataReceived()    ) );
  connect( socket_, SIGNAL(  connectionFailed(int) ),
           this,    SLOT  (  connectionFailed(int) ) );
  connect( socket_, SIGNAL(            closed(int) ),
           this,    SLOT  (  connectionClosed(int) ) );
  connect( socket_, SIGNAL(    lookupFinished(int) ),
           this,    SLOT  (    lookupFinished()    ) );
  connect( socket_, SIGNAL( connectionSuccess()    ),
           this,    SLOT  ( connectionSuccess()    ) );

  pingTimer_.stop();
  // Connect the ping timer to the sendPing slot
  connect( &pingTimer_,  SIGNAL(    timeout() ),
           this,         SLOT  (   sendPing() ) );

  // Configure the multi packet buffer
  multiPacketBuffer_.setAutoDelete(true);

#ifdef KMESSTEST
  ASSERT( socket_ != 0 );
#endif
}



/**
 * @brief The destructor
 *
 * Closes the connection, and deletes the sockets.
 */
00094 MsnConnection::~MsnConnection()
{
  // Disconnect from the server on exit
  if(isConnected())
  {
    disconnectFromServer();
  }

  // Delete the socket
  delete socket_;
#ifdef KMESSDEBUG_CONNECTION
  kdDebug() << "DESTROYED " << name() << endl;
#endif
}



// Detect a socket error
void MsnConnection::connectionClosed(int state)
{
#ifdef KMESSDEBUG_CONNECTION_SOCKET
  kdDebug() << "MsnConnection::connectionClosed() - state is " << state << endl;
#endif

/*
// TODO: test for for KMess 1.6

  // Notify
  if( ! disconnected_ && ! ( state & KBufferedIO::closedNow ) )
  {
    // First disable pings, KMessageBox blocks here but it's private event loop would keep processing more ping timeouts.
    setSendPings(false);

    if( state & KBufferedIO::involuntary )
    {
      KMessageBox::error( 0, i18n("The remote server has closed the connection.") );
    }

    // Close connection, updates GUI.
    closeConnection();
    disconnectFromServer(false);
  }
*/
}



/**
 * @brief Called when the connection attempt failed.
 *
 * Closes the connection, and displays
 * the "could not connect to the MSN Messenger service." message box.
 *
 * @param  error  The system error.
 */
00149 void MsnConnection::connectionFailed(int error)
{
#ifdef KMESSDEBUG_CONNECTION_SOCKET
  kdWarning() << "Connection: Received error " << error << " from the socket"
              << " (socket status=" << socket_->status() << " systemerror=" << socket_->systemError() << ")." << endl;
#endif

  QString reason = KExtendedSocket::strError( socket_->status(), error ); // pokes sys_errlist[] / strerror()

  KMessageBox::error( 0, i18n( "KMess could not connect to the MSN Messenger service.\n"
                               "Please, be sure to be connected to the internet.\n"
                               "System error: %1 (code %2)." ).arg(reason).arg(error) );


  closeConnection();
  disconnectFromServer();
}


/**
 * @brief Connect to the given server via the socket
 *
 * The connection attempt is asynchronous.
 * When the connection is made, connectionSuccess() is called,
 * on error connectionFailed() is called.
 * Connection timeouts are not detected here yet.
 *
 * @param  server  The server hostname or IP address.
 * @param  port    The port to connect to.
 * @return  Whether the socket has started connecting.
 */
00180 bool MsnConnection::connectToServer(const QString& server, const int port)
{
#ifdef KMESSTEST
  ASSERT( ( port >= 0 ) && ( port < 32768 ) );
#endif

#ifdef KMESSDEBUG_CONNECTION_SOCKET
  kdDebug() << name() << "::connectToServer() - Connecting to server at " << server << ":" << port << "." << endl;
  kdDebug() << name() << "::connectToServer() - Socket status is " << socket_->socketStatus() << "." << endl;
#endif

  // Check that we are disconnected (the socket is null)
  if ( ! (    ( socket_->socketStatus() == KExtendedSocket::nothing )
           || ( socket_->socketStatus() == KExtendedSocket::done    ) ) )
  {
    kdWarning() << name() << "::connectToServer() - Socket is not disconnected.  Already connected?  Status is " << socket_->socketStatus() << "." << endl;
  }

  // This seems to solve some problems with re-connecting
  // to the switchboard if there is a timeout.
  socket_->reset();

  // Prepare state vars for the new connection
  disconnected_ = false;
  socket_->setAddress( server, port );

  // Start the name lookup...
  return ( socket_->startAsyncLookup() == 0 );
}


/**
 * @brief Called when data is received from the server.
 *
 * This method parses the incoming data for the syntax used by the MSN protocol.
 * When a command is only partially received, it's buffered until the whole command is received by subsequent dataReceived() calls.
 *
 * A parsed message to handled to one of the following methods:
 * - one-line commands are delivered to parseCommand()
 * - <code>PNG</code> commands are handled internally.
 * - <code>MSG</code> commands with MIME payloads are delivered to parseMessage()
 * - other commands with payloads are delivered to parsePayloadMessage().
 *   This uses isPayloadCommand() to detect if a command has a payload.
 */
00224 void MsnConnection::dataReceived()
{
#ifdef KMESSTEST
  ASSERT( socket_ != 0 );
#endif

  char         rawblock[1024];
  QCString     block, commandLine;
  int          index, noBytesRemaining, noBytesRead, payloadLength = 0;
  QStringList  command;
  bool         gotPayloadCommand = false;
  bool         completePayload;
  QByteArray   payloadData;

  // For multi-packet messages
  MultiPacketMessage *multiPacketMessage = 0;
  QString messageId;


  do   // while(noBytesRemaining > 0)
  {
    // Read data from the socket
    noBytesRead      = socket_->readBlock( rawblock, 1024 );   // Read one block
    noBytesRemaining = socket_->bytesAvailable();              // Get number of available bytes

#ifdef KMESSDEBUG_CONNECTION_SOCKET
    kdDebug() << name() << "::dataReceived() - " << noBytesRead      << " bytes read. "
                                                 << noBytesRemaining << " bytes remaining." << endl;
#endif

    // Exit if it's an error code
    if( noBytesRead < 0 )
    {
      return;
    }

    // We've received some data, reset the ping timer
    resetPingTimer();

    // Add the block to the buffer
    buffer_.add( rawblock, noBytesRead );


    // Keep looping until we can't find any commands
    while(true)
    {
      // Get newline
      index = buffer_.findNewline();            // Find a newline
      if(index == -1) break;                    // Stop if it's not received yet

      // Read command and split
      commandLine = buffer_.left( index );      // Fetch one line from the buffer
      commandLine = commandLine.left( index );  // Not sure why this is needed (should already be this length)
      command     = QStringList::split(" ", QString::fromUtf8(commandLine.data(), commandLine.size()));   // Split into separate fields

      // HACK: Avoids getting server commands which start or end with newlines.
      command[0] = command[0].stripWhiteSpace();
      int count = command.count();
      command[ count ] = command[ count ].stripWhiteSpace();

      gotPayloadCommand = false;

      // If it's a payload message, detect whether the full payload is received, otherwise break.
      if( command[0] == "MSG" || isPayloadCommand(command[0]) )
      {
        // Message is followed by a payload section.
        // verify whether the full payload has arrived.
        payloadLength     = command[ command.count() - 1 ].toInt();  // Get payload length (last parameter)
        completePayload   = ( buffer_.length() >= (payloadLength + commandLine.length() + 2)); // Compare length with the size of the buffer
        gotPayloadCommand = true;

        if( ! completePayload )
        {
          // If the buffer doesn't contain the rest of the message,
          // just wait until "dataReceived" is called again, or the top-reading-loop can read more data.
//#ifdef KMESSDEBUG_CONNECTION_SOCKET
//          kdDebug() << name() << "::dataReceived() - Will wait for the rest of the message..." << endl;
//#endif
          break;  // Break processing loop, return to top-reading-loop.
        }
      }


      // Handle debugging.
#ifdef KMESSDEBUG_SERVERMESSAGES
      kdDebug() << name() << " <<< " << commandLine << endl;
#endif
#ifdef KMESS_NETWORK_WINDOW
      KMESS_NET_RECEIVED( this, buffer_.left( index + 2 ) );
#endif


      // Remove command from buffer.
      // Should be done after the "! completePayload" part, keeping messages when
      buffer_.remove( index + 2 );

      // Get payload data
      if( gotPayloadCommand && payloadLength > 0 )
      {
        // Remove the command from the buffer
        // Read message from buffer,
        // delete message from buffer
        payloadData = buffer_.left(payloadLength);
        buffer_.remove( payloadLength );
      }


      // Handle debugging
#ifdef KMESS_NETWORK_WINDOW
      if( payloadLength > 0 )
      {
        KMESS_NET_RECEIVED( this, payloadData );
      }
#endif


      // Parse the messages.
      if( gotPayloadCommand  )
      {
        // It's a payload detected earlier.
        // See if it's a Mime message.
        if( command[0] != "MSG" )
        {
          // Other payload message types are parsed in the subclasses.
          parsePayloadMessage(command, payloadData);
        }
        else
        {
          // It's a mime message
          // Get the message from the buffer and create the mime message
          // Note we can't parse strings here, the message could contain binary p2p data.
          // UTF-8 characters are translated in the MimeMessage constructor itself.
          MimeMessage mimeMessage(payloadData);

          // Detect Multi-packet messages
          if( ! mimeMessage.hasField("Message-ID") )
          {
            // It's a normal message, parse it.
            parseMessage( command, mimeMessage );
          }
          else
          {
            // Handle multi-packet message parts.
#ifdef KMESSDEBUG_CONNECTION_SOCKET
            kdDebug() << name() << "::dataReceived() - Message is a multi-packet message, buffering." << endl;
#endif
            // Get associated multi-packet message buffer, create one if it doesn't exist yet.
            messageId          = mimeMessage.getValue("Message-ID");
            multiPacketMessage = multiPacketBuffer_.find(messageId);
            if( multiPacketMessage == 0 )
            {
              multiPacketMessage = new MultiPacketMessage();
              multiPacketBuffer_.insert(messageId, multiPacketMessage);
            }

            // Add the message to the handler.
            multiPacketMessage->addChunk(mimeMessage);

            // Parse message if complete multi-packet message is received.
            if( multiPacketMessage->isComplete() )
            {
              parseMessage( command, multiPacketMessage->getMessage() );
              multiPacketBuffer_.remove(messageId);   // auto-deletes item.
            }
          }
        }
      }
      else if( command[0] == "QNG" )
      {
        // Response from the internal ping timer.
        pingReceived_ = true;
        missedPings_  = 0;
      }
      else
      {
        // It's a normal command, handle it in the subclass.
        // Parse the command.
        parseCommand( command );
      }


#ifdef KMESSDEBUG_CONNECTION_SOCKET
      // Only display this if there's more data in the buffer
      if( buffer_.length() )
      {
        kdDebug() << name() << "::dataReceived() - Message parsed, buffer length is " << buffer_.length() << endl;
      }
#endif
    }
  }
  while(noBytesRemaining > 0);
}



/**
 * @brief Disconnect from the server
 * 
 * This function is called after closeConnection()
 * It empties all buffers, and resets the sockets.
 *
 * @param  isTransfer  When set, a disconnected() signal won't be fired.
 *                     This is used to handle transfers to another server
 *                     without noticing a disconnect.
 */
00429 void MsnConnection::disconnectFromServer( bool isTransfer )
{
  disconnected_ = true;

  // stop any more pings
  setSendPings( false );

  multiPacketBuffer_.clear();

  // If the socket is connected...
  if( isConnected() )
  {
    // Send "OUT"
    writeData("OUT\r\n");
  }

#ifdef KMESSDEBUG_CONNECTION_SOCKET
  kdDebug() << name() << "::disconnectFromServer() - Flush the socket." << endl;
#endif

  socket_->flush();

#ifdef KMESSDEBUG_CONNECTION_SOCKET
  kdDebug() << name() << "::disconnectFromServer() - Close the socket." << endl;
#endif

  socket_->closeNow();
  socket_->reset();

#ifdef KMESS_NETWORK_WINDOW
  KMESS_NET_CLOSE(this);
#endif

  // Always fire the event to update others.
  if( ! isTransfer )
  {
#ifdef KMESSDEBUG_CONNECTION_SOCKET
  kdDebug() << name() << "::disconnectFromServer() - Emit 'disconnected'." << endl;
#endif
    emit disconnected();
  }
}



/**
 * @brief Return the local IP address of the socket.
 *
 * This is typically a LAN address, unless the system
 * is directly connected to the Internet.
 *
 * @returns The IP address the socket uses at the system.
 */
00482 QString MsnConnection::getLocalIp() const
{
#ifdef KMESSDEBUG_SWITCHBOARD_FILETRANSFER
  kdDebug() << name() << "::getLocalIp()" << endl;
#endif
  QString ip = "";
  const KSocketAddress *address;
  address = socket_->localAddress();
  if ( address != 0 )
  {
    ip = address->pretty();
    // Local address gives something like "1.2.3.4 port 5" in the english
    //  version, and "1.2.3.4-Portnammersomething 5" in the german version.
    // So, to get the port, replace any "-"'s with " " then get everything
    //  to the left of the first space.  That should work.
    ip = ip.replace( QRegExp("-"), " " );
#ifdef KMESSDEBUG_SWITCHBOARD_FILETRANSFER
    kdDebug() << name() << "::getLocalIp() - Raw IP is " << ip << endl;
#endif
    if ( ip.contains(" ") )
    {
      ip = ip.left( ip.find(" ") );
    }
#ifdef KMESSDEBUG_SWITCHBOARD_FILETRANSFER
    kdDebug() << name() << "::getLocalIp() - IP is " << ip << endl;
#endif
  }
  else
  {
    kdWarning() << name() << "::getLocalIp() - IP not found.  Local address was null?" << endl;
  }
#ifdef KMESSDEBUG_SWITCHBOARD_FILETRANSFER
  kdDebug() << name() << "::getLocalIp() - Done." << endl;
#endif
  return ip;
}



/**
 * @brief Return whether or the socket is connected.
 * @returns True when connected, false otherwise.
 */
00525 bool MsnConnection::isConnected() const
{
  return ( socket_->socketStatus() == KExtendedSocket::connected );
}



/**
 * @brief Return whether the given command is a payload command.
 *
 * This method should be re-implemented in the derived class
 * to indicate which commands are payload commands.
 *
 * @returns True when it's a payload command, false otherwise.
 */
00540 bool MsnConnection::isPayloadCommand(const QString &/*command*/) const
{
  // Return false by default, is overwritten in MsnNotificationConnection
  return false;
}



/**
 * @brief Initialize the object
 *
 * This method should be called before the class is used.
 *
 * It sets the currentAccount_ reference.
 * Subclasses may re-implement this method to connect
 * to signals which are not available at startup in the constructor.
 */
00557 bool MsnConnection::initialize()
{
  if ( initialized_ )
  {
    kdDebug() << name() << "::initialize() - Already initialized!" << endl;
    return false;
  }
#ifdef KMESSTEST
  ASSERT( currentAccount_ == 0 );
#endif
  currentAccount_ = CurrentAccount::instance();
  if ( currentAccount_ == 0 )
  {
    kdDebug() << name() << "::initialize() - Couldn't get an instance of the current account." << endl;
    return false;
  }
  initialized_ = true;
#ifdef KMESSTEST
  ASSERT( currentAccount_ != 0 );
  ASSERT( socket_ != 0 );
#endif
  return initialized_;
}


/**
 * @brief Start a connection to the server's IP
 *
 * The connection attempt is asynchronous.
 */
00587 void MsnConnection::lookupFinished()
{
  socket_->startAsyncConnect();
}



/**
 * Internal function to reset the ping timer.
 *
 * This stops the current timer,
 * and restarts a timer to send the next <code>PNG</code> command.
 */
00600 void MsnConnection::resetPingTimer()
{
  if( sendPings_ )
  {
    pingTimer_.stop();
    pingTimer_.start( 30000 );  // 30s ping timer
  }
}



/**
 * @brief Send a command to the server
 *
 * This function automatically inserts the ACK-number
 * between the prefix and text.
 * This can be used later to track error responses.
 *
 * @param  prefix  The three-letter command, which parseCommand() receives in <code>command[0]</code>.
 * @param  text    The command arguments, joined with spaces.
 * @returns The ack-number used by the command.
 */
00622 int MsnConnection::sendCommand(const QString& prefix, const QString &text)
{
#ifdef KMESSTEST
  ASSERT( prefix.length() == 3 );
  if ( ( prefix != "QRY" ) && ( prefix != "MSG" ) )
  {
    ASSERT( text.right( 2 ) == "\r\n" );
  }
#endif

  int ack = ack_++;

//#ifdef KMESSDEBUG_CONNECTION_GENERAL
//  kdDebug() << "MsnConnection::sendCommand: Sending " << prefix << " command (" << ack << ")." << endl;
//#endif

  // Send the data to the server
  QString command = prefix + " " + QString::number( ack ) + " " + text;
  writeData( command );

  // Return the ack used
  return ack;
}



/**
 * @brief Send a MIME message command to the server.
 * @returns, returning the ack
 */
00652 int MsnConnection::sendMimeMessage(AckType ackType, const MimeMessage &message)
{
  // Determine which type to send.
  // Normally a char[4] lookup array would be sufficient,
  // but this is easier to use in the string concatenation with Qt
  const char *ackTypeStr = "?";
  switch(ackType)
  {
    case ACK_NONE:        ackTypeStr = "U"; break;
    case ACK_NAK_ONLY:    ackTypeStr = "N"; break;
    case ACK_ALWAYS:      ackTypeStr = "A"; break;
    case ACK_ALWAYS_P2P:  ackTypeStr = "D"; break;
  }

  // Create the "MSG id type length" header
  QByteArray rawMessage = message.getMessage();
  QString    command;

  // Build the command
  int ack = ack_++;
  command.sprintf("MSG %u %s %u\r\n", ack, ackTypeStr, rawMessage.size());

//#ifdef KMESSDEBUG_CONNECTION_GENERAL
//  kdDebug() << "MsnConnection::sendMimeMessage: Sending MSG command (" << ack << ")." << endl;
//#endif

  // Write the data
  writeData(command);
  writeBinaryData(rawMessage);

  // Return the ack used
  return ack;
}




// Send a payload command to the server, convenience function
int MsnConnection::sendPayloadMessage(const QString &prefix, const QString &arguments, const QString &payload)
{
  // Avoid converting data that has 0 bytes.
  if( payload.isEmpty() )
  {
    return sendPayloadMessage(prefix, arguments, QByteArray());
  }

  // Get UTF-8 encoded raw string.
  QCString utf8Payload = payload.utf8();

  // Downgrade to QByteArray.
  // If this is not done manually, otherwise a '\0' will be padded.
  QByteArray binPayload;
  binPayload.duplicate(utf8Payload.data(), utf8Payload.length());

  // Send payload
  return sendPayloadMessage(prefix, arguments, binPayload);
}



// Send a payload command to the server
int MsnConnection::sendPayloadMessage(const QString &prefix, const QString &arguments, const QByteArray &payload)
{
  QString command;
  int ack = ack_++;

  // Build the command
  command = prefix + " " + QString::number(ack);
  if( ! arguments.isEmpty() )
  {
    command += " " + arguments;
  }
  command += " " + QString::number(payload.size()) + "\r\n";

  // Write the data
  writeData(command);

  if( payload.size() > 0 )
  {
    writeBinaryData(payload);
  }

  // Return the ack used
  return ack;
}



// Send a "ping" to the server
void MsnConnection::sendPing()
{
  QString message;

  if ( pingReceived_ == false )
  {
    missedPings_ ++;

    if ( missedPings_ == 1 )
    {
      message += i18n( "1 ping lost" );
    }
    else
    {
      message += i18n( "%1 pings lost" ).arg(missedPings_);
    }

    emit statusMessage( message, KMessInterface::TYPE_WARNING );
  }
  else
  {
    emit statusMessage( i18n( "Connected" ), KMessInterface::TYPE_MESSAGE );
  }

  pingReceived_ = false;

  // Assume the connection was lost when 3 pings are missed.
  if ( missedPings_ == 3 )
  {
    KMessageBox::error( 0, i18n("The connection to the server was lost.") );
    closeConnection();
    disconnectFromServer(false);
  }

  writeData( "PNG\r\n" );

  emit pingSent();
}



// Set whether we're sending pings or not (also resets ping timer)
void MsnConnection::setSendPings( bool sendPings )
{
  sendPings_ = sendPings;
  missedPings_ = 0;

  pingReceived_ = true;

  if ( sendPings_ )
  {
    sendPing();

    resetPingTimer();
  }
  else
  {
    pingTimer_.stop();
  }
}



// Write data to the socket
void MsnConnection::writeData(const QString& data)
{
#ifdef KMESSTEST
  if ( ( data.left(3) != "QRY" ) && ( data.left(3) != "MSG" ) )
  {
    ASSERT( ( data.right( 2 ) ) == "\r\n" );
  }
#endif
  uint noBytesWritten;

  if( ! isConnected() )
  {
    if( ! disconnected_ )
    {
      kdWarning() << name() << "::writeData() - Attempting to write data to a disconnected socket, closing socket." << endl;

      // First disable pings, KMessageBox blocks here but it's private event loop would keep processing more ping timeouts.
      setSendPings(false);
      KMessageBox::error( 0, i18n("The remote server has closed the connection.") );

      // Close connection, updates GUI.
      closeConnection();
      disconnectFromServer(false);
    }
    return;
  }

  while ( writeLocked_ )
  {
#ifdef KMESSDEBUG_CONNECTION_SOCKET
    kdWarning() << name() << "::writeData() - WRITE DATA IS LOCKED TO AVOID WRITING OVERLAPPING DATA TO THE SOCKET." << endl;
#endif
  }
  // Lock the writing of data.
  writeLocked_ = true;

#ifdef KMESSDEBUG_SERVERMESSAGES
  QString debugData = data;
  QRegExp removeCrLf("\r\n$");
  kdDebug() << name() << " >>> " << debugData.replace(removeCrLf, QString::null) << endl;
#endif

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

  if ( noBytesWritten != unicode.length() ) // Note that the previous code used data.length instead of unicode.length(), but I
  {                                         // changed this since that is the string we send to the socket... (could be wrong here)
    kdWarning() << name() << "::writeData() - Wanted to write " << data.length() << " bytes to the socket, wrote " << noBytesWritten << "." << endl;
  }

  // Unlock the writing of data.
  writeLocked_ = false;

  // Append message to the network window
#ifdef KMESS_NETWORK_WINDOW
  KMESS_NET_SENT( this, data.utf8() );
#endif
}


// Write data to the socket without conversions
void MsnConnection::writeBinaryData(const QByteArray& data)
{
  int noBytesWritten;

  while ( writeLocked_ )
  {
#ifdef KMESSDEBUG_CONNECTION_SOCKET
    kdWarning() << name() << "::writeBinaryData() - WRITE DATA IS LOCKED TO AVOID WRITING OVERLAPPING DATA TO THE SOCKET." << endl;
#endif
  }
  // Lock the writing of data.
  writeLocked_ = true;

  if ( isConnected() )
  {
#ifdef KMESSDEBUG_SERVERMESSAGES

//  To display the entire contents:
/*
    QByteArray debugData = data.copy();  // because QByteArray is explicitly shared
    for(int i = 0; i < debugData.size(); i++) { if(debugData[i] < 10) debugData[i] = '?'; }
    kdDebug() << name() << " >>> " << QString::fromUtf8(debugData.data(), debugData.size()) << endl;
*/
//  To display the first readable part: (removing the final \r\n)
    kdDebug() << name() << " >>> " << QString(data).stripWhiteSpace() << endl;
#endif

    int dataLength = 0;

    dataLength = data.size();
    // NOTE: Assumes the caller used the right encoding already...!
    //       using .utf8() here breaks the ascii zero chars again.
    noBytesWritten = socket_->writeBlock( data.data(), dataLength );

    if ( noBytesWritten != dataLength )
    {
      kdWarning() << name() << "::writeBinaryData() - Wanted to write " << data.size() << " bytes to the socket, wrote " << noBytesWritten << "." << endl;
    }
  }
  else
  {
    kdWarning() << name() << "::writeBinaryData() - Attempting to write data to a disconnected socket." << endl;
  }

  // Unlock the writing of data.
  writeLocked_ = false;

  // Append the message to the network window
#ifdef KMESS_NETWORK_WINDOW
  KMESS_NET_SENT(this, data);
#endif
}


#include "msnconnection.moc"

Generated by  Doxygen 1.6.0   Back to index