]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * IRC - Internet Relay Chat, ircd/ircd_relay.c | |
3 | * Copyright (C) 1990 Jarkko Oikarinen and | |
4 | * University of Oulu, Computing Center | |
5 | * | |
6 | * See file AUTHORS in IRC package for additional names of | |
7 | * the programmers. | |
8 | * | |
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) | |
12 | * any later version. | |
13 | * | |
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. | |
18 | * | |
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. | |
22 | */ | |
23 | /** @file | |
24 | * @brief Helper functions to relay various types of messages. | |
25 | * @version $Id: ircd_relay.c,v 1.17 2004/12/11 05:13:45 klmitch Exp $ | |
26 | * | |
27 | * There are four basic types of messages, each with four subtypes. | |
28 | * | |
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 | |
35 | * NICK. | |
36 | * | |
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. | |
42 | * | |
43 | * As a special note, directed messages do not have server subtypes, | |
44 | * since there is no difference in handling them based on origin. | |
45 | */ | |
46 | #include "config.h" | |
47 | ||
48 | #include "ircd_relay.h" | |
49 | #include "channel.h" | |
50 | #include "client.h" | |
51 | #include "hash.h" | |
52 | #include "ircd.h" | |
53 | #include "ircd_chattr.h" | |
54 | #include "ircd_features.h" | |
55 | #include "ircd_log.h" | |
56 | #include "ircd_reply.h" | |
57 | #include "ircd_string.h" | |
58 | #include "match.h" | |
59 | #include "msg.h" | |
60 | #include "numeric.h" | |
61 | #include "numnicks.h" | |
62 | #include "s_debug.h" | |
63 | #include "s_misc.h" | |
64 | #include "s_user.h" | |
65 | #include "send.h" | |
66 | ||
67 | /* #include <assert.h> -- Now using assert in ircd_log.h */ | |
68 | #include <stdio.h> | |
69 | #include <stdlib.h> | |
70 | #include <string.h> | |
71 | ||
72 | /* | |
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. | |
78 | */ | |
79 | ||
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 | */ | |
86 | void relay_channel_message(struct Client* sptr, const char* name, const char* text) | |
87 | { | |
88 | struct Channel* chptr; | |
89 | const char *ch; | |
90 | assert(0 != sptr); | |
91 | assert(0 != name); | |
92 | assert(0 != text); | |
93 | ||
94 | if (0 == (chptr = FindChannel(name))) { | |
95 | send_reply(sptr, ERR_NOSUCHCHANNEL, name); | |
96 | return; | |
97 | } | |
98 | /* | |
99 | * This first: Almost never a server/service | |
100 | */ | |
101 | if (!client_can_send_to_channel(sptr, chptr, 1)) { | |
102 | send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); | |
103 | return; | |
104 | } | |
105 | if ((chptr->mode.mode & MODE_NOPRIVMSGS) && | |
106 | check_target_limit(sptr, chptr, chptr->chname, 0)) | |
107 | return; | |
108 | ||
109 | /* +cC checks */ | |
110 | if (chptr->mode.mode & MODE_NOCOLOUR) | |
111 | for (ch=text;*ch;ch++) | |
112 | if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31) { | |
113 | send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); | |
114 | return; | |
115 | } | |
116 | ||
117 | if ((chptr->mode.mode & MODE_NOCTCP) && ircd_strncmp(text,"\001ACTION ",8)) | |
118 | for (ch=text;*ch;) | |
119 | if (*ch++==1) { | |
120 | send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); | |
121 | return; | |
122 | } | |
123 | ||
124 | ||
125 | sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, cli_from(sptr), | |
126 | SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text); | |
127 | } | |
128 | ||
129 | /** Relay a local user's notice to a channel. | |
130 | * Silently exits if the client cannot send to the channel. | |
131 | * @param[in] sptr Client that originated the message. | |
132 | * @param[in] name Name of target channel. | |
133 | * @param[in] text %Message to relay. | |
134 | */ | |
135 | void relay_channel_notice(struct Client* sptr, const char* name, const char* text) | |
136 | { | |
137 | struct Channel* chptr; | |
138 | const char *ch; | |
139 | assert(0 != sptr); | |
140 | assert(0 != name); | |
141 | assert(0 != text); | |
142 | ||
143 | if (0 == (chptr = FindChannel(name))) | |
144 | return; | |
145 | /* | |
146 | * This first: Almost never a server/service | |
147 | */ | |
148 | if (!client_can_send_to_channel(sptr, chptr, 1)) | |
149 | return; | |
150 | ||
151 | if ((chptr->mode.mode & MODE_NOPRIVMSGS) && | |
152 | check_target_limit(sptr, chptr, chptr->chname, 0)) | |
153 | return; | |
154 | ||
155 | if ((chptr->mode.mode & MODE_NONOTICE)) { | |
156 | send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); | |
157 | return; | |
158 | } | |
159 | ||
160 | /* +cC checks */ | |
161 | if (chptr->mode.mode & MODE_NOCOLOUR) | |
162 | for (ch=text;*ch;ch++) | |
163 | if (*ch==2 || *ch==3 || *ch==22 || *ch==27 || *ch==31) { | |
164 | send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); | |
165 | return; | |
166 | } | |
167 | ||
168 | if ((chptr->mode.mode & MODE_NOCTCP) && ircd_strncmp(text,"\001ACTION ",8)) | |
169 | for (ch=text;*ch;) | |
170 | if (*ch++==1) { | |
171 | send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); | |
172 | return; | |
173 | } | |
174 | ||
175 | sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, cli_from(sptr), | |
176 | SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text); | |
177 | } | |
178 | ||
179 | /** Relay a message to a channel. | |
180 | * Generates an error if the client cannot send to the channel, | |
181 | * or if the channel is a local channel | |
182 | * @param[in] sptr Client that originated the message. | |
183 | * @param[in] name Name of target channel. | |
184 | * @param[in] text %Message to relay. | |
185 | */ | |
186 | void server_relay_channel_message(struct Client* sptr, const char* name, const char* text) | |
187 | { | |
188 | struct Channel* chptr; | |
189 | assert(0 != sptr); | |
190 | assert(0 != name); | |
191 | assert(0 != text); | |
192 | ||
193 | if (IsLocalChannel(name) || 0 == (chptr = FindChannel(name))) { | |
194 | send_reply(sptr, ERR_NOSUCHCHANNEL, name); | |
195 | return; | |
196 | } | |
197 | /* | |
198 | * This first: Almost never a server/service | |
199 | * Servers may have channel services, need to check for it here | |
200 | */ | |
201 | if (client_can_send_to_channel(sptr, chptr, 1) || IsChannelService(sptr)) { | |
202 | sendcmdto_channel_butone(sptr, CMD_PRIVATE, chptr, cli_from(sptr), | |
203 | SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text); | |
204 | } | |
205 | else | |
206 | send_reply(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname); | |
207 | } | |
208 | ||
209 | /** Relay a notice to a channel. | |
210 | * Generates an error if the client cannot send to the channel, | |
211 | * or if the channel is a local channel | |
212 | * @param[in] sptr Client that originated the message. | |
213 | * @param[in] name Name of target channel. | |
214 | * @param[in] text %Message to relay. | |
215 | */ | |
216 | void server_relay_channel_notice(struct Client* sptr, const char* name, const char* text) | |
217 | { | |
218 | struct Channel* chptr; | |
219 | assert(0 != sptr); | |
220 | assert(0 != name); | |
221 | assert(0 != text); | |
222 | ||
223 | if (IsLocalChannel(name) || 0 == (chptr = FindChannel(name))) | |
224 | return; | |
225 | /* | |
226 | * This first: Almost never a server/service | |
227 | * Servers may have channel services, need to check for it here | |
228 | */ | |
229 | if (client_can_send_to_channel(sptr, chptr, 1) || IsChannelService(sptr)) { | |
230 | sendcmdto_channel_butone(sptr, CMD_NOTICE, chptr, cli_from(sptr), | |
231 | SKIP_DEAF | SKIP_BURST, "%H :%s", chptr, text); | |
232 | } | |
233 | } | |
234 | ||
235 | /** Relay a directed message. | |
236 | * Generates an error if the named server does not exist, if it is not | |
237 | * a services server, or if \a name names a local user and a hostmask | |
238 | * is specified but does not match. | |
239 | * @param[in] sptr Client that originated the message. | |
240 | * @param[in] name Target nickname, with optional "%hostname" suffix. | |
241 | * @param[in] server Name of target server. | |
242 | * @param[in] text %Message to relay. | |
243 | */ | |
244 | void relay_directed_message(struct Client* sptr, char* name, char* server, const char* text) | |
245 | { | |
246 | struct Client* acptr; | |
247 | char* host; | |
248 | ||
249 | assert(0 != sptr); | |
250 | assert(0 != name); | |
251 | assert(0 != text); | |
252 | assert(0 != server); | |
253 | ||
254 | if ((acptr = FindServer(server + 1)) == NULL || !IsService(acptr)) | |
255 | { | |
256 | send_reply(sptr, ERR_NOSUCHNICK, name); | |
257 | return; | |
258 | } | |
259 | /* | |
260 | * NICK[%host]@server addressed? See if <server> is me first | |
261 | */ | |
262 | if (!IsMe(acptr)) | |
263 | { | |
264 | sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text); | |
265 | return; | |
266 | } | |
267 | /* | |
268 | * Look for an user whose NICK is equal to <name> and then | |
269 | * check if it's hostname matches <host> and if it's a local | |
270 | * user. | |
271 | */ | |
272 | *server = '\0'; | |
273 | if ((host = strchr(name, '%'))) | |
274 | *host++ = '\0'; | |
275 | ||
276 | /* As reported by Vampire-, it's possible to brute force finding users | |
277 | * by sending a message to each server and see which one succeeded. | |
278 | * This means we have to remove error reporting. Sigh. Better than | |
279 | * removing the ability to send directed messages to client servers | |
280 | * Thanks for the suggestion Vampire=. -- Isomer 2001-08-28 | |
281 | * Argh, /ping nick@server, disallow messages to non +k clients :/ I hate | |
282 | * this. -- Isomer 2001-09-16 | |
283 | */ | |
284 | if (!(acptr = FindUser(name)) || !MyUser(acptr) || | |
285 | (!EmptyString(host) && 0 != match(host, cli_user(acptr)->host)) || | |
286 | !IsChannelService(acptr)) | |
287 | { | |
288 | /* | |
289 | * By this stage we might as well not bother because they will | |
290 | * know that this server is currently linked because of the | |
291 | * increased lag. | |
292 | */ | |
293 | send_reply(sptr, ERR_NOSUCHNICK, name); | |
294 | return; | |
295 | } | |
296 | ||
297 | *server = '@'; | |
298 | if (host) | |
299 | *--host = '%'; | |
300 | ||
301 | if (!(is_silenced(sptr, acptr))) | |
302 | sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%s :%s", name, text); | |
303 | } | |
304 | ||
305 | /** Relay a directed notice. | |
306 | * Generates an error if the named server does not exist, if it is not | |
307 | * a services server, or if \a name names a local user and a hostmask | |
308 | * is specified but does not match. | |
309 | * @param[in] sptr Client that originated the message. | |
310 | * @param[in] name Target nickname, with optional "%hostname" suffix. | |
311 | * @param[in] server Name of target server. | |
312 | * @param[in] text %Message to relay. | |
313 | */ | |
314 | void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text) | |
315 | { | |
316 | struct Client* acptr; | |
317 | char* host; | |
318 | ||
319 | assert(0 != sptr); | |
320 | assert(0 != name); | |
321 | assert(0 != text); | |
322 | assert(0 != server); | |
323 | ||
324 | if (0 == (acptr = FindServer(server + 1))) | |
325 | return; | |
326 | /* | |
327 | * NICK[%host]@server addressed? See if <server> is me first | |
328 | */ | |
329 | if (!IsMe(acptr)) { | |
330 | sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text); | |
331 | return; | |
332 | } | |
333 | /* | |
334 | * Look for an user whose NICK is equal to <name> and then | |
335 | * check if it's hostname matches <host> and if it's a local | |
336 | * user. | |
337 | */ | |
338 | *server = '\0'; | |
339 | if ((host = strchr(name, '%'))) | |
340 | *host++ = '\0'; | |
341 | ||
342 | if (!(acptr = FindUser(name)) || !MyUser(acptr) || | |
343 | (!EmptyString(host) && 0 != match(host, cli_user(acptr)->host))) | |
344 | return; | |
345 | ||
346 | *server = '@'; | |
347 | if (host) | |
348 | *--host = '%'; | |
349 | ||
350 | if (!(is_silenced(sptr, acptr))) | |
351 | sendcmdto_one(sptr, CMD_NOTICE, acptr, "%s :%s", name, text); | |
352 | } | |
353 | ||
354 | /** Relay a private message from a local user. | |
355 | * Returns an error if the user does not exist or sending to him would | |
356 | * exceed the source's free targets. Sends an AWAY status message if | |
357 | * the target is marked as away. | |
358 | * @param[in] sptr Client that originated the message. | |
359 | * @param[in] name Nickname of target user. | |
360 | * @param[in] text %Message to relay. | |
361 | */ | |
362 | void relay_private_message(struct Client* sptr, const char* name, const char* text) | |
363 | { | |
364 | struct Client* acptr; | |
365 | ||
366 | assert(0 != sptr); | |
367 | assert(0 != name); | |
368 | assert(0 != text); | |
369 | ||
370 | if (0 == (acptr = FindUser(name))) { | |
371 | send_reply(sptr, ERR_NOSUCHNICK, name); | |
372 | return; | |
373 | } | |
374 | if ((!IsChannelService(acptr) && | |
375 | check_target_limit(sptr, acptr, cli_name(acptr), 0)) || | |
376 | is_silenced(sptr, acptr)) | |
377 | return; | |
378 | ||
379 | /* ASUKA -- slug | |
380 | * +R check, if target is +R and we're not +r (or opered) then | |
381 | * deny the message | |
382 | */ | |
383 | ||
384 | if (IsAccountOnly(acptr) && !IsAccount(sptr) && !IsOper(sptr)) { | |
385 | send_reply(sptr, ERR_ACCOUNTONLY, cli_name(acptr)); | |
386 | return; | |
387 | } | |
388 | ||
389 | /* | |
390 | * send away message if user away | |
391 | */ | |
392 | if (cli_user(acptr) && cli_user(acptr)->away) | |
393 | send_reply(sptr, RPL_AWAY, cli_name(acptr), cli_user(acptr)->away); | |
394 | /* | |
395 | * deliver the message | |
396 | */ | |
397 | if (MyUser(acptr)) | |
398 | add_target(acptr, sptr); | |
399 | ||
400 | sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text); | |
401 | } | |
402 | ||
403 | /** Relay a private notice from a local user. | |
404 | * Returns an error if the user does not exist or sending to him would | |
405 | * exceed the source's free targets. Sends an AWAY status message if | |
406 | * the target is marked as away. | |
407 | * @param[in] sptr Client that originated the message. | |
408 | * @param[in] name Nickname of target user. | |
409 | * @param[in] text %Message to relay. | |
410 | */ | |
411 | void relay_private_notice(struct Client* sptr, const char* name, const char* text) | |
412 | { | |
413 | struct Client* acptr; | |
414 | assert(0 != sptr); | |
415 | assert(0 != name); | |
416 | assert(0 != text); | |
417 | ||
418 | if (0 == (acptr = FindUser(name))) | |
419 | return; | |
420 | if ((!IsChannelService(acptr) && | |
421 | check_target_limit(sptr, acptr, cli_name(acptr), 0)) || | |
422 | is_silenced(sptr, acptr)) | |
423 | return; | |
424 | ||
425 | /* ASUKA -- slug | |
426 | * +R check, if target is +R and we're not +r (or opered) then | |
427 | * deny the message | |
428 | */ | |
429 | ||
430 | if (IsAccountOnly(acptr) && !IsAccount(sptr) && !IsOper(sptr)) | |
431 | return; | |
432 | ||
433 | /* | |
434 | * deliver the message | |
435 | */ | |
436 | if (MyUser(acptr)) | |
437 | add_target(acptr, sptr); | |
438 | ||
439 | sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text); | |
440 | } | |
441 | ||
442 | /** Relay a private message that arrived from a server. | |
443 | * Returns an error if the user does not exist. | |
444 | * @param[in] sptr Client that originated the message. | |
445 | * @param[in] name Nickname of target user. | |
446 | * @param[in] text %Message to relay. | |
447 | */ | |
448 | void server_relay_private_message(struct Client* sptr, const char* name, const char* text) | |
449 | { | |
450 | struct Client* acptr; | |
451 | assert(0 != sptr); | |
452 | assert(0 != name); | |
453 | assert(0 != text); | |
454 | /* | |
455 | * nickname addressed? | |
456 | */ | |
457 | if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) { | |
458 | send_reply(sptr, SND_EXPLICIT | ERR_NOSUCHNICK, "* :Target left %s. " | |
459 | "Failed to deliver: [%.20s]", feature_str(FEAT_NETWORK), | |
460 | text); | |
461 | return; | |
462 | } | |
463 | if (is_silenced(sptr, acptr)) | |
464 | return; | |
465 | ||
466 | if (MyUser(acptr)) | |
467 | add_target(acptr, sptr); | |
468 | ||
469 | sendcmdto_one(sptr, CMD_PRIVATE, acptr, "%C :%s", acptr, text); | |
470 | } | |
471 | ||
472 | ||
473 | /** Relay a private notice that arrived from a server. | |
474 | * Returns an error if the user does not exist. | |
475 | * @param[in] sptr Client that originated the message. | |
476 | * @param[in] name Nickname of target user. | |
477 | * @param[in] text %Message to relay. | |
478 | */ | |
479 | void server_relay_private_notice(struct Client* sptr, const char* name, const char* text) | |
480 | { | |
481 | struct Client* acptr; | |
482 | assert(0 != sptr); | |
483 | assert(0 != name); | |
484 | assert(0 != text); | |
485 | /* | |
486 | * nickname addressed? | |
487 | */ | |
488 | if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) | |
489 | return; | |
490 | ||
491 | if (is_silenced(sptr, acptr)) | |
492 | return; | |
493 | ||
494 | if (MyUser(acptr)) | |
495 | add_target(acptr, sptr); | |
496 | ||
497 | sendcmdto_one(sptr, CMD_NOTICE, acptr, "%C :%s", acptr, text); | |
498 | } | |
499 | ||
500 | /** Relay a masked message from a local user. | |
501 | * Sends an error response if there is no top-level domain label in \a | |
502 | * mask, or if that TLD contains a wildcard. | |
503 | * @param[in] sptr Client that originated the message. | |
504 | * @param[in] mask Target mask for the message. | |
505 | * @param[in] text %Message to relay. | |
506 | */ | |
507 | void relay_masked_message(struct Client* sptr, const char* mask, const char* text) | |
508 | { | |
509 | const char* s; | |
510 | int host_mask = 0; | |
511 | ||
512 | assert(0 != sptr); | |
513 | assert(0 != mask); | |
514 | assert(0 != text); | |
515 | /* | |
516 | * look for the last '.' in mask and scan forward | |
517 | */ | |
518 | if (0 == (s = strrchr(mask, '.'))) { | |
519 | send_reply(sptr, ERR_NOTOPLEVEL, mask); | |
520 | return; | |
521 | } | |
522 | while (*++s) { | |
523 | if (*s == '.' || *s == '*' || *s == '?') | |
524 | break; | |
525 | } | |
526 | if (*s == '*' || *s == '?') { | |
527 | send_reply(sptr, ERR_WILDTOPLEVEL, mask); | |
528 | return; | |
529 | } | |
530 | s = mask; | |
531 | if ('@' == *++s) { | |
532 | host_mask = 1; | |
533 | ++s; | |
534 | } | |
535 | ||
536 | sendcmdto_match_butone(sptr, CMD_PRIVATE, s, | |
537 | IsServer(cli_from(sptr)) ? cli_from(sptr) : 0, | |
538 | host_mask ? MATCH_HOST : MATCH_SERVER, | |
539 | "%s :%s", mask, text); | |
540 | } | |
541 | ||
542 | /** Relay a masked notice from a local user. | |
543 | * Sends an error response if there is no top-level domain label in \a | |
544 | * mask, or if that TLD contains a wildcard. | |
545 | * @param[in] sptr Client that originated the message. | |
546 | * @param[in] mask Target mask for the message. | |
547 | * @param[in] text %Message to relay. | |
548 | */ | |
549 | void relay_masked_notice(struct Client* sptr, const char* mask, const char* text) | |
550 | { | |
551 | const char* s; | |
552 | int host_mask = 0; | |
553 | ||
554 | assert(0 != sptr); | |
555 | assert(0 != mask); | |
556 | assert(0 != text); | |
557 | /* | |
558 | * look for the last '.' in mask and scan forward | |
559 | */ | |
560 | if (0 == (s = strrchr(mask, '.'))) { | |
561 | send_reply(sptr, ERR_NOTOPLEVEL, mask); | |
562 | return; | |
563 | } | |
564 | while (*++s) { | |
565 | if (*s == '.' || *s == '*' || *s == '?') | |
566 | break; | |
567 | } | |
568 | if (*s == '*' || *s == '?') { | |
569 | send_reply(sptr, ERR_WILDTOPLEVEL, mask); | |
570 | return; | |
571 | } | |
572 | s = mask; | |
573 | if ('@' == *++s) { | |
574 | host_mask = 1; | |
575 | ++s; | |
576 | } | |
577 | ||
578 | sendcmdto_match_butone(sptr, CMD_NOTICE, s, | |
579 | IsServer(cli_from(sptr)) ? cli_from(sptr) : 0, | |
580 | host_mask ? MATCH_HOST : MATCH_SERVER, | |
581 | "%s :%s", mask, text); | |
582 | } | |
583 | ||
584 | /** Relay a masked message that arrived from a server. | |
585 | * @param[in] sptr Client that originated the message. | |
586 | * @param[in] mask Target mask for the message. | |
587 | * @param[in] text %Message to relay. | |
588 | */ | |
589 | void server_relay_masked_message(struct Client* sptr, const char* mask, const char* text) | |
590 | { | |
591 | const char* s = mask; | |
592 | int host_mask = 0; | |
593 | assert(0 != sptr); | |
594 | assert(0 != mask); | |
595 | assert(0 != text); | |
596 | ||
597 | if ('@' == *++s) { | |
598 | host_mask = 1; | |
599 | ++s; | |
600 | } | |
601 | sendcmdto_match_butone(sptr, CMD_PRIVATE, s, | |
602 | IsServer(cli_from(sptr)) ? cli_from(sptr) : 0, | |
603 | host_mask ? MATCH_HOST : MATCH_SERVER, | |
604 | "%s :%s", mask, text); | |
605 | } | |
606 | ||
607 | /** Relay a masked notice that arrived from a server. | |
608 | * @param[in] sptr Client that originated the message. | |
609 | * @param[in] mask Target mask for the message. | |
610 | * @param[in] text %Message to relay. | |
611 | */ | |
612 | void server_relay_masked_notice(struct Client* sptr, const char* mask, const char* text) | |
613 | { | |
614 | const char* s = mask; | |
615 | int host_mask = 0; | |
616 | assert(0 != sptr); | |
617 | assert(0 != mask); | |
618 | assert(0 != text); | |
619 | ||
620 | if ('@' == *++s) { | |
621 | host_mask = 1; | |
622 | ++s; | |
623 | } | |
624 | sendcmdto_match_butone(sptr, CMD_NOTICE, s, | |
625 | IsServer(cli_from(sptr)) ? cli_from(sptr) : 0, | |
626 | host_mask ? MATCH_HOST : MATCH_SERVER, | |
627 | "%s :%s", mask, text); | |
628 | } | |
629 |