Commit 995a3b8e 995a3b8e157203b84863aeee41a7d4ce103463c8 by Sergey Poznyakoff

from lib/

1 parent 48452ce4
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU 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, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #ifndef MU_ARGP_H
19 #define MU_ARGP_H 1
20
21 #include <mailutils/mailbox.h>
22 #include <argp.h>
23
24 #define MODE_INTERACTIVE 0
25 #define MODE_DAEMON 1
26
27 struct daemon_param {
28 int mode;
29 size_t maxchildren;
30 unsigned int port;
31 unsigned int timeout;
32 };
33
34 #ifdef USE_LIBPAM
35 extern char *pam_service;
36 #endif
37 extern int log_facility;
38 extern int mu_argp_error_code;
39
40 extern void mu_create_argcv __P((const char *capa[],
41 int argc, char **argv,
42 int *p_argc, char ***p_argv));
43 extern error_t mu_argp_parse __P((const struct argp *argp,
44 int *p_argc, char ***p_argv,
45 unsigned flags,
46 const char *capa[],
47 int *arg_index,
48 void *input));
49
50 #endif
51
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU 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, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <getline.h>
23 #include <pwd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.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
34 #ifdef HAVE_STRINGS_H
35 # include <strings.h>
36 #endif
37
38 #include <mailutils/error.h>
39 #include <mailutils/errno.h>
40 #include <mailutils/mutil.h>
41 #include <mailutils/locker.h>
42 #include <mailutils/mu_argp.h>
43
44 #include <argcv.h>
45 #include <mu_asprintf.h>
46
47 #ifdef HAVE_MYSQL
48 # include "../MySql/MySql.h"
49 #endif
50
51 #define ARG_LOG_FACILITY 1
52 #define ARG_SQL_GETPWNAM 2
53 #define ARG_SQL_GETPWUID 3
54 #define ARG_SQL_GETPASS 4
55 #define ARG_SQL_HOST 5
56 #define ARG_SQL_USER 6
57 #define ARG_SQL_PASSWD 7
58 #define ARG_SQL_DB 8
59 #define ARG_SQL_PORT 9
60 #define ARG_PAM_SERVICE 10
61 #define ARG_LOCK_FLAGS 11
62
63 static struct argp_option mu_common_argp_options[] =
64 {
65 { NULL, 0, NULL, 0, "Common options:", 0},
66 { NULL, 0, NULL, 0, NULL, 0 }
67 };
68
69 /* Option to print the license. */
70 static struct argp_option mu_license_argp_option[] = {
71 { "license", 'L', NULL, 0, "Print license and exit", -2 },
72 { NULL, 0, NULL, 0, NULL, 0 }
73 };
74
75 /* Options used by programs that access mailboxes. */
76 static struct argp_option mu_mailbox_argp_option[] = {
77 {"mail-spool", 'm', "URL", 0,
78 "Use specified URL as a mailspool directory", 0},
79 {"lock-flags", ARG_LOCK_FLAGS, "FLAGS", 0,
80 "Default locker flags (E=external, R=retry, T=time, P=pid)", 0},
81 { NULL, 0, NULL, 0, NULL, 0 }
82 };
83
84 /* Options used by programs that do address mapping. */
85 static struct argp_option mu_address_argp_option[] = {
86 {"email-addr", 'E', "EMAIL", 0,
87 "Set current user's email address (default is loginname@defaultdomain)", 0},
88 {"email-domain", 'D', "DOMAIN", 0,
89 "Set domain for unqualified user names (default is this host)", 0},
90 { NULL, 0, NULL, 0, NULL, 0 }
91 };
92
93 /* Options used by programs that log to syslog. */
94 static struct argp_option mu_logging_argp_option[] = {
95 {"log-facility", ARG_LOG_FACILITY, "FACILITY", 0,
96 "Output logs to syslog FACILITY", 0},
97 { NULL, 0, NULL, 0, NULL, 0 }
98 };
99
100 /* Options used by programs that use extended authentication mechanisms. */
101 static struct argp_option mu_auth_argp_option[] = {
102 #ifdef USE_LIBPAM
103 { "pam-service", ARG_PAM_SERVICE, "STRING", 0,
104 "Use STRING as PAM service name", 0},
105 #endif
106 #ifdef HAVE_MYSQL
107 {"sql-getpwnam", ARG_SQL_GETPWNAM, "QUERY", 0,
108 "SQL query to retrieve a passwd entry based on username", 0},
109 {"sql-getpwuid", ARG_SQL_GETPWUID, "QUERY", 0,
110 "SQL query to retrieve a passwd entry based on UID", 0},
111 {"sql-getpass", ARG_SQL_GETPASS, "QUERY", 0,
112 "SQL query to retrieve a password from the database", 0},
113 {"sql-host", ARG_SQL_HOST, "HOSTNAME", 0,
114 "Name or IP of MySQL server to connect to", 0},
115 {"sql-user", ARG_SQL_USER, "NAME", 0,
116 "SQL user name", 0},
117 {"sql-passwd", ARG_SQL_PASSWD, "STRING", 0,
118 "SQL connection password", 0},
119 {"sql-db", ARG_SQL_DB, "STRING", 0,
120 "Name of the database to connect to", 0},
121 {"sql-port", ARG_SQL_PORT, "NUMBER", 0,
122 "Port to use", 0},
123 #endif
124 { NULL, 0, NULL, 0, NULL, 0 }
125 };
126
127 /* Options used by programs that become daemons. */
128 static struct argp_option mu_daemon_argp_option[] = {
129 {"daemon", 'd', "NUMBER", OPTION_ARG_OPTIONAL,
130 "Runs in daemon mode with a maximum of NUMBER children"},
131 {"inetd", 'i', 0, 0,
132 "Run in inetd mode", 0},
133 {"port", 'p', "PORT", 0,
134 "Listen on specified port number", 0},
135 {"timeout", 't', "NUMBER", 0,
136 "Set idle timeout value to NUMBER seconds", 0},
137 { NULL, 0, NULL, 0, NULL, 0 }
138 };
139
140 static error_t mu_common_argp_parser __P((int key, char *arg,
141 struct argp_state *state));
142 static error_t mu_daemon_argp_parser __P((int key, char *arg,
143 struct argp_state *state));
144
145 struct argp mu_common_argp = {
146 mu_common_argp_options,
147 mu_common_argp_parser,
148 };
149
150 struct argp_child mu_common_argp_child = {
151 &mu_common_argp,
152 0,
153 NULL,
154 0,
155 };
156
157 struct argp mu_license_argp = {
158 mu_license_argp_option,
159 mu_common_argp_parser,
160 };
161
162 struct argp_child mu_license_argp_child = {
163 &mu_license_argp,
164 0,
165 NULL,
166 0
167 };
168
169 struct argp mu_mailbox_argp = {
170 mu_mailbox_argp_option,
171 mu_common_argp_parser,
172 };
173
174 struct argp_child mu_mailbox_argp_child = {
175 &mu_mailbox_argp,
176 0,
177 NULL,
178 0
179 };
180
181 struct argp mu_address_argp = {
182 mu_address_argp_option,
183 mu_common_argp_parser,
184 };
185
186 struct argp_child mu_address_argp_child = {
187 &mu_address_argp,
188 0,
189 NULL,
190 0
191 };
192
193 struct argp mu_logging_argp = {
194 mu_logging_argp_option,
195 mu_common_argp_parser,
196 };
197
198 struct argp_child mu_logging_argp_child = {
199 &mu_logging_argp,
200 0,
201 NULL,
202 0
203 };
204
205 struct argp mu_auth_argp = {
206 mu_auth_argp_option,
207 mu_common_argp_parser,
208 };
209
210 struct argp_child mu_auth_argp_child = {
211 &mu_auth_argp,
212 0,
213 "Authentication options",
214 0
215 };
216
217 struct argp mu_daemon_argp = {
218 mu_daemon_argp_option,
219 mu_daemon_argp_parser,
220 };
221
222 struct argp_child mu_daemon_argp_child = {
223 &mu_daemon_argp,
224 0,
225 "Daemon configuration options",
226 0
227 };
228
229 int log_facility = LOG_FACILITY;
230 int mu_argp_error_code = 1;
231
232 static int
233 parse_log_facility (const char *str)
234 {
235 int i;
236 static struct {
237 char *name;
238 int facility;
239 } syslog_kw[] = {
240 { "USER", LOG_USER },
241 { "DAEMON", LOG_DAEMON },
242 { "AUTH", LOG_AUTH },
243 { "LOCAL0", LOG_LOCAL0 },
244 { "LOCAL1", LOG_LOCAL1 },
245 { "LOCAL2", LOG_LOCAL2 },
246 { "LOCAL3", LOG_LOCAL3 },
247 { "LOCAL4", LOG_LOCAL4 },
248 { "LOCAL5", LOG_LOCAL5 },
249 { "LOCAL6", LOG_LOCAL6 },
250 { "LOCAL7", LOG_LOCAL7 },
251 { "MAIL", LOG_MAIL }
252 };
253
254 if (strncmp (str, "LOG_", 4) == 0)
255 str += 4;
256
257 for (i = 0; i < sizeof (syslog_kw) / sizeof (syslog_kw[0]); i++)
258 if (strcasecmp (syslog_kw[i].name, str) == 0)
259 return syslog_kw[i].facility;
260 fprintf (stderr, "unknown facility `%s'\n", str);
261 return LOG_FACILITY;
262 }
263
264 static char license_text[] =
265 " This program is free software; you can redistribute it and/or modify\n"
266 " it under the terms of the GNU General Public License as published by\n"
267 " the Free Software Foundation; either version 2, or (at your option)\n"
268 " any later version.\n"
269 "\n"
270 " This program is distributed in the hope that it will be useful,\n"
271 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
272 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
273 " GNU General Public License for more details.\n"
274 "\n"
275 " You should have received a copy of the GNU General Public License\n"
276 " along with this program; if not, write to the Free Software\n"
277 " Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
278
279 #ifdef HAVE_MYSQL
280 char *sql_getpwnam_query;
281 char *sql_getpass_query;
282 char *sql_getpwuid_query;
283 char *sql_host = MHOST;
284 char *sql_user = MUSER;
285 char *sql_passwd = MPASS;
286 char *sql_db = MDB;
287 char *sql_socket = MSOCKET;
288 int sql_port = MPORT;
289 #endif
290 #ifdef USE_LIBPAM
291 char *pam_service = NULL;
292 #endif
293
294 void
295 mu_argp_fake()
296 {
297 }
298 static error_t
299 mu_common_argp_parser (int key, char *arg, struct argp_state *state)
300 {
301 int err = 0;
302 char *p;
303
304 switch (key)
305 {
306 /* common */
307 case 'L':
308 printf ("License for %s:\n\n", argp_program_version);
309 printf ("%s", license_text);
310 exit (0);
311
312 /* mailbox */
313 case 'm':
314 mu_path_maildir = arg;
315 break;
316
317 case ARG_LOCK_FLAGS:
318 {
319 int flags = 0;
320 for ( ; *arg; arg++)
321 {
322 switch (*arg)
323 {
324 case 'E':
325 flags |= MU_LOCKER_EXTERNAL;
326 break;
327 case 'R':
328 flags |= MU_LOCKER_RETRY;
329 break;
330 case 'T':
331 flags |= MU_LOCKER_TIME;
332 break;
333 case 'P':
334 flags |= MU_LOCKER_PID;
335 break;
336 default:
337 argp_error (state, "invalid lock flag '%c'", *arg);
338 }
339 }
340 locker_set_default_flags(flags);
341 }
342 break;
343
344 /* address */
345 case 'E':
346 if ((err = mu_set_user_email(arg)) != 0)
347 {
348 argp_error (state, "invalid email-addr '%s': %s",
349 arg, mu_errstring(err));
350 }
351 break;
352
353 case 'D':
354 if ((err = mu_set_user_email_domain(arg)) != 0)
355 {
356 argp_error (state, "invalid email-domain '%s': %s",
357 arg, mu_errstring(err));
358 }
359 break;
360
361 /* log */
362 case ARG_LOG_FACILITY:
363 log_facility = parse_log_facility (arg);
364 break;
365
366 /* authentication */
367 #ifdef USE_LIBPAM
368 case ARG_PAM_SERVICE:
369 pam_service = arg;
370 break;
371 #endif
372
373 #ifdef HAVE_MYSQL
374 case ARG_SQL_GETPWNAM:
375 sql_getpwnam_query = arg;
376 break;
377
378 case ARG_SQL_GETPWUID:
379 sql_getpwuid_query = arg;
380 break;
381
382 case ARG_SQL_GETPASS:
383 sql_getpass_query = arg;
384 break;
385
386 case ARG_SQL_HOST:
387 sql_host = arg;
388 break;
389
390 case ARG_SQL_USER:
391 sql_user = arg;
392 break;
393
394 case ARG_SQL_PASSWD:
395 sql_passwd = arg;
396 break;
397
398 case ARG_SQL_DB:
399 sql_db = arg;
400 break;
401
402 case ARG_SQL_PORT:
403 sql_port = strtoul (arg, NULL, 0);
404 if (sql_port == 0)
405 {
406 sql_host = NULL;
407 sql_socket = arg;
408 }
409 break;
410
411 #endif
412 case ARGP_KEY_FINI:
413 p = mu_normalize_maildir (mu_path_maildir);
414 if (!p)
415 {
416 argp_error (state, "badly formed maildir: %s", mu_path_maildir);
417 }
418 mu_path_maildir = p;
419 break;
420
421 default:
422 return ARGP_ERR_UNKNOWN;
423 }
424 return 0;
425 }
426
427 static error_t
428 mu_daemon_argp_parser (int key, char *arg, struct argp_state *state)
429 {
430 struct daemon_param *p = state->input;
431 if (!p)
432 return ARGP_ERR_UNKNOWN;
433 switch (key)
434 {
435 case 'd':
436 p->mode = MODE_DAEMON;
437 if (arg)
438 {
439 size_t n = strtoul (arg, NULL, 10);
440 if (n > 0)
441 p->maxchildren = n;
442 }
443 break;
444
445 case 'i':
446 p->mode = MODE_INTERACTIVE;
447 break;
448
449 case 'p':
450 p->mode = MODE_DAEMON;
451 p->port = strtoul (arg, NULL, 10);
452 break;
453
454 case 't':
455 p->timeout = strtoul (arg, NULL, 10);
456 break;
457
458 default:
459 return ARGP_ERR_UNKNOWN;
460 }
461 return 0;
462 }
463
464 #ifndef MU_CONFIG_FILE
465 # define MU_CONFIG_FILE SYSCONFDIR "/mailutils.rc"
466 #endif
467
468 #ifndef MU_USER_CONFIG_FILE
469 # define MU_USER_CONFIG_FILE "~/.mailutils"
470 #endif
471
472 static int
473 member (const char *array[], const char *text, size_t len)
474 {
475 int i;
476 for (i = 0; array[i]; i++)
477 if (strncmp (array[i], text, len) == 0)
478 return 1;
479 return 0;
480 }
481
482 /*
483 Appends applicable options found in file NAME to argv. If progname
484 is NULL, all the options found are assumed to apply. Otherwise they
485 apply only if the line starts with ":something", and something is
486 found in the CAPA array, or the line starts with PROGNAME.
487 */
488 void
489 read_rc (const char *progname, const char *name, const char *capa[],
490 int *argc, char ***argv)
491 {
492 FILE *fp;
493 char *linebuf = NULL;
494 char *buf = NULL;
495 size_t n = 0;
496 int x_argc = *argc;
497 char **x_argv = *argv;
498 char* rcfile = mu_tilde_expansion (name, "/", NULL);
499
500 if (!rcfile)
501 {
502 fprintf (stderr, "%s: not enough memory\n", progname);
503 exit (1);
504 }
505
506 fp = fopen (rcfile, "r");
507 if (!fp)
508 {
509 free(rcfile);
510 return;
511 }
512
513 while (getline (&buf, &n, fp) > 0)
514 {
515 char *kwp, *p;
516 int len;
517
518 for (kwp = buf; *kwp && isspace (*kwp); kwp++)
519 ;
520
521 if (*kwp == '#' || *kwp == 0)
522 continue;
523
524 len = strlen (kwp);
525 if (kwp[len-1] == '\n')
526 kwp[--len] = 0;
527
528 if (kwp[len-1] == '\\' || linebuf)
529 {
530 int cont;
531
532 if (kwp[len-1] == '\\')
533 {
534 kwp[--len] = 0;
535 cont = 1;
536 }
537 else
538 cont = 0;
539
540 if (!linebuf)
541 linebuf = calloc (len + 1, 1);
542 else
543 linebuf = realloc (linebuf, strlen (linebuf) + len + 1);
544
545 if (!linebuf)
546 {
547 fprintf (stderr, "%s: not enough memory\n", progname);
548 exit (1);
549 }
550
551 strcpy (linebuf + strlen (linebuf), kwp);
552 if (cont)
553 continue;
554 kwp = linebuf;
555 }
556
557 len = 0;
558 if(progname)
559 {
560 for (p = kwp; *p && !isspace (*p); p++)
561 len++;
562 }
563 else
564 p = kwp; /* Use the whole line. */
565
566 if (progname == NULL
567 || (kwp[0] == ':' && member (capa, kwp+1, len-1))
568 || strncmp (progname, kwp, len) == 0
569 )
570 {
571 int i, n_argc = 0;
572 char **n_argv;
573
574 if (argcv_get (p, "", NULL, &n_argc, &n_argv))
575 {
576 argcv_free (n_argc, n_argv);
577 if (linebuf)
578 free (linebuf);
579 linebuf = NULL;
580 continue;
581 }
582 x_argv = realloc (x_argv,
583 (x_argc + n_argc) * sizeof (x_argv[0]));
584 if (!x_argv)
585 {
586 fprintf (stderr, "%s: not enough memory\n", progname);
587 exit (1);
588 }
589
590 for (i = 0; i < n_argc; i++)
591 x_argv[x_argc++] = n_argv[i];
592
593 free (n_argv);
594 if (linebuf)
595 free (linebuf);
596 linebuf = NULL;
597 }
598 }
599 fclose (fp);
600 free(rcfile);
601
602 *argc = x_argc;
603 *argv = x_argv;
604 }
605
606
607 void
608 mu_create_argcv (const char *capa[],
609 int argc, char **argv, int *p_argc, char ***p_argv)
610 {
611 char *progname;
612 int x_argc;
613 char **x_argv;
614 int i;
615 int rcdir = 0;
616
617 progname = strrchr (argv[0], '/');
618 if (progname)
619 progname++;
620 else
621 progname = argv[0];
622
623 x_argv = malloc (sizeof (x_argv[0]));
624 if (!x_argv)
625 {
626 fprintf (stderr, "%s: not enough memory\n", progname);
627 exit (1);
628 }
629
630 /* Add command name */
631 x_argc = 0;
632 x_argv[x_argc] = argv[x_argc];
633 x_argc++;
634
635 /* Add global config file. */
636 read_rc (progname, MU_CONFIG_FILE, capa, &x_argc, &x_argv);
637
638 /* Look for per-user config files in ~/.mailutils/ or in ~/, but
639 not both. This allows mailutils' utilities to have their config
640 files segregated, if necessary. */
641
642 {
643 struct stat s;
644 char* rcdirname = mu_tilde_expansion (MU_USER_CONFIG_FILE, "/", NULL);
645
646 if (!rcdirname)
647 {
648 fprintf (stderr, "%s: not enough memory\n", progname);
649 exit (1);
650 }
651 if(stat(rcdirname, &s) == 0 && S_ISDIR(s.st_mode))
652 rcdir = 1;
653
654 free(rcdirname);
655 }
656
657 /* Add per-user config file. */
658 if(!rcdir)
659 {
660 read_rc (progname, MU_USER_CONFIG_FILE, capa, &x_argc, &x_argv);
661 }
662 else
663 {
664 char* userrc = NULL;
665
666 mu_asprintf(&userrc, "%s/mailutils", MU_USER_CONFIG_FILE);
667
668 if (!userrc)
669 {
670 fprintf (stderr, "%s: not enough memory\n", progname);
671 exit (1);
672 }
673 read_rc (progname, userrc, capa, &x_argc, &x_argv);
674
675 free(userrc);
676 }
677
678 /* Add per-user, per-program config file. */
679 {
680 char* progrc = NULL;
681
682 if(rcdir)
683 mu_asprintf(&progrc, "%s/%src", MU_USER_CONFIG_FILE, progname);
684 else
685 mu_asprintf(&progrc, "~/.mu.%src", progname);
686
687 if (!progrc)
688 {
689 fprintf (stderr, "%s: not enough memory\n", progname);
690 exit (1);
691 }
692
693 read_rc (NULL, progrc, capa, &x_argc, &x_argv);
694 free (progrc);
695 }
696
697 /* Finally, add the command line options */
698 x_argv = realloc (x_argv, (x_argc + argc) * sizeof (x_argv[0]));
699 for (i = 1; i < argc; i++)
700 x_argv[x_argc++] = argv[i];
701
702 x_argv[x_argc] = NULL;
703
704 *p_argc = x_argc;
705 *p_argv = x_argv;
706 }
707
708 struct argp_capa {
709 char *capability;
710 struct argp_child *child;
711 } mu_argp_capa[] = {
712 {"common", &mu_common_argp_child},
713 {"license", &mu_license_argp_child},
714 {"mailbox", &mu_mailbox_argp_child},
715 {"address", &mu_address_argp_child},
716 {"logging", &mu_logging_argp_child},
717 {"auth", &mu_auth_argp_child},
718 {"daemon", &mu_daemon_argp_child},
719 {NULL,}
720 };
721
722 static struct argp_child *
723 find_argp_child (const char *capa)
724 {
725 int i;
726 for (i = 0; mu_argp_capa[i].capability; i++)
727 if (strcmp (mu_argp_capa[i].capability, capa) == 0)
728 return mu_argp_capa[i].child;
729 return NULL;
730 }
731
732 static struct argp *
733 mu_build_argp (const struct argp *template, const char *capa[])
734 {
735 int n;
736 int nchild;
737 struct argp_child *ap;
738 const struct argp_option *opt;
739 struct argp *argp;
740 int group = 0;
741
742 /* Count the capabilities. */
743 for (n = 0; capa && capa[n]; n++)
744 ;
745 if (template->children)
746 for (; template->children[n].argp; n++)
747 ;
748
749 ap = calloc (n + 1, sizeof (*ap));
750 if (!ap)
751 {
752 mu_error ("out of memory");
753 abort ();
754 }
755
756 /* Copy the template's children. */
757 nchild = 0;
758 if (template->children)
759 for (n = 0; template->children[n].argp; n++, nchild++)
760 ap[nchild] = template->children[n];
761
762 /* Find next group number */
763 for (opt = template->options;
764 opt && ((opt->name && opt->key) || opt->doc); opt++)
765 if (opt->group > group)
766 group = opt->group;
767
768 group++;
769
770 /* Append any capabilities to the children or options, as appropriate. */
771 for (n = 0; capa && capa[n]; n++)
772 {
773 struct argp_child *child = find_argp_child (capa[n]);
774 if (!child)
775 {
776 mu_error ("INTERNAL ERROR: requested unknown argp capability %s",
777 capa[n]);
778 abort ();
779 }
780 ap[nchild] = *child;
781 ap[nchild].group = group++;
782 nchild++;
783 }
784 ap[nchild].argp = NULL;
785
786 /* Copy the template, and give it the expanded children. */
787 argp = malloc (sizeof (*argp));
788 if (!argp)
789 {
790 mu_error ("out of memory");
791 abort ();
792 }
793
794 memcpy (argp, template, sizeof (*argp));
795
796 argp->children = ap;
797
798 return argp;
799 }
800
801 error_t
802 mu_argp_parse(const struct argp *argp,
803 int *pargc, char **pargv[],
804 unsigned flags,
805 const char *capa[],
806 int *arg_index,
807 void *input)
808 {
809 error_t ret;
810 const struct argp argpnull = { 0 };
811
812 if(!argp)
813 argp = &argpnull;
814
815 argp = mu_build_argp (argp, capa);
816 mu_create_argcv (capa, *pargc, *pargv, pargc, pargv);
817 ret = argp_parse (argp, *pargc, *pargv, flags, arg_index, input);
818 free ((void*) argp->children);
819 free ((void*) argp);
820 return ret;
821 }
822