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: 4011
Committed: Thu Jun 19 15:56:40 2014 UTC (9 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 21477 byte(s)
Log Message:
- m_message.c:msg_client(): minor optimization

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2014 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
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 entity
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. Its harder to maintain, its
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 *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;
119
120 if (GlobalSetOptions.floodcount && MyConnect(target_p) &&
121 IsClient(source_p) && !IsCanFlood(source_p))
122 {
123 if ((target_p->localClient->first_received_message_time + 1)
124 < CurrentTime)
125 {
126 delta =
127 CurrentTime - target_p->localClient->first_received_message_time;
128 target_p->localClient->received_number_of_privmsgs -= delta;
129 target_p->localClient->first_received_message_time = CurrentTime;
130
131 if (target_p->localClient->received_number_of_privmsgs <= 0)
132 {
133 target_p->localClient->received_number_of_privmsgs = 0;
134 DelFlag(target_p, FLAGS_FLOOD_NOTICED);
135 }
136 }
137
138 if ((target_p->localClient->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->localClient->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->localClient->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;
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->chname);
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->chname);
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->chname, 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->chname, text);
249 else if (result == ERR_NEEDREGGEDNICK)
250 sendto_one_numeric(source_p, &me, ERR_NEEDREGGEDNICK,
251 chptr->chname);
252 else
253 sendto_one_numeric(source_p, &me, ERR_CANNOTSENDTOCHAN,
254 chptr->chname);
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;
276 char c;
277
278 if (flags & CHFL_VOICE)
279 {
280 type = CHFL_VOICE|CHFL_HALFOP|CHFL_CHANOP;
281 c = '+';
282 }
283 else if (flags & CHFL_HALFOP)
284 {
285 type = CHFL_HALFOP|CHFL_CHANOP;
286 c = '%';
287 }
288 else
289 {
290 type = CHFL_CHANOP;
291 c = '@';
292 }
293
294 sendto_channel_butone(source_p, source_p, chptr, type, "%s %c%s :%s",
295 command, c, chptr->chname, text);
296 }
297
298 /* msg_client()
299 *
300 * inputs - flag 0 if PRIVMSG 1 if NOTICE. RFC
301 * say NOTICE must not auto reply
302 * - pointer to command, "PRIVMSG" or "NOTICE"
303 * - pointer to source_p source (struct Client *)
304 * - pointer to target_p target (struct Client *)
305 * - pointer to text
306 * output - NONE
307 * side effects - message given channel either chanop or voice
308 */
309 static void
310 msg_client(int p_or_n, const char *command, struct Client *source_p,
311 struct Client *target_p, const char *text)
312 {
313 if (MyClient(source_p))
314 {
315 if (target_p->away[0] && p_or_n != NOTICE)
316 sendto_one_numeric(source_p, &me, RPL_AWAY, target_p->name, target_p->away);
317
318 if (HasUMode(target_p, UMODE_REGONLY) && target_p != source_p)
319 {
320 if (!HasUMode(source_p, UMODE_REGISTERED|UMODE_OPER))
321 {
322 if (p_or_n != NOTICE)
323 sendto_one_numeric(source_p, &me, ERR_NONONREG, target_p->name);
324 return;
325 }
326 }
327 }
328
329 if (MyClient(target_p))
330 {
331 if (!IsServer(source_p) && HasUMode(target_p, UMODE_CALLERID|UMODE_SOFTCALLERID))
332 {
333 /* Here is the anti-flood bot/spambot code -db */
334 if (HasFlag(source_p, FLAGS_SERVICE) || accept_message(source_p, target_p) ||
335 (HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.opers_bypass_callerid))
336 {
337 sendto_one(target_p, ":%s!%s@%s %s %s :%s",
338 source_p->name, source_p->username,
339 source_p->host, command, target_p->name, text);
340 }
341 else
342 {
343 int callerid = !!HasUMode(target_p, UMODE_CALLERID);
344
345 /* check for accept, flag recipient incoming message */
346 if (p_or_n != NOTICE)
347 sendto_one_numeric(source_p, &me, RPL_TARGUMODEG,
348 target_p->name,
349 callerid ? "+g" : "+G",
350 callerid ? "server side ignore" :
351 "server side ignore with the exception of common channels");
352
353 if ((target_p->localClient->last_caller_id_time +
354 ConfigFileEntry.caller_id_wait) < CurrentTime)
355 {
356 if (p_or_n != NOTICE)
357 sendto_one_numeric(source_p, &me, RPL_TARGNOTIFY, target_p->name);
358
359 sendto_one_numeric(target_p, &me, RPL_UMODEGMSG,
360 get_client_name(source_p, HIDE_IP),
361 callerid ? "+g" : "+G");
362
363 target_p->localClient->last_caller_id_time = CurrentTime;
364
365 }
366
367 /* Only so opers can watch for floods */
368 flood_attack_client(p_or_n, source_p, target_p);
369 }
370 }
371 else
372 {
373 /*
374 * If the client is remote, we dont perform a special check for
375 * flooding.. as we wouldnt block their message anyway.. this means
376 * we dont give warnings.. we then check if theyre opered
377 * (to avoid flood warnings), lastly if theyre our client
378 * and flooding -- fl
379 */
380 if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
381 !flood_attack_client(p_or_n, source_p, target_p))
382 sendto_anywhere(target_p, source_p, command, ":%s", text);
383 }
384 }
385 else if (!MyClient(source_p) || HasUMode(source_p, UMODE_OPER) ||
386 !flood_attack_client(p_or_n, source_p, target_p))
387 sendto_anywhere(target_p, source_p, command, ":%s", text);
388 }
389
390 /* handle_special()
391 *
392 * inputs - client pointer
393 * - nick stuff to grok for opers
394 * - text to send if grok
395 * output - none
396 * side effects - old style username@server is handled here for non opers
397 * opers are allowed username%hostname@server
398 * all the traditional oper type messages are also parsed here.
399 * i.e. "/msg #some.host."
400 * However, syntax has been changed.
401 * previous syntax "/msg #some.host.mask"
402 * now becomes "/msg $#some.host.mask"
403 * previous syntax of: "/msg $some.server.mask" remains
404 * This disambiguates the syntax.
405 *
406 * XXX N.B. dalnet changed it to nick@server as have other servers.
407 * we will stick with tradition for now.
408 * - Dianora
409 */
410 static void
411 handle_special(int p_or_n, const char *command, struct Client *source_p,
412 const char *nick, const char *text)
413 {
414 struct Client *target_p = NULL;
415 const char *server = NULL, *s = NULL;
416
417 /*
418 * user[%host]@server addressed?
419 */
420 if ((server = strchr(nick, '@')))
421 {
422 if ((target_p = hash_find_server(server + 1)) == NULL)
423 {
424 sendto_one_numeric(source_p, &me, ERR_NOSUCHSERVER, server + 1);
425 return;
426 }
427
428 if (!HasUMode(source_p, UMODE_OPER) && strchr(nick, '%'))
429 {
430 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
431 return;
432 }
433
434 if (!IsMe(target_p))
435 {
436 sendto_one(target_p, ":%s %s %s :%s", source_p->id, command, nick, text);
437 return;
438 }
439
440 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
441 return;
442 }
443
444 if (!HasUMode(source_p, UMODE_OPER))
445 {
446 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
447 return;
448 }
449
450 /*
451 * The following two cases allow masks in NOTICEs
452 * (for OPERs only)
453 *
454 * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
455 */
456 if (*nick == '$')
457 {
458 if (*(nick + 1) == '$' || *(nick + 1) == '#')
459 ++nick;
460 else if (MyClient(source_p))
461 {
462 sendto_one_notice(source_p, &me, ":The command %s %s is no longer supported, please use $%s",
463 command, nick, nick);
464 return;
465 }
466
467 if ((s = strrchr(nick, '.')) == NULL)
468 {
469 sendto_one_numeric(source_p, &me, ERR_NOTOPLEVEL, nick);
470 return;
471 }
472
473 while (*++s)
474 if (*s == '.' || *s == '*' || *s == '?')
475 break;
476
477 if (*s == '*' || *s == '?')
478 {
479 sendto_one_numeric(source_p, &me, ERR_WILDTOPLEVEL, nick);
480 return;
481 }
482
483 sendto_match_butone(IsServer(source_p->from) ? source_p->from : NULL, source_p,
484 nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
485 "%s $%s :%s", command, nick, text);
486 }
487 }
488
489 /* build_target_list()
490 *
491 * inputs - pointer to given source (oper/client etc.)
492 * - pointer to list of nicks/channels
493 * - pointer to table to place results
494 * - pointer to text (only used if source_p is an oper)
495 * output - number of valid entities
496 * side effects - target_table is modified to contain a list of
497 * pointers to channels or clients
498 * if source client is an oper
499 * all the classic old bizzare oper privmsg tricks
500 * are parsed and sent as is, if prefixed with $
501 * to disambiguate.
502 *
503 */
504 static int
505 build_target_list(int p_or_n, const char *command, struct Client *source_p,
506 char *nicks_channels, const char *text)
507 {
508 int type = 0;
509 char *p = NULL, *nick = NULL;
510 char *target_list = NULL;
511 struct Channel *chptr = NULL;
512 struct Client *target_p = NULL;
513
514 target_list = nicks_channels;
515
516 ntargets = 0;
517
518 for (nick = strtoken(&p, target_list, ","); nick;
519 nick = strtoken(&p, NULL, ","))
520 {
521 const char *with_prefix = NULL;
522
523 /*
524 * Channels are privmsg'd a lot more than other clients, moved up
525 * here plain old channel msg?
526 */
527 if (IsChanPrefix(*nick))
528 {
529 if ((chptr = hash_find_channel(nick)))
530 {
531 if (!duplicate_ptr(chptr))
532 {
533 if (ntargets >= ConfigFileEntry.max_targets)
534 {
535 sendto_one_numeric(source_p, &me, ERR_TOOMANYTARGETS,
536 nick, ConfigFileEntry.max_targets);
537 return 1;
538 }
539
540 targets[ntargets].ptr = chptr;
541 targets[ntargets++].type = ENTITY_CHANNEL;
542 }
543 }
544 else
545 {
546 if (p_or_n != NOTICE)
547 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
548 }
549
550 continue;
551 }
552
553 /* Look for a PRIVMSG/NOTICE to another client */
554 if ((target_p = find_person(source_p, nick)))
555 {
556 if (!duplicate_ptr(target_p))
557 {
558 if (ntargets >= ConfigFileEntry.max_targets)
559 {
560 sendto_one_numeric(source_p, &me, ERR_TOOMANYTARGETS,
561 nick, ConfigFileEntry.max_targets);
562 return 1;
563 }
564
565 targets[ntargets].ptr = target_p;
566 targets[ntargets].type = ENTITY_CLIENT;
567 targets[ntargets++].flags = 0;
568 }
569
570 continue;
571 }
572
573 /* @#channel or +#channel message ? */
574 type = 0;
575 with_prefix = nick;
576
577 /* Allow %+@ if someone wants to do that */
578 while (1)
579 {
580 if (*nick == '@')
581 type |= CHFL_CHANOP;
582 else if (*nick == '%')
583 type |= CHFL_CHANOP | CHFL_HALFOP;
584 else if (*nick == '+')
585 type |= CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE;
586 else
587 break;
588 ++nick;
589 }
590
591 if (type)
592 {
593 if (EmptyString(nick)) /* If its a '\0' dump it, there is no recipient */
594 {
595 sendto_one_numeric(source_p, &me, ERR_NORECIPIENT, command);
596 continue;
597 }
598
599 /*
600 * At this point, nick+1 should be a channel name i.e. #foo or &foo
601 * if the channel is found, fine, if not report an error
602 */
603 if ((chptr = hash_find_channel(nick)))
604 {
605 if (IsClient(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
606 {
607 if (!has_member_flags(find_channel_link(source_p, chptr),
608 CHFL_CHANOP|CHFL_HALFOP|CHFL_VOICE))
609 {
610 sendto_one_numeric(source_p, &me, ERR_CHANOPRIVSNEEDED, with_prefix);
611 return -1;
612 }
613 }
614
615 if (!duplicate_ptr(chptr))
616 {
617 if (ntargets >= ConfigFileEntry.max_targets)
618 {
619 sendto_one_numeric(source_p, &me, ERR_TOOMANYTARGETS,
620 nick, ConfigFileEntry.max_targets);
621 return 1;
622 }
623
624 targets[ntargets].ptr = chptr;
625 targets[ntargets].type = ENTITY_CHANOPS_ON_CHANNEL;
626 targets[ntargets++].flags = type;
627 }
628 }
629 else
630 {
631 if (p_or_n != NOTICE)
632 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
633 }
634
635 continue;
636 }
637
638 if (*nick == '$' || strchr(nick, '@'))
639 handle_special(p_or_n, command, source_p, nick, text);
640 else
641 {
642 if (p_or_n != NOTICE)
643 {
644 if (!IsDigit(*nick) || MyClient(source_p))
645 sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, nick);
646 }
647 }
648 }
649
650 return 1;
651 }
652
653 /*
654 * inputs - flag privmsg or notice
655 * - pointer to command "PRIVMSG" or "NOTICE"
656 * - pointer to source_p
657 * - pointer to channel
658 */
659 static void
660 m_message(int p_or_n, const char *command, struct Client *source_p, int parc, char *parv[])
661 {
662 if (parc < 2 || EmptyString(parv[1]))
663 {
664 if (p_or_n != NOTICE)
665 sendto_one_numeric(source_p, &me, ERR_NORECIPIENT, command);
666 return;
667 }
668
669 if (parc < 3 || EmptyString(parv[2]))
670 {
671 if (p_or_n != NOTICE)
672 sendto_one_numeric(source_p, &me, ERR_NOTEXTTOSEND);
673 return;
674 }
675
676 /* Finish the flood grace period... */
677 if (MyClient(source_p) && !IsFloodDone(source_p))
678 flood_endgrace(source_p);
679
680 if (build_target_list(p_or_n, command, source_p, parv[1], parv[2]) < 0)
681 return;
682
683 for (unsigned int i = 0; i < ntargets; ++i)
684 {
685 switch (targets[i].type)
686 {
687 case ENTITY_CLIENT:
688 msg_client(p_or_n, command, source_p, targets[i].ptr, parv[2]);
689 break;
690
691 case ENTITY_CHANNEL:
692 msg_channel(p_or_n, command, source_p, targets[i].ptr, parv[2]);
693 break;
694
695 case ENTITY_CHANOPS_ON_CHANNEL:
696 msg_channel_flags(p_or_n, command, source_p, targets[i].ptr,
697 targets[i].flags, parv[2]);
698 break;
699 }
700 }
701 }
702
703 static int
704 m_privmsg(struct Client *source_p, int parc, char *parv[])
705 {
706 /*
707 * Servers have no reason to send privmsgs, yet sometimes there is cause
708 * for a notice.. (for example remote kline replies) --fl_
709 */
710 if (!IsClient(source_p))
711 return 0;
712
713 if (MyConnect(source_p))
714 source_p->localClient->last_privmsg = CurrentTime;
715
716 m_message(PRIVMSG, "PRIVMSG", source_p, parc, parv);
717 return 0;
718 }
719
720 static int
721 m_notice(struct Client *source_p, int parc, char *parv[])
722 {
723 m_message(NOTICE, "NOTICE", source_p, parc, parv);
724 return 0;
725 }
726
727 static struct Message privmsg_msgtab =
728 {
729 "PRIVMSG", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
730 { m_unregistered, m_privmsg, m_privmsg, m_ignore, m_privmsg, m_ignore }
731 };
732
733 static struct Message notice_msgtab =
734 {
735 "NOTICE", 0, 0, 0, MAXPARA, MFLG_SLOW, 0,
736 { m_unregistered, m_notice, m_notice, m_ignore, m_notice, m_ignore }
737 };
738
739 static void
740 module_init(void)
741 {
742 mod_add_cmd(&privmsg_msgtab);
743 mod_add_cmd(&notice_msgtab);
744 }
745
746 static void
747 module_exit(void)
748 {
749 mod_del_cmd(&privmsg_msgtab);
750 mod_del_cmd(&notice_msgtab);
751 }
752
753 struct module module_entry =
754 {
755 .node = { NULL, NULL, NULL },
756 .name = NULL,
757 .version = "$Revision$",
758 .handle = NULL,
759 .modinit = module_init,
760 .modexit = module_exit,
761 .flags = MODULE_FLAG_CORE
762 };

Properties

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