/[svn]/ircd-hybrid-7.2/modules/core/m_message.c
ViewVC logotype

Contents of /ircd-hybrid-7.2/modules/core/m_message.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (show annotations)
Sun Oct 2 21:05:51 2005 UTC (14 years, 6 months ago) by lusky
File MIME type: text/x-chdr
File size: 29923 byte(s)
create 7.2 branch, we can move/rename it as needed.


1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * m_message.c: Sends a (PRIVMSG|NOTICE) message to a user or channel.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "handlers.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 "send.h"
34 #include "msg.h"
35 #include "parse.h"
36 #include "modules.h"
37 #include "channel.h"
38 #include "channel_mode.h"
39 #include "irc_string.h"
40 #include "hash.h"
41 #include "packet.h"
42
43 struct entity
44 {
45 void *ptr;
46 int type;
47 int flags;
48 };
49
50 static int build_target_list(int p_or_n, const char *command,
51 struct Client *client_p,
52 struct Client *source_p,
53 char *nicks_channels, char *text);
54
55 static int flood_attack_client(int p_or_n, struct Client *source_p,
56 struct Client *target_p);
57 static int flood_attack_channel(int p_or_n, struct Client *source_p,
58 struct Channel *chptr, char *chname);
59 static struct Client* find_userhost (char *, char *, int *);
60
61 #define ENTITY_NONE 0
62 #define ENTITY_CHANNEL 1
63 #define ENTITY_CHANOPS_ON_CHANNEL 2
64 #define ENTITY_CLIENT 3
65
66 static struct entity targets[512];
67 static int ntargets = 0;
68
69 static int duplicate_ptr(void *);
70
71 static void m_message(int, const char *, struct Client *,
72 struct Client *, int, char **);
73
74 static void m_privmsg(struct Client *, struct Client *, int, char **);
75 static void m_notice(struct Client *, struct Client *, int, char **);
76
77 static void msg_channel(int p_or_n, const char *command,
78 struct Client *client_p,
79 struct Client *source_p,
80 struct Channel *chptr, char *text);
81
82 static void msg_channel_flags(int p_or_n, const char *command,
83 struct Client *client_p,
84 struct Client *source_p,
85 struct Channel *chptr, int flags, char *text);
86
87 static void msg_client(int p_or_n, const char *command,
88 struct Client *source_p, struct Client *target_p,
89 char *text);
90
91 static void handle_special(int p_or_n, const char *command,
92 struct Client *client_p,
93 struct Client *source_p, char *nick, char *text);
94
95 struct Message privmsg_msgtab = {
96 "PRIVMSG", 0, 0, 1, 0, MFLG_SLOW | MFLG_UNREG, 0L,
97 {m_unregistered, m_privmsg, m_privmsg, m_ignore, m_privmsg, m_ignore}
98 };
99
100 struct Message notice_msgtab = {
101 "NOTICE", 0, 0, 1, 0, MFLG_SLOW, 0L,
102 {m_unregistered, m_notice, m_notice, m_ignore, m_notice, m_ignore}
103 };
104
105 #ifndef STATIC_MODULES
106 struct Callback *client_message;
107 struct Callback *channel_message;
108
109 void
110 _modinit(void)
111 {
112 mod_add_cmd(&privmsg_msgtab);
113 mod_add_cmd(&notice_msgtab);
114 client_message = register_callback("client_message", NULL);
115 channel_message = register_callback("channel_message", NULL);
116 }
117
118 void
119 _moddeinit(void)
120 {
121 mod_del_cmd(&privmsg_msgtab);
122 mod_del_cmd(&notice_msgtab);
123 }
124
125 const char *_version = "$Revision$";
126 #endif
127
128 /*
129 ** m_privmsg
130 **
131 ** massive cleanup
132 ** rev argv 6/91
133 **
134 ** Another massive cleanup Nov, 2000
135 ** (I don't think there is a single line left from 6/91. Maybe.)
136 ** m_privmsg and m_notice do basically the same thing.
137 ** in the original 2.8.2 code base, they were the same function
138 ** "m_message.c." When we did the great cleanup in conjuncton with bleep
139 ** of ircu fame, we split m_privmsg.c and m_notice.c.
140 ** I don't see the point of that now. Its harder to maintain, its
141 ** easier to introduce bugs into one version and not the other etc.
142 ** Really, the penalty of an extra function call isn't that big a deal folks.
143 ** -db Nov 13, 2000
144 **
145 */
146
147 #define PRIVMSG 0
148 #define NOTICE 1
149
150 static void
151 m_privmsg(struct Client *client_p, struct Client *source_p,
152 int parc, char *parv[])
153 {
154 /* servers have no reason to send privmsgs, yet sometimes there is cause
155 * for a notice.. (for example remote kline replies) --fl_
156 */
157 if (!IsClient(source_p))
158 return;
159
160 m_message(PRIVMSG, "PRIVMSG", client_p, source_p, parc, parv);
161 }
162
163 static void
164 m_notice(struct Client *client_p, struct Client *source_p,
165 int parc, char *parv[])
166 {
167 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 */
177 static void
178 m_message(int p_or_n, const char *command, struct Client *client_p,
179 struct Client *source_p, int parc, char *parv[])
180 {
181 int i;
182
183 if (parc < 2 || EmptyString(parv[1]))
184 {
185 if (p_or_n != NOTICE)
186 sendto_one(source_p, form_str(ERR_NORECIPIENT),
187 ID_or_name(&me, client_p),
188 ID_or_name(source_p, client_p), command);
189 return;
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),
196 ID_or_name(&me, client_p),
197 ID_or_name(source_p, client_p));
198 return;
199 }
200
201 /* Finish the flood grace period... */
202 if (MyClient(source_p) && !IsFloodDone(source_p))
203 #if 0
204 &&
205 irccmp(source_p->name, parv[1]) != 0) /* some dumb clients msg/notice themself
206 to determine lag to the server BEFORE
207 sending JOIN commands, and then flood
208 off because they left gracemode. -wiz */
209 /*
210 * Not our problem if they do this. -Michael
211 */
212 #endif
213 flood_endgrace(source_p);
214
215 if (build_target_list(p_or_n, command, client_p, source_p, parv[1],
216 parv[2]) < 0)
217 {
218 /* Sigh. We need to relay this command to the hub */
219 if (!ServerInfo.hub && (uplink != NULL))
220 sendto_one(uplink, ":%s %s %s :%s",
221 source_p->name, command, parv[1], parv[2]);
222 return;
223 }
224
225 for (i = 0; i < ntargets; i++)
226 {
227 switch (targets[i].type)
228 {
229 case ENTITY_CHANNEL:
230 msg_channel(p_or_n, command, client_p, source_p,
231 (struct Channel *)targets[i].ptr, parv[2]);
232 break;
233
234 case ENTITY_CHANOPS_ON_CHANNEL:
235 msg_channel_flags(p_or_n, command, client_p, source_p,
236 (struct Channel *)targets[i].ptr,
237 targets[i].flags, parv[2]);
238 break;
239
240 case ENTITY_CLIENT:
241 msg_client(p_or_n, command, source_p,
242 (struct Client *)targets[i].ptr, parv[2]);
243 break;
244 }
245 }
246 }
247
248 /* build_target_list()
249 *
250 * inputs - pointer to given client_p (server)
251 * - pointer to given source (oper/client etc.)
252 * - pointer to list of nicks/channels
253 * - pointer to table to place results
254 * - pointer to text (only used if source_p is an oper)
255 * output - number of valid entities
256 * side effects - target_table is modified to contain a list of
257 * pointers to channels or clients
258 * if source client is an oper
259 * all the classic old bizzare oper privmsg tricks
260 * are parsed and sent as is, if prefixed with $
261 * to disambiguate.
262 *
263 */
264 static int
265 build_target_list(int p_or_n, const char *command, struct Client *client_p,
266 struct Client *source_p, char *nicks_channels, char *text)
267 {
268 int type;
269 char *p, *nick, *target_list, ncbuf[IRCD_BUFSIZE];
270 struct Channel *chptr = NULL;
271 struct Client *target_p = NULL;
272
273 /* Sigh, we can't mutilate parv[1] incase we need it to send to a hub */
274 if (!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
275 {
276 strlcpy(ncbuf, nicks_channels, sizeof(ncbuf));
277 target_list = ncbuf;
278 }
279 else
280 target_list = nicks_channels; /* skip strcpy for non-lazyleafs */
281
282 ntargets = 0;
283
284 for (nick = strtoken(&p, target_list, ","); nick;
285 nick = strtoken(&p, NULL, ","))
286 {
287 char *with_prefix;
288 /*
289 * channels are privmsg'd a lot more than other clients, moved up
290 * here plain old channel msg?
291 */
292
293 if (IsChanPrefix(*nick))
294 {
295 /* ignore send of local channel to a server (should not happen) */
296 if (*nick == '&' && IsServer(client_p))
297 continue;
298
299 if ((chptr = hash_find_channel(nick)) != NULL)
300 {
301 if (!duplicate_ptr(chptr))
302 {
303 if (ntargets >= ConfigFileEntry.max_targets)
304 {
305 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
306 ID_or_name(&me, client_p),
307 ID_or_name(source_p, client_p), nick,
308 ConfigFileEntry.max_targets);
309 return (1);
310 }
311 targets[ntargets].ptr = (void *)chptr;
312 targets[ntargets++].type = ENTITY_CHANNEL;
313 }
314 }
315 else
316 {
317 if (!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
318 return -1;
319 else if (p_or_n != NOTICE)
320 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
321 ID_or_name(&me, client_p),
322 ID_or_name(source_p, client_p), nick);
323 }
324 continue;
325 }
326
327 /* look for a privmsg to another client */
328 if ((target_p = find_person(client_p, nick)) != NULL)
329 {
330 if (!duplicate_ptr(target_p))
331 {
332 if (ntargets >= ConfigFileEntry.max_targets)
333 {
334 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
335 ID_or_name(&me, client_p),
336 ID_or_name(source_p, client_p), nick,
337 ConfigFileEntry.max_targets);
338 return (1);
339 }
340 targets[ntargets].ptr = (void *)target_p;
341 targets[ntargets].type = ENTITY_CLIENT;
342 targets[ntargets++].flags = 0;
343 }
344 continue;
345 }
346
347 /* @#channel or +#channel message ? */
348
349 type = 0;
350 with_prefix = nick;
351 /* allow %+@ if someone wants to do that */
352 for (; ;)
353 {
354 if (*nick == '@')
355 type |= CHFL_CHANOP;
356 #ifdef HALFOPS
357 else if (*nick == '%')
358 type |= CHFL_CHANOP | CHFL_HALFOP;
359 #endif
360 else if (*nick == '+')
361 type |= CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE;
362 else
363 break;
364 nick++;
365 }
366
367 if (type != 0)
368 {
369 /* suggested by Mortiis */
370 if (*nick == '\0') /* if its a '\0' dump it, there is no recipient */
371 {
372 sendto_one(source_p, form_str(ERR_NORECIPIENT),
373 ID_or_name(&me, client_p),
374 ID_or_name(source_p, client_p), command);
375 continue;
376 }
377
378 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
379 * if the channel is found, fine, if not report an error
380 */
381
382 if ((chptr = hash_find_channel(nick)) != NULL)
383 {
384 if (!has_member_flags(find_channel_link(source_p, chptr),
385 CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
386 {
387 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
388 ID_or_name(&me, client_p),
389 ID_or_name(source_p, client_p), with_prefix);
390 return(-1);
391 }
392
393 if (!duplicate_ptr(chptr))
394 {
395 if (ntargets >= ConfigFileEntry.max_targets)
396 {
397 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
398 ID_or_name(&me, client_p),
399 ID_or_name(source_p, client_p), nick,
400 ConfigFileEntry.max_targets);
401 return(1);
402 }
403 targets[ntargets].ptr = (void *)chptr;
404 targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
405 targets[ntargets++].flags = type;
406 }
407 }
408 else
409 {
410 if (!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
411 return -1;
412 else if (p_or_n != NOTICE)
413 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
414 ID_or_name(&me, client_p),
415 ID_or_name(source_p, client_p), nick);
416 }
417 continue;
418 }
419
420 if ((*nick == '$') || strchr(nick, '@') != NULL)
421 {
422 handle_special(p_or_n, command, client_p, source_p, nick, text);
423 }
424 else
425 {
426 if (!ServerInfo.hub && (uplink != NULL) && IsCapable(uplink, CAP_LL))
427 return -1;
428 else if (p_or_n != NOTICE)
429 {
430 if (!IsDigit(*nick))
431 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
432 ID_or_name(&me, client_p),
433 ID_or_name(source_p, client_p), nick);
434 }
435 }
436 /* continue; */
437 }
438
439 return(1);
440 }
441
442 /* duplicate_ptr()
443 *
444 * inputs - pointer to check
445 * - pointer to table of entities
446 * - number of valid entities so far
447 * output - YES if duplicate pointer in table, NO if not.
448 * note, this does the canonize using pointers
449 * side effects - NONE
450 */
451 static int
452 duplicate_ptr(void *ptr)
453 {
454 int i;
455
456 for (i = 0; i < ntargets; i++)
457 {
458 if (targets[i].ptr == ptr)
459 return(1);
460 }
461
462 return(0);
463 }
464
465 /* msg_channel()
466 *
467 * inputs - flag privmsg or notice
468 * - pointer to command "PRIVMSG" or "NOTICE"
469 * - pointer to client_p
470 * - pointer to source_p
471 * - pointer to channel
472 * output - NONE
473 * side effects - message given channel
474 */
475 static void
476 msg_channel(int p_or_n, const char *command, struct Client *client_p,
477 struct Client *source_p, struct Channel *chptr, char *text)
478 {
479 int result;
480
481 if (MyClient(source_p))
482 {
483 /* idle time shouldnt be reset by notices --fl */
484 if (p_or_n != NOTICE)
485 source_p->localClient->last = CurrentTime;
486 }
487
488 #ifndef STATIC_MODULES
489 execute_callback(channel_message, source_p, chptr, text);
490 #endif
491
492 /* chanops and voiced can flood their own channel with impunity */
493 if ((result = can_send(chptr, source_p)))
494 {
495 if (result == CAN_SEND_OPV ||
496 !flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
497 {
498 sendto_channel_butone(client_p, source_p, chptr, command, ":%s", text);
499 }
500 }
501 else
502 {
503 if (p_or_n != NOTICE)
504 sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN),
505 ID_or_name(&me, client_p),
506 ID_or_name(source_p, client_p), chptr->chname);
507 }
508 }
509
510 /* msg_channel_flags()
511 *
512 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
513 * say NOTICE must not auto reply
514 * - pointer to command, "PRIVMSG" or "NOTICE"
515 * - pointer to client_p
516 * - pointer to source_p
517 * - pointer to channel
518 * - flags
519 * - pointer to text to send
520 * output - NONE
521 * side effects - message given channel either chanop or voice
522 */
523 static void
524 msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
525 struct Client *source_p, struct Channel *chptr,
526 int flags, char *text)
527 {
528 int type;
529 char c;
530
531 if (flags & CHFL_VOICE)
532 {
533 type = CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP;
534 c = '+';
535 }
536 #ifdef HALFOPS
537 else if (flags & CHFL_HALFOP)
538 {
539 type = CHFL_HALFOP|CHFL_CHANOP;
540 c = '%';
541 }
542 #endif
543 else
544 {
545 type = CHFL_CHANOP;
546 c = '@';
547 }
548
549 if (MyClient(source_p))
550 {
551 /* idletime shouldnt be reset by notice --fl */
552 if (p_or_n != NOTICE)
553 source_p->localClient->last = CurrentTime;
554
555 sendto_channel_local_butone(source_p, type, chptr, ":%s!%s@%s %s %c%s :%s",
556 source_p->name, source_p->username,
557 source_p->host, command, c, chptr->chname, text);
558 }
559 else
560 {
561 /*
562 * another good catch, lee. we never would echo to remote clients anyway,
563 * so use slightly less intensive sendto_channel_local()
564 */
565 sendto_channel_local(type, YES, chptr, ":%s!%s@%s %s %c%s :%s",
566 source_p->name, source_p->username,
567 source_p->host, command, c, chptr->chname, text);
568 }
569
570 if (chptr->chname[0] != '#')
571 return;
572
573 sendto_channel_remote(source_p, client_p, type, CAP_CHW, CAP_TS6, chptr,
574 ":%s %s %c%s :%s", source_p->name, command, c, chptr->chname, text);
575 sendto_channel_remote(source_p, client_p, type, CAP_CHW|CAP_TS6, NOCAPS, chptr,
576 ":%s %s %c%s :%s", ID(source_p), command, c, chptr->chname, text);
577 /* non CAP_CHW servers? */
578 }
579
580 /* msg_client()
581 *
582 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
583 * say NOTICE must not auto reply
584 * - pointer to command, "PRIVMSG" or "NOTICE"
585 * - pointer to source_p source (struct Client *)
586 * - pointer to target_p target (struct Client *)
587 * - pointer to text
588 * output - NONE
589 * side effects - message given channel either chanop or voice
590 */
591 static void
592 msg_client(int p_or_n, const char *command, struct Client *source_p,
593 struct Client *target_p, char *text)
594 {
595 if (MyClient(source_p))
596 {
597 /*
598 * reset idle time for message only if its not to self
599 * and its not a notice
600 * NOTE: Normally we really should reset their idletime
601 * if the are messaging themselves, but we have to go
602 * this way in order to prevent them to trick out
603 * idle-klines.
604 */
605 if ((p_or_n != NOTICE) && (source_p != target_p))
606 source_p->localClient->last = CurrentTime;
607 }
608
609 #ifndef STATIC_MODULES
610 execute_callback(client_message, source_p, target_p, text);
611 #endif
612
613 if (MyConnect(source_p) && (p_or_n != NOTICE) && target_p->away)
614 sendto_one(source_p, form_str(RPL_AWAY), me.name,
615 source_p->name, target_p->name, target_p->away);
616
617 if (MyClient(target_p))
618 {
619 if (!IsServer(source_p) && IsSetCallerId(target_p))
620 {
621 /* Here is the anti-flood bot/spambot code -db */
622 if (source_p == target_p || accept_message(source_p, target_p) ||
623 (IsOper(source_p) && (ConfigFileEntry.opers_bypass_callerid == 1)))
624 {
625 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
626 source_p->name, source_p->username,
627 source_p->host, command, target_p->name, text);
628 }
629 else
630 {
631 /* check for accept, flag recipient incoming message */
632 if (p_or_n != NOTICE)
633 sendto_one(source_p, form_str(ERR_TARGUMODEG),
634 ID_or_name(&me, source_p->from),
635 ID_or_name(source_p, source_p->from), target_p->name);
636
637 if ((target_p->localClient->last_caller_id_time +
638 ConfigFileEntry.caller_id_wait) < CurrentTime)
639 {
640 if (p_or_n != NOTICE)
641 sendto_one(source_p, form_str(RPL_TARGNOTIFY),
642 ID_or_name(&me, source_p->from),
643 ID_or_name(source_p, source_p->from), target_p->name);
644
645 sendto_one(target_p, form_str(RPL_UMODEGMSG),
646 me.name, target_p->name,
647 get_client_name(source_p, HIDE_IP));
648
649 target_p->localClient->last_caller_id_time = CurrentTime;
650
651 }
652 /* Only so opers can watch for floods */
653 flood_attack_client(p_or_n, source_p, target_p);
654 }
655 }
656 else
657 {
658 /* If the client is remote, we dont perform a special check for
659 * flooding.. as we wouldnt block their message anyway.. this means
660 * we dont give warnings.. we then check if theyre opered
661 * (to avoid flood warnings), lastly if theyre our client
662 * and flooding -- fl */
663 if (!MyClient(source_p) || IsOper(source_p) ||
664 (MyClient(source_p) &&
665 !flood_attack_client(p_or_n, source_p, target_p)))
666 sendto_anywhere(target_p, source_p, "%s %s :%s",
667 command, target_p->name, text);
668 }
669 }
670 else
671 /* The target is a remote user.. same things apply -- fl */
672 if (!MyClient(source_p) || IsOper(source_p) ||
673 (MyClient(source_p)
674 && !flood_attack_client(p_or_n, source_p, target_p)))
675 sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name,
676 text);
677 }
678
679 /* flood_attack_client()
680 *
681 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
682 * say NOTICE must not auto reply
683 * - pointer to source Client
684 * - pointer to target Client
685 * output - 1 if target is under flood attack
686 * side effects - check for flood attack on target target_p
687 */
688 static int
689 flood_attack_client(int p_or_n, struct Client *source_p,
690 struct Client *target_p)
691 {
692 int delta;
693
694 if (GlobalSetOptions.floodcount && MyConnect(target_p)
695 && IsClient(source_p) && !IsConfCanFlood(source_p))
696 {
697 if ((target_p->localClient->first_received_message_time + 1)
698 < CurrentTime)
699 {
700 delta =
701 CurrentTime - target_p->localClient->first_received_message_time;
702 target_p->localClient->received_number_of_privmsgs -= delta;
703 target_p->localClient->first_received_message_time = CurrentTime;
704 if (target_p->localClient->received_number_of_privmsgs <= 0)
705 {
706 target_p->localClient->received_number_of_privmsgs = 0;
707 target_p->localClient->flood_noticed = 0;
708 }
709 }
710
711 if ((target_p->localClient->received_number_of_privmsgs >=
712 GlobalSetOptions.floodcount) || target_p->localClient->flood_noticed)
713 {
714 if (target_p->localClient->flood_noticed == 0)
715 {
716 sendto_realops_flags(UMODE_BOTS, L_ALL,
717 "Possible Flooder %s on %s target: %s",
718 get_client_name(source_p, HIDE_IP),
719 source_p->servptr->name, target_p->name);
720 target_p->localClient->flood_noticed = 1;
721 /* add a bit of penalty */
722 target_p->localClient->received_number_of_privmsgs += 2;
723 }
724
725 if (MyClient(source_p) && (p_or_n != NOTICE))
726 sendto_one(source_p,
727 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
728 me.name, source_p->name, target_p->name);
729 return(1);
730 }
731 else
732 target_p->localClient->received_number_of_privmsgs++;
733 }
734
735 return(0);
736 }
737
738 /* flood_attack_channel()
739 *
740 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
741 * says NOTICE must not auto reply
742 * - pointer to source Client
743 * - pointer to target channel
744 * output - 1 if target is under flood attack
745 * side effects - check for flood attack on target chptr
746 */
747 static int
748 flood_attack_channel(int p_or_n, struct Client *source_p,
749 struct Channel *chptr, char *chname)
750 {
751 int delta;
752
753 if (GlobalSetOptions.floodcount && !IsConfCanFlood(source_p))
754 {
755 if ((chptr->first_received_message_time + 1) < CurrentTime)
756 {
757 delta = CurrentTime - chptr->first_received_message_time;
758 chptr->received_number_of_privmsgs -= delta;
759 chptr->first_received_message_time = CurrentTime;
760 if (chptr->received_number_of_privmsgs <= 0)
761 {
762 chptr->received_number_of_privmsgs = 0;
763 ClearFloodNoticed(chptr);
764 }
765 }
766
767 if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
768 || IsSetFloodNoticed(chptr))
769 {
770 if (!IsSetFloodNoticed(chptr))
771 {
772 sendto_realops_flags(UMODE_BOTS, L_ALL,
773 "Possible Flooder %s on %s target: %s",
774 get_client_name(source_p, HIDE_IP),
775 source_p->servptr->name, chptr->chname);
776 SetFloodNoticed(chptr);
777
778 /* Add a bit of penalty */
779 chptr->received_number_of_privmsgs += 2;
780 }
781 if (MyClient(source_p) && (p_or_n != NOTICE))
782 sendto_one(source_p,
783 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
784 me.name, source_p->name, chname);
785 return(1);
786 }
787 else
788 chptr->received_number_of_privmsgs++;
789 }
790
791 return(0);
792 }
793
794 /* handle_special()
795 *
796 * inputs - server pointer
797 * - client pointer
798 * - nick stuff to grok for opers
799 * - text to send if grok
800 * output - none
801 * side effects - old style username@server is handled here for non opers
802 * opers are allowed username%hostname@server
803 * all the traditional oper type messages are also parsed here.
804 * i.e. "/msg #some.host."
805 * However, syntax has been changed.
806 * previous syntax "/msg #some.host.mask"
807 * now becomes "/msg $#some.host.mask"
808 * previous syntax of: "/msg $some.server.mask" remains
809 * This disambiguates the syntax.
810 *
811 * XXX N.B. dalnet changed it to nick@server as have other servers.
812 * we will stick with tradition for now.
813 * - Dianora
814 */
815 static void
816 handle_special(int p_or_n, const char *command, struct Client *client_p,
817 struct Client *source_p, char *nick, char *text)
818 {
819 struct Client *target_p;
820 char *host;
821 char *server;
822 char *s;
823 int count;
824
825 /*
826 * user[%host]@server addressed?
827 */
828 if ((server = strchr(nick, '@')) != NULL)
829 {
830 count = 0;
831
832 if ((host = strchr(nick, '%')) && !IsOper(source_p))
833 {
834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
835 ID_or_name(&me, client_p),
836 ID_or_name(source_p, client_p));
837 return;
838 }
839
840 if ((target_p = find_server(server + 1)) != NULL)
841 {
842 if (!IsMe(target_p))
843 {
844 /*
845 * Not destined for a user on me :-(
846 */
847 sendto_one(target_p, ":%s %s %s :%s",
848 ID_or_name(source_p, target_p->from),
849 command, nick, text);
850 if ((p_or_n != NOTICE) && MyClient(source_p))
851 source_p->localClient->last = CurrentTime;
852 return;
853 }
854
855 *server = '\0';
856
857 if (host != NULL)
858 *host++ = '\0';
859
860 /* Check if someones msg'ing opers@our.server */
861 if (strcmp(nick, "opers") == 0)
862 {
863 if (!IsOper(source_p))
864 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
865 ID_or_name(&me, client_p),
866 ID_or_name(source_p, client_p));
867 else
868 sendto_realops_flags(UMODE_ALL, L_ALL, "To opers: From: %s: %s",
869 source_p->name, text);
870 return;
871 }
872
873 /*
874 * Look for users which match the destination host
875 * (no host == wildcard) and if one and one only is
876 * found connected to me, deliver message!
877 */
878 target_p = find_userhost(nick, host, &count);
879
880 if (target_p != NULL)
881 {
882 if (server != NULL)
883 *server = '@';
884 if (host != NULL)
885 *--host = '%';
886
887 if (count == 1)
888 {
889 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
890 source_p->name, source_p->username, source_p->host,
891 command, nick, text);
892 if ((p_or_n != NOTICE) && MyClient(source_p))
893 source_p->localClient->last = CurrentTime;
894 }
895 else
896 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
897 ID_or_name(&me, client_p),
898 ID_or_name(source_p, client_p), nick,
899 ConfigFileEntry.max_targets);
900 }
901 }
902 else if (server && *(server+1) && (target_p == NULL))
903 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
904 ID_or_name(&me, client_p),
905 ID_or_name(source_p, client_p), server+1);
906 else if (server && (target_p == NULL))
907 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
908 ID_or_name(&me, client_p),
909 ID_or_name(source_p, client_p), nick);
910 return;
911 }
912
913 if (!IsOper(source_p))
914 {
915 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
916 ID_or_name(&me, client_p),
917 ID_or_name(source_p, client_p));
918 return;
919 }
920
921 /*
922 * the following two cases allow masks in NOTICEs
923 * (for OPERs only)
924 *
925 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
926 */
927 if (*nick == '$')
928 {
929 if ((*(nick+1) == '$' || *(nick+1) == '#'))
930 nick++;
931 else if(MyOper(source_p))
932 {
933 sendto_one(source_p,
934 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
935 me.name, source_p->name, command, nick, nick);
936 return;
937 }
938
939 if ((s = strrchr(nick, '.')) == NULL)
940 {
941 sendto_one(source_p, form_str(ERR_NOTOPLEVEL),
942 me.name, source_p->name, nick);
943 return;
944 }
945
946 while (*++s)
947 if (*s == '.' || *s == '*' || *s == '?')
948 break;
949
950 if (*s == '*' || *s == '?')
951 {
952 sendto_one(source_p, form_str(ERR_WILDTOPLEVEL),
953 ID_or_name(&me, client_p),
954 ID_or_name(source_p, client_p), nick);
955 return;
956 }
957
958 sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
959 nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
960 "%s $%s :%s", command, nick, text);
961
962 if ((p_or_n != NOTICE) && MyClient(source_p))
963 source_p->localClient->last = CurrentTime;
964
965 return;
966 }
967 }
968
969 /*
970 * find_userhost - find a user@host (server or user).
971 * inputs - user name to look for
972 * - host name to look for
973 * - pointer to count of number of matches found
974 * outputs - pointer to client if found
975 * - count is updated
976 * side effects - none
977 *
978 */
979 static struct Client *
980 find_userhost(char *user, char *host, int *count)
981 {
982 struct Client *c2ptr;
983 struct Client *res = NULL;
984 dlink_node *lc2ptr;
985
986 *count = 0;
987
988 if (collapse(user) != NULL)
989 {
990 DLINK_FOREACH(lc2ptr, local_client_list.head)
991 {
992 c2ptr = lc2ptr->data;
993
994 if (!IsClient(c2ptr)) /* something other than a client */
995 continue;
996
997 if ((!host || match(host, c2ptr->host)) &&
998 irccmp(user, c2ptr->username) == 0)
999 {
1000 (*count)++;
1001 res = c2ptr;
1002 }
1003 }
1004 }
1005
1006 return(res);
1007 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.26