/* Invite mask (+I) related functions. * * IRC Services is copyright (c) 1996-2007 Andrew Church. * E-mail: * Parts written by Andrew Kempe and others. * This program is free but copyrighted software; see the file COPYING for * details. */ #include "services.h" #include "modules.h" #include "language.h" #include "modules/chanserv/chanserv.h" #include "invitemask.h" /*************************************************************************/ static Module *module; static Module *module_chanserv; static const char **p_s_ChanServ = NULL; /* we never use it if it's NULL */ #define s_ChanServ (*p_s_ChanServ) /*************************************************************************/ /*************************************************************************/ /* Callback to handle MODE +/-I. */ static int do_channel_mode(const char *source, Channel *chan, int modechar, int add, char **av) { if (modechar == 'I') { if (add) { ARRAY_EXTEND(chan->invites); chan->invites[chan->invites_count-1] = sstrdup(av[0]); } else { int i; ARRAY_SEARCH_PLAIN(chan->invites, av[0], irc_stricmp, i); if (i < chan->invites_count) { free(chan->invites[i]); ARRAY_REMOVE(chan->invites, i); } else { module_log("invitemask: MODE %s -I %s: mask not found", chan->name, *av); } } return 0; } return 0; } /*************************************************************************/ /* Callback to handle clearing invite masks for clear_channel(). */ static void clear_invites(const char *sender, Channel *chan, const User *u); static int do_clear_channel(const char *sender, Channel *chan, int what, const void *param) { if (what & (CLEAR_USERS | CLEAR_INVITES)) clear_invites(sender, chan, (what & CLEAR_INVITES) ? param : NULL); return 0; } static void clear_invites(const char *sender, Channel *chan, const User *u) { int i, count; char **invites; if (!chan->invites_count) return; count = chan->invites_count; invites = smalloc(sizeof(char *) * count); memcpy(invites, chan->invites, sizeof(char *) * count); for (i = 0; i < count; i++) { if (!u || match_usermask(invites[i], u)) { set_cmode(sender, chan, "-I", invites[i]); } else if (u->ipaddr) { char tmpbuf[BUFSIZE]; int nicklen = snprintf(tmpbuf, sizeof(tmpbuf), "%s!", u->nick); snprintf(tmpbuf+nicklen, sizeof(tmpbuf)-nicklen, "%s@%s", u->username, u->ipaddr); if (match_wild_nocase(invites[i], tmpbuf)) set_cmode(sender, chan, "-I", invites[i]); else if (match_wild_nocase(invites[i], tmpbuf+nicklen)) set_cmode(sender, chan, "-I", invites[i]); } } free(invites); } /*************************************************************************/ /* Callback to handle ChanServ CLEAR INVITES. */ static int do_cs_clear(User *u, Channel *c, const char *what) { if (stricmp(what, "INVITES") == 0) { clear_invites(s_ChanServ, c, NULL); set_cmode(NULL, c); notice_lang(s_ChanServ, u, CHAN_CLEARED_INVITES, c->name); return 1; } return 0; } /*************************************************************************/ /*************************************************************************/ /* Callback to watch for modules being loaded. */ static int do_load_module(Module *mod, const char *name) { if (strcmp(name, "chanserv/main") == 0) { module_chanserv = mod; p_s_ChanServ = get_module_symbol(mod, "s_ChanServ"); if (p_s_ChanServ) { if (!(add_callback(mod, "CLEAR", do_cs_clear))) module_log("invitemask: Unable to add ChanServ CLEAR" " callback"); } else { module_log("invitemask: Unable to resolve symbol `s_ChanServ' in" " module `chanserv/main', CLEAR INVITES will not be" " available"); } } return 0; } /*************************************************************************/ /* Callback to watch for modules being unloaded. */ static int do_unload_module(Module *mod) { if (mod == module_chanserv) { p_s_ChanServ = NULL; module_chanserv = NULL; } return 0; } /*************************************************************************/ /*************************************************************************/ static int old_CLEARMODES_DONE = -1; /*************************************************************************/ int init_invitemask(Module *module_) { module = module_; if (!add_callback(NULL, "channel MODE", do_channel_mode) || !add_callback(NULL, "clear channel", do_clear_channel) || !add_callback(NULL, "load module", do_load_module) || !add_callback(NULL, "unload module", do_unload_module) ) { module_log("invitemask: Unable to add callbacks"); exit_invitemask(); return 0; } protocol_features |= PF_INVITEMASK; old_CLEARMODES_DONE = setstring(OPER_CLEARMODES_DONE, OPER_CLEARMODES_EXCEPT_DONE); return 1; } /*************************************************************************/ void exit_invitemask(void) { if (old_CLEARMODES_DONE >= 0) setstring(OPER_CLEARMODES_DONE, old_CLEARMODES_DONE); old_CLEARMODES_DONE = -1; remove_callback(NULL, "unload module", do_unload_module); remove_callback(NULL, "load module", do_load_module); remove_callback(NULL, "clear channel", do_clear_channel); remove_callback(NULL, "channel MODE", do_channel_mode); } /*************************************************************************/