--- /dev/null
+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]);
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*[]);
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,
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
#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 */
#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 */
#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
+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 {
+
+/* 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 \
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"
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),
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"
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"
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
+
+ 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 */
},
{
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"
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"
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" },
- { 0 },
+ { RPL_STATSSPLIT, "S %s %d %d %d %d %c :%s", "229" },
/* 230 */
- { 0 },
+ { RPL_STATSHEADER, 0, "230" },
/* 231 */
@@ -588,9 +588,9 @@
/* 277 */
- { 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 */
/* 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"
}
/*
-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"
/*
* 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"
#include "struct.h"
#include "userload.h"
-@@ -633,7 +634,10 @@
+@@ -668,7 +669,10 @@
send_usage, 0,
"System resource usage (Debug only)." },
#endif
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
+ /* 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? */
+ 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);
+}
+
+ * 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)) ?
+ * 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!
+ 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)) ?
+ /* 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)) ?
+ "%#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);
+
+{
+ assert(0 != split);
+
++ /* TODO: also check if the server in SPLIT entry is linked atm? */
+ /* past lifetime */
+ if (split->sp_lifetime <= CurrentTime)
+ return 1;
+ 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;
+
+
+ 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);
+ 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];
+ 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));
+
+ /* 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);
+ 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,