ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_message.c
Revision: 3773
Committed: Mon Jun 2 18:46:09 2014 UTC (12 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 23982 byte(s)
Log Message:
- m_message: style corrections; made things use an enum

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

Properties

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