centralize mode checks for +c (no control codes) and +C (no CTCPs) add client_can_send_controlcode_or_ctcp_to_channel() function in channel.c and use that (2x ircd_relay.c, m_wallchops.c, m_wallvoices.c), instead of duplicating code 4 times function uses a table to check for control codes, which is faster than what was used before corrects that an error is returned in WALLVOICES and WALLCHOPS in case +c or +C blocks the message, which is also done for other modes there corrects that CTCP ACTION is only allowed for PRIVMSG, and not for NOTICE WALLCHOPS and WALLVOICES mode +c blocks bold (2), colour (3), reverse (22), ansi escape (27), italic (29) (mIRC 7 - ctrl+i), underline (31) diff -r 718a91e2ff02 include/channel.h --- a/include/channel.h +++ b/include/channel.h @@ -398,6 +398,7 @@ 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 client_can_send_controlcode_or_ctcp_to_channel(struct Client *cptr, struct Channel *chptr, const char *text, int action); extern void remove_user_from_channel(struct Client *sptr, struct Channel *chptr); extern void remove_user_from_all_channels(struct Client* cptr); diff -r 718a91e2ff02 include/ircd_chattr.h --- a/include/ircd_chattr.h +++ b/include/ircd_chattr.h @@ -59,6 +59,8 @@ #define NTL_KTIME 0x20000 /**< Valid character for a k:line time */ #define NTL_CHPFX 0x40000 /**< channel prefix char # & + */ #define NTL_IRCIP6 0x80000 /**< Numeric IPv6 character (hex or colon) */ +#define NTL_CTCP 0x100000 /**< CTCP char \\001 - snircd */ +#define NTL_CONTROL 0x200000 /**< control codes: bold 2, colour 3, reverse 22, ansi escape 27, italic 29 (mIRC 7), underline 31 - snircd */ /* * Tables used for translation and classification macros @@ -104,6 +106,12 @@ #define IsUpper(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_UPPER) /** Test whether a character is a control character. */ #define IsCntrl(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_CNTRL) +/** Test whether a character is a CTCP character - snircd */ +#define IsCtcp(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_CTCP) +/** Test whether a character is a control character - snircd */ +#define IsControl(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_CONTROL) +/** Test whether a character is a CTCP or control character - snircd */ +#define IsCtcpOrControl(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & (NTL_CTCP|NTL_CONTROL)) /** Test whether a character is valid in a channel name. */ #define IsChannelChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCCH) @@ -129,5 +137,4 @@ #define IsKTimeChar(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_KTIME) - #endif /* INCLUDED_ircd_chattr_h */ diff -r 718a91e2ff02 ircd/channel.c --- a/ircd/channel.c +++ b/ircd/channel.c @@ -778,6 +778,75 @@ return member_can_send_to_channel(member, reveal); } +/** Check if a client can send control codes or CTCP to a channel + * + * @param cptr The client to check + * @param chptr The channel to check + * @param text The text to check for control codes and/or CTCP chars + * @param action When 1 allow CTCP ACTION (for PRIVMSG), + * else dont allow (for NOTICE, WALLCHOPS, and WALLVOICES) + * + * @returns true if the client is allowed to speak on the channel, false + * otherwise + * + */ +int client_can_send_controlcode_or_ctcp_to_channel(struct Client *cptr, struct Channel *chptr, const char *text, int action) +{ + int control = 0, ctcp = 0; + const unsigned char *chr; + + assert(0 != cptr); + assert(0 != chptr); + + /* dont check this for remote users or servers - fail safe */ + if (!MyConnect(cptr) || IsServer(cptr)) + return 1; + + /* mode +c set */ + if (chptr->mode.mode & MODE_NOCOLOUR) + control = 1; + + /* mode +C set */ + if (chptr->mode.mode & MODE_NOCTCP) { + ctcp = 1; + + /* when action is 1, do allow CTCP ACTION though */ + if (action && !ircd_strncmp(text,"\001ACTION ",8)) + ctcp = 0; + } + + /* nothing to check */ + if (!ctcp && !control) + return 1; + + /* search for CTCP and control codes */ + if (ctcp && control) { + for (chr = text; *chr; chr++) { + if (IsCtcpOrControl(*chr)) + return 0; + } + } + + /* search for CTCP */ + else if (ctcp) { + for (chr = text; *chr; chr++) { + if (IsCtcp(*chr)) + return 0; + } + } + + /* search for control code */ + else { + for (chr = text; *chr; chr++) { + if (IsControl(*chr)) + return 0; + } + } + + /* nothing found */ + return 1; +} + /** Returns the name of a channel that prevents the user from changing nick. * if a member and not (opped or voiced) and (banned or moderated), return * the name of the first channel banned on. diff -r 718a91e2ff02 ircd/ircd_relay.c --- a/ircd/ircd_relay.c +++ b/ircd/ircd_relay.c @@ -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); @@ -111,19 +110,10 @@ } /* +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; - } + if (!client_can_send_controlcode_or_ctcp_to_channel(sptr, chptr, text, 1)) { + send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); + return; + } if ((chptr->mode.mode & MODE_NOPRIVMSGS) && check_target_limit(sptr, chptr, chptr->chname, 0)) @@ -144,7 +134,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); @@ -165,15 +154,8 @@ 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; + if (!client_can_send_controlcode_or_ctcp_to_channel(sptr, chptr, text, 0)) + return; if ((chptr->mode.mode & MODE_NOPRIVMSGS) && check_target_limit(sptr, chptr, chptr->chname, 0)) diff -r 718a91e2ff02 ircd/m_wallchops.c --- a/ircd/m_wallchops.c +++ b/ircd/m_wallchops.c @@ -103,7 +103,6 @@ { struct Channel *chptr; struct Membership* member; - const char *ch; assert(0 != cptr); assert(cptr == sptr); @@ -117,20 +116,9 @@ 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)) { - - /* +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; - } + if (client_can_send_to_channel(sptr, chptr, 0) && + !(chptr->mode.mode & MODE_NONOTICE) && /* +N check */ + (client_can_send_controlcode_or_ctcp_to_channel(sptr, chptr, parv[parc - 1], 0))) { /* +cC checks */ if ((chptr->mode.mode & MODE_NOPRIVMSGS) && check_target_limit(sptr, chptr, chptr->chname, 0)) diff -r 718a91e2ff02 ircd/m_wallvoices.c --- a/ircd/m_wallvoices.c +++ b/ircd/m_wallvoices.c @@ -102,7 +102,6 @@ { struct Channel *chptr; struct Membership* member; - const char *ch; assert(0 != cptr); assert(cptr == sptr); @@ -116,20 +115,9 @@ 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)) { - - /* +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; - } + if (client_can_send_to_channel(sptr, chptr, 0) && + !(chptr->mode.mode & MODE_NONOTICE) && /* +N check */ + (client_can_send_controlcode_or_ctcp_to_channel(sptr, chptr, parv[parc - 1], 0))) { /* +cC checks */ if ((chptr->mode.mode & MODE_NOPRIVMSGS) && check_target_limit(sptr, chptr, chptr->chname, 0)) diff -r 718a91e2ff02 ircd/table_gen.c --- a/ircd/table_gen.c +++ b/ircd/table_gen.c @@ -87,6 +87,12 @@ markString(NTL_SPACE, "\011\012\013\014\015\040"); + /* CTCP char - snircd */ + markString(NTL_CTCP, "\001"); + + /* control codes bold, colour, reverse, ansi escape, italic, underline - snircd */ + markString(NTL_CONTROL, "\002\003\026\033\035\037"); + /* Make the derived sets, * WARNING: The order of these calls is important, some depend on * the results of the previous ones ! */