ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/core/m_message.c
Revision: 1243
Committed: Fri Sep 30 10:47:53 2011 UTC (12 years, 6 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/modules/core/m_message.c
File size: 28625 byte(s)
Log Message:
- move content of msg.h, ircd_handler.h and handlers.h into parse.h and
  remove headers accordingly
- killed common.h
- remove m_killhost.c and m_flags.c from contrib/
- sort out unused header includes here and there

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

Properties

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