/*
 * conn.h
 * see ezbounce.cpp and LICENCE for licence details  
 */

#ifndef __conn_h
#define __conn_h

class conn;

#include "ezbounce.h"

#define EZBOUNCE_HEADER "(ezbounce)!srv"

#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

#ifdef _USE_SSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#endif

#include "dynbuff.h"
#include "general.h"
#include "config.h"
#include "ruleset.h"
#include "dcc.h"
#include "linkedlist.h"
#include "logfile.h"
#include "socket.h"
#include "commands.h"
#include "user.h"
#include "ircaddr.h"
#include "timer.h"

/* this is for the prototypes */
#ifndef __CMDFUNC
#define __CMDFUNC(f) int do_##f##_cmd(int, int, char **)
#endif

/* for the actual function */
#ifndef CMDFUNC
#define CMDFUNC(f) int conn::do_##f##_cmd(int type, int argc, char * argv[])
#endif

const int MAX_PPCHAR_ARGS  = 8;

enum {
     NICKED                   =     0x8,
     USERED                   =    0x10,
     PWED                     =    0x20,
     CONNECTING               =    0x40,
     BOUNCED                  =    0x80,
     ADMIN                    =   0x100,
     DETACHED                 =   0x200,
     FROM_RULESETS_REGISTERED =   0x800,
     TO_RULESETS_REGISTERED   =  0x1000,
     GOTSERVINFO              =  0x2000,
     GOTSERVINFO2             =  0x4000,
     GOTSERVINFO3	      =  0x8000,		
     NDM                      = 0x10000, /* No Direct Match (when connected) */
     DEFAULT_USER             = 0x20000,
     PPE                      = 0x40000, /* Pong, Ping, Error */
     REGISTERED               = (NICKED | USERED | PWED)
};


class conn 
{
public:
    conn(int fd, bool);
    ~conn();

private:
    class psock : public pollsocket
    {
    public:
        psock(conn * owner, int f, bool * success, int min = 128, int max = 32768)
            : pollsocket::pollsocket(f, success, POLLIN, min, max)
        {
            this->owner = owner;
        }
    protected:
        conn * owner;
        virtual int event_handler(const struct pollfd * pfd);
        friend class conn;
    };
    friend class psock;

private:
    static unsigned num_active;
    static unsigned current_id;

    /* Traffic stats */
    static unsigned bytes_fromc,
                    bytes_toc,
                    bytes_froms,
                    bytes_tos;

    unsigned long id;
    list<ruleset> rulesets;

    /* Sockets */
    psock * client;
    psock * server;

    int stat;                                /* Numeric Flags */
    unsigned short failed_passwords;

    time_t connect_time,                      /* When user connected */
           last_recved,                       /* When last message received */
           detach_time;                       /* When we detached */

    /* The address & port we accepted connection on */
    struct sockaddr_in local_saddr;
    /* The address & port the client came from */
    struct sockaddr_in client_saddr;
    /* The address & port of the server we connected to */
    struct sockaddr_in serv_saddr;

    logfile * log;                            /* Detached logging facilities */
    strlist * loglist;                        /* List of log files open */
    timer   * detach_timer;

    userdef * user;                           /* Pointer to user structure */
    user_options * config;                    /* Shortcut for user->cfg or our own */

    class __uinfo
    {
    public:
        ircaddr * irc;                          /* Store IRC nickname, username, and host */
        char * fulladdr;                        /* Full address of user (as visible to ezbounce) */
        char * usercmd;                         /* USER command text supplied by user */
        char * server;                          /* Server user is connecting to */
        char * ircpass;                         /* optional pw supplied by user to be (sent to server on connect) */
        char * detachpass;

        char * serverversion;
        char * servercreated;
        char * servermodes;
        char * server005_1;
	char * server005_2;

        strlist channels;

        u_short port;                           /* Port we connected on */
        __uinfo();
        ~__uinfo();
    } uinfo;
    
public:
    static conn * lookup(list<conn> *, unsigned);

    static unsigned get_num_active(void)  
    {
        return num_active;
    }

    user_options * get_config() const
    {
        return config;
    }

    strlist * get_loglist()
    {
        return loglist;
    }

    bool dead() const
    { 
        return (!server && !client); 
    }
    unsigned get_id() const
    { 
        return id; 
    }
    bool registered() const
    { 
        return ((stat & PWED) && (stat & NICKED) && (stat & USERED)); 
    }
    const char * addr(void) const
    {
        return uinfo.fulladdr;
    }

