X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=include%2Fmodules.h;h=21e4760897f234045690980735f169f3c88b6287;hb=219993bc9018d9f0d9568330d7a972b68b785d27;hp=4adab2378de604b381ec0ec7efa389d02374b58d;hpb=bf44023d115745d4a6a1ce06ff291ffb73480efb;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/include/modules.h b/include/modules.h index 4adab2378..21e476089 100644 --- a/include/modules.h +++ b/include/modules.h @@ -2,8 +2,8 @@ * | Inspire Internet Relay Chat Daemon | * +------------------------------------+ * - * InspIRCd: (C) 2002-2007 InspIRCd Development Team - * See: http://www.inspircd.org/wiki/index.php/Credits + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits * * This program is free but copyrighted software; see * the file COPYING for details. @@ -14,6 +14,17 @@ #ifndef __MODULES_H #define __MODULES_H +#include "dynamic.h" +#include "base.h" +#include "ctables.h" +#include "inspsocket.h" +#include +#include +#include +#include "timer.h" +#include "mode.h" +#include "dns.h" + class XLine; /** Used with OnAccessCheck() method of modules @@ -65,30 +76,8 @@ enum MessageType { MSG_NOTICE = 1 }; -#include "globals.h" -#include "dynamic.h" -#include "base.h" -#include "ctables.h" -#include "inspsocket.h" -#include -#include -#include -#include "timer.h" -#include "mode.h" -#include "dns.h" - -/** If you change the module API, change this value. - * If you have enabled ipv6, the sizes of structs is - * different, and modules will be incompatible with - * ipv4 servers, so this value will be ten times as - * high on ipv6 servers. - */ -#define NATIVE_API_VERSION 12000 -#ifdef IPV6 -#define API_VERSION (NATIVE_API_VERSION * 10) -#else -#define API_VERSION (NATIVE_API_VERSION * 1) -#endif +/** If you change the module API, change this value. */ +#define API_VERSION 13000 class ServerConfig; @@ -123,20 +112,23 @@ typedef std::map > interfacelist; * loaded modules in a readable simple way, e.g.: * 'FOREACH_MOD(I_OnConnect,OnConnect(user));' */ -#define FOREACH_MOD(y,x) if (!ServerInstance->Modules->EventHandlers[y].empty()) \ -{ \ - for (EventHandlerIter _i = ServerInstance->Modules->EventHandlers[y].begin(); _i != ServerInstance->Modules->EventHandlers[y].end(); ++_i) \ +#define FOREACH_MOD(y,x) do { \ + EventHandlerIter safei; \ + for (EventHandlerIter _i = ServerInstance->Modules->EventHandlers[y].begin(); _i != ServerInstance->Modules->EventHandlers[y].end(); ) \ { \ + safei = _i; \ + ++safei; \ try \ { \ (*_i)->x ; \ } \ catch (CoreException& modexcept) \ { \ - ServerInstance->Log(DEFAULT,"Exception caught: %s",modexcept.GetReason()); \ + ServerInstance->Logs->Log("MODULE",DEFAULT,"Exception caught: %s",modexcept.GetReason()); \ } \ + _i = safei; \ } \ -} +} while (0); /** * This #define allows us to call a method in all @@ -144,31 +136,37 @@ typedef std::map > interfacelist; * an instance pointer to the macro. e.g.: * 'FOREACH_MOD_I(Instance, OnConnect, OnConnect(user));' */ -#define FOREACH_MOD_I(z,y,x) if (!z->Modules->EventHandlers[y].empty()) \ -{ \ - for (EventHandlerIter _i = z->Modules->EventHandlers[y].begin(); _i != z->Modules->EventHandlers[y].end(); ++_i) \ +#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->Log(DEFAULT,"Exception caught: %s",modexcept.GetReason()); \ + 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) if (!ServerInstance->Modules->EventHandlers[y].empty()) \ -{ \ +#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(); ++_i) \ + for (EventHandlerIter _i = ServerInstance->Modules->EventHandlers[y].begin(); _i != ServerInstance->Modules->EventHandlers[y].end(); ) \ { \ + safei = _i; \ + ++safei; \ try \ { \ int res = (*_i)->x ; \ @@ -179,10 +177,11 @@ typedef std::map > interfacelist; } \ catch (CoreException& modexcept) \ { \ - ServerInstance->Log(DEFAULT,"Exception caught: %s",modexcept.GetReason()); \ + ServerInstance->Logs->Log("MODULE",DEFAULT,"Exception caught: %s",modexcept.GetReason()); \ } \ + _i = safei; \ } \ -} +} while(0); /** @@ -190,11 +189,14 @@ typedef std::map > interfacelist; * 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->Modules->EventHandlers[y].empty()) \ -{ \ +#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(); ++_i) \ + for (EventHandlerIter _i = z->Modules->EventHandlers[y].begin(); _i != z->Modules->EventHandlers[y].end(); ) \ { \ + safei = _i; \ + ++safei; \ try \ { \ int res = (*_i)->x ; \ @@ -205,32 +207,54 @@ typedef std::map > interfacelist; } \ catch (CoreException& modexcept) \ { \ - z->Log(DEBUG,"Exception caught: %s",modexcept.GetReason()); \ + z->Logs->Log("MODULE",DEBUG,"Exception caught: %s",modexcept.GetReason()); \ + } \ + _i = safei; \ + } \ +} while (0); + +#define FOREACH_RESULT_MAP(y,x,f) \ +do { \ + EventHandlerIter safei; \ + for (EventHandlerIter _i = ServerInstance->Modules->EventHandlers[y].begin(); _i != ServerInstance->Modules->EventHandlers[y].end(); ) \ + { \ + safei = _i; \ + ++safei; \ + try \ + { \ + int MOD_RESULT = (*_i)->x ; \ + f; \ + } \ + catch (CoreException& modexcept) \ + { \ + ServerInstance->Logs->Log("MODULE",DEFAULT,"Exception caught: %s",modexcept.GetReason()); \ } \ + _i = safei; \ } \ -} +} 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 */ -#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 +#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) +#define IS_OPER(x) (!x->oper.empty()) /** Is away */ -#define IS_AWAY(x) (*x->awaymsg) +#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 @@ -242,13 +266,17 @@ typedef std::map > interfacelist; class CoreExport Version : public classbase { public: - /** Version numbers, build number, flags and API version - */ - const int Major, Minor, Revision, Build, Flags, API; + /** Version information. + */ + std::string version; - /** Initialize version class - */ - Version(int major, int minor, int revision, int build, int flags, int api_ver); + /** Flags and API version + */ + const int Flags, API; + + /** Initialize version class + */ + Version(const std::string &sversion, int flags, int api_ver); }; /** The ModuleMessage class is the base class of Request and Event @@ -274,11 +302,11 @@ class CoreExport Request : public ModuleMessage /** This member holds a pointer to arbitary data set by the emitter of the message */ char* data; - /** 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; + /** 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; /** This is a pointer to the sender of the message, which can be used to * directly trigger events, or to create a reply. */ @@ -288,26 +316,26 @@ class CoreExport Request : public ModuleMessage 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. + * 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); - /** Create a new Request - * This is for the 'new' way of defining a subclass - * of Request and defining it in a common header, + /** 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<>() - */ - Request(Module* src, Module* dst, const char* idstr); + * 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<>() + */ + Request(Module* src, Module* dst, const char* idstr); /** Fetch the Request data */ char* GetData(); - /** Fetch the ID string + /** Fetch the ID string */ const char* GetId(); /** Fetch the request source @@ -321,7 +349,7 @@ class CoreExport Request : public ModuleMessage * sent the request to. It is up to your module to know what this data is and * how to deal with it. */ - char* Send(); + const char* Send(); }; @@ -375,22 +403,25 @@ enum Priority { PRIORITY_FIRST, PRIORITY_DONTCARE, PRIORITY_LAST, PRIORITY_BEFOR enum Implementation { I_BEGIN, - I_OnUserConnect, I_OnUserQuit, I_OnUserDisconnect, I_OnUserJoin, I_OnUserPart, I_OnRehash, I_OnServerRaw, + I_OnUserConnect, I_OnUserQuit, I_OnUserDisconnect, I_OnUserJoin, I_OnUserPart, I_OnRehash, 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_OnSyncChannelMetaData, I_OnSyncUserMetaData, I_OnDecodeMetaData, I_ProtoSendMode, I_ProtoSendMetaData, I_OnWallops, I_OnChangeHost, I_OnChangeName, I_OnAddLine, - I_OnDelLine, I_OnCleanup, I_OnUserPostNick, I_OnAccessCheck, I_On005Numeric, I_OnKill, I_OnRemoteKill, I_OnLoadModule, I_OnUnloadModule, - I_OnBackgroundTimer, I_OnPreCommand, I_OnCheckReady, I_OnUserRrgister, I_OnCheckInvite, - I_OnCheckKey, I_OnCheckLimit, I_OnCheckBan, I_OnStats, I_OnChangeLocalUserHost, I_OnChangeLocalUserGecos, I_OnLocalTopicChange, - I_OnPostLocalTopicChange, I_OnEvent, I_OnRequest, I_OnOperCompre, I_OnGlobalOper, I_OnPostConnect, I_OnAddBan, I_OnDelBan, + I_OnDelLine, I_OnExpireLine, I_OnCleanup, I_OnUserPostNick, I_OnAccessCheck, 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_OnOperCompare, I_OnChannelDelete, I_OnPostOper, I_OnSyncOtherMetaData, I_OnSetAway, I_OnCancelAway, I_OnUserList, + I_OnChannelPreDelete, I_OnChannelDelete, I_OnPostOper, I_OnSyncOtherMetaData, I_OnSetAway, I_OnUserList, I_OnPostCommand, I_OnPostJoin, I_OnWhoisLine, I_OnBuildExemptList, I_OnRawSocketConnect, I_OnGarbageCollect, I_OnBufferFlushed, - I_OnText, + I_OnText, I_OnPassCompare, I_OnRunTestSuite, I_OnNamesListItem, I_OnNumeric, I_OnHookUserIO, I_OnHostCycle, + I_OnPreRehash, I_OnModuleRehash, 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 @@ -416,47 +447,16 @@ class CoreExport Module : public Extensible */ virtual ~Module(); + virtual void Prioritize() + { + } + /** Returns the version number of a Module. * The method should return a Version object with its version information assigned via * Version::Version */ virtual Version GetVersion(); - /** The Implements function specifies which methods a module should receive events for. - * The char* parameter passed to this function contains a set of true or false values - * (1 or 0) which indicate wether each function is implemented. You must use the Iimplementation - * enum (documented elsewhere on this page) to mark functions as active. For example, to - * receive events for OnUserJoin(): - * - * Implements[I_OnUserJoin] = 1; - * - * @param The implement list - */ - virtual void Implements(char* Implements); - - /** Used to set the 'priority' of a module (e.g. when it is called in relation to other modules. - * Some modules prefer to be called before other modules, due to their design. For example, a - * module which is expected to operate on complete information would expect to be placed last, so - * that any other modules which wish to adjust that information would execute before it, to be sure - * its information is correct. You can change your module's priority by returning one of: - * - * PRIORITY_FIRST - To place your module first in the list - * - * PRIORITY_LAST - To place your module last in the list - * - * PRIORITY_DONTCARE - To leave your module as it is (this is the default value, if you do not implement this function) - * - * The result of InspIRCd::PriorityBefore() - To move your module before another named module - * - * The result of InspIRCd::PriorityLast() - To move your module after another named module - * - * For a good working example of this method call, please see src/modules/m_spanningtree.cpp - * and src/modules/m_hostchange.so which make use of it. It is highly recommended that unless - * your module has a real need to reorder its priority, it should not implement this function, - * as many modules changing their priorities can make the system redundant. - */ - virtual Priority Prioritize(); - /** 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 @@ -481,6 +481,12 @@ class CoreExport Module : public Extensible */ virtual void OnUserDisconnect(User* 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); + /** Called whenever a channel is deleted, either by QUIT, KICK or PART. * @param chan The channel being deleted */ @@ -493,8 +499,10 @@ class CoreExport Module : public Extensible * @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 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. */ - virtual void OnUserJoin(User* user, Channel* channel, bool &silent); + virtual void OnUserJoin(User* user, Channel* channel, bool sync, bool &silent); /** Called after a user joins a channel * Identical to OnUserJoin, but called immediately afterwards, when any linking module has @@ -509,35 +517,50 @@ class CoreExport Module : public Extensible * 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 partmessage The part message, or an empty string + * @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, const std::string &partmessage, bool &silent); + virtual void OnUserPart(User* user, Channel* channel, 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(User* user, const std::string ¶meter); - - /** 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 - * data which is passing through a connected socket. If you wish, you may munge this data by changing - * the string parameter "raw". If you do this, after your function exits it will immediately be - * cut down to 510 characters plus a carriage return and linefeed. For INBOUND messages only (where - * inbound is set to true) the value of user will be the User of the connection sending the - * data. This is not possible for outbound data because the data may be being routed to multiple targets. - * @param raw The raw string in RFC1459 format - * @param inbound A flag to indicate wether the data is coming into the daemon or going out to the user - * @param user The user record sending the text, when inbound == true. - */ - virtual void OnServerRaw(std::string &raw, bool inbound, User* user); + * system. This is called in all cases -- including when this server will not execute the + * rehash because it is directed at a remote server. + * + * @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. Empty when server + * initiated. + */ + virtual void OnPreRehash(User* user, const std::string ¶meter); + + /** Called on rehash. + * This method is called when a user initiates a module-specific rehash. This can be used to do + * expensive operations (such as reloading SSL certificates) that are not executed on a normal + * rehash for efficiency. A rehash of this type does not reload the core configuration. + * + * @param user The user performing the rehash. + * @param parameter The parameter given to REHASH + */ + virtual void OnModuleRehash(User* user, const std::string ¶meter); + + /** Called on rehash. + * This method is called after a rehash has completed. You should use it to reload any module + * configuration from the main configuration file. + * @param user The user that performed the rehash, if it was initiated by a user and that user + * is still connected. + */ + virtual void OnRehash(User* user); + + /** Called whenever a snotice is about to be sent to a snomask. + * snomask and type may both be modified; the message may not. + * @param snomask The snomask the message is going to (e.g. 'A') + * @param type The textual description the snomask will go to (e.g. 'OPER') + * @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); /** 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 @@ -556,10 +579,11 @@ class CoreExport Module : public Extensible * @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 "@". * 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); - + virtual int 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 * output to be sent to the user by the core. If you do this you must produce your own numerics, @@ -597,10 +621,11 @@ class CoreExport Module : public Extensible * can be gauranteed to already have processed the oper-up, for example m_spanningtree has sent * out the OPERTYPE, etc. * @param user The user who is opering up + * @param opername The name of the oper that the user is opering up to. Only valid locally. Empty string otherwise. * @param opertype The opers type name */ - virtual void OnPostOper(User* user, const std::string &opertype); - + virtual void OnPostOper(User* user, const std::string &opername, const std::string &opertype); + /** Called whenever a user types /INFO. * The User will contain the information of the user who typed the command. Modules may use this * method to output their own credits in /INFO (which is the ircd's version of an about box). @@ -612,7 +637,7 @@ class CoreExport Module : public Extensible * @param user The user issuing /INFO */ virtual void OnInfo(User* user); - + /** Called whenever a /WHOIS is performed on a local user. * The source parameter contains the details of the user who issued the WHOIS command, and * the dest parameter contains the information of the user they are whoising. @@ -620,7 +645,7 @@ class CoreExport Module : public Extensible * @param dest The user who is being WHOISed */ virtual void OnWhois(User* source, User* dest); - + /** Called whenever a user is about to invite another user into a channel, before any processing is done. * Returning 1 from this function stops the process immediately, causing no * output to be sent to the user by the core. If you do this you must produce your own numerics, @@ -628,19 +653,21 @@ class CoreExport Module : public Extensible * @param source The user who is issuing the INVITE * @param dest The user being invited * @param channel The channel the user is being invited to - * @return 1 to deny the invite, 0 to allow + * @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); - + virtual int 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, * use OnUserPreInvite instead. * @param source The user who is issuing the INVITE * @param dest The user being invited * @param channel The channel the user is being invited to + * @param timeout The time the invite will expire (0 == never) */ - virtual void OnUserInvite(User* source,User* dest,Channel* channel); - + virtual void OnUserInvite(User* source,User* dest,Channel* channel, time_t timeout); + /** Called whenever a user is about to PRIVMSG A user or a channel, before any processing is done. * Returning any nonzero value from this function stops the process immediately, causing no * output to be sent to the user by the core. If you do this you must produce your own numerics, @@ -655,7 +682,7 @@ class CoreExport Module : public Extensible * @param status The status being used, e.g. PRIVMSG @#chan has status== '@', 0 to send to everyone. * @param exempt_list A list of users not to send to. For channel messages, this will usually contain just the sender. * It will be ignored for private messages. - * @return 1 to deny the NOTICE, 0 to allow it + * @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); @@ -690,7 +717,7 @@ class CoreExport Module : public Extensible * @param text The original message text causing the exempt list to be built */ virtual void OnBuildExemptList(MessageType message_type, Channel* chan, User* sender, char status, CUList &exempt_list, const std::string &text); - + /** 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 * NOT make any changes to the User if the user is a remote user as this may cause a desnyc. @@ -747,8 +774,9 @@ class CoreExport Module : public Extensible * @param dest The target of the modes (User* or Channel*) * @param target_type The type of target (TYPE_USER or TYPE_CHANNEL) * @param text The actual modes and their parameters if any + * @param translate The translation types of the mode parameters */ - virtual void OnMode(User* user, void* dest, int target_type, const std::string &text); + virtual void OnMode(User* user, void* dest, int target_type, const std::vector &text, const std::vector &translate); /** Allows modules to alter or create server descriptions * Whenever a module requires a server description, for example for display in @@ -855,8 +883,9 @@ class CoreExport Module : public Extensible * @param target_type The type of item to decode data for, TYPE_USER or TYPE_CHANNEL * @param target The Channel* or User* that modes should be sent for * @param modeline The modes and parameters to be sent + * @param translate The translation types of the mode parameters */ - virtual void ProtoSendMode(void* opaque, int target_type, void* target, const std::string &modeline); + virtual void ProtoSendMode(void* opaque, TargetTypeFlags target_type, void* target, const std::vector &modeline, const std::vector &translate); /** Implemented by modules which provide the ability to link servers. * These modules will implement this method, which allows metadata (extra data added to @@ -872,8 +901,8 @@ class CoreExport Module : public Extensible * @param extname The extension name to send metadata for * @param extdata Encoded data for this extension name, which will be encoded at the oppsite end by an identical module using OnDecodeMetaData */ - virtual void ProtoSendMetaData(void* opaque, int target_type, void* target, const std::string &extname, const std::string &extdata); - + virtual void ProtoSendMetaData(void* opaque, TargetTypeFlags target_type, void* target, const std::string &extname, const std::string &extdata); + /** Called after every WALLOPS command. * @param user The user sending the WALLOPS * @param text The content of the WALLOPS message @@ -901,18 +930,18 @@ class CoreExport Module : public Extensible */ virtual void OnAddLine(User* source, XLine* line); - /** Called whenever an xline is deleted. + /** Called whenever an xline is deleted MANUALLY. See OnExpireLine for expiry. * This method is triggered after the line is deleted. * @param source The user removing the line or NULL for local server * @param line the line being deleted */ virtual void OnDelLine(User* source, XLine* line); - /** Called whenever a zline is deleted. + /** Called whenever an xline expires. * This method is triggered after the line is deleted. - * @param source The user removing the line - * @param hostmask The hostmask to delete + * @param line The line being deleted. */ + virtual void OnExpireLine(XLine *line); /** Called before your module is unloaded to clean up Extensibles. * This method is called once for every user and channel on the network, @@ -941,15 +970,15 @@ class CoreExport Module : public Extensible * 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:

