Merge branch 'master' into SpamServ
[srvx.git] / src / spamserv.c
index 9987398772bc4c98737380d9e018fa9b569f37c0..178818395a46ae011fcb9b0c48aac44e4080ce40 100644 (file)
 #define KEY_INFO                     "info"
 #define KEY_EXCEPTLEVEL              "exceptlevel"
 #define KEY_EXPIRY                   "expiry"
-#define KEY_LASTBADWORDID                       "last_badword_id"
+#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_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"
 #define KEY_GLOBAL_EXCEPTIONS        "global_exceptions"
 #define KEY_NETWORK_RULES            "network_rules"
 #define KEY_TRIGGER                  "trigger"
@@ -76,7 +77,8 @@ dict_t connected_users_dict;
 dict_t killed_users_dict;
 
 #define spamserv_notice(target, format...) send_message(target , spamserv , ## format)
-#define spamserv_debug(format...) do { if(spamserv_conf.debug_channel) send_channel_notice(spamserv_conf.debug_channel , spamserv , ## format); } while(0)
+#define spamserv_debug(format...) do { if(spamserv_conf.debug_channel) send_channel_message(spamserv_conf.debug_channel , spamserv , ## format); } while(0)
+#define spamserv_oper_message(format...) do { if(spamserv_conf.oper_channel) send_channel_message(spamserv_conf.oper_channel , spamserv , ## format); } while(0)
 #define ss_reply(format...)    send_message(user , spamserv , ## format)
 
 #define SET_SUBCMDS_SIZE 10
@@ -128,14 +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_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 }
 };
 
