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