ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/core/m_message.c
Revision: 1176
Committed: Sun Aug 14 11:24:24 2011 UTC (12 years, 8 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/modules/core/m_message.c
File size: 28402 byte(s)
Log Message:
- remove idle-time klines
- rename LocalUser.last to LocalUser.last_privmsg
- m_message.c: reset source_p->last_privmsg even if a client is messaging itself


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_privmsg = 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_privmsg = 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 it's not a notice
560 */
561 if ((p_or_n != NOTICE))
562 source_p->localClient->last_privmsg = CurrentTime;
563
564 if ((p_or_n != NOTICE) && target_p->away)
565 sendto_one(source_p, form_str(RPL_AWAY), me.name,
566 source_p->name, target_p->name, target_p->away);
567
568 if (HasUMode(target_p, UMODE_REGONLY) && target_p != source_p)
569 {
570 if (!HasUMode(source_p, UMODE_REGISTERED|UMODE_OPER))
571 {
572 if (p_or_n != NOTICE)
573 sendto_one(source_p, form_str(ERR_NONONREG), me.name, source_p->name,
574 target_p->name);
575 return;
576 }
577 }
578 }
579
580 if (MyClient(target_p))
581 {
582 if (!IsServer(source_p) && IsSetCallerId(target_p))
583 {
584 /* Here is the anti-flood bot/spambot code -db */
585 if (accept_message(source_p, target_p) || IsService(source_p) ||
586 (IsOper(source_p) && (ConfigFileEntry.opers_bypass_callerid == 1)))
587 {
588 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
589 source_p->name, source_p->username,
590 source_p->host, command, target_p->name, text);
591 }
592 else
593 {
594 /* check for accept, flag recipient incoming message */
595 if (p_or_n != NOTICE)
596 sendto_one(source_p, form_str(RPL_TARGUMODEG),
597 ID_or_name(&me, source_p->from),
598 ID_or_name(source_p, source_p->from), target_p->name);
599
600 if ((target_p->localClient->last_caller_id_time +
601 ConfigFileEntry.caller_id_wait) < CurrentTime)
602 {
603 if (p_or_n != NOTICE)
604 sendto_one(source_p, form_str(RPL_TARGNOTIFY),
605 ID_or_name(&me, source_p->from),
606 ID_or_name(source_p, source_p->from), target_p->name);
607
608 sendto_one(target_p, form_str(RPL_UMODEGMSG),
609 me.name, target_p->name,
610 get_client_name(source_p, HIDE_IP));
611
612 target_p->localClient->last_caller_id_time = CurrentTime;
613
614 }
615 /* Only so opers can watch for floods */
616 flood_attack_client(p_or_n, source_p, target_p);
617 }
618 }
619 else
620 {
621 /* If the client is remote, we dont perform a special check for
622 * flooding.. as we wouldnt block their message anyway.. this means
623 * we dont give warnings.. we then check if theyre opered
624 * (to avoid flood warnings), lastly if theyre our client
625 * and flooding -- fl */
626 if (!MyClient(source_p) || IsOper(source_p) ||
627 (MyClient(source_p) &&
628 !flood_attack_client(p_or_n, source_p, target_p)))
629 sendto_anywhere(target_p, source_p, "%s %s :%s",
630 command, target_p->name, text);
631 }
632 }
633 else
634 /* The target is a remote user.. same things apply -- fl */
635 if (!MyClient(source_p) || IsOper(source_p) ||
636 (MyClient(source_p)
637 && !flood_attack_client(p_or_n, source_p, target_p)))
638 sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name,
639 text);
640 }
641
642 /* flood_attack_client()
643 *
644 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
645 * say NOTICE must not auto reply
646 * - pointer to source Client
647 * - pointer to target Client
648 * output - 1 if target is under flood attack
649 * side effects - check for flood attack on target target_p
650 */
651 static int
652 flood_attack_client(int p_or_n, struct Client *source_p,
653 struct Client *target_p)
654 {
655 int delta;
656
657 if (GlobalSetOptions.floodcount && MyConnect(target_p)
658 && IsClient(source_p) && !IsConfCanFlood(source_p))
659 {
660 if ((target_p->localClient->first_received_message_time + 1)
661 < CurrentTime)
662 {
663 delta =
664 CurrentTime - target_p->localClient->first_received_message_time;
665 target_p->localClient->received_number_of_privmsgs -= delta;
666 target_p->localClient->first_received_message_time = CurrentTime;
667
668 if (target_p->localClient->received_number_of_privmsgs <= 0)
669 {
670 target_p->localClient->received_number_of_privmsgs = 0;
671 ClearMsgFloodNoticed(target_p);
672 }
673 }
674
675 if ((target_p->localClient->received_number_of_privmsgs >=
676 GlobalSetOptions.floodcount) || IsMsgFloodNoticed(target_p))
677 {
678 if (!IsMsgFloodNoticed(target_p))
679 {
680 sendto_realops_flags(UMODE_BOTS, L_ALL,
681 "Possible Flooder %s on %s target: %s",
682 get_client_name(source_p, HIDE_IP),
683 source_p->servptr->name, target_p->name);
684 SetMsgFloodNoticed(target_p);
685 /* add a bit of penalty */
686 target_p->localClient->received_number_of_privmsgs += 2;
687 }
688
689 if (MyClient(source_p) && (p_or_n != NOTICE))
690 sendto_one(source_p,
691 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
692 me.name, source_p->name, target_p->name);
693 return(1);
694 }
695 else
696 target_p->localClient->received_number_of_privmsgs++;
697 }
698
699 return(0);
700 }
701
702 /* flood_attack_channel()
703 *
704 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
705 * says NOTICE must not auto reply
706 * - pointer to source Client
707 * - pointer to target channel
708 * output - 1 if target is under flood attack
709 * side effects - check for flood attack on target chptr
710 */
711 static int
712 flood_attack_channel(int p_or_n, struct Client *source_p,
713 struct Channel *chptr, char *chname)
714 {
715 int delta;
716
717 if (GlobalSetOptions.floodcount && !IsConfCanFlood(source_p))
718 {
719 if ((chptr->first_received_message_time + 1) < CurrentTime)
720 {
721 delta = CurrentTime - chptr->first_received_message_time;
722 chptr->received_number_of_privmsgs -= delta;
723 chptr->first_received_message_time = CurrentTime;
724 if (chptr->received_number_of_privmsgs <= 0)
725 {
726 chptr->received_number_of_privmsgs = 0;
727 ClearFloodNoticed(chptr);
728 }
729 }
730
731 if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
732 || IsSetFloodNoticed(chptr))
733 {
734 if (!IsSetFloodNoticed(chptr))
735 {
736 sendto_realops_flags(UMODE_BOTS, L_ALL,
737 "Possible Flooder %s on %s target: %s",
738 get_client_name(source_p, HIDE_IP),
739 source_p->servptr->name, chptr->chname);
740 SetFloodNoticed(chptr);
741
742 /* Add a bit of penalty */
743 chptr->received_number_of_privmsgs += 2;
744 }
745 if (MyClient(source_p) && (p_or_n != NOTICE))
746 sendto_one(source_p,
747 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
748 me.name, source_p->name, chname);
749 return(1);
750 }
751 else
752 chptr->received_number_of_privmsgs++;
753 }
754
755 return(0);
756 }
757
758 /* handle_special()
759 *
760 * inputs - server pointer
761 * - client pointer
762 * - nick stuff to grok for opers
763 * - text to send if grok
764 * output - none
765 * side effects - old style username@server is handled here for non opers
766 * opers are allowed username%hostname@server
767 * all the traditional oper type messages are also parsed here.
768 * i.e. "/msg #some.host."
769 * However, syntax has been changed.
770 * previous syntax "/msg #some.host.mask"
771 * now becomes "/msg $#some.host.mask"
772 * previous syntax of: "/msg $some.server.mask" remains
773 * This disambiguates the syntax.
774 *
775 * XXX N.B. dalnet changed it to nick@server as have other servers.
776 * we will stick with tradition for now.
777 * - Dianora
778 */
779 static void
780 handle_special(int p_or_n, const char *command, struct Client *client_p,
781 struct Client *source_p, char *nick, char *text)
782 {
783 struct Client *target_p;
784 char *host;
785 char *server;
786 char *s;
787 int count;
788
789 /*
790 * user[%host]@server addressed?
791 */
792 if ((server = strchr(nick, '@')) != NULL)
793 {
794 count = 0;
795
796 if ((host = strchr(nick, '%')) && !IsOper(source_p))
797 {
798 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
799 ID_or_name(&me, client_p),
800 ID_or_name(source_p, client_p));
801 return;
802 }
803
804 if ((target_p = hash_find_server(server + 1)) != NULL)
805 {
806 if (!IsMe(target_p))
807 {
808 /*
809 * Not destined for a user on me :-(
810 */
811 sendto_one(target_p, ":%s %s %s :%s",
812 ID_or_name(source_p, target_p->from),
813 command, nick, text);
814 if ((p_or_n != NOTICE) && MyClient(source_p))
815 source_p->localClient->last_privmsg = CurrentTime;
816 return;
817 }
818
819 *server = '\0';
820
821 if (host != NULL)
822 *host++ = '\0';
823
824 /* Check if someones msg'ing opers@our.server */
825 if (strcmp(nick, "opers") == 0)
826 {
827 if (!IsOper(source_p))
828 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
829 ID_or_name(&me, client_p),
830 ID_or_name(source_p, client_p));
831 else
832 sendto_realops_flags(UMODE_ALL, L_ALL, "To opers: From: %s: %s",
833 source_p->name, text);
834 return;
835 }
836
837 /*
838 * Look for users which match the destination host
839 * (no host == wildcard) and if one and one only is
840 * found connected to me, deliver message!
841 */
842 target_p = find_userhost(nick, host, &count);
843
844 if (target_p != NULL)
845 {
846 if (server != NULL)
847 *server = '@';
848 if (host != NULL)
849 *--host = '%';
850
851 if (count == 1)
852 {
853 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
854 source_p->name, source_p->username, source_p->host,
855 command, nick, text);
856 if ((p_or_n != NOTICE) && MyClient(source_p))
857 source_p->localClient->last_privmsg = CurrentTime;
858 }
859 else
860 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
861 ID_or_name(&me, client_p),
862 ID_or_name(source_p, client_p), nick,
863 ConfigFileEntry.max_targets);
864 }
865 }
866 else if (server && *(server+1) && (target_p == NULL))
867 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
868 ID_or_name(&me, client_p),
869 ID_or_name(source_p, client_p), server+1);
870 else if (server && (target_p == NULL))
871 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
872 ID_or_name(&me, client_p),
873 ID_or_name(source_p, client_p), nick);
874 return;
875 }
876
877 if (!IsOper(source_p))
878 {
879 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
880 ID_or_name(&me, client_p),
881 ID_or_name(source_p, client_p));
882 return;
883 }
884
885 /*
886 * the following two cases allow masks in NOTICEs
887 * (for OPERs only)
888 *
889 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
890 */
891 if (*nick == '$')
892 {
893 if ((*(nick+1) == '$' || *(nick+1) == '#'))
894 nick++;
895 else if(MyOper(source_p))
896 {
897 sendto_one(source_p,
898 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
899 me.name, source_p->name, command, nick, nick);
900 return;
901 }
902
903 if ((s = strrchr(nick, '.')) == NULL)
904 {
905 sendto_one(source_p, form_str(ERR_NOTOPLEVEL),
906 me.name, source_p->name, nick);
907 return;
908 }
909
910 while (*++s)
911 if (*s == '.' || *s == '*' || *s == '?')
912 break;
913
914 if (*s == '*' || *s == '?')
915 {
916 sendto_one(source_p, form_str(ERR_WILDTOPLEVEL),
917 ID_or_name(&me, client_p),
918 ID_or_name(source_p, client_p), nick);
919 return;
920 }
921
922 sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
923 nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
924 "%s $%s :%s", command, nick, text);
925
926 if ((p_or_n != NOTICE) && MyClient(source_p))
927 source_p->localClient->last_privmsg = CurrentTime;
928
929 return;
930 }
931 }
932
933 /*
934 * find_userhost - find a user@host (server or user).
935 * inputs - user name to look for
936 * - host name to look for
937 * - pointer to count of number of matches found
938 * outputs - pointer to client if found
939 * - count is updated
940 * side effects - none
941 *
942 */
943 static struct Client *
944 find_userhost(char *user, char *host, int *count)
945 {
946 struct Client *c2ptr;
947 struct Client *res = NULL;
948 dlink_node *lc2ptr;
949
950 *count = 0;
951
952 if (collapse(user) != NULL)
953 {
954 DLINK_FOREACH(lc2ptr, local_client_list.head)
955 {
956 c2ptr = lc2ptr->data;
957
958 if (!IsClient(c2ptr)) /* something other than a client */
959 continue;
960
961 if ((!host || match(host, c2ptr->host)) &&
962 irccmp(user, c2ptr->username) == 0)
963 {
964 (*count)++;
965 res = c2ptr;
966 }
967 }
968 }
969
970 return(res);
971 }

Properties

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