ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/modules/core/m_message.c
Revision: 273
Committed: Mon Nov 14 23:17:02 2005 UTC (20 years, 8 months ago) by adx
Content type: text/x-csrc
File size: 30712 byte(s)
Log Message:
+ another slight fix for /msg nick@server,nick@server bug

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

Properties

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