ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/core/m_message.c
Revision: 2796
Committed: Thu Jan 9 20:44:09 2014 UTC (10 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_message.c
File size: 26648 byte(s)
Log Message:
- m_message.c: fixed indentation, style cleanups, reformatting

File Contents

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

Properties

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