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

#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmdcodec.h>
#include <kmessagebox.h>
#include <kpassdlg.h>
#include <krun.h>
#include <kurl.h>

#include "../contact/contact.h"
#include "../contact/contactlist.h"
#include "../currentaccount.h"
#include "../kmessdebug.h"
#include "../specialgroups.h"
#include "chatinformation.h"
#include "mimemessage.h"
#include "sslloginhandler.h"

#ifdef KMESSDEBUG_NOTIFICATION
  #define KMESSDEBUG_NOTIFICATION_GENERAL
  #define KMESSDEBUG_NOTIFICATION_MESSAGES
  #define KMESSDEBUG_NOTIFICATION_INVISIBLE
  #define KMESSDEBUG_NOTIFICATION_MSN9
#endif

// The constructor
MsnNotificationConnection::MsnNotificationConnection()
 : MsnConnection("MsnNotificationConnection"),
   initialized_(false),
   movingAck_(-1),
   movingSource_(0),
   noContacts_(0),
   sslLoginHandler_(0),
   totalNoContacts_(0)
{
  // We manage the contact list
  contactList_ = new ContactList();

  //  addGroup( SpecialGroups::INDIVIDUALS, i18n("Individuals")  ); // Not persistent
  contactList_->addGroup( SpecialGroups::ONLINE,      i18n("Online")       );
  contactList_->addGroup( SpecialGroups::OFFLINE,     i18n("Offline")      );
  contactList_->addGroup( SpecialGroups::ALLOWED,     i18n("Allowed")      );
  contactList_->addGroup( SpecialGroups::REMOVED,     i18n("Removed")      );

  // Connect the login timer to the checkLogin slot
  connect( &loginTimer_, SIGNAL(    timeout() ),
           this,         SLOT  ( checkLogin() ) );
}



// The destructor
MsnNotificationConnection::~MsnNotificationConnection()
{
  delete contactList_;
  delete sslLoginHandler_;

#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "DESTROYED Notification" << endl;
#endif
}



// Add a contact to the given list or, if applicable, group
// (This function is private)
void MsnNotificationConnection::addContact(QString handle, QString list, QString groupId)
{
#ifdef KMESSTEST
  bool goodGroupId;
  groupId.toInt( &goodGroupId );
  if(list == "FL") ASSERT( goodGroupId );
  ASSERT( ( list == "FL" ) || ( list == "AL" ) || ( list == "BL" ) );
#endif

  QString command;
  command = list + " " + handle + " " + handle;
  if ( list == "FL" )
  {
    command += " " + groupId;
  }
  command += "\r\n";
  sendCommand( "ADD", command );
}


// Add an existing contact to the friends list
void MsnNotificationConnection::addExistingContact(QString handle)
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Re-adding contact " << handle << endl;
#endif

  // Add a contact by unblocking it then adding it to the allowed list and the friends list
  // (at group 0 by default - the user can move it later)
  addContact   (handle, "FL", "0");
  removeContact(handle, "BL", "0");
  addContact   (handle, "AL", "0");
}



// Add a new contact to the list
void MsnNotificationConnection::addNewContact(QString handle)
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Adding contact " << handle << endl;
#endif

  // Ask the server to add the contact to the friends list
  // (group 0 by default) and the allowed list.
  addContact( handle, "AL", "0" );
  addContact( handle, "FL", "0" );
}



// Adds the given contact to the allow list.
void MsnNotificationConnection::allowContact(QString handle)
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Allowing contact " << handle << endl;
#endif

  addContact(handle, "AL", "0");
}



// Add a new group
void MsnNotificationConnection::addGroup(QString name)
{
  addPercents( name );
  sendCommand( "ADG", name  + "\r\n" );
}



// Block the given contact
void MsnNotificationConnection::blockContact(QString handle)
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Blocking contact " << handle << endl;
#endif

  // Block a contact by removing it from the allowed list
  // and adding it to the blocked list
  removeContact(handle, "AL", "0");
  addContact   (handle, "BL", "0");
}



// The msn object has required, requires a notification message
void MsnNotificationConnection::changedMsnObject()
{
  if(isConnected())
  {
    // Send the same status message, with a new msn object
    changeStatus(currentAccount_->getStatus());
  }
}



// Change a contact or the user's friendly name
void MsnNotificationConnection::changeFriendlyName( QString handle, QString newName )
{
  QString name = newName;
  addPercents( name );
  sendCommand( "REA", handle + " " + name + "\r\n" );
}



// Request a change in the user's status
void MsnNotificationConnection::changeStatus( const QString& newStatus )
{
  const uint capabilities = (Contact::MSN_CAP_MSN60);

  QString objStr = KURL::encode_string( currentAccount_->getMsnObjectString() );

  /*
  // To test the old file transfer:
  sendCommand( "CHG", newStatus + " 0\r\n");
  return;
  */

  if(objStr.isEmpty())
  {
    // Just don't send it if we don't have it.
    sendCommand( "CHG", newStatus + " " + QString::number(capabilities) + "\r\n" );
  }
  else
  {
    sendCommand( "CHG", newStatus + " " + QString::number(capabilities) + " " + objStr + "\r\n" );
  }
}



// Check whether login was successful within time limit
void MsnNotificationConnection::checkLogin()
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Login not successful within time limit." << endl;
#endif

  QString message;
  // Show a message to the user
  message = i18n("Connection timed out") + "\r\n";
  message += i18n("There may be a problem with the servers");
  KMessageBox::error( 0, message );
  closeConnection();
}



// Close the connection with the server
void MsnNotificationConnection::closeConnection()
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Close the connection." << endl;
#endif
  // Stop the login timer in case the user closed the connection during login
  loginTimer_.stop();
  noContacts_ = 0;
  totalNoContacts_ = 0;

  // Disconnect from the server
  disconnectFromServer();

  // Remove contacts and non-special groups from the contact list
  if ( contactList_ != 0 )
  {
    contactList_->saveProperties( kapp->config() );  // Make sure the contactlist is saved
    contactList_->reset();
    // The contact list is not deleted, like this class it's being
    // shared through the entire application, and attached to slots.
  }
 
  if ( currentAccount_ != 0 )
  {
    currentAccount_->setNoEmails( 0 );
  }
}



