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: 1478
Committed: Sun Jul 22 15:50:02 2012 UTC (11 years, 8 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/modules/core/m_message.c
File size: 28578 byte(s)
Log Message:
- Allow servers and service to send @%+ prepended channel messages

File Contents

# Content
1 /*
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 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "list.h"
27 #include "client.h"
28 #include "ircd.h"
29 #include "numeric.h"
30 #include "conf.h"
31 #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
42 struct entity
43 {
44 void *ptr;
45 int type;
46 int flags;
47 };
48
49 static int build_target_list(int p_or_n, const char *command,
50 struct Client *client_p,
51 struct Client *source_p,
52 char *nicks_channels, char *text);
53
54 static int flood_attack_client(int p_or_n, struct Client *source_p,
55 struct Client *target_p);
56 static int flood_attack_channel(int p_or_n, struct Client *source_p,
57 struct Channel *chptr, char *chname);
58 static struct Client* find_userhost (char *, char *, int *);
59
60 #define ENTITY_NONE 0
61 #define ENTITY_CHANNEL 1
62 #define ENTITY_CHANOPS_ON_CHANNEL 2
63 #define ENTITY_CLIENT 3
64
65 static struct entity targets[512];
66 static int ntargets = 0;
67
68 static int duplicate_ptr(void *);
69
70 static void m_message(int, const char *, struct Client *,
71 struct Client *, int, char **);
72
73 static void msg_channel(int p_or_n, const char *command,
74 struct Client *client_p,
75 struct Client *source_p,
76 struct Channel *chptr, char *text);
77
78 static void msg_channel_flags(int p_or_n, const char *command,
79 struct Client *client_p,
80 struct Client *source_p,
81 struct Channel *chptr, int flags, char *text);
82
83 static void msg_client(int p_or_n, const char *command,
84 struct Client *source_p, struct Client *target_p,
85 char *text);
86
87 static void handle_special(int p_or_n, const char *command,
88 struct Client *client_p,
89 struct Client *source_p, char *nick, char *text);
90
91 /*
92 ** m_privmsg
93 **
94 ** massive cleanup
95 ** rev argv 6/91
96 **
97 ** Another massive cleanup Nov, 2000
98 ** (I don't think there is a single line left from 6/91. Maybe.)
99 ** m_privmsg and m_notice do basically the same thing.
100 ** in the original 2.8.2 code base, they were the same function
101 ** "m_message.c." When we did the great cleanup in conjuncton with bleep
102 ** of ircu fame, we split m_privmsg.c and m_notice.c.
103 ** I don't see the point of that now. Its harder to maintain, its
104 ** easier to introduce bugs into one version and not the other etc.
105 ** Really, the penalty of an extra function call isn't that big a deal folks.
106 ** -db Nov 13, 2000
107 **
108 */
109
110 #define PRIVMSG 0
111 #define NOTICE 1
112
113 static void
114 m_privmsg(struct Client *client_p, struct Client *source_p,
115 int parc, char *parv[])
116 {
117 /* servers have no reason to send privmsgs, yet sometimes there is cause
118 * for a notice.. (for example remote kline replies) --fl_
119 */
120 if (!IsClient(source_p))
121 return;
122
123 m_message(PRIVMSG, "PRIVMSG", client_p, source_p, parc, parv);
124 }
125
126 static void
127 m_notice(struct Client *client_p, struct Client *source_p,
128 int parc, char *parv[])
129 {
130 m_message(NOTICE, "NOTICE", client_p, source_p, parc, parv);
131 }
132
133 /*
134 * inputs - flag privmsg or notice
135 * - pointer to command "PRIVMSG" or "NOTICE"
136 * - pointer to client_p
137 * - pointer to source_p
138 * - pointer to channel
139 */
140 static void
141 m_message(int p_or_n, const char *command, struct Client *client_p,
142 struct Client *source_p, int parc, char *parv[])
143 {
144 int i;
145
146 if (parc < 2 || EmptyString(parv[1]))
147 {
148 if (p_or_n != NOTICE)
149 sendto_one(source_p, form_str(ERR_NORECIPIENT),
150 ID_or_name(&me, client_p),
151 ID_or_name(source_p, client_p), command);
152 return;
153 }
154
155 if (parc < 3 || EmptyString(parv[2]))
156 {
157 if (p_or_n != NOTICE)
158 sendto_one(source_p, form_str(ERR_NOTEXTTOSEND),
159 ID_or_name(&me, client_p),
160 ID_or_name(source_p, client_p));
161 return;
162 }
163
164 /* Finish the flood grace period... */
165 if (MyClient(source_p) && !IsFloodDone(source_p))
166 flood_endgrace(source_p);
167
168 if (build_target_list(p_or_n, command, client_p, source_p, parv[1],
169 parv[2]) < 0)
170 return;
171
172 for (i = 0; i < ntargets; i++)
173 {
174 switch (targets[i].type)
175 {
176 case ENTITY_CHANNEL:
177 msg_channel(p_or_n, command, client_p, source_p,
178 (struct Channel *)targets[i].ptr, parv[2]);
179 break;
180
181 case ENTITY_CHANOPS_ON_CHANNEL:
182 msg_channel_flags(p_or_n, command, client_p, source_p,
183 (struct Channel *)targets[i].ptr,
184 targets[i].flags, parv[2]);
185 break;
186
187 case ENTITY_CLIENT:
188 msg_client(p_or_n, command, source_p,
189 (struct Client *)targets[i].ptr, parv[2]);
190 break;
191 }
192 }
193 }
194
195 /* build_target_list()
196 *
197 * inputs - pointer to given client_p (server)
198 * - pointer to given source (oper/client etc.)
199 * - pointer to list of nicks/channels
200 * - pointer to table to place results
201 * - pointer to text (only used if source_p is an oper)
202 * output - number of valid entities
203 * side effects - target_table is modified to contain a list of
204 * pointers to channels or clients
205 * if source client is an oper
206 * all the classic old bizzare oper privmsg tricks
207 * are parsed and sent as is, if prefixed with $
208 * to disambiguate.
209 *
210 */
211 static int
212 build_target_list(int p_or_n, const char *command, struct Client *client_p,
213 struct Client *source_p, char *nicks_channels, char *text)
214 {
215 int type;
216 char *p = NULL, *nick, *target_list;
217 struct Channel *chptr = NULL;
218 struct Client *target_p = NULL;
219
220 target_list = nicks_channels;
221
222 ntargets = 0;
223
224 for (nick = strtoken(&p, target_list, ","); nick;
225 nick = strtoken(&p, NULL, ","))
226 {
227 char *with_prefix;
228 /*
229 * channels are privmsg'd a lot more than other clients, moved up
230 * here plain old channel msg?
231 */
232
233 if (IsChanPrefix(*nick))
234 {
235 if ((chptr = hash_find_channel(nick)) != NULL)
236 {
237 if (!duplicate_ptr(chptr))
238 {
239 if (ntargets >= ConfigFileEntry.max_targets)
240 {
241 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
242 ID_or_name(&me, client_p),
243 ID_or_name(source_p, client_p), nick,
244 ConfigFileEntry.max_targets);
245 return (1);
246 }
247 targets[ntargets].ptr = (void *)chptr;
248 targets[ntargets++].type = ENTITY_CHANNEL;
249 }
250 }
251 else
252 {
253 if (p_or_n != NOTICE)
254 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
255 ID_or_name(&me, client_p),
256 ID_or_name(source_p, client_p), nick);
257 }
258 continue;
259 }
260
261 /* look for a privmsg to another client */
262 if ((target_p = find_person(client_p, nick)) != NULL)
263 {
264 if (!duplicate_ptr(target_p))
265 {
266 if (ntargets >= ConfigFileEntry.max_targets)
267 {
268 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
269 ID_or_name(&me, client_p),
270 ID_or_name(source_p, client_p), nick,
271 ConfigFileEntry.max_targets);
272 return (1);
273 }
274 targets[ntargets].ptr = (void *)target_p;
275 targets[ntargets].type = ENTITY_CLIENT;
276 targets[ntargets++].flags = 0;
277 }
278 continue;
279 }
280
281 /* @#channel or +#channel message ? */
282
283 type = 0;
284 with_prefix = nick;
285 /* allow %+@ if someone wants to do that */
286 for (; ;)
287 {
288 if (*nick == '@')
289 type |= CHFL_CHANOP;
290 #ifdef HALFOPS
291 else if (*nick == '%')
292 type |= CHFL_CHANOP | CHFL_HALFOP;
293 #endif
294 else if (*nick == '+')
295 type |= CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE;
296 else
297 break;
298 nick++;
299 }
300
301 if (type != 0)
302 {
303 /* suggested by Mortiis */
304 if (*nick == '\0') /* if its a '\0' dump it, there is no recipient */
305 {
306 sendto_one(source_p, form_str(ERR_NORECIPIENT),
307 ID_or_name(&me, client_p),
308 ID_or_name(source_p, client_p), command);
309 continue;
310 }
311
312 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
313 * if the channel is found, fine, if not report an error
314 */
315
316 if ((chptr = hash_find_channel(nick)) != NULL)
317 {
318 if (IsClient(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
319 {
320 if (!has_member_flags(find_channel_link(source_p, chptr),
321 CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
322 {
323 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
324 ID_or_name(&me, client_p),
325 ID_or_name(source_p, client_p), with_prefix);
326 return(-1);
327 }
328 }
329
330 if (!duplicate_ptr(chptr))
331 {
332 if (ntargets >= ConfigFileEntry.max_targets)
333 {
334 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
335 ID_or_name(&me, client_p),
336 ID_or_name(source_p, client_p), nick,
337 ConfigFileEntry.max_targets);
338 return(1);
339 }
340 targets[ntargets].ptr = (void *)chptr;
341 targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
342 targets[ntargets++].flags = type;
343 }
344 }
345 else
346 {
347 if (p_or_n != NOTICE)
348 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
349 ID_or_name(&me, client_p),
350 ID_or_name(source_p, client_p), nick);
351 }
352 continue;
353 }
354
355 if ((*nick == '$') || strchr(nick, '@') != NULL)
356 {
357 handle_special(p_or_n, command, client_p, source_p, nick, text);
358 }
359 else
360 {
361 if (p_or_n != NOTICE)
362 {
363 if (!IsDigit(*nick) || MyClient(source_p))
364 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
365 ID_or_name(&me, client_p),
366 ID_or_name(source_p, client_p), nick);
367 }
368 }
369 /* continue; */
370 }
371
372 return(1);
373 }
374
375 /* duplicate_ptr()
376 *
377 * inputs - pointer to check
378 * - pointer to table of entities
379 * - number of valid entities so far
380 * output - YES if duplicate pointer in table, NO if not.
381 * note, this does the canonize using pointers
382 * side effects - NONE
383 */
384 static int
385 duplicate_ptr(void *ptr)
386 {
387 int i;
388
389 for (i = 0; i < ntargets; i++)
390 {
391 if (targets[i].ptr == ptr)
392 return(1);
393 }
394
395 return(0);
396 }
397
398 /* msg_channel()
399 *
400 * inputs - flag privmsg or notice
401 * - pointer to command "PRIVMSG" or "NOTICE"
402 * - pointer to client_p
403 * - pointer to source_p
404 * - pointer to channel
405 * output - NONE
406 * side effects - message given channel
407 */
408 static void
409 msg_channel(int p_or_n, const char *command, struct Client *client_p,
410 struct Client *source_p, struct Channel *chptr, char *text)
411 {
412 int result;
413
414 if (MyClient(source_p))
415 {
416 /* idle time shouldnt be reset by notices --fl */
417 if (p_or_n != NOTICE)
418 source_p->localClient->last_privmsg = CurrentTime;
419 }
420
421 /* chanops and voiced can flood their own channel with impunity */
422 if ((result = can_send(chptr, source_p, NULL)) < 0)
423 {
424 if (result == CAN_SEND_OPV ||
425 !flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
426 sendto_channel_butone(client_p, source_p, chptr, command, ":%s", text);
427 }
428 else
429 {
430 if (p_or_n != NOTICE)
431 sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN),
432 ID_or_name(&me, client_p),
433 ID_or_name(source_p, client_p), chptr->chname);
434 }
435 }
436
437 /* msg_channel_flags()
438 *
439 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
440 * say NOTICE must not auto reply
441 * - pointer to command, "PRIVMSG" or "NOTICE"
442 * - pointer to client_p
443 * - pointer to source_p
444 * - pointer to channel
445 * - flags
446 * - pointer to text to send
447 * output - NONE
448 * side effects - message given channel either chanop or voice
449 */
450 static void
451 msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
452 struct Client *source_p, struct Channel *chptr,
453 int flags, char *text)
454 {
455 int type;
456 char c;
457
458 if (flags & CHFL_VOICE)
459 {
460 type = CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP;
461 c = '+';
462 }
463 #ifdef HALFOPS
464 else if (flags & CHFL_HALFOP)
465 {
466 type = CHFL_HALFOP|CHFL_CHANOP;
467 c = '%';
468 }
469 #endif
470 else
471 {
472 type = CHFL_CHANOP;
473 c = '@';
474 }
475
476 if (MyClient(source_p))
477 {
478 /* idletime shouldnt be reset by notice --fl */
479 if (p_or_n != NOTICE)
480 source_p->localClient->last_privmsg = CurrentTime;
481
482 sendto_channel_local_butone(source_p, type, chptr, ":%s!%s@%s %s %c%s :%s",
483 source_p->name, source_p->username,
484 source_p->host, command, c, chptr->chname, text);
485 }
486 else
487 {
488 /*
489 * another good catch, lee. we never would echo to remote clients anyway,
490 * so use slightly less intensive sendto_channel_local()
491 */
492 sendto_channel_local(type, 1, chptr, ":%s!%s@%s %s %c%s :%s",
493 source_p->name, source_p->username,
494 source_p->host, command, c, chptr->chname, text);
495 }
496
497 if (chptr->chname[0] != '#')
498 return;
499
500 sendto_channel_remote(source_p, client_p, type, CAP_CHW, CAP_TS6, chptr,
501 ":%s %s %c%s :%s", source_p->name, command, c, chptr->chname, text);
502 sendto_channel_remote(source_p, client_p, type, CAP_CHW|CAP_TS6, NOCAPS, chptr,
503 ":%s %s %c%s :%s", ID(source_p), command, c, chptr->chname, text);
504 /* non CAP_CHW servers? */
505 }
506
507 /* msg_client()
508 *
509 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
510 * say NOTICE must not auto reply
511 * - pointer to command, "PRIVMSG" or "NOTICE"
512 * - pointer to source_p source (struct Client *)
513 * - pointer to target_p target (struct Client *)
514 * - pointer to text
515 * output - NONE
516 * side effects - message given channel either chanop or voice
517 */
518 static void
519 msg_client(int p_or_n, const char *command, struct Client *source_p,
520 struct Client *target_p, char *text)
521 {
522 if (MyConnect(source_p))
523 {
524 /*
525 * reset idle time for message only if it's not a notice
526 */
527 if ((p_or_n != NOTICE))
528 source_p->localClient->last_privmsg = CurrentTime;
529
530 if ((p_or_n != NOTICE) && target_p->away)
531 sendto_one(source_p, form_str(RPL_AWAY), me.name,
532 source_p->name, target_p->name, target_p->away);
533
534 if (HasUMode(target_p, UMODE_REGONLY) && target_p != source_p)
535 {
536 if (!HasUMode(source_p, UMODE_REGISTERED|UMODE_OPER))
537 {
538 if (p_or_n != NOTICE)
539 sendto_one(source_p, form_str(ERR_NONONREG), me.name, source_p->name,
540 target_p->name);
541 return;
542 }
543 }
544 }
545
546 if (MyClient(target_p))
547 {
548 if (!IsServer(source_p) && HasUMode(target_p, UMODE_CALLERID|UMODE_SOFTCALLERID))
549 {
550 /* Here is the anti-flood bot/spambot code -db */
551 if (accept_message(source_p, target_p) || HasFlag(source_p, FLAGS_SERVICE) ||
552 (HasUMode(source_p, UMODE_OPER) && (ConfigFileEntry.opers_bypass_callerid == 1)))
553 {
554 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
555 source_p->name, source_p->username,
556 source_p->host, command, target_p->name, text);
557 }
558 else
559 {
560 /* check for accept, flag recipient incoming message */
561 if (p_or_n != NOTICE)
562 sendto_one(source_p, form_str(RPL_TARGUMODEG),
563 ID_or_name(&me, source_p->from),
564 ID_or_name(source_p, source_p->from), target_p->name);
565
566 if ((target_p->localClient->last_caller_id_time +
567 ConfigFileEntry.caller_id_wait) < CurrentTime)
568 {
569 if (p_or_n != NOTICE)
570 sendto_one(source_p, form_str(RPL_TARGNOTIFY),
571 ID_or_name(&me, source_p->from),
572 ID_or_name(source_p, source_p->from), target_p->name);
573
574 sendto_one(target_p, form_str(RPL_UMODEGMSG),
575 me.name, target_p->name,
576 get_client_name(source_p, HIDE_IP));
577
578 target_p->localClient->last_caller_id_time = CurrentTime;
579
580 }
581 /* Only so opers can watch for floods */
582 flood_attack_client(p_or_n, source_p, target_p);
583 }
584 }
585 else
586 {
587 /* If the client is remote, we dont perform a special check for
588 * flooding.. as we wouldnt block their message anyway.. this means
589 * we dont give warnings.. we then check if theyre opered
590 * (to avoid flood warnings), lastly if theyre our client
591 * and flooding -- fl */
592 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
593 (MyClient(source_p) &&
594 !flood_attack_client(p_or_n, source_p, target_p)))
595 sendto_anywhere(target_p, source_p, "%s %s :%s",
596 command, target_p->name, text);
597 }
598 }
599 else
600 /* The target is a remote user.. same things apply -- fl */
601 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
602 (MyClient(source_p)
603 && !flood_attack_client(p_or_n, source_p, target_p)))
604 sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name,
605 text);
606 }
607
608 /* flood_attack_client()
609 *
610 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
611 * say NOTICE must not auto reply
612 * - pointer to source Client
613 * - pointer to target Client
614 * output - 1 if target is under flood attack
615 * side effects - check for flood attack on target target_p
616 */
617 static int
618 flood_attack_client(int p_or_n, struct Client *source_p,
619 struct Client *target_p)
620 {
621 int delta;
622
623 if (GlobalSetOptions.floodcount && MyConnect(target_p)
624 && IsClient(source_p) && !IsConfCanFlood(source_p))
625 {
626 if ((target_p->localClient->first_received_message_time + 1)
627 < CurrentTime)
628 {
629 delta =
630 CurrentTime - target_p->localClient->first_received_message_time;
631 target_p->localClient->received_number_of_privmsgs -= delta;
632 target_p->localClient->first_received_message_time = CurrentTime;
633
634 if (target_p->localClient->received_number_of_privmsgs <= 0)
635 {
636 target_p->localClient->received_number_of_privmsgs = 0;
637 DelFlag(target_p, FLAGS_FLOOD_NOTICED);
638 }
639 }
640
641 if ((target_p->localClient->received_number_of_privmsgs >=
642 GlobalSetOptions.floodcount) || HasFlag(target_p, FLAGS_FLOOD_NOTICED))
643 {
644 if (!HasFlag(target_p, FLAGS_FLOOD_NOTICED))
645 {
646 sendto_realops_flags(UMODE_BOTS, L_ALL,
647 "Possible Flooder %s on %s target: %s",
648 get_client_name(source_p, HIDE_IP),
649 source_p->servptr->name, target_p->name);
650 AddFlag(target_p, FLAGS_FLOOD_NOTICED);
651 /* add a bit of penalty */
652 target_p->localClient->received_number_of_privmsgs += 2;
653 }
654
655 if (MyClient(source_p) && (p_or_n != NOTICE))
656 sendto_one(source_p,
657 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
658 me.name, source_p->name, target_p->name);
659 return(1);
660 }
661 else
662 target_p->localClient->received_number_of_privmsgs++;
663 }
664
665 return(0);
666 }
667
668 /* flood_attack_channel()
669 *
670 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
671 * says NOTICE must not auto reply
672 * - pointer to source Client
673 * - pointer to target channel
674 * output - 1 if target is under flood attack
675 * side effects - check for flood attack on target chptr
676 */
677 static int
678 flood_attack_channel(int p_or_n, struct Client *source_p,
679 struct Channel *chptr, char *chname)
680 {
681 int delta;
682
683 if (GlobalSetOptions.floodcount && !IsConfCanFlood(source_p))
684 {
685 if ((chptr->first_received_message_time + 1) < CurrentTime)
686 {
687 delta = CurrentTime - chptr->first_received_message_time;
688 chptr->received_number_of_privmsgs -= delta;
689 chptr->first_received_message_time = CurrentTime;
690 if (chptr->received_number_of_privmsgs <= 0)
691 {
692 chptr->received_number_of_privmsgs = 0;
693 ClearFloodNoticed(chptr);
694 }
695 }
696
697 if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
698 || IsSetFloodNoticed(chptr))
699 {
700 if (!IsSetFloodNoticed(chptr))
701 {
702 sendto_realops_flags(UMODE_BOTS, L_ALL,
703 "Possible Flooder %s on %s target: %s",
704 get_client_name(source_p, HIDE_IP),
705 source_p->servptr->name, chptr->chname);
706 SetFloodNoticed(chptr);
707
708 /* Add a bit of penalty */
709 chptr->received_number_of_privmsgs += 2;
710 }
711 if (MyClient(source_p) && (p_or_n != NOTICE))
712 sendto_one(source_p,
713 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
714 me.name, source_p->name, chname);
715 return(1);
716 }
717 else
718 chptr->received_number_of_privmsgs++;
719 }
720
721 return(0);
722 }
723
724 /* handle_special()
725 *
726 * inputs - server pointer
727 * - client pointer
728 * - nick stuff to grok for opers
729 * - text to send if grok
730 * output - none
731 * side effects - old style username@server is handled here for non opers
732 * opers are allowed username%hostname@server
733 * all the traditional oper type messages are also parsed here.
734 * i.e. "/msg #some.host."
735 * However, syntax has been changed.
736 * previous syntax "/msg #some.host.mask"
737 * now becomes "/msg $#some.host.mask"
738 * previous syntax of: "/msg $some.server.mask" remains
739 * This disambiguates the syntax.
740 *
741 * XXX N.B. dalnet changed it to nick@server as have other servers.
742 * we will stick with tradition for now.
743 * - Dianora
744 */
745 static void
746 handle_special(int p_or_n, const char *command, struct Client *client_p,
747 struct Client *source_p, char *nick, char *text)
748 {
749 struct Client *target_p;
750 char *host;
751 char *server;
752 char *s;
753 int count;
754
755 /*
756 * user[%host]@server addressed?
757 */
758 if ((server = strchr(nick, '@')) != NULL)
759 {
760 count = 0;
761
762 if ((host = strchr(nick, '%')) && !HasUMode(source_p, UMODE_OPER))
763 {
764 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
765 ID_or_name(&me, client_p),
766 ID_or_name(source_p, client_p));
767 return;
768 }
769
770 if ((target_p = hash_find_server(server + 1)) != NULL)
771 {
772 if (!IsMe(target_p))
773 {
774 /*
775 * Not destined for a user on me :-(
776 */
777 sendto_one(target_p, ":%s %s %s :%s",
778 ID_or_name(source_p, target_p->from),
779 command, nick, text);
780 if ((p_or_n != NOTICE) && MyClient(source_p))
781 source_p->localClient->last_privmsg = CurrentTime;
782 return;
783 }
784
785 *server = '\0';
786
787 if (host != NULL)
788 *host++ = '\0';
789
790 /* Check if someones msg'ing opers@our.server */
791 if (strcmp(nick, "opers") == 0)
792 {
793 if (!HasUMode(source_p, UMODE_OPER))
794 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
795 ID_or_name(&me, client_p),
796 ID_or_name(source_p, client_p));
797 else
798 sendto_realops_flags(UMODE_ALL, L_ALL, "To opers: From: %s: %s",
799 source_p->name, text);
800 return;
801 }
802
803 /*
804 * Look for users which match the destination host
805 * (no host == wildcard) and if one and one only is
806 * found connected to me, deliver message!
807 */
808 target_p = find_userhost(nick, host, &count);
809
810 if (target_p != NULL)
811 {
812 if (server != NULL)
813 *server = '@';
814 if (host != NULL)
815 *--host = '%';
816
817 if (count == 1)
818 {
819 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
820 source_p->name, source_p->username, source_p->host,
821 command, nick, text);
822 if ((p_or_n != NOTICE) && MyClient(source_p))
823 source_p->localClient->last_privmsg = CurrentTime;
824 }
825 else
826 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
827 ID_or_name(&me, client_p),
828 ID_or_name(source_p, client_p), nick,
829 ConfigFileEntry.max_targets);
830 }
831 }
832 else if (server && *(server+1) && (target_p == NULL))
833 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
834 ID_or_name(&me, client_p),
835 ID_or_name(source_p, client_p), server+1);
836 else if (server && (target_p == NULL))
837 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
838 ID_or_name(&me, client_p),
839 ID_or_name(source_p, client_p), nick);
840 return;
841 }
842
843 if (!HasUMode(source_p, UMODE_OPER))
844 {
845 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
846 ID_or_name(&me, client_p),
847 ID_or_name(source_p, client_p));
848 return;
849 }
850
851 /*
852 * the following two cases allow masks in NOTICEs
853 * (for OPERs only)
854 *
855 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
856 */
857 if (*nick == '$')
858 {
859 if ((*(nick+1) == '$' || *(nick+1) == '#'))
860 nick++;
861 else if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
862 {
863 sendto_one(source_p,
864 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
865 me.name, source_p->name, command, nick, nick);
866 return;
867 }
868
869 if ((s = strrchr(nick, '.')) == NULL)
870 {
871 sendto_one(source_p, form_str(ERR_NOTOPLEVEL),
872 me.name, source_p->name, nick);
873 return;
874 }
875
876 while (*++s)
877 if (*s == '.' || *s == '*' || *s == '?')
878 break;
879
880 if (*s == '*' || *s == '?')
881 {
882 sendto_one(source_p, form_str(ERR_WILDTOPLEVEL),
883 ID_or_name(&me, client_p),
884 ID_or_name(source_p, client_p), nick);
885 return;
886 }
887
888 sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
889 nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
890 "%s $%s :%s", command, nick, text);
891
892 if ((p_or_n != NOTICE) && MyClient(source_p))
893 source_p->localClient->last_privmsg = CurrentTime;
894
895 return;
896 }
897 }
898
899 /*
900 * find_userhost - find a user@host (server or user).
901 * inputs - user name to look for
902 * - host name to look for
903 * - pointer to count of number of matches found
904 * outputs - pointer to client if found
905 * - count is updated
906 * side effects - none
907 *
908 */
909 static struct Client *
910 find_userhost(char *user, char *host, int *count)
911 {
912 struct Client *c2ptr;
913 struct Client *res = NULL;
914 dlink_node *lc2ptr;
915
916 *count = 0;
917
918 if (collapse(user) != NULL)
919 {
920 DLINK_FOREACH(lc2ptr, local_client_list.head)
921 {
922 c2ptr = lc2ptr->data;
923
924 if (!IsClient(c2ptr)) /* something other than a client */
925 continue;
926
927 if ((!host || match(host, c2ptr->host)) &&
928 irccmp(user, c2ptr->username) == 0)
929 {
930 (*count)++;
931 res = c2ptr;
932 }
933 }
934 }
935
936 return(res);
937 }
938
939 static struct Message privmsg_msgtab = {
940 "PRIVMSG", 0, 0, 0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
941 {m_unregistered, m_privmsg, m_privmsg, m_ignore, m_privmsg, m_ignore}
942 };
943
944 static struct Message notice_msgtab = {
945 "NOTICE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
946 {m_unregistered, m_notice, m_notice, m_ignore, m_notice, m_ignore}
947 };
948
949 static void
950 module_init(void)
951 {
952 mod_add_cmd(&privmsg_msgtab);
953 mod_add_cmd(&notice_msgtab);
954 }
955
956 static void
957 module_exit(void)
958 {
959 mod_del_cmd(&privmsg_msgtab);
960 mod_del_cmd(&notice_msgtab);
961 }
962
963 struct module module_entry = {
964 .node = { NULL, NULL, NULL },
965 .name = NULL,
966 .version = "$Revision$",
967 .handle = NULL,
968 .modinit = module_init,
969 .modexit = module_exit,
970 .flags = MODULE_FLAG_CORE
971 };

Properties

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