Logo Search packages:      
Sourcecode: kmess version File versions

msnsocketnull.cpp

/***************************************************************************
                          msnsocketnull.cpp  -  description
                             -------------------
    begin                : Sat May 10 2008
    copyright            : (C) 2008 by Valerio Pilo
    email                : valerio@kmess.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "msnsocketnull.h"

#include <QDir>
#include <QFile>
#include <QHostAddress>
#include <QTimer>
#include <QUrl>

#include <KInputDialog>
#include <KLocale>

#include <config-kmess.h>
#include "../kmessdebug.h"
#include "../contact/contact.h"
#include "../currentaccount.h"


// Initialize static class members
QMap<QString,MsnSocketNull::FakeContact>   MsnSocketNull::contactList_;
QMap<QString,QString>                      MsnSocketNull::groupList_;
QMap<QString,MsnSocketNull::OnlineDetails> MsnSocketNull::onlineList_;


#ifdef KMESSDEBUG_CONNECTION // Area-specific debug statements
  #define KMESSDEBUG_CONNECTION_SOCKET_NULL
#endif


// Change this to the position where you want KMess to search for a debug log
// to replicate :)
#define DEBUG_LOG_FILE    QDir::homePath() + "/kmessdebug.log"



/**
 * @brief The constructor
 *
 * Does nothing.
 */
