modules.c

Go to the documentation of this file.
00001 
00002 /* Modular support
00003  *
00004  * (C) 2003-2013 Anope Team
00005  * Contact us at team@anope.org
00006  *
00007  * Please read COPYING and README for further details.
00008  *
00009  * Based on the original code of Epona by Lara.
00010  * Based on the original code of Services by Andy Church.
00011  *
00012  *
00013  */
00014 #include "modules.h"
00015 #include "language.h"
00016 #include "version.h"
00017 
00018 #if defined(USE_MODULES) && !defined(_WIN32)
00019 #include <dlfcn.h>
00020 /* Define these for systems without them */
00021 #ifndef RTLD_NOW
00022 #define RTLD_NOW 0
00023 #endif
00024 #ifndef RTLD_LAZY
00025 #define RTLD_LAZY RTLD_NOW
00026 #endif
00027 #ifndef RTLD_GLOBAL
00028 #define RTLD_GLOBAL 0
00029 #endif
00030 #ifndef RTLD_LOCAL
00031 #define RTLD_LOCAL 0
00032 #endif
00033 #endif
00034 
00035 #ifdef _WIN32
00036 const char *ano_moderr(void);
00037 #endif
00038 
00042 CommandHash *HOSTSERV[MAX_CMD_HASH];
00043 CommandHash *BOTSERV[MAX_CMD_HASH];
00044 CommandHash *MEMOSERV[MAX_CMD_HASH];
00045 CommandHash *NICKSERV[MAX_CMD_HASH];
00046 CommandHash *CHANSERV[MAX_CMD_HASH];
00047 CommandHash *HELPSERV[MAX_CMD_HASH];
00048 CommandHash *OPERSERV[MAX_CMD_HASH];
00049 MessageHash *IRCD[MAX_CMD_HASH];
00050 ModuleHash *MODULE_HASH[MAX_CMD_HASH];
00051 
00052 Module *mod_current_module;
00053 char *mod_current_module_name = NULL;
00054 char *mod_current_buffer = NULL;
00055 User *mod_current_user;
00056 ModuleCallBack *moduleCallBackHead = NULL;
00057 ModuleQueue *mod_operation_queue = NULL;
00058 
00059 int displayCommand(Command * c);
00060 int displayCommandFromHash(CommandHash * cmdTable[], char *name);
00061 int displayMessageFromHash(char *name);
00062 int displayMessage(Message * m);
00063 char *ModuleGetErrStr(int status);
00064 
00065 char *ModuleGetErrStr(int status)
00066 {
00067     const char *module_err_str[] = {
00068         "Module, Okay - No Error",                                             /* MOD_ERR_OK */
00069         "Module Error, Allocating memory",                                     /* MOD_ERR_MEMORY */
00070         "Module Error, Not enough parameters",                                 /* MOD_ERR_PARAMS */
00071         "Module Error, Already loaded",                                        /* MOD_ERR_EXISTS */
00072         "Module Error, File does not exist",                                   /* MOD_ERR_NOEXIST */
00073         "Module Error, No User",                                               /* MOD_ERR_NOUSER */
00074         "Module Error, Error during load time or module returned MOD_STOP",    /* MOD_ERR_NOLOAD */
00075         "Module Error, Unable to unload",                                      /* MOD_ERR_NOUNLOAD */
00076         "Module Error, Incorrect syntax",                                      /* MOD_ERR_SYNTAX */
00077         "Module Error, Unable to delete",                                      /* MOD_ERR_NODELETE */
00078         "Module Error, Unknown Error occuried",                                /* MOD_ERR_UNKOWN */
00079         "Module Error, File I/O Error",                                        /* MOD_ERR_FILE_IO */
00080         "Module Error, No Service found for request",                          /* MOD_ERR_NOSERVICE */
00081         "Module Error, No module name for request"                             /* MOD_ERR_NO_MOD_NAME */
00082     };
00083     return (char *) module_err_str[status];
00084 }
00085 
00091 void modules_init(void)
00092 {
00093 #ifdef USE_MODULES
00094     int idx;
00095         int ret;
00096     Module *m;
00097 
00098     if(nothird) {
00099         return;
00100     }
00101 
00102     for (idx = 0; idx < ModulesNumber; idx++) {
00103         m = findModule(ModulesAutoload[idx]);
00104         if (!m) {
00105             m = createModule(ModulesAutoload[idx]);
00106             mod_current_module = m;
00107             mod_current_module_name = m->name;
00108             mod_current_user = NULL;
00109             alog("trying to load [%s]", mod_current_module->name);
00110                         ret = loadModule(mod_current_module, NULL);
00111             alog("status: [%d][%s]", ret, ModuleGetErrStr(ret));
00112                         if (ret != MOD_ERR_OK)
00113                                 destroyModule(m);
00114             mod_current_module = NULL;
00115             mod_current_module_name = NULL;
00116             mod_current_user = NULL;
00117         }
00118     }
00119 #endif
00120 }
00121 
00127 void modules_core_init(int number, char **list)
00128 {
00129     int idx;
00130     Module *m;
00131     int status = 0;
00132     for (idx = 0; idx < number; idx++) {
00133         m = findModule(list[idx]);
00134         if (!m) {
00135             m = createModule(list[idx]);
00136             mod_current_module = m;
00137             mod_current_module_name = m->name;
00138             mod_current_user = NULL;
00139             status = loadModule(mod_current_module, NULL);
00140             mod_current_module = m;
00141             mod_current_module_name = m->name;
00142             if (debug || status) {
00143                 alog("debug: trying to load core module [%s]",
00144                      mod_current_module->name);
00145                 alog("debug: status: [%d][%s]", status, ModuleGetErrStr(status));
00146                                 if (status != MOD_ERR_OK)
00147                                         destroyModule(mod_current_module);
00148             }
00149             mod_current_module = NULL;
00150             mod_current_module_name = NULL;
00151             mod_current_user = NULL;
00152         }
00153     }
00154 }
00158 int encryption_module_init(void) {
00159     int ret = 0;
00160     Module *m;
00161         
00162     m = createModule(EncModule);
00163     mod_current_module = m;
00164     mod_current_module_name = m->name;
00165     mod_current_user = NULL;
00166     alog("Loading Encryption Module: [%s]", mod_current_module->name);
00167     ret = loadModule(mod_current_module, NULL);
00168     mod_current_module = m;
00169     mod_current_module_name = m->name;
00170     moduleSetType(ENCRYPTION);
00171     alog("status: [%d][%s]", ret, ModuleGetErrStr(ret));
00172     mod_current_module = NULL;
00173     mod_current_module_name = NULL;
00174     if (ret != MOD_ERR_OK) {
00175         destroyModule(m);
00176     }
00177     return ret;
00178 }
00179 
00183 int protocol_module_init(void)
00184 {
00185     int ret = 0, noforksave = nofork;
00186     Module *m;
00187         
00188     m = createModule(IRCDModule);
00189     mod_current_module = m;
00190     mod_current_module_name = m->name;
00191     mod_current_user = NULL;
00192     alog("Loading IRCD Protocol Module: [%s]", mod_current_module->name);
00193     ret = loadModule(mod_current_module, NULL);
00194     mod_current_module = m;
00195     mod_current_module_name = m->name;
00196     moduleSetType(PROTOCOL);
00197     alog("status: [%d][%s]", ret, ModuleGetErrStr(ret));
00198     mod_current_module = NULL;
00199     mod_current_module_name = NULL;
00200         
00201         if (ret == MOD_ERR_OK) {
00202                 /* This is really NOT the correct place to do config checks, but
00203                  * as we only have the ircd struct filled here, we have to over
00204                  * here. -GD
00205                  */
00206                 if (UseTokens && !ircd->token) {
00207                         alog("Anope does not support TOKENS for this ircd setting; unsetting UseToken");
00208                         UseTokens = 0;
00209                 }
00210                 
00211                 if (UseTS6 && !ircd->ts6) {
00212                         alog("Chosen IRCd does not support TS6, unsetting UseTS6");
00213                         UseTS6 = 0;
00214                 }
00215                 
00216                 /* We can assume the ircd supports TS6 here */
00217                 if (UseTS6 && !Numeric) {
00218                     nofork = 1; /* We're going down, set nofork so this error is printed */
00219                     alog("UseTS6 requires the setting of Numeric to be enabled.");
00220                     nofork = noforksave;
00221                     ret = -1;
00222                 }
00223         } else {
00224                 destroyModule(m);
00225         }
00226         
00227     return ret;
00228 }
00229 
00235 void modules_delayed_init(void)
00236 {
00237 #ifdef USE_MODULES
00238     int idx;
00239         int ret;
00240     Module *m;
00241 
00242     if(nothird) {
00243         return;
00244     }
00245 
00246     for (idx = 0; idx < ModulesDelayedNumber; idx++) {
00247         m = findModule(ModulesDelayedAutoload[idx]);
00248         if (!m) {
00249             m = createModule(ModulesDelayedAutoload[idx]);
00250             mod_current_module = m;
00251             mod_current_module_name = m->name;
00252             mod_current_user = NULL;
00253             alog("trying to load [%s]", mod_current_module->name);
00254                         ret = loadModule(mod_current_module, NULL);
00255             alog("status: [%d][%s]", ret, ModuleGetErrStr(ret));
00256             mod_current_module = NULL;
00257             mod_current_module_name = NULL;
00258             mod_current_user = NULL;
00259                         if (ret != MOD_ERR_OK)
00260                                 destroyModule(m);
00261         }
00262     }
00263 #endif
00264 }
00265 
00276 void modules_unload_all(boolean fini, boolean unload_proto)
00277 {
00278 #ifdef USE_MODULES
00279         int idx;
00280         ModuleHash *mh, *next;
00281         
00282         for (idx = 0; idx < MAX_CMD_HASH; idx++) {
00283                 mh = MODULE_HASH[idx];
00284                 while (mh) {
00285                         next = mh->next;
00286                         if (unload_proto || (mh->m->type != PROTOCOL)) {
00287                                 mod_current_module = mh->m;
00288                                 mod_current_module_name = mh->m->name;
00289                             if(fini) {
00290                                 union fini_union
00291                                 {
00292                                         void *ptr;
00293                                         void (*func)(void);
00294                                 } u;
00295                                 u.ptr = ano_modsym(mh->m->handle, "AnopeFini");
00296                                 if (u.ptr)
00297                                         u.func(); /* exec AnopeFini */
00298                                 
00299                             if (prepForUnload(mh->m) != MOD_ERR_OK) {
00300                                         mh = next;
00301                                                 continue;
00302                                 }
00303                                 
00304                                 if ((ano_modclose(mh->m->handle)) != 0)
00305                                     alog("%s", ano_moderr());
00306                                 else
00307                                     delModule(mh->m);
00308                         } else {
00309                                 delModule(mh->m);
00310                                 }
00311                         mod_current_module = NULL;
00312                         mod_current_module_name = NULL;
00313                     }
00314                     mh = next;
00315                 }
00316         }
00317 #endif
00318 }
00319 
00325 Module *createModule(char *filename)
00326 {
00327     Module *m;
00328     int i = 0;
00329     if (!filename) {
00330         return NULL;
00331     }
00332     if ((m = malloc(sizeof(Module))) == NULL) {
00333         fatal("Out of memory!");
00334     }
00335 
00336     m->name = sstrdup(filename);        /* Our Name */
00337     m->handle = NULL;           /* Handle */
00338     m->version = NULL;
00339     m->author = NULL;
00340     m->nickHelp = NULL;
00341     m->chanHelp = NULL;
00342     m->memoHelp = NULL;
00343     m->botHelp = NULL;
00344     m->operHelp = NULL;
00345     m->hostHelp = NULL;
00346     m->helpHelp = NULL;
00347 
00348     m->type = THIRD;
00349     for (i = 0; i < NUM_LANGS; i++) {
00350         m->lang[i].argc = 0;
00351     }
00352     return m;                   /* return a nice new module */
00353 }
00354 
00361 int destroyModule(Module * m)
00362 {
00363     int i = 0;
00364     if (!m) {
00365         return MOD_ERR_PARAMS;
00366     }
00367 
00368     mod_current_module = m;
00369     mod_current_module_name = m->name;
00370     for (i = 0; i < NUM_LANGS; i++) {
00371         moduleDeleteLanguage(i);
00372     }
00373 
00374     if (m->name) {
00375         free(m->name);
00376     }
00377     if (m->filename) {
00378         remove(m->filename);
00379         free(m->filename);
00380     }
00381     m->handle = NULL;
00382     if (m->author) {
00383         free(m->author);
00384     }
00385     if (m->version) {
00386         free(m->version);
00387     }
00388 
00389     /* No need to free our cmd/msg list, as they will always be empty by the module is destroyed */
00390     free(m);
00391     
00392     mod_current_module = NULL;
00393     mod_current_module_name = NULL;
00394 
00395     return MOD_ERR_OK;
00396 }
00397 
00403 int addModule(Module * m)
00404 {
00405     int index = 0;
00406     ModuleHash *current = NULL;
00407     ModuleHash *newHash = NULL;
00408     ModuleHash *lastHash = NULL;
00409 
00410     index = CMD_HASH(m->name);
00411 
00412     for (current = MODULE_HASH[index]; current; current = current->next) {
00413         if (stricmp(m->name, current->name) == 0)
00414             return MOD_ERR_EXISTS;
00415         lastHash = current;
00416     }
00417 
00418     if ((newHash = malloc(sizeof(ModuleHash))) == NULL) {
00419         fatal("Out of memory");
00420     }
00421     m->time = time(NULL);
00422     newHash->next = NULL;
00423     newHash->name = sstrdup(m->name);
00424     newHash->m = m;
00425 
00426     if (lastHash == NULL)
00427         MODULE_HASH[index] = newHash;
00428     else
00429         lastHash->next = newHash;
00430     return MOD_ERR_OK;
00431 }
00432 
00438 int delModule(Module * m)
00439 {
00440     int index = 0;
00441     ModuleHash *current = NULL;
00442     ModuleHash *lastHash = NULL;
00443 
00444     if (!m) {
00445         return MOD_ERR_PARAMS;
00446     }
00447 
00448     index = CMD_HASH(m->name);
00449 
00450     for (current = MODULE_HASH[index]; current; current = current->next) {
00451         if (stricmp(m->name, current->name) == 0) {
00452             if (!lastHash) {
00453                 MODULE_HASH[index] = current->next;
00454             } else {
00455                 lastHash->next = current->next;
00456             }
00457             destroyModule(current->m);
00458             free(current->name);
00459             free(current);
00460             return MOD_ERR_OK;
00461         }
00462         lastHash = current;
00463     }
00464     return MOD_ERR_NOEXIST;
00465 }
00466 
00472 Module *findModule(char *name)
00473 {
00474     int idx;
00475     ModuleHash *current = NULL;
00476     if (!name) {
00477         return NULL;
00478     }
00479     idx = CMD_HASH(name);
00480 
00481     for (current = MODULE_HASH[idx]; current; current = current->next) {
00482         if (stricmp(name, current->name) == 0) {
00483             return current->m;
00484         }
00485     }
00486     return NULL;
00487 
00488 }
00489 
00494 int protocolModuleLoaded()
00495 {
00496     int idx = 0;
00497     ModuleHash *current = NULL;
00498 
00499     for (idx = 0; idx != MAX_CMD_HASH; idx++) {
00500         for (current = MODULE_HASH[idx]; current; current = current->next) {
00501             if (current->m->type == PROTOCOL) {
00502                 return 1;
00503             }
00504         }
00505     }
00506     return 0;
00507 }
00508 
00513 int encryptionModuleLoaded()
00514 {
00515     int idx = 0;
00516     ModuleHash *current = NULL;
00517 
00518     for (idx = 0; idx != MAX_CMD_HASH; idx++) {
00519         for (current = MODULE_HASH[idx]; current; current = current->next) {
00520             if (current->m->type == ENCRYPTION) {
00521                 return 1;
00522             }
00523         }
00524     }
00525     return 0;
00526 }
00527 
00537 int moduleCopyFile(char *name, char *output)
00538 {
00539 #ifdef USE_MODULES
00540     int ch;
00541     FILE *source, *target;
00542         int srcfp;
00543     char input[4096] = "";
00544     int len;
00545 
00546     strncpy(input, MODULE_PATH, 4095);  /* Get full path with module extension */
00547     len = strlen(input);
00548     strncat(input, name, 4095 - len);
00549     len = strlen(output);
00550     strncat(input, MODULE_EXT, 4095 - len);
00551 
00552 #ifndef _WIN32
00553         if ((srcfp = mkstemp(output)) == -1)
00554                 return MOD_ERR_FILE_IO;
00555 #else
00556         if (!mktemp(output))
00557                 return MOD_ERR_FILE_IO;
00558 #endif
00559         
00560         if (debug)
00561                 alog("Runtime module location: %s", output);
00562         
00563         /* Linux/UNIX should ignore the b param, why do we still have seperate
00564          * calls for it here? -GD
00565          */
00566 #ifndef _WIN32
00567     if ((source = fopen(input, "r")) == NULL) {
00568         close(srcfp);
00569 #else
00570     if ((source = fopen(input, "rb")) == NULL) {
00571 #endif
00572         return MOD_ERR_NOEXIST;
00573     }
00574 #ifndef _WIN32
00575     if ((target = fdopen(srcfp, "w")) == NULL) {
00576 #else
00577     if ((target = fopen(output, "wb")) == NULL) {
00578 #endif
00579         fclose(source);
00580         return MOD_ERR_FILE_IO;
00581     }
00582     while ((ch = fgetc(source)) != EOF) {
00583         fputc(ch, target);
00584     }
00585     fclose(source);
00586     if (fclose(target) != 0) {
00587         return MOD_ERR_FILE_IO;
00588     }
00589 #endif
00590     return MOD_ERR_OK;
00591 }
00592 
00599 int loadModule(Module * m, User * u)
00600 {
00601 #ifdef USE_MODULES
00602     char buf[4096];
00603     int len;
00604     const char *err;
00605     int ret = 0;
00606     char *argv[1];
00607     int argc = 0;
00608 
00609     union init_func_union
00610     {
00611         void *ptr;
00612         int (*func)(int, char **);
00613     } init_union;
00614 
00615     union version_func_union
00616     {
00617         void *ptr;
00618         int (*func)();
00619     } version_union;
00620 
00621     Module *m2;
00622     if (!m || !m->name) {
00623         return MOD_ERR_PARAMS;
00624     }
00625     if (m->handle) {
00626         return MOD_ERR_EXISTS;
00627     }
00628     if ((m2 = findModule(m->name)) != NULL) {
00629         return MOD_ERR_EXISTS;
00630     }
00631         
00632         /* Generate the filename for the temporary copy of the module */
00633     strncpy(buf, MODULE_PATH, 4095);    /* Get full path with module extension */
00634     len = strlen(buf);
00635 #ifndef _WIN32
00636     strncat(buf, "runtime/", 4095 - len);
00637 #else
00638     strncat(buf, "runtime\\", 4095 - len);
00639 #endif
00640     len = strlen(buf);
00641     strncat(buf, m->name, 4095 - len);
00642     len = strlen(buf);
00643     strncat(buf, MODULE_EXT, 4095 - len);
00644         len = strlen(buf);
00645         strncat(buf, ".", 4095 - len);
00646         len = strlen(buf);
00647         strncat(buf, "XXXXXX", 4095 - len);
00648     buf[4095] = '\0';
00649         /* Don't skip return value checking! -GD */
00650     if ((ret = moduleCopyFile(m->name, buf)) != MOD_ERR_OK) {
00651         m->filename = sstrdup(buf);
00652         return ret;
00653         }
00654 
00655     m->filename = sstrdup(buf);
00656     ano_modclearerr();
00657     m->handle = ano_modopen(m->filename);
00658     if ( m->handle == NULL && (err = ano_moderr()) != NULL) {
00659         alog("%s", err);
00660         return MOD_ERR_NOLOAD;
00661     }
00662     ano_modclearerr();
00663 
00664     init_union.ptr = ano_modsym(m->handle, "AnopeInit");
00665 
00666     if ( init_union.ptr == NULL && (err = ano_moderr()) != NULL) {
00667         ano_modclose(m->handle);        /* If no AnopeInit - it isnt an Anope Module, close it */
00668         return MOD_ERR_NOLOAD;
00669     }
00670     if (init_union.ptr) {
00671         version_union.ptr = ano_modsym(m->handle,"getAnopeBuildVersion");
00672         if (version_union.ptr) {
00673         if (version_union.func() >= VERSION_BUILD ) {
00674             if(debug) {
00675                 alog("Module %s compiled against current or newer anope revision %d, this is %d",m->name,version_union.func(),VERSION_BUILD);
00676             }
00677         } else {
00678             alog("Module %s is compiled against an old version of anope (%d) current is %d", m->name, version_union.func(), VERSION_BUILD);
00679             alog("Rebuild module %s against the current version to resolve this error", m->name);
00680             ano_modclose(m->handle);
00681             ano_modclearerr();
00682             return MOD_ERR_NOLOAD;
00683         }
00684     } else {
00685         ano_modclose(m->handle);
00686         ano_modclearerr();
00687         alog("Module %s is compiled against an older version of anope (unknown)", m->name);
00688         alog("Rebuild module %s against the current version to resolve this error", m->name);
00689         return MOD_ERR_NOLOAD;
00690         }
00691         /* TODO */
00692         mod_current_module = m;
00693         mod_current_module_name = m->name;
00694         /* argv[0] is the user if there was one, or NULL if not */
00695         if (u) {
00696             argv[0] = sstrdup(u->nick);
00697         } else {
00698             argv[0] = NULL;
00699         }
00700         argc++;
00701 
00702         init_union.func(argc, argv); /* exec AnopeInit */
00703         if (u) {
00704             free(argv[0]);
00705         }
00706         if (m->type == PROTOCOL && protocolModuleLoaded()) {
00707             alog("You cannot load two protocol modules");
00708             ret = MOD_STOP;
00709         } else if (m->type == ENCRYPTION && encryptionModuleLoaded()) {
00710             alog("You cannot load two encryption modules");
00711             ret = MOD_STOP;
00712         }
00713         if (ret == MOD_STOP) {
00714             alog("%s requested unload...", m->name);
00715             unloadModule(m, NULL);
00716             mod_current_module = NULL;
00717             mod_current_module_name = NULL;
00718             return MOD_ERR_NOLOAD;
00719         }
00720 
00721         mod_current_module = NULL;
00722         mod_current_module_name = NULL;
00723     }
00724 
00725     if (u) {
00726         anope_cmd_global(s_OperServ, "%s loaded module %s", u->nick,
00727                          m->name);
00728         notice_lang(s_OperServ, u, OPER_MODULE_LOADED, m->name);
00729     }
00730     addModule(m);
00731 
00732     /* Loading is complete.. send out an event in case anyone s interested.. ~ Viper */
00733     send_event(EVENT_MODLOAD, 1, m->name);
00734 
00735     return MOD_ERR_OK;
00736 
00737 #else
00738     return MOD_ERR_NOLOAD;
00739 #endif
00740 }
00741 
00748 int unloadModule(Module * m, User * u)
00749 {
00750 #ifdef USE_MODULES
00751     union fini_union
00752     {
00753         void *ptr;
00754         void (*func)(void);
00755     } un;
00756 
00757     if (!m || !m->handle) {
00758         if (u) {
00759             notice_lang(s_OperServ, u, OPER_MODULE_REMOVE_FAIL, m->name);
00760         }
00761         return MOD_ERR_PARAMS;
00762     }
00763 
00764     if (m->type == PROTOCOL) {
00765         if (u) {
00766             notice_lang(s_OperServ, u, OPER_MODULE_NO_UNLOAD);
00767         }
00768         return MOD_ERR_NOUNLOAD;
00769     } else if(m->type == ENCRYPTION) {
00770         if (u) {
00771             notice_lang(s_OperServ, u, OPER_MODULE_NO_UNLOAD);
00772         }
00773         return MOD_ERR_NOUNLOAD;
00774     }
00775 
00776     un.ptr = ano_modsym(m->handle, "AnopeFini");
00777     if (un.ptr) {
00778         mod_current_module = m;
00779         mod_current_module_name = m->name;
00780         un.func();                 /* exec AnopeFini */
00781     }
00782 
00783     if (prepForUnload(m) != MOD_ERR_OK) {
00784         return MOD_ERR_UNKNOWN;
00785     }
00786 
00787     /* Unloading is complete: AnopeFini has been called and all commands, hooks and callbacks
00788      * have been removed.. send out an event in case anyone s interested.. ~ Viper */
00789     send_event(EVENT_MODUNLOAD, 1, m->name);
00790 
00791     if ((ano_modclose(m->handle)) != 0) {
00792         alog("%s", ano_moderr());
00793         if (u) {
00794             notice_lang(s_OperServ, u, OPER_MODULE_REMOVE_FAIL, m->name);
00795         }
00796         mod_current_module = NULL;
00797         mod_current_module_name = NULL;
00798         return MOD_ERR_NOUNLOAD;
00799     } else {
00800         if (u) {
00801             anope_cmd_global(s_OperServ, "%s unloaded module %s", u->nick,
00802                              m->name);
00803             notice_lang(s_OperServ, u, OPER_MODULE_UNLOADED, m->name);
00804         }
00805         delModule(m);
00806         mod_current_module = NULL;
00807         mod_current_module_name = NULL;
00808         return MOD_ERR_OK;
00809     }
00810 #else
00811     return MOD_ERR_NOUNLOAD;
00812 #endif
00813 }
00814 
00819 void moduleSetType(MODType type)
00820 {
00821     mod_current_module->type = type;
00822 }
00823 
00831 int prepForUnload(Module * m)
00832 {
00833     int idx;
00834     CommandHash *current = NULL;
00835     MessageHash *mcurrent = NULL;
00836     EvtMessageHash *ecurrent = NULL;
00837     EvtHookHash *ehcurrent = NULL;
00838 
00839     Command *c;
00840     Message *msg;
00841     EvtMessage *eMsg;
00842     EvtHook *eHook;
00843 
00844     if (!m) {
00845         return MOD_ERR_PARAMS;
00846     }
00847 
00848     /* Kill any active callbacks this module has */
00849     moduleCallBackPrepForUnload(m->name);
00850 
00851     /* Remove any stored data this module has */
00852     moduleDelAllDataMod(m);
00853 
00857     for (idx = 0; idx < MAX_CMD_HASH; idx++) {
00858         for (current = HS_cmdTable[idx]; current; current = current->next) {
00859             for (c = current->c; c; c = c->next) {
00860                 if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
00861                     moduleDelCommand(HOSTSERV, c->name);
00862                 }
00863             }
00864         }
00865 
00866         for (current = BS_cmdTable[idx]; current; current = current->next) {
00867             for (c = current->c; c; c = c->next) {
00868                 if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
00869                     moduleDelCommand(BOTSERV, c->name);
00870                 }
00871             }
00872         }
00873 
00874         for (current = MS_cmdTable[idx]; current; current = current->next) {
00875             for (c = current->c; c; c = c->next) {
00876                 if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
00877                     moduleDelCommand(MEMOSERV, c->name);
00878                 }
00879             }
00880         }
00881 
00882         for (current = NS_cmdTable[idx]; current; current = current->next) {
00883             for (c = current->c; c; c = c->next) {
00884                 if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
00885                     moduleDelCommand(NICKSERV, c->name);
00886                 }
00887             }
00888         }
00889 
00890         for (current = CS_cmdTable[idx]; current; current = current->next) {
00891             for (c = current->c; c; c = c->next) {
00892                 if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
00893                     moduleDelCommand(CHANSERV, c->name);
00894                 }
00895             }
00896         }
00897 
00898         for (current = HE_cmdTable[idx]; current; current = current->next) {
00899             for (c = current->c; c; c = c->next) {
00900                 if ((c->mod_name) && (strcmp(c->mod_name, m->name) == 0)) {
00901                     moduleDelCommand(HELPSERV, c->name);
00902                 }
00903             }
00904         }
00905 
00906         for (current = OS_cmdTable[idx]; current; current = current->next) {
00907             for (c = current->c; c; c = c->next) {
00908                 if ((c->mod_name) && (stricmp(c->mod_name, m->name) == 0)) {
00909                     moduleDelCommand(OPERSERV, c->name);
00910                 }
00911             }
00912         }
00913 
00914         for (mcurrent = IRCD[idx]; mcurrent; mcurrent = mcurrent->next) {
00915             for (msg = mcurrent->m; msg; msg = msg->next) {
00916                 if ((msg->mod_name)
00917                     && (stricmp(msg->mod_name, m->name) == 0)) {
00918                     moduleDelMessage(msg->name);
00919                 }
00920             }
00921         }
00922 
00923         for (ecurrent = EVENT[idx]; ecurrent; ecurrent = ecurrent->next) {
00924             for (eMsg = ecurrent->evm; eMsg; eMsg = eMsg->next) {
00925                 if ((eMsg->mod_name)
00926                     && (stricmp(eMsg->mod_name, m->name) == 0)) {
00927                     delEventHandler(EVENT, eMsg, m->name);
00928                 }
00929             }
00930         }
00931         for (ehcurrent = EVENTHOOKS[idx]; ehcurrent;
00932              ehcurrent = ehcurrent->next) {
00933             for (eHook = ehcurrent->evh; eHook; eHook = eHook->next) {
00934                 if ((eHook->mod_name)
00935                     && (stricmp(eHook->mod_name, m->name) == 0)) {
00936                     delEventHook(EVENTHOOKS, eHook, m->name);
00937                 }
00938             }
00939         }
00940 
00941     }
00942     return MOD_ERR_OK;
00943 }
00944 
00945 /*******************************************************************************
00946  * Command Functions
00947  *******************************************************************************/
00960 Command *createCommand(const char *name, int (*func) (User * u),
00961                        int (*has_priv) (User * u), int help_all,
00962                        int help_reg, int help_oper, int help_admin,
00963                        int help_root)
00964 {
00965     Command *c;
00966     if (!name || !*name) {
00967         return NULL;
00968     }
00969 
00970     if ((c = malloc(sizeof(Command))) == NULL) {
00971         fatal("Out of memory!");
00972     }
00973     c->name = sstrdup(name);
00974     c->routine = func;
00975     c->has_priv = has_priv;
00976     c->helpmsg_all = help_all;
00977     c->helpmsg_reg = help_reg;
00978     c->helpmsg_oper = help_oper;
00979     c->helpmsg_admin = help_admin;
00980     c->helpmsg_root = help_root;
00981     c->help_param1 = NULL;
00982     c->help_param2 = NULL;
00983     c->help_param3 = NULL;
00984     c->help_param4 = NULL;
00985     c->next = NULL;
00986     c->mod_name = NULL;
00987     c->service = NULL;
00988     c->all_help = NULL;
00989     c->regular_help = NULL;
00990     c->oper_help = NULL;
00991     c->admin_help = NULL;
00992     c->root_help = NULL;
00993     return c;
00994 }
00995 
01001 int destroyCommand(Command * c)
01002 {
01003     if (!c) {
01004         return MOD_ERR_PARAMS;
01005     }
01006     if (c->core == 1) {
01007         return MOD_ERR_UNKNOWN;
01008     }
01009     if (c->name) {
01010         free(c->name);
01011     }
01012     c->routine = NULL;
01013     c->has_priv = NULL;
01014     c->helpmsg_all = -1;
01015     c->helpmsg_reg = -1;
01016     c->helpmsg_oper = -1;
01017     c->helpmsg_admin = -1;
01018     c->helpmsg_root = -1;
01019     if (c->help_param1) {
01020         free(c->help_param1);
01021     }
01022     if (c->help_param2) {
01023         free(c->help_param2);
01024     }
01025     if (c->help_param3) {
01026         free(c->help_param3);
01027     }
01028     if (c->help_param4) {
01029         free(c->help_param4);
01030     }
01031     if (c->mod_name) {
01032         free(c->mod_name);
01033     }
01034     if (c->service) {
01035         free(c->service);
01036     }
01037     c->next = NULL;
01038     free(c);
01039     return MOD_ERR_OK;
01040 }
01041 
01048 int addCoreCommand(CommandHash * cmdTable[], Command * c)
01049 {
01050     if (!cmdTable || !c) {
01051         return MOD_ERR_PARAMS;
01052     }
01053     c->core = 1;
01054     c->next = NULL;
01055     return addCommand(cmdTable, c, 0);
01056 }
01057 
01067 int moduleAddCommand(CommandHash * cmdTable[], Command * c, int pos)
01068 {
01069     int status;
01070 
01071     if (!cmdTable || !c) {
01072         return MOD_ERR_PARAMS;
01073     }
01074 
01075     if (!mod_current_module) {
01076         return MOD_ERR_UNKNOWN;
01077     }                           /* shouldnt happen */
01078     c->core = 0;
01079     if (!c->mod_name) {
01080         c->mod_name = sstrdup(mod_current_module->name);
01081     }
01082 
01083 
01084     if (cmdTable == HOSTSERV) {
01085         if (s_HostServ) {
01086             c->service = sstrdup(s_HostServ);
01087         } else {
01088             return MOD_ERR_NOSERVICE;
01089         }
01090     } else if (cmdTable == BOTSERV) {
01091         if (s_BotServ) {
01092             c->service = sstrdup(s_BotServ);
01093         } else {
01094             return MOD_ERR_NOSERVICE;
01095         }
01096     } else if (cmdTable == MEMOSERV) {
01097         if (s_MemoServ) {
01098             c->service = sstrdup(s_MemoServ);
01099         } else {
01100             return MOD_ERR_NOSERVICE;
01101         }
01102     } else if (cmdTable == CHANSERV) {
01103         if (s_ChanServ) {
01104             c->service = sstrdup(s_ChanServ);
01105         } else {
01106             return MOD_ERR_NOSERVICE;
01107         }
01108     } else if (cmdTable == NICKSERV) {
01109         if (s_NickServ) {
01110             c->service = sstrdup(s_NickServ);
01111         } else {
01112             return MOD_ERR_NOSERVICE;
01113         }
01114     } else if (cmdTable == HELPSERV) {
01115         if (s_HelpServ) {
01116             c->service = sstrdup(s_HelpServ);
01117         } else {
01118             return MOD_ERR_NOSERVICE;
01119         }
01120     } else if (cmdTable == OPERSERV) {
01121         if (s_OperServ) {
01122             c->service = sstrdup(s_OperServ);
01123         } else {
01124             return MOD_ERR_NOSERVICE;
01125         }
01126     } else
01127         c->service = sstrdup("Unknown");
01128 
01129     if (debug >= 2)
01130         displayCommandFromHash(cmdTable, c->name);
01131     status = addCommand(cmdTable, c, pos);
01132     if (debug >= 2)
01133         displayCommandFromHash(cmdTable, c->name);
01134     if (status != MOD_ERR_OK) {
01135         alog("ERROR! [%d]", status);
01136     }
01137     return status;
01138 }
01139 
01146 int moduleDelCommand(CommandHash * cmdTable[], char *name)
01147 {
01148     Command *c = NULL;
01149     Command *cmd = NULL;
01150     int status = 0;
01151 
01152     if (!mod_current_module) {
01153         return MOD_ERR_UNKNOWN;
01154     }
01155 
01156     c = findCommand(cmdTable, name);
01157     if (!c) {
01158         return MOD_ERR_NOEXIST;
01159     }
01160 
01161 
01162     for (cmd = c; cmd; cmd = cmd->next) {
01163         if (cmd->mod_name
01164             && stricmp(cmd->mod_name, mod_current_module->name) == 0) {
01165             if (debug >= 2) {
01166                 displayCommandFromHash(cmdTable, name);
01167             }
01168             status = delCommand(cmdTable, cmd, mod_current_module->name);
01169             if (debug >= 2) {
01170                 displayCommandFromHash(cmdTable, name);
01171             }
01172         }
01173     }
01174     return status;
01175 }
01176 
01184 int displayCommandFromHash(CommandHash * cmdTable[], char *name)
01185 {
01186     CommandHash *current = NULL;
01187     int index = 0;
01188     index = CMD_HASH(name);
01189     if (debug > 1) {
01190         alog("debug: trying to display command %s", name);
01191     }
01192     for (current = cmdTable[index]; current; current = current->next) {
01193         if (stricmp(name, current->name) == 0) {
01194             displayCommand(current->c);
01195         }
01196     }
01197     if (debug > 1) {
01198         alog("debug: done displaying command %s", name);
01199     }
01200     return 0;
01201 }
01202 
01210 int displayCommand(Command * c)
01211 {
01212     Command *cmd = NULL;
01213     int i = 0;
01214     alog("Displaying command list for %s", c->name);
01215     for (cmd = c; cmd; cmd = cmd->next) {
01216         alog("%d:  0x%p", ++i, (void *) cmd);
01217     }
01218     alog("end");
01219     return 0;
01220 }
01221 
01228 int displayMessageFromHash(char *name)
01229 {
01230     MessageHash *current = NULL;
01231     int index = 0;
01232     index = CMD_HASH(name);
01233     if (debug > 1) {
01234         alog("debug: trying to display message %s", name);
01235     }
01236     for (current = IRCD[index]; current; current = current->next) {
01237         if (stricmp(name, current->name) == 0) {
01238             displayMessage(current->m);
01239         }
01240     }
01241     if (debug > 1) {
01242         alog("debug: done displaying message %s", name);
01243     }
01244     return 0;
01245 }
01246 
01253 int displayMessage(Message * m)
01254 {
01255     Message *msg = NULL;
01256     int i = 0;
01257     alog("Displaying message list for %s", m->name);
01258     for (msg = m; msg; msg = msg->next) {
01259         alog("%d: 0x%p", ++i, (void *) msg);
01260     }
01261     alog("end");
01262     return 0;
01263 }
01264 
01265 
01276 int addCommand(CommandHash * cmdTable[], Command * c, int pos)
01277 {
01278     /* We can assume both param's have been checked by this point.. */
01279     int index = 0;
01280     CommandHash *current = NULL;
01281     CommandHash *newHash = NULL;
01282     CommandHash *lastHash = NULL;
01283     Command *tail = NULL;
01284 
01285     if (!cmdTable || !c || (pos < 0 || pos > 2)) {
01286         return MOD_ERR_PARAMS;
01287     }
01288 
01289     if (mod_current_module_name && !c->mod_name)
01290         return MOD_ERR_NO_MOD_NAME;
01291 
01292     index = CMD_HASH(c->name);
01293 
01294     for (current = cmdTable[index]; current; current = current->next) {
01295         if ((c->service) && (current->c) && (current->c->service)
01296             && (!strcmp(c->service, current->c->service) == 0)) {
01297             continue;
01298         }
01299         if ((stricmp(c->name, current->name) == 0)) {   /* the cmd exist's we are a addHead */
01300             if (pos == 1) {
01301                 c->next = current->c;
01302                 current->c = c;
01303                 if (debug)
01304                     alog("debug: existing cmd: (0x%p), new cmd (0x%p)",
01305                          (void *) c->next, (void *) c);
01306                 send_event(EVENT_ADDCOMMAND, 2, c->mod_name, c->name);
01307                 return MOD_ERR_OK;
01308             } else if (pos == 2) {
01309 
01310                 tail = current->c;
01311                 while (tail->next)
01312                     tail = tail->next;
01313                 if (debug)
01314                     alog("debug: existing cmd: (0x%p), new cmd (0x%p)",
01315                          (void *) tail, (void *) c);
01316                 tail->next = c;
01317                 c->next = NULL;
01318 
01319                 send_event(EVENT_ADDCOMMAND, 2, c->mod_name, c->name);
01320                 return MOD_ERR_OK;
01321             } else
01322                 return MOD_ERR_EXISTS;
01323         }
01324         lastHash = current;
01325     }
01326 
01327     if ((newHash = malloc(sizeof(CommandHash))) == NULL) {
01328         fatal("Out of memory");
01329     }
01330     newHash->next = NULL;
01331     newHash->name = sstrdup(c->name);
01332     newHash->c = c;
01333 
01334     if (lastHash == NULL)
01335         cmdTable[index] = newHash;
01336     else
01337         lastHash->next = newHash;
01338 
01339     send_event(EVENT_ADDCOMMAND, 2, c->mod_name, c->name);
01340     return MOD_ERR_OK;
01341 }
01342 
01350 int delCommand(CommandHash * cmdTable[], Command * c, char *mod_name)
01351 {
01352     int index = 0;
01353     CommandHash *current = NULL;
01354     CommandHash *lastHash = NULL;
01355     Command *tail = NULL, *last = NULL;
01356 
01357     if (!c || !cmdTable) {
01358         return MOD_ERR_PARAMS;
01359     }
01360 
01361     index = CMD_HASH(c->name);
01362     for (current = cmdTable[index]; current; current = current->next) {
01363         if (stricmp(c->name, current->name) == 0) {
01364             if (!lastHash) {
01365                 tail = current->c;
01366                 if (tail->next) {
01367                     while (tail) {
01368                         if (mod_name && tail->mod_name
01369                             && (stricmp(mod_name, tail->mod_name) == 0)) {
01370                             if (last) {
01371                                 last->next = tail->next;
01372                             } else {
01373                                 current->c = tail->next;
01374                             }
01375                             send_event(EVENT_DELCOMMAND, 2, c->mod_name, c->name);
01376                             return MOD_ERR_OK;
01377                         }
01378                         last = tail;
01379                         tail = tail->next;
01380                     }
01381                 } else {
01382                     cmdTable[index] = current->next;
01383                     free(current->name);
01384                     send_event(EVENT_DELCOMMAND, 2, c->mod_name, c->name);
01385                     return MOD_ERR_OK;
01386                 }
01387             } else {
01388                 tail = current->c;
01389                 if (tail->next) {
01390                     while (tail) {
01391                         if (mod_name && tail->mod_name
01392                             && (stricmp(mod_name, tail->mod_name) == 0)) {
01393                             if (last) {
01394                                 last->next = tail->next;
01395                             } else {
01396                                 current->c = tail->next;
01397                             }
01398                             send_event(EVENT_DELCOMMAND, 2, c->mod_name, c->name);
01399                             return MOD_ERR_OK;
01400                         }
01401                         last = tail;
01402                         tail = tail->next;
01403                     }
01404                 } else {
01405                     lastHash->next = current->next;
01406                     free(current->name);
01407                     send_event(EVENT_DELCOMMAND, 2, c->mod_name, c->name);
01408                     return MOD_ERR_OK;
01409                 }
01410             }
01411         }
01412         lastHash = current;
01413     }
01414     return MOD_ERR_NOEXIST;
01415 }
01416 
01423 Command *findCommand(CommandHash * cmdTable[], const char *name)
01424 {
01425     int idx;
01426     CommandHash *current = NULL;
01427     if (!cmdTable || !name) {
01428         return NULL;
01429     }
01430 
01431     idx = CMD_HASH(name);
01432 
01433     for (current = cmdTable[idx]; current; current = current->next) {
01434         if (stricmp(name, current->name) == 0) {
01435             return current->c;
01436         }
01437     }
01438     return NULL;
01439 }
01440 
01441 /*******************************************************************************
01442  * Message Functions
01443  *******************************************************************************/
01444 
01451 Message *createMessage(const char *name,
01452                        int (*func) (char *source, int ac, char **av))
01453 {
01454     Message *m = NULL;
01455     if (!name || !func) {
01456         return NULL;
01457     }
01458     if ((m = malloc(sizeof(Message))) == NULL) {
01459         fatal("Out of memory!");
01460     }
01461     m->name = sstrdup(name);
01462     m->func = func;
01463     m->mod_name = NULL;
01464     m->next = NULL;
01465     return m;
01466 }
01467 
01475 Message *findMessage(MessageHash * msgTable[], const char *name)
01476 {
01477     int idx;
01478     MessageHash *current = NULL;
01479     if (!msgTable || !name) {
01480         return NULL;
01481     }
01482     idx = CMD_HASH(name);
01483 
01484     for (current = msgTable[idx]; current; current = current->next) {
01485         if (UseTokens) {
01486             if (ircd->tokencaseless) {
01487                 if (stricmp(name, current->name) == 0) {
01488                     return current->m;
01489                 }
01490             } else {
01491                 if (strcmp(name, current->name) == 0) {
01492                     return current->m;
01493                 }
01494             }
01495         } else {
01496             if (stricmp(name, current->name) == 0) {
01497                 return current->m;
01498             }
01499         }
01500     }
01501     return NULL;
01502 }
01503 
01512 int addMessage(MessageHash * msgTable[], Message * m, int pos)
01513 {
01514     /* We can assume both param's have been checked by this point.. */
01515     int index = 0;
01516     MessageHash *current = NULL;
01517     MessageHash *newHash = NULL;
01518     MessageHash *lastHash = NULL;
01519     Message *tail = NULL;
01520     int match = 0;
01521 
01522     if (!msgTable || !m || (pos < 0 || pos > 2)) {
01523         return MOD_ERR_PARAMS;
01524     }
01525 
01526     index = CMD_HASH(m->name);
01527 
01528     for (current = msgTable[index]; current; current = current->next) {
01529         if ((UseTokens) && (!ircd->tokencaseless)) {
01530             match = strcmp(m->name, current->name);
01531         } else {
01532             match = stricmp(m->name, current->name);
01533         }
01534         if (match == 0) {       /* the msg exist's we are a addHead */
01535             if (pos == 1) {
01536                 m->next = current->m;
01537                 current->m = m;
01538                 if (debug)
01539                     alog("debug: existing msg: (0x%p), new msg (0x%p)",
01540                          (void *) m->next, (void *) m);
01541                 return MOD_ERR_OK;
01542             } else if (pos == 2) {
01543                 tail = current->m;
01544                 while (tail->next)
01545                     tail = tail->next;
01546                 if (debug)
01547                     alog("debug: existing msg: (0x%p), new msg (0x%p)",
01548                          (void *) tail, (void *) m);
01549                 tail->next = m;
01550                 m->next = NULL;
01551                 return MOD_ERR_OK;
01552             } else
01553                 return MOD_ERR_EXISTS;
01554         }
01555         lastHash = current;
01556     }
01557 
01558     if ((newHash = malloc(sizeof(MessageHash))) == NULL) {
01559         fatal("Out of memory");
01560     }
01561     newHash->next = NULL;
01562     newHash->name = sstrdup(m->name);
01563     newHash->m = m;
01564 
01565     if (lastHash == NULL)
01566         msgTable[index] = newHash;
01567     else
01568         lastHash->next = newHash;
01569     return MOD_ERR_OK;
01570 }
01571 
01578 int addCoreMessage(MessageHash * msgTable[], Message * m)
01579 {
01580     if (!msgTable || !m) {
01581         return MOD_ERR_PARAMS;
01582     }
01583     m->core = 1;
01584     return addMessage(msgTable, m, 0);
01585 }
01586 
01593 int moduleAddMessage(Message * m, int pos)
01594 {
01595     int status;
01596 
01597     if (!m) {
01598         return MOD_ERR_PARAMS;
01599     }
01600 
01601     if (!mod_current_module) {
01602         return MOD_ERR_UNKNOWN;
01603     }                           /* shouldnt happen */
01604     m->core = 0;
01605     if (!m->mod_name) {
01606         m->mod_name = sstrdup(mod_current_module->name);
01607     }
01608 
01609     status = addMessage(IRCD, m, pos);
01610     if (debug) {
01611         displayMessageFromHash(m->name);
01612     }
01613     return status;
01614 }
01615 
01621 int moduleDelMessage(char *name)
01622 {
01623     Message *m;
01624     int status;
01625 
01626     if (!mod_current_module) {
01627         return MOD_ERR_UNKNOWN;
01628     }
01629     m = findMessage(IRCD, name);
01630     if (!m) {
01631         return MOD_ERR_NOEXIST;
01632     }
01633 
01634     status = delMessage(IRCD, m, mod_current_module->name);
01635     if (debug) {
01636         displayMessageFromHash(m->name);
01637     }
01638     return status;
01639 }
01640 
01648 int delMessage(MessageHash * msgTable[], Message * m, char *mod_name)
01649 {
01650     int index = 0;
01651     MessageHash *current = NULL;
01652     MessageHash *lastHash = NULL;
01653     Message *tail = NULL, *last = NULL;
01654 
01655     if (!m || !msgTable) {
01656         return MOD_ERR_PARAMS;
01657     }
01658 
01659     index = CMD_HASH(m->name);
01660 
01661     for (current = msgTable[index]; current; current = current->next) {
01662         if (stricmp(m->name, current->name) == 0) {
01663             if (!lastHash) {
01664                 tail = current->m;
01665                 if (tail->next) {
01666                     while (tail) {
01667                         if (mod_name && tail->mod_name
01668                             && (stricmp(mod_name, tail->mod_name) == 0)) {
01669                             if (last) {
01670                                 last->next = tail->next;
01671                             } else {
01672                                 current->m = tail->next;
01673                             }
01674                             return MOD_ERR_OK;
01675                         }
01676                         last = tail;
01677                         tail = tail->next;
01678                     }
01679                 } else {
01680                     msgTable[index] = current->next;
01681                     free(current->name);
01682                     return MOD_ERR_OK;
01683                 }
01684             } else {
01685                 tail = current->m;
01686                 if (tail->next) {
01687                     while (tail) {
01688                         if (mod_name && tail->mod_name
01689                             && (stricmp(mod_name, tail->mod_name) == 0)) {
01690                             if (last) {
01691                                 last->next = tail->next;
01692                             } else {
01693                                 current->m = tail->next;
01694                             }
01695                             return MOD_ERR_OK;
01696                         }
01697                         last = tail;
01698                         tail = tail->next;
01699                     }
01700                 } else {
01701                     lastHash->next = current->next;
01702                     free(current->name);
01703                     return MOD_ERR_OK;
01704                 }
01705             }
01706         }
01707         lastHash = current;
01708     }
01709     return MOD_ERR_NOEXIST;
01710 }
01711 
01717 int destroyMessage(Message * m)
01718 {
01719     if (!m) {
01720         return MOD_ERR_PARAMS;
01721     }
01722     if (m->name) {
01723         free(m->name);
01724     }
01725     m->func = NULL;
01726     if (m->mod_name) {
01727         free(m->mod_name);
01728     }
01729     m->next = NULL;
01730     return MOD_ERR_OK;
01731 }
01732 
01737 void moduleAddVersion(const char *version)
01738 {
01739     if (mod_current_module && version) {
01740         mod_current_module->version = sstrdup(version);
01741     }
01742 }
01743 
01748 void moduleAddAuthor(const char *author)
01749 {
01750     if (mod_current_module && author) {
01751         mod_current_module->author = sstrdup(author);
01752     }
01753 }
01754 
01755 /*******************************************************************************
01756  * Module Callback Functions
01757  *******************************************************************************/
01769 int moduleAddCallback(char *name, time_t when,
01770                       int (*func) (int argc, char *argv[]), int argc,
01771                       char **argv)
01772 {
01773     ModuleCallBack *new, *tmp, *prev;
01774     int i;
01775     new = malloc(sizeof(ModuleCallBack));
01776     if (!new)
01777         return MOD_ERR_MEMORY;
01778 
01779     if (name)
01780         new->name = sstrdup(name);
01781     else
01782         new->name = NULL;
01783     new->when = when;
01784     if (mod_current_module_name) {
01785         new->owner_name = sstrdup(mod_current_module_name);
01786     } else {
01787         new->owner_name = NULL;
01788     }
01789     new->func = func;
01790     new->argc = argc;
01791     new->argv = malloc(sizeof(char *) * argc);
01792     for (i = 0; i < argc; i++) {
01793         new->argv[i] = sstrdup(argv[i]);
01794     }
01795     new->next = NULL;
01796 
01797     if (moduleCallBackHead == NULL) {
01798         moduleCallBackHead = new;
01799     } else {                    /* find place in list */
01800         tmp = moduleCallBackHead;
01801         prev = tmp;
01802         if (new->when < tmp->when) {
01803             new->next = tmp;
01804             moduleCallBackHead = new;
01805         } else {
01806             while (tmp && new->when >= tmp->when) {
01807                 prev = tmp;
01808                 tmp = tmp->next;
01809             }
01810             prev->next = new;
01811             new->next = tmp;
01812         }
01813     }
01814     if (debug)
01815         alog("debug: added module CallBack: [%s] due to execute at %ld",
01816              new->name ? new->name : "?", (long int) new->when);
01817     return MOD_ERR_OK;
01818 }
01819 
01823 void moduleCallBackRun(void)
01824 {
01825     ModuleCallBack *tmp;
01826         
01827         while ((tmp = moduleCallBackHead) && (tmp->when <= time(NULL))) {
01828                 if (debug)
01829                         alog("debug: executing callback: %s", tmp->name ? tmp->name : "<unknown>");
01830                 if (tmp->func) {
01831                         mod_current_module = findModule(tmp->owner_name);
01832                         mod_current_module_name = tmp->owner_name;
01833                         tmp->func(tmp->argc, tmp->argv);
01834                         mod_current_module = NULL;
01835                         mod_current_module_name = NULL;
01836                         moduleCallBackDeleteEntry(NULL);
01837                 }
01838         }
01839 }
01840 
01845 void moduleCallBackDeleteEntry(ModuleCallBack * prev)
01846 {
01847     ModuleCallBack *tmp = NULL;
01848     int i;
01849     if (prev == NULL) {
01850         tmp = moduleCallBackHead;
01851         moduleCallBackHead = tmp->next;
01852     } else {
01853         tmp = prev->next;
01854         prev->next = tmp->next;
01855     }
01856     if (tmp->name)
01857         free(tmp->name);
01858     if (tmp->owner_name)
01859         free(tmp->owner_name);
01860     tmp->func = NULL;
01861     for (i = 0; i < tmp->argc; i++) {
01862         free(tmp->argv[i]);
01863     }
01864     tmp->argc = 0;
01865     tmp->next = NULL;
01866     free(tmp);
01867 }
01868 
01875 ModuleCallBack *moduleCallBackFindEntry(char *mod_name, boolean * found)
01876 {
01877     ModuleCallBack *prev = NULL, *current = NULL;
01878     *found = false;
01879     current = moduleCallBackHead;
01880     while (current != NULL) {
01881         if (current->owner_name
01882             && (strcmp(mod_name, current->owner_name) == 0)) {
01883             *found = true;
01884             break;
01885         } else {
01886             prev = current;
01887             current = current->next;
01888         }
01889     }
01890     if (current == moduleCallBackHead) {
01891         return NULL;
01892     } else {
01893         return prev;
01894     }
01895 }
01896 
01901 void moduleDelCallback(char *name)
01902 {
01903     ModuleCallBack *current = NULL;
01904     ModuleCallBack *prev = NULL, *tmp = NULL;
01905     int del = 0;
01906     if (!mod_current_module_name) {
01907         return;
01908     }
01909     if (!name) {
01910         return;
01911     }
01912     current = moduleCallBackHead;
01913     while (current) {
01914         if ((current->owner_name) && (current->name)) {
01915             if ((strcmp(mod_current_module_name, current->owner_name) == 0)
01916                 && (strcmp(current->name, name) == 0)) {
01917                 if (debug) {
01918                     alog("debug: removing CallBack %s for module %s", name,
01919                          mod_current_module_name);
01920                 }
01921                 tmp = current->next;    /* get a pointer to the next record, as once we delete this record, we'll lose it :) */
01922                 moduleCallBackDeleteEntry(prev);        /* delete this record */
01923                 del = 1;        /* set the record deleted flag */
01924             }
01925         }
01926         if (del == 1) {         /* if a record was deleted */
01927             current = tmp;      /* use the value we stored in temp */
01928             tmp = NULL;         /* clear it for next time */
01929             del = 0;            /* reset the flag */
01930         } else {
01931             prev = current;     /* just carry on as normal */
01932             current = current->next;
01933         }
01934     }
01935 }
01936 
01942 void moduleCallBackPrepForUnload(char *mod_name)
01943 {
01944     boolean found = false;
01945     ModuleCallBack *tmp = NULL;
01946 
01947     tmp = moduleCallBackFindEntry(mod_name, &found);
01948     while (found) {
01949         if (debug) {
01950             alog("debug: removing CallBack for module %s", mod_name);
01951         }
01952         moduleCallBackDeleteEntry(tmp);
01953         tmp = moduleCallBackFindEntry(mod_name, &found);
01954     }
01955 }
01956 
01962 char *moduleGetLastBuffer(void)
01963 {
01964     char *tmp = NULL;
01965     if (mod_current_buffer) {
01966         tmp = strchr(mod_current_buffer, ' ');
01967         if (tmp) {
01968             tmp++;
01969         }
01970     }
01971     return tmp;
01972 }
01973 
01974 /*******************************************************************************
01975  * Module HELP Functions
01976  *******************************************************************************/
01982 int moduleAddRootHelp(Command * c, int (*func) (User * u))
01983 {
01984     if (c) {
01985         c->root_help = func;
01986         return MOD_STOP;
01987     }
01988     return MOD_CONT;
01989 }
01990 
01996 int moduleAddAdminHelp(Command * c, int (*func) (User * u))
01997 {
01998     if (c) {
01999         c->admin_help = func;
02000         return MOD_STOP;
02001     }
02002     return MOD_CONT;
02003 }
02004 
02010 int moduleAddOperHelp(Command * c, int (*func) (User * u))
02011 {
02012     if (c) {
02013         c->oper_help = func;
02014         return MOD_STOP;
02015     }
02016     return MOD_CONT;
02017 }
02018 
02024 int moduleAddRegHelp(Command * c, int (*func) (User * u))
02025 {
02026     if (c) {
02027         c->regular_help = func;
02028         return MOD_STOP;
02029     }
02030     return MOD_CONT;
02031 }
02032 
02038 int moduleAddHelp(Command * c, int (*func) (User * u))
02039 {
02040     if (c) {
02041         c->all_help = func;
02042         return MOD_STOP;
02043     }
02044     return MOD_CONT;
02045 }
02046 
02052 void moduleSetNickHelp(void (*func) (User * u))
02053 {
02054     if (mod_current_module) {
02055         mod_current_module->nickHelp = func;
02056     }
02057 }
02058 
02064 void moduleSetChanHelp(void (*func) (User * u))
02065 {
02066     if (mod_current_module) {
02067         mod_current_module->chanHelp = func;
02068     }
02069 }
02070 
02076 void moduleSetMemoHelp(void (*func) (User * u))
02077 {
02078     if (mod_current_module) {
02079         mod_current_module->memoHelp = func;
02080     }
02081 }
02082 
02088 void moduleSetBotHelp(void (*func) (User * u))
02089 {
02090     if (mod_current_module) {
02091         mod_current_module->botHelp = func;
02092     }
02093 }
02094 
02100 void moduleSetOperHelp(void (*func) (User * u))
02101 {
02102     if (mod_current_module) {
02103         mod_current_module->operHelp = func;
02104     }
02105 }
02106 
02112 void moduleSetHostHelp(void (*func) (User * u))
02113 {
02114     if (mod_current_module) {
02115         mod_current_module->hostHelp = func;
02116     }
02117 }
02118 
02124 void moduleSetHelpHelp(void (*func) (User * u))
02125 {
02126     if (mod_current_module) {
02127         mod_current_module->helpHelp = func;
02128     }
02129 }
02130 
02136 void moduleDisplayHelp(int service, User * u)
02137 {
02138 #ifdef USE_MODULES
02139     int idx;
02140     ModuleHash *current = NULL;
02141         Module *calling_module = mod_current_module;
02142         char *calling_module_name = mod_current_module_name;
02143 
02144     for (idx = 0; idx != MAX_CMD_HASH; idx++) {
02145         for (current = MODULE_HASH[idx]; current; current = current->next) {
02146                         mod_current_module_name = current->name;
02147                         mod_current_module = current->m;
02148                         
02149             if ((service == 1) && current->m->nickHelp) {
02150                 current->m->nickHelp(u);
02151             } else if ((service == 2) && current->m->chanHelp) {
02152                 current->m->chanHelp(u);
02153             } else if ((service == 3) && current->m->memoHelp) {
02154                 current->m->memoHelp(u);
02155             } else if ((service == 4) && current->m->botHelp) {
02156                 current->m->botHelp(u);
02157             } else if ((service == 5) && current->m->operHelp) {
02158                 current->m->operHelp(u);
02159             } else if ((service == 6) && current->m->hostHelp) {
02160                 current->m->hostHelp(u);
02161             } else if ((service == 7) && current->m->helpHelp) {
02162                 current->m->helpHelp(u);
02163             }
02164         }
02165     }
02166         
02167         mod_current_module = calling_module;
02168         mod_current_module_name = calling_module_name;
02169 #endif
02170 }
02171 
02179 int moduleDataDebug(ModuleData ** md)
02180 {
02181     ModuleData *current = NULL;
02182     alog("Dumping module data....");
02183     for (current = *md; current; current = current->next) {
02184         alog("Module: [%s]", current->moduleName);
02185         alog(" Key [%s]\tValue [%s]", current->key, current->value);
02186     }
02187     alog("End of module data dump");
02188     return 0;
02189 }
02190 
02199 int moduleAddData(ModuleData ** md, char *key, char *value)
02200 {
02201     ModuleData *newData = NULL;
02202 
02203     if (mod_current_module_name == NULL) {
02204         alog("moduleAddData() called with mod_current_module_name being NULL");
02205         if (debug)
02206             do_backtrace(0);
02207     }
02208 
02209     if (!key || !value) {
02210         alog("A module (%s) tried to use ModuleAddData() with one or more NULL arguments... returning", mod_current_module_name);
02211         return MOD_ERR_PARAMS;
02212     }
02213 
02214     moduleDelData(md, key);     /* Remove any existing module data for this module with the same key */
02215 
02216     newData = malloc(sizeof(ModuleData));
02217     if (!newData) {
02218         return MOD_ERR_MEMORY;
02219     }
02220 
02221     newData->moduleName = sstrdup(mod_current_module_name);
02222     newData->key = sstrdup(key);
02223     newData->value = sstrdup(value);
02224     newData->next = *md;
02225     *md = newData;
02226 
02227     if (debug) {
02228         moduleDataDebug(md);
02229     }
02230     return MOD_ERR_OK;
02231 }
02232 
02240 char *moduleGetData(ModuleData ** md, char *key)
02241 {
02242     /* See comment in moduleAddData... -GD */
02243     char *mod_name = sstrdup(mod_current_module_name);
02244     ModuleData *current = *md;
02245 
02246     if (mod_current_module_name == NULL) {
02247         alog("moduleGetData() called with mod_current_module_name being NULL");
02248         if (debug)
02249             do_backtrace(0);
02250     }
02251 
02252     if (debug > 1) {
02253         alog("debug: moduleGetData %p : key %s", (void *) md, key);
02254         alog("debug: Current Module %s", mod_name);
02255     }
02256 
02257     while (current) {
02258         if ((stricmp(current->moduleName, mod_name) == 0)
02259             && (stricmp(current->key, key) == 0)) {
02260             free(mod_name);
02261             return sstrdup(current->value);
02262         }
02263         current = current->next;
02264     }
02265     free(mod_name);
02266     return NULL;
02267 }
02268 
02275 void moduleDelData(ModuleData ** md, char *key)
02276 {
02277     /* See comment in moduleAddData... -GD */
02278     char *mod_name = sstrdup(mod_current_module_name);
02279     ModuleData *current = *md;
02280     ModuleData *prev = NULL;
02281     ModuleData *next = NULL;
02282 
02283     if (mod_current_module_name == NULL) {
02284         alog("moduleDelData() called with mod_current_module_name being NULL");
02285         if (debug)
02286             do_backtrace(0);
02287     }
02288 
02289     if (key) {
02290         while (current) {
02291             next = current->next;
02292             if ((stricmp(current->moduleName, mod_name) == 0)
02293                 && (stricmp(current->key, key) == 0)) {
02294                 if (prev) {
02295                     prev->next = current->next;
02296                 } else {
02297                     *md = current->next;
02298                 }
02299                 free(current->moduleName);
02300                 free(current->key);
02301                 free(current->value);
02302                 current->next = NULL;
02303                 free(current);
02304             } else {
02305                 prev = current;
02306             }
02307             current = next;
02308         }
02309     }
02310     free(mod_name);
02311 }
02312 
02319 void moduleDelAllData(ModuleData ** md)
02320 {
02321     /* See comment in moduleAddData... -GD */
02322     char *mod_name = sstrdup(mod_current_module_name);
02323     ModuleData *current = *md;
02324     ModuleData *prev = NULL;
02325     ModuleData *next = NULL;
02326 
02327     if (mod_current_module_name == NULL) {
02328         alog("moduleDelAllData() called with mod_current_module_name being NULL");
02329         if (debug)
02330             do_backtrace(0);
02331     }
02332 
02333     while (current) {
02334         next = current->next;
02335         if ((stricmp(current->moduleName, mod_name) == 0)) {
02336             if (prev) {
02337                 prev->next = current->next;
02338             } else {
02339                 *md = current->next;
02340             }
02341             free(current->moduleName);
02342             free(current->key);
02343             free(current->value);
02344             current->next = NULL;
02345             free(current);
02346         } else {
02347             prev = current;
02348         }
02349         current = next;
02350     }
02351     free(mod_name);
02352 }
02353 
02358 void moduleDelAllDataMod(Module * m)
02359 {
02360     boolean freeme = false;
02361     int i, j;
02362     User *user;
02363     NickAlias *na;
02364     NickCore *nc;
02365     ChannelInfo *ci;
02366 
02367     if (!mod_current_module_name) {
02368         mod_current_module_name = sstrdup(m->name);
02369         freeme = true;
02370     }
02371 
02372     for (i = 0; i < 1024; i++) {
02373         /* Remove the users */
02374         for (user = userlist[i]; user; user = user->next) {
02375             moduleDelAllData(&user->moduleData);
02376         }
02377         /* Remove the nick Cores */
02378         for (nc = nclists[i]; nc; nc = nc->next) {
02379             moduleDelAllData(&nc->moduleData);
02380             /* Remove any memo data for this nick core */
02381             for (j = 0; j < nc->memos.memocount; j++) {
02382                 moduleCleanStruct(&nc->memos.memos[j].moduleData);
02383             }
02384         }
02385         /* Remove the nick Aliases */
02386         for (na = nalists[i]; na; na = na->next) {
02387             moduleDelAllData(&na->moduleData);
02388         }
02389     }
02390 
02391     for (i = 0; i < 256; i++) {
02392         /* Remove any chan info data */
02393         for (ci = chanlists[i]; ci; ci = ci->next) {
02394             moduleDelAllData(&ci->moduleData);
02395             /* Remove any memo data for this nick core */
02396             for (j = 0; j < ci->memos.memocount; j++) {
02397                 moduleCleanStruct(&ci->memos.memos[j].moduleData);
02398             }
02399         }
02400     }
02401 
02402     if (freeme) {
02403         free(mod_current_module_name);
02404         mod_current_module_name = NULL;
02405     }
02406 }
02407 
02413 void moduleCleanStruct(ModuleData ** moduleData)
02414 {
02415     ModuleData *current = *moduleData;
02416     ModuleData *next = NULL;
02417 
02418     while (current) {
02419         next = current->next;
02420         free(current->moduleName);
02421         free(current->key);
02422         free(current->value);
02423         current->next = NULL;
02424         free(current);
02425         current = next;
02426     }
02427     *moduleData = NULL;
02428 }
02429 
02439 boolean moduleMinVersion(int major, int minor, int patch, int build)
02440 {
02441     boolean ret = false;
02442     if (VERSION_MAJOR > major) {        /* Def. new */
02443         ret = true;
02444     } else if (VERSION_MAJOR == major) {        /* Might be newer */
02445         if (minor == -1) {
02446             return true;
02447         }                       /* They dont care about minor */
02448         if (VERSION_MINOR > minor) {    /* Def. newer */
02449             ret = true;
02450         } else if (VERSION_MINOR == minor) {    /* Might be newer */
02451             if (patch == -1) {
02452                 return true;
02453             }                   /* They dont care about patch */
02454             if (VERSION_PATCH > patch) {
02455                 ret = true;
02456             } else if (VERSION_PATCH == patch) {
02457                 if (build == -1) {
02458                     return true;
02459                 }               /* They dont care about build */
02460                 if (VERSION_BUILD >= build) {
02461                     ret = true;
02462                 }
02463             }
02464         }
02465     }
02466     return ret;
02467 }
02468 
02469 #ifdef _WIN32
02470 const char *ano_moderr(void)
02471 {
02472     static char errbuf[513];
02473     DWORD err = GetLastError();
02474     if (err == 0)
02475         return NULL;
02476     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
02477                   FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, errbuf, 512,
02478                   NULL);
02479     return errbuf;
02480 }
02481 #endif
02482 
02486 void updateProtectDetails(char *level_info_protect_word,
02487                           char *level_info_protectme_word,
02488                           char *fant_protect_add, char *fant_protect_del,
02489                           char *level_protect_word, char *protect_set_mode,
02490                           char *protect_unset_mode)
02491 {
02492     int i = 0;
02493     CSModeUtil ptr;
02494     LevelInfo l_ptr;
02495 
02496     ptr = csmodeutils[i];
02497     while (ptr.name) {
02498         if (strcmp(ptr.name, "PROTECT") == 0) {
02499             csmodeutils[i].bsname = sstrdup(fant_protect_add);
02500             csmodeutils[i].mode = sstrdup(protect_set_mode);
02501         } else if (strcmp(ptr.name, "DEPROTECT") == 0) {
02502             csmodeutils[i].bsname = sstrdup(fant_protect_del);
02503             csmodeutils[i].mode = sstrdup(protect_unset_mode);
02504         }
02505         ptr = csmodeutils[++i];
02506     }
02507 
02508     i = 0;
02509     l_ptr = levelinfo[i];
02510     while (l_ptr.what != -1) {
02511         if (l_ptr.what == CA_PROTECT) {
02512             levelinfo[i].name = sstrdup(level_info_protect_word);
02513         } else if (l_ptr.what == CA_PROTECTME) {
02514             levelinfo[i].name = sstrdup(level_info_protectme_word);
02515         } else if (l_ptr.what == CA_AUTOPROTECT) {
02516             levelinfo[i].name = sstrdup(level_protect_word);
02517         }
02518         l_ptr = levelinfo[++i];
02519     }
02520 }
02521 
02527 int moduleGetConfigDirective(Directive * d)
02528 {
02529     FILE *config;
02530     char *dir = NULL;
02531     char buf[1024];
02532         char *directive;
02533     int linenum = 0;
02534     int ac = 0;
02535     char *av[MAXPARAMS];
02536         char *str = NULL;
02537     char *s = NULL;
02538         char *t = NULL;
02539     int retval = 1;
02540 
02541     config = fopen(SERVICES_CONF, "r");
02542     if (!config) {
02543         alog("Can't open %s", SERVICES_CONF);
02544         return 0;
02545     }
02546     while (fgets(buf, sizeof(buf), config)) {
02547         linenum++;
02548         if (*buf == '#' || *buf == '\r' || *buf == '\n') {
02549             continue;
02550                 }
02551         dir = myStrGetOnlyToken(buf, '\t', 0);
02552         if (dir) {
02553             str = myStrGetTokenRemainder(buf, '\t', 1);
02554         } else {
02555             dir = myStrGetOnlyToken(buf, ' ', 0);
02556             if (dir || (dir = myStrGetOnlyToken(buf, '\n', 0))) {
02557                 str = myStrGetTokenRemainder(buf, ' ', 1);
02558             } else {
02559                 continue;
02560             }
02561         }
02562                 if (dir) {
02563                         directive = normalizeBuffer(dir);
02564                 } else {
02565                         continue;
02566                 }       
02567 
02568         if (stricmp(directive, d->name) == 0) {
02569             if (str) {
02570                                 s = str;
02571                 while (isspace(*s))
02572                     s++;
02573                 while (*s) {
02574                     if (ac >= MAXPARAMS) {
02575                         alog("module error: too many config. params");
02576                         break;
02577                     }
02578                     t = s;
02579                     if (*s == '"') {
02580                         t++;
02581                         s++;
02582                         while (*s && *s != '"') {
02583                             if (*s == '\\' && s[1] != 0)
02584                                 s++;
02585                             s++;
02586                         }
02587                         if (!*s)
02588                             alog("module error: Warning: unterminated double-quoted string");
02589                         else
02590                             *s++ = 0;
02591                     } else {
02592                         s += strcspn(s, " \t\r\n");
02593                         if (*s)
02594                             *s++ = 0;
02595                     }
02596                     av[ac++] = t;
02597                     while (isspace(*s))
02598                         s++;
02599                 }
02600             }
02601             retval = parse_directive(d, directive, ac, av, linenum, 0, s);
02602         }
02603                 if (directive) {
02604                         free(directive);
02605                 }
02606     }
02607     if (dir)
02608         free(dir);
02609     if (str)
02610        free(str);
02611     fclose(config);
02612     return retval;
02613 }
02614 
02621 void moduleInsertLanguage(int langNumber, int ac, char **av)
02622 {
02623     int i;
02624 
02625     if ((mod_current_module_name) && (!mod_current_module || strcmp(mod_current_module_name, mod_current_module->name))) {
02626         mod_current_module = findModule(mod_current_module_name);
02627     }
02628         
02629         if (debug)
02630                 alog("debug: %s Adding %d texts for language %d", mod_current_module->name, ac, langNumber);
02631         
02632     if (mod_current_module->lang[langNumber].argc > 0) {
02633         moduleDeleteLanguage(langNumber);
02634     }
02635 
02636     mod_current_module->lang[langNumber].argc = ac;
02637     mod_current_module->lang[langNumber].argv =
02638         malloc(sizeof(char *) * ac);
02639     for (i = 0; i < ac; i++) {
02640         mod_current_module->lang[langNumber].argv[i] = sstrdup(av[i]);
02641     }
02642 }
02643 
02651 void moduleNoticeLang(char *source, User * u, int number, ...)
02652 {
02653     va_list va;
02654     char buffer[4096], outbuf[4096];
02655     char *fmt = NULL;
02656     int lang = NSDefLanguage;
02657     char *s, *t, *buf;
02658 
02659     if ((mod_current_module_name) && (!mod_current_module || strcmp(mod_current_module_name, mod_current_module->name))) {
02660         mod_current_module = findModule(mod_current_module_name);
02661     }
02662         
02663     /* Find the users lang, and use it if we can */
02664     if (u && u->na && u->na->nc) {
02665         lang = u->na->nc->language;
02666     }
02667 
02668     /* If the users lang isnt supported, drop back to English */
02669     if (mod_current_module->lang[lang].argc == 0) {
02670         lang = LANG_EN_US;
02671     }
02672 
02673     /* If the requested lang string exists for the language */
02674     if (mod_current_module->lang[lang].argc > number) {
02675         fmt = mod_current_module->lang[lang].argv[number];
02676 
02677         buf = sstrdup(fmt);
02678         va_start(va, number);
02679         vsnprintf(buffer, 4095, buf, va);
02680         va_end(va);
02681         s = buffer;
02682         while (*s) {
02683             t = s;
02684             s += strcspn(s, "\n");
02685             if (*s)
02686                 *s++ = '\0';
02687             strscpy(outbuf, t, sizeof(outbuf));
02688             notice_user(source, u, "%s", outbuf);
02689         }
02690                 free(buf);
02691     } else {
02692         alog("%s: INVALID language string call, language: [%d], String [%d]", mod_current_module->name, lang, number);
02693     }
02694 }
02695 
02702 char *moduleGetLangString(User * u, int number)
02703 {
02704     int lang = NSDefLanguage;
02705 
02706     if ((mod_current_module_name) && (!mod_current_module || strcmp(mod_current_module_name, mod_current_module->name)))
02707         mod_current_module = findModule(mod_current_module_name);
02708         
02709     /* Find the users lang, and use it if we can */
02710     if (u && u->na && u->na->nc)
02711         lang = u->na->nc->language;
02712 
02713     /* If the users lang isnt supported, drop back to English */
02714     if (mod_current_module->lang[lang].argc == 0)
02715         lang = LANG_EN_US;
02716 
02717     /* If the requested lang string exists for the language */
02718     if (mod_current_module->lang[lang].argc > number) {
02719         return mod_current_module->lang[lang].argv[number];
02720         /* Return an empty string otherwise, because we might be used without
02721          * the return value being checked. If we would return NULL, bad things
02722          * would happen!
02723          */
02724         } else {
02725         alog("%s: INVALID language string call, language: [%d], String [%d]", mod_current_module->name, lang, number);
02726                 return "";
02727     }
02728 }
02729 
02734 void moduleDeleteLanguage(int langNumber)
02735 {
02736     int idx = 0;
02737     if ((mod_current_module_name) && (!mod_current_module || strcmp(mod_current_module_name, mod_current_module->name))) {
02738         mod_current_module = findModule(mod_current_module_name);
02739     }
02740     for (idx = 0; idx > mod_current_module->lang[langNumber].argc; idx++) {
02741         free(mod_current_module->lang[langNumber].argv[idx]);
02742     }
02743     mod_current_module->lang[langNumber].argc = 0;
02744 }
02745 
02752 void queueModuleOperation(Module *m, ModuleOperation op, User *u)
02753 {
02754         ModuleQueue *qm;
02755         
02756         qm = scalloc(1, sizeof(ModuleQueue));
02757         qm->m = m;
02758         qm->op = op;
02759         qm->u = u;
02760         qm->next = mod_operation_queue;
02761         mod_operation_queue = qm;
02762 }
02763 
02770 int queueModuleLoad(char *name, User *u)
02771 {
02772         Module *m;
02773         
02774         if (!name || !u)
02775                 return 0;
02776         
02777         if (findModule(name))
02778                 return 0;
02779         m = createModule(name);
02780         queueModuleOperation(m, MOD_OP_LOAD, u);
02781         
02782         return 1;
02783 }
02784 
02791 int queueModuleUnload(char *name, User *u)
02792 {
02793         Module *m;
02794         
02795         if (!name || !u)
02796                 return 0;
02797         
02798         m = findModule(name);
02799         if (!m)
02800                 return 0;
02801         queueModuleOperation(m, MOD_OP_UNLOAD, u);
02802         
02803         return 1;
02804 }
02805 
02809 void handleModuleOperationQueue(void)
02810 {
02811         ModuleQueue *next;
02812         int status;
02813         
02814         if (!mod_operation_queue)
02815                 return;
02816         
02817         while (mod_operation_queue) {
02818                 next = mod_operation_queue->next;
02819                 
02820                 mod_current_module = mod_operation_queue->m;
02821                 mod_current_user = mod_operation_queue->u;
02822 
02823                 if (mod_operation_queue->op == MOD_OP_LOAD) {
02824                         alog("Trying to load module [%s]", mod_operation_queue->m->name);
02825                         status = loadModule(mod_operation_queue->m, mod_operation_queue->u);
02826                         alog("Module loading status: %d (%s)", status, ModuleGetErrStr(status));
02827                         if (status != MOD_ERR_OK) {
02828                                 if(mod_current_user) {
02829                                    notice_lang(s_OperServ, mod_current_user, OPER_MODULE_LOAD_FAIL,mod_operation_queue->m->name);
02830                                 }
02831                                 destroyModule(mod_operation_queue->m);
02832                         }
02833                 } else if (mod_operation_queue->op == MOD_OP_UNLOAD) {
02834                         alog("Trying to unload module [%s]", mod_operation_queue->m->name);
02835                         status = unloadModule(mod_operation_queue->m, mod_operation_queue->u);
02836                         alog("Module unloading status: %d (%s)", status, ModuleGetErrStr(status));
02837                 }
02838                 
02839                 /* Remove the ModuleQueue from memory */
02840                 free(mod_operation_queue);
02841                 
02842                 mod_operation_queue = next;
02843         }
02844         
02845         mod_current_module = NULL;
02846         mod_current_user = NULL;
02847 }
02848 
02849 void ModuleRunTimeDirCleanUp(void)
02850 {
02851 #ifndef _WIN32
02852     DIR *dirp;
02853     struct dirent *dp;
02854 #else
02855     BOOL fFinished;
02856     HANDLE hList;
02857     TCHAR szDir[MAX_PATH + 1];
02858     TCHAR szSubDir[MAX_PATH + 1];
02859     WIN32_FIND_DATA FileData;
02860     char buffer[_MAX_PATH];
02861 #endif
02862     char dirbuf[BUFSIZE];
02863     char filebuf[BUFSIZE];
02864 
02865 
02866 #ifndef _WIN32
02867     snprintf(dirbuf, BUFSIZE, "%s/modules/runtime", services_dir);
02868 #else
02869     snprintf(dirbuf, BUFSIZE, "\\%s", "modules/runtime");
02870 #endif
02871 
02872         if (debug) {
02873                 alog("debug: Cleaning out Module run time directory (%s) - this may take a moment please wait", dirbuf);
02874         }
02875 
02876 #ifndef _WIN32
02877     if ((dirp = opendir(dirbuf)) == NULL) {
02878                 if (debug) {
02879                 alog("debug: cannot open directory (%s)", dirbuf);
02880                 }
02881         return;
02882     }
02883     while ((dp = readdir(dirp)) != NULL) {
02884         if (dp->d_ino == 0) {
02885             continue;
02886         }
02887         if (!stricmp(dp->d_name, ".") || !stricmp(dp->d_name, "..")) {
02888             continue;
02889         }
02890             snprintf(filebuf, BUFSIZE, "%s/%s", dirbuf, dp->d_name);
02891                 unlink(filebuf);
02892     }
02893     closedir(dirp);
02894 #else
02895     /* Get the current working directory: */
02896     if (_getcwd(buffer, _MAX_PATH) == NULL) {
02897                 if (debug) {
02898                 alog("debug: Unable to set Current working directory");
02899                 }
02900     }
02901     snprintf(szDir, sizeof(szDir), "%s\\%s\\*", buffer, dirbuf);
02902 
02903     hList = FindFirstFile(szDir, &FileData);
02904     if (hList != INVALID_HANDLE_VALUE) {
02905         fFinished = FALSE;
02906         while (!fFinished) {
02907             if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
02908                             snprintf(filebuf, BUFSIZE, "%s/%s", dirbuf, FileData.cFileName);
02909                                 DeleteFile(filebuf);
02910             }
02911             if (!FindNextFile(hList, &FileData)) {
02912                 if (GetLastError() == ERROR_NO_MORE_FILES) {
02913                     fFinished = TRUE;
02914                 }
02915             }
02916         }
02917     } else {
02918                 if (debug) {
02919                 alog("debug: Invalid File Handle. GetLastError reports %d\n", GetLastError());
02920                 }
02921     }
02922     FindClose(hList);
02923 #endif
02924         if (debug) {
02925                 alog("debug: Module run time directory has been cleaned out");
02926         }
02927 }
02928 
02929 /* EOF */