ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_message.c
Revision: 1954
Committed: Mon May 6 18:51:19 2013 UTC (13 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 27727 byte(s)
Log Message:
- Implemented channel mode +M. Clients that haven't identified their
  name with NickServ may not speak in a channel that has this mode set

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 michael 1309 #include "conf.h"
31 adx 30 #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 michael 1480 struct Channel *chptr);
58 adx 30 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 michael 1834 sendto_one(source_p, form_str(ERR_NORECIPIENT),
150 adx 30 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 michael 1834 sendto_one(source_p, form_str(ERR_NOTEXTTOSEND),
159 adx 30 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     if ((chptr = hash_find_channel(nick)) != NULL)
236     {
237     if (!duplicate_ptr(chptr))
238     {
239     if (ntargets >= ConfigFileEntry.max_targets)
240     {
241 michael 1834 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
242 adx 30 ID_or_name(&me, client_p),
243     ID_or_name(source_p, client_p), nick,
244     ConfigFileEntry.max_targets);
245     return (1);
246     }
247     targets[ntargets].ptr = (void *)chptr;
248     targets[ntargets++].type = ENTITY_CHANNEL;
249     }
250     }
251     else
252     {
253 michael 885 if (p_or_n != NOTICE)
254 michael 1834 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
255 adx 30 ID_or_name(&me, client_p),
256     ID_or_name(source_p, client_p), nick);
257     }
258     continue;
259     }
260    
261     /* look for a privmsg to another client */
262     if ((target_p = find_person(client_p, nick)) != NULL)
263     {
264     if (!duplicate_ptr(target_p))
265     {
266     if (ntargets >= ConfigFileEntry.max_targets)
267     {
268 michael 1834 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
269 adx 30 ID_or_name(&me, client_p),
270     ID_or_name(source_p, client_p), nick,
271     ConfigFileEntry.max_targets);
272     return (1);
273     }
274     targets[ntargets].ptr = (void *)target_p;
275     targets[ntargets].type = ENTITY_CLIENT;
276     targets[ntargets++].flags = 0;
277     }
278     continue;
279     }
280    
281     /* @#channel or +#channel message ? */
282    
283     type = 0;
284     with_prefix = nick;
285     /* allow %+@ if someone wants to do that */
286     for (; ;)
287     {
288     if (*nick == '@')
289     type |= CHFL_CHANOP;
290     #ifdef HALFOPS
291     else if (*nick == '%')
292     type |= CHFL_CHANOP | CHFL_HALFOP;
293     #endif
294     else if (*nick == '+')
295     type |= CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE;
296     else
297     break;
298     nick++;
299     }
300    
301     if (type != 0)
302     {
303     /* suggested by Mortiis */
304     if (*nick == '\0') /* if its a '\0' dump it, there is no recipient */
305     {
306 michael 1834 sendto_one(source_p, form_str(ERR_NORECIPIENT),
307 adx 30 ID_or_name(&me, client_p),
308     ID_or_name(source_p, client_p), command);
309     continue;
310     }
311    
312     /* At this point, nick+1 should be a channel name i.e. #foo or &foo
313     * if the channel is found, fine, if not report an error
314     */
315    
316     if ((chptr = hash_find_channel(nick)) != NULL)
317     {
318 michael 1478 if (IsClient(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
319 adx 30 {
320 michael 1478 if (!has_member_flags(find_channel_link(source_p, chptr),
321     CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
322     {
323 michael 1834 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
324 michael 1478 ID_or_name(&me, client_p),
325     ID_or_name(source_p, client_p), with_prefix);
326     return(-1);
327     }
328 adx 30 }
329    
330     if (!duplicate_ptr(chptr))
331     {
332     if (ntargets >= ConfigFileEntry.max_targets)
333     {
334 michael 1834 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
335 adx 30 ID_or_name(&me, client_p),
336     ID_or_name(source_p, client_p), nick,
337     ConfigFileEntry.max_targets);
338     return(1);
339     }
340     targets[ntargets].ptr = (void *)chptr;
341     targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
342     targets[ntargets++].flags = type;
343     }
344     }
345     else
346     {
347 michael 885 if (p_or_n != NOTICE)
348 michael 1834 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
349 adx 30 ID_or_name(&me, client_p),
350     ID_or_name(source_p, client_p), nick);
351     }
352     continue;
353     }
354    
355     if ((*nick == '$') || strchr(nick, '@') != NULL)
356     {
357     handle_special(p_or_n, command, client_p, source_p, nick, text);
358     }
359     else
360     {
361 michael 885 if (p_or_n != NOTICE)
362 adx 30 {
363 michael 606 if (!IsDigit(*nick) || MyClient(source_p))
364 michael 1834 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
365 adx 30 ID_or_name(&me, client_p),
366     ID_or_name(source_p, client_p), nick);
367     }
368     }
369     /* continue; */
370     }
371    
372     return(1);
373     }
374    
375     /* duplicate_ptr()
376     *
377     * inputs - pointer to check
378     * - pointer to table of entities
379     * - number of valid entities so far
380     * output - YES if duplicate pointer in table, NO if not.
381     * note, this does the canonize using pointers
382     * side effects - NONE
383     */
384     static int
385     duplicate_ptr(void *ptr)
386     {
387     int i;
388    
389     for (i = 0; i < ntargets; i++)
390     {
391     if (targets[i].ptr == ptr)
392     return(1);
393     }
394    
395     return(0);
396     }
397    
398     /* msg_channel()
399     *
400     * inputs - flag privmsg or notice
401     * - pointer to command "PRIVMSG" or "NOTICE"
402     * - pointer to client_p
403     * - pointer to source_p
404     * - pointer to channel
405     * output - NONE
406     * side effects - message given channel
407     */
408     static void
409     msg_channel(int p_or_n, const char *command, struct Client *client_p,
410     struct Client *source_p, struct Channel *chptr, char *text)
411     {
412 michael 1937 int result = 0;
413 adx 30
414     if (MyClient(source_p))
415     {
416     /* idle time shouldnt be reset by notices --fl */
417     if (p_or_n != NOTICE)
418 michael 1176 source_p->localClient->last_privmsg = CurrentTime;
419 adx 30 }
420    
421     /* chanops and voiced can flood their own channel with impunity */
422 michael 1937 if ((result = can_send(chptr, source_p, NULL, text)) < 0)
423 adx 30 {
424     if (result == CAN_SEND_OPV ||
425 michael 1480 !flood_attack_channel(p_or_n, source_p, chptr))
426 michael 1479 sendto_channel_butone(client_p, source_p, chptr, 0, "%s %s :%s",
427     command, chptr->chname, text);
428 adx 30 }
429     else
430     {
431     if (p_or_n != NOTICE)
432 michael 1937 {
433     if (result == ERR_NOCTRLSONCHAN)
434     sendto_one(source_p, form_str(ERR_NOCTRLSONCHAN),
435     ID_or_name(&me, client_p),
436     ID_or_name(source_p, client_p), chptr->chname, text);
437 michael 1954 else if (result == ERR_NEEDREGGEDNICK)
438     sendto_one(source_p, form_str(ERR_NEEDREGGEDNICK),
439     ID_or_name(&me, client_p),
440     ID_or_name(source_p, client_p), chptr->chname);
441 michael 1937 else
442     sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN),
443     ID_or_name(&me, client_p),
444     ID_or_name(source_p, client_p), chptr->chname);
445     }
446 adx 30 }
447     }
448    
449     /* msg_channel_flags()
450     *
451     * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
452     * say NOTICE must not auto reply
453     * - pointer to command, "PRIVMSG" or "NOTICE"
454     * - pointer to client_p
455     * - pointer to source_p
456     * - pointer to channel
457     * - flags
458     * - pointer to text to send
459     * output - NONE
460     * side effects - message given channel either chanop or voice
461     */
462     static void
463     msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
464     struct Client *source_p, struct Channel *chptr,
465     int flags, char *text)
466     {
467 michael 1479 unsigned int type;
468 adx 30 char c;
469    
470     if (flags & CHFL_VOICE)
471     {
472     type = CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP;
473     c = '+';
474     }
475     #ifdef HALFOPS
476     else if (flags & CHFL_HALFOP)
477     {
478     type = CHFL_HALFOP|CHFL_CHANOP;
479     c = '%';
480     }
481     #endif
482     else
483     {
484     type = CHFL_CHANOP;
485     c = '@';
486     }
487    
488 michael 1479 if (MyClient(source_p) && p_or_n != NOTICE)
489     source_p->localClient->last_privmsg = CurrentTime;
490 adx 30
491 michael 1479 sendto_channel_butone(client_p, source_p, chptr, type, "%s %c%s :%s",
492     command, c, chptr->chname, text);
493 adx 30 }
494    
495     /* msg_client()
496     *
497     * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
498     * say NOTICE must not auto reply
499     * - pointer to command, "PRIVMSG" or "NOTICE"
500     * - pointer to source_p source (struct Client *)
501     * - pointer to target_p target (struct Client *)
502     * - pointer to text
503     * output - NONE
504     * side effects - message given channel either chanop or voice
505     */
506     static void
507     msg_client(int p_or_n, const char *command, struct Client *source_p,
508     struct Client *target_p, char *text)
509     {
510 michael 1173 if (MyConnect(source_p))
511 adx 30 {
512     /*
513 michael 1176 * reset idle time for message only if it's not a notice
514 adx 30 */
515 michael 1176 if ((p_or_n != NOTICE))
516     source_p->localClient->last_privmsg = CurrentTime;
517 michael 1173
518 michael 1483 if ((p_or_n != NOTICE) && target_p->away[0])
519 michael 1834 sendto_one(source_p, form_str(RPL_AWAY), me.name,
520 michael 1173 source_p->name, target_p->name, target_p->away);
521 michael 1175
522     if (HasUMode(target_p, UMODE_REGONLY) && target_p != source_p)
523 michael 1173 {
524 michael 1175 if (!HasUMode(source_p, UMODE_REGISTERED|UMODE_OPER))
525     {
526     if (p_or_n != NOTICE)
527 michael 1834 sendto_one(source_p, form_str(ERR_NONONREG), me.name, source_p->name,
528 michael 1175 target_p->name);
529     return;
530     }
531 michael 1173 }
532 adx 30 }
533    
534     if (MyClient(target_p))
535     {
536 michael 1219 if (!IsServer(source_p) && HasUMode(target_p, UMODE_CALLERID|UMODE_SOFTCALLERID))
537 adx 30 {
538     /* Here is the anti-flood bot/spambot code -db */
539 michael 1219 if (accept_message(source_p, target_p) || HasFlag(source_p, FLAGS_SERVICE) ||
540     (HasUMode(source_p, UMODE_OPER) && (ConfigFileEntry.opers_bypass_callerid == 1)))
541 adx 30 {
542     sendto_one(target_p, ":%s!%s@%s %s %s :%s",
543     source_p->name, source_p->username,
544     source_p->host, command, target_p->name, text);
545     }
546     else
547     {
548     /* check for accept, flag recipient incoming message */
549     if (p_or_n != NOTICE)
550 michael 1834 sendto_one(source_p, form_str(RPL_TARGUMODEG),
551 adx 30 ID_or_name(&me, source_p->from),
552     ID_or_name(source_p, source_p->from), target_p->name);
553    
554     if ((target_p->localClient->last_caller_id_time +
555     ConfigFileEntry.caller_id_wait) < CurrentTime)
556     {
557     if (p_or_n != NOTICE)
558 michael 1834 sendto_one(source_p, form_str(RPL_TARGNOTIFY),
559 adx 30 ID_or_name(&me, source_p->from),
560     ID_or_name(source_p, source_p->from), target_p->name);
561    
562 michael 1834 sendto_one(target_p, form_str(RPL_UMODEGMSG),
563 adx 30 me.name, target_p->name,
564     get_client_name(source_p, HIDE_IP));
565    
566     target_p->localClient->last_caller_id_time = CurrentTime;
567    
568     }
569     /* Only so opers can watch for floods */
570     flood_attack_client(p_or_n, source_p, target_p);
571     }
572     }
573     else
574     {
575     /* If the client is remote, we dont perform a special check for
576     * flooding.. as we wouldnt block their message anyway.. this means
577     * we dont give warnings.. we then check if theyre opered
578     * (to avoid flood warnings), lastly if theyre our client
579     * and flooding -- fl */
580 michael 1219 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
581 adx 30 (MyClient(source_p) &&
582     !flood_attack_client(p_or_n, source_p, target_p)))
583     sendto_anywhere(target_p, source_p, "%s %s :%s",
584     command, target_p->name, text);
585     }
586     }
587     else
588     /* The target is a remote user.. same things apply -- fl */
589 michael 1219 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
590 adx 30 (MyClient(source_p)
591     && !flood_attack_client(p_or_n, source_p, target_p)))
592     sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name,
593     text);
594     }
595    
596     /* flood_attack_client()
597     *
598     * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
599     * say NOTICE must not auto reply
600     * - pointer to source Client
601     * - pointer to target Client
602     * output - 1 if target is under flood attack
603     * side effects - check for flood attack on target target_p
604     */
605     static int
606     flood_attack_client(int p_or_n, struct Client *source_p,
607     struct Client *target_p)
608     {
609     int delta;
610    
611     if (GlobalSetOptions.floodcount && MyConnect(target_p)
612 michael 1716 && IsClient(source_p) && !IsCanFlood(source_p))
613 adx 30 {
614     if ((target_p->localClient->first_received_message_time + 1)
615     < CurrentTime)
616     {
617     delta =
618     CurrentTime - target_p->localClient->first_received_message_time;
619     target_p->localClient->received_number_of_privmsgs -= delta;
620     target_p->localClient->first_received_message_time = CurrentTime;
621 michael 948
622 adx 30 if (target_p->localClient->received_number_of_privmsgs <= 0)
623     {
624     target_p->localClient->received_number_of_privmsgs = 0;
625 michael 1219 DelFlag(target_p, FLAGS_FLOOD_NOTICED);
626 adx 30 }
627     }
628    
629     if ((target_p->localClient->received_number_of_privmsgs >=
630 michael 1219 GlobalSetOptions.floodcount) || HasFlag(target_p, FLAGS_FLOOD_NOTICED))
631 adx 30 {
632 michael 1219 if (!HasFlag(target_p, FLAGS_FLOOD_NOTICED))
633 adx 30 {
634 michael 1618 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
635 adx 30 "Possible Flooder %s on %s target: %s",
636     get_client_name(source_p, HIDE_IP),
637     source_p->servptr->name, target_p->name);
638 michael 1219 AddFlag(target_p, FLAGS_FLOOD_NOTICED);
639 adx 30 /* add a bit of penalty */
640     target_p->localClient->received_number_of_privmsgs += 2;
641     }
642    
643     if (MyClient(source_p) && (p_or_n != NOTICE))
644     sendto_one(source_p,
645     ":%s NOTICE %s :*** Message to %s throttled due to flooding",
646     me.name, source_p->name, target_p->name);
647     return(1);
648     }
649     else
650     target_p->localClient->received_number_of_privmsgs++;
651     }
652    
653     return(0);
654     }
655    
656     /* flood_attack_channel()
657     *
658     * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
659     * says NOTICE must not auto reply
660     * - pointer to source Client
661     * - pointer to target channel
662     * output - 1 if target is under flood attack
663     * side effects - check for flood attack on target chptr
664     */
665     static int
666     flood_attack_channel(int p_or_n, struct Client *source_p,
667 michael 1480 struct Channel *chptr)
668 adx 30 {
669     int delta;
670    
671 michael 1716 if (GlobalSetOptions.floodcount && !IsCanFlood(source_p))
672 adx 30 {
673     if ((chptr->first_received_message_time + 1) < CurrentTime)
674     {
675     delta = CurrentTime - chptr->first_received_message_time;
676     chptr->received_number_of_privmsgs -= delta;
677     chptr->first_received_message_time = CurrentTime;
678     if (chptr->received_number_of_privmsgs <= 0)
679     {
680     chptr->received_number_of_privmsgs = 0;
681     ClearFloodNoticed(chptr);
682     }
683     }
684    
685     if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
686     || IsSetFloodNoticed(chptr))
687     {
688     if (!IsSetFloodNoticed(chptr))
689     {
690 michael 1618 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
691 adx 30 "Possible Flooder %s on %s target: %s",
692     get_client_name(source_p, HIDE_IP),
693     source_p->servptr->name, chptr->chname);
694     SetFloodNoticed(chptr);
695    
696     /* Add a bit of penalty */
697     chptr->received_number_of_privmsgs += 2;
698     }
699     if (MyClient(source_p) && (p_or_n != NOTICE))
700     sendto_one(source_p,
701     ":%s NOTICE %s :*** Message to %s throttled due to flooding",
702 michael 1480 me.name, source_p->name, chptr->chname);
703 adx 30 return(1);
704     }
705     else
706     chptr->received_number_of_privmsgs++;
707     }
708    
709     return(0);
710     }
711    
712     /* handle_special()
713     *
714     * inputs - server pointer
715     * - client pointer
716     * - nick stuff to grok for opers
717     * - text to send if grok
718     * output - none
719     * side effects - old style username@server is handled here for non opers
720     * opers are allowed username%hostname@server
721     * all the traditional oper type messages are also parsed here.
722     * i.e. "/msg #some.host."
723     * However, syntax has been changed.
724     * previous syntax "/msg #some.host.mask"
725     * now becomes "/msg $#some.host.mask"
726     * previous syntax of: "/msg $some.server.mask" remains
727     * This disambiguates the syntax.
728     *
729     * XXX N.B. dalnet changed it to nick@server as have other servers.
730     * we will stick with tradition for now.
731     * - Dianora
732     */
733     static void
734     handle_special(int p_or_n, const char *command, struct Client *client_p,
735     struct Client *source_p, char *nick, char *text)
736     {
737     struct Client *target_p;
738     char *host;
739     char *server;
740     char *s;
741     int count;
742    
743     /*
744     * user[%host]@server addressed?
745     */
746     if ((server = strchr(nick, '@')) != NULL)
747     {
748     count = 0;
749    
750 michael 1219 if ((host = strchr(nick, '%')) && !HasUMode(source_p, UMODE_OPER))
751 adx 30 {
752 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
753 adx 30 ID_or_name(&me, client_p),
754     ID_or_name(source_p, client_p));
755     return;
756     }
757    
758 michael 1169 if ((target_p = hash_find_server(server + 1)) != NULL)
759 adx 30 {
760     if (!IsMe(target_p))
761     {
762     /*
763     * Not destined for a user on me :-(
764     */
765     sendto_one(target_p, ":%s %s %s :%s",
766     ID_or_name(source_p, target_p->from),
767     command, nick, text);
768     if ((p_or_n != NOTICE) && MyClient(source_p))
769 michael 1176 source_p->localClient->last_privmsg = CurrentTime;
770 adx 30 return;
771     }
772    
773     *server = '\0';
774    
775     if (host != NULL)
776     *host++ = '\0';
777    
778     /*
779     * Look for users which match the destination host
780     * (no host == wildcard) and if one and one only is
781     * found connected to me, deliver message!
782     */
783     target_p = find_userhost(nick, host, &count);
784    
785     if (target_p != NULL)
786     {
787     if (server != NULL)
788     *server = '@';
789     if (host != NULL)
790     *--host = '%';
791    
792     if (count == 1)
793     {
794     sendto_one(target_p, ":%s!%s@%s %s %s :%s",
795     source_p->name, source_p->username, source_p->host,
796     command, nick, text);
797     if ((p_or_n != NOTICE) && MyClient(source_p))
798 michael 1176 source_p->localClient->last_privmsg = CurrentTime;
799 adx 30 }
800     else
801 michael 1834 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
802 adx 30 ID_or_name(&me, client_p),
803     ID_or_name(source_p, client_p), nick,
804     ConfigFileEntry.max_targets);
805     }
806     }
807     else if (server && *(server+1) && (target_p == NULL))
808 michael 1834 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
809 adx 30 ID_or_name(&me, client_p),
810     ID_or_name(source_p, client_p), server+1);
811     else if (server && (target_p == NULL))
812 michael 1834 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
813 adx 30 ID_or_name(&me, client_p),
814     ID_or_name(source_p, client_p), nick);
815     return;
816     }
817    
818 michael 1219 if (!HasUMode(source_p, UMODE_OPER))
819 adx 30 {
820 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
821 adx 30 ID_or_name(&me, client_p),
822     ID_or_name(source_p, client_p));
823     return;
824     }
825    
826     /*
827     * the following two cases allow masks in NOTICEs
828     * (for OPERs only)
829     *
830     * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
831     */
832     if (*nick == '$')
833     {
834     if ((*(nick+1) == '$' || *(nick+1) == '#'))
835     nick++;
836 michael 1219 else if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
837 adx 30 {
838     sendto_one(source_p,
839     ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
840     me.name, source_p->name, command, nick, nick);
841     return;
842     }
843    
844     if ((s = strrchr(nick, '.')) == NULL)
845     {
846 michael 1834 sendto_one(source_p, form_str(ERR_NOTOPLEVEL),
847 adx 30 me.name, source_p->name, nick);
848     return;
849     }
850    
851     while (*++s)
852     if (*s == '.' || *s == '*' || *s == '?')
853     break;
854    
855     if (*s == '*' || *s == '?')
856     {
857 michael 1834 sendto_one(source_p, form_str(ERR_WILDTOPLEVEL),
858 adx 30 ID_or_name(&me, client_p),
859     ID_or_name(source_p, client_p), nick);
860     return;
861     }
862    
863     sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
864     nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
865     "%s $%s :%s", command, nick, text);
866    
867     if ((p_or_n != NOTICE) && MyClient(source_p))
868 michael 1176 source_p->localClient->last_privmsg = CurrentTime;
869 adx 30
870     return;
871     }
872     }
873    
874     /*
875     * find_userhost - find a user@host (server or user).
876     * inputs - user name to look for
877     * - host name to look for
878     * - pointer to count of number of matches found
879     * outputs - pointer to client if found
880     * - count is updated
881     * side effects - none
882     *
883     */
884     static struct Client *
885     find_userhost(char *user, char *host, int *count)
886     {
887     struct Client *c2ptr;
888     struct Client *res = NULL;
889     dlink_node *lc2ptr;
890    
891     *count = 0;
892    
893     if (collapse(user) != NULL)
894     {
895     DLINK_FOREACH(lc2ptr, local_client_list.head)
896     {
897     c2ptr = lc2ptr->data;
898    
899     if (!IsClient(c2ptr)) /* something other than a client */
900     continue;
901    
902 michael 1652 if ((!host || !match(host, c2ptr->host)) &&
903 adx 30 irccmp(user, c2ptr->username) == 0)
904     {
905     (*count)++;
906     res = c2ptr;
907     }
908     }
909     }
910    
911     return(res);
912     }
913 michael 1230
914     static struct Message privmsg_msgtab = {
915 michael 1569 "PRIVMSG", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
916 michael 1230 {m_unregistered, m_privmsg, m_privmsg, m_ignore, m_privmsg, m_ignore}
917     };
918    
919     static struct Message notice_msgtab = {
920     "NOTICE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
921     {m_unregistered, m_notice, m_notice, m_ignore, m_notice, m_ignore}
922     };
923    
924     static void
925     module_init(void)
926     {
927     mod_add_cmd(&privmsg_msgtab);
928     mod_add_cmd(&notice_msgtab);
929     }
930    
931     static void
932     module_exit(void)
933     {
934     mod_del_cmd(&privmsg_msgtab);
935     mod_del_cmd(&notice_msgtab);
936     }
937    
938     struct module module_entry = {
939     .node = { NULL, NULL, NULL },
940     .name = NULL,
941     .version = "$Revision$",
942     .handle = NULL,
943     .modinit = module_init,
944     .modexit = module_exit,
945     .flags = MODULE_FLAG_CORE
946     };

Properties

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