* clear out some warnings by gcc 9.3.1.
[alpine.git] / alpine / arg.c
blob8e00a21008935bfda984c9323c5037a7cc3ae908
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: arg.c 900 2008-01-05 01:13:26Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2013-2020 Eduardo Chappa
8 * Copyright 2006-2008 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 /*======================================================================
20 Command line argument parsing functions
22 ====*/
24 #include "headers.h"
26 #include "../pith/state.h"
27 #include "../pith/init.h"
28 #include "../pith/conf.h"
29 #include "../pith/list.h"
30 #include "../pith/util.h"
31 #include "../pith/help.h"
33 #include "imap.h"
35 #include "arg.h"
36 #include "xoauth2conf.h"
38 int process_debug_str(char *);
39 void args_add_attach(PATMT **, char *, int);
40 int pinerc_cmdline_opt(char *);
41 void display_config_options(char *, char *);
43 extern char configoptions[];
46 * Name started as to invoke function key mode
48 #define ALPINE_FKEY_NAME "alpinef"
51 * Various error and informational strings..
53 /* TRANSLATORS: This is a list of errors printed when something goes wrong
54 early on with the argument list. Be careful not to change literal
55 option names mentioned in the strings. */
56 static char args_err_missing_pinerc[] = N_("missing argument for option \"-pinerc\" (use - for standard out)");
57 #if defined(DOS) || defined(OS2)
58 static char args_err_missing_aux[] = N_("missing argument for option \"-aux\"");
59 #endif
60 #ifdef SMIME
61 static char args_err_missing_smimedir[] = N_("missing argument for option \"-smimedir\"");
62 static char args_err_non_abs_smimedir[] = N_("argument to \"-smimedir\" should be fully-qualified");
63 #endif /* SMIME */
64 #ifdef PASSFILE
65 static char args_err_missing_passfile[] = N_("missing argument for option \"-passfile\"");
66 static char args_err_non_abs_passfile[] = N_("argument to \"-passfile\" should be fully-qualified");
67 #ifdef SMIME
68 static char args_err_missing_pwdcertdir[] = N_("missing argument for option \"-pwdcertdir\"");
69 static char args_err_non_abs_pwdcertdir[] = N_("argument to \"-pwdcertdir\" should be fully-qualified");
70 #endif /* SMIME inside PASSFILE */
71 #endif
72 static char args_err_missing_sort[] = N_("missing argument for option \"-sort\"");
73 static char args_err_missing_flag_arg[] = N_("missing argument for flag \"%c\"");
74 static char args_err_missing_flag_num[] = N_("Non numeric argument for flag \"%c\"");
75 static char args_err_missing_debug_num[] = N_("Non numeric argument for \"%s\"");
76 static char args_err_missing_url[] = N_("missing URL for \"-url\"");
77 static char args_err_missing_attachment[] = N_("missing attachment for \"%s\"");
78 static char args_err_conflict[] = N_("conflicting action: \"%s\"");
79 static char args_err_unknown[] = N_("unknown flag \"%c\"");
80 static char args_err_I_error[] = N_("-I argument \"%s\": %s");
81 static char args_err_d_error[] = N_("-d argument \"%s\": %s");
82 static char args_err_internal[] = "%s";
83 static char args_err_missing_copyprc[] = N_("missing argument for option \"-copy_pinerc\"\nUsage: pine -copy_pinerc <local_pinerc> <remote_pinerc>");
84 static char args_err_missing_copyabook[] = N_("missing argument for option \"-copy_abook\"\nUsage: pine -copy_abook <local_abook> <remote_abook>");
85 static char args_err_missing_server_name[] = N_("missing server name. Example: -xoauth2-server Gmail");
86 static char args_err_missing_client_id[] = N_("missing client-id name. Example: -xoauth2-client-id 760.someserver.com");
87 static char args_err_missing_client_secret[] = N_("missing client-secret name. Example: -xoauth2-client-secret V56i0fa_");
88 static char args_err_missing_tenant[] = N_("missing tenant value. Example: -xoauth2-tenant common");
89 static char args_err_missing_user[] = N_("missing username value. Example: -xoauth2-user user@example.com");
90 static char args_err_missing_xoauth_option[] = N_("at least one of the arguments -xoauth2-server, or -xoauth2-client-id, xoauth2-tenant, or -xoauth2-client-secret is missing.");
92 static char *args_pine_args[] = {
93 N_("Possible Starting Arguments for Alpine program:"),
94 "",
95 N_(" Argument\tMeaning"),
96 N_(" <addrs>...\tGo directly into composer sending to given address"),
97 N_("\t\tList multiple addresses with a single space between them."),
98 N_("\t\tStandard input redirection is allowed with addresses."),
99 N_("\t\tNote: Places addresses in the \"To\" field only."),
100 N_(" -attach <file>\tGo directly into composer with given file"),
101 N_(" -attachlist <file-list>"),
102 N_(" -attach_and_delete <file>"),
103 N_("\t\tGo to composer, attach file, delete when finished"),
104 N_("\t\tNote: Attach options can't be used if -f, -F"),
105 N_("\t\tadded to Attachment list. Attachlist must be the last"),
106 N_("\t\toption on the command line"),
107 N_(" -bail\t\tExit if pinerc file doesn't already exist"),
108 #ifdef DEBUG
109 N_(" -d n\t\tDebug - set debug level to 'n', or use the following:"),
110 N_(" -d keywords...\tflush,timestamp,imap=0..4,tcp,numfiles=0..31,verbose=0..9"),
111 #endif
112 N_(" -f <folder>\tFolder - give folder name to open"),
113 N_(" -c <number>\tContext - which context to apply to -f arg"),
114 N_(" -F <file>\tFile - give file name to open and page through and"),
115 N_("\t\tforward as email."),
116 N_(" -h \t\tHelp - give this list of options"),
117 N_(" -k \t\tKeys - Force use of function keys"),
118 N_(" -z \t\tSuspend - allow use of ^Z suspension"),
119 N_(" -r \t\tRestricted - can only send mail to oneself"),
120 N_(" -sort <sort>\tSort - Specify sort order of folder:"),
121 N_("\t\t\tarrival, subject, threaded, orderedsubject, date,"),
122 N_("\t\t\tfrom, size, score, to, cc, /reverse"),
123 N_(" -i\t\tIndex - Go directly to index, bypassing main menu"),
124 N_(" -I <keystroke_list> Initial keystrokes to be executed"),
125 N_(" -n <number>\tEntry in index to begin on"),
126 N_(" -o \t\tReadOnly - Open first folder read-only"),
127 N_(" -conf\t\tConfiguration - Print out fresh global configuration. The"),
128 N_("\t\tvalues of your global configuration affect all Alpine users"),
129 N_("\t\ton your system unless they have overridden the values in their"),
130 N_("\t\tpinerc files."),
131 N_(" -pinerc <file>\tConfiguration - Put fresh pinerc configuration in <file>"),
132 N_(" -p <pinerc>\tUse alternate .pinerc file"),
133 #if !defined(DOS) && !defined(OS2)
134 N_(" -P <pine.conf>\tUse alternate pine.conf file"),
135 #else
136 N_(" -aux <aux_files_dir>\tUse this with remote pinerc"),
137 N_(" -P <pine.conf>\tUse pine.conf file for default settings"),
138 N_(" -nosplash \tDisable the PC-Alpine splash screen"),
139 #endif
141 #if defined(APPLEKEYCHAIN) || (WINCRED > 0)
142 N_(" -erase_stored_passwords\tEliminate any stored passwords"),
143 #endif
145 #ifdef SMIME
146 N_(" -smimedir <fully_qualified_path>\tdirectory where smime personal certificates are saved"),
147 #endif /* SMIME */
149 #ifdef PASSFILE
150 N_(" -passfile <fully_qualified_filename>\tSet the password file to something other"),
151 N_("\t\tthan the default"),
152 #ifdef SMIME
153 N_(" -pwdcertdir <fully_qualified_path>\tSet the directory to store a personal"),
154 N_("\t\tkey and certificate to encrypt and decrypt your password file."),
155 #endif /* SMIME inside PASSFILE */
156 #endif /* PASSFILE */
158 #ifdef LOCAL_PASSWD_CACHE
159 N_(" -nowrite_password_cache\tRead from a password cache if there is one, but"),
160 N_("\t\t\t\tnever offer to write a password to the cache"),
161 #endif /* LOCAL_PASSWD_CACHE */
163 N_(" -x <config>\tUse configuration exceptions in <config>."),
164 N_("\t\tExceptions are used to override your default pinerc"),
165 N_("\t\tsettings for a particular platform, can be a local file or"),
166 N_("\t\ta remote folder."),
167 N_(" -v \t\tVersion - show version information"),
168 N_(" -version\tVersion - show version information"),
169 N_(" -supported\tList supported options"),
170 N_(" -url <url>\tOpen the given URL"),
171 N_("\t\tNote: Can't be used if -f, -F"),
172 N_("\t\tStandard input redirection is not allowed with URLs."),
173 N_("\t\tFor mailto URLs, 'body='text should be used in place of"),
174 N_("\t\tinput redirection."),
175 N_(" -copy_pinerc <local_pinerc> <remote_pinerc> copy local pinerc to remote"),
176 N_(" -copy_abook <local_abook> <remote_abook> copy local addressbook to remote"),
177 N_(" -convert_sigs -p <pinerc> convert signatures to literal signatures"),
178 #if defined(_WINDOWS)
179 N_(" -install \tPrompt for some basic setup information"),
180 N_(" -uninstall \tRemove traces of Alpine from Windows system settings"),
181 N_(" -registry <cmd>\tWhere cmd is set,noset,clear,clearsilent,dump"),
182 #endif
183 N_(" -xoauth2-server <value>"),
184 N_(" -xoauth2-client-id <value>"),
185 N_(" -xoauth2-client-secret <value>"),
186 N_("\tNote: All of -xoauth options above must be used, if any of them is used"),
187 " -<option>=<value> Assign <value> to the pinerc option <option>",
188 "\t\t e.g. -signature-file=sig1",
189 "\t\t e.g. -color-style=no-color",
190 "\t\t e.g. -feature-list=enable-sigdashes",
191 "\t\t Note: feature-list is additive.",
192 "\t\t You may leave off the \"feature-list=\" part of that,",
193 "\t\t e.g. -enable-sigdashes",
194 NULL
197 void
198 display_config_options(char *configopts, char *defprefix)
200 char *copts = configopts ? cpystr(configopts) : NULL;
201 char **options = NULL;
202 char *s, *t, *prefix;
203 int len, nlines, pending;
205 for(nlines = 0, s = copts; s != NULL; nlines++){
206 s = strchr(s, '\'');
207 if(s != NULL) s++;
209 options = fs_get((nlines/2 + 4)*sizeof(char *)); /* 4 in worst case scenario */
210 memset((void *) options, 0, (nlines/2 + 4)*sizeof(char *));
211 for(s = copts, len = 0, nlines = 0; s != NULL; ){
212 pending = 0;
213 prefix = len == 0 ? (nlines == 0 ? defprefix : " ") : " ";
214 if((s = strchr(s, '\'')) != NULL){
215 t = strchr(s+1, '\'');
216 *t = '\0';
217 if(!strncmp(s+1, "CFLAGS=", 7)
218 || !strncmp(s+1, "CC=", 3)
219 || !strncmp(s+1, "LIBS=", 5)
220 || !strncmp(s+1, "CPP=", 4)
221 || !strncmp(s+1, "CPPFLAGS=", 9)
222 || !strncmp(s+1, "LT_SYS_LIBRARY_PATH=", 20)
223 || !strncmp(s+1, "LDFLAGS=", 8)){
224 display_args_err(s+1, NULL, 0);
225 *t++ = '\'';
226 s = t;
227 continue;
229 if(len + strlen(prefix) + strlen(s+1) > 74 ){
230 if(len == 0){
231 options[nlines] = fs_get((strlen(prefix) + strlen(s+1) + 3)*sizeof(char));
232 sprintf(options[nlines++], "%s%s \\", prefix, s+1);
234 else{
235 strcat(options[nlines++], " \\");
236 pending++;
238 len = 0;
240 else{
241 if(len == 0){
242 options[nlines] = fs_get(76*sizeof(char));
243 *options[nlines] = '\0';
245 strcat(options[nlines], prefix);
246 strcat(options[nlines], s+1);
247 len = strlen(options[nlines]);
249 if(t != NULL)
250 *t = '\'';
251 if(!pending)
252 s = t ? t + 1 : NULL;
255 display_args_err(NULL, options, 0);
256 free_list_array(&options);
257 fs_give((void **) &copts);
261 * Parse the command line args.
263 * Args: pine_state -- The pine_state structure to put results in
264 * argc, argv -- The obvious
265 * addrs -- Pointer to address list that we set for caller
267 * Result: command arguments parsed
268 * possible printing of help for command line
269 * various flags in pine_state set
270 * returns the string name of the first folder to open
271 * addrs is set
273 void
274 pine_args(struct pine *pine_state, int argc, char **argv, ARGDATA_S *args)
276 register int ac;
277 register char **av;
278 int c;
279 char *str;
280 char *cmd_list = NULL;
281 char *debug_str = NULL;
282 char *sort = NULL;
283 char *pinerc_file = NULL;
284 char *lc = NULL;
285 XOAUTH2_INFO_S x;
286 int do_help = 0;
287 int do_conf = 0;
288 int usage = 0;
289 int do_use_fk = 0;
290 int do_can_suspend = 0;
291 int do_version = 0;
292 struct variable *vars = pine_state->vars;
294 ac = argc;
295 av = argv;
296 memset(args, 0, sizeof(ARGDATA_S));
297 args->action = aaFolder;
298 memset((void *) &x, 0, sizeof(XOAUTH2_INFO_S));
300 pine_state->pine_name = (lc = last_cmpnt(argv[0])) ? lc : (lc = argv[0]);
301 #ifdef DOS
302 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%.*s", pine_state->pine_name - argv[0], argv[0]);
303 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
304 pine_state->pine_dir = cpystr(tmp_20k_buf);
305 #endif
307 /* while more arguments with leading - */
308 Loop: while(--ac > 0)
309 if(**++av == '-'){
310 /* while more chars in this argument */
311 while(*++*av){
312 /* check for pinerc options */
313 if(pinerc_cmdline_opt(*av)){
314 goto Loop; /* done with this arg, go to next */
316 /* then other multi-char options */
317 else if(strcmp(*av, "conf") == 0){
318 do_conf = 1;
319 goto Loop; /* done with this arg, go to next */
321 else if(strcmp(*av, "pinerc") == 0){
322 if(--ac)
323 pinerc_file = *++av;
324 else{
325 display_args_err(_(args_err_missing_pinerc), NULL, 1);
326 ++usage;
329 goto Loop;
331 #if defined(DOS) || defined(OS2)
332 else if(strcmp(*av, "aux") == 0){
333 if(--ac){
334 if((str = *++av) != NULL)
335 pine_state->aux_files_dir = cpystr(str);
337 else{
338 display_args_err(_(args_err_missing_aux), NULL, 1);
339 ++usage;
342 goto Loop;
344 else if(strcmp(*av, "nosplash") == 0)
345 goto Loop; /* already taken care of in WinMain */
346 #endif
348 #if defined(APPLEKEYCHAIN) || (WINCRED > 0)
349 else if(strcmp(*av, "erase_stored_passwords") == 0){
350 #if (WINCRED > 0)
351 erase_windows_credentials();
352 #else
353 macos_erase_keychain();
354 #endif
355 goto Loop;
357 #endif /* defined(APPLEKEYCHAIN) || (WINCRED > 0) */
359 #ifdef SMIME
360 else if(strcmp(*av, "smimedir") == 0){
361 if(--ac){
362 if((str = *++av) != NULL){
363 if(!is_absolute_path(str)){
364 display_args_err(_(args_err_non_abs_smimedir),
365 NULL, 1);
366 ++usage;
368 else{
369 if(pine_state->smimedir)
370 fs_give((void **)&pine_state->smimedir);
372 pine_state->smimedir = cpystr(str);
376 else{
377 display_args_err(_(args_err_missing_smimedir), NULL, 1);
378 ++usage;
381 goto Loop;
383 #endif /* SMIME */
384 #ifdef PASSFILE
385 else if(strcmp(*av, "passfile") == 0){
386 if(--ac){
387 if((str = *++av) != NULL){
388 if(!is_absolute_path(str)){
389 display_args_err(_(args_err_non_abs_passfile),
390 NULL, 1);
391 ++usage;
393 else{
394 if(pine_state->passfile)
395 fs_give((void **)&pine_state->passfile);
397 pine_state->passfile = cpystr(str);
401 else{
402 display_args_err(_(args_err_missing_passfile), NULL, 1);
403 ++usage;
406 goto Loop;
408 #ifdef SMIME
409 else if(strcmp(*av, "pwdcertdir") == 0){
410 if(--ac){
411 if((str = *++av) != NULL){
412 if(!is_absolute_path(str)){
413 display_args_err(_(args_err_non_abs_pwdcertdir),
414 NULL, 1);
415 ++usage;
417 else{
418 if(pine_state->pwdcertdir)
419 fs_give((void **)&pine_state->pwdcertdir);
421 pine_state->pwdcertdir = cpystr(str);
425 else{
426 display_args_err(_(args_err_missing_pwdcertdir), NULL, 1);
427 ++usage;
430 goto Loop;
432 #endif /* SMIME inside PASSFILE */
433 #endif /* PASSFILE */
435 #ifdef LOCAL_PASSWD_CACHE
436 else if(strcmp(*av, "nowrite_password_cache") == 0){
437 ps_global->nowrite_password_cache = 1;
438 goto Loop;
440 #endif /* LOCAL_PASSWD_CACHE */
442 else if(strcmp(*av, "convert_sigs") == 0){
443 ps_global->convert_sigs = 1;
444 goto Loop;
446 else if(strcmp(*av, "supported") == 0){
447 ps_global->dump_supported_options = 1;
448 goto Loop;
450 else if(strcmp(*av, "copy_pinerc") == 0){
451 if(args->action == aaFolder && !args->data.folder){
452 args->action = aaPrcCopy;
453 if(ac > 2){
454 ac -= 2;
455 args->data.copy.local = *++av;
456 args->data.copy.remote = *++av;
458 else{
459 display_args_err(_(args_err_missing_copyprc), NULL, 1);
460 ++usage;
463 else{
464 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-copy_pinerc");
465 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
466 display_args_err(tmp_20k_buf, NULL, 1);
467 ++usage;
470 goto Loop;
472 else if(strcmp(*av, "copy_abook") == 0){
473 if(args->action == aaFolder && !args->data.folder){
474 args->action = aaAbookCopy;
475 if(ac > 2){
476 ac -= 2;
477 args->data.copy.local = *++av;
478 args->data.copy.remote = *++av;
480 else{
481 display_args_err(_(args_err_missing_copyabook), NULL, 1);
482 ++usage;
485 else{
486 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-copy_abook");
487 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
488 display_args_err(tmp_20k_buf, NULL, 1);
489 ++usage;
492 goto Loop;
494 else if(strcmp(*av, "sort") == 0){
495 if(--ac){
496 sort = *++av;
497 COM_SORT_KEY = cpystr(sort);
499 else{
500 display_args_err(_(args_err_missing_sort), NULL, 1);
501 ++usage;
504 goto Loop;
506 else if(strcmp(*av, "url") == 0){
507 if(args->action == aaFolder && !args->data.folder){
508 args->action = aaURL;
509 if(--ac){
510 args->url = cpystr(*++av);
512 else{
513 display_args_err(_(args_err_missing_url), NULL, 1);
514 ++usage;
517 else{
518 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-url");
519 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
520 display_args_err(tmp_20k_buf, NULL, 1);
521 ++usage;
524 goto Loop;
526 else if(strcmp(*av, "attach") == 0){
527 if((args->action == aaFolder && !args->data.folder)
528 || args->action == aaMail
529 || args->action == aaURL){
530 if(args->action != aaURL)
531 args->action = aaMail;
532 if(--ac){
533 args_add_attach(&args->data.mail.attachlist,
534 *++av, FALSE);
536 else{
537 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attach");
538 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
539 display_args_err(tmp_20k_buf, NULL, 1);
540 ++usage;
543 else{
544 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attach");
545 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
546 display_args_err(tmp_20k_buf, NULL, 1);
547 ++usage;
550 goto Loop;
552 else if(strcmp(*av, "attachlist") == 0){
553 if((args->action == aaFolder && !args->data.folder)
554 || args->action == aaMail
555 || args->action == aaURL){
556 if(args->action != aaURL)
557 args->action = aaMail;
558 if(ac - 1){
560 if(can_access(*(av+1), READ_ACCESS) == 0){
561 ac--;
562 args_add_attach(&args->data.mail.attachlist,
563 *++av, FALSE);
565 else
566 break;
568 while(ac);
570 else{
571 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attachList");
572 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
573 display_args_err(tmp_20k_buf, NULL, 1);
574 ++usage;
577 else{
578 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attachList");
579 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
580 display_args_err(tmp_20k_buf, NULL, 1);
581 ++usage;
584 goto Loop;
586 else if(strcmp(*av, "attach_and_delete") == 0){
587 if((args->action == aaFolder && !args->data.folder)
588 || args->action == aaMail
589 || args->action == aaURL){
590 if(args->action != aaURL)
591 args->action = aaMail;
592 if(--ac){
593 args_add_attach(&args->data.mail.attachlist,
594 *++av, TRUE);
596 else{
597 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attach_and_delete");
598 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
599 display_args_err(tmp_20k_buf, NULL, 1);
600 ++usage;
603 else{
604 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attach_and_delete");
605 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
606 display_args_err(tmp_20k_buf, NULL, 1);
607 ++usage;
610 goto Loop;
612 else if(strcmp(*av, "bail") == 0){
613 pine_state->exit_if_no_pinerc = 1;
614 goto Loop;
616 else if(strcmp(*av, "version") == 0){
617 do_version = 1;
618 goto Loop;
620 else if(strcmp(*av, "xoauth2-server") == 0){
621 if(--ac){
622 if((str = *++av) != NULL){
623 if(x.name)
624 fs_give((void **) &x.name);
625 x.name = cpystr(str);
628 else{
629 display_args_err(_(args_err_missing_server_name), NULL, 1);
630 ++usage;
632 goto Loop;
634 else if(strcmp(*av, "xoauth2-client-id") == 0){
635 if(--ac){
636 if((str = *++av) != NULL){
637 if(x.client_id)
638 fs_give((void **) &x.client_id);
639 x.client_id = cpystr(str);
642 else{
643 display_args_err(_(args_err_missing_client_id), NULL, 1);
644 ++usage;
646 goto Loop;
648 else if(strcmp(*av, "xoauth2-client-secret") == 0){
649 if(--ac){
650 if((str = *++av) != NULL){
651 if(x.client_secret)
652 fs_give((void **) &x.client_secret);
653 x.client_secret = cpystr(str);
656 else{
657 display_args_err(_(args_err_missing_client_secret), NULL, 1);
658 ++usage;
660 goto Loop;
662 else if(strcmp(*av, "xoauth2-tenant") == 0){
663 if(--ac){
664 if((str = *++av) != NULL){
665 if(x.tenant)
666 fs_give((void **) &x.tenant);
667 x.tenant = cpystr(str);
670 else{
671 display_args_err(_(args_err_missing_tenant), NULL, 1);
672 ++usage;
674 goto Loop;
676 else if(strcmp(*av, "xoauth2-user") == 0){
677 if(--ac){
678 if((str = *++av) != NULL){
679 if(x.users)
680 fs_give((void **) &x.users);
681 x.users = cpystr(str);
684 else{
685 display_args_err(_(args_err_missing_user), NULL, 1);
686 ++usage;
688 goto Loop;
690 #ifdef _WINDOWS
691 else if(strcmp(*av, "install") == 0){
692 pine_state->install_flag = 1;
693 pine_state->update_registry = UREG_ALWAYS_SET;
694 goto Loop;
696 else if(strcmp(*av, "uninstall") == 0){
698 * Blast password cache, clear registry settings
700 #if (WINCRED > 0)
701 erase_windows_credentials();
702 #endif
703 mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0);
704 exit(0);
706 else if(strcmp(*av, "registry") == 0){
707 if(--ac){
708 if(!strucmp(*++av, "set")){
709 pine_state->update_registry = UREG_ALWAYS_SET;
711 else if(!strucmp(*av, "noset")){
712 pine_state->update_registry = UREG_NEVER_SET;
714 else if(!strucmp(*av, "clear")){
715 if(!mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0))
716 display_args_err(
717 _("Alpine related Registry values removed."),
718 NULL, 0);
719 else
720 display_args_err(
721 _("Not all Alpine related Registry values could be removed"),
722 NULL, 0);
723 exit(0);
725 else if(!strucmp(*av, "clearsilent")){
726 mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0);
727 exit(0);
729 else if(!strucmp(*av, "dump")){
730 char **pRegistry = mswin_reg_dump();
732 if(pRegistry){
733 display_args_err(NULL, pRegistry, 0);
734 free_list_array(&pRegistry);
736 exit(0);
738 else{
739 display_args_err(_("unknown registry command"),
740 NULL, 1);
741 ++usage;
744 else{
745 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_flag_arg), c);
746 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
747 display_args_err(tmp_20k_buf, NULL, 1);
748 ++usage;
751 goto Loop;
753 #endif
754 /* single char flags */
755 else{
756 switch(c = **av){
757 case 'h':
758 do_help = 1;
759 break; /* break back to inner-while */
760 case 'k':
761 do_use_fk = 1;
762 break;
763 case 'z':
764 do_can_suspend = 1;
765 break;
766 case 'r':
767 pine_state->restricted = 1;
768 break;
769 case 'o':
770 pine_state->open_readonly_on_startup = 1;
771 break;
772 case 'i':
773 pine_state->start_in_index = 1;
774 break;
775 case 'v':
776 do_version = 1;
777 break; /* break back to inner-while */
778 /* these take arguments */
779 case 'f': case 'F': case 'p': case 'I':
780 case 'c': case 'd': case 'P': case 'x': /* string args */
781 case 'n': /* integer args */
782 if(*++*av)
783 str = *av;
784 else if(--ac)
785 str = *++av;
786 else if(c == 'f' || c == 'F')
787 str = "";
788 else{
789 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_flag_arg), c);
790 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
791 display_args_err(tmp_20k_buf, NULL, 1);
792 ++usage;
793 goto Loop;
796 switch(c){
797 case 'f':
798 if(args->action == aaFolder && !args->data.folder){
799 args->data.folder = cpystr(str);
801 else{
802 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-f");
803 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
804 display_args_err(tmp_20k_buf, NULL, 1);
805 usage++;
808 break;
809 case 'F':
810 if(args->action == aaFolder && !args->data.folder){
811 args->action = aaMore;
812 args->data.file = cpystr(str);
814 else{
815 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-F");
816 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
817 display_args_err(tmp_20k_buf, NULL, 1);
818 usage++;
821 break;
822 case 'd':
823 debug_str = str;
824 break;
825 case 'I':
826 cmd_list = str;
827 break;
828 case 'p':
829 if(str){
830 char path[MAXPATH], dir[MAXPATH];
832 if(IS_REMOTE(str) || is_absolute_path(str)){
833 strncpy(path, str, sizeof(path)-1);
834 path[sizeof(path)-1] = '\0';
836 else{
837 if(getcwd(dir, sizeof(path)) != NULL)
838 build_path(path, dir, str, sizeof(path));
839 else
840 alpine_panic(_("getcwd() call failed while parsing argument (1)"));
844 * Pinerc used to be the name of the pinerc
845 * file. Now, since the pinerc can be remote,
846 * we've replaced the variable pinerc with the
847 * structure prc. Unfortunately, other parts of
848 * pine rely on the fact that pinerc is the
849 * name of the pinerc _file_, and use the
850 * directory that the pinerc file is located
851 * in for their own purposes. We keep that so
852 * things will keep working.
855 if(!IS_REMOTE(path)){
856 if(pine_state->pinerc)
857 fs_give((void **)&pine_state->pinerc);
859 pine_state->pinerc = cpystr(path);
863 * Last one wins. This would be the place where
864 * we put multiple pinercs in a list if we
865 * were to allow that.
867 if(pine_state->prc)
868 free_pinerc_s(&pine_state->prc);
870 pine_state->prc = new_pinerc_s(path);
873 break;
874 case 'P':
875 if(str){
876 char path[MAXPATH], dir[MAXPATH];
878 if(IS_REMOTE(str) || is_absolute_path(str)){
879 strncpy(path, str, sizeof(path)-1);
880 path[sizeof(path)-1] = '\0';
882 else{
883 if(getcwd(dir, sizeof(path)) != NULL)
884 build_path(path, dir, str, sizeof(path));
885 else
886 alpine_panic(_("getcwd() call failed while parsing argument (2)"));
889 if(pine_state->pconf)
890 free_pinerc_s(&pine_state->pconf);
892 pine_state->pconf = new_pinerc_s(path);
895 break;
896 case 'x':
897 if(str)
898 pine_state->exceptions = cpystr(str);
900 break;
901 case 'c':
902 if(!isdigit((unsigned char)str[0])){
903 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
904 _(args_err_missing_flag_num), c);
905 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
906 display_args_err(tmp_20k_buf, NULL, 1);
907 ++usage;
908 break;
911 pine_state->init_context = (short) atoi(str);
912 break;
914 case 'n':
915 if(!isdigit((unsigned char)str[0])){
916 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
917 _(args_err_missing_flag_num), c);
918 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
919 display_args_err(tmp_20k_buf, NULL, 1);
920 ++usage;
921 break;
924 pine_state->start_entry = atoi(str);
925 if(pine_state->start_entry < 1)
926 pine_state->start_entry = 1;
928 break;
931 goto Loop;
933 default:
934 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_unknown), c);
935 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
936 display_args_err(tmp_20k_buf, NULL, 1);
937 ++usage;
938 break;
943 else if(args->action == aaMail
944 || (args->action == aaFolder && !args->data.folder)){
945 STRLIST_S *stp, **slp;
947 args->action = aaMail;
949 stp = new_strlist(*av);
951 for(slp = &args->data.mail.addrlist; *slp; slp = &(*slp)->next)
954 *slp = stp;
956 else{
957 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), *av);
958 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
959 display_args_err(tmp_20k_buf, NULL, 1);
960 usage++;
963 if(cmd_list){
964 int commas = 0;
965 char *p = cmd_list;
966 char *error = NULL;
968 while(*p++)
969 if(*p == ',')
970 ++commas;
972 COM_INIT_CMD_LIST = parse_list(cmd_list, commas+1, 0, &error);
973 if(error){
974 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_I_error), cmd_list, error);
975 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
976 display_args_err(tmp_20k_buf, NULL, 1);
977 exit(-1);
981 #ifdef DEBUG
982 pine_state->debug_nfiles = NUMDEBUGFILES;
983 #endif
984 if(debug_str && process_debug_str(debug_str))
985 usage++;
987 if(lc && strncmp(lc, ALPINE_FKEY_NAME, sizeof(ALPINE_FKEY_NAME) - 1) == 0)
988 do_use_fk = 1;
990 if(do_use_fk || do_can_suspend){
991 char list[500];
992 int commas = 0;
993 char *p = list;
994 char *error = NULL;
996 list[0] = '\0';
998 if(do_use_fk){
999 if(list[0]){
1000 strncat(list, ",", sizeof(list)-strlen(list)-1);
1001 list[sizeof(list)-1] = '\0';
1004 strncat(list, "use-function-keys", sizeof(list)-strlen(list)-1);
1005 list[sizeof(list)-1] = '\0';
1008 if(do_can_suspend){
1009 if(list[0]){
1010 strncat(list, ",", sizeof(list)-strlen(list)-1);
1011 list[sizeof(list)-1] = '\0';
1014 strncat(list, "enable-suspend", sizeof(list)-strlen(list)-1);
1015 list[sizeof(list)-1] = '\0';
1018 while(*p++)
1019 if(*p == ',')
1020 ++commas;
1022 pine_state->feat_list_back_compat = parse_list(list,commas+1,0,&error);
1023 if(error){
1024 snprintf(tmp_20k_buf, SIZEOF_20KBUF, args_err_internal, error);
1025 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1026 display_args_err(tmp_20k_buf, NULL, 1);
1027 exit(-1);
1031 if(((do_conf ? 1 : 0)+(pinerc_file ? 1 : 0)) > 1){
1032 display_args_err(_("May only have one of -conf and -pinerc"),
1033 NULL, 1);
1034 exit(-1);
1037 if(do_help || usage)
1038 args_help();
1040 if(usage)
1041 exit(-1);
1043 if(x.name){
1044 char *tmp1, *tmp2;
1045 tmp2 = xoauth_config_line(&x);
1046 if(tmp2){
1047 tmp1 = fs_get((strlen(ps_global->vars[V_XOAUTH2_INFO].name) + strlen(tmp2) + 2)*sizeof(char));
1048 if(tmp1){
1049 sprintf(tmp1,"%s=%s", ps_global->vars[V_XOAUTH2_INFO].name, tmp2);
1050 pinerc_cmdline_opt(tmp1);
1051 fs_give((void **) &tmp1);
1053 fs_give((void **) &tmp2);
1057 if(do_version){
1058 extern char datestamp[], hoststamp[];
1059 char rev[128];
1061 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Alpine %s (%s %s) built %s on %s",
1062 ALPINE_VERSION,
1063 SYSTYPE ? SYSTYPE : "?",
1064 get_alpine_revision_string(rev, sizeof(rev)),
1065 datestamp, hoststamp);
1066 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1067 display_args_err(tmp_20k_buf, NULL, 0);
1068 if(*configoptions){
1069 display_args_err(_("Alpine was built with the following options:"), NULL, 0);
1070 display_config_options(configoptions, "./configure ");
1072 exit(0);
1075 if(do_conf)
1076 dump_global_conf();
1078 if(pinerc_file)
1079 dump_new_pinerc(pinerc_file);
1082 * Don't NULL out argv[0] or we might crash in unexpected ways. In OS X, we were
1083 * crashing when opening attachments because of this.
1085 if(ac <= 0 && av != argv)
1086 *av = NULL;
1091 * Returns 0 if ok, -1 if error.
1094 process_debug_str(char *debug_str)
1096 int i, usage = 0;
1097 int commas = 0;
1098 int new_style_debug_arg = 0;
1099 char *q = debug_str;
1100 char *error = NULL;
1101 char **list, **p;
1103 #ifdef DEBUG
1104 if(debug_str){
1105 if(!isdigit((unsigned char)debug_str[0]))
1106 new_style_debug_arg++;
1108 if(new_style_debug_arg){
1109 while(*q++)
1110 if(*q == ',')
1111 ++commas;
1113 list = parse_list(debug_str, commas+1, 0, &error);
1114 if(error){
1115 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_d_error), debug_str, error);
1116 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1117 display_args_err(tmp_20k_buf, NULL, 1);
1118 return(-1);
1121 if(list){
1122 for(p = list; *p; p++){
1123 if(struncmp(*p, "timestamp", 9) == 0){
1124 ps_global->debug_timestamp = 1;
1126 else if(struncmp(*p, "imap", 4) == 0){
1127 q = *p + 4;
1128 if(!*q || !*(q+1) || *q != '=' ||
1129 !isdigit((unsigned char)*(q+1))){
1130 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
1131 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1132 display_args_err(tmp_20k_buf, NULL, 1);
1133 usage = -1;
1135 else{
1136 i = atoi(q+1);
1137 ps_global->debug_imap = MIN(5,MAX(0,i));
1140 else if(struncmp(*p, "flush", 5) == 0){
1141 ps_global->debug_flush = 1;
1143 else if(struncmp(*p, "tcp", 3) == 0
1144 || struncmp(*p, "tcpdebug", 8) == 0){
1145 ps_global->debug_tcp = 1;
1147 else if(struncmp(*p, "verbose", 7) == 0){
1148 q = *p + 7;
1149 if(!*q || !*(q+1) || *q != '=' ||
1150 !isdigit((unsigned char)*(q+1))){
1151 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
1152 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1153 display_args_err(tmp_20k_buf, NULL, 1);
1154 usage = -1;
1156 else
1157 debug = atoi(q+1);
1159 else if(struncmp(*p, "numfiles", 8) == 0){
1160 q = *p + 8;
1161 if(!*q || !*(q+1) || *q != '=' ||
1162 !isdigit((unsigned char)*(q+1))){
1163 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
1164 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1165 display_args_err(tmp_20k_buf, NULL, 1);
1166 usage = -1;
1168 else{
1169 i = atoi(q+1);
1170 ps_global->debug_nfiles = MIN(31,MAX(0,i));
1173 else if(struncmp(*p, "malloc", 6) == 0){
1174 q = *p + 6;
1175 if(!*q || !*(q+1) || *q != '=' ||
1176 !isdigit((unsigned char)*(q+1))){
1177 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
1178 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1179 display_args_err(tmp_20k_buf, NULL, 1);
1180 usage = -1;
1182 else{
1183 i = atoi(q+1);
1184 ps_global->debug_malloc = MIN(63,MAX(0,i));
1187 #if defined(ENABLE_LDAP) && defined(LDAP_DEBUG)
1188 else if(struncmp(*p, "ldap", 4) == 0){
1189 q = *p + 4;
1190 if(!*q || !*(q+1) || *q != '=' ||
1191 !isdigit((unsigned char)*(q+1))){
1192 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
1193 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1194 display_args_err(tmp_20k_buf, NULL, 1);
1195 usage = -1;
1197 else{
1198 i = atoi(q+1);
1199 ldap_debug = i;
1202 #endif /* LDAP */
1203 else{
1204 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("unknown debug keyword \"%s\""), *p);
1205 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1206 display_args_err(tmp_20k_buf, NULL, 1);
1207 usage = -1;
1211 free_list_array(&list);
1214 else{
1215 debug = atoi(debug_str);
1216 if(debug > 9)
1217 ps_global->debug_imap = 5;
1218 else if(debug > 7)
1219 ps_global->debug_imap = 4;
1220 else if(debug > 6)
1221 ps_global->debug_imap = 3;
1222 else if(debug > 4)
1223 ps_global->debug_imap = 2;
1224 else if(debug > 2)
1225 ps_global->debug_imap = 1;
1227 if(debug > 7)
1228 ps_global->debug_timestamp = 1;
1230 if(debug > 8)
1231 ps_global->debug_flush = 1;
1235 if(usage >= 0) ps_global->write_debug_file++;
1236 if(!new_style_debug_arg){
1237 #ifdef CSRIMALLOC
1238 ps_global->debug_malloc =
1239 (debug <= DEFAULT_DEBUG) ? 1 : (debug < 9) ? 2 : 3;
1240 #else /* !CSRIMALLOC */
1241 #ifdef HAVE_SMALLOC
1242 if(debug > 8)
1243 ps_global->debug_malloc = 2;
1244 #else /* !HAVE_SMALLOC */
1245 #ifdef NXT
1246 if(debug > 8)
1247 ps_global->debug_malloc = 32;
1248 #endif /* NXT */
1249 #endif /* HAVE_SMALLOC */
1250 #endif /* CSRIMALLOC */
1253 #else /* !DEBUG */
1255 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("unknown flag \"d\", debugging not compiled in"));
1256 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1257 display_args_err(tmp_20k_buf, NULL, 1);
1258 usage = -1;
1260 #endif /* !DEBUG */
1262 return(usage);
1266 void
1267 args_add_attach(PATMT **alpp, char *s, int deleted)
1269 PATMT *atmp, **atmpp;
1271 atmp = (PATMT *) fs_get(sizeof(PATMT));
1272 memset(atmp, 0, sizeof(PATMT));
1273 atmp->filename = cpystr(s);
1275 #if defined(DOS) || defined(OS2)
1276 (void) removing_quotes(atmp->filename);
1277 #endif
1279 if(deleted)
1280 atmp->flags |= A_TMP;
1282 for(atmpp = alpp; *atmpp; atmpp = &(*atmpp)->next)
1285 *atmpp = atmp;
1289 /*----------------------------------------------------------------------
1290 print a few lines of help for command line arguments
1292 Args: none
1294 Result: prints help messages
1295 ----------------------------------------------------------------------*/
1296 void
1297 args_help(void)
1299 char *pp[2];
1300 #ifndef _WINDOWS
1301 char **a;
1302 #endif
1304 pp[1] = NULL;
1306 /** print out possible starting arguments... **/
1309 * display_args_err expects already translated input
1310 * so we need to translate a line at a time. Since
1311 * the 1st and 3rd args are zero it is ok to call it
1312 * a line at a time.
1314 * Windows expects the full block of text so we'll pass
1315 * it as such.
1317 #ifndef _WINDOWS
1318 for(a=args_pine_args; a && *a; a++){
1319 pp[0] = _(*a);
1320 display_args_err(NULL, pp, 0);
1322 #else
1323 display_args_err(NULL, args_pine_args, 0);
1324 #endif
1326 exit(1);
1330 /*----------------------------------------------------------------------
1331 write argument error to the display...
1333 Args: none
1335 Result: prints help messages
1336 ----------------------------------------------------------------------*/
1337 void
1338 display_args_err(char *s, char **a, int err)
1340 char errstr[256], *errp;
1341 FILE *fp = err ? stderr : stdout;
1344 if(err && s){
1345 snprintf(errp = errstr, sizeof(errstr), "%s: %s", _("Argument Error"), s);
1346 errstr[sizeof(errstr)-1] = '\0';
1348 else
1349 errp = s;
1351 #ifdef _WINDOWS
1352 if(errp)
1353 mswin_messagebox(errp, err);
1355 if(a && *a){
1356 os_argsdialog(a);
1358 #else
1359 if(errp)
1360 fprintf(fp, "%s\n", errp);
1362 while(a && *a)
1363 fprintf(fp, "%s\n", *a++);
1364 #endif
1369 * The argument is an argument from the command line. We check to see
1370 * if it is specifying an alternate value for one of the options that is
1371 * normally set in pinerc. If so, we return 1 and set the appropriate
1372 * values in the variables array.
1373 * The arg can be
1374 * varname=value
1375 * varname=value1,value2,value3
1376 * feature-list=featurename these are just a special
1377 * feature-list=featurename1,featurename2 case of above
1378 * featurename This is equivalent to above
1379 * no-featurename
1382 pinerc_cmdline_opt(char *arg)
1384 struct variable *v;
1385 char *p1 = NULL,
1386 *value,
1387 **oldlvalue = NULL,
1388 **lvalue;
1389 int i, count;
1391 if(!arg || !arg[0])
1392 return 0;
1394 if((value = strchr(arg, '=')) != NULL){
1395 i = value - arg;
1396 arg[i] = '\0';
1398 else
1399 i = -1;
1401 for(v = ps_global->vars; v->name != NULL; v++){
1402 if(v->is_used && strucmp(v->name, arg) == 0){
1403 p1 = arg + strlen(v->name);
1404 if(i > 0) arg[i] = '=';
1406 /*----- Skip to '=' -----*/
1407 while(*p1 && (*p1 == '\t' || *p1 == ' '))
1408 p1++;
1410 if(*p1 != '='){
1411 char buf[MAILTMPLEN];
1413 snprintf(buf, sizeof(buf), _("Missing \"=\" after -%s\n"), v->name);
1414 buf[sizeof(buf)-1] = '\0';
1415 exceptional_exit(buf, -1);
1418 p1++;
1419 break;
1424 if(i > 0) arg[i] = '=';
1426 /* no match, check for a feature name used directly */
1427 if(v->name == NULL){
1428 FEATURE_S *feat;
1429 char *featname;
1431 if(struncmp(arg, "no-", 3) == 0)
1432 featname = arg+3;
1433 else
1434 featname = arg;
1436 for(i = 0; (feat = feature_list(i)) != NULL; i++){
1437 if(strucmp(featname, feat->name) == 0){
1438 v = &(ps_global->vars)[V_FEATURE_LIST];
1439 p1 = arg;
1440 break;
1445 if(!p1)
1446 return 0;
1448 if(v->is_obsolete || !v->is_user){
1449 char buf[MAILTMPLEN];
1451 if(v->is_obsolete)
1452 snprintf(buf, sizeof(buf), _("Option \"%s\" is obsolete\n"), v->name);
1453 else
1454 snprintf(buf, sizeof(buf), _("Option \"%s\" is not user settable\n"), v->name);
1456 exceptional_exit(buf, -1);
1459 /* free mem */
1460 if(v->is_list){
1461 oldlvalue = v->cmdline_val.l;
1462 v->cmdline_val.l = NULL;
1464 else if(v->cmdline_val.p)
1465 fs_give((void **) &(v->cmdline_val.p));
1467 /*----- Matched a variable, get its value ----*/
1468 while(*p1 == ' ' || *p1 == '\t')
1469 p1++;
1470 value = p1;
1472 if(*value == '\0'){
1473 if(v->is_list){
1474 v->cmdline_val.l = (char **)fs_get(2 * sizeof(char *));
1476 * we let people leave off the quotes on command line so that
1477 * they don't have to mess with shell quoting
1479 v->cmdline_val.l[0] = cpystr("");
1480 v->cmdline_val.l[1] = NULL;
1481 if(oldlvalue)
1482 free_list_array(&oldlvalue);
1484 }else{
1485 v->cmdline_val.p = cpystr("");
1487 return 1;
1490 /*--value is non-empty--*/
1491 if(*value == '"' && !v->is_list){
1492 value++;
1493 for(p1 = value; *p1 && *p1 != '"'; p1++)
1495 if(*p1 == '"')
1496 *p1 = '\0';
1497 else
1498 removing_trailing_white_space(value);
1499 }else{
1500 removing_trailing_white_space(value);
1503 if(v->is_list){
1504 int was_quoted = 0;
1505 char *error = NULL;
1507 count = 1;
1508 for(p1=value; *p1; p1++){ /* generous count of list elements */
1509 if(*p1 == '"') /* ignore ',' if quoted */
1510 was_quoted = (was_quoted) ? 0 : 1;
1512 if(*p1 == ',' && !was_quoted)
1513 count++;
1516 lvalue = parse_list(value, count, 0, &error);
1517 if(error){
1518 char buf[MAILTMPLEN];
1520 snprintf(buf, sizeof(buf), "%s in %s = \"%s\"\n", error, v->name, value);
1521 buf[sizeof(buf)-1] = '\0';
1522 exceptional_exit(buf, -1);
1525 * Special case: turn "" strings into empty strings.
1526 * This allows users to turn off default lists. For example,
1527 * if smtp-server is set then a user could override smtp-server
1528 * with smtp-server="".
1530 for(i = 0; lvalue[i]; i++)
1531 if(lvalue[i][0] == '"' &&
1532 lvalue[i][1] == '"' &&
1533 lvalue[i][2] == '\0')
1534 lvalue[i][0] = '\0';
1537 if(v->is_list){
1538 if(oldlvalue){
1539 char **combinedlvalue;
1540 int j;
1542 /* combine old and new cmdline lists */
1543 for(count = 0, i = 0; oldlvalue[i]; i++, count++)
1546 for(i = 0; lvalue && lvalue[i]; i++, count++)
1549 combinedlvalue = (char **) fs_get((count+1) * sizeof(char *));
1550 memset(combinedlvalue, 0, (count+1) * sizeof(*combinedlvalue));
1552 for(i = 0, j = 0; oldlvalue[i]; i++, j++)
1553 combinedlvalue[j] = cpystr(oldlvalue[i]);
1555 for(i = 0; lvalue && lvalue[i]; i++, j++)
1556 combinedlvalue[j] = cpystr(lvalue[i]);
1558 v->cmdline_val.l = combinedlvalue;
1560 fs_give((void **) &oldlvalue);
1561 if(lvalue)
1562 fs_give((void **) &lvalue);
1564 else
1565 v->cmdline_val.l = lvalue;
1567 else
1568 v->cmdline_val.p = cpystr(value);
1570 return 1;