ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_message.c
Revision: 948
Committed: Tue Jul 21 17:34:06 2009 UTC (17 years, 2 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/modules/core/m_message.c
File size: 29110 byte(s)
Log Message:
- lp64\llp64\ilp32 portability fixes

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     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 michael 885 char *p = NULL, *nick, *target_list;
264 adx 30 struct Channel *chptr = NULL;
265     struct Client *target_p = NULL;
266    
267 michael 885 target_list = nicks_channels;
268 adx 30
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 michael 885 if (p_or_n != NOTICE)
305 adx 30 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 michael 885 if (p_or_n != NOTICE)
396 adx 30 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 michael 885 if (p_or_n != NOTICE)
410 adx 30 {
411 michael 606 if (!IsDigit(*nick) || MyClient(source_p))
412 adx 30 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 michael 454 if ((result = can_send(chptr, source_p, NULL)))
475 adx 30 {
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 stu 666 sendto_one(source_p, form_str(RPL_TARGUMODEG),
615 adx 30 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 michael 948
686 adx 30 if (target_p->localClient->received_number_of_privmsgs <= 0)
687     {
688     target_p->localClient->received_number_of_privmsgs = 0;
689 michael 948 ClearMsgFloodNoticed(target_p);
690 adx 30 }
691     }
692    
693     if ((target_p->localClient->received_number_of_privmsgs >=
694 michael 948 GlobalSetOptions.floodcount) || IsMsgFloodNoticed(target_p))
695 adx 30 {
696 michael 948 if (!IsMsgFloodNoticed(target_p))
697 adx 30 {
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 michael 948 SetMsgFloodNoticed(target_p);
703 adx 30 /* 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