- * AC_KICK (0) - A user is being kicked
- * AC_DEOP (1) - a user is being deopped
- * AC_OP (2) - a user is being opped
- * AC_VOICE (3) - a user is being voiced
- * AC_DEVOICE (4) - a user is being devoiced
- * AC_HALFOP (5) - a user is being halfopped
- * AC_DEHALFOP (6) - a user is being dehalfopped
- * AC_INVITE () - a user is being invited
- * AC_GENERAL_MODE (8) - a user channel mode is being changed

+ * 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 user channel mode is being changed

* 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 @@ -1041,10 +1070,11 @@ class CoreExport Module : public Extensible * @param pcnt The nuimber of parameters passed to the command * @param user the user issuing the command * @param validated True if the command has passed all checks, e.g. it is recognised, has enough parameters, the user has permission to execute it, etc. + * You should only change the parameter list and command string if validated == false (e.g. before the command lookup occurs). * @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(const std::string &command, const char** parameters, int pcnt, User *user, bool validated, const std::string &original_line); + virtual int OnPreCommand(std::string &command, std::vector& 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, @@ -1058,7 +1088,7 @@ class CoreExport Module : public Extensible * @param result The return code given by the command handler, one of CMD_SUCCESS or CMD_FAILURE * @param original_line The entire original line as passed to the parser from the user */ - virtual void OnPostCommand(const std::string &command, const char** parameters, int pcnt, User *user, CmdResult result, const std::string &original_line); + virtual void OnPostCommand(const std::string &command, const std::vector& parameters, User *user, CmdResult result, const std::string &original_line); /** Called to check if a user who is connecting can now be allowed to register * If any modules return false for this function, the user is held in the waiting @@ -1093,6 +1123,20 @@ class CoreExport Module : public Extensible */ virtual int 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. + * @param user The user who is sending the mode + * @param chan The channel the mode is being sent to (or NULL if a usermode) + * @param mode The mode character being set + * @param param The parameter for the mode or an empty string + * @param adding true of the mode is being added, false if it is being removed + * @param pcnt The parameter count for the mode (0 or 1) + * @return ACR_DENY to deny the mode, ACR_DEFAULT to do standard mode checking, and ACR_ALLOW + * 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 ¶m, bool adding, int pcnt, bool servermode = true); + /** 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 * determines the outcome of an if statement around the whole section of key checking code. @@ -1120,10 +1164,26 @@ class CoreExport Module : public Extensible * 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 allow the join, 0 to proceed as normal. Return -1 to explicitly deny the + * join to the channel. */ virtual int OnCheckBan(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 + */ + virtual int OnCheckExtBan(User *u, Channel *c, char type); + + /** 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 + */ + virtual int OnCheckStringExtBan(const std::string &s, Channel *c, char type); + /** Called on all /STATS commands * This method is triggered for all /STATS use, including stats symbols handled by the core. * @param symbol the symbol provided to /STATS @@ -1149,10 +1209,10 @@ 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 int OnChangeLocalUserGECOS(User* user, const std::string &newhost); /** Called whenever a topic is changed by a local user. - * Return 1 to deny the topic change, or 0 to allow it. + * Return 1 to deny the topic change, 0 to check details on the change, -1 to let it through with no checks * @param user The user changing the topic * @param chan The channels who's topic is being changed * @param topic The actual topic text @@ -1183,19 +1243,19 @@ class CoreExport Module : public Extensible * may be able to use for pre-determined purposes (e.g. the results of an SQL query, etc). * @param request The Request class being received */ - virtual char* OnRequest(Request* request); + virtual const char* OnRequest(Request* request); - /** Called whenever an oper password is to be compared to what a user has input. + /** 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 - * 'input'. This method allows for encryption of oper passwords and much more besides. - * You should return a nonzero value if you want to allow the comparison or zero if you wish - * to do nothing. - * @param password The oper's password - * @param input The password entered - * @param tagnumber The tag number (from the configuration file) of this oper's tag - * @return 1 to match the passwords, 0 to do nothing. -1 to not match, and not continue. + * 'input'. This method allows for encryption of passwords (oper, connect:allow, die/restart, etc). + * You should return a nonzero value to override the normal comparison, or zero to pass it on. + * @param ex The object that's causing the authentication (User* for etc, Server* for ). + * @param password The password from the configuration file (the password="" value). + * @param input The password entered by the user or whoever. + * @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 OnOperCompare(const std::string &password, const std::string &input, int tagnumber); + virtual int 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 @@ -1231,16 +1291,19 @@ class CoreExport Module : public Extensible */ virtual int OnDelBan(User* source, Channel* channel,const std::string &banmask); + virtual void OnHookUserIO(User* user); + /** 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 * process the connection. * @param fd The file descriptor returned from accept() - * @param ip The IP address of the connecting user + * @param client The client IP address and port + * @param server The server IP address and port * @param localport The local port number the user connected to */ - virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport); + virtual void OnRawSocketAccept(int fd, 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 @@ -1283,17 +1346,15 @@ class CoreExport Module : public Extensible */ virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult); - /** Called whenever a user sets away. - * This method has no parameter for the away message, as it is available in the - * user record as User::awaymsg. + /** Called whenever a user sets away or returns from being away. + * The away message is available as a parameter, but should not be modified. + * At this stage, it has already been copied into the user record. + * If awaymsg is empty, the user is returning from away. * @param user The user setting away + * @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 void OnSetAway(User* user); - - /** Called when a user cancels their away state. - * @param user The user returning from away - */ - virtual void OnCancelAway(User* user); + virtual int OnSetAway(User* user, const std::string &awaymsg); /** Called whenever a NAMES list is requested. * You can produce the nameslist yourself, overriding the current list, @@ -1304,7 +1365,9 @@ class CoreExport Module : public Extensible * @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 + * @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); @@ -1336,6 +1399,25 @@ class CoreExport Module : public Extensible * @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. + */ + virtual void OnRunTestSuite(); + + /** Called for every item in a NAMES list, so that modules may reformat portions of it as they see fit. + * 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 int 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. + */ + virtual bool OnHostCycle(User* user); }; @@ -1356,35 +1438,16 @@ class CoreExport ConfigReader : public classbase { protected: InspIRCd* ServerInstance; - /** The contents of the configuration file - * This protected member should never be accessed by a module (and cannot be accessed unless the - * core is changed). It will contain a pointer to the configuration file data with unneeded data - * (such as comments) stripped from it. - */ - ConfigDataHash* data; - /** Used to store errors - */ - 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: /** Default constructor. * This constructor initialises the ConfigReader class to read the inspircd.conf file * as specified when running ./configure. */ ConfigReader(InspIRCd* Instance); - /** Overloaded constructor. - * This constructor initialises the ConfigReader class to read a user-specified config file - */ - ConfigReader(InspIRCd* Instance, const std::string &filename); /** Default destructor. * This method destroys the ConfigReader class. */ @@ -1448,18 +1511,6 @@ class CoreExport ConfigReader : public classbase * multiple instance tag. */ int Enumerate(const std::string &tag); - /** Returns true if a config file is valid. - * This method is partially implemented and will only return false if the config - * file does not exist or could not be opened. - */ - bool Verify(); - /** Dumps the list of errors in a config file to an output location. If bail is true, - * then the program will abort. If bail is false and user points to a valid user - * record, the error report will be spooled to the given user by means of NOTICE. - * if bool is false AND user is false, the error report will be spooled to all opers - * by means of a NOTICE to all opers. - */ - void DumpErrors(bool bail,User* user); /** Returns the number of items within a tag. * For example if the tag was <test tag="blah" data="foo"> then this @@ -1529,7 +1580,7 @@ class CoreExport FileReader : public classbase * This function will return false if the file could not be opened. */ bool Exists(); - + /** Retrieve one line from the file. * This method retrieves one line from the text file. If an empty non-NULL string is returned, * the index was out of bounds, or the line had no data on it. @@ -1545,20 +1596,19 @@ class CoreExport FileReader : public classbase }; /** A DLLFactory (designed to load shared objects) containing a - * handle to a module's init_module() function. + * 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 ircd_module; -/** A list of loaded Modules +/** A list of modules */ -typedef std::vector ModuleList; +typedef std::vector IntModuleList; -/** A list of loaded module handles (ircd_module) +/** An event handler iterator */ -typedef std::vector ModuleHandleList; - -typedef std::list IntModuleList; -typedef std::vector EventHandlerList; typedef IntModuleList::iterator EventHandlerIter; /** ModuleManager takes care of all things module-related @@ -1569,54 +1619,94 @@ class CoreExport ModuleManager : public classbase private: /** Holds a string describing the last module error to occur */ - char MODERR[MAXBUF]; - - /** The feature names published by various modules + std::string LastModuleError; + + /** The feature names published by various modules */ featurelist Features; /** The interface names published by various modules */ interfacelist Interfaces; - - /** Total number of modules loaded into the ircd, minus one + + /** Total number of modules loaded into the ircd */ - int ModCount; - + int ModCount; + /** Our pointer to the main insp instance */ InspIRCd* Instance; - public: + /** List of loaded modules and shared object/dll handles + * keyed by module name + */ + std::map > Modules; - EventHandlerList EventHandlers; + enum { + PRIO_STATE_FIRST, + PRIO_STATE_AGAIN, + PRIO_STATE_LAST + } prioritizationState; + public: - /** A list of ircd_module* module handles - * Note that this list is always exactly 255 in size. - * The actual number of loaded modules is available from GetModuleCount() - */ - ModuleHandleList handles; - - /** A list of Module* module classes - * Note that this list is always exactly 255 in size. - * The actual number of loaded modules is available from GetModuleCount() + /** Event handler hooks. + * This needs to be public to be used by FOREACH_MOD and friends. */ - ModuleList modules; + IntModuleList EventHandlers[I_END]; /** Simple, bog-standard, boring constructor. */ ModuleManager(InspIRCd* Ins); - ~ModuleManager(); - - /** Attach an event to a module + /** Destructor + */ + ~ModuleManager(); + + /** Change the priority of one event in a module. + * Each module event has a list of modules which are attached to that event type. + * If you wish to be called before or after other specific modules, you may use this + * method (usually within void Module::Prioritize()) to set your events priority. + * You may use this call in other methods too, however, this is not supported behaviour + * for a module. + * @param mod The module to change the priority of + * @param i The event to change the priority of + * @param s The state you wish to use for this event. Use one of + * PRIO_FIRST to set the event to be first called, PRIO_LAST to + * set it to be the last called, or PRIO_BEFORE and PRIORITY_AFTER + * to set it to be before or after one or more other modules. + * @param modules If PRIO_BEFORE or PRIORITY_AFTER is set in parameter 's', + * then this contains a list of one or more modules your module must be + * placed before or after. Your module will be placed before the highest + * priority module in this list for PRIO_BEFORE, or after the lowest + * priority module in this list for PRIORITY_AFTER. + * @param sz The number of modules being passed for PRIO_BEFORE and PRIORITY_AFTER. + * Defaults to 1, as most of the time you will only want to prioritize your module + * to be before or after one other module. + */ + bool SetPriority(Module* mod, Implementation i, Priority s, Module** modules = NULL, size_t sz = 1); + + /** Change the priority of all events in a module. + * @param mod The module to set the priority of + * @param s The priority of all events in the module. + * Note that with this method, it is not possible to effectively use + * PRIO_BEFORE or PRIORITY_AFTER, you should use the more fine tuned + * SetPriority method for this, where you may specify other modules to + * be prioritized against. + */ + bool SetPriority(Module* mod, Priority s); + + /** Attach an event to a module. + * You may later detatch the event with ModuleManager::Detach(). + * If your module is unloaded, all events are automatically detatched. * @param i Event type to attach * @param mod Module to attach event to * @return True if the event was attached */ bool Attach(Implementation i, Module* mod); - /** Detatch an event from a module + /** Detatch an event from a module. + * This is not required when your module unloads, as the core will + * automatically detatch your module from all events it is attached to. * @param i Event type to detach * @param mod Module to detach event from * @param Detach true if the event was detached @@ -1633,11 +1723,11 @@ class CoreExport ModuleManager : public classbase * @param mod Module to detach from */ void DetachAll(Module* mod); - + /** Returns text describing the last module error * @return The last error message to occur */ - const char* LastError(); + std::string& LastError(); /** Load a given module file * @param filename The file to load @@ -1650,11 +1740,11 @@ class CoreExport ModuleManager : public classbase * @return True if the module was unloaded */ bool Unload(const char* filename); - + /** Called by the InspIRCd constructor to load all modules from the config file. */ void LoadAll(); - + /** Get the total number of currently loaded modules * @return The number of loaded modules */ @@ -1662,73 +1752,13 @@ class CoreExport ModuleManager : public classbase { return this->ModCount; } - + /** Find a module by name, and return a Module* to it. * This is preferred over iterating the module lists yourself. * @param name The module name to look up * @return A pointer to the module, or NULL if the module cannot be found */ Module* Find(const std::string &name); - - /** Remove a module handle pointer - * @param j Index number of the module handle to remove - * @return True if a handle existed at the given index, false otherwise - */ - bool EraseHandle(unsigned int j); - - /** Remove a Module pointer - * @param j Index number of the Module to remove - * @return True if a handle existed at the given index, false otherwise - */ - bool EraseModule(unsigned int j); - - /** Move a given module to a specific slot in the list - * @param modulename The module name to relocate - * @param slot The slot to move the module into - */ - void MoveTo(std::string modulename,int slot); - - /** Moves the given module to the last slot in the list - * @param modulename The module name to relocate - */ - void MoveToLast(std::string modulename); - - /** Moves the given module to the first slot in the list - * @param modulename The module name to relocate - */ - void MoveToFirst(std::string modulename); - - /** Moves one module to be placed after another in the list - * @param modulename The module name to relocate - * @param after The module name to place the module after - */ - void MoveAfter(std::string modulename, std::string after); - - /** Moves one module to be placed before another in the list - * @param modulename The module name to relocate - * @param after The module name to place the module before - */ - void MoveBefore(std::string modulename, std::string before); - - /** For use with Module::Prioritize(). - * When the return value of this function is returned from - * Module::Prioritize(), this specifies that the module wishes - * to be ordered exactly BEFORE 'modulename'. For more information - * please see Module::Prioritize(). - * @param modulename The module your module wants to be before in the call list - * @returns a priority ID which the core uses to relocate the module in the list - */ - long PriorityBefore(const std::string &modulename); - - /** For use with Module::Prioritize(). - * When the return value of this function is returned from - * Module::Prioritize(), this specifies that the module wishes - * to be ordered exactly AFTER 'modulename'. For more information please - * see Module::Prioritize(). - * @param modulename The module your module wants to be after in the call list - * @returns a priority ID which the core uses to relocate the module in the list - */ - long PriorityAfter(const std::string &modulename); /** Publish a 'feature'. * There are two ways for a module to find another module it depends on. @@ -1827,21 +1857,58 @@ class CoreExport ModuleManager : public classbase */ modulelist* FindInterface(const std::string &InterfaceName); + /** Determine if a module has published the named interface. + * This could be used in, for example, OnLoadModule to pick up other modules that can be used. + * @param mod The module to check. + * @param InterfaceName the interface you want to check for + * @return True if the module provides the interface, false otherwise. + */ + bool ModuleHasInterface(Module* mod, const std::string& InterfaceName); + /** Given a pointer to a Module, return its filename * @param m The module pointer to identify * @return The module name or an empty string */ const std::string& GetModuleName(Module* m); + + /** Return a list of all modules matching the given filter + * @param filter This int is a bitmask of flags set in Module::Flags, + * such as VF_VENDOR or VF_STATIC. If you wish to receive a list of + * all modules with no filtering, set this to 0. + * @return The list of module names + */ + const std::vector GetAllModuleNames(int filter); }; /** 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. */ +#ifdef WINDOWS + +#define MODULE_INIT(y) \ + extern "C" DllExport Module * init_module(InspIRCd* Me) \ + { \ + return new y(Me); \ + } \ + BOOLEAN WINAPI DllMain(HINSTANCE hDllHandle, DWORD nReason, LPVOID Reserved) \ + { \ + switch ( nReason ) \ + { \ + case DLL_PROCESS_ATTACH: \ + case DLL_PROCESS_DETACH: \ + break; \ + } \ + return TRUE; \ + } + +#else + #define MODULE_INIT(y) \ extern "C" DllExport Module * init_module(InspIRCd* Me) \ { \ return new y(Me); \ } +#endif #endif