/* 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: modules.c 419 2004-10-23 17:59:28Z trystan $
*
*/
#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);
/*******************************************************************************
* Module Functions
*******************************************************************************/
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
}
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
}
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 */
}
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;
}
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;
}
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;
}
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;
}
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 full path with .so extension */
len = strlen(output);
strncat(output, "runtime/", 4095 - len);
len += strlen(output);
strncat(output, name, 4095 - len);
strncat(input, name, 4095 - len);
len += strlen(output);
strncat(output, ".so", 4095 - len);
strncat(input, ".so", 4095 - len);
if ((source = fopen(input, "r")) == NULL) {
return MOD_ERR_NOEXIST;
}
if ((target = fopen(output, "w")) == NULL) {
return MOD_ERR_FILE_IO;
}
while ((ch = fgetc(source)) != EOF) {
fputc(ch, target);
}
fclose(source);
if (fclose(target) != 0) {
return MOD_ERR_FILE_IO;
}
#endif
return MOD_ERR_OK;
}
int loadModule(Module * m, User * u)
{
#ifdef USE_MODULES
char buf[4096];
int len;
const char *err;
int (*func) (int, char **);
int ret = 0;
Module *m2;
if (!m || !m->name) {
return MOD_ERR_PARAMS;
}
if (m->handle) {
return MOD_ERR_EXISTS;
}
if ((m2 = findModule(m->name)) != NULL) {
return MOD_ERR_EXISTS;
}
moduleCopyFile(m->name);
strncpy(buf, MODULE_PATH, 4095); /* Get full path with .so extension */
len = strlen(buf);
strncat(buf, "runtime/", 4095 - len);
len += strlen(buf);
strncat(buf, m->name, 4095 - len);
len += strlen(buf);
strncat(buf, ".so", 4095 - len);
m->filename = sstrdup(buf);
#ifdef HAS_RTLD_LOCAL
m->handle = dlopen(m->filename, RTLD_LAZY | RTLD_LOCAL);
#else
m->handle = dlopen(m->filename, RTLD_LAZY);
#endif
if ((err = dlerror()) != NULL) {
alog(err);
if (u) {
notice_lang(s_OperServ, u, OPER_MODULE_LOAD_FAIL, m->name);
}
return MOD_ERR_NOLOAD;
}
func = dlsym(m->handle, "AnopeInit");
if ((err = dlerror()) != NULL) {
dlclose(m->handle); /* If no AnopeInit - it isnt an Anope Module, close it */
return MOD_ERR_NOLOAD;
}
if (func) {
mod_current_module_name = m->name;
ret = func(0, NULL); /* exec AnopeInit */
if (ret == MOD_STOP) {
alog("%s requested unload...", m->name);
unloadModule(m, NULL);
mod_current_module_name = NULL;
return MOD_ERR_NOLOAD;
}
mod_current_module_name = NULL;
}
if (u) {
wallops(s_OperServ, "%s loaded module %s", u->nick, m->name);
notice_lang(s_OperServ, u, OPER_MODULE_LOADED, m->name);
}
addModule(m);
return MOD_ERR_OK;
#else
return MOD_ERR_NOLOAD;
#endif
}
int unloadModule(Module * m, User * u)
{
#ifdef USE_MODULES
void (*func) ();
if (!m || !m->handle) {
if (u) {
notice_lang(s_OperServ, u, OPER_MODULE_REMOVE_FAIL, m->name);
}
return MOD_ERR_PARAMS;
}
if (prepForUnload(mod_current_module) != MOD_ERR_OK) {
return MOD_ERR_UNKNOWN;
}
func = dlsym(m->handle, "AnopeFini");
if (func) {
func(); /* exec AnopeFini */
}
if ((dlclose(m->handle)) != 0) {
alog(dlerror());
if (u) {
notice_lang(s_OperServ, u, OPER_MODULE_REMOVE_FAIL, m->name);
}
return MOD_ERR_NOUNLOAD;
} else {
if (u) {
wallops(s_OperServ, "%s unloaded module %s", u->nick, m->name);
notice_lang(s_OperServ, u, OPER_MODULE_UNLOADED, m->name);
}
delModule(m);
return MOD_ERR_OK;
}
#else
return MOD_ERR_NOUNLOAD;
#endif
}
int prepForUnload(Module * m)
{
int idx;
CommandHash *current = NULL;
MessageHash *mcurrent = NULL;
Command *c;
Message *msg;
if (!m) {
return MOD_ERR_PARAMS;
}
/* Kill any active callbacks this module has */
moduleCallBackPrepForUnload(m->name);
/**
* ok, im going to walk every hash looking for commands we own, now, not exactly elegant or efficiant :)
**/
for (idx = 0; idx < MAX_CMD_HASH; idx++) {
for (current = HS_cmdTable[idx]; current; current = current->next) {
for (c = current->c; c; c = c->next) {
if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
moduleDelCommand(HOSTSERV, c->name);
}
}
}
for (current = BS_cmdTable[idx]; current; current = current->next) {
for (c = current->c; c; c = c->next) {
if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
moduleDelCommand(BOTSERV, c->name);
}
}
}
for (current = MS_cmdTable[idx]; current; current = current->next) {
for (c = current->c; c; c = c->next) {
if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
moduleDelCommand(MEMOSERV, c->name);
}
}
}
for (current = NS_cmdTable[idx]; current; current = current->next) {
for (c = current->c; c; c = c->next) {
if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
moduleDelCommand(NICKSERV, c->name);
}
}
}
for (current = CS_cmdTable[idx]; current; current = current->next) {
for (c = current->c; c; c = c->next) {
if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
moduleDelCommand(CHANSERV, c->name);
}
}
}
for (current = HE_cmdTable[idx]; current; current = current->next) {
for (c = current->c; c; c = c->next) {
if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
moduleDelCommand(HELPSERV, c->name);
}
}
}
for (current = OS_cmdTable[idx]; current; current = current->next) {
for (c = current->c; c; c = c->next) {
if ((c->mod_name) && (stricmp(c->mod_name, m->name) == 0)) {
moduleDelCommand(OPERSERV, c->name);
}
}
}
for (mcurrent = IRCD[idx]; mcurrent; mcurrent = mcurrent->next) {
for (msg = mcurrent->m; msg; msg = msg->next) {
if ((msg->mod_name)
&& (stricmp(msg->mod_name, m->name) == 0)) {
moduleDelMessage(msg->name);
}
}
}
}
return MOD_ERR_OK;
}
/*******************************************************************************
* Command Functions
*******************************************************************************/
Command *createCommand(const char *name, int (*func) (User * u),
int (*has_priv) (User * u), int help_all,
int help_reg, int help_oper, int help_admin,
int help_root)
{
Command *c;
if ((c = malloc(sizeof(Command))) == NULL) {
fatal("Out of memory!");
}
c->name = sstrdup(name);
c->routine = func;
c->has_priv = has_priv;
c->helpmsg_all = help_all;
c->helpmsg_reg = help_reg;
c->helpmsg_oper = help_oper;
c->helpmsg_admin = help_admin;
c->helpmsg_root = help_root;
c->help_param1 = NULL;
c->help_param2 = NULL;
c->help_param3 = NULL;
c->help_param4 = NULL;
c->next = NULL;
c->mod_name = NULL;
c->service = NULL;
c->all_help = NULL;
c->regular_help = NULL;
c->oper_help = NULL;
c->admin_help = NULL;
c->root_help = NULL;
return c;
}
int destroyCommand(Command * c)
{
if (!c) {
return MOD_ERR_PARAMS;
}
if (c->core == 1) {
return MOD_ERR_UNKNOWN;
}
if (c->name) {
free(c->name);
}
c->routine = NULL;
c->has_priv = NULL;
c->helpmsg_all = -1;
c->helpmsg_reg = -1;
c->helpmsg_oper = -1;
c->helpmsg_admin = -1;
c->helpmsg_root = -1;
if (c->help_param1) {
free(c->help_param1);
}
if (c->help_param2) {
free(c->help_param2);
}
if (c->help_param3) {
free(c->help_param3);
}
if (c->help_param4) {
free(c->help_param4);
}
if (c->mod_name) {
free(c->mod_name);
}
if (c->service) {
free(c->service);
}
c->next = NULL;
free(c);
return MOD_ERR_OK;
}
int addCoreCommand(CommandHash * cmdTable[], Command * c)
{
if (!cmdTable || !c) {
return MOD_ERR_PARAMS;
}
c->core = 1;
c->next = NULL;
return addCommand(cmdTable, c, 0);
}
int moduleAddCommand(CommandHash * cmdTable[], Command * c, int pos)
{
int status;
if (!cmdTable || !c) {
return MOD_ERR_PARAMS;
}
/* ok, this appears to be a module adding a command from outside of AnopeInit, try to look up its module struct for it */
if ((mod_current_module_name) && (!mod_current_module)) {
mod_current_module = findModule(mod_current_module_name);
}
if (!mod_current_module) {
return MOD_ERR_UNKNOWN;
} /* shouldnt happen */
c->core = 0;
if (!c->mod_name) {
c->mod_name = sstrdup(mod_current_module->name);
}
if (cmdTable == HOSTSERV) {
if (s_HostServ) {
c->service = sstrdup(s_HostServ);
} else {
return MOD_ERR_NOSERVICE;
}
} else if (cmdTable == BOTSERV) {
if (s_BotServ) {
c->service = sstrdup(s_BotServ);
} else {
return MOD_ERR_NOSERVICE;
}
} else if (cmdTable == MEMOSERV) {
if (s_MemoServ) {
c->service = sstrdup(s_MemoServ);
} else {
return MOD_ERR_NOSERVICE;
}
} else if (cmdTable == CHANSERV) {
if (s_ChanServ) {
c->service = sstrdup(s_ChanServ);
} else {
return MOD_ERR_NOSERVICE;
}
} else if (cmdTable == NICKSERV) {
if (s_NickServ) {
c->service = sstrdup(s_NickServ);
} else {
return MOD_ERR_NOSERVICE;
}
} else if (cmdTable == HELPSERV) {
if (s_HelpServ) {
c->service = sstrdup(s_HelpServ);
} else {
return MOD_ERR_NOSERVICE;
}
} else if (cmdTable == OPERSERV) {
if (s_OperServ) {
c->service = sstrdup(s_OperServ);
} else {
return MOD_ERR_NOSERVICE;
}
} else
c->service = sstrdup("Unknown");
if (debug)
displayCommandFromHash(cmdTable, c->name);
status = addCommand(cmdTable, c, pos);
if (debug)
displayCommandFromHash(cmdTable, c->name);
if (status != MOD_ERR_OK) {
alog("ERROR! [%d]", status);
}
return status;
}
int moduleDelCommand(CommandHash * cmdTable[], char *name)
{
Command *c = NULL;
Command *cmd = NULL;
int status = 0;
if (!mod_current_module) {
return MOD_ERR_UNKNOWN;
}
c = findCommand(cmdTable, name);
if (!c) {
return MOD_ERR_NOEXIST;
}
for (cmd = c; cmd; cmd = cmd->next) {
if (cmd->mod_name
&& strcasecmp(cmd->mod_name, mod_current_module->name) == 0) {
if (debug) {
displayCommandFromHash(cmdTable, name);
}
status = delCommand(cmdTable, cmd, mod_current_module->name);
if (debug) {
displayCommandFromHash(cmdTable, name);
}
}
}
return status;
}
int displayCommandFromHash(CommandHash * cmdTable[], char *name)
{
CommandHash *current = NULL;
int index = 0;
index = CMD_HASH(name);
if (debug > 1) {
alog("trying to display command %s", name);
}
for (current = cmdTable[index]; current; current = current->next) {
if (strcasecmp(name, current->name) == 0) {
displayCommand(current->c);
}
}
if (debug > 1) {
alog("done displaying command %s", name);
}
return 0;
}
int displayCommand(Command * c)
{
Command *cmd = NULL;
int i = 0;
alog("Displaying command list for %s", c->name);
for (cmd = c; cmd; cmd = cmd->next) {
alog("%d: %p", ++i, cmd);
}
alog("end");
return 0;
}
int displayMessageFromHash(char *name)
{
MessageHash *current = NULL;
int index = 0;
index = CMD_HASH(name);
if (debug > 1) {
alog("trying to display message %s", name);
}
for (current = IRCD[index]; current; current = current->next) {
if (strcasecmp(name, current->name) == 0) {
displayMessage(current->m);
}
}
if (debug > 1) {
alog("done displaying message %s", name);
}
return 0;
}
int displayMessage(Message * m)
{
Message *msg = NULL;
int i = 0;
alog("Displaying message list for %s", m->name);
for (msg = m; msg; msg = msg->next) {
alog("%d: %p", ++i, msg);
}
alog("end");
return 0;
}
/**
* Add a command to a command table
* only add if were unique, pos = 0;
* if we want it at the "head" of that command, pos = 1
* at the tail, pos = 2
**/
int addCommand(CommandHash * cmdTable[], Command * c, int pos)
{
/* We can assume both param's have been checked by this point.. */
int index = 0;
CommandHash *current = NULL;
CommandHash *newHash = NULL;
CommandHash *lastHash = NULL;
Command *tail = NULL;
if (!cmdTable || !c || (pos < 0 || pos > 2)) {
return MOD_ERR_PARAMS;
}
index = CMD_HASH(c->name);
for (current = cmdTable[index]; current; current = current->next) {
if ((c->service) && (current->c) && (current->c->service)
&& (!strcmp(c->service, current->c->service) == 0)) {
continue;
}
if ((strcasecmp(c->name, current->name) == 0)) { /* the cmd exist's we are a addHead */
if (pos == 1) {
c->next = current->c;
current->c = c;
if (debug)
alog("existing cmd: (%p), new cmd (%p)", c->next, c);
return MOD_ERR_OK;
} else if (pos == 2) {
tail = current->c;
while (tail->next)
tail = tail->next;
if (debug)
alog("existing cmd: (%p), new cmd (%p)", tail, c);
tail->next = c;
c->next = NULL;
return MOD_ERR_OK;
} else
return MOD_ERR_EXISTS;
}
lastHash = current;
}
if ((newHash = malloc(sizeof(CommandHash))) == NULL) {
fatal("Out of memory");
}
newHash->next = NULL;
newHash->name = sstrdup(c->name);
newHash->c = c;
if (lastHash == NULL)
cmdTable[index] = newHash;
else
lastHash->next = newHash;
return MOD_ERR_OK;
}
int delCommand(CommandHash * cmdTable[], Command * c, char *mod_name)
{
int index = 0;
CommandHash *current = NULL;
CommandHash *lastHash = NULL;
Command *tail = NULL, *last = NULL;
if (!c || !cmdTable) {
return MOD_ERR_PARAMS;
}
index = CMD_HASH(c->name);
for (current = cmdTable[index]; current; current = current->next) {
if (strcasecmp(c->name, current->name) == 0) {
if (!lastHash) {
tail = current->c;
if (tail->next) {
while (tail) {
if (mod_name && tail->mod_name
&& (stricmp(mod_name, tail->mod_name) == 0)) {
if (last) {
last->next = tail->next;
} else {
current->c = tail->next;
}
return MOD_ERR_OK;
}
last = tail;
tail = tail->next;
}
} else {
cmdTable[index] = current->next;
free(current->name);
return MOD_ERR_OK;
}
} else {
tail = current->c;
if (tail->next) {
while (tail) {
if (mod_name && tail->mod_name
&& (stricmp(mod_name, tail->mod_name) == 0)) {
if (last) {
last->next = tail->next;
} else {
current->c = tail->next;
}
return MOD_ERR_OK;
}
last = tail;
tail = tail->next;
}
} else {
lastHash->next = current->next;
free(current->name);
return MOD_ERR_OK;
}
}
}
lastHash = current;
}
return MOD_ERR_NOEXIST;
}
Command *findCommand(CommandHash * cmdTable[], const char *name)
{
int idx;
CommandHash *current = NULL;
if (!cmdTable || !name) {
return NULL;
}
idx = CMD_HASH(name);
for (current = cmdTable[idx]; current; current = current->next) {
if (stricmp(name, current->name) == 0) {
return current->c;
}
}
return NULL;
}
/*******************************************************************************
* Message Functions
*******************************************************************************/
Message *createMessage(char *name,
int (*func) (char *source, int ac, char **av))
{
Message *m = NULL;
if (!name || !func) {
return NULL;
}
if ((m = malloc(sizeof(Message))) == NULL) {
fatal("Out of memory!");
}
m->name = sstrdup(name);
m->func = func;
m->mod_name = NULL;
m->next = NULL;
return m;
}
Message *findMessage(MessageHash * msgTable[], const char *name)
{
int idx;
MessageHash *current = NULL;
if (!msgTable || !name) {
return NULL;
}
idx = CMD_HASH(name);
for (current = msgTable[idx]; current; current = current->next) {
if (stricmp(name, current->name) == 0) {
return current->m;
}
}
return NULL;
}
int addMessage(MessageHash * msgTable[], Message * m, int pos)
{
/* We can assume both param's have been checked by this point.. */
int index = 0;
MessageHash *current = NULL;
MessageHash *newHash = NULL;
MessageHash *lastHash = NULL;
Message *tail = NULL;
if (!msgTable || !m || (pos < 0 || pos > 2)) {
return MOD_ERR_PARAMS;
}
index = CMD_HASH(m->name);
for (current = msgTable[index]; current; current = current->next) {
if (strcasecmp(m->name, current->name) == 0) { /* the msg exist's we are a addHead */
if (pos == 1) {
m->next = current->m;
current->m = m;
if (debug)
alog("existing msg: (%p), new msg (%p)", m->next, m);
return MOD_ERR_OK;
} else if (pos == 2) {
tail = current->m;
while (tail->next)
tail = tail->next;
if (debug)
alog("existing msg: (%p), new msg (%p)", tail, m);
tail->next = m;
m->next = NULL;
return MOD_ERR_OK;
} else
return MOD_ERR_EXISTS;
}
lastHash = current;
}
if ((newHash = malloc(sizeof(MessageHash))) == NULL) {
fatal("Out of memory");
}
newHash->next = NULL;
newHash->name = sstrdup(m->name);
newHash->m = m;
if (lastHash == NULL)
msgTable[index] = newHash;
else
lastHash->next = newHash;
return MOD_ERR_OK;
}
int addCoreMessage(MessageHash * msgTable[], Message * m)
{
if (!msgTable || !m) {
return MOD_ERR_PARAMS;
}
m->core = 1;
return addMessage(msgTable, m, 0);
}
int moduleAddMessage(Message * m, int pos)
{
int status;
if (!m) {
return MOD_ERR_PARAMS;
}
/* ok, this appears to be a module adding a message from outside of AnopeInit, try to look up its module struct for it */
if ((mod_current_module_name) && (!mod_current_module)) {
mod_current_module = findModule(mod_current_module_name);
}
if (!mod_current_module) {
return MOD_ERR_UNKNOWN;
} /* shouldnt happen */
m->core = 0;
if (!m->mod_name) {
m->mod_name = sstrdup(mod_current_module->name);
}
status = addMessage(IRCD, m, pos);
if (debug) {
displayMessageFromHash(m->name);
}
return status;
}
int moduleDelMessage(char *name)
{
Message *m;
int status;
if (!mod_current_module) {
return MOD_ERR_UNKNOWN;
}
m = findMessage(IRCD, name);
if (!m) {
return MOD_ERR_NOEXIST;
}
status = delMessage(IRCD, m, mod_current_module->name);
if (debug) {
displayMessageFromHash(m->name);
}
return status;
}
int delMessage(MessageHash * msgTable[], Message * m, char *mod_name)
{
int index = 0;
MessageHash *current = NULL;
MessageHash *lastHash = NULL;
Message *tail = NULL, *last = NULL;
if (!m || !msgTable) {
return MOD_ERR_PARAMS;
}
index = CMD_HASH(m->name);
for (current = msgTable[index]; current; current = current->next) {
if (strcasecmp(m->name, current->name) == 0) {
if (!lastHash) {
tail = current->m;
if (tail->next) {
while (tail) {
if (mod_name && tail->mod_name
&& (stricmp(mod_name, tail->mod_name) == 0)) {
if (last) {
last->next = tail->next;
} else {
current->m = tail->next;
}
return MOD_ERR_OK;
}
last = tail;
tail = tail->next;
}
} else {
msgTable[index] = current->next;
free(current->name);
return MOD_ERR_OK;
}
} else {
tail = current->m;
if (tail->next) {
while (tail) {
if (mod_name && tail->mod_name
&& (stricmp(mod_name, tail->mod_name) == 0)) {
if (last) {
last->next = tail->next;
} else {
current->m = tail->next;
}
return MOD_ERR_OK;
}
last = tail;
tail = tail->next;
}
} else {
lastHash->next = current->next;
free(current->name);
return MOD_ERR_OK;
}
}
}
lastHash = current;
}
return MOD_ERR_NOEXIST;
}
int destroyMessage(Message * m)
{
if (!m) {
return MOD_ERR_PARAMS;
}
if (m->name) {
free(m->name);
}
m->func = NULL;
if (m->mod_name) {
free(m->mod_name);
}
m->next = NULL;
return MOD_ERR_OK;
}
void moduleAddVersion(char *version)
{
if (mod_current_module && version) {
mod_current_module->version = sstrdup(version);
}
}
void moduleAddAuthor(char *author)
{
if (mod_current_module && author) {
mod_current_module->author = sstrdup(author);
}
}
/*******************************************************************************
* Module Callback Functions
*******************************************************************************/
int moduleAddCallback(char *name, time_t when,
int (*func) (int argc, char *argv[]), int argc,
char **argv)
{
ModuleCallBack *new, *tmp, *prev;
int i;
new = malloc(sizeof(ModuleCallBack));
if (!new)
return MOD_ERR_MEMORY;
if (name)
new->name = sstrdup(name);
else
new->name = NULL;
new->when = when;
if (mod_current_module_name) {
new->owner_name = sstrdup(mod_current_module_name);
} else {
new->owner_name = NULL;
}
new->func = func;
new->argc = argc;
new->argv = malloc(sizeof(char *) * argc);
for (i = 0; i < argc; i++) {
new->argv[i] = sstrdup(argv[i]);
}
new->next = NULL;
if (moduleCallBackHead == NULL) {
moduleCallBackHead = new;
} else { /* find place in list */
tmp = moduleCallBackHead;
prev = tmp;
if (new->when < tmp->when) {
new->next = tmp;
moduleCallBackHead = new;
} else {
while (tmp && new->when >= tmp->when) {
prev = tmp;
tmp = tmp->next;
}
prev->next = new;
new->next = tmp;
}
}
if (debug)
alog("Added module CallBack: [%s] due to execute at %ld",
new->name ? new->name : "?", (long int) new->when);
return MOD_ERR_OK;
}
void moduleCallBackRun(void)
{
ModuleCallBack *tmp;
if (!moduleCallBackHead) {
return;
}
tmp = moduleCallBackHead;
if (tmp->when <= time(NULL)) {
if (debug)
alog("Executing callback: %s", tmp->name ? tmp->name : "?");
if (tmp->func) {
mod_current_module_name = tmp->owner_name;
tmp->func(tmp->argc, tmp->argv);
mod_current_module = NULL;
moduleCallBackDeleteEntry(NULL); /* delete the head */
}
}
return;
}
void moduleCallBackDeleteEntry(ModuleCallBack * prev)
{
ModuleCallBack *tmp = NULL;
int i;
if (prev == NULL) {
tmp = moduleCallBackHead;
moduleCallBackHead = tmp->next;
} else {
tmp = prev->next;
prev->next = tmp->next;
}
if (tmp->name)
free(tmp->name);
if (tmp->owner_name)
free(tmp->owner_name);
tmp->func = NULL;
for (i = 0; i < tmp->argc; i++) {
free(tmp->argv[i]);
}
tmp->argc = 0;
tmp->next = NULL;
free(tmp);
}
ModuleCallBack *moduleCallBackFindEntry(char *mod_name, boolean * found)
{
ModuleCallBack *prev = NULL, *current = NULL;
*found = false;
current = moduleCallBackHead;
while (current != NULL) {
if (current->owner_name
&& (strcmp(mod_name, current->owner_name) == 0)) {
*found = true;
break;
} else {
prev = current;
current = current->next;
}
}
if (current == moduleCallBackHead) {
return NULL;
} else {
return prev;
}
}
void moduleDelCallback(char *name)
{
ModuleCallBack *current = NULL;
ModuleCallBack *prev = NULL, *tmp = NULL;
int del = 0;
if (!mod_current_module_name) {
return;
}
if (!name) {
return;
}
current = moduleCallBackHead;
while (current) {
if ((current->owner_name) && (current->name)) {
if ((strcmp(mod_current_module_name, current->owner_name) == 0)
&& (strcmp(current->name, name) == 0)) {
if (debug) {
alog("Removing CallBack %s for module %s", name,
mod_current_module_name);
}
tmp = current->next; /* get a pointer to the next record, as once we delete this record, we'll lose it :) */
moduleCallBackDeleteEntry(prev); /* delete this record */
del = 1; /* set the record deleted flag */
}
}
if (del == 1) { /* if a record was deleted */
current = tmp; /* use the value we stored in temp */
tmp = NULL; /* clear it for next time */
del = 0; /* reset the flag */
} else {
prev = current; /* just carry on as normal */
current = current->next;
}
}
}
void moduleCallBackPrepForUnload(char *mod_name)
{
boolean found = false;
ModuleCallBack *tmp = NULL;
tmp = moduleCallBackFindEntry(mod_name, &found);
while (found) {
if (debug) {
alog("Removing CallBack for module %s", mod_name);
}
moduleCallBackDeleteEntry(tmp);
tmp = moduleCallBackFindEntry(mod_name, &found);
}
}
char *moduleGetLastBuffer(void)
{
char *tmp = NULL;
if (mod_current_buffer) {
tmp = strchr(mod_current_buffer, ' ');
if (tmp) {
tmp++;
}
}
return tmp;
}
/*******************************************************************************
* Module HELP Functions
*******************************************************************************/
int moduleAddRootHelp(Command * c, int (*func) (User * u))
{
if (c) {
c->root_help = func;
return MOD_STOP;
}
return MOD_CONT;
}
int moduleAddAdminHelp(Command * c, int (*func) (User * u))
{
if (c) {
c->admin_help = func;
return MOD_STOP;
}
return MOD_CONT;
}
int moduleAddOperHelp(Command * c, int (*func) (User * u))
{
if (c) {
c->oper_help = func;
return MOD_STOP;
}
return MOD_CONT;
}
int moduleAddRegHelp(Command * c, int (*func) (User * u))
{
if (c) {
c->regular_help = func;
return MOD_STOP;
}
return MOD_CONT;
}
int moduleAddHelp(Command * c, int (*func) (User * u))
{
if (c) {
c->all_help = func;
return MOD_STOP;
}
return MOD_CONT;
}
void moduleSetNickHelp(void (*func) (User * u))
{
if (mod_current_module) {
mod_current_module->nickHelp = func;
}
}
void moduleSetChanHelp(void (*func) (User * u))
{
if (mod_current_module) {
mod_current_module->chanHelp = func;
}
}
void moduleSetMemoHelp(void (*func) (User * u))
{
if (mod_current_module) {
mod_current_module->memoHelp = func;
}
}
void moduleSetBotHelp(void (*func) (User * u))
{
if (mod_current_module) {
mod_current_module->botHelp = func;
}
}
void moduleSetOperHelp(void (*func) (User * u))
{
if (mod_current_module) {
mod_current_module->operHelp = func;
}
}
void moduleSetHostHelp(void (*func) (User * u))
{
if (mod_current_module) {
mod_current_module->hostHelp = func;
}
}
void moduleSetHelpHelp(void (*func) (User * u))
{
if (mod_current_module) {
mod_current_module->helpHelp = func;
}
}
void moduleDisplayHelp(int service, User * u)
{
#ifdef USE_MODULES
int idx;
int header_shown = 0;
ModuleHash *current = NULL;
for (idx = 0; idx != MAX_CMD_HASH; idx++) {
for (current = MODULE_HASH[idx]; current; current = current->next) {
if ((service == 1) && current->m->nickHelp) {
if (header_shown == 0) {
notice_lang(s_NickServ, u, MODULE_HELP_HEADER);
header_shown = 1;
}
current->m->nickHelp(u);
} else if ((service == 2) && current->m->chanHelp) {
if (header_shown == 0) {
notice_lang(s_ChanServ, u, MODULE_HELP_HEADER);
header_shown = 1;
}
current->m->chanHelp(u);
} else if ((service == 3) && current->m->memoHelp) {
if (header_shown == 0) {
notice_lang(s_MemoServ, u, MODULE_HELP_HEADER);
header_shown = 1;
}
current->m->memoHelp(u);
} else if ((service == 4) && current->m->botHelp) {
if (header_shown == 0) {
notice_lang(s_BotServ, u, MODULE_HELP_HEADER);
header_shown = 1;
}
current->m->botHelp(u);
} else if ((service == 5) && current->m->operHelp) {
if (header_shown == 0) {
notice_lang(s_OperServ, u, MODULE_HELP_HEADER);
header_shown = 1;
}
current->m->operHelp(u);
} else if ((service == 6) && current->m->hostHelp) {
if (header_shown == 0) {
notice_lang(s_HostServ, u, MODULE_HELP_HEADER);
header_shown = 1;
}
current->m->hostHelp(u);
} else if ((service == 7) && current->m->helpHelp) {
if (header_shown == 0) {
notice_lang(s_HelpServ, u, MODULE_HELP_HEADER);
header_shown = 1;
}
current->m->helpHelp(u);
}
}
}
#endif
}
/* EOF */
syntax highlighted by Code2HTML, v. 0.9.1