ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_message.c
Revision: 1029
Committed: Sun Nov 8 13:10:50 2009 UTC (15 years, 9 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.3/modules/core/m_message.c
File size: 29128 byte(s)
Log Message:
- branch off trunk to create 7.3 branch

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

Properties

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