/[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 948 - (show annotations)
Tue Jul 21 17:34:06 2009 UTC (12 years, 2 months ago) by michael
File MIME type: text/x-chdr
File size: 29110 byte(s)
- lp64\llp64\ilp32 portability fixes

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 return;
218
219 for (i = 0; i < ntargets; i++)
220 {
221 switch (targets[i].type)
222 {
223 case ENTITY_CHANNEL:
224 msg_channel(p_or_n, command, client_p, source_p,
225 (struct Channel *)targets[i].ptr, parv[2]);
226 break;
227
228 case ENTITY_CHANOPS_ON_CHANNEL:
229 msg_channel_flags(p_or_n, command, client_p, source_p,
230 (struct Channel *)targets[i].ptr,
231 targets[i].flags, parv[2]);
232 break;
233
234 case ENTITY_CLIENT:
235 msg_client(p_or_n, command, source_p,
236 (struct Client *)targets[i].ptr, parv[2]);
237 break;
238 }
239 }
240 }
241
242 /* build_target_list()
243 *
244 * inputs - pointer to given client_p (server)
245 * - pointer to given source (oper/client etc.)
246 * - pointer to list of nicks/channels
247 * - pointer to table to place results
248 * - pointer to text (only used if source_p is an oper)
249 * output - number of valid entities
250 * side effects - target_table is modified to contain a list of
251 * pointers to channels or clients
252 * if source client is an oper
253 * all the classic old bizzare oper privmsg tricks
254 * are parsed and sent as is, if prefixed with $
255 * to disambiguate.
256 *
257 */
258 static int
259 build_target_list(int p_or_n, const char *command, struct Client *client_p,
260 struct Client *source_p, char *nicks_channels, char *text)
261 {
262 int type;
263 char *p = NULL, *nick, *target_list;
264 struct Channel *chptr = NULL;
265 struct Client *target_p = NULL;
266
267 target_list = nicks_channels;
268
269 ntargets = 0;
270
271 for (nick = strtoken(&p, target_list, ","); nick;
272 nick = strtoken(&p, NULL, ","))
273 {
274 char *with_prefix;
275 /*
276 * channels are privmsg'd a lot more than other clients, moved up
277 * here plain old channel msg?
278 */
279
280 if (IsChanPrefix(*nick))
281 {
282 /* ignore send of local channel to a server (should not happen) */
283 if (*nick == '&' && IsServer(client_p))
284 continue;
285
286 if ((chptr = hash_find_channel(nick)) != NULL)
287 {
288 if (!duplicate_ptr(chptr))
289 {
290 if (ntargets >= ConfigFileEntry.max_targets)
291 {
292 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
293 ID_or_name(&me, client_p),
294 ID_or_name(source_p, client_p), nick,
295 ConfigFileEntry.max_targets);
296 return (1);
297 }
298 targets[ntargets].ptr = (void *)chptr;
299 targets[ntargets++].type = ENTITY_CHANNEL;
300 }
301 }
302 else
303 {
304 if (p_or_n != NOTICE)
305 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
306 ID_or_name(&me, client_p),
307 ID_or_name(source_p, client_p), nick);
308 }
309 continue;
310 }
311
312 /* look for a privmsg to another client */
313 if ((target_p = find_person(client_p, nick)) != NULL)
314 {
315 if (!duplicate_ptr(target_p))
316 {
317 if (ntargets >= ConfigFileEntry.max_targets)
318 {
319 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
320 ID_or_name(&me, client_p),
321 ID_or_name(source_p, client_p), nick,
322 ConfigFileEntry.max_targets);
323 return (1);
324 }
325 targets[ntargets].ptr = (void *)target_p;
326 targets[ntargets].type = ENTITY_CLIENT;
327 targets[ntargets++].flags = 0;
328 }
329 continue;
330 }
331
332 /* @#channel or +#channel message ? */
333
334 type = 0;
335 with_prefix = nick;
336 /* allow %+@ if someone wants to do that */
337 for (; ;)
338 {
339 if (*nick == '@')
340 type |= CHFL_CHANOP;
341 #ifdef HALFOPS
342 else if (*nick == '%')
343 type |= CHFL_CHANOP | CHFL_HALFOP;
344 #endif
345 else if (*nick == '+')
346 type |= CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE;
347 else
348 break;
349 nick++;
350 }
351
352 if (type != 0)
353 {
354 /* suggested by Mortiis */
355 if (*nick == '\0') /* if its a '\0' dump it, there is no recipient */
356 {
357 sendto_one(source_p, form_str(ERR_NORECIPIENT),
358 ID_or_name(&me, client_p),
359 ID_or_name(source_p, client_p), command);
360 continue;
361 }
362
363 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
364 * if the channel is found, fine, if not report an error
365 */
366
367 if ((chptr = hash_find_channel(nick)) != NULL)
368 {
369 if (!has_member_flags(find_channel_link(source_p, chptr),
370 CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
371 {
372 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
373 ID_or_name(&me, client_p),
374 ID_or_name(source_p, client_p), with_prefix);
375 return(-1);
376 }
377
378 if (!duplicate_ptr(chptr))
379 {
380 if (ntargets >= ConfigFileEntry.max_targets)
381 {
382 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
383 ID_or_name(&me, client_p),
384 ID_or_name(source_p, client_p), nick,
385 ConfigFileEntry.max_targets);
386 return(1);
387 }
388 targets[ntargets].ptr = (void *)chptr;
389 targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
390 targets[ntargets++].flags = type;
391 }
392 }
393 else
394 {
395 if (p_or_n != NOTICE)
396 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
397 ID_or_name(&me, client_p),
398 ID_or_name(source_p, client_p), nick);
399 }
400 continue;
401 }
402
403 if ((*nick == '$') || strchr(nick, '@') != NULL)
404 {
405 handle_special(p_or_n, command, client_p, source_p, nick, text);
406 }
407 else
408 {
409 if (p_or_n != NOTICE)
410 {
411 if (!IsDigit(*nick) || MyClient(source_p))
412 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
413 ID_or_name(&me, client_p),
414 ID_or_name(source_p, client_p), nick);
415 }
416 }
417 /* continue; */
418 }
419
420 return(1);
421 }
422
423 /* duplicate_ptr()
424 *
425 * inputs - pointer to check
426 * - pointer to table of entities
427 * - number of valid entities so far
428 * output - YES if duplicate pointer in table, NO if not.
429 * note, this does the canonize using pointers
430 * side effects - NONE
431 */
432 static int
433 duplicate_ptr(void *ptr)
434 {
435 int i;
436
437 for (i = 0; i < ntargets; i++)
438 {
439 if (targets[i].ptr == ptr)
440 return(1);
441 }
442
443 return(0);
444 }
445
446 /* msg_channel()
447 *
448 * inputs - flag privmsg or notice
449 * - pointer to command "PRIVMSG" or "NOTICE"
450 * - pointer to client_p
451 * - pointer to source_p
452 * - pointer to channel
453 * output - NONE
454 * side effects - message given channel
455 */
456 static void
457 msg_channel(int p_or_n, const char *command, struct Client *client_p,
458 struct Client *source_p, struct Channel *chptr, char *text)
459 {
460 int result;
461
462 if (MyClient(source_p))
463 {
464 /* idle time shouldnt be reset by notices --fl */
465 if (p_or_n != NOTICE)
466 source_p->localClient->last = CurrentTime;
467 }
468
469 #ifndef STATIC_MODULES
470 execute_callback(channel_message, source_p, chptr, text);
471 #endif
472
473 /* chanops and voiced can flood their own channel with impunity */
474 if ((result = can_send(chptr, source_p, NULL)))
475 {
476 if (result == CAN_SEND_OPV ||
477 !flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
478 {
479 sendto_channel_butone(client_p, source_p, chptr, command, ":%s", text);
480 }
481 }
482 else
483 {
484 if (p_or_n != NOTICE)
485 sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN),
486 ID_or_name(&me, client_p),
487 ID_or_name(source_p, client_p), chptr->chname);
488 }
489 }
490
491 /* msg_channel_flags()
492 *
493 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
494 * say NOTICE must not auto reply
495 * - pointer to command, "PRIVMSG" or "NOTICE"
496 * - pointer to client_p
497 * - pointer to source_p
498 * - pointer to channel
499 * - flags
500 * - pointer to text to send
501 * output - NONE
502 * side effects - message given channel either chanop or voice
503 */
504 static void
505 msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
506 struct Client *source_p, struct Channel *chptr,
507 int flags, char *text)
508 {
509 int type;
510 char c;
511
512 if (flags & CHFL_VOICE)
513 {
514 type = CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP;
515 c = '+';
516 }
517 #ifdef HALFOPS
518 else if (flags & CHFL_HALFOP)
519 {
520 type = CHFL_HALFOP|CHFL_CHANOP;
521 c = '%';
522 }
523 #endif
524 else
525 {
526 type = CHFL_CHANOP;
527 c = '@';
528 }
529
530 if (MyClient(source_p))
531 {
532 /* idletime shouldnt be reset by notice --fl */
533 if (p_or_n != NOTICE)
534 source_p->localClient->last = CurrentTime;
535
536 sendto_channel_local_butone(source_p, type, chptr, ":%s!%s@%s %s %c%s :%s",
537 source_p->name, source_p->username,
538 source_p->host, command, c, chptr->chname, text);
539 }
540 else
541 {
542 /*
543 * another good catch, lee. we never would echo to remote clients anyway,
544 * so use slightly less intensive sendto_channel_local()
545 */
546 sendto_channel_local(type, YES, chptr, ":%s!%s@%s %s %c%s :%s",
547 source_p->name, source_p->username,
548 source_p->host, command, c, chptr->chname, text);
549 }
550
551 if (chptr->chname[0] != '#')
552 return;
553
554 sendto_channel_remote(source_p, client_p, type, CAP_CHW, CAP_TS6, chptr,
555 ":%s %s %c%s :%s", source_p->name, command, c, chptr->chname, text);
556 sendto_channel_remote(source_p, client_p, type, CAP_CHW|CAP_TS6, NOCAPS, chptr,
557 ":%s %s %c%s :%s", ID(source_p), command, c, chptr->chname, text);
558 /* non CAP_CHW servers? */
559 }
560
561 /* msg_client()
562 *
563 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
564 * say NOTICE must not auto reply
565 * - pointer to command, "PRIVMSG" or "NOTICE"
566 * - pointer to source_p source (struct Client *)
567 * - pointer to target_p target (struct Client *)
568 * - pointer to text
569 * output - NONE
570 * side effects - message given channel either chanop or voice
571 */
572 static void
573 msg_client(int p_or_n, const char *command, struct Client *source_p,
574 struct Client *target_p, char *text)
575 {
576 if (MyClient(source_p))
577 {
578 /*
579 * reset idle time for message only if its not to self
580 * and its not a notice
581 * NOTE: Normally we really should reset their idletime
582 * if the are messaging themselves, but we have to go
583 * this way in order to prevent them to trick out
584 * idle-klines.
585 */
586 if ((p_or_n != NOTICE) && (source_p != target_p))
587 source_p->localClient->last = CurrentTime;
588 }
589
590 #ifndef STATIC_MODULES
591 execute_callback(client_message, source_p, target_p, text);
592 #endif
593
594 if (MyConnect(source_p) && (p_or_n != NOTICE) && target_p->away)
595 sendto_one(source_p, form_str(RPL_AWAY), me.name,
596 source_p->name, target_p->name, target_p->away);
597
598 if (MyClient(target_p))
599 {
600 if (!IsServer(source_p) && IsSetCallerId(target_p))
601 {
602 /* Here is the anti-flood bot/spambot code -db */
603 if (source_p == target_p || accept_message(source_p, target_p) ||
604 (IsOper(source_p) && (ConfigFileEntry.opers_bypass_callerid == 1)))
605 {
606 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
607 source_p->name, source_p->username,
608 source_p->host, command, target_p->name, text);
609 }
610 else
611 {
612 /* check for accept, flag recipient incoming message */
613 if (p_or_n != NOTICE)
614 sendto_one(source_p, form_str(RPL_TARGUMODEG),
615 ID_or_name(&me, source_p->from),
616 ID_or_name(source_p, source_p->from), target_p->name);
617
618 if ((target_p->localClient->last_caller_id_time +
619 ConfigFileEntry.caller_id_wait) < CurrentTime)
620 {
621 if (p_or_n != NOTICE)
622 sendto_one(source_p, form_str(RPL_TARGNOTIFY),
623 ID_or_name(&me, source_p->from),
624 ID_or_name(source_p, source_p->from), target_p->name);
625
626 sendto_one(target_p, form_str(RPL_UMODEGMSG),
627 me.name, target_p->name,
628 get_client_name(source_p, HIDE_IP));
629
630 target_p->localClient->last_caller_id_time = CurrentTime;
631
632 }
633 /* Only so opers can watch for floods */
634 flood_attack_client(p_or_n, source_p, target_p);
635 }
636 }
637 else
638 {
639 /* If the client is remote, we dont perform a special check for
640 * flooding.. as we wouldnt block their message anyway.. this means
641 * we dont give warnings.. we then check if theyre opered
642 * (to avoid flood warnings), lastly if theyre our client
643 * and flooding -- fl */
644 if (!MyClient(source_p) || IsOper(source_p) ||
645 (MyClient(source_p) &&
646 !flood_attack_client(p_or_n, source_p, target_p)))
647 sendto_anywhere(target_p, source_p, "%s %s :%s",
648 command, target_p->name, text);
649 }
650 }
651 else
652 /* The target is a remote user.. same things apply -- fl */
653 if (!MyClient(source_p) || IsOper(source_p) ||
654 (MyClient(source_p)
655 && !flood_attack_client(p_or_n, source_p, target_p)))
656 sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name,
657 text);
658 }
659
660 /* flood_attack_client()
661 *
662 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
663 * say NOTICE must not auto reply
664 * - pointer to source Client
665 * - pointer to target Client
666 * output - 1 if target is under flood attack
667 * side effects - check for flood attack on target target_p
668 */
669 static int
670 flood_attack_client(int p_or_n, struct Client *source_p,
671 struct Client *target_p)
672 {
673 int delta;
674
675 if (GlobalSetOptions.floodcount && MyConnect(target_p)
676 && IsClient(source_p) && !IsConfCanFlood(source_p))
677 {
678 if ((target_p->localClient->first_received_message_time + 1)
679 < CurrentTime)
680 {
681 delta =
682 CurrentTime - target_p->localClient->first_received_message_time;
683 target_p->localClient->received_number_of_privmsgs -= delta;
684 target_p->localClient->first_received_message_time = CurrentTime;
685
686 if (target_p->localClient->received_number_of_privmsgs <= 0)
687 {
688 target_p->localClient->received_number_of_privmsgs = 0;
689 ClearMsgFloodNoticed(target_p);
690 }
691 }
692
693 if ((target_p->localClient->received_number_of_privmsgs >=
694 GlobalSetOptions.floodcount) || IsMsgFloodNoticed(target_p))
695 {
696 if (!IsMsgFloodNoticed(target_p))
697 {
698 sendto_realops_flags(UMODE_BOTS, L_ALL,
699 "Possible Flooder %s on %s target: %s",
700 get_client_name(source_p, HIDE_IP),
701 source_p->servptr->name, target_p->name);
702 SetMsgFloodNoticed(target_p);
703 /* add a bit of penalty */
704 target_p->localClient->received_number_of_privmsgs += 2;
705 }
706
707 if (MyClient(source_p) && (p_or_n != NOTICE))
708 sendto_one(source_p,
709 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
710 me.name, source_p->name, target_p->name);
711 return(1);
712 }
713 else
714 target_p->localClient->received_number_of_privmsgs++;
715 }
716
717 return(0);
718 }
719
720 /* flood_attack_channel()
721 *
722 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
723 * says NOTICE must not auto reply
724 * - pointer to source Client
725 * - pointer to target channel
726 * output - 1 if target is under flood attack
727 * side effects - check for flood attack on target chptr
728 */
729 static int
730 flood_attack_channel(int p_or_n, struct Client *source_p,
731 struct Channel *chptr, char *chname)
732 {
733 int delta;
734
735 if (GlobalSetOptions.floodcount && !IsConfCanFlood(source_p))
736 {
737 if ((chptr->first_received_message_time + 1) < CurrentTime)
738 {
739 delta = CurrentTime - chptr->first_received_message_time;
740 chptr->received_number_of_privmsgs -= delta;
741 chptr->first_received_message_time = CurrentTime;
742 if (chptr->received_number_of_privmsgs <= 0)
743 {
744 chptr->received_number_of_privmsgs = 0;
745 ClearFloodNoticed(chptr);
746 }
747 }
748
749 if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
750 || IsSetFloodNoticed(chptr))
751 {
752 if (!IsSetFloodNoticed(chptr))
753 {
754 sendto_realops_flags(UMODE_BOTS, L_ALL,
755 "Possible Flooder %s on %s target: %s",
756 get_client_name(source_p, HIDE_IP),
757 source_p->servptr->name, chptr->chname);
758 SetFloodNoticed(chptr);
759
760 /* Add a bit of penalty */
761 chptr->received_number_of_privmsgs += 2;
762 }
763 if (MyClient(source_p) && (p_or_n != NOTICE))
764 sendto_one(source_p,
765 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
766 me.name, source_p->name, chname);
767 return(1);
768 }
769 else
770 chptr->received_number_of_privmsgs++;
771 }
772
773 return(0);
774 }
775
776 /* handle_special()
777 *
778 * inputs - server pointer
779 * - client pointer
780 * - nick stuff to grok for opers
781 * - text to send if grok
782 * output - none
783 * side effects - old style username@server is handled here for non opers
784 * opers are allowed username%hostname@server
785 * all the traditional oper type messages are also parsed here.
786 * i.e. "/msg #some.host."
787 * However, syntax has been changed.
788 * previous syntax "/msg #some.host.mask"
789 * now becomes "/msg $#some.host.mask"
790 * previous syntax of: "/msg $some.server.mask" remains
791 * This disambiguates the syntax.
792 *
793 * XXX N.B. dalnet changed it to nick@server as have other servers.
794 * we will stick with tradition for now.
795 * - Dianora
796 */
797 static void
798 handle_special(int p_or_n, const char *command, struct Client *client_p,
799 struct Client *source_p, char *nick, char *text)
800 {
801 struct Client *target_p;
802 char *host;
803 char *server;
804 char *s;
805 int count;
806
807 /*
808 * user[%host]@server addressed?
809 */
810 if ((server = strchr(nick, '@')) != NULL)
811 {
812 count = 0;
813
814 if ((host = strchr(nick, '%')) && !IsOper(source_p))
815 {
816 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
817 ID_or_name(&me, client_p),
818 ID_or_name(source_p, client_p));
819 return;
820 }
821
822 if ((target_p = find_server(server + 1)) != NULL)
823 {
824 if (!IsMe(target_p))
825 {
826 /*
827 * Not destined for a user on me :-(
828 */
829 sendto_one(target_p, ":%s %s %s :%s",
830 ID_or_name(source_p, target_p->from),
831 command, nick, text);
832 if ((p_or_n != NOTICE) && MyClient(source_p))
833 source_p->localClient->last = CurrentTime;
834 return;
835 }
836
837 *server = '\0';
838
839 if (host != NULL)
840 *host++ = '\0';
841
842 /* Check if someones msg'ing opers@our.server */
843 if (strcmp(nick, "opers") == 0)
844 {
845 if (!IsOper(source_p))
846 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
847 ID_or_name(&me, client_p),
848 ID_or_name(source_p, client_p));
849 else
850 sendto_realops_flags(UMODE_ALL, L_ALL, "To opers: From: %s: %s",
851 source_p->name, text);
852 return;
853 }
854
855 /*
856 * Look for users which match the destination host
857 * (no host == wildcard) and if one and one only is
858 * found connected to me, deliver message!
859 */
860 target_p = find_userhost(nick, host, &count);
861
862 if (target_p != NULL)
863 {
864 if (server != NULL)
865 *server = '@';
866 if (host != NULL)
867 *--host = '%';
868
869 if (count == 1)
870 {
871 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
872 source_p->name, source_p->username, source_p->host,
873 command, nick, text);
874 if ((p_or_n != NOTICE) && MyClient(source_p))
875 source_p->localClient->last = CurrentTime;
876 }
877 else
878 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
879 ID_or_name(&me, client_p),
880 ID_or_name(source_p, client_p), nick,
881 ConfigFileEntry.max_targets);
882 }
883 }
884 else if (server && *(server+1) && (target_p == NULL))
885 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
886 ID_or_name(&me, client_p),
887 ID_or_name(source_p, client_p), server+1);
888 else if (server && (target_p == NULL))
889 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
890 ID_or_name(&me, client_p),
891 ID_or_name(source_p, client_p), nick);
892 return;
893 }
894
895 if (!IsOper(source_p))
896 {
897 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
898 ID_or_name(&me, client_p),
899 ID_or_name(source_p, client_p));
900 return;
901 }
902
903 /*
904 * the following two cases allow masks in NOTICEs
905 * (for OPERs only)
906 *
907 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
908 */
909 if (*nick == '$')
910 {
911 if ((*(nick+1) == '$' || *(nick+1) == '#'))
912 nick++;
913 else if(MyOper(source_p))
914 {
915 sendto_one(source_p,
916 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
917 me.name, source_p->name, command, nick, nick);
918 return;
919 }
920
921 if ((s = strrchr(nick, '.')) == NULL)
922 {
923 sendto_one(source_p, form_str(ERR_NOTOPLEVEL),
924 me.name, source_p->name, nick);
925 return;
926 }
927
928 while (*++s)
929 if (*s == '.' || *s == '*' || *s == '?')
930 break;
931
932 if (*s == '*' || *s == '?')
933 {
934 sendto_one(source_p, form_str(ERR_WILDTOPLEVEL),
935 ID_or_name(&me, client_p),
936 ID_or_name(source_p, client_p), nick);
937 return;
938 }
939
940 sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
941 nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
942 "%s $%s :%s", command, nick, text);
943
944 if ((p_or_n != NOTICE) && MyClient(source_p))
945 source_p->localClient->last = CurrentTime;
946
947 return;
948 }
949 }
950
951 /*
952 * find_userhost - find a user@host (server or user).
953 * inputs - user name to look for
954 * - host name to look for
955 * - pointer to count of number of matches found
956 * outputs - pointer to client if found
957 * - count is updated
958 * side effects - none
959 *
960 */
961 static struct Client *
962 find_userhost(char *user, char *host, int *count)
963 {
964 struct Client *c2ptr;
965 struct Client *res = NULL;
966 dlink_node *lc2ptr;
967
968 *count = 0;
969
970 if (collapse(user) != NULL)
971 {
972 DLINK_FOREACH(lc2ptr, local_client_list.head)
973 {
974 c2ptr = lc2ptr->data;
975
976 if (!IsClient(c2ptr)) /* something other than a client */
977 continue;
978
979 if ((!host || match(host, c2ptr->host)) &&
980 irccmp(user, c2ptr->username) == 0)
981 {
982 (*count)++;
983 res = c2ptr;
984 }
985 }
986 }
987
988 return(res);
989 }

Properties

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

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