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

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

Properties

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