]> jfr.im git - irc/rqf/shadowircd.git/blame - modules/core/m_message.c
Add new topic command ETB, allowing services to set topic+setter+ts always
[irc/rqf/shadowircd.git] / modules / core / m_message.c
CommitLineData
212380e3 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 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"
13ae2f4b 38#include "match.h"
212380e3 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"
26f754d9 45#include "s_stats.h"
7e8e21a4 46#include "inline/stringops.h"
212380e3 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);
bfccb2c0 53static struct ev_entry *expire_tgchange_event;
212380e3 54
55static int
56modinit(void)
57{
bfccb2c0 58 expire_tgchange_event = rb_event_addish("expire_tgchange", expire_tgchange, NULL, 300);
212380e3 59 expire_tgchange(NULL);
60 return 0;
61}
62
63static void
64moddeinit(void)
65{
bfccb2c0 66 rb_event_delete(expire_tgchange_event);
212380e3 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 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
8acef9de 93static struct Channel *find_allowing_channel(struct Client *source_p, struct Client *target_p);
212380e3 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 97
98#define ENTITY_NONE 0
99#define ENTITY_CHANNEL 1
6ce8910d
JT
100#define ENTITY_CHANNEL_OPMOD 2
101#define ENTITY_CHANOPS_ON_CHANNEL 3
102#define ENTITY_CLIENT 4
212380e3 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
6ce8910d
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 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
6ce8910d
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 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
dcbd1d07 265 for(nick = rb_strtok_r(target_list, ",", &p); nick; nick = rb_strtok_r(NULL, ",", &p))
212380e3 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),
364 me.name, source_p->name, with_prefix);
365 return (-1);
366 }
367
368 if(!duplicate_ptr(chptr))
369 {
370 if(ntargets >= ConfigFileEntry.max_targets)
371 {
372 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
373 me.name, source_p->name, nick);
374 return (1);
375 }
376 targets[ntargets].ptr = (void *) chptr;
377 targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
378 targets[ntargets++].flags = type;
379 }
380 }
381 else if(p_or_n != NOTICE)
382 {
383 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
384 form_str(ERR_NOSUCHNICK), nick);
385 }
386
387 continue;
388 }
389
390 if(strchr(nick, '@') || (IsOper(source_p) && (*nick == '$')))
391 {
392 handle_special(p_or_n, command, client_p, source_p, nick, text);
393 continue;
394 }
395
6ce8910d
JT
396 if(IsServer(client_p) && *nick == '=' && nick[1] == '#')
397 {
398 nick++;
399 if((chptr = find_channel(nick)) != NULL)
400 {
401 if(!duplicate_ptr(chptr))
402 {
403 if(ntargets >= ConfigFileEntry.max_targets)
404 {
405 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
406 me.name, source_p->name, nick);
407 return (1);
408 }
409 targets[ntargets].ptr = (void *) chptr;
410 targets[ntargets++].type = ENTITY_CHANNEL_OPMOD;
411 }
412 }
413
414 /* non existant channel */
415 else if(p_or_n != NOTICE)
416 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
417 form_str(ERR_NOSUCHNICK), nick);
418
419 continue;
420 }
421
212380e3 422 /* no matching anything found - error if not NOTICE */
423 if(p_or_n != NOTICE)
424 {
425 /* dont give this numeric when source is local,
426 * because its misleading --anfl
427 */
428 if(!MyClient(source_p) && IsDigit(*nick))
429 sendto_one(source_p, ":%s %d %s * :Target left IRC. "
430 "Failed to deliver: [%.20s]",
431 get_id(&me, source_p), ERR_NOSUCHNICK,
432 get_id(source_p, source_p), text);
433 else
434 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
435 form_str(ERR_NOSUCHNICK), nick);
436 }
437
438 }
439 return (1);
440}
441
442/*
443 * duplicate_ptr
444 *
445 * inputs - pointer to check
446 * - pointer to table of entities
447 * - number of valid entities so far
448 * output - YES if duplicate pointer in table, NO if not.
449 * note, this does the canonize using pointers
450 * side effects - NONE
451 */
452static int
453duplicate_ptr(void *ptr)
454{
455 int i;
456 for(i = 0; i < ntargets; i++)
457 if(targets[i].ptr == ptr)
458 return YES;
459 return NO;
460}
461
462/*
463 * msg_channel
464 *
465 * inputs - flag privmsg or notice
466 * - pointer to command "PRIVMSG" or "NOTICE"
467 * - pointer to client_p
468 * - pointer to source_p
469 * - pointer to channel
470 * output - NONE
471 * side effects - message given channel
472 *
473 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
474 */
475static void
476msg_channel(int p_or_n, const char *command,
477 struct Client *client_p, struct Client *source_p, struct Channel *chptr,
478 const char *text)
479{
480 int result;
481 char text2[BUFSIZE];
482
483 if(MyClient(source_p))
484 {
485 /* idle time shouldnt be reset by notices --fl */
486 if(p_or_n != NOTICE)
9f6bbe3c 487 source_p->localClient->last = rb_current_time();
212380e3 488 }
489
490 if(chptr->mode.mode & MODE_NOCOLOR)
491 {
907468c4 492 rb_strlcpy(text2, text, BUFSIZE);
212380e3 493 strip_colour(text2);
494 text = text2;
495 if (EmptyString(text))
496 {
497 /* could be empty after colour stripping and
498 * that would cause problems later */
499 if(p_or_n != NOTICE)
500 sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
501 return;
502 }
503 }
504
505 /* chanops and voiced can flood their own channel with impunity */
506 if((result = can_send(chptr, source_p, NULL)))
507 {
508 if(result == CAN_SEND_OPV ||
509 !flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
510 {
511 sendto_channel_flags(client_p, ALL_MEMBERS, source_p, chptr,
512 "%s %s :%s", command, chptr->chname, text);
513 }
514 }
515 else if(chptr->mode.mode & MODE_OPMODERATE &&
59eedf15
JT
516 (!(chptr->mode.mode & MODE_NOPRIVMSGS) ||
517 IsMember(source_p, chptr)))
212380e3 518 {
212380e3 519 if(!flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
520 {
6ce8910d
JT
521 sendto_channel_opmod(client_p, source_p, chptr,
522 command, text);
523 }
524 }
525 else
526 {
527 if(p_or_n != NOTICE)
528 sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
529 form_str(ERR_CANNOTSENDTOCHAN), chptr->chname);
530 }
531}
532/*
533 * msg_channel_opmod
534 *
535 * inputs - flag privmsg or notice
536 * - pointer to command "PRIVMSG" or "NOTICE"
537 * - pointer to client_p
538 * - pointer to source_p
539 * - pointer to channel
540 * output - NONE
541 * side effects - message given channel ops
542 *
543 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
544 */
545static void
546msg_channel_opmod(int p_or_n, const char *command,
547 struct Client *client_p, struct Client *source_p,
548 struct Channel *chptr, const char *text)
549{
550 char text2[BUFSIZE];
551
552 if(chptr->mode.mode & MODE_NOCOLOR)
553 {
554 rb_strlcpy(text2, text, BUFSIZE);
555 strip_colour(text2);
556 text = text2;
557 if (EmptyString(text))
558 {
559 /* could be empty after colour stripping and
560 * that would cause problems later */
561 if(p_or_n != NOTICE)
562 sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
563 return;
564 }
565 }
566
567 if(chptr->mode.mode & MODE_OPMODERATE &&
568 (!(chptr->mode.mode & MODE_NOPRIVMSGS) ||
569 IsMember(source_p, chptr)))
570 {
571 if(!flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
572 {
573 sendto_channel_opmod(client_p, source_p, chptr,
574 command, text);
212380e3 575 }
576 }
577 else
578 {
579 if(p_or_n != NOTICE)
580 sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
581 form_str(ERR_CANNOTSENDTOCHAN), chptr->chname);
582 }
583}
584
585/*
586 * msg_channel_flags
587 *
588 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
589 * say NOTICE must not auto reply
590 * - pointer to command, "PRIVMSG" or "NOTICE"
591 * - pointer to client_p
592 * - pointer to source_p
593 * - pointer to channel
594 * - flags
595 * - pointer to text to send
596 * output - NONE
597 * side effects - message given channel either chanop or voice
598 */
599static void
600msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
601 struct Client *source_p, struct Channel *chptr, int flags, const char *text)
602{
603 int type;
604 char c;
605
606 if(flags & CHFL_VOICE)
607 {
608 type = ONLY_CHANOPSVOICED;
609 c = '+';
610 }
611 else
612 {
613 type = ONLY_CHANOPS;
614 c = '@';
615 }
616
617 if(MyClient(source_p))
618 {
619 /* idletime shouldnt be reset by notice --fl */
620 if(p_or_n != NOTICE)
9f6bbe3c 621 source_p->localClient->last = rb_current_time();
212380e3 622 }
623
624 sendto_channel_flags(client_p, type, source_p, chptr, "%s %c%s :%s",
625 command, c, chptr->chname, text);
626}
627
628#define PREV_FREE_TARGET(x) ((FREE_TARGET(x) == 0) ? 9 : FREE_TARGET(x) - 1)
629#define PREV_TARGET(i) ((i == 0) ? i = 9 : --i)
630#define NEXT_TARGET(i) ((i == 9) ? i = 0 : ++i)
631
632static void
633expire_tgchange(void *unused)
634{
635 tgchange *target;
90a3c35b 636 rb_dlink_node *ptr, *next_ptr;
212380e3 637
90a3c35b 638 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, tgchange_list.head)
212380e3 639 {
640 target = ptr->data;
641
9f6bbe3c 642 if(target->expiry < rb_current_time())
212380e3 643 {
31c047d7
WP
644 rb_dlinkDelete(ptr, &tgchange_list);
645 rb_patricia_remove(tgchange_tree, target->pnode);
a55e5724
VY
646 rb_free(target->ip);
647 rb_free(target);
212380e3 648 }
649 }
650}
651
58e8319c
VY
652static int
653add_target(struct Client *source_p, struct Client *target_p)
654{
655 int i, j;
656 uint32_t hashv;
657
658 /* can msg themselves or services without using any target slots */
659 if(source_p == target_p || IsService(target_p))
660 return 1;
661
662 /* special condition for those who have had PRIVMSG crippled to allow them
663 * to talk to IRCops still.
664 *
665 * XXX: is this controversial?
666 */
667 if(source_p->localClient->target_last > rb_current_time() && IsOper(target_p))
668 return 1;
669
670 hashv = fnv_hash_upper((const unsigned char *)use_id(target_p), 32);
671
672 if(USED_TARGETS(source_p))
673 {
674 /* hunt for an existing target */
675 for(i = PREV_FREE_TARGET(source_p), j = USED_TARGETS(source_p);
676 j; --j, PREV_TARGET(i))
677 {
678 if(source_p->localClient->targets[i] == hashv)
679 return 1;
680 }
681
682 /* first message after connect, we may only start clearing
683 * slots after this message --anfl
684 */
685 if(!IsTGChange(source_p))
686 {
687 SetTGChange(source_p);
688 source_p->localClient->target_last = rb_current_time();
689 }
690 /* clear as many targets as we can */
691 else if((i = (rb_current_time() - source_p->localClient->target_last) / 60))
692 {
693 if(i > USED_TARGETS(source_p))
694 USED_TARGETS(source_p) = 0;
695 else
696 USED_TARGETS(source_p) -= i;
697
698 source_p->localClient->target_last = rb_current_time();
699 }
700 /* cant clear any, full target list */
701 else if(USED_TARGETS(source_p) == 10)
702 {
83251205 703 ServerStats.is_tgch++;
58e8319c
VY
704 add_tgchange(source_p->sockhost);
705 return 0;
706 }
707 }
708 /* no targets in use, reset their target_last so that they cant
709 * abuse a long idle to get targets back more quickly
710 */
711 else
712 {
713 source_p->localClient->target_last = rb_current_time();
714 SetTGChange(source_p);
715 }
716
717 source_p->localClient->targets[FREE_TARGET(source_p)] = hashv;
718 NEXT_TARGET(FREE_TARGET(source_p));
719 ++USED_TARGETS(source_p);
720 return 1;
212380e3 721}
722
723/*
724 * msg_client
725 *
726 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
727 * say NOTICE must not auto reply
728 * - pointer to command, "PRIVMSG" or "NOTICE"
729 * - pointer to source_p source (struct Client *)
730 * - pointer to target_p target (struct Client *)
731 * - pointer to text
732 * output - NONE
733 * side effects - message given channel either chanop or voice
734 */
735static void
736msg_client(int p_or_n, const char *command,
737 struct Client *source_p, struct Client *target_p, const char *text)
738{
8acef9de
JT
739 int do_floodcount = 0;
740
212380e3 741 if(MyClient(source_p))
742 {
743 /* reset idle time for message only if its not to self
744 * and its not a notice */
745 if(p_or_n != NOTICE)
9f6bbe3c 746 source_p->localClient->last = rb_current_time();
212380e3 747
8acef9de
JT
748 /* auto cprivmsg/cnotice */
749 do_floodcount = !IsOper(source_p) &&
750 !find_allowing_channel(source_p, target_p);
751
212380e3 752 /* target change stuff, dont limit ctcp replies as that
753 * would allow people to start filling up random users
754 * targets just by ctcping them
755 */
756 if((p_or_n != NOTICE || *text != '\001') &&
8acef9de 757 ConfigFileEntry.target_change && do_floodcount)
212380e3 758 {
759 if(!add_target(source_p, target_p))
760 {
761 sendto_one(source_p, form_str(ERR_TARGCHANGE),
762 me.name, source_p->name, target_p->name);
763 return;
764 }
765 }
766 }
767 else if(source_p->from == target_p->from)
768 {
769 sendto_realops_snomask(SNO_DEBUG, L_ALL,
770 "Send message to %s[%s] dropped from %s(Fake Dir)",
771 target_p->name, target_p->from->name, source_p->name);
772 return;
773 }
774
775 if(MyConnect(source_p) && (p_or_n != NOTICE) && target_p->user && target_p->user->away)
776 sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY),
777 target_p->name, target_p->user->away);
778
779 if(MyClient(target_p))
780 {
781 /* XXX Controversial? allow opers always to send through a +g */
782 if(!IsServer(source_p) && (IsSetCallerId(target_p) ||
783 (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])))
784 {
785 /* Here is the anti-flood bot/spambot code -db */
786 if(accept_message(source_p, target_p) || IsOper(source_p))
787 {
788 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
789 source_p->name,
790 source_p->username,
791 source_p->host, command, target_p->name, text);
792 }
793 else if (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])
794 {
795 if (p_or_n != NOTICE)
796 sendto_one_numeric(source_p, ERR_NONONREG,
797 form_str(ERR_NONONREG),
798 target_p->name);
799 /* Only so opers can watch for floods */
8acef9de 800 if (do_floodcount)
dada366b 801 (void) flood_attack_client(p_or_n, source_p, target_p);
212380e3 802 }
803 else
804 {
805 /* check for accept, flag recipient incoming message */
806 if(p_or_n != NOTICE)
807 {
808 sendto_one_numeric(source_p, ERR_TARGUMODEG,
809 form_str(ERR_TARGUMODEG),
810 target_p->name);
811 }
812
813 if((target_p->localClient->last_caller_id_time +
9f6bbe3c 814 ConfigFileEntry.caller_id_wait) < rb_current_time())
212380e3 815 {
816 if(p_or_n != NOTICE)
817 sendto_one_numeric(source_p, RPL_TARGNOTIFY,
818 form_str(RPL_TARGNOTIFY),
819 target_p->name);
820
821 sendto_one(target_p, form_str(RPL_UMODEGMSG),
822 me.name, target_p->name, source_p->name,
823 source_p->username, source_p->host);
824
9f6bbe3c 825 target_p->localClient->last_caller_id_time = rb_current_time();
212380e3 826 }
827 /* Only so opers can watch for floods */
8acef9de 828 if (do_floodcount)
dada366b 829 (void) flood_attack_client(p_or_n, source_p, target_p);
212380e3 830 }
831 }
832 else
833 {
834 /* If the client is remote, we dont perform a special check for
835 * flooding.. as we wouldnt block their message anyway.. this means
836 * we dont give warnings.. we then check if theyre opered
837 * (to avoid flood warnings), lastly if theyre our client
838 * and flooding -- fl */
8acef9de 839 if(!do_floodcount ||
212380e3 840 !flood_attack_client(p_or_n, source_p, target_p))
841 sendto_anywhere(target_p, source_p, command, ":%s", text);
842 }
843 }
8acef9de 844 else if(!do_floodcount ||
212380e3 845 !flood_attack_client(p_or_n, source_p, target_p))
846 sendto_anywhere(target_p, source_p, command, ":%s", text);
847
848 return;
849}
850
8acef9de
JT
851static struct Channel *
852find_allowing_channel(struct Client *source_p, struct Client *target_p)
853{
854 rb_dlink_node *ptr;
855 struct membership *msptr;
856
857 RB_DLINK_FOREACH(ptr, source_p->user->channel.head)
858 {
859 msptr = ptr->data;
860 if (is_chanop_voiced(msptr) && IsMember(target_p, msptr->chptr))
861 return msptr->chptr;
862 }
863 return NULL;
864}
865
212380e3 866/*
867 * flood_attack_client
868 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
869 * say NOTICE must not auto reply
870 * - pointer to source Client
871 * - pointer to target Client
872 * output - 1 if target is under flood attack
873 * side effects - check for flood attack on target target_p
874 */
875static int
876flood_attack_client(int p_or_n, struct Client *source_p, struct Client *target_p)
877{
878 int delta;
879
dada366b
JT
880 /* Services could get many messages legitimately and
881 * can be messaged without rate limiting via aliases
882 * and msg user@server.
883 * -- jilles
884 */
885 if(GlobalSetOptions.floodcount && IsClient(source_p) && source_p != target_p && !IsService(target_p))
212380e3 886 {
dada366b 887 if((target_p->first_received_message_time + 1) < rb_current_time())
212380e3 888 {
dada366b
JT
889 delta = rb_current_time() - target_p->first_received_message_time;
890 target_p->received_number_of_privmsgs -= delta;
891 target_p->first_received_message_time = rb_current_time();
892 if(target_p->received_number_of_privmsgs <= 0)
212380e3 893 {
dada366b
JT
894 target_p->received_number_of_privmsgs = 0;
895 target_p->flood_noticed = 0;
212380e3 896 }
897 }
898
dada366b
JT
899 if((target_p->received_number_of_privmsgs >=
900 GlobalSetOptions.floodcount) || target_p->flood_noticed)
212380e3 901 {
dada366b 902 if(target_p->flood_noticed == 0)
212380e3 903 {
9f8d60cc 904 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
212380e3 905 "Possible Flooder %s[%s@%s] on %s target: %s",
906 source_p->name, source_p->username,
63aecfb9 907 source_p->orighost,
c88cdb00 908 source_p->servptr->name, target_p->name);
dada366b 909 target_p->flood_noticed = 1;
212380e3 910 /* add a bit of penalty */
dada366b 911 target_p->received_number_of_privmsgs += 2;
212380e3 912 }
913 if(MyClient(source_p) && (p_or_n != NOTICE))
914 sendto_one(source_p,
915 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
916 me.name, source_p->name, target_p->name);
917 return 1;
918 }
919 else
dada366b 920 target_p->received_number_of_privmsgs++;
212380e3 921 }
922
923 return 0;
924}
925
926/*
927 * flood_attack_channel
928 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
929 * says NOTICE must not auto reply
930 * - pointer to source Client
931 * - pointer to target channel
932 * output - 1 if target is under flood attack
933 * side effects - check for flood attack on target chptr
934 */
935static int
936flood_attack_channel(int p_or_n, struct Client *source_p, struct Channel *chptr, char *chname)
937{
938 int delta;
939
940 if(GlobalSetOptions.floodcount && MyClient(source_p))
941 {
9f6bbe3c 942 if((chptr->first_received_message_time + 1) < rb_current_time())
212380e3 943 {
9f6bbe3c 944 delta = rb_current_time() - chptr->first_received_message_time;
212380e3 945 chptr->received_number_of_privmsgs -= delta;
9f6bbe3c 946 chptr->first_received_message_time = rb_current_time();
212380e3 947 if(chptr->received_number_of_privmsgs <= 0)
948 {
949 chptr->received_number_of_privmsgs = 0;
950 chptr->flood_noticed = 0;
951 }
952 }
953
954 if((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
955 || chptr->flood_noticed)
956 {
957 if(chptr->flood_noticed == 0)
958 {
9f8d60cc 959 sendto_realops_snomask(SNO_BOTS, *chptr->chname == '&' ? L_ALL : L_NETWIDE,
212380e3 960 "Possible Flooder %s[%s@%s] on %s target: %s",
961 source_p->name, source_p->username,
63aecfb9 962 source_p->orighost,
c88cdb00 963 source_p->servptr->name, chptr->chname);
212380e3 964 chptr->flood_noticed = 1;
965
966 /* Add a bit of penalty */
967 chptr->received_number_of_privmsgs += 2;
968 }
969 if(MyClient(source_p) && (p_or_n != NOTICE))
970 sendto_one(source_p,
971 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
972 me.name, source_p->name, chptr->chname);
973 return 1;
974 }
975 else
976 chptr->received_number_of_privmsgs++;
977 }
978
979 return 0;
980}
981
982
983/*
984 * handle_special
985 *
986 * inputs - server pointer
987 * - client pointer
988 * - nick stuff to grok for opers
989 * - text to send if grok
990 * output - none
991 * side effects - all the traditional oper type messages are parsed here.
992 * i.e. "/msg #some.host."
993 * However, syntax has been changed.
994 * previous syntax "/msg #some.host.mask"
995 * now becomes "/msg $#some.host.mask"
996 * previous syntax of: "/msg $some.server.mask" remains
997 * This disambiguates the syntax.
998 */
999static void
1000handle_special(int p_or_n, const char *command, struct Client *client_p,
1001 struct Client *source_p, const char *nick, const char *text)
1002{
1003 struct Client *target_p;
212380e3 1004 char *server;
1005 char *s;
212380e3 1006
1007 /* user[%host]@server addressed?
1008 * NOTE: users can send to user@server, but not user%host@server
1009 * or opers@server
1010 */
1011 if((server = strchr(nick, '@')) != NULL)
1012 {
1013 if((target_p = find_server(source_p, server + 1)) == NULL)
1014 {
1015 sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
1016 form_str(ERR_NOSUCHSERVER), server + 1);
1017 return;
1018 }
1019
212380e3 1020 if(!IsOper(source_p))
1021 {
1022 if(strchr(nick, '%') || (strncmp(nick, "opers", 5) == 0))
1023 {
1024 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
1025 form_str(ERR_NOSUCHNICK), nick);
1026 return;
1027 }
1028 }
1029
1030 /* somewhere else.. */
1031 if(!IsMe(target_p))
1032 {
1033 sendto_one(target_p, ":%s %s %s :%s",
1034 get_id(source_p, target_p), command, nick, text);
1035 return;
1036 }
1037
212380e3 1038 /* Check if someones msg'ing opers@our.server */
ceac83d9 1039 if(strncmp(nick, "opers@", 6) == 0)
212380e3 1040 {
1041 sendto_realops_snomask(SNO_GENERAL, L_ALL, "To opers: From: %s: %s",
1042 source_p->name, text);
1043 return;
1044 }
1045
ceac83d9
JT
1046 /* This was not very useful except for bypassing certain
1047 * restrictions. Note that we still allow sending to
1048 * remote servers this way, for messaging pseudoservers
1049 * securely whether they have a service{} block or not.
1050 * -- jilles
212380e3 1051 */
ceac83d9
JT
1052 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
1053 form_str(ERR_NOSUCHNICK), nick);
1054 return;
212380e3 1055 }
1056
1057 /*
1058 * the following two cases allow masks in NOTICEs
1059 * (for OPERs only)
1060 *
1061 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
1062 */
1063 if(IsOper(source_p) && *nick == '$')
1064 {
1065 if((*(nick + 1) == '$' || *(nick + 1) == '#'))
1066 nick++;
1067 else if(MyOper(source_p))
1068 {
1069 sendto_one(source_p,
1070 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
1071 me.name, source_p->name, command, nick, nick);
1072 return;
1073 }
1074
c13a2d9a
JT
1075 if(MyClient(source_p) && !IsOperMassNotice(source_p))
1076 {
1077 sendto_one(source_p, form_str(ERR_NOPRIVS),
1078 me.name, source_p->name, "mass_notice");
1079 return;
1080 }
1081
212380e3 1082 if((s = strrchr(nick, '.')) == NULL)
1083 {
1084 sendto_one_numeric(source_p, ERR_NOTOPLEVEL,
1085 form_str(ERR_NOTOPLEVEL), nick);
1086 return;
1087 }
1088 while(*++s)
1089 if(*s == '.' || *s == '*' || *s == '?')
1090 break;
1091 if(*s == '*' || *s == '?')
1092 {
1093 sendto_one_numeric(source_p, ERR_WILDTOPLEVEL,
1094 form_str(ERR_WILDTOPLEVEL), nick);
1095 return;
1096 }
1097
1098 sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
1099 nick + 1,
1100 (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
1101 "%s $%s :%s", command, nick, text);
1102 return;
1103 }
1104}