* include/mailutils/cfg.h (mu_cfg_section): New type.
(struct mu_cfg_param.offset): New member (mu_offsetof): New define (mu_cfg_section_fp): Change signature (struct mu_cfg_section.label,target): New members. (struct mu_cfg_section.data): Remove. (struct mu_cfg_section.children): New member, instead of param and subsec which are removed. (mu_cfg_scan_tree): Change signature. (mu_config_register_section): Change signature. (mu_parse_config): Change signature. (mu_parse_config_tree): Rename to mu_cfg_tree_reduce. (mu_get_config): New proto. * include/mailutils/libcfg.h (mu_parse_config_files): Change prototype. * dotlock/dotlock.c, imap4d/imap4d.c, lib/tcpwrap.h, libargp/muinit.c, libcfg/auth.c, libcfg/common.c, libcfg/gsasl.c, libcfg/init.c, libcfg/ldap.c, libcfg/pam.c, libcfg/radius.c, libcfg/sieve.c, libcfg/sql.c, libcfg/tls.c, libcfg/virtdomain.c, maidag/maidag.c, mail.local/main.c, mail.remote/mail.remote.c, mailbox/cfg_format.c, mailbox/cfg_parser.y, mimeview/mimeview.c, movemail/movemail.c, pop3d/pop3d.c, readmsg/readmsg.c, sieve/sieve.c: Reflect changes to the cfg framework. * mailbox/Makefile.am (libmailutils_la_SOURCES): Add cfg_driver.c. * mailbox/cfg_driver.c: New file. * mailbox/cfg_lexer.c: Move driver part into a separate file. * examples/Makefile.am (AM_LDFLAGS): Remove libmuaux * examples/echosrv.c: Remove getopt.h
Showing
33 changed files
with
853 additions
and
709 deletions
1 | 2007-12-11 Sergey Poznyakoff <gray@gnu.org.ua> | ||
2 | |||
3 | * include/mailutils/cfg.h (mu_cfg_section): New type. | ||
4 | (struct mu_cfg_param.offset): New member | ||
5 | (mu_offsetof): New define | ||
6 | (mu_cfg_section_fp): Change signature | ||
7 | (struct mu_cfg_section.label,target): New members. | ||
8 | (struct mu_cfg_section.data): Remove. | ||
9 | (struct mu_cfg_section.children): New member, instead of | ||
10 | param and subsec which are removed. | ||
11 | (mu_cfg_scan_tree): Change signature. | ||
12 | (mu_config_register_section): Change signature. | ||
13 | (mu_parse_config): Change signature. | ||
14 | (mu_parse_config_tree): Rename to mu_cfg_tree_reduce. | ||
15 | (mu_get_config): New proto. | ||
16 | |||
17 | * include/mailutils/libcfg.h (mu_parse_config_files): Change | ||
18 | prototype. | ||
19 | |||
20 | * dotlock/dotlock.c, imap4d/imap4d.c, lib/tcpwrap.h, | ||
21 | libargp/muinit.c, libcfg/auth.c, libcfg/common.c, libcfg/gsasl.c, | ||
22 | libcfg/init.c, libcfg/ldap.c, libcfg/pam.c, libcfg/radius.c, | ||
23 | libcfg/sieve.c, libcfg/sql.c, libcfg/tls.c, libcfg/virtdomain.c, | ||
24 | maidag/maidag.c, mail.local/main.c, mail.remote/mail.remote.c, | ||
25 | mailbox/cfg_format.c, mailbox/cfg_parser.y, mimeview/mimeview.c, | ||
26 | movemail/movemail.c, pop3d/pop3d.c, readmsg/readmsg.c, | ||
27 | sieve/sieve.c: Reflect changes to the cfg framework. | ||
28 | |||
29 | * mailbox/Makefile.am (libmailutils_la_SOURCES): Add cfg_driver.c. | ||
30 | * mailbox/cfg_driver.c: New file. | ||
31 | * mailbox/cfg_lexer.c: Move driver part into a separate file. | ||
32 | |||
33 | * examples/Makefile.am (AM_LDFLAGS): Remove libmuaux | ||
34 | * examples/echosrv.c: Remove getopt.h | ||
35 | |||
1 | 2007-12-09 Sergey Poznyakoff <gray@gnu.org.ua> | 36 | 2007-12-09 Sergey Poznyakoff <gray@gnu.org.ua> |
2 | 37 | ||
3 | * examples/Makefile.am: add echosrv.c. | 38 | * examples/Makefile.am: add echosrv.c. | ... | ... |
... | @@ -125,11 +125,11 @@ parse_opt (int key, char *arg, struct argp_state *state) | ... | @@ -125,11 +125,11 @@ parse_opt (int key, char *arg, struct argp_state *state) |
125 | 125 | ||
126 | 126 | ||
127 | struct mu_cfg_param dotlock_cfg_param[] = { | 127 | struct mu_cfg_param dotlock_cfg_param[] = { |
128 | { "force", mu_cfg_time, &force, NULL, | 128 | { "force", mu_cfg_time, &force, 0, NULL, |
129 | N_("Forcibly break an existing lock older than the specified time.") }, | 129 | N_("Forcibly break an existing lock older than the specified time.") }, |
130 | { "retry", mu_cfg_int, &retries, NULL, | 130 | { "retry", mu_cfg_int, &retries, 0, NULL, |
131 | N_("Number of times to retry acquiring the lock.") }, | 131 | N_("Number of times to retry acquiring the lock.") }, |
132 | { "debug", mu_cfg_bool, &debug, NULL, | 132 | { "debug", mu_cfg_bool, &debug, 0, NULL, |
133 | N_("Print details of failure reasons to stderr.") }, | 133 | N_("Print details of failure reasons to stderr.") }, |
134 | { NULL } | 134 | { NULL } |
135 | }; | 135 | }; | ... | ... |
... | @@ -54,7 +54,6 @@ mod_LTLIBRARIES = numaddr.la | ... | @@ -54,7 +54,6 @@ mod_LTLIBRARIES = numaddr.la |
54 | INCLUDES = @MU_COMMON_INCLUDES@ | 54 | INCLUDES = @MU_COMMON_INCLUDES@ |
55 | 55 | ||
56 | AM_LDFLAGS = \ | 56 | AM_LDFLAGS = \ |
57 | ../lib/libmuaux.la\ | ||
58 | ${MU_LIB_MAILUTILS}\ | 57 | ${MU_LIB_MAILUTILS}\ |
59 | @MU_COMMON_LIBRARIES@ | 58 | @MU_COMMON_LIBRARIES@ |
60 | 59 | ... | ... |
... | @@ -28,7 +28,6 @@ | ... | @@ -28,7 +28,6 @@ |
28 | #include <arpa/inet.h> | 28 | #include <arpa/inet.h> |
29 | #include <signal.h> | 29 | #include <signal.h> |
30 | #include <sys/wait.h> | 30 | #include <sys/wait.h> |
31 | #include "getopt.h" | ||
32 | 31 | ||
33 | #include <mailutils/mailutils.h> | 32 | #include <mailutils/mailutils.h> |
34 | #include <mailutils/server.h> | 33 | #include <mailutils/server.h> |
... | @@ -185,7 +184,8 @@ server_idle (void *server_data) | ... | @@ -185,7 +184,8 @@ server_idle (void *server_data) |
185 | (unsigned long) pid, | 184 | (unsigned long) pid, |
186 | WTERMSIG (status)); | 185 | WTERMSIG (status)); |
187 | else | 186 | else |
188 | mu_diag_output (MU_DIAG_ERR, "%lu: terminated (cause unknown)"); | 187 | mu_diag_output (MU_DIAG_ERR, "%lu: terminated (cause unknown)", |
188 | (unsigned long) pid); | ||
189 | } | 189 | } |
190 | } | 190 | } |
191 | return 0; | 191 | return 0; | ... | ... |
... | @@ -272,33 +272,33 @@ cb_preauth (mu_debug_t debug, void *data, char *arg) | ... | @@ -272,33 +272,33 @@ cb_preauth (mu_debug_t debug, void *data, char *arg) |
272 | } | 272 | } |
273 | 273 | ||
274 | static struct mu_cfg_param imap4d_cfg_param[] = { | 274 | static struct mu_cfg_param imap4d_cfg_param[] = { |
275 | { "other-namespace", mu_cfg_callback, NULL, cb_other, | 275 | { "other-namespace", mu_cfg_callback, NULL, 0, cb_other, |
276 | N_("Set other users' namespace. Argument is a colon-separated list " | 276 | N_("Set other users' namespace. Argument is a colon-separated list " |
277 | "of directories comprising the namespace.") }, | 277 | "of directories comprising the namespace.") }, |
278 | { "shared-namespace", mu_cfg_callback, NULL, cb_shared, | 278 | { "shared-namespace", mu_cfg_callback, NULL, 0, cb_shared, |
279 | N_("Set shared namespace. Argument is a colon-separated list " | 279 | N_("Set shared namespace. Argument is a colon-separated list " |
280 | "of directories comprising the namespace.") }, | 280 | "of directories comprising the namespace.") }, |
281 | { "login-disabled", mu_cfg_int, &login_disabled, NULL, | 281 | { "login-disabled", mu_cfg_int, &login_disabled, 0, NULL, |
282 | N_("Disable LOGIN command.") }, | 282 | N_("Disable LOGIN command.") }, |
283 | { "create-home-dir", mu_cfg_bool, &create_home_dir, NULL, | 283 | { "create-home-dir", mu_cfg_bool, &create_home_dir, 0, NULL, |
284 | N_("If true, create non-existing user home directories.") }, | 284 | N_("If true, create non-existing user home directories.") }, |
285 | { "home-dir-mode", mu_cfg_callback, NULL, cb_mode, | 285 | { "home-dir-mode", mu_cfg_callback, NULL, 0, cb_mode, |
286 | N_("File mode for creating user home directories (octal)."), | 286 | N_("File mode for creating user home directories (octal)."), |
287 | N_("mode") }, | 287 | N_("mode") }, |
288 | { "tls-required", mu_cfg_int, &tls_required, NULL, | 288 | { "tls-required", mu_cfg_int, &tls_required, 0, NULL, |
289 | N_("Always require STARTTLS before entering authentication phase.") }, | 289 | N_("Always require STARTTLS before entering authentication phase.") }, |
290 | { "preauth", mu_cfg_callback, NULL, cb_preauth, | 290 | { "preauth", mu_cfg_callback, NULL, 0, cb_preauth, |
291 | N_("Configure PREAUTH mode. MODE is one of:\n" | 291 | N_("Configure PREAUTH mode. MODE is one of:\n" |
292 | " prog:///<full-program-name: string>\n" | 292 | " prog:///<full-program-name: string>\n" |
293 | " ident[://:<port: string-or-number>]\n" | 293 | " ident[://:<port: string-or-number>]\n" |
294 | " stdio"), | 294 | " stdio"), |
295 | N_("MODE") }, | 295 | N_("MODE") }, |
296 | { "preauth-only", mu_cfg_bool, &preauth_only, NULL, | 296 | { "preauth-only", mu_cfg_bool, &preauth_only, 0, NULL, |
297 | N_("Use only preauth mode. If unable to setup it, disconnect " | 297 | N_("Use only preauth mode. If unable to setup it, disconnect " |
298 | "immediately.") }, | 298 | "immediately.") }, |
299 | { "ident-keyfile", mu_cfg_string, &ident_keyfile, NULL, | 299 | { "ident-keyfile", mu_cfg_string, &ident_keyfile, 0, NULL, |
300 | N_("Name of DES keyfile for decoding ecrypted ident responses.") }, | 300 | N_("Name of DES keyfile for decoding ecrypted ident responses.") }, |
301 | { "ident-entrypt-only", mu_cfg_bool, &ident_encrypt_only, NULL, | 301 | { "ident-entrypt-only", mu_cfg_bool, &ident_encrypt_only, 0, NULL, |
302 | N_("Use only encrypted ident responses.") }, | 302 | N_("Use only encrypted ident responses.") }, |
303 | TCP_WRAPPERS_CONFIG | 303 | TCP_WRAPPERS_CONFIG |
304 | { NULL } | 304 | { NULL } | ... | ... |
... | @@ -118,7 +118,8 @@ enum mu_cfg_param_data_type | ... | @@ -118,7 +118,8 @@ enum mu_cfg_param_data_type |
118 | mu_cfg_ipv4, | 118 | mu_cfg_ipv4, |
119 | mu_cfg_cidr, | 119 | mu_cfg_cidr, |
120 | mu_cfg_host, | 120 | mu_cfg_host, |
121 | mu_cfg_callback | 121 | mu_cfg_callback, |
122 | mu_cfg_section | ||
122 | }; | 123 | }; |
123 | 124 | ||
124 | typedef int (*mu_cfg_callback_t) (mu_debug_t, void *, char *); | 125 | typedef int (*mu_cfg_callback_t) (mu_debug_t, void *, char *); |
... | @@ -128,11 +129,17 @@ struct mu_cfg_param | ... | @@ -128,11 +129,17 @@ struct mu_cfg_param |
128 | const char *ident; | 129 | const char *ident; |
129 | enum mu_cfg_param_data_type type; | 130 | enum mu_cfg_param_data_type type; |
130 | void *data; | 131 | void *data; |
132 | size_t offset; | ||
131 | mu_cfg_callback_t callback; | 133 | mu_cfg_callback_t callback; |
132 | const char *docstring; | 134 | const char *docstring; |
133 | const char *argname; | 135 | const char *argname; |
134 | }; | 136 | }; |
135 | 137 | ||
138 | #define mu_offsetof(s,f) ((size_t)&((s*)0).f) | ||
139 | |||
140 | #define MU_TARGET_REF(f) &f, 0 | ||
141 | #define MU_TARGET_OFF(s,f) NULL, mu_offsetof(s,f) | ||
142 | |||
136 | enum mu_cfg_section_stage | 143 | enum mu_cfg_section_stage |
137 | { | 144 | { |
138 | mu_cfg_section_start, | 145 | mu_cfg_section_start, |
... | @@ -141,17 +148,18 @@ enum mu_cfg_section_stage | ... | @@ -141,17 +148,18 @@ enum mu_cfg_section_stage |
141 | 148 | ||
142 | typedef int (*mu_cfg_section_fp) (enum mu_cfg_section_stage stage, | 149 | typedef int (*mu_cfg_section_fp) (enum mu_cfg_section_stage stage, |
143 | const mu_cfg_node_t *node, | 150 | const mu_cfg_node_t *node, |
144 | void *section_data, | 151 | const char *label, |
152 | void **section_data_ptr, | ||
145 | void *call_data, | 153 | void *call_data, |
146 | mu_cfg_tree_t *tree); | 154 | mu_cfg_tree_t *tree); |
147 | 155 | ||
148 | struct mu_cfg_section | 156 | struct mu_cfg_section |
149 | { | 157 | { |
150 | const char *ident; | 158 | const char *ident; |
159 | char *label; | ||
151 | mu_cfg_section_fp parser; | 160 | mu_cfg_section_fp parser; |
152 | void *data; | 161 | void *target; |
153 | mu_list_t /* of mu_cfg_cont/mu_cfg_section */ subsec; | 162 | mu_list_t /* of mu_cfg_cont */ children; |
154 | mu_list_t /* of mu_cfg_cont/mu_cfg_param */ param; | ||
155 | char *docstring; | 163 | char *docstring; |
156 | }; | 164 | }; |
157 | 165 | ||
... | @@ -187,15 +195,15 @@ int mu_config_clone_container (struct mu_cfg_cont *cont); | ... | @@ -187,15 +195,15 @@ int mu_config_clone_container (struct mu_cfg_cont *cont); |
187 | void mu_config_destroy_container (struct mu_cfg_cont **pcont); | 195 | void mu_config_destroy_container (struct mu_cfg_cont **pcont); |
188 | 196 | ||
189 | int mu_cfg_scan_tree (mu_cfg_tree_t *tree, struct mu_cfg_section *sections, | 197 | int mu_cfg_scan_tree (mu_cfg_tree_t *tree, struct mu_cfg_section *sections, |
190 | void *call_data); | 198 | void *target, void *call_data); |
191 | 199 | ||
192 | int mu_cfg_find_section (struct mu_cfg_section *root_sec, | 200 | int mu_cfg_find_section (struct mu_cfg_section *root_sec, |
193 | const char *path, struct mu_cfg_section **retval); | 201 | const char *path, struct mu_cfg_section **retval); |
194 | 202 | ||
195 | int mu_config_register_section (const char *parent_path, | 203 | int mu_config_register_section (const char *parent_path, |
196 | const char *ident, | 204 | const char *ident, |
205 | const char *label, | ||
197 | mu_cfg_section_fp parser, | 206 | mu_cfg_section_fp parser, |
198 | void *data, | ||
199 | struct mu_cfg_param *param); | 207 | struct mu_cfg_param *param); |
200 | int mu_config_register_plain_section (const char *parent_path, | 208 | int mu_config_register_plain_section (const char *parent_path, |
201 | const char *ident, | 209 | const char *ident, |
... | @@ -206,7 +214,8 @@ int mu_config_register_plain_section (const char *parent_path, | ... | @@ -206,7 +214,8 @@ int mu_config_register_plain_section (const char *parent_path, |
206 | #define MU_PARSE_CONFIG_DUMP 0x4 | 214 | #define MU_PARSE_CONFIG_DUMP 0x4 |
207 | 215 | ||
208 | int mu_parse_config (const char *file, const char *progname, | 216 | int mu_parse_config (const char *file, const char *progname, |
209 | struct mu_cfg_param *progparam, int flags); | 217 | struct mu_cfg_param *progparam, int flags, |
218 | void *target_ptr); | ||
210 | 219 | ||
211 | int mu_cfg_parse_boolean (const char *str, int *res); | 220 | int mu_cfg_parse_boolean (const char *str, int *res); |
212 | 221 | ||
... | @@ -218,8 +227,14 @@ void mu_cfg_format_parse_tree (mu_stream_t stream, struct mu_cfg_tree *tree); | ... | @@ -218,8 +227,14 @@ void mu_cfg_format_parse_tree (mu_stream_t stream, struct mu_cfg_tree *tree); |
218 | void mu_cfg_format_container (mu_stream_t stream, struct mu_cfg_cont *cont); | 227 | void mu_cfg_format_container (mu_stream_t stream, struct mu_cfg_cont *cont); |
219 | void mu_format_config_tree (mu_stream_t stream, const char *progname, | 228 | void mu_format_config_tree (mu_stream_t stream, const char *progname, |
220 | struct mu_cfg_param *progparam, int flags); | 229 | struct mu_cfg_param *progparam, int flags); |
221 | int mu_parse_config_tree (mu_cfg_tree_t *parse_tree, const char *progname, | 230 | int mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree, const char *progname, |
222 | struct mu_cfg_param *progparam, int flags); | 231 | struct mu_cfg_param *progparam, |
232 | int flags, void *target_ptr); | ||
233 | |||
234 | int mu_get_config (const char *file, const char *progname, | ||
235 | struct mu_cfg_param *progparam, int flags, | ||
236 | void *target_ptr); | ||
237 | |||
223 | 238 | ||
224 | int mu_cfg_tree_create (struct mu_cfg_tree **ptree); | 239 | int mu_cfg_tree_create (struct mu_cfg_tree **ptree); |
225 | void mu_cfg_tree_set_debug (struct mu_cfg_tree *tree, mu_debug_t debug); | 240 | void mu_cfg_tree_set_debug (struct mu_cfg_tree *tree, mu_debug_t debug); | ... | ... |
... | @@ -49,7 +49,8 @@ extern int mu_register_cfg_capa (const char *name, | ... | @@ -49,7 +49,8 @@ extern int mu_register_cfg_capa (const char *name, |
49 | mu_cfg_section_fp *parser); | 49 | mu_cfg_section_fp *parser); |
50 | 50 | ||
51 | extern void mu_libcfg_init (char **cnames); | 51 | extern void mu_libcfg_init (char **cnames); |
52 | extern int mu_parse_config_files (struct mu_cfg_param *param); | 52 | extern int mu_parse_config_files (struct mu_cfg_param *param, |
53 | void *target_ptr); | ||
53 | 54 | ||
54 | #define __mu_common_cat2__(a,b) a ## b | 55 | #define __mu_common_cat2__(a,b) a ## b |
55 | #define __mu_common_cat3__(a,b,c) a ## b ## c | 56 | #define __mu_common_cat3__(a,b,c) a ## b ## c |
... | @@ -57,7 +58,8 @@ extern int mu_parse_config_files (struct mu_cfg_param *param); | ... | @@ -57,7 +58,8 @@ extern int mu_parse_config_files (struct mu_cfg_param *param); |
57 | int \ | 58 | int \ |
58 | __mu_common_cat3__(mu_,capa,_section_parser) \ | 59 | __mu_common_cat3__(mu_,capa,_section_parser) \ |
59 | (enum mu_cfg_section_stage stage, const mu_cfg_node_t *node, \ | 60 | (enum mu_cfg_section_stage stage, const mu_cfg_node_t *node, \ |
60 | void *section_data, void *call_data, mu_cfg_tree_t *tree) \ | 61 | const char *section_label, void **section_data, \ |
62 | void *call_data, mu_cfg_tree_t *tree) \ | ||
61 | { \ | 63 | { \ |
62 | switch (stage) \ | 64 | switch (stage) \ |
63 | { \ | 65 | { \ | ... | ... |
... | @@ -33,25 +33,27 @@ extern int mu_tcpwrapper_access (int fd); | ... | @@ -33,25 +33,27 @@ extern int mu_tcpwrapper_access (int fd); |
33 | 33 | ||
34 | #ifdef WITH_LIBWRAP | 34 | #ifdef WITH_LIBWRAP |
35 | # define TCP_WRAPPERS_CONFIG \ | 35 | # define TCP_WRAPPERS_CONFIG \ |
36 | { "tcp-wrapper-enable", mu_cfg_bool, &mu_tcp_wrapper_enable, NULL, \ | 36 | { "tcp-wrapper-enable", mu_cfg_bool, &mu_tcp_wrapper_enable, 0, NULL, \ |
37 | N_("Enable TCP wrapper access control. Default is \"yes\".") }, \ | 37 | N_("Enable TCP wrapper access control. Default is \"yes\".") }, \ |
38 | { "tcp-wrapper-daemon", mu_cfg_string, &mu_tcp_wrapper_daemon, NULL, \ | 38 | { "tcp-wrapper-daemon", mu_cfg_string, &mu_tcp_wrapper_daemon, 0, NULL, \ |
39 | N_("Set daemon name for TCP wrapper lookups. Default is program name."), \ | 39 | N_("Set daemon name for TCP wrapper lookups. Default is program name."), \ |
40 | N_("name") }, \ | 40 | N_("name") }, \ |
41 | { "hosts-allow-table", mu_cfg_callback, NULL, mu_tcp_wrapper_cb_hosts_allow,\ | 41 | { "hosts-allow-table", mu_cfg_callback, NULL, 0, \ |
42 | mu_tcp_wrapper_cb_hosts_allow, \ | ||
42 | N_("Use file for positive client address access control " \ | 43 | N_("Use file for positive client address access control " \ |
43 | "(default: /etc/hosts.allow)."), \ | 44 | "(default: /etc/hosts.allow)."), \ |
44 | N_("file") }, \ | 45 | N_("file") }, \ |
45 | { "hosts-deny-table", mu_cfg_callback, NULL, mu_tcp_wrapper_cb_hosts_deny, \ | 46 | { "hosts-deny-table", mu_cfg_callback, NULL, 0, \ |
47 | mu_tcp_wrapper_cb_hosts_deny, \ | ||
46 | N_("Use file for negative client address access control " \ | 48 | N_("Use file for negative client address access control " \ |
47 | "(default: /etc/hosts.deny)."), \ | 49 | "(default: /etc/hosts.deny)."), \ |
48 | N_("file") }, \ | 50 | N_("file") }, \ |
49 | { "hosts-allow-syslog-level", mu_cfg_callback, NULL, \ | 51 | { "hosts-allow-syslog-level", mu_cfg_callback, NULL, 0, \ |
50 | mu_tcp_wrapper_cb_hosts_allow_syslog, \ | 52 | mu_tcp_wrapper_cb_hosts_allow_syslog, \ |
51 | N_("Log host allows at this syslog level. See logging { facility } for " \ | 53 | N_("Log host allows at this syslog level. See logging { facility } for " \ |
52 | "a description of argument syntax."), \ | 54 | "a description of argument syntax."), \ |
53 | N_("level") }, \ | 55 | N_("level") }, \ |
54 | { "hosts-allow-deny-level", mu_cfg_callback, NULL, \ | 56 | { "hosts-allow-deny-level", mu_cfg_callback, NULL, 0, \ |
55 | mu_tcp_wrapper_cb_hosts_deny_syslog, \ | 57 | mu_tcp_wrapper_cb_hosts_deny_syslog, \ |
56 | N_("Log host denies at this syslog level. See logging { facility } for " \ | 58 | N_("Log host denies at this syslog level. See logging { facility } for " \ |
57 | "a description of argument syntax."), \ | 59 | "a description of argument syntax."), \ | ... | ... |
... | @@ -77,7 +77,7 @@ mu_app_init (struct argp *myargp, const char **capa, | ... | @@ -77,7 +77,7 @@ mu_app_init (struct argp *myargp, const char **capa, |
77 | 77 | ||
78 | mu_libcfg_init (excapa); | 78 | mu_libcfg_init (excapa); |
79 | free (excapa); | 79 | free (excapa); |
80 | mu_parse_config_files (cfg_param); | 80 | mu_parse_config_files (cfg_param, data); |
81 | 81 | ||
82 | if (mu_help_config_mode) | 82 | if (mu_help_config_mode) |
83 | { | 83 | { |
... | @@ -113,8 +113,8 @@ mu_app_init (struct argp *myargp, const char **capa, | ... | @@ -113,8 +113,8 @@ mu_app_init (struct argp *myargp, const char **capa, |
113 | cfgflags |= MU_PARSE_CONFIG_VERBOSE; | 113 | cfgflags |= MU_PARSE_CONFIG_VERBOSE; |
114 | if (mu_cfg_parser_verbose > 1) | 114 | if (mu_cfg_parser_verbose > 1) |
115 | cfgflags |= MU_PARSE_CONFIG_DUMP; | 115 | cfgflags |= MU_PARSE_CONFIG_DUMP; |
116 | rc = mu_parse_config_tree (mu_argp_tree, mu_program_name, cfg_param, | 116 | rc = mu_cfg_tree_reduce (mu_argp_tree, mu_program_name, cfg_param, |
117 | cfgflags); | 117 | cfgflags, data); |
118 | 118 | ||
119 | mu_gocs_flush (); | 119 | mu_gocs_flush (); |
120 | mu_cfg_destroy_tree (&mu_argp_tree); | 120 | mu_cfg_destroy_tree (&mu_argp_tree); | ... | ... |
... | @@ -50,12 +50,12 @@ cb_authorization (mu_debug_t err, void *data, char *arg) | ... | @@ -50,12 +50,12 @@ cb_authorization (mu_debug_t err, void *data, char *arg) |
50 | } | 50 | } |
51 | 51 | ||
52 | static struct mu_cfg_param mu_auth_param[] = { | 52 | static struct mu_cfg_param mu_auth_param[] = { |
53 | { "authentication", mu_cfg_callback, NULL, cb_authentication, | 53 | { "authentication", mu_cfg_callback, NULL, 0, cb_authentication, |
54 | N_("Set a list of modules for authentication. Modlist is a " | 54 | N_("Set a list of modules for authentication. Modlist is a " |
55 | "colon-separated list of module names or a word `clear' to " | 55 | "colon-separated list of module names or a word `clear' to " |
56 | "clear the previously set up values."), | 56 | "clear the previously set up values."), |
57 | N_("modlist") }, | 57 | N_("modlist") }, |
58 | { "authorization", mu_cfg_callback, NULL, cb_authorization, | 58 | { "authorization", mu_cfg_callback, NULL, 0, cb_authorization, |
59 | N_("Set a list of modules for authorization. Modlist is a " | 59 | N_("Set a list of modules for authorization. Modlist is a " |
60 | "colon-separated list of module names or a word `clear' to " | 60 | "colon-separated list of module names or a word `clear' to " |
61 | "clear the previously set up values."), | 61 | "clear the previously set up values."), |
... | @@ -66,7 +66,8 @@ static struct mu_cfg_param mu_auth_param[] = { | ... | @@ -66,7 +66,8 @@ static struct mu_cfg_param mu_auth_param[] = { |
66 | int | 66 | int |
67 | mu_auth_section_parser | 67 | mu_auth_section_parser |
68 | (enum mu_cfg_section_stage stage, const mu_cfg_node_t *node, | 68 | (enum mu_cfg_section_stage stage, const mu_cfg_node_t *node, |
69 | void *section_data, void *call_data, mu_cfg_tree_t *tree) | 69 | const char *section_label, void **section_data, void *call_data, |
70 | mu_cfg_tree_t *tree) | ||
70 | { | 71 | { |
71 | switch (stage) | 72 | switch (stage) |
72 | { | 73 | { | ... | ... |
... | @@ -40,10 +40,10 @@ static struct mu_gocs_debug debug_settings; | ... | @@ -40,10 +40,10 @@ static struct mu_gocs_debug debug_settings; |
40 | /* ************************************************************************* */ | 40 | /* ************************************************************************* */ |
41 | 41 | ||
42 | static struct mu_cfg_param mu_mailbox_param[] = { | 42 | static struct mu_cfg_param mu_mailbox_param[] = { |
43 | { "mail-spool", mu_cfg_string, &mailbox_settings.mail_spool, NULL, | 43 | { "mail-spool", mu_cfg_string, &mailbox_settings.mail_spool, 0, NULL, |
44 | N_("Use specified URL as a mailspool directory."), | 44 | N_("Use specified URL as a mailspool directory."), |
45 | N_("url") }, | 45 | N_("url") }, |
46 | { "mailbox-type", mu_cfg_string, &mailbox_settings.mailbox_type, NULL, | 46 | { "mailbox-type", mu_cfg_string, &mailbox_settings.mailbox_type, 0, NULL, |
47 | N_("Default mailbox type."), N_("protocol") }, | 47 | N_("Default mailbox type."), N_("protocol") }, |
48 | { NULL } | 48 | { NULL } |
49 | }; | 49 | }; |
... | @@ -57,16 +57,18 @@ DCL_CFG_CAPA (mailbox); | ... | @@ -57,16 +57,18 @@ DCL_CFG_CAPA (mailbox); |
57 | 57 | ||
58 | static struct mu_cfg_param mu_locking_param[] = { | 58 | static struct mu_cfg_param mu_locking_param[] = { |
59 | /* FIXME: Flags are superfluous. */ | 59 | /* FIXME: Flags are superfluous. */ |
60 | { "flags", mu_cfg_string, &locking_settings.lock_flags, NULL, | 60 | { "flags", mu_cfg_string, &locking_settings.lock_flags, 0, NULL, |
61 | N_("Default locker flags (E=external, R=retry, T=time, P=pid).") }, | 61 | N_("Default locker flags (E=external, R=retry, T=time, P=pid).") }, |
62 | { "retry-timeout", mu_cfg_ulong, &locking_settings.lock_retry_timeout, NULL, | 62 | { "retry-timeout", mu_cfg_ulong, &locking_settings.lock_retry_timeout, |
63 | 0, NULL, | ||
63 | N_("Set timeout for acquiring the lock.") }, | 64 | N_("Set timeout for acquiring the lock.") }, |
64 | { "retry-count", mu_cfg_ulong, &locking_settings.lock_retry_count, NULL, | 65 | { "retry-count", mu_cfg_ulong, &locking_settings.lock_retry_count, 0, NULL, |
65 | N_("Set the maximum number of times to retry acquiring the lock.") }, | 66 | N_("Set the maximum number of times to retry acquiring the lock.") }, |
66 | { "expire-timeout", mu_cfg_ulong, &locking_settings.lock_expire_timeout, | 67 | { "expire-timeout", mu_cfg_ulong, &locking_settings.lock_expire_timeout, |
67 | NULL, | 68 | 0, NULL, |
68 | N_("Expire locks older than this amount of time.") }, | 69 | N_("Expire locks older than this amount of time.") }, |
69 | { "external-locker", mu_cfg_string, &locking_settings.external_locker, NULL, | 70 | { "external-locker", mu_cfg_string, &locking_settings.external_locker, |
71 | 0, NULL, | ||
70 | N_("Use external locker program."), | 72 | N_("Use external locker program."), |
71 | N_("prog") }, | 73 | N_("prog") }, |
72 | { NULL, } | 74 | { NULL, } |
... | @@ -80,11 +82,11 @@ DCL_CFG_CAPA (locking); | ... | @@ -80,11 +82,11 @@ DCL_CFG_CAPA (locking); |
80 | /* ************************************************************************* */ | 82 | /* ************************************************************************* */ |
81 | 83 | ||
82 | static struct mu_cfg_param mu_address_param[] = { | 84 | static struct mu_cfg_param mu_address_param[] = { |
83 | { "email-addr", mu_cfg_string, &address_settings.address, NULL, | 85 | { "email-addr", mu_cfg_string, &address_settings.address, 0, NULL, |
84 | N_("Set the current user email address (default is " | 86 | N_("Set the current user email address (default is " |
85 | "loginname@defaultdomain)."), | 87 | "loginname@defaultdomain)."), |
86 | N_("email") }, | 88 | N_("email") }, |
87 | { "email-domain", mu_cfg_string, &address_settings.domain, NULL, | 89 | { "email-domain", mu_cfg_string, &address_settings.domain, 0, NULL, |
88 | N_("Set e-mail domain for unqualified user names (default is this host)"), | 90 | N_("Set e-mail domain for unqualified user names (default is this host)"), |
89 | N_("domain") }, | 91 | N_("domain") }, |
90 | { NULL } | 92 | { NULL } |
... | @@ -98,7 +100,7 @@ DCL_CFG_CAPA (address); | ... | @@ -98,7 +100,7 @@ DCL_CFG_CAPA (address); |
98 | /* ************************************************************************* */ | 100 | /* ************************************************************************* */ |
99 | 101 | ||
100 | static struct mu_cfg_param mu_mailer_param[] = { | 102 | static struct mu_cfg_param mu_mailer_param[] = { |
101 | { "url", mu_cfg_string, &mailer_settings.mailer, NULL, | 103 | { "url", mu_cfg_string, &mailer_settings.mailer, 0, NULL, |
102 | N_("Use this URL as the default mailer"), | 104 | N_("Use this URL as the default mailer"), |
103 | N_("url") }, | 105 | N_("url") }, |
104 | { NULL } | 106 | { NULL } |
... | @@ -125,7 +127,7 @@ cb_facility (mu_debug_t debug, void *data, char *arg) | ... | @@ -125,7 +127,7 @@ cb_facility (mu_debug_t debug, void *data, char *arg) |
125 | } | 127 | } |
126 | 128 | ||
127 | static struct mu_cfg_param mu_logging_param[] = { | 129 | static struct mu_cfg_param mu_logging_param[] = { |
128 | { "facility", mu_cfg_callback, NULL, cb_facility, | 130 | { "facility", mu_cfg_callback, NULL, 0, cb_facility, |
129 | N_("Set syslog facility. Arg is one of the following: user, daemon, " | 131 | N_("Set syslog facility. Arg is one of the following: user, daemon, " |
130 | "auth, authpriv, mail, cron, local0 through local7 (case-insensitive), " | 132 | "auth, authpriv, mail, cron, local0 through local7 (case-insensitive), " |
131 | "or a facility number.") }, | 133 | "or a facility number.") }, |
... | @@ -156,19 +158,19 @@ _cb_daemon_mode (mu_debug_t debug, void *data, char *arg) | ... | @@ -156,19 +158,19 @@ _cb_daemon_mode (mu_debug_t debug, void *data, char *arg) |
156 | } | 158 | } |
157 | 159 | ||
158 | static struct mu_cfg_param mu_daemon_param[] = { | 160 | static struct mu_cfg_param mu_daemon_param[] = { |
159 | { "max-children", mu_cfg_ulong, &daemon_settings.maxchildren, NULL, | 161 | { "max-children", mu_cfg_ulong, &daemon_settings.maxchildren, 0, NULL, |
160 | N_("Maximum number of children processes to run simultaneously.") }, | 162 | N_("Maximum number of children processes to run simultaneously.") }, |
161 | { "mode", mu_cfg_callback, NULL, _cb_daemon_mode, | 163 | { "mode", mu_cfg_callback, NULL, 0, _cb_daemon_mode, |
162 | N_("Set daemon mode (either inetd (or interactive) or daemon)."), | 164 | N_("Set daemon mode (either inetd (or interactive) or daemon)."), |
163 | N_("mode") }, | 165 | N_("mode") }, |
164 | { "transcript", mu_cfg_bool, &daemon_settings.transcript, NULL, | 166 | { "transcript", mu_cfg_bool, &daemon_settings.transcript, 0, NULL, |
165 | N_("Log the session transcript.") }, | 167 | N_("Log the session transcript.") }, |
166 | { "pidfile", mu_cfg_string, &daemon_settings.pidfile, NULL, | 168 | { "pidfile", mu_cfg_string, &daemon_settings.pidfile, 0, NULL, |
167 | N_("Store PID of the master process in this file."), | 169 | N_("Store PID of the master process in this file."), |
168 | N_("file") }, | 170 | N_("file") }, |
169 | { "port", mu_cfg_ushort, &daemon_settings.port, NULL, | 171 | { "port", mu_cfg_ushort, &daemon_settings.port, 0, NULL, |
170 | N_("Listen on the specified port number.") }, | 172 | N_("Listen on the specified port number.") }, |
171 | { "timeout", mu_cfg_ulong, &daemon_settings.timeout, NULL, | 173 | { "timeout", mu_cfg_ulong, &daemon_settings.timeout, 0, NULL, |
172 | N_("Set idle timeout.") }, | 174 | N_("Set idle timeout.") }, |
173 | { NULL } | 175 | { NULL } |
174 | }; | 176 | }; |
... | @@ -176,7 +178,8 @@ static struct mu_cfg_param mu_daemon_param[] = { | ... | @@ -176,7 +178,8 @@ static struct mu_cfg_param mu_daemon_param[] = { |
176 | int | 178 | int |
177 | mu_daemon_section_parser | 179 | mu_daemon_section_parser |
178 | (enum mu_cfg_section_stage stage, const mu_cfg_node_t *node, | 180 | (enum mu_cfg_section_stage stage, const mu_cfg_node_t *node, |
179 | void *section_data, void *call_data, mu_cfg_tree_t *tree) | 181 | const char *section_label, void **section_data, |
182 | void *call_data, mu_cfg_tree_t *tree) | ||
180 | { | 183 | { |
181 | switch (stage) | 184 | switch (stage) |
182 | { | 185 | { |
... | @@ -209,7 +212,9 @@ cb_debug_level (mu_debug_t debug, void *data, char *arg) | ... | @@ -209,7 +212,9 @@ cb_debug_level (mu_debug_t debug, void *data, char *arg) |
209 | char *pfx; | 212 | char *pfx; |
210 | struct mu_debug_locus locus; | 213 | struct mu_debug_locus locus; |
211 | 214 | ||
212 | debug_settings.string = arg; | 215 | if (debug_settings.string) |
216 | free (debug_settings.string); | ||
217 | debug_settings.string = strdup (arg); | ||
213 | if (mu_debug_get_locus (debug, &locus) == 0) | 218 | if (mu_debug_get_locus (debug, &locus) == 0) |
214 | { | 219 | { |
215 | p = umaxtostr (locus.line, buf); | 220 | p = umaxtostr (locus.line, buf); |
... | @@ -232,11 +237,11 @@ cb_debug_level (mu_debug_t debug, void *data, char *arg) | ... | @@ -232,11 +237,11 @@ cb_debug_level (mu_debug_t debug, void *data, char *arg) |
232 | } | 237 | } |
233 | 238 | ||
234 | static struct mu_cfg_param mu_debug_param[] = { | 239 | static struct mu_cfg_param mu_debug_param[] = { |
235 | { "level", mu_cfg_callback, NULL, &cb_debug_level, | 240 | { "level", mu_cfg_callback, NULL, 0, &cb_debug_level, |
236 | N_("Set Mailutils debugging level. Argument is a colon-separated list " | 241 | N_("Set Mailutils debugging level. Argument is a colon-separated list " |
237 | "of debugging specifications in the form:\n" | 242 | "of debugging specifications in the form:\n" |
238 | " <object: string>[[:]=<level: number>].") }, | 243 | " <object: string>[[:]=<level: number>].") }, |
239 | { "line-info", mu_cfg_bool, &debug_settings.line_info, NULL, | 244 | { "line-info", mu_cfg_bool, &debug_settings.line_info, 0, NULL, |
240 | N_("Prefix debug messages with Mailutils source locations.") }, | 245 | N_("Prefix debug messages with Mailutils source locations.") }, |
241 | { NULL } | 246 | { NULL } |
242 | }; | 247 | }; | ... | ... |
... | @@ -25,7 +25,7 @@ | ... | @@ -25,7 +25,7 @@ |
25 | static struct mu_gsasl_module_data gsasl_settings; | 25 | static struct mu_gsasl_module_data gsasl_settings; |
26 | 26 | ||
27 | static struct mu_cfg_param mu_gsasl_param[] = { | 27 | static struct mu_cfg_param mu_gsasl_param[] = { |
28 | { "cram-passwd", mu_cfg_string, &gsasl_settings.cram_md5_pwd, NULL, | 28 | { "cram-passwd", mu_cfg_string, &gsasl_settings.cram_md5_pwd, 0, NULL, |
29 | N_("Name of GSASL password file."), | 29 | N_("Name of GSASL password file."), |
30 | N_("file") }, | 30 | N_("file") }, |
31 | { NULL } | 31 | { NULL } | ... | ... |
... | @@ -78,14 +78,14 @@ mu_libcfg_init (char **cnames) | ... | @@ -78,14 +78,14 @@ mu_libcfg_init (char **cnames) |
78 | mu_error (_("Requested unknown configuration group `%s'"), | 78 | mu_error (_("Requested unknown configuration group `%s'"), |
79 | cnames[i]); | 79 | cnames[i]); |
80 | else | 80 | else |
81 | mu_config_register_section (NULL, cp->name, cp->parser, NULL, | 81 | mu_config_register_section (NULL, cp->name, NULL, |
82 | cp->cfgparam); | 82 | cp->parser, cp->cfgparam); |
83 | } | 83 | } |
84 | } | 84 | } |
85 | } | 85 | } |
86 | 86 | ||
87 | int | 87 | int |
88 | mu_parse_config_files (struct mu_cfg_param *param) | 88 | mu_parse_config_files (struct mu_cfg_param *param, void *target) |
89 | { | 89 | { |
90 | int flags = 0; | 90 | int flags = 0; |
91 | 91 | ||
... | @@ -96,7 +96,7 @@ mu_parse_config_files (struct mu_cfg_param *param) | ... | @@ -96,7 +96,7 @@ mu_parse_config_files (struct mu_cfg_param *param) |
96 | 96 | ||
97 | if (mu_load_site_rcfile) | 97 | if (mu_load_site_rcfile) |
98 | mu_parse_config (MU_CONFIG_FILE, mu_program_name, param, | 98 | mu_parse_config (MU_CONFIG_FILE, mu_program_name, param, |
99 | flags | MU_PARSE_CONFIG_GLOBAL); | 99 | flags | MU_PARSE_CONFIG_GLOBAL, target); |
100 | 100 | ||
101 | if (mu_load_user_rcfile && mu_program_name) | 101 | if (mu_load_user_rcfile && mu_program_name) |
102 | { | 102 | { |
... | @@ -107,14 +107,14 @@ mu_parse_config_files (struct mu_cfg_param *param) | ... | @@ -107,14 +107,14 @@ mu_parse_config_files (struct mu_cfg_param *param) |
107 | strcpy (file_name, "~/."); | 107 | strcpy (file_name, "~/."); |
108 | strcat (file_name, mu_program_name); | 108 | strcat (file_name, mu_program_name); |
109 | 109 | ||
110 | mu_parse_config (file_name, mu_program_name, param, flags); | 110 | mu_parse_config (file_name, mu_program_name, param, flags, target); |
111 | 111 | ||
112 | free (file_name); | 112 | free (file_name); |
113 | } | 113 | } |
114 | } | 114 | } |
115 | 115 | ||
116 | if (mu_load_rcfile) | 116 | if (mu_load_rcfile) |
117 | mu_parse_config (mu_load_rcfile, mu_program_name, param, flags); | 117 | mu_parse_config (mu_load_rcfile, mu_program_name, param, flags, target); |
118 | 118 | ||
119 | return 0; | 119 | return 0; |
120 | } | 120 | } | ... | ... |
... | @@ -37,24 +37,24 @@ cb_field_map (mu_debug_t debug, void *data, char *arg) | ... | @@ -37,24 +37,24 @@ cb_field_map (mu_debug_t debug, void *data, char *arg) |
37 | } | 37 | } |
38 | 38 | ||
39 | static struct mu_cfg_param mu_ldap_param[] = { | 39 | static struct mu_cfg_param mu_ldap_param[] = { |
40 | { "enable", mu_cfg_bool, &ldap_settings.enable, NULL, | 40 | { "enable", mu_cfg_bool, &ldap_settings.enable, 0, NULL, |
41 | N_("Enable LDAP lookups.") }, | 41 | N_("Enable LDAP lookups.") }, |
42 | { "url", mu_cfg_string, &ldap_settings.url, NULL, | 42 | { "url", mu_cfg_string, &ldap_settings.url, 0, NULL, |
43 | N_("Set URL of the LDAP server."), | 43 | N_("Set URL of the LDAP server."), |
44 | N_("url") }, | 44 | N_("url") }, |
45 | { "base", mu_cfg_string, &ldap_settings.base, NULL, | 45 | { "base", mu_cfg_string, &ldap_settings.base, 0, NULL, |
46 | N_("Base DN for LDAP lookups."), | 46 | N_("Base DN for LDAP lookups."), |
47 | N_("dn") }, | 47 | N_("dn") }, |
48 | { "binddn", mu_cfg_string, &ldap_settings.binddn, NULL, | 48 | { "binddn", mu_cfg_string, &ldap_settings.binddn, 0, NULL, |
49 | N_("DN for accessing LDAP database."), | 49 | N_("DN for accessing LDAP database."), |
50 | N_("dn") }, | 50 | N_("dn") }, |
51 | { "passwd", mu_cfg_string, &ldap_settings.passwd, NULL, | 51 | { "passwd", mu_cfg_string, &ldap_settings.passwd, 0, NULL, |
52 | N_("Password for use with binddn.") }, | 52 | N_("Password for use with binddn.") }, |
53 | { "tls", mu_cfg_bool, &ldap_settings.tls, NULL, | 53 | { "tls", mu_cfg_bool, &ldap_settings.tls, 0, NULL, |
54 | N_("Use TLS encryption.") }, | 54 | N_("Use TLS encryption.") }, |
55 | { "debug", mu_cfg_int, &ldap_settings.debug, NULL, | 55 | { "debug", mu_cfg_int, &ldap_settings.debug, 0, NULL, |
56 | N_("Set LDAP debugging level.") }, | 56 | N_("Set LDAP debugging level.") }, |
57 | { "field-map", mu_cfg_callback, NULL, cb_field_map, | 57 | { "field-map", mu_cfg_callback, NULL, 0, cb_field_map, |
58 | N_("Set a field-map for parsing LDAP replies. The map is a " | 58 | N_("Set a field-map for parsing LDAP replies. The map is a " |
59 | "column-separated list of definitions. Each definition has the " | 59 | "column-separated list of definitions. Each definition has the " |
60 | "following form:\n" | 60 | "following form:\n" |
... | @@ -63,10 +63,10 @@ static struct mu_cfg_param mu_ldap_param[] = { | ... | @@ -63,10 +63,10 @@ static struct mu_cfg_param mu_ldap_param[] = { |
63 | "gecos, dir, shell, mailbox, quota, and <attr> is the name of " | 63 | "gecos, dir, shell, mailbox, quota, and <attr> is the name of " |
64 | "the correspondind LDAP attribute."), | 64 | "the correspondind LDAP attribute."), |
65 | N_("map") }, | 65 | N_("map") }, |
66 | { "getpwnam", mu_cfg_string, &ldap_settings.getpwnam_filter, NULL, | 66 | { "getpwnam", mu_cfg_string, &ldap_settings.getpwnam_filter, 0, NULL, |
67 | N_("LDAP filter to use for getpwnam requests."), | 67 | N_("LDAP filter to use for getpwnam requests."), |
68 | N_("filter") }, | 68 | N_("filter") }, |
69 | { "getpwuid", mu_cfg_string, &ldap_settings.getpwuid_filter, NULL, | 69 | { "getpwuid", mu_cfg_string, &ldap_settings.getpwuid_filter, 0, NULL, |
70 | N_("LDAP filter to use for getpwuid requests."), | 70 | N_("LDAP filter to use for getpwuid requests."), |
71 | N_("filter") }, | 71 | N_("filter") }, |
72 | { NULL } | 72 | { NULL } |
... | @@ -75,7 +75,8 @@ static struct mu_cfg_param mu_ldap_param[] = { | ... | @@ -75,7 +75,8 @@ static struct mu_cfg_param mu_ldap_param[] = { |
75 | int | 75 | int |
76 | mu_ldap_section_parser | 76 | mu_ldap_section_parser |
77 | (enum mu_cfg_section_stage stage, const mu_cfg_node_t *node, | 77 | (enum mu_cfg_section_stage stage, const mu_cfg_node_t *node, |
78 | void *section_data, void *call_data, mu_cfg_tree_t *tree) | 78 | const char *section_label, void **section_data, |
79 | void *call_data, mu_cfg_tree_t *tree) | ||
79 | { | 80 | { |
80 | switch (stage) | 81 | switch (stage) |
81 | { | 82 | { | ... | ... |
... | @@ -24,7 +24,7 @@ | ... | @@ -24,7 +24,7 @@ |
24 | static char *pam_settings; | 24 | static char *pam_settings; |
25 | 25 | ||
26 | static struct mu_cfg_param mu_pam_param[] = { | 26 | static struct mu_cfg_param mu_pam_param[] = { |
27 | { "service", mu_cfg_string, &pam_settings, NULL, | 27 | { "service", mu_cfg_string, &pam_settings, 0, NULL, |
28 | N_("Set PAM service name."), | 28 | N_("Set PAM service name."), |
29 | N_("name") }, | 29 | N_("name") }, |
30 | { NULL } | 30 | { NULL } | ... | ... |
... | @@ -25,16 +25,16 @@ | ... | @@ -25,16 +25,16 @@ |
25 | static struct mu_radius_module_data radius_settings; | 25 | static struct mu_radius_module_data radius_settings; |
26 | 26 | ||
27 | static struct mu_cfg_param mu_radius_param[] = { | 27 | static struct mu_cfg_param mu_radius_param[] = { |
28 | { "auth", mu_cfg_string, &radius_settings.auth_request, NULL, | 28 | { "auth", mu_cfg_string, &radius_settings.auth_request, 0, NULL, |
29 | N_("Radius request for authorization."), | 29 | N_("Radius request for authorization."), |
30 | N_("request") }, | 30 | N_("request") }, |
31 | { "getpwnam", mu_cfg_string, &radius_settings.getpwnam_request, NULL, | 31 | { "getpwnam", mu_cfg_string, &radius_settings.getpwnam_request, 0, NULL, |
32 | N_("Radius request for getpwnam."), | 32 | N_("Radius request for getpwnam."), |
33 | N_("request") }, | 33 | N_("request") }, |
34 | { "getpwuid", mu_cfg_string, &radius_settings.getpwuid_request, NULL, | 34 | { "getpwuid", mu_cfg_string, &radius_settings.getpwuid_request, 0, NULL, |
35 | N_("Radius request for getpwuid."), | 35 | N_("Radius request for getpwuid."), |
36 | N_("request") }, | 36 | N_("request") }, |
37 | { "directory", mu_cfg_string, &radius_settings.config_dir, NULL, | 37 | { "directory", mu_cfg_string, &radius_settings.config_dir, 0, NULL, |
38 | N_("Set radius configuration directory.") }, | 38 | N_("Set radius configuration directory.") }, |
39 | { NULL } | 39 | { NULL } |
40 | }; | 40 | }; | ... | ... |
... | @@ -92,15 +92,15 @@ cb_library_path (mu_debug_t debug, void *data, char *arg) | ... | @@ -92,15 +92,15 @@ cb_library_path (mu_debug_t debug, void *data, char *arg) |
92 | } | 92 | } |
93 | 93 | ||
94 | static struct mu_cfg_param mu_sieve_param[] = { | 94 | static struct mu_cfg_param mu_sieve_param[] = { |
95 | { "clear-library-path", mu_cfg_callback, NULL, cb_clear_library_path, | 95 | { "clear-library-path", mu_cfg_callback, NULL, 0, cb_clear_library_path, |
96 | N_("Clear library search path.") }, | 96 | N_("Clear library search path.") }, |
97 | { "clear-include-path", mu_cfg_callback, NULL, cb_clear_include_path, | 97 | { "clear-include-path", mu_cfg_callback, NULL, 0, cb_clear_include_path, |
98 | N_("Clear include search path.") }, | 98 | N_("Clear include search path.") }, |
99 | { "library-path", mu_cfg_callback, NULL, cb_library_path, | 99 | { "library-path", mu_cfg_callback, NULL, 0, cb_library_path, |
100 | N_("Add directories to the library search path. Argument is a " | 100 | N_("Add directories to the library search path. Argument is a " |
101 | "comma-separated list of directories."), | 101 | "comma-separated list of directories."), |
102 | N_("list") }, | 102 | N_("list") }, |
103 | { "include-path", mu_cfg_callback, NULL, cb_include_path, | 103 | { "include-path", mu_cfg_callback, NULL, 0, cb_include_path, |
104 | N_("Add directories to the include search path. Argument is a " | 104 | N_("Add directories to the include search path. Argument is a " |
105 | "comma-separated list of directories."), | 105 | "comma-separated list of directories."), |
106 | N_("list") }, | 106 | N_("list") }, | ... | ... |
... | @@ -50,31 +50,31 @@ cb_field_map (mu_debug_t debug, void *data, char *arg) | ... | @@ -50,31 +50,31 @@ cb_field_map (mu_debug_t debug, void *data, char *arg) |
50 | } | 50 | } |
51 | 51 | ||
52 | static struct mu_cfg_param mu_sql_param[] = { | 52 | static struct mu_cfg_param mu_sql_param[] = { |
53 | { "interface", mu_cfg_string, &sql_settings.interface, NULL, | 53 | { "interface", mu_cfg_string, &sql_settings.interface, 0, NULL, |
54 | N_("Set SQL interface to use (one of: mysql, odbc, or postgres).") }, | 54 | N_("Set SQL interface to use (one of: mysql, odbc, or postgres).") }, |
55 | { "getwpnam", mu_cfg_string, &sql_settings.getpwnam_query, NULL, | 55 | { "getwpnam", mu_cfg_string, &sql_settings.getpwnam_query, 0, NULL, |
56 | N_("SQL query to use for getpwnam requests."), | 56 | N_("SQL query to use for getpwnam requests."), |
57 | N_("query") }, | 57 | N_("query") }, |
58 | { "getpwuid", mu_cfg_string, &sql_settings.getpwuid_query, NULL, | 58 | { "getpwuid", mu_cfg_string, &sql_settings.getpwuid_query, 0, NULL, |
59 | N_("SQL query to use for getpwuid requests."), | 59 | N_("SQL query to use for getpwuid requests."), |
60 | N_("query") }, | 60 | N_("query") }, |
61 | { "getpass", mu_cfg_string, &sql_settings.getpass_query, NULL, | 61 | { "getpass", mu_cfg_string, &sql_settings.getpass_query, 0, NULL, |
62 | N_("SQL query returning the user's password."), | 62 | N_("SQL query returning the user's password."), |
63 | N_("query") }, | 63 | N_("query") }, |
64 | { "host", mu_cfg_string, &sql_settings.host, NULL, | 64 | { "host", mu_cfg_string, &sql_settings.host, 0, NULL, |
65 | N_("SQL server host name.") }, | 65 | N_("SQL server host name.") }, |
66 | { "user", mu_cfg_string, &sql_settings.user, NULL, | 66 | { "user", mu_cfg_string, &sql_settings.user, 0, NULL, |
67 | N_("SQL user name.") }, | 67 | N_("SQL user name.") }, |
68 | { "passwd", mu_cfg_string, &sql_settings.passwd, NULL, | 68 | { "passwd", mu_cfg_string, &sql_settings.passwd, 0, NULL, |
69 | N_("Password for the SQL user.") }, | 69 | N_("Password for the SQL user.") }, |
70 | { "port", mu_cfg_int, &sql_settings.port, NULL, | 70 | { "port", mu_cfg_int, &sql_settings.port, 0, NULL, |
71 | N_("SQL server port.") }, | 71 | N_("SQL server port.") }, |
72 | { "db", mu_cfg_string, &sql_settings.db, NULL, | 72 | { "db", mu_cfg_string, &sql_settings.db, 0, NULL, |
73 | N_("Database name.") }, | 73 | N_("Database name.") }, |
74 | { "password-type", mu_cfg_callback, NULL, cb_password_type, | 74 | { "password-type", mu_cfg_callback, NULL, 0, cb_password_type, |
75 | N_("Type of password returned by getpass query (one of: plain, hash, " | 75 | N_("Type of password returned by getpass query (one of: plain, hash, " |
76 | "scrambled).") }, | 76 | "scrambled).") }, |
77 | { "field-map", mu_cfg_callback, NULL, cb_field_map, | 77 | { "field-map", mu_cfg_callback, NULL, 0, cb_field_map, |
78 | N_("Set a field-map for parsing SQL replies. The map is a " | 78 | N_("Set a field-map for parsing SQL replies. The map is a " |
79 | "column-separated list of definitions. Each definition has the " | 79 | "column-separated list of definitions. Each definition has the " |
80 | "following form:\n" | 80 | "following form:\n" | ... | ... |
... | @@ -25,15 +25,15 @@ | ... | @@ -25,15 +25,15 @@ |
25 | static struct mu_tls_module_config tls_settings; | 25 | static struct mu_tls_module_config tls_settings; |
26 | 26 | ||
27 | static struct mu_cfg_param mu_tls_param[] = { | 27 | static struct mu_cfg_param mu_tls_param[] = { |
28 | { "tls", mu_cfg_bool, &tls_settings.client_enable, NULL, | 28 | { "tls", mu_cfg_bool, &tls_settings.client_enable, 0, NULL, |
29 | N_("Enable client TLS encryption.") }, | 29 | N_("Enable client TLS encryption.") }, |
30 | { "ssl-cert", mu_cfg_string, &tls_settings.ssl_cert, NULL, | 30 | { "ssl-cert", mu_cfg_string, &tls_settings.ssl_cert, 0, NULL, |
31 | N_("Specify SSL certificate file."), | 31 | N_("Specify SSL certificate file."), |
32 | N_("file") }, | 32 | N_("file") }, |
33 | { "ssl-key", mu_cfg_string, &tls_settings.ssl_key, NULL, | 33 | { "ssl-key", mu_cfg_string, &tls_settings.ssl_key, 0, NULL, |
34 | N_("Specify SSL certificate key file."), | 34 | N_("Specify SSL certificate key file."), |
35 | N_("file") }, | 35 | N_("file") }, |
36 | { "ssl-cafile", mu_cfg_string, &tls_settings.ssl_cafile, NULL, | 36 | { "ssl-cafile", mu_cfg_string, &tls_settings.ssl_cafile, 0, NULL, |
37 | N_("Specify trusted CAs file."), | 37 | N_("Specify trusted CAs file."), |
38 | N_("file") }, | 38 | N_("file") }, |
39 | { NULL } | 39 | { NULL } | ... | ... |
... | @@ -24,7 +24,7 @@ | ... | @@ -24,7 +24,7 @@ |
24 | static struct mu_gocs_virtual virtdomain_settings; | 24 | static struct mu_gocs_virtual virtdomain_settings; |
25 | 25 | ||
26 | static struct mu_cfg_param mu_virtdomain_param[] = { | 26 | static struct mu_cfg_param mu_virtdomain_param[] = { |
27 | { "passwd-dir", mu_cfg_string, &virtdomain_settings, NULL, | 27 | { "passwd-dir", mu_cfg_string, &virtdomain_settings, 0, NULL, |
28 | N_("Name of the directory where virtual domain password files are " | 28 | N_("Name of the directory where virtual domain password files are " |
29 | "located."), | 29 | "located."), |
30 | N_("dir") }, | 30 | N_("dir") }, | ... | ... |
... | @@ -238,57 +238,57 @@ cb_debug (mu_debug_t debug, void *data, char *arg) | ... | @@ -238,57 +238,57 @@ cb_debug (mu_debug_t debug, void *data, char *arg) |
238 | } | 238 | } |
239 | 239 | ||
240 | struct mu_cfg_param maidag_cfg_param[] = { | 240 | struct mu_cfg_param maidag_cfg_param[] = { |
241 | { "exit-multiple-delivery-success", mu_cfg_bool, &multiple_delivery, NULL, | 241 | { "exit-multiple-delivery-success", mu_cfg_bool, &multiple_delivery, 0, NULL, |
242 | N_("In case of multiple delivery, exit with code 0 if at least one " | 242 | N_("In case of multiple delivery, exit with code 0 if at least one " |
243 | "delivery succeeded.") }, | 243 | "delivery succeeded.") }, |
244 | { "exit-quota-tempfail", mu_cfg_bool, &ex_quota_tempfail, NULL, | 244 | { "exit-quota-tempfail", mu_cfg_bool, &ex_quota_tempfail, 0, NULL, |
245 | N_("Indicate temporary failure if the recipient is over his mail quota.") | 245 | N_("Indicate temporary failure if the recipient is over his mail quota.") |
246 | }, | 246 | }, |
247 | #ifdef USE_DBM | 247 | #ifdef USE_DBM |
248 | { "quota-db", mu_cfg_string, "adbname, NULL, | 248 | { "quota-db", mu_cfg_string, "adbname, 0, NULL, |
249 | N_("Name of DBM quota database file."), | 249 | N_("Name of DBM quota database file."), |
250 | N_("file") }, | 250 | N_("file") }, |
251 | #endif | 251 | #endif |
252 | #ifdef USE_SQL | 252 | #ifdef USE_SQL |
253 | { "quota-query", mu_cfg_string, "a_query, NULL, | 253 | { "quota-query", mu_cfg_string, "a_query, 0, NULL, |
254 | N_("SQL query to retrieve mailbox quota. This is deprecated, use " | 254 | N_("SQL query to retrieve mailbox quota. This is deprecated, use " |
255 | "sql { ... } instead."), | 255 | "sql { ... } instead."), |
256 | N_("query") }, | 256 | N_("query") }, |
257 | #endif | 257 | #endif |
258 | { "sieve-filter", mu_cfg_string, &sieve_pattern, NULL, | 258 | { "sieve-filter", mu_cfg_string, &sieve_pattern, 0, NULL, |
259 | N_("File name or name pattern for Sieve filter file."), | 259 | N_("File name or name pattern for Sieve filter file."), |
260 | N_("file-or-pattern") }, | 260 | N_("file-or-pattern") }, |
261 | { "message-id-header", mu_cfg_string, &message_id_header, NULL, | 261 | { "message-id-header", mu_cfg_string, &message_id_header, 0, NULL, |
262 | N_("When logging Sieve actions, identify messages by the value of " | 262 | N_("When logging Sieve actions, identify messages by the value of " |
263 | "this header."), | 263 | "this header."), |
264 | N_("name") }, | 264 | N_("name") }, |
265 | #ifdef WITH_GUILE | 265 | #ifdef WITH_GUILE |
266 | { "guile-filter", mu_cfg_string, &progfile_pattern, NULL, | 266 | { "guile-filter", mu_cfg_string, &progfile_pattern, 0, NULL, |
267 | N_("File name or name pattern for Guile filter file."), | 267 | N_("File name or name pattern for Guile filter file."), |
268 | N_("file-or-pattern") }, | 268 | N_("file-or-pattern") }, |
269 | #endif | 269 | #endif |
270 | { "debug", mu_cfg_callback, NULL, cb_debug, | 270 | { "debug", mu_cfg_callback, NULL, 0, cb_debug, |
271 | N_("Set maidag debug level. Debug level consists of one or more " | 271 | N_("Set maidag debug level. Debug level consists of one or more " |
272 | "of the following letters:\n" | 272 | "of the following letters:\n" |
273 | " g - guimb stack traces\n" | 273 | " g - guimb stack traces\n" |
274 | " t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n" | 274 | " t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n" |
275 | " i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n" | 275 | " i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n" |
276 | " l - sieve action logs\n") }, | 276 | " l - sieve action logs\n") }, |
277 | { "stderr", mu_cfg_bool, &log_to_stderr, NULL, | 277 | { "stderr", mu_cfg_bool, &log_to_stderr, 0, NULL, |
278 | N_("Log to stderr instead of syslog.") }, | 278 | N_("Log to stderr instead of syslog.") }, |
279 | /* LMTP support */ | 279 | /* LMTP support */ |
280 | { "lmtp", mu_cfg_bool, &lmtp_mode, NULL, | 280 | { "lmtp", mu_cfg_bool, &lmtp_mode, 0, NULL, |
281 | N_("Run in LMTP mode.") }, | 281 | N_("Run in LMTP mode.") }, |
282 | { "group", mu_cfg_string, &lmtp_group, NULL, | 282 | { "group", mu_cfg_string, &lmtp_group, 0, NULL, |
283 | N_("In LMTP mode, change to this group after startup.") }, | 283 | N_("In LMTP mode, change to this group after startup.") }, |
284 | { "listen", mu_cfg_string, &lmtp_url_string, NULL, | 284 | { "listen", mu_cfg_string, &lmtp_url_string, 0, NULL, |
285 | N_("In LMTP mode, listen on the given URL. Valid URLs are:\n" | 285 | N_("In LMTP mode, listen on the given URL. Valid URLs are:\n" |
286 | " tcp://<address: string>:<port: number> (note that port is " | 286 | " tcp://<address: string>:<port: number> (note that port is " |
287 | "mandatory)\n" | 287 | "mandatory)\n" |
288 | " file://<socket-file-name>\n" | 288 | " file://<socket-file-name>\n" |
289 | "or socket://<socket-file-name>"), | 289 | "or socket://<socket-file-name>"), |
290 | N_("url") }, | 290 | N_("url") }, |
291 | { "reuse-address", mu_cfg_bool, &reuse_lmtp_address, NULL, | 291 | { "reuse-address", mu_cfg_bool, &reuse_lmtp_address, 0, NULL, |
292 | N_("Reuse existing address (LMTP mode). Default is \"yes\".") }, | 292 | N_("Reuse existing address (LMTP mode). Default is \"yes\".") }, |
293 | TCP_WRAPPERS_CONFIG | 293 | TCP_WRAPPERS_CONFIG |
294 | { NULL } | 294 | { NULL } | ... | ... |
... | @@ -255,36 +255,36 @@ cb_debug (mu_debug_t debug, void *data, char *arg) | ... | @@ -255,36 +255,36 @@ cb_debug (mu_debug_t debug, void *data, char *arg) |
255 | } | 255 | } |
256 | 256 | ||
257 | struct mu_cfg_param mail_local_cfg_param[] = { | 257 | struct mu_cfg_param mail_local_cfg_param[] = { |
258 | { "ex-multiple-delivery-success", mu_cfg_bool, &multiple_delivery, NULL, | 258 | { "ex-multiple-delivery-success", mu_cfg_bool, &multiple_delivery, 0, NULL, |
259 | N_("In case of multiple delivery, exit with code 0 if at least one " | 259 | N_("In case of multiple delivery, exit with code 0 if at least one " |
260 | "delivery succeeded.") }, | 260 | "delivery succeeded.") }, |
261 | { "ex-quota-tempfail", mu_cfg_bool, &ex_quota_tempfail, NULL, | 261 | { "ex-quota-tempfail", mu_cfg_bool, &ex_quota_tempfail, 0, NULL, |
262 | N_("Indicate temporary failure if the recipient is over his mail quota.") | 262 | N_("Indicate temporary failure if the recipient is over his mail quota.") |
263 | }, | 263 | }, |
264 | #ifdef USE_DBM | 264 | #ifdef USE_DBM |
265 | { "quota-db", mu_cfg_string, "adbname, NULL, | 265 | { "quota-db", mu_cfg_string, "adbname, 0, NULL, |
266 | N_("Name of DBM quota database file."), | 266 | N_("Name of DBM quota database file."), |
267 | N_("file") }, | 267 | N_("file") }, |
268 | #endif | 268 | #endif |
269 | #ifdef USE_SQL | 269 | #ifdef USE_SQL |
270 | { "quota-query", mu_cfg_string, "a_query, NULL, | 270 | { "quota-query", mu_cfg_string, "a_query, 0, NULL, |
271 | N_("SQL query to retrieve mailbox quota. This is deprecated, use " | 271 | N_("SQL query to retrieve mailbox quota. This is deprecated, use " |
272 | "sql { ... } instead."), | 272 | "sql { ... } instead."), |
273 | N_("query") }, | 273 | N_("query") }, |
274 | #endif | 274 | #endif |
275 | { "sieve-filter", mu_cfg_string, &sieve_pattern, NULL, | 275 | { "sieve-filter", mu_cfg_string, &sieve_pattern, 0, NULL, |
276 | N_("File name or name pattern for Sieve filter file."), | 276 | N_("File name or name pattern for Sieve filter file."), |
277 | N_("file-or-pattern") }, | 277 | N_("file-or-pattern") }, |
278 | { "message-id-header", mu_cfg_string, &message_id_header, NULL, | 278 | { "message-id-header", mu_cfg_string, &message_id_header, 0, NULL, |
279 | N_("When logging Sieve actions, identify messages by the value of " | 279 | N_("When logging Sieve actions, identify messages by the value of " |
280 | "this header."), | 280 | "this header."), |
281 | N_("name") }, | 281 | N_("name") }, |
282 | #ifdef WITH_GUILE | 282 | #ifdef WITH_GUILE |
283 | { "guile-filter", mu_cfg_string, &progfile_pattern, NULL, | 283 | { "guile-filter", mu_cfg_string, &progfile_pattern, 0, NULL, |
284 | N_("File name or name pattern for Guile filter file."), | 284 | N_("File name or name pattern for Guile filter file."), |
285 | N_("file-or-pattern") }, | 285 | N_("file-or-pattern") }, |
286 | #endif | 286 | #endif |
287 | { "debug", mu_cfg_callback, NULL, cb_debug, | 287 | { "debug", mu_cfg_callback, NULL, 0, cb_debug, |
288 | N_("Set mail.local debug level. Debug level consists of one or more " | 288 | N_("Set mail.local debug level. Debug level consists of one or more " |
289 | "of the following letters:\n" | 289 | "of the following letters:\n" |
290 | " g - guimb stack traces\n" | 290 | " g - guimb stack traces\n" | ... | ... |
... | @@ -136,12 +136,12 @@ static struct argp argp = { | ... | @@ -136,12 +136,12 @@ static struct argp argp = { |
136 | 136 | ||
137 | 137 | ||
138 | struct mu_cfg_param mail_remote_cfg_param[] = { | 138 | struct mu_cfg_param mail_remote_cfg_param[] = { |
139 | { "from", mu_cfg_string, &optfrom, NULL, | 139 | { "from", mu_cfg_string, &optfrom, 0, NULL, |
140 | N_("Set sender email address."), | 140 | N_("Set sender email address."), |
141 | N_("email") }, | 141 | N_("email") }, |
142 | { "read-recipients", mu_cfg_string, &read_recipients, NULL, | 142 | { "read-recipients", mu_cfg_string, &read_recipients, 0, NULL, |
143 | N_("Read recipient addresses from the message.") }, | 143 | N_("Read recipient addresses from the message.") }, |
144 | { "debug", mu_cfg_int, &optdebug, NULL, | 144 | { "debug", mu_cfg_int, &optdebug, 0, NULL, |
145 | N_("Set debug verbosity level. Level 1 prints envelope commands in " | 145 | N_("Set debug verbosity level. Level 1 prints envelope commands in " |
146 | "the SMTP protocol transaction. Levels 2 and above print the data " | 146 | "the SMTP protocol transaction. Levels 2 and above print the data " |
147 | "part of the transaction as well.") }, | 147 | "part of the transaction as well.") }, | ... | ... |
... | @@ -50,6 +50,7 @@ libmailutils_la_SOURCES = \ | ... | @@ -50,6 +50,7 @@ libmailutils_la_SOURCES = \ |
50 | dbgstderr.c\ | 50 | dbgstderr.c\ |
51 | dbgsyslog.c\ | 51 | dbgsyslog.c\ |
52 | debug.c\ | 52 | debug.c\ |
53 | cfg_driver.c\ | ||
53 | cfg_format.c\ | 54 | cfg_format.c\ |
54 | cfg_lexer.c\ | 55 | cfg_lexer.c\ |
55 | cfg_parser.c\ | 56 | cfg_parser.c\ | ... | ... |
mailbox/cfg_driver.c
0 → 100644
1 | /* cfg_driver.c -- Main driver for Mailutils configuration files | ||
2 | Copyright (C) 2007 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU General Public License as | ||
6 | published by the Free Software Foundation; either version 3, or (at | ||
7 | your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, but | ||
10 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | #ifdef HAVE_CONFIG_H | ||
18 | # include <config.h> | ||
19 | #endif | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <sys/types.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include <fcntl.h> | ||
25 | #include <errno.h> | ||
26 | #include <unistd.h> | ||
27 | #include <ctype.h> | ||
28 | #include <mailutils/argcv.h> | ||
29 | #include <mailutils/nls.h> | ||
30 | #include <mailutils/cfg.h> | ||
31 | #include <mailutils/errno.h> | ||
32 | #include <mailutils/error.h> | ||
33 | #include <mailutils/mutil.h> | ||
34 | #include <mailutils/monitor.h> | ||
35 | #include <mailutils/refcount.h> | ||
36 | #include <mailutils/list.h> | ||
37 | #include <mailutils/iterator.h> | ||
38 | #include <mailutils/stream.h> | ||
39 | #include <mailutils/assoc.h> | ||
40 | |||
41 | |||
42 | static mu_assoc_t section_tab; | ||
43 | |||
44 | static void | ||
45 | alloc_section_tab () | ||
46 | { | ||
47 | if (!section_tab) | ||
48 | mu_assoc_create (§ion_tab, sizeof (struct mu_cfg_cont *), | ||
49 | MU_ASSOC_COPY_KEY); | ||
50 | } | ||
51 | |||
52 | int | ||
53 | mu_create_canned_section (struct mu_cfg_section *section) | ||
54 | { | ||
55 | struct mu_cfg_cont *cont; | ||
56 | alloc_section_tab (); | ||
57 | mu_config_create_container (&cont, mu_cfg_cont_section); | ||
58 | cont->v.section = *section; | ||
59 | return mu_assoc_install (section_tab, cont->v.section.ident, &cont); | ||
60 | } | ||
61 | |||
62 | int | ||
63 | mu_create_canned_param (struct mu_cfg_param *param) | ||
64 | { | ||
65 | struct mu_cfg_cont *cont; | ||
66 | alloc_section_tab (); | ||
67 | mu_config_create_container (&cont, mu_cfg_cont_param); | ||
68 | cont->v.param = *param; | ||
69 | return mu_assoc_install (section_tab, cont->v.param.ident, &cont); | ||
70 | } | ||
71 | |||
72 | struct mu_cfg_cont * | ||
73 | mu_get_canned_container (const char *name) | ||
74 | { | ||
75 | struct mu_cfg_cont **pcont = mu_assoc_ref (section_tab, name); | ||
76 | return pcont ? *pcont : NULL; | ||
77 | } | ||
78 | |||
79 | |||
80 | static struct mu_cfg_cont *root_container; | ||
81 | |||
82 | int | ||
83 | mu_config_create_container (struct mu_cfg_cont **pcont, | ||
84 | enum mu_cfg_cont_type type) | ||
85 | { | ||
86 | struct mu_cfg_cont *cont; | ||
87 | int rc; | ||
88 | |||
89 | cont = calloc (1, sizeof (*cont)); | ||
90 | if (!cont) | ||
91 | return ENOMEM; | ||
92 | rc = mu_refcount_create (&cont->refcount); | ||
93 | if (rc) | ||
94 | free (cont); | ||
95 | else | ||
96 | { | ||
97 | cont->type = type; | ||
98 | *pcont = cont; | ||
99 | } | ||
100 | return rc; | ||
101 | } | ||
102 | |||
103 | |||
104 | struct dup_data | ||
105 | { | ||
106 | struct mu_cfg_cont *cont; | ||
107 | }; | ||
108 | |||
109 | static int dup_container (struct mu_cfg_cont **pcont); | ||
110 | |||
111 | static int | ||
112 | _dup_cont_action (void *item, void *cbdata) | ||
113 | { | ||
114 | int rc; | ||
115 | struct mu_cfg_cont *cont = item; | ||
116 | struct dup_data *pdd = cbdata; | ||
117 | |||
118 | rc = dup_container (&cont); | ||
119 | if (rc) | ||
120 | return rc; | ||
121 | |||
122 | if (!pdd->cont->v.section.children) | ||
123 | { | ||
124 | int rc = mu_list_create (&pdd->cont->v.section.children); | ||
125 | if (rc) | ||
126 | return rc; | ||
127 | } | ||
128 | return mu_list_append (pdd->cont->v.section.children, cont); | ||
129 | } | ||
130 | |||
131 | static int | ||
132 | dup_container (struct mu_cfg_cont **pcont) | ||
133 | { | ||
134 | int rc; | ||
135 | struct mu_cfg_cont *newcont, *oldcont = *pcont; | ||
136 | struct dup_data dd; | ||
137 | |||
138 | rc = mu_config_create_container (&newcont, oldcont->type); | ||
139 | if (rc) | ||
140 | return rc; | ||
141 | |||
142 | dd.cont = newcont; | ||
143 | switch (oldcont->type) | ||
144 | { | ||
145 | case mu_cfg_cont_section: | ||
146 | newcont->v.section.ident = oldcont->v.section.ident; | ||
147 | newcont->v.section.label = oldcont->v.section.label; | ||
148 | newcont->v.section.parser = oldcont->v.section.parser; | ||
149 | newcont->v.section.target = oldcont->v.section.target; | ||
150 | newcont->v.section.docstring = oldcont->v.section.docstring; | ||
151 | newcont->v.section.children = NULL; | ||
152 | mu_list_do (oldcont->v.section.children, _dup_cont_action, &dd); | ||
153 | break; | ||
154 | |||
155 | case mu_cfg_cont_param: | ||
156 | newcont->v.param = oldcont->v.param; | ||
157 | break; | ||
158 | } | ||
159 | *pcont = newcont; | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | |||
164 | static void | ||
165 | destroy_list (mu_list_t *plist) | ||
166 | { | ||
167 | mu_list_t list = *plist; | ||
168 | mu_iterator_t itr = NULL; | ||
169 | |||
170 | if (!list) | ||
171 | return; | ||
172 | |||
173 | mu_list_get_iterator (list, &itr); | ||
174 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); | ||
175 | mu_iterator_next (itr)) | ||
176 | { | ||
177 | struct mu_cfg_cont *cont, *p; | ||
178 | mu_iterator_current (itr, (void**)&cont); | ||
179 | p = cont; | ||
180 | mu_config_destroy_container (&p); | ||
181 | if (!p) | ||
182 | mu_list_remove (list, cont); | ||
183 | } | ||
184 | mu_iterator_destroy (&itr); | ||
185 | if (mu_list_is_empty (list)) | ||
186 | mu_list_destroy (plist); | ||
187 | } | ||
188 | |||
189 | void | ||
190 | mu_config_destroy_container (struct mu_cfg_cont **pcont) | ||
191 | { | ||
192 | struct mu_cfg_cont *cont = *pcont; | ||
193 | unsigned refcount = mu_refcount_dec (cont->refcount); | ||
194 | /* printf ("destr %p-%s: %d\n", cont, cont->v.section.ident, refcount); */ | ||
195 | switch (cont->type) | ||
196 | { | ||
197 | case mu_cfg_cont_section: | ||
198 | destroy_list (&cont->v.section.children); | ||
199 | break; | ||
200 | |||
201 | case mu_cfg_cont_param: | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | if (refcount == 0) | ||
206 | { | ||
207 | free (cont); | ||
208 | *pcont = 0; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | |||
213 | static int | ||
214 | add_parameters (struct mu_cfg_section *sect, struct mu_cfg_param *param) | ||
215 | { | ||
216 | if (!param) | ||
217 | return 0; | ||
218 | if (!sect->children) | ||
219 | mu_list_create (§->children); | ||
220 | for (; param->ident; param++) | ||
221 | { | ||
222 | int rc; | ||
223 | struct mu_cfg_cont *container; | ||
224 | |||
225 | if (param->type == mu_cfg_section) | ||
226 | { | ||
227 | container = mu_get_canned_container (param->ident); | ||
228 | if (!container) | ||
229 | { | ||
230 | mu_error (_("INTERNAL ERROR: Requested unknown canned " | ||
231 | "section %s"), | ||
232 | param->ident); | ||
233 | abort (); | ||
234 | } | ||
235 | mu_config_clone_container (container); | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | rc = mu_config_create_container (&container, mu_cfg_cont_param); | ||
240 | if (rc) | ||
241 | return rc; | ||
242 | container->v.param = *param; | ||
243 | } | ||
244 | mu_list_append (sect->children, container); | ||
245 | } | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int | ||
250 | _clone_action (void *item, void *cbdata) | ||
251 | { | ||
252 | struct mu_cfg_cont *cont = item; | ||
253 | return mu_config_clone_container (cont); | ||
254 | } | ||
255 | |||
256 | int | ||
257 | mu_config_clone_container (struct mu_cfg_cont *cont) | ||
258 | { | ||
259 | mu_refcount_inc (cont->refcount); | ||
260 | /* printf("clone %p-%s: %d\n", cont, cont->v.section.ident, n); */ | ||
261 | switch (cont->type) | ||
262 | { | ||
263 | case mu_cfg_cont_section: | ||
264 | mu_list_do (cont->v.section.children, _clone_action, NULL); | ||
265 | break; | ||
266 | |||
267 | case mu_cfg_cont_param: | ||
268 | break; | ||
269 | } | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | |||
274 | int | ||
275 | _mu_config_register_section (struct mu_cfg_cont **proot, | ||
276 | const char *parent_path, | ||
277 | const char *ident, | ||
278 | const char *label, | ||
279 | mu_cfg_section_fp parser, | ||
280 | struct mu_cfg_param *param, | ||
281 | struct mu_cfg_section **psection) | ||
282 | { | ||
283 | int rc; | ||
284 | struct mu_cfg_section *root_section; | ||
285 | struct mu_cfg_section *parent; | ||
286 | |||
287 | if (!*proot) | ||
288 | { | ||
289 | rc = mu_config_create_container (proot, mu_cfg_cont_section); | ||
290 | if (rc) | ||
291 | return rc; | ||
292 | memset (&(*proot)->v.section, 0, sizeof (*proot)->v.section); | ||
293 | } | ||
294 | |||
295 | root_section = &(*proot)->v.section; | ||
296 | |||
297 | if (parent_path) | ||
298 | { | ||
299 | if (mu_cfg_find_section (root_section, parent_path, &parent)) | ||
300 | return MU_ERR_NOENT; | ||
301 | } | ||
302 | else | ||
303 | parent = root_section; | ||
304 | |||
305 | if (mu_refcount_value ((*proot)->refcount) > 1) | ||
306 | { | ||
307 | /* It is a clone, do copy-on-write */ | ||
308 | rc = dup_container (proot); | ||
309 | if (rc) | ||
310 | return rc; | ||
311 | |||
312 | root_section = &(*proot)->v.section; | ||
313 | |||
314 | if (parent_path) | ||
315 | { | ||
316 | if (mu_cfg_find_section (root_section, parent_path, &parent)) | ||
317 | return MU_ERR_NOENT; | ||
318 | } | ||
319 | else | ||
320 | parent = root_section; | ||
321 | } | ||
322 | |||
323 | if (ident) | ||
324 | { | ||
325 | struct mu_cfg_cont *container; | ||
326 | struct mu_cfg_section *s; | ||
327 | |||
328 | if (!parent->children) | ||
329 | mu_list_create (&parent->children); | ||
330 | mu_config_create_container (&container, mu_cfg_cont_section); | ||
331 | mu_list_append (parent->children, container); | ||
332 | s = &container->v.section; | ||
333 | |||
334 | s->ident = strdup (ident); | ||
335 | s->label = label ? strdup (label) : NULL; | ||
336 | s->parser = parser; | ||
337 | s->children = NULL; | ||
338 | add_parameters (s, param); | ||
339 | if (psection) | ||
340 | *psection = s; | ||
341 | } | ||
342 | else | ||
343 | { | ||
344 | add_parameters (parent, param); | ||
345 | /* FIXME: */ | ||
346 | if (!parent->parser) | ||
347 | parent->parser = parser; | ||
348 | if (psection) | ||
349 | *psection = parent; | ||
350 | } | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | int | ||
355 | mu_config_register_section (const char *parent_path, | ||
356 | const char *ident, | ||
357 | const char *label, | ||
358 | mu_cfg_section_fp parser, | ||
359 | struct mu_cfg_param *param) | ||
360 | { | ||
361 | return _mu_config_register_section (&root_container, | ||
362 | parent_path, | ||
363 | ident, label, | ||
364 | parser, param, NULL); | ||
365 | } | ||
366 | |||
367 | int | ||
368 | mu_config_register_plain_section (const char *parent_path, const char *ident, | ||
369 | struct mu_cfg_param *params) | ||
370 | { | ||
371 | return mu_config_register_section (parent_path, ident, NULL, NULL, params); | ||
372 | } | ||
373 | |||
374 | static int | ||
375 | prog_parser (enum mu_cfg_section_stage stage, | ||
376 | const mu_cfg_node_t *node, | ||
377 | const char *label, void **section_data, | ||
378 | void *call_data, | ||
379 | mu_cfg_tree_t *tree) | ||
380 | { | ||
381 | if (stage == mu_cfg_section_start) | ||
382 | return strcmp (node->tag_label, label); | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static char * | ||
388 | make_file_name (const char *dir, const char *file) | ||
389 | { | ||
390 | char *tmp; | ||
391 | size_t len = strlen (dir) + 1 + strlen (file); | ||
392 | tmp = malloc (len + 1); | ||
393 | if (!tmp) | ||
394 | { | ||
395 | mu_error ("%s", mu_strerror (errno)); | ||
396 | exit (1); | ||
397 | } | ||
398 | strcpy (tmp, dir); | ||
399 | strcat (tmp, "/"); | ||
400 | strcat (tmp, file); | ||
401 | return tmp; | ||
402 | } | ||
403 | |||
404 | struct include_data | ||
405 | { | ||
406 | const char *progname; | ||
407 | struct mu_cfg_param *progparam; | ||
408 | int flags; | ||
409 | void *target; | ||
410 | }; | ||
411 | |||
412 | static int | ||
413 | _cb_include (mu_debug_t debug, void *data, char *arg) | ||
414 | { | ||
415 | int ret = 0; | ||
416 | struct stat sb; | ||
417 | char *dirname = arg; | ||
418 | struct include_data *idp = data; | ||
419 | char *tmp = NULL; | ||
420 | |||
421 | if (dirname[0] != '/') | ||
422 | dirname = tmp = make_file_name (SYSCONFDIR, dirname); | ||
423 | |||
424 | if (stat (dirname, &sb) == 0) | ||
425 | { | ||
426 | if (S_ISDIR (sb.st_mode)) | ||
427 | { | ||
428 | char *file = make_file_name (dirname, idp->progname); | ||
429 | ret = mu_get_config (file, idp->progname, idp->progparam, 0, | ||
430 | idp->target); | ||
431 | } | ||
432 | else | ||
433 | ret = mu_get_config (dirname, idp->progname, idp->progparam, | ||
434 | idp->flags, idp->target); | ||
435 | } | ||
436 | else if (errno == ENOENT) | ||
437 | { | ||
438 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
439 | _("include file or directory does not exist")); | ||
440 | ret = 1; | ||
441 | } | ||
442 | else | ||
443 | { | ||
444 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
445 | _("cannot stat include file or directory: %s"), | ||
446 | mu_strerror (errno)); | ||
447 | ret = 1; | ||
448 | } | ||
449 | free (tmp); | ||
450 | return ret; | ||
451 | } | ||
452 | |||
453 | struct mu_cfg_cont * | ||
454 | mu_build_container (const char *progname, | ||
455 | struct mu_cfg_param *progparam, int flags, void *target) | ||
456 | { | ||
457 | struct mu_cfg_cont *cont = root_container; | ||
458 | struct include_data idata; | ||
459 | struct mu_cfg_param mu_include_param[] = { | ||
460 | { "include", mu_cfg_callback, &idata, 0, _cb_include, | ||
461 | N_("Include contents of the given file. If a directory is given, " | ||
462 | "include contents of the file <file>/<program>, where <program> is " | ||
463 | "the name of the program. This latter form is allowed only in " | ||
464 | "the site-wide configuration file."), | ||
465 | N_("file-or-directory") }, | ||
466 | { NULL } | ||
467 | }; | ||
468 | |||
469 | mu_config_clone_container (cont); | ||
470 | idata.progname = progname; | ||
471 | idata.progparam = progparam; | ||
472 | idata.flags = flags & MU_PARSE_CONFIG_GLOBAL; | ||
473 | idata.target = target; | ||
474 | _mu_config_register_section (&cont, NULL, NULL, NULL, | ||
475 | (void*) progname, mu_include_param, NULL); | ||
476 | if (flags & MU_PARSE_CONFIG_GLOBAL) | ||
477 | { | ||
478 | mu_iterator_t iter; | ||
479 | struct mu_cfg_section *prog_sect; | ||
480 | struct mu_cfg_cont *old_root = root_container; | ||
481 | static struct mu_cfg_param empty_param = { NULL }; | ||
482 | if (!progparam) | ||
483 | progparam = &empty_param; | ||
484 | |||
485 | _mu_config_register_section (&cont, NULL, "program", progname, | ||
486 | prog_parser, progparam, &prog_sect); | ||
487 | |||
488 | if (old_root->v.section.children) | ||
489 | { | ||
490 | if (!prog_sect->children) | ||
491 | mu_list_create (&prog_sect->children); | ||
492 | mu_list_get_iterator (old_root->v.section.children, &iter); | ||
493 | for (mu_iterator_first (iter); !mu_iterator_is_done (iter); | ||
494 | mu_iterator_next (iter)) | ||
495 | { | ||
496 | struct mu_cfg_cont *c; | ||
497 | mu_iterator_current (iter, (void**)&c); | ||
498 | mu_list_append (prog_sect->children, c); | ||
499 | } | ||
500 | mu_iterator_destroy (&iter); | ||
501 | } | ||
502 | } | ||
503 | else if (progparam) | ||
504 | _mu_config_register_section (&cont, NULL, NULL, NULL, NULL, | ||
505 | progparam, NULL); | ||
506 | return cont; | ||
507 | } | ||
508 | |||
509 | int | ||
510 | mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree, const char *progname, | ||
511 | struct mu_cfg_param *progparam, int flags, | ||
512 | void *target_ptr) | ||
513 | { | ||
514 | int rc = 1; | ||
515 | |||
516 | if (root_container) | ||
517 | { | ||
518 | struct mu_cfg_cont *cont = mu_build_container (progname, progparam, | ||
519 | flags, target_ptr); | ||
520 | rc = mu_cfg_scan_tree (parse_tree, &cont->v.section, target_ptr, | ||
521 | (void*) progname); | ||
522 | mu_config_destroy_container (&cont); | ||
523 | } | ||
524 | |||
525 | if (flags & MU_PARSE_CONFIG_DUMP) | ||
526 | { | ||
527 | mu_stream_t stream; | ||
528 | mu_stdio_stream_create (&stream, stderr, | ||
529 | MU_STREAM_NO_CHECK|MU_STREAM_NO_CLOSE); | ||
530 | mu_stream_open (stream); | ||
531 | mu_cfg_format_parse_tree (stream, parse_tree); | ||
532 | mu_stream_destroy (&stream, NULL); | ||
533 | } | ||
534 | |||
535 | return rc; | ||
536 | } | ||
537 | |||
538 | void | ||
539 | mu_format_config_tree (mu_stream_t stream, const char *progname, | ||
540 | struct mu_cfg_param *progparam, int flags) | ||
541 | { | ||
542 | struct mu_cfg_cont *cont = mu_build_container (progname, progparam, flags, | ||
543 | NULL); | ||
544 | mu_cfg_format_container (stream, cont); | ||
545 | mu_config_destroy_container (&cont); | ||
546 | } | ||
547 | |||
548 | int | ||
549 | mu_parse_config (const char *file, const char *progname, | ||
550 | struct mu_cfg_param *progparam, int flags, | ||
551 | void *target_ptr) | ||
552 | { | ||
553 | int rc; | ||
554 | char *full_name = mu_tilde_expansion (file, "/", NULL); | ||
555 | if (full_name) | ||
556 | { | ||
557 | if (access (full_name, R_OK) == 0) | ||
558 | { | ||
559 | rc = mu_get_config (full_name, progname, progparam, flags, | ||
560 | target_ptr); | ||
561 | free (full_name); | ||
562 | } | ||
563 | else | ||
564 | rc = ENOENT; | ||
565 | } | ||
566 | else | ||
567 | rc = ENOMEM; | ||
568 | return rc; | ||
569 | } |
... | @@ -172,6 +172,8 @@ mu_cfg_data_type_string (enum mu_cfg_param_data_type type) | ... | @@ -172,6 +172,8 @@ mu_cfg_data_type_string (enum mu_cfg_param_data_type type) |
172 | return N_("host"); | 172 | return N_("host"); |
173 | case mu_cfg_callback: | 173 | case mu_cfg_callback: |
174 | return N_("string"); | 174 | return N_("string"); |
175 | case mu_cfg_section: | ||
176 | return N_("section"); | ||
175 | } | 177 | } |
176 | return N_("unknown"); | 178 | return N_("unknown"); |
177 | } | 179 | } |
... | @@ -261,19 +263,16 @@ format_section (mu_stream_t stream, struct mu_cfg_section *sect, int level) | ... | @@ -261,19 +263,16 @@ format_section (mu_stream_t stream, struct mu_cfg_section *sect, int level) |
261 | if (sect->ident) | 263 | if (sect->ident) |
262 | { | 264 | { |
263 | mu_stream_sequential_write (stream, sect->ident, strlen (sect->ident)); | 265 | mu_stream_sequential_write (stream, sect->ident, strlen (sect->ident)); |
264 | if (sect->data) | 266 | if (sect->label) |
265 | { | 267 | { |
266 | /* FIXME: This is wrong in general. Data is an opaque data | ||
267 | pointer. */ | ||
268 | char *s = sect->data; | ||
269 | mu_stream_sequential_write (stream, " ", 1); | 268 | mu_stream_sequential_write (stream, " ", 1); |
270 | mu_stream_sequential_write (stream, s, strlen (s)); | 269 | mu_stream_sequential_write (stream, sect->label, |
270 | strlen (sect->label)); | ||
271 | } | 271 | } |
272 | mu_stream_sequential_write (stream, " {\n", 3); | 272 | mu_stream_sequential_write (stream, " {\n", 3); |
273 | c.stream = stream; | 273 | c.stream = stream; |
274 | c.level = level + 1; | 274 | c.level = level + 1; |
275 | mu_list_do (sect->subsec, _f_helper, &c); | 275 | mu_list_do (sect->children, _f_helper, &c); |
276 | mu_list_do (sect->param, _f_helper, &c); | ||
277 | format_level (stream, level); | 276 | format_level (stream, level); |
278 | mu_stream_sequential_write (stream, "};\n\n", 4); | 277 | mu_stream_sequential_write (stream, "};\n\n", 4); |
279 | } | 278 | } |
... | @@ -281,8 +280,7 @@ format_section (mu_stream_t stream, struct mu_cfg_section *sect, int level) | ... | @@ -281,8 +280,7 @@ format_section (mu_stream_t stream, struct mu_cfg_section *sect, int level) |
281 | { | 280 | { |
282 | c.stream = stream; | 281 | c.stream = stream; |
283 | c.level = level; | 282 | c.level = level; |
284 | mu_list_do (sect->subsec, _f_helper, &c); | 283 | mu_list_do (sect->children, _f_helper, &c); |
285 | mu_list_do (sect->param, _f_helper, &c); | ||
286 | } | 284 | } |
287 | } | 285 | } |
288 | 286 | ... | ... |
... | @@ -25,17 +25,12 @@ | ... | @@ -25,17 +25,12 @@ |
25 | #include <errno.h> | 25 | #include <errno.h> |
26 | #include <unistd.h> | 26 | #include <unistd.h> |
27 | #include <ctype.h> | 27 | #include <ctype.h> |
28 | #include <mailutils/errno.h> | ||
29 | #include <mailutils/error.h> | ||
28 | #include <mailutils/argcv.h> | 30 | #include <mailutils/argcv.h> |
29 | #include <mailutils/nls.h> | 31 | #include <mailutils/nls.h> |
30 | #include <mailutils/cfg.h> | 32 | #include <mailutils/cfg.h> |
31 | #include <mailutils/errno.h> | ||
32 | #include <mailutils/error.h> | ||
33 | #include <mailutils/mutil.h> | ||
34 | #include <mailutils/monitor.h> | ||
35 | #include <mailutils/refcount.h> | ||
36 | #include <mailutils/list.h> | 33 | #include <mailutils/list.h> |
37 | #include <mailutils/iterator.h> | ||
38 | #include <mailutils/stream.h> | ||
39 | 34 | ||
40 | #include "cfg_parser.h" | 35 | #include "cfg_parser.h" |
41 | 36 | ||
... | @@ -350,497 +345,9 @@ again: | ... | @@ -350,497 +345,9 @@ again: |
350 | } | 345 | } |
351 | 346 | ||
352 | 347 | ||
353 | static struct mu_cfg_cont *root_container; | ||
354 | |||
355 | int | ||
356 | mu_config_create_container (struct mu_cfg_cont **pcont, | ||
357 | enum mu_cfg_cont_type type) | ||
358 | { | ||
359 | struct mu_cfg_cont *cont; | ||
360 | int rc; | ||
361 | |||
362 | cont = calloc (1, sizeof (*cont)); | ||
363 | if (!cont) | ||
364 | return ENOMEM; | ||
365 | rc = mu_refcount_create (&cont->refcount); | ||
366 | if (rc) | ||
367 | free (cont); | ||
368 | else | ||
369 | { | ||
370 | cont->type = type; | ||
371 | *pcont = cont; | ||
372 | } | ||
373 | return rc; | ||
374 | } | ||
375 | |||
376 | |||
377 | struct dup_data | ||
378 | { | ||
379 | struct mu_cfg_cont *cont; | ||
380 | }; | ||
381 | |||
382 | static int dup_container (struct mu_cfg_cont **pcont); | ||
383 | |||
384 | static int | ||
385 | _dup_section_action (void *item, void *cbdata) | ||
386 | { | ||
387 | int rc; | ||
388 | struct mu_cfg_cont *cont = item; | ||
389 | struct dup_data *pdd = cbdata; | ||
390 | |||
391 | rc = dup_container (&cont); | ||
392 | if (rc) | ||
393 | return rc; | ||
394 | |||
395 | if (!pdd->cont->v.section.subsec) | ||
396 | { | ||
397 | int rc = mu_list_create (&pdd->cont->v.section.subsec); | ||
398 | if (rc) | ||
399 | return rc; | ||
400 | } | ||
401 | return mu_list_append (pdd->cont->v.section.subsec, cont); | ||
402 | } | ||
403 | |||
404 | static int | ||
405 | _dup_param_action (void *item, void *cbdata) | ||
406 | { | ||
407 | int rc; | ||
408 | struct mu_cfg_cont *cont = item; | ||
409 | struct dup_data *pdd = cbdata; | ||
410 | rc = dup_container (&cont); | ||
411 | if (rc) | ||
412 | return rc; | ||
413 | if (!pdd->cont->v.section.param) | ||
414 | { | ||
415 | rc = mu_list_create (&pdd->cont->v.section.param); | ||
416 | if (rc) | ||
417 | return rc; | ||
418 | } | ||
419 | return mu_list_append (pdd->cont->v.section.param, cont); | ||
420 | } | ||
421 | |||
422 | static int | ||
423 | dup_container (struct mu_cfg_cont **pcont) | ||
424 | { | ||
425 | int rc; | ||
426 | struct mu_cfg_cont *newcont, *oldcont = *pcont; | ||
427 | struct dup_data dd; | ||
428 | |||
429 | rc = mu_config_create_container (&newcont, oldcont->type); | ||
430 | if (rc) | ||
431 | return rc; | ||
432 | |||
433 | dd.cont = newcont; | ||
434 | switch (oldcont->type) | ||
435 | { | ||
436 | case mu_cfg_cont_section: | ||
437 | newcont->v.section.ident = oldcont->v.section.ident; | ||
438 | newcont->v.section.parser = oldcont->v.section.parser; | ||
439 | newcont->v.section.data = oldcont->v.section.data; | ||
440 | newcont->v.section.docstring = oldcont->v.section.docstring; | ||
441 | newcont->v.section.subsec = NULL; | ||
442 | newcont->v.section.param = NULL; | ||
443 | mu_list_do (oldcont->v.section.subsec, _dup_section_action, &dd); | ||
444 | mu_list_do (oldcont->v.section.param, _dup_param_action, &dd); | ||
445 | break; | ||
446 | |||
447 | case mu_cfg_cont_param: | ||
448 | newcont->v.param = oldcont->v.param; | ||
449 | break; | ||
450 | } | ||
451 | *pcont = newcont; | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | |||
456 | static void | ||
457 | destroy_list (mu_list_t *plist) | ||
458 | { | ||
459 | mu_list_t list = *plist; | ||
460 | mu_iterator_t itr = NULL; | ||
461 | |||
462 | if (!list) | ||
463 | return; | ||
464 | |||
465 | mu_list_get_iterator (list, &itr); | ||
466 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); | ||
467 | mu_iterator_next (itr)) | ||
468 | { | ||
469 | struct mu_cfg_cont *cont, *p; | ||
470 | mu_iterator_current (itr, (void**)&cont); | ||
471 | p = cont; | ||
472 | mu_config_destroy_container (&p); | ||
473 | if (!p) | ||
474 | mu_list_remove (list, cont); | ||
475 | } | ||
476 | mu_iterator_destroy (&itr); | ||
477 | if (mu_list_is_empty (list)) | ||
478 | mu_list_destroy (plist); | ||
479 | } | ||
480 | |||
481 | void | ||
482 | mu_config_destroy_container (struct mu_cfg_cont **pcont) | ||
483 | { | ||
484 | struct mu_cfg_cont *cont = *pcont; | ||
485 | unsigned refcount = mu_refcount_dec (cont->refcount); | ||
486 | /* printf ("destr %p-%s: %d\n", cont, cont->v.section.ident, refcount); */ | ||
487 | switch (cont->type) | ||
488 | { | ||
489 | case mu_cfg_cont_section: | ||
490 | destroy_list (&cont->v.section.subsec); | ||
491 | destroy_list (&cont->v.section.param); | ||
492 | break; | ||
493 | |||
494 | case mu_cfg_cont_param: | ||
495 | break; | ||
496 | } | ||
497 | |||
498 | if (refcount == 0) | ||
499 | { | ||
500 | free (cont); | ||
501 | *pcont = 0; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | |||
506 | static int | ||
507 | add_parameters (struct mu_cfg_section *sect, struct mu_cfg_param *param) | ||
508 | { | ||
509 | if (!param) | ||
510 | return 0; | ||
511 | if (!sect->param) | ||
512 | mu_list_create (§->param); | ||
513 | for (; param->ident; param++) | ||
514 | { | ||
515 | int rc; | ||
516 | struct mu_cfg_cont *container; | ||
517 | |||
518 | rc = mu_config_create_container (&container, mu_cfg_cont_param); | ||
519 | if (rc) | ||
520 | return rc; | ||
521 | container->v.param = *param; | ||
522 | mu_list_append (sect->param, container); | ||
523 | } | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int | ||
528 | _clone_action (void *item, void *cbdata) | ||
529 | { | ||
530 | struct mu_cfg_cont *cont = item; | ||
531 | return mu_config_clone_container (cont); | ||
532 | } | ||
533 | |||
534 | int | ||
535 | mu_config_clone_container (struct mu_cfg_cont *cont) | ||
536 | { | ||
537 | mu_refcount_inc (cont->refcount); | ||
538 | /* printf("clone %p-%s: %d\n", cont, cont->v.section.ident, n); */ | ||
539 | switch (cont->type) | ||
540 | { | ||
541 | case mu_cfg_cont_section: | ||
542 | mu_list_do (cont->v.section.subsec, _clone_action, NULL); | ||
543 | mu_list_do (cont->v.section.param, _clone_action, NULL); | ||
544 | break; | ||
545 | |||
546 | case mu_cfg_cont_param: | ||
547 | break; | ||
548 | } | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | |||
553 | int | 348 | int |
554 | _mu_config_register_section (struct mu_cfg_cont **proot, | 349 | mu_get_config (const char *file, const char *progname, |
555 | const char *parent_path, | 350 | struct mu_cfg_param *progparam, int flags, void *target_ptr) |
556 | const char *ident, | ||
557 | mu_cfg_section_fp parser, | ||
558 | void *data, | ||
559 | struct mu_cfg_param *param, | ||
560 | struct mu_cfg_section **psection) | ||
561 | { | ||
562 | int rc; | ||
563 | struct mu_cfg_section *root_section; | ||
564 | struct mu_cfg_section *parent; | ||
565 | |||
566 | if (!*proot) | ||
567 | { | ||
568 | rc = mu_config_create_container (proot, mu_cfg_cont_section); | ||
569 | if (rc) | ||
570 | return rc; | ||
571 | memset (&(*proot)->v.section, 0, sizeof (*proot)->v.section); | ||
572 | } | ||
573 | |||
574 | root_section = &(*proot)->v.section; | ||
575 | |||
576 | if (parent_path) | ||
577 | { | ||
578 | if (mu_cfg_find_section (root_section, parent_path, &parent)) | ||
579 | return MU_ERR_NOENT; | ||
580 | } | ||
581 | else | ||
582 | parent = root_section; | ||
583 | |||
584 | if (mu_refcount_value ((*proot)->refcount) > 1) | ||
585 | { | ||
586 | /* It is a clone, do copy-on-write */ | ||
587 | rc = dup_container (proot); | ||
588 | if (rc) | ||
589 | return rc; | ||
590 | |||
591 | root_section = &(*proot)->v.section; | ||
592 | |||
593 | if (parent_path) | ||
594 | { | ||
595 | if (mu_cfg_find_section (root_section, parent_path, &parent)) | ||
596 | return MU_ERR_NOENT; | ||
597 | } | ||
598 | else | ||
599 | parent = root_section; | ||
600 | } | ||
601 | |||
602 | if (ident) | ||
603 | { | ||
604 | struct mu_cfg_cont *container; | ||
605 | struct mu_cfg_section *s; | ||
606 | |||
607 | if (!parent->subsec) | ||
608 | mu_list_create (&parent->subsec); | ||
609 | mu_config_create_container (&container, mu_cfg_cont_section); | ||
610 | mu_list_append (parent->subsec, container); | ||
611 | s = &container->v.section; | ||
612 | |||
613 | s->ident = strdup (ident); | ||
614 | s->parser = parser; | ||
615 | s->data = data; | ||
616 | s->subsec = NULL; | ||
617 | s->param = NULL; | ||
618 | add_parameters (s, param); | ||
619 | if (psection) | ||
620 | *psection = s; | ||
621 | } | ||
622 | else | ||
623 | { | ||
624 | add_parameters (parent, param); | ||
625 | if (!parent->parser) | ||
626 | parent->parser = parser; | ||
627 | if (!parent->data) | ||
628 | parent->data = data; | ||
629 | if (psection) | ||
630 | *psection = parent; | ||
631 | } | ||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | int | ||
636 | mu_config_register_section (const char *parent_path, | ||
637 | const char *ident, | ||
638 | mu_cfg_section_fp parser, | ||
639 | void *data, | ||
640 | struct mu_cfg_param *param) | ||
641 | { | ||
642 | return _mu_config_register_section (&root_container, | ||
643 | parent_path, | ||
644 | ident, parser, data, param, NULL); | ||
645 | } | ||
646 | |||
647 | int | ||
648 | mu_config_register_plain_section (const char *parent_path, const char *ident, | ||
649 | struct mu_cfg_param *params) | ||
650 | { | ||
651 | return mu_config_register_section (parent_path, ident, NULL, NULL, params); | ||
652 | } | ||
653 | |||
654 | static int | ||
655 | prog_parser (enum mu_cfg_section_stage stage, | ||
656 | const mu_cfg_node_t *node, | ||
657 | void *section_data, void *call_data, | ||
658 | mu_cfg_tree_t *tree) | ||
659 | { | ||
660 | if (stage == mu_cfg_section_start) | ||
661 | { | ||
662 | return strcmp (node->tag_label, call_data); | ||
663 | } | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static char * | ||
668 | make_file_name (const char *dir, const char *file) | ||
669 | { | ||
670 | char *tmp; | ||
671 | size_t len = strlen (dir) + 1 + strlen (file); | ||
672 | tmp = malloc (len + 1); | ||
673 | if (!tmp) | ||
674 | { | ||
675 | mu_error ("%s", mu_strerror (errno)); | ||
676 | exit (1); | ||
677 | } | ||
678 | strcpy (tmp, dir); | ||
679 | strcat (tmp, "/"); | ||
680 | strcat (tmp, file); | ||
681 | return tmp; | ||
682 | } | ||
683 | |||
684 | struct include_data | ||
685 | { | ||
686 | const char *progname; | ||
687 | struct mu_cfg_param *progparam; | ||
688 | int flags; | ||
689 | }; | ||
690 | |||
691 | static int _mu_parse_config (const char *file, const char *progname, | ||
692 | struct mu_cfg_param *progparam, int flags); | ||
693 | |||
694 | static int | ||
695 | _cb_include (mu_debug_t debug, void *data, char *arg) | ||
696 | { | ||
697 | int ret = 0; | ||
698 | struct stat sb; | ||
699 | char *dirname = arg; | ||
700 | struct include_data *idp = data; | ||
701 | char *tmp = NULL; | ||
702 | |||
703 | if (dirname[0] != '/') | ||
704 | dirname = tmp = make_file_name (SYSCONFDIR, dirname); | ||
705 | |||
706 | if (stat (dirname, &sb) == 0) | ||
707 | { | ||
708 | if (S_ISDIR (sb.st_mode)) | ||
709 | { | ||
710 | char *file = make_file_name (dirname, idp->progname); | ||
711 | ret = _mu_parse_config (file, idp->progname, idp->progparam, 0); | ||
712 | } | ||
713 | else | ||
714 | ret = _mu_parse_config (dirname, idp->progname, idp->progparam, | ||
715 | idp->flags); | ||
716 | } | ||
717 | else if (errno == ENOENT) | ||
718 | { | ||
719 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
720 | _("include file or directory does not exist")); | ||
721 | ret = 1; | ||
722 | } | ||
723 | else | ||
724 | { | ||
725 | mu_cfg_format_error (debug, MU_DEBUG_ERROR, | ||
726 | _("cannot stat include file or directory: %s"), | ||
727 | mu_strerror (errno)); | ||
728 | ret = 1; | ||
729 | } | ||
730 | free (tmp); | ||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | struct mu_cfg_cont * | ||
735 | mu_build_container (const char *progname, | ||
736 | struct mu_cfg_param *progparam, int flags) | ||
737 | { | ||
738 | struct mu_cfg_cont *cont = root_container; | ||
739 | struct include_data idata; | ||
740 | struct mu_cfg_param mu_include_param[] = { | ||
741 | { "include", mu_cfg_callback, &idata, _cb_include, | ||
742 | N_("Include contents of the given file. If a directory is given, " | ||
743 | "include contents of the file <file>/<program>, where <program> is " | ||
744 | "the name of the program. This latter form is allowed only in " | ||
745 | "the site-wide configuration file."), | ||
746 | N_("file-or-directory") }, | ||
747 | { NULL } | ||
748 | }; | ||
749 | |||
750 | mu_config_clone_container (cont); | ||
751 | idata.progname = progname; | ||
752 | idata.progparam = progparam; | ||
753 | idata.flags = flags & MU_PARSE_CONFIG_GLOBAL; | ||
754 | _mu_config_register_section (&cont, NULL, NULL, NULL, | ||
755 | (void*) progname, mu_include_param, NULL); | ||
756 | if (flags & MU_PARSE_CONFIG_GLOBAL) | ||
757 | { | ||
758 | mu_iterator_t iter; | ||
759 | struct mu_cfg_section *prog_sect; | ||
760 | struct mu_cfg_cont *old_root = root_container; | ||
761 | static struct mu_cfg_param empty_param = { NULL }; | ||
762 | if (!progparam) | ||
763 | progparam = &empty_param; | ||
764 | |||
765 | _mu_config_register_section (&cont, NULL, "program", prog_parser, | ||
766 | (void*) progname, | ||
767 | progparam, &prog_sect); | ||
768 | |||
769 | if (old_root->v.section.subsec) | ||
770 | { | ||
771 | if (!prog_sect->subsec) | ||
772 | mu_list_create (&prog_sect->subsec); | ||
773 | mu_list_get_iterator (old_root->v.section.subsec, &iter); | ||
774 | for (mu_iterator_first (iter); !mu_iterator_is_done (iter); | ||
775 | mu_iterator_next (iter)) | ||
776 | { | ||
777 | struct mu_cfg_cont *c; | ||
778 | mu_iterator_current (iter, (void**)&c); | ||
779 | mu_list_append (prog_sect->subsec, c); | ||
780 | } | ||
781 | mu_iterator_destroy (&iter); | ||
782 | } | ||
783 | |||
784 | if (old_root->v.section.param) | ||
785 | { | ||
786 | if (!prog_sect->param) | ||
787 | mu_list_create (&prog_sect->param); | ||
788 | mu_list_get_iterator (old_root->v.section.param, &iter); | ||
789 | for (mu_iterator_first (iter); !mu_iterator_is_done (iter); | ||
790 | mu_iterator_next (iter)) | ||
791 | { | ||
792 | struct mu_cfg_cont *c; | ||
793 | mu_iterator_current (iter, (void**)&c); | ||
794 | mu_list_append (prog_sect->param, c); | ||
795 | } | ||
796 | mu_iterator_destroy (&iter); | ||
797 | } | ||
798 | } | ||
799 | else if (progparam) | ||
800 | _mu_config_register_section (&cont, NULL, NULL, NULL, NULL, | ||
801 | progparam, NULL); | ||
802 | return cont; | ||
803 | } | ||
804 | |||
805 | int | ||
806 | mu_parse_config_tree (mu_cfg_tree_t *parse_tree, const char *progname, | ||
807 | struct mu_cfg_param *progparam, int flags) | ||
808 | { | ||
809 | int rc = 1; | ||
810 | |||
811 | if (root_container) | ||
812 | { | ||
813 | struct mu_cfg_cont *cont = mu_build_container (progname, progparam, | ||
814 | flags); | ||
815 | rc = mu_cfg_scan_tree (parse_tree, &cont->v.section, (void*) progname); | ||
816 | mu_config_destroy_container (&cont); | ||
817 | } | ||
818 | |||
819 | if (flags & MU_PARSE_CONFIG_DUMP) | ||
820 | { | ||
821 | mu_stream_t stream; | ||
822 | mu_stdio_stream_create (&stream, stderr, | ||
823 | MU_STREAM_NO_CHECK|MU_STREAM_NO_CLOSE); | ||
824 | mu_stream_open (stream); | ||
825 | mu_cfg_format_parse_tree (stream, parse_tree); | ||
826 | mu_stream_destroy (&stream, NULL); | ||
827 | } | ||
828 | |||
829 | return rc; | ||
830 | } | ||
831 | |||
832 | void | ||
833 | mu_format_config_tree (mu_stream_t stream, const char *progname, | ||
834 | struct mu_cfg_param *progparam, int flags) | ||
835 | { | ||
836 | struct mu_cfg_cont *cont = mu_build_container (progname, progparam, flags); | ||
837 | mu_cfg_format_container (stream, cont); | ||
838 | mu_config_destroy_container (&cont); | ||
839 | } | ||
840 | |||
841 | static int | ||
842 | _mu_parse_config (const char *file, const char *progname, | ||
843 | struct mu_cfg_param *progparam, int flags) | ||
844 | { | 351 | { |
845 | struct lexer_data data; | 352 | struct lexer_data data; |
846 | struct stat st; | 353 | struct stat st; |
... | @@ -883,7 +390,8 @@ _mu_parse_config (const char *file, const char *progname, | ... | @@ -883,7 +390,8 @@ _mu_parse_config (const char *file, const char *progname, |
883 | NULL); | 390 | NULL); |
884 | 391 | ||
885 | if (rc == 0) | 392 | if (rc == 0) |
886 | rc = mu_parse_config_tree (parse_tree, progname, progparam, flags); | 393 | rc = mu_cfg_tree_reduce (parse_tree, progname, progparam, flags, |
394 | target_ptr); | ||
887 | 395 | ||
888 | mu_cfg_destroy_tree (&parse_tree); | 396 | mu_cfg_destroy_tree (&parse_tree); |
889 | mu_list_destroy (&data.mpool); | 397 | mu_list_destroy (&data.mpool); |
... | @@ -896,23 +404,3 @@ _mu_parse_config (const char *file, const char *progname, | ... | @@ -896,23 +404,3 @@ _mu_parse_config (const char *file, const char *progname, |
896 | return rc; | 404 | return rc; |
897 | } | 405 | } |
898 | 406 | ||
899 | int | ||
900 | mu_parse_config (const char *file, const char *progname, | ||
901 | struct mu_cfg_param *progparam, int flags) | ||
902 | { | ||
903 | int rc; | ||
904 | char *full_name = mu_tilde_expansion (file, "/", NULL); | ||
905 | if (full_name) | ||
906 | { | ||
907 | if (access (full_name, R_OK) == 0) | ||
908 | { | ||
909 | rc = _mu_parse_config (full_name, progname, progparam, flags); | ||
910 | free (full_name); | ||
911 | } | ||
912 | else | ||
913 | rc = ENOENT; | ||
914 | } | ||
915 | else | ||
916 | rc = ENOMEM; | ||
917 | return rc; | ||
918 | } | ... | ... |
... | @@ -497,13 +497,15 @@ struct mu_cfg_section_list | ... | @@ -497,13 +497,15 @@ struct mu_cfg_section_list |
497 | struct scan_tree_data | 497 | struct scan_tree_data |
498 | { | 498 | { |
499 | struct mu_cfg_section_list *list; | 499 | struct mu_cfg_section_list *list; |
500 | void *target; | ||
500 | void *call_data; | 501 | void *call_data; |
501 | mu_cfg_tree_t *tree; | 502 | mu_cfg_tree_t *tree; |
502 | int error; | 503 | int error; |
503 | }; | 504 | }; |
504 | 505 | ||
505 | static struct mu_cfg_cont * | 506 | static struct mu_cfg_cont * |
506 | find_container (mu_list_t list, const char *ident, size_t len) | 507 | find_container (mu_list_t list, enum mu_cfg_cont_type type, |
508 | const char *ident, size_t len) | ||
507 | { | 509 | { |
508 | mu_iterator_t iter; | 510 | mu_iterator_t iter; |
509 | struct mu_cfg_cont *ret = NULL; | 511 | struct mu_cfg_cont *ret = NULL; |
... | @@ -518,7 +520,8 @@ find_container (mu_list_t list, const char *ident, size_t len) | ... | @@ -518,7 +520,8 @@ find_container (mu_list_t list, const char *ident, size_t len) |
518 | struct mu_cfg_cont *cont; | 520 | struct mu_cfg_cont *cont; |
519 | mu_iterator_current (iter, (void**) &cont); | 521 | mu_iterator_current (iter, (void**) &cont); |
520 | 522 | ||
521 | if (strlen (cont->v.ident) == len | 523 | if (cont->type == type |
524 | && strlen (cont->v.ident) == len | ||
522 | && memcmp (cont->v.ident, ident, len) == 0) | 525 | && memcmp (cont->v.ident, ident, len) == 0) |
523 | { | 526 | { |
524 | ret = cont; | 527 | ret = cont; |
... | @@ -534,9 +537,11 @@ find_subsection (struct mu_cfg_section *sec, const char *ident, size_t len) | ... | @@ -534,9 +537,11 @@ find_subsection (struct mu_cfg_section *sec, const char *ident, size_t len) |
534 | { | 537 | { |
535 | if (sec) | 538 | if (sec) |
536 | { | 539 | { |
537 | if (sec->subsec) | 540 | if (sec->children) |
538 | { | 541 | { |
539 | struct mu_cfg_cont *cont = find_container (sec->subsec, ident, len); | 542 | struct mu_cfg_cont *cont = find_container (sec->children, |
543 | mu_cfg_cont_section, | ||
544 | ident, len); | ||
540 | if (cont) | 545 | if (cont) |
541 | return &cont->v.section; | 546 | return &cont->v.section; |
542 | } | 547 | } |
... | @@ -549,9 +554,11 @@ find_param (struct mu_cfg_section *sec, const char *ident, size_t len) | ... | @@ -549,9 +554,11 @@ find_param (struct mu_cfg_section *sec, const char *ident, size_t len) |
549 | { | 554 | { |
550 | if (sec) | 555 | if (sec) |
551 | { | 556 | { |
552 | if (sec->param) | 557 | if (sec->children) |
553 | { | 558 | { |
554 | struct mu_cfg_cont *cont = find_container (sec->param, ident, len); | 559 | struct mu_cfg_cont *cont = find_container (sec->children, |
560 | mu_cfg_cont_param, | ||
561 | ident, len); | ||
555 | if (cont) | 562 | if (cont) |
556 | return &cont->v.param; | 563 | return &cont->v.param; |
557 | } | 564 | } |
... | @@ -842,8 +849,10 @@ parse_bool (struct scan_tree_data *sdata, const mu_cfg_node_t *node, int *res) | ... | @@ -842,8 +849,10 @@ parse_bool (struct scan_tree_data *sdata, const mu_cfg_node_t *node, int *res) |
842 | static int | 849 | static int |
843 | parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) | 850 | parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) |
844 | { | 851 | { |
852 | void *tgt; | ||
845 | struct mu_cfg_param *param = find_param (sdata->list->sec, node->tag_name, | 853 | struct mu_cfg_param *param = find_param (sdata->list->sec, node->tag_name, |
846 | 0); | 854 | 0); |
855 | |||
847 | if (!param) | 856 | if (!param) |
848 | { | 857 | { |
849 | _mu_cfg_perror (sdata->tree->debug, &node->locus, | 858 | _mu_cfg_perror (sdata->tree->debug, &node->locus, |
... | @@ -852,6 +861,22 @@ parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) | ... | @@ -852,6 +861,22 @@ parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) |
852 | return 1; | 861 | return 1; |
853 | } | 862 | } |
854 | 863 | ||
864 | if (param->data) | ||
865 | tgt = param->data; | ||
866 | else if (sdata->list->sec->target) | ||
867 | tgt = (char*)sdata->list->sec->target + param->offset; | ||
868 | else if (sdata->target) | ||
869 | tgt = (char*)sdata->target + param->offset; | ||
870 | else if (param->type == mu_cfg_callback) | ||
871 | tgt = NULL; | ||
872 | else | ||
873 | { | ||
874 | _mu_cfg_perror (sdata->tree->debug, &node->locus, | ||
875 | _("INTERNAL ERROR: cannot determine target offset for " | ||
876 | "%s"), param->ident); | ||
877 | abort (); | ||
878 | } | ||
879 | |||
855 | switch (param->type) | 880 | switch (param->type) |
856 | { | 881 | { |
857 | case mu_cfg_string: | 882 | case mu_cfg_string: |
... | @@ -865,80 +890,80 @@ parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) | ... | @@ -865,80 +890,80 @@ parse_param (struct scan_tree_data *sdata, const mu_cfg_node_t *node) |
865 | return 1; | 890 | return 1; |
866 | } | 891 | } |
867 | strcpy (s, node->tag_label); | 892 | strcpy (s, node->tag_label); |
868 | /* FIXME: free param->data? */ | 893 | /* FIXME: free tgt? */ |
869 | *(char**)param->data = s; | 894 | *(char**)tgt = s; |
870 | break; | 895 | break; |
871 | } | 896 | } |
872 | 897 | ||
873 | case mu_cfg_short: | 898 | case mu_cfg_short: |
874 | GETSNUM (node->tag_label, short, *(short*)param->data, | 899 | GETSNUM (node->tag_label, short, *(short*)tgt, |
875 | sdata->tree->debug); | 900 | sdata->tree->debug); |
876 | break; | 901 | break; |
877 | 902 | ||
878 | case mu_cfg_ushort: | 903 | case mu_cfg_ushort: |
879 | GETUNUM (node->tag_label, unsigned short, *(unsigned short*)param->data, | 904 | GETUNUM (node->tag_label, unsigned short, *(unsigned short*)tgt, |
880 | sdata->tree->debug); | 905 | sdata->tree->debug); |
881 | break; | 906 | break; |
882 | 907 | ||
883 | case mu_cfg_int: | 908 | case mu_cfg_int: |
884 | GETSNUM (node->tag_label, int, *(int*)param->data, sdata->tree->debug); | 909 | GETSNUM (node->tag_label, int, *(int*)tgt, sdata->tree->debug); |
885 | break; | 910 | break; |
886 | 911 | ||
887 | case mu_cfg_uint: | 912 | case mu_cfg_uint: |
888 | GETUNUM (node->tag_label, unsigned int, *(unsigned int*)param->data, | 913 | GETUNUM (node->tag_label, unsigned int, *(unsigned int*)tgt, |
889 | sdata->tree->debug); | 914 | sdata->tree->debug); |
890 | break; | 915 | break; |
891 | 916 | ||
892 | case mu_cfg_long: | 917 | case mu_cfg_long: |
893 | GETSNUM (node->tag_label, long, *(long*)param->data, | 918 | GETSNUM (node->tag_label, long, *(long*)tgt, |
894 | sdata->tree->debug); | 919 | sdata->tree->debug); |
895 | break; | 920 | break; |
896 | 921 | ||
897 | case mu_cfg_ulong: | 922 | case mu_cfg_ulong: |
898 | GETUNUM (node->tag_label, unsigned long, *(unsigned long*)param->data, | 923 | GETUNUM (node->tag_label, unsigned long, *(unsigned long*)tgt, |
899 | sdata->tree->debug); | 924 | sdata->tree->debug); |
900 | break; | 925 | break; |
901 | 926 | ||
902 | case mu_cfg_size: | 927 | case mu_cfg_size: |
903 | GETUNUM (node->tag_label, size_t, *(size_t*)param->data, | 928 | GETUNUM (node->tag_label, size_t, *(size_t*)tgt, |
904 | sdata->tree->debug); | 929 | sdata->tree->debug); |
905 | break; | 930 | break; |
906 | 931 | ||
907 | case mu_cfg_off: | 932 | case mu_cfg_off: |
908 | _mu_cfg_perror (sdata->tree->debug, &node->locus, | 933 | _mu_cfg_perror (sdata->tree->debug, &node->locus, |
909 | _("not implemented yet")); | 934 | _("not implemented yet")); |
910 | /* GETSNUM(node->tag_label, off_t, *(off_t*)param->data); */ | 935 | /* GETSNUM(node->tag_label, off_t, *(off_t*)tgt); */ |
911 | return 1; | 936 | return 1; |
912 | 937 | ||
913 | case mu_cfg_time: | 938 | case mu_cfg_time: |
914 | GETUNUM (node->tag_label, time_t, *(time_t*)param->data, | 939 | GETUNUM (node->tag_label, time_t, *(time_t*)tgt, |
915 | sdata->tree->debug); | 940 | sdata->tree->debug); |
916 | break; | 941 | break; |
917 | 942 | ||
918 | case mu_cfg_bool: | 943 | case mu_cfg_bool: |
919 | if (parse_bool (sdata, node, (int*) param->data)) | 944 | if (parse_bool (sdata, node, (int*) tgt)) |
920 | return 1; | 945 | return 1; |
921 | break; | 946 | break; |
922 | 947 | ||
923 | case mu_cfg_ipv4: | 948 | case mu_cfg_ipv4: |
924 | if (parse_ipv4 (sdata, node, (struct in_addr *)param->data)) | 949 | if (parse_ipv4 (sdata, node, (struct in_addr *)tgt)) |
925 | return 1; | 950 | return 1; |
926 | break; | 951 | break; |
927 | 952 | ||
928 | case mu_cfg_cidr: | 953 | case mu_cfg_cidr: |
929 | if (parse_cidr (sdata, node, (mu_cfg_cidr_t *)param->data)) | 954 | if (parse_cidr (sdata, node, (mu_cfg_cidr_t *)tgt)) |
930 | return 1; | 955 | return 1; |
931 | break; | 956 | break; |
932 | 957 | ||
933 | case mu_cfg_host: | 958 | case mu_cfg_host: |
934 | if (parse_host (sdata, node, (struct in_addr *)param->data)) | 959 | if (parse_host (sdata, node, (struct in_addr *)tgt)) |
935 | return 1; | 960 | return 1; |
936 | break; | 961 | break; |
937 | 962 | ||
938 | case mu_cfg_callback: | 963 | case mu_cfg_callback: |
939 | mu_debug_set_locus (sdata->tree->debug, node->locus.file, | 964 | mu_debug_set_locus (sdata->tree->debug, node->locus.file, |
940 | node->locus.line); | 965 | node->locus.line); |
941 | if (param->callback (sdata->tree->debug, param->data, node->tag_label)) | 966 | if (param->callback (sdata->tree->debug, tgt, node->tag_label)) |
942 | return 1; | 967 | return 1; |
943 | break; | 968 | break; |
944 | 969 | ||
... | @@ -972,11 +997,12 @@ _scan_tree_helper (const mu_cfg_node_t *node, void *data) | ... | @@ -972,11 +997,12 @@ _scan_tree_helper (const mu_cfg_node_t *node, void *data) |
972 | } | 997 | } |
973 | return MU_CFG_ITER_SKIP; | 998 | return MU_CFG_ITER_SKIP; |
974 | } | 999 | } |
975 | if (!sec->subsec && !sec->param) | 1000 | if (!sec->children) |
976 | return MU_CFG_ITER_SKIP; | 1001 | return MU_CFG_ITER_SKIP; |
977 | if (sec->parser && | 1002 | if (sec->parser && |
978 | sec->parser (mu_cfg_section_start, node, | 1003 | sec->parser (mu_cfg_section_start, node, |
979 | sec->data, sdata->call_data, sdata->tree)) | 1004 | sec->label, &sec->target, |
1005 | sdata->call_data, sdata->tree)) | ||
980 | { | 1006 | { |
981 | sdata->error++; | 1007 | sdata->error++; |
982 | return MU_CFG_ITER_SKIP; | 1008 | return MU_CFG_ITER_SKIP; |
... | @@ -1010,7 +1036,8 @@ _scan_tree_end_helper (const mu_cfg_node_t *node, void *data) | ... | @@ -1010,7 +1036,8 @@ _scan_tree_end_helper (const mu_cfg_node_t *node, void *data) |
1010 | sec = pop_section (sdata); | 1036 | sec = pop_section (sdata); |
1011 | if (sec && sec->parser) | 1037 | if (sec && sec->parser) |
1012 | { | 1038 | { |
1013 | if (sec->parser (mu_cfg_section_end, node, sec->data, | 1039 | if (sec->parser (mu_cfg_section_end, node, |
1040 | sec->label, &sec->target, | ||
1014 | sdata->call_data, sdata->tree)) | 1041 | sdata->call_data, sdata->tree)) |
1015 | { | 1042 | { |
1016 | sdata->error++; | 1043 | sdata->error++; |
... | @@ -1023,13 +1050,14 @@ _scan_tree_end_helper (const mu_cfg_node_t *node, void *data) | ... | @@ -1023,13 +1050,14 @@ _scan_tree_end_helper (const mu_cfg_node_t *node, void *data) |
1023 | 1050 | ||
1024 | int | 1051 | int |
1025 | mu_cfg_scan_tree (mu_cfg_tree_t *tree, struct mu_cfg_section *sections, | 1052 | mu_cfg_scan_tree (mu_cfg_tree_t *tree, struct mu_cfg_section *sections, |
1026 | void *data) | 1053 | void *target, void *data) |
1027 | { | 1054 | { |
1028 | struct scan_tree_data dat; | 1055 | struct scan_tree_data dat; |
1029 | dat.tree = tree; | 1056 | dat.tree = tree; |
1030 | dat.list = NULL; | 1057 | dat.list = NULL; |
1031 | dat.error = 0; | 1058 | dat.error = 0; |
1032 | dat.call_data = data; | 1059 | dat.call_data = data; |
1060 | dat.target = target; | ||
1033 | if (push_section (&dat, sections)) | 1061 | if (push_section (&dat, sections)) |
1034 | return 1; | 1062 | return 1; |
1035 | mu_cfg_preorder (tree->node, _scan_tree_helper, _scan_tree_end_helper, &dat); | 1063 | mu_cfg_preorder (tree->node, _scan_tree_helper, _scan_tree_end_helper, &dat); | ... | ... |
... | @@ -166,13 +166,13 @@ cb_metamail (mu_debug_t debug, void *data, char *arg) | ... | @@ -166,13 +166,13 @@ cb_metamail (mu_debug_t debug, void *data, char *arg) |
166 | } | 166 | } |
167 | 167 | ||
168 | struct mu_cfg_param mimeview_cfg_param[] = { | 168 | struct mu_cfg_param mimeview_cfg_param[] = { |
169 | { "debug", mu_cfg_callback, NULL, cb_debug, | 169 | { "debug", mu_cfg_callback, NULL, 0, cb_debug, |
170 | N_("Set debug verbosity level."), | 170 | N_("Set debug verbosity level."), |
171 | N_("flags") }, | 171 | N_("flags") }, |
172 | { "mimetypes", mu_cfg_string, &mimetypes_config, NULL, | 172 | { "mimetypes", mu_cfg_string, &mimetypes_config, 0, NULL, |
173 | N_("Use this mime.types file."), | 173 | N_("Use this mime.types file."), |
174 | N_("file") }, | 174 | N_("file") }, |
175 | { "metamail", mu_cfg_string, NULL, cb_metamail, | 175 | { "metamail", mu_cfg_string, NULL, 0, cb_metamail, |
176 | N_("Use this program to display files."), | 176 | N_("Use this program to display files."), |
177 | N_("prog") }, | 177 | N_("prog") }, |
178 | { NULL } | 178 | { NULL } | ... | ... |
... | @@ -90,11 +90,11 @@ static struct argp argp = { | ... | @@ -90,11 +90,11 @@ static struct argp argp = { |
90 | 90 | ||
91 | 91 | ||
92 | struct mu_cfg_param movemail_cfg_param[] = { | 92 | struct mu_cfg_param movemail_cfg_param[] = { |
93 | { "preserve", mu_cfg_bool, &preserve_mail, NULL, | 93 | { "preserve", mu_cfg_bool, &preserve_mail, 0, NULL, |
94 | N_("Do not remove messages from the source mailbox.") }, | 94 | N_("Do not remove messages from the source mailbox.") }, |
95 | { "reverse", mu_cfg_bool, &reverse_order, NULL, | 95 | { "reverse", mu_cfg_bool, &reverse_order, 0, NULL, |
96 | N_("Reverse message sorting order.") }, | 96 | N_("Reverse message sorting order.") }, |
97 | { "emacs", mu_cfg_bool, &emacs_mode, NULL, | 97 | { "emacs", mu_cfg_bool, &emacs_mode, 0, NULL, |
98 | N_("Output information used by Emacs rmail interface.") }, | 98 | N_("Output information used by Emacs rmail interface.") }, |
99 | { NULL } | 99 | { NULL } |
100 | }; | 100 | }; | ... | ... |
... | @@ -134,28 +134,28 @@ cb_bulletin_db (mu_debug_t debug, void *data, char *arg) | ... | @@ -134,28 +134,28 @@ cb_bulletin_db (mu_debug_t debug, void *data, char *arg) |
134 | } | 134 | } |
135 | 135 | ||
136 | static struct mu_cfg_param pop3d_cfg_param[] = { | 136 | static struct mu_cfg_param pop3d_cfg_param[] = { |
137 | { "undelete", mu_cfg_int, &undelete_on_startup, NULL, | 137 | { "undelete", mu_cfg_int, &undelete_on_startup, 0, NULL, |
138 | N_("On startup, clear deletion marks from all the messages.") }, | 138 | N_("On startup, clear deletion marks from all the messages.") }, |
139 | { "expire", mu_cfg_uint, &expire, NULL, | 139 | { "expire", mu_cfg_uint, &expire, 0, NULL, |
140 | N_("Automatically expire read messages after the given number of days."), | 140 | N_("Automatically expire read messages after the given number of days."), |
141 | N_("days") }, | 141 | N_("days") }, |
142 | { "delete-expired", mu_cfg_int, &expire_on_exit, NULL, | 142 | { "delete-expired", mu_cfg_int, &expire_on_exit, 0, NULL, |
143 | N_("Delete expired messages upon closing the mailbox.") }, | 143 | N_("Delete expired messages upon closing the mailbox.") }, |
144 | #ifdef WITH_TLS | 144 | #ifdef WITH_TLS |
145 | { "tls-required", mu_cfg_callback, NULL, cb_tls_required, | 145 | { "tls-required", mu_cfg_callback, NULL, 0, cb_tls_required, |
146 | N_("Always require STLS before entering authentication phase.") }, | 146 | N_("Always require STLS before entering authentication phase.") }, |
147 | #endif | 147 | #endif |
148 | #ifdef ENABLE_LOGIN_DELAY | 148 | #ifdef ENABLE_LOGIN_DELAY |
149 | { "login-delay", mu_cfg_time, &login_delay, NULL, | 149 | { "login-delay", mu_cfg_time, &login_delay, 0, NULL, |
150 | N_("Set the minimal allowed delay between two successive logins.") }, | 150 | N_("Set the minimal allowed delay between two successive logins.") }, |
151 | { "stat-file", mu_cfg_string, &login_stat_file, NULL, | 151 | { "stat-file", mu_cfg_string, &login_stat_file, 0, NULL, |
152 | N_("Set the name of login statistics file (for login-delay).") }, | 152 | N_("Set the name of login statistics file (for login-delay).") }, |
153 | #endif | 153 | #endif |
154 | { "bulletin-source", mu_cfg_callback, NULL, cb_bulletin_source, | 154 | { "bulletin-source", mu_cfg_callback, NULL, 0, cb_bulletin_source, |
155 | N_("Get bulletins from the specified mailbox."), | 155 | N_("Get bulletins from the specified mailbox."), |
156 | N_("url") }, | 156 | N_("url") }, |
157 | #ifdef USE_DBM | 157 | #ifdef USE_DBM |
158 | { "bulletin-db", mu_cfg_callback, NULL, cb_bulletin_db, | 158 | { "bulletin-db", mu_cfg_callback, NULL, 0, cb_bulletin_db, |
159 | N_("Set the bulletin database file name."), | 159 | N_("Set the bulletin database file name."), |
160 | N_("file") }, | 160 | N_("file") }, |
161 | #endif | 161 | #endif | ... | ... |
... | @@ -129,21 +129,21 @@ readmsg_parse_opt (int key, char *arg, struct argp_state *astate) | ... | @@ -129,21 +129,21 @@ readmsg_parse_opt (int key, char *arg, struct argp_state *astate) |
129 | 129 | ||
130 | 130 | ||
131 | struct mu_cfg_param readmsg_cfg_param[] = { | 131 | struct mu_cfg_param readmsg_cfg_param[] = { |
132 | { "debug", mu_cfg_int, &dbug, NULL, | 132 | { "debug", mu_cfg_int, &dbug, 0, NULL, |
133 | N_("Set debug verbosity level.") }, | 133 | N_("Set debug verbosity level.") }, |
134 | { "header", mu_cfg_bool, &all_header, NULL, | 134 | { "header", mu_cfg_bool, &all_header, 0, NULL, |
135 | N_("Display entire headers.") }, | 135 | N_("Display entire headers.") }, |
136 | { "weedlist", mu_cfg_string, &weedlist, NULL, | 136 | { "weedlist", mu_cfg_string, &weedlist, 0, NULL, |
137 | N_("Display only headers from this list. Argument is a list of header " | 137 | N_("Display only headers from this list. Argument is a list of header " |
138 | "names separated by whitespace or commas."), | 138 | "names separated by whitespace or commas."), |
139 | N_("list") }, | 139 | N_("list") }, |
140 | { "folder", mu_cfg_string, &mailbox_name, NULL, | 140 | { "folder", mu_cfg_string, &mailbox_name, 0, NULL, |
141 | N_("Read messages from this folder.") }, | 141 | N_("Read messages from this folder.") }, |
142 | { "no-header", mu_cfg_bool, &no_header, NULL, | 142 | { "no-header", mu_cfg_bool, &no_header, 0, NULL, |
143 | N_("Exclude all headers.") }, | 143 | N_("Exclude all headers.") }, |
144 | { "form-feeds", mu_cfg_bool, &form_feed, NULL, | 144 | { "form-feeds", mu_cfg_bool, &form_feed, 0, NULL, |
145 | N_("Output formfeed character between messages.") }, | 145 | N_("Output formfeed character between messages.") }, |
146 | { "show-all-match", mu_cfg_bool, &show_all, NULL, | 146 | { "show-all-match", mu_cfg_bool, &show_all, 0, NULL, |
147 | N_("Print all messages matching pattern, not only the first.") }, | 147 | N_("Print all messages matching pattern, not only the first.") }, |
148 | { NULL } | 148 | { NULL } |
149 | }; | 149 | }; | ... | ... |
... | @@ -287,15 +287,15 @@ cb_ticket (mu_debug_t debug, void *data, char *arg) | ... | @@ -287,15 +287,15 @@ cb_ticket (mu_debug_t debug, void *data, char *arg) |
287 | } | 287 | } |
288 | 288 | ||
289 | static struct mu_cfg_param sieve_cfg_param[] = { | 289 | static struct mu_cfg_param sieve_cfg_param[] = { |
290 | { "keep-going", mu_cfg_int, &keep_going, NULL, | 290 | { "keep-going", mu_cfg_int, &keep_going, 0, NULL, |
291 | N_("Do not abort if execution fails on a message.") }, | 291 | N_("Do not abort if execution fails on a message.") }, |
292 | { "mbox-url", mu_cfg_string, &mbox_url, NULL, | 292 | { "mbox-url", mu_cfg_string, &mbox_url, 0, NULL, |
293 | N_("Mailbox to sieve (defaults to user's mail spool)."), | 293 | N_("Mailbox to sieve (defaults to user's mail spool)."), |
294 | N_("url") }, | 294 | N_("url") }, |
295 | { "ticket", mu_cfg_callback, NULL, cb_ticket, | 295 | { "ticket", mu_cfg_callback, NULL, 0, cb_ticket, |
296 | N_("Ticket file for user authentication."), | 296 | N_("Ticket file for user authentication."), |
297 | N_("ticket") }, | 297 | N_("ticket") }, |
298 | { "debug", mu_cfg_callback, NULL, cb_debug, | 298 | { "debug", mu_cfg_callback, NULL, 0, cb_debug, |
299 | N_("Debug flags. Argument consists of one or more of the following " | 299 | N_("Debug flags. Argument consists of one or more of the following " |
300 | "flags:\n" | 300 | "flags:\n" |
301 | " g - main parser traces\n" | 301 | " g - main parser traces\n" |
... | @@ -303,11 +303,11 @@ static struct mu_cfg_param sieve_cfg_param[] = { | ... | @@ -303,11 +303,11 @@ static struct mu_cfg_param sieve_cfg_param[] = { |
303 | " P - network protocols (MU_DEBUG_PROT)\n" | 303 | " P - network protocols (MU_DEBUG_PROT)\n" |
304 | " t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n" | 304 | " t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n" |
305 | " i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR).") }, | 305 | " i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR).") }, |
306 | { "verbose", mu_cfg_bool, &verbose, NULL, | 306 | { "verbose", mu_cfg_bool, &verbose, 0, NULL, |
307 | N_("Log all executed actions.") }, | 307 | N_("Log all executed actions.") }, |
308 | { "line-info", mu_cfg_bool, &sieve_print_locus, NULL, | 308 | { "line-info", mu_cfg_bool, &sieve_print_locus, 0, NULL, |
309 | N_("Print source locations along with action logs (default).") }, | 309 | N_("Print source locations along with action logs (default).") }, |
310 | { "email", mu_cfg_callback, NULL, cb_email, | 310 | { "email", mu_cfg_callback, NULL, 0, cb_email, |
311 | N_("Set user email address.") }, | 311 | N_("Set user email address.") }, |
312 | { NULL } | 312 | { NULL } |
313 | }; | 313 | }; | ... | ... |
-
Please register or sign in to post a comment