]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - include/modules.h
Add m_nickflood: Provides usermode +F nickchanges:seconds - allows nickchanges:second...
[user/henk/code/inspircd.git] / include / modules.h
index ef103a1a595d7ce78fc5db71bcddddac57a88657..389fa6184455bdce3f639b8f47cb75cd4fba39bf 100644 (file)
@@ -6,7 +6,7 @@
  * See: http://www.inspircd.org/wiki/index.php/Credits
  *
  * This program is free but copyrighted software; see
- *            the file COPYING for details.
+ *         the file COPYING for details.
  *
  * ---------------------------------------------------
  */
@@ -40,11 +40,15 @@ enum ModuleFlags {
        VF_COMMON = 8           // module needs to be common on all servers in a network to link
 };
 
+/** Used with SendToMode()
+ */
 enum WriteModeFlags {
        WM_AND = 1,
        WM_OR = 2
 };
 
+/** Used to represent an event type, for user, channel or server
+ */
 enum TargetTypeFlags {
        TYPE_USER = 1,
        TYPE_CHANNEL,
@@ -52,6 +56,8 @@ enum TargetTypeFlags {
        TYPE_OTHER
 };
 
+/** Used to represent wether a message was PRIVMSG or NOTICE
+ */
 enum MessageType {
        MSG_PRIVMSG = 0,
        MSG_NOTICE = 1
@@ -75,7 +81,7 @@ enum MessageType {
  * ipv4 servers, so this value will be ten times as
  * high on ipv6 servers.
  */
-#define NATIVE_API_VERSION 11008
+#define NATIVE_API_VERSION 11025
 #ifdef IPV6
 #define API_VERSION (NATIVE_API_VERSION * 10)
 #else
@@ -88,9 +94,13 @@ class ServerConfig;
  */
 class Module;
 
-/** Low level definition of a FileReader classes file cache area
+/** 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.
@@ -108,7 +118,7 @@ typedef std::map<std::string, std::pair<int, modulelist> > interfacelist;
 /**
  * This #define allows us to call a method in all
  * loaded modules in a readable simple way, e.g.:
- * 'FOREACH_MOD(I_OnXonnwxr,OnConnect(user));'
+ * 'FOREACH_MOD(I_OnConnect,OnConnect(user));'
  */
 #define FOREACH_MOD(y,x) if (ServerInstance->Config->global_implementation[y] > 0) { \
        for (int _i = 0; _i <= ServerInstance->GetModuleCount(); _i++) { \
@@ -117,13 +127,19 @@ typedef std::map<std::string, std::pair<int, modulelist> > interfacelist;
                { \
                        ServerInstance->modules[_i]->x ; \
                } \
-               catch (ModuleException& modexcept) \
+               catch (CoreException& modexcept) \
                { \
-                       ServerInstance->Log(DEBUG,"Module exception caught: %s",modexcept.GetReason()); \
+                       ServerInstance->Log(DEFAULT,"Exception cought: %s",modexcept.GetReason()); \
                } \
        } \
   }
 
+/**
+ * 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) if (z->Config->global_implementation[y] > 0) { \
        for (int _i = 0; _i <= z->GetModuleCount(); _i++) { \
                if (z->Config->implement_lists[_i][y]) \
@@ -131,14 +147,14 @@ typedef std::map<std::string, std::pair<int, modulelist> > interfacelist;
                { \
                        z->modules[_i]->x ; \
                } \
-               catch (ModuleException& modexcept) \
+               catch (CoreException& modexcept) \
                { \
-                       z->Log(DEBUG,"Module exception caught: %s",modexcept.GetReason()); \
+                       z->Log(DEFAULT,"Exception cought: %s",modexcept.GetReason()); \
                } \
        } \
 }
 /**
- *  This define is similar to the one above but returns a result in MOD_RESULT.
+ * 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.
  */
@@ -154,15 +170,20 @@ typedef std::map<std::string, std::pair<int, modulelist> > interfacelist;
                                                break; \
                                        } \
                                } \
-                               catch (ModuleException& modexcept) \
+                               catch (CoreException& modexcept) \
                                { \
-                                       ServerInstance->Log(DEBUG,"Module exception cought: %s",modexcept.GetReason()); \
+                                       ServerInstance->Log(DEFAULT,"Exception cought: %s",modexcept.GetReason()); \
                                } \
                        } \
                } \
        } \
  }
 
