]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - include/modules.h
Move MODENOTICE command to a command module
[user/henk/code/inspircd.git] / include / modules.h
index f4a9b0fb6f2cacd308ac5d39c855e0df789d659d..dc59abdd91514be96dcfd3305293641ec3690377 100644 (file)
 #include "mode.h"
 #include "dns.h"
 
-class XLine;
-
-/** Used with OnAccessCheck() method of modules
- */
-enum AccessControlType {
-       ACR_DEFAULT,            // Do default action (act as if the module isnt even loaded)
-       ACR_DENY,               // deny the action
-       ACR_ALLOW,              // allow the action
-       AC_KICK,                // a user is being kicked
-       AC_DEOP,                // a user is being deopped
-       AC_OP,                  // a user is being opped
-       AC_VOICE,               // a user is being voiced
-       AC_DEVOICE,             // a user is being devoiced
-       AC_HALFOP,              // a user is being halfopped
-       AC_DEHALFOP,            // a user is being dehalfopped
-       AC_INVITE,              // a user is being invited
-       AC_GENERAL_MODE         // a channel mode is being changed
-};
-
 /** Used to define a set of behavior bits for a module
  */
 enum ModuleFlags {
+       VF_NONE = 0,            // module is not special at all
        VF_STATIC = 1,          // module is static, cannot be /unloadmodule'd
        VF_VENDOR = 2,          // module is a vendor module (came in the original tarball, not 3rd party)
-       VF_SERVICEPROVIDER = 4, // module provides a service to other modules (can be a dependency)
-       VF_COMMON = 8,          // module needs to be common on all servers in a network to link
-       VF_OPTCOMMON = 16       // module should be common on all servers for unsurprising behavior
-};
-
-/** Used with SendToMode()
- */
-enum WriteModeFlags {
-       WM_AND = 1,
-       WM_OR = 2
+       VF_COMMON = 4,          // module needs to be common on all servers in a network to link
+       VF_OPTCOMMON = 8,       // module should be common on all servers for unsurprising behavior
+       VF_CORE = 16            // module is a core command, can be assumed loaded on all servers
 };
 
 /** Used to represent an event type, for user, channel or server
@@ -77,61 +52,52 @@ enum MessageType {
        MSG_NOTICE = 1
 };
 
+#define MOD_RES_ALLOW (ModResult(1))
+#define MOD_RES_PASSTHRU (ModResult(0))
+#define MOD_RES_DENY (ModResult(-1))
+
 /** Used to represent an allow/deny module result.
  * Not constructed as an enum because it reverses the value logic of some functions;
  * the compiler will inline accesses to have the same efficiency as integer operations.
  */
 struct ModResult {
        int res;
+       ModResult() : res(0) {}
        explicit ModResult(int r) : res(r) {}
-       bool operator==(const ModResult& r) const
+       inline bool operator==(const ModResult& r) const
        {
                return res == r.res;
        }
-       bool operator!=(const ModResult& r) const
+       inline bool operator!=(const ModResult& r) const
        {
                return res != r.res;
        }
-       bool operator!() const
+       inline bool operator!() const
        {
                return !res;
        }
+       inline bool check(bool def) const
+       {
+               return (res == 1 || (res == 0 && def));
+       }
+       /**
+        * Merges two results, preferring ALLOW to DENY
+        */
+       inline ModResult operator+(const ModResult& r) const
+       {
+               if (res == r.res || r.res == 0)
+                       return *this;
+               if (res == 0)
+                       return r;
+               // they are different, and neither is passthru
+               return MOD_RES_ALLOW;
+       }
 };
 
-#define MOD_RES_ALLOW (ModResult(1))
-#define MOD_RES_PASSTHRU (ModResult(0))
-#define MOD_RES_DENY (ModResult(-1))
-
-/** If you change the module API, change this value. */
-#define API_VERSION 13000
-
-class ServerConfig;
-
-/* Forward-delacare module for ModuleMessage etc
- */
-class Module;
-class InspIRCd;
-
-/** Low level definition of a FileReader classes file cache area -
- * a text file seperated into lines.
- */
-typedef std::deque<std::string> file_cache;
-
-/** A set of strings.
- */
-typedef file_cache string_list;
-
-/** Holds a list of 'published features' for modules.
- */
-typedef std::map<std::string,Module*> featurelist;
-
-/** Holds a list of modules which implement an interface
- */
-typedef std::deque<Module*> modulelist;
-
-/** Holds a list of all modules which implement interfaces, by interface name
+/** If you change the module API in any way, increment this value.
+ * This MUST be a pure integer, with no parenthesis
  */
-typedef std::map<std::string, std::pair<int, modulelist> > interfacelist;
+#define API_VERSION 137
 
 /**
  * This #define allows us to call a method in all
@@ -156,99 +122,16 @@ typedef std::map<std::string, std::pair<int, modulelist> > interfacelist;
        } \
 } while (0);
 
-/**
- * This #define allows us to call a method in all
- * loaded modules in a readable simple way and pass
- * an instance pointer to the macro. e.g.:
- * 'FOREACH_MOD_I(Instance, OnConnect, OnConnect(user));'
- */
-#define FOREACH_MOD_I(z,y,x) do { \
-       EventHandlerIter safei; \
-       for (EventHandlerIter _i = z->Modules->EventHandlers[y].begin(); _i != z->Modules->EventHandlers[y].end(); ) \
-       { \
-               safei = _i; \
-               ++safei; \
-               try \
-               { \
-                       (*_i)->x ; \
-               } \
-               catch (CoreException& modexcept) \
-               { \
-                       z->Logs->Log("MODULE",DEFAULT,"Exception caught: %s",modexcept.GetReason()); \
-               } \
-               _i = safei; \
-       } \
-} while (0);
-
-/**
- * This define is similar to the one above but returns a result in MOD_RESULT.
- * The first module to return a nonzero result is the value to be accepted,
- * and any modules after are ignored.
- */
-#define FOREACH_RESULT(y,x) \
-do { \
-       EventHandlerIter safei; \
-       MOD_RESULT = 0; \
-       for (EventHandlerIter _i = ServerInstance->Modules->EventHandlers[y].begin(); _i != ServerInstance->Modules->EventHandlers[y].end(); ) \
-       { \
-               safei = _i; \
-               ++safei; \
-               try \
-               { \
-                       int res = (*_i)->x ; \
-                       if (res != 0) { \
-                               MOD_RESULT = res; \
-                               break; \
-                       } \
-               } \
-               catch (CoreException& modexcept) \
-               { \
-                       ServerInstance->Logs->Log("MODULE",DEFAULT,"Exception caught: %s",modexcept.GetReason()); \
-               } \
-               _i = safei; \
-       } \
-} while(0);
-
-
-/**
- * This define is similar to the one above but returns a result in MOD_RESULT.
- * The first module to return a nonzero result is the value to be accepted,
- * and any modules after are ignored.
- */
-#define FOREACH_RESULT_I(z,y,x) \
-do { \
-       EventHandlerIter safei; \
-       MOD_RESULT = 0; \
-       for (EventHandlerIter _i = z->Modules->EventHandlers[y].begin(); _i != z->Modules->EventHandlers[y].end(); ) \
-       { \
-               safei = _i; \
-               ++safei; \
-               try \
-               { \
-                       int res = (*_i)->x ; \
-                       if (res != 0) { \
-                               MOD_RESULT = res; \
-                               break; \
-                       } \
-               } \
-               catch (CoreException& modexcept) \
-               { \
-                       z->Logs->Log("MODULE",DEBUG,"Exception caught: %s",modexcept.GetReason()); \
-               } \
-               _i = safei; \
-       } \
-} while (0);
-
 /**
  * Custom module result handling loop. This is a paired macro, and should only
  * be used with while_each_hook.
  *
  * See src/channels.cpp for an example of use.
  */
