Commit 651c2400 651c2400140bf12cb836d5bca2572a1c62b8467e by Sam Roberts

Default per-utility config files are ~/.programrc. If you want to segregate

you mailutils configuration, make ~/.mailutils a directory, and put your
config files in it (same name, minus the leading ".").
Also organized all common options under the heading "Common options",
moved the daemon and auth options before the common options, and implemented
a --lock-flags option.
1 parent 1a5883c5
...@@ -18,23 +18,30 @@ ...@@ -18,23 +18,30 @@
18 #ifdef HAVE_CONFIG_H 18 #ifdef HAVE_CONFIG_H
19 # include <config.h> 19 # include <config.h>
20 #endif 20 #endif
21 #include <stdlib.h> 21
22 #include <getline.h>
23 #include <pwd.h>
22 #include <stdio.h> 24 #include <stdio.h>
25 #include <stdlib.h>
23 #include <string.h> 26 #include <string.h>
24 #include <syslog.h> 27 #include <syslog.h>
28 #include <unistd.h>
29 #include <xalloc.h>
30
31 #include <sys/types.h>
32 #include <sys/stat.h>
33
25 #ifdef HAVE_STRINGS_H 34 #ifdef HAVE_STRINGS_H
26 # include <strings.h> 35 # include <strings.h>
27 #endif 36 #endif
28 #include <sys/types.h> 37
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <pwd.h>
32 #include <xalloc.h>
33 #include <getline.h>
34 #include <mailutils/mutil.h>
35 #include <mailutils/error.h> 38 #include <mailutils/error.h>
39 #include <mailutils/mutil.h>
40 #include <mailutils/locker.h>
41
36 #include <argcv.h> 42 #include <argcv.h>
37 #include <mu_argp.h> 43 #include <mu_argp.h>
44
38 #ifdef HAVE_MYSQL 45 #ifdef HAVE_MYSQL
39 # include "../MySql/MySql.h" 46 # include "../MySql/MySql.h"
40 #endif 47 #endif
...@@ -49,21 +56,37 @@ ...@@ -49,21 +56,37 @@
49 #define ARG_SQL_DB 8 56 #define ARG_SQL_DB 8
50 #define ARG_SQL_PORT 9 57 #define ARG_SQL_PORT 9
51 #define ARG_PAM_SERVICE 10 58 #define ARG_PAM_SERVICE 10
59 #define ARG_LOCK_FLAGS 11
60
61 static struct argp_option mu_common_argp_options[] =
62 {
63 { NULL, 0, NULL, 0, "Common options:", 0},
64 { NULL, 0, NULL, 0, NULL, 0 }
65 };
66
67 /* Option to print the licence. */
68 static struct argp_option mu_licence_argp_option[] = {
69 { "license", 'L', NULL, 0, "Print license and exit", -2 },
70 { NULL, 0, NULL, 0, NULL, 0 }
71 };
52 72
53 static struct argp_option mu_common_argp_option[] = { 73 /* Options used by programs that access mailboxes. */
74 static struct argp_option mu_mailbox_argp_option[] = {
54 {"mail-spool", 'm', "URL", 0, 75 {"mail-spool", 'm', "URL", 0,
55 "use specified URL as a mailspool directory", 0}, 76 "Use specified URL as a mailspool directory", 0},
56 { "license", 'L', NULL, 0, "print license and exit", 0 }, 77 {"lock-flags", ARG_LOCK_FLAGS, "FLAGS", 0,
78 "Default locker flags (E=external, R=retry, T=time, P=pid)", 0},
57 { NULL, 0, NULL, 0, NULL, 0 } 79 { NULL, 0, NULL, 0, NULL, 0 }
58 }; 80 };
59 81
82 /* Options used by programs that log to syslog. */
60 static struct argp_option mu_logging_argp_option[] = { 83 static struct argp_option mu_logging_argp_option[] = {
61 {"log-facility", ARG_LOG_FACILITY, "FACILITY", 0, 84 {"log-facility", ARG_LOG_FACILITY, "FACILITY", 0,
62 "output logs to syslog FACILITY", 0}, 85 "Output logs to syslog FACILITY", 0},
63 { NULL, 0, NULL, 0, NULL, 0 } 86 { NULL, 0, NULL, 0, NULL, 0 }
64 }; 87 };
65 88
66 89 /* Options used by programs that use extended authentication mechanisms. */
67 static struct argp_option mu_auth_argp_option[] = { 90 static struct argp_option mu_auth_argp_option[] = {
68 #ifdef USE_LIBPAM 91 #ifdef USE_LIBPAM
69 { "pam-service", ARG_PAM_SERVICE, "STRING", 0, 92 { "pam-service", ARG_PAM_SERVICE, "STRING", 0,
...@@ -83,22 +106,23 @@ static struct argp_option mu_auth_argp_option[] = { ...@@ -83,22 +106,23 @@ static struct argp_option mu_auth_argp_option[] = {
83 {"sql-passwd", ARG_SQL_PASSWD, "STRING", 0, 106 {"sql-passwd", ARG_SQL_PASSWD, "STRING", 0,
84 "SQL connection password", 0}, 107 "SQL connection password", 0},
85 {"sql-db", ARG_SQL_DB, "STRING", 0, 108 {"sql-db", ARG_SQL_DB, "STRING", 0,
86 "name of the database to connect to", 0}, 109 "Name of the database to connect to", 0},
87 {"sql-port", ARG_SQL_PORT, "NUMBER", 0, 110 {"sql-port", ARG_SQL_PORT, "NUMBER", 0,
88 "port to use", 0}, 111 "Port to use", 0},
89 #endif 112 #endif
90 { NULL, 0, NULL, 0, NULL, 0 } 113 { NULL, 0, NULL, 0, NULL, 0 }
91 }; 114 };
92 115
116 /* Options used by programs that become daemons. */
93 static struct argp_option mu_daemon_argp_option[] = { 117 static struct argp_option mu_daemon_argp_option[] = {
94 {"daemon", 'd', "NUMBER", OPTION_ARG_OPTIONAL, 118 {"daemon", 'd', "NUMBER", OPTION_ARG_OPTIONAL,
95 "runs in daemon mode with a maximum of NUMBER children"}, 119 "Runs in daemon mode with a maximum of NUMBER children"},
96 {"inetd", 'i', 0, 0, 120 {"inetd", 'i', 0, 0,
97 "run in inetd mode", 0}, 121 "Run in inetd mode", 0},
98 {"port", 'p', "PORT", 0, 122 {"port", 'p', "PORT", 0,
99 "listen on specified port number", 0}, 123 "Listen on specified port number", 0},
100 {"timeout", 't', "NUMBER", 0, 124 {"timeout", 't', "NUMBER", 0,
101 "set idle timeout value to NUMBER seconds", 0}, 125 "Set idle timeout value to NUMBER seconds", 0},
102 { NULL, 0, NULL, 0, NULL, 0 } 126 { NULL, 0, NULL, 0, NULL, 0 }
103 }; 127 };
104 128
...@@ -108,71 +132,74 @@ static error_t mu_daemon_argp_parser __P((int key, char *arg, ...@@ -108,71 +132,74 @@ static error_t mu_daemon_argp_parser __P((int key, char *arg,
108 struct argp_state *state)); 132 struct argp_state *state));
109 133
110 struct argp mu_common_argp = { 134 struct argp mu_common_argp = {
111 mu_common_argp_option, 135 mu_common_argp_options,
112 mu_common_argp_parser, 136 mu_common_argp_parser,
113 "",
114 "",
115 NULL,
116 NULL,
117 NULL
118 }; 137 };
119 138
120 struct argp_child mu_common_argp_child = { 139 struct argp_child mu_common_argp_child = {
121 &mu_common_argp, 140 &mu_common_argp,
122 0, 141 0,
123 "Common mailutils options", 142 "",
124 1 143 -10,
125 }; 144 };
126 145
127 struct argp mu_auth_argp = { 146 struct argp mu_licence_argp = {
128 mu_auth_argp_option, 147 mu_licence_argp_option,
129 mu_common_argp_parser, 148 mu_common_argp_parser,
149 };
150
151 struct argp_child mu_licence_argp_child = {
152 &mu_licence_argp,
153 0,
130 "", 154 "",
131 "", 155 -2
132 NULL,
133 NULL,
134 NULL
135 }; 156 };
136 157
137 struct argp_child mu_auth_argp_child = { 158 struct argp mu_mailbox_argp = {
138 &mu_auth_argp, 159 mu_mailbox_argp_option,
160 mu_common_argp_parser,
161 };
162
163 struct argp_child mu_mailbox_argp_child = {
164 &mu_mailbox_argp,
139 0, 165 0,
140 "Authentication-relevant options", 166 "",
141 1 167 -3
142 }; 168 };
143 169
144 struct argp mu_logging_argp = { 170 struct argp mu_logging_argp = {
145 mu_logging_argp_option, 171 mu_logging_argp_option,
146 mu_common_argp_parser, 172 mu_common_argp_parser,
147 "",
148 "",
149 NULL,
150 NULL,
151 NULL
152 }; 173 };
153 174
154 struct argp_child mu_logging_argp_child = { 175 struct argp_child mu_logging_argp_child = {
155 &mu_logging_argp, 176 &mu_logging_argp,
156 0, 177 0,
157 "Logging options", 178 "",
158 1 179 -3
180 };
181
182 struct argp mu_auth_argp = {
183 mu_auth_argp_option,
184 mu_common_argp_parser,
185 };
186
187 struct argp_child mu_auth_argp_child = {
188 &mu_auth_argp,
189 0,
190 "Authentication options",
159 }; 191 };
160 192
161 struct argp mu_daemon_argp = { 193 struct argp mu_daemon_argp = {
162 mu_daemon_argp_option, 194 mu_daemon_argp_option,
163 mu_daemon_argp_parser, 195 mu_daemon_argp_parser,
164 "",
165 "",
166 NULL,
167 NULL,
168 NULL
169 }; 196 };
170 197
171 struct argp_child mu_daemon_argp_child = { 198 struct argp_child mu_daemon_argp_child = {
172 &mu_daemon_argp, 199 &mu_daemon_argp,
173 0, 200 0,
174 "Daemon configuration options", 201 "Daemon configuration options",
175 1 202 0
176 }; 203 };
177 204
178 int log_facility = LOG_FACILITY; 205 int log_facility = LOG_FACILITY;
...@@ -247,18 +274,50 @@ mu_common_argp_parser (int key, char *arg, struct argp_state *state) ...@@ -247,18 +274,50 @@ mu_common_argp_parser (int key, char *arg, struct argp_state *state)
247 274
248 switch (key) 275 switch (key)
249 { 276 {
277 /* common */
278 case 'L':
279 printf ("Licence for %s:\n\n", argp_program_version);
280 printf ("%s", license_text);
281 exit (0);
282
283 /* mailbox */
250 case 'm': 284 case 'm':
251 mu_path_maildir = arg; 285 mu_path_maildir = arg;
252 break; 286 break;
253 287
254 case 'L': 288 case ARG_LOCK_FLAGS:
255 printf ("%s", license_text); 289 {
256 exit (0); 290 int flags = 0;
291 for ( ; *arg; arg++)
292 {
293 switch (*arg)
294 {
295 case 'E':
296 flags |= MU_LOCKER_EXTERNAL;
297 break;
298 case 'R':
299 flags |= MU_LOCKER_RETRY;
300 break;
301 case 'T':
302 flags |= MU_LOCKER_TIME;
303 break;
304 case 'P':
305 flags |= MU_LOCKER_PID;
306 break;
307 default:
308 argp_error (state, "invalid lock flag '%c'", *arg);
309 }
310 }
311 locker_set_default_flags(flags);
312 }
313 break;
257 314
315 /* log */
258 case ARG_LOG_FACILITY: 316 case ARG_LOG_FACILITY:
259 log_facility = parse_log_facility (arg); 317 log_facility = parse_log_facility (arg);
260 break; 318 break;
261 319
320 /* authentication */
262 #ifdef USE_LIBPAM 321 #ifdef USE_LIBPAM
263 case ARG_PAM_SERVICE: 322 case ARG_PAM_SERVICE:
264 pam_service = arg; 323 pam_service = arg;
...@@ -308,8 +367,7 @@ mu_common_argp_parser (int key, char *arg, struct argp_state *state) ...@@ -308,8 +367,7 @@ mu_common_argp_parser (int key, char *arg, struct argp_state *state)
308 p = mu_normalize_maildir (mu_path_maildir); 367 p = mu_normalize_maildir (mu_path_maildir);
309 if (!p) 368 if (!p)
310 { 369 {
311 mu_error ("Badly formed maildir: %s", mu_path_maildir); 370 argp_error (state, "badly formed maildir: %s", mu_path_maildir);
312 exit (mu_argp_error_code);
313 } 371 }
314 mu_path_maildir = p; 372 mu_path_maildir = p;
315 break; 373 break;
...@@ -508,6 +566,7 @@ mu_create_argcv (const char *capa[], ...@@ -508,6 +566,7 @@ mu_create_argcv (const char *capa[],
508 int x_argc; 566 int x_argc;
509 char **x_argv; 567 char **x_argv;
510 int i; 568 int i;
569 int rcdir = 0;
511 570
512 progname = strrchr (argv[0], '/'); 571 progname = strrchr (argv[0], '/');
513 if (progname) 572 if (progname)
...@@ -530,20 +589,61 @@ mu_create_argcv (const char *capa[], ...@@ -530,20 +589,61 @@ mu_create_argcv (const char *capa[],
530 /* Add global config file. */ 589 /* Add global config file. */
531 read_rc (progname, MU_CONFIG_FILE, capa, &x_argc, &x_argv); 590 read_rc (progname, MU_CONFIG_FILE, capa, &x_argc, &x_argv);
532 591
592 /* Look for per-user config files in ~/.mailutils/ or in ~/, but
593 not both. This allows mailutils' utilities to have their config
594 files segregated, if necessary. */
595
596 {
597 struct stat s;
598 char* rcdirname = mu_tilde_expansion (MU_USER_CONFIG_FILE, "/", NULL);
599
600 if (!rcdirname)
601 {
602 fprintf (stderr, "%s: not enough memory\n", progname);
603 exit (1);
604 }
605 if(stat(rcdirname, &s) == 0 && S_ISDIR(s.st_mode))
606 rcdir = 1;
607
608 free(rcdirname);
609 }
610
533 /* Add per-user config file. */ 611 /* Add per-user config file. */
612 if(!rcdir)
613 {
534 read_rc (progname, MU_USER_CONFIG_FILE, capa, &x_argc, &x_argv); 614 read_rc (progname, MU_USER_CONFIG_FILE, capa, &x_argc, &x_argv);
615 }
616 else
617 {
618 char* userrc = NULL;
535 619
536 /* Add per-program (and per-user) config file. */ 620 asprintf(&userrc, "%s/mailutils", MU_USER_CONFIG_FILE);
621
622 if (!userrc)
537 { 623 {
538 char* progrc = malloc (strlen (progname) 624 fprintf (stderr, "%s: not enough memory\n", progname);
539 + 6 /* ~/.mu. */ 625 exit (1);
540 + 3 /* rc */ + 1); 626 }
627 read_rc (progname, userrc, capa, &x_argc, &x_argv);
628
629 free(userrc);
630 }
631
632 /* Add per-user, per-program config file. */
633 {
634 char* progrc = NULL;
635
636 if(rcdir)
637 asprintf(&progrc, "%s/%src", MU_USER_CONFIG_FILE, progname);
638 else
639 asprintf(&progrc, "~/.%src", progname);
640
541 if (!progrc) 641 if (!progrc)
542 { 642 {
543 fprintf (stderr, "%s: not enough memory\n", progname); 643 fprintf (stderr, "%s: not enough memory\n", progname);
544 exit (1); 644 exit (1);
545 } 645 }
546 sprintf (progrc, "~/.mu.%src", progname); 646
547 read_rc (NULL, progrc, capa, &x_argc, &x_argv); 647 read_rc (NULL, progrc, capa, &x_argc, &x_argv);
548 free (progrc); 648 free (progrc);
549 } 649 }
...@@ -563,10 +663,12 @@ struct argp_capa { ...@@ -563,10 +663,12 @@ struct argp_capa {
563 char *capability; 663 char *capability;
564 struct argp_child *child; 664 struct argp_child *child;
565 } mu_argp_capa[] = { 665 } mu_argp_capa[] = {
566 {"mailutils", &mu_common_argp_child}, 666 {"common", &mu_common_argp_child},
567 {"daemon", &mu_daemon_argp_child}, 667 {"licence", &mu_licence_argp_child},
568 {"auth", &mu_auth_argp_child}, 668 {"mailbox", &mu_mailbox_argp_child},
569 {"logging", &mu_logging_argp_child}, 669 {"logging", &mu_logging_argp_child},
670 {"auth", &mu_auth_argp_child},
671 {"daemon", &mu_daemon_argp_child},
570 {NULL,} 672 {NULL,}
571 }; 673 };
572 674
...@@ -584,10 +686,12 @@ static struct argp * ...@@ -584,10 +686,12 @@ static struct argp *
584 mu_build_argp (const struct argp *template, const char *capa[]) 686 mu_build_argp (const struct argp *template, const char *capa[])
585 { 687 {
586 int n; 688 int n;
689 int nchild;
587 struct argp_child *ap; 690 struct argp_child *ap;
588 struct argp *argp; 691 struct argp *argp;
692 int group = -100;
589 693
590 /* Count the capabilities */ 694 /* Count the capabilities. */
591 for (n = 0; capa && capa[n]; n++) 695 for (n = 0; capa && capa[n]; n++)
592 ; 696 ;
593 if (template->children) 697 if (template->children)
...@@ -601,32 +705,42 @@ mu_build_argp (const struct argp *template, const char *capa[]) ...@@ -601,32 +705,42 @@ mu_build_argp (const struct argp *template, const char *capa[])
601 abort (); 705 abort ();
602 } 706 }
603 707
604 n = 0; 708 /* Copy the template's children. */
709 nchild = 0;
605 if (template->children) 710 if (template->children)
606 for (; template->children[n].argp; n++) 711 for (n = 0; template->children[n].argp; n++, nchild++)
607 ap[n] = template->children[n]; 712 ap[nchild] = template->children[n];
713
714 group = -nchild - 1;
608 715
609 for (; capa && capa[n]; n++) 716 /* Append any capabilities to the children or options, as appropriate. */
717 for (n = 0; capa && capa[n]; n++)
610 { 718 {
611 struct argp_child *tmp = find_argp_child (capa[n]); 719 struct argp_child *child = find_argp_child (capa[n]);
612 if (!tmp) 720 if (!child)
613 { 721 {
614 mu_error ("INTERNAL ERROR: requested unknown argp capability %s", 722 mu_error ("INTERNAL ERROR: requested unknown argp capability %s",
615 capa[n]); 723 capa[n]);
616 abort (); 724 abort ();
617 } 725 }
618 ap[n] = *tmp; 726 ap[nchild] = *child;
619 ap[n].group = n; 727 // ap[nchild].group = group++;
728 nchild++;
620 } 729 }
621 ap[n].argp = NULL; 730 ap[nchild].argp = NULL;
731
732 /* Copy the template, and give it the expanded children. */
622 argp = malloc (sizeof (*argp)); 733 argp = malloc (sizeof (*argp));
623 if (!argp) 734 if (!argp)
624 { 735 {
625 mu_error ("out of memory"); 736 mu_error ("out of memory");
626 abort (); 737 abort ();
627 } 738 }
739
628 memcpy (argp, template, sizeof (*argp)); 740 memcpy (argp, template, sizeof (*argp));
741
629 argp->children = ap; 742 argp->children = ap;
743
630 return argp; 744 return argp;
631 } 745 }
632 746
......