// The socket connected, so send the version command.
void MsnNotificationConnection::connectionSuccess()
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Connected Asynchronously, so send VER." << endl;
#endif

  putVer();
}



// Create the SSL login handler
SslLoginHandler* MsnNotificationConnection::createLoginHandler()
{
  SslLoginHandler *sslLoginHandler;
  // Create the SSL login handler
  sslLoginHandler = new SslLoginHandler();
  connect( sslLoginHandler, SIGNAL(       loginFailed()        ),
           this,            SLOT  (    sslLoginFailed()        ) );
  connect( sslLoginHandler, SIGNAL(    loginIncorrect()        ),
           this,            SLOT  ( sslLoginIncorrect()        ) );
  connect( sslLoginHandler, SIGNAL(    loginSucceeded(QString) ),
           this,            SLOT  ( sslLoginSucceeded(QString) ) );
  return sslLoginHandler;
}



// Show a .net status message.
void MsnNotificationConnection::dotNetMessage(QString message)
{
  int    result;
  KURL   netURL( "http://status.messenger.msn.com/Status.aspx" );

  message += "\n" + i18n("Show .NET service status?");
  result = KMessageBox::questionYesNo( 0, message, i18n("Server Error") );
  if ( result == KMessageBox::Yes )
  {
    new KRun( netURL );
  }
  closeConnection();
}


// Return the contact list
const ContactList* MsnNotificationConnection::getContactList() const
{
  return contactList_;
}


// Go online
void MsnNotificationConnection::goOnline()
{
//  kdDebug() << "Local IP is " << getLocalIp() << endl;
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Lists received.  Go online." << endl;
#endif
  int      ack;
  QString ackString;

  if ( currentAccount_ != 0 )
  {
#ifdef KMESSDEBUG_NOTIFICATION_INVISIBLE
    kdDebug() << "Notification: Prepare to change status to online or invisible." << endl;
    kdDebug() << "Notification: 'Start invisible' is " << currentAccount_->getStartInvisible() << "." << endl;
#endif
    // Change status to either online or invisible
    if ( currentAccount_->getStartInvisible() )
    {
#ifdef KMESSDEBUG_NOTIFICATION_INVISIBLE
      kdDebug() << "Notification: Change status to invisible." << endl;
#endif
      // Change status to invisible
      changeStatus( "HDN" );
    }
    else
    {
#ifdef KMESSDEBUG_NOTIFICATION_INVISIBLE
      kdDebug() << "Notification: Change status to online." << endl;
#endif
      // Change status to online
      changeStatus( "NLN" );
    }
    // Ask for inbox and compose URLs
    ack = sendCommand("URL", "INBOX\r\n");
    ackString.sprintf( "%d", ack );
    currentAccount_->setInboxInformation( ackString, "", "" );

    ack = sendCommand("URL", "COMPOSE\r\n");
    ackString.sprintf( "%d", ack );
    currentAccount_->setComposeInformation( ackString, "", "" );
  }
  else
  {
    kdDebug() << "Notification::goOnline() - WARNING - currentAccount_ is null!" << endl;
  }

  setSendPings( true );

  // Notify observers that the server is connected
  loginTimer_.stop();
  emit connected();
}



// Received the addition of a contact to a list or list and group
void MsnNotificationConnection::gotAdd(const QStringList& command)
{
  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotAdd - WARNING - Contact list is null!" << endl;
    return;
  }

  Contact *contact;
  int      listNumber;

  // Extract the handle, friendlyName, and list from the message
  QString listType;
  QString handle;
  QString friendlyName;
  QString groupId;

  listType     = command[2];
  // TODO? contactListVersion = command[3];
  handle       = command[4];
  friendlyName = command[5];
  groupId      = (listType == "FL" ? command[6] : QString::null);

  removePercents( friendlyName );

#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Added " << friendlyName << " (" << handle << ")"
            << " to " << listType << " " << groupId << "." << endl;
#endif


  // Check whether the contact exists.
  contact = contactList_->getContactByHandle(handle);

  if(contact == 0)
  {
    // Add the contact if he/she does not exist.
    if     (listType == "FL") listNumber = Contact::MSN_LIST_FRIEND;
    else if(listType == "AL") listNumber = Contact::MSN_LIST_ALLOWED;
    else if(listType == "BL") listNumber = Contact::MSN_LIST_BLOCKED;
    else if(listType == "RL") listNumber = Contact::MSN_LIST_REVERSE;
    else                      listNumber = 0;

    contact = contactList_->addContact(handle, friendlyName, listNumber, groupId);
  }
  else
  {
    // Contact was added to a certain group, activate it
    contact->setList(listType, true);

    // Also update the groupId for the FL list
    if(listType == "FL")
    {
      // NOTE: If we like to add a contact to multiple groups at once, this needs updating.
      //       Currently it is not required, because KMess doesn't send such commands to the server.
      contact->addGroupId(groupId);

      // TODO: make the moving operation smoother, something like: contact->anticipateMove(movingDestination_);

      // If this contact was added from moveContact(), remove from source group.
      if(command[1].toInt() == movingAck_ && movingSource_ != 0)
      {
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
        kdDebug() << "Notification: Detected moving-ack, removing contact from old group." << endl;
#endif
        removeContact(handle, "FL", QString::number(movingSource_));
        movingSource_ = 0;
        movingAck_ = -1;
      }
    }
  }


  // Check whether the contact added you
  if(contact->checkIfContactAddedUser())
  {
    emit contactAddedUser(contact);
  }
}



// Received the addition of a group
void MsnNotificationConnection::gotAdg(const QStringList& command)
{
  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotAdg - WARNING - Contact list is null!" << endl;
    return;
  }

  QString name = command[3];
  QString id   = command[4];
  removePercents( name );

#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Added group " << name << " (" << command[4] << ")." << endl;
#endif

  // Pass the information to the group list.
  contactList_->addGroup( id, name );
}



