Merge branch 'master' into SpamServ
authorNurPech <nurpech@nurpech.de>
Tue, 27 Aug 2013 19:09:35 +0000 (21:09 +0200)
committerNurPech <nurpech@nurpech.de>
Tue, 27 Aug 2013 19:09:54 +0000 (21:09 +0200)
src/mod-watchdog.c
src/spamserv.c
src/spamserv.h
src/spamserv.help

index 0edf09dfb5cec806111b9e91cf6809ab70f38d03..23b68c55ac7d43887b6b252a66c40c0f205e1070 100644 (file)
@@ -543,7 +543,7 @@ watchdog_conf_read(void)
     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);
+       str = database_get_data(conf_node, "alert_channel", RECDB_QSTRING);
        if(str)
        {
                watchdog_conf.alert_channel = AddChannel(str, now, "+tinms", NULL);
index e4bcf4bb76161800364b5c785ece033286c91af0..178818395a46ae011fcb9b0c48aac44e4080ce40 100644 (file)
 #define KEY_INFO                     "info"
 #define KEY_EXCEPTLEVEL              "exceptlevel"
 #define KEY_EXPIRY                   "expiry"
+#define KEY_LASTBADWORDID            "last_badword_id"
+#define KEY_BADWORDS                 "badwords"
+
+#define KEY_BADWORD_MASK             "mask"
+#define KEY_BADWORD_TRIGGERED        "count"
+#define KEY_BADWORD_ACTION           "action"
+#define KEY_BADWORDID                "badwordid"
 
 #define KEY_DEBUG_CHANNEL            "debug_channel"
 #define KEY_OPER_CHANNEL            "oper_channel"
@@ -123,6 +130,16 @@ static const struct message_entry msgtab[] = {
     { "SSMSG_STATUS_MEMORY",           "$bMemory Information:$b" },
     { "SSMSG_STATUS_CHANNEL_LIST",     "$bRegistered Channels:$b" },
     { "SSMSG_STATUS_NO_CHANNEL",       "No channels registered." },
+    
+    { "SSMSG_BADWORD_ALREADY_ADDED",   "$b%s$b is already added. (ID: %s)" },
+    { "SSMSG_BADWORD_ADDED",           "added '$b%s$b' to the badword list with ID %s." },
+    { "SSMSG_BADWORD_SET_DONE",        "Done." },
+    { "SSMSG_BADWORD_SET_INVALID",     "Invalid Option for setting %s" },
+    { "SSMSG_BADWORD_SET",             "Settings for BadWord entry $b%s$b" },
+    { "SSMSG_BADWORD_SET_MASK",        "$bMASK$b:   %s" },
+    { "SSMSG_BADWORD_SET_ACTION",      "$bACTION$b: %s" },
+    { "SSMSG_BADWORD_NOT_FOUND",       "badword with ID %s does not exist." },
+    { "SSMSG_BADWORD_REMOVED",         "badword ID $b%s$b has been removed (mask: '%s')" },
        { NULL, NULL }
 };
 
@@ -139,6 +156,7 @@ static const struct message_entry msgtab[] = {
 #define SSMSG_WARNING_2               "You are violating the network rules"
 #define SSMSG_WARNING_RULES           "%s is against the network rules. Read the network rules at %s"
 #define SSMSG_WARNING_RULES_2         "You are violating the network rules. Read the network rules at %s"
+#define SSMSG_BADWORD_DETECTED           "Your message contained a forbidden word."
 #define SSMSG_CHANNEL_REGISTERED      "%s (channel %s) registered by %s."
 #define SSMSG_CHANNEL_UNREGISTERED    "%s (channel %s) unregistered by %s."
 
@@ -672,6 +690,27 @@ spamserv_user_part(struct modeNode *mn, UNUSED_ARG(const char *reason))
        }
 }
 
