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