ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_message.c
Revision: 3347
Committed: Sun Apr 20 14:03:06 2014 UTC (12 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 24100 byte(s)
Log Message:
- Moved files:
  s_user.c -> user.c
  s_misc.c -> misc.c
  s_serv.c -> server.c

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

Properties

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