Kaynağa Gözat

Merge branch '48-voice-updates'

* 48-voice-updates:
  Enforce 'chanmode' minutely (#48)
  Don't kick a user if already devoiced and -m (#48)
  Don't unset +m when unlocking channel from flood (#48)
  Allow any user op (+o) to enable/disable EVOICE (#48)
  Properly log response to flood (#48)
  Document 'voice-moderate' (#48)
  Respect devoices from other bots (#48)
  Set EVOICE on abusive clients (#48)
  Implement devoicing on flood (#48)
  DRY flood punishment (#48)
  Auto set +m when 'voice-moderate' is set (#48)
  Auto unset 'voice-moderate' if 'chanmode -m' is set (#48)
  Add chanset 'voice-moderate' (#48)
Bryan Drewery 14 yıl önce
ebeveyn
işleme
768894cdb3

+ 4 - 0
doc/UPDATES

@@ -47,6 +47,10 @@
   * Add chanset 'color-limit' to handle how many color codes are allowed in a message before kick (#8)
   * Add chanset 'color-limit' to handle how many color codes are allowed in a message before kick (#8)
   * Add chanset 'closed-exempt' which will allow exempting non-users (who are opped or voice) from being kicked. (fixes #171)
   * Add chanset 'closed-exempt' which will allow exempting non-users (who are opped or voice) from being kicked. (fixes #171)
   * Tweak limit range checking such that bot will set limit less often
   * Tweak limit range checking such that bot will set limit less often
+  * Bots now again respect devoices made by other bots and will not revoice those users.
+  * Add chanset 'voice-moderate' which will auto set +m in '+voice' channel and devoice flooding clients instead of kick. (#48)
+  * Bots now will enforce devoices made by ops (user +o) and allow any op (user +o) to revoice to disable that enforcement.
+    This used to use +m to enforce/allowed revoicing.
 
 
 1.3.4 - http://wraith.botpack.net/milestone/1.3.4
 1.3.4 - http://wraith.botpack.net/milestone/1.3.4
   * Fix various compile warnings with newer GCC
   * Fix various compile warnings with newer GCC

+ 2 - 0
doc/help.txt

@@ -437,6 +437,8 @@ See also: link%{+a}, newhub%{-}
                           channel is +protect.
                           channel is +protect.
         $bvoice-non-ident$b   If channel is +voice, clients without an ident will 
         $bvoice-non-ident$b   If channel is +voice, clients without an ident will 
                           be voiced. Set to 0 to not voice clients without ident.
                           be voiced. Set to 0 to not voice clients without ident.
+        $bvoice-moderate$b    If channel is +voice, auto set +m and devoice flooders
+                          instead of kicking them. Set to 0 to disable.
  
  
    The following options choose how to respond to specific events.
    The following options choose how to respond to specific events.
         Each can be set as any of the specified options.
         Each can be set as any of the specified options.

+ 1 - 0
src/chan.h

@@ -197,6 +197,7 @@ struct chanset_t {
   int closed_private;
   int closed_private;
   int closed_invite;
   int closed_invite;
   int closed_exempt_mode;
   int closed_exempt_mode;
+  int voice_moderate;
   deflag_t bad_cookie;
   deflag_t bad_cookie;
   deflag_t manop;
   deflag_t manop;
   deflag_t mdop;
   deflag_t mdop;

+ 11 - 0
src/mod/channels.mod/chanmisc.c

@@ -452,6 +452,16 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
         return ERROR;
         return ERROR;
       }
       }
       chan->closed_ban = atoi(item[i]);
       chan->closed_ban = atoi(item[i]);
+    } else if (!strcmp(item[i], "voice-moderate")) {
+      i++;
+      if (i >= items) {
+        if (result)
+          strlcpy(result, "channel voice-moderate needs argument", RESULT_LEN);
+        return ERROR;
+      }
+      chan->voice_moderate = atoi(item[i]);
+      if (chan->mode_mns_prot & CHANMODER && chan->voice_moderate)
+        chan->voice_moderate = 0;
     } else if (!strcmp(item[i], "closed-invite")) {
     } else if (!strcmp(item[i], "closed-invite")) {
       i++;
       i++;
       if (i >= items) {
       if (i >= items) {
@@ -1082,6 +1092,7 @@ int channel_add(char *result, const char *newname, char *options, bool isdefault
     chan->closed_ban = 0;
     chan->closed_ban = 0;
     chan->closed_private = 1;
     chan->closed_private = 1;
     chan->closed_invite = 1;
     chan->closed_invite = 1;
+    chan->voice_moderate = 1;
     chan->voice_non_ident = 1;
     chan->voice_non_ident = 1;
     chan->auto_delay = 5;
     chan->auto_delay = 5;
     chan->ban_type = 3;
     chan->ban_type = 3;

+ 6 - 0
src/mod/channels.mod/channels.c

@@ -567,6 +567,9 @@ static void set_mode_protect(struct chanset_t *chan, char *set)
 
 
   if (chan->mode_mns_prot & CHANINV && chan->closed_invite)
   if (chan->mode_mns_prot & CHANINV && chan->closed_invite)
     chan->closed_invite = 0;
     chan->closed_invite = 0;
+
+  if (chan->mode_mns_prot & CHANMODER && chan->voice_moderate)
+    chan->voice_moderate = 0;
 }
 }
 
 
 static void get_mode_protect(struct chanset_t *chan, char *s, size_t ssiz)
 static void get_mode_protect(struct chanset_t *chan, char *s, size_t ssiz)
@@ -790,6 +793,9 @@ void channels_report(int idx, int details)
         if (chan->closed_private)
         if (chan->closed_private)
           strlcat(s2, "p", sizeof(s2));
           strlcat(s2, "p", sizeof(s2));
       }
       }
+      if (channel_voice(chan) && chan->voice_moderate) {
+        strlcat(s2, "m", sizeof(s2));
+      }
 
 
       if (conf.bot->hub || shouldjoin(chan)) {
       if (conf.bot->hub || shouldjoin(chan)) {
 	if (channel_active(chan)) {
 	if (channel_active(chan)) {

+ 1 - 0
src/mod/channels.mod/cmdschan.c

@@ -1258,6 +1258,7 @@ static void cmd_chaninfo(int idx, char *par)
     SHOW_INT("Revenge: ", chan->revenge, DEFLAG_STR, "Ignore");
     SHOW_INT("Revenge: ", chan->revenge, DEFLAG_STR, "Ignore");
     SHOW_INT("Protect-backup: ", chan->protect_backup, "Do!", "Don't!");
     SHOW_INT("Protect-backup: ", chan->protect_backup, "Do!", "Don't!");
     SHOW_INT("Voice-non-ident: ", chan->voice_non_ident, "Do!", "Don't!");
     SHOW_INT("Voice-non-ident: ", chan->voice_non_ident, "Do!", "Don't!");
+    SHOW_INT("Voice-moderate:", chan->voice_moderate, NULL, "Don't!");
 
 
     dprintf(idx, "Flood settings:   chan bytes ctcp join kick deop nick mjoin mpub mbytes mctcp\n");
     dprintf(idx, "Flood settings:   chan bytes ctcp join kick deop nick mjoin mpub mbytes mctcp\n");
     dprintf(idx, "  number:          %3d  %4d  %3d  %3d  %3d  %3d  %3d   %3d  %3d   %4d   %3d\n",
     dprintf(idx, "  number:          %3d  %4d  %3d  %3d  %3d  %3d  %3d   %3d  %3d   %4d   %3d\n",

+ 2 - 1
src/mod/channels.mod/userchan.c

@@ -719,7 +719,7 @@ flood-chan %d:%d flood-bytes %d:%d flood-ctcp %d:%d flood-join %d:%d \
 flood-kick %d:%d flood-deop %d:%d flood-nick %d:%d flood-mjoin %d:%d \
 flood-kick %d:%d flood-deop %d:%d flood-nick %d:%d flood-mjoin %d:%d \
 flood-mpub %d:%d flood-mbytes %d:%d flood-mctcp %d:%d \
 flood-mpub %d:%d flood-mbytes %d:%d flood-mctcp %d:%d \
 capslimit %d colorlimit %d closed-ban %d closed-invite %d closed-private %d closed-exempt %d ban-time %d \
 capslimit %d colorlimit %d closed-ban %d closed-invite %d closed-private %d closed-exempt %d ban-time %d \
-exempt-time %d invite-time %d voice-non-ident %d auto-delay %d \
+exempt-time %d invite-time %d voice-non-ident %d voice-moderate %d auto-delay %d \
 flood-exempt %d flood-lock-time %d knock %d fish-key { %s } \
 flood-exempt %d flood-lock-time %d knock %d fish-key { %s } \
 %cmeankicks %cenforcebans %cdynamicbans %cuserbans %cbitch %cfloodban \
 %cmeankicks %cenforcebans %cdynamicbans %cuserbans %cbitch %cfloodban \
 %cprivate %ccycle %cinactive %cdynamicexempts %cuserexempts \
 %cprivate %ccycle %cinactive %cdynamicexempts %cuserexempts \
@@ -763,6 +763,7 @@ flood-exempt %d flood-lock-time %d knock %d fish-key { %s } \
         chan->exempt_time,
         chan->exempt_time,
         chan->invite_time,
         chan->invite_time,
         chan->voice_non_ident,
         chan->voice_non_ident,
+        chan->voice_moderate,
         chan->auto_delay,
         chan->auto_delay,
         chan->flood_exempt_mode,
         chan->flood_exempt_mode,
         chan->flood_lock_time,
         chan->flood_lock_time,

+ 6 - 3
src/mod/irc.mod/chan.c

@@ -730,9 +730,8 @@ static bool detect_chan_flood(memberlist* m, const char *from, struct chanset_t
           char *s1 = quickban(chan, from);
           char *s1 = quickban(chan, from);
           u_addmask('b', chan, s1, conf.bot->nick, "channel flood", now + (60 * chan->ban_time), 0);
           u_addmask('b', chan, s1, conf.bot->nick, "channel flood", now + (60 * chan->ban_time), 0);
         } else {
         } else {
-          putlog(LOG_MODES, chan->dname, "Channel flood from %s -- kicking", m->nick);
-          dprintf(DP_MODE, "KICK %s %s :%s%s\n", chan->name, m->nick, kickprefix, response(RES_FLOOD));
-          m->flags |= SENTKICK;
+          const char *response = punish_flooder(chan, m);
+          putlog(LOG_MODES, chan->dname, "Channel flood from %s -- %s", m->nick, response);
         }
         }
       }
       }
       return 1;
       return 1;
@@ -1121,6 +1120,10 @@ void recheck_channel_modes(struct chanset_t *chan)
       mns &= ~CHANPRIV;
       mns &= ~CHANPRIV;
     }
     }
   }
   }
+  if (channel_voice(chan) && chan->voice_moderate) {
+    pls |= CHANMODER;
+    mns &= ~CHANMODER;
+  }
 
 
   if (!(chan->ircnet_status & CHAN_ASKEDMODES)) {
   if (!(chan->ircnet_status & CHAN_ASKEDMODES)) {
     if (pls & CHANINV && !(cur & CHANINV))
     if (pls & CHANINV && !(cur & CHANINV))

+ 38 - 7
src/mod/irc.mod/irc.c

@@ -184,29 +184,56 @@ detect_offense(memberlist* m, struct chanset_t *chan, char *msg)
   if (chan->capslimit && caps_count && tot >= 6) {
   if (chan->capslimit && caps_count && tot >= 6) {
     caps_percentage = (caps_count)/(double(tot));
     caps_percentage = (caps_count)/(double(tot));
     if (caps_percentage >= caps_limit) {
     if (caps_percentage >= caps_limit) {
-      putlog(LOG_MODES, chan->name, "Caps flood (%d%%) from %s -- kicking", int(caps_percentage * 100), m->nick);
-      dprintf(DP_SERVER, "KICK %s %s :%s%s\n", chan->name, m->nick, kickprefix, response(RES_FLOOD));
-      m->flags |= SENTKICK;
+      const char *response = punish_flooder(chan, m);
+      putlog(LOG_MODES, chan->name, "Caps flood (%d%%) from %s -- %s", int(caps_percentage * 100), m->nick, response);
       return 1;
       return 1;
     }
     }
   } else if (chan->colorlimit && color_count) {
   } else if (chan->colorlimit && color_count) {
     if (color_count >= chan->colorlimit) {
     if (color_count >= chan->colorlimit) {
-      putlog(LOG_MODES, chan->name, "Color flood (%d) from %s -- kicking", color_count, m->nick);
-      dprintf(DP_SERVER, "KICK %s %s :%s%s\n", chan->name, m->nick, kickprefix, response(RES_FLOOD));
-      m->flags |= SENTKICK;
+      const char *response = punish_flooder(chan, m);
+      putlog(LOG_MODES, chan->name, "Color flood (%d) from %s -- %s", color_count, m->nick, response);
       return 1;
       return 1;
     }
     }
   }
   }
   return 0;
   return 0;
 }
 }
 
 
+void set_devoice(struct chanset_t *chan, memberlist* m) {
+  if (!(m->flags & EVOICE)) {
+    putlog(LOG_DEBUG, "@", "Giving EVOICE flag to: %s (%s)", m->nick, chan->dname);
+    m->flags |= EVOICE;
+  }
+}
+
+const char* punish_flooder(struct chanset_t* chan, memberlist* m, const char *reason) {
+  if (channel_voice(chan) && chan->voice_moderate) {
+    if (!chan_sentdevoice(m)) {
+      add_mode(chan, '-', 'v', m->nick);
+      m->flags |= SENTDEVOICE;
+      set_devoice(chan, m);
+      return "devoicing";
+    } else {
+      return "devoiced";
+    }
+  } else {
+    if (!chan_sentkick(m)) {
+      dprintf(DP_SERVER, "KICK %s %s :%s%s\n", chan->name, m->nick, kickprefix, reason ? reason : response(RES_FLOOD));
+      m->flags |= SENTKICK;
+      return "kicking";
+    } else {
+      return "kicked";
+    }
+  }
+  return "ignoring";
+}
+
 void unlock_chan(struct chanset_t *chan)
 void unlock_chan(struct chanset_t *chan)
 {
 {
   if (chan->channel.drone_set_mode) {
   if (chan->channel.drone_set_mode) {
     char buf[3] = "", *p = buf;
     char buf[3] = "", *p = buf;
     if ((chan->channel.drone_set_mode & CHANINV) && !(chan->mode_pls_prot & CHANINV))
     if ((chan->channel.drone_set_mode & CHANINV) && !(chan->mode_pls_prot & CHANINV))
       *p++ = 'i';
       *p++ = 'i';
-    if ((chan->channel.drone_set_mode & CHANMODER) && !(chan->mode_pls_prot & CHANMODER))
+    if ((chan->channel.drone_set_mode & CHANMODER) && !((chan->mode_pls_prot & CHANMODER) || (channel_voice(chan) && chan->voice_moderate)))
       *p++ = 'm';
       *p++ = 'm';
     *p = 0;
     *p = 0;
     dprintf(DP_MODE, "MODE %s :-%s\n", chan->name[0] ? chan->name : chan->dname, buf);
     dprintf(DP_MODE, "MODE %s :-%s\n", chan->name[0] ? chan->name : chan->dname, buf);
@@ -1554,6 +1581,10 @@ check_expired_chanstuff(struct chanset_t *chan)
     if (bot_ops && !im_opped) {
     if (bot_ops && !im_opped) {
       request_op(chan);
       request_op(chan);
     }
     }
+
+    if (role == 3) {
+      recheck_channel_modes(chan);
+    }
   }
   }
 }
 }
 
 

+ 2 - 0
src/mod/irc.mod/irc.h

@@ -107,6 +107,8 @@ typedef struct resolvstruct resolv_member;
 void resolve_to_rbl(struct chanset_t *chan, const char *host, struct resolvstruct *r = NULL);
 void resolve_to_rbl(struct chanset_t *chan, const char *host, struct resolvstruct *r = NULL);
 static void do_mask(struct chanset_t *chan, masklist *m, char *mask, char Mode);
 static void do_mask(struct chanset_t *chan, masklist *m, char *mask, char Mode);
 static void get_channel_masks(struct chanset_t* chan);
 static void get_channel_masks(struct chanset_t* chan);
+const char* punish_flooder(struct chanset_t* chan, memberlist* m, const char *reason = NULL);
+void set_devoice(struct chanset_t* chan, memberlist* m);
 
 
 #endif /* MAKING_IRC */
 #endif /* MAKING_IRC */
 
 

+ 5 - 8
src/mod/irc.mod/mode.c

@@ -1482,8 +1482,7 @@ gotmode(char *from, char *msg)
 
 
               if (msign == '+') {
               if (msign == '+') {
                 if (mv->flags & EVOICE) {
                 if (mv->flags & EVOICE) {
-                  /* FIXME: This is a lame check, we need to expand on this more */
-                  if (!chan_master(user) && !glob_master(user) && !chk_voice(victim, chan)) {
+                  if (!chk_op(user, chan) && !chk_voice(victim, chan)) {
                     dv = 1;
                     dv = 1;
                   } else {
                   } else {
                     mv->flags &= ~EVOICE;
                     mv->flags &= ~EVOICE;
@@ -1509,14 +1508,12 @@ gotmode(char *from, char *msg)
                     add_mode(chan, '+', 'v', mparam);
                     add_mode(chan, '+', 'v', mparam);
                     /* if they arent +v|v and VOICER is m+ then EVOICE them */
                     /* if they arent +v|v and VOICER is m+ then EVOICE them */
                   } else {
                   } else {
-                    /* FIXME: same thing here */
-                    if (!match_my_nick(nick) && channel_voice(chan) && !glob_bot(user) &&
-                        (glob_master(user) || chan_master(user)) &&
+                    if (!match_my_nick(nick) && channel_voice(chan) &&
+                        (chk_op(user, chan) || glob_bot(user)) &&
                         rfc_casecmp(nick, mparam)) {
                         rfc_casecmp(nick, mparam)) {
                       /* if the user is not +q set them norEVOICE. */
                       /* if the user is not +q set them norEVOICE. */
-                      if (!chan_quiet(victim) && !(mv->flags & EVOICE)) {
-                        putlog(LOG_DEBUG, "@", "Giving EVOICE flag to: %s (%s)", mv->nick, chan->dname);
-                        mv->flags |= EVOICE;
+                      if (!chan_quiet(victim)) {
+                        set_devoice(chan, mv);
                       }
                       }
                     }
                     }
                   }
                   }