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

msnconnection.h

/***************************************************************************
                          msnconnection.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 MSNCONNECTION_H
#define MSNCONNECTION_H

#include "kmessbuffer.h"
#include "multipacketmessage.h"

#include "../kmessinterface.h"

#include <qobject.h>
#include <qtimer.h>
#include <qvaluelist.h>
#include <qdict.h>

#include <kextsock.h>

#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <string.h>

// Forward declarations
class CurrentAccount;
class KMessTest;
class MimeMessage;
class QMutex;

/**
 * @brief The base functionality for the MSN server protocol handling.
 * 
 * The class provides the following facilities:
 * - asynchronous connection to the MSN servers.
 * - parsing the network data into protocol commands.
 * - sending protocol commands and payloads.
 * - built-in handling of <code>PNG</code> commands, to keep the connection alive.
 * - built-in handling of multi-packet <code>MSG</code> commands.
 *
 * Data from the server is handled by the dataReceived() slot.
 * This method buffers and processes the data, until a complete command or payload message is received.
 * Then, it calls one of the following methods to deliver the message the a derived class:
 * - parseCommand()
 * - parseMessage()
 * - parsePayloadMessage()
 * - isPayloadCommand()
 *
 * These methods are implemented in the derived classes,
 * to handle the action for every command.
 *
 * To send protocol commands to the server, use:
 * - sendCommand()
 * - sendMimeMessage()
 * - sendPayloadMessage()
 *
 * @author Mike K. Bennett
 * @ingroup NetworkCore
 */