// Received confirmation of the user's status change
void MsnNotificationConnection::gotChg(const QStringList& command)
{
  if ( currentAccount_ != 0 )
  {
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "Notification: User's status changed to " << command[2] << "." << endl;
#endif
    // Change the user's status
    currentAccount_->setStatus( command[2] );
  }
  else
  {
    kdDebug() << "Notification::gotChg() - WARNING - currentAccount_ is null!" << endl;
  }
}



// Received a challenge from the server
void MsnNotificationConnection::gotChl(const QStringList& command)
{
  // Get the challengeCode from the message
  QString addCode = "Q1P7W2E4J9R8U3S5";

  // Get the md5 context of the challenge code combined with the stored code
  KMD5 context( command[2] + addCode );

  sendCommand("QRY", "msmsgs@msnmsgr.com 32\r\n" + context.hexDigest() );
}



// Received a version update from the server
void MsnNotificationConnection::gotCvr(const QStringList& /*command*/)
{
  if ( currentAccount_ != 0 )
  {
    // Send the USR command
    sendCommand( "USR", "TWN I " + currentAccount_->getHandle() + "\r\n" );
  }
}



// Received notice that a contact went offline
void MsnNotificationConnection::gotFln(const QStringList& command)
{
  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotFln - WARNING - Contact list is null!" << endl;
    return;
  }
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: " << command[1] << " went offline." << endl;
#endif
  contactList_->setContactOffline( command[1] );
}



// Received notice that a contact is already online
void MsnNotificationConnection::gotIln(const QStringList& command)
{
  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotIln - WARNING - Contact list is null!" << endl;
    return;
  }
  // Get the contact info from the message
  QString friendlyName = command[4];
  removePercents( friendlyName );
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: " << friendlyName << " (" << command[3] << ") is initially " << command[2] << "." << endl;
#endif

  uint    capabilities = command[5].toUInt();
  QString msnObject    = command[6];
  if ( !msnObject.isEmpty() )
  {
    removePercents( msnObject );
#ifdef KMESSDEBUG_NOTIFICATION_MSN9
    kdDebug() << "Notification: This person has an msn6 picture: " << msnObject << endl;
#endif
  }

  contactList_->changeContactStatus( command[3], friendlyName, command[2], capabilities, msnObject, false );

}



// Received authentication protocols
void MsnNotificationConnection::gotInf(const QStringList& command)
{
#ifdef KMESSTEST
  ASSERT( command[2] == "MD5" );
#endif
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Got authentication protocols." << endl;
#endif
  if ( currentAccount_ != 0 )
  {
    // Send user information
    sendCommand( "USR", "MD5 I " + currentAccount_->getHandle() + "\r\n" );
  }
  else
  {
    kdDebug() << "Notification::gotInf() - WARNING - currentAccount_ is null!" << endl;
  }
}



// Received group information
void MsnNotificationConnection::gotLsg(const QStringList& command)
{
#ifdef KMESSTEST
  bool goodId;
  command[1].toInt( &goodId );
  ASSERT( goodId );
#endif

  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotLsg - WARNING - Contact list is null!" << endl;
    return;
  }

  QString groupId = command[1];
  QString name    = command[2];
  removePercents( name );

  if(groupId == "0")
  {
#ifdef KMESSDEBUG_NOTIFICATION_MSN9
    kdDebug() << "Notification: Got implicit group 0, ignoring" << endl;
#endif
    return;
  }
  else
  {
#ifdef KMESSDEBUG_NOTIFICATION_MSN9
    kdDebug() << "Notification: Got group " << name << "(" << groupId << ")" << endl;
#endif
    contactList_->addGroup( groupId, name );
  }
}



// Received contact information
void MsnNotificationConnection::gotLst(const QStringList& command)
{
  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotLst - WARNING - Contact list is null!" << endl;
    return;
  }

  //emit statusMessage( i18n("Getting lists"), 2 );
#ifdef KMESSDEBUG_NOTIFICATION_MSN9
  kdDebug() << "Notification: Got LST : " << command.join( " " ) << endl;
#endif

  QString handle       = command[1];
  QString friendlyName = command[2];
  int     list         = command[3].toInt();
  QString groupIds     = command[4];

  removePercents( friendlyName );

#ifdef KMESSDEBUG_NOTIFICATION_MSN9
  kdDebug() << "Notification: Got contact " << friendlyName << "(" << handle << ") " << list << " " << groupIds << "." << endl;
#endif

  // Add the contact
  Contact *contact = contactList_->addContact( handle, friendlyName, list, groupIds );

  // Check whether the contact added you
  if(contact->checkIfContactAddedUser())
  {
    emit contactAddedUser(contact);
  }


  // Check if this is the last LST
  noContacts_++;
  if ( noContacts_ == totalNoContacts_ )
  {
#ifdef KMESSDEBUG_NOTIFICATION_MSN9
    kdDebug() << "Notification: All " << totalNoContacts_ << " were received.  Go online." << endl;
#endif
    goOnline();
  }
}



// Received notice that a contact has changed status
void MsnNotificationConnection::gotNln(const QStringList& command)
{
  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotNln - WARNING - Contact list is null!" << endl;
    return;
  }
  // Get the contact info from the message
  QString friendlyName = command[3];
  removePercents( friendlyName );

#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: " << friendlyName << " (" << command[2] << ") is now " << command[1] << "." << endl;
  kdDebug() << "Notification: Rename the contact in the list?" << endl;
#endif

  // If the contact's name has changed, change it in MSN's version of the contact list.
  QString currentFriendlyName = contactList_->getContactFriendlyNameByHandle( command[2] );
  if ( ( friendlyName != currentFriendlyName ) && ( friendlyName != command[2] ) )
  {
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "Notification: The current friendly name of " << currentFriendlyName << " doesn't match " << friendlyName << ".  Rename the contact in the list." << endl;
#endif
    changeFriendlyName( command[2], friendlyName );
  }

  uint capabilities = command[4].toUInt();

  // If the user has sent an MsnObject, we want it!
  // ChangeContactStatus will intelligently determine if the object is different,
  // which will be true if the user changes their portrait.
  QString msnObject = command[5];
  if ( !msnObject.isEmpty() )
  {
    removePercents( msnObject );
  }

  contactList_->changeContactStatus( command[2], friendlyName, command[1], capabilities, msnObject );
}