-#define DO_EACH_HOOK(z,n,v,args) \
+#define DO_EACH_HOOK(n,v,args) \
 do { \
-       EventHandlerIter iter_ ## n = z->Modules->EventHandlers[I_ ## n].begin(); \
-       while (iter_ ## n != z->Modules->EventHandlers[I_ ## n].end()) \
+       EventHandlerIter iter_ ## n = ServerInstance->Modules->EventHandlers[I_ ## n].begin(); \
+       while (iter_ ## n != ServerInstance->Modules->EventHandlers[I_ ## n].end()) \
        { \
                Module* mod_ ## n = *iter_ ## n; \
                iter_ ## n ++; \
@@ -256,143 +139,94 @@ do { \
                { \
                        v = (mod_ ## n)->n args;
 
-#define WHILE_EACH_HOOK(z,n) \
+#define WHILE_EACH_HOOK(n) \
                } \
                catch (CoreException& except_ ## n) \
                { \
-                       z->Logs->Log("MODULE",DEFAULT,"Exception caught: %s", (except_ ## n).GetReason()); \
+                       ServerInstance->Logs->Log("MODULE",DEFAULT,"Exception caught: %s", (except_ ## n).GetReason()); \
                        (void) mod_ ## n; /* catch mismatched pairs */ \
                } \
        } \
 } while(0)
 
-#define FIRST_MOD_RESULT(z,n,v,args) do { \
+/**
+ * Module result iterator
+ * Runs the given hook until some module returns a useful result.
+ *
+ * Example: ModResult result;
+ * FIRST_MOD_RESULT(OnUserPreNick, result, (user, newnick))
+ */
+#define FIRST_MOD_RESULT(n,v,args) do { \
        v = MOD_RES_PASSTHRU; \
-       DO_EACH_HOOK(z,n,v,args) \
+       DO_EACH_HOOK(n,v,args) \
        { \
                if (v != MOD_RES_PASSTHRU) \
                        break; \
        } \
-       WHILE_EACH_HOOK(z,n); \
+       WHILE_EACH_HOOK(n); \
 } while (0)
 
-/** Represents a non-local user.
- * (in fact, any FD less than -1 does)
- */
-#define FD_MAGIC_NUMBER -42
-/** Represents a fake user (i.e. a server)
- */
-#define FD_FAKEUSER_NUMBER -7
-
-/* Useful macros */
-
-/** Is a local user */
-#define IS_LOCAL(x) (x->GetFd() > -1)
-/** Is a remote user */
-#define IS_REMOTE(x) (x->GetFd() < 0)
-/** Is a fake user */
-#define IS_FAKE(x) (x->GetFd() == FD_FAKEUSER_NUMBER)
-/** Is a module created user */
-#define IS_MODULE_CREATED(x) (x->GetFd() == FD_MAGIC_NUMBER)
-/** Is an oper */
-#define IS_OPER(x) (!x->oper.empty())
-/** Is away */
-#define IS_AWAY(x) (!x->awaymsg.empty())
-
 /** Holds a module's Version information.
- *  The four members (set by the constructor only) indicate details as to the version number
- *  of a module. A class of type Version is returned by the GetVersion method of the Module class.
- *  The flags and API values represent the module flags and API version of the module.
- *  The API version of a module must match the API version of the core exactly for the module to
- *  load successfully.
+ * The members (set by the constructor only) indicate details as to the version number
+ * of a module. A class of type Version is returned by the GetVersion method of the Module class.
+ *
+ * The core provides only one implementation of the template, causing a run-time linking
+ * error when attempting to load a module compiled against a different API_VERSION.
  */
-class CoreExport Version : public classbase
+template<int api>
+class CoreExport VersionBase
 {
  public:
+       /** Module description
+        */
+       const std::string description;
        /** Version information.
         */
-       std::string version;
+       const std::string version;
 
-       /** Flags and API version
+       /** Flags
         */
-       const int Flags, API;
+       const int Flags;
 
        /** Initialize version class
         */
-       Version(const std::string &sversion, int flags, int api_ver);
+       VersionBase(const std::string &desc, int flags = VF_NONE, const std::string& src_rev = VERSION " r" REVISION);
 };
 
-/** The ModuleMessage class is the base class of Request and Event
- * This class is used to represent a basic data structure which is passed
- * between modules for safe inter-module communications.
- */
-class CoreExport ModuleMessage : public Extensible
-{
- public:
-       /** Destructor
-        */
-       virtual ~ModuleMessage() {};
-};
+typedef VersionBase<API_VERSION> Version;
 
 /** The Request class is a unicast message directed at a given module.
  * When this class is properly instantiated it may be sent to a module
  * using the Send() method, which will call the given module's OnRequest
  * method with this class as its parameter.
  */
-class CoreExport Request : public ModuleMessage
+class CoreExport Request : public classbase
 {
- protected:
-       /** This member holds a pointer to arbitary data set by the emitter of the message
-        */
-       char* data;
+ public:
        /** This should be a null-terminated string identifying the type of request,
         * all modules should define this and use it to determine the nature of the
         * request before they attempt to cast the Request in any way.
         */
-       const char* id;
+       const char* const id;
        /** This is a pointer to the sender of the message, which can be used to
         * directly trigger events, or to create a reply.
         */
-       Module* source;
+       ModuleRef source;
        /** The single destination of the Request
         */
-       Module* dest;
- public:
-       /** Create a new Request
-        * This is for the 'old' way of casting whatever the data is
-        * to char* and hoping you get the right thing at the other end.
-        * This is slowly being depreciated in favor of the 'new' way.
-        */
-       Request(char* anydata, Module* src, Module* dst);
+       ModuleRef dest;
+
        /** Create a new Request
         * This is for the 'new' way of defining a subclass
         * of Request and defining it in a common header,
         * passing an object of your Request subclass through
         * as a Request* and using the ID string to determine
-        * what to cast it back to and the other end. This is
-        * much safer as there are no casts not confirmed by
-        * the ID string, and all casts are child->parent and
-        * can be checked at runtime with dynamic_cast<>()
+        * what to cast it back to and the other end.
         */
        Request(Module* src, Module* dst, const char* idstr);
-       /** Fetch the Request data
-        */
-       char* GetData();
-       /** Fetch the ID string
-        */
-       const char* GetId();
-       /** Fetch the request source
-        */
-       Module* GetSource();
-       /** Fetch the request destination (should be 'this' in the receiving module)
-        */
-       Module* GetDest();
        /** Send the Request.
-        * Upon returning the result will be arbitary data returned by the module you
-        * sent the request to. It is up to your module to know what this data is and
-        * how to deal with it.
         */
-       const char* Send();
+       void Send();
 };
 
 
@@ -401,43 +235,30 @@ class CoreExport Request : public ModuleMessage
  * using the Send() method, which will trigger the OnEvent method in
  * all modules passing the object as its parameter.
  */
-class CoreExport Event : public ModuleMessage
+class CoreExport Event : public classbase
 {
- protected:
-       /** This member holds a pointer to arbitary data set by the emitter of the message
-        */
-       char* data;
+ public:
        /** This is a pointer to the sender of the message, which can be used to
         * directly trigger events, or to create a reply.
         */
-       Module* source;
+       ModuleRef source;
        /** The event identifier.
         * This is arbitary text which should be used to distinguish
         * one type of event from another.
         */
-       std::string id;
- public:
+       const std::string id;
+
        /** Create a new Event
         */
-       Event(char* anydata, Module* src, const std::string &eventid);
-       /** Get the Event data
-        */
-       char* GetData();
-       /** Get the event Source
-        */
-       Module* GetSource();
-       /** Get the event ID.
-        * Use this to determine the event type for safe casting of the data
-        */
-       std::string GetEventID();
+       Event(Module* src, const std::string &eventid);
        /** Send the Event.
         * The return result of an Event::Send() will always be NULL as
         * no replies are expected.
         */
-       char* Send(InspIRCd* ServerInstance);
+       void Send();
 };
 
-/** Priority types which can be returned from Module::Prioritize()
+/** Priority types which can be used by Module::Prioritize()
  */
 enum Priority { PRIORITY_FIRST, PRIORITY_DONTCARE, PRIORITY_LAST, PRIORITY_BEFORE, PRIORITY_AFTER };
 
@@ -450,43 +271,47 @@ enum Implementation
        I_OnSendSnotice, I_OnUserPreJoin, I_OnUserPreKick, I_OnUserKick, I_OnOper, I_OnInfo, I_OnWhois,
        I_OnUserPreInvite, I_OnUserInvite, I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserPreNick,
        I_OnUserMessage, I_OnUserNotice, I_OnMode, I_OnGetServerDescription, I_OnSyncUser,
-       I_OnSyncChannel, I_OnDecodeMetaData, I_OnWallops,
-       I_OnChangeHost, I_OnChangeName, I_OnAddLine, I_OnDelLine, I_OnExpireLine, I_OnCleanup,
-       I_OnUserPostNick, I_OnAccessCheck, I_On005Numeric, I_OnKill, I_OnRemoteKill, I_OnLoadModule,
+       I_OnSyncChannel, I_OnDecodeMetaData, I_OnWallops, I_OnAcceptConnection,
+       I_OnChangeHost, I_OnChangeName, I_OnAddLine, I_OnDelLine, I_OnExpireLine,
+       I_OnUserPostNick, I_OnPreMode, I_On005Numeric, I_OnKill, I_OnRemoteKill, I_OnLoadModule,
        I_OnUnloadModule, I_OnBackgroundTimer, I_OnPreCommand, I_OnCheckReady, I_OnCheckInvite,
-       I_OnRawMode, I_OnCheckKey, I_OnCheckLimit, I_OnCheckBan, I_OnCheckExtBan, I_OnCheckStringExtBan,
-       I_OnStats, I_OnChangeLocalUserHost, I_OnChangeLocalUserGecos, I_OnLocalTopicChange,
-       I_OnPostLocalTopicChange, I_OnEvent, I_OnRequest, I_OnGlobalOper, I_OnPostConnect, I_OnAddBan,
-       I_OnDelBan, I_OnRawSocketAccept, I_OnRawSocketClose, I_OnRawSocketWrite, I_OnRawSocketRead,
-       I_OnChangeLocalUserGECOS, I_OnUserRegister, I_OnChannelPreDelete, I_OnChannelDelete,
+       I_OnRawMode, I_OnCheckKey, I_OnCheckLimit, I_OnCheckBan, I_OnCheckChannelBan, I_OnExtBanCheck,
+       I_OnStats, I_OnChangeLocalUserHost, I_OnPreTopicChange,
+       I_OnPostTopicChange, I_OnEvent, I_OnGlobalOper, I_OnPostConnect, I_OnAddBan,
+       I_OnDelBan, I_OnChangeLocalUserGECOS, I_OnUserRegister, I_OnChannelPreDelete, I_OnChannelDelete,
        I_OnPostOper, I_OnSyncNetwork, I_OnSetAway, I_OnUserList, I_OnPostCommand, I_OnPostJoin,
-       I_OnWhoisLine, I_OnBuildExemptList, I_OnRawSocketConnect, I_OnGarbageCollect, I_OnBufferFlushed,
+       I_OnWhoisLine, I_OnBuildNeighborList, I_OnGarbageCollect,
        I_OnText, I_OnPassCompare, I_OnRunTestSuite, I_OnNamesListItem, I_OnNumeric, I_OnHookIO,
-       I_OnHostCycle, I_OnPreRehash, I_OnModuleRehash,
+       I_OnPreRehash, I_OnModuleRehash, I_OnSendWhoLine, I_OnChangeIdent, I_OnChannelRestrictionApply,
        I_END
 };
 
-class ConfigReader;
-
 /** Base class for all InspIRCd modules
  *  This class is the base class for InspIRCd modules. All modules must inherit from this class,
  *  its methods will be called when irc server events occur. class inherited from module must be
  *  instantiated by the ModuleFactory class (see relevent section) for the module to be initialised.
  */
-class CoreExport Module : public Extensible
+class CoreExport Module : public classbase, public usecountbase
 {
- protected:
-       /** Creator/owner pointer
-        */
-       InspIRCd* ServerInstance;
  public:
+       /** File that this module was loaded from
+        */
+       std::string ModuleSourceFile;
+       /** Reference to the dlopen() value
+        */
+       DLLManager* ModuleDLLManager;
 
        /** Default constructor.
         * Creates a module class.
         * @param Me An instance of the InspIRCd class which will be saved into ServerInstance for your use
         * \exception ModuleException Throwing this class, or any class derived from ModuleException, causes loading of the module to abort.
         */
-       Module(InspIRCd* Me);
+       Module();
+
+       /** Clean up prior to destruction
+        * If you override, you must call this AFTER your module's cleanup
+        */
+       virtual CullResult cull();
 
        /** Default destructor.
         * destroys a module class
@@ -501,13 +326,13 @@ class CoreExport Module : public Extensible
         * The method should return a Version object with its version information assigned via
         * Version::Version
         */
-       virtual Version GetVersion();
+       virtual Version GetVersion() = 0;
 
        /** Called when a user connects.
         * The details of the connecting user are available to you in the parameter User *user
         * @param user The user who is connecting
         */
-       virtual void OnUserConnect(User* user);
+       virtual void OnUserConnect(LocalUser* user);
 
        /** Called when a user quits.
         * The details of the exiting user are available to you in the parameter User *user
@@ -525,13 +350,13 @@ class CoreExport Module : public Extensible
         * which might assign resources to user, such as dns lookups, objects and sockets.
         * @param user The user who is disconnecting
         */
-       virtual void OnUserDisconnect(User* user);
+       virtual void OnUserDisconnect(LocalUser* user);
 
        /** Called whenever a channel is about to be deleted
         * @param chan The channel being deleted
         * @return An integer specifying whether or not the channel may be deleted. 0 for yes, 1 for no.
         */
-       virtual int OnChannelPreDelete(Channel *chan);
+       virtual ModResult OnChannelPreDelete(Channel *chan);
 
        /** Called whenever a channel is deleted, either by QUIT, KICK or PART.
         * @param chan The channel being deleted
@@ -541,34 +366,27 @@ class CoreExport Module : public Extensible
        /** Called when a user joins a channel.
         * The details of the joining user are available to you in the parameter User *user,
         * and the details of the channel they have joined is available in the variable Channel *channel
-        * @param user The user who is joining
-        * @param channel The channel being joined
-        * @param silent Change this to true if you want to conceal the JOIN command from the other users
-        * of the channel (useful for modules such as auditorium)
+        * @param memb The channel membership being created
         * @param sync This is set to true if the JOIN is the result of a network sync and the remote user is being introduced
         * to a channel due to the network sync.
         * @param created This is true if the join created the channel
         */
-       virtual void OnUserJoin(User* user, Channel* channel, bool sync, bool &silent, bool created);
+       virtual void OnUserJoin(Membership* memb, bool sync, bool created, CUList& except_list);
 
        /** Called after a user joins a channel
         * Identical to OnUserJoin, but called immediately afterwards, when any linking module has
         * seen the join.
-        * @param user The user who is joining
-        * @param channel The channel being joined
+        * @param memb The channel membership created
         */
-       virtual void OnPostJoin(User* user, Channel* channel);
+       virtual void OnPostJoin(Membership*);
 
        /** Called when a user parts a channel.
         * The details of the leaving user are available to you in the parameter User *user,
         * and the details of the channel they have left is available in the variable Channel *channel
-        * @param user The user who is parting
-        * @param channel The channel being parted
+        * @param memb The channel membership being destroyed
         * @param partmessage The part message, or an empty string (may be modified)
-        * @param silent Change this to true if you want to conceal the PART command from the other users
-        * of the channel (useful for modules such as auditorium)
         */
-       virtual void OnUserPart(User* user, Channel* channel, std::string &partmessage, bool &silent);
+       virtual void OnUserPart(Membership* memb, std::string &partmessage, CUList& except_list);
 
        /** Called on rehash.
         * This method is called prior to a /REHASH or when a SIGHUP is received from the operating
@@ -607,7 +425,7 @@ class CoreExport Module : public Extensible
         * @param message The text message to be sent via snotice
         * @return 1 to block the snotice from being sent entirely, 0 else.
         */
-       virtual int OnSendSnotice(char &snomask, std::string &type, const std::string &message);
+       virtual ModResult OnSendSnotice(char &snomask, std::string &type, const std::string &message);
 
        /** Called whenever a user is about to join a channel, before any processing is done.
         * Returning a value of 1 from this function stops the process immediately, causing no
@@ -624,12 +442,12 @@ class CoreExport Module : public Extensible
         * @param user The user joining the channel
         * @param chan If the  channel is a new channel, this will be NULL, otherwise it will be a pointer to the channel being joined
         * @param cname The channel name being joined. For new channels this is valid where chan is not.
-        * @param privs A string containing the users privilages when joining the channel. For new channels this will contain "@".
+        * @param privs A string containing the users privilages when joining the channel. For new channels this will contain "o".
         * You may alter this string to alter the user's modes on the channel.
         * @param keygiven The key given to join the channel, or an empty string if none was provided
         * @return 1 To prevent the join, 0 to allow it.
         */
-       virtual int OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven);
+       virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven);
 
        /** Called whenever a user is about to be kicked.
         * Returning a value of 1 from this function stops the process immediately, causing no
@@ -641,7 +459,7 @@ class CoreExport Module : public Extensible
         * @param reason The kick reason
         * @return 1 to prevent the kick, 0 to continue normally, -1 to explicitly allow the kick regardless of normal operation
         */
-       virtual int OnUserPreKick(User* source, User* user, Channel* chan, const std::string &reason);
+       virtual ModResult OnUserPreKick(User* source, Membership* memb, const std::string &reason);
 
        /** Called whenever a user is kicked.
         * If this method is called, the kick is already underway and cannot be prevented, so
@@ -650,10 +468,8 @@ class CoreExport Module : public Extensible
         * @param user The user being kicked
         * @param chan The channel the user is being kicked from
         * @param reason The kick reason
-        * @param silent Change this to true if you want to conceal the PART command from the other users
-        * of the channel (useful for modules such as auditorium)
         */
-       virtual void OnUserKick(User* source, User* user, Channel* chan, const std::string &reason, bool &silent);
+       virtual void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& except_list);
 
        /** Called whenever a user opers locally.
         * The User will contain the oper mode 'o' as this function is called after any modifications
@@ -703,7 +519,7 @@ class CoreExport Module : public Extensible
         * @param timeout The time the invite will expire (0 == never)
         * @return 1 to deny the invite, 0 to check whether or not the user has permission to invite, -1 to explicitly allow the invite
         */
-       virtual int OnUserPreInvite(User* source,User* dest,Channel* channel, time_t timeout);
+       virtual ModResult OnUserPreInvite(User* source,User* dest,Channel* channel, time_t timeout);
 
        /** Called after a user has been successfully invited to a channel.
         * You cannot prevent the invite from occuring using this function, to do that,
@@ -731,7 +547,7 @@ class CoreExport Module : public Extensible
         * It will be ignored for private messages.
         * @return 1 to deny the message, 0 to allow it
         */
-       virtual int OnUserPreMessage(User* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list);
+       virtual ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list);
 
        /** Called whenever a user is about to NOTICE A user or a channel, before any processing is done.
         * Returning any nonzero value from this function stops the process immediately, causing no
@@ -752,18 +568,18 @@ class CoreExport Module : public Extensible
         * It will be ignored for private notices.
         * @return 1 to deny the NOTICE, 0 to allow it
         */
-       virtual int OnUserPreNotice(User* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list);
+       virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text,char status, CUList &exempt_list);
 
-       /** Called whenever the server wants to build the exemption list for a channel, but is not directly doing a PRIVMSG or NOTICE.
-        * For example, the spanningtree protocol will call this event when passing a privmsg on (but not processing it directly).
-        * @param message_type The message type, either MSG_PRIVMSG or MSG_NOTICE
-        * @param chan The channel to build the exempt list of
-        * @param sender The original sender of the PRIVMSG or NOTICE
-        * @param status The status char to be used for the channel list
-        * @param exempt_list The exempt list to be populated
-        * @param text The original message text causing the exempt list to be built
+       /** Called when sending a message to all "neighbors" of a given user -
+        * that is, all users that share a common channel. This is used in
+        * commands such as NICK, QUIT, etc.
+        * @param source The source of the message
+        * @param include_c Channels to scan for users to include
+        * @param exceptions Map of user->bool that overrides the inclusion decision
+        *
+        * Set exceptions[user] = true to include, exceptions[user] = false to exclude
         */
-       virtual void OnBuildExemptList(MessageType message_type, Channel* chan, User* sender, char status, CUList &exempt_list, const std::string &text);
+       virtual void OnBuildNeighborList(User* source, UserChanList &include_c, std::map<User*,bool> &exceptions);
 
        /** Called before any nickchange, local or remote. This can be used to implement Q-lines etc.
         * Please note that although you can see remote nickchanges through this function, you should
@@ -775,7 +591,7 @@ class CoreExport Module : public Extensible
         * @param newnick Their new nickname
         * @return 1 to deny the change, 0 to allow
         */
-       virtual int OnUserPreNick(User* user, const std::string &newnick);
+       virtual ModResult OnUserPreNick(User* user, const std::string &newnick);
 
        /** Called after any PRIVMSG sent from a user.
         * The dest variable contains a User* if target_type is TYPE_USER and a Channel*
@@ -918,13 +734,6 @@ class CoreExport Module : public Extensible
         */
        virtual void ProtoSendMetaData(void* opaque, Extensible* target, const std::string &extname, const std::string &extdata);
 
-       /**
-        * Implemented by all modules that implement ProtoSendMetaData.
-        * Translates the item into a string format suitable for sending to other servers.
-        * Currently, this just translates nicks to their UID and channels to their name
-        */
-       virtual std::string ProtoTranslate(Extensible* item);
-
        /** Called after every WALLOPS command.
         * @param user The user sending the WALLOPS
         * @param text The content of the WALLOPS message
@@ -945,6 +754,13 @@ class CoreExport Module : public Extensible
         */
        virtual void OnChangeName(User* user, const std::string &gecos);
 
+       /** Called whenever a user's IDENT is changed.
+        * This event triggers after the name has been set.
+        * @param user The user who's IDENT is being changed
+        * @param gecos The new IDENT being set on the user
+        */
+       virtual void OnChangeIdent(User* user, const std::string &ident);
+
        /** Called whenever an xline is added by a local user.
         * This method is triggered after the line is added.
         * @param source The sender of the line or NULL for local server
@@ -987,32 +803,18 @@ class CoreExport Module : public Extensible
         */
        virtual void OnUserPostNick(User* user, const std::string &oldnick);
 
-       /** Called before an action which requires a channel privilage check.
-        * This function is called before many functions which check a users status on a channel, for example
-        * before opping a user, deopping a user, kicking a user, etc.
-        * There are several values for access_type which indicate for what reason access is being checked.
-        * These are:<br><br>
-        * AC_KICK - A user is being kicked<br>
-        * AC_DEOP - a user is being deopped<br>
-        * AC_OP - a user is being opped<br>
-        * AC_VOICE - a user is being voiced<br>
-        * AC_DEVOICE - a user is being devoiced<br>
-        * AC_HALFOP - a user is being halfopped<br>
-        * AC_DEHALFOP - a user is being dehalfopped<br>
-        * AC_INVITE - a user is being invited<br>
-        * AC_GENERAL_MODE - a user channel mode is being changed<br><br>
-        * Upon returning from your function you must return either ACR_DEFAULT, to indicate the module wishes
-        * to do nothing, or ACR_DENY where approprate to deny the action, and ACR_ALLOW where appropriate to allow
-        * the action. Please note that in the case of some access checks (such as AC_GENERAL_MODE) access may be
-        * denied 'upstream' causing other checks such as AC_DEOP to not be reached. Be very careful with use of the
-        * AC_GENERAL_MODE type, as it may inadvertently override the behaviour of other modules. When the access_type
-        * is AC_GENERAL_MODE, the destination of the mode will be NULL (as it has not yet been determined).
-        * @param source The source of the access check
-        * @param dest The destination of the access check
-        * @param channel The channel which is being checked
-        * @param access_type See above
-        */
-       virtual int OnAccessCheck(User* source,User* dest,Channel* channel,int access_type);
+       /** Called before any mode change, to allow a single access check for
+        * a full mode change (use OnRawMode to check individual modes)
+        *
+        * Returning MOD_RES_ALLOW will skip prefix level checks, but can be overridden by
+        * OnRawMode for each individual mode
+        *
+        * @param source the user making the mode change
+        * @param dest the user destination of the umode change (NULL if a channel mode)
+        * @param channel the channel destination of the mode change
+        * @param parameters raw mode parameters; parameters[0] is the user/channel being changed
+        */
+       virtual ModResult OnPreMode(User* source, User* dest, Channel* channel, const std::vector<std::string>& parameters);
 
        /** Called when a 005 numeric is about to be output.
         * The module should modify the 005 numeric if needed to indicate its features.
@@ -1033,7 +835,7 @@ class CoreExport Module : public Extensible
         * @param reason The kill reason
         * @return 1 to prevent the kill, 0 to allow
         */
-       virtual int OnKill(User* source, User* dest, const std::string &reason);
+       virtual ModResult OnKill(User* source, User* dest, const std::string &reason);
 
        /** Called when an oper wants to disconnect a remote user via KILL
         * @param source The user sending the KILL
@@ -1052,9 +854,8 @@ class CoreExport Module : public Extensible
         * absolutely neccessary (e.g. a module that extends the features of another
         * module).
         * @param mod A pointer to the new module
-        * @param name The new module's filename
         */
-       virtual void OnLoadModule(Module* mod,const std::string &name);
+       virtual void OnLoadModule(Module* mod);
 
        /** Called whenever a module is unloaded.
         * mod will contain a pointer to the module, and string will contain its name,
@@ -1068,7 +869,7 @@ class CoreExport Module : public Extensible
         * @param mod Pointer to the module being unloaded (still valid)
         * @param name The filename of the module being unloaded
         */
-       virtual void OnUnloadModule(Module* mod,const std::string &name);
+       virtual void OnUnloadModule(Module* mod);
 
        /** Called once every five seconds for background processing.
         * This timer can be used to control timed features. Its period is not accurate
@@ -1096,7 +897,7 @@ class CoreExport Module : public Extensible
         * @param original_line The entire original line as passed to the parser from the user
         * @return 1 to block the command, 0 to allow
         */
-       virtual int OnPreCommand(std::string &command, std::vector<std::string>& parameters, User *user, bool validated, const std::string &original_line);
+       virtual ModResult OnPreCommand(std::string &command, std::vector<std::string>& parameters, User *user, bool validated, const std::string &original_line);
 
        /** Called after any command has been executed.
         * This event occurs for all registered commands, wether they are registered in the core,
@@ -1122,7 +923,7 @@ class CoreExport Module : public Extensible
         * @param user The user to check
         * @return true to indicate readiness, false if otherwise
         */
-       virtual bool OnCheckReady(User* user);
+       virtual ModResult OnCheckReady(LocalUser* user);
 
        /** Called whenever a user is about to register their connection (e.g. before the user
         * is sent the MOTD etc). Modules can use this method if they are performing a function
@@ -1133,7 +934,7 @@ class CoreExport Module : public Extensible
         * @param user The user registering
         * @return 1 to indicate user quit, 0 to continue
         */
-       virtual int OnUserRegister(User* user);
+       virtual ModResult OnUserRegister(LocalUser* user);
 
        /** Called whenever a user joins a channel, to determine if invite checks should go ahead or not.
         * This method will always be called for each join, wether or not the channel is actually +i, and
@@ -1143,7 +944,7 @@ class CoreExport Module : public Extensible
         * @param chan The channel being joined
         * @return 1 to explicitly allow the join, 0 to proceed as normal
         */
-       virtual int OnCheckInvite(User* user, Channel* chan);
+       virtual ModResult OnCheckInvite(User* user, Channel* chan);
 
        /** Called whenever a mode character is processed.
         * Return 1 from this function to block the mode character from being processed entirely.
@@ -1157,7 +958,7 @@ class CoreExport Module : public Extensible
         * to skip all permission checking. Please note that for remote mode changes, your return value
         * will be ignored!
         */
-       virtual int OnRawMode(User* user, Channel* chan, const char mode, const std::string &param, bool adding, int pcnt, bool servermode = true);
+       virtual ModResult OnRawMode(User* user, Channel* chan, const char mode, const std::string &param, bool adding, int pcnt);
 
        /** Called whenever a user joins a channel, to determine if key checks should go ahead or not.
         * This method will always be called for each join, wether or not the channel is actually +k, and
@@ -1168,7 +969,7 @@ class CoreExport Module : public Extensible
         * @param chan The channel being joined
         * @return 1 to explicitly allow the join, 0 to proceed as normal
         */
-       virtual int OnCheckKey(User* user, Channel* chan, const std::string &keygiven);
+       virtual ModResult OnCheckKey(User* user, Channel* chan, const std::string &keygiven);
 
        /** Called whenever a user joins a channel, to determine if channel limit checks should go ahead or not.
         * This method will always be called for each join, wether or not the channel is actually +l, and
@@ -1178,33 +979,32 @@ class CoreExport Module : public Extensible
         * @param chan The channel being joined
         * @return 1 to explicitly allow the join, 0 to proceed as normal
         */
-       virtual int OnCheckLimit(User* user, Channel* chan);
+       virtual ModResult OnCheckLimit(User* user, Channel* chan);
 
-       /** Called whenever a user joins a channel, to determine if banlist checks should go ahead or not.
-        * This method will always be called for each join, wether or not the user actually matches a channel ban, and
-        * determines the outcome of an if statement around the whole section of ban checking code.
-        * return 1 to explicitly allow the join to go ahead or 0 to ignore the event.
-        * @param user The user joining the channel
-        * @param chan The channel being joined
-        * @return 1 to explicitly allow the join, 0 to proceed as normal. Return -1 to explicitly deny the
-        * join to the channel.
+       /**
+        * Checks for a user's ban from the channel
+        * @param user The user to check
+        * @param chan The channel to check in
+        * @return MOD_RES_DENY to mark as banned, MOD_RES_ALLOW to skip the
+        * ban check, or MOD_RES_PASSTHRU to check bans normally
         */
-       virtual int OnCheckBan(User* user, Channel* chan);
+       virtual ModResult OnCheckChannelBan(User* user, Channel* chan);
 
-       /* Called whenever checking whether or not a user is matched by an applicable extended bantype.
-        * NOTE: may also trigger extra OnCheckStringExtBan events!
-        * @param u The user to check
-        * @param c The channel the user is on
-        * @param type The type of extended ban to check for.
-        * @returns 1 = exempt, 0 = no match, -1 = banned
+       /**
+        * Checks for a user's match of a single ban
+        * @param user The user to check for match
+        * @param chan The channel on which the match is being checked
+        * @param mask The mask being checked
+        * @return MOD_RES_DENY to mark as banned, MOD_RES_ALLOW to skip the
+        * ban check, or MOD_RES_PASSTHRU to check bans normally
         */
-       virtual int OnCheckExtBan(User *u, Channel *c, char type);
+       virtual ModResult OnCheckBan(User* user, Channel* chan, const std::string& mask);
 
-       /** Called whenever checking whether or not a string is extbanned. NOTE: one OnCheckExtBan will also trigger a number of
-        * OnCheckStringExtBan events for seperate host/IP comnbinations.
-        * @returns 1 = exempt, 0 = no match, -1 = banned
+       /** Checks for a match on a given extban type
+        * @return MOD_RES_DENY to mark as banned, MOD_RES_ALLOW to skip the
+        * ban check, or MOD_RES_PASSTHRU to check bans normally
         */
-       virtual int OnCheckStringExtBan(const std::string &s, Channel *c, char type);
+       virtual ModResult OnExtBanCheck(User* user, Channel* chan, char type);
 
        /** Called on all /STATS commands
         * This method is triggered for all /STATS use, including stats symbols handled by the core.
@@ -1215,7 +1015,7 @@ class CoreExport Module : public Extensible
         * work when remote STATS queries are received.
         * @return 1 to block the /STATS from being processed by the core, 0 to allow it
         */
-       virtual int OnStats(char symbol, User* user, string_list &results);
+       virtual ModResult OnStats(char symbol, User* user, string_list &results);
 
        /** Called whenever a change of a local users displayed host is attempted.
         * Return 1 to deny the host change, or 0 to allow it.
@@ -1223,7 +1023,7 @@ class CoreExport Module : public Extensible
         * @param newhost The new hostname
         * @return 1 to deny the host change, 0 to allow
         */
-       virtual int OnChangeLocalUserHost(User* user, const std::string &newhost);
+       virtual ModResult OnChangeLocalUserHost(LocalUser* user, const std::string &newhost);
 
        /** Called whenever a change of a local users GECOS (fullname field) is attempted.
         * return 1 to deny the name change, or 0 to allow it.
@@ -1231,41 +1031,37 @@ class CoreExport Module : public Extensible
         * @param newhost The new GECOS
         * @return 1 to deny the GECOS change, 0 to allow
         */
-       virtual int OnChangeLocalUserGECOS(User* user, const std::string &newhost);
+       virtual ModResult OnChangeLocalUserGECOS(LocalUser* user, const std::string &newhost);
 
-       /** Called whenever a topic is changed by a local user.
+       /** Called before a topic is changed.
         * Return 1 to deny the topic change, 0 to check details on the change, -1 to let it through with no checks
+        * As with other 'pre' events, you should only ever block a local event.
         * @param user The user changing the topic
         * @param chan The channels who's topic is being changed
         * @param topic The actual topic text
         * @param 1 to block the topic change, 0 to allow
         */
-       virtual int OnLocalTopicChange(User* user, Channel* chan, const std::string &topic);
+       virtual ModResult OnPreTopicChange(User* user, Channel* chan, const std::string &topic);
 
-       /** Called whenever a local topic has been changed.
-        * To block topic changes you must use OnLocalTopicChange instead.
+       /** Called whenever a topic has been changed.
+        * To block topic changes you must use OnPreTopicChange instead.
         * @param user The user changing the topic
         * @param chan The channels who's topic is being changed
         * @param topic The actual topic text
         */
-       virtual void OnPostLocalTopicChange(User* user, Channel* chan, const std::string &topic);
+       virtual void OnPostTopicChange(User* user, Channel* chan, const std::string &topic);
 
-       /** Called whenever an Event class is sent to all module by another module.
-        * Please see the documentation of Event::Send() for further information. The Event sent can
-        * always be assumed to be non-NULL, you should *always* check the value of Event::GetEventID()
-        * before doing anything to the event data, and you should *not* change the event data in any way!
+       /** Called whenever an Event class is sent to all modules by another module.
+        * You should *always* check the value of Event::id to determine the event type.
         * @param event The Event class being received
         */
-       virtual void OnEvent(Event* event);
+       virtual void OnEvent(Event& event);
 
        /** Called whenever a Request class is sent to your module by another module.
-        * Please see the documentation of Request::Send() for further information. The Request sent
-        * can always be assumed to be non-NULL, you should not change the request object or its data.
-        * Your method may return arbitary data in the char* result which the requesting module
-        * may be able to use for pre-determined purposes (e.g. the results of an SQL query, etc).
+        * The value of Request::id should be used to determine the type of request.
         * @param request The Request class being received
         */
-       virtual const char* OnRequest(Request* request);
+       virtual void OnRequest(Request& request);
 
        /** Called whenever a password check is to be made. Replaces the old OldOperCompare API.
         * The password field (from the config file) is in 'password' and is to be compared against
@@ -1277,7 +1073,7 @@ class CoreExport Module : public Extensible
         * @param hashtype The hash value from the config
         * @return 0 to do nothing (pass on to next module/default), 1 == password is OK, -1 == password is not OK
         */
-       virtual int OnPassCompare(Extensible* ex, const std::string &password, const std::string &input, const std::string& hashtype);
+       virtual ModResult OnPassCompare(Extensible* ex, const std::string &password, const std::string &input, const std::string& hashtype);
 
        /** Called whenever a user is given usermode +o, anywhere on the network.
         * You cannot override this and prevent it from happening as it is already happened and
@@ -1302,7 +1098,7 @@ class CoreExport Module : public Extensible
         * @param banmask The ban mask being added
         * @return 1 to block the ban, 0 to continue as normal
         */
-       virtual int OnAddBan(User* source, Channel* channel,const std::string &banmask);
+       virtual ModResult OnAddBan(User* source, Channel* channel,const std::string &banmask);
 
        /** Called whenever a ban is removed from a channel's list.
         * Return a non-zero value to 'eat' the mode change and prevent the ban from being removed.
@@ -1311,15 +1107,24 @@ class CoreExport Module : public Extensible
         * @param banmask The ban mask being deleted
         * @return 1 to block the unban, 0 to continue as normal
         */
-       virtual int OnDelBan(User* source, Channel* channel,const std::string &banmask);
+       virtual ModResult OnDelBan(User* source, Channel* channel,const std::string &banmask);
 
        /** Called to install an I/O hook on an event handler
         * @param user The item to possibly install the I/O hook on
         * @param via The port that <user> connected on
         */
-       virtual void OnHookIO(EventHandler* user, ListenSocketBase* via);
+       virtual void OnHookIO(StreamSocket*, ListenSocket* via);
+
+       /** Called when a port accepts a connection
+        * Return MOD_RES_ACCEPT if you have used the file descriptor.
+        * @param fd The file descriptor returned from accept()
+        * @param from The local port the user connected to
+        * @param client The client IP address and port
+        * @param server The server IP address and port
+        */
+       virtual ModResult OnAcceptConnection(int fd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server);
 
-       /** Called immediately after any  connection is accepted. This is intended for raw socket
+       /** Called immediately after any connection is accepted. This is intended for raw socket
         * processing (e.g. modules which wrap the tcp connection within another library) and provides
         * no information relating to a user record as the connection has not been assigned yet.
         * There are no return values from this call as all modules get an opportunity if required to
@@ -1329,48 +1134,38 @@ class CoreExport Module : public Extensible
         * @param server The server IP address and port
         * @param localport The local port number the user connected to
         */
-       virtual void OnRawSocketAccept(int fd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server);
+       virtual void OnStreamSocketAccept(StreamSocket*, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server);
 
-       /** Called immediately before any write() operation on a user's socket in the core. Because
-        * this event is a low level event no user information is associated with it. It is intended
-        * for use by modules which may wrap connections within another API such as SSL for example.
-        * return a non-zero result if you have handled the write operation, in which case the core
-        * will not call write().
-        * @param fd The file descriptor of the socket
-        * @param buffer A char* buffer being written
-        * @param Number of characters to write
-        * @return Number of characters actually written or 0 if you didn't handle the operation
+       /**
+        * Called when a hooked stream has data to write, or when the socket
+        * engine returns it as writable
+        * @param socket The socket in question
+        * @param sendq Data to send to the socket
+        * @return 1 if the sendq has been completely emptied, 0 if there is
+        *  still data to send, and -1 if there was an error
         */
-       virtual int OnRawSocketWrite(int fd, const char* buffer, int count);
+       virtual int OnStreamSocketWrite(StreamSocket*, std::string& sendq);
 
        /** Called immediately before any socket is closed. When this event is called, shutdown()
         * has not yet been called on the socket.
         * @param fd The file descriptor of the socket prior to close()
         */
-       virtual void OnRawSocketClose(int fd);
+       virtual void OnStreamSocketClose(StreamSocket*);
 
        /** Called immediately upon connection of an outbound BufferedSocket which has been hooked
         * by a module.
         * @param fd The file descriptor of the socket immediately after connect()
         */
-       virtual void OnRawSocketConnect(int fd);
-
-       /** Called immediately before any read() operation on a client socket in the core.
-        * This occurs AFTER the select() or poll() so there is always data waiting to be read
-        * when this event occurs.
-        * Your event should return 1 if it has handled the reading itself, which prevents the core
-        * just using read(). You should place any data read into buffer, up to but NOT GREATER THAN
-        * the value of count. The value of readresult must be identical to an actual result that might
-        * be returned from the read() system call, for example, number of bytes read upon success,
-        * 0 upon EOF or closed socket, and -1 for error. If your function returns a nonzero value,
-        * you MUST set readresult.
-        * @param fd The file descriptor of the socket
-        * @param buffer A char* buffer being read to
-        * @param count The size of the buffer
-        * @param readresult The amount of characters read, or 0
-        * @return nonzero if the event was handled, in which case readresult must be valid on exit
-        */
-       virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult);
+       virtual void OnStreamSocketConnect(StreamSocket*);
+
+       /**
+        * Called when the stream socket has data to read
+        * @param socket The socket that is ready
+        * @param recvq The receive queue that new data should be appended to
+        * @return 1 if new data has been read, 0 if no new data is ready (but the
+        *  socket is still connected), -1 if there was an error or close
+        */
+       virtual int OnStreamSocketRead(StreamSocket*, std::string& recvq);
 
        /** Called whenever a user sets away or returns from being away.
         * The away message is available as a parameter, but should not be modified.
@@ -1380,7 +1175,7 @@ class CoreExport Module : public Extensible
         * @param awaymsg The away message of the user, or empty if returning from away
         * @return nonzero if the away message should be blocked - should ONLY be nonzero for LOCAL users (IS_LOCAL) (no output is returned by core)
         */
-       virtual int OnSetAway(User* user, const std::string &awaymsg);
+       virtual ModResult OnSetAway(User* user, const std::string &awaymsg);
 
        /** Called whenever a NAMES list is requested.
         * You can produce the nameslist yourself, overriding the current list,
@@ -1388,14 +1183,8 @@ class CoreExport Module : public Extensible
         * return 0.
         * @param The user requesting the NAMES list
         * @param Ptr The channel the NAMES list is requested for
-        * @param userlist The user list for the channel (you may change this pointer.
-        * If you want to change the values, take a copy first, and change the copy, then
-        * point the pointer at your copy)
-        * @return 1 to prevent the user list being sent to the client, 0 to allow it.
-        * Returning -1 allows the names list, but bypasses any checks which check for
-        * channel membership before sending the names list.
         */
-       virtual int OnUserList(User* user, Channel* Ptr, CUList* &userlist);
+       virtual ModResult OnUserList(User* user, Channel* Ptr);
 
        /** Called whenever a line of WHOIS output is sent to a user.
         * You may change the numeric and the text of the output by changing
@@ -1408,7 +1197,7 @@ class CoreExport Module : public Extensible
         * @return nonzero to drop the line completely so that the user does not
         * receive it, or zero to allow the line to be sent.
         */
-       virtual int OnWhoisLine(User* user, User* dest, int &numeric, std::string &text);
+       virtual ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text);
 
        /** Called at intervals for modules to garbage-collect any hashes etc.
         * Certain data types such as hash_map 'leak' buckets, which must be
@@ -1417,15 +1206,6 @@ class CoreExport Module : public Extensible
         */
        virtual void OnGarbageCollect();
 
-       /** Called whenever a user's write buffer has been completely sent.
-        * This is called when the user's write buffer is completely empty, and
-        * there are no more pending bytes to be written and no pending write events
-        * in the socket engine's queue. This may be used to refill the buffer with
-        * data which is being spooled in a controlled manner, e.g. LIST lines.
-        * @param user The user who's buffer is now empty.
-        */
-       virtual void OnBufferFlushed(User* user);
-
        /** Add test suite hooks here. These are used for testing functionality of a module
         * via the --testsuite debugging parameter.
         */
@@ -1435,15 +1215,23 @@ class CoreExport Module : public Extensible
         * For example NAMESX, channel mode +u and +I, and UHNAMES. If the nick is set to an empty string by any
         * module, then this will cause the nickname not to be displayed at all.
         */
-       virtual void OnNamesListItem(User* issuer, User* user, Channel* channel, std::string &prefixes, std::string &nick);
+       virtual void OnNamesListItem(User* issuer, Membership* item, std::string &prefixes, std::string &nick);
 
-       virtual int OnNumeric(User* user, unsigned int numeric, const std::string &text);
+       virtual ModResult OnNumeric(User* user, unsigned int numeric, const std::string &text);
 
-       /** Called for every time the user's host or ident changes, to indicate wether or not the 'Changing host'
-        * message should be sent, if enabled. Certain modules such as auditorium may opt to hide this message
-        * even if it is enabled.
+       /** Called whenever a result from /WHO is about to be returned
+        * @param source The user running the /WHO query
+        * @param user The user that this line of the query is about
+        * @param channel The channel being queried (or NULL if not a channel query)
+        * @param line The raw line to send; modifiable, if empty no line will be returned.
         */
-       virtual bool OnHostCycle(User* user);
+       virtual void OnSendWhoLine(User* source, User* user, Channel* channel, std::string& line);
+
+       /** Called to check whether a channel restriction mode applies to a user on it
+        * @return MOD_RES_DENY to apply the restriction, MOD_RES_ALLOW to bypass
+        * the restriction, or MOD_RES_PASSTHRU to check restriction status normally
+        */
+       virtual ModResult OnChannelRestrictionApply(User* user, Channel* chan, const char* restriction);
 };
 
 