    int check_server(int);
    int check_client(int); 
    
    void kill(const char *, const char *);
    void die(void);
    int  is_idle(time_t);
    char * mkstat(char *) const;
    int  cprintf(const char *, ...) const;
    int  cprintf_multiline(const char *) const;

    static void broadcast(list<conn> *, const char *);
    static void kill_dccs(void);
    static int  detached_timer_proc(time_t, int, void *);
    static list<dcc> dcc_list;

protected:
    int  parse(void);
    int  parse_from_server(void);
    int  init_rulesets(void);
    int  unregister_rulesets(char);
    int  is_authorized(void);

    int  detach(const char *);
    int  do_auto_detach(void);
    int  reattach(const char *, conn *);
    
    int  do_ctcp(bool incoming, const char * ctcp, const char * source, 
                  const char * target, const char * args);
    int  do_connect(const char *, unsigned short port, const char * pass, int);
    bool can_connect(const char *, unsigned short);
    bool copy_fake_ident(void);
    void show_motd(void) const;
    void show_whois(conn *) const;
    
    int  on_server_disconnect(int = 0);
    int  on_client_disconnect(int = 0);
    int  on_server_connect(int);
    int  on_client_connect(int);

private:
    /* The command handlers and such */
    static htbl cmdhash, incoming_hash;

public:
    static int  init_command_hash(void);

    __CMDFUNC(registration);
    __CMDFUNC(pass);
    __CMDFUNC(conn);
    __CMDFUNC(misc);
    __CMDFUNC(ident);
    __CMDFUNC(help);
    __CMDFUNC(ezb);
    __CMDFUNC(vhost);
    __CMDFUNC(vhosts);
    __CMDFUNC(detach);
    __CMDFUNC(reattach);
    __CMDFUNC(disconnect);
    __CMDFUNC(log);
    __CMDFUNC(quit);
    __CMDFUNC(motd);
    __CMDFUNC(status);
    __CMDFUNC(rehash);
    __CMDFUNC(write);
    __CMDFUNC(adminmisc);
    __CMDFUNC(hash);
    __CMDFUNC(privmsg);
    __CMDFUNC(login);
    __CMDFUNC(sessions);
    __CMDFUNC(traffic);
    __CMDFUNC(whois);
    __CMDFUNC(set);
    __CMDFUNC(save);
    __CMDFUNC(echo);
    __CMDFUNC(trace);
    __CMDFUNC(allowed);
    __CMDFUNC(reload);
    __CMDFUNC(about);
    __CMDFUNC(debug);
    __CMDFUNC(version);
#ifdef __DEBUG__
    __CMDFUNC(dccsend);
#endif

    /* incoming traps */
    __CMDFUNC(servinfo);
    __CMDFUNC(privmsg_incoming);
    __CMDFUNC(nick_incoming);
    __CMDFUNC(mode_incoming);
    __CMDFUNC(join_incoming);
    __CMDFUNC(part_incoming);
    __CMDFUNC(kick_incoming);
    __CMDFUNC(notice_incoming);
    __CMDFUNC(topic_incoming);
    __CMDFUNC(quit_incoming);
    __CMDFUNC(pong_incoming);
    __CMDFUNC(ping_incoming);
    __CMDFUNC(error_incoming);

protected:
    void   disown_dccs(conn *);
    dcc   * dcc_send_file(const char *, const char * = 0, struct sockaddr_in * = 0, bool = 0, bool = 0);
  
    /* To help with use of flags and such */
    inline int checkf(int flag) const
    {
        return (stat & flag);
    }
    inline int clearf(int flag)
    {
        return (stat &= ~(flag));
    }
    inline int setf(int flag)
    {
        return (stat |= flag);
    }
    inline int isadmin(void) const
    {
        return checkf(ADMIN);
    }
};      


enum  {
     CONN_NOWAITING = -50,                    // no data to read
     CONN_DISCONNECTED,                       // sock got disconnected during operation
     CONN_FAILED,                             // operation didn't work
     CONN_KILLME = -30,                       // fatal error, destroy this object   
     CONN_NOTCONNECTED,      
     CONN_FULL, 
     CONN_NOLINK, 
     CONN_LINK_ACTIVATED,                        
     CONN_LINK_DEACTIVATED
};

#endif


syntax highlighted by Code2HTML, v. 0.9.1