ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/modules/core/m_message.c
Revision: 1175
Committed: Sun Aug 14 10:47:48 2011 UTC (12 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 28599 byte(s)
Log Message:
- several fixes to services compatibility mode

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

Properties

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