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: 5346
Committed: Sun Jan 11 12:41:14 2015 UTC (9 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 22190 byte(s)
Log Message:
- Update copyright years

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2015 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file m_message.c
23 * \brief Includes required functions for processing the PRIVMSG/NOTICE command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "client.h"
30 #include "ircd.h"
31 #include "numeric.h"
32 #include "conf.h"
33 #include "server.h"
34 #include "send.h"
35 #include "parse.h"
36 #include "modules.h"
37 #include "channel.h"
38 #include "channel_mode.h"
39 #include "irc_string.h"
40 #include "hash.h"
41 #include "packet.h"
42
43
44 enum
45 {
46 PRIVMSG = 0,
47 NOTICE = 1
48 };
49
50 enum
51 {
52 ENTITY_NONE = 0,
53 ENTITY_CHANNEL = 1,
54 ENTITY_CHANOPS_ON_CHANNEL = 2,
55 ENTITY_CLIENT = 3
56 };
57
58 static struct
59 {
60 void *ptr;
61 int type;
62 int flags;
63 } targets[IRCD_BUFSIZE];
64
65 static int unsigned ntargets = 0;
66
67
68 /*
69 ** m_privmsg
70 **
71 ** massive cleanup
72 ** rev argv 6/91
73 **
74 ** Another massive cleanup Nov, 2000
75 ** (I don't think there is a single line left from 6/91. Maybe.)
76 ** m_privmsg and m_notice do basically the same thing.
77 ** in the original 2.8.2 code base, they were the same function
78 ** "m_message.c." When we did the great cleanup in conjuncton with bleep
79 ** of ircu fame, we split m_privmsg.c and m_notice.c.
80 ** I don't see the point of that now. It's harder to maintain, it's
81 ** easier to introduce bugs into one version and not the other etc.
82 ** Really, the penalty of an extra function call isn't that big a deal folks.
83 ** -db Nov 13, 2000
84 **
85 */
86
87 /* duplicate_ptr()
88 *
89 * inputs - pointer to check
90 * - pointer to table of entities
91 * - number of valid entities so far
92 * output - YES if duplicate pointer in table, NO if not.
93 * note, this does the canonize using pointers
94 * side effects - NONE
95 */
96 static int
97 duplicate_ptr(const void *const ptr)
98 {
99 for (unsigned int i = 0; i < ntargets; ++i)
100 if (targets[i].ptr == ptr)
101 return 1;
102
103 return 0;
104 }
105
106 /* flood_attack_client()
107 *
108 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
109 * say NOTICE must not auto reply
110 * - pointer to source Client
111 * - pointer to target Client
112 * output - 1 if target is under flood attack
113 * side effects - check for flood attack on target target_p
114 */
115 static int
116 flood_attack_client(int p_or_n, struct Client *source_p, struct Client *target_p)
117 {
118 int delta = 0;
119
120 if (GlobalSetOptions.floodcount && MyConnect(target_p) &&
121 IsClient(source_p) && !IsCanFlood(source_p))
122 {
123 if ((target_p->connection->first_received_message_time + 1)
124 < CurrentTime)
125 {
126 delta =
127 CurrentTime - target_p->connection->first_received_message_time;
128 target_p->connection->received_number_of_privmsgs -= delta;
129 target_p->connection->first_received_message_time = CurrentTime;
130
131 if (target_p->connection->received_number_of_privmsgs <= 0)
132 {
133 target_p->connection->received_number_of_privmsgs = 0;
134 DelFlag(target_p, FLAGS_FLOOD_NOTICED);
135 }
136 }
137
138 if ((target_p->connection->received_number_of_privmsgs >=
139 GlobalSetOptions.floodcount) || HasFlag(target_p, FLAGS_FLOOD_NOTICED))
140 {
141 if (!HasFlag(target_p, FLAGS_FLOOD_NOTICED))
142 {
143 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
144 "Possible Flooder %s on %s target: %s",
145 get_client_name(source_p, HIDE_IP),
146 source_p->servptr->name, target_p->name);
147
148 AddFlag(target_p, FLAGS_FLOOD_NOTICED);
149 target_p->connection->received_number_of_privmsgs += 2; /* Add a bit of penalty */
150 }
151
152 if (MyClient(source_p) && p_or_n != NOTICE)
153 sendto_one_notice(source_p, &me, ":*** Message to %s throttled due to flooding",
154 target_p->name);
155 return 1;
156 }
157 else
158 target_p->connection->received_number_of_privmsgs++;
159 }
160
161 return 0;
162 }
163
164 /* flood_attack_channel()
165 *
166 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
167 * says NOTICE must not auto reply
168 * - pointer to source Client
169 * - pointer to target channel
170 * output - 1 if target is under flood attack
171 * side effects - check for flood attack on target chptr
172 */
173 static int
174 flood_attack_channel(int p_or_n, struct Client *source_p, struct Channel *chptr)
175 {
176 int delta = 0;
177
178 if (GlobalSetOptions.floodcount && !IsCanFlood(source_p))
179 {
180 if ((chptr->first_received_message_time + 1) < CurrentTime)
181 {
182 delta = CurrentTime - chptr->first_received_message_time;
183 chptr->received_number_of_privmsgs -= delta;
184 chptr->first_received_message_time = CurrentTime;
185
186 if (chptr->received_number_of_privmsgs <= 0)
187 {
188 chptr->received_number_of_privmsgs = 0;
189 ClearFloodNoticed(chptr);
190 }
191 }
192
193 if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount) ||
194 IsSetFloodNoticed(chptr))
195 {
196 if (!IsSetFloodNoticed(chptr))
197 {
198 sendto_realops_flags(UMODE_BOTS, L_ALL, SEND_NOTICE,
199 "Possible Flooder %s on %s target: %s",
200 get_client_name(source_p, HIDE_IP),
201 source_p->servptr->name, chptr->name);
202
203 SetFloodNoticed(chptr);
204 chptr->received_number_of_privmsgs += 2; /* Add a bit of penalty */
205 }
206
207 if (MyClient(source_p) && p_or_n != NOTICE)
208 sendto_one_notice(source_p, &me, ":*** Message to %s throttled due to flooding",
209 chptr->name);
210 return 1;
211 }
212 else
213 chptr->received_number_of_privmsgs++;
214 }
215
216 return 0;
217 }
218
219 /* msg_channel()
220 *
221 * inputs - flag privmsg or notice
222 * - pointer to command "PRIVMSG" or "NOTICE"
223 * - pointer to source_p
224 * - pointer to channel
225 * output - NONE
226 * side effects - message given channel
227 */
228 static void
229 msg_channel(int p_or_n, const char *command, struct Client *source_p,
230 struct Channel *chptr, const char *text)
231 {
232 int result = 0;
233
234 /* Chanops and voiced can flood their own channel with impunity */
235 if ((result = can_send(chptr, source_p, NULL, text)) < 0)
236 {
237 if (result == CAN_SEND_OPV ||
238 !flood_attack_channel(p_or_n, source_p, chptr))
239 sendto_channel_butone(source_p, source_p, chptr, 0, "%s %s :%s",
240 command, chptr->name, text);
241 }
242 else
243 {
244 if (p_or_n != NOTICE)
245 {
246 if (result == ERR_NOCTRLSONCHAN)
247 sendto_one_numeric(source_p, &me, ERR_NOCTRLSONCHAN,
248 chptr->name, text);
249 else if (result == ERR_NEEDREGGEDNICK)
250 sendto_one_numeric(source_p, &me, ERR_NEEDREGGEDNICK,
251 chptr->name);
252 else
253 sendto_one_numeric(source_p, &me, ERR_CANNOTSENDTOCHAN,
254 chptr->name);
255 }
256 }
257 }
258
259 /* msg_channel_flags()
260 *
261 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
262 * say NOTICE must not auto reply
263 * - pointer to command, "PRIVMSG" or "NOTICE"
264 * - pointer to source_p
265 * - pointer to channel
266 * - flags
267 * - pointer to text to send
268 * output - NONE
269 * side effects - message given channel either chanop or voice
270 */
271 static void
272 msg_channel_flags(int p_or_n, const char *command, struct Client *source_p,
273 struct Channel *chptr, int flags, const char *text)
274 {
275 unsigned int type = 0;
276 int result = 0;
277 char c = '\0';
278
279 if (flags & CHFL_VOICE)
280 {
281 type = CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP;
282 c = '+';
283 }
284 else if (flags & CHFL_HALFOP)
285 {
286 type = CHFL_HALFOP|CHFL_CHANOP;
287 c = '%';
288 }
289 else
290 {
291 type = CHFL_CHANOP;
292 c = '@';
293 }
294
295 /* Chanops and voiced can flood their own channel with impunity */
296 if ((result = can_send(chptr, source_p, NULL, text)) < 0)
297 {
298 if (result == CAN_SEND_OPV ||
299 !flood_attack_channel(p_or_n, source_p, chptr))
300 sendto_channel_butone(source_p, source_p, chptr, type, "%s %c%s :%s",
301 command, c, chptr->name, text);
302 }
303 else
304 {
305 if (p_or_n != NOTICE)
306 {
307 if (result == ERR_NOCTRLSONCHAN)
308 sendto_one_numeric(source_p, &me, ERR_NOCTRLSONCHAN,
309 chptr->name, text);
310 else if (result == ERR_NEEDREGGEDNICK)
311 sendto_one_numeric(source_p, &me, ERR_NEEDREGGEDNICK,
312 chptr->name);
313 else
314 sendto_one_numeric(source_p, &me, ERR_CANNOTSENDTOCHAN,
315 chptr->name);
316 }
317 }
318 }
319
320 /* msg_client()
321 *
322 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
323 * say NOTICE must not auto reply
324 * - pointer to command, "PRIVMSG" or "NOTICE"
325 * - pointer to source_p source (struct Client *)
326 * - pointer to target_p target (struct Client *)
327 * - pointer to text
328 * output - NONE
329 * side effects - message given channel either chanop or voice
330 */
331 static void
332 msg_client(int p_or_n, const char *command, struct Client *source_p,
333 struct Client *target_p, const char *text)
334 {
335 if (MyClient(source_p))
336 {
337 if (target_p->away[0] && p_or_n != NOTICE)
338 sendto_one_numeric(source_p, &me, RPL_AWAY, target_p->name, target_p->away);
339
340 if (HasUMode(target_p, UMODE_REGONLY) && target_p != source_p)
341 {
342 if (!HasUMode(source_p, UMODE_REGISTERED|UMODE_OPER))
343 {
344 if (p_or_n != NOTICE)
345 sendto_one_numeric(source_p, &me, ERR_NONONREG, target_p->name);
346 return;
347 }
348 }
349 }
350
351 if (MyClient(target_p))
352 {
353 if (!IsServer(source_p) && HasUMode(target_p, UMODE_CALLERID|UMODE_SOFTCALLERID))
354 {
355 /* Here is the anti-flood bot/spambot code -db */
356 if (HasFlag(source_p, FLAGS_SERVICE) || accept_message(source_p, target_p) ||
357 (HasUMode(source_p, UMODE_OPER) && ConfigGeneral.opers_bypass_callerid))
358 {
359 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
360 source_p->name, source_p->username,
361 source_p->host, command, target_p->name, text);
362 }
363 else
364 {
365 int callerid = !!HasUMode(target_p, UMODE_CALLERID);
366
367 /* check for accept, flag recipient incoming message */
368 if (p_or_n != NOTICE)
369 sendto_one_numeric(source_p, &me, RPL_TARGUMODEG,
370 target_p->name,
371 callerid ? "+g" : "+G",
372 callerid ? "server side ignore" :
373 "server side ignore with the exception of common channels");
374
375 if ((target_p->connection->last_caller_id_time +
376 ConfigGeneral.caller_id_wait) < CurrentTime)
377 {
378 if (p_or_n != NOTICE)
379 sendto_one_numeric(source_p, &me, RPL_TARGNOTIFY, target_p->name);
380
381 sendto_one_numeric(target_p, &me, RPL_UMODEGMSG,
382 get_client_name(source_p, HIDE_IP),
383 callerid ? "+g" : "+G");
384
385 target_p->connection->last_caller_id_time = CurrentTime;
386
387 }
388
389 /* Only so opers can watch for floods */
390 flood_attack_client(p_or_n, source_p, target_p);
391 }
392 }
393 else
394 {
395 /*
396 * If the client is remote, we dont perform a special check for
397 * flooding.. as we wouldn't block their message anyway.. this means
398 * we dont give warnings.. we then check if theyre opered
399 * (to avoid flood warnings), lastly if theyre our client
400 * and flooding -- fl
401 */
402 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
403 !flood_attack_client(p_or_n, source_p, target_p))
404 sendto_anywhere(target_p, source_p, command, ":%s", text);
405 }
406 }
407 else if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
408 !flood_attack_client(p_or_n, source_p, target_p))
409 sendto_anywhere(target_p, source_p, command, ":%s", text);
410 }
411
412 /* handle_special()
413 *
414 * inputs - client pointer
415 * - nick stuff to grok for opers
416 * - text to send if grok
417 * output - none
418 * side effects - old style username@server is handled here for non opers
419 * opers are allowed username%hostname@server
420 * all the traditional oper type messages are also parsed here.
421 * i.e. "/msg #some.host."
422 * However, syntax has been changed.
423 * previous syntax "/msg #some.host.mask"
424 * now becomes "/msg $#some.host.mask"
425 * previous syntax of: "/msg $some.server.mask" remains
426 * This disambiguates the syntax.
427 *
428 * XXX N.B. dalnet changed it to nick@server as have other servers.
429 * we will stick with tradition for now.
430 * - Dianora
431 */
432 static void
433 handle_special(int p_or_n, const char *command, struct Client *source_p,
434 const char *nick, const char *text)
435 {
436 struct Client *target_p = NULL;
437 const char *server = NULL, *s = NULL;
438
439 /*
440 * user[%host]@server addressed?
441 */
442 if ((server = strchr(nick, '@')))
443 {
444 if ((target_p = hash_find_server(server + 1)) == NULL)
445 {
446 sendto_one_numeric(source_p, &me, ERR_NOSUCHSERVER, server + 1);
447 return;
448 }
449
450 if (!HasUMode(source_p, UMODE_OPER) && strchr(nick, '%'))
451 {
452 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
453 return;
454 }
455
456 if (!IsMe(target_p))
457 {
458 sendto_one(target_p, ":%s %s %s :%s", source_p->id, command, nick, text);
459 return;
460 }
461
462 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
463 return;
464 }
465
466 if (!HasUMode(source_p, UMODE_OPER))
467 {
468 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
469 return;
470 }
471
472 /*
473 * The following two cases allow masks in NOTICEs
474 * (for OPERs only)
475 *
476 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
477 */
478 if (*nick == '$')
479 {
480 if (*(nick + 1) == '$' || *(nick + 1) == '#')
481 ++nick;
482 else if (MyClient(source_p))
483 {
484 sendto_one_notice(source_p, &me, ":The command %s %s is no longer supported, please use $%s",
485 command, nick, nick);
486 return;
487 }
488
489 if ((s = strrchr(nick, '.')) == NULL)
490 {
491 sendto_one_numeric(source_p, &me, ERR_NOTOPLEVEL, nick);
492 return;
493 }
494
495 while (*++s)
496 if (*s == '.' || *s == '*' || *s == '?')
497 break;
498
499 if (*s == '*' || *s == '?')
500 {
501 sendto_one_numeric(source_p, &me, ERR_WILDTOPLEVEL, nick);
502 return;
503 }
504
505 sendto_match_butone(IsServer(source_p->from) ? source_p->from : NULL, source_p,
506 nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
507 "%s $%s :%s", command, nick, text);
508 }
509 }
510
511 /* build_target_list()
512 *
513 * inputs - pointer to given source (oper/client etc.)
514 * - pointer to list of nicks/channels
515 * - pointer to table to place results
516 * - pointer to text (only used if source_p is an oper)
517 * output - number of valid entities
518 * side effects - target_table is modified to contain a list of
519 * pointers to channels or clients
520 * if source client is an oper
521 * all the classic old bizzare oper privmsg tricks
522 * are parsed and sent as is, if prefixed with $
523 * to disambiguate.
524 *
525 */
526 static int
527 build_target_list(int p_or_n, const char *command, struct Client *source_p,
528 char *nicks_channels, const char *text)
529 {
530 int type = 0;
531 char *p = NULL, *nick = NULL;
532 char *target_list = NULL;
533 struct Channel *chptr = NULL;
534 struct Client *target_p = NULL;
535
536 target_list = nicks_channels;
537
538 ntargets = 0;
539
540 for (nick = strtoken(&p, target_list, ","); nick;
541 nick = strtoken(&p, NULL, ","))
542 {
543 const char *with_prefix = NULL;
544
545 /*
546 * Channels are privmsg'd a lot more than other clients, moved up
547 * here plain old channel msg?
548 */
549 if (IsChanPrefix(*nick))
550 {
551 if ((chptr = hash_find_channel(nick)))
552 {
553 if (!duplicate_ptr(chptr))
554 {
555 if (ntargets >= ConfigGeneral.max_targets)
556 {
557 sendto_one_numeric(source_p, &me, ERR_TOOMANYTARGETS,
558 nick, ConfigGeneral.max_targets);
559 return 1;
560 }
561
562 targets[ntargets].ptr = chptr;
563 targets[ntargets++].type = ENTITY_CHANNEL;
564 }
565 }
566 else
567 {
568 if (p_or_n != NOTICE)
569 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
570 }
571
572 continue;
573 }
574
575 /* Look for a PRIVMSG/NOTICE to another client */
576 if ((target_p = find_person(source_p, nick)))
577 {
578 if (!duplicate_ptr(target_p))
579 {
580 if (ntargets >= ConfigGeneral.max_targets)
581 {
582 sendto_one_numeric(source_p, &me, ERR_TOOMANYTARGETS,
583 nick, ConfigGeneral.max_targets);
584 return 1;
585 }
586
587 targets[ntargets].ptr = target_p;
588 targets[ntargets].type = ENTITY_CLIENT;
589 targets[ntargets++].flags = 0;
590 }
591
592 continue;
593 }
594
595 /* @#channel or +#channel message ? */
596 type = 0;
597 with_prefix = nick;
598
599 /* Allow %+@ if someone wants to do that */
600 while (1)
601 {
602 if (*nick == '@')
603 type |= CHFL_CHANOP;
604 else if (*nick == '%')
605 type |= CHFL_CHANOP | CHFL_HALFOP;
606 else if (*nick == '+')
607 type |= CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE;
608 else
609 break;
610 ++nick;
611 }
612
613 if (type)
614 {
615 if (EmptyString(nick)) /* If it's a '\0' dump it, there is no recipient */
616 {
617 sendto_one_numeric(source_p, &me, ERR_NORECIPIENT, command);
618 continue;
619 }
620
621 /*
622 * At this point, nick+1 should be a channel name i.e. #foo or &foo
623 * if the channel is found, fine, if not report an error
624 */
625 if ((chptr = hash_find_channel(nick)))
626 {
627 if (IsClient(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
628 {
629 if (!has_member_flags(find_channel_link(source_p, chptr),
630 CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
631 {
632 sendto_one_numeric(source_p, &me, ERR_CHANOPRIVSNEEDED, with_prefix);
633 return -1;
634 }
635 }
636
637 if (!duplicate_ptr(chptr))
638 {
639 if (ntargets >= ConfigGeneral.max_targets)
640 {
641 sendto_one_numeric(source_p, &me, ERR_TOOMANYTARGETS,
642 nick, ConfigGeneral.max_targets);
643 return 1;
644 }
645
646 targets[ntargets].ptr = chptr;
647 targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
648 targets[ntargets++].flags = type;
649 }
650 }
651 else
652 {
653 if (p_or_n != NOTICE)
654 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
655 }
656
657 continue;
658 }
659
660 if (*nick == '$' || strchr(nick, '@'))
661 handle_special(p_or_n, command, source_p, nick, text);
662 else
663 {
664 if (p_or_n != NOTICE)
665 {
666 if (!IsDigit(*nick) || MyClient(source_p))
667 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
668 }
669 }
670 }
671
672 return 1;
673 }
674
675 /*
676 * inputs - flag privmsg or notice
677 * - pointer to command "PRIVMSG" or "NOTICE"
678 * - pointer to source_p
679 * - pointer to channel
680 */
681 static void
682 m_message(int p_or_n, const char *command, struct Client *source_p, int parc, char *parv[])
683 {
684 if (parc < 2 || EmptyString(parv[1]))
685 {
686 if (p_or_n != NOTICE)
687 sendto_one_numeric(source_p, &me, ERR_NORECIPIENT, command);
688 return;
689 }
690
691 if (parc < 3 || EmptyString(parv[2]))
692 {
693 if (p_or_n != NOTICE)
694 sendto_one_numeric(source_p, &me, ERR_NOTEXTTOSEND);
695 return;
696 }
697
698 /* Finish the flood grace period... */
699 if (MyClient(source_p) && !IsFloodDone(source_p))
700 flood_endgrace(source_p);
701
702 if (build_target_list(p_or_n, command, source_p, parv[1], parv[2]) < 0)
703 return;
704
705 for (unsigned int i = 0; i < ntargets; ++i)
706 {
707 switch (targets[i].type)
708 {
709 case ENTITY_CLIENT:
710 msg_client(p_or_n, command, source_p, targets[i].ptr, parv[2]);
711 break;
712
713 case ENTITY_CHANNEL:
714 msg_channel(p_or_n, command, source_p, targets[i].ptr, parv[2]);
715 break;
716
717 case ENTITY_CHANOPS_ON_CHANNEL:
718 msg_channel_flags(p_or_n, command, source_p, targets[i].ptr,
719 targets[i].flags, parv[2]);
720 break;
721 }
722 }
723 }
724
725 static int
726 m_privmsg(struct Client *source_p, int parc, char *parv[])
727 {
728 /*
729 * Servers have no reason to send privmsgs, yet sometimes there is cause
730 * for a notice.. (for example remote kline replies) --fl_
731 */
732 if (!IsClient(source_p))
733 return 0;
734
735 if (MyConnect(source_p))
736 source_p->connection->last_privmsg = CurrentTime;
737
738 m_message(PRIVMSG, "PRIVMSG", source_p, parc, parv);
739 return 0;
740 }
741
742 static int
743 m_notice(struct Client *source_p, int parc, char *parv[])
744 {
745 m_message(NOTICE, "NOTICE", source_p, parc, parv);
746 return 0;
747 }
748
749 static struct Message privmsg_msgtab =
750 {
751 "PRIVMSG", NULL, 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
752 { m_unregistered, m_privmsg, m_privmsg, m_ignore, m_privmsg, m_ignore }
753 };
754
755 static struct Message notice_msgtab =
756 {
757 "NOTICE", NULL, 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
758 { m_unregistered, m_notice, m_notice, m_ignore, m_notice, m_ignore }
759 };
760
761 static void
762 module_init(void)
763 {
764 mod_add_cmd(&privmsg_msgtab);
765 mod_add_cmd(&notice_msgtab);
766 }
767
768 static void
769 module_exit(void)
770 {
771 mod_del_cmd(&privmsg_msgtab);
772 mod_del_cmd(&notice_msgtab);
773 }
774
775 struct module module_entry =
776 {
777 .node = { NULL, NULL, NULL },
778 .name = NULL,
779 .version = "$Revision$",
780 .handle = NULL,
781 .modinit = module_init,
782 .modexit = module_exit,
783 .flags = MODULE_FLAG_CORE
784 };

Properties

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