X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=include%2Fmodules.h;h=3601dd659253bdaf1fc18c40f83867ff6e45eb58;hb=095e0a067b6ed1a191c31711771df66acfc41f2c;hp=d59bdf05b9dab521dca8f1d4e916fe233fd792e7;hpb=f9717e35cab505cfca95e708b53336bd7bf78f56;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/include/modules.h b/include/modules.h index d59bdf05b..3601dd659 100644 --- a/include/modules.h +++ b/include/modules.h @@ -2,7 +2,7 @@ * | Inspire Internet Relay Chat Daemon | * +------------------------------------+ * - * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * InspIRCd: (C) 2002-2010 InspIRCd Development Team * See: http://wiki.inspircd.org/Credits * * This program is free but copyrighted software; see @@ -25,25 +25,15 @@ #include "mode.h" #include "dns.h" -class XLine; - /** 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 - VF_CORE = 32 // module is a core command, can be assumed loaded on all servers -}; - -/** 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 @@ -74,26 +64,26 @@ 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; } - bool check(bool def) const + inline bool check(bool def) const { return (res == 1 || (res == 0 && def)); } /** * Merges two results, preferring ALLOW to DENY */ - ModResult operator+(const ModResult& r) const + inline ModResult operator+(const ModResult& r) const { if (res == r.res || r.res == 0) return *this; @@ -104,36 +94,17 @@ struct ModResult { } }; -/** If you change the module API in any way, increment this value. */ -#define API_VERSION 131 - -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. +/** InspIRCd major version. + * 1.2 -> 102; 2.1 -> 201; 2.12 -> 212 */ -typedef std::deque file_cache; - -/** A set of strings. - */ -typedef file_cache string_list; - -/** Holds a list of 'published features' for modules. - */ -typedef std::map featurelist; - -/** Holds a list of modules which implement an interface - */ -typedef std::deque modulelist; - -/** Holds a list of all modules which implement interfaces, by interface name +#define INSPIRCD_VERSION_MAJ 200 +/** InspIRCd API version. + * If you change any API elements, increment this value. This counter should be + * reset whenever the major version is changed. Modules can use these two values + * and numerical comparisons in preprocessor macros if they wish to support + * multiple versions of InspIRCd in one file. */ -typedef std::map > interfacelist; +#define INSPIRCD_VERSION_API 1 /** * This #define allows us to call a method in all @@ -202,68 +173,31 @@ do { \ 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_SERVER(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 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. */ -template -class CoreExport VersionBase : public classbase +class CoreExport Version { public: /** Module description */ const std::string description; - /** Version information. - */ - const std::string version; /** Flags */ const int Flags; - /** Initialize version class - */ - VersionBase(const std::string &desc, int flags = VF_NONE, int dummy = 0, const std::string& src_rev = VERSION " r" REVISION); -}; + /** Server linking description string */ + const std::string link_data; -typedef VersionBase Version; + /** Simple module version */ + Version(const std::string &desc, int flags = VF_NONE); -/** 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() {}; + /** Complex version information, including linking compatability data */ + Version(const std::string &desc, int flags, const std::string& linkdata); + + virtual ~Version() {} }; /** The Request class is a unicast message directed at a given module. @@ -271,60 +205,33 @@ class CoreExport ModuleMessage : public Extensible * 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(); }; @@ -333,45 +240,71 @@ 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(); + void Send(); +}; + +class CoreExport DataProvider : public ServiceProvider +{ + public: + DataProvider(Module* Creator, const std::string& Name) + : ServiceProvider(Creator, Name, SERVICE_DATA) {} }; -/** Priority types which can be returned from Module::Prioritize() +class CoreExport dynamic_reference_base : public interfacebase +{ + private: + std::string name; + protected: + DataProvider* value; + public: + ModuleRef creator; + dynamic_reference_base(Module* Creator, const std::string& Name); + ~dynamic_reference_base(); + inline void ClearCache() { value = NULL; } + inline const std::string& GetProvider() { return name; } + void SetProvider(const std::string& newname); + void lookup(); + operator bool(); + static void reset_all(); +}; + +template +class dynamic_reference : public dynamic_reference_base +{ + public: + dynamic_reference(Module* Creator, const std::string& Name) + : dynamic_reference_base(Creator, Name) {} + inline T* operator->() + { + if (!value) + lookup(); + return static_cast(value); + } +}; + +/** Priority types which can be used by Module::Prioritize() */ -enum Priority { PRIORITY_FIRST, PRIORITY_DONTCARE, PRIORITY_LAST, PRIORITY_BEFORE, PRIORITY_AFTER }; +enum Priority { PRIORITY_FIRST, PRIORITY_LAST, PRIORITY_BEFORE, PRIORITY_AFTER }; /** Implementation-specific flags which may be set in Module::Implements() */ @@ -382,29 +315,27 @@ 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_OnSyncChannel, I_OnDecodeMetaData, I_OnWallops, I_OnAcceptConnection, I_OnUserInit, + 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_OnCheckChannelBan, I_OnExtBanCheck, - I_OnStats, I_OnChangeLocalUserHost, I_OnChangeLocalUserGecos, I_OnPreTopicChange, - I_OnPostTopicChange, I_OnEvent, I_OnRequest, I_OnGlobalOper, I_OnPostConnect, I_OnAddBan, + 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_OnBuildNeighborList, I_OnGarbageCollect, + I_OnPostOper, I_OnSyncNetwork, I_OnSetAway, I_OnPostCommand, I_OnPostJoin, + I_OnWhoisLine, I_OnBuildNeighborList, I_OnGarbageCollect, I_OnSetConnectClass, I_OnText, I_OnPassCompare, I_OnRunTestSuite, I_OnNamesListItem, I_OnNumeric, I_OnHookIO, I_OnPreRehash, I_OnModuleRehash, I_OnSendWhoLine, I_OnChangeIdent, 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 { public: /** File that this module was loaded from @@ -412,19 +343,23 @@ class CoreExport Module : public Extensible std::string ModuleSourceFile; /** Reference to the dlopen() value */ - DLLFactory* ModuleDLLFactory; + 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. + * Creates a module class. Don't do any type of hook registration or checks + * for other modules here; do that in init(). */ Module(); + /** Module setup + * \exception ModuleException Throwing this class, or any class derived from ModuleException, causes loading of the module to abort. + */ + virtual void init() {} + /** Clean up prior to destruction * If you override, you must call this AFTER your module's cleanup */ - virtual bool cull(); + virtual CullResult cull(); /** Default destructor. * destroys a module class @@ -445,7 +380,7 @@ class CoreExport Module : public Extensible * 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 @@ -463,7 +398,7 @@ 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 @@ -967,9 +902,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, @@ -983,7 +917,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 @@ -1011,7 +945,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 ModResult OnPreCommand(std::string &command, std::vector& parameters, User *user, bool validated, const std::string &original_line); + virtual ModResult OnPreCommand(std::string &command, std::vector& parameters, LocalUser *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, @@ -1025,7 +959,12 @@ 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 std::vector& parameters, User *user, CmdResult result, const std::string &original_line); + virtual void OnPostCommand(const std::string &command, const std::vector& parameters, LocalUser *user, CmdResult result, const std::string &original_line); + + /** Called when a user is first connecting, prior to starting DNS lookups, checking initial + * connect class, or accepting any commands. + */ + virtual void OnUserInit(LocalUser* user); /** 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 @@ -1037,7 +976,7 @@ class CoreExport Module : public Extensible * @param user The user to check * @return true to indicate readiness, false if otherwise */ - virtual ModResult 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 @@ -1048,7 +987,7 @@ class CoreExport Module : public Extensible * @param user The user registering * @return 1 to indicate user quit, 0 to continue */ - virtual ModResult 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 @@ -1137,7 +1076,7 @@ class CoreExport Module : public Extensible * @param newhost The new hostname * @return 1 to deny the host change, 0 to allow */ - virtual ModResult 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. @@ -1145,7 +1084,7 @@ class CoreExport Module : public Extensible * @param newhost The new GECOS * @return 1 to deny the GECOS change, 0 to allow */ - virtual ModResult OnChangeLocalUserGECOS(User* user, const std::string &newhost); + virtual ModResult OnChangeLocalUserGECOS(LocalUser* user, const std::string &newhost); /** 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 @@ -1165,22 +1104,17 @@ class CoreExport Module : public Extensible */ 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 @@ -1232,7 +1166,16 @@ class CoreExport Module : public Extensible * @param user The item to possibly install the I/O hook on * @param via The port that connected on */ - virtual void OnHookIO(StreamSocket*, 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 * processing (e.g. modules which wrap the tcp connection within another library) and provides @@ -1287,15 +1230,6 @@ class CoreExport Module : public Extensible */ 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, - * 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 - */ - 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 * the values numeric and text, but you cannot change the user the @@ -1316,6 +1250,12 @@ class CoreExport Module : public Extensible */ virtual void OnGarbageCollect(); + /** Called when a user's connect class is being matched + * @return MOD_RES_ALLOW to force the class to match, MOD_RES_DENY to forbid it, or + * MOD_RES_PASSTHRU to allow normal matching (by host/port). + */ + virtual ModResult OnSetConnectClass(LocalUser* user, ConnectClass* myclass); + /** Add test suite hooks here. These are used for testing functionality of a module * via the --testsuite debugging parameter. */ @@ -1331,11 +1271,11 @@ class CoreExport Module : public Extensible /** Called whenever a result from /WHO is about to be returned * @param source The user running the /WHO query + * @param params The parameters to 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 void OnSendWhoLine(User* source, User* user, Channel* channel, std::string& line); + virtual void OnSendWhoLine(User* source, const std::vector& params, User* user, std::string& line); }; @@ -1352,7 +1292,7 @@ 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: /** Error code @@ -1421,6 +1361,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 @@ -1428,13 +1369,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 <test tag="blah" data="foo"> then this - * function would return 2. Spaces and newlines both qualify as valid seperators - * between values. - */ - int EnumerateValues(const std::string &tag, int index); }; @@ -1448,7 +1382,7 @@ class CoreExport FileReader : public classbase { /** The file contents */ - file_cache fc; + std::vector fc; /** Content size in bytes */ @@ -1522,21 +1456,13 @@ 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 */ 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 */ int ModCount; @@ -1551,6 +1477,9 @@ class CoreExport ModuleManager : public classbase PRIO_STATE_AGAIN, PRIO_STATE_LAST } prioritizationState; + + /** Internal unload module hook */ + bool CanUnload(Module*); public: /** Event handler hooks. @@ -1558,6 +1487,9 @@ class CoreExport ModuleManager : public classbase */ IntModuleList EventHandlers[I_END]; + /** List of data services keyed by name */ + std::multimap DataProviders; + /** Simple, bog-standard, boring constructor. */ ModuleManager(); @@ -1578,16 +1510,17 @@ class CoreExport ModuleManager : public classbase * 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. + * @param which If PRIO_BEFORE or PRIORITY_AFTER is set in parameter 's', + * then this contains a the module that your module must be placed before + * or after. */ - bool SetPriority(Module* mod, Implementation i, Priority s, Module** modules = NULL, size_t sz = 1); + bool SetPriority(Module* mod, Implementation i, Priority s, Module* which = NULL); + + /** Backwards compat interface */ + inline bool SetPriority(Module* mod, Implementation i, Priority s, Module** dptr) + { + return SetPriority(mod, i, s, *dptr); + } /** Change the priority of all events in a module. * @param mod The module to set the priority of @@ -1635,19 +1568,29 @@ class CoreExport ModuleManager : public classbase /** Load a given module file * @param filename The file to load + * @param defer Defer module init (loading many modules) * @return True if the module was found and loaded */ - bool Load(const char* filename); + bool Load(const std::string& filename, bool defer = false); + + /** 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); - /** Unload a given module file - * @param filename The file to unload - * @return True if the module was unloaded + /** 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* 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 @@ -1664,116 +1607,27 @@ class CoreExport ModuleManager : public classbase */ Module* Find(const std::string &name); - /** Publish a 'feature'. - * There are two ways for a module to find another module it depends on. - * Either by name, using InspIRCd::FindModule, or by feature, using this - * function. A feature is an arbitary string which identifies something this - * module can do. For example, if your module provides SSL support, but other - * modules provide SSL support too, all the modules supporting SSL should - * publish an identical 'SSL' feature. This way, any module requiring use - * of SSL functions can just look up the 'SSL' feature using FindFeature, - * then use the module pointer they are given. - * @param FeatureName The case sensitive feature name to make available - * @param Mod a pointer to your module class - * @returns True on success, false if the feature is already published by - * another module. - */ - bool PublishFeature(const std::string &FeatureName, Module* Mod); - - /** Publish a module to an 'interface'. - * Modules which implement the same interface (the same way of communicating - * with other modules) can publish themselves to an interface, using this - * method. When they do so, they become part of a list of related or - * compatible modules, and a third module may then query for that list - * and know that all modules within that list offer the same API. - * A prime example of this is the hashing modules, which all accept the - * same types of Request class. Consider this to be similar to PublishFeature, - * except for that multiple modules may publish the same 'feature'. - * @param InterfaceName The case sensitive interface name to make available - * @param Mod a pointer to your module class - * @returns True on success, false on failure (there are currently no failure - * cases) - */ - bool PublishInterface(const std::string &InterfaceName, Module* Mod); - - /** Return a pair saying how many other modules are currently using the - * interfaces provided by module m. - * @param m The module to count usage for - * @return A pair, where the first value is the number of uses of the interface, - * and the second value is the interface name being used. - */ - std::pair GetInterfaceInstanceCount(Module* m); - - /** Mark your module as using an interface. - * If you mark your module as using an interface, then that interface - * module may not unload until your module has unloaded first. - * This can be used to prevent crashes by ensuring code you depend on - * is always in memory while your module is active. - * @param InterfaceName The interface to use - */ - void UseInterface(const std::string &InterfaceName); - - /** Mark your module as finished with an interface. - * If you used UseInterface() above, you should use this method when - * your module is finished with the interface (usually in its destructor) - * to allow the modules which implement the given interface to be unloaded. - * @param InterfaceName The interface you are finished with using. - */ - void DoneWithInterface(const std::string &InterfaceName); - - /** Unpublish a 'feature'. - * When your module exits, it must call this method for every feature it - * is providing so that the feature table is cleaned up. - * @param FeatureName the feature to remove - */ - bool UnpublishFeature(const std::string &FeatureName); - - /** Unpublish your module from an interface - * When your module exits, it must call this method for every interface - * it is part of so that the interfaces table is cleaned up. Only when - * the last item is deleted from an interface does the interface get - * removed. - * @param InterfaceName the interface to be removed from - * @param Mod The module to remove from the interface list - */ - bool UnpublishInterface(const std::string &InterfaceName, Module* Mod); - - /** Find a 'feature'. - * There are two ways for a module to find another module it depends on. - * Either by name, using InspIRCd::FindModule, or by feature, using the - * InspIRCd::PublishFeature method. A feature is an arbitary string which - * identifies something this module can do. For example, if your module - * provides SSL support, but other modules provide SSL support too, all - * the modules supporting SSL should publish an identical 'SSL' feature. - * To find a module capable of providing the feature you want, simply - * call this method with the feature name you are looking for. - * @param FeatureName The feature name you wish to obtain the module for - * @returns A pointer to a valid module class on success, NULL on failure. - */ - Module* FindFeature(const std::string &FeatureName); - - /** Find an 'interface'. - * An interface is a list of modules which all implement the same API. - * @param InterfaceName The Interface you wish to obtain the module - * list of. - * @return A pointer to a deque of Module*, or NULL if the interface - * does not exist. - */ - 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); + /** Register a service provided by a module */ + void AddService(ServiceProvider&); + + /** Unregister a service provided by a module */ + void DelService(ServiceProvider&); + + inline void AddServices(ServiceProvider** list, int count) + { + for(int i=0; i < count; i++) + AddService(*list[i]); + } + + /** Find a service by name. + * If multiple modules provide a given service, the first one loaded will be chosen. + */ + ServiceProvider* FindService(ServiceType Type, const std::string& name); + + template inline T* FindDataService(const std::string& name) + { + return static_cast(FindService(SERVICE_DATA, name)); + } /** Return a list of all modules matching the given filter * @param filter This int is a bitmask of flags set in Module::Flags, @@ -1784,6 +1638,41 @@ class CoreExport ModuleManager : public classbase const std::vector 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(INSPIRCD_VERSION_MAJ, INSPIRCD_VERSION_API) +#define MODULE_INIT_SYM_FN_2(x,y) MODULE_INIT_SYM_FN_1(x,y) +#define MODULE_INIT_SYM_FN_1(x,y) inspircd_module_ ## x ## _ ## y + +#ifdef PURE_STATIC + +struct AllCommandList { + typedef Command* (*fn)(Module*); + AllCommandList(fn cmd); +}; +#define COMMAND_INIT(x) static Command* MK_ ## x(Module* m) { return new x(m); } \ + static const AllCommandList PREP_ ## x(&MK_ ## x); + +struct AllModuleList { + typedef Module* (*fn)(); + fn init; + std::string name; + AllModuleList(fn mod, const std::string& Name); +}; + +#define MODULE_INIT(x) static Module* MK_ ## x() { return new x; } \ + static const AllModuleList PREP_ ## x(&MK_ ## x, MODNAMESTR); + +#define MODNAMESTR MODNAMESTR_FN_2(MODNAME) +#define MODNAMESTR_FN_2(x) MODNAMESTR_FN_1(x) +#define MODNAMESTR_FN_1(x) #x + +#else + /** 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. @@ -1791,7 +1680,7 @@ class CoreExport ModuleManager : public classbase #ifdef WINDOWS #define MODULE_INIT(y) \ - extern "C" DllExport Module * init_module() \ + extern "C" DllExport Module * MODULE_INIT_SYM() \ { \ return new y; \ } \ @@ -1809,12 +1698,15 @@ class CoreExport ModuleManager : public classbase #else #define MODULE_INIT(y) \ - extern "C" DllExport Module * init_module() \ + extern "C" DllExport Module * MODULE_INIT_SYM() \ { \ return new y; \ - } + } \ + extern "C" const char inspircd_src_version[] = VERSION " r" REVISION; #endif #define COMMAND_INIT(c) MODULE_INIT(CommandModule) #endif + +#endif