ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/core/m_join.c
Revision: 1687
Committed: Wed Dec 19 20:47:44 2012 UTC (11 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_join.c
File size: 18383 byte(s)
Log Message:
- Forward-port -r1685 [STATS q|Q now shows how many times a resv{}
  block has been matched]

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

Properties

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