* A few improvements to the http code, which make the http_* functions not return...
[alpine.git] / alpine / arg.c
blob1971e80272bcad74e826a73c99cba7003782e026
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 *);
44 * Name started as to invoke function key mode
46 #define ALPINE_FKEY_NAME "alpinef"
49 * Various error and informational strings..
51 /* TRANSLATORS: This is a list of errors printed when something goes wrong
52 early on with the argument list. Be careful not to change literal
53 option names mentioned in the strings. */
54 static char args_err_missing_pinerc[] = N_("missing argument for option \"-pinerc\" (use - for standard out)");
55 #if defined(DOS) || defined(OS2)
56 static char args_err_missing_aux[] = N_("missing argument for option \"-aux\"");
57 #endif
58 #ifdef SMIME
59 static char args_err_missing_smimedir[] = N_("missing argument for option \"-smimedir\"");
60 static char args_err_non_abs_smimedir[] = N_("argument to \"-smimedir\" should be fully-qualified");
61 #endif /* SMIME */
62 #ifdef PASSFILE
63 static char args_err_missing_passfile[] = N_("missing argument for option \"-passfile\"");
64 static char args_err_non_abs_passfile[] = N_("argument to \"-passfile\" should be fully-qualified");
65 #ifdef SMIME
66 static char args_err_missing_pwdcertdir[] = N_("missing argument for option \"-pwdcertdir\"");
67 static char args_err_non_abs_pwdcertdir[] = N_("argument to \"-pwdcertdir\" should be fully-qualified");
68 #endif /* SMIME inside PASSFILE */
69 #endif
70 static char args_err_missing_sort[] = N_("missing argument for option \"-sort\"");
71 static char args_err_missing_flag_arg[] = N_("missing argument for flag \"%c\"");
72 static char args_err_missing_flag_num[] = N_("Non numeric argument for flag \"%c\"");
73 static char args_err_missing_debug_num[] = N_("Non numeric argument for \"%s\"");
74 static char args_err_missing_url[] = N_("missing URL for \"-url\"");
75 static char args_err_missing_attachment[] = N_("missing attachment for \"%s\"");
76 static char args_err_conflict[] = N_("conflicting action: \"%s\"");
77 static char args_err_unknown[] = N_("unknown flag \"%c\"");
78 static char args_err_I_error[] = N_("-I argument \"%s\": %s");
79 static char args_err_d_error[] = N_("-d argument \"%s\": %s");
80 static char args_err_internal[] = "%s";
81 static char args_err_missing_copyprc[] = N_("missing argument for option \"-copy_pinerc\"\nUsage: pine -copy_pinerc <local_pinerc> <remote_pinerc>");
82 static char args_err_missing_copyabook[] = N_("missing argument for option \"-copy_abook\"\nUsage: pine -copy_abook <local_abook> <remote_abook>");
83 static char args_err_missing_server_name[] = N_("missing server name. Example: -xoauth2-server Gmail");
84 static char args_err_missing_client_id[] = N_("missing client-id name. Example: -xoauth2-client-id 760.someserver.com");
85 static char args_err_missing_client_secret[] = N_("missing client-secret name. Example: -xoauth2-client-secret V56i0fa_");
86 static char args_err_missing_xoauth_option[] = N_("at least one of the arguments -xoauth2-server, or -xoauth2-client-id, or -xoauth2-client-secret is missing.");
88 static char *args_pine_args[] = {
89 N_("Possible Starting Arguments for Alpine program:"),
90 "",
91 N_(" Argument\tMeaning"),
92 N_(" <addrs>...\tGo directly into composer sending to given address"),
93 N_("\t\tList multiple addresses with a single space between them."),
94 N_("\t\tStandard input redirection is allowed with addresses."),
95 N_("\t\tNote: Places addresses in the \"To\" field only."),
96 N_(" -attach <file>\tGo directly into composer with given file"),
97 N_(" -attachlist <file-list>"),
98 N_(" -attach_and_delete <file>"),
99 N_("\t\tGo to composer, attach file, delete when finished"),
100 N_("\t\tNote: Attach options can't be used if -f, -F"),
101 N_("\t\tadded to Attachment list. Attachlist must be the last"),
102 N_("\t\toption on the command line"),
103 N_(" -bail\t\tExit if pinerc file doesn't already exist"),
104 #ifdef DEBUG
105 N_(" -d n\t\tDebug - set debug level to 'n', or use the following:"),
106 N_(" -d keywords...\tflush,timestamp,imap=0..4,tcp,numfiles=0..31,verbose=0..9"),
107 #endif
108 N_(" -f <folder>\tFolder - give folder name to open"),
109 N_(" -c <number>\tContext - which context to apply to -f arg"),
110 N_(" -F <file>\tFile - give file name to open and page through and"),
111 N_("\t\tforward as email."),
112 N_(" -h \t\tHelp - give this list of options"),
113 N_(" -k \t\tKeys - Force use of function keys"),
114 N_(" -z \t\tSuspend - allow use of ^Z suspension"),
115 N_(" -r \t\tRestricted - can only send mail to oneself"),
116 N_(" -sort <sort>\tSort - Specify sort order of folder:"),
117 N_("\t\t\tarrival, subject, threaded, orderedsubject, date,"),
118 N_("\t\t\tfrom, size, score, to, cc, /reverse"),
119 N_(" -i\t\tIndex - Go directly to index, bypassing main menu"),
120 N_(" -I <keystroke_list> Initial keystrokes to be executed"),
121 N_(" -n <number>\tEntry in index to begin on"),
122 N_(" -o \t\tReadOnly - Open first folder read-only"),
123 N_(" -conf\t\tConfiguration - Print out fresh global configuration. The"),
124 N_("\t\tvalues of your global configuration affect all Alpine users"),
125 N_("\t\ton your system unless they have overridden the values in their"),
126 N_("\t\tpinerc files."),
127 N_(" -pinerc <file>\tConfiguration - Put fresh pinerc configuration in <file>"),
128 N_(" -p <pinerc>\tUse alternate .pinerc file"),
129 #if !defined(DOS) && !defined(OS2)
130 N_(" -P <pine.conf>\tUse alternate pine.conf file"),
131 #else
132 N_(" -aux <aux_files_dir>\tUse this with remote pinerc"),
133 N_(" -P <pine.conf>\tUse pine.conf file for default settings"),
134 N_(" -nosplash \tDisable the PC-Alpine splash screen"),
135 #endif
137 #if defined(APPLEKEYCHAIN) || (WINCRED > 0)
138 N_(" -erase_stored_passwords\tEliminate any stored passwords"),
139 #endif
141 #ifdef SMIME
142 N_(" -smimedir <fully_qualified_path>\tdirectory where smime personal certificates are saved"),
143 #endif /* SMIME */
145 #ifdef PASSFILE
146 N_(" -passfile <fully_qualified_filename>\tSet the password file to something other"),
147 N_("\t\tthan the default"),
148 #ifdef SMIME
149 N_(" -pwdcertdir <fully_qualified_path>\tSet the directory to store a personal"),
150 N_("\t\tkey and certificate to encrypt and decrypt your password file."),
151 #endif /* SMIME inside PASSFILE */
152 #endif /* PASSFILE */
154 #ifdef LOCAL_PASSWD_CACHE
155 N_(" -nowrite_password_cache\tRead from a password cache if there is one, but"),
156 N_("\t\t\t\tnever offer to write a password to the cache"),
157 #endif /* LOCAL_PASSWD_CACHE */
159 N_(" -x <config>\tUse configuration exceptions in <config>."),
160 N_("\t\tExceptions are used to override your default pinerc"),
161 N_("\t\tsettings for a particular platform, can be a local file or"),
162 N_("\t\ta remote folder."),
163 N_(" -v \t\tVersion - show version information"),
164 N_(" -version\tVersion - show version information"),
165 N_(" -supported\tList supported options"),
166 N_(" -url <url>\tOpen the given URL"),
167 N_("\t\tNote: Can't be used if -f, -F"),
168 N_("\t\tStandard input redirection is not allowed with URLs."),
169 N_("\t\tFor mailto URLs, 'body='text should be used in place of"),
170 N_("\t\tinput redirection."),
171 N_(" -copy_pinerc <local_pinerc> <remote_pinerc> copy local pinerc to remote"),
172 N_(" -copy_abook <local_abook> <remote_abook> copy local addressbook to remote"),
173 N_(" -convert_sigs -p <pinerc> convert signatures to literal signatures"),
174 #if defined(_WINDOWS)
175 N_(" -install \tPrompt for some basic setup information"),
176 N_(" -uninstall \tRemove traces of Alpine from Windows system settings"),
177 N_(" -registry <cmd>\tWhere cmd is set,noset,clear,clearsilent,dump"),
178 #endif
179 N_(" -xoauth2-server <value>"),
180 N_(" -xoauth2-client-id <value>"),
181 N_(" -xoauth2-client-secret <value>"),
182 N_("\tNote: All of -xoauth options above must be used, if any of them is used"),
183 " -<option>=<value> Assign <value> to the pinerc option <option>",
184 "\t\t e.g. -signature-file=sig1",
185 "\t\t e.g. -color-style=no-color",
186 "\t\t e.g. -feature-list=enable-sigdashes",
187 "\t\t Note: feature-list is additive.",
188 "\t\t You may leave off the \"feature-list=\" part of that,",
189 "\t\t e.g. -enable-sigdashes",
190 NULL
196 * Parse the command line args.
198 * Args: pine_state -- The pine_state structure to put results in
199 * argc, argv -- The obvious
200 * addrs -- Pointer to address list that we set for caller
202 * Result: command arguments parsed
203 * possible printing of help for command line
204 * various flags in pine_state set
205 * returns the string name of the first folder to open
206 * addrs is set
208 void
209 pine_args(struct pine *pine_state, int argc, char **argv, ARGDATA_S *args)
211 register int ac;
212 register char **av;
213 int c;
214 char *str;
215 char *cmd_list = NULL;
216 char *debug_str = NULL;
217 char *sort = NULL;
218 char *pinerc_file = NULL;
219 char *lc = NULL;
220 char *xoauth2_server = NULL;
221 char *xoauth2_client_id = NULL;
222 char *xoauth2_client_secret = NULL;
223 int do_help = 0;
224 int do_conf = 0;
225 int usage = 0;
226 int do_use_fk = 0;
227 int do_can_suspend = 0;
228 int do_version = 0;
229 struct variable *vars = pine_state->vars;
231 ac = argc;
232 av = argv;
233 memset(args, 0, sizeof(ARGDATA_S));
234 args->action = aaFolder;
236 pine_state->pine_name = (lc = last_cmpnt(argv[0])) ? lc : (lc = argv[0]);
237 #ifdef DOS
238 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%.*s", pine_state->pine_name - argv[0], argv[0]);
239 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
240 pine_state->pine_dir = cpystr(tmp_20k_buf);
241 #endif
243 /* while more arguments with leading - */
244 Loop: while(--ac > 0)
245 if(**++av == '-'){
246 /* while more chars in this argument */
247 while(*++*av){
248 /* check for pinerc options */
249 if(pinerc_cmdline_opt(*av)){
250 goto Loop; /* done with this arg, go to next */
252 /* then other multi-char options */
253 else if(strcmp(*av, "conf") == 0){
254 do_conf = 1;
255 goto Loop; /* done with this arg, go to next */
257 else if(strcmp(*av, "pinerc") == 0){
258 if(--ac)
259 pinerc_file = *++av;
260 else{
261 display_args_err(_(args_err_missing_pinerc), NULL, 1);
262 ++usage;
265 goto Loop;
267 #if defined(DOS) || defined(OS2)
268 else if(strcmp(*av, "aux") == 0){
269 if(--ac){
270 if((str = *++av) != NULL)
271 pine_state->aux_files_dir = cpystr(str);
273 else{
274 display_args_err(_(args_err_missing_aux), NULL, 1);
275 ++usage;
278 goto Loop;
280 else if(strcmp(*av, "nosplash") == 0)
281 goto Loop; /* already taken care of in WinMain */
282 #endif
284 #if defined(APPLEKEYCHAIN) || (WINCRED > 0)
285 else if(strcmp(*av, "erase_stored_passwords") == 0){
286 #if (WINCRED > 0)
287 erase_windows_credentials();
288 #else
289 macos_erase_keychain();
290 #endif
291 goto Loop;
293 #endif /* defined(APPLEKEYCHAIN) || (WINCRED > 0) */
295 #ifdef SMIME
296 else if(strcmp(*av, "smimedir") == 0){
297 if(--ac){
298 if((str = *++av) != NULL){
299 if(!is_absolute_path(str)){
300 display_args_err(_(args_err_non_abs_smimedir),
301 NULL, 1);
302 ++usage;
304 else{
305 if(pine_state->smimedir)
306 fs_give((void **)&pine_state->smimedir);
308 pine_state->smimedir = cpystr(str);
312 else{
313 display_args_err(_(args_err_missing_smimedir), NULL, 1);
314 ++usage;
317 goto Loop;
319 #endif /* SMIME */
320 #ifdef PASSFILE
321 else if(strcmp(*av, "passfile") == 0){
322 if(--ac){
323 if((str = *++av) != NULL){
324 if(!is_absolute_path(str)){
325 display_args_err(_(args_err_non_abs_passfile),
326 NULL, 1);
327 ++usage;
329 else{
330 if(pine_state->passfile)
331 fs_give((void **)&pine_state->passfile);
333 pine_state->passfile = cpystr(str);
337 else{
338 display_args_err(_(args_err_missing_passfile), NULL, 1);
339 ++usage;
342 goto Loop;
344 #ifdef SMIME
345 else if(strcmp(*av, "pwdcertdir") == 0){
346 if(--ac){
347 if((str = *++av) != NULL){
348 if(!is_absolute_path(str)){
349 display_args_err(_(args_err_non_abs_pwdcertdir),
350 NULL, 1);
351 ++usage;
353 else{
354 if(pine_state->pwdcertdir)
355 fs_give((void **)&pine_state->pwdcertdir);
357 pine_state->pwdcertdir = cpystr(str);
361 else{
362 display_args_err(_(args_err_missing_pwdcertdir), NULL, 1);
363 ++usage;
366 goto Loop;
368 #endif /* SMIME inside PASSFILE */
369 #endif /* PASSFILE */
371 #ifdef LOCAL_PASSWD_CACHE
372 else if(strcmp(*av, "nowrite_password_cache") == 0){
373 ps_global->nowrite_password_cache = 1;
374 goto Loop;
376 #endif /* LOCAL_PASSWD_CACHE */
378 else if(strcmp(*av, "convert_sigs") == 0){
379 ps_global->convert_sigs = 1;
380 goto Loop;
382 else if(strcmp(*av, "supported") == 0){
383 ps_global->dump_supported_options = 1;
384 goto Loop;
386 else if(strcmp(*av, "copy_pinerc") == 0){
387 if(args->action == aaFolder && !args->data.folder){
388 args->action = aaPrcCopy;
389 if(ac > 2){
390 ac -= 2;
391 args->data.copy.local = *++av;
392 args->data.copy.remote = *++av;
394 else{
395 display_args_err(_(args_err_missing_copyprc), NULL, 1);
396 ++usage;
399 else{
400 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-copy_pinerc");
401 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
402 display_args_err(tmp_20k_buf, NULL, 1);
403 ++usage;
406 goto Loop;
408 else if(strcmp(*av, "copy_abook") == 0){
409 if(args->action == aaFolder && !args->data.folder){
410 args->action = aaAbookCopy;
411 if(ac > 2){
412 ac -= 2;
413 args->data.copy.local = *++av;
414 args->data.copy.remote = *++av;
416 else{
417 display_args_err(_(args_err_missing_copyabook), NULL, 1);
418 ++usage;
421 else{
422 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-copy_abook");
423 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
424 display_args_err(tmp_20k_buf, NULL, 1);
425 ++usage;
428 goto Loop;
430 else if(strcmp(*av, "sort") == 0){
431 if(--ac){
432 sort = *++av;
433 COM_SORT_KEY = cpystr(sort);
435 else{
436 display_args_err(_(args_err_missing_sort), NULL, 1);
437 ++usage;
440 goto Loop;
442 else if(strcmp(*av, "url") == 0){
443 if(args->action == aaFolder && !args->data.folder){
444 args->action = aaURL;
445 if(--ac){
446 args->url = cpystr(*++av);
448 else{
449 display_args_err(_(args_err_missing_url), NULL, 1);
450 ++usage;
453 else{
454 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-url");
455 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
456 display_args_err(tmp_20k_buf, NULL, 1);
457 ++usage;
460 goto Loop;
462 else if(strcmp(*av, "attach") == 0){
463 if((args->action == aaFolder && !args->data.folder)
464 || args->action == aaMail
465 || args->action == aaURL){
466 if(args->action != aaURL)
467 args->action = aaMail;
468 if(--ac){
469 args_add_attach(&args->data.mail.attachlist,
470 *++av, FALSE);
472 else{
473 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attach");
474 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
475 display_args_err(tmp_20k_buf, NULL, 1);
476 ++usage;
479 else{
480 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attach");
481 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
482 display_args_err(tmp_20k_buf, NULL, 1);
483 ++usage;
486 goto Loop;
488 else if(strcmp(*av, "attachlist") == 0){
489 if((args->action == aaFolder && !args->data.folder)
490 || args->action == aaMail
491 || args->action == aaURL){
492 if(args->action != aaURL)
493 args->action = aaMail;
494 if(ac - 1){
496 if(can_access(*(av+1), READ_ACCESS) == 0){
497 ac--;
498 args_add_attach(&args->data.mail.attachlist,
499 *++av, FALSE);
501 else
502 break;
504 while(ac);
506 else{
507 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attachList");
508 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
509 display_args_err(tmp_20k_buf, NULL, 1);
510 ++usage;
513 else{
514 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attachList");
515 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
516 display_args_err(tmp_20k_buf, NULL, 1);
517 ++usage;
520 goto Loop;
522 else if(strcmp(*av, "attach_and_delete") == 0){
523 if((args->action == aaFolder && !args->data.folder)
524 || args->action == aaMail
525 || args->action == aaURL){
526 if(args->action != aaURL)
527 args->action = aaMail;
528 if(--ac){
529 args_add_attach(&args->data.mail.attachlist,
530 *++av, TRUE);
532 else{
533 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attach_and_delete");
534 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
535 display_args_err(tmp_20k_buf, NULL, 1);
536 ++usage;
539 else{
540 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attach_and_delete");
541 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
542 display_args_err(tmp_20k_buf, NULL, 1);
543 ++usage;
546 goto Loop;
548 else if(strcmp(*av, "bail") == 0){
549 pine_state->exit_if_no_pinerc = 1;
550 goto Loop;
552 else if(strcmp(*av, "version") == 0){
553 do_version = 1;
554 goto Loop;
556 else if(strcmp(*av, "xoauth2-server") == 0){
557 if(--ac){
558 if((str = *++av) != NULL){
559 if(xoauth2_server)
560 fs_give((void **) &xoauth2_server);
561 xoauth2_server = cpystr(str);
564 else{
565 display_args_err(_(args_err_missing_server_name), NULL, 1);
566 ++usage;
568 goto Loop;
570 else if(strcmp(*av, "xoauth2-client-id") == 0){
571 if(--ac){
572 if((str = *++av) != NULL){
573 if(xoauth2_client_id)
574 fs_give((void **) &xoauth2_client_id);
575 xoauth2_client_id = cpystr(str);
578 else{
579 display_args_err(_(args_err_missing_client_id), NULL, 1);
580 ++usage;
582 goto Loop;
584 else if(strcmp(*av, "xoauth2-client-secret") == 0){
585 if(--ac){
586 if((str = *++av) != NULL){
587 if(xoauth2_client_secret)
588 fs_give((void **) &xoauth2_client_secret);
589 xoauth2_client_secret = cpystr(str);
592 else{
593 display_args_err(_(args_err_missing_client_secret), NULL, 1);
594 ++usage;
596 goto Loop;
598 #ifdef _WINDOWS
599 else if(strcmp(*av, "install") == 0){
600 pine_state->install_flag = 1;
601 pine_state->update_registry = UREG_ALWAYS_SET;
602 goto Loop;
604 else if(strcmp(*av, "uninstall") == 0){
606 * Blast password cache, clear registry settings
608 #if (WINCRED > 0)
609 erase_windows_credentials();
610 #endif
611 mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0);
612 exit(0);
614 else if(strcmp(*av, "registry") == 0){
615 if(--ac){
616 if(!strucmp(*++av, "set")){
617 pine_state->update_registry = UREG_ALWAYS_SET;
619 else if(!strucmp(*av, "noset")){
620 pine_state->update_registry = UREG_NEVER_SET;
622 else if(!strucmp(*av, "clear")){
623 if(!mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0))
624 display_args_err(
625 _("Alpine related Registry values removed."),
626 NULL, 0);
627 else
628 display_args_err(
629 _("Not all Alpine related Registry values could be removed"),
630 NULL, 0);
631 exit(0);
633 else if(!strucmp(*av, "clearsilent")){
634 mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0);
635 exit(0);
637 else if(!strucmp(*av, "dump")){
638 char **pRegistry = mswin_reg_dump();
640 if(pRegistry){
641 display_args_err(NULL, pRegistry, 0);
642 free_list_array(&pRegistry);
644 exit(0);
646 else{
647 display_args_err(_("unknown registry command"),
648 NULL, 1);
649 ++usage;
652 else{
653 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_flag_arg), c);
654 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
655 display_args_err(tmp_20k_buf, NULL, 1);
656 ++usage;
659 goto Loop;
661 #endif
662 /* single char flags */
663 else{
664 switch(c = **av){
665 case 'h':
666 do_help = 1;
667 break; /* break back to inner-while */
668 case 'k':
669 do_use_fk = 1;
670 break;
671 case 'z':
672 do_can_suspend = 1;
673 break;
674 case 'r':
675 pine_state->restricted = 1;
676 break;
677 case 'o':
678 pine_state->open_readonly_on_startup = 1;
679 break;
680 case 'i':
681 pine_state->start_in_index = 1;
682 break;
683 case 'v':
684 do_version = 1;
685 break; /* break back to inner-while */
686 /* these take arguments */
687 case 'f': case 'F': case 'p': case 'I':
688 case 'c': case 'd': case 'P': case 'x': /* string args */
689 case 'n': /* integer args */
690 if(*++*av)
691 str = *av;
692 else if(--ac)
693 str = *++av;
694 else if(c == 'f' || c == 'F')
695 str = "";
696 else{
697 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_flag_arg), c);
698 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
699 display_args_err(tmp_20k_buf, NULL, 1);
700 ++usage;
701 goto Loop;
704 switch(c){
705 case 'f':
706 if(args->action == aaFolder && !args->data.folder){
707 args->data.folder = cpystr(str);
709 else{
710 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-f");
711 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
712 display_args_err(tmp_20k_buf, NULL, 1);
713 usage++;
716 break;
717 case 'F':
718 if(args->action == aaFolder && !args->data.folder){
719 args->action = aaMore;
720 args->data.file = cpystr(str);
722 else{
723 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-F");
724 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
725 display_args_err(tmp_20k_buf, NULL, 1);
726 usage++;
729 break;
730 case 'd':
731 debug_str = str;
732 break;
733 case 'I':
734 cmd_list = str;
735 break;
736 case 'p':
737 if(str){
738 char path[MAXPATH], dir[MAXPATH];
740 if(IS_REMOTE(str) || is_absolute_path(str)){
741 strncpy(path, str, sizeof(path)-1);
742 path[sizeof(path)-1] = '\0';
744 else{
745 if(getcwd(dir, sizeof(path)) != NULL)
746 build_path(path, dir, str, sizeof(path));
747 else
748 alpine_panic(_("getcwd() call failed while parsing argument (1)"));
752 * Pinerc used to be the name of the pinerc
753 * file. Now, since the pinerc can be remote,
754 * we've replaced the variable pinerc with the
755 * structure prc. Unfortunately, other parts of
756 * pine rely on the fact that pinerc is the
757 * name of the pinerc _file_, and use the
758 * directory that the pinerc file is located
759 * in for their own purposes. We keep that so
760 * things will keep working.
763 if(!IS_REMOTE(path)){
764 if(pine_state->pinerc)
765 fs_give((void **)&pine_state->pinerc);
767 pine_state->pinerc = cpystr(path);
771 * Last one wins. This would be the place where
772 * we put multiple pinercs in a list if we
773 * were to allow that.
775 if(pine_state->prc)
776 free_pinerc_s(&pine_state->prc);
778 pine_state->prc = new_pinerc_s(path);
781 break;
782 case 'P':
783 if(str){
784 char path[MAXPATH], dir[MAXPATH];
786 if(IS_REMOTE(str) || is_absolute_path(str)){
787 strncpy(path, str, sizeof(path)-1);
788 path[sizeof(path)-1] = '\0';
790 else{
791 if(getcwd(dir, sizeof(path)) != NULL)
792 build_path(path, dir, str, sizeof(path));
793 else
794 alpine_panic(_("getcwd() call failed while parsing argument (2)"));
797 if(pine_state->pconf)
798 free_pinerc_s(&pine_state->pconf);
800 pine_state->pconf = new_pinerc_s(path);
803 break;
804 case 'x':
805 if(str)
806 pine_state->exceptions = cpystr(str);
808 break;
809 case 'c':
810 if(!isdigit((unsigned char)str[0])){
811 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
812 _(args_err_missing_flag_num), c);
813 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
814 display_args_err(tmp_20k_buf, NULL, 1);
815 ++usage;
816 break;
819 pine_state->init_context = (short) atoi(str);
820 break;
822 case 'n':
823 if(!isdigit((unsigned char)str[0])){
824 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
825 _(args_err_missing_flag_num), c);
826 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
827 display_args_err(tmp_20k_buf, NULL, 1);
828 ++usage;
829 break;
832 pine_state->start_entry = atoi(str);
833 if(pine_state->start_entry < 1)
834 pine_state->start_entry = 1;
836 break;
839 goto Loop;
841 default:
842 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_unknown), c);
843 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
844 display_args_err(tmp_20k_buf, NULL, 1);
845 ++usage;
846 break;
851 else if(args->action == aaMail
852 || (args->action == aaFolder && !args->data.folder)){
853 STRLIST_S *stp, **slp;
855 args->action = aaMail;
857 stp = new_strlist(*av);
859 for(slp = &args->data.mail.addrlist; *slp; slp = &(*slp)->next)
862 *slp = stp;
864 else{
865 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), *av);
866 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
867 display_args_err(tmp_20k_buf, NULL, 1);
868 usage++;
871 if(cmd_list){
872 int commas = 0;
873 char *p = cmd_list;
874 char *error = NULL;
876 while(*p++)
877 if(*p == ',')
878 ++commas;
880 COM_INIT_CMD_LIST = parse_list(cmd_list, commas+1, 0, &error);
881 if(error){
882 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_I_error), cmd_list, error);
883 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
884 display_args_err(tmp_20k_buf, NULL, 1);
885 exit(-1);
889 #ifdef DEBUG
890 pine_state->debug_nfiles = NUMDEBUGFILES;
891 #endif
892 if(debug_str && process_debug_str(debug_str))
893 usage++;
895 if(lc && strncmp(lc, ALPINE_FKEY_NAME, sizeof(ALPINE_FKEY_NAME) - 1) == 0)
896 do_use_fk = 1;
898 if(do_use_fk || do_can_suspend){
899 char list[500];
900 int commas = 0;
901 char *p = list;
902 char *error = NULL;
904 list[0] = '\0';
906 if(do_use_fk){
907 if(list[0]){
908 strncat(list, ",", sizeof(list)-strlen(list)-1);
909 list[sizeof(list)-1] = '\0';
912 strncat(list, "use-function-keys", sizeof(list)-strlen(list)-1);
913 list[sizeof(list)-1] = '\0';
916 if(do_can_suspend){
917 if(list[0]){
918 strncat(list, ",", sizeof(list)-strlen(list)-1);
919 list[sizeof(list)-1] = '\0';
922 strncat(list, "enable-suspend", sizeof(list)-strlen(list)-1);
923 list[sizeof(list)-1] = '\0';
926 while(*p++)
927 if(*p == ',')
928 ++commas;
930 pine_state->feat_list_back_compat = parse_list(list,commas+1,0,&error);
931 if(error){
932 snprintf(tmp_20k_buf, SIZEOF_20KBUF, args_err_internal, error);
933 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
934 display_args_err(tmp_20k_buf, NULL, 1);
935 exit(-1);
939 if(((do_conf ? 1 : 0)+(pinerc_file ? 1 : 0)) > 1){
940 display_args_err(_("May only have one of -conf and -pinerc"),
941 NULL, 1);
942 exit(-1);
945 if((xoauth2_server || xoauth2_client_id || xoauth2_client_secret)
946 && !(xoauth2_server && xoauth2_client_id && xoauth2_client_secret)){
947 display_args_err(_(args_err_missing_xoauth_option), NULL, 1);
948 ++usage;
951 if(do_help || usage)
952 args_help();
954 if(usage)
955 exit(-1);
957 if(xoauth2_server){
958 char *tmp1, *tmp2;
959 tmp2 = xoauth_config_line(xoauth2_server, xoauth2_client_id, xoauth2_client_secret);
960 if(tmp2){
961 tmp1 = fs_get((strlen(ps_global->vars[V_XOAUTH2_INFO].name) + strlen(tmp2) + 2)*sizeof(char));
962 if(tmp1){
963 sprintf(tmp1,"%s=%s", ps_global->vars[V_XOAUTH2_INFO].name, tmp2);
964 pinerc_cmdline_opt(tmp1);
965 fs_give((void **) &tmp1);
967 fs_give((void **) &tmp2);
971 if(do_version){
972 extern char datestamp[], hoststamp[];
973 char rev[128];
975 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Alpine %s (%s %s) built %s on %s",
976 ALPINE_VERSION,
977 SYSTYPE ? SYSTYPE : "?",
978 get_alpine_revision_string(rev, sizeof(rev)),
979 datestamp, hoststamp);
980 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
981 display_args_err(tmp_20k_buf, NULL, 0);
982 exit(0);
985 if(do_conf)
986 dump_global_conf();
988 if(pinerc_file)
989 dump_new_pinerc(pinerc_file);
992 * Don't NULL out argv[0] or we might crash in unexpected ways. In OS X, we were
993 * crashing when opening attachments because of this.
995 if(ac <= 0 && av != argv)
996 *av = NULL;
1001 * Returns 0 if ok, -1 if error.
1004 process_debug_str(char *debug_str)
1006 int i, usage = 0;
1007 int commas = 0;
1008 int new_style_debug_arg = 0;
1009 char *q = debug_str;
1010 char *error = NULL;
1011 char **list, **p;
1013 #ifdef DEBUG
1014 if(debug_str){
1015 if(!isdigit((unsigned char)debug_str[0]))
1016 new_style_debug_arg++;
1018 if(new_style_debug_arg){
1019 while(*q++)
1020 if(*q == ',')
1021 ++commas;
1023 list = parse_list(debug_str, commas+1, 0, &error);
1024 if(error){
1025 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_d_error), debug_str, error);
1026 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1027 display_args_err(tmp_20k_buf, NULL, 1);
1028 return(-1);
1031 if(list){
1032 for(p = list; *p; p++){
1033 if(struncmp(*p, "timestamp", 9) == 0){
1034 ps_global->debug_timestamp = 1;
1036 else if(struncmp(*p, "imap", 4) == 0){
1037 q = *p + 4;
1038 if(!*q || !*(q+1) || *q != '=' ||
1039 !isdigit((unsigned char)*(q+1))){
1040 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
1041 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1042 display_args_err(tmp_20k_buf, NULL, 1);
1043 usage = -1;
1045 else{
1046 i = atoi(q+1);
1047 ps_global->debug_imap = MIN(5,MAX(0,i));
1050 else if(struncmp(*p, "flush", 5) == 0){
1051 ps_global->debug_flush = 1;
1053 else if(struncmp(*p, "tcp", 3) == 0
1054 || struncmp(*p, "tcpdebug", 8) == 0){
1055 ps_global->debug_tcp = 1;
1057 else if(struncmp(*p, "verbose", 7) == 0){
1058 q = *p + 7;
1059 if(!*q || !*(q+1) || *q != '=' ||
1060 !isdigit((unsigned char)*(q+1))){
1061 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
1062 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1063 display_args_err(tmp_20k_buf, NULL, 1);
1064 usage = -1;
1066 else
1067 debug = atoi(q+1);
1069 else if(struncmp(*p, "numfiles", 8) == 0){
1070 q = *p + 8;
1071 if(!*q || !*(q+1) || *q != '=' ||
1072 !isdigit((unsigned char)*(q+1))){
1073 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
1074 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1075 display_args_err(tmp_20k_buf, NULL, 1);
1076 usage = -1;
1078 else{
1079 i = atoi(q+1);
1080 ps_global->debug_nfiles = MIN(31,MAX(0,i));
1083 else if(struncmp(*p, "malloc", 6) == 0){
1084 q = *p + 6;
1085 if(!*q || !*(q+1) || *q != '=' ||
1086 !isdigit((unsigned char)*(q+1))){
1087 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
1088 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1089 display_args_err(tmp_20k_buf, NULL, 1);
1090 usage = -1;
1092 else{
1093 i = atoi(q+1);
1094 ps_global->debug_malloc = MIN(63,MAX(0,i));
1097 #if defined(ENABLE_LDAP) && defined(LDAP_DEBUG)
1098 else if(struncmp(*p, "ldap", 4) == 0){
1099 q = *p + 4;
1100 if(!*q || !*(q+1) || *q != '=' ||
1101 !isdigit((unsigned char)*(q+1))){
1102 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
1103 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1104 display_args_err(tmp_20k_buf, NULL, 1);
1105 usage = -1;
1107 else{
1108 i = atoi(q+1);
1109 ldap_debug = i;
1112 #endif /* LDAP */
1113 else{
1114 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("unknown debug keyword \"%s\""), *p);
1115 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1116 display_args_err(tmp_20k_buf, NULL, 1);
1117 usage = -1;
1121 free_list_array(&list);
1124 else{
1125 debug = atoi(debug_str);
1126 if(debug > 9)
1127 ps_global->debug_imap = 5;
1128 else if(debug > 7)
1129 ps_global->debug_imap = 4;
1130 else if(debug > 6)
1131 ps_global->debug_imap = 3;
1132 else if(debug > 4)
1133 ps_global->debug_imap = 2;
1134 else if(debug > 2)
1135 ps_global->debug_imap = 1;
1137 if(debug > 7)
1138 ps_global->debug_timestamp = 1;
1140 if(debug > 8)
1141 ps_global->debug_flush = 1;
1145 if(!new_style_debug_arg){
1146 #ifdef CSRIMALLOC
1147 ps_global->debug_malloc =
1148 (debug <= DEFAULT_DEBUG) ? 1 : (debug < 9) ? 2 : 3;
1149 #else /* !CSRIMALLOC */
1150 #ifdef HAVE_SMALLOC
1151 if(debug > 8)
1152 ps_global->debug_malloc = 2;
1153 #else /* !HAVE_SMALLOC */
1154 #ifdef NXT
1155 if(debug > 8)
1156 ps_global->debug_malloc = 32;
1157 #endif /* NXT */
1158 #endif /* HAVE_SMALLOC */
1159 #endif /* CSRIMALLOC */
1162 #else /* !DEBUG */
1164 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("unknown flag \"d\", debugging not compiled in"));
1165 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1166 display_args_err(tmp_20k_buf, NULL, 1);
1167 usage = -1;
1169 #endif /* !DEBUG */
1171 return(usage);
1175 void
1176 args_add_attach(PATMT **alpp, char *s, int deleted)
1178 PATMT *atmp, **atmpp;
1180 atmp = (PATMT *) fs_get(sizeof(PATMT));
1181 memset(atmp, 0, sizeof(PATMT));
1182 atmp->filename = cpystr(s);
1184 #if defined(DOS) || defined(OS2)
1185 (void) removing_quotes(atmp->filename);
1186 #endif
1188 if(deleted)
1189 atmp->flags |= A_TMP;
1191 for(atmpp = alpp; *atmpp; atmpp = &(*atmpp)->next)
1194 *atmpp = atmp;
1198 /*----------------------------------------------------------------------
1199 print a few lines of help for command line arguments
1201 Args: none
1203 Result: prints help messages
1204 ----------------------------------------------------------------------*/
1205 void
1206 args_help(void)
1208 char *pp[2];
1209 #ifndef _WINDOWS
1210 char **a;
1211 #endif
1213 pp[1] = NULL;
1215 /** print out possible starting arguments... **/
1218 * display_args_err expects already translated input
1219 * so we need to translate a line at a time. Since
1220 * the 1st and 3rd args are zero it is ok to call it
1221 * a line at a time.
1223 * Windows expects the full block of text so we'll pass
1224 * it as such.
1226 #ifndef _WINDOWS
1227 for(a=args_pine_args; a && *a; a++){
1228 pp[0] = _(*a);
1229 display_args_err(NULL, pp, 0);
1231 #else
1232 display_args_err(NULL, args_pine_args, 0);
1233 #endif
1235 exit(1);
1239 /*----------------------------------------------------------------------
1240 write argument error to the display...
1242 Args: none
1244 Result: prints help messages
1245 ----------------------------------------------------------------------*/
1246 void
1247 display_args_err(char *s, char **a, int err)
1249 char errstr[256], *errp;
1250 FILE *fp = err ? stderr : stdout;
1253 if(err && s){
1254 snprintf(errp = errstr, sizeof(errstr), "%s: %s", _("Argument Error"), s);
1255 errstr[sizeof(errstr)-1] = '\0';
1257 else
1258 errp = s;
1260 #ifdef _WINDOWS
1261 if(errp)
1262 mswin_messagebox(errp, err);
1264 if(a && *a){
1265 os_argsdialog(a);
1267 #else
1268 if(errp)
1269 fprintf(fp, "%s\n", errp);
1271 while(a && *a)
1272 fprintf(fp, "%s\n", *a++);
1273 #endif
1278 * The argument is an argument from the command line. We check to see
1279 * if it is specifying an alternate value for one of the options that is
1280 * normally set in pinerc. If so, we return 1 and set the appropriate
1281 * values in the variables array.
1282 * The arg can be
1283 * varname=value
1284 * varname=value1,value2,value3
1285 * feature-list=featurename these are just a special
1286 * feature-list=featurename1,featurename2 case of above
1287 * featurename This is equivalent to above
1288 * no-featurename
1291 pinerc_cmdline_opt(char *arg)
1293 struct variable *v;
1294 char *p1 = NULL,
1295 *value,
1296 **oldlvalue = NULL,
1297 **lvalue;
1298 int i, count;
1300 if(!arg || !arg[0])
1301 return 0;
1303 if((value = strchr(arg, '=')) != NULL){
1304 i = value - arg;
1305 arg[i] = '\0';
1307 else
1308 i = -1;
1310 for(v = ps_global->vars; v->name != NULL; v++){
1311 if(v->is_used && strucmp(v->name, arg) == 0){
1312 p1 = arg + strlen(v->name);
1313 if(i > 0) arg[i] = '=';
1315 /*----- Skip to '=' -----*/
1316 while(*p1 && (*p1 == '\t' || *p1 == ' '))
1317 p1++;
1319 if(*p1 != '='){
1320 char buf[MAILTMPLEN];
1322 snprintf(buf, sizeof(buf), _("Missing \"=\" after -%s\n"), v->name);
1323 buf[sizeof(buf)-1] = '\0';
1324 exceptional_exit(buf, -1);
1327 p1++;
1328 break;
1333 if(i > 0) arg[i] = '=';
1335 /* no match, check for a feature name used directly */
1336 if(v->name == NULL){
1337 FEATURE_S *feat;
1338 char *featname;
1340 if(struncmp(arg, "no-", 3) == 0)
1341 featname = arg+3;
1342 else
1343 featname = arg;
1345 for(i = 0; (feat = feature_list(i)) != NULL; i++){
1346 if(strucmp(featname, feat->name) == 0){
1347 v = &(ps_global->vars)[V_FEATURE_LIST];
1348 p1 = arg;
1349 break;
1354 if(!p1)
1355 return 0;
1357 if(v->is_obsolete || !v->is_user){
1358 char buf[MAILTMPLEN];
1360 if(v->is_obsolete)
1361 snprintf(buf, sizeof(buf), _("Option \"%s\" is obsolete\n"), v->name);
1362 else
1363 snprintf(buf, sizeof(buf), _("Option \"%s\" is not user settable\n"), v->name);
1365 exceptional_exit(buf, -1);
1368 /* free mem */
1369 if(v->is_list){
1370 oldlvalue = v->cmdline_val.l;
1371 v->cmdline_val.l = NULL;
1373 else if(v->cmdline_val.p)
1374 fs_give((void **) &(v->cmdline_val.p));
1376 /*----- Matched a variable, get its value ----*/
1377 while(*p1 == ' ' || *p1 == '\t')
1378 p1++;
1379 value = p1;
1381 if(*value == '\0'){
1382 if(v->is_list){
1383 v->cmdline_val.l = (char **)fs_get(2 * sizeof(char *));
1385 * we let people leave off the quotes on command line so that
1386 * they don't have to mess with shell quoting
1388 v->cmdline_val.l[0] = cpystr("");
1389 v->cmdline_val.l[1] = NULL;
1390 if(oldlvalue)
1391 free_list_array(&oldlvalue);
1393 }else{
1394 v->cmdline_val.p = cpystr("");
1396 return 1;
1399 /*--value is non-empty--*/
1400 if(*value == '"' && !v->is_list){
1401 value++;
1402 for(p1 = value; *p1 && *p1 != '"'; p1++)
1404 if(*p1 == '"')
1405 *p1 = '\0';
1406 else
1407 removing_trailing_white_space(value);
1408 }else{
1409 removing_trailing_white_space(value);
1412 if(v->is_list){
1413 int was_quoted = 0;
1414 char *error = NULL;
1416 count = 1;
1417 for(p1=value; *p1; p1++){ /* generous count of list elements */
1418 if(*p1 == '"') /* ignore ',' if quoted */
1419 was_quoted = (was_quoted) ? 0 : 1;
1421 if(*p1 == ',' && !was_quoted)
1422 count++;
1425 lvalue = parse_list(value, count, 0, &error);
1426 if(error){
1427 char buf[MAILTMPLEN];
1429 snprintf(buf, sizeof(buf), "%s in %s = \"%s\"\n", error, v->name, value);
1430 buf[sizeof(buf)-1] = '\0';
1431 exceptional_exit(buf, -1);
1434 * Special case: turn "" strings into empty strings.
1435 * This allows users to turn off default lists. For example,
1436 * if smtp-server is set then a user could override smtp-server
1437 * with smtp-server="".
1439 for(i = 0; lvalue[i]; i++)
1440 if(lvalue[i][0] == '"' &&
1441 lvalue[i][1] == '"' &&
1442 lvalue[i][2] == '\0')
1443 lvalue[i][0] = '\0';
1446 if(v->is_list){
1447 if(oldlvalue){
1448 char **combinedlvalue;
1449 int j;
1451 /* combine old and new cmdline lists */
1452 for(count = 0, i = 0; oldlvalue[i]; i++, count++)
1455 for(i = 0; lvalue && lvalue[i]; i++, count++)
1458 combinedlvalue = (char **) fs_get((count+1) * sizeof(char *));
1459 memset(combinedlvalue, 0, (count+1) * sizeof(*combinedlvalue));
1461 for(i = 0, j = 0; oldlvalue[i]; i++, j++)
1462 combinedlvalue[j] = cpystr(oldlvalue[i]);
1464 for(i = 0; lvalue && lvalue[i]; i++, j++)
1465 combinedlvalue[j] = cpystr(lvalue[i]);
1467 v->cmdline_val.l = combinedlvalue;
1469 fs_give((void **) &oldlvalue);
1470 if(lvalue)
1471 fs_give((void **) &lvalue);
1473 else
1474 v->cmdline_val.l = lvalue;
1476 else
1477 v->cmdline_val.p = cpystr(value);
1479 return 1;