فهرست منبع

Merge branch '40-revenge'

* 40-revenge: (21 commits)
  Don't punish clients that abuse themselves (#40)
  Use proper DEFLAG_EVENT_REVENGE_BAN (#40)
  Ensure victim is a user to avoid crashing (#40)
  Add missing conversion from 'react' to DEFLAG_REACT
  Avoid excess checks, use the cached matchedUserMembers
  No need to check isexempted() here as it is done above
  Update to standard pattern for looping members/users
  Implement revenge on ban (#40)
  Fix invalid format for channel (#40)
  Implement revenge on deop (#40)
  Use standard mv alias
  Avoid match_my_nick()
  Implement revenge on kick (#40)
  Update old ghost mean code to be revenge (#40)
  Clean got_kick() as it was doing multiple redundant lookups
  Default revenge to 'react' (#40)
  Add 'react' to handle non-user flag change reactions
  Use enums for deflags
  Update docs (#40)
  Add 'revenge [deflag] (#40)
  ...
Bryan Drewery 14 سال پیش
والد
کامیت
84e945fafb

+ 1 - 0
doc/UPDATES

@@ -34,6 +34,7 @@
   * Bots now auto-reop other bots that get deopped
   * Bots now ask for ops quicker if another bot is opped
   * Bots now request/join +ilk channels much quicker
+  * Add 'chanset revenge' which will react/kick/ban/remove users who kick/ban/deop bots.
 
 maint
   * Fix various compile warnings with newer GCC

+ 9 - 6
doc/help.txt

@@ -429,14 +429,17 @@ See also: link%{+a}, newhub%{-}
    The following options choose how to respond to specific events.
         Each can be set as any of the specified options.
         ignore/0           Ignore
-        deop/1             Deop (chattr +d)
-        kick/2             Kick (chattr +k)
+        deop/1             Chattr user +d (deop)
+        kick/2             Chattr user +k (auto kickban)
         delete/remove/3    Remove user
-      
+        react/4            React and punish the client, but don't add or modify
+                             their user flags.
+   These events trigger the bot to react with the above option.
       $bbad-cookie$b             Missing or invalid cookie in bot op line.
-      $bmanop$b                  Users who op manually.
-      $bmdop$b                   Users who mass deop.
-      $bmop$b                    Users who mass op in a -mop chan.
+      $bmanop$b                  Manual op.
+      $bmdop$b                   Mass deop.
+      $bmop$b                    Mass op.
+      $brevenge$b                Client kicking/banning/deopping another bot.
  
    The following can be set + or - (e.g. '%dchanset #channel -enforcebans')
         $bautoop$b         Bots that are +y will auto-op all users with 

+ 1 - 1
doc/responses.txt

@@ -157,7 +157,7 @@
  what's the rush?
  next time you do that, i'll kick you again
  and I thought you were a catcher
-:mean
+:revenge
  hey! that wasn't very nice!
  don't fuck with my pals
  don't touch my buddies like that queer

+ 12 - 17
src/chan.h

@@ -61,10 +61,13 @@ typedef struct memstruct {
 #define chan_wasop(x) (x->flags & WASOP)
 #define chan_stopcheck(x) (x->flags & STOPCHECK)
 
-#define P_IGNORE	0
-#define P_DEOP		1
-#define P_KICK		2
-#define P_DELETE	3
+enum deflag_t {
+  DEFLAG_IGNORE = 0,
+  DEFLAG_DEOP = 1,
+  DEFLAG_KICK = 2,
+  DEFLAG_DELETE = 3,
+  DEFLAG_REACT = 4,
+};
 
 /* Why duplicate this struct for exempts and invites only under another
  * name? <cybah>
@@ -176,10 +179,11 @@ struct chanset_t {
   int closed_ban;
   int closed_private;
   int closed_invite;
-  int bad_cookie;
-  int manop;
-  int mdop;
-  int mop;
+  deflag_t bad_cookie;
+  deflag_t manop;
+  deflag_t mdop;
+  deflag_t mop;
+  deflag_t revenge;
   int voice_non_ident;
   int ban_type;
   interval_t auto_delay;
@@ -189,9 +193,6 @@ struct chanset_t {
  *int temp;
  */
   int flood_exempt_mode;
-#ifdef REVENGE
-  int revenge_mode;
-#endif
   interval_t ban_time;
   interval_t invite_time;
   interval_t exempt_time;
@@ -304,12 +305,6 @@ struct chanset_t *findchan_by_dname(const char *name);
 #define channel_cycle(chan) (chan->status & CHAN_CYCLE)
 #define channel_inactive(chan) (chan->status & CHAN_INACTIVE)
 
-
-#ifdef REVENGE
-#define channel_revenge(chan) (chan->status & CHAN_REVENGE)
-#define channel_revengebot(chan) (chan->status & CHAN_REVENGEBOT)
-#endif 
-
 #define channel_closed(chan) (chan->status & CHAN_CLOSED)
 #define channel_take(chan) (chan->status & CHAN_TAKE)
 #define channel_voice(chan) (chan->status & CHAN_VOICE)

+ 1 - 2
src/chanprog.c

@@ -22,7 +22,6 @@
  * chanprog.c -- handles:
  *   rmspace()
  *   maintaining the server list
- *   revenge punishment
  *   timers, utimers
  *   telling the current programmed settings
  *   initializing a lot of stuff and loading the tcl scripts
@@ -58,7 +57,7 @@
 #include <bdlib/src/Array.h>
 #include <bdlib/src/String.h>
 
-char *def_chanset = "+enforcebans +dynamicbans +userbans -bitch +cycle -inactive +userexempts -dynamicexempts +userinvites -dynamicinvites -nodesynch -closed -take -voice -private -fastop +meankicks ban-type 3 protect-backup 1 groups { main }";
+char *def_chanset = "+enforcebans +dynamicbans +userbans -bitch +cycle -inactive +userexempts -dynamicexempts +userinvites -dynamicinvites -nodesynch -closed -take -voice -private -fastop +meankicks ban-type 3 protect-backup 1 groups { main } revenge react";
 struct chanset_t 	*chanset = NULL;	/* Channel list			*/
 struct chanset_t	*chanset_default = NULL;	/* Default channel list */
 char 			admin[121] = "";	/* Admin info			*/

+ 26 - 26
src/flags.c

@@ -564,64 +564,64 @@ whois_access(struct userrec *user, struct userrec *whois_user)
   return 1;
 }
 
-int deflag_translate(const char *buf)
+deflag_t deflag_translate(const char *buf)
 {
   if (str_isdigit(buf))
-    return (atoi(buf));
+    return (static_cast<deflag_t>(atoi(buf)));
 
   if (!strcasecmp(buf, "ignore"))
-    return P_IGNORE;
+    return DEFLAG_IGNORE;
   else if (!strcasecmp(buf, "deop"))
-    return P_DEOP;
+    return DEFLAG_DEOP;
   else if (!strcasecmp(buf, "kick"))
-    return P_KICK;
+    return DEFLAG_KICK;
   else if (!strcasecmp(buf, "delete") || !strcasecmp(buf, "remove"))
-    return P_DELETE;
-  return P_IGNORE;
+    return DEFLAG_DELETE;
+  else if (!strcasecmp(buf, "react"))
+    return DEFLAG_REACT;
+  return DEFLAG_IGNORE;
 }
 
 
-void deflag_user(struct userrec *u, int why, char *msg, struct chanset_t *chan)
+void deflag_user(struct userrec *u, deflag_event_t why, const char *msg, const struct chanset_t *chan)
 {
   char tmp[30] = "", tmp2[1024] = "";
   struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0 };
   int which = 0;
 
   switch (why) {
-  case DEFLAG_BADCOOKIE:
+  case DEFLAG_EVENT_BADCOOKIE:
     strlcpy(tmp, "Bad op cookie", sizeof(tmp));
     which = chan->bad_cookie;
     break;
-  case DEFLAG_MANUALOP:
+  case DEFLAG_EVENT_MANUALOP:
     strlcpy(tmp, STR("Manual op in -manop channel"), sizeof(tmp));
     which = chan->manop;
     break;
-#ifdef G_MEAN
-  case DEFLAG_MEAN_DEOP:
-    strlcpy(tmp, STR("Deopped bot in +mean channel"), sizeof(tmp));
-    ent = &CFG_MEANDEOP;
+  case DEFLAG_EVENT_REVENGE_DEOP:
+    strlcpy(tmp, STR("Deopped bot in +revenge channel"), sizeof(tmp));
+    which = chan->revenge;
     break;
-  case DEFLAG_MEAN_KICK:
-    strlcpy(tmp, STR("Kicked bot in +mean channel"), sizeof(tmp));
-    ent = &CFG_MEANDEOP;
+  case DEFLAG_EVENT_REVENGE_KICK:
+    strlcpy(tmp, STR("Kicked bot in +revenge channel"), sizeof(tmp));
+    which = chan->revenge;
     break;
-  case DEFLAG_MEAN_BAN:
-    strlcpy(tmp, STR("Banned bot in +mean channel"), sizeof(tmp));
-    ent = &CFG_MEANDEOP;
+  case DEFLAG_EVENT_REVENGE_BAN:
+    strlcpy(tmp, STR("Banned bot in +revenge channel"), sizeof(tmp));
+    which = chan->revenge;
     break;
-#endif /* G_MEAN */
-  case DEFLAG_MDOP:
+  case DEFLAG_EVENT_MDOP:
     strlcpy(tmp, "Mass deop", sizeof(tmp));
     which = chan->mdop;
     break;
-  case DEFLAG_MOP:
+  case DEFLAG_EVENT_MOP:
     strlcpy(tmp, "Mass op", sizeof(tmp));
     which = chan->mop;
     break;
   default:
     simple_snprintf(tmp, sizeof(tmp), "Reason #%i", why);
   }
-  if (which == P_DEOP) {
+  if (which == DEFLAG_DEOP) {
     putlog(LOG_WARN, "*",  "Setting %s +d (%s): %s", u->handle, tmp, msg);
     simple_snprintf(tmp2, sizeof(tmp2), "+d: %s (%s)", tmp, msg);
     set_user(&USERENTRY_COMMENT, u, tmp2);
@@ -640,7 +640,7 @@ void deflag_user(struct userrec *u, int why, char *msg, struct chanset_t *chan)
     /* did anything change? */
     if (fr.match)
       set_user_flagrec(u, &fr, chan->dname);
-  } else if (which == P_KICK) {
+  } else if (which == DEFLAG_KICK) {
     putlog(LOG_WARN, "*",  "Setting %s +dk (%s): %s", u->handle, tmp, msg);
     simple_snprintf(tmp2, sizeof(tmp2), "+dk: %s (%s)", tmp, msg);
     set_user(&USERENTRY_COMMENT, u, tmp2);
@@ -659,7 +659,7 @@ void deflag_user(struct userrec *u, int why, char *msg, struct chanset_t *chan)
     /* did anything change */
     if (fr.match)
       set_user_flagrec(u, &fr, chan->dname);
-  } else if (which == P_DELETE) {
+  } else if (which == DEFLAG_DELETE) {
     putlog(LOG_WARN, "*",  "Deleting %s (%s): %s", u->handle, tmp, msg);
     deluser(u->handle);
   } else {

+ 11 - 12
src/flags.h

@@ -48,16 +48,15 @@ struct flag_record {
  *   unused letters: bchijpstw
  */
 
-#define DEFLAG_BADCOOKIE   1
-#define DEFLAG_MANUALOP    2
-#ifdef G_MEAN
-#  define DEFLAG_MEAN_DEOP   3
-#  define DEFLAG_MEAN_KICK   4
-#  define DEFLAG_MEAN_BAN    5
-#endif /* G_MEAN */
-#define DEFLAG_MDOP        6
-#define DEFLAG_MOP	   7
-
+enum deflag_event_t {
+  DEFLAG_EVENT_BADCOOKIE = 1,
+  DEFLAG_EVENT_MANUALOP,
+  DEFLAG_EVENT_REVENGE_DEOP,
+  DEFLAG_EVENT_REVENGE_KICK,
+  DEFLAG_EVENT_REVENGE_BAN,
+  DEFLAG_EVENT_MDOP,
+  DEFLAG_EVENT_MOP,
+};
 
 #define USER_DEFAULT	0
 
@@ -171,8 +170,8 @@ int dovoice(const struct chanset_t *);
 int doflood(const struct chanset_t *);
 int dolimit(const struct chanset_t *);
 int whois_access(struct userrec *, struct userrec *);
-void deflag_user(struct userrec *, int, char *, struct chanset_t *);
-int deflag_translate(const char *);
+void deflag_user(struct userrec *, deflag_event_t, const char *, const struct chanset_t *);
+deflag_t deflag_translate(const char *);
 
 
 #endif				/* _EGG_FLAGS_H */

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

@@ -398,16 +398,6 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
       key.trim();
       set_fish_key(chan->dname, key);
       strlcpy(chan->fish_key, key.c_str(), sizeof(chan->fish_key));
-/*
-    } else if (!strcmp(item[i], "revenge-mode")) {
-      i++;
-      if (i >= items) {
-        if (result)
-          strlcpy(result, "channel revenge-mode needs argument", RESULT_LEN);
-        return ERROR;
-      }
-      chan->revenge_mode = atoi(item[i]);
-*/
     } else if (!strcmp(item[i], "ban-time")) {
       i++;
       if (i >= items) {
@@ -500,6 +490,14 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
         return ERROR;
       }
       chan->mop = deflag_translate(item[i]);
+    } else if (!strcmp(item[i], "revenge")) {
+      i++;
+      if (i >= items) {
+        if (result)
+          strlcpy(result, "channel revenge needs argument", RESULT_LEN);
+        return ERROR;
+      }
+      chan->revenge = deflag_translate(item[i]);
     } else if (!strcmp(item[i], "knock")) {
       i++;
       if (i >= items) {
@@ -1016,6 +1014,7 @@ int channel_add(char *result, const char *newname, char *options, bool isdefault
     chan->voice_non_ident = 1;
     chan->auto_delay = 5;
     chan->ban_type = 3;
+    chan->revenge = DEFLAG_REACT;
 /* Chanint template
  *  chan->temp = 0;
  */
@@ -1040,7 +1039,6 @@ int channel_add(char *result, const char *newname, char *options, bool isdefault
     chan->flood_nick_time = gfld_nick_time;
     chan->flood_mjoin_thr = 6;
     chan->flood_mjoin_time = 1;
-//    chan->revenge_mode = global_revenge_mode;
     chan->limitraise = 20;
     chan->ban_time = global_ban_time;
     chan->exempt_time = global_exempt_time;

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

@@ -54,7 +54,6 @@
 
 static bool 			use_info = 1;
 static char 			glob_chanmode[64] = "nt";		/* Default chanmode (drummer,990731) */
-//static int 			global_revenge_mode = 3;
 static interval_t 			global_ban_time;
 static interval_t			global_exempt_time;
 static interval_t 			global_invite_time;
@@ -840,12 +839,6 @@ void channels_report(int idx, int details)
 	  i += my_strcpy(s + i, "userbans ");
 	if (channel_bitch(chan))
 	  i += my_strcpy(s + i, "bitch ");
-/*
-	if (channel_revenge(chan))
-	  i += my_strcpy(s + i, "revenge ");
-	if (channel_revenge(chan))
-	  i += my_strcpy(s + i, "revengebot ");
-*/
 	if (channel_secret(chan))
 	  i += my_strcpy(s + i, "secret ");
 	if (channel_cycle(chan))
@@ -896,11 +889,6 @@ void channels_report(int idx, int details)
 	dprintf(idx, "      Options: %s\n", s);
         if (chan->limitraise)
           dprintf(idx, "      Raising limit +%d every 2 minutes\n", chan->limitraise);
-/*
-        if (chan->revenge_mode)
-          dprintf(idx, "      revenge-mode %d\n",
-                  chan->revenge_mode);
-*/
        dprintf(idx, "    Bans last %d mins.\n", chan->ban_time);
        dprintf(idx, "    Exemptions last %d mins.\n", chan->exempt_time);
        dprintf(idx, "    Invitations last %d mins.\n", chan->invite_time);

+ 7 - 8
src/mod/channels.mod/cmdschan.c

@@ -1135,7 +1135,7 @@ static void show_int(int idx, char *work, int *cnt, const char *desc, int state,
 
 #define SHOW_FLAG(name, state) show_flag(idx, work, &cnt, name, state, sizeof(work))
 #define SHOW_INT(desc, state, yes, no) show_int(idx, work, &cnt, desc, state, yes, no, sizeof(work))
-#define P_STR deflag == P_KICK ? "Kick" : (deflag == P_DEOP ? "Deop" : (deflag == P_DELETE ? "Remove" : NULL))
+#define DEFLAG_STR deflag == DEFLAG_KICK ? "Kick" : (deflag == DEFLAG_DEOP ? "Deop" : (deflag == DEFLAG_DELETE ? "Remove" : (deflag == DEFLAG_REACT ? "React" : NULL)))
 #define F_STR(x) x == CHAN_FLAG_OP ? "Op" : (x == CHAN_FLAG_VOICE ? "Voice" : (x == CHAN_FLAG_USER ? "User" : NULL))
 static void cmd_chaninfo(int idx, char *par)
 {
@@ -1208,8 +1208,6 @@ static void cmd_chaninfo(int idx, char *par)
     SHOW_FLAG("private",	channel_privchan(chan));
     SHOW_FLAG("protect",	channel_protect(chan));
     SHOW_FLAG("rbl",		channel_rbl(chan));
-//    SHOW_FLAG("revengebot",	channel_revengebot(chan));
-//    SHOW_FLAG("revenge",	channel_revenge(chan));
     if (HAVE_TAKE)
       SHOW_FLAG("take",		channel_take(chan));
     SHOW_FLAG("voice",		channel_voice(chan));
@@ -1236,7 +1234,7 @@ static void cmd_chaninfo(int idx, char *par)
     dprintf(idx, "Channel settings:\n");
     deflag = chan->bad_cookie;
     SHOW_INT("Auto-delay: ", chan->auto_delay, NULL, "None");
-    SHOW_INT("Bad-cookie:" , chan->bad_cookie, P_STR, "Ignore");
+    SHOW_INT("Bad-cookie:" , chan->bad_cookie, DEFLAG_STR, "Ignore");
     SHOW_INT("Ban-time: ", chan->ban_time, NULL, "Forever");
     SHOW_INT("Ban-type: ", chan->ban_type, NULL, "3");
     SHOW_INT("Closed-ban: ", chan->closed_ban, NULL, "Don't!");
@@ -1249,12 +1247,13 @@ static void cmd_chaninfo(int idx, char *par)
     SHOW_INT("Knock: ", chan->knock_flags, F_STR(chan->knock_flags), "None");
     SHOW_INT("Limit raise (limit): ", chan->limitraise, NULL, "Disabled");
     deflag = chan->manop;
-    SHOW_INT("Manop: ", chan->manop, P_STR, "Ignore");
+    SHOW_INT("Manop: ", chan->manop, DEFLAG_STR, "Ignore");
     deflag = chan->mdop;
-    SHOW_INT("Mdop: ", chan->mdop, P_STR, "Ignore");
+    SHOW_INT("Mdop: ", chan->mdop, DEFLAG_STR, "Ignore");
     deflag = chan->mop;
-    SHOW_INT("Mop: ", chan->mop, P_STR, "Ignore");
-//    SHOW_INT("Revenge-mode: ", chan->revenge_mode, NULL, NULL);
+    SHOW_INT("Mop: ", chan->mop, DEFLAG_STR, "Ignore");
+    deflag = chan->revenge;
+    SHOW_INT("Revenge: ", chan->revenge, DEFLAG_STR, "Ignore");
     SHOW_INT("Protect-backup: ", chan->protect_backup, "Do!", "Don't!");
     SHOW_INT("Voice-non-ident: ", chan->voice_non_ident, "Do!", "Don't!");
 

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

@@ -714,7 +714,7 @@ bd::String channel_to_string(struct chanset_t* chan, bool force_inactive) {
 
   get_mode_protect(chan, w, sizeof(w));
   return bd::String::printf("\
-chanmode { %s } groups { %s } bad-cookie %d manop %d mdop %d mop %d limit %d ban-type %d \
+chanmode { %s } groups { %s } bad-cookie %d manop %d mdop %d mop %d limit %d revenge %d ban-type %d \
 flood-chan %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 \
 closed-ban %d closed-invite %d closed-private %d ban-time %d \
@@ -734,6 +734,7 @@ flood-exempt %d flood-lock-time %d knock %d fish-key { %s } \
 	chan->manop,
 	chan->mdop,
 	chan->mop,
+	chan->revenge,
         chan->limitraise,
         chan->ban_type,
 	chan->flood_pub_thr, chan->flood_pub_time,

+ 33 - 21
src/mod/irc.mod/chan.c

@@ -737,7 +737,7 @@ static bool detect_chan_flood(char *floodnick, char *floodhost, char *from,
         char s[256] = "";
 
         simple_snprintf(s, sizeof(s), "Mass deop on %s by %s", chan->dname, from);
-        deflag_user(u, DEFLAG_MDOP, s, chan);
+        deflag_user(u, DEFLAG_EVENT_MDOP, s, chan);
       }
       if (channel_protect(chan))
         do_protect(chan, "Mass Deop");
@@ -2872,14 +2872,10 @@ static int gotkick(char *from, char *origmsg)
   }
   if (channel_active(chan)) {
     char *whodid = NULL, s1[UHOSTLEN] = "", buf[UHOSTLEN] = "", *uhost = buf;
-    memberlist *m = NULL;
-    struct userrec *u = NULL;
+    memberlist *m = NULL, *mv = NULL;
     struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0 };
 
     fixcolon(msg);
-    u = get_user_by_host(from);
-    if (!u || (u && !u->bot))
-      chan->channel.fighting++;
     strlcpy(uhost, from, sizeof(buf));
     whodid = splitnick(&uhost);
     detect_chan_flood(whodid, uhost, from, chan, FLOOD_KICK, nick);
@@ -2889,27 +2885,43 @@ static int gotkick(char *from, char *origmsg)
       return 0;     
 
     m = ismember(chan, whodid);
-    if (m)
+    if (m) {
       m->last = now;
-    /* This _needs_ to use chan->dname <cybah> */
-    get_user_flagrec(u, &fr, chan->dname, chan);
-    set_handle_laston(chan->dname, u, now);
- 
-    chan = findchan(chname);
-    if (!chan)
-      return 0;
-
-    if ((m = ismember(chan, nick))) {
       member_getuser(m);
-      if (m->user)
+      if (m->user) {
+        /* This _needs_ to use chan->dname <cybah> */
+        get_user_flagrec(m->user, &fr, chan->dname, chan);
         set_handle_laston(chan->dname, m->user, now);
-//      maybe_revenge(chan, from, s1, REVENGE_KICK);
-    } else {
-      simple_snprintf(s1, sizeof(s1), "%s!*@could.not.loookup.hostname", nick);
+      }
+    }
+
+    if ((!m || !m->user) || (m && m->user && !m->user->bot)) {
+      chan->channel.fighting++;
+    }
+
+    mv = ismember(chan, nick);
+
+    member_getuser(mv);
+    if (mv->user) {
+      // Revenge kick clients that kick our bots
+      if (chan->revenge && !mv->is_me && m && m != mv && mv->user->bot) {
+        if (role < 5 && !chan_sentkick(m) && me_op(chan)) {
+          m->flags |= SENTKICK;
+          dprintf(DP_MODE_NEXT, "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_REVENGE));
+        } else {
+          if (m->user) {
+            char tmp[128] = "";
+            simple_snprintf(tmp, sizeof(tmp), "Kicked bot %s on %s", m->nick, chan->dname);
+            deflag_user(m->user, DEFLAG_EVENT_REVENGE_KICK, tmp, chan);
+          }
+        }
+      }
+
+      set_handle_laston(chan->dname, mv->user, now);
     }
     irc_log(chan, "%s was kicked by %s (%s)", s1, from, msg);
     /* Kicked ME?!? the sods! */
-    if (match_my_nick(nick)) {
+    if (mv->is_me) {
       check_rejoin(chan);
     } else {
       killmember(chan, nick);

+ 0 - 183
src/mod/irc.mod/irc.c

@@ -1029,189 +1029,6 @@ request_in(struct chanset_t *chan)
   putlog(LOG_GETIN, "*", "Requested help to join %s", chan->dname);
 }
 
-
-#ifdef REVENGE
-/* Contains the logic to decide wether we want to punish someone. Returns
- * true (1) if we want to, false (0) if not.
- */
-static bool
-want_to_revenge(struct chanset_t *chan, struct userrec *u,
-                struct userrec *u2, char *badnick, char *victimstr, bool mevictim)
-{
-  struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0 };
-
-  /* Do not take revenge upon ourselves. */
-  if (match_my_nick(badnick))
-    return 0;
-
-  get_user_flagrec(u, &fr, chan->dname, chan);
-
-  /* Kickee didn't kick themself? */
-  if (rfc_casecmp(badnick, victimstr)) {
-    /* They kicked me? */
-    if (mevictim) {
-      /* ... and I'm allowed to take revenge? <snicker> */
-      if (channel_revengebot(chan))
-        return 1;
-      /* Do we revenge for our users ... and do we actually know the victim? */
-    } else if (channel_revenge(chan) && u2) {
-      struct flag_record fr2 = { FR_GLOBAL | FR_CHAN, 0, 0, 0 };
-
-      get_user_flagrec(u2, &fr2, chan->dname, chan);
-      /* Protecting friends? */
-      /* Protecting ops? */
-      if ((channel_protectops(chan) && chk_op(fr2, chan)))
-        return 1;
-    }
-  }
-  return 0;
-}
-
-/* Dependant on revenge_mode, punish the offender.
- */
-static void
-punish_badguy(struct chanset_t *chan, char *whobad,
-              struct userrec *u, char *badnick, char *victimstr, bool mevictim, int type)
-{
-  memberlist *m = ismember(chan, badnick);
-
-  if (!m)
-    return;
-
-  char reason[1024] = "", ct[81] = "", *kick_msg = NULL;
-  struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0 };
-
-  get_user_flagrec(u, &fr, chan->dname, chan);
-
-  /* Get current time into a string */
-  strftime(ct, sizeof ct, "%d %b %Z", gmtime(&now));
-
-  /* Put together log and kick messages */
-  reason[0] = 0;
-  switch (type) {
-    case REVENGE_KICK:
-      kick_msg = "don't kick my friends, bud";
-      simple_snprintf(reason, sizeof(reason), "kicked %s off %s", victimstr, chan->dname);
-      break;
-    case REVENGE_DEOP:
-      simple_snprintf(reason, sizeof(reason), "deopped %s on %s", victimstr, chan->dname);
-      kick_msg = "don't deop my friends, bud";
-      break;
-    default:
-      kick_msg = "revenge!";
-  }
-  putlog(LOG_MISC, chan->dname, "Punishing %s (%s)", badnick, reason);
-
-  /* Set the offender +d */
-  if ((chan->revenge_mode > 0) &&
-      /* ... unless there's no more to do */
-      !(chan_deop(fr) || glob_deop(fr))) {
-    char s[UHOSTLEN], s1[UHOSTLEN];
-    memberlist *mx = NULL;
-
-    /* Removing op */
-    if (chk_op(fr, chan)) {
-      fr.match = FR_CHAN;
-      if (chan_op(fr)) {
-        fr.chan &= ~USER_OP;
-      } else {
-        fr.chan |= USER_DEOP;
-      }
-      set_user_flagrec(u, &fr, chan->dname);
-      putlog(LOG_MISC, "*", "No longer opping %s[%s] (%s)", u->handle, whobad, reason);
-    }
-    /* ... or just setting to deop */
-    else if (u) {
-      /* In the user list already, cool :) */
-      fr.match = FR_CHAN;
-      fr.chan |= USER_DEOP;
-      set_user_flagrec(u, &fr, chan->dname);
-      simple_snprintf(s, sizeof(s), "(%s) %s", ct, reason);
-      putlog(LOG_MISC, "*", "Now deopping %s[%s] (%s)", u->handle, whobad, s);
-    }
-    /* ... or creating new user and setting that to deop */
-    else {
-      strlcpy(s1, whobad, sizeof(s1));
-      maskhost(s1, s);
-      strlcpy(s1, badnick, sizeof(s1));
-      /* If that handle exists use "badX" (where X is an increasing number)
-       * instead.
-       */
-      while (get_user_by_handle(userlist, s1)) {
-        if (!strncmp(s1, "bad", 3)) {
-          int i;
-
-          i = atoi(s1 + 3);
-          simple_snprintf(s1 + 3, sizeof(s1) - 3, "%d", i + 1);
-        } else
-          strlcpy(s1, "bad1", sizeof(s1));   /* Start with '1' */
-      }
-      userlist = adduser(userlist, s1, s, "-", 0, 0);
-      fr.match = FR_CHAN;
-      fr.chan = USER_DEOP;
-      u = get_user_by_handle(userlist, s1);
-      if ((mx = ismember(chan, badnick)))
-        mx->user = u;
-      set_user_flagrec(u, &fr, chan->dname);
-      simple_snprintf(s, sizeof(s), "(%s) %s (%s)", ct, reason, whobad);
-      set_user(&USERENTRY_COMMENT, u, (void *) s);
-      putlog(LOG_MISC, "*", "Now deopping %s (%s)", whobad, reason);
-    }
-  }
-
-  /* Always try to deop the offender */
-  if (!mevictim)
-    add_mode(chan, '-', 'o', badnick);
-  /* Ban. Should be done before kicking. */
-  if (chan->revenge_mode > 2) {
-    char s[UHOSTLEN] = "", s1[UHOSTLEN] = "";
-
-    splitnick(&whobad);
-    maskhost(whobad, s1);
-    simple_snprintf(s, sizeof(s), "(%s) %s", ct, reason);
-    u_addmask('b', chan, s1, conf.bot->nick, s, now + (60 * chan->ban_time), 0);
-    if (!mevictim && me_op(chan)) {
-      add_mode(chan, '+', 'b', s1);
-      flush_mode(chan, QUICK);
-    }
-  }
-  /* Kick the offender */
-  if ((chan->revenge_mode > 1) && !chan_sentkick(m) &&
-      /* ... and can I actually do anything about it? */
-      me_op(chan) && !mevictim) {
-    dprintf(DP_MODE, "KICK %s %s :%s%s\n", chan->name, m->nick, bankickprefix, response(RES_MEAN));
-    m->flags |= SENTKICK;
-  }
-}
-
-/* Punishes bad guys under certain circumstances using methods as defined
- * by the revenge_mode flag.
- */
-static void
-maybe_revenge(struct chanset_t *chan, char *whobad, char *whovictim, int type)
-{
-  if (!chan || (type < 0))
-    return;
-
-  /* Get info about offender */
-  struct userrec *u = get_user_by_host(whobad), *u2 = NULL;
-  char *badnick = splitnick(&whobad), *victimstr = NULL;
-  bool mevictim;
-
-  /* Get info about victim */
-  u2 = get_user_by_host(whovictim);
-  victimstr = splitnick(&whovictim);
-  mevictim = match_my_nick(victimstr);
-
-  /* Do we want to revenge? */
-  if (!want_to_revenge(chan, u, u2, badnick, victimstr, mevictim))
-    return;                     /* No, leave them alone ... */
-
-  /* Haha! Do the vengeful thing ... */
-  punish_badguy(chan, whobad, u, badnick, victimstr, mevictim, type);
-}
-#endif
-
 /* Set the key.
  */
 void

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

@@ -11,9 +11,6 @@
 
 enum { BC_NOCOOKIE = 1, BC_SLACK, BC_HASH, BC_COUNTER };
 
-//#define REVENGE_KICK 1		/* Kicked victim	*/
-//#define REVENGE_DEOP 2		/* Took op		*/
-
 #define PRIO_DEOP 1
 #define PRIO_KICK 2
 
@@ -85,7 +82,6 @@ static void do_protect(struct chanset_t* chan, const char* reason);
 static bool do_op(char *, struct chanset_t *, bool, bool);
 static void request_op(struct chanset_t *);
 static void request_in(struct chanset_t *);
-//static void maybe_revenge(struct chanset_t *, char *, char *, int);
 static bool detect_chan_flood(char *, char *, char *, struct chanset_t *, int,
 			     char *);
 static bool new_mask(masklist *, char *, char *);

+ 62 - 28
src/mod/irc.mod/mode.c

@@ -719,15 +719,21 @@ got_deop(struct chanset_t *chan, memberlist *m, memberlist *mv, char *isserver)
 /* need: op */
     if (!m)
       putlog(LOG_MODES, chan->dname, "TS resync deopped me on %s :(", chan->dname);
+  } else {
+    // Revenge kick clients that deop our bots
+    if (chan->revenge && m && m != mv && mv->user && mv->user->bot) {
+      if (role < 5 && !chan_sentkick(m) && me_op(chan)) {
+        m->flags |= SENTKICK;
+        dprintf(DP_MODE_NEXT, "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_REVENGE));
+      } else {
+        if (m->user) {
+          char tmp[128] = "";
+          simple_snprintf(tmp, sizeof(tmp), "Deopped bot %s on %s", m->nick, chan->dname);
+          deflag_user(m->user, DEFLAG_EVENT_REVENGE_DEOP, tmp, chan);
+        }
+      }
+    }
   }
-#ifdef revenge
-  if (m) {
-    char s[UHOSTLEN] = "";
-
-    simple_snprintf(s, sizeof(s), "%s!%s", mv->nick, mv->userhost);
-//    maybe_revenge(chan, s1, s, REVENGE_DEOP);
-  }
-#endif
 }
 
 static void
@@ -744,6 +750,40 @@ got_ban(struct chanset_t *chan, memberlist *m, char *mask, char *isserver)
   if (channel_pending(chan) || !me_op(chan))
     return;
 
+  // Make an array of all matching users
+  bd::Array<memberlist*> matchedUserMembers;
+  bool matched_bot = false;
+  char s1[UHOSTLEN] = "";
+
+  for (memberlist *mv = chan->channel.member; mv && mv->nick[0]; mv = mv->next) {
+    member_getuser(mv);
+    if (mv->user) {
+      simple_snprintf(s1, sizeof s1, "%s!%s", mv->nick, mv->userhost);
+      if ((wild_match(mask, s1) || match_cidr(mask, s1))) {
+        if (!matched_bot && mv != m && mv->user->bot) {
+          matched_bot = true;
+        }
+        if (mv->user && !isexempted(chan, s1)) {
+          matchedUserMembers << mv;
+        }
+      }
+    }
+  }
+
+  // Revenge kick clients that ban our bots
+  if (chan->revenge && m && matched_bot) {
+    if (role < 5 && !chan_sentkick(m)) {
+      m->flags |= SENTKICK;
+      dprintf(DP_MODE_NEXT, "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_REVENGE));
+    } else {
+      if (m->user) {
+        char tmp[128] = "";
+        simple_snprintf(tmp, sizeof(tmp), "Banned bot %s (%s) on %s", m->nick, mask, chan->dname);
+        deflag_user(m->user, DEFLAG_EVENT_REVENGE_BAN, tmp, chan);
+      }
+    }
+  }
+
   if ((wild_match(mask, me) || match_cidr(mask, meip)) && !isexempted(chan, me)) {
     add_mode(chan, '-', 'b', mask);
     reversing = 1;
@@ -756,22 +796,16 @@ got_ban(struct chanset_t *chan, memberlist *m, char *mask, char *isserver)
       return;
     }
     /* remove bans on ops unless a master/bot set it */
-    char s1[UHOSTLEN] = "";
-
-    for (memberlist *m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next) {
-      simple_snprintf(s1, sizeof s1, "%s!%s", m2->nick, m2->userhost);
-      if ((wild_match(mask, s1) || match_cidr(mask, s1))
-          && !isexempted(chan, s1)) {
-        if (m2->user || (!m2->user && (m2->user = get_user_by_host(s1)))) {
-          get_user_flagrec(m2->user, &victim, chan->dname, chan);
-          if (!(glob_kick(victim) || chan_kick(victim)) && 
-              (((chk_op(victim, chan) && !chan_master(user) && !glob_master(user) && !glob_bot(user)) || 
-              (m2->user->bot && findbot(m2->user->handle))) && !isexempted(chan, s1))) {
-            /* if (target_priority(chan, m, 0)) */
-            add_mode(chan, '-', 'b', mask);
-            return;
-          }
-        }
+
+    for (size_t n = 0; n < matchedUserMembers.size(); ++n) {
+      const memberlist *mv = matchedUserMembers[n];
+      get_user_flagrec(mv->user, &victim, chan->dname, chan);
+      if (!(glob_kick(victim) || chan_kick(victim)) &&
+          (((chk_op(victim, chan) && !chan_master(user) && !glob_master(user) && !glob_bot(user)) ||
+            (mv->user->bot && findbot(mv->user->handle))))) {
+        /* if (target_priority(chan, m, 0)) */
+        add_mode(chan, '-', 'b', mask);
+        return;
       }
     }
   }
@@ -1122,7 +1156,7 @@ gotmode(char *from, char *msg)
               } else {
                 if (u) {
                   simple_snprintf(tmp, sizeof(tmp), "Mass deop on %s by %s", chan->dname, m->nick);
-                  deflag_user(u, DEFLAG_MDOP, tmp, chan);
+                  deflag_user(u, DEFLAG_EVENT_MDOP, tmp, chan);
                 }
               }
               reversing = mdop_reversing = 1;
@@ -1142,7 +1176,7 @@ gotmode(char *from, char *msg)
                 } else { 
                   if (u) {
                     simple_snprintf(tmp, sizeof(tmp), "Mass op on %s by %s", chan->dname, m->nick);
-                    deflag_user(u, DEFLAG_MOP, tmp, chan);
+                    deflag_user(u, DEFLAG_EVENT_MOP, tmp, chan);
                   }
                 }
               }
@@ -1210,7 +1244,7 @@ gotmode(char *from, char *msg)
                   dprintf_real(DP_MODE_NEXT, tmp, len, sizeof(tmp));
                 }
                 simple_snprintf(tmp, sizeof(tmp), "%s!%s MODE %s %s", m->nick, m->userhost, chan->dname, modes[modecnt - 1]);
-                deflag_user(u, DEFLAG_BADCOOKIE, tmp, chan);
+                deflag_user(u, DEFLAG_EVENT_BADCOOKIE, tmp, chan);
               }
               /* Do the logging last as it can slow down the KICK pushing */
               putlog(LOG_WARNING, "*", "%s opped in %s with bad cookie(%d): %s", m->nick, chan->dname, isbadop, msg);
@@ -1249,7 +1283,7 @@ gotmode(char *from, char *msg)
                     m->flags |= SENTKICK;
                   }
                   simple_snprintf(tmp, sizeof(tmp), "%s!%s MODE %s %s", m->nick, m->userhost, chan->dname, modes[modecnt - 1]);
-                  deflag_user(u, DEFLAG_MANUALOP, tmp, chan);
+                  deflag_user(u, DEFLAG_EVENT_MANUALOP, tmp, chan);
                 }
                 break;
               default: