ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/modules/core/m_message.c
Revision: 1480
Committed: Sun Jul 22 17:25:34 2012 UTC (14 years ago) by michael
Content type: text/x-csrc
File size: 27664 byte(s)
Log Message:
- flood_attack_channel(): remove useless argument

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);
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))
426 sendto_channel_butone(client_p, source_p, chptr, 0, "%s %s :%s",
427 command, chptr->chname, text);
428 }
429 else
430 {
431 if (p_or_n != NOTICE)
432 sendto_one(source_p, form_str(ERR_CANNOTSENDTOCHAN),
433 ID_or_name(&me, client_p),
434 ID_or_name(source_p, client_p), chptr->chname);
435 }
436 }
437
438 /* msg_channel_flags()
439 *
440 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
441 * say NOTICE must not auto reply
442 * - pointer to command, "PRIVMSG" or "NOTICE"
443 * - pointer to client_p
444 * - pointer to source_p
445 * - pointer to channel
446 * - flags
447 * - pointer to text to send
448 * output - NONE
449 * side effects - message given channel either chanop or voice
450 */
451 static void
452 msg_channel_flags(int p_or_n, const char *command, struct Client *client_p,
453 struct Client *source_p, struct Channel *chptr,
454 int flags, char *text)
455 {
456 unsigned int type;
457 char c;
458
459 if (flags & CHFL_VOICE)
460 {
461 type = CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP;
462 c = '+';
463 }
464 #ifdef HALFOPS
465 else if (flags & CHFL_HALFOP)
466 {
467 type = CHFL_HALFOP|CHFL_CHANOP;
468 c = '%';
469 }
470 #endif
471 else
472 {
473 type = CHFL_CHANOP;
474 c = '@';
475 }
476
477 if (MyClient(source_p) && p_or_n != NOTICE)
478 source_p->localClient->last_privmsg = CurrentTime;
479
480 sendto_channel_butone(client_p, source_p, chptr, type, "%s %c%s :%s",
481 command, c, chptr->chname, text);
482 }
483
484 /* msg_client()
485 *
486 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
487 * say NOTICE must not auto reply
488 * - pointer to command, "PRIVMSG" or "NOTICE"
489 * - pointer to source_p source (struct Client *)
490 * - pointer to target_p target (struct Client *)
491 * - pointer to text
492 * output - NONE
493 * side effects - message given channel either chanop or voice
494 */
495 static void
496 msg_client(int p_or_n, const char *command, struct Client *source_p,
497 struct Client *target_p, char *text)
498 {
499 if (MyConnect(source_p))
500 {
501 /*
502 * reset idle time for message only if it's not a notice
503 */
504 if ((p_or_n != NOTICE))
505 source_p->localClient->last_privmsg = CurrentTime;
506
507 if ((p_or_n != NOTICE) && target_p->away)
508 sendto_one(source_p, form_str(RPL_AWAY), me.name,
509 source_p->name, target_p->name, target_p->away);
510
511 if (HasUMode(target_p, UMODE_REGONLY) && target_p != source_p)
512 {
513 if (!HasUMode(source_p, UMODE_REGISTERED|UMODE_OPER))
514 {
515 if (p_or_n != NOTICE)
516 sendto_one(source_p, form_str(ERR_NONONREG), me.name, source_p->name,
517 target_p->name);
518 return;
519 }
520 }
521 }
522
523 if (MyClient(target_p))
524 {
525 if (!IsServer(source_p) && HasUMode(target_p, UMODE_CALLERID|UMODE_SOFTCALLERID))
526 {
527 /* Here is the anti-flood bot/spambot code -db */
528 if (accept_message(source_p, target_p) || HasFlag(source_p, FLAGS_SERVICE) ||
529 (HasUMode(source_p, UMODE_OPER) && (ConfigFileEntry.opers_bypass_callerid == 1)))
530 {
531 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
532 source_p->name, source_p->username,
533 source_p->host, command, target_p->name, text);
534 }
535 else
536 {
537 /* check for accept, flag recipient incoming message */
538 if (p_or_n != NOTICE)
539 sendto_one(source_p, form_str(RPL_TARGUMODEG),
540 ID_or_name(&me, source_p->from),
541 ID_or_name(source_p, source_p->from), target_p->name);
542
543 if ((target_p->localClient->last_caller_id_time +
544 ConfigFileEntry.caller_id_wait) < CurrentTime)
545 {
546 if (p_or_n != NOTICE)
547 sendto_one(source_p, form_str(RPL_TARGNOTIFY),
548 ID_or_name(&me, source_p->from),
549 ID_or_name(source_p, source_p->from), target_p->name);
550
551 sendto_one(target_p, form_str(RPL_UMODEGMSG),
552 me.name, target_p->name,
553 get_client_name(source_p, HIDE_IP));
554
555 target_p->localClient->last_caller_id_time = CurrentTime;
556
557 }
558 /* Only so opers can watch for floods */
559 flood_attack_client(p_or_n, source_p, target_p);
560 }
561 }
562 else
563 {
564 /* If the client is remote, we dont perform a special check for
565 * flooding.. as we wouldnt block their message anyway.. this means
566 * we dont give warnings.. we then check if theyre opered
567 * (to avoid flood warnings), lastly if theyre our client
568 * and flooding -- fl */
569 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
570 (MyClient(source_p) &&
571 !flood_attack_client(p_or_n, source_p, target_p)))
572 sendto_anywhere(target_p, source_p, "%s %s :%s",
573 command, target_p->name, text);
574 }
575 }
576 else
577 /* The target is a remote user.. same things apply -- fl */
578 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
579 (MyClient(source_p)
580 && !flood_attack_client(p_or_n, source_p, target_p)))
581 sendto_anywhere(target_p, source_p, "%s %s :%s", command, target_p->name,
582 text);
583 }
584
585 /* flood_attack_client()
586 *
587 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
588 * say NOTICE must not auto reply
589 * - pointer to source Client
590 * - pointer to target Client
591 * output - 1 if target is under flood attack
592 * side effects - check for flood attack on target target_p
593 */
594 static int
595 flood_attack_client(int p_or_n, struct Client *source_p,
596 struct Client *target_p)
597 {
598 int delta;
599
600 if (GlobalSetOptions.floodcount && MyConnect(target_p)
601 && IsClient(source_p) && !IsConfCanFlood(source_p))
602 {
603 if ((target_p->localClient->first_received_message_time + 1)
604 < CurrentTime)
605 {
606 delta =
607 CurrentTime - target_p->localClient->first_received_message_time;
608 target_p->localClient->received_number_of_privmsgs -= delta;
609 target_p->localClient->first_received_message_time = CurrentTime;
610
611 if (target_p->localClient->received_number_of_privmsgs <= 0)
612 {
613 target_p->localClient->received_number_of_privmsgs = 0;
614 DelFlag(target_p, FLAGS_FLOOD_NOTICED);
615 }
616 }
617
618 if ((target_p->localClient->received_number_of_privmsgs >=
619 GlobalSetOptions.floodcount) || HasFlag(target_p, FLAGS_FLOOD_NOTICED))
620 {
621 if (!HasFlag(target_p, FLAGS_FLOOD_NOTICED))
622 {
623 sendto_realops_flags(UMODE_BOTS, L_ALL,
624 "Possible Flooder %s on %s target: %s",
625 get_client_name(source_p, HIDE_IP),
626 source_p->servptr->name, target_p->name);
627 AddFlag(target_p, FLAGS_FLOOD_NOTICED);
628 /* add a bit of penalty */
629 target_p->localClient->received_number_of_privmsgs += 2;
630 }
631
632 if (MyClient(source_p) && (p_or_n != NOTICE))
633 sendto_one(source_p,
634 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
635 me.name, source_p->name, target_p->name);
636 return(1);
637 }
638 else
639 target_p->localClient->received_number_of_privmsgs++;
640 }
641
642 return(0);
643 }
644
645 /* flood_attack_channel()
646 *
647 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
648 * says NOTICE must not auto reply
649 * - pointer to source Client
650 * - pointer to target channel
651 * output - 1 if target is under flood attack
652 * side effects - check for flood attack on target chptr
653 */
654 static int
655 flood_attack_channel(int p_or_n, struct Client *source_p,
656 struct Channel *chptr)
657 {
658 int delta;
659
660 if (GlobalSetOptions.floodcount && !IsConfCanFlood(source_p))
661 {
662 if ((chptr->first_received_message_time + 1) < CurrentTime)
663 {
664 delta = CurrentTime - chptr->first_received_message_time;
665 chptr->received_number_of_privmsgs -= delta;
666 chptr->first_received_message_time = CurrentTime;
667 if (chptr->received_number_of_privmsgs <= 0)
668 {
669 chptr->received_number_of_privmsgs = 0;
670 ClearFloodNoticed(chptr);
671 }
672 }
673
674 if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
675 || IsSetFloodNoticed(chptr))
676 {
677 if (!IsSetFloodNoticed(chptr))
678 {
679 sendto_realops_flags(UMODE_BOTS, L_ALL,
680 "Possible Flooder %s on %s target: %s",
681 get_client_name(source_p, HIDE_IP),
682 source_p->servptr->name, chptr->chname);
683 SetFloodNoticed(chptr);
684
685 /* Add a bit of penalty */
686 chptr->received_number_of_privmsgs += 2;
687 }
688 if (MyClient(source_p) && (p_or_n != NOTICE))
689 sendto_one(source_p,
690 ":%s NOTICE %s :*** Message to %s throttled due to flooding",
691 me.name, source_p->name, chptr->chname);
692 return(1);
693 }
694 else
695 chptr->received_number_of_privmsgs++;
696 }
697
698 return(0);
699 }
700
701 /* handle_special()
702 *
703 * inputs - server pointer
704 * - client pointer
705 * - nick stuff to grok for opers
706 * - text to send if grok
707 * output - none
708 * side effects - old style username@server is handled here for non opers
709 * opers are allowed username%hostname@server
710 * all the traditional oper type messages are also parsed here.
711 * i.e. "/msg #some.host."
712 * However, syntax has been changed.
713 * previous syntax "/msg #some.host.mask"
714 * now becomes "/msg $#some.host.mask"
715 * previous syntax of: "/msg $some.server.mask" remains
716 * This disambiguates the syntax.
717 *
718 * XXX N.B. dalnet changed it to nick@server as have other servers.
719 * we will stick with tradition for now.
720 * - Dianora
721 */
722 static void
723 handle_special(int p_or_n, const char *command, struct Client *client_p,
724 struct Client *source_p, char *nick, char *text)
725 {
726 struct Client *target_p;
727 char *host;
728 char *server;
729 char *s;
730 int count;
731
732 /*
733 * user[%host]@server addressed?
734 */
735 if ((server = strchr(nick, '@')) != NULL)
736 {
737 count = 0;
738
739 if ((host = strchr(nick, '%')) && !HasUMode(source_p, UMODE_OPER))
740 {
741 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
742 ID_or_name(&me, client_p),
743 ID_or_name(source_p, client_p));
744 return;
745 }
746
747 if ((target_p = hash_find_server(server + 1)) != NULL)
748 {
749 if (!IsMe(target_p))
750 {
751 /*
752 * Not destined for a user on me :-(
753 */
754 sendto_one(target_p, ":%s %s %s :%s",
755 ID_or_name(source_p, target_p->from),
756 command, nick, text);
757 if ((p_or_n != NOTICE) && MyClient(source_p))
758 source_p->localClient->last_privmsg = CurrentTime;
759 return;
760 }
761
762 *server = '\0';
763
764 if (host != NULL)
765 *host++ = '\0';
766
767 /* Check if someones msg'ing opers@our.server */
768 if (strcmp(nick, "opers") == 0)
769 {
770 if (!HasUMode(source_p, UMODE_OPER))
771 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
772 ID_or_name(&me, client_p),
773 ID_or_name(source_p, client_p));
774 else
775 sendto_realops_flags(UMODE_ALL, L_ALL, "To opers: From: %s: %s",
776 source_p->name, text);
777 return;
778 }
779
780 /*
781 * Look for users which match the destination host
782 * (no host == wildcard) and if one and one only is
783 * found connected to me, deliver message!
784 */
785 target_p = find_userhost(nick, host, &count);
786
787 if (target_p != NULL)
788 {
789 if (server != NULL)
790 *server = '@';
791 if (host != NULL)
792 *--host = '%';
793
794 if (count == 1)
795 {
796 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
797 source_p->name, source_p->username, source_p->host,
798 command, nick, text);
799 if ((p_or_n != NOTICE) && MyClient(source_p))
800 source_p->localClient->last_privmsg = CurrentTime;
801 }
802 else
803 sendto_one(source_p, form_str(ERR_TOOMANYTARGETS),
804 ID_or_name(&me, client_p),
805 ID_or_name(source_p, client_p), nick,
806 ConfigFileEntry.max_targets);
807 }
808 }
809 else if (server && *(server+1) && (target_p == NULL))
810 sendto_one(source_p, form_str(ERR_NOSUCHSERVER),
811 ID_or_name(&me, client_p),
812 ID_or_name(source_p, client_p), server+1);
813 else if (server && (target_p == NULL))
814 sendto_one(source_p, form_str(ERR_NOSUCHNICK),
815 ID_or_name(&me, client_p),
816 ID_or_name(source_p, client_p), nick);
817 return;
818 }
819
820 if (!HasUMode(source_p, UMODE_OPER))
821 {
822 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
823 ID_or_name(&me, client_p),
824 ID_or_name(source_p, client_p));
825 return;
826 }
827
828 /*
829 * the following two cases allow masks in NOTICEs
830 * (for OPERs only)
831 *
832 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
833 */
834 if (*nick == '$')
835 {
836 if ((*(nick+1) == '$' || *(nick+1) == '#'))
837 nick++;
838 else if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
839 {
840 sendto_one(source_p,
841 ":%s NOTICE %s :The command %s %s is no longer supported, please use $%s",
842 me.name, source_p->name, command, nick, nick);
843 return;
844 }
845
846 if ((s = strrchr(nick, '.')) == NULL)
847 {
848 sendto_one(source_p, form_str(ERR_NOTOPLEVEL),
849 me.name, source_p->name, nick);
850 return;
851 }
852
853 while (*++s)
854 if (*s == '.' || *s == '*' || *s == '?')
855 break;
856
857 if (*s == '*' || *s == '?')
858 {
859 sendto_one(source_p, form_str(ERR_WILDTOPLEVEL),
860 ID_or_name(&me, client_p),
861 ID_or_name(source_p, client_p), nick);
862 return;
863 }
864
865 sendto_match_butone(IsServer(client_p) ? client_p : NULL, source_p,
866 nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
867 "%s $%s :%s", command, nick, text);
868
869 if ((p_or_n != NOTICE) && MyClient(source_p))
870 source_p->localClient->last_privmsg = CurrentTime;
871
872 return;
873 }
874 }
875
876 /*
877 * find_userhost - find a user@host (server or user).
878 * inputs - user name to look for
879 * - host name to look for
880 * - pointer to count of number of matches found
881 * outputs - pointer to client if found
882 * - count is updated
883 * side effects - none
884 *
885 */
886 static struct Client *
887 find_userhost(char *user, char *host, int *count)
888 {
889 struct Client *c2ptr;
890 struct Client *res = NULL;
891 dlink_node *lc2ptr;
892
893 *count = 0;
894
895 if (collapse(user) != NULL)
896 {
897 DLINK_FOREACH(lc2ptr, local_client_list.head)
898 {
899 c2ptr = lc2ptr->data;
900
901 if (!IsClient(c2ptr)) /* something other than a client */
902 continue;
903
904 if ((!host || match(host, c2ptr->host)) &&
905 irccmp(user, c2ptr->username) == 0)
906 {
907 (*count)++;
908 res = c2ptr;
909 }
910 }
911 }
912
913 return(res);
914 }
915
916 static struct Message privmsg_msgtab = {
917 "PRIVMSG", 0, 0, 0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
918 {m_unregistered, m_privmsg, m_privmsg, m_ignore, m_privmsg, m_ignore}
919 };
920
921 static struct Message notice_msgtab = {
922 "NOTICE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
923 {m_unregistered, m_notice, m_notice, m_ignore, m_notice, m_ignore}
924 };
925
926 static void
927 module_init(void)
928 {
929 mod_add_cmd(&privmsg_msgtab);
930 mod_add_cmd(&notice_msgtab);
931 }
932
933 static void
934 module_exit(void)
935 {
936 mod_del_cmd(&privmsg_msgtab);
937 mod_del_cmd(&notice_msgtab);
938 }
939
940 struct module module_entry = {
941 .node = { NULL, NULL, NULL },
942 .name = NULL,
943 .version = "$Revision$",
944 .handle = NULL,
945 .modinit = module_init,
946 .modexit = module_exit,
947 .flags = MODULE_FLAG_CORE
948 };

Properties

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