]> jfr.im git - solanum.git/blame - modules/core/m_message.c
Check the return value on rb_pipe.
[solanum.git] / modules / core / m_message.c
CommitLineData
212380e3
AC
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_message.c: Sends a (PRIVMSG|NOTICE) message to a user or channel.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
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 2 of the License, or
12 * (at your option) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
63aecfb9 24 * $Id: m_message.c 3173 2007-01-31 23:57:18Z jilles $
212380e3
AC
25 */
26
27#include "stdinc.h"
28#include "client.h"
29#include "ircd.h"
30#include "numeric.h"
31#include "common.h"
32#include "s_conf.h"
33#include "s_serv.h"
34#include "msg.h"
35#include "parse.h"
36#include "modules.h"
37#include "channel.h"
4562c604 38#include "match.h"
212380e3
AC
39#include "hash.h"
40#include "class.h"
41#include "msg.h"
42#include "packet.h"
43#include "send.h"
212380e3 44#include "s_newconf.h"
43f8445d 45#include "s_stats.h"
ab428518 46#include "inline/stringops.h"
212380e3
AC
47
48static int m_message(int, const char *, struct Client *, struct Client *, int, const char **);
49static int m_privmsg(struct Client *, struct Client *, int, const char **);
50static int m_notice(struct Client *, struct Client *, int, const char **);
51
52static void expire_tgchange(void *unused);
0e7cb7e6 53static struct ev_entry *expire_tgchange_event;
212380e3
AC
54
55static int
56modinit(void)
57{
0e7cb7e6 58 expire_tgchange_event = rb_event_addish("expire_tgchange", expire_tgchange, NULL, 300);
212380e3
AC
59 expire_tgchange(NULL);
60 return 0;
61}
62
63static void
64moddeinit(void)
65{
0e7cb7e6 66 rb_event_delete(expire_tgchange_event);
212380e3
AC
67}
68
69struct Message privmsg_msgtab = {
70 "PRIVMSG", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
71 {mg_unreg, {m_privmsg, 0}, {m_privmsg, 0}, mg_ignore, mg_ignore, {m_privmsg, 0}}
72};
73struct Message notice_msgtab = {
74 "NOTICE", 0, 0, 0, MFLG_SLOW,
75 {mg_unreg, {m_notice, 0}, {m_notice, 0}, {m_notice, 0}, mg_ignore, {m_notice, 0}}
76};
77
78mapi_clist_av1 message_clist[] = { &privmsg_msgtab, &notice_msgtab, NULL };
79
63aecfb9 80DECLARE_MODULE_AV1(message, modinit, moddeinit, message_clist, NULL, NULL, "$Revision: 3173 $");
212380e3
AC
81
82struct entity
83{
84 void *ptr;
85 int type;
86 int flags;
87};
88
89static int build_target_list(int p_or_n, const char *command,
90 struct Client *client_p,
91 struct Client *source_p, const char *nicks_channels, const char *text);
92
c2874388 93static struct Channel *find_allowing_channel(struct Client *source_p, struct Client *target_p);
212380e3
AC
94static int flood_attack_client(int p_or_n, struct Client *source_p, struct Client *target_p);
95static int flood_attack_channel(int p_or_n, struct Client *source_p,
96 struct Channel *chptr, char *chname);
212380e3
AC
97
98#define ENTITY_NONE 0
99#define ENTITY_CHANNEL 1
c4d2d014
JT
100#define ENTITY_CHANNEL_OPMOD 2
101#define ENTITY_CHANOPS_ON_CHANNEL 3
102#define ENTITY_CLIENT 4
212380e3
AC
103
104static struct entity targets[512];
105static int ntargets = 0;
106
107static int duplicate_ptr(void *);
108
109static void msg_channel(int p_or_n, const char *command,
110 struct Client *client_p,
111 struct Client *source_p, struct Channel *chptr, const char *text);
112
c4d2d014
JT
113static void msg_channel_opmod(int p_or_n, const char *command,
114 struct Client *client_p,
115 struct Client *source_p, struct Channel *chptr,
116 const char *text);
117
212380e3
AC
118static void msg_channel_flags(int p_or_n, const char *command,
119 struct Client *client_p,
120 struct Client *source_p,
121 struct Channel *chptr, int flags, const char *text);
122
123static void msg_client(int p_or_n, const char *command,
124 struct Client *source_p, struct Client *target_p, const char *text);
125
126static void handle_special(int p_or_n, const char *command,
127 struct Client *client_p, struct Client *source_p, const char *nick,
128 const char *text);
129
130/*
131** m_privmsg
132**
133** massive cleanup
134** rev argv 6/91
135**
136** Another massive cleanup Nov, 2000
137** (I don't think there is a single line left from 6/91. Maybe.)
138** m_privmsg and m_notice do basically the same thing.
139** in the original 2.8.2 code base, they were the same function
140** "m_message.c." When we did the great cleanup in conjuncton with bleep
141** of ircu fame, we split m_privmsg.c and m_notice.c.
142** I don't see the point of that now. Its harder to maintain, its
143** easier to introduce bugs into one version and not the other etc.
144** Really, the penalty of an extra function call isn't that big a deal folks.
145** -db Nov 13, 2000
146**
147*/
148
149#define PRIVMSG 0
150#define NOTICE 1
151
152static int
153m_privmsg(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
154{
155 return m_message(PRIVMSG, "PRIVMSG", client_p, source_p, parc, parv);
156}
157
158static int
159m_notice(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
160{
161 return m_message(NOTICE, "NOTICE", client_p, source_p, parc, parv);
162}
163
164/*
165 * inputs - flag privmsg or notice
166 * - pointer to command "PRIVMSG" or "NOTICE"
167 * - pointer to client_p
168 * - pointer to source_p
169 * - pointer to channel
170 */
171static int
172m_message(int p_or_n,
173 const char *command,
174 struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
175{
176 int i;
177
178 if(parc < 2 || EmptyString(parv[1]))
179 {
180 if(p_or_n != NOTICE)
181 sendto_one(source_p, form_str(ERR_NORECIPIENT), me.name,
182 source_p->name, command);
183 return 0;
184 }
185
186 if(parc < 3 || EmptyString(parv[2]))
187 {
188 if(p_or_n != NOTICE)
189 sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
190 return 0;
191 }
192
193 /* Finish the flood grace period if theyre not messaging themselves
194 * as some clients (ircN) do this as a "lag check"
195 */
196 if(MyClient(source_p) && !IsFloodDone(source_p) && irccmp(source_p->name, parv[1]))
197 flood_endgrace(source_p);
198
199 if(build_target_list(p_or_n, command, client_p, source_p, parv[1], parv[2]) < 0)
200 {
201 return 0;
202 }
203
204 for(i = 0; i < ntargets; i++)
205 {
206 switch (targets[i].type)
207 {
208 case ENTITY_CHANNEL:
209 msg_channel(p_or_n, command, client_p, source_p,
210 (struct Channel *) targets[i].ptr, parv[2]);
211 break;
212
c4d2d014
JT
213 case ENTITY_CHANNEL_OPMOD:
214 msg_channel_opmod(p_or_n, command, client_p, source_p,
215 (struct Channel *) targets[i].ptr, parv[2]);
216 break;
217
212380e3
AC
218 case ENTITY_CHANOPS_ON_CHANNEL:
219 msg_channel_flags(p_or_n, command, client_p, source_p,
220 (struct Channel *) targets[i].ptr,
221 targets[i].flags, parv[2]);
222 break;
223
224 case ENTITY_CLIENT:
225 msg_client(p_or_n, command, source_p,
226 (struct Client *) targets[i].ptr, parv[2]);
227 break;
228 }
229 }
230
231 return 0;
232}
233
234/*
235 * build_target_list
236 *
237 * inputs - pointer to given client_p (server)
238 * - pointer to given source (oper/client etc.)
239 * - pointer to list of nicks/channels
240 * - pointer to table to place results
241 * - pointer to text (only used if source_p is an oper)
242 * output - number of valid entities
243 * side effects - target_table is modified to contain a list of
244 * pointers to channels or clients
245 * if source client is an oper
246 * all the classic old bizzare oper privmsg tricks
247 * are parsed and sent as is, if prefixed with $
248 * to disambiguate.
249 *
250 */
251
252static int
253build_target_list(int p_or_n, const char *command, struct Client *client_p,
254 struct Client *source_p, const char *nicks_channels, const char *text)
255{
256 int type;
257 char *p, *nick, *target_list;
258 struct Channel *chptr = NULL;
259 struct Client *target_p;
260
261 target_list = LOCAL_COPY(nicks_channels); /* skip strcpy for non-lazyleafs */
262
263 ntargets = 0;
264
4a2651e5 265 for(nick = rb_strtok_r(target_list, ",", &p); nick; nick = rb_strtok_r(NULL, ",", &p))
212380e3
AC
266 {
267 char *with_prefix;
268 /*
269 * channels are privmsg'd a lot more than other clients, moved up
270 * here plain old channel msg?
271 */
272
273 if(IsChanPrefix(*nick))
274 {
275 /* ignore send of local channel to a server (should not happen) */
276 if(IsServer(client_p) && *nick == '&')
277 continue;
278
279 if((chptr = find_channel(nick)) != NULL)
280 {
281 if(!duplicate_ptr(chptr))
282 {
283 if(ntargets >= ConfigFileEntry.max_targets)
284 {
285 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
286 me.name, source_p->name, nick);
287 return (1);
288 }
289 targets[ntargets].ptr = (void *) chptr;
290 targets[ntargets++].type = ENTITY_CHANNEL;
291 }
292 }
293
294 /* non existant channel */
295 else if(p_or_n != NOTICE)
296 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
297 form_str(ERR_NOSUCHNICK), nick);
298
299 continue;
300 }
301
302 if(MyClient(source_p))
303 target_p = find_named_person(nick);
304 else
305 target_p = find_person(nick);
306
307 /* look for a privmsg to another client */
308 if(target_p)
309 {
310 if(!duplicate_ptr(target_p))
311 {
312 if(ntargets >= ConfigFileEntry.max_targets)
313 {
314 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
315 me.name, source_p->name, nick);
316 return (1);
317 }
318 targets[ntargets].ptr = (void *) target_p;
319 targets[ntargets].type = ENTITY_CLIENT;
320 targets[ntargets++].flags = 0;
321 }
322 continue;
323 }
324
325 /* @#channel or +#channel message ? */
326
327 type = 0;
328 with_prefix = nick;
329 /* allow %+@ if someone wants to do that */
330 for(;;)
331 {
332 if(*nick == '@')
333 type |= CHFL_CHANOP;
334 else if(*nick == '+')
335 type |= CHFL_CHANOP | CHFL_VOICE;
336 else
337 break;
338 nick++;
339 }
340
341 if(type != 0)
342 {
343 /* no recipient.. */
344 if(EmptyString(nick))
345 {
346 sendto_one(source_p, form_str(ERR_NORECIPIENT),
347 me.name, source_p->name, command);
348 continue;
349 }
350
351 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
352 * if the channel is found, fine, if not report an error
353 */
354
355 if((chptr = find_channel(nick)) != NULL)
356 {
357 struct membership *msptr;
358
359 msptr = find_channel_membership(chptr, source_p);
360
361 if(!IsServer(source_p) && !IsService(source_p) && !is_chanop_voiced(msptr))
362 {
363 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
631b4a54
JT
364 get_id(&me, source_p),
365 get_id(source_p, source_p),
366 with_prefix);
212380e3
AC
367 return (-1);
368 }
369
370 if(!duplicate_ptr(chptr))
371 {
372 if(ntargets >= ConfigFileEntry.max_targets)
373 {
374 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
375 me.name, source_p->name, nick);
376 return (1);
377 }
378 targets[ntargets].ptr = (void *) chptr;
379 targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
380 targets[ntargets++].flags = type;
381 }
382 }
383 else if(p_or_n != NOTICE)
384 {
385 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
386 form_str(ERR_NOSUCHNICK), nick);
387 }
388
389 continue;
390 }
391
392 if(strchr(nick, '@') || (IsOper(source_p) && (*nick == '$')))
393 {
394 handle_special(p_or_n, command, client_p, source_p, nick, text);
395 continue;
396 }
397
c4d2d014
JT
398 if(IsServer(client_p) && *nick == '=' && nick[1] == '#')
399 {
400 nick++;
401 if((chptr = find_channel(nick)) != NULL)
402 {
403 if(!duplicate_ptr(chptr))
404 {
405 if(ntargets >= ConfigFileEntry.max_targets)
406 {
407 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
408 me.name, source_p->name, nick);
409 return (1);
410 }
411 targets[ntargets].ptr = (void *) chptr;
412 targets[ntargets++].type = ENTITY_CHANNEL_OPMOD;
413 }
414 }
415
416 /* non existant channel */
417 else if(p_or_n != NOTICE)
418 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
419 form_str(ERR_NOSUCHNICK), nick);
420
421 continue;
422 }
423
212380e3
AC
424 /* no matching anything found - error if not NOTICE */
425 if(p_or_n != NOTICE)
426 {
427 /* dont give this numeric when source is local,
428 * because its misleading --anfl
429 */
430 if(!MyClient(source_p) && IsDigit(*nick))
431 sendto_one(source_p, ":%s %d %s * :Target left IRC. "
432 "Failed to deliver: [%.20s]",
433 get_id(&me, source_p), ERR_NOSUCHNICK,
434 get_id(source_p, source_p), text);
435 else
436 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
437 form_str(ERR_NOSUCHNICK), nick);
438 }
439
440 }
441 return (1);
442}
443
444/*
445 * duplicate_ptr
446 *
447 * inputs - pointer to check
448 * - pointer to table of entities
449 * - number of valid entities so far
450 * output - YES if duplicate pointer in table, NO if not.
451 * note, this does the canonize using pointers
452 * side effects - NONE
453 */
454static int
455duplicate_ptr(void *ptr)
456{
457 int i;
458 for(i = 0; i < ntargets; i++)
459 if(targets[i].ptr == ptr)
460 return YES;
461 return NO;
462}
463
464/*
465 * msg_channel
466 *
467 * inputs - flag privmsg or notice
468 * - pointer to command "PRIVMSG" or "NOTICE"
469 * - pointer to client_p
470 * - pointer to source_p
471 * - pointer to channel
472 * output - NONE
473 * side effects - message given channel
474 *
475 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
476 */
477static void
478msg_channel(int p_or_n, const char *command,
479 struct Client *client_p, struct Client *source_p, struct Channel *chptr,
480 const char *text)
481{
482 int result;
483 char text2[BUFSIZE];
484
485 if(MyClient(source_p))
486 {
487 /* idle time shouldnt be reset by notices --fl */
488 if(p_or_n != NOTICE)
e3354945 489 source_p->localClient->last = rb_current_time();
212380e3
AC
490 }
491
492 if(chptr->mode.mode & MODE_NOCOLOR)
493 {
f427c8b0 494 rb_strlcpy(text2, text, BUFSIZE);
212380e3
AC
495 strip_colour(text2);
496 text = text2;
497 if (EmptyString(text))
498 {
499 /* could be empty after colour stripping and
500 * that would cause problems later */
501 if(p_or_n != NOTICE)
502 sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
503 return;
504 }
505 }
506
507 /* chanops and voiced can flood their own channel with impunity */
508 if((result = can_send(chptr, source_p, NULL)))
509 {
510 if(result == CAN_SEND_OPV ||
511 !flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
512 {
513 sendto_channel_flags(client_p, ALL_MEMBERS, source_p, chptr,
514 "%s %s :%s", command, chptr->chname, text);
515 }
516 }
517 else if(chptr->mode.mode & MODE_OPMODERATE &&
8feca176
JT
518 (!(chptr->mode.mode & MODE_NOPRIVMSGS) ||
519 IsMember(source_p, chptr)))
212380e3 520 {
212380e3
AC
521 if(!flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
522 {
c4d2d014
JT
523 sendto_channel_opmod(client_p, source_p, chptr,
524 command, text);
525 }
526 }
527 else
528 {
529 if(p_or_n != NOTICE)
530 sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
531 form_str(ERR_CANNOTSENDTOCHAN), chptr->chname);
532 }
533}
534/*
535 * msg_channel_opmod
536 *
537 * inputs - flag privmsg or notice
538 * - pointer to command "PRIVMSG" or "NOTICE"
539 * - pointer to client_p
540 * - pointer to source_p
541 * - pointer to channel
542 * output - NONE
543 * side effects - message given channel ops
544 *
545 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
546 */
547static void
548msg_channel_opmod(int p_or_n, const char *command,
549 struct Client *client_p, struct Client *source_p,
550 struct Channel *chptr, const char *text)
551{
552 char text2[BUFSIZE];
553
554 if(chptr->mode.mode & MODE_NOCOLOR)
555 {
556 rb_strlcpy(text2, text, BUFSIZE);
557 strip_colour(text2);
558 text = text2;
559 if (EmptyString(text))
560 {
561 /* could be empty after colour stripping and
562 * that would cause problems later */
563 if(p_or_n != NOTICE)
564 sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
565 return;
566 }
567 }
568
569 if(chptr->mode.mode & MODE_OPMODERATE &&
570 (!(chptr->mode.mode & MODE_NOPRIVMSGS) ||
571 IsMember(source_p, chptr)))
572 {
573 if(!flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
574 {
575 sendto_channel_opmod(client_p, source_p, chptr,
576 command, text);
212380e3
AC
577 }
578 }
579 else
580 {
581 if(p_or_n != NOTICE)
582 sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
583 form_str(ERR_CANNOTSENDTOCHAN), chptr->chname);
584 }
585}
586
587/*
588 * msg_channel_flags
589 *
590 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
591 * say NOTICE must not auto reply
592 * - pointer to command, "PRIVMSG" or "NOTICE"
593 * - pointer to client_p
594 * - pointer to source_p
595 * - pointer to channel
596 * - flags
597 * - pointer to text to send
598 * output - NONE
599 * side effects - message given channel either chanop or voice
600 */
601static void
602msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
603 struct Client *source_p, struct Channel *chptr, int flags, const char *text)
604{
605 int type;
606 char c;
607
608 if(flags & CHFL_VOICE)
609 {
610 type = ONLY_CHANOPSVOICED;
611 c = '+';
612 }
613 else
614 {
615 type = ONLY_CHANOPS;
616 c = '@';
617 }
618
619 if(MyClient(source_p))
620 {
621 /* idletime shouldnt be reset by notice --fl */
622 if(p_or_n != NOTICE)
e3354945 623 source_p->localClient->last = rb_current_time();
212380e3
AC
624 }
625
626 sendto_channel_flags(client_p, type, source_p, chptr, "%s %c%s :%s",
627 command, c, chptr->chname, text);
628}
629
630#define PREV_FREE_TARGET(x) ((FREE_TARGET(x) == 0) ? 9 : FREE_TARGET(x) - 1)
631#define PREV_TARGET(i) ((i == 0) ? i = 9 : --i)
632#define NEXT_TARGET(i) ((i == 9) ? i = 0 : ++i)
633
634static void
635expire_tgchange(void *unused)
636{
637 tgchange *target;
637c4932 638 rb_dlink_node *ptr, *next_ptr;
212380e3 639
637c4932 640 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, tgchange_list.head)
212380e3
AC
641 {
642 target = ptr->data;
643
e3354945 644 if(target->expiry < rb_current_time())
212380e3 645 {
ba200635
AC
646 rb_dlinkDelete(ptr, &tgchange_list);
647 rb_patricia_remove(tgchange_tree, target->pnode);
bd198292
VY
648 rb_free(target->ip);
649 rb_free(target);
212380e3
AC
650 }
651 }
652}
653
ae78a571
VY
654static int
655add_target(struct Client *source_p, struct Client *target_p)
656{
657 int i, j;
658 uint32_t hashv;
659
660 /* can msg themselves or services without using any target slots */
661 if(source_p == target_p || IsService(target_p))
662 return 1;
663
664 /* special condition for those who have had PRIVMSG crippled to allow them
665 * to talk to IRCops still.
666 *
667 * XXX: is this controversial?
668 */
669 if(source_p->localClient->target_last > rb_current_time() && IsOper(target_p))
670 return 1;
671
672 hashv = fnv_hash_upper((const unsigned char *)use_id(target_p), 32);
673
674 if(USED_TARGETS(source_p))
675 {
676 /* hunt for an existing target */
677 for(i = PREV_FREE_TARGET(source_p), j = USED_TARGETS(source_p);
678 j; --j, PREV_TARGET(i))
679 {
680 if(source_p->localClient->targets[i] == hashv)
681 return 1;
682 }
683
684 /* first message after connect, we may only start clearing
685 * slots after this message --anfl
686 */
687 if(!IsTGChange(source_p))
688 {
689 SetTGChange(source_p);
690 source_p->localClient->target_last = rb_current_time();
691 }
692 /* clear as many targets as we can */
693 else if((i = (rb_current_time() - source_p->localClient->target_last) / 60))
694 {
695 if(i > USED_TARGETS(source_p))
696 USED_TARGETS(source_p) = 0;
697 else
698 USED_TARGETS(source_p) -= i;
699
700 source_p->localClient->target_last = rb_current_time();
701 }
702 /* cant clear any, full target list */
703 else if(USED_TARGETS(source_p) == 10)
704 {
47adde3d 705 ServerStats.is_tgch++;
ae78a571
VY
706 add_tgchange(source_p->sockhost);
707 return 0;
708 }
709 }
710 /* no targets in use, reset their target_last so that they cant
711 * abuse a long idle to get targets back more quickly
712 */
713 else
714 {
715 source_p->localClient->target_last = rb_current_time();
716 SetTGChange(source_p);
717 }
718
719 source_p->localClient->targets[FREE_TARGET(source_p)] = hashv;
720 NEXT_TARGET(FREE_TARGET(source_p));
721 ++USED_TARGETS(source_p);
722 return 1;
212380e3
AC
723}
724
725/*
726 * msg_client
727 *
728 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
729 * say NOTICE must not auto reply
730 * - pointer to command, "PRIVMSG" or "NOTICE"
731 * - pointer to source_p source (struct Client *)
732 * - pointer to target_p target (struct Client *)
733 * - pointer to text
734 * output - NONE
735 * side effects - message given channel either chanop or voice
736 */
737static void
738msg_client(int p_or_n, const char *command,
739 struct Client *source_p, struct Client *target_p, const char *text)
740{
c2874388
JT
741 int do_floodcount = 0;
742
212380e3
AC
743 if(MyClient(source_p))
744 {
745 /* reset idle time for message only if its not to self
746 * and its not a notice */
747 if(p_or_n != NOTICE)
e3354945 748 source_p->localClient->last = rb_current_time();
212380e3 749
c2874388
JT
750 /* auto cprivmsg/cnotice */
751 do_floodcount = !IsOper(source_p) &&
752 !find_allowing_channel(source_p, target_p);
753
212380e3
AC
754 /* target change stuff, dont limit ctcp replies as that
755 * would allow people to start filling up random users
756 * targets just by ctcping them
757 */
758 if((p_or_n != NOTICE || *text != '\001') &&
c2874388 759 ConfigFileEntry.target_change && do_floodcount)
212380e3
AC
760 {
761 if(!add_target(source_p, target_p))
762 {
763 sendto_one(source_p, form_str(ERR_TARGCHANGE),
764 me.name, source_p->name, target_p->name);
765 return;
766 }
767 }
b7b1d686
JT
768
769 if (do_floodcount &&
770 flood_attack_client(p_or_n, source_p, target_p))
771 return;
212380e3
AC
772 }
773 else if(source_p->from == target_p->from)
774 {
775 sendto_realops_snomask(SNO_DEBUG, L_ALL,
776 "Send message to %s[%s] dropped from %s(Fake Dir)",
777 target_p->name, target_p->from->name, source_p->name);
778 return;
779 }
780
781 if(MyConnect(source_p) && (p_or_n != NOTICE) && target_p->user && target_p->user->away)
782 sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY),
783 target_p->name, target_p->user->away);
784
785 if(MyClient(target_p))
786 {
787 /* XXX Controversial? allow opers always to send through a +g */
788 if(!IsServer(source_p) && (IsSetCallerId(target_p) ||
789 (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])))
790 {
791 /* Here is the anti-flood bot/spambot code -db */
792 if(accept_message(source_p, target_p) || IsOper(source_p))
793 {
794 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
795 source_p->name,
796 source_p->username,
797 source_p->host, command, target_p->name, text);
798 }
799 else if (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])
800 {
801 if (p_or_n != NOTICE)
802 sendto_one_numeric(source_p, ERR_NONONREG,
803 form_str(ERR_NONONREG),
804 target_p->name);
212380e3
AC
805 }
806 else
807 {
808 /* check for accept, flag recipient incoming message */
809 if(p_or_n != NOTICE)
810 {
811 sendto_one_numeric(source_p, ERR_TARGUMODEG,
812 form_str(ERR_TARGUMODEG),
813 target_p->name);
814 }
815
816 if((target_p->localClient->last_caller_id_time +
e3354945 817 ConfigFileEntry.caller_id_wait) < rb_current_time())
212380e3
AC
818 {
819 if(p_or_n != NOTICE)
820 sendto_one_numeric(source_p, RPL_TARGNOTIFY,
821 form_str(RPL_TARGNOTIFY),
822 target_p->name);
823
824 sendto_one(target_p, form_str(RPL_UMODEGMSG),
825 me.name, target_p->name, source_p->name,
826 source_p->username, source_p->host);
827
e3354945 828 target_p->localClient->last_caller_id_time = rb_current_time();
212380e3 829 }
212380e3
AC
830 }
831 }
832 else
b7b1d686 833 sendto_anywhere(target_p, source_p, command, ":%s", text);
212380e3 834 }
b7b1d686 835 else
212380e3
AC
836 sendto_anywhere(target_p, source_p, command, ":%s", text);
837
838 return;
839}
840
c2874388
JT
841static struct Channel *
842find_allowing_channel(struct Client *source_p, struct Client *target_p)
843{
844 rb_dlink_node *ptr;
845 struct membership *msptr;
846
847 RB_DLINK_FOREACH(ptr, source_p->user->channel.head)
848 {
849 msptr = ptr->data;
850 if (is_chanop_voiced(msptr) && IsMember(target_p, msptr->chptr))
851 return msptr->chptr;
852 }
853 return NULL;
854}
855
212380e3
AC
856/*
857 * flood_attack_client
858 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
859 * say NOTICE must not auto reply
860 * - pointer to source Client
861 * - pointer to target Client
862 * output - 1 if target is under flood attack
863 * side effects - check for flood attack on target target_p
864 */
865static int
866flood_attack_client(int p_or_n, struct Client *source_p, struct Client *target_p)
867{
868 int delta;
869
c24efdc0
JT
870 /* Services could get many messages legitimately and
871 * can be messaged without rate limiting via aliases
872 * and msg user@server.
873 * -- jilles
874 */
875 if(GlobalSetOptions.floodcount && IsClient(source_p) && source_p != target_p && !IsService(target_p))
212380e3 876 {
c24efdc0 877 if((target_p->first_received_message_time + 1) < rb_current_time())
212380e3 878 {
c24efdc0
JT
879 delta = rb_current_time() - target_p->first_received_message_time;
880 target_p->received_number_of_privmsgs -= delta;
881 target_p->first_received_message_time = rb_current_time();
882 if(target_p->received_number_of_privmsgs <= 0)
212380e3 883 {
c24efdc0
JT
884 target_p->received_number_of_privmsgs = 0;
885 target_p->flood_noticed = 0;
212380e3
AC
886 }
887 }
888
c24efdc0
JT
889 if((target_p->received_number_of_privmsgs >=
890 GlobalSetOptions.floodcount) || target_p->flood_noticed)
212380e3 891 {
c24efdc0 892 if(target_p->flood_noticed == 0)
212380e3 893 {
f2c1b06b 894 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
212380e3
AC
895 "Possible Flooder %s[%s@%s] on %s target: %s",
896 source_p->name, source_p->username,
63aecfb9 897 source_p->orighost,
c88cdb00 898 source_p->servptr->name, target_p->name);
c24efdc0 899 target_p->flood_noticed = 1;
212380e3 900 /* add a bit of penalty */
c24efdc0 901 target_p->received_number_of_privmsgs += 2;
212380e3
AC
902 }
903 if(MyClient(source_p) && (p_or_n != NOTICE))
904 sendto_one(source_p,
905 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
906 me.name, source_p->name, target_p->name);
907 return 1;
908 }
909 else
c24efdc0 910 target_p->received_number_of_privmsgs++;
212380e3
AC
911 }
912
913 return 0;
914}
915
916/*
917 * flood_attack_channel
918 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
919 * says NOTICE must not auto reply
920 * - pointer to source Client
921 * - pointer to target channel
922 * output - 1 if target is under flood attack
923 * side effects - check for flood attack on target chptr
924 */
925static int
926flood_attack_channel(int p_or_n, struct Client *source_p, struct Channel *chptr, char *chname)
927{
928 int delta;
929
930 if(GlobalSetOptions.floodcount && MyClient(source_p))
931 {
e3354945 932 if((chptr->first_received_message_time + 1) < rb_current_time())
212380e3 933 {
e3354945 934 delta = rb_current_time() - chptr->first_received_message_time;
212380e3 935 chptr->received_number_of_privmsgs -= delta;
e3354945 936 chptr->first_received_message_time = rb_current_time();
212380e3
AC
937 if(chptr->received_number_of_privmsgs <= 0)
938 {
939 chptr->received_number_of_privmsgs = 0;
940 chptr->flood_noticed = 0;
941 }
942 }
943
944 if((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
945 || chptr->flood_noticed)
946 {
947 if(chptr->flood_noticed == 0)
948 {
f2c1b06b 949 sendto_realops_snomask(SNO_BOTS, *chptr->chname == '&' ? L_ALL : L_NETWIDE,
212380e3
AC
950 "Possible Flooder %s[%s@%s] on %s target: %s",
951 source_p->name, source_p->username,
63aecfb9 952 source_p->orighost,
c88cdb00 953 source_p->servptr->name, chptr->chname);
212380e3
AC
954 chptr->flood_noticed = 1;
955
956 /* Add a bit of penalty */
957 chptr->received_number_of_privmsgs += 2;
958 }
959 if(MyClient(source_p) && (p_or_n != NOTICE))
960 sendto_one(source_p,
961 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
962 me.name, source_p->name, chptr->chname);
963 return 1;
964 }
965 else
966 chptr->received_number_of_privmsgs++;
967 }
968
969 return 0;
970}
971
972
973/*
974 * handle_special
975 *
976 * inputs - server pointer
977 * - client pointer
978 * - nick stuff to grok for opers
979 * - text to send if grok
980 * output - none
981 * side effects - all the traditional oper type messages are parsed here.
982 * i.e. "/msg #some.host."
983 * However, syntax has been changed.
984 * previous syntax "/msg #some.host.mask"
985 * now becomes "/msg $#some.host.mask"
986 * previous syntax of: "/msg $some.server.mask" remains
987 * This disambiguates the syntax.
988 */
989static void
990handle_special(int p_or_n, const char *command, struct Client *client_p,
991 struct Client *source_p, const char *nick, const char *text)
992{
993 struct Client *target_p;
212380e3
AC
994 char *server;
995 char *s;
212380e3
AC
996
997 /* user[%host]@server addressed?
998 * NOTE: users can send to user@server, but not user%host@server
999 * or opers@server
1000 */
1001 if((server = strchr(nick, '@')) != NULL)
1002 {
1003 if((target_p = find_server(source_p, server + 1)) == NULL)
1004 {
1005 sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
1006 form_str(ERR_NOSUCHSERVER), server + 1);
1007 return;
1008 }
1009
212380e3
AC
1010 if(!IsOper(source_p))
1011 {
1012 if(strchr(nick, '%') || (strncmp(nick, "opers", 5) == 0))
1013 {
1014 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
1015 form_str(ERR_NOSUCHNICK), nick);
1016 return;
1017 }
1018 }
1019
1020 /* somewhere else.. */
1021 if(!IsMe(target_p))
1022 {
1023 sendto_one(target_p, ":%s %s %s :%s",
1024 get_id(source_p, target_p), command, nick, text);
1025 return;
1026 }
1027
212380e3 1028 /* Check if someones msg'ing opers@our.server */
ef57f7fb 1029 if(strncmp(nick, "opers@", 6) == 0)
212380e3
AC
1030 {
1031 sendto_realops_snomask(SNO_GENERAL, L_ALL, "To opers: From: %s: %s",
1032 source_p->name, text);
1033 return;
1034 }
1035
ef57f7fb
JT
1036 /* This was not very useful except for bypassing certain
1037 * restrictions. Note that we still allow sending to
1038 * remote servers this way, for messaging pseudoservers
1039 * securely whether they have a service{} block or not.
1040 * -- jilles
212380e3 1041 */
ef57f7fb
JT
1042 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
1043 form_str(ERR_NOSUCHNICK), nick);
1044 return;
212380e3
AC
1045 }
1046
1047 /*
1048 * the following two cases allow masks in NOTICEs
1049 * (for OPERs only)
1050 *
1051 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
1052 */
1053 if(IsOper(source_p) && *nick == '$')
1054 {
1055 if((*(nick + 1) == '$' || *(nick + 1) == '#'))
1056 nick++;
1057 else if(MyOper(source_p))
1058 {
1059 sendto_one(source_p,
1060 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
1061 me.name, source_p->name, command, nick, nick);
1062 return;
1063 }
1064
a6f4368b
JT
1065 if(MyClient(source_p) && !IsOperMassNotice(source_p))
1066 {
1067 sendto_one(source_p, form_str(ERR_NOPRIVS),
1068 me.name, source_p->name, "mass_notice");
1069 return;
1070 }
1071
212380e3
AC
1072 if((s = strrchr(nick, '.')) == NULL)
1073 {
1074 sendto_one_numeric(source_p, ERR_NOTOPLEVEL,
1075 form_str(ERR_NOTOPLEVEL), nick);
1076 return;
1077 }
1078 while(*++s)
1079 if(*s == '.' || *s == '*' || *s == '?')
1080 break;
1081 if(*s == '*' || *s == '?')
1082 {
1083 sendto_one_numeric(source_p, ERR_WILDTOPLEVEL,
1084 form_str(ERR_WILDTOPLEVEL), nick);
1085 return;
1086 }
1087
1088 sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
1089 nick + 1,
1090 (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
1091 "%s $%s :%s", command, nick, text);
1092 return;
1093 }
1094}