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: 34
Committed: Sun Oct 2 21:05:51 2005 UTC (18 years, 5 months ago) by lusky
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/modules/core/m_message.c
File size: 29923 byte(s)
Log Message:
create 7.2 branch, we can move/rename it as needed.


File Contents

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

Properties

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