/* Ban exception related functions.
*
* IRC Services is copyright (c) 1996-2007 Andrew Church.
* E-mail: <achurch@achurch.org>
* 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 "banexcept.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 +/-e. */
static int do_channel_mode(const char *source, Channel *chan,
int modechar, int add, char **av)
{
if (modechar == 'e') {
if (add) {
ARRAY_EXTEND(chan->excepts);
chan->excepts[chan->excepts_count-1] = sstrdup(av[0]);
} else {
int i;
ARRAY_SEARCH_PLAIN(chan->excepts, av[0], irc_stricmp, i);
if (i < chan->excepts_count) {
free(chan->excepts[i]);
ARRAY_REMOVE(chan->excepts, i);
} else {
module_log("banexcept: MODE %s -e %s: exception not found",
chan->name, *av);
}
}
return 0;
}
return 0;
}
/*************************************************************************/
/* Callback to handle clearing exceptions for clear_channel(). */
static void clear_excepts(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_EXCEPTS))
clear_excepts(sender, chan, (what & CLEAR_EXCEPTS) ? param : NULL);
return 0;
}
static void clear_excepts(const char *sender, Channel *chan, const User *u)
{
int i, count;
char **excepts;
if (!chan->excepts_count)
return;
count = chan->excepts_count;
excepts = smalloc(sizeof(char *) * count);
memcpy(excepts, chan->excepts, sizeof(char *) * count);
for (i = 0; i < count; i++) {
if (!u || match_usermask(excepts[i], u)) {
set_cmode(sender, chan, "-e", excepts[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(excepts[i], tmpbuf))
set_cmode(sender, chan, "-e", excepts[i]);
else if (match_wild_nocase(excepts[i], tmpbuf+nicklen))
set_cmode(sender, chan, "-e", excepts[i]);
}
}
free(excepts);
}
/*************************************************************************/
/* Callback to handle ChanServ CLEAR EXCEPTIONS. */
static int do_cs_clear(User *u, Channel *c, const char *what)
{
if (stricmp(what, "EXCEPTIONS") == 0) {
clear_excepts(s_ChanServ, c, NULL);
set_cmode(NULL, c);
notice_lang(s_ChanServ, u, CHAN_CLEARED_EXCEPTIONS, 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("banexcept: Unable to add ChanServ CLEAR callback");
} else {
module_log("banexcept: Unable to resolve symbol `s_ChanServ' in"
" module `chanserv/main', CLEAR EXCEPTIONS 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_banexcept(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("banexcept: Unable to add callbacks");
exit_banexcept();
return 0;
}
protocol_features |= PF_BANEXCEPT;
old_CLEARMODES_DONE =
setstring(OPER_CLEARMODES_DONE, OPER_CLEARMODES_EXCEPT_DONE);
return 1;
}
/*************************************************************************/
void exit_banexcept(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);
}
/*************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1