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