+static struct badword*
+add_badword(struct chanInfo *cInfo, const char *badword_mask, unsigned int triggered, unsigned int action, const char *id)
+{
+    struct badword *badword;
+
+    badword = calloc(1, sizeof(*badword));
+    if (!badword)
+        return NULL;
+
+    if(!id) {
+        cInfo->last_badword_id++;
+        badword->id = strtab(cInfo->last_badword_id);
+    } else
+        badword->id = strdup(id);
+    badword->badword_mask = strdup(badword_mask);
+    badword->triggered = triggered;
+    badword->action = action;
+    dict_insert(cInfo->badwords, badword->id, badword);
+    return badword;
+}
+
 /***********************************************/
 /*                 Other Stuff                 */
 /***********************************************/
@@ -1146,7 +1185,7 @@ SPAMSERV_FUNC(cmd_unregister)
        
        spamserv_unregister_channel(cInfo);     
 
-       spamserv_oper_message(SSMSG_CHANNEL_UNREGISTERED, channel->name, user->handle_info->handle);
+       spamserv_oper_message(SSMSG_CHANNEL_UNREGISTERED, spamserv->nick, channel->name, user->handle_info->handle);
        ss_reply("SSMSG_UNREG_SUCCESS", channel->name);
 
        return 1;
@@ -1441,6 +1480,272 @@ SPAMSERV_FUNC(opt_exceptlevel)
     return 1;
 }
 
