/***************************************************************************
                          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 <qmutex.h>
#include <qobject.h>
#include <qtimer.h>
#include <qvaluelist.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;

/**The class provides basic networking commands to the particular connection types.
  *@author Mike K. Bennett
  */

class MsnConnection : public QObject
{
  Q_OBJECT

  friend class KMessTest;

  public:
    //only when Dest Server is connected(not just Proxy Server), throw CONNTECTED
    enum PROXYSTATE     { PROXYCONNECTED, PROXYERROR, PROXYFAIL, PROXYHOSTCONNECTED };

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

  protected: // Protected methods
    // The constructor
                         MsnConnection(QString identifier);
    // Replace any "%" values with their regular values, i.e. "%20" to " ".
    void                 addPercents(QString &word) const;
    // Connect to the given server via the socket
    bool                 connectToServer(const QString& server, const int& port);
    // Disconnect from the server, if connected
    void                 disconnectFromServer( bool isTransfer = false );
    // Get the IP address of this machine.
    QString              getLocalIp() const;
    // Get whether we're sending pings or not
    bool                 getSendPings() const;
    // Extract some information from a message (like "Name: Joe" - extract the "Joe")
    QString              getValueFromMessage(const QString& field, const QString& message, bool goToEndOfLine = false) const;
    // Initialize the object
    bool                 initialize();
    // Parse a regular command
    virtual void         parseCommand(const QStringList& command) = 0;
    // Parse a message command
    virtual void         parseMessage(const QStringList& command, const MimeMessage &message) = 0;
    // Show a message that the proxy failed
    virtual void         proxyFailed();
    // Insert "%" values for certain regular expressions, i.e. "%20" for " ".
    void                 removePercents(QString &word) const;
    // 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
    enum AckType
    {
      // If ordering is changed, update sendMimeMessage()
      ACK_NONE,
      ACK_NAK_ONLY,
      ACK_ALWAYS,
      ACK_ALWAYS_P2P
    };
    int                  sendMimeMessage(AckType ackType, const MimeMessage &message);
    // Set whether we're sending pings or not (also resets ping timer)
    void                 setSendPings( bool sendPings );

  protected: // Protected attributes
    // A pointer to the instance of the current account
    CurrentAccount      *currentAccount_;

  protected slots: // Protected slots
    // Send all waiting messages and allow further writes to the socket
    virtual void         connectionSuccess();

  private: // Private methods
    // Connect to the given server, not using the proxy
    bool                 connectToServerDirectly(const QString& server, const int& port);
    // Connect to the given server via the proxy
    bool                 connectToServerViaProxy(const QString& server, const int& port);
    // Return an acknowledgement number
    int                  getAck();
    // Resets the ping timer
    void                 resetPingTimer();
    // Connect proper slots to socket_'s signals after the host has been connected
    void                 reconnectSocketSignal(bool hostconnected);
    // Dealing different proxy state, implemented in class MsnNotificationConnection
    void                 setProxyState(PROXYSTATE state);
    // Send authentication info to the socks5 server
    void                 socks5_auth(void);
    // Finally connect to the destination through the socks5 server
    void                 socks5_connect(void);
    // Send different request(send authentication info, connect to the destination)
    // to the socks5 server according to its reply
    void                 socks5_reply(const char *buf,int nread);
    // Write data to the socket
    void                 writeData(const QString& data);
    // Write data to the socket without conversions
    void                 writeBinaryData(const QByteArray& data);
    // Write data to the socket dealing requests and replies with the proxy
    void                 writeProxyData(const char *buf,int len);

  private slots: // Private slots
    // Read data from the socket
    void                 dataReceived();
     // Send a "ping" to the server
    void                 sendPing();
     // Proxy connected, now send furthur requests
    void                 proxyConnected(void);
    // Read proxy reply data from the socket
    void                 proxyDataReceived(void);
    // Detect a socket error
    void                 socketError(int error);


  private: // Private attributes
    // An acknowledgement number
    int                  ack_;
    // Save the port of the host that we want to connect through a proxy
    int                  destPort_;
    // Save the name of the host  that we want to connect through a proxy
    QString              destServer_;
    // 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_;
    // Protect the write process to the socket
    QMutex               mproxywriteLocked_;
    // Indicate which phase we are at during the interaction with the proxy
    int                  proxyState_;
    // Store the host's info and send it to the proxy
    struct               sockaddr_in addr_destServer_;  // TODO: Make sure this is not needed. Causes compile error in FreeBSD (or include netinet/in.h, but I don't see why this struct is needed here)
    // A lock on the write command so that hopefully two messages aren't sent simultaneously.
    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 some connection information
    void                 statusMessage( QString message, int connectStatus );
    /// Signal that a message was received on the connection
    void                 messageReceived(const QString &msg);
    /// Signal that a message was sent out on the connection
    void                 messageSent(const QString &msg);

};

#endif
