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

#ifndef MSNNOTIFICATIONCONNECTION_H
#define MSNNOTIFICATIONCONNECTION_H

#include "../contact/msnstatus.h"
#include "../notification/notificationmanager.h"
#include "../network/soap/addressbookservice.h"
#include "chatinformation.h"
#include "msnconnection.h"

#include <QDateTime>
#include <QList>
#include <QTimer>



// Forward declarations
class ChatInformation;
class ChatMessage;
class Contact;
class ContactList;
class KMessTest;
class MimeMessage;
class PassportLoginService;
class QAbstractItemModel;
class OfflineImService;
class AddressBookService;
class RoamingService;


/**
 * @brief The primary connection to the MSN server.
 *
 * The notification connection is initialized when the
 * user signs in to the MSN Messenger service.
 * When this connection is dropped, the user is signed off as well.
 * The notification connection is used for the following actions:
 * - managing the contact list
 * - starting new chat sessions
 * - receive invitations for a chat session
 * - receive status updates about contacts, e.g.:
 *   - online/offline changes
 *   - new email
 *   - personal status messages
 *   - now playing information
 *   - new offline-im messages
 *
 * Most protocol commands are echo'ed back to the client.
 * This allows a Model-View-Controller based protocol handling,
 * see MsnConnection::parseCommand() for details.
 *
 * When the connection to the notification server is established,
 * the the PassportLoginService class is used to retrieve an authentication token.
 * This token is provided to the <code>USR</code> command complete the login process.
 *
 * When a contact is updated, it's information in the
 * ContactList class is updated automatically.
 * Contacts are organized in multiple "lists".
 * This differs from the "groups" seen in the main window!
 * See the Contact class for information about "lists" and "groups".
 *
 * New chat invitations are handled by the <code>XFR</code> command.
 * The server response contains the login data for a chat session (or "chat room")
 * at a switchboard server. This information is used to start the chat session.
 * The information about new chats is forwarded to the ChatMaster first.
 * This class looks for existing chats with a contact,
 * or opens a new chat window instead when needed.
 * The actual chat session is handled by the MsnSwitchboardConnection class.
 * Once the chat session is created, the other contact
 * is invited to the session at the switchboard server.
 *
 * Some contact commands include an MsnObject argument.
 * This is the "ticket" to request a display picture later,
 * by "inviting" the contact to transfer the data belonging to the MsnObject.
 * Invitations for file and msnobject transfers are not handled by the notification connection however.
 * A chat session needs to be started first. The invitation for the msnobject or file transfer can be sent there.
 *
 * Note that each connection starts with a version exchange.
 * Clients inform the server about the versions of the protocol it supports.
 * The commands documented here may differ from other clients using a different protocol version.
 * Currently KMess uses <code>MSNP15</code> for all the notification connection.
 * New features are added to new protocol versions only.
 * Therefore, something as simple as a 'personal status message' required
 * an upgrade to a complete new protocol version. The <code>UBX</code>
 * command - which contains the personal status message - is only sent as of <code>MSNP11</code>.
 *
 * The <code>CHG</code> and <code>NLN</code> commands include a bitwise flag
 * with the supported client-to-client features. This includes the
 * MSNC version for the invitation system, the type of the client ('normal', 'mobile', 'web messenger') and features like 'winks', 'webcam', 'folder sharing'.
 * By advertising these values, a client promoses the feature is fully supported.
 * Changing the advertised MSNC version changes the type of P2P messages sent by another client.
 * Hence, changing the capabilities value could pose a major impact.
 * The list of known flags can be found in the ContactBase::MsnClientCapabilities enum.
 *
 * @author Mike K. Bennett
 * @author Valerio Pilo
 * @author Antonio Nastasi
 * @ingroup NetworkCore
 */
class MsnNotificationConnection : public MsnConnection
{
  Q_OBJECT

  friend class KMessTest;


  public:
    // The constructor
                         MsnNotificationConnection();
    // The destructor
                         ~MsnNotificationConnection();
    // Request a change in the user's status
    void                 changeStatus( const Status newStatus );
    // Close the connection with the server
    void                 closeConnection();
    // Return the contact list model
    QAbstractItemModel*  getContactListModel();
    // Initialize the object
    bool                 initialize();
    // Open a connection to the server
    bool                 openConnection();
    // Load the contact list properties
    void                 readProperties();
    // Save the contact list properties
    void                 saveProperties();


