ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_message.c
Revision: 3109
Committed: Thu Mar 6 19:25:12 2014 UTC (11 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 24619 byte(s)
Log Message:
- Applied Adam's sendto_one_numeric() changes

File Contents

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

Properties

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