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