]> jfr.im git - irc/quakenet/snircd-patchqueue.git/commitdiff
added cansendtochan.patch to move snircd chanmode checks into one central function...
authorwiebe <redacted>
Mon, 19 Jan 2009 21:19:07 +0000 (22:19 +0100)
committerwiebe <redacted>
Mon, 19 Jan 2009 21:19:07 +0000 (22:19 +0100)
cansendtochan.patch [new file with mode: 0644]
series
split.patch

diff --git a/cansendtochan.patch b/cansendtochan.patch
new file mode 100644 (file)
index 0000000..1640b8c
--- /dev/null
@@ -0,0 +1,556 @@
+attempt to move checks for chanmodes c C N T u into
+the *_can_send_to_channel() functions in channel.c where ircu by default has its chanmode checks
+
+instead of having them in each of the places used (m_wallchops, m_wallvoices, ircd_relay.c, etc.)
+not tested completely
+
+client_can_send_to_channel()
+and
+member_can_send_to_channel()
+do have some of the exact same code - should maybe add a new function and move those there.
+
+possible problem discovered:
+in some places *_can_send_to_channel() is first called with reveal delayedjoin user ON
+but the code then proceeds to check target limits, which upon refusal means the delayedjoin
+user is revealed (locally) without actually sending anything to the channel... that's ugly
+must find a way around that
+
+
+diff -r f6d476f109e2 include/channel.h
+--- a/include/channel.h        Mon Jan 19 15:32:18 2009 +0100
++++ b/include/channel.h        Mon Jan 19 22:10:14 2009 +0100
+@@ -103,9 +103,9 @@
+ #define MODE_DELJOINS   0x1000        /**< New join messages are delayed */
+ #define MODE_REGISTERED 0x2000          /**< Channel marked as registered
+                                          * (for future semantic expansion) */
+-#define MODE_NOCOLOUR   0x4000          /**< No mIRC/ANSI colors/bold */
+-#define MODE_NOCTCP     0x8000          /**< No channel CTCPs */
+-#define MODE_NONOTICE   0x10000          /**< No channel notices */
++#define MODE_NOCOLOUR   0x4000          /**< +c No mIRC/ANSI colors/bold */
++#define MODE_NOCTCP     0x8000          /**< +C No channel CTCPs */
++#define MODE_NONOTICE   0x10000          /**< +N No channel notices */
+ #define MODE_SAVE     0x20000         /**< save this mode-with-arg 'til 
+                                        * later */
+ #define MODE_FREE     0x40000         /**< string needs to be passed to 
+@@ -115,7 +115,7 @@
+ #define MODE_APASS    0x200000
+ #define MODE_WASDELJOINS 0x400000     /**< Not DELJOINS, but some joins 
+                                        * pending */
+-#define MODE_NOQUITPARTS 0x800000
++#define MODE_NOQUITPARTS 0x800000       /**< +u No user defined quit or part messages */
+ #define MODE_NOMULTITARGET 0x1000000    /**< +T No multiple targets */
+ #define MODE_MODERATENOREG 0x2000000    /**< +M Moderate unauthed users */
+@@ -396,8 +396,10 @@
+ extern const char* find_no_nickchange_channel(struct Client* cptr);
+ extern struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr);
+-extern int member_can_send_to_channel(struct Membership* member, int reveal);
+-extern int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal);
++extern int member_can_send_to_channel(struct Membership* member, int reveal,
++  unsigned int flags, const char *text, const int target);
++extern int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr,
++  int reveal, unsigned int flags, const char *text, const int target);
+ extern void remove_user_from_channel(struct Client *sptr, struct Channel *chptr);
+ extern void remove_user_from_all_channels(struct Client* cptr);
+diff -r f6d476f109e2 ircd/channel.c
+--- a/ircd/channel.c   Mon Jan 19 15:32:18 2009 +0100
++++ b/ircd/channel.c   Mon Jan 19 22:10:14 2009 +0100
+@@ -681,53 +681,102 @@
+  * @param member      The membership of the user
+  * @param reveal      If true, the user will be "revealed" on a delayed
+  *                    joined channel.
++ * @param flags The bitmask of additional modes to check (besides +n +m +r +M +b)
++ * @param text The message from the user, needed for modes +c and +C
++ * @param target The number of targets the message is sent to, for +T
+  *
+  * @returns True if the client can speak on the channel.
+  */
+-int member_can_send_to_channel(struct Membership* member, int reveal)
++int member_can_send_to_channel(struct Membership* member, int reveal,
++  unsigned int flags, const char *text, const int target)
+ {
++  const char *ch;
++  unsigned int modes;
++  int controlcodes = 0;
++
+   assert(0 != member);
++  
++  modes = member->channel->mode.mode;
+   /* Do not check for users on other servers: This should be a
+    * temporary desynch, or maybe they are on an older server, but
+    * we do not want to send ERR_CANNOTSENDTOCHAN more than once.
+    */
+-  if (!MyUser(member->user))
+-  {
+-    if (IsDelayedJoin(member) && reveal)
+-      RevealDelayedJoin(member);
+-    return 1;
+-  }
+-  
+-  /* +X user can always speak on the channel */
+-  if (IsXtraOp(member->user)) {
++  /* client on service server (+s) - let it through */
++  if (IsService(cli_user(member->user)->server)) {
+     if (IsDelayedJoin(member) && reveal)
+       RevealDelayedJoin(member);
+     return 1;
+   }
+-  /* Discourage using the Apass to get op.  They should use the Upass. */
++  /* +A   Discourage using the Apass to get op.  They should use the Upass. */
++  /* TODO: exclude +X from this? */
+   if (IsChannelManager(member) && member->channel->mode.apass[0])
+     return 0;
+-  /* If you have voice or ops, you can speak. */
+-  if (IsVoicedOrOpped(member))
+-    return 1;
++  /* If you have voice or ops, you can speak,
++   *   else we need do some more checks
++   *     but allow umode +X to bypass modes +m +r +M and bans 
++   */
++  if (!IsVoicedOrOpped(member) && !IsXtraOp(member->user)) {
+-  /*
+-   * If it's moderated, and you aren't a privileged user, you can't
+-   * speak.
+-   */
+-  if (member->channel->mode.mode & MODE_MODERATED)
+-    return 0;
++    /*
++     * +m   If it's moderated, and you aren't a privileged user, you can't
++     * speak.
++     */
++    if (modes & MODE_MODERATED)
++      return 0;
+-  /* If only logged in users may join and you're not one, you can't speak. */
+-  if (member->channel->mode.mode & (MODE_MODERATENOREG|MODE_REGONLY) && !IsAccount(member->user))
+-    return 0;
++    /* +r and +M   If only logged in users may join and you're not one, you can't speak. */
++    if (modes & (MODE_MODERATENOREG|MODE_REGONLY) && !IsAccount(member->user))
++      return 0;
+-  /* If you're banned then you can't speak either. */
+-  if (is_banned(member))
+-    return 0;
++    /* +b   If you're banned then you can't speak either. */
++    if (is_banned(member))
++      return 0;
++  }
++
++  /* check these only for local users */
++  if (MyUser(member->user)) {
++
++    /* +T   check for multi target message and they are not allowed */
++    if ((flags & MODE_NOMULTITARGET) && (modes & MODE_NOMULTITARGET) &&
++      target > 1) 
++      return 0;
++
++    /* +N   check for channel wide notice and they are not allowed */
++    if ((flags & MODE_NONOTICE) && (modes & MODE_NONOTICE))
++      return 0;
++    
++    /* +u   check for user defined quit and part messages, and they are not allowed */
++    if ((flags & MODE_NOQUITPARTS) && (modes & MODE_NOQUITPARTS))
++      return 0;
++
++    /* these last two checks should always be last
++     * as they loop over the entire message in search for
++     * CTCP char and control codes 
++     */
++    /* +C   check for CTCP and CTCPs are not allowed */
++    if ((flags & MODE_NOCTCP) && (modes & MODE_NOCTCP) && (text != NULL) &&
++      ircd_strncmp(text,"\001ACTION ",8)) {
++      for (ch=text;*ch;) {
++        if (*ch++==1)
++          return 0;
++        if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31)
++          controlcodes = 1;
++      }
++    }
++
++    /* +c   check for control codes and they are not allowed */
++    if ((flags & MODE_NOCOLOUR) && (modes & MODE_NOCOLOUR) && (text != NULL)) {
++      if (controlcodes) /* already found control codes */
++        return 0;
++      for (ch=text;*ch;ch++) {
++        if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31)
++          return 0;
++      }
++    }
++  }
+   if (IsDelayedJoin(member) && reveal)
+     RevealDelayedJoin(member);
+@@ -744,38 +793,95 @@
+  * @param chptr       The channel to check
+  * @param reveal If the user should be revealed (see 
+  *            member_can_send_to_channel())
++ * @param flags The bitmask of additional modes to check (besides +n +m +r +M +b)
++ * @param text  The message needed to check for +c and +C
++ * @param target The number of targets the message is sent to, for +T
+  *
+  * @returns true if the client is allowed to speak on the channel, false 
+  *            otherwise
+  *
+  * @see member_can_send_to_channel()
+  */
+-int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal)
++int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int reveal,
++  unsigned int flags, const char *text, const int target)
+ {
+   struct Membership *member;
+-  assert(0 != cptr); 
++  const char *ch;
++  unsigned int modes;
++  int controlcodes = 0;  
++  
++  assert(0 != cptr);
++  
+   /*
+    * Servers can always speak on channels.
+    */
+   if (IsServer(cptr))
+     return 1;
++  modes = chptr->mode.mode;
+   member = find_channel_member(cptr, chptr);
+-  /*
++  /* 
+    * You can't speak if you're off channel, and it is +n (no external messages)
+    * or +m (moderated).
++   *   (moderated also includes +r and +M when you do not have an account set)
++   *   exempt clients with umode +X and service clients (clients on +s server)
+    */
+   if (!member) {
+-    if (IsXtraOp(cptr))
++    /* client on service server (+s) - let it through */
++    if (IsService(cli_user(cptr)->server))
+       return 1;
+-    else if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
+-      ((chptr->mode.mode & (MODE_REGONLY|MODE_MODERATENOREG)) && !IsAccount(cptr)))
++    /* client with umode +X exempt from modes +n +m +r +M +b */
++    if (!IsXtraOp(cptr)) {
++      if ((modes & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
++           ((modes & (MODE_REGONLY|MODE_MODERATENOREG)) && !IsAccount(cptr)))
++         return 0;
++      if (find_ban(cptr, chptr->banlist))
++        return 0;
++    }
++
++    /* argh..., now we still have this duplicate code, although closer together
++     * maybe move the checks below into its own function to be used here
++     * from client_can_send_to_channel() and
++     *  member_can_send_to_channel() ?
++     */
++
++    /* +T   check for multi target message and they are not allowed */
++    if ((flags & MODE_NOMULTITARGET) && (modes & MODE_NOMULTITARGET) &&
++      target > 1) 
+       return 0;
+-    else
+-      return !find_ban(cptr, chptr->banlist);
++
++    /* +N   check for channel wide notice and they are not allowed */
++    if ((flags & MODE_NONOTICE) && (modes & MODE_NONOTICE))
++      return 0;
++
++    /* these last two checks should always be last
++     * as they loop over the entire message in search for
++     * CTCP char and control codes
++     */
++    /* +C   check for CTCP and CTCPs are not allowed */
++    if ((flags & MODE_NOCTCP) && (modes & MODE_NOCTCP) && (text != NULL) &&
++      ircd_strncmp(text,"\001ACTION ",8)) {
++      for (ch=text;*ch;) {
++        if (*ch++==1)
++          return 0;
++        if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31)
++          controlcodes = 1;
++      }
++    }
++
++    /* +c   check for control codes and they are not allowed */
++    if ((flags & MODE_NOCOLOUR) && (modes & MODE_NOCOLOUR) && (text != NULL)) {
++      if (controlcodes) /* already found control codes */
++        return 0;
++      for (ch=text;*ch;ch++) {
++        if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31)
++          return 0;
++      }
++    }
++    return 1;
+   }
+-  return member_can_send_to_channel(member, reveal);
++  return member_can_send_to_channel(member, reveal, flags, text, target);
+ }
+ /** Returns the name of a channel that prevents the user from changing nick.
+@@ -3625,13 +3731,11 @@
+     /* Send notification to channel */
+     if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
+       sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
+-                  ((flags & CHFL_BANNED) || ((chan->mode.mode & MODE_NOQUITPARTS)
+-                   && !IsChannelService(member->user)) || !jbuf->jb_comment) ?
++                  ((flags & CHFL_BANNED) || !jbuf->jb_comment) ?
+                   "%H" : "%H :%s", chan, jbuf->jb_comment);
+     else if (MyUser(jbuf->jb_source))
+       sendcmdto_one(jbuf->jb_source, CMD_PART, jbuf->jb_source,
+-                  ((flags & CHFL_BANNED) || (chan->mode.mode & MODE_NOQUITPARTS)
+-                   || !jbuf->jb_comment) ?
++                  ((flags & CHFL_BANNED) || !jbuf->jb_comment) ?
+                   ":%H" : "%H :%s", chan, jbuf->jb_comment);
+     /* XXX: Shouldn't we send a PART here anyway? */
+     /* to users on the channel?  Why?  From their POV, the user isn't on
+diff -r f6d476f109e2 ircd/ircd_relay.c
+--- a/ircd/ircd_relay.c        Mon Jan 19 15:32:18 2009 +0100
++++ b/ircd/ircd_relay.c        Mon Jan 19 22:10:14 2009 +0100
+@@ -87,7 +87,6 @@
+ void relay_channel_message(struct Client* sptr, const char* name, const char* text, const int targetc)
+ {
+   struct Channel* chptr;
+-  const char *ch;
+   assert(0 != sptr);
+   assert(0 != name);
+   assert(0 != text);
+@@ -99,35 +98,19 @@
+   /*
+    * This first: Almost never a server/service
+    */
+-  if (!client_can_send_to_channel(sptr, chptr, 1)) {
++  if (!client_can_send_to_channel(sptr, chptr, 1,
++    (MODE_NOCOLOUR | MODE_NOCTCP | MODE_NOMULTITARGET), text, targetc)) {
+     send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+     return;
+   }
++  /* TODO: what is this again?
++   * clinet_can_send_to_channel already reveals delayed join user
++   * locally anyway, and now the message gets denied?
++   * hmm...
++   */
+   if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+       check_target_limit(sptr, chptr, chptr->chname, 0))
+     return;
+-
+-  /* +T check */
+-  if ((chptr->mode.mode & MODE_NOMULTITARGET) && (targetc > 1)) {
+-    send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+-    return;
+-  }
+-
+-  /* +cC checks */
+-  if (chptr->mode.mode & MODE_NOCOLOUR)
+-    for (ch=text;*ch;ch++)
+-      if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31) {
+-        send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+-        return;
+-      }
+-
+-  if ((chptr->mode.mode & MODE_NOCTCP) && ircd_strncmp(text,"\001ACTION ",8))
+-    for (ch=text;*ch;)
+-      if (*ch++==1) { 
+-        send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+-        return;
+-      }
+-
+   
+   sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, cli_from(sptr),
+                          SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text);
+@@ -143,7 +126,6 @@
+ void relay_channel_notice(struct Client* sptr, const char* name, const char* text, const int targetc)
+ {
+   struct Channel* chptr;
+-  const char *ch;
+   assert(0 != sptr);
+   assert(0 != name);
+   assert(0 != text);
+@@ -153,30 +135,14 @@
+   /*
+    * This first: Almost never a server/service
+    */
+-  if (!client_can_send_to_channel(sptr, chptr, 1))
++  if (!client_can_send_to_channel(sptr, chptr, 1,
++    (MODE_NONOTICE | MODE_NOCOLOUR | MODE_NOCTCP | MODE_NOMULTITARGET), text, targetc))
+     return;
++  /* TODO: idem as in previous function */
+   if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+       check_target_limit(sptr, chptr, chptr->chname, 0))
+     return;
+-
+-  if ((chptr->mode.mode & MODE_NONOTICE))
+-    return;
+-
+-  /* +T check */
+-  if ((chptr->mode.mode & MODE_NOMULTITARGET) && (targetc > 1))
+-    return;
+-
+-  /* +cC checks */
+-  if (chptr->mode.mode & MODE_NOCOLOUR)
+-    for (ch=text;*ch;ch++)
+-      if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31)
+-        return;
+-
+-  if (chptr->mode.mode & MODE_NOCTCP)
+-    for (ch=text;*ch;)
+-      if (*ch++==1)
+-        return;
+   sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, cli_from(sptr),
+                          SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text);
+@@ -204,7 +170,7 @@
+    * This first: Almost never a server/service
+    * Servers may have channel services, need to check for it here
+    */
+-  if (client_can_send_to_channel(sptr, chptr, 1) || IsChannelService(sptr)) {
++  if (client_can_send_to_channel(sptr, chptr, 1, 0, NULL, 1)) {
+     sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, cli_from(sptr),
+                            SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text);
+   }
+@@ -232,7 +198,8 @@
+    * This first: Almost never a server/service
+    * Servers may have channel services, need to check for it here
+    */
+-  if (client_can_send_to_channel(sptr, chptr, 1) || IsChannelService(sptr)) {
++  /* TODO: check how we get here */
++  if (client_can_send_to_channel(sptr, chptr, 1, 0, NULL, 1)) {
+     sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, cli_from(sptr),
+                            SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text);
+   }
+diff -r f6d476f109e2 ircd/m_part.c
+--- a/ircd/m_part.c    Mon Jan 19 15:32:18 2009 +0100
++++ b/ircd/m_part.c    Mon Jan 19 22:10:14 2009 +0100
+@@ -140,7 +140,8 @@
+     assert(!IsZombie(member)); /* Local users should never zombie */
+-    if (!member_can_send_to_channel(member, 0))
++    /* check +u here or later somewhere in channel.c ? */
++    if (!member_can_send_to_channel(member, 0, MODE_NOQUITPARTS, NULL, 1))
+     {
+       flags |= CHFL_BANNED;
+       /* Remote clients don't want to see a comment either. */
+diff -r f6d476f109e2 ircd/m_quit.c
+--- a/ircd/m_quit.c    Mon Jan 19 15:32:18 2009 +0100
++++ b/ircd/m_quit.c    Mon Jan 19 22:10:14 2009 +0100
+@@ -109,8 +109,8 @@
+     struct Membership* chan;
+     /* (slug for +u) removed !IsDelayedJoin(chan) as splidge said to */
+     for (chan = cli_user(sptr)->channel; chan; chan = chan->next_channel) {
+-        if (!IsZombie(chan) && (!member_can_send_to_channel(chan, 0)
+-           || (chan->channel->mode.mode & MODE_NOQUITPARTS)))
++        if (!IsZombie(chan) && (!member_can_send_to_channel(chan, 0,
++          MODE_NOQUITPARTS, NULL, 1)))
+           return exit_client(cptr, sptr, sptr, "Signed off");
+     }
+   }
+diff -r f6d476f109e2 ircd/m_topic.c
+--- a/ircd/m_topic.c   Mon Jan 19 15:32:18 2009 +0100
++++ b/ircd/m_topic.c   Mon Jan 19 22:10:14 2009 +0100
+@@ -144,7 +144,7 @@
+     }
+     else if ((chptr->mode.mode & MODE_TOPICLIMIT) && !is_chan_op(sptr, chptr))
+       send_reply(sptr, ERR_CHANOPRIVSNEEDED, chptr->chname);
+-    else if (!client_can_send_to_channel(sptr, chptr, 1))
++    else if (!client_can_send_to_channel(sptr, chptr, 1, 0, NULL, 1))
+       send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+     else
+       do_settopic(sptr,cptr,chptr,topic,0);
+diff -r f6d476f109e2 ircd/m_wallchops.c
+--- a/ircd/m_wallchops.c       Mon Jan 19 15:32:18 2009 +0100
++++ b/ircd/m_wallchops.c       Mon Jan 19 22:10:14 2009 +0100
+@@ -103,7 +103,6 @@
+ {
+   struct Channel *chptr;
+   struct Membership* member;
+-  const char *ch;
+   assert(0 != cptr);
+   assert(cptr == sptr);
+@@ -117,23 +116,12 @@
+     return send_reply(sptr, ERR_NOTEXTTOSEND);
+   if (IsChannelName(parv[1]) && (chptr = FindChannel(parv[1]))) {
+-    if (client_can_send_to_channel(sptr, chptr, 0) && !(chptr->mode.mode & MODE_NONOTICE)) {
++    /* check also for modes +N +c and +C */
++    if (client_can_send_to_channel(sptr, chptr, 0,
++      (MODE_NONOTICE | MODE_NOCOLOUR | MODE_NOCTCP), parv[parc - 1], 1)) {
+       if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+           check_target_limit(sptr, chptr, chptr->chname, 0))
+         return 0;
+-
+-      /* +cC checks */
+-      if (chptr->mode.mode & MODE_NOCOLOUR)
+-        for (ch=parv[parc - 1];*ch;ch++)
+-          if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31) {
+-            return 0;
+-          }
+-
+-      if ((chptr->mode.mode & MODE_NOCTCP) && ircd_strncmp(parv[parc - 1],"\001ACTION ",8))
+-        for (ch=parv[parc - 1];*ch;)
+-          if (*ch++==1) {
+-            return 0;
+-          }
+       /* Reveal delayedjoin user */
+      if ((member = find_member_link(chptr, cptr)) && IsDelayedJoin(member))
+@@ -165,7 +153,7 @@
+     return 0;
+   if (!IsLocalChannel(parv[1]) && (chptr = FindChannel(parv[1]))) {
+-    if (client_can_send_to_channel(sptr, chptr, 1)) {
++    if (client_can_send_to_channel(sptr, chptr, 1, 0, NULL, 1)) {
+       sendcmdto_channel_butone(sptr, CMD_WALLCHOPS, chptr, cptr,
+                              SKIP_DEAF | SKIP_BURST | SKIP_NONOPS,
+                              "%H :%s", chptr, parv[parc - 1]);
+diff -r f6d476f109e2 ircd/m_wallvoices.c
+--- a/ircd/m_wallvoices.c      Mon Jan 19 15:32:18 2009 +0100
++++ b/ircd/m_wallvoices.c      Mon Jan 19 22:10:14 2009 +0100
+@@ -102,7 +102,6 @@
+ {
+   struct Channel *chptr;
+   struct Membership* member;
+-  const char *ch;
+   assert(0 != cptr);
+   assert(cptr == sptr);
+@@ -116,23 +115,11 @@
+     return send_reply(sptr, ERR_NOTEXTTOSEND);
+   if (IsChannelName(parv[1]) && (chptr = FindChannel(parv[1]))) {
+-    if (client_can_send_to_channel(sptr, chptr, 0) && !(chptr->mode.mode & MODE_NONOTICE)) {
++    if (client_can_send_to_channel(sptr, chptr, 0,
++      (MODE_NONOTICE | MODE_NOCOLOUR | MODE_NOCTCP), parv[parc - 1], 1)) {
+       if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+           check_target_limit(sptr, chptr, chptr->chname, 0))
+         return 0;
+-
+-      /* +cC checks */
+-      if (chptr->mode.mode & MODE_NOCOLOUR)
+-        for (ch=parv[parc - 1];*ch;ch++)
+-          if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31) {
+-            return 0;
+-          }
+-
+-      if ((chptr->mode.mode & MODE_NOCTCP) && ircd_strncmp(parv[parc - 1],"\001ACTION ",8))
+-        for (ch=parv[parc - 1];*ch;)
+-          if (*ch++==1) {
+-            return 0;
+-          }
+       /* Reveal delayedjoin user */
+      if ((member = find_member_link(chptr, cptr)) && IsDelayedJoin(member))
+@@ -164,7 +151,7 @@
+     return 0;
+   if (!IsLocalChannel(parv[1]) && (chptr = FindChannel(parv[1]))) {
+-    if (client_can_send_to_channel(sptr, chptr, 1)) {
++    if (client_can_send_to_channel(sptr, chptr, 1, 0, NULL, 1)) {
+       sendcmdto_channel_butone(sptr, CMD_WALLVOICES, chptr, cptr,
+                              SKIP_DEAF | SKIP_BURST | SKIP_NONVOICES, 
+                              "%H :%s", chptr, parv[parc - 1]);
diff --git a/series b/series
index b5f8d7283f1af78e43bdfd1d75c0cb342362842a..edd75932a8d425ffb43ab691048a8ff577c216fc 100644 (file)
--- a/series
+++ b/series
@@ -4,6 +4,7 @@ addnickchasetomodenick.patch #+nickchase
 chanopaccountabilityforkickdelayedjoin.patch
 addopkickcmd.patch #+opkick
 addhacktypetohackkick.patch
+cansendtochan.patch
 hidebanowner.patch #+hidebanowner
 hisadmin.patch
 hisversionremote.patch
index 92a35cd74a1848952cdecee9dda4dc6ab65476aa..d4e27460ebbdcbe5a8e8b77112aced1a7ad1a085 100644 (file)
@@ -5,9 +5,9 @@ Add /stats S/split (make /STATS s/S case sensitive, s spoofhosts)
 Add feature SPLIT
 Add split.c split.h m_split.c
 
-diff -r 2da61ac38fa1 include/handlers.h
---- a/include/handlers.h       Sun Jan 18 14:18:36 2009 +0100
-+++ b/include/handlers.h       Sun Jan 18 15:26:56 2009 +0100
+diff -r 64eb6d1a4c6a include/handlers.h
+--- a/include/handlers.h       Mon Jan 19 13:11:21 2009 +0100
++++ b/include/handlers.h       Mon Jan 19 15:03:45 2009 +0100
 @@ -139,6 +139,7 @@
  extern int m_registered(struct Client*, struct Client*, int, char*[]);
  extern int m_sethost(struct Client*, struct Client*, int, char*[]);
@@ -32,18 +32,21 @@ diff -r 2da61ac38fa1 include/handlers.h
  extern int ms_squit(struct Client*, struct Client*, int, char*[]);
  extern int ms_stats(struct Client*, struct Client*, int, char*[]);
  extern int ms_topic(struct Client*, struct Client*, int, char*[]);
-diff -r 2da61ac38fa1 include/ircd_features.h
---- a/include/ircd_features.h  Sun Jan 18 14:18:36 2009 +0100
-+++ b/include/ircd_features.h  Sun Jan 18 15:26:56 2009 +0100
-@@ -109,6 +109,7 @@
-   FEAT_SETHOST,
+diff -r 64eb6d1a4c6a include/ircd_features.h
+--- a/include/ircd_features.h  Mon Jan 19 13:11:21 2009 +0100
++++ b/include/ircd_features.h  Mon Jan 19 15:03:45 2009 +0100
+@@ -110,6 +110,10 @@
    FEAT_SETHOST_USER,
    FEAT_SETHOST_AUTO,
-+  FEAT_SPLIT,
  
++  /* SPLIT */
++  FEAT_SPLIT,
++  FEAT_SPLIT_AUTO_EXPIRE,
++
    /* HEAD_IN_SAND Features */
    FEAT_HIS_SNOTICES,
-@@ -137,6 +138,7 @@
+   FEAT_HIS_SNOTICES_OPER_ONLY,
+@@ -137,6 +141,7 @@
    FEAT_HIS_STATS_q,
    FEAT_HIS_STATS_R,
    FEAT_HIS_STATS_r,
@@ -51,9 +54,9 @@ diff -r 2da61ac38fa1 include/ircd_features.h
    FEAT_HIS_STATS_s,
    FEAT_HIS_STATS_t,
    FEAT_HIS_STATS_T,
-diff -r 2da61ac38fa1 include/msg.h
---- a/include/msg.h    Sun Jan 18 14:18:36 2009 +0100
-+++ b/include/msg.h    Sun Jan 18 15:26:56 2009 +0100
+diff -r 64eb6d1a4c6a include/msg.h
+--- a/include/msg.h    Mon Jan 19 13:11:21 2009 +0100
++++ b/include/msg.h    Mon Jan 19 15:03:45 2009 +0100
 @@ -332,6 +332,10 @@
  #define TOK_JUPE                "JU"
  #define CMD_JUPE              MSG_JUPE, TOK_JUPE
@@ -65,18 +68,18 @@ diff -r 2da61ac38fa1 include/msg.h
  #define MSG_OPMODE              "OPMODE"        /* OPMO */
  #define TOK_OPMODE              "OM"
  #define CMD_OPMODE            MSG_OPMODE, TOK_OPMODE
-diff -r 2da61ac38fa1 include/numeric.h
---- a/include/numeric.h        Sun Jan 18 14:18:36 2009 +0100
-+++ b/include/numeric.h        Sun Jan 18 15:26:56 2009 +0100
+diff -r 64eb6d1a4c6a include/numeric.h
+--- a/include/numeric.h        Mon Jan 19 13:11:21 2009 +0100
++++ b/include/numeric.h        Mon Jan 19 15:03:45 2009 +0100
 @@ -117,6 +117,7 @@
        RPL_STATSVLINE       227           unreal */
  #define RPL_STATSALINE       226        /* Hybrid, Undernet */
  #define RPL_STATSQLINE       228        /* Undernet extension */
 +#define RPL_STATSSPLIT       229        /* QuakeNet extension */
+ #define RPL_STATSHEADER      230        /* QuakeNet extension */
  
  /*      RPL_SERVICEINFO      231      unused */
- /*      RPL_ENDOFSERVICES    232      unused */
-@@ -177,6 +178,8 @@
+@@ -178,6 +179,8 @@
  #define RPL_STATSDLINE       275        /* Undernet extension */
  #define RPL_STATSRLINE       276        /* Undernet extension */
  
@@ -85,7 +88,7 @@ diff -r 2da61ac38fa1 include/numeric.h
  #define RPL_GLIST            280        /* Undernet extension */
  #define RPL_ENDOFGLIST       281        /* Undernet extension */
  #define RPL_JUPELIST         282        /* Undernet extension - jupe -Kev */
-@@ -440,6 +443,7 @@
+@@ -441,6 +444,7 @@
  /*      ERR_GHOSTEDCLIENT    503           efnet */
  /*    ERR_VWORLDWARN       503           austnet */
  
@@ -93,10 +96,10 @@ diff -r 2da61ac38fa1 include/numeric.h
  #define ERR_SILELISTFULL     511        /* Undernet extension */
  /*      ERR_NOTIFYFULL       512           aircd */
  /*    ERR_TOOMANYWATCH     512           Numeric List: Dalnet */
-diff -r 2da61ac38fa1 include/split.h
+diff -r 64eb6d1a4c6a include/split.h
 --- /dev/null  Thu Jan 01 00:00:00 1970 +0000
-+++ b/include/split.h  Sun Jan 18 15:26:56 2009 +0100
-@@ -0,0 +1,121 @@
++++ b/include/split.h  Mon Jan 19 15:03:45 2009 +0100
+@@ -0,0 +1,120 @@
 +/* TODO: ifndef ? */
 +#ifndef INCLUDED_jupe_h
 +#define INCLUDED_jupe_h
@@ -134,8 +137,7 @@ diff -r 2da61ac38fa1 include/split.h
 +struct Client;
 +struct StatDesc;
 +
-+#define SPLIT_MAX_EXPIRE   604800   /**< Maximum split expiration time (7 days). */
-+#define SPLIT_AUTO_EXPIRE  604800   /**< Expireation time used for auto created entries. */
++#define SPLIT_MAX_EXPIRE   2419200   /**< Maximum split expiration time (4 weeks). */
 +
 +/* Describes a SPLIT server entry. */
 +struct Split {
@@ -218,9 +220,9 @@ diff -r 2da61ac38fa1 include/split.h
 +
 +/* TODO: endif ? */
 +#endif /* INCLUDED_jupe_h */
-diff -r 2da61ac38fa1 ircd/Makefile.in
---- a/ircd/Makefile.in Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/Makefile.in Sun Jan 18 15:26:56 2009 +0100
+diff -r 64eb6d1a4c6a ircd/Makefile.in
+--- a/ircd/Makefile.in Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/Makefile.in Mon Jan 19 15:03:45 2009 +0100
 @@ -173,6 +173,7 @@
        m_sethost.c \
        m_settime.c \
@@ -278,9 +280,9 @@ diff -r 2da61ac38fa1 ircd/Makefile.in
  uping.o: uping.c ../config.h ../include/uping.h ../include/ircd_defs.h \
    ../include/ircd_events.h ../config.h ../include/res.h \
    ../include/client.h ../include/dbuf.h ../include/msgq.h \
-diff -r 2da61ac38fa1 ircd/ircd.c
---- a/ircd/ircd.c      Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/ircd.c      Sun Jan 18 15:26:56 2009 +0100
+diff -r 64eb6d1a4c6a ircd/ircd.c
+--- a/ircd/ircd.c      Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/ircd.c      Mon Jan 19 15:03:45 2009 +0100
 @@ -55,6 +55,7 @@
  #include "s_misc.h"
  #include "s_stats.h"
@@ -299,18 +301,21 @@ diff -r 2da61ac38fa1 ircd/ircd.c
    event_loop();
  
    return 0;
-diff -r 2da61ac38fa1 ircd/ircd_features.c
---- a/ircd/ircd_features.c     Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/ircd_features.c     Sun Jan 18 15:26:56 2009 +0100
-@@ -363,6 +363,7 @@
-   F_B(SETHOST, 0, 0, 0),
+diff -r 64eb6d1a4c6a ircd/ircd_features.c
+--- a/ircd/ircd_features.c     Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/ircd_features.c     Mon Jan 19 15:03:45 2009 +0100
+@@ -364,6 +364,10 @@
    F_B(SETHOST_USER, 0, 0, 0),
    F_B(SETHOST_AUTO, 0, 0, 0),
-+  F_B(SPLIT, 0, 1, 0),
  
++  /* SPLIT */
++  F_B(SPLIT, 0, 1, 0),
++  F_I(SPLIT_AUTO_EXPIRE, 0, 604800, 0),
++
    /* HEAD_IN_SAND Features */
    F_B(HIS_SNOTICES, 0, 1, 0),
-@@ -391,6 +392,7 @@
+   F_B(HIS_SNOTICES_OPER_ONLY, 0, 1, 0),
+@@ -391,6 +395,7 @@
    F_B(HIS_STATS_q, 0, 1, 0),
    F_B(HIS_STATS_R, 0, 1, 0),
    F_B(HIS_STATS_r, 0, 1, 0),
@@ -318,9 +323,9 @@ diff -r 2da61ac38fa1 ircd/ircd_features.c
    F_B(HIS_STATS_s, 0, 1, 0),
    F_B(HIS_STATS_t, 0, 1, 0),
    F_B(HIS_STATS_T, 0, 1, 0),
-diff -r 2da61ac38fa1 ircd/m_endburst.c
---- a/ircd/m_endburst.c        Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/m_endburst.c        Sun Jan 18 15:26:56 2009 +0100
+diff -r 64eb6d1a4c6a ircd/m_endburst.c
+--- a/ircd/m_endburst.c        Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/m_endburst.c        Mon Jan 19 15:03:45 2009 +0100
 @@ -85,6 +85,7 @@
  #include "client.h"
  #include "hash.h"
@@ -356,9 +361,9 @@ diff -r 2da61ac38fa1 ircd/m_endburst.c
    if (MyConnect(sptr))
      sendcmdto_one(&me, CMD_END_OF_BURST_ACK, sptr, "");
  
-diff -r 2da61ac38fa1 ircd/m_reburst.c
---- a/ircd/m_reburst.c Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/m_reburst.c Sun Jan 18 15:26:56 2009 +0100
+diff -r 64eb6d1a4c6a ircd/m_reburst.c
+--- a/ircd/m_reburst.c Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/m_reburst.c Mon Jan 19 15:03:45 2009 +0100
 @@ -102,6 +102,7 @@
  #include "ircd_snprintf.h"
  #include "gline.h"
@@ -378,9 +383,9 @@ diff -r 2da61ac38fa1 ircd/m_reburst.c
      default:
        break;
    }
-diff -r 2da61ac38fa1 ircd/m_split.c
+diff -r 64eb6d1a4c6a ircd/m_split.c
 --- /dev/null  Thu Jan 01 00:00:00 1970 +0000
-+++ b/ircd/m_split.c   Sun Jan 18 15:26:56 2009 +0100
++++ b/ircd/m_split.c   Mon Jan 19 15:03:45 2009 +0100
 @@ -0,0 +1,374 @@
 +/*
 + * IRC - Internet Relay Chat, ircd/m_split.c
@@ -756,9 +761,9 @@ diff -r 2da61ac38fa1 ircd/m_split.c
 +
 +  return split_list(sptr, parv[1]);
 +}
-diff -r 2da61ac38fa1 ircd/parse.c
---- a/ircd/parse.c     Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/parse.c     Sun Jan 18 15:26:56 2009 +0100
+diff -r 64eb6d1a4c6a ircd/parse.c
+--- a/ircd/parse.c     Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/parse.c     Mon Jan 19 15:03:45 2009 +0100
 @@ -505,6 +505,13 @@
      0, MAXPARA, MFLG_SLOW, 0, NULL,
      /* UNREG, CLIENT, SERVER, OPER, SERVICE */
@@ -773,9 +778,9 @@ diff -r 2da61ac38fa1 ircd/parse.c
    },
    {
      MSG_OPMODE,
-diff -r 2da61ac38fa1 ircd/s_conf.c
---- a/ircd/s_conf.c    Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/s_conf.c    Sun Jan 18 15:26:56 2009 +0100
+diff -r 64eb6d1a4c6a ircd/s_conf.c
+--- a/ircd/s_conf.c    Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/s_conf.c    Mon Jan 19 15:03:45 2009 +0100
 @@ -53,6 +53,7 @@
  #include "s_debug.h"
  #include "s_misc.h"
@@ -792,9 +797,9 @@ diff -r 2da61ac38fa1 ircd/s_conf.c
  
    return ret;
  }
-diff -r 2da61ac38fa1 ircd/s_debug.c
---- a/ircd/s_debug.c   Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/s_debug.c   Sun Jan 18 15:26:57 2009 +0100
+diff -r 64eb6d1a4c6a ircd/s_debug.c
+--- a/ircd/s_debug.c   Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/s_debug.c   Mon Jan 19 15:03:45 2009 +0100
 @@ -48,6 +48,7 @@
  #include "s_user.h"
  #include "s_stats.h"
@@ -832,9 +837,9 @@ diff -r 2da61ac38fa1 ircd/s_debug.c
  
    send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
             ":Hash: client %d(%zu), chan is the same", HASHSIZE,
-diff -r 2da61ac38fa1 ircd/s_err.c
---- a/ircd/s_err.c     Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/s_err.c     Sun Jan 18 15:26:57 2009 +0100
+diff -r 64eb6d1a4c6a ircd/s_err.c
+--- a/ircd/s_err.c     Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/s_err.c     Mon Jan 19 15:03:45 2009 +0100
 @@ -490,7 +490,7 @@
  /* 228 */
    { RPL_STATSQLINE, "Q %s :%s", "228" },
@@ -842,7 +847,7 @@ diff -r 2da61ac38fa1 ircd/s_err.c
 -  { 0 },
 +  { RPL_STATSSPLIT, "S %s %d %d %d %d %c :%s", "229" },
  /* 230 */
-   { 0 },
+   { RPL_STATSHEADER, 0, "230" },
  /* 231 */
 @@ -588,9 +588,9 @@
  /* 277 */
@@ -854,7 +859,7 @@ diff -r 2da61ac38fa1 ircd/s_err.c
 -  { 0 },
 +  { RPL_ENDOFSPLITLIST, ":End of Split List", "279" },
  /* 280 */
-   { RPL_GLIST, "%s%s%s%s%s %Tu %Tu %Tu %s %s%c :%s", "280" },
+   { RPL_GLIST, "%s%s%s%s%s %Tu %Tu %Tu %s %s%s%c :%s", "280" },
  /* 281 */
 @@ -1052,7 +1052,7 @@
  /* 509 */
@@ -865,9 +870,9 @@ diff -r 2da61ac38fa1 ircd/s_err.c
  /* 511 */
    { ERR_SILELISTFULL, "%s :Your silence list is full", "511" },
  /* 512 */
-diff -r 2da61ac38fa1 ircd/s_misc.c
---- a/ircd/s_misc.c    Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/s_misc.c    Sun Jan 18 15:26:57 2009 +0100
+diff -r 64eb6d1a4c6a ircd/s_misc.c
+--- a/ircd/s_misc.c    Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/s_misc.c    Mon Jan 19 15:03:45 2009 +0100
 @@ -53,6 +53,7 @@
  #include "s_stats.h"
  #include "s_user.h"
@@ -899,9 +904,9 @@ diff -r 2da61ac38fa1 ircd/s_misc.c
    }
  
    /*
-diff -r 2da61ac38fa1 ircd/s_serv.c
---- a/ircd/s_serv.c    Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/s_serv.c    Sun Jan 18 15:26:57 2009 +0100
+diff -r 64eb6d1a4c6a ircd/s_serv.c
+--- a/ircd/s_serv.c    Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/s_serv.c    Mon Jan 19 15:03:45 2009 +0100
 @@ -54,6 +54,7 @@
  #include "s_misc.h"
  #include "s_user.h"
@@ -918,9 +923,9 @@ diff -r 2da61ac38fa1 ircd/s_serv.c
  
    /*
     * Pass on my client information to the new server
-diff -r 2da61ac38fa1 ircd/s_stats.c
---- a/ircd/s_stats.c   Sun Jan 18 14:18:36 2009 +0100
-+++ b/ircd/s_stats.c   Sun Jan 18 15:26:57 2009 +0100
+diff -r 64eb6d1a4c6a ircd/s_stats.c
+--- a/ircd/s_stats.c   Mon Jan 19 13:11:21 2009 +0100
++++ b/ircd/s_stats.c   Mon Jan 19 15:03:45 2009 +0100
 @@ -52,6 +52,7 @@
  #include "s_stats.h"
  #include "s_user.h"
@@ -929,7 +934,7 @@ diff -r 2da61ac38fa1 ircd/s_stats.c
  #include "struct.h"
  #include "userload.h"
  
-@@ -633,7 +634,10 @@
+@@ -668,7 +669,10 @@
      send_usage, 0,
      "System resource usage (Debug only)." },
  #endif
@@ -941,10 +946,10 @@ diff -r 2da61ac38fa1 ircd/s_stats.c
      stats_sline, 0,
      "Spoofed hosts information." },
    { 'T', "motds", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
-diff -r 2da61ac38fa1 ircd/split.c
+diff -r 64eb6d1a4c6a ircd/split.c
 --- /dev/null  Thu Jan 01 00:00:00 1970 +0000
-+++ b/ircd/split.c     Sun Jan 18 15:26:57 2009 +0100
-@@ -0,0 +1,746 @@
++++ b/ircd/split.c     Mon Jan 19 15:03:45 2009 +0100
+@@ -0,0 +1,771 @@
 +/*
 + * IRC - Internet Relay Chat, ircd/split.c
 + * Copyright (C) 1990 Jarkko Oikarinen and
@@ -1022,11 +1027,13 @@ diff -r 2da61ac38fa1 ircd/split.c
 +  /* TODO: some limit for servername length? HOSTLEN? */
 +  DupString(asplit->sp_server, server); /* copy vital information */
 +  /* TODO:  some limit for reason length? QUITLEN TOPICLEN? */
++  /* TODO: prefix the reason here with the opername/ID? */
 +  DupString(asplit->sp_reason, reason);
 +  /* TODO: what we use creation for and do we need it? */
 +  asplit->sp_creation = creation;
 +  asplit->sp_expire = expire;
 +  /* TODO: are we using nettime etc.? CurrentTime is used. */
++  /* TODO: TStime() is CurrentTime + TSoffset */
 +  asplit->sp_lastmod = lastmod;
 +  asplit->sp_lifetime = lifetime;
 +  /* CHECK: does this make it active upon creation regardless of the flags given? */
@@ -1056,6 +1063,7 @@ diff -r 2da61ac38fa1 ircd/split.c
 +    SplitIsActive(split) && !SplitIsRemoving(split) ? '+' : '-', /* always !- not !+ */
 +    split->sp_server, split->sp_creation, split->sp_expire,
 +    split->sp_lastmod, split->sp_lifetime,
++    /* TODO: does reason ? reason : split->sp_reason work too? */
 +    reason != NULL ? reason : split->sp_reason);
 +}
 +
@@ -1121,9 +1129,14 @@ diff -r 2da61ac38fa1 ircd/split.c
 +       * 60 seconds?
 +       * no no no! - see above
 +       */
++      /* TODO: raise error with timestamps to SNO_OLDSNO?
++       * in the form of
++       * Nick collision on nick (nick 1232368192 <- hub.xx.quakenet.org 1232368192 (Same user@host))
++       */
 +      return 0;
 +  }
 +
++  /* TODO: add opername */
 +  /* inform ops and log it */
 +  sendto_opmask_butone(0, SNO_NETWORK, "%s adding%sSPLIT for %s, expiring at %Tu: %s",
 +    (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
@@ -1188,6 +1201,7 @@ diff -r 2da61ac38fa1 ircd/split.c
 +   *       and not when a server is introduced.
 +   *       so between net junction and end of burst,
 +   *       we can get SPLITs for a linked server.
++   *       also more than one server can be bursting at a time.
 +   */
 +  /* TODO: should we free it here or let that be done in end of burst?
 +   *   only when that is the ONLY situation we can get to this point!
@@ -1313,6 +1327,7 @@ diff -r 2da61ac38fa1 ircd/split.c
 +               pos ? ";" : "", pos ? " and" : "", reason);
 +  }
 +
++  /* TODO: add opername */
 +  /* All right, inform ops... */
 +  sendto_opmask_butone(0, SNO_NETWORK, "%s modifying SPLIT for %s:%s",
 +    (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
@@ -1356,6 +1371,7 @@ diff -r 2da61ac38fa1 ircd/split.c
 +  /* CHECK: turn bit SPLIT_ACTIVE off? */
 +  split->sp_flags |= SPLIT_ACTIVE;
 +
++  /* TODO: add opername? */
 +  /* inform ops and log it */
 +  sendto_opmask_butone(0, SNO_NETWORK, "%s removing SPLIT for %s, expiring at %Tu: %s (%s)",
 +    (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
@@ -1367,9 +1383,6 @@ diff -r 2da61ac38fa1 ircd/split.c
 +    "%#C removing SPLIT for %s, expiring at %Tu: %s (%s)",
 +    sptr, split->sp_server, split->sp_expire, split->sp_reason, reason);
 +
-+  /* TODO: the reason supplied for removing this SPLIT does not go upstream
-+   * either propagate manually here, or update the record or?
-+   */
 +  /* propagate it */
 +  split_propagate(cptr, sptr, split, reason);
 +
@@ -1432,6 +1445,7 @@ diff -r 2da61ac38fa1 ircd/split.c
 +{
 +  assert(0 != split);
 +
++  /* TODO: also check if the server in SPLIT entry is linked atm? */
 +  /* past lifetime */
 +  if (split->sp_lifetime <= CurrentTime)
 +    return 1;
@@ -1573,7 +1587,7 @@ diff -r 2da61ac38fa1 ircd/split.c
 +  struct DLink *lp;
 +  struct Split *split;
 +  int count = 0;
-+  time_t creation = CurrentTime, expire = CurrentTime + SPLIT_AUTO_EXPIRE,
++  time_t creation = CurrentTime, expire = CurrentTime + feature_int(FEAT_SPLIT_AUTO_EXPIRE),
 +    lastmod = CurrentTime, lifetime = expire;
 +  unsigned int flags = SPLIT_ACTIVE;
 +
@@ -1581,6 +1595,10 @@ diff -r 2da61ac38fa1 ircd/split.c
 +
 +  Debug((DEBUG_DEBUG, "split_break(\"%s\", \"%s\")", cli_name(server), reason));
 +
++  /* bad auto expire value */
++  if (feature_int(FEAT_SPLIT_AUTO_EXPIRE) <= 0)
++    return 0;
++
 +  /* find the SPLIT for this server */
 +  if (!(split = split_find(cli_name(server)))) {
 +    split_make(cli_name(server), reason, creation, expire, lastmod, lifetime, flags);
@@ -1604,7 +1622,7 @@ diff -r 2da61ac38fa1 ircd/split.c
 +  struct Client *server;
 +  struct Split *split;
 +  struct Split *asplit;
-+  time_t creation = CurrentTime, expire = CurrentTime + SPLIT_AUTO_EXPIRE,
++  time_t creation = CurrentTime, expire = CurrentTime + feature_int(FEAT_SPLIT_AUTO_EXPIRE),
 +    lastmod = CurrentTime, lifetime = expire;
 +  unsigned int flags = SPLIT_ACTIVE;
 +  char reason[BUFSIZE];
@@ -1615,6 +1633,10 @@ diff -r 2da61ac38fa1 ircd/split.c
 +  if (!feature_bool(FEAT_SPLIT))
 +    return;
 +
++  /* bad auto expire value */
++  if (feature_int(FEAT_SPLIT_AUTO_EXPIRE) <= 0)
++    return;
++
 +  ircd_snprintf(0, reason, sizeof(reason),
 +    "Generated upon loading conf file on %s", cli_name(&me));
 +
@@ -1629,6 +1651,12 @@ diff -r 2da61ac38fa1 ircd/split.c
 +    /* we have a SPLIT for this server already */
 +    if (split = split_find(conf->name))
 +      continue;
++    /* TODO: use SNO_OLDSNO here?
++     * just like nickcollisions on local users go there?
++     * or at least change the source / message format?
++     * /REHASH goes to SNO_OLDSNO? so this too?
++     * if oper did rehash, add his name here?
++     */
 +    /* inform ops and log it */
 +    sendto_opmask_butone(0, SNO_NETWORK, "%C adding SPLIT for %s, expiring at %Tu: %s",
 +      &me, conf->name, expire, reason);
@@ -1661,8 +1689,10 @@ diff -r 2da61ac38fa1 ircd/split.c
 +  struct Split *split;
 +  struct Split *ssplit;
 +
-+  send_reply(sptr, SND_EXPLICIT | RPL_STATSSPLIT,
-+    "S servername creation expire lastmod lifetime active :reason");
++  /* send header so the client knows what we are showing */
++  send_reply(sptr, SND_EXPLICIT | RPL_STATSHEADER,
++    "S Server Creation Expire Lastmod Lifetime Status :Reason");
++
 +  for (split = GlobalSplitList; split; split = split->sp_next)
 +    send_reply(sptr, RPL_STATSSPLIT, split->sp_server,
 +      split->sp_creation, split->sp_expire, split->sp_lastmod, split->sp_lifetime,