ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/releases/8.1.12/modules/core/m_join.c
Revision: 1230
Committed: Thu Sep 22 19:41:19 2011 UTC (15 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/modules/core/m_join.c
File size: 18699 byte(s)
Log Message:
- cleanup module loader. Make module api more flexible

File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * m_join.c: Joins a 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 knight 31 * $Id$
23 adx 30 */
24    
25     #include "stdinc.h"
26 michael 1011 #include "list.h"
27 adx 30 #include "handlers.h"
28     #include "channel.h"
29     #include "channel_mode.h"
30     #include "client.h"
31     #include "hash.h"
32     #include "irc_string.h"
33     #include "sprintf_irc.h"
34     #include "ircd.h"
35     #include "numeric.h"
36     #include "send.h"
37     #include "s_serv.h"
38     #include "s_conf.h"
39     #include "msg.h"
40     #include "parse.h"
41     #include "modules.h"
42    
43    
44 michael 894 static void do_join_0(struct Client *, struct Client *);
45 adx 30
46     static void set_final_mode(struct Mode *, struct Mode *);
47     static void remove_our_modes(struct Channel *, struct Client *);
48     static void remove_a_mode(struct Channel *, struct Client *, int, char);
49    
50     static char modebuf[MODEBUFLEN];
51     static char parabuf[MODEBUFLEN];
52     static char sendbuf[MODEBUFLEN];
53     static char *mbuf;
54    
55 michael 488 /* last0() stolen from ircu */
56     static char *
57     last0(struct Client *client_p, struct Client *source_p, char *chanlist)
58     {
59     char *p;
60     int join0 = 0;
61    
62     for (p = chanlist; *p; ++p) /* find last "JOIN 0" */
63     {
64     if (*p == '0' && (*(p + 1) == ',' || *(p + 1) == '\0'))
65     {
66     if ((*p + 1) == ',')
67     ++p;
68    
69     chanlist = p + 1;
70     join0 = 1;
71     }
72     else
73     {
74     while (*p != ',' && *p != '\0') /* skip past channel name */
75     ++p;
76    
77     if (*p == '\0') /* hit the end */
78     break;
79     }
80     }
81    
82     if (join0)
83     do_join_0(client_p, source_p);
84    
85     return chanlist;
86     }
87    
88 adx 30 /* m_join()
89     * parv[0] = sender prefix
90     * parv[1] = channel
91     * parv[2] = channel password (key)
92     */
93     static void
94     m_join(struct Client *client_p, struct Client *source_p,
95     int parc, char *parv[])
96     {
97 michael 488 char *p = NULL;
98     char *key_list = NULL;
99     char *chan_list = NULL;
100     char *chan = NULL;
101 adx 30 struct Channel *chptr = NULL;
102 michael 488 int i = 0;
103 adx 30 unsigned int flags = 0;
104    
105 michael 632 if (EmptyString(parv[1]))
106 adx 30 {
107     sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
108     me.name, source_p->name, "JOIN");
109     return;
110     }
111    
112 michael 487 assert(client_p == source_p);
113 adx 30
114 michael 488 key_list = parv[2];
115     chan_list = last0(client_p, source_p, parv[1]);
116 michael 487
117 michael 488 for (chan = strtoken(&p, chan_list, ","); chan;
118     chan = strtoken(&p, NULL, ","))
119 adx 30 {
120 michael 488 char *key = NULL;
121 adx 30
122 michael 488 /* If we have any more keys, take the first for this channel. */
123     if (!EmptyString(key_list) && (key_list = strchr(key = key_list, ',')))
124     *key_list++ = '\0';
125    
126     /* Empty keys are the same as no keys. */
127     if (key && *key == '\0')
128     key = NULL;
129    
130 michael 632 if (!check_channel_name(chan, 1))
131 michael 488 {
132     sendto_one(source_p, form_str(ERR_BADCHANNAME),
133     me.name, source_p->name, chan);
134 adx 30 continue;
135 michael 488 }
136 adx 30
137 michael 488 if (ConfigChannel.disable_local_channels && (*chan == '&'))
138     {
139     sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
140     me.name, source_p->name, chan);
141     continue;
142     }
143    
144     if (!IsExemptResv(source_p) &&
145 michael 1219 !(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv) &&
146 michael 488 (!hash_find_resv(chan) == ConfigChannel.restrict_channels))
147     {
148     sendto_one(source_p, form_str(ERR_BADCHANNAME),
149     me.name, source_p->name, chan);
150     sendto_realops_flags(UMODE_SPY, L_ALL,
151     "User %s (%s@%s) is attempting to join locally juped channel %s",
152     source_p->name, source_p->username, source_p->host, chan);
153     continue;
154     }
155    
156     if ((dlink_list_length(&source_p->channel) >= ConfigChannel.max_chans_per_user) &&
157 michael 1219 (!HasUMode(source_p, UMODE_OPER) || (dlink_list_length(&source_p->channel) >=
158 michael 488 ConfigChannel.max_chans_per_user * 3)))
159     {
160 michael 494 sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS),
161     me.name, source_p->name, chan);
162     break;
163 michael 488 }
164    
165     if ((chptr = hash_find_channel(chan)) != NULL)
166     {
167     if (IsMember(source_p, chptr))
168     continue;
169    
170 michael 1219 if (splitmode && !HasUMode(source_p, UMODE_OPER) && (*chan != '&') &&
171 michael 488 ConfigChannel.no_join_on_split)
172     {
173     sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
174     me.name, source_p->name, chan);
175     continue;
176     }
177    
178     /*
179 michael 894 * can_join checks for +i key, bans.
180     */
181     if ((i = can_join(source_p, chptr, key)))
182     {
183     sendto_one(source_p, form_str(i), me.name,
184     source_p->name, chptr->chname);
185     continue;
186     }
187    
188     /*
189 michael 488 * This should never be the case unless there is some sort of
190     * persistant channels.
191     */
192     if (dlink_list_length(&chptr->members) == 0)
193     flags = CHFL_CHANOP;
194     else
195     flags = 0;
196     }
197     else
198     {
199 michael 1219 if (splitmode && !HasUMode(source_p, UMODE_OPER) && (*chan != '&') &&
200 michael 488 (ConfigChannel.no_create_on_split || ConfigChannel.no_join_on_split))
201     {
202     sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
203     me.name, source_p->name, chan);
204     continue;
205     }
206    
207     flags = CHFL_CHANOP;
208 michael 632 chptr = make_channel(chan);
209 michael 488 }
210    
211 michael 1219 if (!HasUMode(source_p, UMODE_OPER))
212 adx 30 check_spambot_warning(source_p, chptr->chname);
213    
214 michael 894 add_user_to_channel(chptr, source_p, flags, 1);
215 adx 30
216     /*
217 michael 488 * Set timestamp if appropriate, and propagate
218     */
219 adx 30 if (flags & CHFL_CHANOP)
220     {
221     chptr->channelts = CurrentTime;
222     chptr->mode.mode |= MODE_TOPICLIMIT;
223     chptr->mode.mode |= MODE_NOPRIVMSGS;
224    
225 michael 885 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
226 adx 30 ":%s SJOIN %lu %s +nt :@%s",
227     me.id, (unsigned long)chptr->channelts,
228     chptr->chname, source_p->id);
229 michael 885 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
230 adx 30 ":%s SJOIN %lu %s +nt :@%s",
231     me.name, (unsigned long)chptr->channelts,
232 michael 632 chptr->chname, source_p->name);
233 adx 30 /*
234     * notify all other users on the new channel
235     */
236 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
237 adx 30 source_p->name, source_p->username,
238     source_p->host, chptr->chname);
239 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s +nt",
240 adx 30 me.name, chptr->chname);
241     }
242     else
243     {
244 michael 885 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
245 adx 30 ":%s JOIN %lu %s +",
246     source_p->id, (unsigned long)chptr->channelts,
247     chptr->chname);
248 michael 885 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
249 adx 30 ":%s SJOIN %lu %s + :%s",
250     me.name, (unsigned long)chptr->channelts,
251     chptr->chname, source_p->name);
252    
253 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
254 adx 30 source_p->name, source_p->username,
255     source_p->host, chptr->chname);
256     }
257    
258     del_invite(chptr, source_p);
259    
260 michael 1203 if (chptr->topic[0])
261 adx 30 {
262     sendto_one(source_p, form_str(RPL_TOPIC), me.name,
263     source_p->name, chptr->chname, chptr->topic);
264    
265     sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
266     me.name, source_p->name, chptr->chname,
267     chptr->topic_info, chptr->topic_time);
268     }
269    
270     channel_member_names(source_p, chptr, 1);
271    
272 michael 487 source_p->localClient->last_join_time = CurrentTime;
273 adx 30 }
274     }
275    
276     /* ms_join()
277     *
278     * inputs - parv[0] = uid
279     * parv[1] = ts
280     * parv[2] = channel name
281 db 853 * parv[3] = modes (Deprecated)
282 adx 30 * output - none
283     * side effects - handles remote JOIN's sent by servers. In TSora
284     * remote clients are joined using SJOIN, hence a
285     * JOIN sent by a server on behalf of a client is an error.
286     * here, the initial code is in to take an extra parameter
287     * and use it for the TimeStamp on a new channel.
288     */
289     static void
290     ms_join(struct Client *client_p, struct Client *source_p,
291     int parc, char *parv[])
292     {
293 michael 632 time_t newts = 0;
294     time_t oldts = 0;
295     int keep_our_modes = 1;
296     int keep_new_modes = 1;
297     int isnew = 0;
298     const char *servername = NULL;
299     struct Channel *chptr = NULL;
300     struct Mode mode, *oldmode;
301 adx 30
302 michael 632 if (parc == 2 && !irccmp(parv[1], "0"))
303 adx 30 {
304     do_join_0(client_p, source_p);
305     return;
306     }
307    
308 michael 632 if (parc < 4 || *parv[2] == '&')
309 adx 30 return;
310    
311 michael 632 if (!check_channel_name(parv[2], 0))
312     {
313     sendto_realops_flags(UMODE_DEBUG, L_ALL,
314     "*** Too long or invalid channel name from %s: %s",
315     client_p->name, parv[2]);
316 adx 30 return;
317 michael 632 }
318 adx 30
319     mbuf = modebuf;
320     mode.mode = mode.limit = 0;
321     mode.key[0] = '\0';
322    
323 michael 632 if ((chptr = hash_find_channel(parv[2])) == NULL)
324     {
325     isnew = 1;
326     chptr = make_channel(parv[2]);
327     }
328    
329     newts = atol(parv[1]);
330 adx 30 oldts = chptr->channelts;
331     oldmode = &chptr->mode;
332    
333     if (ConfigFileEntry.ignore_bogus_ts)
334     {
335     if (newts < 800000000)
336     {
337     sendto_realops_flags(UMODE_DEBUG, L_ALL,
338     "*** Bogus TS %lu on %s ignored from %s",
339     (unsigned long)newts, chptr->chname,
340     client_p->name);
341    
342     newts = (oldts == 0) ? 0 : 800000000;
343     }
344     }
345     else
346     {
347     if (!newts && !isnew && oldts)
348     {
349 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr,
350 michael 873 ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to 0",
351     me.name, chptr->chname, chptr->chname, (unsigned long)oldts);
352 adx 30 sendto_realops_flags(UMODE_ALL, L_ALL,
353     "Server %s changing TS on %s from %lu to 0",
354     source_p->name, chptr->chname, (unsigned long)oldts);
355     }
356     }
357    
358     if (isnew)
359     chptr->channelts = newts;
360     else if (newts == 0 || oldts == 0)
361     chptr->channelts = 0;
362     else if (newts == oldts)
363     ;
364     else if (newts < oldts)
365     {
366 michael 894 keep_our_modes = 0;
367 adx 30 chptr->channelts = newts;
368     }
369     else
370 michael 894 keep_new_modes = 0;
371 adx 30
372     if (!keep_new_modes)
373     mode = *oldmode;
374     else if (keep_our_modes)
375     {
376     mode.mode |= oldmode->mode;
377     if (oldmode->limit > mode.limit)
378     mode.limit = oldmode->limit;
379     if (strcmp(mode.key, oldmode->key) < 0)
380     strcpy(mode.key, oldmode->key);
381     }
382    
383     set_final_mode(&mode, oldmode);
384     chptr->mode = mode;
385    
386     /* Lost the TS, other side wins, so remove modes on this side */
387     if (!keep_our_modes)
388     {
389     remove_our_modes(chptr, source_p);
390 michael 873
391 michael 1203 if (chptr->topic[0])
392 michael 873 {
393 michael 1203 set_channel_topic(chptr, "", "", 0);
394 michael 896 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s TOPIC %s :",
395 michael 873 (IsHidden(source_p) ||
396     ConfigServerHide.hide_servers) ?
397     me.name : source_p->name, chptr->chname);
398     }
399    
400 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr,
401 adx 30 ":%s NOTICE %s :*** Notice -- TS for %s changed from %lu to %lu",
402     me.name, chptr->chname, chptr->chname,
403     (unsigned long)oldts, (unsigned long)newts);
404     }
405    
406     if (*modebuf != '\0')
407     {
408     servername = (ConfigServerHide.hide_servers || IsHidden(source_p)) ?
409     me.name : source_p->name;
410    
411     /* This _SHOULD_ be to ALL_MEMBERS
412     * It contains only +imnpstlk, etc */
413 michael 896 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s %s %s",
414 adx 30 servername, chptr->chname, modebuf, parabuf);
415     }
416    
417     if (!IsMember(source_p, chptr))
418     {
419 michael 894 add_user_to_channel(chptr, source_p, 0, 1);
420     sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s",
421 adx 30 source_p->name, source_p->username,
422     source_p->host, chptr->chname);
423     }
424    
425 michael 885 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
426 adx 30 ":%s JOIN %lu %s +",
427     ID(source_p), (unsigned long)chptr->channelts, chptr->chname);
428 michael 885 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
429 adx 30 ":%s SJOIN %lu %s + :%s",
430     source_p->servptr->name, (unsigned long)chptr->channelts,
431     chptr->chname, source_p->name);
432     }
433    
434     /* do_join_0()
435     *
436     * inputs - pointer to client doing join 0
437     * output - NONE
438     * side effects - Use has decided to join 0. This is legacy
439     * from the days when channels were numbers not names. *sigh*
440     * There is a bunch of evilness necessary here due to
441     * anti spambot code.
442     */
443     static void
444     do_join_0(struct Client *client_p, struct Client *source_p)
445     {
446     struct Channel *chptr = NULL;
447 michael 488 dlink_node *ptr = NULL, *ptr_next = NULL;
448 adx 30
449 michael 1219 if (source_p->channel.head)
450     if (MyConnect(source_p) && !HasUMode(source_p, UMODE_OPER))
451     check_spambot_warning(source_p, NULL);
452 adx 30
453     DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->channel.head)
454     {
455     chptr = ((struct Membership *)ptr->data)->chptr;
456    
457 michael 885 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
458 michael 488 ":%s PART %s", ID(source_p), chptr->chname);
459 michael 885 sendto_server(client_p, chptr, NOCAPS, CAP_TS6,
460 michael 488 ":%s PART %s", source_p->name, chptr->chname);
461 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s PART %s",
462 michael 488 source_p->name, source_p->username,
463     source_p->host, chptr->chname);
464 adx 30
465 michael 488 remove_user_from_channel(ptr->data);
466 adx 30 }
467     }
468    
469 michael 1175 /* set_final_mode
470 adx 30 *
471 michael 1175 * inputs - channel mode
472     * - old channel mode
473 adx 30 * output - NONE
474 michael 1175 * side effects - walk through all the channel modes turning off modes
475     * that were on in oldmode but aren't on in mode.
476     * Then walk through turning on modes that are on in mode
477     * but were not set in oldmode.
478 adx 30 */
479     static void
480     set_final_mode(struct Mode *mode, struct Mode *oldmode)
481     {
482 michael 1175 const struct mode_letter *tab;
483 adx 30 char *pbuf = parabuf;
484     int what = 0;
485     int len;
486    
487 michael 1175 for (tab = chan_modes; tab->letter; ++tab)
488 adx 30 {
489 michael 1175 if ((tab->mode & mode->mode) &&
490     !(tab->mode & oldmode->mode))
491 adx 30 {
492     if (what != 1)
493     {
494     *mbuf++ = '+';
495     what = 1;
496     }
497 michael 1175 *mbuf++ = tab->letter;
498 adx 30 }
499     }
500    
501 michael 1175 for (tab = chan_modes; tab->letter; ++tab)
502 adx 30 {
503 michael 1175 if ((tab->mode & oldmode->mode) &&
504     !(tab->mode & mode->mode))
505 adx 30 {
506     if (what != -1)
507     {
508     *mbuf++ = '-';
509     what = -1;
510     }
511 michael 1175 *mbuf++ = tab->letter;
512 adx 30 }
513     }
514    
515     if (oldmode->limit != 0 && mode->limit == 0)
516     {
517     if (what != -1)
518     {
519     *mbuf++ = '-';
520     what = -1;
521     }
522     *mbuf++ = 'l';
523     }
524    
525     if (oldmode->key[0] && !mode->key[0])
526     {
527     if (what != -1)
528     {
529     *mbuf++ = '-';
530     what = -1;
531     }
532     *mbuf++ = 'k';
533     len = ircsprintf(pbuf, "%s ", oldmode->key);
534     pbuf += len;
535     }
536    
537     if (mode->limit != 0 && oldmode->limit != mode->limit)
538     {
539     if (what != 1)
540     {
541     *mbuf++ = '+';
542     what = 1;
543     }
544     *mbuf++ = 'l';
545     len = ircsprintf(pbuf, "%d ", mode->limit);
546     pbuf += len;
547     }
548    
549     if (mode->key[0] && strcmp(oldmode->key, mode->key))
550     {
551     if (what != 1)
552     {
553     *mbuf++ = '+';
554     what = 1;
555     }
556     *mbuf++ = 'k';
557     len = ircsprintf(pbuf, "%s ", mode->key);
558     pbuf += len;
559     }
560     *mbuf = '\0';
561     }
562    
563     /* remove_our_modes()
564     *
565     * inputs - pointer to channel to remove modes from
566     * - client pointer
567     * output - NONE
568     * side effects - Go through the local members, remove all their
569     * chanop modes etc., this side lost the TS.
570     */
571     static void
572     remove_our_modes(struct Channel *chptr, struct Client *source_p)
573     {
574     remove_a_mode(chptr, source_p, CHFL_CHANOP, 'o');
575     #ifdef HALFOPS
576     remove_a_mode(chptr, source_p, CHFL_HALFOP, 'h');
577     #endif
578     remove_a_mode(chptr, source_p, CHFL_VOICE, 'v');
579     }
580    
581     /* remove_a_mode()
582     *
583     * inputs -
584     * output - NONE
585     * side effects - remove ONE mode from a channel
586     */
587     static void
588     remove_a_mode(struct Channel *chptr, struct Client *source_p,
589     int mask, char flag)
590     {
591     dlink_node *ptr;
592     struct Membership *ms;
593     char lmodebuf[MODEBUFLEN];
594     const char *lpara[MAXMODEPARAMS];
595     int count = 0;
596     int lcount;
597    
598     mbuf = lmodebuf;
599     *mbuf++ = '-';
600    
601     for (lcount = 0; lcount < MAXMODEPARAMS; lcount++)
602     lpara[lcount] = "";
603     sendbuf[0] = '\0';
604    
605     DLINK_FOREACH(ptr, chptr->members.head)
606     {
607     ms = ptr->data;
608    
609     if ((ms->flags & mask) == 0)
610     continue;
611    
612     ms->flags &= ~mask;
613    
614     lpara[count++] = ms->client_p->name;
615    
616     *mbuf++ = flag;
617    
618     if (count >= MAXMODEPARAMS)
619     {
620     for (lcount = 0; lcount < MAXMODEPARAMS; lcount++)
621     {
622     if (*lpara[lcount] == '\0')
623     break;
624    
625     strlcat(sendbuf, " ", sizeof(sendbuf));
626     strlcat(sendbuf, lpara[lcount], sizeof(sendbuf));
627     lpara[lcount] = "";
628     }
629    
630     *mbuf = '\0';
631 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr,
632 adx 30 ":%s MODE %s %s%s",
633     (IsHidden(source_p) ||
634     ConfigServerHide.hide_servers) ?
635     me.name : source_p->name,
636     chptr->chname, lmodebuf, sendbuf);
637     mbuf = lmodebuf;
638     *mbuf++ = '-';
639     count = 0;
640     sendbuf[0] = '\0';
641     }
642     }
643    
644     if (count != 0)
645     {
646     *mbuf = '\0';
647     for (lcount = 0; lcount < MAXMODEPARAMS; lcount++)
648     {
649     if (*lpara[lcount] == '\0')
650     break;
651    
652     strlcat(sendbuf, " ", sizeof(sendbuf));
653     strlcat(sendbuf, lpara[lcount], sizeof(sendbuf));
654     }
655 michael 894 sendto_channel_local(ALL_MEMBERS, 0, chptr,
656 adx 30 ":%s MODE %s %s%s",
657     (IsHidden(source_p) || ConfigServerHide.hide_servers) ?
658     me.name : source_p->name,
659     chptr->chname, lmodebuf, sendbuf);
660     }
661     }
662 michael 1230
663     static struct Message join_msgtab = {
664     "JOIN", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
665     { m_unregistered, m_join, ms_join, m_ignore, m_join, m_ignore }
666     };
667    
668     static void
669     module_init(void)
670     {
671     mod_add_cmd(&join_msgtab);
672     }
673    
674     static void
675     module_exit(void)
676     {
677     mod_del_cmd(&join_msgtab);
678     }
679    
680     struct module module_entry = {
681     .node = { NULL, NULL, NULL },
682     .name = NULL,
683     .version = "$Revision$",
684     .handle = NULL,
685     .modinit = module_init,
686     .modexit = module_exit,
687     .flags = MODULE_FLAG_CORE
688     };

Properties

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