00057 MsnSocketNull::MsnSocketNull( ServerType serverType )
: MsnSocketBase( serverType )
, sendPings_( false )
{
  setObjectName( "MsnSocketNull" );

  // Connect the server request timer
  connect( &responseTimer_, SIGNAL(        timeout() ),
           this,            SLOT  (   sendResponse() ) );

  // If the lists are already filled, we're done
  if( ! contactList_.isEmpty() || ! groupList_.isEmpty() )
  {
    return;
  }

  // If that file exists, parse it
  kDebug() << "File" << DEBUG_LOG_FILE << "file exists?" << QFile::exists( DEBUG_LOG_FILE );
  if( QFile::exists( DEBUG_LOG_FILE ) )
  {
    QFile file( DEBUG_LOG_FILE );
    file.open( QIODevice::ReadOnly );
    QStringList fileContents( QString( file.readAll() ).split( QString( "\n" ) ) );
    file.close();

    int index;
    QList<int> connections;
    QStringList fileCommands;
    QRegExp commandRegexp( "\"\\s+-\\s+<<<\\s+\\((.+)\\)$" );

    foreach( const QString &row, fileContents )
    {
      index = commandRegexp.indexIn( row );
      if( index == -1 )
        continue;

      QString command( commandRegexp.cap( 1 ) );

      // Every connection starts with a good SYN
      if( command.startsWith( "\"SYN\"" ) )
      {
        connections.append( fileCommands.size() );
        continue;
      }

      // The only messages we care of are the list retrieval ones
      if( ! command.startsWith( "\"LSG\"" ) &&
          ! command.startsWith( "\"LST\"" ) &&
          ! command.startsWith( "\"ILN\"" ) )
      {
        continue;
      }

      // Extract the QStringList of commands from the row
      fileCommands.append( command );
    }

/*
    kDebug() << "###########################################################################";
    kDebug() << connections;
    kDebug() << "###########################################################################";
    for( int i = 0; i < fileCommands.size(); i++ )
    {
      if( connections.contains( i ) )
      {
        kDebug() << "###########################################################################";
        kDebug() << "Connection" << connections.indexOf( i );
        kDebug() << "**************";
      }

      kDebug() << fileCommands[ i ];
    }

    kDebug() << "###########################################################################";
*/

    int number = 0;
    if( connections.size() > 1 )
    {
      bool ok;
      number = KInputDialog::getInteger( "KMess log mimicker", "Choose a connection from the log file \""
                                         + DEBUG_LOG_FILE + "\" to replicate:",
                                         1, 1,
                                         connections.size(),
                                         1, 10,
                                         &ok );
      if( ! ok )
      {
        number = 0;
      }
      else
      {
        number--; // reindex from 0
      }
    }

    int end = ( number == connections.size() - 1 ) ? fileCommands.size() - 1 : connections[ number ];

    for( int idx = connections[ number ]; idx < end; idx++ )
    {
      if( fileCommands[idx].isEmpty() )
        continue;

      QStringList parts( fileCommands[idx].split( ", " ) );
      for( int i=0; i < parts.size(); i++ )
      {
        parts[ i ] = parts[ i ].mid( 1, parts[i].size() - 2 );
      }

      if( parts[0] == "LSG" )
      {
        //("LSG", "KMess", "b07456fe-a6fd-4746-b63a-62f363a923ef")
        groupList_[ parts[2] ] = QUrl::fromPercentEncoding( parts[1].toUtf8() );
      }
      else if( parts[0] == "LST" )
      {
        // ("LST", "N=friend@site.dom", "F=[a=1][c=4][b]-%20Emet%20-[/b][/c][/a]", "C=aef50adb-434d-4e85-bcfd-0d14c3baf529", "11", "1", "7ed2567a-71f0-4bf1-8ab6-9549f616c093")
//          ("LST", "N=non-friend@site.dom", "10", "1")
        FakeContact newContact;

        if( parts.size() == 4 )
        {
          newContact.handle       = parts[1].mid(2);
          newContact.friendlyName = parts[1].mid(2);
          newContact.guId         = parts[1].mid(2);
          newContact.lists        = parts[2].toInt();
          newContact.groupIds     = QStringList();
        }
        else
        {
          newContact.handle       = parts[1].mid(2);
          newContact.friendlyName = QUrl::fromPercentEncoding( parts[2].mid(2).toUtf8() );
          newContact.guId         = parts[3].mid(2);
          newContact.lists        = parts[4].toInt();
          newContact.groupIds     = ( parts.size() > 6 ) ? parts[6].split( "," ) : QStringList();
        }

        contactList_[ newContact.handle ] = newContact;
      }
      else if( parts[0] == "ILN" )
      {
        // ("ILN", "10", "BSY", "contact@site.com", "Nickname%20encoded", "1342210100", "%3Cmsnobj%20Creator%3D%22contact%40site.com%22%20Size%3D%229333%22%20Type%3D%223%22%20Location%3D%22KMess.tmp%22%20Friendly%3D%22AA%3D%3D%22%20SHA1D%3D%22ysV4cHpd04lOhjHYB%2BTnggTwjdA%3D%22%20SHA1C%3D%226jkVICIHHIgJvSZAzgJ6FlNK10c%3D%22%2F%3E")
        contactList_[ parts[3] ].friendlyName = QUrl::fromPercentEncoding( parts[4].toUtf8() );

        OnlineDetails details;
        details.msnObject    = parts[6];
        details.capabilities = parts[5].toUInt();
        details.status       = parts[2];
        onlineList_[ parts[3] ] = details;
      }
    }
  }
  else // Generate a standard contact list
  {
    groupList_[ "0000-family" ] = "Family";
    groupList_[ "000-friends" ] = "Friends";
    groupList_[ "0-workmates" ] = "Workmates";
    groupList_[ "00000-empty" ] = "Empty Group";

    // lists 'templates'
    int isFriend  = Contact::MSN_LIST_ALLOWED | Contact::MSN_LIST_FRIEND | Contact::MSN_LIST_REVERSE;
    // NOTE: Add some invalid characters to the email addresses, so they will never resolve to possibly valid mailboxes.
    contactList_.insert( "mum@kmess.orgX", createFakeContact
      ( "mum@kmess.orgX",    "Mom", "c1mum", QStringList() << "0000-family", isFriend ) );
    contactList_.insert( "sister@kmess.orgX", createFakeContact
      ( "sister@kmess.orgX", "Sis", "c2sister", QStringList() << "0000-family", isFriend ) );
    contactList_.insert( "frank@kmess.com" , createFakeContact
      ( "frank@kmess.comX", "[u]Frankie[/u]", "c3frank", QStringList() << "000-friends", isFriend ) );
    contactList_.insert( "elaine@kmess.comX", createFakeContact
      ( "elaine@kmess.com", "[c=orange]Ely[/c=yellow]", "c4elaine", QStringList() << "0-workmates", isFriend ) );
    contactList_.insert( "badguy@bothering.comX", createFakeContact
      ( "badguy@bothering.comX", "[b]Bad Guy[/b]", "c5badguy", QStringList(), Contact::MSN_LIST_BLOCKED ) );
    contactList_.insert( "idiot@friend.comX", createFakeContact
      ( "jack@idiotry.comX", "Jackie - OLOLOLO", "c6jack", QStringList() << "000-friends", isFriend | Contact::MSN_LIST_BLOCKED ) );
    contactList_.insert( "sylvie@hotmail.comX", createFakeContact
      ( "sylvie@hotmail.comX", "(*)Sylvie(*) I'm working! (l)", "c7sylvie", QStringList() << "0-workmates", isFriend ) );
    contactList_.insert( "evan123@hotmail.usX", createFakeContact
      ( "evan123@hotmail.usX", "€v1³", "c8evan", QStringList() << "0-workmates", isFriend ) );
    contactList_.insert( "richard@multinational.comX", createFakeContact
      ( "richard@multinational.comX", "Richard ~ next week: vacation! :D", "c9richard", QStringList() << "0-workmates", isFriend ) );
    contactList_.insert( "awesome_girl222@hotmail.comX", createFakeContact
      ( "awesome_girl222@hotmail.comX", "[b][c=12]Katie (L)[/c=21] [c=21]I love you...[/c=12][/b]", "c10katie", QStringList() << "0000-family", isFriend ) );
    contactList_.insert( "unknown@unknown.wtfX", createFakeContact
      ( "unknown@unknown.wtfX", "Unknown Faceless Guy", "c11unknown", QStringList(), Contact::MSN_LIST_ALLOWED | Contact::MSN_LIST_REVERSE ) );

    // Same seed everytime, so we get the same results when starting multiple times KMess
    srand( 5 );

    QMap<QString,FakeContact>::ConstIterator cIt;
    for( cIt = contactList_.constBegin(); cIt != contactList_.constEnd(); ++cIt )
    {
      // Don't change to online all contacts
      if( ( rand() % 4 ) == 0 || ( rand() % 3 ) == 0 )
        continue;

        OnlineDetails details;
        details.msnObject    = ""; // no pic atm
        details.capabilities = 1985855532;
        details.status       = MsnStatus::getCode( (Status)(rand() % 8) );
        onlineList_[ cIt.key() ] = details;
    }
  }
}



