/* NeoStats - IRC Statistical Services ** Copyright (c) 1999-2002 Adam Rutter, Justin Hammond ** http://www.neostats.net/ ** ** Portions Copyright (c) 2000 - 2001 ^Enigma^ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ** USA ** ** NeoStats CVS Identification ** $Id: dl.c,v 1.45 2002/09/04 08:40:26 fishwaldo Exp $ */ #include #include #include #include #include "dl.h" #include "hash.h" #include "stats.h" #include "config.h" void init_dl() { if (usr_mds); } void __init_mod_list() { strcpy(segv_location, "__init_mod_list"); mh = hash_create(NUM_MODULES, 0, 0); bh = hash_create(B_TABLE_SIZE, 0, 0); th = hash_create(T_TABLE_SIZE, 0, 0); bch = hash_create(C_TABLE_SIZE, 0, 0); sockh = hash_create(me.maxsocks, 0, 0); } static Mod_Timer *new_timer(char *timer_name) { Mod_Timer *t; hnode_t *tn; strcpy(segv_location, "Mod_Timer"); #ifdef DEBUG log("New Timer: %s", timer_name); #endif t = smalloc(sizeof(Mod_Timer)); if (!timer_name) timer_name=""; t->timername = timer_name; tn = hnode_create(t); if (hash_isfull(th)) { log("new_timer(): Couldn't add new Timer, Hash is Full!"); return NULL; } else { hash_insert(th, tn, timer_name); } return t; } Mod_Timer *findtimer(char *timer_name) { hnode_t *tn; strcpy(segv_location, "findtimer"); tn = hash_lookup(th, timer_name); if (tn) return (Mod_Timer *)hnode_get(tn); return NULL; } int add_mod_timer(char *func_name, char *timer_name, char *mod_name, int interval) { Mod_Timer *Mod_timer_list; strcpy(segv_location, "add_mod_timer"); if (dlsym((int *)get_dl_handle(mod_name), func_name) == NULL) { log("Oh Oh, The Timer Function doesn't exist"); return -1; } Mod_timer_list = new_timer(timer_name); Mod_timer_list->interval = interval; Mod_timer_list->lastrun = time(NULL); Mod_timer_list->modname = sstrdup(mod_name); Mod_timer_list->function = dlsym((int *)get_dl_handle(mod_name), func_name); log("Registered Module %s with timer for Function %s", mod_name, func_name); return 1; } int del_mod_timer(char *timer_name) { Mod_Timer *list; hnode_t *tn; strcpy(segv_location, "del_mod_timer"); tn = hash_lookup(th, timer_name); if (tn) { list = hnode_get(tn); #ifdef DEBUG log("Unregistered Timer function %s from Module %s", timer_name, list->modname); #endif hash_delete(th, tn); hnode_destroy(tn); free(list); return 1; } return -1; } void list_module_timer(User *u) { Mod_Timer *mod_ptr = NULL; hscan_t ts; hnode_t *tn; strcpy(segv_location, "list_module_timer"); prefmsg(u->nick,s_Services,"Module timer List:"); hash_scan_begin(&ts, th); while ((tn = hash_scan_next(&ts)) != NULL) { mod_ptr= hnode_get(tn); prefmsg(u->nick,s_Services,"%s:--------------------------------",mod_ptr->modname); prefmsg(u->nick,s_Services,"Module Timer Name: %s",mod_ptr->timername); prefmsg(u->nick,s_Services,"Module Interval: %d",mod_ptr->interval); prefmsg(u->nick,s_Services,"Time till next Run: %d", mod_ptr->interval - (time(NULL) - mod_ptr->lastrun)); } prefmsg(u->nick,s_Services,"End of Module timer List"); } static Sock_List *new_sock(char *sock_name) { Sock_List *s; hnode_t *sn; strcpy(segv_location, "Sock_List"); #ifdef DEBUG log("New Socket: %s", sock_name); #endif s = smalloc(sizeof(Sock_List)); if (!sock_name) sock_name=""; s->sockname = sstrdup(sock_name); sn = hnode_create(s); if (hash_isfull(sockh)) { log("Eeek, SocketHash is full, can not add a new socket"); return NULL; } else { hash_insert(sockh, sn, s->sockname); } return s; } Sock_List *findsock(char *sock_name) { hnode_t *sn; strcpy(segv_location, "findsock"); sn = hash_lookup(sockh, sock_name); if (sn) return hnode_get(sn); return NULL; } int add_socket(char *readfunc, char *writefunc, char *errfunc, char *sock_name, int socknum, char *mod_name) { Sock_List *Sockets_mod_list; strcpy(segv_location, "add_Socket"); if (readfunc) { if (dlsym((int *)get_dl_handle(mod_name), readfunc) == NULL) { log("oh oh, the socket function doesn't exist"); return -1; } } if (writefunc) { if (dlsym((int *)get_dl_handle(mod_name), writefunc) == NULL) { log("oh oh, the socket function doesn't exist"); return -1; } } if (errfunc) { if (dlsym((int *)get_dl_handle(mod_name), errfunc) == NULL) { log("oh oh, the socket function doesn't exist"); return -1; } } Sockets_mod_list = new_sock(sock_name); Sockets_mod_list->sock_no = socknum; Sockets_mod_list->modname = sstrdup(mod_name); Sockets_mod_list->readfnc = dlsym((int *)get_dl_handle(mod_name), readfunc); Sockets_mod_list->writefnc = dlsym((int *)get_dl_handle(mod_name), writefunc); Sockets_mod_list->errfnc = dlsym((int *)get_dl_handle(mod_name), errfunc); #ifdef DEBUG log("Registered Module %s with Socket functions %s", mod_name, Sockets_mod_list->sockname); #endif return 1; } int del_socket(char *sock_name) { Sock_List *list; hnode_t *sn; strcpy(segv_location, "del_mod_timer"); sn = hash_lookup(sockh, sock_name); if (sn) { list = hnode_get(sn); #ifdef DEBUG log("Unregistered Socket function %s from Module %s", sock_name, list->modname); #endif hash_scan_delete(sockh, sn); hnode_destroy(sn); free(list->sockname); free(list); return 1; } return -1; } void list_sockets(User *u) { Sock_List *mod_ptr = NULL; hscan_t ss; hnode_t *sn; strcpy(segv_location, "list_sockets"); prefmsg(u->nick,s_Services,"Sockets List: (%d)", hash_count(sockh)); hash_scan_begin(&ss, sockh); while ((sn = hash_scan_next(&ss)) != NULL) { mod_ptr = hnode_get(sn); prefmsg(u->nick,s_Services,"%s:--------------------------------",mod_ptr->modname); prefmsg(u->nick,s_Services,"Socket Name: %s",mod_ptr->sockname); prefmsg(u->nick,s_Services,"Socket Number: %d",mod_ptr->sock_no); } prefmsg(u->nick,s_Services,"End of Socket List"); } extern void add_bot_to_chan(char *bot, char *chan) { hnode_t *cbn; Chan_Bot *bc; lnode_t *bmn; char *botname; cbn = hash_lookup(bch, chan); if (!cbn) { bc = malloc(sizeof(Chan_Bot)); bc->chan = sstrdup(chan); bc->bots = list_create(B_TABLE_SIZE); cbn = hnode_create(bc); if (hash_isfull(bch)) { log("eek, bot channel hash is full"); return; } hash_insert(bch, cbn, bc->chan); } else { bc = hnode_get(cbn); } if (list_isfull(bc->bots)) { log("Eeek, Bot Channel List is full for Chan %s", chan); return; } botname = sstrdup(bot); bmn = lnode_create(botname); list_append(bc->bots, bmn); return; } extern void del_bot_from_chan(char *bot, char *chan) { hnode_t *cbn; Chan_Bot *bc; lnode_t *bmn; cbn = hash_lookup(bch, chan); if (!cbn) { log("Hu? Can't Find Channel %s for botchanhash", chan); return; } bc = hnode_get(cbn); bmn = list_find(bc->bots, bot, comparef); if (!bmn) { log("Hu? Can't find bot %s in %s in botchanhash", bot, chan); return; } list_delete(bc->bots, bmn); if (list_isempty(bc->bots)) { /* delete the hash and list because its all over */ hash_delete(bch, cbn); list_destroy(bc->bots); free(lnode_get(bmn)); lnode_destroy(bmn); free(bc->chan); hnode_destroy(cbn); } } extern void bot_chan_message(char *origin, char *chan, char **av, int ac) { hnode_t *cbn; Chan_Bot *bc; lnode_t *bmn; Mod_User *u; cbn = hash_lookup(bch, chan); if (!cbn) { log("eeeh, Can't find channel %s for BotChanMessage", chan); return; } bc = hnode_get(cbn); bmn = list_first(bc->bots); while (bmn) { u = findbot(lnode_get(bmn)); if (u->chanfunc) { #ifdef DEBUG log("Running Module for Chanmessage %s", chan); #endif u->chanfunc(origin, chan, av, ac); } bmn = list_next(bc->bots, bmn); } } extern void botchandump(User *u) { hscan_t hs; hnode_t *hn; lnode_t *ln; Chan_Bot *bc; prefmsg(u->nick, s_Services, "BotChanDump:"); hash_scan_begin(&hs, bch); while ((hn = hash_scan_next(&hs)) != NULL) { bc = hnode_get(hn); prefmsg(u->nick,s_Services,"%s:--------------------------------",bc->chan); ln = list_first(bc->bots); while (ln) { prefmsg(u->nick,s_Services,"Bot Name: %s",lnode_get(ln)); ln = list_next(bc->bots, ln); } } } static Mod_User *new_bot(char *bot_name) { Mod_User *u; hnode_t *bn; strcpy(segv_location, "Mod_User"); #ifdef DEBUG log("New Bot: %s", bot_name); #endif u = smalloc(sizeof(Mod_User)); if (!bot_name) bot_name=""; u->nick = sstrdup(bot_name); u->chanlist = hash_create(C_TABLE_SIZE, 0, 0); bn = hnode_create(u); if (hash_isfull(bh)) { chanalert(s_Services, "Warning ModuleBotlist is full"); return NULL; } else { hash_insert(bh, bn, bot_name); } return u; } int add_mod_user(char *nick, char *mod_name) { Mod_User *Mod_Usr_list; Module *list_ptr; hnode_t *mn; strcpy(segv_location, "add_mod_user"); Mod_Usr_list = new_bot(nick); /* add a brand new user */ Mod_Usr_list->nick = sstrdup(nick); Mod_Usr_list->modname = sstrdup(mod_name); mn = hash_lookup(mh, mod_name); if (mn) { list_ptr = hnode_get(mn); Mod_Usr_list->function = dlsym(list_ptr->dl_handle, "__Bot_Message"); Mod_Usr_list->chanfunc = dlsym(list_ptr->dl_handle, "__Chan_Message"); return 1; } log("add_mod_user(): Couldn't Add ModuleBot to List"); return 0; } Mod_User *findbot(char *bot_name) { hnode_t *bn; strcpy(segv_location, "findbot"); bn = hash_lookup(bh, bot_name); if (bn) { return (Mod_User *)hnode_get(bn); } return NULL; } int del_mod_user(char *bot_name) { Mod_User *list; hnode_t *bn; strcpy(segv_location, "del_mod_user"); bn = hash_lookup(bh, bot_name); if (bn) { hash_delete(bh, bn); list = hnode_get(bn); hnode_destroy(bn); free(list); return 1; } return -1; } int bot_nick_change(char *oldnick, char *newnick) { User *u; Mod_User *mod_tmp, *mod_ptr; strcpy(segv_location, "bot_nick_change"); /* First, try to find out if the newnick is unique! */ #ifdef DEBUG log("oldnick %s newnick %s",oldnick,newnick); #endif u = finduser(oldnick); if (!u) { log("A non-registered bot(%s) attempted to change its nick to %s",oldnick, newnick); return -1; } u = finduser(newnick); if (!u) { if ((mod_ptr = findbot(oldnick)) != NULL) { #ifdef DEBUG log("Bot %s Changed its nick to %s", oldnick, newnick); #endif mod_tmp = new_bot(newnick); /* add a brand new user */ mod_tmp->nick = sstrdup(newnick); mod_tmp->modname = sstrdup(mod_ptr->modname); mod_tmp->function = mod_ptr->function; /* Now Delete the Old bot nick */ del_mod_user(oldnick); snick_cmd(oldnick, newnick); return 1; } } log("Couldn't find Bot Nick %s in Bot list", oldnick); return -1; } void list_module_bots(User *u) { Mod_User *mod_ptr; hnode_t *bn; hscan_t bs; strcpy(segv_location, "list_module_bots"); prefmsg(u->nick,s_Services,"Module Bot List:"); hash_scan_begin(&bs, bh); while ((bn = hash_scan_next(&bs)) != NULL) { mod_ptr = hnode_get(bn); prefmsg(u->nick,s_Services,"Module: %s",mod_ptr->modname); prefmsg(u->nick,s_Services,"Module Bots: %s",mod_ptr->nick); } prefmsg(u->nick,s_Services,"End of Module Bot List"); } int load_module(char *path1, User *u) { #ifndef HAVE_LIBDL const char *dl_error; #else char *dl_error; #endif void *dl_handle; int do_msg; char *path = NULL; char p[255]; char **av; int ac = 0; Module_Info * (*mod_get_info)() = NULL; Functions * (*mod_get_funcs)() = NULL; EventFnList * (*mod_get_events)() = NULL; Module_Info *mod_info_ptr = NULL; Functions *mod_funcs_ptr = NULL; EventFnList *event_fn_ptr = NULL; Module *mod_ptr = NULL; hnode_t *mn; strcpy(segv_location, "load_module"); if (u == NULL) { do_msg = 0; } else { do_msg = 1; } path = sstrdup(path1); path = strcat(path,".so"); dl_handle = dlopen(path, RTLD_NOW || RTLD_GLOBAL); if (!dl_handle) { snprintf(p, 255, "%s/%s", me.modpath, path); dl_handle = dlopen(p, RTLD_NOW || RTLD_GLOBAL); } if (!dl_handle) { if (do_msg) prefmsg(u->nick, s_Services, "Error, Couldn't Load Module"); if (do_msg) prefmsg(u->nick, s_Services, "%s",dlerror()); log("Couldn't Load Module: %s", dlerror()); return -1; } mod_get_info = dlsym(dl_handle, "__module_get_info"); #ifndef HAVE_LIBDL if (mod_get_info == NULL) { dl_error = dlerror(); #else if ((dl_error = dlerror()) != NULL) { #endif if (do_msg) prefmsg(u->nick, s_Services, "Error, Couldn't Load Module"); if (do_msg) prefmsg(u->nick, s_Services, "%s",dl_error); log("Couldn't Load Module: %s", dl_error); dlclose(dl_handle); return -1; } mod_get_funcs = dlsym(dl_handle, "__module_get_functions"); #ifndef HAVE_LIBDL if (mod_get_info == NULL) { dl_error = dlerror(); #else if ((dl_error = dlerror()) != NULL) { #endif if (do_msg) prefmsg(u->nick, s_Services, "Error, Couldn't Load Module"); if (do_msg) prefmsg(u->nick, s_Services, "%s",dl_error); log("Couldn't Load Module: %s", dl_error); dlclose(dl_handle); return -1; } mod_get_events = dlsym(dl_handle, "__module_get_events"); /* no error check here - this one isn't essential to the functioning of the module */ mod_info_ptr = (*mod_get_info)(); mod_funcs_ptr = (*mod_get_funcs)(); if (mod_get_events) event_fn_ptr = (*mod_get_events)(); if (mod_info_ptr == NULL || mod_funcs_ptr == NULL) { dlclose(dl_handle); log("%s: Could not load dynamic library %s!\n", __PRETTY_FUNCTION__, path); log("Couldn't Load Module: %s", dlerror()); return -1; } /* Check that the Module hasn't already been loaded */ if (hash_lookup(mh, mod_info_ptr->module_name)) { dlclose(dl_handle); if (do_msg) prefmsg(u->nick,s_Services,"Module %s already Loaded, Can't Load 2 Copies",mod_info_ptr->module_name); free(mod_ptr); return -1; } mod_ptr = (Module *)smalloc(sizeof(Module)); mn = hnode_create(mod_ptr); if (hash_isfull(mh)) { if (do_msg) chanalert(s_Services, "Module List is Full. Can't Load any more modules"); if (do_msg) prefmsg(u->nick, s_Services, "Module List is Full, Can't Load any more Modules"); dlclose(dl_handle); free(mod_ptr); return -1; } else { hash_insert(mh, mn, mod_info_ptr->module_name); } log("internal module name: %s", mod_info_ptr->module_name); log("module description: %s", mod_info_ptr->module_description); mod_ptr->info = mod_info_ptr; mod_ptr->function_list = mod_funcs_ptr; mod_ptr->dl_handle = dl_handle; mod_ptr->other_funcs = event_fn_ptr; /* Let this module know we are online if we are! */ if (me.onchan == 1) { while (event_fn_ptr->cmd_name != NULL ) { if (!strcasecmp(event_fn_ptr->cmd_name, "ONLINE")) { AddStringToList(&av, me.s->name, &ac); event_fn_ptr->function(av, ac); FreeList(av, ac); break; } event_fn_ptr++; } } if (do_msg) prefmsg(u->nick,s_Services,"Module %s Loaded, Description: %s",mod_info_ptr->module_name,mod_info_ptr->module_description); return 0; } extern int get_dl_handle(char *mod_name) { Module *list_ptr; hnode_t *mn; strcpy(segv_location, "get_dl_handle"); mn = hash_lookup(mh, mod_name); if (mn) { list_ptr=hnode_get(mn); return (int)list_ptr->dl_handle; } return 0; } void list_module(User *u) { Module *mod_ptr = NULL; hnode_t *mn; hscan_t hs; strcpy(segv_location, "list_module"); hash_scan_begin(&hs, mh); while ((mn = hash_scan_next(&hs)) != NULL) { mod_ptr=hnode_get(mn); prefmsg(u->nick,s_Services,"Module: %s (%s)",mod_ptr->info->module_name, mod_ptr->info->module_version); prefmsg(u->nick,s_Services,"Module Description: %s",mod_ptr->info->module_description); } prefmsg(u->nick,s_Services,"End of Module List"); } int unload_module(char *module_name, User *u) { Module *list; Mod_User *mod_ptr = NULL; Mod_Timer *mod_tmr = NULL; Sock_List *mod_sock = NULL; hnode_t *modnode; hscan_t hscan; strcpy(segv_location, "unload_module"); /* Check to see if this Module has any timers registered.... */ chanalert(s_Services, "Unloading Module %s", module_name); hash_scan_begin(&hscan, th); while ((modnode = hash_scan_next(&hscan)) != NULL) { mod_tmr = hnode_get(modnode); if (!strcasecmp(mod_tmr->modname, module_name)) { chanalert(s_Services, "Module %s has timer %s Registered. Deleting..", module_name, mod_tmr->timername); del_mod_timer(mod_tmr->timername); } } /* check if the module had a socket registered... */ hash_scan_begin(&hscan, sockh); while ((modnode = hash_scan_next(&hscan)) != NULL) { mod_sock = hnode_get(modnode); if (!strcasecmp(mod_sock->modname, module_name)) { notice (s_Services, "Module %s had Socket %s Registered. Deleting..", module_name, mod_sock->sockname); del_socket(mod_sock->sockname); } } /* now, see if this Module has any bots with it */ hash_scan_begin(&hscan, bh); while ((modnode = hash_scan_next(&hscan)) != NULL) { mod_ptr = hnode_get(modnode); if (!strcasecmp(mod_ptr->modname, module_name)) { chanalert(s_Services,"Module %s had bot %s Registered. Deleting..",module_name,mod_ptr->nick); del_bot(mod_ptr->nick, "Module Unloaded"); } } modnode = hash_lookup(mh, module_name); if (modnode) { #ifdef DEBUG log("Deleting Module %s from ModHash", module_name); #endif list = hnode_get(modnode); hash_delete(mh, modnode); hnode_destroy(modnode); dlclose(list->dl_handle); free(list); return 1; } else { if (u) { prefmsg(u->nick,s_Services,"Couldn't Find Module %s Loaded, Try /msg %s modlist",module_name,s_Services); chanalert(s_Services,"%s tried to Unload %s but its not loaded",u->nick,module_name); } } return -1; }