X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Fmod-watchdog.c;h=0866b0076d37be6081c3bc0feafee95c78be78a0;hb=58d823d306b690515fbc6f671636d4ec152b867a;hp=975cd1b116194a8c79b64d9cc7fcd91ade66a86b;hpb=bcc710494381568109876a02dae23f4e754b9e07;p=srvx.git diff --git a/src/mod-watchdog.c b/src/mod-watchdog.c index 975cd1b..0866b00 100644 --- a/src/mod-watchdog.c +++ b/src/mod-watchdog.c @@ -22,36 +22,55 @@ * "modules" { * "watchdog" { * "nick" "Watchdog"; - * "modes" "+iok" + * "modes" "+iok"; + "ban_duration" "2h"; //only if the channel is registered with chanserv + "gline_duration" "1h"; + "punishment_reason" "Your message contained a forbidden word."; * }; * }; * */ #include "chanserv.h" +#include "opserv.h" #include "conf.h" #include "modcmd.h" #include "saxdb.h" #include "timeq.h" +#include "gline.h" #define KEY_BADWORDS "badwords" #define KEY_BADWORD_MASK "mask" #define KEY_BADWORD_TRIGGERED "count" #define KEY_BADWORD_ACTION "action" +#define KEY_BADWOR_ALERT "alert" #define KEY_CHANNELS "channel" +#define KEY_BADWORDID "badwordid" static const struct message_entry msgtab[] = { - { "WDMSG_NULL", "null." }, + { "WDMSG_REGISTER_SUCCESS", "$b%s$b is now registered with %s." }, + { "WDMSG_UNREG_SUCCESS", "$b%s$b is now unregistered." }, + { "WDMSG_NOT_REGISTERED", "$b%s$b is not registered with %s." }, + { "WDMSG_ALREADY_ADDED", "$b%s$b is already added. (ID: %s)" }, + { "WDMSG_BADWORD_ADDED", "added '$b%s$b' to the badword list with ID %s." }, + { "WDMSG_BADWORD_NOT_FOUND", "badword with ID %s does not exist." }, + { "WDMSG_BADWORD_REMOVED", "badword ID $b%s$b has been removed (mask: '%s')" }, + { "WDMSG_BADWORD_SET_DONE", "Done." }, + { "WDMSG_BADWORD_SET_INVALID", "Invalid Option for setting %s" }, + { "OSMSG_BADWORD_SETTING_INVALID", "unknown setting $b%s$b." }, + { "WDMSG_BADWORD_SET", "Settings for BadWord entry $b%s$b" }, + { "WDMSG_BADWORD_SET_MASK", "$bMASK$b: %s" }, + { "WDMSG_BADWORD_SET_ACTION", "$bACTION$b: %s" }, + { "WDMSG_BADWORD_SET_ALERT", "$bALERT$b: %d" }, { NULL, NULL } }; -DECLARE_LIST(shitList, struct badword*); -DEFINE_LIST(shitList, struct badword*) - struct badword { + char *id; char *badword_mask; unsigned int triggered : 29; unsigned int action : 3; + unsigned int alert; }; struct watchdog_channel { @@ -60,68 +79,377 @@ struct watchdog_channel { }; /* badword.action fields */ -#define BADACTION_KICK 1 +#define BADACTION_KICK 0 +#define BADACTION_BAN 1 #define BADACTION_KILL 2 #define BADACTION_GLINE 3 +#define WDMSG_BADWORD_ALERT "%s used badword '%s' in channel: %s" + static struct { const char *nick; const char *modes; + const char *punishment_reason; + unsigned long ban_duration; + unsigned long gline_duration; + struct chanNode *alert_channel; + struct chanNode *oper_channel; } watchdog_conf; const char *watchdog_module_deps[] = { NULL }; struct userNode *watchdog; static struct module *watchdog_module; static struct service *watchdog_service; -static struct shitList shitlist; +static dict_t shitlist; static dict_t chanlist; static struct log_type *MS_LOG; +static unsigned int last_badword_id = 0; +static struct watchdog_channel *add_channel(const char *name); +static struct badword *add_badword(const char *badword_mask, unsigned int triggered, unsigned int action, unsigned int alert, const char *id); +#define watchdog_notice(target, format...) send_message(target , watchdog , ## format) +#define watchdog_debug(format...) do { if(watchdog_conf.alert_channel) send_channel_message(watchdog_conf.alert_channel , watchdog , ## format); } while(0) +#define watchdog_oper_message(format...) do { if(watchdog_conf.oper_channel) send_channel_message(watchdog_conf.oper_channel , watchdog , ## format); } while(0) static MODCMD_FUNC(cmd_addbad) { - //to be continued... + dict_iterator_t it; + char *mask = unsplit_string(argv + 1, argc - 1, NULL); + for (it = dict_first(shitlist); it; it = iter_next(it)) { + struct badword *badword = iter_data(it); + if(match_ircglob(mask,badword->badword_mask)) { + reply("WDMSG_ALREADY_ADDED", mask, badword->id); + return 1; + } + } + + struct badword *new_badword = add_badword(mask, 0, BADACTION_KICK, 0, NULL); + for (it = dict_first(shitlist); it; it = iter_next(it)) { + struct badword *badword = iter_data(it); + if(match_ircglob(badword->badword_mask, new_badword->badword_mask) && badword != new_badword) { + dict_remove(shitlist, badword->id); + } + } + + reply("WDMSG_BADWORD_ADDED", new_badword->badword_mask, new_badword->id); return 1; } static MODCMD_FUNC(cmd_delbad) { - //to be continued... + unsigned int n; + + for (n=1; nbadword_mask); + dict_remove(shitlist, argv[n]); + } return 1; } -static MODCMD_FUNC(cmd_editbad) +static MODCMD_FUNC(cmd_setbad) { - //to be continued... + struct badword *badword; + if ((badword = dict_find(shitlist, argv[1], NULL))) { + if (argc > 3) { + unsigned int ii; + char *setting = argv[2]; + char *value = argv[3]; + for( ii = 0; setting[ ii ]; ii++) + setting[ ii ] = toupper( setting[ ii ] ); + for( ii = 0; value[ ii ]; ii++) + value[ ii ] = toupper( value[ ii ] ); + if(!strcmp("MASK",setting)) { + free(badword->badword_mask); + badword->badword_mask = strdup(argv[3]); + badword->triggered = 0; + reply("WDMSG_BADWORD_SET_DONE"); + } + else if(!strcmp("ACTION",setting)) { + if (!strcmp("1",value) || !strcmp("KICK",value)) { + badword->action = BADACTION_KICK; + reply("WDMSG_BADWORD_SET_DONE"); + } else if (!strcmp("2",value) || !strcmp("BAN",value)) { + badword->action = BADACTION_BAN; + reply("WDMSG_BADWORD_SET_DONE"); + } else if (!strcmp("3",value) || !strcmp("KILL",value)) { + badword->action = BADACTION_KILL; + reply("WDMSG_BADWORD_SET_DONE"); + } else if (!strcmp("4",value) || !strcmp("GLINE",value)) { + badword->action = BADACTION_GLINE; + reply("WDMSG_BADWORD_SET_DONE"); + } else { + reply("WDMSG_BADWORD_SET_INVALID", setting); + } + } + else if(!strcmp("ALERT",setting)) { + if (!strcmp("0",value)) { + badword->alert = 0; + reply("WDMSG_BADWORD_SET_DONE"); + } else if (!strcmp("1",value)) { + badword->alert = 1; + reply("WDMSG_BADWORD_SET_DONE"); + } else { + reply("WDMSG_BADWORD_SET_INVALID", setting); + } + } else { + reply("WDMSG_BADWORD_SETTING_INVALID", setting); + } + + } else { + reply("WDMSG_BADWORD_SET", badword->id); + reply("WDMSG_BADWORD_SET_MASK", badword->badword_mask); + switch(badword->action) { + case BADACTION_KICK: + reply("WDMSG_BADWORD_SET_ACTION", "KICK"); + break; + case BADACTION_BAN: + reply("WDMSG_BADWORD_SET_ACTION", "BAN"); + break; + case BADACTION_KILL: + reply("WDMSG_BADWORD_SET_ACTION", "KILL"); + break; + case BADACTION_GLINE: + reply("WDMSG_BADWORD_SET_ACTION", "GLINE"); + break; + default: + reply("WDMSG_BADWORD_SET_ACTION", "*undef*"); + } + reply("WDMSG_BADWORD_SET_ALERT", badword->alert); + } + } else { + reply("WDMSG_BADWORD_NOT_FOUND", argv[1]); + return 0; + } return 1; } +int +badwords_sort(const void *pa, const void *pb) +{ + struct badword *a = *(struct badword**)pa; + struct badword *b = *(struct badword**)pb; + + return strtoul(a->id, NULL, 0) - strtoul(b->id, NULL, 0); +} + static MODCMD_FUNC(cmd_listbad) { - //to be continued... + struct helpfile_table tbl; + unsigned int count = 0, ii = 0; + struct badword **badwords; + + dict_iterator_t it; + for (it = dict_first(shitlist); it; it = iter_next(it)) { + count++; + } + tbl.length = count+1; + tbl.width = 5; + tbl.flags = 0; + tbl.flags = TABLE_NO_FREE; + tbl.contents = malloc(tbl.length * sizeof(tbl.contents[0])); + tbl.contents[0] = malloc(tbl.width * sizeof(tbl.contents[0][0])); + tbl.contents[0][0] = "#"; + tbl.contents[0][1] = "Badword"; + tbl.contents[0][2] = "Action"; + tbl.contents[0][3] = "(Triggered)"; + tbl.contents[0][4] = "Alert"; + if(!count) + { + table_send(cmd->parent->bot, user->nick, 0, NULL, tbl); + reply("MSG_NONE"); + free(tbl.contents[0]); + free(tbl.contents); + return 0; + } + badwords = alloca(count * sizeof(badwords[0])); + for (it = dict_first(shitlist); it; it = iter_next(it)) { + struct badword *bw = iter_data(it); + badwords[ii++] = bw; + } + qsort(badwords, count, sizeof(badwords[0]), badwords_sort); + for (ii = 1; ii <= count; ii++) { + struct badword *bw = badwords[ii-1]; + tbl.contents[ii] = malloc(tbl.width * sizeof(tbl.contents[0][0])); + tbl.contents[ii][0] = strdup(bw->id); + tbl.contents[ii][1] = strdup(bw->badword_mask); + switch(bw->action) { + case BADACTION_KICK: + tbl.contents[ii][2] = "KICK"; + break; + case BADACTION_BAN: + tbl.contents[ii][2] = "BAN"; + break; + case BADACTION_KILL: + tbl.contents[ii][2] = "KILL"; + break; + case BADACTION_GLINE: + tbl.contents[ii][2] = "GLINE"; + break; + default: + tbl.contents[ii][2] = "*undef*"; + } + tbl.contents[ii][3] = strtab(bw->triggered); + tbl.contents[ii][4] = strtab(bw->alert); + } + table_send(cmd->parent->bot, user->nick, 0, NULL, tbl); + for(ii = 1; ii < tbl.length; ++ii) + { + free(tbl.contents[ii]); + } + free(tbl.contents[0]); + free(tbl.contents); return 1; } static MODCMD_FUNC(cmd_register) { - //to be continued... + dict_iterator_t it; + struct modeNode *mn; + + if(channel) + { + + if(channel->bad_channel) + { + reply("CSMSG_ILLEGAL_CHANNEL", channel->name); + return 0; + } + + if(!IsHelping(user) + && (!(mn = GetUserMode(channel, user)) || !(mn->modes & MODE_CHANOP))) + { + reply("CSMSG_MUST_BE_OPPED", channel->name); + return 0; + } + + } + else + { + + if((argc < 2) || !IsChannelName(argv[1])) + { + reply("MSG_NOT_CHANNEL_NAME"); + return 0; + } + + if(opserv_bad_channel(argv[1])) + { + reply("CSMSG_ILLEGAL_CHANNEL", argv[1]); + return 0; + } + + channel = AddChannel(argv[1], now, NULL, NULL); + } + + for (it = dict_first(chanlist); it; it = iter_next(it)) { + struct watchdog_channel *chan = iter_data(it); + if(chan->channel == channel) { + reply("CSMSG_ALREADY_REGGED", channel->name); + return 0; + } + } + + add_channel(channel->name); + reply("WDMSG_REGISTER_SUCCESS", channel->name, watchdog->nick); + watchdog_oper_message("WDMSG_REGISTER_SUCCESS", channel->name, watchdog->nick); return 1; } static MODCMD_FUNC(cmd_unregister) { - //to be continued... - return 1; + struct watchdog_channel *chan = NULL; + dict_iterator_t it; + + for (it = dict_first(chanlist); it; it = iter_next(it)) { + chan = iter_data(it); + if(chan->channel == channel) + break; + } + + if(chan && chan->channel == channel) { + //found, unregister it! + char reason[MAXLEN]; + sprintf(reason, "Unregistered by %s.", user->handle_info->handle); + DelChannelUser(watchdog, channel, reason, 0); + dict_remove(chanlist, channel->name); + reply("CSMSG_UNREG_SUCCESS", channel->name); + watchdog_oper_message("CSMSG_UNREG_SUCCESS", channel->name); + return 1; + } else { + reply("WDMSG_NOT_REGISTERED", channel->name, watchdog->nick); + return 0; + } + } static void -watchdog_channel_message(struct userNode *user, struct chanNode *chan, const char *text, struct userNode *bot, unsigned int is_notice) +watchdog_detected_badword(struct userNode *user, struct chanNode *chan, struct badword *badword) { - //to be continued... + char *hostmask; + char *reason = watchdog_conf.punishment_reason; + char mask[IRC_NTOP_MAX_SIZE+3] = { '*', '@', '\0' }; + if(!IsOper(user)) { + if(badword->alert == 1) { + log_module(MS_LOG, LOG_WARNING, "%s used badword '%s' in channel: %s", user->nick, badword->badword_mask, chan->name); + watchdog_debug(WDMSG_BADWORD_ALERT, user->nick, badword->badword_mask, chan->name); + } + switch(badword->action) { + case BADACTION_BAN: + hostmask = generate_hostmask(user, GENMASK_STRICT_HOST | GENMASK_ANY_IDENT); + sanitize_ircmask(hostmask); + if(chan->channel_info) { + //registered channel + add_channel_ban(chan->channel_info, hostmask, watchdog->nick, now, now, now + watchdog_conf.ban_duration, reason); + } + struct mod_chanmode change; + mod_chanmode_init(&change); + change.argc = 1; + change.args[0].mode = MODE_BAN; + change.args[0].u.hostmask = hostmask; + mod_chanmode_announce(watchdog, chan, &change); + free(hostmask); + + case BADACTION_KICK: + if(GetUserMode(chan, user)) + KickChannelUser(user, chan, watchdog, reason); + break; + case BADACTION_KILL: + DelUser(user, watchdog, 1, reason); + break; + case BADACTION_GLINE: + irc_ntop(mask + 2, sizeof(mask) - 2, &user->ip); + gline_add(watchdog->nick, mask, watchdog_conf.gline_duration, reason, now, now, 0, 1); + break; + default: + //error? + break; + } + } +} + +static void +watchdog_channel_message(struct userNode *user, struct chanNode *chan, const char *text, UNUSED_ARG(struct userNode *bot), UNUSED_ARG(unsigned int is_notice)) +{ + dict_iterator_t it; + + if(!watchdog || !dict_find(chanlist, chan->name, NULL)) + return; + + for (it = dict_first(shitlist); it; it = iter_next(it)) { + struct badword *badword = iter_data(it); + if(match_ircglob(text, badword->badword_mask)) { + watchdog_detected_badword(user, chan, badword); + } + } } static struct badword* -add_badword(char *badword_mask, unsigned int triggered, unsigned int action) +add_badword(const char *badword_mask, unsigned int triggered, unsigned int action, unsigned int alert, const char *id) { struct badword *badword; @@ -129,17 +457,24 @@ add_badword(char *badword_mask, unsigned int triggered, unsigned int action) if (!badword) return NULL; + if(!id) { + last_badword_id++; + badword->id = strtab(last_badword_id); + } else + badword->id = strdup(id); badword->badword_mask = strdup(badword_mask); badword->triggered = triggered; badword->action = action; - shitList_append(&shitlist, badword); + badword->alert = alert; + dict_insert(shitlist, badword->id, badword); return badword; } static void -delete_badword(struct badword *badword) +free_shitlist_entry(void *data) { - shitList_remove(&shitlist, badword); + struct badword *badword = data; + free(badword->id); free(badword->badword_mask); free(badword); } @@ -148,13 +483,22 @@ static struct watchdog_channel* add_channel(const char *name) { struct watchdog_channel *wc; + struct mod_chanmode *change; + + if(!watchdog) //module disabled + return NULL; wc = calloc(1, sizeof(*wc)); if (!wc) return NULL; wc->channel = AddChannel(name, now, NULL, NULL); - AddChannelUser(watchdog, wc->channel)->modes |= MODE_CHANOP; + change = mod_chanmode_alloc(1); + change->argc = 1; + change->args[0].mode = MODE_CHANOP; + change->args[0].u.member = AddChannelUser(watchdog, wc->channel); + mod_chanmode_announce(watchdog, wc->channel, change); + mod_chanmode_free(change); dict_insert(chanlist, wc->channel->name, wc); return wc; } @@ -187,6 +531,35 @@ watchdog_conf_read(void) str = database_get_data(conf_node, "modes", RECDB_QSTRING); watchdog_conf.modes = (str ? str : NULL); + + str = database_get_data(conf_node, "ban_duration", RECDB_QSTRING); + watchdog_conf.ban_duration = str ? ParseInterval(str) : ParseInterval("2h"); + + str = database_get_data(conf_node, "gline_duration", RECDB_QSTRING); + watchdog_conf.gline_duration = str ? ParseInterval(str) : ParseInterval("1h"); + + str = database_get_data(conf_node, "punishment_reason", RECDB_QSTRING); + watchdog_conf.punishment_reason = (str ? str : "Your message contained a forbidden word."); + + str = database_get_data(conf_node, "alert_chan", RECDB_QSTRING); + if(str) + { + watchdog_conf.alert_channel = AddChannel(str, now, "+tinms", NULL); + } + else + { + watchdog_conf.alert_channel = NULL; + } + + str = database_get_data(conf_node, "oper_chan", RECDB_QSTRING); + if(str) + { + watchdog_conf.oper_channel = AddChannel(str, now, "+tinms", NULL); + } + else + { + watchdog_conf.oper_channel = NULL; + } } static int @@ -194,7 +567,7 @@ watchdog_saxdb_read_shitlist(const char *name, void *data, UNUSED_ARG(void *extr { struct record_data *rd = data; char *badword; - char *triggered, *action; + char *triggered, *action, *alert; if (rd->type == RECDB_OBJECT) { dict_t obj = GET_RECORD_OBJECT(rd); @@ -202,11 +575,11 @@ watchdog_saxdb_read_shitlist(const char *name, void *data, UNUSED_ARG(void *extr badword = database_get_data(obj, KEY_BADWORD_MASK, RECDB_QSTRING); triggered = database_get_data(obj, KEY_BADWORD_TRIGGERED, RECDB_QSTRING); action = database_get_data(obj, KEY_BADWORD_ACTION, RECDB_QSTRING); + alert = database_get_data(obj, KEY_BADWOR_ALERT, RECDB_QSTRING); - add_badword(badword, strtoul(triggered, NULL, 0), strtoul(action, NULL, 0)); - return 1; - } else - return 0; + add_badword(badword, strtoul(triggered, NULL, 0), strtoul(action, NULL, 0), strtoul(alert, NULL, 0), name); + } + return 0; } static int @@ -215,53 +588,65 @@ watchdog_saxdb_read_chanlist(const char *name, void *data, UNUSED_ARG(void *extr struct record_data *rd = data; if (rd->type == RECDB_OBJECT) { - dict_t obj = GET_RECORD_OBJECT(rd); + //dict_t obj = GET_RECORD_OBJECT(rd); /* nothing in here, yet */ add_channel(name); - return 1; - } else - return 0; + } + return 0; } static int watchdog_saxdb_read(struct dict *db) { struct dict *object; + char *str; + str = database_get_data(db, KEY_BADWORDID, RECDB_QSTRING); + last_badword_id = str ? strtoul(str, NULL, 0) : 0; + if ((object = database_get_data(db, KEY_BADWORDS, RECDB_OBJECT))) dict_foreach(object, watchdog_saxdb_read_shitlist, NULL); + if ((object = database_get_data(db, KEY_CHANNELS, RECDB_OBJECT))) dict_foreach(object, watchdog_saxdb_read_chanlist, NULL); + return 1; } static int watchdog_saxdb_write(struct saxdb_context *ctx) { - struct badword *badword; - char str[17]; - unsigned int id = 0, ii; dict_iterator_t it; - saxdb_start_record(ctx, KEY_BADWORDS, 1); - for (ii = 0; ii < shitlist.used; ++ii) { - badword = shitlist.list[ii]; - snprintf(str, sizeof(str), "%x", id++); - saxdb_start_record(ctx, str, 0); - saxdb_write_string(ctx, KEY_BADWORD_MASK, badword->badword_mask); - saxdb_write_int(ctx, KEY_BADWORD_TRIGGERED, badword->triggered); - saxdb_write_int(ctx, KEY_BADWORD_ACTION, badword->action); + saxdb_write_int(ctx, KEY_BADWORDID, last_badword_id); + + if (dict_size(shitlist)) { + saxdb_start_record(ctx, KEY_BADWORDS, 1); + for (it = dict_first(shitlist); it; it = iter_next(it)) { + struct badword *badword = iter_data(it); + if(badword && badword->badword_mask) { + saxdb_start_record(ctx, iter_key(it), 0); + + saxdb_write_string(ctx, KEY_BADWORD_MASK, badword->badword_mask); + saxdb_write_int(ctx, KEY_BADWORD_TRIGGERED, badword->triggered); + saxdb_write_int(ctx, KEY_BADWORD_ACTION, badword->action); + saxdb_write_int(ctx, KEY_BADWOR_ALERT, badword->alert); + + saxdb_end_record(ctx); + } + } saxdb_end_record(ctx); } - saxdb_end_record(ctx); if (dict_size(chanlist)) { saxdb_start_record(ctx, KEY_CHANNELS, 1); for (it = dict_first(chanlist); it; it = iter_next(it)) { struct watchdog_channel *wc = iter_data(it); - saxdb_start_record(ctx, wc->channel->name, 0); - //anything else? - saxdb_end_record(ctx); + if(wc && wc->channel && wc->channel->name) { + saxdb_start_record(ctx, wc->channel->name, 0); + //anything else? + saxdb_end_record(ctx); + } } saxdb_end_record(ctx); } @@ -272,9 +657,7 @@ watchdog_saxdb_write(struct saxdb_context *ctx) static void watchdog_cleanup(void) { - while (shitlist.used) - delete_badword(shitlist.list[0]); - shitList_clean(&shitlist); + dict_delete(shitlist); dict_delete(chanlist); } @@ -283,31 +666,35 @@ watchdog_init(void) { MS_LOG = log_register_type("Watchdog", "file:watchdog.log"); - shitList_init(&shitlist); + /* set up shitlist dict */ + dict_delete(shitlist); + shitlist = dict_new(); + dict_set_free_data(shitlist, free_shitlist_entry); /* set up chanlist dict */ dict_delete(chanlist); chanlist = dict_new(); dict_set_free_data(chanlist, free_chanlist_entry); - - conf_register_reload(watchdog_conf_read); - reg_exit_func(watchdog_cleanup); - saxdb_register("Watchdog", watchdog_saxdb_read, watchdog_saxdb_write); const char *nick, *modes; if((nick = conf_get_data("modules/watchdog/nick", RECDB_QSTRING))) { modes = conf_get_data("modules/watchdog/modes", RECDB_QSTRING); watchdog = AddLocalUser(nick, nick, NULL, "Watchdog Service", modes); watchdog_service = service_register(watchdog); + watchdog_service->trigger = ','; reg_allchanmsg_func(watchdog, watchdog_channel_message); } + conf_register_reload(watchdog_conf_read); + reg_exit_func(watchdog_cleanup); + saxdb_register("Watchdog", watchdog_saxdb_read, watchdog_saxdb_write); + watchdog_module = module_register("Watchdog", MS_LOG, "mod-watchdog.help", NULL); - modcmd_register(watchdog_module, "addbad", cmd_addbad, 1, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL); - modcmd_register(watchdog_module, "delbad", cmd_delbad, 1, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL); - modcmd_register(watchdog_module, "editbad", cmd_editbad, 1, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL); + modcmd_register(watchdog_module, "addbad", cmd_addbad, 2, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL); + modcmd_register(watchdog_module, "delbad", cmd_delbad, 2, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL); + modcmd_register(watchdog_module, "setbad", cmd_setbad, 2, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL); modcmd_register(watchdog_module, "listbad", cmd_listbad, 1, MODCMD_REQUIRE_AUTHED, "flags", "+oper", NULL); - modcmd_register(watchdog_module, "register", cmd_register, 1, MODCMD_REQUIRE_AUTHED, "flags", "+helping", NULL); - modcmd_register(watchdog_module, "unregister", cmd_unregister, 1, MODCMD_REQUIRE_AUTHED, "flags", "+helping", NULL); + modcmd_register(watchdog_module, "register", cmd_register, 1, MODCMD_REQUIRE_AUTHED, "flags", "+acceptchan,+helping", NULL); + modcmd_register(watchdog_module, "unregister", cmd_unregister, 1, MODCMD_REQUIRE_AUTHED | MODCMD_REQUIRE_CHANNEL, "flags", "+helping", NULL); message_register_table(msgtab); return 1; @@ -329,5 +716,15 @@ watchdog_finalize(void) { str = database_get_data(conf_node, "modes", RECDB_QSTRING); if (str) watchdog_conf.modes = str; + + str = database_get_data(conf_node, "ban_duration", RECDB_QSTRING); + if (str) watchdog_conf.ban_duration = ParseInterval(str); + + str = database_get_data(conf_node, "gline_duration", RECDB_QSTRING); + if (str) watchdog_conf.gline_duration = ParseInterval(str); + + str = database_get_data(conf_node, "punishment_reason", RECDB_QSTRING); + if (str) watchdog_conf.punishment_reason = str; + return 1; }