// Received notice of disconnetion from the server
void MsnNotificationConnection::gotOut(const QStringList& command)
{
  // If the first word is "OTH", it means that this user connected from elsewhere.
  if ( command[1] == "OTH" )
  {
    KMessageBox::error( 0, i18n("You have been disconnected because you \nconnected from another MSN Messenger client \nor from another location") );
  }
  closeConnection();
}



// Received confirmation of the user's or a contact's renaming
void MsnNotificationConnection::gotRea(const QStringList& command)
{
  if ( currentAccount_ == 0 )
  {
    kdDebug() << "Notification::gotRea() - WARNING - currentAccount_ is null!" << endl;
    return;
  }
  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotRea - WARNING - Contact list is null!" << endl;
    return;
  }
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: " << command[3] << " renamed to " << command[4] << "." << endl;
#endif
  // Check if this REA applies to the user or a contact
  if ( command[3] == currentAccount_->getHandle() )
  {
    QString friendlyName = command[4];
    removePercents( friendlyName );
    // Change the user's name
    currentAccount_->setFriendlyName( friendlyName );
  }
}



// Received confirmation of change in a group's name
void MsnNotificationConnection::gotReg(const QStringList& command)
{
  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotReg - WARNING - Contact list is null!" << endl;
    return;
  }
  QString name = command[4];
  removePercents( name );

#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Group " << command[3] << " renamed to " << name << "." << endl;
#endif
  // Pass the info to the group list
  contactList_->renameGroup( command[3], name );
}



// Received confirmation of a conact's removal from list or list and group
void MsnNotificationConnection::gotRem(const QStringList& command)
{
  /*
   * Note, if this method is called, it doesn't mean the contact is entirely removed.
   * It only indicated the contact was removed from a certain group or list.
   */

  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotRem - WARNING - Contact list is null!" << endl;
    return;
  }

  Contact *contact;

  // Extract the handle, friendlyName, and list from the message
  QString listType;
  QString handle;
  QString groupId;

  listType = command[2];
  // command[3] is new contact list version
  handle   = command[4];
  groupId  = (listType == "FL" ? command[5] : QString::null);

#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Contact " << handle << " removed from " << listType << " " << groupId << "." << endl;
#endif


  // Get the contact
  contact = contactList_->getContactByHandle(handle);
  if(contact == 0)
  {
    kdDebug() << "Notification::getRem - WARNING - Couldn't find contact " << handle << " in the contact list." << endl;
    return;
  }

  // Remove the contact from the given list
  if(listType == "FL")
  {
    if(groupId.length() == 0)
    {
      // A contact is only removed from the FL if no groupId is given
      contact->setList("FL", false);
    }
    else
    {
      // Otherwise, only remove from the given group,
      // the contact defaults to group "0" automatically.
      contact->removeGroupId(groupId);
    }
  }
  else
  {
    // Contact was removed from the given list.
    contact->setList(listType, false);

    // Even if the contact is removed from all lists, they are not removed entirely.
    // You might want to add them again, with the history/ContactExtension settings preserved.
    // TODO perhaps change the contact-remove "policy" in the future
  }


#ifdef KMESSTEST
  ASSERT( movingAck_ == -1 );  // only fails if ack was not detected.
  movingAck_ = -1;
#endif
}



// Received confirmation of a group's removal
void MsnNotificationConnection::gotRmg(const QStringList& command)
{
  if ( contactList_ == 0 )
  {
    kdDebug() << "Notification::gotRmg - WARNING - Contact list is null!" << endl;
    return;
  }
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Remove group " << command[3] << "." << endl;
#endif

  // Pass the info to the group list
  contactList_->removeGroup( command[3] );
}



// Received a chat request from a contact
void MsnNotificationConnection::gotRng(const QStringList& command)
{
  // Pull the data from the message
  QString friendlyName  = command[6];
  removePercents( friendlyName );

  QString serverAndPort = command[2];
  QString server     = serverAndPort.left ( serverAndPort.find(":") );
  QString portString = serverAndPort.right( serverAndPort.length() - serverAndPort.find(":") - 1 );
  bool goodPort;
  int port = portString.toInt( &goodPort );
  if ( !goodPort )
  {
    kdDebug() << "Notification::gotRng - WARNING - Couldn't get port from string " << portString << endl;
    return;
  }
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: " << friendlyName << " (" << command[5] << ") requesting a chat at " << server << ":" << port << " id = " << command[1] << " auth = " << command[4] << "." << endl;
#endif
  // Create a chat information object
  ChatInformation *chatInfo = new ChatInformation( this, command[5], contactList_, server, port, command[4], command[1] );
  emit startChat( chatInfo );
}



// Received synchronization information
void MsnNotificationConnection::gotSyn(const QStringList& command)
{
  emit ( i18n("Got synchronization") );
  totalNoContacts_ = command[3].toInt();
  
#ifdef KMESSDEBUG_NOTIFICATION_MSN9
  kdDebug() << "Got SYN.  # of contacts is " << totalNoContacts_ << endl;
#endif

  // Go online if contactlist is empty (new account)
  if(totalNoContacts_ == 0)
  {
    goOnline();
  }
}



// Received the folder and command info for Hotmail's inbox or compose
void MsnNotificationConnection::gotUrl(const QStringList& command)
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Got URL information." << endl;
#endif
  if ( currentAccount_ != 0 )
  {
    // Check the inbox and compose URLs to see if they're storing this ack
    if ( currentAccount_->getInboxCommand() == command[1] )
    { // This is the inbox url
      currentAccount_->setInboxInformation( command[4], command[2], command[3] );
    }
    else if ( currentAccount_->getComposeCommand() == command[1] )
    { // This is the compose url
      currentAccount_->setComposeInformation( command[4], command[2], command[3] );
    }
  }
  else
  {
    kdDebug() << "Notification::gotUrl() - WARNING - currentAccount_ is null!" << endl;
  }
}



