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: 2888
Committed: Tue Jan 21 17:47:11 2014 UTC (10 years, 2 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_message.c
File size: 26599 byte(s)
Log Message:
- Fixed improper use of the ID_or_name macro in several places

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2014 ircd-hybrid development team
5 *
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 /*! \file m_message.c
23 * \brief Includes required functions for processing the PRIVMSG/NOTICE command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "client.h"
30 #include "ircd.h"
31 #include "numeric.h"
32 #include "conf.h"
33 #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
44 #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 static struct entity
53 {
54 void *ptr;
55 int type;
56 int flags;
57 } targets[IRCD_BUFSIZE];
58
59 static int ntargets = 0;
60
61
62 /*
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 /* 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 {
93 int i = 0;
94
95 for (; i < ntargets; ++i)
96 if (targets[i].ptr == ptr)
97 return 1;
98
99 return 0;
100 }
101
102 /*
103 * 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 */
112 static struct Client *
113 find_userhost(char *user, char *host, int *count)
114 {
115 struct Client *res = NULL;
116 dlink_node *lc2ptr = NULL;
117
118 *count = 0;
119
120 if (collapse(user))
121 {
122 DLINK_FOREACH(lc2ptr, local_client_list.head)
123 {
124 struct Client *c2ptr = lc2ptr->data;
125
126 if (!IsClient(c2ptr))
127 continue;
128
129 if ((!host || !match(host, c2ptr->host)) &&
130 !irccmp(user, c2ptr->username))
131 {
132 (*count)++;
133 res = c2ptr;
134 }
135 }
136 }
137
138 return res;
139 }
140
141 /* flood_attack_client()
142 *
143 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
144 * say NOTICE must not auto reply
145 * - pointer to source Client
146 * - 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 */
150 static int
151 flood_attack_client(int p_or_n, struct Client *source_p,
152 struct Client *target_p)
153 {
154 int delta;
155
156 if (GlobalSetOptions.floodcount && MyConnect(target_p) &&
157 IsClient(source_p) && !IsCanFlood(source_p))
158 {
159 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
167 if (target_p->localClient->received_number_of_privmsgs <= 0)
168 {
169 target_p->localClient->received_number_of_privmsgs = 0;
170 DelFlag(target_p, FLAGS_FLOOD_NOTICED);
171 }
172 }
173
174 if ((target_p->localClient->received_number_of_privmsgs >=
175 GlobalSetOptions.floodcount) || HasFlag(target_p, FLAGS_FLOOD_NOTICED))
176 {
177 if (!HasFlag(target_p, FLAGS_FLOOD_NOTICED))
178 {
179 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 }
188
189 if (MyClient(source_p) && (p_or_n != NOTICE))
190 sendto_one(source_p,
191 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
192 me.name, source_p->name, target_p->name);
193 return 1;
194 }
195 else
196 target_p->localClient->received_number_of_privmsgs++;
197 }
198
199 return 0;
200 }
201
202 /* flood_attack_channel()
203 *
204 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
205 * says NOTICE must not auto reply
206 * - pointer to source Client
207 * - pointer to target channel
208 * output - 1 if target is under flood attack
209 * side effects - check for flood attack on target chptr
210 */
211 static int
212 flood_attack_channel(int p_or_n, struct Client *source_p,
213 struct Channel *chptr)
214 {
215 int delta;
216
217 if (GlobalSetOptions.floodcount && !IsCanFlood(source_p))
218 {
219 if ((chptr->first_received_message_time + 1) < CurrentTime)
220 {
221 delta = CurrentTime - chptr->first_received_message_time;
222 chptr->received_number_of_privmsgs -= delta;
223 chptr->first_received_message_time = CurrentTime;
224
225 if (chptr->received_number_of_privmsgs <= 0)
226 {
227 chptr->received_number_of_privmsgs = 0;
228 ClearFloodNoticed(chptr);
229 }
230 }
231
232 if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount) ||
233 IsSetFloodNoticed(chptr))
234 {
235 if (!IsSetFloodNoticed(chptr))
236 {
237 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
238 "Possible Flooder %s on %s target: %s",
239 get_client_name(source_p, HIDE_IP),
240 source_p->servptr->name, chptr->chname);
241 SetFloodNoticed(chptr);
242
243 /* Add a bit of penalty */
244 chptr->received_number_of_privmsgs += 2;
245 }
246
247 if (MyClient(source_p) && (p_or_n != NOTICE))
248 sendto_one(source_p,
249 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
250 me.name, source_p->name, chptr->chname);
251 return 1;
252 }
253 else
254 chptr->received_number_of_privmsgs++;
255 }
256
257 return 0;
258 }
259
260 /* msg_channel()
261 *
262 * inputs - flag privmsg or notice
263 * - pointer to command "PRIVMSG" or "NOTICE"
264 * - pointer to client_p
265 * - pointer to source_p
266 * - pointer to channel
267 * output - NONE
268 * side effects - message given channel
269 */
270 static void
271 msg_channel(int p_or_n, const char *command, struct Client *client_p,
272 struct Client *source_p, struct Channel *chptr, char *text)
273 {
274 int result = 0;
275
276 if (MyClient(source_p))
277 {
278 /* Idle time shouldnt be reset by notices --fl */
279 if (p_or_n != NOTICE)
280 source_p->localClient->last_privmsg = CurrentTime;
281 }
282
283 /* Chanops and voiced can flood their own channel with impunity */
284 if ((result = can_send(chptr, source_p, NULL, text)) < 0)
285 {
286 if (result == CAN_SEND_OPV ||
287 !flood_attack_channel(p_or_n, source_p, chptr))
288 sendto_channel_butone(client_p, source_p, chptr, 0, "%s %s :%s",
289 command, chptr->chname, text);
290 }
291 else
292 {
293 if (p_or_n != NOTICE)
294 {
295 if (result == ERR_NOCTRLSONCHAN)
296 sendto_one(source_p, form_str(ERR_NOCTRLSONCHAN),
297 ID_or_name(&me, client_p),
298 ID_or_name(source_p, client_p), chptr->chname, text);
299 else if (result == ERR_NEEDREGGEDNICK)
300 sendto_one(source_p, form_str(ERR_NEEDREGGEDNICK),
301 ID_or_name(&me, client_p),
302 ID_or_name(source_p, client_p), chptr->chname);
303 else
304 sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN),
305 ID_or_name(&me, client_p),
306 ID_or_name(source_p, client_p), chptr->chname);
307 }
308 }
309 }
310
311 /* msg_channel_flags()
312 *
313 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
314 * say NOTICE must not auto reply
315 * - pointer to command, "PRIVMSG" or "NOTICE"
316 * - pointer to client_p
317 * - pointer to source_p
318 * - pointer to channel
319 * - flags
320 * - pointer to text to send
321 * output - NONE
322 * side effects - message given channel either chanop or voice
323 */
324 static void
325 msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
326 struct Client *source_p, struct Channel *chptr,
327 int flags, char *text)
328 {
329 unsigned int type;
330 char c;
331
332 if (flags & CHFL_VOICE)
333 {
334 type = CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP;
335 c = '+';
336 }
337 #ifdef HALFOPS
338 else if (flags & CHFL_HALFOP)
339 {
340 type = CHFL_HALFOP|CHFL_CHANOP;
341 c = '%';
342 }
343 #endif
344 else
345 {
346 type = CHFL_CHANOP;
347 c = '@';
348 }
349
350 if (MyClient(source_p) && p_or_n != NOTICE)
351 source_p->localClient->last_privmsg = CurrentTime;
352
353 sendto_channel_butone(client_p, source_p, chptr, type, "%s %c%s :%s",
354 command, c, chptr->chname, text);
355 }
356
357 /* msg_client()
358 *
359 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
360 * say NOTICE must not auto reply
361 * - pointer to command, "PRIVMSG" or "NOTICE"
362 * - pointer to source_p source (struct Client *)
363 * - pointer to target_p target (struct Client *)
364 * - pointer to text
365 * output - NONE
366 * side effects - message given channel either chanop or voice
367 */
368 static void
369 msg_client(int p_or_n, const char *command, struct Client *source_p,
370 struct Client *target_p, char *text)
371 {
372 if (MyConnect(source_p))
373 {
374 /*
375 * Reset idle time for message only if it's not a notice
376 */
377 if ((p_or_n != NOTICE))
378 source_p->localClient->last_privmsg = CurrentTime;
379
380 if ((p_or_n != NOTICE) && target_p->away[0])
381 sendto_one(source_p, form_str(RPL_AWAY), me.name,
382 source_p->name, target_p->name, target_p->away);
383
384 if (HasUMode(target_p, UMODE_REGONLY) && target_p != source_p)
385 {
386 if (!HasUMode(source_p, UMODE_REGISTERED|UMODE_OPER))
387 {
388 if (p_or_n != NOTICE)
389 sendto_one(source_p, form_str(ERR_NONONREG), me.name, source_p->name,
390 target_p->name);
391 return;
392 }
393 }
394 }
395
396 if (MyClient(target_p))
397 {
398 if (!IsServer(source_p) && HasUMode(target_p, UMODE_CALLERID|UMODE_SOFTCALLERID))
399 {
400 /* Here is the anti-flood bot/spambot code -db */
401 if (accept_message(source_p, target_p) || HasFlag(source_p, FLAGS_SERVICE) ||
402 (HasUMode(source_p, UMODE_OPER) && (ConfigFileEntry.opers_bypass_callerid == 1)))
403 {
404 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
405 source_p->name, source_p->username,
406 source_p->host, command, target_p->name, text);
407 }
408 else
409 {
410 int callerid = !!HasUMode(target_p, UMODE_CALLERID);
411
412 /* check for accept, flag recipient incoming message */
413 if (p_or_n != NOTICE)
414 sendto_one(source_p, form_str(RPL_TARGUMODEG),
415 ID_or_name(&me, source_p),
416 ID_or_name(source_p, source_p), target_p->name,
417 callerid ? "+g" : "+G",
418 callerid ? "server side ignore" :
419 "server side ignore with the exception of common channels");
420
421 if ((target_p->localClient->last_caller_id_time +
422 ConfigFileEntry.caller_id_wait) < CurrentTime)
423 {
424 if (p_or_n != NOTICE)
425 sendto_one(source_p, form_str(RPL_TARGNOTIFY),
426 ID_or_name(&me, source_p),
427 ID_or_name(source_p, source_p), target_p->name);
428
429 sendto_one(target_p, form_str(RPL_UMODEGMSG),
430 me.name, target_p->name,
431 get_client_name(source_p, HIDE_IP),
432 callerid ? "+g" : "+G");
433
434 target_p->localClient->last_caller_id_time = CurrentTime;
435
436 }
437
438 /* Only so opers can watch for floods */
439 flood_attack_client(p_or_n, source_p, target_p);
440 }
441 }
442 else
443 {
444 /*
445 * If the client is remote, we dont perform a special check for
446 * flooding.. as we wouldnt block their message anyway.. this means
447 * we dont give warnings.. we then check if theyre opered
448 * (to avoid flood warnings), lastly if theyre our client
449 * and flooding -- fl
450 */
451 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
452 !flood_attack_client(p_or_n, source_p, target_p))
453 sendto_anywhere(target_p, source_p, command, ":%s", text);
454 }
455 }
456 else if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
457 !flood_attack_client(p_or_n, source_p, target_p))
458 sendto_anywhere(target_p, source_p, command, ":%s", text);
459 }
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 struct Client *source_p, char *nick, char *text)
485 {
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 if ((server = strchr(nick, '@')))
496 {
497 count = 0;
498
499 if ((host = strchr(nick, '%')) && !HasUMode(source_p, UMODE_OPER))
500 {
501 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
502 ID_or_name(&me, client_p),
503 ID_or_name(source_p, client_p));
504 return;
505 }
506
507 if ((target_p = hash_find_server(server + 1)))
508 {
509 if (!IsMe(target_p))
510 {
511 /*
512 * Not destined for a user on me :-(
513 */
514 sendto_one(target_p, ":%s %s %s :%s",
515 ID_or_name(source_p, target_p),
516 command, nick, text);
517 if ((p_or_n != NOTICE) && MyClient(source_p))
518 source_p->localClient->last_privmsg = CurrentTime;
519
520 return;
521 }
522
523 *server = '\0';
524
525 if (host != NULL)
526 *host++ = '\0';
527
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 if ((target_p = find_userhost(nick, host, &count)))
534 {
535 if (server != NULL)
536 *server = '@';
537 if (host != NULL)
538 *--host = '%';
539
540 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 ID_or_name(&me, client_p),
552 ID_or_name(source_p, client_p), nick,
553 ConfigFileEntry.max_targets);
554 }
555 }
556 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 else if (server && (target_p == NULL))
561 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 return;
565 }
566
567 if (!HasUMode(source_p, UMODE_OPER))
568 {
569 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
570 ID_or_name(&me, client_p),
571 ID_or_name(source_p, client_p));
572 return;
573 }
574
575 /*
576 * The following two cases allow masks in NOTICEs
577 * (for OPERs only)
578 *
579 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
580 */
581 if (*nick == '$')
582 {
583 if ((*(nick + 1) == '$' || *(nick + 1) == '#'))
584 ++nick;
585 else if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
586 {
587 sendto_one(source_p,
588 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
589 me.name, source_p->name, command, nick, nick);
590 return;
591 }
592
593 if ((s = strrchr(nick, '.')) == NULL)
594 {
595 sendto_one(source_p, form_str(ERR_NOTOPLEVEL),
596 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 sendto_one(source_p, form_str(ERR_WILDTOPLEVEL),
607 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 source_p->localClient->last_privmsg = CurrentTime;
618 }
619 }
620
621 /* build_target_list()
622 *
623 * 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 */
637 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 {
641 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
647 target_list = nicks_channels;
648
649 ntargets = 0;
650
651 for (nick = strtoken(&p, target_list, ","); nick;
652 nick = strtoken(&p, NULL, ","))
653 {
654 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 {
662 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
675 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 continue;
740 }
741
742 /*
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 {
748 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 }
776 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 }
786
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 }
801
802 return 1;
803 }
804
805 /*
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 int
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 0;
873
874 m_message(PRIVMSG, "PRIVMSG", client_p, source_p, parc, parv);
875 return 0;
876 }
877
878 static int
879 m_notice(struct Client *client_p, struct Client *source_p,
880 int parc, char *parv[])
881 {
882 m_message(NOTICE, "NOTICE", client_p, source_p, parc, parv);
883 return 0;
884 }
885
886 static struct Message privmsg_msgtab =
887 {
888 "PRIVMSG", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
889 { m_unregistered, m_privmsg, m_privmsg, m_ignore, m_privmsg, m_ignore }
890 };
891
892 static struct Message notice_msgtab =
893 {
894 "NOTICE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
895 { m_unregistered, m_notice, m_notice, m_ignore, m_notice, m_ignore }
896 };
897
898 static void
899 module_init(void)
900 {
901 mod_add_cmd(&privmsg_msgtab);
902 mod_add_cmd(&notice_msgtab);
903 }
904
905 static void
906 module_exit(void)
907 {
908 mod_del_cmd(&privmsg_msgtab);
909 mod_del_cmd(&notice_msgtab);
910 }
911
912 struct module module_entry =
913 {
914 .node = { NULL, NULL, NULL },
915 .name = NULL,
916 .version = "$Revision$",
917 .handle = NULL,
918 .modinit = module_init,
919 .modexit = module_exit,
920 .flags = MODULE_FLAG_CORE
921 };

Properties

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