+static SPAMSERV_FUNC(cmd_addbad)
+{
+        struct chanInfo *cInfo = get_chanInfo(channel->name);
+        struct userData *uData;
+
+        if(!cInfo)
+        {
+               ss_reply("SSMSG_NOT_REGISTERED", channel->name);
+               return 0;
+        }
+
+        if(CHECK_SUSPENDED(cInfo))
+        {
+                ss_reply("SSMSG_SUSPENDED", channel->name);
+            return 0;
+        }
+
+        if(!check_user_level(channel,user,lvlSetters,1,0))
+        {
+               ss_reply("SSMSG_NO_ACCESS");
+               return 0;
+        }
+
+        dict_iterator_t it;
+        char *mask = unsplit_string(argv + 1, argc - 1, NULL);
+        for (it = dict_first(cInfo->badwords); it; it = iter_next(it)) {
+                struct badword *badword = iter_data(it);
+                if(match_ircglob(mask,badword->badword_mask)) {
+                        reply("SSMSG_BADWORD_ALREADY_ADDED", mask, badword->id);
+                        return 1;
+                }
+        }
+
+        struct badword *new_badword = add_badword(cInfo, mask, 0, BADACTION_KICK, NULL);
+        for (it = dict_first(cInfo->badwords); 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(cInfo->badwords, badword->id);
+                }
+        }
+
+        reply("SSMSG_BADWORD_ADDED", new_badword->badword_mask, new_badword->id);
+        return 1;
+}
+
+static SPAMSERV_FUNC(cmd_delbad)
+{
+        struct chanInfo *cInfo = get_chanInfo(channel->name);
+        struct userData *uData;
+        unsigned int n;
+
+        if(!cInfo)
+        {
+                ss_reply("SSMSG_NOT_REGISTERED", channel->name);
+                return 0;
+        }
+
+        if(CHECK_SUSPENDED(cInfo))
+        {
+                ss_reply("SSMSG_SUSPENDED", channel->name);
+            return 0;
+        }
+
+        if(!check_user_level(channel,user,lvlSetters,1,0))
+        {
+                ss_reply("SSMSG_NO_ACCESS");
+                return 0;
+        }
+
+        for (n=1; n<argc; n++) {
+                struct badword *badword = dict_find(cInfo->badwords, argv[n], NULL);
+                if (!badword) {
+                        reply("SSMSG_BADWORD_NOT_FOUND", argv[n]);
+                        continue;
+                }
+                reply("SSMSG_BADWORD_REMOVED", argv[n], badword->badword_mask);
+                dict_remove(cInfo->badwords, argv[n]);
+        }
+        return 1;
+}
+
+static SPAMSERV_FUNC(cmd_setbad)
+{
+        struct chanInfo *cInfo = get_chanInfo(channel->name);
+        struct userData *uData;
+        struct badword *badword;
+
+        if(!cInfo)
+        {
+                ss_reply("SSMSG_NOT_REGISTERED", channel->name);
+                return 0;
+        }
+
+        if(CHECK_SUSPENDED(cInfo))
+        {
+                ss_reply("SSMSG_SUSPENDED", channel->name);
+                return 0;
+        }
+
+        if(!check_user_level(channel,user,lvlSetters,1,0))
+        {
+                ss_reply("SSMSG_NO_ACCESS");
+                return 0;
+        }
+
+        if ((badword = dict_find(cInfo->badwords, 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("SSMSG_BADWORD_SET_DONE");
+                        }
+                        else if(!strcmp("ACTION",setting)) {
+                                 if (!strcmp("1",value) || !strcmp("KICK",value)) {
+                                        badword->action = BADACTION_KICK;
+                                        reply("SSMSG_BADWORD_SET_DONE");
+                                 } else if (!strcmp("2",value) || !strcmp("BAN",value)) {
+                                        badword->action = BADACTION_BAN;
+                                        reply("SSMSG_BADWORD_SET_DONE");
+                                 } else if (!strcmp("3",value) || !strcmp("KILL",value)) {
+                                        badword->action = BADACTION_KILL;
+                                        reply("SSMSG_BADWORD_SET_DONE");
+                                 } else if (!strcmp("4",value) || !strcmp("GLINE",value)) {
+                                        badword->action = BADACTION_GLINE;
+                                        reply("SSMSG_BADWORD_SET_DONE");
+                                 } else {
+                                        reply("SSMSG_BADWORD_SET_INVALID", setting);
+                                 }
+                        } else {
+                                 reply("SSMSG_BADWORD_SETTING_INVALID", setting);
+                        }
+
+                } else {
+                        reply("SSMSG_BADWORD_SET", badword->id);
+                        reply("SSMSG_BADWORD_SET_MASK", badword->badword_mask);
+                        switch(badword->action) {
+                                case BADACTION_KICK:
+                                  reply("SSMSG_BADWORD_SET_ACTION", "KICK");
+                                  break;
+                                case BADACTION_BAN:
+                                  reply("SSMSG_BADWORD_SET_ACTION", "BAN");
+                                  break;
+                                case BADACTION_KILL:
+                                  reply("SSMSG_BADWORD_SET_ACTION", "KILL");
+                                  break;
+                                case BADACTION_GLINE:
+                                  reply("SSMSG_BADWORD_SET_ACTION", "GLINE");
+                                  break;
+                                default:
+                                  reply("SSMSG_BADWORD_SET_ACTION", "*undef*");
+                        }
+                }
+        } else {
+                reply("SSMSG_BADWORD_NOT_FOUND", argv[1]);
+                return 0;
+        }
+        return 1;
+}
+
+int
+ss_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 SPAMSERV_FUNC(cmd_listbad)
+{
+        struct helpfile_table tbl;
+        struct chanInfo *cInfo = get_chanInfo(channel->name);
+        struct userData *uData;
+        struct badword **badwords;
+        unsigned int count = 0, ii = 0;
+
+        if(!cInfo)
+        {
+            ss_reply("SSMSG_NOT_REGISTERED", channel->name);
+                return 0;
+        }
+
+     if(CHECK_SUSPENDED(cInfo))
+        {
+                ss_reply("SSMSG_SUSPENDED", channel->name);
+                return 0;
+        }
+
+        if(!check_user_level(channel,user,lvlSetters,1,0))
+        {
+                ss_reply("SSMSG_NO_ACCESS");
+                return 0;
+        }
+
+        dict_iterator_t it;
+        for (it = dict_first(cInfo->badwords); it; it = iter_next(it)) {
+                count++;
+        }
+
+        tbl.length = count+1;
+        tbl.width = 4;
+        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)";
+        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(cInfo->badwords); it; it = iter_next(it)) {
+            struct badword *bw = iter_data(it);
+            badwords[ii++] = bw;
+         }
+
+        qsort(badwords, count, sizeof(badwords[0]), ss_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);
+        }
+
+        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 void 
 to_lower(char *message)
 {
@@ -1592,6 +1897,45 @@ spamserv_punish(struct chanNode *channel, struct userNode *user, time_t expires,
        KickChannelUser(user, channel, spamserv, reason);       
 }
 
+static void
+spamserv_detected_badword(struct userNode *user, struct chanNode *chan, struct badword *badword)
+{
+    char *hostmask;
+    char *reason = SSMSG_BADWORD_DETECTED;
+    char mask[IRC_NTOP_MAX_SIZE+3] = { '*', '@', '\0' };
+    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, spamserv->nick, now, now, now + spamserv_conf.long_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(spamserv, chan, &change);
+            free(hostmask);
+            break;
+        case BADACTION_KICK:
+            if(GetUserMode(chan, user))
+            KickChannelUser(user, chan, spamserv, reason);
+            break;
+        case BADACTION_KILL:
+            DelUser(user, spamserv, 1, reason);
+            break;
+        case BADACTION_GLINE:
+            irc_ntop(mask + 2, sizeof(mask) - 2, &user->ip);
+            gline_add(spamserv->nick, mask, spamserv_conf.gline_duration, reason, now, now, 0, 1);
+            break;
+        default:
+            //error?
+            break;
+    }
+}
+
 void
 spamserv_channel_message(struct chanNode *channel, struct userNode *user, char *text)
 {
@@ -1754,6 +2098,15 @@ spamserv_channel_message(struct chanNode *channel, struct userNode *user, char *
                        }
                }
        }