// Received user authentication information
void MsnNotificationConnection::gotUsr(const QStringList& command)
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Got USR information." << endl;
#endif
  if ( currentAccount_ != 0 )
  {
    // This is either asking for authentication or confirming it
    if ( command[2] == "TWN" )
    {
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
      kdDebug() << "Notification: USR authentication." << endl;
#endif
      QString parameters;
      parameters = command[4];
      removePercents( parameters );
      // Change statusbar
      emit statusMessage( i18n("Authenticating"), 2 );
      // Create the sslLoginHandler
      sslLoginHandler_ = createLoginHandler();
      // Send the SSL login handler the parameter list.
      sslLoginHandler_->login( parameters, currentAccount_->getHandle(), currentAccount_->getPassword() );
    }
    else if ( command[2] == "OK" )
    {
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
      kdDebug() << "Notification: USR confirmation." << endl;
#endif
      // This is a confirmation message.  Get the user's friendly name from the message.
      QString friendlyName = command[4];
      removePercents( friendlyName );
      currentAccount_->setFriendlyName( friendlyName );

      emit statusMessage( i18n("Received user confirmation"), 2 );
      // Synchronize with the server (which will cause it to send the account data and contact lists)
      sendCommand( "SYN", "0\r\n" );
      emit statusMessage( i18n("Waiting for contact list..."), 2 );
    }
  }
  else
  {
    kdDebug() << "Notification::gotUsr - WARNING - Current account is null." << endl;
  }
}



// Received version information
void MsnNotificationConnection::gotVer(const QStringList& command)
{
#ifdef KMESSTEST
  ASSERT( command[2] == "MSNP9" );
#endif
  // Send some fake info about the current version
  if ( currentAccount_ != 0 )
  {
    // First parameter is the locale-id (0x0409 is U.S. English).
    sendCommand( "CVR", "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0250 MSMSGS " + currentAccount_->getHandle() + "\r\n" );
  }
}



// Received server transfer information
void MsnNotificationConnection::gotXfr(const QStringList& command)
{
  // Find out what the server type is.
  QString serverType = command[2];
  // Get the server ip and port (as server:port) from the message
  QString serverAndPort = command[3];
#ifdef KMESSTEST
  ASSERT( serverAndPort.contains(":") );
#endif
  // Get the server from that
  QString server = serverAndPort.left( serverAndPort.find(":") );
  QString portString = serverAndPort.right( serverAndPort.length() - serverAndPort.findRev(":") - 1 );
  // Convert the port to an integer
  bool goodPort;
  int port = portString.toInt( &goodPort );
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Got " << serverType << " transfer to " << server << ":" << port << "." << endl;
#endif
  if ( !goodPort )
  {
    kdDebug() << "Notfication: Got bad port number : " << portString << "." << endl;
    return;
  }
  if ( serverType == "NS" )
  {
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "Notification: Disconnecting from old server." << endl;
#endif
    // Disconnect from the existing server.
    disconnectFromServer( true );
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "Notification: Connecting to new server." << endl;
#endif
    // This is a notification server transfer.  Switch this socket to the given server.
    emit statusMessage( i18n("Transfer to notification server"), 2 );
    // Connect to the new server.
    if ( connectToServer( server, port ) )
    {
      // Send version information again
      //putVer();
    }
    else
    {
      kdDebug() << "Notification: WARNING - Couldn't connect to new server." << endl;
    }
  }
  else if ( serverType == "SB" )
  {
#ifdef KMESSTEST
    ASSERT( openChats_.count() > 0 );
    uint noChatsBefore = openChats_.count();
#endif
    // This is a switchboard server.  This message should be in response to
    //  a user-requested chat.  Look for the pending chat information.
    QString authorization = command[5];
    ChatInformation *chatInfo = openChats_.first();
    if ( chatInfo == 0 )
    {
      kdDebug() << "MsnNotificationConnection - Got switchboard, but there are no open chats." << endl;
      return;
    }
    // Update the chat information
    chatInfo->setServerInformation( server, port, authorization );
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "Notification signal a chat to " << server << ":" << port << endl;
#endif
    // Signal the chat
    emit startChat( chatInfo );
    // Remove the first chat from the open chats
    openChats_.remove( chatInfo );
#ifdef KMESSTEST
    ASSERT( openChats_.count() == ( noChatsBefore - 1 ) );
#endif
  }
}



// Initialize the object
bool MsnNotificationConnection::initialize()
{
  if ( initialized_ )
  {
    kdDebug() << "Notification Connection already initialized!" << endl;
    return false;
  }
  if ( !MsnConnection::initialize() )
  {
    kdDebug() << "Notification Connection: Couldn't initialize parent." << endl;
    return false;
  }

  initialized_ = true;
  return initialized_;
}



// Move the contact to another group.
void MsnNotificationConnection::moveContact(QString handle, QString fromGroupId, QString toGroupId)
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Moving '" << handle << "' from '" << fromGroupId << "' to '" << toGroupId << "'." << endl;
#endif

  Contact* contact = contactList_->getContactByHandle(handle);
  if(contact == 0)
  {
    kdDebug() << "MsnNotificationConnection - moveContact() - Couldn't find the contact." << endl;
    return;
  }

  if(fromGroupId == toGroupId)
  {
    // Would remove the contact otherwise. (re-added to original group, removed from original group afterwards)
    kdDebug() << "MsnNotificationConnection - moveContact() - Attempted to move contact to same group." << endl;
    return;
  }

  
  // Move the contact
  if(fromGroupId == "0" || fromGroupId.isEmpty())
  {
    // Move from implicit "individuals" group to something else requires a single ADD.
    addContact( handle, "FL", toGroupId );
  }
  else
  {
    // Add to new group, remove from old.
    // The REM can only be called if the ADD is ack-ed.
    movingSource_ = fromGroupId.toInt();
    movingAck_    = sendCommand("ADD", "FL " + handle + " " + handle + " " + toGroupId + "\r\n");

#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "MsnNotificationConnection: waiting for ack " << movingAck_ << " to remove contact from group." << endl;
#endif
  }
}



