1 /* praxis: services for TSora IRC networks.
2 * src/config.c: Configuration file parser.
4 * Copyright (c) 2004 Eric Will <rakaur@malkier.net>
5 * Copyright (c) 2003-2004 shrike development team.
11 #include "configparse.h"
14 #include "connection.h"
22 static uchar
c_serverinfo(ConfigEntry
*);
23 static uchar
c_si_name(ConfigEntry
*);
24 static uchar
c_si_description(ConfigEntry
*);
25 static uchar
c_si_sid(ConfigEntry
*);
26 static uchar
c_si_vhost(ConfigEntry
*);
27 static uchar
c_si_reconnect_time(ConfigEntry
*);
28 static uchar
c_si_ping_time(ConfigEntry
*);
29 static uchar
c_si_admin_name(ConfigEntry
*);
30 static uchar
c_si_admin_email(ConfigEntry
*);
32 static uchar
c_uplink(ConfigEntry
*);
34 static uchar
c_userserv(ConfigEntry
*);
35 static uchar
c_us_enable(ConfigEntry
*);
36 static uchar
c_us_nick(ConfigEntry
*);
37 static uchar
c_us_user(ConfigEntry
*);
38 static uchar
c_us_host(ConfigEntry
*);
39 static uchar
c_us_real(ConfigEntry
*);
40 static uchar
c_us_max_users(ConfigEntry
*);
41 static uchar
c_us_default_flags(ConfigEntry
*);
43 static uchar
c_chanserv(ConfigEntry
*);
44 static uchar
c_cs_enable(ConfigEntry
*);
45 static uchar
c_cs_nick(ConfigEntry
*);
46 static uchar
c_cs_user(ConfigEntry
*);
47 static uchar
c_cs_host(ConfigEntry
*);
48 static uchar
c_cs_real(ConfigEntry
*);
49 static uchar
c_cs_max_chans(ConfigEntry
*);
50 static uchar
c_cs_join_chans(ConfigEntry
*);
51 static uchar
c_cs_part_chans(ConfigEntry
*);
52 static uchar
c_cs_default_flags(ConfigEntry
*);
54 static uchar
c_modules(ConfigEntry
*);
55 static uchar
c_modules_path(ConfigEntry
*);
59 static ConfigTable config_root_table
[] =
61 { "SERVERINFO", 1, c_serverinfo
},
62 { "UPLINK", 1, c_uplink
},
63 { "USERSERV", 1, c_userserv
},
64 { "CHANSERV", 1, c_chanserv
},
65 { "MODULES", 1, c_modules
},
69 static ConfigTable config_si_table
[] =
71 { "NAME", 0, c_si_name
},
72 { "DESCRIPTION", 0, c_si_description
},
73 { "SID", 0, c_si_sid
},
74 { "VHOST", 0, c_si_vhost
},
75 { "RECONNECT_TIME", 1, c_si_reconnect_time
},
76 { "PING_TIME", 1, c_si_ping_time
},
77 { "ADMIN_NAME", 1, c_si_admin_name
},
78 { "ADMIN_EMAIL", 1, c_si_admin_email
},
82 static ConfigTable config_us_table
[] =
84 { "ENABLE", 1, c_us_enable
},
85 { "NICK", 1, c_us_nick
},
86 { "USER", 0, c_us_user
},
87 { "HOST", 0, c_us_host
},
88 { "REAL", 0, c_us_real
},
89 { "MAX_USERS", 1, c_us_max_users
},
90 { "DEFAULT_FLAGS", 1, c_us_default_flags
},
94 static ConfigTable config_cs_table
[] =
96 { "ENABLE", 1, c_cs_enable
},
97 { "NICK", 1, c_cs_nick
},
98 { "USER", 0, c_cs_user
},
99 { "HOST", 0, c_cs_host
},
100 { "REAL", 0, c_cs_real
},
101 { "MAX_CHANS", 1, c_cs_max_chans
},
102 { "JOIN_CHANS", 1, c_cs_join_chans
},
103 { "PART_CHANS", 1, c_cs_part_chans
},
104 { "DEFAULT_FLAGS", 1, c_cs_default_flags
},
108 static ConfigTable config_modules_table
[] =
110 { "PATH", 1, c_modules_path
},
114 /* XXX uncomment this when i add chanserv/userserv
115 static Token config_uflags[] =
117 { "HIDEMAIL", MU_HIDEMAIL },
119 { "NEVEROP", MU_NEVEROP },
124 static Token config_cflags[] =
127 { "NEVEROP", MC_NEVEROP },
128 { "SECURE", MC_SECURE },
129 { "VERBOSE", MC_VERBOSE },
136 * Initialises the configuration settings.
144 /* Initialise serverinfo{} stuff. */
147 if (me
.admin_name
!= NULL
)
149 if (me
.admin_email
!= NULL
)
150 free(me
.admin_email
);
152 me
.desc
[0] = me
.sid
[0] = '\0';
154 me
.admin_name
= me
.admin_email
= NULL
;
156 settings
.vhost
[0] = '\0';
158 if (settings
.network_name
!= NULL
)
159 free(settings
.network_name
);
160 if (settings
.mta_path
!= NULL
)
161 free(settings
.mta_path
);
163 settings
.network_name
= settings
.mta_path
= NULL
;
164 settings
.reconnect_time
= settings
.ping_time
= settings
.expire_time
= 0;
165 settings
.auth_type
= 0;
167 globals
.start
= globals
.max_fd
= 0;
168 globals
.uplink_failed
= globals
.connected
= globals
.bursting
= 0;
170 globals
.currtime
= time(NULL
);
172 if (dlinkLength(&uplink_list
) > 0)
175 memset(&uplink_list
, '\0', sizeof(uplink_list
));
177 /* Initialise userserv{} stuff. */
178 userserv
.nick
[0] = userserv
.user
[0] = '\0';
179 userserv
.host
[0] = userserv
.real
[0] = '\0';
181 userserv
.enabled
= userserv
.max_users
= userserv
.default_flags
= 0;
183 /* Initialise chanserv{} stuff. */
184 chanserv
.nick
[0] = chanserv
.user
[0] = '\0';
185 chanserv
.host
[0] = chanserv
.real
[0] = '\0';
187 chanserv
.max_chans
= chanserv
.default_flags
= 0;
188 chanserv
.enabled
= chanserv
.join_chans
= chanserv
.part_chans
= 0;
192 * Parses the configuration file.
200 ConfigFile
*cfptr
, *cfp
;
202 ConfigTable
*ct
= NULL
;
204 cfptr
= cfp
= config_load(globals
.config_file
);
208 ilog(L_INFO
, "configParse(): Error: %s", strerror(errno
));
212 for (; cfptr
; cfptr
= cfptr
->cf_next
)
214 for (ce
= cfptr
->cf_entries
; ce
; ce
= ce
->ce_next
)
216 for (ct
= config_root_table
; ct
->name
; ct
++)
218 if (!strcasecmp(ct
->name
, ce
->ce_varname
))
220 if ((globals
.run_flags
& RF_REHASHING
) &&
221 (ct
->rehashable
== 0))
229 if (ct
->name
== NULL
)
231 ilog(L_ERROR
, "%s:%d: Invalid configuration option: %s",
232 ce
->ce_fileptr
->cf_filename
, ce
->ce_varlinenum
,
242 * Performs sanity checking on configuration settings.
245 * outputs - 1 on verified or 0 on failure
250 if (me
.name
[0] == '\0')
252 ilog(L_INFO
, "Config error: no serverinfo::name set.");
256 if (me
.desc
[0] == '\0')
258 ilog(L_INFO
, "Config error: no serverinfo::description set.");
264 ilog(L_INFO
, "Config error: no serverinfo::sid set.");
268 if (settings
.reconnect_time
< 5)
270 ilog(L_INFO
, "Config warning: value too low for "
271 "serverinfo::reconnect_time; defaulting to 5.");
274 if (settings
.ping_time
== 0)
276 ilog(L_INFO
, "Config warning: value too low for "
277 "serverinfo::ping_time; defaulting to 5.");
280 if (me
.admin_name
== NULL
)
282 ilog(L_INFO
, "Config error: no serverinfo::admin_name set.");
286 if (me
.admin_email
== NULL
)
288 ilog(L_INFO
, "Config error: no serverinfo::admin_email set.");
292 /* This spits out a warning and not an error because other services
293 * later on might want to use MyUsers. Making it error out is probably
294 * a bad idea, while spitting out a warning could serve as a reminder for
295 * someone that didn't mean to do this.
297 if ((userserv
.enabled
== 1) && (chanserv
.enabled
== 0))
299 ilog(L_INFO
, "Config warning: userserv is enabled without chanserv.");
302 if ((userserv
.enabled
== 0) && (chanserv
.enabled
== 1))
304 ilog(L_INFO
, "Config error: chanserv is enabled without userserv.");
308 if (userserv
.enabled
== 1)
310 if (userserv
.nick
[0] == '\0')
312 ilog(L_INFO
, "Config error: no userserv::nick set.");
316 if (userserv
.user
[0] == '\0')
318 ilog(L_INFO
, "Config error: no userserv::user set.");
322 if (userserv
.host
[0] == '\0')
324 ilog(L_INFO
, "Config error: no userserv::host set.");
328 if (userserv
.real
[0] == '\0')
330 ilog(L_INFO
, "Config error: no userserv::real set.");
334 if (userserv
.max_users
< 1)
336 ilog(L_INFO
, "Config warning: value too low for "
337 "userserv::max_users; defaulting to 5.");
341 if (chanserv
.enabled
== 1)
343 if (chanserv
.nick
[0] == '\0')
345 ilog(L_INFO
, "Config error: no chanserv::nick set.");
349 if (chanserv
.user
[0] == '\0')
351 ilog(L_INFO
, "Config error: no chanserv::user set.");
355 if (chanserv
.host
[0] == '\0')
357 ilog(L_INFO
, "Config error: no chanserv::host set.");
361 if (chanserv
.real
[0] == '\0')
363 ilog(L_INFO
, "Config error: no chanserv::real set.");
367 if (chanserv
.max_chans
< 1)
369 ilog(L_INFO
, "Config warning: value too low for "
370 "chanserv::max_users; defaulting to 5.");
378 c_subblock(ConfigEntry
*ce
, const char *subblock
, ConfigTable
*table
)
380 ConfigTable
*ct
= NULL
;
382 for (ce
= ce
->ce_entries
; ce
; ce
= ce
->ce_next
)
384 for (ct
= table
; ct
->name
; ct
++)
386 if (!strcasecmp(ct
->name
, ce
->ce_varname
))
388 if ((globals
.run_flags
& RF_REHASHING
) && (ct
->rehashable
== 0))
396 if (ct
->name
== NULL
)
398 ilog(L_ERROR
, "%s:%d: Invalid configuration option: %s::%s",
399 ce
->ce_fileptr
->cf_filename
, ce
->ce_varlinenum
,
400 subblock
, ce
->ce_varname
);
408 c_serverinfo(ConfigEntry
*ce
)
410 c_subblock(ce
, "serverinfo", config_si_table
);
415 c_si_name(ConfigEntry
*ce
)
417 if (ce
->ce_vardata
== NULL
)
420 strlcpy(me
.name
, ce
->ce_vardata
, HOSTLEN
);
426 c_si_description(ConfigEntry
*ce
)
428 if (ce
->ce_vardata
== NULL
)
431 strlcpy(me
.desc
, ce
->ce_vardata
, REALLEN
);
437 c_si_sid(ConfigEntry
*ce
)
439 if (ce
->ce_vardata
== NULL
)
442 strlcpy(me
.sid
, ce
->ce_vardata
, 4);
448 c_si_vhost(ConfigEntry
*ce
)
450 if (ce
->ce_vardata
== NULL
)
453 strlcpy(settings
.vhost
, ce
->ce_vardata
, HOSTLEN
);
459 c_si_reconnect_time(ConfigEntry
*ce
)
461 if (ce
->ce_vardata
== NULL
)
464 settings
.reconnect_time
= ce
->ce_vardatanum
;
470 c_si_ping_time(ConfigEntry
*ce
)
472 if (ce
->ce_vardata
== NULL
)
475 settings
.ping_time
= (ce
->ce_vardatanum
* 60);
481 c_si_admin_name(ConfigEntry
*ce
)
483 if (ce
->ce_vardata
== NULL
)
486 me
.admin_name
= istrdup(ce
->ce_vardata
);
492 c_si_admin_email(ConfigEntry
*ce
)
494 if (ce
->ce_vardata
== NULL
)
497 me
.admin_email
= istrdup(ce
->ce_vardata
);
503 c_uplink(ConfigEntry
*ce
)
506 char name
[HOSTLEN
+ 1], host
[HOSTLEN
+ 1];
507 char pass
[PASSLEN
+ 1], vhost
[HOSTLEN
+ 1];
510 name
[0] = host
[0] = pass
[0] = vhost
[0] = '\0';
512 if (ce
->ce_vardata
== NULL
)
515 strlcpy(name
, ce
->ce_vardata
, HOSTLEN
);
517 for (ce
= ce
->ce_entries
; ce
; ce
= ce
->ce_next
)
519 if (!strcasecmp(ce
->ce_varname
, "HOST"))
521 if (ce
->ce_vardata
== NULL
)
524 strlcpy(host
, ce
->ce_vardata
, HOSTLEN
);
529 else if (!strcasecmp(ce
->ce_varname
, "VHOST"))
531 if (ce
->ce_vardata
== NULL
)
534 strlcpy(vhost
, ce
->ce_vardata
, HOSTLEN
);
539 else if (!strcasecmp(ce
->ce_varname
, "PASSWORD"))
541 if (ce
->ce_vardata
== NULL
)
544 strlcpy(pass
, ce
->ce_vardata
, PASSLEN
);
549 else if (!strcasecmp(ce
->ce_varname
, "PORT"))
551 if (ce
->ce_vardata
== NULL
)
554 port
= ce
->ce_vardatanum
;
560 ilog(L_ERROR
, "%s:%d: Invalid configuration option: uplink::%s",
561 ce
->ce_fileptr
->cf_filename
, ce
->ce_varlinenum
,
568 /* Make sure it's all valid. */
571 ilog(L_INFO
, "Invalid uplink{} block: no host specified.");
578 ilog(L_INFO
, "Invalid uplink{} block: no pass specified.");
586 /* If we get to here then it's good to add. */
587 uplink_p
= uplinkAdd(name
, host
, pass
, port
);
589 strlcpy(uplink_p
->vhost
, vhost
, HOSTLEN
);
595 c_userserv(ConfigEntry
*ce
)
597 c_subblock(ce
, "userserv", config_us_table
);
602 c_us_enable(ConfigEntry
*ce
)
604 userserv
.enabled
= 1;
609 c_us_nick(ConfigEntry
*ce
)
611 if (ce
->ce_vardata
== NULL
)
614 if (userserv
.enabled
== 0)
617 strlcpy(userserv
.nick
, ce
->ce_vardata
, NICKLEN
);
623 c_us_user(ConfigEntry
*ce
)
625 if (ce
->ce_vardata
== NULL
)
628 if (userserv
.enabled
== 0)
631 strlcpy(userserv
.user
, ce
->ce_vardata
, USERLEN
);
637 c_us_host(ConfigEntry
*ce
)
639 if (ce
->ce_vardata
== NULL
)
642 if (userserv
.enabled
== 0)
645 strlcpy(userserv
.host
, ce
->ce_vardata
, HOSTLEN
);
651 c_us_real(ConfigEntry
*ce
)
653 if (ce
->ce_vardata
== NULL
)
656 if (userserv
.enabled
== 0)
659 strlcpy(userserv
.real
, ce
->ce_vardata
, REALLEN
);
665 c_us_max_users(ConfigEntry
*ce
)
667 if (ce
->ce_vardata
== NULL
)
670 if (userserv
.enabled
== 0)
673 userserv
.max_users
= ce
->ce_vardatanum
;
679 c_us_default_flags(ConfigEntry
*ce
)
681 if (userserv
.enabled
== 0)
684 /* XXX - uncomment this when i do chanserv/userserv
685 for (flce = ce->ce_entries; flce; flce = flce->ce_next)
689 val = token_to_value(config_uflags, flce->ce_varname);
691 if ((val != TOKEN_UNMATCHED) && (val != TOKEN_ERROR))
692 userserv.default_flags |= val;
696 ilog(L_INFO, "%s:%d: unknown flag: %s",
697 flce->ce_fileptr->cf_filename, flce->ce_varlinenum,
706 c_chanserv(ConfigEntry
*ce
)
708 c_subblock(ce
, "chanserv", config_cs_table
);
713 c_cs_enable(ConfigEntry
*ce
)
715 chanserv
.enabled
= 1;
720 c_cs_nick(ConfigEntry
*ce
)
722 if (ce
->ce_vardata
== NULL
)
725 if (chanserv
.enabled
== 0)
728 strlcpy(chanserv
.nick
, ce
->ce_vardata
, NICKLEN
);
734 c_cs_user(ConfigEntry
*ce
)
736 if (ce
->ce_vardata
== NULL
)
739 if (chanserv
.enabled
== 0)
742 strlcpy(chanserv
.user
, ce
->ce_vardata
, USERLEN
);
748 c_cs_host(ConfigEntry
*ce
)
750 if (ce
->ce_vardata
== NULL
)
753 if (chanserv
.enabled
== 0)
756 strlcpy(chanserv
.host
, ce
->ce_vardata
, HOSTLEN
);
762 c_cs_real(ConfigEntry
*ce
)
764 if (ce
->ce_vardata
== NULL
)
767 if (chanserv
.enabled
== 0)
770 strlcpy(chanserv
.real
, ce
->ce_vardata
, REALLEN
);
776 c_cs_max_chans(ConfigEntry
*ce
)
778 if (ce
->ce_vardata
== NULL
)
781 if (chanserv
.enabled
== 0)
784 chanserv
.max_chans
= ce
->ce_vardatanum
;
790 c_cs_join_chans(ConfigEntry
*ce
)
792 if (chanserv
.enabled
== 0)
795 chanserv
.join_chans
= 1;
801 c_cs_part_chans(ConfigEntry
*ce
)
803 if (chanserv
.enabled
== 0)
806 chanserv
.part_chans
= 1;
812 c_cs_default_flags(ConfigEntry
*ce
)
814 if (chanserv
.enabled
== 0)
817 /* XXX uncomment this when i do chanserv/userserv
818 for (flce = ce->ce_entries; flce; flce = flce->ce_next)
822 val = token_to_value(config_cflags, flce->ce_varname);
824 if ((val != TOKEN_UNMATCHED) && (val != TOKEN_ERROR))
825 chanserv.default_flags |= val;
829 ilog(L_INFO, "%s:%d: unknown flag: %s",
830 flce->ce_fileptr->cf_filename, flce->ce_varlinenum,
839 c_modules(ConfigEntry
*ce
)
841 c_subblock(ce
, "modules", config_modules_table
);
846 c_modules_path(ConfigEntry
*ce
)
848 if (ce
->ce_vardata
== NULL
)
851 #ifndef STATIC_MODULES
852 modulePathAdd(ce
->ce_vardata
);