1
0
Эх сурвалжийг харах

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 16 жил өмнө
parent
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
 1.3 - http://wraith.botpack.net/milestone/1.3
 * Binary / shell / startup changes
 * Binary / shell / startup changes
   * Binary error messages are no longer obscure numbers or fake segfaults. (Compile with OBSCURE_ERRORS to re-enable)
   * 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.
                        unless they are +q globally or +q for the channel.
                        If a botnet master devoices them, they will remain 
                        If a botnet master devoices them, they will remain 
                        devoiced no matter who voices them.
                        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?
         $bdynamicbans$b    Only activate bans on the channel when necessary?
                        This keeps the channel's ban list from getting
                        This keeps the channel's ban list from getting
                        excessively long. The bot still remembers every ban,
                        excessively long. The bot still remembers every ban,

+ 32 - 27
src/chan.h

@@ -23,9 +23,9 @@ typedef struct memstruct {
   char userip[UHOSTLEN];
   char userip[UHOSTLEN];
 } memberlist;
 } 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 CHANMETA "#&!+"
 #define NICKVALID "[{}]^`|\\_-"
 #define NICKVALID "[{}]^`|\\_-"
@@ -242,24 +242,26 @@ struct chanset_t {
 #define CHAN_NODESYNCH      BIT15
 #define CHAN_NODESYNCH      BIT15
 #define CHAN_FASTOP         BIT16	/* Bots will not use +o-b to op (no cookies) */ 
 #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_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_EXEMPTS  BIT0
 #define CHAN_ASKED_INVITES  BIT1
 #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 */
 /* prototypes */
 memberlist *ismember(struct chanset_t *, const char *);
 memberlist *ismember(struct chanset_t *, const char *);
 struct chanset_t *findchan(const char *name);
 struct chanset_t *findchan(const char *name);
@@ -270,9 +272,16 @@ struct chanset_t *findchan_by_dname(const char *name);
 /* is this channel +t? */
 /* is this channel +t? */
 #define channel_optopic(chan) (chan->channel.mode & CHANTOPIC)
 #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_backup(chan) (chan->status & CHAN_BACKUP)
 #define channel_bitch(chan) (chan->status & CHAN_BITCH)
 #define channel_bitch(chan) (chan->status & CHAN_BITCH)
 #define chan_bitch(chan) (chan->status & (CHAN_BITCH|CHAN_BOTBITCH))
 #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_secret(chan) (chan->status & CHAN_SECRET)
 #define channel_cycle(chan) (chan->status & CHAN_CYCLE)
 #define channel_cycle(chan) (chan->status & CHAN_CYCLE)
 #define channel_inactive(chan) (chan->status & CHAN_INACTIVE)
 #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
 #ifdef REVENGE
 #define channel_revenge(chan) (chan->status & CHAN_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_nomassjoin(chan) (chan->status & CHAN_NOMASSJOIN)
 #define channel_meankicks(chan) (chan->status & CHAN_MEANKICKS)
 #define channel_meankicks(chan) (chan->status & CHAN_MEANKICKS)
 #define channel_rbl(chan) (chan->status & CHAN_RBL)
 #define channel_rbl(chan) (chan->status & CHAN_RBL)
+#define channel_voicebitch(chan) (chan->status & CHAN_VOICEBITCH)
 /* Chanflag template
 /* Chanflag template
  *#define channel_temp(chan) (chan->status & CHAN_PRIVATE)
  *#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;
       chan->channel.jointime = 0;
     if (shouldjoin(chan) && !channel_active(chan) && !channel_joining(chan)) {
     if (shouldjoin(chan) && !channel_active(chan) && !channel_joining(chan)) {
       dprintf(DP_MODE, "JOIN %s %s\n", chan->dname, chan->key_prot);
       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)) {
   } else if (channel_closed(chan)) {
     enforce_closed(chan);
     enforce_closed(chan);
@@ -485,7 +485,7 @@ static void got_jn(int idx, char *code, char *par)
     chan->channel.jointime = 0;
     chan->channel.jointime = 0;
     if (!conf.bot->hub && shouldjoin(chan) && !channel_active(chan) && !channel_joining(chan)) {
     if (!conf.bot->hub && shouldjoin(chan) && !channel_active(chan) && !channel_joining(chan)) {
       dprintf(DP_MODE, "JOIN %s %s\n", chan->name, chan->key_prot);
       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 ");
           i += my_strcpy(s + i, "meankicks ");
         if (channel_rbl(chan))
         if (channel_rbl(chan))
           i += my_strcpy(s + i, "rbl ");
           i += my_strcpy(s + i, "rbl ");
+        if (channel_voicebitch(chan))
+          i += my_strcpy(s + i, "voicebitch ");
 /* Chanflag template
 /* Chanflag template
  *	if (channel_temp(chan))
  *	if (channel_temp(chan))
  *	  i += my_strcpy(s + i, "temp ");
  *	  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)) {
   if (!conf.bot->hub && shouldjoin(chan) && !channel_joining(chan)) {
     dprintf(DP_MODE, "JOIN %s %s\n", chan->name, chan->key_prot);
     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_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 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 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)
 static void cmd_chaninfo(int idx, char *par)
 {
 {
   char *chname = NULL, work[512] = "";
   char *chname = NULL, work[512] = "";
@@ -1255,6 +1255,7 @@ static void cmd_chaninfo(int idx, char *par)
     if (HAVE_TAKE)
     if (HAVE_TAKE)
       SHOW_FLAG("take",		channel_take(chan));
       SHOW_FLAG("take",		channel_take(chan));
     SHOW_FLAG("voice",		channel_voice(chan));
     SHOW_FLAG("voice",		channel_voice(chan));
+    SHOW_FLAG("voicebitch",		channel_voicebitch(chan));
     SHOW_FLAG("", 0);
     SHOW_FLAG("", 0);
     SHOW_FLAG("dynamicbans",	channel_dynamicbans(chan));
     SHOW_FLAG("dynamicbans",	channel_dynamicbans(chan));
     SHOW_FLAG("userbans",	!channel_nouserbans(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;
   bool error = 0;
   int old_status = chan->status,
   int old_status = chan->status,
-      old_ircnet_status = chan->ircnet_status,
       old_mode_mns_prot = chan->mode_mns_prot,
       old_mode_mns_prot = chan->mode_mns_prot,
       old_mode_pls_prot = chan->mode_pls_prot;
       old_mode_pls_prot = chan->mode_pls_prot;
   char s[121] = "", result_extra[RESULT_LEN / 2] = "";
   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 (!str_isdigit(item[i])) {
         if (!strcasecmp("Op",  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]))
         else if (!strcasecmp("Voice", item[i]))
-          chan->knock_flags = FLOOD_EXEMPT_VOICE;
+          chan->knock_flags = CHAN_FLAG_VOICE;
         else if (!strcasecmp("User", item[i]))
         else if (!strcasecmp("User", item[i]))
-          chan->knock_flags = FLOOD_EXEMPT_USER;
+          chan->knock_flags = CHAN_FLAG_USER;
         else if (!strcasecmp("None", item[i]))
         else if (!strcasecmp("None", item[i]))
           chan->knock_flags = 0;
           chan->knock_flags = 0;
         else {
         else {
@@ -508,9 +507,9 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
       }
       }
       if (!str_isdigit(item[i])) {
       if (!str_isdigit(item[i])) {
         if (!strcasecmp("Op",  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]))
         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]))
         else if (!strcasecmp("None", item[i]))
           chan->flood_exempt_mode = 0;
           chan->flood_exempt_mode = 0;
         else {
         else {
@@ -592,21 +591,21 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
     else if (!strcmp(item[i], "-cycle"))
     else if (!strcmp(item[i], "-cycle"))
       chan->status &= ~CHAN_CYCLE;
       chan->status &= ~CHAN_CYCLE;
     else if (!strcmp(item[i], "+dynamicexempts"))
     else if (!strcmp(item[i], "+dynamicexempts"))
-      chan->ircnet_status|= CHAN_DYNAMICEXEMPTS;
+      chan->status |= CHAN_DYNAMICEXEMPTS;
     else if (!strcmp(item[i], "-dynamicexempts"))
     else if (!strcmp(item[i], "-dynamicexempts"))
-      chan->ircnet_status&= ~CHAN_DYNAMICEXEMPTS;
+      chan->status &= ~CHAN_DYNAMICEXEMPTS;
     else if (!strcmp(item[i], "-userexempts"))
     else if (!strcmp(item[i], "-userexempts"))
-      chan->ircnet_status|= CHAN_NOUSEREXEMPTS;
+      chan->status |= CHAN_NOUSEREXEMPTS;
     else if (!strcmp(item[i], "+userexempts"))
     else if (!strcmp(item[i], "+userexempts"))
-      chan->ircnet_status&= ~CHAN_NOUSEREXEMPTS;
+      chan->status &= ~CHAN_NOUSEREXEMPTS;
     else if (!strcmp(item[i], "+dynamicinvites"))
     else if (!strcmp(item[i], "+dynamicinvites"))
-      chan->ircnet_status|= CHAN_DYNAMICINVITES;
+      chan->status |= CHAN_DYNAMICINVITES;
     else if (!strcmp(item[i], "-dynamicinvites"))
     else if (!strcmp(item[i], "-dynamicinvites"))
-      chan->ircnet_status&= ~CHAN_DYNAMICINVITES;
+      chan->status &= ~CHAN_DYNAMICINVITES;
     else if (!strcmp(item[i], "-userinvites"))
     else if (!strcmp(item[i], "-userinvites"))
-      chan->ircnet_status|= CHAN_NOUSERINVITES;
+      chan->status |= CHAN_NOUSERINVITES;
     else if (!strcmp(item[i], "+userinvites"))
     else if (!strcmp(item[i], "+userinvites"))
-      chan->ircnet_status&= ~CHAN_NOUSERINVITES;
+      chan->status &= ~CHAN_NOUSERINVITES;
     else if (!strcmp(item[i], "+closed"))
     else if (!strcmp(item[i], "+closed"))
       chan->status |= CHAN_CLOSED;
       chan->status |= CHAN_CLOSED;
     else if (!strcmp(item[i], "-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;
       chan->status |= CHAN_RBL;
     else if (!strcmp(item[i], "-rbl"))
     else if (!strcmp(item[i], "-rbl"))
       chan->status &= ~CHAN_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
 /* Chanflag template
  *  else if (!strcmp(item[i], "+temp"))
  *  else if (!strcmp(item[i], "+temp"))
  *    chan->status |= CHAN_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 (!conf.bot->hub && (chan != chanset_default)) {
     if ((old_status ^ chan->status) & (CHAN_INACTIVE | CHAN_BACKUP)) {
     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);
         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]) ?
         dprintf(DP_SERVER, "JOIN %s %s\n", (chan->name[0]) ?
   			   chan->name : chan->dname,
   			   chan->name : chan->dname,
   			   chan->channel.key[0] ?
   			   chan->channel.key[0] ?
     			   chan->channel.key : chan->key_prot);
     			   chan->channel.key : chan->key_prot);
-        chan->status |= CHAN_JOINING;
+        chan->ircnet_status |= CHAN_JOINING;
       }
       }
     }
     }
     if (me_op(chan)) {
     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);
         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);
         recheck_channel(chan, 0);
       } else if ((old_status & CHAN_TAKE) && !(chan->status & CHAN_TAKE)) {
       } else if ((old_status & CHAN_TAKE) && !(chan->status & CHAN_TAKE)) {
         //Set -take, fetch bans/exempts/invites
         //Set -take, fetch bans/exempts/invites
@@ -900,7 +902,9 @@ void clear_channel(struct chanset_t *chan, bool reset)
   clear_masklist(chan->channel.invite);
   clear_masklist(chan->channel.invite);
   chan->channel.invite = NULL;
   chan->channel.invite = NULL;
 
 
-  chan->status &= ~CHAN_HAVEBANS;
+  chan->channel.last_eI = 0;
+
+  chan->ircnet_status &= ~CHAN_HAVEBANS;
 
 
   if (reset)
   if (reset)
     init_channel(chan, 1);
     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
       } else
 	display_mask(type, idx, k++, mr, chan, show_inact);
 	display_mask(type, idx, k++, mr, chan, show_inact);
     }
     }
-    if (chan->status & CHAN_ACTIVE) {
+    if (chan->ircnet_status & CHAN_ACTIVE) {
       masklist *ml = NULL;
       masklist *ml = NULL;
       masklist *channel_list = (type == 'b' ? chan->channel.ban : type == 'e' ? chan->channel.exempt : chan->channel.invite);
       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 \
 %cmeankicks %cenforcebans %cdynamicbans %cuserbans %cbitch \
 %cprivate %ccycle %cinactive %cdynamicexempts %cuserexempts \
 %cprivate %ccycle %cinactive %cdynamicexempts %cuserexempts \
 %cdynamicinvites %cuserinvites %cnodesynch %cclosed %cvoice \
 %cdynamicinvites %cuserinvites %cnodesynch %cclosed %cvoice \
-%cfastop %cautoop %cbotbitch %cbackup %cnomassjoin %crbl %c%s",
+%cfastop %cautoop %cbotbitch %cbackup %cnomassjoin %crbl %cvoicebitch %c%s",
 	w,
 	w,
 /* Chanchar template
 /* Chanchar template
  *      temp,
  *      temp,
@@ -789,6 +789,7 @@ flood-exempt %d flood-lock-time %d knock %d \
         PLSMNS(channel_backup(chan)),
         PLSMNS(channel_backup(chan)),
         PLSMNS(channel_nomassjoin(chan)),
         PLSMNS(channel_nomassjoin(chan)),
         PLSMNS(channel_rbl(chan)),
         PLSMNS(channel_rbl(chan)),
+        PLSMNS(channel_voicebitch(chan)),
 	HAVE_TAKE ? PLSMNS(channel_take(chan)) : ' ',
 	HAVE_TAKE ? PLSMNS(channel_take(chan)) : ' ',
         HAVE_TAKE ? "take " : " "
         HAVE_TAKE ? "take " : " "
 /* Chanflag template
 /* 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)
     if (p)
       *p = 0;
       *p = 0;
     while (chan) {
     while (chan) {
-      if (chan->status & CHAN_ACTIVE) {
+      if (chan->ircnet_status & CHAN_ACTIVE) {
         if (!strcasecmp(chan->name, chname)) {
         if (!strcasecmp(chan->name, chname)) {
           dprintf(DP_HELP, "NOTICE %s :\002BitchX\002: Access Denied\n", nick);
           dprintf(DP_HELP, "NOTICE %s :\002BitchX\002: Access Denied\n", nick);
           return BIND_RET_LOG;
           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))) ||
        (glob_master(fr) || chan_master(fr))) ||
       ((which != FLOOD_DEOP) && (which != FLOOD_KICK) && 
       ((which != FLOOD_DEOP) && (which != FLOOD_KICK) && 
        ( (chk_noflood(fr) || 
        ( (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;
     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))
     if (pls & CHANINV && !(cur & CHANINV))
       add_mode(chan, '+', 'i', "");
       add_mode(chan, '+', 'i', "");
     else if (mns & CHANINV && cur & CHANINV)
     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 (dovoice(chan)) {
     if (chan_hasvoice(m) && !chan_hasop(m)) {
     if (chan_hasvoice(m) && !chan_hasop(m)) {
       /* devoice +q users .. */
       /* devoice +q users .. */
-      if (chk_devoice(*fr))
+      if (chk_devoice(*fr) || (channel_voicebitch(chan) && !chk_voice(*fr, chan)))
         add_mode(chan, '-', 'v', m->nick);
         add_mode(chan, '-', 'v', m->nick);
     } else if (!chan_hasvoice(m) && !chan_hasop(m)) {
     } else if (!chan_hasvoice(m) && !chan_hasop(m)) {
       /* voice +v users */
       /* 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)
     //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)
     //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)
       if (channel_nouserbans(chan) && !stop_reset)
         resetbans(chan);
         resetbans(chan);
       else
       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.
     // Do this here as the above only runs after already having been opped and having gotten bans.
     if (dobans) {
     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);
         dprintf(DP_MODE, "MODE %s\n", chan->name);
       recheck_channel_modes(chan);
       recheck_channel_modes(chan);
     }
     }
@@ -1661,9 +1661,9 @@ static int got710(char *from, char *msg)
   get_user_flagrec(u, &fr, chan->dname, chan);
   get_user_flagrec(u, &fr, chan->dname, chan);
 
 
   // PASSING: +o and op || +v and op/voice || user
   // 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)) {
       chan_kick(fr) || glob_kick(fr)) {
     return 0;
     return 0;
   }
   }
@@ -1701,9 +1701,9 @@ static int got324(char *from, char *msg)
   bool ok = 0;
   bool ok = 0;
   char *p = NULL, *q = NULL;
   char *p = NULL, *q = NULL;
 
 
-  if (chan->status & CHAN_ASKEDMODES)
+  if (chan->ircnet_status & CHAN_ASKEDMODES)
     ok = 1;
     ok = 1;
-  chan->status &= ~CHAN_ASKEDMODES;
+  chan->ircnet_status &= ~CHAN_ASKEDMODES;
   chan->channel.mode = 0;
   chan->channel.mode = 0;
   while (msg[i] != 0) {
   while (msg[i] != 0) {
     if (msg[i] == 'i')
     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 
 	 * an asterisk and this has been agreed upon by other major IRC 
 	 * networks so we'll check for an asterisk here as well 
 	 * networks so we'll check for an asterisk here as well 
 	 * (guppy 22Dec2001) */ 
 	 * (guppy 22Dec2001) */ 
-        chan->status |= CHAN_ASKEDMODES;
+        chan->ircnet_status |= CHAN_ASKEDMODES;
     }
     }
     if (msg[i] == 'l') {
     if (msg[i] == 'l') {
       p = strchr(msg, ' ');
       p = strchr(msg, ' ');
@@ -2015,14 +2015,14 @@ static int got315(char *from, char *msg)
     return 0;
     return 0;
 
 
   /* Finished getting who list, can now be considered officially ON CHANNEL */
   /* 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. */
   /* Am *I* on the channel now? if not, well d0h. */
   if (shouldjoin(chan) && !ismember(chan, botname)) {
   if (shouldjoin(chan) && !ismember(chan, botname)) {
     putlog(LOG_MISC | LOG_JOIN, chan->dname, "Oops, I'm not really on %s.", chan->dname);
     putlog(LOG_MISC | LOG_JOIN, chan->dname, "Oops, I'm not really on %s.", chan->dname);
     clear_channel(chan, 1);
     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",
     dprintf(DP_MODE, "JOIN %s %s\n",
 	    (chan->name[0]) ? chan->name : chan->dname,
 	    (chan->name[0]) ? chan->name : chan->dname,
 	    chan->channel.key[0] ? chan->channel.key : chan->key_prot);
 	    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))
     if (me_op(chan))
       recheck_channel(chan, 2);
       recheck_channel(chan, 2);
     else if (chan->channel.members == 1)
     else if (chan->channel.members == 1)
-      chan->status |= CHAN_STOP_CYCLE;
+      chan->ircnet_status |= CHAN_STOP_CYCLE;
     else if (any_ops(chan))
     else if (any_ops(chan))
       request_op(chan);
       request_op(chan);
   }
   }
