/[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 1474 - (show annotations)
Sun Jul 22 14:44:07 2012 UTC (10 years, 6 months ago) by michael
File MIME type: text/x-chdr
File size: 28473 byte(s)
- removed &localchannels

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

Properties

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

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