ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_gline.c
Revision: 1459
Committed: Fri Jul 6 14:23:09 2012 UTC (13 years, 1 month ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/modules/m_gline.c
File size: 19347 byte(s)
Log Message:
- remove g-line acls
- added general::gline_request_duration configuration option which
  simply replaces the harcoded PENDING_GLINE_TIME definition

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     char *user = NULL;
261     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 1459 sendto_server(source_p->from, NULL, CAP_GLN, NOCAPS,
289     ":%s GLINE %s %s :%s",
290     source_p->name, user, host, reason);
291     /* hyb-6 version to the rest */
292     sendto_server(source_p->from, NULL, NOCAPS, CAP_GLN,
293     ":%s GLINE %s %s %s %s %s %s :%s",
294     source_p->servptr->name,
295     source_p->name, source_p->username, source_p->host,
296     source_p->servptr->name,
297     user, host, reason);
298 michael 1011
299 adx 30 if (ConfigFileEntry.glines)
300     {
301 michael 1243 if (!valid_wild_card(source_p, 1, 2, user, host))
302 adx 30 return;
303    
304     if (IsClient(source_p))
305     {
306     const char *p = NULL;
307 michael 958
308 adx 30 if ((p = strchr(host, '/')))
309     {
310     int bitlen = strtol(++p, NULL, 10);
311     int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
312     ConfigFileEntry.gline_min_cidr;
313    
314     if (bitlen < min_bitlen)
315     {
316     sendto_realops_flags(UMODE_ALL, L_ALL, "%s!%s@%s on %s is requesting "
317     "a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
318     source_p->name, source_p->username, source_p->host,
319     source_p->servptr->name, min_bitlen, user, host, reason);
320     return;
321     }
322     }
323     }
324    
325     /* If at least 3 opers agree this user should be G lined then do it */
326 michael 988 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
327 adx 30 GLINE_ALREADY_VOTED)
328     {
329     sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
330     return;
331     }
332    
333 michael 554 sendto_realops_flags(UMODE_ALL, L_ALL,
334     "%s requesting G-Line for [%s@%s] [%s]",
335     get_oper_name(source_p),
336     user, host, reason);
337 michael 1247 ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s",
338 adx 30 user, host, reason, get_oper_name(source_p));
339     }
340     }
341    
342 michael 1008
343     /*! \brief GLINE command handler (called by operators)
344 adx 30 *
345 michael 1008 * \param client_p Pointer to allocated Client struct with physical connection
346     * to this server, i.e. with an open socket connected.
347     * \param source_p Pointer to allocated Client struct from which the message
348     * originally comes from. This can be a local or remote client.
349     * \param parc Integer holding the number of supplied arguments.
350     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
351     * pointers.
352     * \note Valid arguments for this command are:
353     * - parv[0] = sender prefix
354     * - parv[1] = user\@host mask
355     * - parv[2] = reason
356 adx 30 */
357     static void
358 michael 1008 mo_gline(struct Client *client_p, struct Client *source_p,
359     int parc, char *parv[])
360 adx 30 {
361 michael 1008 char *user = NULL;
362     char *host = NULL;
363     char *reason = NULL;
364     char *p;
365 adx 30
366 michael 1008 if (!ConfigFileEntry.glines)
367     {
368     sendto_one(source_p, ":%s NOTICE %s :GLINE disabled",
369     me.name, source_p->name);
370     return;
371     }
372 adx 30
373 michael 1219 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
374 michael 1008 {
375     sendto_one(source_p, form_str(ERR_NOPRIVS),
376     me.name, source_p->name, "gline");
377     return;
378     }
379 adx 30
380 michael 1008 if (parse_aline("GLINE", source_p, parc, parv, AWILD,
381     &user, &host, NULL, NULL, &reason) < 0)
382     return;
383 adx 30
384 michael 1008 if ((p = strchr(host, '/')) != NULL)
385 adx 30 {
386 michael 1008 int bitlen = strtol(++p, NULL, 10);
387     int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
388     ConfigFileEntry.gline_min_cidr;
389     if (bitlen < min_bitlen)
390 adx 30 {
391 michael 1008 sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with CIDR length < %d",
392     me.name, source_p->name, min_bitlen);
393     return;
394 michael 957 }
395 adx 30 }
396 michael 1008
397     /* If at least 3 opers agree this user should be G lined then do it */
398     if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
399     GLINE_ALREADY_VOTED)
400     {
401     sendto_one(source_p,
402     ":%s NOTICE %s :This server or oper has already voted",
403     me.name, source_p->name);
404     return;
405     }
406 adx 30
407 michael 957 /*
408 michael 1008 * call these two functions first so the 'requesting' notice always comes
409     * before the 'has triggered' notice. -bill
410 adx 30 */
411 michael 1008 sendto_realops_flags(UMODE_ALL, L_ALL,
412     "%s requesting G-Line for [%s@%s] [%s]",
413     get_oper_name(source_p),
414     user, host, reason);
415 michael 1247 ilog(LOG_TYPE_GLINE, "#gline for %s@%s [%s] requested by %s!%s@%s",
416 michael 1008 user, host, reason, source_p->name, source_p->username,
417     source_p->host);
418 adx 30
419 michael 1008 /* 4 param version for hyb-7 servers */
420     sendto_server(NULL, NULL, CAP_GLN|CAP_TS6, NOCAPS,
421     ":%s GLINE %s %s :%s",
422     ID(source_p), user, host, reason);
423     sendto_server(NULL, NULL, CAP_GLN, CAP_TS6,
424     ":%s GLINE %s %s :%s",
425     source_p->name, user, host, reason);
426 adx 30
427 michael 1008 /* 8 param for hyb-6 */
428     sendto_server(NULL, NULL, CAP_TS6, CAP_GLN,
429     ":%s GLINE %s %s %s %s %s %s :%s",
430     ID(&me),
431     ID(source_p), source_p->username,
432     source_p->host, source_p->servptr->name, user, host,
433     reason);
434     sendto_server(NULL, NULL, NOCAPS, CAP_GLN|CAP_TS6,
435     ":%s GLINE %s %s %s %s %s %s :%s",
436     me.name, source_p->name, source_p->username,
437     source_p->host, source_p->servptr->name, user, host,
438     reason);
439 adx 30 }
440    
441 michael 1008 /* ms_gline()
442     * me_gline()
443     * do_sgline()
444 db 937 *
445     * inputs - The usual for a m_ function
446     * output -
447     * side effects -
448     *
449 michael 1008 * Place a G line if 3 opers agree on the identical user@host
450 db 937 *
451 michael 1008 * Allow this server to pass along GLINE if received and
452     * GLINES is not defined.
453     *
454     * ENCAP'd GLINES are propagated by encap code.
455 db 937 */
456    
457     static void
458 michael 1008 ms_gline(struct Client *client_p, struct Client *source_p,
459     int parc, char *parv[])
460 db 937 {
461 michael 1008 do_sgline(source_p, parc, parv, 1);
462 db 937 }
463    
464     static void
465 michael 1008 me_gline(struct Client *client_p, struct Client *source_p,
466     int parc, char *parv[])
467     {
468     do_sgline(source_p, parc, parv, 0);
469     }
470    
471     static void
472 michael 1006 do_sungline(struct Client *source_p, const char *user,
473     const char *host, const char *reason, int prop)
474 db 937 {
475     assert(source_p->servptr != NULL);
476    
477 michael 957 sendto_realops_flags(UMODE_ALL, L_ALL,
478     "%s requesting UNG-Line for [%s@%s] [%s]",
479 michael 1006 get_oper_name(source_p), user, host, reason);
480 michael 1247 ilog(LOG_TYPE_GLINE, "#ungline for %s@%s [%s] requested by %s",
481 michael 957 user, host, reason, get_oper_name(source_p));
482 db 937
483 michael 957 /* If at least 3 opers agree this user should be un G lined then do it */
484 michael 958 if (check_majority(source_p, user, host, reason, GLINE_PENDING_DEL_TYPE) ==
485 michael 957 GLINE_ALREADY_VOTED)
486     sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
487 michael 1006
488     if (prop)
489     {
490     sendto_server(source_p->from, NULL, CAP_ENCAP|CAP_TS6, NOCAPS,
491     ":%s ENCAP * GUNGLINE %s %s :%s",
492     ID(source_p), user, host, reason);
493     sendto_server(source_p->from, NULL, CAP_ENCAP, CAP_TS6,
494     ":%s ENCAP * GUNGLINE %s %s :%s",
495     source_p->name, user, host, reason);
496     }
497 db 937 }
498    
499 michael 1008 /*! \brief GUNGLINE command handler (called in response to an encapsulated
500     * GUNGLINE command)
501 db 937 *
502 michael 1008 * \param client_p Pointer to allocated Client struct with physical connection
503     * to this server, i.e. with an open socket connected.
504     * \param source_p Pointer to allocated Client struct from which the message
505     * originally comes from. This can be a local or remote client.
506     * \param parc Integer holding the number of supplied arguments.
507     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
508     * pointers.
509     * \note Valid arguments for this command are:
510     * - parv[0] = sender prefix
511     * - parv[1] = username
512     * - parv[2] = hostname
513     * - parv[3] = reason
514 db 937 */
515 michael 1008 static void
516     me_gungline(struct Client *client_p, struct Client *source_p,
517     int parc, char *parv[])
518     {
519     if (ConfigFileEntry.glines)
520     do_sungline(source_p, parv[1], parv[2], parv[3], 0);
521     }
522    
523     /*! \brief GUNGLINE command handler (called by operators)
524 db 937 *
525 michael 1008 * \param client_p Pointer to allocated Client struct with physical connection
526     * to this server, i.e. with an open socket connected.
527     * \param source_p Pointer to allocated Client struct from which the message
528     * originally comes from. This can be a local or remote client.
529     * \param parc Integer holding the number of supplied arguments.
530     * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
531     * pointers.
532     * \note Valid arguments for this command are:
533     * - parv[0] = sender prefix
534     * - parv[1] = user\@host mask
535     * - parv[2] = reason
536 db 937 */
537     static void
538 db 940 mo_gungline(struct Client *client_p, struct Client *source_p,
539 michael 957 int parc, char *parv[])
540 db 937 {
541     char *user = NULL;
542 michael 1008 char *host = NULL;
543     char *reason = NULL;
544 db 937
545     if (!ConfigFileEntry.glines)
546     {
547 michael 957 sendto_one(source_p, ":%s NOTICE %s :GUNGLINE disabled",
548 db 937 me.name, source_p->name);
549     return;
550     }
551    
552 michael 1219 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
553 db 937 {
554     sendto_one(source_p, form_str(ERR_NOPRIVS),
555 michael 957 me.name, source_p->name, "gungline");
556 db 937 return;
557     }
558    
559 michael 957 if (parse_aline("GUNGLINE", source_p, parc, parv, 0, &user,
560     &host, NULL, NULL, &reason) < 0)
561 db 937 return;
562    
563 michael 1006 do_sungline(source_p, user, host, reason, 1);
564 db 937 }
565 michael 1230
566     /*
567     * gline enforces 3 parameters to force operator to give a reason
568     * a gline is not valid with "No reason"
569     * -db
570     */
571     static struct Message gline_msgtab = {
572     "GLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
573     { m_unregistered, m_not_oper, ms_gline, me_gline, mo_gline, m_ignore }
574     };
575    
576     static struct Message ungline_msgtab = {
577     "GUNGLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
578     { m_unregistered, m_not_oper, m_ignore, me_gungline, mo_gungline, m_ignore }
579     };
580    
581     static void
582     module_init(void)
583     {
584     mod_add_cmd(&gline_msgtab);
585     mod_add_cmd(&ungline_msgtab);
586     add_capability("GLN", CAP_GLN, 1);
587     }
588    
589     static void
590     module_exit(void)
591     {
592     mod_del_cmd(&gline_msgtab);
593     mod_del_cmd(&ungline_msgtab);
594     delete_capability("GLN");
595     }
596    
597     struct module module_entry = {
598     .node = { NULL, NULL, NULL },
599     .name = NULL,
600     .version = "$Revision$",
601     .handle = NULL,
602     .modinit = module_init,
603     .modexit = module_exit,
604     .flags = 0
605     };

Properties

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