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