ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/modules/core/m_message.c
Revision: 1029
Committed: Sun Nov 8 13:10:50 2009 UTC (14 years, 5 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.3/modules/core/m_message.c
File size: 29128 byte(s)
Log Message:
- branch off trunk to create 7.3 branch

File Contents

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

Properties

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