ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_message.c
Revision: 2793
Committed: Thu Jan 9 17:38:12 2014 UTC (11 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 27796 byte(s)
Log Message:
 - Make PRIVMSG/NOTICE use UID targets if possible

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

Properties

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