@@ -2077,8 +2077,8 @@ static int got368(char *from, char *msg)
   chname = newsplit(&msg);
   chname = newsplit(&msg);
   chan = findchan(chname);
   chan = findchan(chname);
   if (chan) {
   if (chan) {
-    chan->status &= ~CHAN_ASKEDBANS;
-    chan->status |= CHAN_HAVEBANS;
+    chan->ircnet_status &= ~CHAN_ASKEDBANS;
+    chan->ircnet_status |= CHAN_HAVEBANS;
 
 
     if (channel_nouserbans(chan))
     if (channel_nouserbans(chan))
       resetbans(chan);
       resetbans(chan);
@@ -2253,7 +2253,7 @@ static int got403(char *from, char *msg)
              "Unique channel %s does not exist... Attempting to join with "
              "Unique channel %s does not exist... Attempting to join with "
              "short name.", chname);
              "short name.", chname);
       dprintf(DP_SERVER, "JOIN %s\n", chan->dname);
       dprintf(DP_SERVER, "JOIN %s\n", chan->dname);
-      chan->status |= CHAN_JOINING;
+      chan->ircnet_status |= CHAN_JOINING;
     } else {
     } else {
       /* We have found the channel, so the server has given us the short
       /* We have found the channel, so the server has given us the short
        * name. Prefix another '!' to it, and attempt the join again...
        * 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);
   chan = findchan_by_dname(chname);
   if (chan) {
   if (chan) {
-    chan->status &= ~CHAN_JOINING;
+    chan->ircnet_status &= ~CHAN_JOINING;
     putlog(LOG_JOIN, chan->dname, "Channel full--can't join: %s", chan->dname);
     putlog(LOG_JOIN, chan->dname, "Channel full--can't join: %s", chan->dname);
     request_in(chan);
     request_in(chan);
 /* need: limit */
 /* need: limit */
@@ -2320,7 +2320,7 @@ static int got473(char *from, char *msg)
    */
    */
   chan = findchan_by_dname(chname);
   chan = findchan_by_dname(chname);
   if (chan) {
   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);
     putlog(LOG_JOIN, chan->dname, "Channel invite only--can't join: %s", chan->dname);
     request_in(chan);
     request_in(chan);
 /* need: invite */
 /* need: invite */
@@ -2353,7 +2353,7 @@ static int got474(char *from, char *msg)
    */
    */
   chan = findchan_by_dname(chname);
   chan = findchan_by_dname(chname);
   if (chan) {
   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);
     putlog(LOG_JOIN, chan->dname, "Banned from channel--can't join: %s", chan->dname);
     request_in(chan);
     request_in(chan);
 /* need: unban */
 /* need: unban */
@@ -2386,7 +2386,7 @@ static int got475(char *from, char *msg)
    */
    */
   chan = findchan_by_dname(chname);
   chan = findchan_by_dname(chname);
   if (chan && shouldjoin(chan)) {
   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);
     putlog(LOG_JOIN, chan->dname, "Bad key--can't join: %s", chan->dname);
     if (chan->channel.key[0]) {
     if (chan->channel.key[0]) {
       free(chan->channel.key);
       free(chan->channel.key);
@@ -2567,7 +2567,7 @@ static int gotjoin(char *from, char *chname)
   } else if (!channel_pending(chan)) {
   } else if (!channel_pending(chan)) {
     char *host = NULL;
     char *host = NULL;
 
 
-    chan->status &= ~CHAN_STOP_CYCLE;
+    chan->ircnet_status &= ~CHAN_STOP_CYCLE;
 
 
     detect_chan_flood(nick, uhost, from, chan, FLOOD_JOIN, NULL);
     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)) {
     if (!channel_active(chan) && !match_my_nick(nick)) {
       /* uh, what?!  i'm on the channel?! */
       /* uh, what?!  i'm on the channel?! */
       putlog(LOG_ERROR, "*", "confused bot: guess I'm on %s and didn't realize it", chan->dname);
       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);
       reset_chan_info(chan);
     } else {
     } else {
       memberlist *m = ismember(chan, nick);
       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>
 	   * unique name for the channel (as the server see's it). <cybah>
 	   */
 	   */
 	  strlcpy(chan->name, chname, 81);
 	  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
           /* ... and log us joining. Using chan->dname for the channel is
 	   * important in this case. As the config file will never contain
 	   * 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->user) {
               if (!(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))
                    (!channel_voice(chan) && !privchan(fr, chan, PRIV_VOICE) && chk_voice(fr, chan))
                   )
                   )
                  ) {
                  ) {
                 m->delay = now + chan->auto_delay;
                 m->delay = now + chan->auto_delay;
                 m->flags |= SENTVOICE;
                 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->delay = now + chan->auto_delay;
               m->flags |= SENTVOICE;
               m->flags |= SENTVOICE;
             }
             }
@@ -2784,7 +2786,7 @@ static int gotpart(char *from, char *msg)
   if (chan && !shouldjoin(chan) && match_my_nick(nick)) {
   if (chan && !shouldjoin(chan) && match_my_nick(nick)) {
     irc_log(chan, "Parting");    
     irc_log(chan, "Parting");    
     clear_channel(chan, 1);
     clear_channel(chan, 1);
-    chan->status &= ~(CHAN_ACTIVE | CHAN_PEND | CHAN_JOINING);
+    chan->ircnet_status = 0;
     return 0;
     return 0;
   }
   }
   if (chan && !channel_pending(chan)) {
   if (chan && !channel_pending(chan)) {
@@ -2794,8 +2796,8 @@ static int gotpart(char *from, char *msg)
     if (!channel_active(chan)) {
     if (!channel_active(chan)) {
       /* whoa! */
       /* whoa! */
       putlog(LOG_ERRORS, "*", "confused bot: guess I'm on %s and didn't realize it", chan->dname);
       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);
       reset_chan_info(chan);
     }
     }
     set_handle_laston(chan->dname, u, now);
     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 it was me, all hell breaks loose... */
     if (match_my_nick(nick)) {
     if (match_my_nick(nick)) {
       clear_channel(chan, 1);
       clear_channel(chan, 1);
-      chan->status &= ~(CHAN_ACTIVE | CHAN_PEND | CHAN_JOINING);
+      chan->ircnet_status = 0;
       if (shouldjoin(chan)) {
       if (shouldjoin(chan)) {
 	dprintf(DP_MODE, "JOIN %s %s\n",
 	dprintf(DP_MODE, "JOIN %s %s\n",
 	        (chan->name[0]) ? chan->name : chan->dname,
 	        (chan->name[0]) ? chan->name : chan->dname,
 	        chan->channel.key[0] ? chan->channel.key : chan->key_prot);
 	        chan->channel.key[0] ? chan->channel.key : chan->key_prot);
-        chan->status |= CHAN_JOINING;
+        chan->ircnet_status |= CHAN_JOINING;
       }
       }
     } else
     } else
       check_lonely_channel(chan);
       check_lonely_channel(chan);
