ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_gline.c
Revision: 1474
Committed: Sun Jul 22 14:44:07 2012 UTC (14 years, 2 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/modules/m_gline.c
File size: 19247 byte(s)
Log Message:
- removed &localchannels

File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     *
4     * Copyright (C) 2002 by the past and present ircd coders, and others.
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 michael 1008 /*! \file m_gline.c
23     * \brief Includes required functions for processing the GLINE command.
24     * \version $Id$
25     */
26    
27 adx 30 #include "stdinc.h"
28 michael 1011 #include "list.h"
29 adx 30 #include "s_gline.h"
30     #include "channel.h"
31     #include "client.h"
32     #include "irc_string.h"
33     #include "sprintf_irc.h"
34     #include "ircd.h"
35     #include "hostmask.h"
36     #include "numeric.h"
37     #include "s_bsd.h"
38 michael 1309 #include "conf.h"
39 adx 30 #include "s_misc.h"
40     #include "send.h"
41     #include "s_serv.h"
42     #include "hash.h"
43     #include "parse.h"
44     #include "modules.h"
45 michael 1309 #include "log.h"
46 adx 30
47     #define GLINE_NOT_PLACED 0
48     #define GLINE_ALREADY_VOTED -1
49     #define GLINE_PLACED 1
50    
51    
52 michael 1009 /*! \brief Adds a GLINE to the configuration subsystem.
53     *
54     * \param source_p Operator requesting gline
55     * \param user Username covered by the gline
56     * \param host Hostname covered by the gline
57     * \param reason Reason for the gline
58     */
59     static void
60     set_local_gline(const struct Client *source_p, const char *user,
61     const char *host, const char *reason)
62     {
63     char buffer[IRCD_BUFSIZE];
64     struct ConfItem *conf;
65     struct AccessItem *aconf;
66 michael 1008
67    
68 michael 1009 conf = make_conf_item(GLINE_TYPE);
69     aconf = map_to_conf(conf);
70    
71     snprintf(buffer, sizeof(buffer), "%s (%s)", reason, smalldate(CurrentTime));
72     DupString(aconf->reason, buffer);
73     DupString(aconf->user, user);
74     DupString(aconf->host, host);
75    
76     aconf->hold = CurrentTime + ConfigFileEntry.gline_time;
77 michael 1369 SetConfTemporary(aconf);
78     add_conf_by_address(CONF_GLINE, aconf);
79 michael 1009
80     sendto_realops_flags(UMODE_ALL, L_ALL,
81     "%s added G-Line for [%s@%s] [%s]",
82     get_oper_name(source_p),
83     aconf->user, aconf->host, aconf->reason);
84 michael 1247 ilog(LOG_TYPE_GLINE, "%s added G-Line for [%s@%s] [%s]",
85 michael 1009 get_oper_name(source_p), aconf->user, aconf->host, aconf->reason);
86 michael 1247
87 michael 1009 /* Now, activate gline against current online clients */
88     rehashed_klines = 1;
89     }
90    
91     /*! \brief Removes a GLINE from the configuration subsystem.
92     *
93     * \param user Username covered by the gline
94     * \param host Hostname covered by the gline
95     */
96     static int
97     remove_gline_match(const char *user, const char *host)
98     {
99 michael 1369 struct irc_ssaddr iphost, *piphost;
100 michael 1009 struct AccessItem *aconf;
101 michael 1369 int t;
102 michael 1009
103 michael 1369 if ((t = parse_netmask(host, &iphost, NULL)) != HM_HOST)
104 michael 1009 {
105     #ifdef IPV6
106 michael 1369 if (t == HM_IPV6)
107     t = AF_INET6;
108     else
109 michael 1009 #endif
110 michael 1369 t = AF_INET;
111     piphost = &iphost;
112     }
113     else
114     {
115     t = 0;
116     piphost = NULL;
117     }
118    
119 michael 1371 if ((aconf = find_conf_by_address(host, piphost, CONF_GLINE, t, user, NULL, 0)))
120 michael 1369 {
121     if (IsConfTemporary(aconf))
122 michael 1009 {
123 michael 1369 delete_one_address_conf(host, aconf);
124 michael 1009 return 1;
125     }
126     }
127    
128     return 0;
129     }
130    
131 michael 1008 /*! \brief This function is called once a majority of opers have agreed on a
132     * GLINE/GUNGLINE, and it can be placed. The information about an
133     * operator being passed to us happens to be the operator who pushed us
134     * over the "majority" level needed. See check_majority() for more
135     * information.
136 adx 30 *
137 michael 1008 * \param source_p Operator requesting gline
138     * \param user Username covered by the gline
139     * \param host Hostname covered by the gline
140     * \param reason Reason for the gline
141     * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
142     * GLINE_PENDING_DEL_TYPE
143 adx 30 */
144 michael 1008 static void
145     add_new_majority(const struct Client *source_p, const char *user,
146     const char *host, const char *reason, const unsigned int type)
147     {
148     struct gline_pending *pending = MyMalloc(sizeof(struct gline_pending));
149    
150     strlcpy(pending->vote_1.oper_nick, source_p->name, sizeof(pending->vote_1.oper_nick));
151     strlcpy(pending->vote_1.oper_user, source_p->username, sizeof(pending->vote_1.oper_user));
152     strlcpy(pending->vote_1.oper_host, source_p->host, sizeof(pending->vote_1.oper_host));
153     strlcpy(pending->vote_1.oper_server, source_p->servptr->name, sizeof(pending->vote_1.oper_server));
154    
155     strlcpy(pending->user, user, sizeof(pending->user));
156     strlcpy(pending->host, host, sizeof(pending->host));
157     strlcpy(pending->vote_1.reason, reason, sizeof(pending->vote_1.reason));
158    
159     pending->last_gline_time = CurrentTime;
160     pending->vote_1.time_request = CurrentTime;
161    
162     dlinkAdd(pending, &pending->node, &pending_glines[type]);
163     }
164    
165     /*! \brief See if there is a majority agreement on a GLINE on the given user.
166     * There must be at least 3 different opers agreeing on this
167     * GLINE/GUNGLINE
168 adx 30 *
169 michael 1008 * \param source_p Operator requesting gline
170     * \param user Username covered by the gline
171     * \param host Hostname covered by the gline
172     * \param reason Reason for the gline
173     * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
174     * GLINE_PENDING_DEL_TYPE
175     *
176     * \return
177     * - GLINE_ALREADY_VOTED returned if oper/server has already voted
178     * - GLINE_PLACED returned if this triggers a gline
179     * - GLINE_NOT_PLACED returned if not triggered
180 adx 30 */
181 michael 1008 static int
182     check_majority(const struct Client *source_p, const char *user,
183     const char *host, const char *reason, const int type)
184 adx 30 {
185 michael 1008 dlink_node *dn_ptr = NULL;
186 adx 30
187 michael 1008 cleanup_glines(NULL);
188 adx 30
189 michael 1008 /* if its already glined, why bother? :) -- fl_ */
190     if ((type == GLINE_PENDING_ADD_TYPE) && find_is_glined(host, user))
191     return GLINE_NOT_PLACED;
192    
193     DLINK_FOREACH(dn_ptr, pending_glines[type].head)
194 adx 30 {
195 michael 1008 struct gline_pending *gp_ptr = dn_ptr->data;
196 adx 30
197 michael 1008 if (irccmp(gp_ptr->user, user) ||
198     irccmp(gp_ptr->host, host))
199     continue;
200 adx 30
201 michael 1008 if ((!irccmp(gp_ptr->vote_1.oper_user, source_p->username) &&
202     !irccmp(gp_ptr->vote_1.oper_host, source_p->host)) ||
203     !irccmp(gp_ptr->vote_1.oper_server, source_p->servptr->name))
204     return GLINE_ALREADY_VOTED;
205    
206     if (gp_ptr->vote_2.oper_user[0] != '\0')
207 adx 30 {
208 michael 1008 /* if two other opers on two different servers have voted yes */
209     if ((!irccmp(gp_ptr->vote_2.oper_user, source_p->username) &&
210     !irccmp(gp_ptr->vote_2.oper_host, source_p->host)) ||
211     !irccmp(gp_ptr->vote_2.oper_server, source_p->servptr->name))
212     return GLINE_ALREADY_VOTED;
213    
214     if (type == GLINE_PENDING_DEL_TYPE)
215     {
216     if (remove_gline_match(user, host))
217     {
218     sendto_realops_flags(UMODE_ALL, L_ALL,
219     "%s has removed the G-Line for: [%s@%s]",
220     get_oper_name(source_p), user, host);
221 michael 1247 ilog(LOG_TYPE_GLINE, "%s removed G-Line for [%s@%s]",
222 michael 1008 get_oper_name(source_p), user, host);
223     }
224     }
225     else
226     /* trigger the gline using the original reason --fl */
227     set_local_gline(source_p, user, host, gp_ptr->vote_1.reason);
228    
229     cleanup_glines(gp_ptr);
230     return GLINE_PLACED;
231 adx 30 }
232 michael 1008
233     strlcpy(gp_ptr->vote_2.oper_nick, source_p->name,
234     sizeof(gp_ptr->vote_2.oper_nick));
235     strlcpy(gp_ptr->vote_2.oper_user, source_p->username,
236     sizeof(gp_ptr->vote_2.oper_user));
237     strlcpy(gp_ptr->vote_2.oper_host, source_p->host,
238     sizeof(gp_ptr->vote_2.oper_host));
239     strlcpy(gp_ptr->vote_2.reason, reason,
240     sizeof(gp_ptr->vote_2.reason));
241     strlcpy(gp_ptr->vote_2.oper_server, source_p->servptr->name,
242     sizeof(gp_ptr->vote_2.oper_server));
243     gp_ptr->last_gline_time = CurrentTime;
244     gp_ptr->vote_2.time_request = CurrentTime;
245     return GLINE_NOT_PLACED;
246 adx 30 }
247    
248 michael 552 /*
249 michael 1008 * Didn't find this user@host gline in pending gline list
250     * so add it.
251 adx 30 */
252 michael 1008 add_new_majority(source_p, user, host, reason, type);
253     return GLINE_NOT_PLACED;
254 adx 30 }
255    
256     static void
257 michael 1008 do_sgline(struct Client *source_p, int parc, char *parv[], int prop)
258 adx 30 {
259     const char *reason = NULL; /* reason for "victims" demise */
260 michael 1463 const char *user = NULL;
261     const char *host = NULL; /* user and host of GLINE "victim" */
262 michael 1008 struct Client *target_p = NULL;
263 adx 30
264 michael 1008 switch (parc)
265 adx 30 {
266 michael 1008 case 4: /* hyb-7 style */
267     if (!IsClient(source_p))
268     return;
269     break;
270     case 8: /* hyb-6 style */
271     if (!IsServer(source_p))
272     return;
273     target_p = find_person(source_p->from, parv[1]);
274     if (target_p == NULL || target_p->servptr != source_p)
275     return;
276 michael 1459 source_p = target_p;
277 michael 1008 break;
278     default:
279 adx 30 return;
280     }
281    
282     assert(source_p->servptr != NULL);
283    
284 michael 1459 user = parv[parc - 3];
285     host = parv[parc - 2];
286     reason = parv[parc - 1];
287 adx 30
288 michael 1474 sendto_server(source_p->from, CAP_GLN|CAP_TS6, NOCAPS,
289 michael 1459 ":%s GLINE %s %s :%s",
290 michael 1463 ID(source_p), user, host, reason);
291 michael 1474 sendto_server(source_p->from, CAP_GLN, CAP_TS6,
292 michael 1463 ":%s GLINE %s %s :%s",
293 michael 1459 source_p->name, user, host, reason);
294 michael 1463
295 michael 1459 /* hyb-6 version to the rest */
296 michael 1474 sendto_server(source_p->from, NOCAPS, CAP_GLN,
297 michael 1459 ":%s GLINE %s %s %s %s %s %s :%s",
298     source_p->servptr->name,
299     source_p->name, source_p->username, source_p->host,
300     source_p->servptr->name,
301     user, host, reason);
302 michael 1011
303 adx 30 if (ConfigFileEntry.glines)
304     {
305 michael 1243 if (!valid_wild_card(source_p, 1, 2, user, host))
306 adx 30 return;
307    
308     if (IsClient(source_p))
309     {
310     const char *p = NULL;
311 michael 958
312 adx 30 if ((p = strchr(host, '/')))
313     {
314     int bitlen = strtol(++p, NULL, 10);
315     int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
316     ConfigFileEntry.gline_min_cidr;
317    
318     if (bitlen < min_bitlen)
319     {
320     sendto_realops_flags(UMODE_ALL, L_ALL, "%s!%s@%s on %s is requesting "
321     "a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
322     source_p->name, source_p->username, source_p->host,
323     source_p->servptr->name, min_bitlen, user, host, reason);
324     return;
325     }
326     }
327     }
328    
329     /* If at least 3 opers agree this user should be G lined then do it */
330 michael 988 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
331 adx 30 GLINE_ALREADY_VOTED)
332     {
333     sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
334     return;
335     }
336    
337 michael 554 sendto_realops_flags(UMODE_ALL, L_ALL,
338     "%s requesting G-Line for [%s@%s] [%s]",
339     get_oper_name(source_p),
340     user, host, reason);
341 michael 1247 ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s",
342 adx 30 user, host, reason, get_oper_name(source_p));
343     }
344     }
345    
346 michael 1008
347     /*! \brief GLINE command handler (called by operators)
348 adx 30 *
349 michael 1008 * \param client_p Pointer to allocated Client struct with physical connection
350     * to this server, i.e. with an open socket connected.
351     * \param source_p Pointer to allocated Client struct from which the message
352     * originally comes from. This can be a local or remote client.
353     * \param parc Integer holding the number of supplied arguments.
354     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
355     * pointers.
356     * \note Valid arguments for this command are:
357     * - parv[0] = sender prefix
358     * - parv[1] = user\@host mask
359     * - parv[2] = reason
360 adx 30 */
361     static void
362 michael 1008 mo_gline(struct Client *client_p, struct Client *source_p,
363     int parc, char *parv[])
364 adx 30 {
365 michael 1008 char *user = NULL;
366     char *host = NULL;
367     char *reason = NULL;
368     char *p;
369 adx 30
370 michael 1463 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
371 michael 1008 {
372 michael 1463 sendto_one(source_p, form_str(ERR_NOPRIVS),
373     me.name, source_p->name, "gline");
374 michael 1008 return;
375     }
376 adx 30
377 michael 1463 if (!ConfigFileEntry.glines)
378 michael 1008 {
379 michael 1463 sendto_one(source_p, ":%s NOTICE %s :GLINE disabled",
380     me.name, source_p->name);
381 michael 1008 return;
382     }
383 adx 30
384 michael 1008 if (parse_aline("GLINE", source_p, parc, parv, AWILD,
385     &user, &host, NULL, NULL, &reason) < 0)
386     return;
387 adx 30
388 michael 1008 if ((p = strchr(host, '/')) != NULL)
389 adx 30 {
390 michael 1008 int bitlen = strtol(++p, NULL, 10);
391     int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
392     ConfigFileEntry.gline_min_cidr;
393     if (bitlen < min_bitlen)
394 adx 30 {
395 michael 1008 sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with CIDR length < %d",
396     me.name, source_p->name, min_bitlen);
397     return;
398 michael 957 }
399 adx 30 }
400 michael 1008
401     /* If at least 3 opers agree this user should be G lined then do it */
402     if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
403     GLINE_ALREADY_VOTED)
404     {
405     sendto_one(source_p,
406     ":%s NOTICE %s :This server or oper has already voted",
407     me.name, source_p->name);
408     return;
409     }
410 adx 30
411 michael 957 /*
412 michael 1008 * call these two functions first so the 'requesting' notice always comes
413     * before the 'has triggered' notice. -bill
414 adx 30 */
415 michael 1008 sendto_realops_flags(UMODE_ALL, L_ALL,
416     "%s requesting G-Line for [%s@%s] [%s]",
417     get_oper_name(source_p),
418     user, host, reason);
419 michael 1247 ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s!%s@%s",
420 michael 1008 user, host, reason, source_p->name, source_p->username,
421     source_p->host);
422 adx 30
423 michael 1008 /* 4 param version for hyb-7 servers */
424 michael 1474 sendto_server(NULL, CAP_GLN|CAP_TS6, NOCAPS,
425 michael 1008 ":%s GLINE %s %s :%s",
426     ID(source_p), user, host, reason);
427 michael 1474 sendto_server(NULL, CAP_GLN, CAP_TS6,
428 michael 1008 ":%s GLINE %s %s :%s",
429     source_p->name, user, host, reason);
430 adx 30
431 michael 1008 /* 8 param for hyb-6 */
432 michael 1474 sendto_server(NULL, NOCAPS, CAP_GLN|CAP_TS6,
433 michael 1008 ":%s GLINE %s %s %s %s %s %s :%s",
434     me.name, source_p->name, source_p->username,
435     source_p->host, source_p->servptr->name, user, host,
436     reason);
437 adx 30 }
438    
439 michael 1008 /* ms_gline()
440     * me_gline()
441     * do_sgline()
442 db 937 *
443     * inputs - The usual for a m_ function
444     * output -
445     * side effects -
446     *
447 michael 1008 * Place a G line if 3 opers agree on the identical user@host
448 db 937 *
449 michael 1008 * Allow this server to pass along GLINE if received and
450     * GLINES is not defined.
451     *
452     * ENCAP'd GLINES are propagated by encap code.
453 db 937 */
454    
455     static void
456 michael 1008 ms_gline(struct Client *client_p, struct Client *source_p,
457     int parc, char *parv[])
458 db 937 {
459 michael 1008 do_sgline(source_p, parc, parv, 1);
460 db 937 }
461    
462     static void
463 michael 1008 me_gline(struct Client *client_p, struct Client *source_p,
464     int parc, char *parv[])
465     {
466     do_sgline(source_p, parc, parv, 0);
467     }
468    
469     static void
470 michael 1006 do_sungline(struct Client *source_p, const char *user,
471     const char *host, const char *reason, int prop)
472 db 937 {
473     assert(source_p->servptr != NULL);
474    
475 michael 957 sendto_realops_flags(UMODE_ALL, L_ALL,
476     "%s requesting UNG-Line for [%s@%s] [%s]",
477 michael 1006 get_oper_name(source_p), user, host, reason);
478 michael 1247 ilog(LOG_TYPE_GLINE, "#ungline for %s@%s [%s] requested by %s",
479 michael 957 user, host, reason, get_oper_name(source_p));
480 db 937
481 michael 957 /* If at least 3 opers agree this user should be un G lined then do it */
482 michael 958 if (check_majority(source_p, user, host, reason, GLINE_PENDING_DEL_TYPE) ==
483 michael 957 GLINE_ALREADY_VOTED)
484     sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
485 michael 1006
486     if (prop)
487     {
488 michael 1474 sendto_server(source_p->from, CAP_ENCAP|CAP_TS6, NOCAPS,
489 michael 1006 ":%s ENCAP * GUNGLINE %s %s :%s",
490     ID(source_p), user, host, reason);
491 michael 1474 sendto_server(source_p->from, CAP_ENCAP, CAP_TS6,
492 michael 1006 ":%s ENCAP * GUNGLINE %s %s :%s",
493     source_p->name, user, host, reason);
494     }
495 db 937 }
496    
497 michael 1008 /*! \brief GUNGLINE command handler (called in response to an encapsulated
498     * GUNGLINE command)
499 db 937 *
500 michael 1008 * \param client_p Pointer to allocated Client struct with physical connection
501     * to this server, i.e. with an open socket connected.
502     * \param source_p Pointer to allocated Client struct from which the message
503     * originally comes from. This can be a local or remote client.
504     * \param parc Integer holding the number of supplied arguments.
505     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
506     * pointers.
507     * \note Valid arguments for this command are:
508     * - parv[0] = sender prefix
509     * - parv[1] = username
510     * - parv[2] = hostname
511     * - parv[3] = reason
512 db 937 */
513 michael 1008 static void
514     me_gungline(struct Client *client_p, struct Client *source_p,
515     int parc, char *parv[])
516     {
517     if (ConfigFileEntry.glines)
518     do_sungline(source_p, parv[1], parv[2], parv[3], 0);
519     }
520    
521     /*! \brief GUNGLINE command handler (called by operators)
522 db 937 *
523 michael 1008 * \param client_p Pointer to allocated Client struct with physical connection
524     * to this server, i.e. with an open socket connected.
525     * \param source_p Pointer to allocated Client struct from which the message
526     * originally comes from. This can be a local or remote client.
527     * \param parc Integer holding the number of supplied arguments.
528     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
529     * pointers.
530     * \note Valid arguments for this command are:
531     * - parv[0] = sender prefix
532     * - parv[1] = user\@host mask
533     * - parv[2] = reason
534 db 937 */
535     static void
536 db 940 mo_gungline(struct Client *client_p, struct Client *source_p,
537 michael 957 int parc, char *parv[])
538 db 937 {
539     char *user = NULL;
540 michael 1008 char *host = NULL;
541     char *reason = NULL;
542 db 937
543 michael 1463 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
544 db 937 {
545 michael 1463 sendto_one(source_p, form_str(ERR_NOPRIVS),
546     me.name, source_p->name, "gline");
547 db 937 return;
548     }
549    
550 michael 1463 if (!ConfigFileEntry.glines)
551 db 937 {
552 michael 1463 sendto_one(source_p, ":%s NOTICE %s :GUNGLINE disabled",
553     me.name, source_p->name);
554 db 937 return;
555     }
556    
557 michael 957 if (parse_aline("GUNGLINE", source_p, parc, parv, 0, &user,
558     &host, NULL, NULL, &reason) < 0)
559 db 937 return;
560    
561 michael 1006 do_sungline(source_p, user, host, reason, 1);
562 db 937 }
563 michael 1230
564     /*
565     * gline enforces 3 parameters to force operator to give a reason
566     * a gline is not valid with "No reason"
567     * -db
568     */
569     static struct Message gline_msgtab = {
570     "GLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
571     { m_unregistered, m_not_oper, ms_gline, me_gline, mo_gline, m_ignore }
572     };
573    
574     static struct Message ungline_msgtab = {
575     "GUNGLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
576     { m_unregistered, m_not_oper, m_ignore, me_gungline, mo_gungline, m_ignore }
577     };
578    
579     static void
580     module_init(void)
581     {
582     mod_add_cmd(&gline_msgtab);
583     mod_add_cmd(&ungline_msgtab);
584     add_capability("GLN", CAP_GLN, 1);
585     }
586    
587     static void
588     module_exit(void)
589     {
590     mod_del_cmd(&gline_msgtab);
591     mod_del_cmd(&ungline_msgtab);
592     delete_capability("GLN");
593     }
594    
595     struct module module_entry = {
596     .node = { NULL, NULL, NULL },
597     .name = NULL,
598     .version = "$Revision$",
599     .handle = NULL,
600     .modinit = module_init,
601     .modexit = module_exit,
602     .flags = 0
603     };

Properties

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