  public slots:
    // Adds the given contact to the allow list.
    void                 allowContact(QString handle);
    // Copy contact to another group.
    void                 addContactToGroup(QString handle, QString groupId);
    // Add an existing contact to the friends list
    void                 addExistingContact( QString handle, const QStringList& groupsId = QStringList() );
        // Add a new group
    void                 addGroup(QString name);
    // Add a new contact to the list
    void                 addNewContact( QString handle, const QStringList& groupsId = QStringList() );
    // Block the given contact
    void                 blockContact(QString handle);
    // Change the current media of the user.
    void                 changeCurrentMedia( const QString &application, const QString &mediaType, bool enabled,
                                             const QString &formatString, const QStringList arguments );
    // The msn object has required, requires a notification message
    void                 changedMsnObject();
    // Change the friendly name of the user.
    void                 changeFriendlyName( QString newName );
    // Change the personal message of the user.
    void                 changePersonalMessage( QString newMessage );
    // Change the personal properties
    void                 changePersonalProperties( const QString& cid, int blp );
    // Change a user property
    void                 changeProperty( QString type, QString value );
    // Change a contact property
    void                 changeProperty( QString handle, QString type, QString value );
    // Move the contact to another group.
    void                 moveContact(QString handle, QString fromGroupId, QString toGroupId);
    // Request a switchboard to connect to a contact
    void                 requestSwitchboard( QString handle, ChatInformation::ConnectionType type );
    // Rename a group
    void                 renameGroup(QString id, QString newName);
    // Remove a contact from the contact list completely
    void                 removeContact(QString handle, bool block = true);
    // Remove a contact from a single group
    void                 removeContactFromGroup(QString handle, QString groupId);
    // Remove the current media advertising in the personal status.
    void                 removeCurrentMedia();
    // Remove a group
    void                 removeGroup(QString id);
    // Unblock the given contact
    void                 unblockContact(QString handle);

  private slots:
    // The socket connected, so send the version command.
    void                 slotConnected();
    // Create the Roaming service
    RoamingService       *createRoamingService();
    // Show warning notifications
    void                 slotWarning( const QString &warning, bool isImportant );
    // Shows error notifications
    void                 slotError( QString error, MsnSocketBase::ErrorType type );
    // Displays additional info about network errors
    void                 slotErrorEventActivated( NotificationManager::EventSettings settings, NotificationManager::Buttons button );
    // Go online
    void                 goOnline();

  private: // Private methods
    // Create and return one pointer to address book service
    AddressBookService   *createAddressBookService();
    // Create the Offline-IM service
    OfflineImService     *createOfflineImService();
    // Create the passport login handler
    PassportLoginService *createPassportLoginService();
    // Create triple des encryption
    QByteArray           createTripleDes ( const QByteArray &key, const QByteArray &secret,
                                            const QByteArray &iv );
    // Received response to adl command
    void                 gotAdl( const QStringList& command, const QString &payload = "" );
    // Received confirmation of the user's status change
    void                 gotChg( const QStringList& command );
    // Received a challenge from the server
    void                 gotChl( const QStringList& command );
    // Received a version update from the server
    void                 gotCvr( const QStringList& command );
    // Received notice that a contact went offline
    void                 gotFln( const QStringList& command );
    // Received notice that a contact is already online
    void                 gotIln( const QStringList& command );
    // Received notice that a contact has changed status
    void                 gotNln( const QStringList& command );
    // Received notice of disconnetion from the server
    void                 gotOut( const QStringList& command );
    // Received a property change (friendly name, phone number, etc..)
    void                 gotPrp(const QStringList& command);
    void                 gotRml( const QStringList &command );
    // Received a chat request from a contact
    void                 gotRng( const QStringList& command );
    // Received details of a contact's personal message
    void                 gotUbx( const QStringList &command, const QByteArray &payload );
    // Received the folder and command info for Hotmail's inbox or compose
    void                 gotUrl( const QStringList& command );
    // Received user authentication information
    void                 gotUsr( const QStringList& command );
    // Received version information
    void                 gotVer( const QStringList& command );
    // Received server transfer information
    void                 gotXfr( const QStringList& command );
    // Send the ADL command
    void                 putAdl( const QString &handle = "", int list = 0 );
    // Send the RML command
    void                 putRml( const QString &handle, int list );
    // Send the personal status and current media fields.
    void                 putUux();
    // Send the version command
    void                 putVer();
    // Parse a regular command
    void                 parseCommand( const QStringList& command );
    // Parse an error command
    void                 parseError( const QStringList& command, const QByteArray &payloadData );
    // Parse a message command
    void                 parseMimeMessage( const QStringList& command, const MimeMessage &message );
    // Parse a payload command
    void                 parsePayloadMessage( const QStringList &command, const QByteArray &payload );