/**
 * @brief The destructor
 *
 * Does nothing.
 */
00268 MsnSocketNull::~MsnSocketNull()
{
  // Disconnect from the server on exit
  if( connected_ )
  {
    disconnectFromServer();
  }

  // Stop the timer
  responseTimer_.stop();


#ifdef KMESSDEBUG_CONNECTION_SOCKET_NULL
  kDebug() << "DESTROYED";
#endif
}


MsnSocketNull::FakeContact MsnSocketNull::createFakeContact( const QString &handle, const QString &friendlyName, const QString &guId, const QStringList &groupIds, int lists ) const
{
    MsnSocketNull::FakeContact c;
    c.handle = handle;
    c.friendlyName = friendlyName;
    c.guId = guId;
    c.groupIds = groupIds;
    c.lists = lists;
    return c;
}


/**
 * @brief Connect to the given server
 *
 * The initial connection is always made through the main Gateway.
 * The first server response usually carries the new gateway IP
 * which will be used for the rest of the connection.
 *
 * @param  server  The server hostname or IP address.
 * @param  port    The port to connect to. Not used - all of our
 *                 traffic goes through the default port.
 */
00309 void MsnSocketNull::connectToServer( const QString& server, const quint16 port )
{
#ifdef KMESSDEBUG_CONNECTION_SOCKET_NULL
  if( server.isEmpty() && port == 0 )
  {
    kDebug() << "Faking connection to the default server.";
  }
  else
  {
    kDebug() << "Faking connection to server at " << server << ":" << port << ".";
  }
#endif

  // Set our internal state variables
  connected_ = true;
  setSendPings( true );
  responseTime_.start();

  // Start answering to the queued messages
  scheduleNext();

  // Signal we're ready
  emit connected();
  emit statusMessage( i18n( "Connected" ), false );
}