// Open a connection to the server
bool MsnNotificationConnection::openConnection()
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Opening connection." << endl;
#endif
  if ( !initialized_ )
  {
    kdDebug() << "Notification: ERROR - Notification should be initialized before attempting to connect." << endl;
    return false;
  }

  bool connected;

  emit statusMessage( i18n( "Connecting..." ), 2 );

  // Attempt to connect to the main MSN server
  connected = connectToServer( "messenger.hotmail.com", 1863 );
  if ( connected )
  {
    // Start the login timer
    loginTimer_.start( timeoutDuration_, true );
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "Notification: Socket started connecting OK.  Started. the timer." << endl;
#endif
  }
  else
  {
    kdDebug() << "Notification: Couldn't connect to the server." << endl;
  }
  return connected;
}



// Parse a regular command
void MsnNotificationConnection::parseCommand(const QStringList& command)
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "MsnNotificationConnection: Parsing command " << command[0] << "." << endl;
#endif

  if(command[0].toInt() != 0)
  {
    // I've desided to always print these messages, should make "error-resolving" easier.
    kdDebug() << "WARNING - Received error code " << command[0] << " from server." << endl;
  }

  if ( command[0] == "ADD" )
  {
    gotAdd( command );
  }
  else if ( command[0] == "ADG" )
  {
    gotAdg( command );
  }
  else if ( command[0] == "BLP" )
  {
    // Ignore this
  }
  else if ( command[0] == "BPR" )
  {
    // Ignore this
  }
  else if ( command[0] == "CHG" )
  {
    gotChg( command );
  }
  else if ( command[0] == "CHL" )
  {
    gotChl( command );
  }
  else if ( command[0] == "CVR" )
  {
    gotCvr( command );
  }
  else if ( command[0] == "FLN" )
  {
    gotFln( command );
  }
  else if ( command[0] == "GTC" )
  {
    // Ignore this
    // (GTC is a policy setting, how to handle chats with contacts not in your list)
  }
  else if ( command[0] == "ILN" )
  {
    gotIln( command );
  }
  else if ( command[0] == "INF" )
  {
    gotInf( command );
  }
  else if ( command[0] == "LSG" )
  {
    gotLsg( command );
  }
  else if ( command[0] == "LST" )
  {
    gotLst( command );
  }
  else if ( command[0] == "NLN" )
  {
    gotNln( command );
  }
  else if ( command[0] == "OUT" )
  {
    gotOut( command );
  }
  else if ( command[0] == "PRP" )
  {
    // Ignore this
  }
  else if ( command[0] == "QRY" )
  {
    // Ignore this
  }
  else if ( command[0] == "REA" )
  {
    gotRea( command );
  }
  else if ( command[0] == "REG" )
  {
    gotReg( command );
  }
  else if ( command[0] == "REM" )
  {
    gotRem( command );
  }
  else if ( command[0] == "RMG" )
  {
    gotRmg( command );
  }
  else if ( command[0] == "RNG" )
  {
    gotRng( command );
  }
  else if ( command[0] == "SYN" )
  {
    gotSyn( command );
  }
  else if ( command[0] == "URL" )
  {
    gotUrl( command );
  }
  else if ( command[0] == "USR" )
  {
    gotUsr( command );
  }
  else if ( command[0] == "VER" )
  {
    gotVer( command );
  }
  else if ( command[0] == "XFR" )
  {
    gotXfr( command );
  }
  // Check error codes
  // Check http://www.hypothetic.org/docs/msn/reference/error_list.php for details
  else if ( command[0] == "200" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Invalid command syntax") );
  }
  else if ( command[0] == "201" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Invalid command parameter") );
  }
  else if ( command[0] == "205" )
  {
    KMessageBox::error( 0, i18n("The account name given does not exist") );
  }
  else if ( command[0] == "206" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Domain name missing") );
  }
  else if ( command[0] == "207" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Already logged in") );
  }
  else if ( command[0] == "208" )
  {
    KMessageBox::error( 0, i18n("The account name given is invalid") );
  }
  else if ( command[0] == "209" )
  {
    KMessageBox::error( 0, i18n("That account name is invalid, or your passport has not been confirmed yet") );
  }
  else if ( command[0] == "210" )
  {
    KMessageBox::error( 0, i18n("Your contact list is full") );
  }
  else if ( command[0] == "215" )
  {
    KMessageBox::error( 0, i18n("This contact is already on your list") );
  }
  else if ( command[0] == "216" )
  {
    KMessageBox::error( 0, i18n("This contact is not on your list") );
  }
  else if ( command[0] == "217" )
  {
    KMessageBox::error( 0, i18n("This contact is not online") );
  }
  else if ( command[0] == "218" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Already in this mode") );
  }
  else if ( command[0] == "219" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Contact is in the opposite list") );
  }
  else if ( command[0] == "223" )
  {
    KMessageBox::error( 0, i18n("Your contact list has too many groups") );
  }
  else if ( command[0] == "224" )
  {
    KMessageBox::error( 0, i18n("This group can't be changed") );
  }
  else if ( command[0] == "227" )
  {
    KMessageBox::error( 0, i18n("This group is not empty") );
  }
  else if ( command[0] == "228" )
  {
    KMessageBox::error( 0, i18n("The group name is already in use by your Messenger or Hotmail contact list") );
  }
  else if ( command[0] == "229" )
  {
    KMessageBox::error( 0, i18n("The group name is too long") );
  }
  else if ( command[0] == "230" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Attempted to change group \"0\"") );
  }
  else if ( command[0] == "231" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Invalid Group") );
  }
  else if ( command[0] == "280" )
  {
    KMessageBox::error( 0, i18n("Switchboard server failed") );
  }
  else if ( command[0] == "281" )
  {
    KMessageBox::error( 0, i18n("Transfer to switchboard server failed") );
  }
  else if ( command[0] == "300" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Required field missing") );
  }
  else if ( command[0] == "302" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Not logged in") );
  }
  else if ( command[0] == "500" )
  {
    dotNetMessage( i18n("There was an internal server error") );
    closeConnection();
  }
  else if ( command[0] == "501" )
  {
    // Database server error
    dotNetMessage( i18n("There was an internal server error") );
    closeConnection();
  }
  else if ( command[0] == "502" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Command is disabled") );
  }
  else if ( command[0] == "510" )
  {
    // File operation failed
    dotNetMessage( i18n("There was an internal server error") );
    closeConnection();
  }
  else if ( command[0] == "520" )
  {
    // Memory allocation failed
    dotNetMessage( i18n("There was an internal server error") );
    closeConnection();
  }
  else if ( command[0] == "540" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Challenge response failed") );
  }
  else if ( command[0] == "600" )
  {
    dotNetMessage( i18n("The server is busy") );
    closeConnection();
  }
  else if ( command[0] == "601" )
  {
    dotNetMessage( i18n("The server is unavailable") );
  }
  else if ( command[0] == "602" )
  {
    dotNetMessage( i18n("Peer notification server down") );
    closeConnection();
  }
  else if ( command[0] == "603" )
  {
    // Database connection failed
    dotNetMessage( i18n("There was an internal server error") );
    closeConnection();
  }
  else if ( command[0] == "604" )
  {
    dotNetMessage( i18n("The server is going down") );
  }
  else if ( command[0] == "605" )
  {
    dotNetMessage( i18n("The server is unavailable") );
  }
  else if ( command[0] == "640" )
  {
    dotNetMessage( i18n("The server is going down soon") );
  }
  else if ( command[0] == "711" )
  {
    dotNetMessage( i18n("Write is blocking") );
  }
  else if ( command[0] == "712" )
  {
    dotNetMessage( i18n("Session is overloaded") );
  }
  else if ( command[0] == "713" )
  {
    // Too many CAL's
    KMessageBox::error( 0, i18n("You're opening sessions too rapidly") );
  }
  else if ( command[0] == "714" )
  {
    KMessageBox::error( 0, i18n("You have too many sessions opened") );
  }
  else if ( command[0] == "715" )
  {
    // Sent in response to a PRP setting an invalid phone type of three or less characters.
    // Also sent in response to a change of display name (REA) on an unverified Passport account.
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Unexpected PRP or REA command") );
  }
  else if ( command[0] == "717" )
  {
    KMessageBox::error( 0, i18n("Bad friend name") );
  }
  else if ( command[0] == "731" )
  {
    // Sent in response to a badly formatted CVR
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Bad CVR data") );
  }
  else if ( command[0] == "800" )
  {
    KMessageBox::error( 0, i18n("You're changing your name too rapidly") );
  }
  else if ( command[0] == "910" )
  {
    dotNetMessage( i18n("Server too busy") );
  }
  else if ( command[0] == "911" )
  {
    // User/pass was probably correct, TWN ticket was incorrect
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Authentication ticket was incorrect") );
    closeConnection();
  }
  else if ( command[0] == "912" )
  {
    dotNetMessage( i18n("Server too busy") );
  }
  else if ( command[0] == "913" )
  {
    KMessageBox::error( 0, i18n("You can't start a chat with someone while you are invisible.") );
  }
  else if ( command[0] == "914" )
  {
    dotNetMessage( i18n("Server unavailable") );
  }
  else if ( command[0] == "915" )
  {
    dotNetMessage( i18n("Server unavailable") );
  }
  else if ( command[0] == "916" )
  {
    dotNetMessage( i18n("Server unavailable") );
  }
  else if ( command[0] == "917" )
  {
    dotNetMessage( i18n("Authentication failed") );
  }
  else if ( command[0] == "918" )
  {
    dotNetMessage( i18n("Server too busy") );
  }
  else if ( command[0] == "919" )
  {
    dotNetMessage( i18n("Server too busy") );
  }
  else if ( command[0] == "920" )
  {
    dotNetMessage( i18n("Not accepting new principals") );
  }
  else if ( command[0] == "921" )
  {
    dotNetMessage( i18n("Server too busy") );
  }
  else if ( command[0] == "922" )
  {
    dotNetMessage( i18n("Server too busy") );
  }
  else if ( command[0] == "923" )
  {
    KMessageBox::error( 0, i18n("You have a kids passport, you need parental consent to chat online.") );
    closeConnection();
  }
  else if ( command[0] == "924" )
  {
    KMessageBox::error( 0, i18n("Your passport needs to be verified first.") );
    closeConnection();
  }
  else if ( command[0] == "928" )
  {
    KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("Bad USR ticket") );
  }
  else
  {
    if(command[0].toInt() != 0)
    {
      KMessageBox::error( 0, i18n("KMess received an unknown error message from the server: %1").arg(command[0]) );
    }
    kdDebug() << "Notification: Command " <<  command[0] << " not supported." << endl;
  }
}