00075 class MsnConnection : public QObject
{
  Q_OBJECT

  friend class KMessTest;

  public:
    // The destructor
                        ~MsnConnection();
    // Whether or not the class is connected
    bool                 isConnected() const;

  protected: // Protected methods
    // If ordering is changed, update sendMimeMessage()
    /// Ack type parameter for sendMimeMessage()
00090     enum AckType
    {
00092       ACK_NONE,       ///< Don't request any ACK message.
00093       ACK_NAK_ONLY,   ///< Send a NAK on failure, but nothing on success.
00094       ACK_ALWAYS,     ///< Send a NAK on failure, and ACK on success
00095       ACK_ALWAYS_P2P  ///< Special case for P2P data messsages ('<code>D</code>' type).
    };

    // The constructor
                         MsnConnection( const char *name = 0 );
    /**
     * @brief Close the connection.
     *
     * This method is called by this class only
     * when the connection needs to be closed.
     */
    virtual void         closeConnection() = 0;
    // Connect to the given server via the socket
    bool                 connectToServer( const QString& server, const int port = 1863 );
    // Disconnect from the server, if connected
    void                 disconnectFromServer( bool isTransfer = false );
    // Get the IP address of this machine.
    QString              getLocalIp() const;
    // Initialize the object
    bool                 initialize();
    // Test whether the given command is a payload command
    virtual bool         isPayloadCommand(const QString &command) const;
    /**
     * @brief Process a received command
     *
     * A command may look like:
     * @code
ADC 27 AL N=someone@kmessdemo.org
@endcode
     * This is a confirmation of a sent command (with ACK-number 27) that the contact someone@kmessdemo.org was added to the allow (<code>AL</code>) list.
     *
     * The command is always a three-letter acronym, stored in <code>command[0]</code>
     * Arguments are separated by spaces, stored in the remaining <code>command[1..n]</code> elements.
     *
     * Most commands sent with sendCommand() are echo'ed back to the client.
     * This is not only a confirmation, but also allow event-based development
     * (or Model-Viewer-Controller; the server is the model in this situation).
     * Instead of assuming a command like "add contact" succeeds,
     * the client simply waits for a returned <code>ADC</code> command.
     * Hence, the same <code>ADC</code> command is also used to report about new contacts.
     * The client only have to execute that the server intructs to do.
     *
     * When an error occurs, the command is a three-diget code, followed by the ACK-number of the sent command.
     * For example, in response to a <code>CAL</code> command, the server may return code <code>217</code>; "person is offline or invisible".
     * @code
>>> CAL 2 myname@kmessdemo.org
@endcode
     * @code
<<< 217 2
@endcode
     *
     * Some commands, like <code>MSG</code> or <code>UBX</code> are followed by a payload.
     * These commands are handled by parseMessage() or parsePayloadMessage().
     *
     * @param  command  The command and arguments.
     */
    virtual void         parseCommand(const QStringList& command) = 0;
    /**
     * @brief Process a received MIME message.
     *
     * A incoming message may look like:
     * @code
MSG somecontact@kmessdemo.org KMessDemo 146
@endcode
     * @code
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-MMS-IM-Format: FN=Arial; EF=; CO=0; CS=0; PF=0

no prob. How is development doing?
@endcode
     * 
     * Notice the MIME-style header, and body below.
     * The <code>Content-Type</code> header indicates the message type,
     * for example: <code>text/plain</code> (a chat message)
     * <code>text/x-mms-emoticon</code> (custom emoticon definition)
     * or <code>text/x-msmsgsemailnotification</code> (new e-mail notification).
     *
     * All MIME messages are preceeded by the <code>MSG</code> command.
     * This command is not delivered to parseCommand().
     * Instead, this class waits for the payload (the MIME message) to arrive.
     * The complete command and payload is forwarded to this method.
     * When the MIME message was splitted in a multi-packet message,
     * it's merged before this method is called.
     * The last argument of <code>command</code> can be ignored.
     * It indicates the size of the payload, in this case 146 bytes.
     *
     * @param  command  The MSG command and it's arguments
     * @param  message  The MIME message which followed the command.
     */
    virtual void         parseMessage(const QStringList& command, const MimeMessage &message) = 0;
    /**
     * @brief Process a received payload message
     *
     * A incoming message may look like:
     * @code
UBX someuser@kmessdemo.org 67
@endcode
     * @code
<Data><PSM>hello everyone</PSM><CurrentMedia></CurrentMedia></Data>
@endcode
     *
     * Notice the similarities with parseMessage().
     * Both methods handle commands followed by payloads,
     * but differ in the type of messages:
     * - parseMessage() only handles MIME payloads of the <code>MSG</code> command.
     * - this method handles any payload of a command returned by isPayloadCommand().
     *
     * The value of <code>command[0]</code> indicates which command is received.
     * The payload may have any contents, although XML has only been observed so far.
     * The last argument of <code>command</code> can be ignored.
     * It indicates the size of the payload, in this case 67 bytes.
     *
     * @param  command  The received command and it's arguments.
     * @param  payload  The message payload which followed the command.
     */
    virtual void         parsePayloadMessage(const QStringList &command, const QByteArray &messageData) = 0;
    // Send a command to the server, returning the ack
    int                  sendCommand(const QString& prefix, const QString &text = "\r\n");
    // Send a command to the server, returning the ack
    int                  sendMimeMessage(AckType ackType, const MimeMessage &message);
    // Send a payload command to the server, convenience function
    int                  sendPayloadMessage(const QString &prefix, const QString &arguments, const QString &payload);
    // Send a payload command to the server
    int                  sendPayloadMessage(const QString &prefix, const QString &arguments, const QByteArray &payload);
    // Set whether we're sending pings or not (also resets ping timer)
    void                 setSendPings( bool sendPings );

  protected: // Protected attributes
    /// The instance of the current account
00225     CurrentAccount      *currentAccount_;

  protected slots: // Protected slots
    /**
     * @brief Called when the connection attempt is successful.
     *
     * This allows the first command to be sent.
     */
    virtual void         connectionSuccess() = 0;

  private: // Private methods
    // Resets the ping timer
    void                 resetPingTimer();
    // Write data to the socket
    void                 writeData(const QString& data);
    // Write data to the socket without conversions
    void                 writeBinaryData(const QByteArray& data);

  private slots: // Private slots
    // Detect a socket error
    void                 connectionClosed(int state);
    // Detect a socket error
    void                 connectionFailed(int error);
    // Read data from the socket
    void                 dataReceived();
    // Server name lookup has been completed
    void                 lookupFinished();
     // Send a "ping" to the server
    void                 sendPing();


  private: // Private attributes
    // An acknowledgement number
    int                  ack_;
    // State variable to detect whether the client or server disconnected
    bool                 disconnected_;
    // Whether or not the object was initialized
    bool                 initialized_;
    // Number of errant pings since last good one
    int                  missedPings_;
    // Whether the last ping send got a reply
    bool                 pingReceived_;
    // A timer to regularly "ping" the server
    QTimer               pingTimer_;
    // Are we sending pings?
    bool                 sendPings_;
    // The socket
    KExtendedSocket     *socket_;
    // A buffer for multi-packet messages
    QDict<MultiPacketMessage> multiPacketBuffer_;
    bool                 writeLocked_;
    // A buffer where we save the data until a command is received complete
    KMessBuffer          buffer_;

  signals: // Public signals
    // Signal that the server has disconnected
    void                 disconnected();
    // Signal that a ping to the connection has been sent
    void                 pingSent();
    // Signal to send information to the main window's status bar
    void                 statusMessage( QString message, KMessInterface::ConnectionStatus connectStatus );

};

#endif

Generated by  Doxygen 1.6.0   Back to index