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