+/**
+ * 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) { if (z->Config->global_implementation[y] > 0) { \
                        MOD_RESULT = 0; \
                        for (int _i = 0; _i <= z->GetModuleCount(); _i++) { \
@@ -175,31 +196,53 @@ typedef std::map<std::string, std::pair<int, modulelist> > interfacelist;
                                                break; \
                                        } \
                                } \
-                               catch (ModuleException& modexcept) \
+                               catch (CoreException& modexcept) \
                                { \
-                                       z->Log(DEBUG,"Module exception cought: %s",modexcept.GetReason()); \
+                                       z->Log(DEBUG,"Exception cought: %s",modexcept.GetReason()); \
                                } \
                        } \
                } \
        } \
 }
 
+/** Represents a non-local user.
+ * (in fact, any FD less than -1 does)
+ */
 #define FD_MAGIC_NUMBER -42
 
-// useful macros
-
+/* Useful macros */
+#ifdef WINDOWS
+/** Is a local user */
+#define IS_LOCAL(x) ((x->GetFd() > -1))
+#else
+/** Is a local user */
 #define IS_LOCAL(x) ((x->GetFd() > -1) && (x->GetFd() <= MAX_DESCRIPTORS))
+#endif
+/** Is a remote user */
 #define IS_REMOTE(x) (x->GetFd() < 0)
+/** Is a module created user */
 #define IS_MODULE_CREATED(x) (x->GetFd() == FD_MAGIC_NUMBER)
+/** Is an oper */
+#define IS_OPER(x) (*x->oper)
+/** Is away */
+#define IS_AWAY(x) (*x->awaymsg)
 
-/** Holds a module's Version information
+/** 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.
  */
-class Version : public classbase
+class CoreExport Version : public classbase
 {
  public:
+        /** Version numbers, build number, flags and API version
+         */
         const int Major, Minor, Revision, Build, Flags, API;
+
+        /** Initialize version class
+         */
         Version(int major, int minor, int revision, int build, int flags, int api_ver);
 };
 
@@ -207,9 +250,11 @@ class Version : public classbase
  * This class is used to represent a basic data structure which is passed
  * between modules for safe inter-module communications.
  */
-class ModuleMessage : public Extensible
+class CoreExport ModuleMessage : public Extensible
 {
  public:
+       /** Destructor
+        */
        virtual ~ModuleMessage() {};
 };
 
@@ -218,7 +263,7 @@ class ModuleMessage : public Extensible
  * using the Send() method, which will call the given module's OnRequest
  * method with this class as its parameter.
  */
