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:
+move our cCNT mode checks to new function can_send_to_channel() used
+from the two functions above
+now the checks for cCNT modes are in one place.
+check for +u remains in member_can_send_to_chan() - as quit from non-member does not show
+
+need to verify handling of remote users, services, servers etc.
+
+possible problem discovered (ircu):
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
-
+user is revealed (locally) without actually sending anything to the channel...
+...that seems wrong/weird
-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
+diff -r 7113a0179d71 include/channel.h
+--- a/include/channel.h Wed Jan 21 16:44:50 2009 +0100
++++ b/include/channel.h Wed Jan 21 17:13:44 2009 +0100
@@ -103,9 +103,9 @@
#define MODE_DELJOINS 0x1000 /**< New join messages are delayed */
#define MODE_REGISTERED 0x2000 /**< Channel marked as registered
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 @@
+diff -r 7113a0179d71 ircd/channel.c
+--- a/ircd/channel.c Wed Jan 21 16:44:50 2009 +0100
++++ b/ircd/channel.c Wed Jan 21 17:13:44 2009 +0100
+@@ -681,10 +681,14 @@
* @param member The membership of the user
* @param reveal If true, the user will be "revealed" on a delayed
* joined channel.
+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
+@@ -692,15 +696,17 @@
* 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;
}
+-
+- /* +X user can always speak on the channel */
++
++ /* +X exclude +X clients from modes +mMR and bans */
+ if (IsXtraOp(member->user)) {
++ if (!can_send_to_channel(member->user, member->channel, flags, text, target))
++ return 0;
+ if (IsDelayedJoin(member) && reveal)
+ RevealDelayedJoin(member);
+ return 1;
+@@ -712,7 +718,7 @@
-- /* 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))
+ /* 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;
++ return can_send_to_channel(member->user, member->channel, flags, text, target);
-- /* 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 it's moderated, and you aren't a privileged user, you can't
+@@ -727,6 +733,23 @@
-- /* 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)) {
+ /* If you're banned then you can't speak either. */
+ if (is_banned(member))
++ return 0;
+
-+ /* +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;
++ /* enough checked for remote users */
++ if (!MyUser(member->user)) {
++ if (IsDelayedJoin(member) && reveal)
++ RevealDelayedJoin(member);
++ return 1;
++ }
+
-+ /* 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;
-+ }
-+ }
++ /* +u check for user defined quit and part messages,
++ * and they are not allowed
++ */
++ if ((flags & MODE_NOQUITPARTS) && (member->channel->mode.mode & MODE_NOQUITPARTS))
++ return 0;
+
-+ /* +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;
-+ }
-+ }
-+ }
++ /* check various other modes (like cCNT) */
++ if (!can_send_to_channel(member->user, member->channel, flags, text, target))
+ return 0;
if (IsDelayedJoin(member) && reveal)
- RevealDelayedJoin(member);
-@@ -744,38 +793,95 @@
+@@ -744,16 +767,22 @@
* @param chptr The channel to check
* @param reveal If the user should be revealed (see
* member_can_send_to_channel())
{
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)
+@@ -767,15 +796,90 @@
* 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))
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 */
++ /* client with umode +X exempt from modes +nmrM and bans */
+ if (!IsXtraOp(cptr)) {
-+ if ((modes & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
-+ ((modes & (MODE_REGONLY|MODE_MODERATENOREG)) && !IsAccount(cptr)))
++ if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) ||
++ ((chptr->mode.mode & (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)
++ /* check various other modes (like cCNT) */
++ if (!can_send_to_channel(cptr, chptr, flags, text, target))
return 0;
- else
- return !find_ban(cptr, chptr->banlist);
+ }
+- return member_can_send_to_channel(member, reveal);
++ return member_can_send_to_channel(member, reveal, flags, text, target);
++}
+
-+ /* +N check for channel wide notice and they are not allowed */
-+ if ((flags & MODE_NONOTICE) && (modes & MODE_NONOTICE))
-+ return 0;
++/** Check if a client can send to a channel.
++ *
++ * These checks are done for both clients on and off the channel.
++ *
++ * @param cptr The client to check
++ * @param chptr The channel to check
++ * @param flags The bitmask of modes to check
++ * @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 client_can_send_to_channel()
++ * @see member_can_send_to_channel()
++ */
++int can_send_to_channel(struct Client *cptr, struct Channel *chptr,
++ unsigned int flags, const char *text, const int target)
++{
++ const char *ch;
++ unsigned int modes;
++ int controlcodes = 0;
++
++ assert(0 != cptr);
++ assert(0 != chptr);
++
++ modes = chptr->mode.mode;
++
++ /* only check these modes on local users */
++ if (!MyUser(cptr))
++ return 1;
++
++ /* +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;
+
-+ /* 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;
-+ }
++ /* 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 */
++ /* +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;
-+ 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);
++ }
++ return 1;
}
/** Returns the name of a channel that prevents the user from changing nick.
-@@ -3625,13 +3731,11 @@
+@@ -3625,13 +3729,11 @@
/* Send notification to channel */
if (!(flags & (CHFL_ZOMBIE | CHFL_DELAYED)))
sendcmdto_channel_butserv_butone(jbuf->jb_source, CMD_PART, chan, NULL, 0,
":%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
+diff -r 7113a0179d71 ircd/ircd_relay.c
+--- a/ircd/ircd_relay.c Wed Jan 21 16:44:50 2009 +0100
++++ b/ircd/ircd_relay.c Wed Jan 21 17:13:44 2009 +0100
@@ -87,7 +87,6 @@
void relay_channel_message(struct Client* sptr, const char* name, const char* text, const int targetc)
{
return;
}
+ /* TODO: what is this again?
-+ * clinet_can_send_to_channel already reveals delayed join user
++ * client_can_send_to_channel already reveals delayed join user
+ * locally anyway, and now the message gets denied?
+ * hmm...
+ */
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
+diff -r 7113a0179d71 ircd/m_part.c
+--- a/ircd/m_part.c Wed Jan 21 16:44:50 2009 +0100
++++ b/ircd/m_part.c Wed Jan 21 17:13:44 2009 +0100
@@ -140,7 +140,8 @@
assert(!IsZombie(member)); /* Local users should never zombie */
{
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
+diff -r 7113a0179d71 ircd/m_quit.c
+--- a/ircd/m_quit.c Wed Jan 21 16:44:50 2009 +0100
++++ b/ircd/m_quit.c Wed Jan 21 17:13:44 2009 +0100
@@ -109,8 +109,8 @@
struct Membership* chan;
/* (slug for +u) removed !IsDelayedJoin(chan) as splidge said to */
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
+diff -r 7113a0179d71 ircd/m_topic.c
+--- a/ircd/m_topic.c Wed Jan 21 16:44:50 2009 +0100
++++ b/ircd/m_topic.c Wed Jan 21 17:13:44 2009 +0100
@@ -144,7 +144,7 @@
}
else if ((chptr->mode.mode & MODE_TOPICLIMIT) && !is_chan_op(sptr, chptr))
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
+diff -r 7113a0179d71 ircd/m_wallchops.c
+--- a/ircd/m_wallchops.c Wed Jan 21 16:44:50 2009 +0100
++++ b/ircd/m_wallchops.c Wed Jan 21 17:13:44 2009 +0100
@@ -103,7 +103,6 @@
{
struct Channel *chptr;
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
+diff -r 7113a0179d71 ircd/m_wallvoices.c
+--- a/ircd/m_wallvoices.c Wed Jan 21 16:44:50 2009 +0100
++++ b/ircd/m_wallvoices.c Wed Jan 21 17:13:44 2009 +0100
@@ -102,7 +102,6 @@
{
struct Channel *chptr;