/[svn]/ircd-hybrid-8/modules/core/m_message.c
ViewVC logotype

Contents of /ircd-hybrid-8/modules/core/m_message.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1429 - (show annotations)
Thu Jun 7 19:14:14 2012 UTC (8 years, 1 month ago) by michael
File MIME type: text/x-chdr
File size: 28852 byte(s)
- Unregistered clients may not talk in a +R channel

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 /* ignore send of local channel to a server (should not happen) */
236 if (*nick == '&' && IsServer(client_p))
237 continue;
238
239 if ((chptr = hash_find_channel(nick)) != NULL)
240 {
241 if (!duplicate_ptr(chptr))
242 {
243 if (ntargets >= ConfigFileEntry.max_targets)
244 {
245 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
246 ID_or_name(&me, client_p),
247 ID_or_name(source_p, client_p), nick,
248 ConfigFileEntry.max_targets);
249 return (1);
250 }
251 targets[ntargets].ptr = (void *)chptr;
252 targets[ntargets++].type = ENTITY_CHANNEL;
253 }
254 }
255 else
256 {
257 if (p_or_n != NOTICE)
258 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
259 ID_or_name(&me, client_p),
260 ID_or_name(source_p, client_p), nick);
261 }
262 continue;
263 }
264
265 /* look for a privmsg to another client */
266 if ((target_p = find_person(client_p, nick)) != NULL)
267 {
268 if (!duplicate_ptr(target_p))
269 {
270 if (ntargets >= ConfigFileEntry.max_targets)
271 {
272 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
273 ID_or_name(&me, client_p),
274 ID_or_name(source_p, client_p), nick,
275 ConfigFileEntry.max_targets);
276 return (1);
277 }
278 targets[ntargets].ptr = (void *)target_p;
279 targets[ntargets].type = ENTITY_CLIENT;
280 targets[ntargets++].flags = 0;
281 }
282 continue;
283 }
284
285 /* @#channel or +#channel message ? */
286
287 type = 0;
288 with_prefix = nick;
289 /* allow %+@ if someone wants to do that */
290 for (; ;)
291 {
292 if (*nick == '@')
293 type |= CHFL_CHANOP;
294 #ifdef HALFOPS
295 else if (*nick == '%')
296 type |= CHFL_CHANOP | CHFL_HALFOP;
297 #endif
298 else if (*nick == '+')
299 type |= CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE;
300 else
301 break;
302 nick++;
303 }
304
305 if (type != 0)
306 {
307 /* suggested by Mortiis */
308 if (*nick == '\0') /* if its a '\0' dump it, there is no recipient */
309 {
310 sendto_one(source_p, form_str(ERR_NORECIPIENT),
311 ID_or_name(&me, client_p),
312 ID_or_name(source_p, client_p), command);
313 continue;
314 }
315
316 /* At this point, nick+1 should be a channel name i.e. #foo or &foo
317 * if the channel is found, fine, if not report an error
318 */
319
320 if ((chptr = hash_find_channel(nick)) != NULL)
321 {
322 if (!has_member_flags(find_channel_link(source_p, chptr),
323 CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
324 {
325 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
326 ID_or_name(&me, client_p),
327 ID_or_name(source_p, client_p), with_prefix);
328 return(-1);
329 }
330
331 if (!duplicate_ptr(chptr))
332 {
333 if (ntargets >= ConfigFileEntry.max_targets)
334 {
335 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
336 ID_or_name(&me, client_p),
337 ID_or_name(source_p, client_p), nick,
338 ConfigFileEntry.max_targets);
339 return(1);
340 }
341 targets[ntargets].ptr = (void *)chptr;
342 targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
343 targets[ntargets++].flags = type;
344 }
345 }
346 else
347 {
348 if (p_or_n != NOTICE)
349 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
350 ID_or_name(&me, client_p),
351 ID_or_name(source_p, client_p), nick);
352 }
353 continue;
354 }
355
356 if ((*nick == '$') || strchr(nick, '@') != NULL)
357 {
358 handle_special(p_or_n, command, client_p, source_p, nick, text);
359 }
360 else
361 {
362 if (p_or_n != NOTICE)
363 {
364 if (!IsDigit(*nick) || MyClient(source_p))
365 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
366 ID_or_name(&me, client_p),
367 ID_or_name(source_p, client_p), nick);
368 }
369 }
370 /* continue; */
371 }
372
373 return(1);
374 }
375
376 /* duplicate_ptr()
377 *
378 * inputs - pointer to check
379 * - pointer to table of entities
380 * - number of valid entities so far
381 * output - YES if duplicate pointer in table, NO if not.
382 * note, this does the canonize using pointers
383 * side effects - NONE
384 */
385 static int
386 duplicate_ptr(void *ptr)
387 {
388 int i;
389
390 for (i = 0; i < ntargets; i++)
391 {
392 if (targets[i].ptr == ptr)
393 return(1);
394 }
395
396 return(0);
397 }
398
399 /* msg_channel()
400 *
401 * inputs - flag privmsg or notice
402 * - pointer to command "PRIVMSG" or "NOTICE"
403 * - pointer to client_p
404 * - pointer to source_p
405 * - pointer to channel
406 * output - NONE
407 * side effects - message given channel
408 */
409 static void
410 msg_channel(int p_or_n, const char *command, struct Client *client_p,
411 struct Client *source_p, struct Channel *chptr, char *text)
412 {
413 int result;
414
415 if (MyClient(source_p))
416 {
417 /* idle time shouldnt be reset by notices --fl */
418 if (p_or_n != NOTICE)
419 source_p->localClient->last_privmsg = CurrentTime;
420 }
421
422 /* chanops and voiced can flood their own channel with impunity */
423 if ((result = can_send(chptr, source_p, NULL)) < 0)
424 {
425 if (result == CAN_SEND_OPV ||
426 !flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
427 sendto_channel_butone(client_p, source_p, chptr, command, ":%s", text);
428 }
429 else
430 {
431 if (p_or_n != NOTICE)
432 {
433 if (result == ERR_NEEDREGGEDNICK)
434 sendto_one(source_p, form_str(ERR_NEEDREGGEDNICK),
435 ID_or_name(&me, client_p),
436 ID_or_name(source_p, client_p), chptr->chname);
437 else
438 sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN),
439 ID_or_name(&me, client_p),
440 ID_or_name(source_p, client_p), chptr->chname);
441 }
442 }
443 }
444
445 /* msg_channel_flags()
446 *
447 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
448 * say NOTICE must not auto reply
449 * - pointer to command, "PRIVMSG" or "NOTICE"
450 * - pointer to client_p
451 * - pointer to source_p
452 * - pointer to channel
453 * - flags
454 * - pointer to text to send
455 * output - NONE
456 * side effects - message given channel either chanop or voice
457 */
458 static void
459 msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
460 struct Client *source_p, struct Channel *chptr,
461 int flags, char *text)
462 {
463 int type;
464 char c;
465
466 if (flags & CHFL_VOICE)
467 {
468 type = CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP;
469 c = '+';
470 }
471 #ifdef HALFOPS
472 else if (flags & CHFL_HALFOP)
473 {
474 type = CHFL_HALFOP|CHFL_CHANOP;
475 c = '%';
476 }
477 #endif
478 else
479 {
480 type = CHFL_CHANOP;
481 c = '@';
482 }
483
484 if (MyClient(source_p))
485 {
486 /* idletime shouldnt be reset by notice --fl */
487 if (p_or_n != NOTICE)
488 source_p->localClient->last_privmsg = CurrentTime;
489
490 sendto_channel_local_butone(source_p, type, chptr, ":%s!%s@%s %s %c%s :%s",
491 source_p->name, source_p->username,
492 source_p->host, command, c, chptr->chname, text);
493 }
494 else
495 {
496 /*
497 * another good catch, lee. we never would echo to remote clients anyway,
498 * so use slightly less intensive sendto_channel_local()
499 */
500 sendto_channel_local(type, 1, chptr, ":%s!%s@%s %s %c%s :%s",
501 source_p->name, source_p->username,
502 source_p->host, command, c, chptr->chname, text);
503 }
504
505 if (chptr->chname[0] != '#')
506 return;
507
508 sendto_channel_remote(source_p, client_p, type, CAP_CHW, CAP_TS6, chptr,
509 ":%s %s %c%s :%s", source_p->name, command, c, chptr->chname, text);
510 sendto_channel_remote(source_p, client_p, type, CAP_CHW|CAP_TS6, NOCAPS, chptr,
511 ":%s %s %c%s :%s", ID(source_p), command, c, chptr->chname, text);
512 /* non CAP_CHW servers? */
513 }
514
515 /* msg_client()
516 *
517 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
518 * say NOTICE must not auto reply
519 * - pointer to command, "PRIVMSG" or "NOTICE"
520 * - pointer to source_p source (struct Client *)
521 * - pointer to target_p target (struct Client *)
522 * - pointer to text
523 * output - NONE
524 * side effects - message given channel either chanop or voice
525 */
526 static void
527 msg_client(int p_or_n, const char *command, struct Client *source_p,
528 struct Client *target_p, char *text)
529 {
530 if (MyConnect(source_p))
531 {
532 /*
533 * reset idle time for message only if it's not a notice
534 */
535 if ((p_or_n != NOTICE))
536 source_p->localClient->last_privmsg = CurrentTime;
537
538 if ((p_or_n != NOTICE) && target_p->away)
539 sendto_one(source_p, form_str(RPL_AWAY), me.name,
540 source_p->name, target_p->name, target_p->away);
541
542 if (HasUMode(target_p, UMODE_REGONLY) && target_p != source_p)
543 {
544 if (!HasUMode(source_p, UMODE_REGISTERED|UMODE_OPER))
545 {
546 if (p_or_n != NOTICE)
547 sendto_one(source_p, form_str(ERR_NONONREG), me.name, source_p->name,
548 target_p->name);
549 return;
550 }
551 }
552 }
553
554 if (MyClient(target_p))
555 {
556 if (!IsServer(source_p) && HasUMode(target_p, UMODE_CALLERID|UMODE_SOFTCALLERID))
557 {
558 /* Here is the anti-flood bot/spambot code -db */
559 if (accept_message(source_p, target_p) || HasFlag(source_p, FLAGS_SERVICE) ||
560 (HasUMode(source_p, UMODE_OPER) && (ConfigFileEntry.opers_bypass_callerid == 1)))
561 {
562 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
563 source_p->name, source_p->username,
564 source_p->host, command, target_p->name, text);
565 }
566 else
567 {
568 /* check for accept, flag recipient incoming message */
569 if (p_or_n != NOTICE)
570 sendto_one(source_p, form_str(RPL_TARGUMODEG),
571 ID_or_name(&me, source_p->from),
572 ID_or_name(source_p, source_p->from), target_p->name);
573
574 if ((target_p->localClient->last_caller_id_time +
575 ConfigFileEntry.caller_id_wait) < CurrentTime)
576 {
577 if (p_or_n != NOTICE)
578 sendto_one(source_p, form_str(RPL_TARGNOTIFY),
579 ID_or_name(&me, source_p->from),
580 ID_or_name(source_p, source_p->from), target_p->name);
581
582 sendto_one(target_p, form_str(RPL_UMODEGMSG),
583 me.name, target_p->name,
584 get_client_name(source_p, HIDE_IP));
585
586 target_p->localClient->last_caller_id_time = CurrentTime;
587
588 }
589 /* Only so opers can watch for floods */
590 flood_attack_client(p_or_n, source_p, target_p);
591 }
592 }
593 else
594 {
595 /* If the client is remote, we dont perform a special check for
596 * flooding.. as we wouldnt block their message anyway.. this means
597 * we dont give warnings.. we then check if theyre opered
598 * (to avoid flood warnings), lastly if theyre our client
599 * and flooding -- fl */
600 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
601 (MyClient(source_p) &&
602 !flood_attack_client(p_or_n, source_p, target_p)))
603 sendto_anywhere(target_p, source_p, "%s %s :%s",
604 command, target_p->name, text);
605 }
606 }
607 else
608 /* The target is a remote user.. same things apply -- fl */
609 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
610 (MyClient(source_p)
611 && !flood_attack_client(p_or_n, source_p, target_p)))
612 sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name,
613 text);
614 }
615
616 /* flood_attack_client()
617 *
618 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
619 * say NOTICE must not auto reply
620 * - pointer to source Client
621 * - pointer to target Client
622 * output - 1 if target is under flood attack
623 * side effects - check for flood attack on target target_p
624 */
625 static int
626 flood_attack_client(int p_or_n, struct Client *source_p,
627 struct Client *target_p)
628 {
629 int delta;
630
631 if (GlobalSetOptions.floodcount && MyConnect(target_p)
632 && IsClient(source_p) && !IsConfCanFlood(source_p))
633 {
634 if ((target_p->localClient->first_received_message_time + 1)
635 < CurrentTime)
636 {
637 delta =
638 CurrentTime - target_p->localClient->first_received_message_time;
639 target_p->localClient->received_number_of_privmsgs -= delta;
640 target_p->localClient->first_received_message_time = CurrentTime;
641
642 if (target_p->localClient->received_number_of_privmsgs <= 0)
643 {
644 target_p->localClient->received_number_of_privmsgs = 0;
645 DelFlag(target_p, FLAGS_FLOOD_NOTICED);
646 }
647 }
648
649 if ((target_p->localClient->received_number_of_privmsgs >=
650 GlobalSetOptions.floodcount) || HasFlag(target_p, FLAGS_FLOOD_NOTICED))
651 {
652 if (!HasFlag(target_p, FLAGS_FLOOD_NOTICED))
653 {
654 sendto_realops_flags(UMODE_BOTS, L_ALL,
655 "Possible Flooder %s on %s target: %s",
656 get_client_name(source_p, HIDE_IP),
657 source_p->servptr->name, target_p->name);
658 AddFlag(target_p, FLAGS_FLOOD_NOTICED);
659 /* add a bit of penalty */
660 target_p->localClient->received_number_of_privmsgs += 2;
661 }
662
663 if (MyClient(source_p) && (p_or_n != NOTICE))
664 sendto_one(source_p,
665 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
666 me.name, source_p->name, target_p->name);
667 return(1);
668 }
669 else
670 target_p->localClient->received_number_of_privmsgs++;
671 }
672
673 return(0);
674 }
675
676 /* flood_attack_channel()
677 *
678 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
679 * says NOTICE must not auto reply
680 * - pointer to source Client
681 * - pointer to target channel
682 * output - 1 if target is under flood attack
683 * side effects - check for flood attack on target chptr
684 */
685 static int
686 flood_attack_channel(int p_or_n, struct Client *source_p,
687 struct Channel *chptr, char *chname)
688 {
689 int delta;
690
691 if (GlobalSetOptions.floodcount && !IsConfCanFlood(source_p))
692 {
693 if ((chptr->first_received_message_time + 1) < CurrentTime)
694 {
695 delta = CurrentTime - chptr->first_received_message_time;
696 chptr->received_number_of_privmsgs -= delta;
697 chptr->first_received_message_time = CurrentTime;
698 if (chptr->received_number_of_privmsgs <= 0)
699 {
700 chptr->received_number_of_privmsgs = 0;
701 ClearFloodNoticed(chptr);
702 }
703 }
704
705 if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
706 || IsSetFloodNoticed(chptr))
707 {
708 if (!IsSetFloodNoticed(chptr))
709 {
710 sendto_realops_flags(UMODE_BOTS, L_ALL,
711 "Possible Flooder %s on %s target: %s",
712 get_client_name(source_p, HIDE_IP),
713 source_p->servptr->name, chptr->chname);
714 SetFloodNoticed(chptr);
715
716 /* Add a bit of penalty */
717 chptr->received_number_of_privmsgs += 2;
718 }
719 if (MyClient(source_p) && (p_or_n != NOTICE))
720 sendto_one(source_p,
721 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
722 me.name, source_p->name, chname);
723 return(1);
724 }
725 else
726 chptr->received_number_of_privmsgs++;
727 }
728
729 return(0);
730 }
731
732 /* handle_special()
733 *
734 * inputs - server pointer
735 * - client pointer
736 * - nick stuff to grok for opers
737 * - text to send if grok
738 * output - none
739 * side effects - old style username@server is handled here for non opers
740 * opers are allowed username%hostname@server
741 * all the traditional oper type messages are also parsed here.
742 * i.e. "/msg #some.host."
743 * However, syntax has been changed.
744 * previous syntax "/msg #some.host.mask"
745 * now becomes "/msg $#some.host.mask"
746 * previous syntax of: "/msg $some.server.mask" remains
747 * This disambiguates the syntax.
748 *
749 * XXX N.B. dalnet changed it to nick@server as have other servers.
750 * we will stick with tradition for now.
751 * - Dianora
752 */
753 static void
754 handle_special(int p_or_n, const char *command, struct Client *client_p,
755 struct Client *source_p, char *nick, char *text)
756 {
757 struct Client *target_p;
758 char *host;
759 char *server;
760 char *s;
761 int count;
762
763 /*
764 * user[%host]@server addressed?
765 */
766 if ((server = strchr(nick, '@')) != NULL)
767 {
768 count = 0;
769
770 if ((host = strchr(nick, '%')) && !HasUMode(source_p, UMODE_OPER))
771 {
772 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
773 ID_or_name(&me, client_p),
774 ID_or_name(source_p, client_p));
775 return;
776 }
777
778 if ((target_p = hash_find_server(server + 1)) != NULL)
779 {
780 if (!IsMe(target_p))
781 {
782 /*
783 * Not destined for a user on me :-(
784 */
785 sendto_one(target_p, ":%s %s %s :%s",
786 ID_or_name(source_p, target_p->from),
787 command, nick, text);
788 if ((p_or_n != NOTICE) && MyClient(source_p))
789 source_p->localClient->last_privmsg = CurrentTime;
790 return;
791 }
792
793 *server = '\0';
794
795 if (host != NULL)
796 *host++ = '\0';
797
798 /* Check if someones msg'ing opers@our.server */
799 if (strcmp(nick, "opers") == 0)
800 {
801 if (!HasUMode(source_p, UMODE_OPER))
802 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
803 ID_or_name(&me, client_p),
804 ID_or_name(source_p, client_p));
805 else
806 sendto_realops_flags(UMODE_ALL, L_ALL, "To opers: From: %s: %s",
807 source_p->name, text);
808 return;
809 }
810
811 /*
812 * Look for users which match the destination host
813 * (no host == wildcard) and if one and one only is
814 * found connected to me, deliver message!
815 */
816 target_p = find_userhost(nick, host, &count);
817
818 if (target_p != NULL)
819 {
820 if (server != NULL)
821 *server = '@';
822 if (host != NULL)
823 *--host = '%';
824
825 if (count == 1)
826 {
827 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
828 source_p->name, source_p->username, source_p->host,
829 command, nick, text);
830 if ((p_or_n != NOTICE) && MyClient(source_p))
831 source_p->localClient->last_privmsg = CurrentTime;
832 }
833 else
834 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
835 ID_or_name(&me, client_p),
836 ID_or_name(source_p, client_p), nick,
837 ConfigFileEntry.max_targets);
838 }
839 }
840 else if (server && *(server+1) && (target_p == NULL))
841 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
842 ID_or_name(&me, client_p),
843 ID_or_name(source_p, client_p), server+1);
844 else if (server && (target_p == NULL))
845 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
846 ID_or_name(&me, client_p),
847 ID_or_name(source_p, client_p), nick);
848 return;
849 }
850
851 if (!HasUMode(source_p, UMODE_OPER))
852 {
853 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
854 ID_or_name(&me, client_p),
855 ID_or_name(source_p, client_p));
856 return;
857 }
858
859 /*
860 * the following two cases allow masks in NOTICEs
861 * (for OPERs only)
862 *
863 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
864 */
865 if (*nick == '$')
866 {
867 if ((*(nick+1) == '$' || *(nick+1) == '#'))
868 nick++;
869 else if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
870 {
871 sendto_one(source_p,
872 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
873 me.name, source_p->name, command, nick, nick);
874 return;
875 }
876
877 if ((s = strrchr(nick, '.')) == NULL)
878 {
879 sendto_one(source_p, form_str(ERR_NOTOPLEVEL),
880 me.name, source_p->name, nick);
881 return;
882 }
883
884 while (*++s)
885 if (*s == '.' || *s == '*' || *s == '?')
886 break;
887
888 if (*s == '*' || *s == '?')
889 {
890 sendto_one(source_p, form_str(ERR_WILDTOPLEVEL),
891 ID_or_name(&me, client_p),
892 ID_or_name(source_p, client_p), nick);
893 return;
894 }
895
896 sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
897 nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
898 "%s $%s :%s", command, nick, text);
899
900 if ((p_or_n != NOTICE) && MyClient(source_p))
901 source_p->localClient->last_privmsg = CurrentTime;
902
903 return;
904 }
905 }
906
907 /*
908 * find_userhost - find a user@host (server or user).
909 * inputs - user name to look for
910 * - host name to look for
911 * - pointer to count of number of matches found
912 * outputs - pointer to client if found
913 * - count is updated
914 * side effects - none
915 *
916 */
917 static struct Client *
918 find_userhost(char *user, char *host, int *count)
919 {
920 struct Client *c2ptr;
921 struct Client *res = NULL;
922 dlink_node *lc2ptr;
923
924 *count = 0;
925
926 if (collapse(user) != NULL)
927 {
928 DLINK_FOREACH(lc2ptr, local_client_list.head)
929 {
930 c2ptr = lc2ptr->data;
931
932 if (!IsClient(c2ptr)) /* something other than a client */
933 continue;
934
935 if ((!host || match(host, c2ptr->host)) &&
936 irccmp(user, c2ptr->username) == 0)
937 {
938 (*count)++;
939 res = c2ptr;
940 }
941 }
942 }
943
944 return(res);
945 }
946
947 static struct Message privmsg_msgtab = {
948 "PRIVMSG", 0, 0, 0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
949 {m_unregistered, m_privmsg, m_privmsg, m_ignore, m_privmsg, m_ignore}
950 };
951
952 static struct Message notice_msgtab = {
953 "NOTICE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
954 {m_unregistered, m_notice, m_notice, m_ignore, m_notice, m_ignore}
955 };
956
957 static void
958 module_init(void)
959 {
960 mod_add_cmd(&privmsg_msgtab);
961 mod_add_cmd(&notice_msgtab);
962 }
963
964 static void
965 module_exit(void)
966 {
967 mod_del_cmd(&privmsg_msgtab);
968 mod_del_cmd(&notice_msgtab);
969 }
970
971 struct module module_entry = {
972 .node = { NULL, NULL, NULL },
973 .name = NULL,
974 .version = "$Revision$",
975 .handle = NULL,
976 .modinit = module_init,
977 .modexit = module_exit,
978 .flags = MODULE_FLAG_CORE
979 };

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28