/**
 * @brief Send to the client the fake contact list
 *
 * This method sends the entire groups and contacts list back to KMess.
 */
00342 void MsnSocketNull::deliverContactList()
{
  QMap<QString,QString>::ConstIterator gIt;
  for( gIt = groupList_.constBegin(); gIt != groupList_.constEnd(); ++gIt )
  {
    emit dataReceived( QStringList() << "LSG"
                                     << QUrl::toPercentEncoding( gIt.value() )
                                     << gIt.key(), QByteArray() );
  }

  QMap<QString,FakeContact>::ConstIterator cIt;
  for( cIt = contactList_.constBegin(); cIt != contactList_.constEnd(); ++cIt )
  {
    const FakeContact contact = cIt.value();
    emit dataReceived( QStringList() << "LST"
                                     << "N=" + contact.handle
                                     << "F=" + QUrl::toPercentEncoding( contact.friendlyName )
                                     << "C=" + contact.guId
                                     << QString::number( contact.lists )
                                     << "1" // Meaning unknown
                                     << contact.groupIds.join(","),
                       QByteArray() );
  }

  // Same seed everytime, so we get the same results when starting multiple times KMess
  srand( 5 );

  QMap<QString,OnlineDetails>::ConstIterator oIt;
  for( oIt = onlineList_.constBegin(); oIt != onlineList_.constEnd(); ++oIt )
  {
    const OnlineDetails details = oIt.value();
    emit dataReceived( QStringList() << "ILN"
                                     << "999" // TODO: what is this? the ack number of the initial CHG? We don't use it.
                                     << details.status
                                     << contactList_[ oIt.key() ].handle
                                     << contactList_[ oIt.key() ].friendlyName
                                     << QString::number( details.capabilities )
                                     << details.msnObject
                     , QByteArray() );
  }
}



/**
 * @brief Disconnect from the server
 *
 * This method closes the connection to the server and does some cleaning up.
 * It empties all buffers, and resets the internal state.
 * To avoid losing data, all pending requests are merged into a single huge
 * request and sent altogether, before closing the connection. We won't
 * receive responses for them; but at least we lose no outgoing data.
 *
 * @param  isTransfer  When set, a disconnected() signal won't be fired.
 *                     This is used to handle transfers to another server
 *                     without noticing a disconnect.
 */
00399 void MsnSocketNull::disconnectFromServer( bool isTransfer )
{
  // Stop pinging
  setSendPings( false );

  // Just clean up if we are disconnected already
  if( ! connected_ )
  {
    return;
  }

  connected_ = false;
  messageQueue_.clear();
  responseTimer_.stop();

#ifdef KMESS_NETWORK_WINDOW
  KMESS_NET_CLOSE( this );
#endif

  // Do not signal a disconnection when we are transferring to another "server"
  if( isTransfer )
  {
    return;
  }

#ifdef KMESSDEBUG_CONNECTION_SOCKET_NULL
  kDebug() << "Emitting disconnection signal.";
#endif

  emit disconnected();
}



