Explorar el Código

Merge branch 'voice-improvements'

* voice-improvements:
  * When setting +voice/+voicebitch, recheck the channel
  * Consider +voicebitch when voicing non-users in +voice
  * Rename FLOOD_EXEMPT_* flags to CHAN_FLAG_*
  * Don't EVOICE a user if they were devoiced by a bot
  * Cleanup some redundant/useless code
  * If the chan is both +voice and +voicebitch, only voice users who actually have flag: +v
  * Implement +voicebitch when seeing a +v or checking a member
  * Add chanset '+/-voicebitch' for a +bitch style enforcement over voices.
  * Fix case where bot would not get the +e and +I lists when getting opped.
  * Clear out irc status flags when appropriate
  * Move all channel flags to chan->status, and all irc status flags to chan->ircnet_status

Conflicts:
	src/mod/irc.mod/chan.c
	src/mod/irc.mod/irc.c
Bryan Drewery hace 16 años
padre
commit
a4224d9d48

+ 4 - 0
doc/UPDATES

@@ -1,3 +1,7 @@
+* Fix case where bot would not get the +e and +I lists when getting opped.
+* Add chanset '+/-voicebitch' for a +bitch style enforcement over voices.
+* If a bot devoices a user in a +voice channel, the +y bot will no longer enforce this.
+
 1.3 - http://wraith.botpack.net/milestone/1.3
 * Binary / shell / startup changes
   * Binary error messages are no longer obscure numbers or fake segfaults. (Compile with OBSCURE_ERRORS to re-enable)

+ 3 - 0
doc/help.txt

@@ -499,6 +499,9 @@ See also: link
                        unless they are +q globally or +q for the channel.
                        If a botnet master devoices them, they will remain 
                        devoiced no matter who voices them.
+        $bvoicebitch$b     Enforce voices in a +bitch style. Only +v users
+                       will be allowed to be voiced. This does take +private
+                       into mind as well.
         $bdynamicbans$b    Only activate bans on the channel when necessary?
                        This keeps the channel's ban list from getting
                        excessively long. The bot still remembers every ban,

+ 32 - 27
src/chan.h

@@ -23,9 +23,9 @@ typedef struct memstruct {
   char userip[UHOSTLEN];
 } memberlist;
 
-#define FLOOD_EXEMPT_OP	1
-#define FLOOD_EXEMPT_VOICE 2
-#define FLOOD_EXEMPT_USER 3
+#define CHAN_FLAG_OP	1
+#define CHAN_FLAG_VOICE 2
+#define CHAN_FLAG_USER 3
 
 #define CHANMETA "#&!+"
 #define NICKVALID "[{}]^`|\\_-"
