* Update to version 2.19.5
[alpine.git] / alpine / arg.c
blob9391a1db62029b8be2f35b80098547e899992ec9
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 2006-2008 University of Washington
8 * Copyright 2013-2014 Eduardo Chappa
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"
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 PASSFILE
59 static char args_err_missing_passfile[] = N_("missing argument for option \"-passfile\"");
60 static char args_err_non_abs_passfile[] = N_("argument to \"-passfile\" should be fully-qualified");
61 #endif
62 static char args_err_missing_sort[] = N_("missing argument for option \"-sort\"");
63 static char args_err_missing_flag_arg[] = N_("missing argument for flag \"%c\"");
64 static char args_err_missing_flag_num[] = N_("Non numeric argument for flag \"%c\"");
65 static char args_err_missing_debug_num[] = N_("Non numeric argument for \"%s\"");
66 static char args_err_missing_url[] = N_("missing URL for \"-url\"");
67 static char args_err_missing_attachment[] = N_("missing attachment for \"%s\"");
68 static char args_err_conflict[] = N_("conflicting action: \"%s\"");
69 static char args_err_unknown[] = N_("unknown flag \"%c\"");
70 static char args_err_I_error[] = N_("-I argument \"%s\": %s");
71 static char args_err_d_error[] = N_("-d argument \"%s\": %s");
72 static char args_err_internal[] = "%s";
73 static char args_err_missing_copyprc[] = N_("missing argument for option \"-copy_pinerc\"\nUsage: pine -copy_pinerc <local_pinerc> <remote_pinerc>");
74 static char args_err_missing_copyabook[] = N_("missing argument for option \"-copy_abook\"\nUsage: pine -copy_abook <local_abook> <remote_abook>");
77 static char *args_pine_args[] = {
78 N_("Possible Starting Arguments for Alpine program:"),
79 "",
80 N_(" Argument\tMeaning"),
81 N_(" <addrs>...\tGo directly into composer sending to given address"),
82 N_("\t\tList multiple addresses with a single space between them."),
83 N_("\t\tStandard input redirection is allowed with addresses."),
84 N_("\t\tNote: Places addresses in the \"To\" field only."),
85 N_(" -attach <file>\tGo directly into composer with given file"),
86 N_(" -attachlist <file-list>"),
87 N_(" -attach_and_delete <file>"),
88 N_("\t\tGo to composer, attach file, delete when finished"),
89 N_("\t\tNote: Attach options can't be used if -f, -F"),
90 N_("\t\tadded to Attachment list. Attachlist must be the last"),
91 N_("\t\toption on the command line"),
92 N_(" -bail\t\tExit if pinerc file doesn't already exist"),
93 #ifdef DEBUG
94 N_(" -d n\t\tDebug - set debug level to 'n', or use the following:"),
95 N_(" -d keywords...\tflush,timestamp,imap=0..4,tcp,numfiles=0..31,verbose=0..9"),
96 #endif
97 N_(" -f <folder>\tFolder - give folder name to open"),
98 N_(" -c <number>\tContext - which context to apply to -f arg"),
99 N_(" -F <file>\tFile - give file name to open and page through and"),
100 N_("\t\tforward as email."),
101 N_(" -h \t\tHelp - give this list of options"),
102 N_(" -k \t\tKeys - Force use of function keys"),
103 N_(" -z \t\tSuspend - allow use of ^Z suspension"),
104 N_(" -r \t\tRestricted - can only send mail to oneself"),
105 N_(" -sort <sort>\tSort - Specify sort order of folder:"),
106 N_("\t\t\tarrival, subject, threaded, orderedsubject, date,"),
107 N_("\t\t\tfrom, size, score, to, cc, /reverse"),
108 N_(" -i\t\tIndex - Go directly to index, bypassing main menu"),
109 N_(" -I <keystroke_list> Initial keystrokes to be executed"),
110 N_(" -n <number>\tEntry in index to begin on"),
111 N_(" -o \t\tReadOnly - Open first folder read-only"),
112 N_(" -conf\t\tConfiguration - Print out fresh global configuration. The"),
113 N_("\t\tvalues of your global configuration affect all Alpine users"),
114 N_("\t\ton your system unless they have overridden the values in their"),
115 N_("\t\tpinerc files."),
116 N_(" -pinerc <file>\tConfiguration - Put fresh pinerc configuration in <file>"),
117 N_(" -p <pinerc>\tUse alternate .pinerc file"),
118 #if !defined(DOS) && !defined(OS2)
119 N_(" -P <pine.conf>\tUse alternate pine.conf file"),
120 #else
121 N_(" -aux <aux_files_dir>\tUse this with remote pinerc"),
122 N_(" -P <pine.conf>\tUse pine.conf file for default settings"),
123 N_(" -nosplash \tDisable the PC-Alpine splash screen"),
124 #endif
126 #if defined(APPLEKEYCHAIN) || (WINCRED > 0)
127 N_(" -erase_stored_passwords\tEliminate any stored passwords"),
128 #endif
130 #ifdef PASSFILE
131 N_(" -passfile <fully_qualified_filename>\tSet the password file to something other"),
132 N_("\t\tthan the default"),
133 #endif /* PASSFILE */
135 #ifdef LOCAL_PASSWD_CACHE
136 N_(" -nowrite_password_cache\tRead from a password cache if there is one, but"),
137 N_("\t\t\t\tnever offer to write a password to the cache"),
138 #endif /* LOCAL_PASSWD_CACHE */
140 N_(" -x <config>\tUse configuration exceptions in <config>."),
141 N_("\t\tExceptions are used to override your default pinerc"),
142 N_("\t\tsettings for a particular platform, can be a local file or"),
143 N_("\t\ta remote folder."),
144 N_(" -v \t\tVersion - show version information"),
145 N_(" -version\tVersion - show version information"),
146 N_(" -supported\tList supported options"),
147 N_(" -url <url>\tOpen the given URL"),
148 N_("\t\tNote: Can't be used if -f, -F"),
149 N_("\t\tStandard input redirection is not allowed with URLs."),
150 N_("\t\tFor mailto URLs, 'body='text should be used in place of"),
151 N_("\t\tinput redirection."),
152 N_(" -copy_pinerc <local_pinerc> <remote_pinerc> copy local pinerc to remote"),
153 N_(" -copy_abook <local_abook> <remote_abook> copy local addressbook to remote"),
154 N_(" -convert_sigs -p <pinerc> convert signatures to literal signatures"),
155 #if defined(_WINDOWS)
156 N_(" -install \tPrompt for some basic setup information"),
157 N_(" -uninstall \tRemove traces of Alpine from Windows system settings"),
158 N_(" -registry <cmd>\tWhere cmd is set,noset,clear,clearsilent,dump"),
159 #endif
160 " -<option>=<value> Assign <value> to the pinerc option <option>",
161 "\t\t e.g. -signature-file=sig1",
162 "\t\t e.g. -color-style=no-color",
163 "\t\t e.g. -feature-list=enable-sigdashes",
164 "\t\t Note: feature-list is additive.",
165 "\t\t You may leave off the \"feature-list=\" part of that,",
166 "\t\t e.g. -enable-sigdashes",
167 NULL
173 * Parse the command line args.
175 * Args: pine_state -- The pine_state structure to put results in
176 * argc, argv -- The obvious
177 * addrs -- Pointer to address list that we set for caller
179 * Result: command arguments parsed
180 * possible printing of help for command line
181 * various flags in pine_state set
182 * returns the string name of the first folder to open
183 * addrs is set
185 void
186 pine_args(struct pine *pine_state, int argc, char **argv, ARGDATA_S *args)
188 register int ac;
189 register char **av;
190 int c;
191 char *str;
192 char *cmd_list = NULL;
193 char *debug_str = NULL;
194 char *sort = NULL;
195 char *pinerc_file = NULL;
196 char *lc = NULL;
197 int do_help = 0;
198 int do_conf = 0;
199 int usage = 0;
200 int do_use_fk = 0;
201 int do_can_suspend = 0;
202 int do_version = 0;
203 struct variable *vars = pine_state->vars;
205 ac = argc;
206 av = argv;
207 memset(args, 0, sizeof(ARGDATA_S));
208 args->action = aaFolder;
210 pine_state->pine_name = (lc = last_cmpnt(argv[0])) ? lc : (lc = argv[0]);
211 #ifdef DOS
212 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%.*s", pine_state->pine_name - argv[0], argv[0]);
213 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
214 pine_state->pine_dir = cpystr(tmp_20k_buf);
215 #endif
217 /* while more arguments with leading - */
218 Loop: while(--ac > 0)
219 if(**++av == '-'){
220 /* while more chars in this argument */
221 while(*++*av){
222 /* check for pinerc options */
223 if(pinerc_cmdline_opt(*av)){
224 goto Loop; /* done with this arg, go to next */
226 /* then other multi-char options */
227 else if(strcmp(*av, "conf") == 0){
228 do_conf = 1;
229 goto Loop; /* done with this arg, go to next */
231 else if(strcmp(*av, "pinerc") == 0){
232 if(--ac)
233 pinerc_file = *++av;
234 else{
235 display_args_err(_(args_err_missing_pinerc), NULL, 1);
236 ++usage;
239 goto Loop;
241 #if defined(DOS) || defined(OS2)
242 else if(strcmp(*av, "aux") == 0){
243 if(--ac){
244 if((str = *++av) != NULL)
245 pine_state->aux_files_dir = cpystr(str);
247 else{
248 display_args_err(_(args_err_missing_aux), NULL, 1);
249 ++usage;
252 goto Loop;
254 else if(strcmp(*av, "nosplash") == 0)
255 goto Loop; /* already taken care of in WinMain */
256 #endif
258 #if defined(APPLEKEYCHAIN) || (WINCRED > 0)
259 else if(strcmp(*av, "erase_stored_passwords") == 0){
260 #if (WINCRED > 0)
261 erase_windows_credentials();
262 #else
263 macos_erase_keychain();
264 #endif
265 goto Loop;
267 #endif /* defined(APPLEKEYCHAIN) || (WINCRED > 0) */
269 #ifdef PASSFILE
270 else if(strcmp(*av, "passfile") == 0){
271 if(--ac){
272 if((str = *++av) != NULL){
273 if(!is_absolute_path(str)){
274 display_args_err(_(args_err_non_abs_passfile),
275 NULL, 1);
276 ++usage;
278 else{
279 if(pine_state->passfile)
280 fs_give((void **)&pine_state->passfile);
282 pine_state->passfile = cpystr(str);
286 else{
287 display_args_err(_(args_err_missing_passfile), NULL, 1);
288 ++usage;
291 goto Loop;
293 #endif /* PASSFILE */
295 #ifdef LOCAL_PASSWD_CACHE
296 else if(strcmp(*av, "nowrite_password_cache") == 0){
297 ps_global->nowrite_password_cache = 1;
298 goto Loop;
300 #endif /* LOCAL_PASSWD_CACHE */
302 else if(strcmp(*av, "convert_sigs") == 0){
303 ps_global->convert_sigs = 1;
304 goto Loop;
306 else if(strcmp(*av, "supported") == 0){
307 ps_global->dump_supported_options = 1;
308 goto Loop;
310 else if(strcmp(*av, "copy_pinerc") == 0){
311 if(args->action == aaFolder && !args->data.folder){
312 args->action = aaPrcCopy;
313 if(ac > 2){
314 ac -= 2;
315 args->data.copy.local = *++av;
316 args->data.copy.remote = *++av;
318 else{
319 display_args_err(_(args_err_missing_copyprc), NULL, 1);
320 ++usage;
323 else{
324 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-copy_pinerc");
325 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
326 display_args_err(tmp_20k_buf, NULL, 1);
327 ++usage;
330 goto Loop;
332 else if(strcmp(*av, "copy_abook") == 0){
333 if(args->action == aaFolder && !args->data.folder){
334 args->action = aaAbookCopy;
335 if(ac > 2){
336 ac -= 2;
337 args->data.copy.local = *++av;
338 args->data.copy.remote = *++av;
340 else{
341 display_args_err(_(args_err_missing_copyabook), NULL, 1);
342 ++usage;
345 else{
346 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-copy_abook");
347 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
348 display_args_err(tmp_20k_buf, NULL, 1);
349 ++usage;
352 goto Loop;
354 else if(strcmp(*av, "sort") == 0){
355 if(--ac){
356 sort = *++av;
357 COM_SORT_KEY = cpystr(sort);
359 else{
360 display_args_err(_(args_err_missing_sort), NULL, 1);
361 ++usage;
364 goto Loop;
366 else if(strcmp(*av, "url") == 0){
367 if(args->action == aaFolder && !args->data.folder){
368 args->action = aaURL;
369 if(--ac){
370 args->url = cpystr(*++av);
372 else{
373 display_args_err(_(args_err_missing_url), NULL, 1);
374 ++usage;
377 else{
378 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-url");
379 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
380 display_args_err(tmp_20k_buf, NULL, 1);
381 ++usage;
384 goto Loop;
386 else if(strcmp(*av, "attach") == 0){
387 if((args->action == aaFolder && !args->data.folder)
388 || args->action == aaMail
389 || args->action == aaURL){
390 if(args->action != aaURL)
391 args->action = aaMail;
392 if(--ac){
393 args_add_attach(&args->data.mail.attachlist,
394 *++av, FALSE);
396 else{
397 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attach");
398 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
399 display_args_err(tmp_20k_buf, NULL, 1);
400 ++usage;
403 else{
404 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attach");
405 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
406 display_args_err(tmp_20k_buf, NULL, 1);
407 ++usage;
410 goto Loop;
412 else if(strcmp(*av, "attachlist") == 0){
413 if((args->action == aaFolder && !args->data.folder)
414 || args->action == aaMail
415 || args->action == aaURL){
416 if(args->action != aaURL)
417 args->action = aaMail;
418 if(ac - 1){
420 if(can_access(*(av+1), READ_ACCESS) == 0){
421 ac--;
422 args_add_attach(&args->data.mail.attachlist,
423 *++av, FALSE);
425 else
426 break;
428 while(ac);
430 else{
431 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attachList");
432 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
433 display_args_err(tmp_20k_buf, NULL, 1);
434 ++usage;
437 else{
438 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attachList");
439 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
440 display_args_err(tmp_20k_buf, NULL, 1);
441 ++usage;
444 goto Loop;
446 else if(strcmp(*av, "attach_and_delete") == 0){
447 if((args->action == aaFolder && !args->data.folder)
448 || args->action == aaMail
449 || args->action == aaURL){
450 if(args->action != aaURL)
451 args->action = aaMail;
452 if(--ac){
453 args_add_attach(&args->data.mail.attachlist,
454 *++av, TRUE);
456 else{
457 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attach_and_delete");
458 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
459 display_args_err(tmp_20k_buf, NULL, 1);
460 ++usage;
463 else{
464 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attach_and_delete");
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, "bail") == 0){
473 pine_state->exit_if_no_pinerc = 1;
474 goto Loop;
476 else if(strcmp(*av, "version") == 0){
477 do_version = 1;
478 goto Loop;
480 #ifdef _WINDOWS
481 else if(strcmp(*av, "install") == 0){
482 pine_state->install_flag = 1;
483 pine_state->update_registry = UREG_ALWAYS_SET;
484 goto Loop;
486 else if(strcmp(*av, "uninstall") == 0){
488 * Blast password cache, clear registry settings
490 #if (WINCRED > 0)
491 erase_windows_credentials();
492 #endif
493 mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0);
494 exit(0);
496 else if(strcmp(*av, "registry") == 0){
497 if(--ac){
498 if(!strucmp(*++av, "set")){
499 pine_state->update_registry = UREG_ALWAYS_SET;
501 else if(!strucmp(*av, "noset")){
502 pine_state->update_registry = UREG_NEVER_SET;
504 else if(!strucmp(*av, "clear")){
505 if(!mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0))
506 display_args_err(
507 _("Alpine related Registry values removed."),
508 NULL, 0);
509 else
510 display_args_err(
511 _("Not all Alpine related Registry values could be removed"),
512 NULL, 0);
513 exit(0);
515 else if(!strucmp(*av, "clearsilent")){
516 mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0);
517 exit(0);
519 else if(!strucmp(*av, "dump")){
520 char **pRegistry = mswin_reg_dump();
522 if(pRegistry){
523 display_args_err(NULL, pRegistry, 0);
524 free_list_array(&pRegistry);
526 exit(0);
528 else{
529 display_args_err(_("unknown registry command"),
530 NULL, 1);
531 ++usage;
534 else{
535 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_flag_arg), c);
536 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
537 display_args_err(tmp_20k_buf, NULL, 1);
538 ++usage;
541 goto Loop;
543 #endif
544 /* single char flags */
545 else{
546 switch(c = **av){
547 case 'h':
548 do_help = 1;
549 break; /* break back to inner-while */
550 case 'k':
551 do_use_fk = 1;
552 break;
553 case 'z':
554 do_can_suspend = 1;
555 break;
556 case 'r':
557 pine_state->restricted = 1;
558 break;
559 case 'o':
560 pine_state->open_readonly_on_startup = 1;
561 break;
562 case 'i':
563 pine_state->start_in_index = 1;
564 break;
565 case 'v':
566 do_version = 1;
567 break; /* break back to inner-while */
568 /* these take arguments */
569 case 'f': case 'F': case 'p': case 'I':
570 case 'c': case 'd': case 'P': case 'x': /* string args */
571 case 'n': /* integer args */
572 if(*++*av)
573 str = *av;
574 else if(--ac)
575 str = *++av;
576 else if(c == 'f' || c == 'F')
577 str = "";
578 else{
579 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_flag_arg), c);
580 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
581 display_args_err(tmp_20k_buf, NULL, 1);
582 ++usage;
583 goto Loop;
586 switch(c){
587 case 'f':
588 if(args->action == aaFolder && !args->data.folder){
589 args->data.folder = cpystr(str);
591 else{
592 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-f");
593 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
594 display_args_err(tmp_20k_buf, NULL, 1);
595 usage++;
598 break;
599 case 'F':
600 if(args->action == aaFolder && !args->data.folder){
601 args->action = aaMore;
602 args->data.file = cpystr(str);
604 else{
605 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-F");
606 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
607 display_args_err(tmp_20k_buf, NULL, 1);
608 usage++;
611 break;
612 case 'd':
613 debug_str = str;
614 break;
615 case 'I':
616 cmd_list = str;
617 break;
618 case 'p':
619 if(str){
620 char path[MAXPATH], dir[MAXPATH];
622 if(IS_REMOTE(str) || is_absolute_path(str)){
623 strncpy(path, str, sizeof(path)-1);
624 path[sizeof(path)-1] = '\0';
626 else{
627 getcwd(dir, sizeof(path));
628 build_path(path, dir, str, sizeof(path));
632 * Pinerc used to be the name of the pinerc
633 * file. Now, since the pinerc can be remote,
634 * we've replaced the variable pinerc with the
635 * structure prc. Unfortunately, other parts of
636 * pine rely on the fact that pinerc is the
637 * name of the pinerc _file_, and use the
638 * directory that the pinerc file is located
639 * in for their own purposes. We keep that so
640 * things will keep working.
643 if(!IS_REMOTE(path)){
644 if(pine_state->pinerc)
645 fs_give((void **)&pine_state->pinerc);
647 pine_state->pinerc = cpystr(path);
651 * Last one wins. This would be the place where
652 * we put multiple pinercs in a list if we
653 * were to allow that.
655 if(pine_state->prc)
656 free_pinerc_s(&pine_state->prc);
658 pine_state->prc = new_pinerc_s(path);
661 break;
662 case 'P':
663 if(str){
664 char path[MAXPATH], dir[MAXPATH];
666 if(IS_REMOTE(str) || is_absolute_path(str)){
667 strncpy(path, str, sizeof(path)-1);
668 path[sizeof(path)-1] = '\0';
670 else{
671 getcwd(dir, sizeof(path));
672 build_path(path, dir, str, sizeof(path));
675 if(pine_state->pconf)
676 free_pinerc_s(&pine_state->pconf);
678 pine_state->pconf = new_pinerc_s(path);
681 break;
682 case 'x':
683 if(str)
684 pine_state->exceptions = cpystr(str);
686 break;
687 case 'c':
688 if(!isdigit((unsigned char)str[0])){
689 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
690 _(args_err_missing_flag_num), c);
691 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
692 display_args_err(tmp_20k_buf, NULL, 1);
693 ++usage;
694 break;
697 pine_state->init_context = (short) atoi(str);
698 break;
700 case 'n':
701 if(!isdigit((unsigned char)str[0])){
702 snprintf(tmp_20k_buf, SIZEOF_20KBUF,
703 _(args_err_missing_flag_num), c);
704 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
705 display_args_err(tmp_20k_buf, NULL, 1);
706 ++usage;
707 break;
710 pine_state->start_entry = atoi(str);
711 if(pine_state->start_entry < 1)
712 pine_state->start_entry = 1;
714 break;
717 goto Loop;
719 default:
720 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_unknown), c);
721 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
722 display_args_err(tmp_20k_buf, NULL, 1);
723 ++usage;
724 break;
729 else if(args->action == aaMail
730 || (args->action == aaFolder && !args->data.folder)){
731 STRLIST_S *stp, **slp;
733 args->action = aaMail;
735 stp = new_strlist(*av);
737 for(slp = &args->data.mail.addrlist; *slp; slp = &(*slp)->next)
740 *slp = stp;
742 else{
743 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), *av);
744 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
745 display_args_err(tmp_20k_buf, NULL, 1);
746 usage++;
749 if(cmd_list){
750 int commas = 0;
751 char *p = cmd_list;
752 char *error = NULL;
754 while(*p++)
755 if(*p == ',')
756 ++commas;
758 COM_INIT_CMD_LIST = parse_list(cmd_list, commas+1, 0, &error);
759 if(error){
760 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_I_error), cmd_list, error);
761 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
762 display_args_err(tmp_20k_buf, NULL, 1);
763 exit(-1);
767 #ifdef DEBUG
768 pine_state->debug_nfiles = NUMDEBUGFILES;
769 #endif
770 if(debug_str && process_debug_str(debug_str))
771 usage++;
773 if(lc && strncmp(lc, ALPINE_FKEY_NAME, sizeof(ALPINE_FKEY_NAME) - 1) == 0)
774 do_use_fk = 1;
776 if(do_use_fk || do_can_suspend){
777 char list[500];
778 int commas = 0;
779 char *p = list;
780 char *error = NULL;
782 list[0] = '\0';
784 if(do_use_fk){
785 if(list[0]){
786 strncat(list, ",", sizeof(list)-strlen(list)-1);
787 list[sizeof(list)-1] = '\0';
790 strncat(list, "use-function-keys", sizeof(list)-strlen(list)-1);
791 list[sizeof(list)-1] = '\0';
794 if(do_can_suspend){
795 if(list[0]){
796 strncat(list, ",", sizeof(list)-strlen(list)-1);
797 list[sizeof(list)-1] = '\0';
800 strncat(list, "enable-suspend", sizeof(list)-strlen(list)-1);
801 list[sizeof(list)-1] = '\0';
804 while(*p++)
805 if(*p == ',')
806 ++commas;
808 pine_state->feat_list_back_compat = parse_list(list,commas+1,0,&error);
809 if(error){
810 snprintf(tmp_20k_buf, SIZEOF_20KBUF, args_err_internal, error);
811 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
812 display_args_err(tmp_20k_buf, NULL, 1);
813 exit(-1);
817 if(((do_conf ? 1 : 0)+(pinerc_file ? 1 : 0)) > 1){
818 display_args_err(_("May only have one of -conf and -pinerc"),
819 NULL, 1);
820 exit(-1);
823 if(do_help || usage)
824 args_help();
826 if(usage)
827 exit(-1);
829 if(do_version){
830 extern char datestamp[], hoststamp[];
831 char rev[128];
833 snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Alpine %s (%s %s) built %s on %s",
834 ALPINE_VERSION,
835 SYSTYPE ? SYSTYPE : "?",
836 get_alpine_revision_string(rev, sizeof(rev)),
837 datestamp, hoststamp);
838 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
839 display_args_err(tmp_20k_buf, NULL, 0);
840 exit(0);
843 if(do_conf)
844 dump_global_conf();
846 if(pinerc_file)
847 dump_new_pinerc(pinerc_file);
850 * Don't NULL out argv[0] or we might crash in unexpected ways. In OS X, we were
851 * crashing when opening attachments because of this.
853 if(ac <= 0 && av != argv)
854 *av = NULL;
859 * Returns 0 if ok, -1 if error.
862 process_debug_str(char *debug_str)
864 int i, usage = 0;
865 int commas = 0;
866 int new_style_debug_arg = 0;
867 char *q = debug_str;
868 char *error = NULL;
869 char **list, **p;
871 #ifdef DEBUG
872 if(debug_str){
873 if(!isdigit((unsigned char)debug_str[0]))
874 new_style_debug_arg++;
876 if(new_style_debug_arg){
877 while(*q++)
878 if(*q == ',')
879 ++commas;
881 list = parse_list(debug_str, commas+1, 0, &error);
882 if(error){
883 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_d_error), debug_str, error);
884 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
885 display_args_err(tmp_20k_buf, NULL, 1);
886 return(-1);
889 if(list){
890 for(p = list; *p; p++){
891 if(struncmp(*p, "timestamp", 9) == 0){
892 ps_global->debug_timestamp = 1;
894 else if(struncmp(*p, "imap", 4) == 0){
895 q = *p + 4;
896 if(!*q || !*(q+1) || *q != '=' ||
897 !isdigit((unsigned char)*(q+1))){
898 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
899 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
900 display_args_err(tmp_20k_buf, NULL, 1);
901 usage = -1;
903 else{
904 i = atoi(q+1);
905 ps_global->debug_imap = MIN(5,MAX(0,i));
908 else if(struncmp(*p, "flush", 5) == 0){
909 ps_global->debug_flush = 1;
911 else if(struncmp(*p, "tcp", 3) == 0){
912 ps_global->debug_tcp = 1;
914 else if(struncmp(*p, "verbose", 7) == 0){
915 q = *p + 7;
916 if(!*q || !*(q+1) || *q != '=' ||
917 !isdigit((unsigned char)*(q+1))){
918 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
919 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
920 display_args_err(tmp_20k_buf, NULL, 1);
921 usage = -1;
923 else
924 debug = atoi(q+1);
926 else if(struncmp(*p, "numfiles", 8) == 0){
927 q = *p + 8;
928 if(!*q || !*(q+1) || *q != '=' ||
929 !isdigit((unsigned char)*(q+1))){
930 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
931 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
932 display_args_err(tmp_20k_buf, NULL, 1);
933 usage = -1;
935 else{
936 i = atoi(q+1);
937 ps_global->debug_nfiles = MIN(31,MAX(0,i));
940 else if(struncmp(*p, "malloc", 6) == 0){
941 q = *p + 6;
942 if(!*q || !*(q+1) || *q != '=' ||
943 !isdigit((unsigned char)*(q+1))){
944 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
945 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
946 display_args_err(tmp_20k_buf, NULL, 1);
947 usage = -1;
949 else{
950 i = atoi(q+1);
951 ps_global->debug_malloc = MIN(63,MAX(0,i));
954 #if defined(ENABLE_LDAP) && defined(LDAP_DEBUG)
955 else if(struncmp(*p, "ldap", 4) == 0){
956 q = *p + 4;
957 if(!*q || !*(q+1) || *q != '=' ||
958 !isdigit((unsigned char)*(q+1))){
959 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
960 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
961 display_args_err(tmp_20k_buf, NULL, 1);
962 usage = -1;
964 else{
965 i = atoi(q+1);
966 ldap_debug = i;
969 #endif /* LDAP */
970 else{
971 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("unknown debug keyword \"%s\""), *p);
972 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
973 display_args_err(tmp_20k_buf, NULL, 1);
974 usage = -1;
978 free_list_array(&list);
981 else{
982 debug = atoi(debug_str);
983 if(debug > 9)
984 ps_global->debug_imap = 5;
985 else if(debug > 7)
986 ps_global->debug_imap = 4;
987 else if(debug > 6)
988 ps_global->debug_imap = 3;
989 else if(debug > 4)
990 ps_global->debug_imap = 2;
991 else if(debug > 2)
992 ps_global->debug_imap = 1;
994 if(debug > 7)
995 ps_global->debug_timestamp = 1;
997 if(debug > 8)
998 ps_global->debug_flush = 1;
1002 if(!new_style_debug_arg){
1003 #ifdef CSRIMALLOC
1004 ps_global->debug_malloc =
1005 (debug <= DEFAULT_DEBUG) ? 1 : (debug < 9) ? 2 : 3;
1006 #else /* !CSRIMALLOC */
1007 #ifdef HAVE_SMALLOC
1008 if(debug > 8)
1009 ps_global->debug_malloc = 2;
1010 #else /* !HAVE_SMALLOC */
1011 #ifdef NXT
1012 if(debug > 8)
1013 ps_global->debug_malloc = 32;
1014 #endif /* NXT */
1015 #endif /* HAVE_SMALLOC */
1016 #endif /* CSRIMALLOC */
1019 #else /* !DEBUG */
1021 snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("unknown flag \"d\", debugging not compiled in"));
1022 tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
1023 display_args_err(tmp_20k_buf, NULL, 1);
1024 usage = -1;
1026 #endif /* !DEBUG */
1028 return(usage);
1032 void
1033 args_add_attach(PATMT **alpp, char *s, int deleted)
1035 PATMT *atmp, **atmpp;
1037 atmp = (PATMT *) fs_get(sizeof(PATMT));
1038 memset(atmp, 0, sizeof(PATMT));
1039 atmp->filename = cpystr(s);
1041 #if defined(DOS) || defined(OS2)
1042 (void) removing_quotes(atmp->filename);
1043 #endif
1045 if(deleted)
1046 atmp->flags |= A_TMP;
1048 for(atmpp = alpp; *atmpp; atmpp = &(*atmpp)->next)
1051 *atmpp = atmp;
1055 /*----------------------------------------------------------------------
1056 print a few lines of help for command line arguments
1058 Args: none
1060 Result: prints help messages
1061 ----------------------------------------------------------------------*/
1062 void
1063 args_help(void)
1065 char *pp[2];
1066 #ifndef _WINDOWS
1067 char **a;
1068 #endif
1070 pp[1] = NULL;
1072 /** print out possible starting arguments... **/
1075 * display_args_err expects already translated input
1076 * so we need to translate a line at a time. Since
1077 * the 1st and 3rd args are zero it is ok to call it
1078 * a line at a time.
1080 * Windows expects the full block of text so we'll pass
1081 * it as such.
1083 #ifndef _WINDOWS
1084 for(a=args_pine_args; a && *a; a++){
1085 pp[0] = _(*a);
1086 display_args_err(NULL, pp, 0);
1088 #else
1089 display_args_err(NULL, args_pine_args, 0);
1090 #endif
1092 exit(1);
1096 /*----------------------------------------------------------------------
1097 write argument error to the display...
1099 Args: none
1101 Result: prints help messages
1102 ----------------------------------------------------------------------*/
1103 void
1104 display_args_err(char *s, char **a, int err)
1106 char errstr[256], *errp;
1107 FILE *fp = err ? stderr : stdout;
1110 if(err && s){
1111 snprintf(errp = errstr, sizeof(errstr), "%s: %s", _("Argument Error"), s);
1112 errstr[sizeof(errstr)-1] = '\0';
1114 else
1115 errp = s;
1117 #ifdef _WINDOWS
1118 if(errp)
1119 mswin_messagebox(errp, err);
1121 if(a && *a){
1122 os_argsdialog(a);
1124 #else
1125 if(errp)
1126 fprintf(fp, "%s\n", errp);
1128 while(a && *a)
1129 fprintf(fp, "%s\n", *a++);
1130 #endif
1135 * The argument is an argument from the command line. We check to see
1136 * if it is specifying an alternate value for one of the options that is
1137 * normally set in pinerc. If so, we return 1 and set the appropriate
1138 * values in the variables array.
1139 * The arg can be
1140 * varname=value
1141 * varname=value1,value2,value3
1142 * feature-list=featurename these are just a special
1143 * feature-list=featurename1,featurename2 case of above
1144 * featurename This is equivalent to above
1145 * no-featurename
1148 pinerc_cmdline_opt(char *arg)
1150 struct variable *v;
1151 char *p1 = NULL,
1152 *value,
1153 **oldlvalue = NULL,
1154 **lvalue;
1155 int i, count;
1157 if(!arg || !arg[0])
1158 return 0;
1160 for(v = ps_global->vars; v->name != NULL; v++){
1161 if(v->is_used && struncmp(v->name, arg, strlen(v->name)) == 0){
1162 p1 = arg + strlen(v->name);
1164 /*----- Skip to '=' -----*/
1165 while(*p1 && (*p1 == '\t' || *p1 == ' '))
1166 p1++;
1168 if(*p1 != '='){
1169 char buf[MAILTMPLEN];
1171 snprintf(buf, sizeof(buf), _("Missing \"=\" after -%s\n"), v->name);
1172 buf[sizeof(buf)-1] = '\0';
1173 exceptional_exit(buf, -1);
1176 p1++;
1177 break;
1181 /* no match, check for a feature name used directly */
1182 if(v->name == NULL){
1183 FEATURE_S *feat;
1184 char *featname;
1186 if(struncmp(arg, "no-", 3) == 0)
1187 featname = arg+3;
1188 else
1189 featname = arg;
1191 for(i = 0; (feat = feature_list(i)) != NULL; i++){
1192 if(strucmp(featname, feat->name) == 0){
1193 v = &(ps_global->vars)[V_FEATURE_LIST];
1194 p1 = arg;
1195 break;
1200 if(!p1)
1201 return 0;
1203 if(v->is_obsolete || !v->is_user){
1204 char buf[MAILTMPLEN];
1206 if(v->is_obsolete)
1207 snprintf(buf, sizeof(buf), _("Option \"%s\" is obsolete\n"), v->name);
1208 else
1209 snprintf(buf, sizeof(buf), _("Option \"%s\" is not user settable\n"), v->name);
1211 exceptional_exit(buf, -1);
1214 /* free mem */
1215 if(v->is_list){
1216 oldlvalue = v->cmdline_val.l;
1217 v->cmdline_val.l = NULL;
1219 else if(v->cmdline_val.p)
1220 fs_give((void **) &(v->cmdline_val.p));
1222 /*----- Matched a variable, get its value ----*/
1223 while(*p1 == ' ' || *p1 == '\t')
1224 p1++;
1225 value = p1;
1227 if(*value == '\0'){
1228 if(v->is_list){
1229 v->cmdline_val.l = (char **)fs_get(2 * sizeof(char *));
1231 * we let people leave off the quotes on command line so that
1232 * they don't have to mess with shell quoting
1234 v->cmdline_val.l[0] = cpystr("");
1235 v->cmdline_val.l[1] = NULL;
1236 if(oldlvalue)
1237 free_list_array(&oldlvalue);
1239 }else{
1240 v->cmdline_val.p = cpystr("");
1242 return 1;
1245 /*--value is non-empty--*/
1246 if(*value == '"' && !v->is_list){
1247 value++;
1248 for(p1 = value; *p1 && *p1 != '"'; p1++);
1249 if(*p1 == '"')
1250 *p1 = '\0';
1251 else
1252 removing_trailing_white_space(value);
1253 }else{
1254 removing_trailing_white_space(value);
1257 if(v->is_list){
1258 int was_quoted = 0;
1259 char *error = NULL;
1261 count = 1;
1262 for(p1=value; *p1; p1++){ /* generous count of list elements */
1263 if(*p1 == '"') /* ignore ',' if quoted */
1264 was_quoted = (was_quoted) ? 0 : 1;
1266 if(*p1 == ',' && !was_quoted)
1267 count++;
1270 lvalue = parse_list(value, count, 0, &error);
1271 if(error){
1272 char buf[MAILTMPLEN];
1274 snprintf(buf, sizeof(buf), "%s in %s = \"%s\"\n", error, v->name, value);
1275 buf[sizeof(buf)-1] = '\0';
1276 exceptional_exit(buf, -1);
1279 * Special case: turn "" strings into empty strings.
1280 * This allows users to turn off default lists. For example,
1281 * if smtp-server is set then a user could override smtp-server
1282 * with smtp-server="".
1284 for(i = 0; lvalue[i]; i++)
1285 if(lvalue[i][0] == '"' &&
1286 lvalue[i][1] == '"' &&
1287 lvalue[i][2] == '\0')
1288 lvalue[i][0] = '\0';
1291 if(v->is_list){
1292 if(oldlvalue){
1293 char **combinedlvalue;
1294 int j;
1296 /* combine old and new cmdline lists */
1297 for(count = 0, i = 0; oldlvalue[i]; i++, count++)
1300 for(i = 0; lvalue && lvalue[i]; i++, count++)
1303 combinedlvalue = (char **) fs_get((count+1) * sizeof(char *));
1304 memset(combinedlvalue, 0, (count+1) * sizeof(*combinedlvalue));
1306 for(i = 0, j = 0; oldlvalue[i]; i++, j++)
1307 combinedlvalue[j] = cpystr(oldlvalue[i]);
1309 for(i = 0; lvalue && lvalue[i]; i++, j++)
1310 combinedlvalue[j] = cpystr(lvalue[i]);
1312 v->cmdline_val.l = combinedlvalue;
1314 fs_give((void **) &oldlvalue);
1315 if(lvalue)
1316 fs_give((void **) &lvalue);
1318 else
1319 v->cmdline_val.l = lvalue;
1321 else
1322 v->cmdline_val.p = cpystr(value);
1324 return 1;