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: 1451
Committed: Fri Jun 29 11:28:25 2012 UTC (11 years, 9 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/modules/core/m_join.c
File size: 18556 byte(s)
Log Message:
- Style corrections

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

Properties

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