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: 1618
Committed: Tue Oct 30 21:04:38 2012 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/trunk/modules/core/m_join.c
File size: 18303 byte(s)
Log Message:
- Made m_globops() and ms_globops() use sendto_realops_flags()
- Added message-type parameter to sendto_realops_flags() which can be one of
  SEND_NOTICE, SEND_GLOBAL, SEND_LOCOPS
- Forward-port -r1617

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

Properties

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