+    
+    dict_iterator_t it;
+
+       for (it = dict_first(cInfo->badwords); it; it = iter_next(it)) {
+               struct badword *badword = iter_data(it);
+               if(match_ircglob(text, badword->badword_mask)) {
+                       spamserv_detected_badword(user, channel, badword);
+               }
+       }
 
        if(CHECK_ADV(cInfo) && check_advertising(cInfo, text))
        {
@@ -1841,16 +2194,37 @@ spamserv_channel_message(struct chanNode *channel, struct userNode *user, char *
        }
 }
 
+static int
+spamserv_saxdb_read_shitlist(const char *name, void *data, void *extra)
+{
+       struct record_data *rd = data;
+       struct chanInfo *chan = extra;
+       char *badword;
+       char *triggered, *action;
+
+       if (rd->type == RECDB_OBJECT) {
+               dict_t obj = GET_RECORD_OBJECT(rd);
+               /* new style structure */
+               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);
+
+               add_badword(chan, badword, strtoul(triggered, NULL, 0), strtoul(action, NULL, 0), name);
+       }
+       return 0;
+}
+
 static int
 spamserv_saxdb_read(struct dict *database)
 {
        dict_iterator_t it;
+       struct dict *badwords;
        struct record_data *hir;
        struct chanNode *channel;
        struct chanInfo *cInfo;
        struct string_list *strlist;
-       unsigned int flags,exceptlevel;
-       char *str, *info;       
+       unsigned int flags,exceptlevel,badwordid;
+       char *str, *info;
        unsigned long expiry;    
 
        for(it = dict_first(database); it; it = iter_next(it))
@@ -1892,6 +2266,12 @@ spamserv_saxdb_read(struct dict *database)
                                else
                                        cInfo->suspend_expiry = expiry;                 
                 cInfo->exceptlevel=exceptlevel;
+                cInfo->badwords = dict_new();
+                str = database_get_data(hir->d.object, KEY_LASTBADWORDID, RECDB_QSTRING);
+                badwordid = str ? atoi(str) : 0;
+                cInfo->last_badword_id = badwordid;
+                if ((badwords = database_get_data(hir->d.object, KEY_BADWORDS, RECDB_OBJECT)))
+                       dict_foreach(badwords, spamserv_saxdb_read_shitlist, cInfo);
                        }
                }
                else
@@ -1922,8 +2302,21 @@ spamserv_saxdb_write(struct saxdb_context *ctx)
         saxdb_write_int(ctx, KEY_EXCEPTLEVEL, cInfo->exceptlevel);             
 
                if(cInfo->suspend_expiry)