/**
 * @brief Return the local IP address
 *
 * Just returns "127.0.0.1". We're not going anywhere.
 *
 * @returns The IP address the socket uses at the system.
 */
00440 QString MsnSocketNull::getLocalIp() const
{
  // We don't care about our own IP, return a generic one
  return QHostAddress( QHostAddress::LocalHost ).toString();
}

/**
 * @brief Schedule the next response
 *
 * Restarts the internal timer to determine when the next command
 * will be sent back to KMess
 */
00452 void MsnSocketNull::scheduleNext()
{
  // Also send the ping if needed
  if( sendPings_ && responseTime_.restart() > 30000 )
  {
#ifdef KMESSDEBUG_CONNECTION_SOCKET_NULL
    kDebug() << "Emitting ping signal.";
#endif

    emit pingSent();
  }

  int nextResponseInterval = SOCKET_NULL_LAGGINESS_MIN + ( rand() % ( SOCKET_NULL_LAGGINESS_MAX + 1 ) );
#ifdef KMESSDEBUG_CONNECTION_SOCKET_NULL
  kDebug() << "Next response will happen in" << nextResponseInterval << "milliseconds.";
#endif

  responseTimer_.start( nextResponseInterval );
}



/**
 * @brief Answer a queued command
 *
 * This slot sends a response to a command sent by kmess
 */
00479 void MsnSocketNull::sendResponse()
{
  // When the queue is empty, just try again every now and then
  if( messageQueue_.isEmpty() )
  {
#ifdef KMESSDEBUG_CONNECTION_SOCKET_NULL
    kDebug() << "Queue is empty, idling.";
#endif
    scheduleNext();
    return;
  }

  // Extract the oldest message from the queue
  bool success;
  QByteArray  lastMessage( messageQueue_.takeFirst() );
  QString     commandLine( QString::fromUtf8( lastMessage.data(), lastMessage.size() ) );
  QStringList     command( commandLine.trimmed().split(" ") );

#ifdef KMESSDEBUG_CONNECTION_SOCKET_NULL
  kDebug() << "Parsing oldest queue message:" << command;
#endif

  // Each server type has a different message set with different responses; so we implement them separately
  if( serverType_ == MsnSocketBase::SERVER_NOTIFICATION )
  {
    success = sendNotificationServerResponse( command );
  }
  else
  {
    success = sendSwitchboardServerResponse( command );
  }

  // Answer the next message
  if( success && ! messageQueue_.isEmpty() )
  {
    scheduleNext();
  }
  else
  {
    // Stop parsing stuff if there's an error or there's no messages to parse
    responseTimer_.stop();
  }
}



