2 * IRC - Internet Relay Chat, ircd/ircd_relay.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 1, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * @brief Helper functions to relay various types of messages.
25 * @version $Id: ircd_relay.c 1271 2004-12-11 05:14:07Z klmitch $
27 * There are four basic types of messages, each with four subtypes.
29 * The basic types are: channel, directed, masked, and private.
30 * Channel messages are (perhaps obviously) sent directly to a
31 * channel. Directed messages are sent to "NICK[%host]@server", but
32 * only allowed if the server is a services server (to avoid
33 * information leaks for normal clients). Masked messages are sent to
34 * either *@*host.mask or *.server.mask. Private messages are sent to
37 * The subtypes for each type are: client message, client notice,
38 * server message, and server notice. Client subtypes are sent by a
39 * local user, and server subtypes are given to us by a server.
40 * Notice subtypes correspond to the NOTICE command, and message
41 * subtypes correspond to the PRIVMSG command.
43 * As a special note, directed messages do not have server subtypes,
44 * since there is no difference in handling them based on origin.
48 #include "ircd_relay.h"
53 #include "ircd_chattr.h"
54 #include "ircd_features.h"
56 #include "ircd_reply.h"
57 #include "ircd_string.h"
67 /* #include <assert.h> -- Now using assert in ircd_log.h */
73 * This file contains message relaying functions for client and server
74 * private messages and notices
75 * TODO: This file contains a lot of cut and paste code, and needs
76 * to be cleaned up a bit. The idea is to factor out the common checks
77 * but not introduce any IsOper/IsUser/MyUser/IsServer etc. stuff.
80 /** Relay a local user's message to a channel.
81 * Generates an error if the client cannot send to the channel.
82 * @param[in] sptr Client that originated the message.
83 * @param[in] name Name of target channel.
84 * @param[in] text %Message to relay.
85 * @param[in] ccount Count of channels we're sending the message to.
87 void relay_channel_message(struct Client* sptr, const char* name, const char* text, const int ccount)
89 struct Channel* chptr;
95 if (0 == (chptr = FindChannel(name))) {
96 send_reply(sptr, ERR_NOSUCHCHANNEL, name);
100 /* First thing we do is passing the message to the extended NOAMSG mode.
101 * It even can use the input when the message is dropped later on.
103 if(!IsXtraOp(sptr) && !HasPriv(sptr, PRIV_NOAMSG_OVERRIDE) && ext_amsg_block(sptr, chptr, text)) {
104 send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
108 if(!IsXtraOp(sptr) && ext_noflood_block(sptr, chptr)) {
109 send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
114 * This first: Almost never a server/service
116 if (!client_can_send_to_channel(sptr, chptr, 0)) {
117 send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
120 if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
121 check_target_limit(sptr, chptr, chptr->chname, 0))
124 /* multi target message check */
125 if(!IsXtraOp(sptr) && !HasPriv(sptr, PRIV_NOAMSG_OVERRIDE) && (chptr->mode.mode & MODE_NOAMSGS) && (ccount > 1)) {
126 send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
130 /* Check for color/ctcp. */
131 if((chptr->mode.mode & MODE_NOCOLOUR) && !IsOverrideCC(sptr)) {
132 for(c = text; *c; c++) {
133 if(*c == 3 || *c == 27) {
134 send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
139 /* Still allow /me to function. */
140 if((chptr->mode.mode & MODE_NOCTCP) && !IsOverrideCC(sptr) && ircd_strncmp(text, "\001ACTION ", 8)) {
141 for(c = text; *c; ++c) {
143 send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
149 RevealDelayedJoinIfNeeded(sptr, chptr);
150 sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, cli_from(sptr),
151 SKIP_DEAF | SKIP_BURST, text[0], "%H :%s", chptr, text);
154 /** Relay a local user's notice to a channel.
155 * Silently exits if the client cannot send to the channel.
156 * @param[in] sptr Client that originated the message.
157 * @param[in] name Name of target channel.
158 * @param[in] text %Message to relay.
159 * @param[in] ccount Count of channels we're sending the message to.
161 void relay_channel_notice(struct Client* sptr, const char* name, const char* text, const int ccount)
163 struct Channel* chptr;
169 if (0 == (chptr = FindChannel(name)))
172 /* First thing we do is passing the message to the extended NOAMSG mode.
173 * It even can use the input when the message is dropped later on.
175 if(!IsXtraOp(sptr) && !HasPriv(sptr, PRIV_NOAMSG_OVERRIDE) && ext_amsg_block(sptr, chptr, text))
178 if(!IsXtraOp(sptr) && ext_noflood_block(sptr, chptr)) {
179 send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
183 /* Now we check if the channel has the NONOTICE mode
184 * If NONOTICE is set only XtraOPS or ColorOverride users can send notices!
186 if((chptr->mode.mode & MODE_NONOTICE) && !IsOverrideCC(sptr) && !IsXtraOp(sptr)) {
187 send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
192 * This first: Almost never a server/service
194 if (!client_can_send_to_channel(sptr, chptr, 0))
197 if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
198 check_target_limit(sptr, chptr, chptr->chname, 0))
201 /* multi target message check */
202 if(!IsXtraOp(sptr) && !HasPriv(sptr, PRIV_NOAMSG_OVERRIDE) && (chptr->mode.mode & MODE_NOAMSGS) && (ccount > 1))
205 /* Check for color/ctcp. */
206 if((chptr->mode.mode & MODE_NOCOLOUR) && !IsOverrideCC(sptr)) {
207 for(c = text; *c; c++) {
208 if(*c == 3 || *c == 27) {
213 /* Still allow /me to function. */
214 if((chptr->mode.mode & MODE_NOCTCP) && !IsOverrideCC(sptr) && ircd_strncmp(text, "\001ACTION ", 8)) {
215 for(c = text; *c; ++c) {
222 RevealDelayedJoinIfNeeded(sptr, chptr);
223 sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, cli_from(sptr),
224 SKIP_DEAF | SKIP_BURST, '\0', "%H :%s", chptr, text);
227 /** Relay a message to a channel.
228 * Generates an error if the client cannot send to the channel,
229 * or if the channel is a local channel
230 * @param[in] sptr Client that originated the message.
231 * @param[in] name Name of target channel.
232 * @param[in] text %Message to relay.
234 void server_relay_channel_message(struct Client* sptr, const char* name, const char* text)
236 struct Channel* chptr;
241 if (IsLocalChannel(name) || 0 == (chptr = FindChannel(name))) {
242 send_reply(sptr, ERR_NOSUCHCHANNEL, name);
246 * This first: Almost never a server/service
247 * Servers may have channel services, need to check for it here
249 if (client_can_send_to_channel(sptr, chptr, 1) || IsChannelService(sptr)) {
250 sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, cli_from(sptr),
251 SKIP_DEAF | SKIP_BURST, text[0], "%H :%s", chptr, text);
254 send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
257 /** Relay a notice to a channel.
258 * Generates an error if the client cannot send to the channel,
259 * or if the channel is a local channel
260 * @param[in] sptr Client that originated the message.
261 * @param[in] name Name of target channel.
262 * @param[in] text %Message to relay.
264 void server_relay_channel_notice(struct Client* sptr, const char* name, const char* text)
266 struct Channel* chptr;
271 if (IsLocalChannel(name) || 0 == (chptr = FindChannel(name)))
274 * This first: Almost never a server/service
275 * Servers may have channel services, need to check for it here
277 if (client_can_send_to_channel(sptr, chptr, 1) || IsChannelService(sptr)) {
278 sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, cli_from(sptr),
279 SKIP_DEAF | SKIP_BURST, '\0', "%H :%s", chptr, text);
283 /** Relay a directed message.
284 * Same as "relay_directed_message" but has some other privilege checks.
285 * Checks that the target user is on an ulined server.
286 * If this check fails, it takes \a server as an account
287 * name and checks whether \a name has the account set.
288 * If both checks fail, it prints a message to the user and returns.
289 * @param[in] sptr Client that originated the message.
290 * @param[in] name Target nickname.
291 * @param[in] server Name of target server.
292 * @param[in] text %Message to relay.
294 int relay_directed_account_server_message(struct Client* sptr, char* name, char* server, const char* text)
296 struct Client* acptr, *dest;
307 if ((host = strchr(name, '%')))
310 if (!(acptr = FindUser(name)) || (!EmptyString(host) && 0 != match(host, cli_user(acptr)->host)))
315 if((dest = FindServer(serv)) == NULL || dest != cli_user(acptr)->server || !IsService(dest)) {
316 if(!IsNetServ(acptr) || !IsAccount(acptr) || 0 != ircd_strcmp(cli_user(acptr)->account, serv)) {
325 sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text);
331 sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text);
335 if (!(is_silenced(sptr, acptr)))
336 sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text);
346 /** Relay a directed message.
347 * Generates an error if the named server does not exist, if it is not
348 * a services server, or if \a name names a local user and a hostmask
349 * is specified but does not match.
350 * @param[in] sptr Client that originated the message.
351 * @param[in] name Target nickname, with optional "%hostname" suffix.
352 * @param[in] server Name of target server.
353 * @param[in] text %Message to relay.
355 void relay_directed_message(struct Client* sptr, char* name, char* server, const char* text)
357 struct Client* acptr;
365 if ((acptr = FindServer(server + 1)) == NULL || !IsService(acptr))
367 send_reply(sptr, ERR_NOSUCHNICK, name);
371 * NICK[%host]@server addressed? See if <server> is me first
375 sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text);
379 * Look for an user whose NICK is equal to <name> and then
380 * check if it's hostname matches <host> and if it's a local
384 if ((host = strchr(name, '%')))
387 /* As reported by Vampire-, it's possible to brute force finding users
388 * by sending a message to each server and see which one succeeded.
389 * This means we have to remove error reporting. Sigh. Better than
390 * removing the ability to send directed messages to client servers
391 * Thanks for the suggestion Vampire=. -- Isomer 2001-08-28
392 * Argh, /ping nick@server, disallow messages to non +k clients :/ I hate
393 * this. -- Isomer 2001-09-16
395 if (!(acptr = FindUser(name)) || !MyUser(acptr) ||
396 (!EmptyString(host) && 0 != match(host, cli_user(acptr)->host)) ||
397 !IsChannelService(acptr))
400 * By this stage we might as well not bother because they will
401 * know that this server is currently linked because of the
404 send_reply(sptr, ERR_NOSUCHNICK, name);
412 if (!(is_silenced(sptr, acptr)))
413 sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text);
416 /** Relay a directed notice.
417 * Generates an error if the named server does not exist, if it is not
418 * a services server, or if \a name names a local user and a hostmask
419 * is specified but does not match.
420 * @param[in] sptr Client that originated the message.
421 * @param[in] name Target nickname, with optional "%hostname" suffix.
422 * @param[in] server Name of target server.
423 * @param[in] text %Message to relay.
425 void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text)
427 struct Client* acptr;
435 if (0 == (acptr = FindServer(server + 1)))
438 * NICK[%host]@server addressed? See if <server> is me first
441 sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text);
445 * Look for an user whose NICK is equal to <name> and then
446 * check if it's hostname matches <host> and if it's a local
450 if ((host = strchr(name, '%')))
453 if (!(acptr = FindUser(name)) || !MyUser(acptr) ||
454 (!EmptyString(host) && 0 != match(host, cli_user(acptr)->host)))
461 if (!(is_silenced(sptr, acptr)))
462 sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text);
465 /** Relay a private message from a local user.
466 * Returns an error if the user does not exist or sending to him would
467 * exceed the source's free targets. Sends an AWAY status message if
468 * the target is marked as away.
469 * @param[in] sptr Client that originated the message.
470 * @param[in] name Nickname of target user.
471 * @param[in] text %Message to relay.
473 void relay_private_message(struct Client* sptr, const char* name, const char* text)
475 struct Client* acptr;
481 if (0 == (acptr = FindUser(name))) {
482 send_reply(sptr, ERR_NOSUCHNICK, name);
485 if ((!IsChannelService(acptr) &&
486 check_target_limit(sptr, acptr, cli_name(acptr), 0)) ||
487 is_silenced(sptr, acptr))
491 * send away message if user away
493 if (cli_user(acptr) && cli_user(acptr)->away)
494 send_reply(sptr, RPL_AWAY, cli_name(acptr), cli_user(acptr)->away);
496 * deliver the message
499 add_target(acptr, sptr);
501 sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text);
504 /** Relay a private notice from a local user.
505 * Returns an error if the user does not exist or sending to him would
506 * exceed the source's free targets. Sends an AWAY status message if
507 * the target is marked as away.
508 * @param[in] sptr Client that originated the message.
509 * @param[in] name Nickname of target user.
510 * @param[in] text %Message to relay.
512 void relay_private_notice(struct Client* sptr, const char* name, const char* text)
514 struct Client* acptr;
519 if (0 == (acptr = FindUser(name)))
521 if ((!IsChannelService(acptr) &&
522 check_target_limit(sptr, acptr, cli_name(acptr), 0)) ||
523 is_silenced(sptr, acptr))
526 * deliver the message
529 add_target(acptr, sptr);
531 sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text);
534 /** Relay a private message that arrived from a server.
535 * Returns an error if the user does not exist.
536 * @param[in] sptr Client that originated the message.
537 * @param[in] name Nickname of target user.
538 * @param[in] text %Message to relay.
540 void server_relay_private_message(struct Client* sptr, const char* name, const char* text)
542 struct Client* acptr;
547 * nickname addressed?
549 if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) {
550 send_reply(sptr, SND_EXPLICIT | ERR_NOSUCHNICK, "* :Target left %s. "
551 "Failed to deliver: [%.20s]", feature_str(FEAT_NETWORK),
555 if (is_silenced(sptr, acptr))
559 add_target(acptr, sptr);
561 sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text);
565 /** Relay a private notice that arrived from a server.
566 * Returns an error if the user does not exist.
567 * @param[in] sptr Client that originated the message.
568 * @param[in] name Nickname of target user.
569 * @param[in] text %Message to relay.
571 void server_relay_private_notice(struct Client* sptr, const char* name, const char* text)
573 struct Client* acptr;
578 * nickname addressed?
580 if (0 == (acptr = findNUser(name)) || !IsUser(acptr))
583 if (is_silenced(sptr, acptr))
587 add_target(acptr, sptr);
589 sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text);
592 /** Relay a masked message from a local user.
593 * Sends an error response if there is no top-level domain label in \a
594 * mask, or if that TLD contains a wildcard.
595 * @param[in] sptr Client that originated the message.
596 * @param[in] mask Target mask for the message.
597 * @param[in] text %Message to relay.
599 void relay_masked_message(struct Client* sptr, const char* mask, const char* text)
608 * look for the last '.' in mask and scan forward
610 if (0 == (s = strrchr(mask, '.'))) {
611 send_reply(sptr, ERR_NOTOPLEVEL, mask);
615 if (*s == '.' || *s == '*' || *s == '?')
618 if (*s == '*' || *s == '?') {
619 send_reply(sptr, ERR_WILDTOPLEVEL, mask);
628 sendcmdto_match_butone(sptr, CMD_PRIVATE, s,
629 IsServer(cli_from(sptr)) ? cli_from(sptr) : 0,
630 host_mask ? MATCH_HOST : MATCH_SERVER,
631 "%s :%s", mask, text);
634 /** Relay a masked notice from a local user.
635 * Sends an error response if there is no top-level domain label in \a
636 * mask, or if that TLD contains a wildcard.
637 * @param[in] sptr Client that originated the message.
638 * @param[in] mask Target mask for the message.
639 * @param[in] text %Message to relay.
641 void relay_masked_notice(struct Client* sptr, const char* mask, const char* text)
650 * look for the last '.' in mask and scan forward
652 if (0 == (s = strrchr(mask, '.'))) {
653 send_reply(sptr, ERR_NOTOPLEVEL, mask);
657 if (*s == '.' || *s == '*' || *s == '?')
660 if (*s == '*' || *s == '?') {
661 send_reply(sptr, ERR_WILDTOPLEVEL, mask);
670 sendcmdto_match_butone(sptr, CMD_NOTICE, s,
671 IsServer(cli_from(sptr)) ? cli_from(sptr) : 0,
672 host_mask ? MATCH_HOST : MATCH_SERVER,
673 "%s :%s", mask, text);
676 /** Relay a masked message that arrived from a server.
677 * @param[in] sptr Client that originated the message.
678 * @param[in] mask Target mask for the message.
679 * @param[in] text %Message to relay.
681 void server_relay_masked_message(struct Client* sptr, const char* mask, const char* text)
683 const char* s = mask;
693 sendcmdto_match_butone(sptr, CMD_PRIVATE, s,
694 IsServer(cli_from(sptr)) ? cli_from(sptr) : 0,
695 host_mask ? MATCH_HOST : MATCH_SERVER,
696 "%s :%s", mask, text);
699 /** Relay a masked notice that arrived from a server.
700 * @param[in] sptr Client that originated the message.
701 * @param[in] mask Target mask for the message.
702 * @param[in] text %Message to relay.
704 void server_relay_masked_notice(struct Client* sptr, const char* mask, const char* text)
706 const char* s = mask;
716 sendcmdto_match_butone(sptr, CMD_NOTICE, s,
717 IsServer(cli_from(sptr)) ? cli_from(sptr) : 0,
718 host_mask ? MATCH_HOST : MATCH_SERVER,
719 "%s :%s", mask, text);