@@ -1460,10 +1248,9 @@ class CoreExport Module : public Extensible
  * Constructing the class using one parameter allows you to specify a path to your own configuration
  * file, otherwise, inspircd.conf is read.
  */
-class CoreExport ConfigReader : public classbase
+class CoreExport ConfigReader : public interfacebase
 {
   protected:
-       InspIRCd* ServerInstance;
        /** Error code
         */
        long error;
@@ -1473,7 +1260,7 @@ class CoreExport ConfigReader : public classbase
         * This constructor initialises the ConfigReader class to read the inspircd.conf file
         * as specified when running ./configure.
         */
-       ConfigReader(InspIRCd* Instance);
+       ConfigReader();
        /** Default destructor.
         * This method destroys the ConfigReader class.
         */
@@ -1530,6 +1317,7 @@ class CoreExport ConfigReader : public classbase
         * A call to GetError() resets the error flag back to 0.
         */
        long GetError();
+
        /** Counts the number of times a given tag appears in the config file.
         * This method counts the number of times a tag appears in a config file, for use where
         * there are several tags of the same kind, e.g. with opers and connect types. It can be
@@ -1537,13 +1325,6 @@ class CoreExport ConfigReader : public classbase
         * multiple instance tag.
         */
        int Enumerate(const std::string &tag);
-
-       /** Returns the number of items within a tag.
-        * For example if the tag was &lt;test tag="blah" data="foo"&gt; then this
-        * function would return 2. Spaces and newlines both qualify as valid seperators
-        * between values.
-        */
-       int EnumerateValues(const std::string &tag, int index);
 };
 
 