  private slots:
    // Removes any expired switchboard requests, so new ones can be made
    void                 checkSwitchboardsTimeout();
    // The passport login failed, username/password was incorrect
    void                 loginIncorrect();
    // The passport login succeeded
    void                 loginSucceeded();
    // Received the Mail-Data field over SOAP or at the notification connection.
    void                 receivedMailData( QDomElement mailData );
    // An Offline-IM message was downloaded
    void                 receivedOfflineIm( const QString &messageId, const QString &from, const QString &to,
                                            const QDateTime &date, const QString &body,
                                            const QString &runId, int sequenceNum );
    // The authentication process has timed out
    void                 slotAuthenticationFailed();
    // Unlock notifications after the first seconds of connections
    void                 unlockNotifications();
    // Contact added, notify it to contactlist
    void                 slotContactAdded( const QString &handle, const QString &contactId,
                                           const QStringList &groupsId );
    // Contact added to group
    void                 slotContactAddedToGroup( const QString &contactId, const QString &groupId );
    // Contact blocked
    void                 slotContactBlocked( const QString &handle );
    // Contact deleted
    void                 slotContactDeleted( const QString &contactId );
    // Contact removed from group
    void                 slotContactDeletedFromGroup( const QString &contactId, const QString &groupId );
    // Called when address book services retrieved address book list
    void                 slotGotAddressBookList( const QList< QHash<QString,QVariant> > &contacts );
    // Called when address book services retrieved membership lists
    void                 slotGotMembershipLists( const QString &serviceType, const QHash<QString,int> &contactsRole );
    // Called when address book services parsed a group
    void                 slotGotGroup( const QString &id, const QString &name );
    // Contact unblocked
    void                 slotContactUnblocked( const QString &handle );


  private: // Private attributes

    // The address book service
    AddressBookService   *addressBookService_;
    bool                 connected_;
    // Nonce received by the server on first SSO command
    QByteArray           nonceBase64_;
    // The list of contacts' role
    QHash<QString,int>   contactsRole_;

    struct MSNPMSNG {
      quint32 headerSize;
      quint32 cryptMode;
      quint32 cipherType;
      quint32 hashType;
      quint32 ivLength;
      quint32 hashLength;
      quint32 cipherLength;

      unsigned char ivBytes[8];
      unsigned char hashBytes[20];
      unsigned char cipherBytes[72];
    };

    struct OfflineImMessage
    {
      QString   messageId;
      QString   from;
      QDateTime date;
      QString   body;
      QString   runId;
      int       sequenceNum;
    };

    // A pointer to the list of contacts
    ContactList          *contactList_;
    // A pointer to the shared current account singleton.
    CurrentAccount       *currentAccount_;
    // Whether or not to enable presence notifications
    bool                 enableNotifications_;
    // Whether the goOnline() operation was completed
    bool                 goneOnline_;
    // Group where to initially place a newly added contact
    QString              initialContactAddedGroup_;
    // Whether or not the object was initialized
    bool                 initialized_;
    // Whether or not the connection has just been established
    bool                 isInitiatingConnection_;
    // The last current media set.
    QString              lastCurrentMedia_;
    // The last Personal Status Message set.
    QString              lastPsm_;
    // Last status used
    int                  lastStatus_;
    // A timer to watch over the login process
    QTimer               loginTimer_;
    // A timer used to unlock notifications after the last ILN is received.
    QTimer               notificationUnlockTimer_;
    // A timer to login directly if the SOAP requests take too long.
    QTimer               friendlyNameWaitTimer_;
    // The received offline messages.
    QList<OfflineImMessage*>  offlineImMessages_;
    // The Offline-IM SOAP client
    OfflineImService          *offlineImService_;
    // A list of switchboard requests which haven't yet been given servers
    QList<ChatInformation*>   openRequests_;
    // The object than handles the passport login
    PassportLoginService      *passportLoginService_;
    // The Roaming SOAP client
    RoamingService            *roamingService_;
    // The pending offline-im messages
    QStringList               pendingOfflineImMessages_;
    // Whether the initial status was already sent. See goOnline()
    bool                      initialStatusSent_;


  signals:
    // Signal a chat message, used for offline-im messages
    void                 offlineMessage( const ChatMessage &message );
    // Signal that the connection has been made sucessfully
    void                 connected();
    // Signal that a contact added you
    void                 contactAddedUser( const QString handle );
    // Signal that a new email has been received
    void                 newEmail(QString sender, QString subject, bool inInbox, QString command, QString folder, QString url);
    // Signal that the connection should be established again after a disconnection
    void                 reconnect( QString handle );
    // A new switchboard with a contact has been opened
    void                 startSwitchboard( const ChatInformation &chatInfo );
    // Signal that a change has occurred in the AB (contact add/remove/delete, etc)
    void addressBookChanged( const QString &id, AddressBookService::AddressBookUpdate update );

};



#endif