@@ -242,24 +242,26 @@ struct chanset_t {
 #define CHAN_NODESYNCH      BIT15
 #define CHAN_FASTOP         BIT16	/* Bots will not use +o-b to op (no cookies) */ 
 #define CHAN_PRIVATE        BIT17	/* users need |o to access chan */ 
-#define CHAN_ACTIVE         BIT18	/* like i'm actually on the channel and stuff */
-#define CHAN_PEND           BIT19	/* just joined; waiting for end of WHO list */
-#define CHAN_FLAGGED        BIT20	/* flagged during rehash for delete   */
-#define CHAN_ASKEDBANS      BIT21
-#define CHAN_ASKEDMODES     BIT22	/* find out key-info on IRCu          */
-#define CHAN_JUPED          BIT23	/* Is channel juped                   */
-#define CHAN_STOP_CYCLE     BIT24	/* Some efnetservers have defined NO_CHANOPS_WHEN_SPLIT */
-#define CHAN_AUTOOP         BIT25
-#define CHAN_JOINING        BIT26	/* attempting to join, dont flood with JOIN #chan */
-#define CHAN_MEANKICKS      BIT27	/* use mean/offensive kicks/bans */
-#define CHAN_HAVEBANS       BIT28	/* have been opped and received the ban list */
+#define CHAN_DYNAMICEXEMPTS BIT18
+#define CHAN_NOUSEREXEMPTS  BIT19
+#define CHAN_DYNAMICINVITES BIT20
+#define CHAN_NOUSERINVITES  BIT21
+#define CHAN_FLAGGED        BIT22	/* flagged during rehash for delete   */
+#define CHAN_AUTOOP         BIT23
+#define CHAN_MEANKICKS      BIT24	/* use mean/offensive kicks/bans */
+#define CHAN_VOICEBITCH     BIT25
 
 #define CHAN_ASKED_EXEMPTS  BIT0
 #define CHAN_ASKED_INVITES  BIT1
-#define CHAN_DYNAMICEXEMPTS BIT2
-#define CHAN_NOUSEREXEMPTS  BIT3
-#define CHAN_DYNAMICINVITES BIT4
-#define CHAN_NOUSERINVITES  BIT5
+#define CHAN_HAVEBANS       BIT2	/* have been opped and received the ban list */
+#define CHAN_ASKEDBANS      BIT3
+#define CHAN_ASKEDMODES     BIT4	/* find out key-info on IRCu          */
+#define CHAN_ACTIVE         BIT5	/* like i'm actually on the channel and stuff */
+#define CHAN_PEND           BIT6	/* just joined; waiting for end of WHO list */
+#define CHAN_JOINING        BIT7	/* attempting to join, dont flood with JOIN #chan */
+#define CHAN_JUPED          BIT8	/* Is channel juped                   */
+#define CHAN_STOP_CYCLE     BIT9	/* Some efnetservers have defined NO_CHANOPS_WHEN_SPLIT */
+
 /* prototypes */
 memberlist *ismember(struct chanset_t *, const char *);
 struct chanset_t *findchan(const char *name);
@@ -270,9 +272,16 @@ struct chanset_t *findchan_by_dname(const char *name);
 /* is this channel +t? */
 #define channel_optopic(chan) (chan->channel.mode & CHANTOPIC)
 
-#define channel_active(chan)  (chan->status & CHAN_ACTIVE)
-#define channel_joining(chan) (chan->status & CHAN_JOINING)
-#define channel_pending(chan)  (chan->status & CHAN_PEND)
+#define channel_active(chan)  (chan->ircnet_status & CHAN_ACTIVE)
+#define channel_joining(chan) (chan->ircnet_status & CHAN_JOINING)
+#define channel_pending(chan)  (chan->ircnet_status & CHAN_PEND)
+#define channel_juped(chan) (chan->ircnet_status & CHAN_JUPED)
+#define channel_stop_cycle(chan) (chan->ircnet_status & CHAN_STOP_CYCLE)
+
+#define channel_dynamicexempts(chan) (chan->status & CHAN_DYNAMICEXEMPTS)
+#define channel_nouserexempts(chan) (chan->status & CHAN_NOUSEREXEMPTS)
+#define channel_dynamicinvites(chan) (chan->status & CHAN_DYNAMICINVITES)
+#define channel_nouserinvites(chan) (chan->status & CHAN_NOUSERINVITES)
 #define channel_backup(chan) (chan->status & CHAN_BACKUP)
 #define channel_bitch(chan) (chan->status & CHAN_BITCH)
 #define chan_bitch(chan) (chan->status & (CHAN_BITCH|CHAN_BOTBITCH))
@@ -284,12 +293,7 @@ struct chanset_t *findchan_by_dname(const char *name);
 #define channel_secret(chan) (chan->status & CHAN_SECRET)
 #define channel_cycle(chan) (chan->status & CHAN_CYCLE)
 #define channel_inactive(chan) (chan->status & CHAN_INACTIVE)
-#define channel_dynamicexempts(chan) (chan->ircnet_status & CHAN_DYNAMICEXEMPTS)
-#define channel_nouserexempts(chan) (chan->ircnet_status & CHAN_NOUSEREXEMPTS)
-#define channel_dynamicinvites(chan) (chan->ircnet_status & CHAN_DYNAMICINVITES)
-#define channel_nouserinvites(chan) (chan->ircnet_status & CHAN_NOUSERINVITES)
-#define channel_juped(chan) (chan->status & CHAN_JUPED)
-#define channel_stop_cycle(chan) (chan->status & CHAN_STOP_CYCLE)
+
 
 #ifdef REVENGE
 #define channel_revenge(chan) (chan->status & CHAN_REVENGE)
@@ -305,6 +309,7 @@ struct chanset_t *findchan_by_dname(const char *name);
 #define channel_nomassjoin(chan) (chan->status & CHAN_NOMASSJOIN)
 #define channel_meankicks(chan) (chan->status & CHAN_MEANKICKS)
 #define channel_rbl(chan) (chan->status & CHAN_RBL)
+#define channel_voicebitch(chan) (chan->status & CHAN_VOICEBITCH)
 /* Chanflag template
  *#define channel_temp(chan) (chan->status & CHAN_PRIVATE)
  */

+ 4 - 2
src/mod/channels.mod/channels.c

@@ -390,7 +390,7 @@ check_slowjoinpart(struct chanset_t *chan)
       chan->channel.jointime = 0;
     if (shouldjoin(chan) && !channel_active(chan) && !channel_joining(chan)) {
       dprintf(DP_MODE, "JOIN %s %s\n", chan->dname, chan->key_prot);
-      chan->status |= CHAN_JOINING;
+      chan->ircnet_status |= CHAN_JOINING;
     }
   } else if (channel_closed(chan)) {
     enforce_closed(chan);
@@ -485,7 +485,7 @@ static void got_jn(int idx, char *code, char *par)
     chan->channel.jointime = 0;
     if (!conf.bot->hub && shouldjoin(chan) && !channel_active(chan) && !channel_joining(chan)) {
       dprintf(DP_MODE, "JOIN %s %s\n", chan->name, chan->key_prot);
-      chan->status |= CHAN_JOINING;
+      chan->ircnet_status |= CHAN_JOINING;
     }
   }
 }
@@ -883,6 +883,8 @@ void channels_report(int idx, int details)
           i += my_strcpy(s + i, "meankicks ");
         if (channel_rbl(chan))
           i += my_strcpy(s + i, "rbl ");
