]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_spanningtree/treesocket.h
OOPS! We try again, since I'm smoking craq. LF is 0x0a NOT CR.
[user/henk/code/inspircd.git] / src / modules / m_spanningtree / treesocket.h
index bd99c1480e315493bbf77a7a232ddf944c98ec9d..fae22638d6c8d4c030184e74f93fda7c0eebcd04 100644 (file)
@@ -1 +1,413 @@
-/*       +------------------------------------+\r *       | Inspire Internet Relay Chat Daemon |\r *       +------------------------------------+\r *\r *  InspIRCd: (C) 2002-2007 InspIRCd Development Team\r * See: http://www.inspircd.org/wiki/index.php/Credits\r *\r * This program is free but copyrighted software; see\r *            the file COPYING for details.\r *\r * ---------------------------------------------------\r */\r\r#ifndef __TREESOCKET_H__\r#define __TREESOCKET_H__\r\r#include "configreader.h"\r#include "users.h"\r#include "channels.h"\r#include "modules.h"\r#include "commands/cmd_whois.h"\r#include "commands/cmd_stats.h"\r#include "socket.h"\r#include "inspircd.h"\r#include "wildcard.h"\r#include "xline.h"\r#include "transport.h"\r\r#include "m_spanningtree/utils.h"\r\r/*\r * The server list in InspIRCd is maintained as two structures\r * which hold the data in different ways. Most of the time, we\r * want to very quicky obtain three pieces of information:\r *\r * (1) The information on a server\r * (2) The information on the server we must send data through\r *     to actually REACH the server we're after\r * (3) Potentially, the child/parent objects of this server\r *\r * The InspIRCd spanning protocol provides easy access to these\r * by storing the data firstly in a recursive structure, where\r * each item references its parent item, and a dynamic list\r * of child items, and another structure which stores the items\r * hashed, linearly. This means that if we want to find a server\r * by name quickly, we can look it up in the hash, avoiding\r * any O(n) lookups. If however, during a split or sync, we want\r * to apply an operation to a server, and any of its child objects\r * we can resort to recursion to walk the tree structure.\r * Any socket can have one of five states at any one time.\r * The LISTENER state indicates a socket which is listening\r * for connections. It cannot receive data itself, only incoming\r * sockets.\r * The CONNECTING state indicates an outbound socket which is\r * waiting to be writeable.\r * The WAIT_AUTH_1 state indicates the socket is outbound and\r * has successfully connected, but has not yet sent and received\r * SERVER strings.\r * The WAIT_AUTH_2 state indicates that the socket is inbound\r * (allocated by a LISTENER) but has not yet sent and received\r * SERVER strings.\r * The CONNECTED state represents a fully authorized, fully\r * connected server.\r */\renum ServerState { LISTENER, CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED };\r\r/** Every SERVER connection inbound or outbound is represented by\r * an object of type TreeSocket.\r * TreeSockets, being inherited from InspSocket, can be tied into\r * the core socket engine, and we cn therefore receive activity events\r * for them, just like activex objects on speed. (yes really, that\r * is a technical term!) Each of these which relates to a locally\r * connected server is assocated with it, by hooking it onto a\r * TreeSocket class using its constructor. In this way, we can\r * maintain a list of servers, some of which are directly connected,\r * some of which are not.\r */\rclass TreeSocket : public InspSocket\r{\r     SpanningTreeUtilities* Utils;           /* Utility class */\r    std::string myhost;                     /* Canonical hostname */\r       std::string in_buffer;                  /* Input buffer */\r     ServerState LinkState;                  /* Link state */\r       std::string InboundServerName;          /* Server name sent to us by other side */\r     std::string InboundDescription;         /* Server description (GECOS) sent to us by the other side */\r  int num_lost_users;                     /* Users lost in split */\r      int num_lost_servers;                   /* Servers lost in split */\r    time_t NextPing;                        /* Time when we are due to ping this server */\r bool LastPingWasGood;                   /* Responded to last ping we sent? */\r  bool bursting;                          /* True if not finished bursting yet */\r        unsigned int keylength;                 /* Is this still used? */\r      std::string ModuleList;                 /* Module list of other server from CAPAB */\r   std::map<std::string,std::string> CapKeys;      /* CAPAB keys from other server */\r     Module* Hook;                           /* I/O hooking module that we're attached to for this socket */\r        std::string ourchallenge;               /* Challenge sent for challenge/response */\r    std::string theirchallenge;             /* Challenge recv for challenge/response */\r    std::string OutboundPass;               /* Outbound password */\r        bool sentcapab;                         /* Have sent CAPAB already */\r public:\r\r        /** Because most of the I/O gubbins are encapsulated within\r     * InspSocket, we just call the superclass constructor for\r      * most of the action, and append a few of our own values\r       * to it.\r       */\r    TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, Module* HookMod = NULL);\r\r     /** Because most of the I/O gubbins are encapsulated within\r     * InspSocket, we just call the superclass constructor for\r      * most of the action, and append a few of our own values\r       * to it.\r       */\r    TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Module* HookMod = NULL);\r\r   /** When a listening socket gives us a new file descriptor,\r     * we must associate it with a socket without creating a new\r    * connection. This constructor is used for this purpose.\r       */\r    TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Module* HookMod = NULL);\r\r   /** Get link state\r      */\r    ServerState GetLinkState();\r\r   /** Get challenge set in our CAPAB for challenge/response\r       */\r    const std::string& GetOurChallenge();\r\r /** Get challenge set in our CAPAB for challenge/response\r       */\r    void SetOurChallenge(const std::string &c);\r\r   /** Get challenge set in their CAPAB for challenge/response\r     */\r    const std::string& GetTheirChallenge();\r\r       /** Get challenge set in their CAPAB for challenge/response\r     */\r    void SetTheirChallenge(const std::string &c);\r\r /** Compare two passwords based on authentication scheme\r        */\r    bool ComparePass(const std::string &ours, const std::string &theirs);\r\r /** Return the module which we are hooking to for I/O encapsulation\r     */\r    Module* GetHook();\r\r    /** Destructor\r  */\r    ~TreeSocket();\r\r        /** Generate random string used for challenge-response auth\r     */\r    std::string RandString(unsigned int length);\r\r  /** Construct a password, optionally hashed with the other side's\r       * challenge string\r     */\r    std::string MakePass(const std::string &password, const std::string &challenge);\r\r      /** When an outbound connection finishes connecting, we receive\r         * this event, and must send our SERVER string to the other\r     * side. If the other side is happy, as outlined in the server\r  * to server docs on the inspircd.org site, the other side\r      * will then send back its own server string.\r   */\r    virtual bool OnConnected();\r\r   /** Handle socket error event\r   */\r    virtual void OnError(InspSocketError e);\r\r      /** Sends an error to the remote server, and displays it locally to show\r        * that it was sent.\r    */\r    void SendError(const std::string &errormessage);\r\r      /** Handle socket disconnect event\r      */\r    virtual int OnDisconnect();\r\r   /** Recursively send the server tree with distances as hops.\r    * This is used during network burst to inform the other server\r         * (and any of ITS servers too) of what servers we know about.\r  * If at any point any of these servers already exist on the other\r      * end, our connection may be terminated. The hopcounts given\r   * by this function are relative, this doesn't matter so long as\r        * they are all >1, as all the remote servers re-calculate them\r         * to be relative too, with themselves as hop 0.\r        */\r    void SendServers(TreeServer* Current, TreeServer* s, int hops);\r\r       /** Returns my capabilities as a string\r         */\r    std::string MyCapabilities();\r\r /** Send my capabilities to the remote side\r     */\r    void SendCapabilities();\r\r      /* Check a comma seperated list for an item */\r bool HasItem(const std::string &list, const std::string &item);\r\r       /* Isolate and return the elements that are different between two comma seperated lists */\r     std::string ListDifference(const std::string &one, const std::string &two);\r\r   bool Capab(const std::deque<std::string> &params);\r\r    /** This function forces this server to quit, removing this server\r      * and any users on it (and servers and users below that, etc etc).\r     * It's very slow and pretty clunky, but luckily unless your network\r    * is having a REAL bad hair day, this function shouldnt be called\r      * too many times a month ;-)\r   */\r    void SquitServer(std::string &from, TreeServer* Current);\r\r     /** This is a wrapper function for SquitServer above, which\r     * does some validation first and passes on the SQUIT to all\r    * other remaining servers.\r     */\r    void Squit(TreeServer* Current, const std::string &reason);\r\r   /** FMODE command - server mode with timestamp checks */\r       bool ForceMode(const std::string &source, std::deque<std::string> &params);\r\r   /** FTOPIC command */\r  bool ForceTopic(const std::string &source, std::deque<std::string> &params);\r\r  /** FJOIN, similar to TS6 SJOIN, but not quite. */\r     bool ForceJoin(const std::string &source, std::deque<std::string> &params);\r\r   /** NICK command */\r    bool IntroduceClient(const std::string &source, std::deque<std::string> &params);\r\r     /** Send one or more FJOINs for a channel of users.\r     * If the length of a single line is more than 480-NICKMAX\r      * in length, it is split over multiple lines.\r  */\r    void SendFJoins(TreeServer* Current, chanrec* c);\r\r     /** Send G, Q, Z and E lines */\r        void SendXLines(TreeServer* Current);\r\r /** Send channel modes and topics */\r   void SendChannelModes(TreeServer* Current);\r\r   /** send all users and their oper state/modes */\r       void SendUsers(TreeServer* Current);\r\r  /** This function is called when we want to send a netburst to a local\r  * server. There is a set order we must do this, because for example\r    * users require their servers to exist, and channels require their\r     * users to exist. You get the idea.\r    */\r    void DoBurst(TreeServer* s);\r\r  /** This function is called when we receive data from a remote\r  * server. We buffer the data in a std::string (it doesnt stay\r  * there for long), reading using InspSocket::Read() which can\r  * read up to 16 kilobytes in one operation.\r    *\r      * IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES\r  * THE SOCKET OBJECT FOR US.\r    */\r    virtual bool OnDataReady();\r\r   /** Send one or more complete lines down the socket\r     */\r    int WriteLine(std::string line);\r\r      /** Handle ERROR command */\r    bool Error(std::deque<std::string> &params);\r\r  /** remote MOTD. leet, huh? */\r bool Motd(const std::string &prefix, std::deque<std::string> &params);\r\r        /** remote ADMIN. leet, huh? */\r        bool Admin(const std::string &prefix, std::deque<std::string> &params);\r\r       /** Remote MODULES */\r  bool Modules(const std::string &prefix, std::deque<std::string> &params);\r\r     bool Stats(const std::string &prefix, std::deque<std::string> &params);\r\r       /** Because the core won't let users or even SERVERS set +o,\r    * we use the OPERTYPE command to do this.\r      */\r    bool OperType(const std::string &prefix, std::deque<std::string> &params);\r\r    /** Because Andy insists that services-compatible servers must\r  * implement SVSNICK and SVSJOIN, that's exactly what we do :p\r  */\r    bool ForceNick(const std::string &prefix, std::deque<std::string> &params);\r\r   bool OperQuit(const std::string &prefix, std::deque<std::string> &params);\r\r    /** SVSJOIN\r     */\r    bool ServiceJoin(const std::string &prefix, std::deque<std::string> &params);\r\r /** REHASH\r      */\r    bool RemoteRehash(const std::string &prefix, std::deque<std::string> &params);\r\r        /** KILL\r        */\r    bool RemoteKill(const std::string &prefix, std::deque<std::string> &params);\r\r  /** PONG\r        */\r    bool LocalPong(const std::string &prefix, std::deque<std::string> &params);\r\r   /** METADATA\r    */\r    bool MetaData(const std::string &prefix, std::deque<std::string> &params);\r\r    /** VERSION\r     */\r    bool ServerVersion(const std::string &prefix, std::deque<std::string> &params);\r\r       /** CHGHOST\r     */\r    bool ChangeHost(const std::string &prefix, std::deque<std::string> &params);\r\r  /** ADDLINE\r     */\r    bool AddLine(const std::string &prefix, std::deque<std::string> &params);\r\r     /** CHGNAME\r     */\r    bool ChangeName(const std::string &prefix, std::deque<std::string> &params);\r\r  /** WHOIS\r       */\r    bool Whois(const std::string &prefix, std::deque<std::string> &params);\r\r       /** PUSH\r        */\r    bool Push(const std::string &prefix, std::deque<std::string> &params);\r\r        /** SETTIME\r     */\r    bool HandleSetTime(const std::string &prefix, std::deque<std::string> &params);\r\r       /** TIME\r        */\r    bool Time(const std::string &prefix, std::deque<std::string> &params);\r\r        /** PING\r        */\r    bool LocalPing(const std::string &prefix, std::deque<std::string> &params);\r\r   /** Remove all modes from a channel, including statusmodes (+qaovh etc), simplemodes, parameter modes.\r  * This does not update the timestamp of the target channel, this must be done seperately.\r      */\r    bool RemoveStatus(const std::string &prefix, std::deque<std::string> &params);\r\r        /** <- (remote) <- SERVER\r       */\r    bool RemoteServer(const std::string &prefix, std::deque<std::string> &params);\r\r        /** (local) -> SERVER\r   */\r    bool Outbound_Reply_Server(std::deque<std::string> &params);\r\r  /** (local) <- SERVER\r   */\r    bool Inbound_Server(std::deque<std::string> &params);\r\r /** Handle netsplit\r     */\r    void Split(const std::string &line, std::deque<std::string> &n);\r\r      /** Process complete line from buffer\r   */\r    bool ProcessLine(std::string &line);\r\r  /** Get this server's name\r      */\r    virtual std::string GetName();\r\r        /** Handle socket timeout from connect()\r        */\r    virtual void OnTimeout();\r\r     /** Handle socket close event\r   */\r    virtual void OnClose();\r\r       /** Handle incoming connection event\r    */\r    virtual int OnIncomingConnection(int newsock, char* ip);\r};\r\r/* Used to validate the value lengths of multiple parameters for a command */\rstruct cmd_validation\r{\r     const char* item;\r      size_t param;\r  size_t length;\r};\r\r/* Used to validate the length values in CAPAB CAPABILITIES */\rstruct cap_validation\r{\r      const char* reason;\r    const char* key;\r       size_t size;\r};\r\r#endif\r\r
\ No newline at end of file
+/*       +------------------------------------+
+ *       | Inspire Internet Relay Chat Daemon |
+ *       +------------------------------------+
+ *
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
+ * This program is free but copyrighted software; see
+ *            the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+#ifndef __TREESOCKET_H__
+#define __TREESOCKET_H__
+
+#include "configreader.h"
+#include "users.h"
+#include "channels.h"
+#include "modules.h"
+#include "commands/cmd_whois.h"
+#include "commands/cmd_stats.h"
+#include "socket.h"
+#include "inspircd.h"
+#include "wildcard.h"
+#include "xline.h"
+#include "transport.h"
+
+#include "m_spanningtree/utils.h"
+
+/*
+ * The server list in InspIRCd is maintained as two structures
+ * which hold the data in different ways. Most of the time, we
+ * want to very quicky obtain three pieces of information:
+ *
+ * (1) The information on a server
+ * (2) The information on the server we must send data through
+ *     to actually REACH the server we're after
+ * (3) Potentially, the child/parent objects of this server
+ *
+ * The InspIRCd spanning protocol provides easy access to these
+ * by storing the data firstly in a recursive structure, where
+ * each item references its parent item, and a dynamic list
+ * of child items, and another structure which stores the items
+ * hashed, linearly. This means that if we want to find a server
+ * by name quickly, we can look it up in the hash, avoiding
+ * any O(n) lookups. If however, during a split or sync, we want
+ * to apply an operation to a server, and any of its child objects
+ * we can resort to recursion to walk the tree structure.
+ * Any socket can have one of five states at any one time.
+ * The LISTENER state indicates a socket which is listening
+ * for connections. It cannot receive data itself, only incoming
+ * sockets.
+ * The CONNECTING state indicates an outbound socket which is
+ * waiting to be writeable.
+ * The WAIT_AUTH_1 state indicates the socket is outbound and
+ * has successfully connected, but has not yet sent and received
+ * SERVER strings.
+ * The WAIT_AUTH_2 state indicates that the socket is inbound
+ * (allocated by a LISTENER) but has not yet sent and received
+ * SERVER strings.
+ * The CONNECTED state represents a fully authorized, fully
+ * connected server.
+ */
+enum ServerState { LISTENER, CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED };
+
+/** Every SERVER connection inbound or outbound is represented by
+ * an object of type TreeSocket.
+ * TreeSockets, being inherited from InspSocket, can be tied into
+ * the core socket engine, and we cn therefore receive activity events
+ * for them, just like activex objects on speed. (yes really, that
+ * is a technical term!) Each of these which relates to a locally
+ * connected server is assocated with it, by hooking it onto a
+ * TreeSocket class using its constructor. In this way, we can
+ * maintain a list of servers, some of which are directly connected,
+ * some of which are not.
+ */
+class TreeSocket : public InspSocket
+{
+       SpanningTreeUtilities* Utils;           /* Utility class */
+       std::string myhost;                     /* Canonical hostname */
+       std::string in_buffer;                  /* Input buffer */
+       ServerState LinkState;                  /* Link state */
+       std::string InboundServerName;          /* Server name sent to us by other side */
+       std::string InboundDescription;         /* Server description (GECOS) sent to us by the other side */
+       int num_lost_users;                     /* Users lost in split */
+       int num_lost_servers;                   /* Servers lost in split */
+       time_t NextPing;                        /* Time when we are due to ping this server */
+       bool LastPingWasGood;                   /* Responded to last ping we sent? */
+       bool bursting;                          /* True if not finished bursting yet */
+       unsigned int keylength;                 /* Is this still used? */
+       std::string ModuleList;                 /* Module list of other server from CAPAB */
+       std::map<std::string,std::string> CapKeys;      /* CAPAB keys from other server */
+       Module* Hook;                           /* I/O hooking module that we're attached to for this socket */
+       std::string ourchallenge;               /* Challenge sent for challenge/response */
+       std::string theirchallenge;             /* Challenge recv for challenge/response */
+       std::string OutboundPass;               /* Outbound password */
+       bool sentcapab;                         /* Have sent CAPAB already */
+ public:
+
+       /** Because most of the I/O gubbins are encapsulated within
+        * InspSocket, we just call the superclass constructor for
+        * most of the action, and append a few of our own values
+        * to it.
+        */
+       TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, Module* HookMod = NULL);
+
+       /** Because most of the I/O gubbins are encapsulated within
+        * InspSocket, we just call the superclass constructor for
+        * most of the action, and append a few of our own values
+        * to it.
+        */
+       TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, std::string host, int port, bool listening, unsigned long maxtime, const std::string &ServerName, const std::string &bindto, Module* HookMod = NULL);
+
+       /** When a listening socket gives us a new file descriptor,
+        * we must associate it with a socket without creating a new
+        * connection. This constructor is used for this purpose.
+        */
+       TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, char* ip, Module* HookMod = NULL);
+
+       /** Get link state
+        */
+       ServerState GetLinkState();
+
+       /** Get challenge set in our CAPAB for challenge/response
+        */
+       const std::string& GetOurChallenge();
+
+       /** Get challenge set in our CAPAB for challenge/response
+        */
+       void SetOurChallenge(const std::string &c);
+
+       /** Get challenge set in their CAPAB for challenge/response
+        */
+       const std::string& GetTheirChallenge();
+
+       /** Get challenge set in their CAPAB for challenge/response
+        */
+       void SetTheirChallenge(const std::string &c);
+
+       /** Compare two passwords based on authentication scheme
+        */
+       bool ComparePass(const std::string &ours, const std::string &theirs);
+
+       /** Return the module which we are hooking to for I/O encapsulation
+        */
+       Module* GetHook();
+
+       /** Destructor
+        */
+       ~TreeSocket();
+
+       /** Generate random string used for challenge-response auth
+        */
+       std::string RandString(unsigned int length);
+
+       /** Construct a password, optionally hashed with the other side's
+        * challenge string
+        */
+       std::string MakePass(const std::string &password, const std::string &challenge);
+
+       /** When an outbound connection finishes connecting, we receive
+        * this event, and must send our SERVER string to the other
+        * side. If the other side is happy, as outlined in the server
+        * to server docs on the inspircd.org site, the other side
+        * will then send back its own server string.
+        */
+       virtual bool OnConnected();
+
+       /** Handle socket error event
+        */
+       virtual void OnError(InspSocketError e);
+
+       /** Sends an error to the remote server, and displays it locally to show
+        * that it was sent.
+        */
+       void SendError(const std::string &errormessage);
+
+       /** Handle socket disconnect event
+        */
+       virtual int OnDisconnect();
+
+       /** Recursively send the server tree with distances as hops.
+        * This is used during network burst to inform the other server
+        * (and any of ITS servers too) of what servers we know about.
+        * If at any point any of these servers already exist on the other
+        * end, our connection may be terminated. The hopcounts given
+        * by this function are relative, this doesn't matter so long as
+        * they are all >1, as all the remote servers re-calculate them
+        * to be relative too, with themselves as hop 0.
+        */
+       void SendServers(TreeServer* Current, TreeServer* s, int hops);
+
+       /** Returns my capabilities as a string
+        */
+       std::string MyCapabilities();
+
+       /** Send my capabilities to the remote side
+        */
+       void SendCapabilities();
+
+       /* Check a comma seperated list for an item */
+       bool HasItem(const std::string &list, const std::string &item);
+
+       /* Isolate and return the elements that are different between two comma seperated lists */
+       std::string ListDifference(const std::string &one, const std::string &two);
+
+       bool Capab(const std::deque<std::string> &params);
+
+       /** This function forces this server to quit, removing this server
+        * and any users on it (and servers and users below that, etc etc).
+        * It's very slow and pretty clunky, but luckily unless your network
+        * is having a REAL bad hair day, this function shouldnt be called
+        * too many times a month ;-)
+        */
+       void SquitServer(std::string &from, TreeServer* Current);
+
+       /** This is a wrapper function for SquitServer above, which
+        * does some validation first and passes on the SQUIT to all
+        * other remaining servers.
+        */
+       void Squit(TreeServer* Current, const std::string &reason);
+
+       /** FMODE command - server mode with timestamp checks */
+       bool ForceMode(const std::string &source, std::deque<std::string> &params);
+
+       /** FTOPIC command */
+       bool ForceTopic(const std::string &source, std::deque<std::string> &params);
+
+       /** FJOIN, similar to TS6 SJOIN, but not quite. */
+       bool ForceJoin(const std::string &source, std::deque<std::string> &params);
+
+       /** NICK command */
+       bool IntroduceClient(const std::string &source, std::deque<std::string> &params);
+
+       /** Send one or more FJOINs for a channel of users.
+        * If the length of a single line is more than 480-NICKMAX
+        * in length, it is split over multiple lines.
+        */
+       void SendFJoins(TreeServer* Current, chanrec* c);
+
+       /** Send G, Q, Z and E lines */
+       void SendXLines(TreeServer* Current);
+
+       /** Send channel modes and topics */
+       void SendChannelModes(TreeServer* Current);
+
+       /** send all users and their oper state/modes */
+       void SendUsers(TreeServer* Current);
+
+       /** This function is called when we want to send a netburst to a local
+        * server. There is a set order we must do this, because for example
+        * users require their servers to exist, and channels require their
+        * users to exist. You get the idea.
+        */
+       void DoBurst(TreeServer* s);
+
+       /** This function is called when we receive data from a remote
+        * server. We buffer the data in a std::string (it doesnt stay
+        * there for long), reading using InspSocket::Read() which can
+        * read up to 16 kilobytes in one operation.
+        *
+        * IF THIS FUNCTION RETURNS FALSE, THE CORE CLOSES AND DELETES
+        * THE SOCKET OBJECT FOR US.
+        */
+       virtual bool OnDataReady();
+
+       /** Send one or more complete lines down the socket
+        */
+       int WriteLine(std::string line);
+
+       /** Handle ERROR command */
+       bool Error(std::deque<std::string> &params);
+
+       /** remote MOTD. leet, huh? */
+       bool Motd(const std::string &prefix, std::deque<std::string> &params);
+
+       /** remote ADMIN. leet, huh? */
+       bool Admin(const std::string &prefix, std::deque<std::string> &params);
+
+       /** Remote MODULES */
+       bool Modules(const std::string &prefix, std::deque<std::string> &params);
+
+       bool Stats(const std::string &prefix, std::deque<std::string> &params);
+
+       /** Because the core won't let users or even SERVERS set +o,
+        * we use the OPERTYPE command to do this.
+        */
+       bool OperType(const std::string &prefix, std::deque<std::string> &params);
+
+       /** Because Andy insists that services-compatible servers must
+        * implement SVSNICK and SVSJOIN, that's exactly what we do :p
+        */
+       bool ForceNick(const std::string &prefix, std::deque<std::string> &params);
+
+       bool OperQuit(const std::string &prefix, std::deque<std::string> &params);
+
+       /** SVSJOIN
+        */
+       bool ServiceJoin(const std::string &prefix, std::deque<std::string> &params);
+
+       /** REHASH
+        */
+       bool RemoteRehash(const std::string &prefix, std::deque<std::string> &params);
+
+       /** KILL
+        */
+       bool RemoteKill(const std::string &prefix, std::deque<std::string> &params);
+
+       /** PONG
+        */
+       bool LocalPong(const std::string &prefix, std::deque<std::string> &params);
+
+       /** METADATA
+        */
+       bool MetaData(const std::string &prefix, std::deque<std::string> &params);
+
+       /** VERSION
+        */
+       bool ServerVersion(const std::string &prefix, std::deque<std::string> &params);
+
+       /** CHGHOST
+        */
+       bool ChangeHost(const std::string &prefix, std::deque<std::string> &params);
+
+       /** ADDLINE
+        */
+       bool AddLine(const std::string &prefix, std::deque<std::string> &params);
+
+       /** CHGNAME
+        */
+       bool ChangeName(const std::string &prefix, std::deque<std::string> &params);
+
+       /** WHOIS
+        */
+       bool Whois(const std::string &prefix, std::deque<std::string> &params);
+
+       /** PUSH
+        */
+       bool Push(const std::string &prefix, std::deque<std::string> &params);
+
+       /** SETTIME
+        */
+       bool HandleSetTime(const std::string &prefix, std::deque<std::string> &params);
+
+       /** TIME
+        */
+       bool Time(const std::string &prefix, std::deque<std::string> &params);
+
+       /** PING
+        */
+       bool LocalPing(const std::string &prefix, std::deque<std::string> &params);
+
+       /** Remove all modes from a channel, including statusmodes (+qaovh etc), simplemodes, parameter modes.
+        * This does not update the timestamp of the target channel, this must be done seperately.
+        */
+       bool RemoveStatus(const std::string &prefix, std::deque<std::string> &params);
+
+       /** <- (remote) <- SERVER
+        */
+       bool RemoteServer(const std::string &prefix, std::deque<std::string> &params);
+
+       /** (local) -> SERVER
+        */
+       bool Outbound_Reply_Server(std::deque<std::string> &params);
+
+       /** (local) <- SERVER
+        */
+       bool Inbound_Server(std::deque<std::string> &params);
+
+       /** Handle netsplit
+        */
+       void Split(const std::string &line, std::deque<std::string> &n);
+
+       /** Process complete line from buffer
+        */
+       bool ProcessLine(std::string &line);
+
+       /** Get this server's name
+        */
+       virtual std::string GetName();
+
+       /** Handle socket timeout from connect()
+        */
+       virtual void OnTimeout();
+
+       /** Handle socket close event
+        */
+       virtual void OnClose();
+
+       /** Handle incoming connection event
+        */
+       virtual int OnIncomingConnection(int newsock, char* ip);
+};
+
+/* Used to validate the value lengths of multiple parameters for a command */
+struct cmd_validation
+{
+       const char* item;
+       size_t param;
+       size_t length;
+};
+
+/* Used to validate the length values in CAPAB CAPABILITIES */
+struct cap_validation
+{
+       const char* reason;
+       const char* key;
+       size_t size;
+};
+
+#endif
+