@@ -2841,8 +2843,8 @@ static int gotkick(char *from, char *origmsg)
   char *nick = newsplit(&msg);
   char *nick = newsplit(&msg);
 
 
   if (match_my_nick(nick) && channel_pending(chan) && shouldjoin(chan) && !channel_joining(chan)) {
   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",
     dprintf(DP_MODE, "JOIN %s %s\n",
             (chan->name[0]) ? chan->name : chan->dname,
             (chan->name[0]) ? chan->name : chan->dname,
             chan->channel.key[0] ? chan->channel.key : chan->key_prot);
             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);
     irc_log(chan, "%s was kicked by %s (%s)", s1, from, msg);
     /* Kicked ME?!? the sods! */
     /* Kicked ME?!? the sods! */
     if (match_my_nick(nick) && shouldjoin(chan) && !channel_joining(chan)) {
     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",
       dprintf(DP_MODE, "JOIN %s %s\n",
               (chan->name[0]) ? chan->name : chan->dname,
               (chan->name[0]) ? chan->name : chan->dname,
               chan->channel.key[0] ? chan->channel.key : chan->key_prot);
               chan->channel.key[0] ? chan->channel.key : chan->key_prot);
-      chan->status |= CHAN_JOINING;
+      chan->ircnet_status |= CHAN_JOINING;
       clear_channel(chan, 1);
       clear_channel(chan, 1);
     } else {
     } else {
       killmember(chan, nick);
       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);
         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);
         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 {
       } else {
         putlog(LOG_GETIN, "*", "Got key for %s from %s - I'm already in the channel", chan->dname, botnick);
         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) {
 static void get_channel_masks(struct chanset_t* chan) {
   bd::String tocheck(size_t(4));
   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';
     tocheck += 'b';
   }
   }
 
 