+        if (channel_voicebitch(chan))
+          i += my_strcpy(s + i, "voicebitch ");
 /* Chanflag template
  *	if (channel_temp(chan))
  *	  i += my_strcpy(s + i, "temp ");

+ 3 - 2
src/mod/channels.mod/cmdschan.c

@@ -607,7 +607,7 @@ static void cmd_slowjoin(int idx, char *par)
 
   if (!conf.bot->hub && shouldjoin(chan) && !channel_joining(chan)) {
     dprintf(DP_MODE, "JOIN %s %s\n", chan->name, chan->key_prot);
-    chan->status |= CHAN_JOINING;
+    chan->ircnet_status |= CHAN_JOINING;
   }
 }
 
@@ -1182,7 +1182,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 F_STR(x) x == FLOOD_EXEMPT_OP ? "Op" : (x == FLOOD_EXEMPT_VOICE ? "Voice" : (x == FLOOD_EXEMPT_USER ? "User" : 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)
 {
   char *chname = NULL, work[512] = "";
@@ -1255,6 +1255,7 @@ static void cmd_chaninfo(int idx, char *par)
     if (HAVE_TAKE)
       SHOW_FLAG("take",		channel_take(chan));
     SHOW_FLAG("voice",		channel_voice(chan));
+    SHOW_FLAG("voicebitch",		channel_voicebitch(chan));
     SHOW_FLAG("", 0);
     SHOW_FLAG("dynamicbans",	channel_dynamicbans(chan));
     SHOW_FLAG("userbans",	!channel_nouserbans(chan));

+ 26 - 22
src/mod/channels.mod/tclchan.c

@@ -308,7 +308,6 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
 {
   bool error = 0;
   int old_status = chan->status,
-      old_ircnet_status = chan->ircnet_status,
       old_mode_mns_prot = chan->mode_mns_prot,
       old_mode_pls_prot = chan->mode_pls_prot;
   char s[121] = "", result_extra[RESULT_LEN / 2] = "";
@@ -485,11 +484,11 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
       }
       if (!str_isdigit(item[i])) {
         if (!strcasecmp("Op",  item[i]))
-          chan->knock_flags = FLOOD_EXEMPT_OP;
+          chan->knock_flags = CHAN_FLAG_OP;
         else if (!strcasecmp("Voice", item[i]))
-          chan->knock_flags = FLOOD_EXEMPT_VOICE;
+          chan->knock_flags = CHAN_FLAG_VOICE;
         else if (!strcasecmp("User", item[i]))
-          chan->knock_flags = FLOOD_EXEMPT_USER;
+          chan->knock_flags = CHAN_FLAG_USER;
         else if (!strcasecmp("None", item[i]))
           chan->knock_flags = 0;
         else {
@@ -508,9 +507,9 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
       }
       if (!str_isdigit(item[i])) {
         if (!strcasecmp("Op",  item[i]))
-          chan->flood_exempt_mode = FLOOD_EXEMPT_OP;
+          chan->flood_exempt_mode = CHAN_FLAG_OP;
         else if (!strcasecmp("Voice", item[i]))
-          chan->flood_exempt_mode = FLOOD_EXEMPT_VOICE;
+          chan->flood_exempt_mode = CHAN_FLAG_VOICE;
         else if (!strcasecmp("None", item[i]))
           chan->flood_exempt_mode = 0;
         else {
@@ -592,21 +591,21 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
     else if (!strcmp(item[i], "-cycle"))
       chan->status &= ~CHAN_CYCLE;
     else if (!strcmp(item[i], "+dynamicexempts"))
-      chan->ircnet_status|= CHAN_DYNAMICEXEMPTS;
+      chan->status |= CHAN_DYNAMICEXEMPTS;
     else if (!strcmp(item[i], "-dynamicexempts"))
-      chan->ircnet_status&= ~CHAN_DYNAMICEXEMPTS;
+      chan->status &= ~CHAN_DYNAMICEXEMPTS;
     else if (!strcmp(item[i], "-userexempts"))
-      chan->ircnet_status|= CHAN_NOUSEREXEMPTS;
+      chan->status |= CHAN_NOUSEREXEMPTS;
     else if (!strcmp(item[i], "+userexempts"))
-      chan->ircnet_status&= ~CHAN_NOUSEREXEMPTS;
+      chan->status &= ~CHAN_NOUSEREXEMPTS;
     else if (!strcmp(item[i], "+dynamicinvites"))
-      chan->ircnet_status|= CHAN_DYNAMICINVITES;
+      chan->status |= CHAN_DYNAMICINVITES;
     else if (!strcmp(item[i], "-dynamicinvites"))
-      chan->ircnet_status&= ~CHAN_DYNAMICINVITES;
+      chan->status &= ~CHAN_DYNAMICINVITES;
     else if (!strcmp(item[i], "-userinvites"))
-      chan->ircnet_status|= CHAN_NOUSERINVITES;
+      chan->status |= CHAN_NOUSERINVITES;
     else if (!strcmp(item[i], "+userinvites"))
-      chan->ircnet_status&= ~CHAN_NOUSERINVITES;
+      chan->status &= ~CHAN_NOUSERINVITES;
     else if (!strcmp(item[i], "+closed"))
       chan->status |= CHAN_CLOSED;
     else if (!strcmp(item[i], "-closed"))
@@ -643,6 +642,10 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
       chan->status |= CHAN_RBL;
     else if (!strcmp(item[i], "-rbl"))
       chan->status &= ~CHAN_RBL;
+    else if (!strcmp(item[i], "+voicebitch"))
+      chan->status |= CHAN_VOICEBITCH;
+    else if (!strcmp(item[i], "-voicebitch"))
+      chan->status &= ~CHAN_VOICEBITCH;
 /* Chanflag template
  *  else if (!strcmp(item[i], "+temp"))
  *    chan->status |= CHAN_TEMP;
@@ -800,22 +803,21 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
 
   if (!conf.bot->hub && (chan != chanset_default)) {
     if ((old_status ^ chan->status) & (CHAN_INACTIVE | CHAN_BACKUP)) {
-      if (!shouldjoin(chan) && (chan->status & (CHAN_ACTIVE | CHAN_PEND)))
+      if (!shouldjoin(chan) && (chan->ircnet_status & (CHAN_ACTIVE | CHAN_PEND)))
         dprintf(DP_SERVER, "PART %s\n", chan->name);
-      if (shouldjoin(chan) && !(chan->status & (CHAN_ACTIVE | CHAN_PEND | CHAN_JOINING))) {
+      if (shouldjoin(chan) && !(chan->ircnet_status & (CHAN_ACTIVE | CHAN_PEND | CHAN_JOINING))) {
         dprintf(DP_SERVER, "JOIN %s %s\n", (chan->name[0]) ?
   			   chan->name : chan->dname,
   			   chan->channel.key[0] ?
     			   chan->channel.key : chan->key_prot);
-        chan->status |= CHAN_JOINING;
+        chan->ircnet_status |= CHAN_JOINING;
       }
     }
     if (me_op(chan)) {
-      if ((old_status ^ chan->status) & (CHAN_ENFORCEBANS|CHAN_NOUSERBANS|CHAN_DYNAMICBANS) || (old_ircnet_status ^ chan->ircnet_status) & (CHAN_NOUSEREXEMPTS|CHAN_NOUSERINVITES|CHAN_DYNAMICEXEMPTS|CHAN_DYNAMICINVITES)) {
+      if ((old_status ^ chan->status) & (CHAN_ENFORCEBANS|CHAN_NOUSERBANS|CHAN_DYNAMICBANS|CHAN_NOUSEREXEMPTS|CHAN_NOUSERINVITES|CHAN_DYNAMICEXEMPTS|CHAN_DYNAMICINVITES)) {
         recheck_channel(chan, 1);
-      /* if we -take, recheck the chan for modes and shit */
-      /* also -[bot]bitch/-private might allow for auto-opping users */
-      } else if ((chan->status ^ old_status) & (CHAN_BITCH | CHAN_BOTBITCH | CHAN_PRIVATE | CHAN_CLOSED)) {
+        /* Does a change in channel flag affect client status in the channel? */
+      } else if ((chan->status ^ old_status) & (CHAN_BITCH | CHAN_BOTBITCH | CHAN_PRIVATE | CHAN_CLOSED | CHAN_VOICE | CHAN_VOICEBITCH )) {
         recheck_channel(chan, 0);
       } else if ((old_status & CHAN_TAKE) && !(chan->status & CHAN_TAKE)) {
         //Set -take, fetch bans/exempts/invites
@@ -900,7 +902,9 @@ void clear_channel(struct chanset_t *chan, bool reset)
   clear_masklist(chan->channel.invite);
   chan->channel.invite = NULL;
 
-  chan->status &= ~CHAN_HAVEBANS;
+  chan->channel.last_eI = 0;
+
+  chan->ircnet_status &= ~CHAN_HAVEBANS;
 
   if (reset)
     init_channel(chan, 1);

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

@@ -525,7 +525,7 @@ static void tell_masks(const char type, int idx, bool show_inact, char *match, b
       } else
 	display_mask(type, idx, k++, mr, chan, show_inact);
     }