// Respond to a command when acting as a Notification Server
bool MsnSocketNull::sendNotificationServerResponse( const QStringList& command )
{
  QStringList replyCommand;
  QByteArray  payloadData;

  // Set the command for the reply to the name and ack id, so we can fill it with some other stuff
  for( int i = 0; i < 2; i++ )
  {
    if( command.size() <= i )
    {
      break;
    }
    replyCommand.append( command[ i ] );
  }

  // Reply to the message, if it contains a known command

  if( command[0] == "VER" )
  {
    // Initial version info

    // Only reply with "VER <ackID> <MSNP version>"

    emit dataReceived( replyCommand << command[2], payloadData );
  }
  else if( command[0] == "CVR" )
  {
    emit dataReceived( replyCommand << KMESS_VERSION << KMESS_VERSION << KMESS_VERSION
                                    << "http://www.kmess.org/download/" << "http://www.kmess.org/",
                       payloadData );
  }
  else if( command[0] == "USR" )
  {
    // Test once the server redirection capabilities of KMess
    if( ! isTransferDone_ )
    {
      isTransferDone_ = true;

      // TODO: WTF are the other two arguments? We don't use them..
      messageQueue_ << QString( "XFR %1 NS fakeServerRedirection::1234 0 fakeServerRedirection2::4321" )
                                .arg( command[1] ).toUtf8();
    }
    else
    {
      // We can't easily proceed with faking authentication, since it involves HTTP requests external to
      // the scope of this class. Therefore, we just 'confirm' authentication
      emit dataReceived( replyCommand << "OK"
                         << CurrentAccount::instance()->getHandle()
                         << SOCKET_NULL_IS_ACCOUNT_VERIFIED
                         << "0",
                         payloadData );
    }
  }
  else if( command[0] == "XFR" )
  {
    // Redirection request: we emit it as is
    emit dataReceived( command, payloadData );
  }
  else if( command[0] == "OUT" )
  {
    // Quit/disconnection request

    // If needed, fake having been disconnected from this server due to connection from another place/client
    if( SOCKET_NULL_FAKE_OTH )
    {
      emit dataReceived( replyCommand << "OTH", payloadData );
    }

    disconnectFromServer();
  }
  else if( command[0] == "SYN" )
  {
    // Contact list synchronization
    QDateTime now( QDateTime::currentDateTime() );

    // TODO: When we'll start caching contact list contents, this could need to be updated
    // to avoid sync issues with old data
    QString listDate( now.toString( Qt::ISODate ) + ".00-00:00" );

    emit dataReceived( replyCommand << listDate << listDate
                                    << QString::number( contactList_.count() )
                                    << QString::number( groupList_.count() ),
                       payloadData );

    // Then start sending out to the client our Original Fake(tm) of the contact list
    deliverContactList();
  }
  else if( command[0] == "GCF" )
  {
    // Do nothing.
    // TODO: It should send something back so check what and replicate here
  }
  else if( command[0] == "CHG" )
  {
    // Status change. Reply as is.
    emit dataReceived( command, payloadData );
  }
  else if( command[0] == "UUX" )
  {
    // Response to an UUX command: reply without the original payload (if any)
    replyCommand << "0";
    emit dataReceived( replyCommand, payloadData );
  }
  else if( command[0] == "URL" )
  {
    if( command[2] == "INBOX" )
    {
      replyCommand << "inbox";                 // TODO: Fix URL
      replyCommand << "http://mail.live.com/"; // TODO: Fix URL
      replyCommand << "wtf";                   // TODO: Fix URL
    }
    else if( command[2] == "COMPOSE" )
    {
      replyCommand << "compose";               // TODO: Fix URL
      replyCommand << "http://mail.live.com/"; // TODO: Fix URL
      replyCommand << "wtf";                   // TODO: Fix URL
    }
    else
    {
      replyCommand << "http://www.kmess.org/";
    }

    emit dataReceived( replyCommand, payloadData );
  }
  else if( command[0] == "ADC" )
  {
    QString arg( command[3] );
    QString str, handle;

    if( arg.startsWith("N=") )
    {
      handle = arg.mid(2).toLower();
    }
    else if( arg.startsWith("F=") )
    {
      str = QUrl::fromPercentEncoding( arg.mid(2).toUtf8() );
      foreach( const FakeContact &contact, contactList_ )
      {
        if( contact.friendlyName == str )
        {
          handle = contact.handle;
          break;
        }
      }
    }
    else if( arg.startsWith("C=") )
    {
      str = arg.mid(2);
      foreach( const FakeContact &contact, contactList_ )
      {
        if( contact.guId == str )
        {
          handle = contact.handle;
          break;
        }
      }
    }

    if( ! handle.isEmpty() && ! contactList_.contains( handle ) )
    {
      FakeContact item;
      item.handle = handle;
      item.guId = handle + "-guid";
      item.friendlyName = handle + "'s Friendly Name";
      item.groupIds = QStringList();
      item.lists = 3; // Allowed + Friend

      contactList_[ handle ] = item;
    }

    // Contact adding or list change, reply as is
    emit dataReceived( command, payloadData );
  }
  else if( command[0] == "REM" )
  {
    // Contact removal

    emit dataReceived( command, payloadData );
  }
  else if( command[0] == "ADG" )
  {
    // Group adding, append the group ID

    QString id( replyCommand.last().toLower() );
    id.replace( QRegExp( "[^a-z0-9]" ), "-" );
    id.append( "-" + QString::number( rand() ) );

    groupList_[ id ] = QUrl::fromPercentEncoding( replyCommand.last().toUtf8() );

    replyCommand = command;
    replyCommand << id;
    emit dataReceived( replyCommand, payloadData );
  }
  else if( command[0] == "REG" )
  {
    // Group rename
    groupList_[ command[2] ] = QUrl::fromPercentEncoding( command[3].toUtf8() );

    emit dataReceived( command, payloadData );
  }
  else if( command[0] == "RMG" )
  {
    // Group rename
    groupList_.remove( command[2] );
    emit dataReceived( command, payloadData );
  }


  else if( command[0] == "WTF" )
  {
    // Template for other commands :)
    replyCommand << QString();
    emit dataReceived( replyCommand, payloadData );
  }
  else
  {
#ifdef KMESSDEBUG_CONNECTION_SOCKET_NULL
    kDebug() << "Unknown notification message:" << command;
#endif

    disconnectFromServer();
    emit error( "Connection closed by peer", ERROR_DROP );
    return false;
  }

  return true;
}