@@ -1555,10 +1336,9 @@ class CoreExport ConfigReader : public classbase
  */
 class CoreExport FileReader : public classbase
 {
-       InspIRCd* ServerInstance;
        /** The file contents
         */
-       file_cache fc;
+       std::vector<std::string> fc;
 
        /** Content size in bytes
         */
@@ -1573,14 +1353,14 @@ class CoreExport FileReader : public classbase
         * This method does not load any file into memory, you must use the LoadFile method
         * after constructing the class this way.
         */
-       FileReader(InspIRCd* Instance);
+       FileReader();
 
        /** Secondary constructor.
         * This method initialises the class with a file loaded into it ready for GetLine and
         * and other methods to be called. If the file could not be loaded, FileReader::FileSize
         * returns 0.
         */
-       FileReader(InspIRCd* Instance, const std::string &filename);
+       FileReader(const std::string &filename);
 
        /** Default destructor.
         * This deletes the memory allocated to the file.
@@ -1621,14 +1401,6 @@ class CoreExport FileReader : public classbase
        int FileSize();
 };
 
-/** A DLLFactory (designed to load shared objects) containing a
- * handle to a module's init_module() function. Unfortunately,
- * due to the design of shared object systems we must keep this
- * hanging around, as if we remove this handle, we remove the
- * shared object file from memory (!)
- */
-typedef DLLFactory<Module> ircd_module;
-
 /** A list of modules
  */
 typedef std::vector<Module*> IntModuleList;
@@ -1640,7 +1412,7 @@ typedef IntModuleList::iterator EventHandlerIter;
 /** ModuleManager takes care of all things module-related
  * in the core.
  */
-class CoreExport ModuleManager : public classbase
+class CoreExport ModuleManager
 {
  private:
        /** Holds a string describing the last module error to occur
@@ -1659,20 +1431,19 @@ class CoreExport ModuleManager : public classbase
         */
        int ModCount;
 
-       /** Our pointer to the main insp instance
-        */
-       InspIRCd* Instance;
-
        /** List of loaded modules and shared object/dll handles
         * keyed by module name
         */
-       std::map<std::string, std::pair<ircd_module*, Module*> > Modules;
+       std::map<std::string, Module*> Modules;
 
        enum {
                PRIO_STATE_FIRST,
                PRIO_STATE_AGAIN,
                PRIO_STATE_LAST
        } prioritizationState;
+
+       /** Internal unload module hook */
+       bool CanUnload(Module*);
  public:
 
        /** Event handler hooks.
@@ -1682,7 +1453,7 @@ class CoreExport ModuleManager : public classbase
 
        /** Simple, bog-standard, boring constructor.
         */
-       ModuleManager(InspIRCd* Ins);
+       ModuleManager();
 
        /** Destructor
         */
@@ -1761,15 +1532,24 @@ class CoreExport ModuleManager : public classbase
         */
        bool Load(const char* filename);
 
-       /** Unload a given module file
-        * @param filename The file to unload
-        * @return True if the module was unloaded
+       /** Unload a given module file. Note that the module will not be
+        * completely gone until the cull list has finished processing.
+        *
+        * @return true on success; if false, LastError will give a reason
+        */
+       bool Unload(Module* module);
+
+       /** Run an asynchronous reload of the given module. When the reload is
+        * complete, the callback will be run with true if the reload succeeded
+        * and false if it did not.
         */
-       bool Unload(const char* filename);
+       void Reload(Module* module, HandlerBase1<void, bool>* callback);
 
        /** Called by the InspIRCd constructor to load all modules from the config file.
         */
        void LoadAll();
+       void UnloadAll();
+       void DoSafeUnload(Module*);
 
        /** Get the total number of currently loaded modules
         * @return The number of loaded modules
@@ -1906,6 +1686,16 @@ class CoreExport ModuleManager : public classbase
        const std::vector<std::string> GetAllModuleNames(int filter);
 };
 
+/** Do not mess with these functions unless you know the C preprocessor
+ * well enough to explain why they are needed. The order is important.
+ */
+#define MODULE_INIT_STR MODULE_INIT_STR_FN_2(MODULE_INIT_SYM)
+#define MODULE_INIT_STR_FN_2(x) MODULE_INIT_STR_FN_1(x)
+#define MODULE_INIT_STR_FN_1(x) #x
+#define MODULE_INIT_SYM MODULE_INIT_SYM_FN_2(API_VERSION)
+#define MODULE_INIT_SYM_FN_2(x) MODULE_INIT_SYM_FN_1(x)
+#define MODULE_INIT_SYM_FN_1(x) inspircd_module_ ## x
+
 /** This definition is used as shorthand for the various classes
  * and functions needed to make a module loadable by the OS.
  * It defines the class factory and external init_module function.
@@ -1913,9 +1703,9 @@ class CoreExport ModuleManager : public classbase
 #ifdef WINDOWS
 
 #define MODULE_INIT(y) \
-       extern "C" DllExport Module * init_module(InspIRCd* Me) \
+       extern "C" DllExport Module * MODULE_INIT_SYM() \
        { \
-               return new y(Me); \
+               return new y; \
        } \
        BOOLEAN WINAPI DllMain(HINSTANCE hDllHandle, DWORD nReason, LPVOID Reserved) \
        { \
@@ -1931,10 +1721,12 @@ class CoreExport ModuleManager : public classbase
 #else
 
 #define MODULE_INIT(y) \
-       extern "C" DllExport Module * init_module(InspIRCd* Me) \
+       extern "C" DllExport Module * MODULE_INIT_SYM() \
        { \
-               return new y(Me); \
+               return new y; \
        }
 #endif
 
+#define COMMAND_INIT(c) MODULE_INIT(CommandModule<c>)
+
 #endif