unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

modules.c (37877B)

      1 /************************************************************************
      2  *   UnrealIRCd - Unreal Internet Relay Chat Daemon - src/modules.c
      3  *   (C) 2001 Carsten Munk (Techie/Stskeeps) <stskeeps@tspre.org>
      4  *
      5  *   See file AUTHORS in IRC package for additional names of
      6  *   the programmers. 
      7  *
      8  *   This program is free software; you can redistribute it and/or modify
      9  *   it under the terms of the GNU General Public License as published by
     10  *   the Free Software Foundation; either version 1, or (at your option)
     11  *   any later version.
     12  *
     13  *   This program is distributed in the hope that it will be useful,
     14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *   GNU General Public License for more details.
     17  *
     18  *   You should have received a copy of the GNU General Public License
     19  *   along with this program; if not, write to the Free Software
     20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     21  */
     22 
     23 #define UNREALCORE
     24 #include "unrealircd.h"
     25 #ifdef _WIN32
     26 #define RTLD_NOW 0
     27 #elif defined(HPUX)
     28 #include <dl.h>
     29 #define RTLD_NOW BIND_IMMEDIATE
     30 #else
     31 #include <dlfcn.h>
     32 #endif
     33 #ifndef RTLD_NOW
     34 #define RTLD_NOW RTLD_LAZY
     35 #endif
     36 #include "modversion.h"
     37 
     38 Hook	   	*Hooks[MAXHOOKTYPES];
     39 Hooktype	Hooktypes[MAXCUSTOMHOOKS];
     40 Callback	*Callbacks[MAXCALLBACKS];	/* Callback objects for modules, used for rehashing etc (can be multiple) */
     41 Callback	*RCallbacks[MAXCALLBACKS];	/* 'Real' callback function, used for callback function calls */
     42 MODVAR Module          *Modules = NULL;
     43 MODVAR Versionflag     *Versionflags = NULL;
     44 
     45 Module *Module_make(ModuleHeader *header, 
     46 #ifdef _WIN32
     47        HMODULE mod
     48 #else
     49        void *mod
     50 #endif
     51        );
     52 
     53 #ifdef UNDERSCORE
     54 /* dlsym for OpenBSD */
     55 void *obsd_dlsym(void *handle, const char *symbol)
     56 {
     57 	size_t buflen = strlen(symbol) + 2;
     58 	char *obsdsymbol = safe_alloc(buflen);
     59 	void *symaddr = NULL;
     60 
     61 	if (obsdsymbol)
     62 	{
     63 		ircsnprintf(obsdsymbol, buflen, "_%s", symbol);
     64 		symaddr = dlsym(handle, obsdsymbol);
     65 		safe_free(obsdsymbol);
     66 	}
     67 
     68 	return symaddr;
     69 }
     70 #endif
     71 
     72 void deletetmp(const char *path)
     73 {
     74 #ifndef NOREMOVETMP
     75 	if (!loop.config_test)
     76 		remove(path);
     77 #endif
     78 }
     79 
     80 void DeleteTempModules(void)
     81 {
     82 	char tempbuf[PATH_MAX+1];
     83 #ifndef _WIN32
     84 	DIR *fd = opendir(TMPDIR);
     85 	struct dirent *dir;
     86 
     87 	if (!fd) /* Ouch.. this is NOT good!! */
     88 	{
     89 		config_error("Unable to open temp directory %s: %s, please create one with the appropriate permissions",
     90 			TMPDIR, strerror(errno));
     91 		if (!loop.booted)
     92 			exit(7);
     93 		return; 
     94 	}
     95 
     96 	while ((dir = readdir(fd)))
     97 	{
     98 		char *fname = dir->d_name;
     99 		if (!strcmp(fname, ".") || !strcmp(fname, ".."))
    100 			continue;
    101 		if (!strstr(fname, ".so") && !strstr(fname, ".conf") &&
    102 		    (strstr(fname, "core") || strstr(fname, "unrealircd_asan.")))
    103 			continue; /* core dump or ASan log */
    104 		ircsnprintf(tempbuf, sizeof(tempbuf), "%s/%s", TMPDIR, fname);
    105 		deletetmp(tempbuf);
    106 	}
    107 	closedir(fd);
    108 #else
    109 	WIN32_FIND_DATA hData;
    110 	HANDLE hFile;
    111 	
    112 	snprintf(tempbuf, sizeof(tempbuf), "%s/*", TMPDIR);
    113 	
    114 	hFile = FindFirstFile(tempbuf, &hData);
    115 	if (hFile != INVALID_HANDLE_VALUE)
    116 	{
    117 		if (strcmp(hData.cFileName, ".") || strcmp(hData.cFileName, ".."))
    118 		{
    119 			ircsnprintf(tempbuf, sizeof(tempbuf), "%s/%s", TMPDIR, hData.cFileName);
    120 			deletetmp(tempbuf);
    121 		}
    122 	}
    123 	while (FindNextFile(hFile, &hData))
    124 	{
    125 		if (!strcmp(hData.cFileName, ".") || !strcmp(hData.cFileName, ".."))
    126 			continue;
    127 		ircsnprintf(tempbuf, sizeof(tempbuf), "%s/%s", TMPDIR, hData.cFileName);
    128 		deletetmp(tempbuf);
    129 	}
    130 	FindClose(hFile);
    131 #endif	
    132 }
    133 
    134 Module *Module_Find(const char *name)
    135 {
    136 	Module *p;
    137 	
    138 	for (p = Modules; p; p = p->next)
    139 	{
    140 		if (!(p->options & MOD_OPT_PERM) &&
    141 		    (!(p->flags & MODFLAG_TESTING) || (p->flags & MODFLAG_DELAYED)))
    142 			continue;
    143 		if (!strcmp(p->header->name, name))
    144 		{
    145 			return (p);
    146 		}
    147 	}
    148 	return NULL;
    149 	
    150 }
    151 
    152 int parse_modsys_version(const char *version)
    153 {
    154 	if (!strcmp(version, "unrealircd-6"))
    155 		return 0x600000;
    156 	return 0;
    157 }
    158 
    159 void make_compiler_string(char *buf, size_t buflen, unsigned int ver)
    160 {
    161 	unsigned int maj, min, plevel;
    162 
    163 	if (ver == 0)
    164 	{
    165 		strlcpy(buf, "0", buflen);
    166 		return;
    167 	}
    168 	
    169 	maj = ver >> 16;
    170 	min = (ver >> 8) & 0xff;
    171 	plevel = ver & 0xff;
    172 	
    173 	if (plevel == 0)
    174 		snprintf(buf, buflen, "%d.%d", maj, min);
    175 	else
    176 		snprintf(buf, buflen, "%d.%d.%d", maj, min, plevel);
    177 }
    178 
    179 /** Transform a loadmodule path like "third/la" to
    180  * something like "/home/xyz/unrealircd/modules/third/la.so
    181  * (and other tricks)
    182  */
    183 const char *Module_TransformPath(const char *path_)
    184 {
    185 	static char path[1024];
    186 
    187 	/* Prefix the module path with MODULESDIR, unless it's an absolute path
    188 	 * (we check for "/", "\" and things like "C:" to detect absolute paths).
    189 	 */
    190 	if ((*path_ != '/') && (*path_ != '\\') && !(*path_ && (path_[1] == ':')))
    191 	{
    192 		snprintf(path, sizeof(path), "%s/%s", MODULESDIR, path_);
    193 	} else {
    194 		strlcpy(path, path_, sizeof(path));
    195 	}
    196 
    197 	/* Auto-suffix .dll / .so */
    198 	if (!strstr(path, MODULE_SUFFIX))
    199 		strlcat(path, MODULE_SUFFIX, sizeof(path));
    200 
    201 	return path;
    202 }
    203 
    204 /** This function is the inverse of Module_TransformPath() */
    205 const char *Module_GetRelPath(const char *fullpath)
    206 {
    207 	static char buf[512];
    208 	char prefix[512];
    209 	const char *without_prefix = fullpath;
    210 	char *s;
    211 
    212 	/* Strip the prefix */
    213 	snprintf(prefix, sizeof(prefix), "%s/", MODULESDIR);
    214 	if (!strncasecmp(fullpath, prefix, strlen(prefix)))
    215 		without_prefix += strlen(prefix);
    216 	strlcpy(buf, without_prefix, sizeof(buf));
    217 
    218 	/* Strip the suffix */
    219 	s = strstr(buf, MODULE_SUFFIX);
    220 	if (s)
    221 		*s = '\0';
    222 
    223 	return buf;
    224 }
    225 
    226 /** Validate a modules' ModuleHeader.
    227  * @returns Error message is returned, or NULL if everything is OK.
    228  */
    229 static const char *validate_mod_header(const char *relpath, ModuleHeader *mod_header)
    230 {
    231 	char *p;
    232 	static char buf[256];
    233 
    234 	if (!mod_header->name || !mod_header->version || !mod_header->author || !mod_header->description)
    235 		return "NULL values encountered in Mod_Header struct members";
    236 
    237 	/* Validate module name */
    238 	if (strcmp(mod_header->name, relpath))
    239 	{
    240 		snprintf(buf, sizeof(buf), "Module has path '%s' but uses name '%s' in MOD_HEADER. These should be the same!",
    241 			relpath, mod_header->name);
    242 		return buf;
    243 	}
    244 	/* This too, just to be sure.. we never ever want other characters
    245 	 * than these, since it may break the S2S SMOD command or /MODULE
    246 	 * output etc.
    247 	 */
    248 	for (p = mod_header->name; *p; p++)
    249 		if (!isalnum(*p) && !strchr("._-/", *p))
    250 			return "ModuleHeader.name contains illegal characters (must be: a-zA-Z0-9._-/)";
    251 
    252 	/* Validate version, even more strict */
    253 	if (!isdigit(mod_header->version[0]))
    254 		return "ModuleHeader.version must start with a digit";
    255 	for (p = mod_header->version; *p; p++)
    256 		if (!isalnum(*p) && !strchr("._-", *p))
    257 			return "ModuleHeader.version contains illegal characters (must be: a-zA-Z0-9._-)";
    258 
    259 	/* Author and description are not checked, has no constraints */
    260 
    261 	return NULL; /* SUCCESS */
    262 }
    263 
    264 int module_already_in_testing(const char *relpath)
    265 {
    266 	Module *m;
    267 	for (m = Modules; m; m = m->next)
    268 	{
    269 		if (!(m->options & MOD_OPT_PERM) &&
    270 		    (!(m->flags & MODFLAG_TESTING) || (m->flags & MODFLAG_DELAYED)))
    271 			continue;
    272 		if (!strcmp(m->relpath, relpath))
    273 			return 1;
    274 	}
    275 	return 0;
    276 }
    277 
    278 /*
    279  * Returns an error if insucessful .. yes NULL is OK! 
    280 */
    281 const char *Module_Create(const char *path_)
    282 {
    283 #ifdef _WIN32
    284 	HMODULE 	Mod;
    285 #else /* _WIN32 */
    286 	void   		*Mod;
    287 #endif /* _WIN32 */
    288 	int		(*Mod_Test)();
    289 	int		(*Mod_Init)();
    290 	int             (*Mod_Load)();
    291 	int             (*Mod_Unload)();
    292 	char    *Mod_Version;
    293 	unsigned int *compiler_version;
    294 	static char 	errorbuf[1024];
    295 	const char	*path, *relpath, *tmppath;
    296 	ModuleHeader    *mod_header = NULL;
    297 	int		ret = 0;
    298 	const char	*reterr;
    299 	Module          *mod = NULL, **Mod_Handle = NULL;
    300 	char *expectedmodversion = our_mod_version;
    301 	unsigned int expectedcompilerversion = our_compiler_version;
    302 	long modsys_ver = 0;
    303 
    304 	path = Module_TransformPath(path_);
    305 
    306 	relpath = Module_GetRelPath(path);
    307 	if (module_already_in_testing(relpath))
    308 		return 0;
    309 
    310 	if (!file_exists(path))
    311 	{
    312 		snprintf(errorbuf, sizeof(errorbuf), "Cannot open module file: %s", strerror(errno));
    313 		return errorbuf;
    314 	}
    315 
    316 	if (loop.config_test)
    317 	{
    318 		/* For './unrealircd configtest' we don't have to do any copying and shit */
    319 		tmppath = path;
    320 	} else {
    321 		tmppath = unreal_mktemp(TMPDIR, unreal_getmodfilename(path));
    322 		if (!tmppath)
    323 			return "Unable to create temporary file!";
    324 
    325 		/* We have to copy the module, because otherwise the dynamic loader
    326 		 * will not load the new .so if we rehash while holding the original .so
    327 		 * We used to hardlink here instead of copy, but then OpenBSD and Linux
    328 		 * got smart and detected that, so now we always copy.
    329 		 */
    330 		ret = unreal_copyfileex(path, tmppath, 0);
    331 		if (!ret)
    332 		{
    333 			snprintf(errorbuf, sizeof(errorbuf), "Failed to copy module file.");
    334 			return errorbuf;
    335 		}
    336 	}
    337 
    338 	if ((Mod = irc_dlopen(tmppath, RTLD_NOW)))
    339 	{
    340 		/* We have engaged the borg cube. Scan for lifesigns. */
    341 		irc_dlsym(Mod, "Mod_Version", Mod_Version);
    342 		if (Mod_Version && strcmp(Mod_Version, expectedmodversion))
    343 		{
    344 			snprintf(errorbuf, sizeof(errorbuf),
    345 			         "Module was compiled for '%s', we were configured for '%s'. SOLUTION: Recompile the module(s).",
    346 			         Mod_Version, expectedmodversion);
    347 			irc_dlclose(Mod);
    348 			deletetmp(tmppath);
    349 			return errorbuf;
    350 		}
    351 		if (!Mod_Version)
    352 		{
    353 			snprintf(errorbuf, sizeof(errorbuf),
    354 				"Module is lacking Mod_Version. Perhaps a very old one you forgot to recompile?");
    355 			irc_dlclose(Mod);
    356 			deletetmp(tmppath);
    357 			return errorbuf;
    358 		}
    359 		irc_dlsym(Mod, "compiler_version", compiler_version);
    360 		if (compiler_version && ( ((*compiler_version) & 0xffff00) != (expectedcompilerversion & 0xffff00) ) )
    361 		{
    362 			char theyhad[64], wehave[64];
    363 			make_compiler_string(theyhad, sizeof(theyhad), *compiler_version);
    364 			make_compiler_string(wehave, sizeof(wehave), expectedcompilerversion);
    365 			snprintf(errorbuf, sizeof(errorbuf),
    366 			         "Module was compiled with GCC %s, core was compiled with GCC %s. SOLUTION: Recompile your UnrealIRCd and all its modules by doing a 'make clean; ./Config -quick && make'.",
    367 			         theyhad, wehave);
    368 			irc_dlclose(Mod);
    369 			deletetmp(tmppath);
    370 			return errorbuf;
    371 		}
    372 		irc_dlsym(Mod, "Mod_Header", mod_header);
    373 		if (!mod_header)
    374 		{
    375 			irc_dlclose(Mod);
    376 			deletetmp(tmppath);
    377 			return ("Unable to locate Mod_Header");
    378 		}
    379 		if (!mod_header->modversion)
    380 		{
    381 			irc_dlclose(Mod);
    382 			deletetmp(tmppath);
    383 			return ("Lacking mod_header->modversion");
    384 		}
    385 		if (!(modsys_ver = parse_modsys_version(mod_header->modversion)))
    386 		{
    387 			snprintf(errorbuf, 1023, "Unsupported module system version '%s'",
    388 				   mod_header->modversion);
    389 			irc_dlclose(Mod);
    390 			deletetmp(tmppath);
    391 			return(errorbuf);
    392 		}
    393 		if ((reterr = validate_mod_header(relpath, mod_header)))
    394 		{
    395 			irc_dlclose(Mod);
    396 			deletetmp(tmppath);
    397 			return(reterr);
    398 		}
    399 		if (Module_Find(mod_header->name))
    400 		{
    401 		        irc_dlclose(Mod);
    402 			deletetmp(tmppath);
    403 			return (NULL);
    404 		}
    405 		mod = (Module *)Module_make(mod_header, Mod);
    406 		safe_strdup(mod->tmp_file, tmppath);
    407 		mod->mod_sys_version = modsys_ver;
    408 		mod->compiler_version = compiler_version ? *compiler_version : 0;
    409 		safe_strdup(mod->relpath, relpath);
    410 
    411 		irc_dlsym(Mod, "Mod_Init", Mod_Init);
    412 		if (!Mod_Init)
    413 		{
    414 			Module_free(mod);
    415 			return ("Unable to locate Mod_Init");
    416 		}
    417 		irc_dlsym(Mod, "Mod_Unload", Mod_Unload);
    418 		if (!Mod_Unload)
    419 		{
    420 			Module_free(mod);
    421 			return ("Unable to locate Mod_Unload");
    422 		}
    423 		irc_dlsym(Mod, "Mod_Load", Mod_Load);
    424 		if (!Mod_Load)
    425 		{
    426 			Module_free(mod);
    427 			return ("Unable to locate Mod_Load"); 
    428 		}
    429 		irc_dlsym(Mod, "Mod_Handle", Mod_Handle);
    430 		if (Mod_Handle)
    431 			*Mod_Handle = mod;
    432 		irc_dlsym(Mod, "Mod_Test", Mod_Test);
    433 		/* add module here, so ModuleSetOptions() w/MOD_OPT_PRIORITY is available in Mod_Test() */
    434 		AddListItemPrio(mod, Modules, 0);
    435 		if (Mod_Test)
    436 		{
    437 			if ((ret = (*Mod_Test)(&mod->modinfo)) < MOD_SUCCESS)
    438 			{
    439 				ircsnprintf(errorbuf, sizeof(errorbuf), "Mod_Test returned %i", ret);
    440 				/* We EXPECT the module to have cleaned up its mess */
    441 				Module_free(mod);
    442 				return (errorbuf);
    443 			}
    444 		}
    445 		mod->flags = MODFLAG_TESTING;		
    446 		return NULL;
    447 	}
    448 	else
    449 	{
    450 		/* Return the error .. */
    451 		return irc_dlerror();
    452 	}
    453 }
    454 
    455 void Module_DelayChildren(Module *m)
    456 {
    457 	ModuleChild *c;
    458 	for (c = m->children; c; c = c->next)
    459 	{
    460 		c->child->flags |= MODFLAG_DELAYED;
    461 		Module_DelayChildren(c->child);
    462 	}
    463 }
    464 
    465 Module *Module_make(ModuleHeader *header, 
    466 #ifdef _WIN32
    467        HMODULE mod
    468 #else
    469        void *mod
    470 #endif
    471        )
    472 {
    473 	Module *modp = NULL;
    474 	
    475 	modp = safe_alloc(sizeof(Module));
    476 	modp->header = header;
    477 	modp->dll = mod;
    478 	modp->flags = MODFLAG_NONE;
    479 	modp->options = 0;
    480 	modp->errorcode = MODERR_NOERROR;
    481 	modp->children = NULL;
    482 	modp->modinfo.size = sizeof(ModuleInfo);
    483 	modp->modinfo.module_load = 0;
    484 	modp->modinfo.handle = modp;
    485 		
    486 	return (modp);
    487 }
    488 
    489 void Init_all_testing_modules(void)
    490 {
    491 	
    492 	Module *mi, *next;
    493 	int ret;
    494 	iFP Mod_Init;
    495 	for (mi = Modules; mi; mi = next)
    496 	{
    497 		next = mi->next;
    498 		if (!(mi->flags & MODFLAG_TESTING))
    499 			continue;
    500 		irc_dlsym(mi->dll, "Mod_Init", Mod_Init);
    501 		if ((ret = (*Mod_Init)(&mi->modinfo)) < MOD_SUCCESS) {
    502 			config_error("Error loading %s: Mod_Init returned %i",
    503 			    mi->header->name, ret);
    504 			Module_free(mi);
    505 			continue;
    506 		}
    507 		mi->flags = MODFLAG_INIT;
    508 	}
    509 }	
    510 
    511 void FreeModObj(ModuleObject *obj, Module *m)
    512 {
    513 	if (obj->type == MOBJ_EVENT) {
    514 		EventDel(obj->object.event);
    515 	}
    516 	else if (obj->type == MOBJ_HOOK) {
    517 		HookDel(obj->object.hook);
    518 	}
    519 	else if (obj->type == MOBJ_COMMAND) {
    520 		CommandDel(obj->object.command);
    521 	}
    522 	else if (obj->type == MOBJ_HOOKTYPE) {
    523 		//HooktypeDel(obj->object.hooktype, m); -- reinstate if we audited this code
    524 	}
    525 	else if (obj->type == MOBJ_VERSIONFLAG) {
    526 		VersionflagDel(obj->object.versionflag, m);
    527 	}
    528 	else if (obj->type == MOBJ_UMODE) {
    529 		UmodeDel(obj->object.umode);
    530 	}
    531 	else if (obj->type == MOBJ_CMODE) {
    532 		CmodeDel(obj->object.cmode);
    533 	}
    534 	else if (obj->type == MOBJ_COMMANDOVERRIDE) {
    535 		CommandOverrideDel(obj->object.cmdoverride);
    536 	}
    537 	else if (obj->type == MOBJ_EXTBAN) {
    538 		ExtbanDel(obj->object.extban);
    539 	}
    540 	else if (obj->type == MOBJ_CALLBACK) {
    541 		CallbackDel(obj->object.callback);
    542 	}
    543 	else if (obj->type == MOBJ_EFUNCTION) {
    544 		EfunctionDel(obj->object.efunction);
    545 	}
    546 	else if (obj->type == MOBJ_ISUPPORT) {
    547 		ISupportDel(obj->object.isupport);
    548 	}
    549 	else if (obj->type == MOBJ_MODDATA) {
    550 		ModDataDel(obj->object.moddata);
    551 	}
    552 	else if (obj->type == MOBJ_VALIDATOR) {
    553 		OperClassValidatorDel(obj->object.validator);
    554 	}
    555 	else if (obj->type == MOBJ_CLICAP) {
    556 		ClientCapabilityDel(obj->object.clicap);
    557 	}
    558 	else if (obj->type == MOBJ_MTAG) {
    559 		MessageTagHandlerDel(obj->object.mtag);
    560 	}
    561 	else if (obj->type == MOBJ_HISTORY_BACKEND) {
    562 		HistoryBackendDel(obj->object.history_backend);
    563 	}
    564 	else if (obj->type == MOBJ_RPC) {
    565 		RPCHandlerDel(obj->object.rpc);
    566 	}
    567 	else
    568 	{
    569 		unreal_log(ULOG_FATAL, "module", "FREEMODOBJ_UNKNOWN_TYPE", NULL,
    570 		           "[BUG] FreeModObj() called for unknown object (type $type)",
    571 		           log_data_integer("type", obj->type));
    572 		abort();
    573 	}
    574 }
    575 
    576 void Unload_all_loaded_modules(void)
    577 {
    578 	Module *mi, *next;
    579 	ModuleChild *child, *childnext;
    580 	ModuleObject *objs, *objnext;
    581 	iFP Mod_Unload;
    582 	int ret;
    583 
    584 	for (mi = Modules; mi; mi = next)
    585 	{
    586 		next = mi->next;
    587 		if (!(mi->flags & MODFLAG_LOADED) || (mi->flags & MODFLAG_DELAYED) || (mi->options & MOD_OPT_PERM))
    588 			continue;
    589 		irc_dlsym(mi->dll, "Mod_Unload", Mod_Unload);
    590 		if (Mod_Unload)
    591 		{
    592 			ret = (*Mod_Unload)(&mi->modinfo);
    593 			if (ret == MOD_DELAY)
    594 			{
    595 				mi->flags |= MODFLAG_DELAYED;
    596 				Module_DelayChildren(mi);
    597 			}
    598 		}
    599 		for (objs = mi->objects; objs; objs = objnext) {
    600 			objnext = objs->next;
    601 			FreeModObj(objs, mi);
    602 		}
    603 		for (child = mi->children; child; child = childnext)
    604 		{
    605 			childnext = child->next;
    606 			DelListItem(child,mi->children);
    607 			safe_free(child);
    608 		}
    609 		DelListItem(mi,Modules);
    610 		irc_dlclose(mi->dll);
    611 		deletetmp(mi->tmp_file);
    612 		safe_free(mi->tmp_file);
    613 		safe_free(mi->relpath);
    614 		safe_free(mi);
    615 	}
    616 }
    617 
    618 void Unload_all_testing_modules(void)
    619 {
    620 	Module *mi, *next;
    621 	ModuleChild *child, *childnext;
    622 	ModuleObject *objs, *objnext;
    623 
    624 	for (mi = Modules; mi; mi = next)
    625 	{
    626 		next = mi->next;
    627 		if (!(mi->flags & MODFLAG_TESTING))
    628 			continue;
    629 		for (objs = mi->objects; objs; objs = objnext) {
    630 			objnext = objs->next;
    631 			FreeModObj(objs, mi);
    632 		}
    633 		for (child = mi->children; child; child = childnext)
    634 		{
    635 			childnext = child->next;
    636 			DelListItem(child,mi->children);
    637 			safe_free(child);
    638 		}
    639 		DelListItem(mi,Modules);
    640 		irc_dlclose(mi->dll);
    641 		deletetmp(mi->tmp_file);
    642 		safe_free(mi->tmp_file);
    643 		safe_free(mi->relpath);
    644 		safe_free(mi);
    645 	}
    646 }
    647 
    648 /* 
    649  * Returns -1 if you cannot unload due to children still alive 
    650  * Returns 1 if successful 
    651  */
    652 int    Module_free(Module *mod)
    653 {
    654 	Module *p;
    655 	ModuleChild *cp, *cpnext;
    656 	ModuleObject *objs, *next;
    657 	/* Do not kill parent if children still alive */
    658 
    659 	for (cp = mod->children; cp; cp = cp->next)
    660 	{
    661 		Module_Unload(cp->child->header->name);
    662 	}
    663 	for (objs = mod->objects; objs; objs = next) {
    664 		next = objs->next;
    665 		FreeModObj(objs, mod);
    666 	}
    667 	for (p = Modules; p; p = p->next)
    668 	{
    669 		for (cp = p->children; cp; cp = cpnext)
    670 		{
    671 			cpnext = cp->next;
    672 			if (cp->child == mod)
    673 			{
    674 				DelListItem(mod, p->children);
    675 				safe_free(cp);
    676 				/* We can assume there can be only one. */
    677 				break;
    678 			}
    679 		}
    680 	}
    681 	DelListItem(mod, Modules);
    682 	irc_dlclose(mod->dll);
    683 	safe_free(mod->tmp_file);
    684 	safe_free(mod->relpath);
    685 	safe_free(mod);
    686 	return 1;
    687 }
    688 
    689 /*
    690  *  Module_Unload ()
    691  *     char *name        Internal module name
    692  *  Returns:
    693  *     -1                Not able to locate module, severe failure, anything
    694  *      1                Module unloaded
    695  *      2                Module wishes delayed unloading, has placed event
    696  */
    697 int Module_Unload(const char *name)
    698 {
    699 	Module *m;
    700 	int    (*Mod_Unload)();
    701 	int    ret;
    702 	for (m = Modules; m; m = m->next)
    703 	{
    704 		if (!strcmp(m->header->name, name))
    705 		{
    706 		       break;
    707 		}
    708 	}      
    709 	if (!m)
    710 		return -1;
    711 	irc_dlsym(m->dll, "Mod_Unload", Mod_Unload);
    712 	if (!Mod_Unload)
    713 	{
    714 		return -1;
    715 	}
    716 	ret = (*Mod_Unload)(&m->modinfo);
    717 	if (ret == MOD_DELAY)
    718 	{
    719 		m->flags |= MODFLAG_DELAYED;
    720 		Module_DelayChildren(m);
    721 		return 2;
    722 	}
    723 	if (ret == MOD_FAILED)
    724 	{
    725 		return -1;
    726 	}
    727 	/* No more pain detected, let's unload */
    728 	DelListItem(m, Modules);
    729 	Module_free(m);
    730 	return 1;
    731 }
    732 
    733 void module_loadall(void)
    734 {
    735 	iFP	fp;
    736 	Module *mi, *next;
    737 	
    738 	loop.config_status = CONFIG_STATUS_LOAD;
    739 
    740 	/* Run through all modules and check for module load */
    741 	for (mi = Modules; mi; mi = next)
    742 	{
    743 		next = mi->next;
    744 		if (mi->flags & MODFLAG_LOADED)
    745 			continue;
    746 		irc_dlsym(mi->dll, "Mod_Load", fp);
    747 		/* Call the module_load */
    748 		if ((*fp)(&mi->modinfo) != MOD_SUCCESS)
    749 		{
    750 			config_status("cannot load module %s", mi->header->name);
    751 			Module_free(mi);
    752 		}
    753 		else
    754 			mi->flags = MODFLAG_LOADED;
    755 	}
    756 }
    757 
    758 int	Module_IsAlreadyChild(Module *parent, Module *child)
    759 {
    760 	ModuleChild *mcp;
    761 	
    762 	for (mcp = parent->children; mcp; mcp = mcp->next)
    763 	{
    764 		if (mcp->child == child) 
    765 			return 1;
    766 	}
    767 	return 0;
    768 }
    769 
    770 void	Module_AddAsChild(Module *parent, Module *child)
    771 {
    772 	ModuleChild	*childp = NULL;
    773 	
    774 	childp = safe_alloc(sizeof(ModuleChild));
    775 	childp->child = child;
    776 	AddListItem(childp, parent->children);
    777 }
    778 
    779 /* cmd_module.
    780  * by Stskeeps, codemastr, Syzop.
    781  * Changed it so it's now public for users too, as quite some people
    782  * (and users) requested they should have the right to see what kind 
    783  * of weird modules are loaded on the server, especially since people
    784  * like to load spy modules these days.
    785  * I do not consider this sensitive information, but just in case
    786  * I stripped the version string for non-admins (eg: normal users). -- Syzop
    787  */
    788 CMD_FUNC(cmd_module)
    789 {
    790 	Module *mi;
    791 	int i;
    792 	char tmp[1024], *p;
    793 	RealCommand *mptr;
    794 	int all = 0;
    795 
    796 	if ((parc > 1) && !strcmp(parv[1], "-all"))
    797 		all = 1;
    798 
    799 	if (MyUser(client) && !IsOper(client) && all)
    800 		add_fake_lag(client, 7000); /* Lag them up. Big list. */
    801 
    802 	if ((parc > 2) && (hunt_server(client, recv_mtags, "MODULE", 2, parc, parv) != HUNTED_ISME))
    803 		return;
    804 
    805 	if ((parc == 2) && (parv[1][0] != '-') && (hunt_server(client, recv_mtags, "MODULE", 1, parc, parv) != HUNTED_ISME))
    806 		return;
    807 
    808 	if (all)
    809 		sendtxtnumeric(client, "Showing ALL loaded modules:");
    810 	else
    811 		sendtxtnumeric(client, "Showing loaded 3rd party modules (use \"MODULE -all\" to show all modules):");
    812 
    813 	for (mi = Modules; mi; mi = mi->next)
    814 	{
    815 		/* Skip official modules unless "MODULE -all" */
    816 		if (!all && (mi->options & MOD_OPT_OFFICIAL))
    817 			continue;
    818 
    819 		tmp[0] = '\0';
    820 		if (mi->flags & MODFLAG_DELAYED)
    821 			strlcat(tmp, "[Unloading] ", sizeof(tmp));
    822 		if (mi->options & MOD_OPT_PERM_RELOADABLE)
    823 			strlcat(tmp, "[PERM-BUT-RELOADABLE] ", sizeof(tmp));
    824 		if (mi->options & MOD_OPT_PERM)
    825 			strlcat(tmp, "[PERM] ", sizeof(tmp));
    826 		if (!(mi->options & MOD_OPT_OFFICIAL))
    827 			strlcat(tmp, "[3RD] ", sizeof(tmp));
    828 		if (!ValidatePermissionsForPath("server:module",client,NULL,NULL,NULL))
    829 			sendtxtnumeric(client, "*** %s - %s - by %s %s",
    830 				mi->header->name,
    831 				mi->header->description,
    832 				mi->header->author,
    833 				mi->options & MOD_OPT_OFFICIAL ? "" : "[3RD]");
    834 		else
    835 			sendtxtnumeric(client, "*** %s %s - %s - by %s %s",
    836 				mi->header->name,
    837 				mi->header->version,
    838 				mi->header->description,
    839 				mi->header->author,
    840 				tmp);
    841 	}
    842 
    843 	sendtxtnumeric(client, "End of module list");
    844 
    845 	if (!ValidatePermissionsForPath("server:module",client,NULL,NULL,NULL))
    846 		return;
    847 
    848 	tmp[0] = '\0';
    849 	p = tmp;
    850 	for (i=0; i < MAXHOOKTYPES; i++)
    851 	{
    852 		if (!Hooks[i])
    853 			continue;
    854 		ircsnprintf(p, sizeof(tmp) - strlen(tmp), "%d ", i);
    855 		p += strlen(p);
    856 		if (p > tmp + 380)
    857 		{
    858 			sendtxtnumeric(client, "Hooks: %s", tmp);
    859 			tmp[0] = '\0';
    860 			p = tmp;
    861 		}
    862 	}
    863 	sendtxtnumeric(client, "Hooks: %s ", tmp);
    864 
    865 	tmp[0] = '\0';
    866 	p = tmp;
    867 	for (i=0; i < 256; i++)
    868 	{
    869 		for (mptr = CommandHash[i]; mptr; mptr = mptr->next)
    870 			if (mptr->overriders)
    871 			{
    872 				ircsnprintf(p, sizeof(tmp)-strlen(tmp), "%s ", mptr->cmd);
    873 				p += strlen(p);
    874 				if (p > tmp+380)
    875 				{
    876 					sendtxtnumeric(client, "Override: %s", tmp);
    877 					tmp[0] = '\0';
    878 					p = tmp;
    879 				}
    880 			}
    881 	}
    882 	sendtxtnumeric(client, "Override: %s", tmp);
    883 }
    884 
    885 Hooktype *HooktypeFind(const char *string) {
    886 	Hooktype *hooktype;
    887 	for (hooktype = Hooktypes; hooktype->string ;hooktype++) {
    888 		if (!strcasecmp(hooktype->string, string))
    889 			return hooktype;
    890 	}
    891 	return NULL;
    892 }
    893 
    894 Versionflag *VersionflagFind(char flag)
    895 {
    896 	Versionflag *vflag;
    897 	for (vflag = Versionflags; vflag; vflag = vflag->next)
    898 	{
    899 		if (vflag->flag == flag)
    900 			return vflag;
    901 	}
    902 	return NULL;
    903 }
    904 
    905 Versionflag *VersionflagAdd(Module *module, char flag)
    906 {
    907 	Versionflag *vflag;
    908 	ModuleChild *parent;
    909 	if ((vflag = VersionflagFind(flag)))
    910 	{
    911 		ModuleChild *child;
    912 		for (child = vflag->parents; child; child = child->next) {
    913 			if (child->child == module)
    914 				break;
    915 		}
    916 		if (!child)
    917 		{
    918 			parent = safe_alloc(sizeof(ModuleChild));
    919 			parent->child = module;
    920 			if (module) {
    921 				ModuleObject *vflagobj;
    922 				vflagobj = safe_alloc(sizeof(ModuleObject));
    923 				vflagobj->type = MOBJ_VERSIONFLAG;
    924 				vflagobj->object.versionflag = vflag;
    925 				AddListItem(vflagobj, module->objects);
    926 				module->errorcode = MODERR_NOERROR;
    927 			}
    928 			AddListItem(parent,vflag->parents);
    929 		}
    930 		return vflag;
    931 	}
    932 	vflag = safe_alloc(sizeof(Versionflag));
    933 	vflag->flag = flag;
    934 	parent = safe_alloc(sizeof(ModuleChild));
    935 	parent->child = module;
    936 	if (module)
    937 	{
    938 		ModuleObject *vflagobj;
    939 		vflagobj = safe_alloc(sizeof(ModuleObject));
    940 		vflagobj->type = MOBJ_VERSIONFLAG;
    941 		vflagobj->object.versionflag = vflag;
    942 		AddListItem(vflagobj, module->objects);
    943 		module->errorcode = MODERR_NOERROR;
    944 	}
    945 	flag_add(flag);
    946 	AddListItem(parent,vflag->parents);
    947 	AddListItem(vflag, Versionflags);
    948 	return vflag;
    949 }
    950 	
    951 void VersionflagDel(Versionflag *vflag, Module *module)
    952 {
    953 	ModuleChild *owner;
    954 	if (!vflag)
    955 		return;
    956 
    957 	for (owner = vflag->parents; owner; owner = owner->next)
    958 	{
    959 		if (owner->child == module)
    960 		{
    961 			DelListItem(owner,vflag->parents);
    962 			safe_free(owner);
    963 			break;
    964 		}
    965 	}
    966 	if (module)
    967 	{
    968 		ModuleObject *objs;
    969 		for (objs = module->objects; objs; objs = objs->next) {
    970 			if (objs->type == MOBJ_VERSIONFLAG && objs->object.versionflag == vflag) {
    971 				DelListItem(objs,module->objects);
    972 				safe_free(objs);
    973 				break;
    974 			}
    975 		}
    976 	}
    977 	if (!vflag->parents)
    978 	{
    979 		flag_del(vflag->flag);
    980 		DelListItem(vflag, Versionflags);
    981 		safe_free(vflag);
    982 	}
    983 }
    984 
    985 Hook *HookAddMain(Module *module, int hooktype, int priority, int (*func)(), void (*vfunc)(), char *(*stringfunc)(), const char *(*conststringfunc)())
    986 {
    987 	Hook *p;
    988 	
    989 	p = (Hook *) safe_alloc(sizeof(Hook));
    990 	if (func)
    991 		p->func.intfunc = func;
    992 	if (vfunc)
    993 		p->func.voidfunc = vfunc;
    994 	if (stringfunc)
    995 		p->func.stringfunc = stringfunc;
    996 	if (conststringfunc)
    997 		p->func.conststringfunc = conststringfunc;
    998 	p->type = hooktype;
    999 	p->owner = module;
   1000 	p->priority = priority;
   1001 
   1002 	if (module) {
   1003 		ModuleObject *hookobj = (ModuleObject *)safe_alloc(sizeof(ModuleObject));
   1004 		hookobj->object.hook = p;
   1005 		hookobj->type = MOBJ_HOOK;
   1006 		AddListItem(hookobj, module->objects);
   1007 		module->errorcode = MODERR_NOERROR;
   1008 	}
   1009 	
   1010 	AddListItemPrio(p, Hooks[hooktype], p->priority);
   1011 
   1012 	return p;
   1013 }
   1014 
   1015 Hook *HookDel(Hook *hook)
   1016 {
   1017 	Hook *p, *q;
   1018 	for (p = Hooks[hook->type]; p; p = p->next) {
   1019 		if (p == hook) {
   1020 			q = p->next;
   1021 			DelListItem(p, Hooks[hook->type]);
   1022 			if (p->owner) {
   1023 				ModuleObject *hookobj;
   1024 				for (hookobj = p->owner->objects; hookobj; hookobj = hookobj->next) {
   1025 					if (hookobj->type == MOBJ_HOOK && hookobj->object.hook == p) {
   1026 						DelListItem(hookobj, hook->owner->objects);
   1027 						safe_free(hookobj);
   1028 						break;
   1029 					}
   1030 				}
   1031 			}
   1032 			safe_free(p);
   1033 			return q;
   1034 		}
   1035 	}
   1036 	return NULL;
   1037 }
   1038 
   1039 static int num_callbacks(int cbtype)
   1040 {
   1041 Callback *e;
   1042 int cnt = 0;
   1043 
   1044 	for (e = Callbacks[cbtype]; e; e = e->next)
   1045 		if (!e->willberemoved)
   1046 			cnt++;
   1047 			
   1048 	return cnt;
   1049 }
   1050 
   1051 Callback *CallbackAddMain(Module *module, int cbtype, int (*func)(), void (*vfunc)(), void *(*pvfunc)(), char *(*stringfunc)(), const char *(*conststringfunc)())
   1052 {
   1053 	Callback *p;
   1054 	
   1055 	if (num_callbacks(cbtype) > 0)
   1056 	{
   1057 		if (module)
   1058 			module->errorcode = MODERR_EXISTS;
   1059 		return NULL;
   1060 	}
   1061 	
   1062 	p = safe_alloc(sizeof(Callback));
   1063 	if (func)
   1064 		p->func.intfunc = func;
   1065 	if (vfunc)
   1066 		p->func.voidfunc = vfunc;
   1067 	if (pvfunc)
   1068 		p->func.pvoidfunc = pvfunc;
   1069 	if (stringfunc)
   1070 		p->func.stringfunc = stringfunc;
   1071 	if (conststringfunc)
   1072 		p->func.conststringfunc = conststringfunc;
   1073 	p->type = cbtype;
   1074 	p->owner = module;
   1075 	AddListItem(p, Callbacks[cbtype]);
   1076 	if (module) {
   1077 		ModuleObject *cbobj = safe_alloc(sizeof(ModuleObject));
   1078 		cbobj->object.callback = p;
   1079 		cbobj->type = MOBJ_CALLBACK;
   1080 		AddListItem(cbobj, module->objects);
   1081 		module->errorcode = MODERR_NOERROR;
   1082 	}
   1083 	return p;
   1084 }
   1085 
   1086 Callback *CallbackDel(Callback *cb)
   1087 {
   1088 	Callback *p, *q;
   1089 	for (p = Callbacks[cb->type]; p; p = p->next) {
   1090 		if (p == cb) {
   1091 			q = p->next;
   1092 			DelListItem(p, Callbacks[cb->type]);
   1093 			if (RCallbacks[cb->type] == p)
   1094 				RCallbacks[cb->type] = NULL;
   1095 			if (p->owner) {
   1096 				ModuleObject *cbobj;
   1097 				for (cbobj = p->owner->objects; cbobj; cbobj = cbobj->next) {
   1098 					if ((cbobj->type == MOBJ_CALLBACK) && (cbobj->object.callback == p)) {
   1099 						DelListItem(cbobj, cb->owner->objects);
   1100 						safe_free(cbobj);
   1101 						break;
   1102 					}
   1103 				}
   1104 			}
   1105 			safe_free(p);
   1106 			return q;
   1107 		}
   1108 	}
   1109 	return NULL;
   1110 }
   1111 
   1112 CommandOverride *CommandOverrideAdd(Module *module, const char *name, int priority, OverrideCmdFunc function)
   1113 {
   1114 	RealCommand *p;
   1115 	CommandOverride *ovr;
   1116 	
   1117 	if (!(p = find_command_simple(name)))
   1118 	{
   1119 		if (module)
   1120 			module->errorcode = MODERR_NOTFOUND;
   1121 		return NULL;
   1122 	}
   1123 	for (ovr=p->overriders; ovr; ovr=ovr->next)
   1124 	{
   1125 		if ((ovr->owner == module) && (ovr->func == function))
   1126 		{
   1127 			if (module)
   1128 				module->errorcode = MODERR_EXISTS;
   1129 			return NULL;
   1130 		}
   1131 	}
   1132 	ovr = safe_alloc(sizeof(CommandOverride));
   1133 	ovr->func = function;
   1134 	ovr->owner = module;
   1135 	ovr->priority = priority;
   1136 	if (module)
   1137 	{
   1138 		ModuleObject *cmdoverobj = safe_alloc(sizeof(ModuleObject));
   1139 		cmdoverobj->type = MOBJ_COMMANDOVERRIDE;
   1140 		cmdoverobj->object.cmdoverride = ovr;
   1141 		AddListItem(cmdoverobj, module->objects);
   1142 		module->errorcode = MODERR_NOERROR;
   1143 	}
   1144 	ovr->command = p;
   1145 	AddListItemPrio(ovr, p->overriders, ovr->priority);
   1146 	if (p->friend)
   1147 	{
   1148 		AddListItem(ovr, p->friend->overriders);
   1149 	}
   1150 	return ovr;
   1151 }
   1152 
   1153 void CommandOverrideDel(CommandOverride *cmd)
   1154 {
   1155 	DelListItem(cmd, cmd->command->overriders);
   1156 	if (cmd->command->friend)
   1157 	{
   1158 		DelListItem(cmd, cmd->command->friend->overriders);
   1159 	}
   1160 	if (cmd->owner)
   1161 	{
   1162 		ModuleObject *obj;
   1163 		for (obj = cmd->owner->objects; obj; obj = obj->next)
   1164 		{
   1165 			if (obj->type != MOBJ_COMMANDOVERRIDE)
   1166 				continue;
   1167 			if (obj->object.cmdoverride == cmd)
   1168 			{
   1169 				DelListItem(obj, cmd->owner->objects);
   1170 				safe_free(obj);
   1171 				break;
   1172 			}
   1173 		}
   1174 	}
   1175 	safe_free(cmd);
   1176 }
   1177 
   1178 void CallCommandOverride(CommandOverride *ovr, Client *client, MessageTag *mtags, int parc, const char *parv[])
   1179 {
   1180 	if (ovr->next)
   1181 		ovr->next->func(ovr->next, client, mtags, parc, parv);
   1182 	else
   1183 		ovr->command->func(client, mtags, parc, parv);
   1184 }
   1185 
   1186 EVENT(e_unload_module_delayed)
   1187 {
   1188 	char *name = (char *)data;
   1189 	int i; 
   1190 	i = Module_Unload(name);
   1191 	if (i == 1)
   1192 	{
   1193 		unreal_log(ULOG_INFO, "module", "MODULE_UNLOADING_DELAYED", NULL,
   1194 		           "Unloading module $module_name (was delayed earlier)",
   1195 		           log_data_string("module_name", name));
   1196 	}
   1197 	safe_free(name);
   1198 	extcmodes_check_for_changes();
   1199 	umodes_check_for_changes();
   1200 	return;
   1201 }
   1202 
   1203 void unload_all_modules(void)
   1204 {
   1205 	Module *m;
   1206 	int	(*Mod_Unload)();
   1207 	for (m = Modules; m; m = m->next)
   1208 	{
   1209 #ifdef DEBUGMODE
   1210 		unreal_log(ULOG_DEBUG, "module", "MODULE_UNLOADING", NULL,
   1211 		           "Unloading module $module_name",
   1212 		           log_data_string("module_name", m->header->name));
   1213 #endif
   1214 		irc_dlsym(m->dll, "Mod_Unload", Mod_Unload);
   1215 		if (Mod_Unload)
   1216 			(*Mod_Unload)(&m->modinfo);
   1217 		deletetmp(m->tmp_file);
   1218 	}
   1219 }
   1220 
   1221 void ModuleSetOptions(Module *module, unsigned int options, int action)
   1222 {
   1223 	unsigned int oldopts = module->options;
   1224 
   1225 	if (options == MOD_OPT_PRIORITY)
   1226 	{
   1227 		DelListItem(module, Modules);
   1228 		AddListItemPrio(module, Modules, action);
   1229 	} else {
   1230 		/* Simple bit flag(s) */
   1231 		if (action)
   1232 			module->options |= options;
   1233 		else
   1234 			module->options &= ~options;
   1235 	}
   1236 }
   1237 
   1238 unsigned int ModuleGetOptions(Module *module)
   1239 {
   1240 	return module->options;
   1241 }
   1242 
   1243 unsigned int ModuleGetError(Module *module)
   1244 {
   1245 	return module->errorcode;
   1246 }
   1247 
   1248 static const char *module_error_str[] = {
   1249 	"No error",
   1250 	"Object already exists",
   1251 	"No space available",
   1252 	"Invalid parameter(s)",
   1253 	"Object was not found"
   1254 };
   1255 
   1256 const char *ModuleGetErrorStr(Module *module)
   1257 {
   1258 	if (module->errorcode >= sizeof(module_error_str)/sizeof(module_error_str[0]))
   1259 		return NULL;
   1260 
   1261 	return module_error_str[module->errorcode];
   1262 }
   1263 
   1264 /** Ensure that all required callbacks are in place and meet
   1265  * all specified requirements
   1266  */
   1267 int callbacks_check(void)
   1268 {
   1269 int i;
   1270 
   1271 	for (i=0; i < MAXCALLBACKS; i++)
   1272 	{
   1273 		if (num_callbacks(i) > 1)
   1274 		{
   1275 			config_error("ERROR: Multiple callbacks loaded for type %d. "
   1276 			             "Make sure you only load 1 module of 1 type (eg: only 1 cloaking module)",
   1277 			             i);
   1278 			return -1;
   1279 		}
   1280 	}
   1281 
   1282 	if (!Callbacks[CALLBACKTYPE_CLOAK_KEY_CHECKSUM])
   1283 	{
   1284 		unreal_log(ULOG_ERROR, "config", "NO_CLOAKING_MODULE", NULL,
   1285 		           "No cloaking module loaded, you must load 1 of these modulese:\n"
   1286 		           "1) cloak_sha256 - if you are a new network starting with UnrealIRCd 6\n"
   1287 		           "2) cloak_md5 - the old one if migrating an existing network from UnrealIRCd 3.2/4/5\n"
   1288 		           "3) cloak_none - if you don't want to use cloaking at all\n"
   1289 		           "See also https://www.unrealircd.org/docs/FAQ#choose-a-cloaking-module");
   1290 		return -1;
   1291 	}
   1292 	return 0;
   1293 }
   1294 
   1295 void callbacks_switchover(void)
   1296 {
   1297 Callback *e;
   1298 int i;
   1299 
   1300 	/* Now set the real callback, and tag the new one
   1301 	 * as 'willberemoved' if needed.
   1302 	 */
   1303 
   1304 	for (i=0; i < MAXCALLBACKS; i++)
   1305 		for (e = Callbacks[i]; e; e = e->next)
   1306 			if (!e->willberemoved)
   1307 			{
   1308 				RCallbacks[i] = e; /* This is the new one. */
   1309 				if (!(e->owner->options & MOD_OPT_PERM))
   1310 					e->willberemoved = 1;
   1311 				break;
   1312 			}
   1313 }
   1314 
   1315 #ifdef _WIN32
   1316 const char *our_dlerror(void)
   1317 {
   1318 	static char errbuf[513];
   1319 	DWORD err = GetLastError();
   1320 	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
   1321 		0, errbuf, 512, NULL);
   1322 	if (err == ERROR_MOD_NOT_FOUND)
   1323 		strlcat(errbuf, " This could be because the DLL depends on another DLL, for example if you "
   1324 		               "are trying to load a 3rd party module which was compiled with a different compiler version.",
   1325 		               sizeof(errbuf));
   1326 	return errbuf;
   1327 }
   1328 #endif
   1329 
   1330 /** Check if a module is loaded.
   1331  * @param name Name of the module by relative path (eg: 'extbans/timedban')
   1332  * @returns 1 if module is loaded, 0 if not.
   1333  * @note  The name is checked against the module name,
   1334  *        this can be a problem if two modules have the same name.
   1335  */
   1336 int is_module_loaded(const char *name)
   1337 {
   1338 	Module *mi;
   1339 	for (mi = Modules; mi; mi = mi->next)
   1340 	{
   1341 		if (mi->flags & MODFLAG_DELAYED)
   1342 			continue; /* unloading (delayed) */
   1343 
   1344 		/* During config_posttest ignore modules that are loaded,
   1345 		 * since we only care about the 'future' state.
   1346 		 */
   1347 		if ((loop.config_status < CONFIG_STATUS_LOAD) &&
   1348 		    (loop.config_status >= CONFIG_STATUS_POSTTEST) &&
   1349 		    (mi->flags == MODFLAG_LOADED))
   1350 		{
   1351 			continue;
   1352 		}
   1353 
   1354 		if (!strcasecmp(mi->relpath, name))
   1355 			return 1;
   1356 	}
   1357 	return 0;
   1358 }
   1359 
   1360 static const char *mod_var_name(ModuleInfo *modinfo, const char *varshortname)
   1361 {
   1362 	static char fullname[512];
   1363 	snprintf(fullname, sizeof(fullname), "%s:%s", modinfo->handle->header->name, varshortname);
   1364 	return fullname;
   1365 }
   1366 
   1367 int LoadPersistentPointerX(ModuleInfo *modinfo, const char *varshortname, void **var, void (*free_variable)(ModData *m))
   1368 {
   1369 	ModDataInfo *m;
   1370 	const char *fullname = mod_var_name(modinfo, varshortname);
   1371 
   1372 	m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE);
   1373 	if (m)
   1374 	{
   1375 		*var = moddata_local_variable(m).ptr;
   1376 		return 1;
   1377 	} else {
   1378 		ModDataInfo mreq;
   1379 		memset(&mreq, 0, sizeof(mreq));
   1380 		mreq.type = MODDATATYPE_LOCAL_VARIABLE;
   1381 		mreq.name = strdup(fullname);
   1382 		mreq.free = free_variable;
   1383 		m = ModDataAdd(modinfo->handle, mreq);
   1384 		moddata_local_variable(m).ptr = NULL;
   1385 		safe_free(mreq.name);
   1386 		return 0;
   1387 	}
   1388 }
   1389 
   1390 void SavePersistentPointerX(ModuleInfo *modinfo, const char *varshortname, void *var)
   1391 {
   1392 	ModDataInfo *m;
   1393 	const char *fullname = mod_var_name(modinfo, varshortname);
   1394 
   1395 	m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE);
   1396 	moddata_local_variable(m).ptr = var;
   1397 }
   1398 
   1399 int LoadPersistentIntX(ModuleInfo *modinfo, const char *varshortname, int *var)
   1400 {
   1401 	ModDataInfo *m;
   1402 	const char *fullname = mod_var_name(modinfo, varshortname);
   1403 
   1404 	m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE);
   1405 	if (m)
   1406 	{
   1407 		*var = moddata_local_variable(m).i;
   1408 		return 1;
   1409 	} else {
   1410 		ModDataInfo mreq;
   1411 		memset(&mreq, 0, sizeof(mreq));
   1412 		mreq.type = MODDATATYPE_LOCAL_VARIABLE;
   1413 		mreq.name = strdup(fullname);
   1414 		mreq.free = NULL;
   1415 		m = ModDataAdd(modinfo->handle, mreq);
   1416 		moddata_local_variable(m).i = 0;
   1417 		safe_free(mreq.name);
   1418 		return 0;
   1419 	}
   1420 }
   1421 
   1422 void SavePersistentIntX(ModuleInfo *modinfo, const char *varshortname, int var)
   1423 {
   1424 	ModDataInfo *m;
   1425 	const char *fullname = mod_var_name(modinfo, varshortname);
   1426 
   1427 	m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE);
   1428 	moddata_local_variable(m).i = var;
   1429 }
   1430 
   1431 int LoadPersistentLongX(ModuleInfo *modinfo, const char *varshortname, long *var)
   1432 {
   1433 	ModDataInfo *m;
   1434 	const char *fullname = mod_var_name(modinfo, varshortname);
   1435 
   1436 	m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE);
   1437 	if (m)
   1438 	{
   1439 		*var = moddata_local_variable(m).l;
   1440 		return 1;
   1441 	} else {
   1442 		ModDataInfo mreq;
   1443 		memset(&mreq, 0, sizeof(mreq));
   1444 		mreq.type = MODDATATYPE_LOCAL_VARIABLE;
   1445 		mreq.name = strdup(fullname);
   1446 		mreq.free = NULL;
   1447 		m = ModDataAdd(modinfo->handle, mreq);
   1448 		moddata_local_variable(m).l = 0;
   1449 		safe_free(mreq.name);
   1450 		return 0;
   1451 	}
   1452 }
   1453 
   1454 void SavePersistentLongX(ModuleInfo *modinfo, const char *varshortname, long var)
   1455 {
   1456 	ModDataInfo *m;
   1457 	const char *fullname = mod_var_name(modinfo, varshortname);
   1458 
   1459 	m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE);
   1460 	moddata_local_variable(m).l = var;
   1461 }
   1462 
   1463 int LoadPersistentLongLongX(ModuleInfo *modinfo, const char *varshortname, long long *var)
   1464 {
   1465 	ModDataInfo *m;
   1466 	const char *fullname = mod_var_name(modinfo, varshortname);
   1467 
   1468 	m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE);
   1469 	if (m)
   1470 	{
   1471 		*var = moddata_local_variable(m).ll;
   1472 		return 1;
   1473 	} else {
   1474 		ModDataInfo mreq;
   1475 		memset(&mreq, 0, sizeof(mreq));
   1476 		mreq.type = MODDATATYPE_LOCAL_VARIABLE;
   1477 		mreq.name = strdup(fullname);
   1478 		mreq.free = NULL;
   1479 		m = ModDataAdd(modinfo->handle, mreq);
   1480 		moddata_local_variable(m).ll = 0;
   1481 		safe_free(mreq.name);
   1482 		return 0;
   1483 	}
   1484 }
   1485 
   1486 void SavePersistentLongLongX(ModuleInfo *modinfo, const char *varshortname, long long var)
   1487 {
   1488 	ModDataInfo *m;
   1489 	const char *fullname = mod_var_name(modinfo, varshortname);
   1490 
   1491 	m = findmoddata_byname(fullname, MODDATATYPE_LOCAL_VARIABLE);
   1492 	moddata_local_variable(m).ll = var;
   1493 }
   1494 
   1495 extern int module_has_moddata(Module *mod);
   1496 extern int module_has_extcmode_param_mode(Module *mod);
   1497 
   1498 /** Special hack for unloading modules with moddata and parameter extcmodes */
   1499 void special_delayed_unloading(void)
   1500 {
   1501 	Module *m, *m2;
   1502 	extern Module *Modules;
   1503 
   1504 	for (m = Modules; m; m = m->next)
   1505 	{
   1506 		if (!(m->flags & MODFLAG_LOADED))
   1507 			continue;
   1508 		if ((m->options & MOD_OPT_PERM) || (m->options & MOD_OPT_PERM_RELOADABLE))
   1509 			continue;
   1510 		if (module_has_moddata(m) || module_has_extcmode_param_mode(m))
   1511 		{
   1512 			int found = 0;
   1513 			for (m2 = Modules; m2; m2 = m2->next)
   1514 			{
   1515 				if ((m != m2) && !strcmp(m->header->name, m2->header->name))
   1516 					found = 1;
   1517 			}
   1518 			if (!found)
   1519 			{
   1520 				char *name = strdup(m->header->name);
   1521 				config_warn("Delaying module unloading of '%s' for a millisecond...", name);
   1522 				m->flags |= MODFLAG_DELAYED;
   1523 				EventAdd(NULL, "e_unload_module_delayed", e_unload_module_delayed, name, 0, 1);
   1524 			}
   1525 		}
   1526 	}
   1527 }