/[svn]/ircd-hybrid/trunk/modules/m_info.c
ViewVC logotype

Contents of /ircd-hybrid/trunk/modules/m_info.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5891 - (show annotations)
Sun May 3 19:15:01 2015 UTC (7 years, 3 months ago) by michael
File MIME type: text/x-chdr
File size: 19177 byte(s)
- m_info.c: don't int overflow if for some unknown reason someone configures insanely high values of > 2^31-1

1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2015 ircd-hybrid development team
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file m_info.c
23 * \brief Includes required functions for processing the INFO command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "client.h"
30 #include "ircd.h"
31 #include "numeric.h"
32 #include "misc.h"
33 #include "server.h"
34 #include "send.h"
35 #include "conf.h"
36 #include "parse.h"
37 #include "modules.h"
38
39
40 /* Types for output_type in InfoStruct */
41 enum
42 {
43 OUTPUT_STRING = 1 << 0, /* Output option as %s w/ dereference */
44 OUTPUT_STRING_PTR = 1 << 1, /* Output option as %s w/out deference */
45 OUTPUT_DECIMAL = 1 << 2, /* Output option as decimal (%d) */
46 OUTPUT_BOOLEAN = 1 << 3, /* Output option as "ON" or "OFF" */
47 OUTPUT_BOOLEAN_YN = 1 << 4, /* Output option as "YES" or "NO" */
48 OUTPUT_BOOLEAN2 = 1 << 5 /* Output option as "YES/NO/MASKED" */
49 };
50
51 /*
52 * jdc -- Structure for our configuration value table
53 */
54 struct InfoStruct
55 {
56 const char *name; /* Displayed variable name */
57 const unsigned int output_type; /* Type of output. See enum above */
58 const void *option; /* Pointer reference to the value */
59 const char *desc; /* ASCII description of the variable */
60 };
61
62 static const struct InfoStruct info_table[] =
63 {
64 /* --[ START OF TABLE ]-------------------------------------------- */
65
66 {
67 "DPATH",
68 OUTPUT_STRING,
69 &ConfigGeneral.dpath,
70 "Root directory of installation"
71 },
72 {
73 "SPATH",
74 OUTPUT_STRING,
75 &ConfigGeneral.spath,
76 "Path to server executable"
77 },
78 {
79 "MPATH",
80 OUTPUT_STRING,
81 &ConfigGeneral.mpath,
82 "Path to main motd (Message of the Day) file"
83 },
84 {
85 "CPATH",
86 OUTPUT_STRING,
87 &ConfigGeneral.configfile,
88 "Path to main configuration file"
89 },
90 {
91 "DLPATH",
92 OUTPUT_STRING,
93 &ConfigGeneral.dlinefile,
94 "Path to D-line database file"
95 },
96 {
97 "KPATH",
98 OUTPUT_STRING,
99 &ConfigGeneral.klinefile,
100 "Path to K-line database file"
101 },
102 {
103 "XPATH",
104 OUTPUT_STRING,
105 &ConfigGeneral.xlinefile,
106 "Path to X-line database file"
107 },
108 {
109 "RESVPATH",
110 OUTPUT_STRING,
111 &ConfigGeneral.resvfile,
112 "Path to resv database file"
113 },
114 {
115 "network_name",
116 OUTPUT_STRING,
117 &ConfigServerInfo.network_name,
118 "Network name"
119 },
120 {
121 "network_desc",
122 OUTPUT_STRING,
123 &ConfigServerInfo.network_desc,
124 "Network description"
125 },
126 {
127 "hub",
128 OUTPUT_BOOLEAN_YN,
129 &ConfigServerInfo.hub,
130 "Server is a hub"
131 },
132 {
133 "default_max_clients",
134 OUTPUT_DECIMAL,
135 &ConfigServerInfo.default_max_clients,
136 "The default maximum number of clients permitted simultaneously on this server"
137 },
138 {
139 "max_nick_length",
140 OUTPUT_DECIMAL,
141 &ConfigServerInfo.max_nick_length,
142 "Maximum nickname length"
143 },
144 {
145 "max_topic_length",
146 OUTPUT_DECIMAL,
147 &ConfigServerInfo.max_topic_length,
148 "Maximum topic length"
149 },
150 {
151 "use_logging",
152 OUTPUT_BOOLEAN_YN,
153 &ConfigLog.use_logging,
154 "Enable logging"
155 },
156 {
157 "disable_fake_channels",
158 OUTPUT_BOOLEAN_YN,
159 &ConfigChannel.disable_fake_channels,
160 "Forbids channels with special ASCII characters in their name"
161 },
162 {
163 "invite_client_count",
164 OUTPUT_DECIMAL,
165 &ConfigChannel.invite_client_count,
166 "How many INVITE attempts are permitted in invite_client_time"
167 },
168 {
169 "invite_client_time",
170 OUTPUT_DECIMAL,
171 &ConfigChannel.invite_client_time,
172 "How many invite_client_count invites are allowed in this time"
173 },
174 {
175 "knock_client_count",
176 OUTPUT_DECIMAL,
177 &ConfigChannel.knock_client_count,
178 "How many KNOCK attempts are permitted in knock_client_time"
179 },
180 {
181 "knock_client_time",
182 OUTPUT_DECIMAL,
183 &ConfigChannel.knock_client_time,
184 "How many knock_client_count knocks are allowed in this time"
185 },
186 {
187 "knock_delay_channel",
188 OUTPUT_DECIMAL,
189 &ConfigChannel.knock_delay_channel,
190 "Delay between KNOCK attempts to a channel"
191 },
192 {
193 "max_channels",
194 OUTPUT_DECIMAL,
195 &ConfigChannel.max_channels,
196 "Maximum number of channels a user can join"
197 },
198 {
199 "max_bans",
200 OUTPUT_DECIMAL,
201 &ConfigChannel.max_bans,
202 "Total +b/e/I modes allowed in a channel"
203 },
204 {
205 "default_split_user_count",
206 OUTPUT_DECIMAL,
207 &ConfigChannel.default_split_user_count,
208 "Startup value of SPLITUSERS"
209 },
210 {
211 "default_split_server_count",
212 OUTPUT_DECIMAL,
213 &ConfigChannel.default_split_server_count,
214 "Startup value of SPLITNUM"
215 },
216 {
217 "no_create_on_split",
218 OUTPUT_BOOLEAN_YN,
219 &ConfigChannel.no_create_on_split,
220 "Disallow creation of channels when split"
221 },
222 {
223 "no_join_on_split",
224 OUTPUT_BOOLEAN_YN,
225 &ConfigChannel.no_join_on_split,
226 "Disallow joining channels when split"
227 },
228 {
229 "flatten_links",
230 OUTPUT_BOOLEAN_YN,
231 &ConfigServerHide.flatten_links,
232 "Flatten /links list"
233 },
234 {
235 "links_delay",
236 OUTPUT_DECIMAL,
237 &ConfigServerHide.links_delay,
238 "Links rehash delay"
239 },
240 {
241 "hidden",
242 OUTPUT_BOOLEAN_YN,
243 &ConfigServerHide.hidden,
244 "Hide this server from a flattened /links on remote servers"
245 },
246 {
247 "hide_servers",
248 OUTPUT_BOOLEAN_YN,
249 &ConfigServerHide.hide_servers,
250 "Hide servernames from users"
251 },
252 {
253 "hide_services",
254 OUTPUT_BOOLEAN_YN,
255 &ConfigServerHide.hide_services,
256 "Hides the location of services server"
257 },
258 {
259 "hidden_name",
260 OUTPUT_STRING,
261 &ConfigServerHide.hidden_name,
262 "Server name users see if hide_servers = yes"
263 },
264 {
265 "hide_server_ips",
266 OUTPUT_BOOLEAN_YN,
267 &ConfigServerHide.hide_server_ips,
268 "Prevent people from seeing server IP addresses"
269 },
270 {
271 "away_count",
272 OUTPUT_DECIMAL,
273 &ConfigGeneral.away_count,
274 "How many AWAY attempts are permitted in away_time"
275 },
276 {
277 "away_time",
278 OUTPUT_DECIMAL,
279 &ConfigGeneral.away_time,
280 "How many away_count aways are allowed in this time"
281 },
282 {
283 "dline_min_cidr",
284 OUTPUT_DECIMAL,
285 &ConfigGeneral.dline_min_cidr,
286 "Minimum required length of a CIDR bitmask for IPv4 D-Lines"
287 },
288 {
289 "dline_min_cidr6",
290 OUTPUT_DECIMAL,
291 &ConfigGeneral.dline_min_cidr6,
292 "Minimum required length of a CIDR bitmask for IPv6 D-Lines"
293 },
294 {
295 "kline_min_cidr",
296 OUTPUT_DECIMAL,
297 &ConfigGeneral.kline_min_cidr,
298 "Minimum required length of a CIDR bitmask for IPv4 K-Lines"
299 },
300 {
301 "kline_min_cidr6",
302 OUTPUT_DECIMAL,
303 &ConfigGeneral.kline_min_cidr6,
304 "Minimum required length of a CIDR bitmask for IPv6 K-Lines"
305 },
306 {
307 "invisible_on_connect",
308 OUTPUT_BOOLEAN_YN,
309 &ConfigGeneral.invisible_on_connect,
310 "Automatically set mode +i on connecting users"
311 },
312 {
313 "kill_chase_time_limit",
314 OUTPUT_DECIMAL,
315 &ConfigGeneral.kill_chase_time_limit,
316 "Nick Change Tracker for KILL"
317 },
318 {
319 "ignore_bogus_ts",
320 OUTPUT_BOOLEAN_YN,
321 &ConfigGeneral.ignore_bogus_ts,
322 "Ignore bogus timestamps from other servers"
323 },
324 {
325 "cycle_on_host_change",
326 OUTPUT_BOOLEAN_YN,
327 &ConfigGeneral.cycle_on_host_change,
328 "Send a fake QUIT/JOIN combination on host change"
329 },
330 {
331 "disable_auth",
332 OUTPUT_BOOLEAN_YN,
333 &ConfigGeneral.disable_auth,
334 "Completely disable ident lookups"
335 },
336 {
337 "disable_remote_commands",
338 OUTPUT_BOOLEAN_YN,
339 &ConfigServerHide.disable_remote_commands,
340 "Prevent users issuing commands on remote servers"
341 },
342 {
343 "tkline_expire_notices",
344 OUTPUT_BOOLEAN_YN,
345 &ConfigGeneral.tkline_expire_notices,
346 "Show temporary kline/xline expire notices"
347 },
348 {
349 "default_floodcount",
350 OUTPUT_DECIMAL,
351 &ConfigGeneral.default_floodcount,
352 "Startup value of FLOODCOUNT"
353 },
354 {
355 "failed_oper_notice",
356 OUTPUT_BOOLEAN_YN,
357 &ConfigGeneral.failed_oper_notice,
358 "Inform opers if someone tries to /oper with the wrong password"
359 },
360 {
361 "dots_in_ident",
362 OUTPUT_DECIMAL,
363 &ConfigGeneral.dots_in_ident,
364 "Number of permissable dots in an ident"
365 },
366 {
367 "min_nonwildcard",
368 OUTPUT_DECIMAL,
369 &ConfigGeneral.min_nonwildcard,
370 "Minimum non-wildcard chars in K/G lines"
371 },
372 {
373 "min_nonwildcard_simple",
374 OUTPUT_DECIMAL,
375 &ConfigGeneral.min_nonwildcard_simple,
376 "Minimum non-wildcards in gecos bans"
377 },
378 {
379 "max_watch",
380 OUTPUT_DECIMAL,
381 &ConfigGeneral.max_watch,
382 "Maximum nicknames on watch list"
383 },
384 {
385 "max_accept",
386 OUTPUT_DECIMAL,
387 &ConfigGeneral.max_accept,
388 "Maximum nicknames on accept list"
389 },
390 {
391 "anti_nick_flood",
392 OUTPUT_BOOLEAN_YN,
393 &ConfigGeneral.anti_nick_flood,
394 "NICK flood protection"
395 },
396 {
397 "max_nick_time",
398 OUTPUT_DECIMAL,
399 &ConfigGeneral.max_nick_time,
400 "NICK flood protection time interval"
401 },
402 {
403 "max_nick_changes",
404 OUTPUT_DECIMAL,
405 &ConfigGeneral.max_nick_changes,
406 "NICK change threshhold setting"
407 },
408 {
409 "anti_spam_exit_message_time",
410 OUTPUT_DECIMAL,
411 &ConfigGeneral.anti_spam_exit_message_time,
412 "Duration a client must be connected for to have an exit message"
413 },
414 {
415 "ts_warn_delta",
416 OUTPUT_DECIMAL,
417 &ConfigGeneral.ts_warn_delta,
418 "Maximum permitted TS delta before displaying a warning"
419 },
420 {
421 "ts_max_delta",
422 OUTPUT_DECIMAL,
423 &ConfigGeneral.ts_max_delta,
424 "Maximum permitted TS delta from another server"
425 },
426 {
427 "warn_no_connect_block",
428 OUTPUT_BOOLEAN_YN,
429 &ConfigGeneral.warn_no_connect_block,
430 "Display warning if connecting server lacks a connect{} block"
431 },
432 {
433 "stats_e_disabled",
434 OUTPUT_BOOLEAN_YN,
435 &ConfigGeneral.stats_e_disabled,
436 "Whether or not STATS e is disabled"
437 },
438 {
439 "stats_m_oper_only",
440 OUTPUT_BOOLEAN_YN,
441 &ConfigGeneral.stats_m_oper_only,
442 "STATS m output is only shown to operators"
443 },
444 {
445 "stats_o_oper_only",
446 OUTPUT_BOOLEAN_YN,
447 &ConfigGeneral.stats_o_oper_only,
448 "STATS O output is only shown to operators"
449 },
450 {
451 "stats_P_oper_only",
452 OUTPUT_BOOLEAN_YN,
453 &ConfigGeneral.stats_P_oper_only,
454 "STATS P is only shown to operators"
455 },
456 {
457 "stats_u_oper_only",
458 OUTPUT_BOOLEAN_YN,
459 &ConfigGeneral.stats_u_oper_only,
460 "STATS u is only shown to operators"
461 },
462 {
463 "stats_i_oper_only",
464 OUTPUT_BOOLEAN2,
465 &ConfigGeneral.stats_i_oper_only,
466 "STATS I output is only shown to operators"
467 },
468 {
469 "stats_k_oper_only",
470 OUTPUT_BOOLEAN2,
471 &ConfigGeneral.stats_k_oper_only,
472 "STATS K output is only shown to operators"
473 },
474 {
475 "caller_id_wait",
476 OUTPUT_DECIMAL,
477 &ConfigGeneral.caller_id_wait,
478 "Minimum delay between notifying UMODE +g users of messages"
479 },
480 {
481 "opers_bypass_callerid",
482 OUTPUT_BOOLEAN_YN,
483 &ConfigGeneral.opers_bypass_callerid,
484 "Allows IRC operators to message users who are +g (callerid)"
485 },
486 {
487 "pace_wait_simple",
488 OUTPUT_DECIMAL,
489 &ConfigGeneral.pace_wait_simple,
490 "Minimum delay between less intensive commands"
491 },
492 {
493 "pace_wait",
494 OUTPUT_DECIMAL,
495 &ConfigGeneral.pace_wait,
496 "Minimum delay between uses of certain commands"
497 },
498 {
499 "short_motd",
500 OUTPUT_BOOLEAN_YN,
501 &ConfigGeneral.short_motd,
502 "Do not show MOTD; only tell clients they should read it"
503 },
504 {
505 "ping_cookie",
506 OUTPUT_BOOLEAN_YN,
507 &ConfigGeneral.ping_cookie,
508 "Require ping cookies to connect"
509 },
510 {
511 "no_oper_flood",
512 OUTPUT_BOOLEAN_YN,
513 &ConfigGeneral.no_oper_flood,
514 "Reduce flood control for operators"
515 },
516 {
517 "oper_pass_resv",
518 OUTPUT_BOOLEAN_YN,
519 &ConfigGeneral.oper_pass_resv,
520 "Opers can over-ride RESVs"
521 },
522 {
523 "max_targets",
524 OUTPUT_DECIMAL,
525 &ConfigGeneral.max_targets,
526 "The maximum number of PRIVMSG/NOTICE targets"
527 },
528 {
529 "throttle_count",
530 OUTPUT_DECIMAL,
531 &ConfigGeneral.throttle_count,
532 "Number of connects in throttle_time before connections are blocked"
533 },
534 {
535 "throttle_time",
536 OUTPUT_DECIMAL,
537 &ConfigGeneral.throttle_time,
538 "Minimum time between client reconnects"
539 },
540
541 /* --[ END OF TABLE ]---------------------------------------------- */
542 {
543 NULL,
544 0,
545 NULL,
546 NULL
547 }
548 };
549
550 /* send_birthdate_online_time()
551 *
552 * inputs - client pointer to send to
553 * output - NONE
554 * side effects - birthdate and online time are sent
555 */
556 static void
557 send_birthdate_online_time(struct Client *source_p)
558 {
559 sendto_one_numeric(source_p, &me, RPL_INFO | SND_EXPLICIT,
560 ":On-line since %s",
561 myctime(me.connection->firsttime));
562 }
563
564 /* send_conf_options()
565 *
566 * inputs - client pointer to send to
567 * output - NONE
568 * side effects - send config options to client
569 */
570 static void
571 send_conf_options(struct Client *source_p)
572 {
573 /*
574 * Parse the info_table[] and do the magic.
575 */
576 for (const struct InfoStruct *iptr = info_table; iptr->name; ++iptr)
577 {
578 switch (iptr->output_type)
579 {
580 /* For "char *" references */
581 case OUTPUT_STRING:
582 {
583 const char *option = *((const char *const *)iptr->option);
584
585 sendto_one_numeric(source_p, &me, RPL_INFO | SND_EXPLICIT,
586 ":%-30s %-5s [%s]",
587 iptr->name, option ? option : "NONE",
588 iptr->desc ? iptr->desc : "<none>");
589 break;
590 }
591
592 /* For "char foo[]" references */
593 case OUTPUT_STRING_PTR:
594 {
595 const char *option = iptr->option;
596
597 sendto_one_numeric(source_p, &me, RPL_INFO | SND_EXPLICIT,
598 ":%-30s %-5s [%s]",
599 iptr->name, option ? option : "NONE",
600 iptr->desc ? iptr->desc : "<none>");
601 break;
602 }
603
604 /* Output info_table[i].option as a decimal value. */
605 case OUTPUT_DECIMAL:
606 {
607 const unsigned int option = *((const unsigned int *const)iptr->option);
608
609 sendto_one_numeric(source_p, &me, RPL_INFO | SND_EXPLICIT,
610 ":%-30s %-5u [%s]",
611 iptr->name, option, iptr->desc ? iptr->desc : "<none>");
612 break;
613 }
614
615 /* Output info_table[i].option as "ON" or "OFF" */
616 case OUTPUT_BOOLEAN:
617 {
618 const unsigned int option = *((const unsigned int *const)iptr->option);
619
620 sendto_one_numeric(source_p, &me, RPL_INFO | SND_EXPLICIT,
621 ":%-30s %-5s [%s]",
622 iptr->name, option ? "ON" : "OFF",
623 iptr->desc ? iptr->desc : "<none>");
624
625 break;
626 }
627
628 /* Output info_table[i].option as "YES" or "NO" */
629 case OUTPUT_BOOLEAN_YN:
630 {
631 const unsigned int option = *((const unsigned int *const)iptr->option);
632
633 sendto_one_numeric(source_p, &me, RPL_INFO | SND_EXPLICIT,
634 ":%-30s %-5s [%s]",
635 iptr->name, option ? "YES" : "NO",
636 iptr->desc ? iptr->desc : "<none>");
637 break;
638 }
639
640 case OUTPUT_BOOLEAN2:
641 {
642 const unsigned int option = *((const unsigned int *const)iptr->option);
643
644 sendto_one_numeric(source_p, &me, RPL_INFO | SND_EXPLICIT,
645 ":%-30s %-5s [%s]",
646 iptr->name, option ? ((option == 1) ? "MASK" : "YES") : "NO",
647 iptr->desc ? iptr->desc : "<none>");
648 break;
649 }
650 }
651 }
652
653 sendto_one_numeric(source_p, &me, RPL_INFO, "");
654 }
655
656 /* send_info_text()
657 *
658 * inputs - client pointer to send info text to
659 * output - NONE
660 * side effects - info text is sent to client
661 */
662 static void
663 send_info_text(struct Client *source_p)
664 {
665 sendto_realops_flags(UMODE_SPY, L_ALL, SEND_NOTICE,
666 "INFO requested by %s (%s@%s) [%s]",
667 source_p->name, source_p->username,
668 source_p->host, source_p->servptr->name);
669
670 for (const char **text = infotext; *text; ++text)
671 {
672 const char *line = *text;
673
674 if (*line == '\0')
675 line = " ";
676
677 sendto_one_numeric(source_p, &me, RPL_INFO, line);
678 }
679
680 if (HasUMode(source_p, UMODE_OPER))
681 send_conf_options(source_p);
682
683 send_birthdate_online_time(source_p);
684
685 sendto_one_numeric(source_p, &me, RPL_ENDOFINFO);
686 }
687
688 /*! \brief INFO command handler
689 *
690 * \param source_p Pointer to allocated Client struct from which the message
691 * originally comes from. This can be a local or remote client.
692 * \param parc Integer holding the number of supplied arguments.
693 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
694 * pointers.
695 * \note Valid arguments for this command are:
696 * - parv[0] = command
697 * - parv[1] = nickname/servername
698 */
699 static int
700 m_info(struct Client *source_p, int parc, char *parv[])
701 {
702 static time_t last_used = 0;
703
704 if ((last_used + ConfigGeneral.pace_wait) > CurrentTime)
705 {
706 sendto_one_numeric(source_p, &me, RPL_LOAD2HI, "INFO");
707 return 0;
708 }
709
710 last_used = CurrentTime;
711
712 if (!ConfigServerHide.disable_remote_commands)
713 if (hunt_server(source_p, ":%s INFO :%s", 1, parc, parv) != HUNTED_ISME)
714 return 0;
715
716 send_info_text(source_p);
717 return 0;
718 }
719
720 /*! \brief INFO command handler
721 *
722 * \param source_p Pointer to allocated Client struct from which the message
723 * originally comes from. This can be a local or remote client.
724 * \param parc Integer holding the number of supplied arguments.
725 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
726 * pointers.
727 * \note Valid arguments for this command are:
728 * - parv[0] = command
729 * - parv[1] = nickname/servername
730 */
731 static int
732 ms_info(struct Client *source_p, int parc, char *parv[])
733 {
734 if (hunt_server(source_p, ":%s INFO :%s", 1, parc, parv) != HUNTED_ISME)
735 return 0;
736
737 send_info_text(source_p);
738 return 0;
739 }
740
741 static struct Message info_msgtab =
742 {
743 .cmd = "INFO",
744 .args_max = MAXPARA,
745 .handlers[UNREGISTERED_HANDLER] = m_unregistered,
746 .handlers[CLIENT_HANDLER] = m_info,
747 .handlers[SERVER_HANDLER] = ms_info,
748 .handlers[ENCAP_HANDLER] = m_ignore,
749 .handlers[OPER_HANDLER] = ms_info
750 };
751
752 static void
753 module_init(void)
754 {
755 mod_add_cmd(&info_msgtab);
756 }
757
758 static void
759 module_exit(void)
760 {
761 mod_del_cmd(&info_msgtab);
762 }
763
764 struct module module_entry =
765 {
766 .version = "$Revision$",
767 .modinit = module_init,
768 .modexit = module_exit,
769 };

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28