// Parse a message command
void MsnNotificationConnection::parseMessage(const QStringList& /*command*/, const MimeMessage &mainMessage)
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "MsnNotification - Got " << mainMessage.getSubValue("Content-Type") << "." << endl;
#endif

  QString contentType = mainMessage.getSubValue("Content-Type");
  MimeMessage message( mainMessage.getBody() );

#ifdef KMESSDEBUG_NOTIFICATION_MESSAGES
  mainMessage.print();
  kdDebug() << "MsnNotification - Message body as mime:" << endl;
  message.print();
#endif

  // Check the message type
  if ( contentType == "text/x-msmsgsprofile" )
  {
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "MsnNotification - Load profile information." << endl;
#endif
    uint externalPort = mainMessage.getValue("ClientPort").toUInt();
    externalPort      = ((externalPort & 0x00ff) << 8) | ((externalPort & 0xff00) >> 8); // Byte swapped

    currentAccount_->setAccountInformation( mainMessage.getValue("MSPAuth"),
                                            mainMessage.getValue("kv"),
                                            mainMessage.getValue("preferredEmail"),
                                            mainMessage.getValue("sid"),
                                            mainMessage.getValue("EmailEnabled") == "1",
                                            mainMessage.getValue("ClientIP"),
                                            externalPort );
  }
  else if ( contentType == "text/x-msmsgsinitialemailnotification" )
  {
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "MsnNotification - Load initial email information." << endl;
#endif

    currentAccount_->setInitialEmailInformation( message.getValue("Post-URL"),
                                                 message.getValue("Inbox-Unread").toInt(),
                                                 message.getValue("Folders-Unread").toInt() );
  }
  else if ( contentType == "text/x-msmsgsemailnotification" )
  {
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "Notification: An email was received"
              << " from \""             << message.getValue("From")        << "\""
              << " with the subject \"" << message.getValue("Subject")     << "\""
              << " in the folder \""    << message.getValue("Dest-Folder") << "\"." << endl;
#endif

    // If a message delta is to the active folder, emails were moved into it, so use a negative deletion
    if ( message.getValue("Dest-Folder") == "ACTIVE" )
    {
      // Received in the inbox
      currentAccount_->changeNoEmails( 1 );
    }

    emit newEmail( message.decodeRFC2047String( message.getValue("From").data() ),
                   message.decodeRFC2047String( message.getValue("Subject").data() ),
                   (message.getValue("Dest-Folder") == "ACTIVE"),
                   message.getValue("id"),
                   message.getValue("Message-URL"),
                   message.getValue("Post-URL") );
  }
  else if ( contentType == "text/x-msmsgsactivemailnotification" )
  {
    int messageDelta = message.getValue("Message-Delta").toInt();

    // If a message delta is from the active folder, emails were deleted
    if ( message.getValue("Src-Folder") == "ACTIVE" )
    {
      currentAccount_->changeNoEmails( -1 * messageDelta );
    }
    // If a message delta is to the active folder, emails were moved into it
    else if ( message.getValue("Dest-Folder") == "ACTIVE" )
    {
      currentAccount_->changeNoEmails( messageDelta );
    }
  }
  else
  {
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
    kdDebug() << "MsnNotification: Content-Type '" << contentType << "' not reconized, message ignored." << endl;
#endif
  }
}



