* loaded modules in a readable simple way, e.g.:
* 'FOREACH_MOD(I_OnConnect,OnConnect(user));'
*/
-#define FOREACH_MOD(y,x) if (ServerInstance->Config->global_implementation[y] > 0) { \
- for (int _i = 0; _i <= ServerInstance->Modules->GetCount(); _i++) { \
- if (ServerInstance->Config->implement_lists[_i][y]) \
- try \
- { \
- ServerInstance->Modules->modules[_i]->x ; \
- } \
- catch (CoreException& modexcept) \
- { \
- ServerInstance->Log(DEFAULT,"Exception caught: %s",modexcept.GetReason()); \
- } \
+#define FOREACH_MOD(y,x) \
+for (EventHandlerIter _i = ServerInstance->Modules->EventHandlers[y].begin(); _i != ServerInstance->Modules->EventHandlers[y].end(); ++_i) \
+{ \
+ try \
+ { \
+ (*_i)->x ; \
+ } \
+ catch (CoreException& modexcept) \
+ { \
+ ServerInstance->Log(DEFAULT,"Exception caught: %s",modexcept.GetReason()); \
} \
- }
+}
/**
* This #define allows us to call a method in all
* 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->Modules->GetCount(); _i++) { \
- if (z->Config->implement_lists[_i][y]) \
- try \
- { \
- z->Modules->modules[_i]->x ; \
- } \
- catch (CoreException& modexcept) \
- { \
- z->Log(DEFAULT,"Exception caught: %s",modexcept.GetReason()); \
- } \
+#define FOREACH_MOD_I(z,y,x) \
+for (EventHandlerIter _i = z->Modules->EventHandlers[y].begin(); _i != z->Modules->EventHandlers[y].end(); ++_i) \
+{ \
+ try \
+ { \
+ (*_i)->x ; \
+ } \
+ catch (CoreException& modexcept) \
+ { \
+ z->Log(DEFAULT,"Exception caught: %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(y,x) { if (ServerInstance->Config->global_implementation[y] > 0) { \
- MOD_RESULT = 0; \
- for (int _i = 0; _i <= ServerInstance->Modules->GetCount(); _i++) { \
- if (ServerInstance->Config->implement_lists[_i][y]) { \
- try \
- { \
- int res = ServerInstance->Modules->modules[_i]->x ; \
- if (res != 0) { \
- MOD_RESULT = res; \
- break; \
- } \
- } \
- catch (CoreException& modexcept) \
- { \
- ServerInstance->Log(DEFAULT,"Exception caught: %s",modexcept.GetReason()); \
- } \
+#define FOREACH_RESULT(y,x) \
+do { \
+ MOD_RESULT = 0; \
+ for (EventHandlerIter _i = ServerInstance->Modules->EventHandlers[y].begin(); _i != ServerInstance->Modules->EventHandlers[y].end(); ++_i) \
+ { \
+ try \
+ { \
+ int res = (*_i)->x ; \
+ if (res != 0) { \
+ MOD_RESULT = res; \
+ break; \
} \
} \
+ catch (CoreException& modexcept) \
+ { \
+ ServerInstance->Log(DEFAULT,"Exception caught: %s",modexcept.GetReason()); \
+ } \
} \
- }
+} while(0);
+
/**
* This define is similar to the one above but returns a result in MOD_RESULT.
* The first module to return a nonzero result is the value to be accepted,
* and any modules after are ignored.
*/
-#define FOREACH_RESULT_I(z,y,x) { if (z->Config->global_implementation[y] > 0) { \
- MOD_RESULT = 0; \
- for (int _i = 0; _i <= z->Modules->GetCount(); _i++) { \
- if (z->Config->implement_lists[_i][y]) { \
- try \
- { \
- int res = z->Modules->modules[_i]->x ; \
- if (res != 0) { \
- MOD_RESULT = res; \
- break; \
- } \
- } \
- catch (CoreException& modexcept) \
- { \
- z->Log(DEBUG,"Exception caught: %s",modexcept.GetReason()); \
- } \
+#define FOREACH_RESULT_I(z,y,x) \
+do { \
+ MOD_RESULT = 0; \
+ for (EventHandlerIter _i = z->Modules->EventHandlers[y].begin(); _i != z->Modules->EventHandlers[y].end(); ++_i) \
+ { \
+ try \
+ { \
+ int res = (*_i)->x ; \
+ if (res != 0) { \
+ MOD_RESULT = res; \
+ break; \
} \
} \
+ catch (CoreException& modexcept) \
+ { \
+ z->Log(DEBUG,"Exception caught: %s",modexcept.GetReason()); \
+ } \
} \
-}
+} while (0);
/** Represents a non-local user.
* (in fact, any FD less than -1 does)
*/
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
};
/** 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<Module> ircd_module;
-/** A list of loaded Modules
+/** A list of modules
*/
-typedef std::vector<Module*> ModuleList;
+typedef std::vector<Module*> IntModuleList;
-/** A list of loaded module handles (ircd_module)
+/** An event handler iterator
*/
-typedef std::vector<ircd_module*> ModuleHandleList;
+typedef IntModuleList::iterator EventHandlerIter;
+
+/** Module priority states
+ */
+enum PriorityState
+{
+ PRIO_DONTCARE,
+ PRIO_FIRST,
+ PRIO_LAST,
+ PRIO_AFTER,
+ PRIO_BEFORE
+};
/** ModuleManager takes care of all things module-related
* in the core.
private:
/** Holds a string describing the last module error to occur
*/
- char MODERR[MAXBUF];
+ std::string LastModuleError;
/** The feature 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;
*/
InspIRCd* Instance;
- public:
+ /** List of loaded modules and shared object/dll handles
+ * keyed by module name
+ */
+ std::map<std::string, std::pair<ircd_module*, Module*> > Modules;
- std::vector<std::list<Module*> > EventHandlers;
+ 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()
+ /** Event handler hooks.
+ * This needs to be public to be used by FOREACH_MOD and friends.
*/
- 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()
- */
- ModuleList modules;
+ IntModuleList EventHandlers[I_END];
/** Simple, bog-standard, boring constructor.
*/
ModuleManager(InspIRCd* Ins);
+ /** 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 PRIO_AFTER
+ * to set it to be before or after one or more other modules.
+ * @param modules If PRIO_BEFORE or PRIO_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 PRIO_AFTER.
+ * @param sz The number of modules being passed for PRIO_BEFORE and PRIO_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, PriorityState 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 PRIO_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, PriorityState 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.
+ * 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
+ */
+ bool Detach(Implementation i, Module* mod);
+
+ /** Attach an array of events to a module
+ * @param i Event types (array) to attach
+ * @param mod Module to attach events to
+ */
+ void Attach(Implementation* i, Module* mod, size_t sz);
+
+ /** Detach all events from a module (used on unload)
+ * @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
*/
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.
* Either by name, using InspIRCd::FindModule, or by feature, using this
* @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<std::string> GetAllModuleNames(int filter);
};
/** This definition is used as shorthand for the various classes