@@ -1323,8 +1323,8 @@ reset_chan_info(struct chanset_t *chan)
     free(chan->channel.key);
     free(chan->channel.key);
     chan->channel.key = (char *) my_calloc(1, 1);
     chan->channel.key = (char *) my_calloc(1, 1);
     clear_channel(chan, 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 */
     /* don't bother checking bans if it's +take */
     if (!channel_take(chan)) {
     if (!channel_take(chan)) {
       if (opped) {
       if (opped) {
@@ -1372,7 +1372,7 @@ check_lonely_channel(struct chanset_t *chan)
       dprintf(DP_MODE, "PART %s\n", chan->name);
       dprintf(DP_MODE, "PART %s\n", chan->name);
       /* If it's a !chan, we need to recreate the channel with !!chan <cybah> */
       /* 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);
       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;
       whined = 0;
     }
     }
   } else if (any_ops(chan)) {
   } else if (any_ops(chan)) {
@@ -1565,24 +1565,24 @@ check_expired_chanstuff(struct chanset_t *chan)
 
 
       if (me_op(chan)) {
       if (me_op(chan)) {
         if (dovoice(chan) && !loading) {      /* autovoice of +v users if bot is +y */
         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);
             member_getuser(m, 1);
 
 
             if (m->user) {
             if (m->user) {
               get_user_flagrec(m->user, &fr, chan->dname, chan);
               get_user_flagrec(m->user, &fr, chan->dname, chan);
               if (!glob_bot(fr)) {
               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))
                      (!channel_voice(chan) && !privchan(fr, chan, PRIV_VOICE) && chk_voice(fr, chan))
                     )
                     )
                    ) {
                    ) {
                   add_mode(chan, '+', 'v', m->nick);
                   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);
               add_mode(chan, '+', 'v', m->nick);
             }
             }
           }
           }