// Respond to a command when acting as a Switchboard Server
bool MsnSocketNull::sendSwitchboardServerResponse( const QStringList& command )
{
  QStringList replyCommand;
  QByteArray  payloadData;

  // Set the command for the reply to the name and ack id, so we can fill it with some other stuff
  for( int i = 0; i < 2; i++ )
  {
    if( command.size() <= i )
    {
      break;
    }
    replyCommand.append( command[ i ] );
  }

  // Reply to the message, if it contains a known command

  // TODO: Everything here
  if( true )
  {
#ifdef KMESSDEBUG_CONNECTION_SOCKET_NULL
    kDebug() << "Unknown switchboard message:" << command;
#endif

    disconnectFromServer();
    emit error( "Connection closed by peer", ERROR_DROP );
    return false;
  }

  return true;
}



/**
 * @brief Set whether to send pings or not
 *
 * When sending pings, the application receives a periodic signal
 * which is used to perform timed updates (like receiving display pics).
 *
 * @param  sendPings  True to send pings.
 */
00799 void MsnSocketNull::setSendPings( bool sendPings )
{
  sendPings_ = sendPings;
}



/**
 * @brief Write data to the gateway without any conversion
 *
 * This method creates a new request and queues it to be sent when possible.
 * See sendNextRequest() for more info on sending.
 *
 * @param  data  Contents of the message which will be sent
 * @return -1 on error, or else always the exact size of the sent data.
 */
00815 qint64 MsnSocketNull::writeBinaryData( const QByteArray &data )
{
  if( ! connected_ )
  {
    kWarning() << "Attempted to write data to a disconnected interface, aborting.";
    return -1;
  }

#ifdef KMESSDEBUG_CONNECTION_SOCKET_NULL
  kDebug() << "Appending message:" << data;
  kDebug() << "To current list:" << messageQueue_;
#endif

  // Reactivate the timer if it's been stopped due to an empty queue
  if( ! responseTimer_.isActive() )
  {
    scheduleNext();
  }

  messageQueue_.append( data.trimmed() );

  return data.size();
}



/**
 * @brief Write a string to the gateway
 *
 * This is a convenience method for writeBinaryData, which can be used to directly send a QString.
 *
 * @param  data  The message which will be sent
 * @return -1 on error, or else always the exact size of the sent data.
 */
00849 qint64 MsnSocketNull::writeData( const QString &data )
{
  return writeBinaryData( data.toUtf8() );
}



#include "msnsocketnull.moc"

Generated by  Doxygen 1.6.0   Back to index