ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/core/m_message.c
Revision: 3164
Committed: Sat Mar 15 20:19:15 2014 UTC (11 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 24110 byte(s)
Log Message:
- More client_p removal cleanups
- parse.c:handle_command: now no longer drop servers if the right
  amount of parameters isn't given

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

Properties

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