@@ -1595,7 +1595,7 @@ check_expired_chanstuff(struct chanset_t *chan)
     dprintf(DP_MODE, "JOIN %s %s\n",
     dprintf(DP_MODE, "JOIN %s %s\n",
             (chan->name[0]) ? chan->name : chan->dname,
             (chan->name[0]) ? chan->name : chan->dname,
             chan->channel.key[0] ? chan->channel.key : chan->key_prot);
             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))) {
     if (!privchan(fr, chan, PRIV_OP) && (idx == DP_STDOUT || glob_master(fr) || chan_master(fr))) {
       p = NULL;
       p = NULL;
       if (shouldjoin(chan)) {
       if (shouldjoin(chan)) {
-        if (chan->status & CHAN_JUPED)
+        if (chan->ircnet_status & CHAN_JUPED)
           p = "juped";
           p = "juped";
         else if (channel_joining(chan))
         else if (channel_joining(chan))
           p = "joining";
           p = "joining";
-        else if (!(chan->status & CHAN_ACTIVE))
+        else if (!(chan->ircnet_status & CHAN_ACTIVE))
           p = "trying";
           p = "trying";
-        else if (chan->status & CHAN_PEND)
+        else if (chan->ircnet_status & CHAN_PEND)
           p = "pending";
           p = "pending";
         else if ((chan->dname[0] != '+') && !me_op(chan))
         else if ((chan->dname[0] != '+') && !me_op(chan))
           p = "want ops!";
           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 &= ~SENTVOICE;
                 mv->flags |= CHANVOICE;
                 mv->flags |= CHANVOICE;
                 if (channel_active(chan) && dovoice(chan)) {
                 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);
                     add_mode(chan, '-', 'v', mparam);
                   } else if (reversing) {
                   } else if (reversing) {
                     add_mode(chan, '-', 'v', mparam);
                     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 */
                     /* if they arent +v|v and VOICER is m+ then EVOICE them */
                   } else {
                   } else {
                     /* FIXME: same thing here */
                     /* 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)) {
                         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)) {
                       if (!chan_quiet(victim) && !(mv->flags & EVOICE)) {
@@ -1488,7 +1488,7 @@ gotmode(char *from, char *msg)
       if (chan->channel.do_opreq)
       if (chan->channel.do_opreq)
         request_op(chan);
         request_op(chan);
       if (!me_op(chan) && isserver[0])		/* FIXME, WTF IS THIS? */
       if (!me_op(chan) && isserver[0])		/* FIXME, WTF IS THIS? */
-        chan->status |= CHAN_ASKEDMODES;
+        chan->ircnet_status |= CHAN_ASKEDMODES;
     }
     }
   }
   }
   return 0;
   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) {
   for (register struct chanset_t *chan = chanset; chan; chan = chan->next) {
     if (shouldjoin(chan)) {
     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,
       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->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)) {
     if (shouldjoin(chan) && !channel_joining(chan)) {
       putlog(LOG_MISC, chname, "Server says I'm not on channel: %s", chname);
       putlog(LOG_MISC, chname, "Server says I'm not on channel: %s", chname);
       clear_channel(chan, 1);
       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,
       dprintf(DP_MODE, "JOIN %s %s\n", chan->name,
 	      chan->channel.key[0] ? chan->channel.key : chan->key_prot);
 	      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)) {
   if (s[0] && (strchr(CHANMETA, s[0]) != NULL)) {
     chan = findchan(s);
     chan = findchan(s);
     if (chan) {
     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);
 	putlog(LOG_MISC, "*", "Can't change nickname on %s.  Is my nickname banned?", s);
       } else {
       } else {
 	if (!channel_juped(chan)) {
 	if (!channel_juped(chan)) {
 	  putlog(LOG_MISC, "*", "Channel %s is juped. :(", s);
 	  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. */
   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
   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
   /* A new server connection will be automatically initiated in
      about 2 seconds. */
      about 2 seconds. */
 }
 }
@@ -1839,7 +1842,7 @@ static void connect_server(void)
     use_monitor = 0;
     use_monitor = 0;
 
 
     for (chan = chanset; chan; chan = chan->next)
     for (chan = chanset; chan; chan = chan->next)
-      chan->status &= ~CHAN_JUPED;
+      chan->ircnet_status &= ~CHAN_JUPED;
 
 
     dcc[newidx].timeval = now;
     dcc[newidx].timeval = now;
     dcc[newidx].sock = -1;
     dcc[newidx].sock = -1;