]> jfr.im git - irc/rqf/shadowircd.git/blame - modules/core/m_message.c
Filter bogus CTCP ACTION messages.
[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 *
212380e3 24 */
25
26#include "stdinc.h"
27#include "client.h"
28#include "ircd.h"
29#include "numeric.h"
30#include "common.h"
31#include "s_conf.h"
32#include "s_serv.h"
33#include "msg.h"
34#include "parse.h"
35#include "modules.h"
36#include "channel.h"
13ae2f4b 37#include "match.h"
212380e3 38#include "hash.h"
39#include "class.h"
40#include "msg.h"
41#include "packet.h"
42#include "send.h"
212380e3 43#include "s_newconf.h"
26f754d9 44#include "s_stats.h"
878733fd 45#include "tgchange.h"
7e8e21a4 46#include "inline/stringops.h"
75a9b0c8 47#include "irc_dictionary.h"
212380e3 48
49static int m_message(int, const char *, struct Client *, struct Client *, int, const char **);
50static int m_privmsg(struct Client *, struct Client *, int, const char **);
51static int m_notice(struct Client *, struct Client *, int, const char **);
52
53static void expire_tgchange(void *unused);
bfccb2c0 54static struct ev_entry *expire_tgchange_event;
212380e3 55
56static int
57modinit(void)
58{
bfccb2c0 59 expire_tgchange_event = rb_event_addish("expire_tgchange", expire_tgchange, NULL, 300);
212380e3 60 expire_tgchange(NULL);
61 return 0;
62}
63
64static void
65moddeinit(void)
66{
bfccb2c0 67 rb_event_delete(expire_tgchange_event);
212380e3 68}
69
70struct 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};
74struct 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
79mapi_clist_av1 message_clist[] = { &privmsg_msgtab, &notice_msgtab, NULL };
80
63aecfb9 81DECLARE_MODULE_AV1(message, modinit, moddeinit, message_clist, NULL, NULL, "$Revision: 3173 $");
212380e3 82
83struct entity
84{
85 void *ptr;
86 int type;
87 int flags;
88};
89
90static 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
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
fcda5662
JT
98/* Fifteen seconds should be plenty for a client to reply a ctcp */
99#define LARGE_CTCP_TIME 15
100
212380e3 101#define ENTITY_NONE 0
102#define ENTITY_CHANNEL 1
6ce8910d
JT
103#define ENTITY_CHANNEL_OPMOD 2
104#define ENTITY_CHANOPS_ON_CHANNEL 3
105#define ENTITY_CLIENT 4
212380e3 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
6ce8910d
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 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
6ce8910d
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 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
dcbd1d07 268 for(nick = rb_strtok_r(target_list, ",", &p); nick; nick = rb_strtok_r(NULL, ",", &p))
212380e3 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
7469e4b0 364 if(!IsServer(source_p) && !IsService(source_p) && !is_chanop_voiced(msptr))
212380e3 365 {
366 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
c925bc77
JT
367 get_id(&me, source_p),
368 get_id(source_p, source_p),
369 with_prefix);
212380e3 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
6ce8910d
JT
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
04bf0760
JT
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
212380e3 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];
b705a46f 487 size_t contor;
2b3c7c29
G
488 int caps = 0;
489 int len = 0;
5ad94b50 490 struct membership *msptr = find_channel_membership(chptr, source_p);
9a4dc29c 491 struct Metadata *md;
212380e3 492
493 if(MyClient(source_p))
494 {
495 /* idle time shouldnt be reset by notices --fl */
496 if(p_or_n != NOTICE)
9f6bbe3c 497 source_p->localClient->last = rb_current_time();
212380e3 498 }
499
90728edb 500 if(chptr->mode.mode & MODE_NOREPEAT)
9a4dc29c 501 {
e80126d0 502 rb_strlcpy(text2, text, BUFSIZE);
aa9a8067 503 strip_unprintable(text2);
9a4dc29c
G
504 md = channel_metadata_find(chptr, "NOREPEAT");
505 if(md && (!ConfigChannel.exempt_cmode_K || !is_any_op(msptr)))
506 {
e80126d0 507 if(!(strcmp(md->value, text2)))
9a4dc29c
G
508 {
509 if(p_or_n != NOTICE)
b6a3d801 510 sendto_one_numeric(source_p, 404, "%s :Cannot send to channel - Message blocked due to repeating (+K set)", chptr->chname);
9a4dc29c
G
511 return;
512 }
513 }
514 channel_metadata_delete(chptr, "NOREPEAT", 0);
e80126d0 515 channel_metadata_add(chptr, "NOREPEAT", text2, 0);
9a4dc29c
G
516 }
517
90728edb 518 if(chptr->mode.mode & MODE_NOCOLOR && (!ConfigChannel.exempt_cmode_c || !is_any_op(msptr)))
212380e3 519 {
907468c4 520 rb_strlcpy(text2, text, BUFSIZE);
212380e3 521 strip_colour(text2);
522 text = text2;
523 if (EmptyString(text))
524 {
525 /* could be empty after colour stripping and
526 * that would cause problems later */
527 if(p_or_n != NOTICE)
528 sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
529 return;
530 }
531 }
532
533 /* chanops and voiced can flood their own channel with impunity */
534 if((result = can_send(chptr, source_p, NULL)))
535 {
9e94d9ea
JT
536 if(result != CAN_SEND_OPV && MyClient(source_p) &&
537 !IsOper(source_p) &&
538 !add_channel_target(source_p, chptr))
539 {
540 sendto_one(source_p, form_str(ERR_TARGCHANGE),
541 me.name, source_p->name, chptr->chname);
542 return;
543 }
212380e3 544 if(result == CAN_SEND_OPV ||
545 !flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
546 {
90728edb 547 if (strlen(text) > 10 && chptr->mode.mode & MODE_NOCAPS && (!ConfigChannel.exempt_cmode_G || !is_any_op(msptr)))
2b3c7c29 548 {
aa9a8067
G
549 rb_strlcpy(text2, text, BUFSIZE);
550 strip_unprintable(text2);
551 for(contor=0; contor < strlen(text2); contor++)
2b3c7c29 552 {
aa9a8067 553 if(IsUpper(text2[contor]) && !isdigit(text2[contor]))
2b3c7c29
G
554 caps++;
555 len++;
556 }
829ce93f 557 /* Added divide by 0 check --alxbl */
558 if(len != 0 && ((caps*100)/(len)) >= 50)
2b3c7c29 559 {
b6a3d801 560 sendto_one_numeric(source_p, 404, "%s :Cannot send to channel - Your message contains mostly capital letters (+G set)", chptr->chname);
2b3c7c29
G
561 return;
562 }
563 }
90728edb 564 if (p_or_n != PRIVMSG && chptr->mode.mode & MODE_NONOTICE && (!ConfigChannel.exempt_cmode_T || !is_any_op(msptr)))
6afd4b91 565 {
b6a3d801 566 sendto_one_numeric(source_p, 404, "%s :Cannot send to channel - Notices are disallowed (+T set)", chptr->chname);
7e6c9180
G
567 return;
568 }
90728edb 569 if (p_or_n != NOTICE && chptr->mode.mode & MODE_NOACTION &&
5ad94b50
G
570 !strncasecmp(text + 1, "ACTION", 6) &&
571 (!ConfigChannel.exempt_cmode_D || !is_any_op(msptr)))
7e6c9180 572 {
b6a3d801 573 sendto_one_numeric(source_p, 404, "%s :Cannot send to channel - ACTIONs are disallowed (+D set)", chptr->chname);
6afd4b91
G
574 return;
575 }
343e2395 576 if (p_or_n != NOTICE && *text == '\001' &&
585e477b 577 strncasecmp(text + 1, "ACTION ", 7))
92a79951 578 {
90728edb 579 if (chptr->mode.mode & MODE_NOCTCP && (!ConfigChannel.exempt_cmode_C || !is_any_op(msptr)))
92a79951 580 {
b6a3d801 581 sendto_one_numeric(source_p, 404, "%s :Cannot send to channel - CTCPs to this channel are disallowed (+C set)", chptr->chname);
92a79951
WP
582 return;
583 }
584 else if (rb_dlink_list_length(&chptr->locmembers) > (unsigned)(GlobalSetOptions.floodcount / 2))
585 source_p->large_ctcp_sent = rb_current_time();
586 }
212380e3 587 sendto_channel_flags(client_p, ALL_MEMBERS, source_p, chptr,
588 "%s %s :%s", command, chptr->chname, text);
589 }
590 }
90728edb 591 else if(chptr->mode.mode & MODE_OPMODERATE &&
59eedf15
JT
592 (!(chptr->mode.mode & MODE_NOPRIVMSGS) ||
593 IsMember(source_p, chptr)))
212380e3 594 {
9e94d9ea
JT
595 if(MyClient(source_p) && !IsOper(source_p) &&
596 !add_channel_target(source_p, chptr))
597 {
598 sendto_one(source_p, form_str(ERR_TARGCHANGE),
599 me.name, source_p->name, chptr->chname);
600 return;
601 }
212380e3 602 if(!flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
603 {
6ce8910d
JT
604 sendto_channel_opmod(client_p, source_p, chptr,
605 command, text);
606 }
607 }
608 else
609 {
610 if(p_or_n != NOTICE)
611 sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
612 form_str(ERR_CANNOTSENDTOCHAN), chptr->chname);
613 }
614}
615/*
616 * msg_channel_opmod
617 *
618 * inputs - flag privmsg or notice
619 * - pointer to command "PRIVMSG" or "NOTICE"
620 * - pointer to client_p
621 * - pointer to source_p
622 * - pointer to channel
623 * output - NONE
624 * side effects - message given channel ops
625 *
626 * XXX - We need to rework this a bit, it's a tad ugly. --nenolod
627 */
628static void
629msg_channel_opmod(int p_or_n, const char *command,
630 struct Client *client_p, struct Client *source_p,
631 struct Channel *chptr, const char *text)
632{
633 char text2[BUFSIZE];
634
90728edb 635 if(chptr->mode.mode & MODE_NOCOLOR)
6ce8910d
JT
636 {
637 rb_strlcpy(text2, text, BUFSIZE);
638 strip_colour(text2);
639 text = text2;
640 if (EmptyString(text))
641 {
642 /* could be empty after colour stripping and
643 * that would cause problems later */
644 if(p_or_n != NOTICE)
645 sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
646 return;
647 }
648 }
649
90728edb 650 if(chptr->mode.mode & MODE_OPMODERATE &&
6ce8910d
JT
651 (!(chptr->mode.mode & MODE_NOPRIVMSGS) ||
652 IsMember(source_p, chptr)))
653 {
654 if(!flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
655 {
656 sendto_channel_opmod(client_p, source_p, chptr,
657 command, text);
212380e3 658 }
659 }
660 else
661 {
662 if(p_or_n != NOTICE)
663 sendto_one_numeric(source_p, ERR_CANNOTSENDTOCHAN,
664 form_str(ERR_CANNOTSENDTOCHAN), chptr->chname);
665 }
666}
667
668/*
669 * msg_channel_flags
670 *
671 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
672 * say NOTICE must not auto reply
673 * - pointer to command, "PRIVMSG" or "NOTICE"
674 * - pointer to client_p
675 * - pointer to source_p
676 * - pointer to channel
677 * - flags
678 * - pointer to text to send
679 * output - NONE
680 * side effects - message given channel either chanop or voice
681 */
682static void
683msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
684 struct Client *source_p, struct Channel *chptr, int flags, const char *text)
685{
686 int type;
687 char c;
688
689 if(flags & CHFL_VOICE)
690 {
691 type = ONLY_CHANOPSVOICED;
692 c = '+';
693 }
694 else
695 {
696 type = ONLY_CHANOPS;
697 c = '@';
698 }
699
700 if(MyClient(source_p))
701 {
702 /* idletime shouldnt be reset by notice --fl */
703 if(p_or_n != NOTICE)
9f6bbe3c 704 source_p->localClient->last = rb_current_time();
212380e3 705 }
706
707 sendto_channel_flags(client_p, type, source_p, chptr, "%s %c%s :%s",
708 command, c, chptr->chname, text);
709}
710
212380e3 711static void
712expire_tgchange(void *unused)
713{
714 tgchange *target;
90a3c35b 715 rb_dlink_node *ptr, *next_ptr;
212380e3 716
90a3c35b 717 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, tgchange_list.head)
212380e3 718 {
719 target = ptr->data;
720
9f6bbe3c 721 if(target->expiry < rb_current_time())
212380e3 722 {
31c047d7
WP
723 rb_dlinkDelete(ptr, &tgchange_list);
724 rb_patricia_remove(tgchange_tree, target->pnode);
a55e5724
VY
725 rb_free(target->ip);
726 rb_free(target);
212380e3 727 }
728 }
729}
730
212380e3 731/*
732 * msg_client
733 *
734 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
735 * say NOTICE must not auto reply
736 * - pointer to command, "PRIVMSG" or "NOTICE"
737 * - pointer to source_p source (struct Client *)
738 * - pointer to target_p target (struct Client *)
739 * - pointer to text
740 * output - NONE
741 * side effects - message given channel either chanop or voice
742 */
743static void
744msg_client(int p_or_n, const char *command,
745 struct Client *source_p, struct Client *target_p, const char *text)
746{
8acef9de 747 int do_floodcount = 0;
1fbf6db6 748 struct Metadata *md;
75a9b0c8 749 struct DictionaryIter iter;
1c646b89 750 int oaccept = 0;
2498a1b5 751 char text3[10];
8acef9de 752
212380e3 753 if(MyClient(source_p))
754 {
33736ea7
JH
755 /*
756 * XXX: Controversial? Allow target users to send replies
757 * through a +g. Rationale is that people can presently use +g
758 * as a way to taunt users, e.g. harass them and hide behind +g
759 * as a way of griefing. --nenolod
760 */
761 if(p_or_n != NOTICE && MyClient(source_p) &&
762 IsSetCallerId(source_p) &&
01b2be6f 763 IsSetSCallerId(source_p) &&
2588ff97 764 !accept_message(target_p, source_p))
33736ea7
JH
765 {
766 if(rb_dlink_list_length(&source_p->localClient->allow_list) <
767 ConfigFileEntry.max_accept)
768 {
769 rb_dlinkAddAlloc(target_p, &source_p->localClient->allow_list);
770 rb_dlinkAddAlloc(source_p, &target_p->on_allow_list);
771 }
772 else
773 {
774 sendto_one_numeric(source_p, ERR_OWNMODE,
775 form_str(ERR_OWNMODE),
776 target_p->name, "+g");
777 return;
778 }
779 }
780
212380e3 781 /* reset idle time for message only if its not to self
782 * and its not a notice */
783 if(p_or_n != NOTICE)
9f6bbe3c 784 source_p->localClient->last = rb_current_time();
212380e3 785
8acef9de
JT
786 /* auto cprivmsg/cnotice */
787 do_floodcount = !IsOper(source_p) &&
788 !find_allowing_channel(source_p, target_p);
789
212380e3 790 /* target change stuff, dont limit ctcp replies as that
791 * would allow people to start filling up random users
792 * targets just by ctcping them
793 */
794 if((p_or_n != NOTICE || *text != '\001') &&
8acef9de 795 ConfigFileEntry.target_change && do_floodcount)
212380e3 796 {
797 if(!add_target(source_p, target_p))
798 {
799 sendto_one(source_p, form_str(ERR_TARGCHANGE),
800 me.name, source_p->name, target_p->name);
801 return;
802 }
803 }
cb9345dc 804
fcda5662
JT
805 if (do_floodcount && p_or_n == NOTICE && *text == '\001' &&
806 target_p->large_ctcp_sent + LARGE_CTCP_TIME >= rb_current_time())
807 do_floodcount = 0;
808
cb9345dc
JT
809 if (do_floodcount &&
810 flood_attack_client(p_or_n, source_p, target_p))
811 return;
212380e3 812 }
813 else if(source_p->from == target_p->from)
814 {
815 sendto_realops_snomask(SNO_DEBUG, L_ALL,
816 "Send message to %s[%s] dropped from %s(Fake Dir)",
817 target_p->name, target_p->from->name, source_p->name);
818 return;
819 }
820
c387fc41 821 if(MyConnect(source_p) && (p_or_n != NOTICE) && target_p->user && target_p->user->away)
212380e3 822 sendto_one_numeric(source_p, RPL_AWAY, form_str(RPL_AWAY),
c387fc41 823 target_p->name, target_p->user->away);
212380e3 824
825 if(MyClient(target_p))
826 {
0099f31a
G
827 if (IsSetNoCTCP(target_p) && p_or_n != NOTICE && *text == '\001' && strncasecmp(text + 1, "ACTION", 6))
828 {
829 sendto_one_numeric(source_p, ERR_NOCTCP,
830 form_str(ERR_NOCTCP),
831 target_p->name);
832 }
1fbf6db6 833 /* If opers want to go through +g, they should load oaccept.*/
85465c43 834 else if(!IsServer(source_p) && !IsService(source_p) && (IsSetCallerId(target_p) ||
99c78094
G
835 (IsSetSCallerId(target_p) && !has_common_channel(source_p, target_p)) ||
836 (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])))
212380e3 837 {
1c646b89 838 if (IsOper(source_p))
1fbf6db6 839 {
2498a1b5 840 rb_snprintf(text3, sizeof(text3), "O%s", source_p->id);
75a9b0c8 841 DICTIONARY_FOREACH(md, &iter, target_p->user->metadata)
1fbf6db6 842 {
bc4764ae 843 if(!strcmp(md->value, "OACCEPT") && !strcmp(md->name, text3))
75a9b0c8 844 {
1c646b89 845 oaccept = 1;
75a9b0c8
G
846 break;
847 }
1fbf6db6
G
848 }
849 }
1c646b89
G
850 /* Here is the anti-flood bot/spambot code -db */
851 if(accept_message(source_p, target_p) || oaccept)
852 {
853 add_reply_target(target_p, source_p);
854 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
855 source_p->name,
856 source_p->username,
857 source_p->host, command, target_p->name, text);
858 }
99c78094 859 else if (IsSetRegOnlyMsg(target_p) && !source_p->user->suser[0])
212380e3 860 {
99c78094
G
861 if (p_or_n != NOTICE)
862 sendto_one_numeric(source_p, ERR_NONONREG,
863 form_str(ERR_NONONREG),
864 target_p->name);
61ffa214 865 }
99c78094 866 else if (IsSetSCallerId(target_p) && !has_common_channel(source_p, target_p))
61ffa214 867 {
99c78094
G
868 if (p_or_n != NOTICE)
869 sendto_one_numeric(source_p, ERR_NOCOMMONCHAN,
870 form_str(ERR_NOCOMMONCHAN),
871 target_p->name);
61ffa214 872 }
99c78094 873 else
212380e3 874 {
99c78094 875 /* check for accept, flag recipient incoming message */
212380e3 876 if(p_or_n != NOTICE)
99c78094
G
877 {
878 sendto_one_numeric(source_p, ERR_TARGUMODEG,
879 form_str(ERR_TARGUMODEG),
212380e3 880 target_p->name);
99c78094 881 }
212380e3 882
99c78094
G
883 if((target_p->localClient->last_caller_id_time +
884 ConfigFileEntry.caller_id_wait) < rb_current_time())
885 {
886 if(p_or_n != NOTICE)
887 sendto_one_numeric(source_p, RPL_TARGNOTIFY,
888 form_str(RPL_TARGNOTIFY),
889 target_p->name);
212380e3 890
99c78094
G
891 add_reply_target(target_p, source_p);
892 sendto_one(target_p, form_str(RPL_UMODEGMSG),
893 me.name, target_p->name, source_p->name,
894 source_p->username, source_p->host);
895
896 target_p->localClient->last_caller_id_time = rb_current_time();
897 }
212380e3 898 }
899 }
900 else
7eb93077
JT
901 {
902 add_reply_target(target_p, source_p);
cb9345dc 903 sendto_anywhere(target_p, source_p, command, ":%s", text);
7eb93077 904 }
212380e3 905 }
cb9345dc 906 else
212380e3 907 sendto_anywhere(target_p, source_p, command, ":%s", text);
908
909 return;
910}
911
912/*
913 * flood_attack_client
914 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
915 * say NOTICE must not auto reply
916 * - pointer to source Client
917 * - pointer to target Client
918 * output - 1 if target is under flood attack
919 * side effects - check for flood attack on target target_p
920 */
921static int
922flood_attack_client(int p_or_n, struct Client *source_p, struct Client *target_p)
923{
924 int delta;
925
dada366b
JT
926 /* Services could get many messages legitimately and
927 * can be messaged without rate limiting via aliases
928 * and msg user@server.
929 * -- jilles
930 */
6f7a78f6 931 if(GlobalSetOptions.floodcount && IsClient(source_p) && source_p != target_p && !IsService(target_p) && (!IsOper(source_p) || !ConfigFileEntry.true_no_oper_flood))
212380e3 932 {
dada366b 933 if((target_p->first_received_message_time + 1) < rb_current_time())
212380e3 934 {
dada366b
JT
935 delta = rb_current_time() - target_p->first_received_message_time;
936 target_p->received_number_of_privmsgs -= delta;
937 target_p->first_received_message_time = rb_current_time();
938 if(target_p->received_number_of_privmsgs <= 0)
212380e3 939 {
dada366b
JT
940 target_p->received_number_of_privmsgs = 0;
941 target_p->flood_noticed = 0;
212380e3 942 }
943 }
944
dada366b
JT
945 if((target_p->received_number_of_privmsgs >=
946 GlobalSetOptions.floodcount) || target_p->flood_noticed)
212380e3 947 {
dada366b 948 if(target_p->flood_noticed == 0)
212380e3 949 {
9f8d60cc 950 sendto_realops_snomask(SNO_BOTS, L_NETWIDE,
212380e3 951 "Possible Flooder %s[%s@%s] on %s target: %s",
952 source_p->name, source_p->username,
63aecfb9 953 source_p->orighost,
c88cdb00 954 source_p->servptr->name, target_p->name);
dada366b 955 target_p->flood_noticed = 1;
212380e3 956 /* add a bit of penalty */
dada366b 957 target_p->received_number_of_privmsgs += 2;
212380e3 958 }
959 if(MyClient(source_p) && (p_or_n != NOTICE))
960 sendto_one(source_p,
961 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
962 me.name, source_p->name, target_p->name);
963 return 1;
964 }
965 else
dada366b 966 target_p->received_number_of_privmsgs++;
212380e3 967 }
968
969 return 0;
970}
971
972/*
973 * flood_attack_channel
974 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
975 * says NOTICE must not auto reply
976 * - pointer to source Client
977 * - pointer to target channel
978 * output - 1 if target is under flood attack
979 * side effects - check for flood attack on target chptr
980 */
981static int
982flood_attack_channel(int p_or_n, struct Client *source_p, struct Channel *chptr, char *chname)
983{
984 int delta;
985
6f7a78f6 986 if(GlobalSetOptions.floodcount && MyClient(source_p) && (!IsOper(source_p) || !ConfigFileEntry.true_no_oper_flood))
212380e3 987 {
9f6bbe3c 988 if((chptr->first_received_message_time + 1) < rb_current_time())
212380e3 989 {
9f6bbe3c 990 delta = rb_current_time() - chptr->first_received_message_time;
212380e3 991 chptr->received_number_of_privmsgs -= delta;
9f6bbe3c 992 chptr->first_received_message_time = rb_current_time();
212380e3 993 if(chptr->received_number_of_privmsgs <= 0)
994 {
995 chptr->received_number_of_privmsgs = 0;
996 chptr->flood_noticed = 0;
997 }
998 }
999
1000 if((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
1001 || chptr->flood_noticed)
1002 {
1003 if(chptr->flood_noticed == 0)
1004 {
9f8d60cc 1005 sendto_realops_snomask(SNO_BOTS, *chptr->chname == '&' ? L_ALL : L_NETWIDE,
212380e3 1006 "Possible Flooder %s[%s@%s] on %s target: %s",
1007 source_p->name, source_p->username,
63aecfb9 1008 source_p->orighost,
c88cdb00 1009 source_p->servptr->name, chptr->chname);
212380e3 1010 chptr->flood_noticed = 1;
1011
1012 /* Add a bit of penalty */
1013 chptr->received_number_of_privmsgs += 2;
1014 }
1015 if(MyClient(source_p) && (p_or_n != NOTICE))
1016 sendto_one(source_p,
1017 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
1018 me.name, source_p->name, chptr->chname);
1019 return 1;
1020 }
1021 else
1022 chptr->received_number_of_privmsgs++;
1023 }
1024
1025 return 0;
1026}
1027
1028
1029/*
1030 * handle_special
1031 *
1032 * inputs - server pointer
1033 * - client pointer
1034 * - nick stuff to grok for opers
1035 * - text to send if grok
1036 * output - none
1037 * side effects - all the traditional oper type messages are parsed here.
1038 * i.e. "/msg #some.host."
1039 * However, syntax has been changed.
1040 * previous syntax "/msg #some.host.mask"
1041 * now becomes "/msg $#some.host.mask"
1042 * previous syntax of: "/msg $some.server.mask" remains
1043 * This disambiguates the syntax.
1044 */
1045static void
1046handle_special(int p_or_n, const char *command, struct Client *client_p,
1047 struct Client *source_p, const char *nick, const char *text)
1048{
1049 struct Client *target_p;
212380e3 1050 char *server;
1051 char *s;
212380e3 1052
1053 /* user[%host]@server addressed?
1054 * NOTE: users can send to user@server, but not user%host@server
1055 * or opers@server
1056 */
1057 if((server = strchr(nick, '@')) != NULL)
1058 {
1059 if((target_p = find_server(source_p, server + 1)) == NULL)
1060 {
1061 sendto_one_numeric(source_p, ERR_NOSUCHSERVER,
1062 form_str(ERR_NOSUCHSERVER), server + 1);
1063 return;
1064 }
1065
212380e3 1066 if(!IsOper(source_p))
1067 {
1068 if(strchr(nick, '%') || (strncmp(nick, "opers", 5) == 0))
1069 {
1070 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
1071 form_str(ERR_NOSUCHNICK), nick);
1072 return;
1073 }
1074 }
1075
1076 /* somewhere else.. */
1077 if(!IsMe(target_p))
1078 {
1079 sendto_one(target_p, ":%s %s %s :%s",
1080 get_id(source_p, target_p), command, nick, text);
1081 return;
1082 }
1083
212380e3 1084 /* Check if someones msg'ing opers@our.server */
ceac83d9 1085 if(strncmp(nick, "opers@", 6) == 0)
212380e3 1086 {
1087 sendto_realops_snomask(SNO_GENERAL, L_ALL, "To opers: From: %s: %s",
1088 source_p->name, text);
1089 return;
1090 }
1091
ceac83d9
JT
1092 /* This was not very useful except for bypassing certain
1093 * restrictions. Note that we still allow sending to
1094 * remote servers this way, for messaging pseudoservers
1095 * securely whether they have a service{} block or not.
1096 * -- jilles
212380e3 1097 */
ceac83d9
JT
1098 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
1099 form_str(ERR_NOSUCHNICK), nick);
1100 return;
212380e3 1101 }
1102
1103 /*
1104 * the following two cases allow masks in NOTICEs
1105 * (for OPERs only)
1106 *
1107 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
1108 */
1109 if(IsOper(source_p) && *nick == '$')
1110 {
1111 if((*(nick + 1) == '$' || *(nick + 1) == '#'))
1112 nick++;
1113 else if(MyOper(source_p))
1114 {
1115 sendto_one(source_p,
1116 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
1117 me.name, source_p->name, command, nick, nick);
1118 return;
1119 }
1120
c13a2d9a
JT
1121 if(MyClient(source_p) && !IsOperMassNotice(source_p))
1122 {
1123 sendto_one(source_p, form_str(ERR_NOPRIVS),
1124 me.name, source_p->name, "mass_notice");
1125 return;
1126 }
1127
212380e3 1128 if((s = strrchr(nick, '.')) == NULL)
1129 {
1130 sendto_one_numeric(source_p, ERR_NOTOPLEVEL,
1131 form_str(ERR_NOTOPLEVEL), nick);
1132 return;
1133 }
1134 while(*++s)
1135 if(*s == '.' || *s == '*' || *s == '?')
1136 break;
1137 if(*s == '*' || *s == '?')
1138 {
1139 sendto_one_numeric(source_p, ERR_WILDTOPLEVEL,
1140 form_str(ERR_WILDTOPLEVEL), nick);
1141 return;
1142 }
1143
1144 sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
1145 nick + 1,
1146 (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
1147 "%s $%s :%s", command, nick, text);
fcda5662
JT
1148 if (p_or_n != NOTICE && *text == '\001')
1149 source_p->large_ctcp_sent = rb_current_time();
212380e3 1150 return;
1151 }
1152}