/* 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 #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 */