-    if (chan->status & CHAN_ACTIVE) {
+    if (chan->ircnet_status & CHAN_ACTIVE) {
       masklist *ml = NULL;
       masklist *channel_list = (type == 'b' ? chan->channel.ban : type == 'e' ? chan->channel.exempt : chan->channel.invite);
 
@@ -734,7 +734,7 @@ flood-exempt %d flood-lock-time %d knock %d \
 %cmeankicks %cenforcebans %cdynamicbans %cuserbans %cbitch \
 %cprivate %ccycle %cinactive %cdynamicexempts %cuserexempts \
 %cdynamicinvites %cuserinvites %cnodesynch %cclosed %cvoice \
-%cfastop %cautoop %cbotbitch %cbackup %cnomassjoin %crbl %c%s",
+%cfastop %cautoop %cbotbitch %cbackup %cnomassjoin %crbl %cvoicebitch %c%s",
 	w,
 /* Chanchar template
  *      temp,
@@ -789,6 +789,7 @@ flood-exempt %d flood-lock-time %d knock %d \
         PLSMNS(channel_backup(chan)),
         PLSMNS(channel_nomassjoin(chan)),
         PLSMNS(channel_rbl(chan)),
+        PLSMNS(channel_voicebitch(chan)),
 	HAVE_TAKE ? PLSMNS(channel_take(chan)) : ' ',
         HAVE_TAKE ? "take " : " "
 /* Chanflag template

+ 1 - 1
src/mod/ctcp.mod/ctcp.c

@@ -504,7 +504,7 @@ static int ctcp_INVITE_UNBAN(char *nick, char *uhost, struct userrec *u, char *o
     if (p)
       *p = 0;
     while (chan) {
-      if (chan->status & CHAN_ACTIVE) {
+      if (chan->ircnet_status & CHAN_ACTIVE) {
         if (!strcasecmp(chan->name, chname)) {
           dprintf(DP_HELP, "NOTICE %s :\002BitchX\002: Access Denied\n", nick);
           return BIND_RET_LOG;

+ 41 - 39
src/mod/irc.mod/chan.c

@@ -539,8 +539,8 @@ static bool detect_chan_flood(char *floodnick, char *floodhost, char *from,
        (glob_master(fr) || chan_master(fr))) ||
       ((which != FLOOD_DEOP) && (which != FLOOD_KICK) && 
        ( (chk_noflood(fr) || 
-         (m && chan->flood_exempt_mode == FLOOD_EXEMPT_OP && chan_hasop(m)) || 
-         (m && chan->flood_exempt_mode == FLOOD_EXEMPT_VOICE && (chan_hasvoice(m) || chan_hasop(m))) )
+         (m && chan->flood_exempt_mode == CHAN_FLAG_OP && chan_hasop(m)) ||
+         (m && chan->flood_exempt_mode == CHAN_FLAG_VOICE && (chan_hasvoice(m) || chan_hasop(m))) )
       )))
     return 0;
 
@@ -1034,7 +1034,7 @@ void recheck_channel_modes(struct chanset_t *chan)
     }
   }
 
-  if (!(chan->status & CHAN_ASKEDMODES)) {
+  if (!(chan->ircnet_status & CHAN_ASKEDMODES)) {
     if (pls & CHANINV && !(cur & CHANINV))
       add_mode(chan, '+', 'i', "");
     else if (mns & CHANINV && cur & CHANINV)
@@ -1127,7 +1127,7 @@ static void check_this_member(struct chanset_t *chan, char *nick, struct flag_re
   if (dovoice(chan)) {
     if (chan_hasvoice(m) && !chan_hasop(m)) {
       /* devoice +q users .. */
-      if (chk_devoice(*fr))
+      if (chk_devoice(*fr) || (channel_voicebitch(chan) && !chk_voice(*fr, chan)))
         add_mode(chan, '-', 'v', m->nick);
     } else if (!chan_hasvoice(m) && !chan_hasop(m)) {
       /* voice +v users */
@@ -1446,7 +1446,7 @@ void recheck_channel(struct chanset_t *chan, int dobans)
 
     //Only reset masks if the bot has already received the ban list before (meaning it has already been opped once)
     //Ie, don't set bans without knowing what they are! (asked for above on first op)
-    if (dobans && (chan->status & CHAN_HAVEBANS)) {
+    if (dobans && (chan->ircnet_status & CHAN_HAVEBANS)) {
       if (channel_nouserbans(chan) && !stop_reset)
         resetbans(chan);
       else
@@ -1472,7 +1472,7 @@ void recheck_channel(struct chanset_t *chan, int dobans)
 
     // Do this here as the above only runs after already having been opped and having gotten bans.
     if (dobans) {
-      if ((chan->status & CHAN_ASKEDMODES) && !channel_inactive(chan)) 
+      if ((chan->ircnet_status & CHAN_ASKEDMODES) && !channel_inactive(chan))
         dprintf(DP_MODE, "MODE %s\n", chan->name);
       recheck_channel_modes(chan);
     }
@@ -1661,9 +1661,9 @@ static int got710(char *from, char *msg)
   get_user_flagrec(u, &fr, chan->dname, chan);
 
   // PASSING: +o and op || +v and op/voice || user
-  if (!((chan->knock_flags == FLOOD_EXEMPT_OP && chk_op(fr, chan)) ||
-       (chan->knock_flags == FLOOD_EXEMPT_VOICE && (chk_op(fr, chan) || chk_voice(fr, chan))) ||
-       (chan->knock_flags == FLOOD_EXEMPT_USER)) ||
+  if (!((chan->knock_flags == CHAN_FLAG_OP && chk_op(fr, chan)) ||
+       (chan->knock_flags == CHAN_FLAG_VOICE && (chk_op(fr, chan) || chk_voice(fr, chan))) ||
+       (chan->knock_flags == CHAN_FLAG_USER)) ||
       chan_kick(fr) || glob_kick(fr)) {
     return 0;
   }
@@ -1701,9 +1701,9 @@ static int got324(char *from, char *msg)
   bool ok = 0;
   char *p = NULL, *q = NULL;
 
-  if (chan->status & CHAN_ASKEDMODES)
+  if (chan->ircnet_status & CHAN_ASKEDMODES)
     ok = 1;
-  chan->status &= ~CHAN_ASKEDMODES;
+  chan->ircnet_status &= ~CHAN_ASKEDMODES;
   chan->channel.mode = 0;
   while (msg[i] != 0) {
     if (msg[i] == 'i')
@@ -1754,7 +1754,7 @@ static int got324(char *from, char *msg)
 	 * an asterisk and this has been agreed upon by other major IRC 
 	 * networks so we'll check for an asterisk here as well 
 	 * (guppy 22Dec2001) */ 
-        chan->status |= CHAN_ASKEDMODES;
+        chan->ircnet_status |= CHAN_ASKEDMODES;
     }
     if (msg[i] == 'l') {
       p = strchr(msg, ' ');
@@ -2015,14 +2015,14 @@ static int got315(char *from, char *msg)
     return 0;
 
   /* Finished getting who list, can now be considered officially ON CHANNEL */
-  chan->status |= CHAN_ACTIVE;
-  chan->status &= ~(CHAN_PEND | CHAN_JOINING);
+  chan->ircnet_status |= CHAN_ACTIVE;
+  chan->ircnet_status &= ~(CHAN_PEND | CHAN_JOINING);
   /* Am *I* on the channel now? if not, well d0h. */
   if (shouldjoin(chan) && !ismember(chan, botname)) {
     putlog(LOG_MISC | LOG_JOIN, chan->dname, "Oops, I'm not really on %s.", chan->dname);
     clear_channel(chan, 1);
-    chan->status &= ~CHAN_ACTIVE;
-    chan->status |= CHAN_JOINING;
+    chan->ircnet_status &= ~CHAN_ACTIVE;
+    chan->ircnet_status |= CHAN_JOINING;
     dprintf(DP_MODE, "JOIN %s %s\n",
 	    (chan->name[0]) ? chan->name : chan->dname,
 	    chan->channel.key[0] ? chan->channel.key : chan->key_prot);
@@ -2030,7 +2030,7 @@ static int got315(char *from, char *msg)
     if (me_op(chan))
       recheck_channel(chan, 2);
     else if (chan->channel.members == 1)
-      chan->status |= CHAN_STOP_CYCLE;
+      chan->ircnet_status |= CHAN_STOP_CYCLE;
     else if (any_ops(chan))
       request_op(chan);
   }
@@ -2077,8 +2077,8 @@ static int got368(char *from, char *msg)
   chname = newsplit(&msg);
   chan = findchan(chname);
   if (chan) {
-    chan->status &= ~CHAN_ASKEDBANS;
-    chan->status |= CHAN_HAVEBANS;
+    chan->ircnet_status &= ~CHAN_ASKEDBANS;
+    chan->ircnet_status |= CHAN_HAVEBANS;
 
     if (channel_nouserbans(chan))
       resetbans(chan);
@@ -2253,7 +2253,7 @@ static int got403(char *from, char *msg)
              "Unique channel %s does not exist... Attempting to join with "
              "short name.", chname);
       dprintf(DP_SERVER, "JOIN %s\n", chan->dname);
-      chan->status |= CHAN_JOINING;
+      chan->ircnet_status |= CHAN_JOINING;
     } else {
       /* We have found the channel, so the server has given us the short
        * name. Prefix another '!' to it, and attempt the join again...
@@ -2287,7 +2287,7 @@ static int got471(char *from, char *msg)
    */
   chan = findchan_by_dname(chname);
   if (chan) {
-    chan->status &= ~CHAN_JOINING;
+    chan->ircnet_status &= ~CHAN_JOINING;
     putlog(LOG_JOIN, chan->dname, "Channel full--can't join: %s", chan->dname);
     request_in(chan);
 /* need: limit */
@@ -2320,7 +2320,7 @@ static int got473(char *from, char *msg)
    */
   chan = findchan_by_dname(chname);
   if (chan) {
-    chan->status &= ~CHAN_JOINING;
+    chan->ircnet_status &= ~CHAN_JOINING;
     putlog(LOG_JOIN, chan->dname, "Channel invite only--can't join: %s", chan->dname);
     request_in(chan);
 /* need: invite */
@@ -2353,7 +2353,7 @@ static int got474(char *from, char *msg)
    */
   chan = findchan_by_dname(chname);
   if (chan) {
-    chan->status &= ~CHAN_JOINING;
+    chan->ircnet_status &= ~CHAN_JOINING;
     putlog(LOG_JOIN, chan->dname, "Banned from channel--can't join: %s", chan->dname);
     request_in(chan);
 /* need: unban */
@@ -2386,7 +2386,7 @@ static int got475(char *from, char *msg)
    */
   chan = findchan_by_dname(chname);
   if (chan && shouldjoin(chan)) {
-    chan->status &= ~CHAN_JOINING;
+    chan->ircnet_status &= ~CHAN_JOINING;
     putlog(LOG_JOIN, chan->dname, "Bad key--can't join: %s", chan->dname);
     if (chan->channel.key[0]) {
       free(chan->channel.key);
@@ -2567,7 +2567,7 @@ static int gotjoin(char *from, char *chname)
   } else if (!channel_pending(chan)) {
     char *host = NULL;
 
-    chan->status &= ~CHAN_STOP_CYCLE;
+    chan->ircnet_status &= ~CHAN_STOP_CYCLE;
 
     detect_chan_flood(nick, uhost, from, chan, FLOOD_JOIN, NULL);
 
@@ -2577,8 +2577,8 @@ static int gotjoin(char *from, char *chname)
     if (!channel_active(chan) && !match_my_nick(nick)) {
       /* uh, what?!  i'm on the channel?! */
       putlog(LOG_ERROR, "*", "confused bot: guess I'm on %s and didn't realize it", chan->dname);
-      chan->status |= CHAN_ACTIVE;
-      chan->status &= ~(CHAN_PEND | CHAN_JOINING);
+      chan->ircnet_status |= CHAN_ACTIVE;
+      chan->ircnet_status &= ~(CHAN_PEND | CHAN_JOINING);
       reset_chan_info(chan);
     } else {
       memberlist *m = ismember(chan, nick);
@@ -2636,7 +2636,7 @@ static int gotjoin(char *from, char *chname)
 	   * unique name for the channel (as the server see's it). <cybah>
 	   */
 	  strlcpy(chan->name, chname, 81);
-	  chan->status &= ~CHAN_JUPED;
+	  chan->ircnet_status &= ~CHAN_JUPED;
 
           /* ... and log us joining. Using chan->dname for the channel is
 	   * important in this case. As the config file will never contain
@@ -2745,14 +2745,16 @@ static int gotjoin(char *from, char *chname)
             if (m->user) {
               if (!(m->flags & EVOICE) &&
                   (
-                   (channel_voice(chan) && !chk_devoice(fr)) ||
+                   /* +voice: Voice all clients who are not flag:+q. If the chan is +voicebitch, only op flag:+v clients */
+                   (channel_voice(chan) && !chk_devoice(fr) && (!channel_voicebitch(chan) || (channel_voicebitch(chan) && chk_voice(fr, chan)))) ||
+                   /* Or, if the channel is -voice but they still qualify to be voiced */
                    (!channel_voice(chan) && !privchan(fr, chan, PRIV_VOICE) && chk_voice(fr, chan))
                   )
                  ) {
                 m->delay = now + chan->auto_delay;
                 m->flags |= SENTVOICE;
               }
-            } else if (!m->user && channel_voice(chan) && voice_ok(m, chan)) {
+            } else if (!m->user && channel_voice(chan) && !channel_voicebitch(chan) && voice_ok(m, chan)) {
               m->delay = now + chan->auto_delay;
               m->flags |= SENTVOICE;
             }
@@ -2784,7 +2786,7 @@ static int gotpart(char *from, char *msg)
   if (chan && !shouldjoin(chan) && match_my_nick(nick)) {
     irc_log(chan, "Parting");    
     clear_channel(chan, 1);
-    chan->status &= ~(CHAN_ACTIVE | CHAN_PEND | CHAN_JOINING);
+    chan->ircnet_status = 0;
     return 0;
   }
   if (chan && !channel_pending(chan)) {
@@ -2794,8 +2796,8 @@ static int gotpart(char *from, char *msg)
     if (!channel_active(chan)) {
       /* whoa! */
       putlog(LOG_ERRORS, "*", "confused bot: guess I'm on %s and didn't realize it", chan->dname);
-      chan->status |= CHAN_ACTIVE;
-      chan->status &= ~(CHAN_PEND | CHAN_JOINING);
+      chan->ircnet_status |= CHAN_ACTIVE;
+      chan->ircnet_status &= ~(CHAN_PEND | CHAN_JOINING);
       reset_chan_info(chan);
     }
     set_handle_laston(chan->dname, u, now);
@@ -2811,12 +2813,12 @@ static int gotpart(char *from, char *msg)
     /* If it was me, all hell breaks loose... */
     if (match_my_nick(nick)) {
       clear_channel(chan, 1);
-      chan->status &= ~(CHAN_ACTIVE | CHAN_PEND | CHAN_JOINING);
+      chan->ircnet_status = 0;
       if (shouldjoin(chan)) {
 	dprintf(DP_MODE, "JOIN %s %s\n",
 	        (chan->name[0]) ? chan->name : chan->dname,
 	        chan->channel.key[0] ? chan->channel.key : chan->key_prot);
-        chan->status |= CHAN_JOINING;
+        chan->ircnet_status |= CHAN_JOINING;
       }
     } else
       check_lonely_channel(chan);
@@ -2841,8 +2843,8 @@ static int gotkick(char *from, char *origmsg)
   char *nick = newsplit(&msg);
 
   if (match_my_nick(nick) && channel_pending(chan) && shouldjoin(chan) && !channel_joining(chan)) {
-    chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
-    chan->status |= CHAN_JOINING;
+    chan->ircnet_status = 0;
+    chan->ircnet_status |= CHAN_JOINING;
     dprintf(DP_MODE, "JOIN %s %s\n",
             (chan->name[0]) ? chan->name : chan->dname,
             chan->channel.key[0] ? chan->channel.key : chan->key_prot);
@@ -2888,11 +2890,11 @@ static int gotkick(char *from, char *origmsg)
     irc_log(chan, "%s was kicked by %s (%s)", s1, from, msg);
     /* Kicked ME?!? the sods! */
     if (match_my_nick(nick) && shouldjoin(chan) && !channel_joining(chan)) {
-      chan->status &= ~(CHAN_ACTIVE | CHAN_PEND);
+      chan->ircnet_status = 0;
       dprintf(DP_MODE, "JOIN %s %s\n",
               (chan->name[0]) ? chan->name : chan->dname,
               chan->channel.key[0] ? chan->channel.key : chan->key_prot);
-      chan->status |= CHAN_JOINING;
+      chan->ircnet_status |= CHAN_JOINING;
       clear_channel(chan, 1);
     } else {
       killmember(chan, nick);

+ 16 - 16
src/mod/irc.mod/irc.c

@@ -606,7 +606,7 @@ getin_request(char *botnick, char *code, char *par)
 
         putlog(LOG_GETIN, "*", "Got key for %s from %s (%s) - Joining", chan->dname, botnick, chan->channel.key);
         dprintf(DP_MODE, "JOIN %s %s\n", chan->name[0] ? chan->name : chan->dname, chan->channel.key);
-        chan->status |= CHAN_JOINING;
+        chan->ircnet_status |= CHAN_JOINING;
       } else {
         putlog(LOG_GETIN, "*", "Got key for %s from %s - I'm already in the channel", chan->dname, botnick);
       }
@@ -1280,8 +1280,8 @@ any_ops(struct chanset_t *chan)
 
 static void get_channel_masks(struct chanset_t* chan) {
   bd::String tocheck(size_t(4));
-  if (!(chan->status & CHAN_ASKEDBANS)) {
-    chan->status |= CHAN_ASKEDBANS;
+  if (!(chan->ircnet_status & CHAN_ASKEDBANS)) {
+    chan->ircnet_status |= CHAN_ASKEDBANS;
     tocheck += 'b';
   }
 
@@ -1323,8 +1323,8 @@ reset_chan_info(struct chanset_t *chan)
     free(chan->channel.key);
     chan->channel.key = (char *) my_calloc(1, 1);
     clear_channel(chan, 1);
-    chan->status |= CHAN_PEND;
-    chan->status &= ~(CHAN_ACTIVE | CHAN_ASKEDMODES | CHAN_JOINING);
+    chan->ircnet_status |= CHAN_PEND;
+    chan->ircnet_status &= ~(CHAN_ACTIVE | CHAN_ASKEDMODES | CHAN_JOINING);
     /* don't bother checking bans if it's +take */
     if (!channel_take(chan)) {
       if (opped) {
@@ -1372,7 +1372,7 @@ check_lonely_channel(struct chanset_t *chan)
       dprintf(DP_MODE, "PART %s\n", chan->name);
       /* If it's a !chan, we need to recreate the channel with !!chan <cybah> */
       dprintf(DP_MODE, "JOIN %s%s %s\n", (chan->dname[0] == '!') ? "!" : "", chan->dname, chan->key_prot);
-      chan->status |= CHAN_JOINING;
+      chan->ircnet_status |= CHAN_JOINING;
       whined = 0;
     }
   } else if (any_ops(chan)) {
@@ -1565,24 +1565,24 @@ check_expired_chanstuff(struct chanset_t *chan)
 
       if (me_op(chan)) {
         if (dovoice(chan) && !loading) {      /* autovoice of +v users if bot is +y */
-          if (!chan_hasop(m) && !chan_hasvoice(m)) {
+          if (!chan_hasop(m) && !chan_hasvoice(m) && !chan_sentvoice(m)) {
             member_getuser(m, 1);
 
             if (m->user) {
               get_user_flagrec(m->user, &fr, chan->dname, chan);
               if (!glob_bot(fr)) {
-                if (!chan_sentvoice(m) && !(m->flags & EVOICE) && 
+                if (!(m->flags & EVOICE) &&
                     (
-                     (channel_voice(chan) && !chk_devoice(fr)) ||
+                     /* +voice: Voice all clients who are not flag:+q. If the chan is +voicebitch, only op flag:+v clients */
+                     (channel_voice(chan) && !chk_devoice(fr) && (!channel_voicebitch(chan) || (channel_voicebitch(chan) && chk_voice(fr, chan)))) ||
+                     /* Or, if the channel is -voice but they still qualify to be voiced */
                      (!channel_voice(chan) && !privchan(fr, chan, PRIV_VOICE) && chk_voice(fr, chan))
                     )
                    ) {
                   add_mode(chan, '+', 'v', m->nick);
-                } else if ((chk_devoice(fr) || (m->flags & EVOICE))) {
-                  add_mode(chan, '-', 'v', m->nick);
                 }
               }
-            } else if (!chan_sentvoice(m) && !m->user && channel_voice(chan) && voice_ok(m, chan)) {
+            } else if (!m->user && channel_voice(chan) && !channel_voicebitch(chan) && voice_ok(m, chan)) {
               add_mode(chan, '+', 'v', m->nick);
             }
           }
@@ -1595,7 +1595,7 @@ check_expired_chanstuff(struct chanset_t *chan)
     dprintf(DP_MODE, "JOIN %s %s\n",
             (chan->name[0]) ? chan->name : chan->dname,
             chan->channel.key[0] ? chan->channel.key : chan->key_prot);
-    chan->status |= CHAN_JOINING;
+    chan->ircnet_status |= CHAN_JOINING;
   }
 }
 
@@ -1681,13 +1681,13 @@ irc_report(int idx, int details)
     if (!privchan(fr, chan, PRIV_OP) && (idx == DP_STDOUT || glob_master(fr) || chan_master(fr))) {
       p = NULL;
       if (shouldjoin(chan)) {
-        if (chan->status & CHAN_JUPED)
+        if (chan->ircnet_status & CHAN_JUPED)
           p = "juped";
         else if (channel_joining(chan))
           p = "joining";
-        else if (!(chan->status & CHAN_ACTIVE))
+        else if (!(chan->ircnet_status & CHAN_ACTIVE))
           p = "trying";
-        else if (chan->status & CHAN_PEND)
+        else if (chan->ircnet_status & CHAN_PEND)
           p = "pending";
         else if ((chan->dname[0] != '+') && !me_op(chan))
           p = "want ops!";

+ 4 - 4
src/mod/irc.mod/mode.c

@@ -1409,7 +1409,7 @@ gotmode(char *from, char *msg)
                 mv->flags &= ~SENTVOICE;
                 mv->flags |= CHANVOICE;
                 if (channel_active(chan) && dovoice(chan)) {
-                  if (dv || chk_devoice(victim)) {
+                  if (dv || chk_devoice(victim) || (channel_voicebitch(chan) && !chk_voice(victim, chan))) {
                     add_mode(chan, '-', 'v', mparam);
                   } else if (reversing) {
                     add_mode(chan, '-', 'v', mparam);
@@ -1427,8 +1427,8 @@ gotmode(char *from, char *msg)
                     /* if they arent +v|v and VOICER is m+ then EVOICE them */
                   } else {
                     /* FIXME: same thing here */
-                    if (!match_my_nick(nick) && channel_voice(chan) && 
-                        (glob_master(user) || chan_master(user) || glob_bot(user)) && 
+                    if (!match_my_nick(nick) && channel_voice(chan) && !glob_bot(user) &&
+                        (glob_master(user) || chan_master(user)) &&
                         rfc_casecmp(nick, mparam)) {
                       /* if the user is not +q set them norEVOICE. */
                       if (!chan_quiet(victim) && !(mv->flags & EVOICE)) {
@@ -1488,7 +1488,7 @@ gotmode(char *from, char *msg)
       if (chan->channel.do_opreq)
         request_op(chan);
       if (!me_op(chan) && isserver[0])		/* FIXME, WTF IS THIS? */
-        chan->status |= CHAN_ASKEDMODES;
+        chan->ircnet_status |= CHAN_ASKEDMODES;
     }
   }
   return 0;

+ 13 - 10
src/mod/server.mod/servmsg.c

@@ -205,10 +205,11 @@ join_chans()
 {
   for (register struct chanset_t *chan = chanset; chan; chan = chan->next) {
     if (shouldjoin(chan)) {
-      chan->status &= ~(CHAN_ACTIVE | CHAN_PEND | CHAN_JOINING);
+      // Clear out all channel status flags
+      chan->ircnet_status = 0;
       dprintf(DP_SERVER, "JOIN %s %s\n", (chan->name[0]) ? chan->name : chan->dname,
                                          chan->channel.key[0] ? chan->channel.key : chan->key_prot);
-      chan->status |= CHAN_JOINING;
+      chan->ircnet_status |= CHAN_JOINING;
     }
   }
 }
@@ -380,8 +381,8 @@ static int got442(char *from, char *msg)
     if (shouldjoin(chan) && !channel_joining(chan)) {
       putlog(LOG_MISC, chname, "Server says I'm not on channel: %s", chname);
       clear_channel(chan, 1);
-      chan->status &= ~CHAN_ACTIVE;
-      chan->status |= CHAN_JOINING;
+      chan->ircnet_status = 0;
+      chan->ircnet_status |= CHAN_JOINING;
       dprintf(DP_MODE, "JOIN %s %s\n", chan->name,
 	      chan->channel.key[0] ? chan->channel.key : chan->key_prot);
     }
@@ -1085,13 +1086,13 @@ static int got437(char *from, char *msg)
   if (s[0] && (strchr(CHANMETA, s[0]) != NULL)) {
     chan = findchan(s);
     if (chan) {
-      chan->status &= ~(CHAN_JOINING);
-      if (chan->status & CHAN_ACTIVE) {
+      chan->ircnet_status &= ~(CHAN_JOINING);
+      if (chan->ircnet_status & CHAN_ACTIVE) {
 	putlog(LOG_MISC, "*", "Can't change nickname on %s.  Is my nickname banned?", s);
       } else {
 	if (!channel_juped(chan)) {
 	  putlog(LOG_MISC, "*", "Channel %s is juped. :(", s);
-	  chan->status |= CHAN_JUPED;
+	  chan->ircnet_status |= CHAN_JUPED;
 	}
       }
     }
@@ -1278,8 +1279,10 @@ static void kill_server(int idx, void *x)
   disconnect_server(idx, NO_LOST);	/* eof_server will lostdcc() it. */
 
   if (!segfaulted)		// don't bother if we've segfaulted, too many memory calls in this loop
-    for (struct chanset_t *chan = chanset; chan; chan = chan->next)
-       clear_channel(chan, 1);
+    for (struct chanset_t *chan = chanset; chan; chan = chan->next) {
+      chan->ircnet_status = 0;
+      clear_channel(chan, 1);
+    }
   /* A new server connection will be automatically initiated in
      about 2 seconds. */
 }
@@ -1839,7 +1842,7 @@ static void connect_server(void)
     use_monitor = 0;
 
     for (chan = chanset; chan; chan = chan->next)
-      chan->status &= ~CHAN_JUPED;
+      chan->ircnet_status &= ~CHAN_JUPED;
 
     dcc[newidx].timeval = now;
     dcc[newidx].sock = -1;