-                       saxdb_write_int(ctx, KEY_EXPIRY, cInfo->suspend_expiry);                
-
+                       saxdb_write_int(ctx, KEY_EXPIRY, cInfo->suspend_expiry);
+
+               saxdb_write_int(ctx, KEY_LASTBADWORDID, cInfo->last_badword_id);
+               saxdb_start_record(ctx, KEY_BADWORDS, 1);
+               dict_iterator_t itbad;
+               for (itbad = dict_first(cInfo->badwords); itbad; itbad = iter_next(itbad)) {
+                       struct badword *badword = iter_data(itbad);
+                       saxdb_start_record(ctx, badword->id, 1);
+                       saxdb_write_string(ctx, KEY_BADWORDID, badword->id);
+                       saxdb_write_string(ctx, KEY_BADWORD_MASK, badword->badword_mask);
+                       saxdb_write_int(ctx, KEY_BADWORD_ACTION, badword->action);
+                       saxdb_write_int(ctx, KEY_BADWORD_TRIGGERED, badword->triggered);
+                       saxdb_end_record(ctx);
+               }
+               saxdb_end_record(ctx);
                saxdb_end_record(ctx);          
        }
        return 0;
@@ -2057,6 +2450,10 @@ init_spamserv(const char *nick)
        modcmd_register(spamserv_module, "ADDEXCEPTION", cmd_addexception, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
        modcmd_register(spamserv_module, "DELEXCEPTION", cmd_delexception, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
        modcmd_register(spamserv_module, "STATUS", cmd_status, 1, 0, NULL);
+    modcmd_register(spamserv_module, "ADDBAD", cmd_addbad, 2, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+    modcmd_register(spamserv_module, "DELBAD", cmd_delbad, 2, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+    modcmd_register(spamserv_module, "SETBAD", cmd_setbad, 2, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
+    modcmd_register(spamserv_module, "LISTBAD", cmd_listbad, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
        modcmd_register(spamserv_module, "SET", cmd_set, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
        modcmd_register(spamserv_module, "SET SPAMLIMIT", opt_spamlimit, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
        modcmd_register(spamserv_module, "SET ADVREACTION", opt_advreaction, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_CHANNEL, NULL);
index b6b6ac61c6ccda29b71924695938c940f8d6c6c7..d74c85dbd383b844f7b15f558c0c0c4aa03593ba 100644 (file)
@@ -58,14 +58,21 @@ enum channelinfo
 #define CHECK_VOICED(x)                ((x)->flags & CHAN_SCAN_VOICED)
 #define CHECK_SUSPENDED(x)     ((x)->flags & CHAN_SUSPENDED)
 
+#define BADACTION_KICK   0
+#define BADACTION_BAN    1
+#define BADACTION_KILL   2
+#define BADACTION_GLINE  3
+
 struct chanInfo
 {
     struct chanNode        *channel;
     struct string_list     *exceptions;
+    dict_t                        badwords;
     unsigned int           flags : 30;
     unsigned int           exceptlevel;
     char                   info[CHAN_INFO_SIZE];
     unsigned long          suspend_expiry;
+    unsigned int                  last_badword_id;
 };
 
 /***********************************************/
@@ -151,6 +158,13 @@ struct userInfo
        time_t                  lastadv;
 };
 
+struct badword {
+    char *id;
+    char *badword_mask;
+    unsigned int triggered : 29;
+    unsigned int action : 3;
+};
+
 /***********************************************/
 /*                 Other Stuff                 */
 /***********************************************/
@@ -168,5 +182,6 @@ void spamserv_channel_message(struct chanNode *channel, struct userNode *user, c
 void spamserv_cs_suspend(struct chanNode *channel, time_t expiry, int suspend, char *reason);
 int  spamserv_cs_move_merge(struct userNode *user, struct chanNode *channel, struct chanNode *target, int move);
 void spamserv_cs_unregister(struct userNode *user, struct chanNode *channel, enum cs_unreg type, char *reason);
+static struct badword *add_badword(struct chanInfo *cInfo, const char *badword_mask, unsigned int triggered, unsigned int action, const char *id);
 
-#endif
\ No newline at end of file
+#endif
index 23ee5ceb3ec9c8ecdb0329f599882c379f286395..63676f4d3a791dc871d5fe50f08d80fd4879c43c 100644 (file)
@@ -6,19 +6,23 @@
         "  SET           Changes various channel settings.",
         "  STATUS        Shows general information about $X.",
         "  VERSION       Prints the srvx and $X version information.",
+        "  ADDBAD        Adds a new badword with the given mask to the badwordlist of the specified channel.",
+        "  DELBAD        Deletes the given badword from the badwordlist of the specified channel.",
+        "  SETBAD        This command will set various badword options.",
+        "  LISTBAD       Causes $X to send you the badwordlist of the specified channel.",
         "$bStaff Commands:$b",
         "  REGISTER      Registers a new channel.",
         "  UNREGISTER    Removes $X from a registered channel.");
 "ADDEXCEPTION" ("/msg $X ADDEXCEPTION [word]",
         "Without an argument, it will show all existing exceptions.",
-         "With an argument, it will add the given word to the exception list.",
-         "$X checks, if one of the words in the sentence of a user is in the exception list; if so, $X will not punish the user, doesn't matter, if it's a bad advertisement.",
-         "This means, you have to make sure, all exceptions are adequate.",
-         "$bFirst example$b: You added the word \"gamesurge.net\" to the exception list and someone posts \"www.gamesurge.net/aup\", he won't get punished.",
-         "$bSecond example$b: You added the word \"support\" to the list and someone tells another person to join #support, he won't get punished.",
-         "$bThird example$b: You added \"GameSurge\" to the list and someone posts \"JOIN #channelxyz on GameSurge\", he will NOT get punished, because the word \"GameSurge\" is in the sentence.",
-         "If he would say \"JOIN #channelxyz\", $X would punish him.",
-         "$uSee Also:$u delexception");
+      "With an argument, it will add the given word to the exception list.",
+      "$X checks, if one of the words in the sentence of a user is in the exception list; if so, $X will not punish the user, doesn't matter, if it's a bad advertisement.",
+      "This means, you have to make sure, all exceptions are adequate.",
+      "$bFirst example$b: You added the word \"gamesurge.net\" to the exception list and someone posts \"www.gamesurge.net/aup\", he won't get punished.",
+      "$bSecond example$b: You added the word \"support\" to the list and someone tells another person to join #support, he won't get punished.",
+      "$bThird example$b: You added \"GameSurge\" to the list and someone posts \"JOIN #channelxyz on GameSurge\", he will NOT get punished, because the word \"GameSurge\" is in the sentence.",
+      "If he would say \"JOIN #channelxyz\", $X would punish him.",
+      "$uSee Also:$u delexception");
 "DELEXCEPTION" ("/msg $X DELEXCEPTION",
         "Without an argument, it will show all existing exceptions.",
         "With an argument, it will delete the given word from the exception list.",
         "If you are not network staff, you must add $bCONFIRM$b to the end of your line to confirm unregistration.",
         "$bSee Also:$b register");
 "VERSION" ("/msg $X VERSION",
-        "$bVERSION$b causes $X to send you the srvx version and some additional version information about $X.");
\ No newline at end of file
+        "$bVERSION$b causes $X to send you the srvx version and some additional version information about $X.");
+"LISTBAD" ("/msg $X <#channel> LISTBAD",
+        "$bLIST$b causes $X to send you the badwordlist of the specified channel");
+"ADDBAD" ("/msg $X <#channel> ADDBAD <MASK>",
+        "$bADDBAD$b adds a new badword with the given mask to the badwordlist of the specified channel");
+"DELBAD" ("/msg $X <#channel> DELBAD <badwordid>",
+        "$bDELBAD$b deletes the given badword from the badwordlist of the specified channel");
+"SETBAD" ("/msg $X SETBAD <#channel> <badwordid> [<parameter> [setting]]",
+        "This command will set various badword options. With no parameters, it will show the current values of all settings of the given badword.",
+        "Only channel owners and coowners may change settings.",
+        "MASK:      Mask of the given badword.",
+        "ACTION:    What happens when someone used the given badword.",
+        "$uSee Also:$u setbad action");
+"SETBAD ACTION" ("/msg $X SETBAD <#channel> <badwordid> ACTION <KICK|BAN|KILL|GLINE>",
+        "What happens when someone used the given badword.");
\ No newline at end of file