// Show a message that the proxy failed
void MsnNotificationConnection::proxyFailed()
{
  KMessageBox::error( 0, i18n("There was a problem connecting to the proxy.") );
  closeConnection();
}



// Send the version command
void MsnNotificationConnection::putVer()
{
  // Send the version command for MSN 9
  sendCommand( "VER", "MSNP9 MSNP8 CVR0\r\n" );
}



// Remove a contact from the given list or, if applicable, group
void MsnNotificationConnection::removeContact(QString handle, QString list, QString groupId)
{
#ifdef KMESSTEST
  bool goodGroupId;
  groupId.toInt( &goodGroupId );
  ASSERT( ( goodGroupId ) || ( list == "FL" ) );
  ASSERT( ( list == "FL" ) || ( list == "AL" ) || ( list == "BL" ) );
#endif
  QString command;
  command = list + " " + handle;

  if ( list == "FL" )
  {
    command += " " + groupId;
  }

  command += "\r\n";
  sendCommand( "REM", command );
}



// Remove a contact from the contact list completely
void MsnNotificationConnection::removeContact(QString handle, bool block)
{
  Contact *contact = contactList_->getContactByHandle(handle);
  if(contact == 0)
  {
    kdDebug() << "MsnNotificationConnection::removeContact: WARNING - Contact '" << handle << "' not found." << endl;
  }

  if(block)
  {
    // Block the contact
    removeContact(handle, "AL", "0");
    addContact(handle, "BL", "0");
  }
  else
  {
    if(! contact->isReverse())
    {
      // Remove from list, but only if we're not on the list of that contact (reverse-list).
      // Otherwise a "contact has added you" message will appear at kmess startup.
      removeContact(handle, "AL", "0");
      removeContact(handle, "BL", "0");
    }
  }

  if(contact->isFriend())
  {
    // If contact was on the friends list, remove it there.
    removeContact(handle, "FL", "");
  }
}


// Remove a group
void MsnNotificationConnection::removeGroup(QString id)
{
#ifdef KMESSTEST
  bool goodGroupId;
  id.toInt( &goodGroupId );
  ASSERT( goodGroupId );
#endif
  sendCommand( "RMG", id + "\r\n" );
}



// Rename a group
void MsnNotificationConnection::renameGroup(QString id, QString newName)
{
#ifdef KMESSTEST
  bool goodGroupId;
  id.toInt( &goodGroupId );
  ASSERT( goodGroupId );
#endif
  addPercents( newName );
  sendCommand( "REG", id + " " + newName + " 0\r\n");
}



// Request a chat with a contact
void MsnNotificationConnection::requestChat(QString handle)
{
  // Create a new chat information object and store it so that it can be
  //  given the switchboard server info when it's returned
  openChats_.append( new ChatInformation( this, handle, contactList_ ) );
  // Save the contact information?
  sendCommand( "XFR", "SB\r\n" );
}



// Save contact list properties
void MsnNotificationConnection::saveProperties(KConfig *config)
{
#ifdef KMESSDEBUG_NOTIFICATION
  kdDebug() << "Notification - saving properties" << endl;
#endif
  contactList_->saveProperties( config );
}


// The SSL login was aborted because an internal error occured
void MsnNotificationConnection::sslLoginFailed()
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Login SSL login failed!" << endl;
#endif

  // Delete the login handler
  delete sslLoginHandler_;
  sslLoginHandler_ = 0;

  // Show a message to the user
  KMessageBox::error( 0, i18n("There was an internal error in KMess: %1").arg("SSL Login failed") );
  closeConnection();
}



// The SSL login failed, username/password was incorrect
void MsnNotificationConnection::sslLoginIncorrect()
{
#ifdef KMESSDEBUG_NOTIFICATION_GENERAL
  kdDebug() << "Notification: Login SSL login was incorrect." << endl;
#endif

  // Delete the login handler
  delete sslLoginHandler_;
  sslLoginHandler_ = 0;

  // Show a message to the user
  KMessageBox::error( 0, i18n("Authentication failed, please verify your account name and password") );
  closeConnection();
}



// The SSL login succeeded
void MsnNotificationConnection::sslLoginSucceeded(QString authentication)
{
#ifdef KMESSDEBUG_NOTIFICATION
  kdDebug() << "Notification - Authentication is " << authentication << endl;
#endif
  // Delete the login handler
  delete sslLoginHandler_;
  sslLoginHandler_ = 0;
  sendCommand( "USR", "TWN S " + authentication + "\r\n" );
}



// Unblock the given contact
void MsnNotificationConnection::unblockContact(QString handle)
{
  // Unblock a contact by removing it from the blocked list
  // and adding to the allowed list
  removeContact(handle, "BL", "0");
  addContact   (handle, "AL", "0");
}

#include "msnnotificationconnection.moc"
