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: 3110
Committed: Thu Mar 6 20:33:17 2014 UTC (10 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_message.c
File size: 24504 byte(s)
Log Message:
- Added sendto_one_notice()

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

Properties

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