-class Request : public ModuleMessage
+class CoreExport Request : public ModuleMessage
 {
  protected:
        /** This member holds a pointer to arbitary data set by the emitter of the message
@@ -280,7 +325,7 @@ class Request : public ModuleMessage
  * using the Send() method, which will trigger the OnEvent method in
  * all modules passing the object as its parameter.
  */
-class Event : public ModuleMessage
+class CoreExport Event : public ModuleMessage
 {
  protected:
        /** This member holds a pointer to arbitary data set by the emitter of the message
@@ -322,19 +367,26 @@ class Event : public ModuleMessage
  * be loaded. If this happens, the error message returned by ModuleException::GetReason will be displayed to the user
  * attempting to load the module, or dumped to the console if the ircd is currently loading for the first time.
  */
-class CoreException : public std::exception
+class CoreExport CoreException : public std::exception
 {
  protected:
        /** Holds the error message to be displayed
         */
        const std::string err;
+       /** Source of the exception
+        */
+       const std::string source;
  public:
        /** Default constructor, just uses the error mesage 'Core threw an exception'.
         */
-       CoreException() : err("Core threw an exception") {}
+       CoreException() : err("Core threw an exception"), source("The core") {}
        /** This constructor can be used to specify an error message before throwing.
         */
-       CoreException(const std::string &message) : err(message) {}
+       CoreException(const std::string &message) : err(message), source("The core") {}
+       /** This constructor can be used to specify an error message before throwing,
+        * and to specify the source of the exception.
+        */
+       CoreException(const std::string &message, const std::string &src) : err(message), source(src) {}
        /** This destructor solves world hunger, cancels the world debt, and causes the world to end.
         * Actually no, it does nothing. Never mind.
         * @throws Nothing!
@@ -347,18 +399,23 @@ class CoreException : public std::exception
        {
                return err.c_str();
        }
+
+       virtual const char* GetSource()
+       {
+               return source.c_str();
+       }
 };
 
-class ModuleException : public CoreException
+class CoreExport ModuleException : public CoreException
 {
  public:
        /** Default constructor, just uses the error mesage 'Module threw an exception'.
         */
-       ModuleException() : CoreException("Module threw an exception") {}
+       ModuleException() : CoreException("Module threw an exception", "A Module") {}
 
        /** This constructor can be used to specify an error message before throwing.
         */
-       ModuleException(const std::string &message) : CoreException(message) {}
+       ModuleException(const std::string &message) : CoreException(message, "A Module") {}
        /** This destructor solves world hunger, cancels the world debt, and causes the world to end.
         * Actually no, it does nothing. Never mind.
         * @throws Nothing!
@@ -384,27 +441,29 @@ enum Implementation {     I_OnUserConnect, I_OnUserQuit, I_OnUserDisconnect, I_OnUse
                        I_OnPostLocalTopicChange, I_OnEvent, I_OnRequest, I_OnOperCompre, I_OnGlobalOper, I_OnPostConnect, I_OnAddBan, I_OnDelBan,
                        I_OnRawSocketAccept, I_OnRawSocketClose, I_OnRawSocketWrite, I_OnRawSocketRead, I_OnChangeLocalUserGECOS, I_OnUserRegister,
                        I_OnOperCompare, I_OnChannelDelete, I_OnPostOper, I_OnSyncOtherMetaData, I_OnSetAway, I_OnCancelAway, I_OnUserList,
-                       I_OnPostCommand, I_OnPostJoin, I_OnWhoisLine, I_OnBuildExemptList, I_OnRawSocketConnect };
+                       I_OnPostCommand, I_OnPostJoin, I_OnWhoisLine, I_OnBuildExemptList, I_OnRawSocketConnect, I_OnGarbageCollect, I_OnBufferFlushed };
 
 /** 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 Module : public Extensible
+class CoreExport Module : public Extensible
 {
  protected:
+       /** Creator/owner pointer
+        */
        InspIRCd* ServerInstance;
  public:
 
-       /** Default constructor
+       /** 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);
 
-       /** Default destructor
+       /** Default destructor.
         * destroys a module class
         */
        virtual ~Module();
@@ -461,9 +520,10 @@ class Module : public Extensible
         * This event is only called when the user is fully registered when they quit. To catch
         * raw disconnections, use the OnUserDisconnect method.
         * @param user The user who is quitting
-        * @param message The user's quit message
+        * @param message The user's quit message (as seen by non-opers)
+        * @param oper_message The user's quit message (as seen by opers)
         */
-       virtual void OnUserQuit(userrec* user, const std::string &message);
+       virtual void OnUserQuit(userrec* user, const std::string &message, const std::string &oper_message);
 
        /** Called whenever a user's socket is closed.
         * The details of the exiting user are available to you in the parameter userrec *user
@@ -483,8 +543,10 @@ class Module : public Extensible
         * and the details of the channel they have joined is available in the variable chanrec *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)
         */
-       virtual void OnUserJoin(userrec* user, chanrec* channel);
+       virtual void OnUserJoin(userrec* user, chanrec* channel, bool &silent);
 
        /** Called after a user joins a channel
         * Identical to OnUserJoin, but called immediately afterwards, when any linking module has
@@ -500,17 +562,21 @@ class Module : public Extensible
         * @param user The user who is parting
         * @param channel The channel being parted
         * @param partmessage The part message, or an empty string
+        * @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(userrec* user, chanrec* channel, const std::string &partmessage);
+       virtual void OnUserPart(userrec* user, chanrec* channel, const std::string &partmessage, bool &silent);
 
        /** Called on rehash.
         * This method is called prior to a /REHASH or when a SIGHUP is received from the operating
         * system. You should use it to reload any files so that your module keeps in step with the
         * rest of the application. If a parameter is given, the core has done nothing. The module
         * receiving the event can decide if this parameter has any relevence to it.
+        * @param user The user performing the rehash, if any -- if this is server initiated, the
+        * value of this variable will be NULL.
         * @param parameter The (optional) parameter given to REHASH from the user.
         */
-       virtual void OnRehash(const std::string &parameter);
+       virtual void OnRehash(userrec* user, const std::string &parameter);
 
        /** Called when a raw command is transmitted or received.
         * This method is the lowest level of handler available to a module. It will be called with raw
@@ -565,8 +631,10 @@ class 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(userrec* source, userrec* user, chanrec* chan, const std::string &reason);
+       virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent);
 
        /** Called whenever a user opers locally.
         * The userrec will contain the oper mode 'o' as this function is called after any modifications
@@ -770,8 +838,10 @@ class Module : public Extensible
         * @param proto A pointer to the module handling network protocol
         * @param opaque An opaque pointer set by the protocol module, should not be modified!
         * @param extname The extensions name which is being searched for
+        * @param displayable If this value is true, the data is going to be displayed to a user,
+        * and not sent across the network. Use this to determine wether or not to show sensitive data.
         */
-       virtual void OnSyncChannelMetaData(chanrec* chan, Module* proto,void* opaque, const std::string &extname);
+       virtual void OnSyncChannelMetaData(chanrec* chan, Module* proto,void* opaque, const std::string &extname, bool displayable = false);
 
        /* Allows modules to syncronize metadata related to users over the network during a netburst.
         * Whenever the linking module wants to send out data, but doesnt know what the data
@@ -783,8 +853,10 @@ class Module : public Extensible
         * @param proto A pointer to the module handling network protocol
         * @param opaque An opaque pointer set by the protocol module, should not be modified!
         * @param extname The extensions name which is being searched for
+        * @param displayable If this value is true, the data is going to be displayed to a user,
+        * and not sent across the network. Use this to determine wether or not to show sensitive data.
         */
-       virtual void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname);
+       virtual void OnSyncUserMetaData(userrec* user, Module* proto,void* opaque, const std::string &extname, bool displayable = false);
 
        /* Allows modules to syncronize metadata not related to users or channels, over the network during a netburst.
         * Whenever the linking module wants to send out data, but doesnt know what the data
@@ -794,8 +866,10 @@ class Module : public Extensible
         * if it belongs to your module.
         * @param proto A pointer to the module handling network protocol
         * @param opaque An opaque pointer set by the protocol module, should not be modified!
+        * @param displayable If this value is true, the data is going to be displayed to a user,
+        * and not sent across the network. Use this to determine wether or not to show sensitive data.
         */
-       virtual void OnSyncOtherMetaData(Module* proto, void* opaque);
+       virtual void OnSyncOtherMetaData(Module* proto, void* opaque, bool displayable = false);
 
        /** Allows module data, sent via ProtoSendMetaData, to be decoded again by a receiving module.
         * Please see src/modules/m_swhois.cpp for a working example of how to use this method call.
@@ -1012,7 +1086,7 @@ class Module : public Extensible
         * @param dest The user being killed
         * @param reason The kill reason
         */
-       virtual void OnRemoteKill(userrec* source, userrec* dest, const std::string &reason);
+       virtual void OnRemoteKill(userrec* source, userrec* dest, const std::string &reason, const std::string &operreason);
 
        /** Called whenever a module is loaded.
         * mod will contain a pointer to the module, and string will contain its name,
@@ -1283,6 +1357,10 @@ class Module : public Extensible
         */
        virtual void OnRawSocketClose(int fd);
 
+       /** Called immediately upon connection of an outbound InspSocket 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.
@@ -1305,10 +1383,12 @@ class Module : public Extensible
        /** Called whenever a user sets away.
         * This method has no parameter for the away message, as it is available in the
         * user record as userrec::awaymsg.
+        * @param user The user setting away
         */
        virtual void OnSetAway(userrec* user);
 
        /** Called when a user cancels their away state.
+        * @param user The user returning from away
         */
        virtual void OnCancelAway(userrec* user);
 
@@ -1316,8 +1396,14 @@ class Module : public Extensible
         * You can produce the nameslist yourself, overriding the current list,
         * and if you do you must return 1. If you do not handle the names list,
         * 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
         */
-       virtual int OnUserList(userrec* user, chanrec* Ptr);
+       virtual int OnUserList(userrec* user, chanrec* Ptr, CUList* &userlist);
 
        /** 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
@@ -1331,6 +1417,22 @@ class Module : public Extensible
         * receive it, or zero to allow the line to be sent.
         */
        virtual int OnWhoisLine(userrec* user, userrec* 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
+        * tidied up and freed by copying into a new item every so often. This
+        * method is called when it is time to do that.
+        */
+       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(userrec* user);
 };
 
 
@@ -1346,7 +1448,7 @@ class 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 ConfigReader : public classbase
+class CoreExport ConfigReader : public classbase
 {
   protected:
        InspIRCd* ServerInstance;
@@ -1356,11 +1458,17 @@ class ConfigReader : public classbase
         * (such as comments) stripped from it.
         */
        ConfigDataHash* data;
-       std::ostringstream* errorlog;;
        /** Used to store errors
         */
-       bool privatehash; // If we're using our own config data hash or not.
+       std::ostringstream* errorlog;
+       /** If we're using our own config data hash or not
+        */
+       bool privatehash;
+       /** True if an error occured reading the config file
+        */
        bool readerror;
+       /** Error code
+        */
        long error;
        
   public:
@@ -1377,17 +1485,33 @@ class ConfigReader : public classbase
         * This method destroys the ConfigReader class.
         */
        ~ConfigReader();
+
        /** Retrieves a value from the config file.
         * This method retrieves a value from the config file. Where multiple copies of the tag
         * exist in the config file, index indicates which of the values to retrieve.
         */
        std::string ReadValue(const std::string &tag, const std::string &name, int index, bool allow_linefeeds = false);
+       /** Retrieves a value from the config file.
+        * This method retrieves a value from the config file. Where multiple copies of the tag
+        * exist in the config file, index indicates which of the values to retrieve. If the
+        * tag is not found the default value is returned instead.
+        */
+       std::string ReadValue(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool allow_linefeeds = false);
+
        /** Retrieves a boolean value from the config file.
         * This method retrieves a boolean value from the config file. Where multiple copies of the tag
         * exist in the config file, index indicates which of the values to retrieve. The values "1", "yes"
         * and "true" in the config file count as true to ReadFlag, and any other value counts as false.
         */
        bool ReadFlag(const std::string &tag, const std::string &name, int index);
+       /** Retrieves a boolean value from the config file.
+        * This method retrieves a boolean value from the config file. Where multiple copies of the tag
+        * exist in the config file, index indicates which of the values to retrieve. The values "1", "yes"
+        * and "true" in the config file count as true to ReadFlag, and any other value counts as false.
+        * If the tag is not found, the default value is used instead.
+        */
+       bool ReadFlag(const std::string &tag, const std::string &name, const std::string &default_value, int index);
+
        /** Retrieves an integer value from the config file.
         * This method retrieves an integer value from the config file. Where multiple copies of the tag
         * exist in the config file, index indicates which of the values to retrieve. Any invalid integer
@@ -1397,6 +1521,16 @@ class ConfigReader : public classbase
         * will return CONF_NOT_UNSIGNED
         */
        long ReadInteger(const std::string &tag, const std::string &name, int index, bool needs_unsigned);
+       /** Retrieves an integer value from the config file.
+        * This method retrieves an integer value from the config file. Where multiple copies of the tag
+        * exist in the config file, index indicates which of the values to retrieve. Any invalid integer
+        * values in the tag will cause the objects error value to be set, and any call to GetError() will
+        * return CONF_INVALID_NUMBER to be returned. needs_unsigned is set if the number must be unsigned.
+        * If a signed number is placed into a tag which is specified unsigned, 0 will be returned and GetError()
+        * will return CONF_NOT_UNSIGNED. If the tag is not found, the default value is used instead.
+        */
+       long ReadInteger(const std::string &tag, const std::string &name, const std::string &default_value, int index, bool needs_unsigned);
+
        /** Returns the last error to occur.
         * Valid errors can be found by looking in modules.h. Any nonzero value indicates an error condition.
         * A call to GetError() resets the error flag back to 0.
@@ -1437,15 +1571,19 @@ class ConfigReader : public classbase
  * Either use the constructor type with one parameter to load a file into memory
  * at construction, or use the LoadFile method to load a file.
  */
-class FileReader : public classbase
+class CoreExport FileReader : public classbase
 {
        InspIRCd* ServerInstance;
        /** The file contents
         */
        file_cache fc;
 
+       /** Content size in bytes
+        */
        unsigned long contentsize;
 
+       /** Calculate content size in bytes
+        */
        void CalcSize();
 
  public:
@@ -1508,7 +1646,7 @@ class FileReader : public classbase
  * In most cases, the simple class shown in the example module m_foobar.so will suffice for most
  * modules.
  */
-class ModuleFactory : public classbase
+class CoreExport ModuleFactory : public classbase
 {
  public:
        /** The default constructor does nothing.
@@ -1536,4 +1674,23 @@ typedef std::vector<Module*> ModuleList;
  */
 typedef std::vector<ircd_module*> FactoryList;
 
+/** 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.
+ */
+#define MODULE_INIT(y) \
+       class Factory : public ModuleFactory \
+       { \
+        public: \
+               virtual Module * CreateModule(InspIRCd* Me) \
+               { \
+                       return new y(Me); \
+               } \
+       }; \
+       extern "C" DllExport void * init_module(void) \
+       { \
+               return new Factory; \
+       }
+
 #endif
+