/* Modular support
*
* (C) 2003 Anope Team
* Contact us at info@anope.org
*
* Please read COPYING and README for furhter details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id$
*
*/
#include "modules.h"
#include "language.h"
/*
* Disable the modules on OpenBSD (for now)
* there is work in progress for this.
*/
#ifdef __OpenBSD__
#ifdef USE_MODULES
#undef USE_MODULES
#endif /* USE_MODULES */
#endif /* __OpenBSD__ */
#ifdef USE_MODULES
#include <dlfcn.h>
#endif
/**
* Declare all the list's we want to use here
**/
CommandHash *HOSTSERV[MAX_CMD_HASH];
CommandHash *BOTSERV[MAX_CMD_HASH];
CommandHash *MEMOSERV[MAX_CMD_HASH];
CommandHash *NICKSERV[MAX_CMD_HASH];
CommandHash *CHANSERV[MAX_CMD_HASH];
CommandHash *HELPSERV[MAX_CMD_HASH];
CommandHash *OPERSERV[MAX_CMD_HASH];
MessageHash *IRCD[MAX_CMD_HASH];
ModuleHash *MODULE_HASH[MAX_CMD_HASH];
Module *mod_current_module;
char *mod_current_module_name = NULL;
char *mod_current_buffer = NULL;
int mod_current_op;
User *mod_current_user;
ModuleCallBack *moduleCallBackHead = NULL;
int displayCommand(Command * c);
int displayCommandFromHash(CommandHash * cmdTable[], char *name);
int displayMessageFromHashl(char *name);
int displayMessage(Message * m);
/**
* Automaticaly load modules at startup.
* This will load modules at startup before the IRCD link is attempted, this
* allows admins to have a module relating to ircd support load
*/
void modules_init(void)
{
#ifdef USE_MODULES
int idx;
Module *m;
for (idx = 0; idx < ModulesNumber; idx++) {
m = findModule(ModulesAutoload[idx]);
if (!m) {
m = createModule(ModulesAutoload[idx]);
mod_current_module = m;
mod_current_user = NULL;
alog("trying to load [%s]", mod_current_module->name);
alog("status: [%d]", loadModule(mod_current_module, NULL));
mod_current_module = NULL;
mod_current_user = NULL;
}
}
#endif
}
/**
* Automaticaly load modules at startup, delayed.
* This function waits until the IRCD link has been made, and then attempts
* to load the specified modules.
*/
void modules_delayed_init(void)
{
#ifdef USE_MODULES
int idx;
Module *m;
for (idx = 0; idx < ModulesDelayedNumber; idx++) {
m = findModule(ModulesDelayedAutoload[idx]);
if (!m) {
m = createModule(ModulesDelayedAutoload[idx]);
mod_current_module = m;
mod_current_user = NULL;
alog("trying to load [%s]", mod_current_module->name);
alog("status: [%d]", loadModule(mod_current_module, NULL));
mod_current_module = NULL;
mod_current_user = NULL;
}
}
#endif
}
/**
* Create a new module, setting up the default values as needed.
* @param filename the filename of the new module
* @return a newly created module struct
*/
Module *createModule(char *filename)
{
Module *m;
if (!filename) {
return NULL;
}
if ((m = malloc(sizeof(Module))) == NULL) {
fatal("Out of memory!");
}
m->name = sstrdup(filename); /* Our Name */
m->handle = NULL; /* Handle */
m->version = NULL;
m->author = NULL;
m->nickHelp = NULL;
m->chanHelp = NULL;
m->memoHelp = NULL;
m->botHelp = NULL;
m->operHelp = NULL;
m->hostHelp = NULL;
m->helpHelp = NULL;
return m; /* return a nice new module */
}
/**
* Destory the module.
* free up all memory used by our module struct.
* @param m the module to free
* @return MOD_ERR_OK on success, anything else on fail
*/
int destroyModule(Module * m)
{
if (!m) {
return MOD_ERR_PARAMS;
}
if (m->name) {
free(m->name);
}
if (m->filename) {
remove(m->filename);
free(m->filename);
}
m->handle = NULL;
if (m->author) {
free(m->author);
}
if (m->version) {
free(m->version);
}
/* No need to free our cmd/msg list, as they will always be empty by the module is destroyed */
free(m);
return MOD_ERR_OK;
}
/**
* Add the module to the list of currently loaded modules.
* @param m the currently loaded module
* @return MOD_ERR_OK on success, anything else on fail
*/
int addModule(Module * m)
{
int index = 0;
ModuleHash *current = NULL;
ModuleHash *newHash = NULL;
ModuleHash *lastHash = NULL;
index = CMD_HASH(m->name);
for (current = MODULE_HASH[index]; current; current = current->next) {
if (strcasecmp(m->name, current->name) == 0)
return MOD_ERR_EXISTS;
lastHash = current;
}
if ((newHash = malloc(sizeof(ModuleHash))) == NULL) {
fatal("Out of memory");
}
m->time = time(NULL);
newHash->next = NULL;
newHash->name = sstrdup(m->name);
newHash->m = m;
if (lastHash == NULL)
MODULE_HASH[index] = newHash;
else
lastHash->next = newHash;
return MOD_ERR_OK;
}
/**
* Remove the module from the list of loaded modules.
* @param m module to remove
* @return MOD_ERR_OK on success anything else on fail
*/
int delModule(Module * m)
{
int index = 0;
ModuleHash *current = NULL;
ModuleHash *lastHash = NULL;
if (!m) {
return MOD_ERR_PARAMS;
}
index = CMD_HASH(m->name);
for (current = MODULE_HASH[index]; current; current = current->next) {
if (strcasecmp(m->name, current->name) == 0) {
if (!lastHash) {
MODULE_HASH[index] = current->next;
} else {
lastHash->next = current->next;
}
destroyModule(current->m);
free(current->name);
free(current);
return MOD_ERR_OK;
}
lastHash = current;
}
return MOD_ERR_NOEXIST;
}
/**
* Search the list of loaded modules for the given name.
* @param name the name of the module to find
* @return a pointer to the module found, or NULL
*/
Module *findModule(char *name)
{
int idx;
ModuleHash *current = NULL;
if (!name) {
return NULL;
}
idx = CMD_HASH(name);
for (current = MODULE_HASH[idx]; current; current = current->next) {
if (stricmp(name, current->name) == 0) {
return current->m;
}
}
return NULL;
}
/**
* Copy the module from the modules folder to the runtime folder.
* This will prevent module updates while the modules is loaded from
* triggering a segfault, as the actaul file in use will be in the
* runtime folder.
* @param name the name of the module to copy
* @return MOD_ERR_OK on success
*/
int moduleCopyFile(char *name)
{
#ifdef USE_MODULES
int ch;
FILE *source, *target;
char output[4096];
char input[4096];
int len;
strncpy(output, MODULE_PATH, 4095); /* Get full path with .so extension */
strncpy(input, MODULE_PATH, 4095); /* Get
|