@@ -153,10 +157,13 @@ static const struct message_entry msgtab[] = {
 #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."
 
 static struct
 {
        struct chanNode *debug_channel;
+       struct chanNode *oper_channel;
        struct string_list *global_exceptions;
        const char *network_rules;
        unsigned char trigger;
@@ -217,8 +224,6 @@ spamserv_register_channel(struct chanNode *channel, struct string_list *exceptio
     cInfo->exceptlevel = 400;
        safestrncpy(cInfo->info, info, sizeof(cInfo->info));
        cInfo->suspend_expiry = 0;
-       cInfo->badwords = dict_new();
-       cInfo->last_badword_id = 0;
        dict_insert(registered_channels_dict, cInfo->channel->name, cInfo);
 
        return cInfo;
@@ -302,7 +307,8 @@ spamserv_cs_move_merge(struct userNode *user, struct chanNode *channel, struct c
                else
                        snprintf(reason, sizeof(reason), "$X (channel %s) merged into %s by %s.", channel->name, target->name, user->handle_info->handle);
 
-               global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
+               /*global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);*/
+               spamserv_oper_message("%s", reason);
                return 1;
        }
 
@@ -338,7 +344,7 @@ spamserv_cs_unregister(struct userNode *user, struct chanNode *channel, enum cs_
                        spamserv_part_channel(channel, partmsg);
                
                spamserv_unregister_channel(cInfo);
-               global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, global);
+               spamserv_oper_message(SSMSG_CHANNEL_UNREGISTERED, spamserv->nick, channel->name, user->handle_info->handle);
        }
 }
 
@@ -588,7 +594,11 @@ spamserv_user_join(struct modeNode *mNode)
 
        if(user->uplink->burst || !(cInfo = get_chanInfo(channel->name)) || !CHECK_JOINFLOOD(cInfo) || !(uInfo = get_userInfo(user->nick)))
                return 0;
-        
+
+       if(IsOper(user))
+       {
+               return;
+       }
         
     if(!CHECK_CHANOPS(cInfo))
        {
@@ -1093,7 +1103,6 @@ static
 SPAMSERV_FUNC(cmd_register)
 {
        struct chanInfo *cInfo;
-       char reason[MAXLEN];
 
        if(!channel || !channel->channel_info)
        {
@@ -1127,8 +1136,7 @@ SPAMSERV_FUNC(cmd_register)
 
        spamserv_join_channel(cInfo->channel);
        
-       snprintf(reason, sizeof(reason), "%s (channel %s) registered by %s.", spamserv->nick, channel->name, user->handle_info->handle);
-       global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
+       spamserv_oper_message(SSMSG_CHANNEL_REGISTERED, spamserv->nick, channel->name, user->handle_info->handle);
        ss_reply("SSMSG_REG_SUCCESS", channel->name);
 
        return 1;
@@ -1177,8 +1185,7 @@ SPAMSERV_FUNC(cmd_unregister)
        
        spamserv_unregister_channel(cInfo);     
 
-       snprintf(reason, sizeof(reason), "%s (channel %s) unregistered by %s.", spamserv->nick, channel->name, user->handle_info->handle);
-       global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
+       spamserv_oper_message(SSMSG_CHANNEL_UNREGISTERED, spamserv->nick, channel->name, user->handle_info->handle);
        ss_reply("SSMSG_UNREG_SUCCESS", channel->name);
 
        return 1;
@@ -1522,6 +1529,7 @@ static SPAMSERV_FUNC(cmd_delbad)
 {
         struct chanInfo *cInfo = get_chanInfo(channel->name);
         struct userData *uData;
+        unsigned int n;
 
         if(!cInfo)
         {
@@ -1540,6 +1548,17 @@ static SPAMSERV_FUNC(cmd_delbad)
                 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)
@@ -1889,8 +1908,8 @@ spamserv_detected_badword(struct userNode *user, struct chanNode *chan, struct b
             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);
+            //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);
@@ -1899,10 +1918,10 @@ spamserv_detected_badword(struct userNode *user, struct chanNode *chan, struct b
             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);
+            KickChannelUser(user, chan, spamserv, reason);
             break;
         case BADACTION_KILL:
             DelUser(user, spamserv, 1, reason);
@@ -1914,7 +1933,7 @@ spamserv_detected_badword(struct userNode *user, struct chanNode *chan, struct b
         default:
             //error?
             break;
-        }
+    }
 }
 
 void
@@ -1931,6 +1950,11 @@ spamserv_channel_message(struct chanNode *channel, struct userNode *user, char *
        if(!spamserv || quit_services || !GetUserMode(channel, spamserv) || !(cInfo = get_chanInfo(channel->name)) || !(uInfo = get_userInfo(user->nick)))
                return;
 
+       if(IsOper(user))
+       {
+               return;
+       }
+
        if(!CHECK_CHANOPS(cInfo))
        {
                struct modeNode *mn = GetUserMode(channel, user);
@@ -2074,8 +2098,8 @@ spamserv_channel_message(struct chanNode *channel, struct userNode *user, char *
                        }
                }
        }
-
-       dict_iterator_t it;
+    
+    dict_iterator_t it;
 
        for (it = dict_first(cInfo->badwords); it; it = iter_next(it)) {
                struct badword *badword = iter_data(it);
@@ -2193,14 +2217,14 @@ spamserv_saxdb_read_shitlist(const char *name, void *data, void *extra)
 static int
 spamserv_saxdb_read(struct dict *database)
 {
-       dict_iterator_t it, itbad;
-       struct dict *object, *badwords;
-       struct record_data *hir, hirbad;
+       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,badwordid,action,triggered;
-       char *str, *info, *mask;
+       unsigned int flags,exceptlevel,badwordid;
+       char *str, *info;
        unsigned long expiry;    
 
        for(it = dict_first(database); it; it = iter_next(it))
@@ -2247,7 +2271,7 @@ spamserv_saxdb_read(struct dict *database)
                 badwordid = str ? atoi(str) : 0;
                 cInfo->last_badword_id = badwordid;
                 if ((badwords = database_get_data(hir->d.object, KEY_BADWORDS, RECDB_OBJECT)))
-                       dict_foreach(object, spamserv_saxdb_read_shitlist, cInfo);
+                       dict_foreach(badwords, spamserv_saxdb_read_shitlist, cInfo);
                        }
                }
                else
@@ -2311,7 +2335,6 @@ spamserv_conf_read(void)
        }
 
        str = database_get_data(conf_node, KEY_DEBUG_CHANNEL, RECDB_QSTRING);
-
        if(str)
        {
                spamserv_conf.debug_channel = AddChannel(str, now, "+tinms", NULL);
@@ -2324,6 +2347,16 @@ spamserv_conf_read(void)
                spamserv_conf.debug_channel = NULL;
        }
 
+       str = database_get_data(conf_node, KEY_OPER_CHANNEL, RECDB_QSTRING);
+       if(str)
+       {
+               spamserv_conf.oper_channel = AddChannel(str, now, "+tinms", NULL);
+       }
+       else
+       {
+               spamserv_conf.oper_channel = NULL;
+       }
+
        spamserv_conf.global_exceptions = database_get_data(conf_node, KEY_GLOBAL_EXCEPTIONS, RECDB_STRING_LIST);
 
        str = database_get_data(conf_node, KEY_NETWORK_RULES, RECDB_QSTRING);