2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 /*======================================================================
16 Command line argument parsing functions
22 #include "../pith/state.h"
23 #include "../pith/init.h"
24 #include "../pith/conf.h"
25 #include "../pith/list.h"
26 #include "../pith/util.h"
27 #include "../pith/help.h"
32 #include "xoauth2conf.h"
34 int process_debug_str(char *);
35 void args_add_attach(PATMT
**, char *, int);
36 int pinerc_cmdline_opt(char *);
37 void display_config_options(char *, char *);
39 extern char configoptions
[];
42 * Name started as to invoke function key mode
44 #define ALPINE_FKEY_NAME "alpinef"
47 * Various error and informational strings..
49 /* TRANSLATORS: This is a list of errors printed when something goes wrong
50 early on with the argument list. Be careful not to change literal
51 option names mentioned in the strings. */
52 static char args_err_missing_pinerc
[] = N_("missing argument for option \"-pinerc\" (use - for standard out)");
53 #if defined(DOS) || defined(OS2)
54 static char args_err_missing_aux
[] = N_("missing argument for option \"-aux\"");
57 static char args_err_missing_smimedir
[] = N_("missing argument for option \"-smimedir\"");
58 static char args_err_non_abs_smimedir
[] = N_("argument to \"-smimedir\" should be fully-qualified");
61 static char args_err_missing_passfile
[] = N_("missing argument for option \"-passfile\"");
62 static char args_err_non_abs_passfile
[] = N_("argument to \"-passfile\" should be fully-qualified");
64 static char args_err_missing_pwdcertdir
[] = N_("missing argument for option \"-pwdcertdir\"");
65 static char args_err_non_abs_pwdcertdir
[] = N_("argument to \"-pwdcertdir\" should be fully-qualified");
66 #endif /* SMIME inside PASSFILE */
68 static char args_err_missing_sort
[] = N_("missing argument for option \"-sort\"");
69 static char args_err_missing_flag_arg
[] = N_("missing argument for flag \"%c\"");
70 static char args_err_missing_flag_num
[] = N_("Non numeric argument for flag \"%c\"");
71 static char args_err_missing_debug_num
[] = N_("Non numeric argument for \"%s\"");
72 static char args_err_missing_url
[] = N_("missing URL for \"-url\"");
73 static char args_err_missing_attachment
[] = N_("missing attachment for \"%s\"");
74 static char args_err_conflict
[] = N_("conflicting action: \"%s\"");
75 static char args_err_unknown
[] = N_("unknown flag \"%c\"");
76 static char args_err_I_error
[] = N_("-I argument \"%s\": %s");
77 static char args_err_d_error
[] = N_("-d argument \"%s\": %s");
78 static char args_err_internal
[] = "%s";
79 static char args_err_missing_copyprc
[] = N_("missing argument for option \"-copy_pinerc\"\nUsage: pine -copy_pinerc <local_pinerc> <remote_pinerc>");
80 static char args_err_missing_copyabook
[] = N_("missing argument for option \"-copy_abook\"\nUsage: pine -copy_abook <local_abook> <remote_abook>");
81 static char args_err_missing_server_name
[] = N_("missing server name. Example: -xoauth2-server Gmail");
82 static char args_err_missing_client_id
[] = N_("missing client-id name. Example: -xoauth2-client-id 760.someserver.com");
83 static char args_err_missing_client_secret
[] = N_("missing client-secret name. Example: -xoauth2-client-secret V56i0fa_");
84 static char args_err_missing_tenant
[] = N_("missing tenant value. Example: -xoauth2-tenant common");
85 static char args_err_missing_user
[] = N_("missing username value. Example: -xoauth2-user user@example.com");
86 static char args_err_missing_flow
[] = N_("missing flow. Example: -xoauth2-client-flow Authorize");
87 static char args_err_missing_xoauth_option
[] = N_("you must set all options -xoauth2-server, -xoauth2-client-id and -xoauth2-client-secret if you use any of them");
89 static char *args_pine_args
[] = {
90 N_("Possible Starting Arguments for Alpine program:"),
92 N_(" Argument\tMeaning"),
93 N_(" <addrs>...\tGo directly into composer sending to given address"),
94 N_("\t\tList multiple addresses with a single space between them."),
95 N_("\t\tStandard input redirection is allowed with addresses."),
96 N_("\t\tNote: Places addresses in the \"To\" field only."),
97 N_(" -attach <file>\tGo directly into composer with given file"),
98 N_(" -attachlist <file-list>"),
99 N_(" -attach_and_delete <file>"),
100 N_("\t\tGo to composer, attach file, delete when finished"),
101 N_("\t\tNote: Attach options can't be used if -f, -F"),
102 N_("\t\tadded to Attachment list. Attachlist must be the last"),
103 N_("\t\toption on the command line"),
104 N_(" -bail\t\tExit if pinerc file doesn't already exist"),
106 N_(" -d n\t\tDebug - set debug level to 'n', or use the following:"),
107 N_(" -d keywords...\tflush,timestamp,imap=0..4,tcp,http,numfiles=0..31,verbose=0..9"),
109 N_(" -f <folder>\tFolder - give folder name to open"),
110 N_(" -c <number>\tContext - which context to apply to -f arg"),
111 N_(" -F <file>\tFile - give file name to open and page through and"),
112 N_("\t\tforward as email."),
113 N_(" -h \t\tHelp - give this list of options"),
114 N_(" -k \t\tKeys - Force use of function keys"),
115 N_(" -z \t\tSuspend - allow use of ^Z suspension"),
116 N_(" -r \t\tRestricted - can only send mail to oneself"),
117 N_(" -sort <sort>\tSort - Specify sort order of folder:"),
118 N_("\t\t\tarrival, subject, threaded, orderedsubject, date,"),
119 N_("\t\t\tfrom, size, score, to, cc, /reverse"),
120 N_(" -i\t\tIndex - Go directly to index, bypassing main menu"),
121 N_(" -I <keystroke_list> Initial keystrokes to be executed"),
122 N_(" -n <number>\tEntry in index to begin on"),
123 N_(" -o \t\tReadOnly - Open first folder read-only"),
124 N_(" -conf\t\tConfiguration - Print out fresh global configuration. The"),
125 N_("\t\tvalues of your global configuration affect all Alpine users"),
126 N_("\t\ton your system unless they have overridden the values in their"),
127 N_("\t\tpinerc files."),
128 N_(" -pinerc <file>\tConfiguration - Put fresh pinerc configuration in <file>"),
129 N_(" -p <pinerc>\tUse alternate .pinerc file"),
130 #if !defined(DOS) && !defined(OS2)
131 N_(" -P <pine.conf>\tUse alternate pine.conf file"),
133 N_(" -aux <aux_files_dir>\tUse this with remote pinerc"),
134 N_(" -P <pine.conf>\tUse pine.conf file for default settings"),
135 N_(" -nosplash \tDisable the PC-Alpine splash screen"),
138 #if defined(APPLEKEYCHAIN) || (WINCRED > 0)
139 N_(" -erase_stored_passwords\tEliminate any stored passwords"),
143 N_(" -smimedir <fully_qualified_path>\tdirectory where smime personal certificates are saved"),
147 N_(" -passfile <fully_qualified_filename>\tSet the password file to something other"),
148 N_("\t\tthan the default"),
150 N_(" -pwdcertdir <fully_qualified_path>\tSet the directory to store a personal"),
151 N_("\t\tkey and certificate to encrypt and decrypt your password file."),
152 #endif /* SMIME inside PASSFILE */
153 #endif /* PASSFILE */
155 #ifdef LOCAL_PASSWD_CACHE
156 N_(" -nowrite_password_cache\tRead from a password cache if there is one, but"),
157 N_("\t\t\t\tnever offer to write a password to the cache"),
158 #endif /* LOCAL_PASSWD_CACHE */
160 N_(" -x <config>\tUse configuration exceptions in <config>."),
161 N_("\t\tExceptions are used to override your default pinerc"),
162 N_("\t\tsettings for a particular platform, can be a local file or"),
163 N_("\t\ta remote folder."),
164 N_(" -v \t\tVersion - show version information"),
165 N_(" -version\tVersion - show version information"),
166 N_(" -supported\tList supported options"),
167 N_(" -url <url>\tOpen the given URL"),
168 N_("\t\tNote: Can't be used if -f, -F"),
169 N_("\t\tStandard input redirection is not allowed with URLs."),
170 N_("\t\tFor mailto URLs, 'body='text should be used in place of"),
171 N_("\t\tinput redirection."),
172 N_(" -copy_pinerc <local_pinerc> <remote_pinerc> copy local pinerc to remote"),
173 N_(" -copy_abook <local_abook> <remote_abook> copy local addressbook to remote"),
174 N_(" -convert_sigs -p <pinerc> convert signatures to literal signatures"),
175 #if defined(_WINDOWS)
176 N_(" -install \tPrompt for some basic setup information"),
177 N_(" -uninstall \tRemove traces of Alpine from Windows system settings"),
178 N_(" -registry <cmd>\tWhere cmd is set,noset,clear,clearsilent,dump"),
180 N_(" -xoauth2-server <value>"),
181 N_(" -xoauth2-client-id <value>"),
182 N_(" -xoauth2-client-secret <value>"),
183 N_("\tNote: All of -xoauth options above must be used, if any of them is used"),
184 N_(" -xoauth2-tenant <value>"),
185 N_(" -xoauth2-user <value>"),
186 N_(" -xoauth2-flow <value>"),
187 N_("\tNote: The previous two options are optional and if not used, Alpine resorts to their default values"),
188 " -<option>=<value> Assign <value> to the pinerc option <option>",
189 "\t\t e.g. -signature-file=sig1",
190 "\t\t e.g. -color-style=no-color",
191 "\t\t e.g. -feature-list=enable-sigdashes",
192 "\t\t Note: feature-list is additive.",
193 "\t\t You may leave off the \"feature-list=\" part of that,",
194 "\t\t e.g. -enable-sigdashes",
199 display_config_options(char *configopts
, char *defprefix
)
201 char *copts
= configopts
? cpystr(configopts
) : NULL
;
202 char **options
= NULL
;
203 char *s
, *t
, *prefix
;
204 int len
, nlines
, pending
;
206 for(nlines
= 0, s
= copts
; s
!= NULL
; nlines
++){
210 options
= fs_get((nlines
/2 + 4)*sizeof(char *)); /* 4 in worst case scenario */
211 memset((void *) options
, 0, (nlines
/2 + 4)*sizeof(char *));
212 for(s
= copts
, len
= 0, nlines
= 0; s
!= NULL
; ){
214 prefix
= len
== 0 ? (nlines
== 0 ? defprefix
: " ") : " ";
215 if((s
= strchr(s
, '\'')) != NULL
){
216 t
= strchr(s
+1, '\'');
218 if(!strncmp(s
+1, "CFLAGS=", 7)
219 || !strncmp(s
+1, "CC=", 3)
220 || !strncmp(s
+1, "LIBS=", 5)
221 || !strncmp(s
+1, "CPP=", 4)
222 || !strncmp(s
+1, "CPPFLAGS=", 9)
223 || !strncmp(s
+1, "LT_SYS_LIBRARY_PATH=", 20)
224 || !strncmp(s
+1, "LDFLAGS=", 8)){
225 display_args_err(s
+1, NULL
, 0);
230 if(len
+ strlen(prefix
) + strlen(s
+1) > 74 ){
232 options
[nlines
] = fs_get((strlen(prefix
) + strlen(s
+1) + 3)*sizeof(char));
233 sprintf(options
[nlines
++], "%s%s \\", prefix
, s
+1);
236 strcat(options
[nlines
++], " \\");
243 options
[nlines
] = fs_get(76*sizeof(char));
244 *options
[nlines
] = '\0';
246 strcat(options
[nlines
], prefix
);
247 strcat(options
[nlines
], s
+1);
248 len
= strlen(options
[nlines
]);
253 s
= t
? t
+ 1 : NULL
;
256 display_args_err(NULL
, options
, 0);
257 free_list_array(&options
);
258 fs_give((void **) &copts
);
262 * Parse the command line args.
264 * Args: pine_state -- The pine_state structure to put results in
265 * argc, argv -- The obvious
266 * addrs -- Pointer to address list that we set for caller
268 * Result: command arguments parsed
269 * possible printing of help for command line
270 * various flags in pine_state set
271 * returns the string name of the first folder to open
275 pine_args(struct pine
*pine_state
, int argc
, char **argv
, ARGDATA_S
*args
)
281 char *cmd_list
= NULL
;
282 char *debug_str
= NULL
;
284 char *pinerc_file
= NULL
;
291 int do_can_suspend
= 0;
293 struct variable
*vars
= pine_state
->vars
;
297 memset(args
, 0, sizeof(ARGDATA_S
));
298 args
->action
= aaFolder
;
299 memset((void *) &x
, 0, sizeof(XOAUTH2_INFO_S
));
301 pine_state
->pine_name
= (lc
= last_cmpnt(argv
[0])) ? lc
: (lc
= argv
[0]);
303 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "%.*s", pine_state
->pine_name
- argv
[0], argv
[0]);
304 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
305 pine_state
->pine_dir
= cpystr(tmp_20k_buf
);
308 /* while more arguments with leading - */
309 Loop
: while(--ac
> 0)
311 /* while more chars in this argument */
313 /* check for pinerc options */
314 if(pinerc_cmdline_opt(*av
)){
315 goto Loop
; /* done with this arg, go to next */
317 /* then other multi-char options */
318 else if(strcmp(*av
, "conf") == 0){
320 goto Loop
; /* done with this arg, go to next */
322 else if(strcmp(*av
, "pinerc") == 0){
326 display_args_err(_(args_err_missing_pinerc
), NULL
, 1);
332 #if defined(DOS) || defined(OS2)
333 else if(strcmp(*av
, "aux") == 0){
335 if((str
= *++av
) != NULL
)
336 pine_state
->aux_files_dir
= cpystr(str
);
339 display_args_err(_(args_err_missing_aux
), NULL
, 1);
345 else if(strcmp(*av
, "nosplash") == 0)
346 goto Loop
; /* already taken care of in WinMain */
349 #if defined(APPLEKEYCHAIN) || (WINCRED > 0)
350 else if(strcmp(*av
, "erase_stored_passwords") == 0){
352 erase_windows_credentials();
354 macos_erase_keychain();
358 #endif /* defined(APPLEKEYCHAIN) || (WINCRED > 0) */
361 else if(strcmp(*av
, "smimedir") == 0){
363 if((str
= *++av
) != NULL
){
364 if(!is_absolute_path(str
)){
365 display_args_err(_(args_err_non_abs_smimedir
),
370 if(pine_state
->smimedir
)
371 fs_give((void **)&pine_state
->smimedir
);
373 pine_state
->smimedir
= cpystr(str
);
378 display_args_err(_(args_err_missing_smimedir
), NULL
, 1);
386 else if(strcmp(*av
, "passfile") == 0){
388 if((str
= *++av
) != NULL
){
389 if(!is_absolute_path(str
)){
390 display_args_err(_(args_err_non_abs_passfile
),
395 if(pine_state
->passfile
)
396 fs_give((void **)&pine_state
->passfile
);
398 pine_state
->passfile
= cpystr(str
);
403 display_args_err(_(args_err_missing_passfile
), NULL
, 1);
410 else if(strcmp(*av
, "pwdcertdir") == 0){
412 if((str
= *++av
) != NULL
){
413 if(!is_absolute_path(str
)){
414 display_args_err(_(args_err_non_abs_pwdcertdir
),
419 if(pine_state
->pwdcertdir
)
420 fs_give((void **)&pine_state
->pwdcertdir
);
422 pine_state
->pwdcertdir
= cpystr(str
);
427 display_args_err(_(args_err_missing_pwdcertdir
), NULL
, 1);
433 #endif /* SMIME inside PASSFILE */
434 #endif /* PASSFILE */
436 #ifdef LOCAL_PASSWD_CACHE
437 else if(strcmp(*av
, "nowrite_password_cache") == 0){
438 ps_global
->nowrite_password_cache
= 1;
441 #endif /* LOCAL_PASSWD_CACHE */
443 else if(strcmp(*av
, "convert_sigs") == 0){
444 ps_global
->convert_sigs
= 1;
447 else if(strcmp(*av
, "supported") == 0){
448 ps_global
->dump_supported_options
= 1;
451 else if(strcmp(*av
, "copy_pinerc") == 0){
452 if(args
->action
== aaFolder
&& !args
->data
.folder
){
453 args
->action
= aaPrcCopy
;
456 args
->data
.copy
.local
= *++av
;
457 args
->data
.copy
.remote
= *++av
;
460 display_args_err(_(args_err_missing_copyprc
), NULL
, 1);
465 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_conflict
), "-copy_pinerc");
466 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
467 display_args_err(tmp_20k_buf
, NULL
, 1);
473 else if(strcmp(*av
, "copy_abook") == 0){
474 if(args
->action
== aaFolder
&& !args
->data
.folder
){
475 args
->action
= aaAbookCopy
;
478 args
->data
.copy
.local
= *++av
;
479 args
->data
.copy
.remote
= *++av
;
482 display_args_err(_(args_err_missing_copyabook
), NULL
, 1);
487 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_conflict
), "-copy_abook");
488 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
489 display_args_err(tmp_20k_buf
, NULL
, 1);
495 else if(strcmp(*av
, "sort") == 0){
498 COM_SORT_KEY
= cpystr(sort
);
501 display_args_err(_(args_err_missing_sort
), NULL
, 1);
507 else if(strcmp(*av
, "url") == 0){
508 if(args
->action
== aaFolder
&& !args
->data
.folder
){
509 args
->action
= aaURL
;
511 args
->url
= cpystr(*++av
);
514 display_args_err(_(args_err_missing_url
), NULL
, 1);
519 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_conflict
), "-url");
520 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
521 display_args_err(tmp_20k_buf
, NULL
, 1);
527 else if(strcmp(*av
, "attach") == 0){
528 if((args
->action
== aaFolder
&& !args
->data
.folder
)
529 || args
->action
== aaMail
530 || args
->action
== aaURL
){
531 if(args
->action
!= aaURL
)
532 args
->action
= aaMail
;
534 args_add_attach(&args
->data
.mail
.attachlist
,
538 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_missing_attachment
), "-attach");
539 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
540 display_args_err(tmp_20k_buf
, NULL
, 1);
545 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_conflict
), "-attach");
546 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
547 display_args_err(tmp_20k_buf
, NULL
, 1);
553 else if(strcmp(*av
, "attachlist") == 0){
554 if((args
->action
== aaFolder
&& !args
->data
.folder
)
555 || args
->action
== aaMail
556 || args
->action
== aaURL
){
557 if(args
->action
!= aaURL
)
558 args
->action
= aaMail
;
561 if(can_access(*(av
+1), READ_ACCESS
) == 0){
563 args_add_attach(&args
->data
.mail
.attachlist
,
572 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_missing_attachment
), "-attachList");
573 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
574 display_args_err(tmp_20k_buf
, NULL
, 1);
579 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_conflict
), "-attachList");
580 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
581 display_args_err(tmp_20k_buf
, NULL
, 1);
587 else if(strcmp(*av
, "attach_and_delete") == 0){
588 if((args
->action
== aaFolder
&& !args
->data
.folder
)
589 || args
->action
== aaMail
590 || args
->action
== aaURL
){
591 if(args
->action
!= aaURL
)
592 args
->action
= aaMail
;
594 args_add_attach(&args
->data
.mail
.attachlist
,
598 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_missing_attachment
), "-attach_and_delete");
599 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
600 display_args_err(tmp_20k_buf
, NULL
, 1);
605 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_conflict
), "-attach_and_delete");
606 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
607 display_args_err(tmp_20k_buf
, NULL
, 1);
613 else if(strcmp(*av
, "bail") == 0){
614 pine_state
->exit_if_no_pinerc
= 1;
617 else if(strcmp(*av
, "version") == 0){
621 else if(strcmp(*av
, "xoauth2-server") == 0 || strcmp(*av
, "x-s") == 0){
623 if((str
= *++av
) != NULL
){
625 fs_give((void **) &x
.name
);
626 x
.name
= (unsigned char *) cpystr(str
);
630 display_args_err(_(args_err_missing_server_name
), NULL
, 1);
635 else if(strcmp(*av
, "xoauth2-client-id") == 0 || strcmp(*av
, "x-c-i") == 0){
637 if((str
= *++av
) != NULL
){
639 fs_give((void **) &x
.client_id
);
640 x
.client_id
= cpystr(str
);
644 display_args_err(_(args_err_missing_client_id
), NULL
, 1);
649 else if(strcmp(*av
, "xoauth2-client-secret") == 0 || strcmp(*av
, "x-c-s") == 0){
651 if((str
= *++av
) != NULL
){
653 fs_give((void **) &x
.client_secret
);
654 x
.client_secret
= cpystr(str
);
658 display_args_err(_(args_err_missing_client_secret
), NULL
, 1);
663 else if(strcmp(*av
, "xoauth2-tenant") == 0 || strcmp(*av
, "x-t") == 0){
665 if((str
= *++av
) != NULL
){
667 fs_give((void **) &x
.tenant
);
668 x
.tenant
= cpystr(str
);
672 display_args_err(_(args_err_missing_tenant
), NULL
, 1);
677 else if(strcmp(*av
, "xoauth2-user") == 0 || strcmp(*av
, "x-u") == 0){
679 if((str
= *++av
) != NULL
){
681 fs_give((void **) &x
.users
);
682 x
.users
= cpystr(str
);
686 display_args_err(_(args_err_missing_user
), NULL
, 1);
691 else if(strcmp(*av
, "xoauth2-flow") == 0 || strcmp(*av
, "x-f") == 0){
693 if((str
= *++av
) != NULL
){
695 fs_give((void **) &x
.flow
);
696 x
.flow
= cpystr(str
);
700 display_args_err(_(args_err_missing_flow
), NULL
, 1);
706 else if(strcmp(*av
, "install") == 0){
707 pine_state
->install_flag
= 1;
708 pine_state
->update_registry
= UREG_ALWAYS_SET
;
711 else if(strcmp(*av
, "uninstall") == 0){
713 * Blast password cache, clear registry settings
716 erase_windows_credentials();
718 mswin_reg(MSWR_OP_BLAST
, MSWR_NULL
, NULL
, 0);
721 else if(strcmp(*av
, "registry") == 0){
723 if(!strucmp(*++av
, "set")){
724 pine_state
->update_registry
= UREG_ALWAYS_SET
;
726 else if(!strucmp(*av
, "noset")){
727 pine_state
->update_registry
= UREG_NEVER_SET
;
729 else if(!strucmp(*av
, "clear")){
730 if(!mswin_reg(MSWR_OP_BLAST
, MSWR_NULL
, NULL
, 0))
732 _("Alpine related Registry values removed."),
736 _("Not all Alpine related Registry values could be removed"),
740 else if(!strucmp(*av
, "clearsilent")){
741 mswin_reg(MSWR_OP_BLAST
, MSWR_NULL
, NULL
, 0);
744 else if(!strucmp(*av
, "dump")){
745 char **pRegistry
= mswin_reg_dump();
748 display_args_err(NULL
, pRegistry
, 0);
749 free_list_array(&pRegistry
);
754 display_args_err(_("unknown registry command"),
760 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_missing_flag_arg
), c
);
761 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
762 display_args_err(tmp_20k_buf
, NULL
, 1);
769 /* single char flags */
774 break; /* break back to inner-while */
782 pine_state
->restricted
= 1;
785 pine_state
->open_readonly_on_startup
= 1;
788 pine_state
->start_in_index
= 1;
792 break; /* break back to inner-while */
793 /* these take arguments */
794 case 'f': case 'F': case 'p': case 'I':
795 case 'c': case 'd': case 'P': case 'x': /* string args */
796 case 'n': /* integer args */
801 else if(c
== 'f' || c
== 'F')
804 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_missing_flag_arg
), c
);
805 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
806 display_args_err(tmp_20k_buf
, NULL
, 1);
813 if(args
->action
== aaFolder
&& !args
->data
.folder
){
814 args
->data
.folder
= cpystr(str
);
817 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_conflict
), "-f");
818 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
819 display_args_err(tmp_20k_buf
, NULL
, 1);
825 if(args
->action
== aaFolder
&& !args
->data
.folder
){
826 args
->action
= aaMore
;
827 args
->data
.file
= cpystr(str
);
830 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_conflict
), "-F");
831 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
832 display_args_err(tmp_20k_buf
, NULL
, 1);
845 char path
[MAXPATH
], dir
[MAXPATH
];
847 if(IS_REMOTE(str
) || is_absolute_path(str
)){
848 strncpy(path
, str
, sizeof(path
)-1);
849 path
[sizeof(path
)-1] = '\0';
852 if(getcwd(dir
, sizeof(path
)) != NULL
)
853 build_path(path
, dir
, str
, sizeof(path
));
855 alpine_panic(_("getcwd() call failed while parsing argument (1)"));
859 * Pinerc used to be the name of the pinerc
860 * file. Now, since the pinerc can be remote,
861 * we've replaced the variable pinerc with the
862 * structure prc. Unfortunately, other parts of
863 * pine rely on the fact that pinerc is the
864 * name of the pinerc _file_, and use the
865 * directory that the pinerc file is located
866 * in for their own purposes. We keep that so
867 * things will keep working.
870 if(!IS_REMOTE(path
)){
871 if(pine_state
->pinerc
)
872 fs_give((void **)&pine_state
->pinerc
);
874 pine_state
->pinerc
= cpystr(path
);
878 * Last one wins. This would be the place where
879 * we put multiple pinercs in a list if we
880 * were to allow that.
883 free_pinerc_s(&pine_state
->prc
);
885 pine_state
->prc
= new_pinerc_s(path
);
891 char path
[MAXPATH
], dir
[MAXPATH
];
893 if(IS_REMOTE(str
) || is_absolute_path(str
)){
894 strncpy(path
, str
, sizeof(path
)-1);
895 path
[sizeof(path
)-1] = '\0';
898 if(getcwd(dir
, sizeof(path
)) != NULL
)
899 build_path(path
, dir
, str
, sizeof(path
));
901 alpine_panic(_("getcwd() call failed while parsing argument (2)"));
904 if(pine_state
->pconf
)
905 free_pinerc_s(&pine_state
->pconf
);
907 pine_state
->pconf
= new_pinerc_s(path
);
913 pine_state
->exceptions
= cpystr(str
);
917 if(!isdigit((unsigned char)str
[0])){
918 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
919 _(args_err_missing_flag_num
), c
);
920 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
921 display_args_err(tmp_20k_buf
, NULL
, 1);
926 pine_state
->init_context
= (short) atoi(str
);
930 if(!isdigit((unsigned char)str
[0])){
931 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
,
932 _(args_err_missing_flag_num
), c
);
933 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
934 display_args_err(tmp_20k_buf
, NULL
, 1);
939 pine_state
->start_entry
= atoi(str
);
940 if(pine_state
->start_entry
< 1)
941 pine_state
->start_entry
= 1;
949 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_unknown
), c
);
950 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
951 display_args_err(tmp_20k_buf
, NULL
, 1);
958 else if(args
->action
== aaMail
959 || (args
->action
== aaFolder
&& !args
->data
.folder
)){
960 STRLIST_S
*stp
, **slp
;
962 args
->action
= aaMail
;
964 stp
= new_strlist(*av
);
966 for(slp
= &args
->data
.mail
.addrlist
; *slp
; slp
= &(*slp
)->next
)
972 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_conflict
), *av
);
973 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
974 display_args_err(tmp_20k_buf
, NULL
, 1);
987 COM_INIT_CMD_LIST
= parse_list(cmd_list
, commas
+1, 0, &error
);
989 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_I_error
), cmd_list
, error
);
990 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
991 display_args_err(tmp_20k_buf
, NULL
, 1);
997 pine_state
->debug_nfiles
= NUMDEBUGFILES
;
999 if(debug_str
&& process_debug_str(debug_str
))
1002 if(lc
&& strncmp(lc
, ALPINE_FKEY_NAME
, sizeof(ALPINE_FKEY_NAME
) - 1) == 0)
1005 if(do_use_fk
|| do_can_suspend
){
1015 strncat(list
, ",", sizeof(list
)-strlen(list
)-1);
1016 list
[sizeof(list
)-1] = '\0';
1019 strncat(list
, "use-function-keys", sizeof(list
)-strlen(list
)-1);
1020 list
[sizeof(list
)-1] = '\0';
1025 strncat(list
, ",", sizeof(list
)-strlen(list
)-1);
1026 list
[sizeof(list
)-1] = '\0';
1029 strncat(list
, "enable-suspend", sizeof(list
)-strlen(list
)-1);
1030 list
[sizeof(list
)-1] = '\0';
1037 pine_state
->feat_list_back_compat
= parse_list(list
,commas
+1,0,&error
);
1039 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, args_err_internal
, error
);
1040 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1041 display_args_err(tmp_20k_buf
, NULL
, 1);
1046 if((x
.name
|| x
.client_id
|| x
.client_secret
)
1047 && !(x
.name
&& x
.client_id
&& x
.client_secret
)){
1048 display_args_err(_(args_err_missing_xoauth_option
), NULL
, 1);
1052 if(((do_conf
? 1 : 0)+(pinerc_file
? 1 : 0)) > 1){
1053 display_args_err(_("May only have one of -conf and -pinerc"),
1058 if(do_help
|| usage
)
1066 tmp2
= xoauth_config_line(&x
);
1068 tmp1
= fs_get((strlen(ps_global
->vars
[V_XOAUTH2_INFO
].name
) + strlen(tmp2
) + 2)*sizeof(char));
1070 sprintf(tmp1
,"%s=%s", ps_global
->vars
[V_XOAUTH2_INFO
].name
, tmp2
);
1071 pinerc_cmdline_opt(tmp1
);
1072 set_current_val(&ps_global
->vars
[V_XOAUTH2_INFO
], TRUE
, TRUE
);
1073 fs_give((void **) &tmp1
);
1075 fs_give((void **) &tmp2
);
1080 extern char datestamp
[], hoststamp
[];
1083 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, "Alpine %s (%s %s) built %s on %s",
1085 SYSTYPE
? SYSTYPE
: "?",
1086 get_alpine_revision_string(rev
, sizeof(rev
)),
1087 datestamp
, hoststamp
);
1088 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1089 display_args_err(tmp_20k_buf
, NULL
, 0);
1091 display_args_err(_("Alpine was built with the following options:"), NULL
, 0);
1092 display_config_options(configoptions
, "./configure ");
1101 dump_new_pinerc(pinerc_file
);
1104 * Don't NULL out argv[0] or we might crash in unexpected ways. In OS X, we were
1105 * crashing when opening attachments because of this.
1107 if(ac
<= 0 && av
!= argv
)
1113 * Returns 0 if ok, -1 if error.
1116 process_debug_str(char *debug_str
)
1120 int new_style_debug_arg
= 0;
1121 char *q
= debug_str
;
1127 if(!isdigit((unsigned char)debug_str
[0]))
1128 new_style_debug_arg
++;
1130 if(new_style_debug_arg
){
1135 list
= parse_list(debug_str
, commas
+1, 0, &error
);
1137 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_d_error
), debug_str
, error
);
1138 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1139 display_args_err(tmp_20k_buf
, NULL
, 1);
1144 for(p
= list
; *p
; p
++){
1145 if(struncmp(*p
, "timestamp", 9) == 0){
1146 ps_global
->debug_timestamp
= 1;
1148 else if(struncmp(*p
, "imap", 4) == 0){
1150 if(!*q
|| !*(q
+1) || *q
!= '=' ||
1151 !isdigit((unsigned char)*(q
+1))){
1152 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_missing_debug_num
), *p
);
1153 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1154 display_args_err(tmp_20k_buf
, NULL
, 1);
1159 ps_global
->debug_imap
= MIN(5,MAX(0,i
));
1162 else if(struncmp(*p
, "flush", 5) == 0){
1163 ps_global
->debug_flush
= 1;
1165 else if(struncmp(*p
, "tcp", 3) == 0
1166 || struncmp(*p
, "tcpdebug", 8) == 0){
1167 ps_global
->debug_tcp
= 1;
1169 else if(struncmp(*p
, "http", 4) == 0
1170 || struncmp(*p
, "httpdebug", 9) == 0){
1171 ps_global
->debug_http
= 1;
1173 else if(struncmp(*p
, "verbose", 7) == 0){
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);
1185 else if(struncmp(*p
, "numfiles", 8) == 0){
1187 if(!*q
|| !*(q
+1) || *q
!= '=' ||
1188 !isdigit((unsigned char)*(q
+1))){
1189 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_missing_debug_num
), *p
);
1190 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1191 display_args_err(tmp_20k_buf
, NULL
, 1);
1196 ps_global
->debug_nfiles
= MIN(31,MAX(0,i
));
1199 else if(struncmp(*p
, "malloc", 6) == 0){
1201 if(!*q
|| !*(q
+1) || *q
!= '=' ||
1202 !isdigit((unsigned char)*(q
+1))){
1203 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_missing_debug_num
), *p
);
1204 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1205 display_args_err(tmp_20k_buf
, NULL
, 1);
1210 ps_global
->debug_malloc
= MIN(63,MAX(0,i
));
1213 #if defined(ENABLE_LDAP) && defined(LDAP_DEBUG)
1214 else if(struncmp(*p
, "ldap", 4) == 0){
1216 if(!*q
|| !*(q
+1) || *q
!= '=' ||
1217 !isdigit((unsigned char)*(q
+1))){
1218 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _(args_err_missing_debug_num
), *p
);
1219 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1220 display_args_err(tmp_20k_buf
, NULL
, 1);
1230 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("unknown debug keyword \"%s\""), *p
);
1231 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1232 display_args_err(tmp_20k_buf
, NULL
, 1);
1237 free_list_array(&list
);
1241 debug
= atoi(debug_str
);
1243 ps_global
->debug_imap
= 5;
1244 ps_global
->debug_http
= 1;
1247 ps_global
->debug_imap
= 4;
1249 ps_global
->debug_imap
= 3;
1251 ps_global
->debug_imap
= 2;
1253 ps_global
->debug_imap
= 1;
1256 ps_global
->debug_timestamp
= 1;
1259 ps_global
->debug_flush
= 1;
1263 if(usage
>= 0) ps_global
->write_debug_file
++;
1264 if(!new_style_debug_arg
){
1266 ps_global
->debug_malloc
=
1267 (debug
<= DEFAULT_DEBUG
) ? 1 : (debug
< 9) ? 2 : 3;
1268 #else /* !CSRIMALLOC */
1271 ps_global
->debug_malloc
= 2;
1272 #else /* !HAVE_SMALLOC */
1275 ps_global
->debug_malloc
= 32;
1277 #endif /* HAVE_SMALLOC */
1278 #endif /* CSRIMALLOC */
1283 snprintf(tmp_20k_buf
, SIZEOF_20KBUF
, _("unknown flag \"d\", debugging not compiled in"));
1284 tmp_20k_buf
[SIZEOF_20KBUF
-1] = '\0';
1285 display_args_err(tmp_20k_buf
, NULL
, 1);
1295 args_add_attach(PATMT
**alpp
, char *s
, int deleted
)
1297 PATMT
*atmp
, **atmpp
;
1299 atmp
= (PATMT
*) fs_get(sizeof(PATMT
));
1300 memset(atmp
, 0, sizeof(PATMT
));
1301 atmp
->filename
= cpystr(s
);
1303 #if defined(DOS) || defined(OS2)
1304 (void) removing_quotes(atmp
->filename
);
1308 atmp
->flags
|= A_TMP
;
1310 for(atmpp
= alpp
; *atmpp
; atmpp
= &(*atmpp
)->next
)
1317 /*----------------------------------------------------------------------
1318 print a few lines of help for command line arguments
1322 Result: prints help messages
1323 ----------------------------------------------------------------------*/
1334 /** print out possible starting arguments... **/
1337 * display_args_err expects already translated input
1338 * so we need to translate a line at a time. Since
1339 * the 1st and 3rd args are zero it is ok to call it
1342 * Windows expects the full block of text so we'll pass
1346 for(a
=args_pine_args
; a
&& *a
; a
++){
1348 display_args_err(NULL
, pp
, 0);
1351 display_args_err(NULL
, args_pine_args
, 0);
1358 /*----------------------------------------------------------------------
1359 write argument error to the display...
1363 Result: prints help messages
1364 ----------------------------------------------------------------------*/
1366 display_args_err(char *s
, char **a
, int err
)
1368 char errstr
[256], *errp
;
1369 FILE *fp
= err
? stderr
: stdout
;
1373 snprintf(errp
= errstr
, sizeof(errstr
), "%s: %s", _("Argument Error"), s
);
1374 errstr
[sizeof(errstr
)-1] = '\0';
1381 mswin_messagebox(errp
, err
);
1388 fprintf(fp
, "%s\n", errp
);
1391 fprintf(fp
, "%s\n", *a
++);
1397 * The argument is an argument from the command line. We check to see
1398 * if it is specifying an alternate value for one of the options that is
1399 * normally set in pinerc. If so, we return 1 and set the appropriate
1400 * values in the variables array.
1403 * varname=value1,value2,value3
1404 * feature-list=featurename these are just a special
1405 * feature-list=featurename1,featurename2 case of above
1406 * featurename This is equivalent to above
1410 pinerc_cmdline_opt(char *arg
)
1422 if((value
= strchr(arg
, '=')) != NULL
){
1429 for(v
= ps_global
->vars
; v
->name
!= NULL
; v
++){
1430 if(v
->is_used
&& strucmp(v
->name
, arg
) == 0){
1431 p1
= arg
+ strlen(v
->name
);
1432 if(i
> 0) arg
[i
] = '=';
1434 /*----- Skip to '=' -----*/
1435 while(*p1
&& (*p1
== '\t' || *p1
== ' '))
1439 char buf
[MAILTMPLEN
];
1441 snprintf(buf
, sizeof(buf
), _("Missing \"=\" after -%s\n"), v
->name
);
1442 buf
[sizeof(buf
)-1] = '\0';
1443 exceptional_exit(buf
, -1);
1452 if(i
> 0) arg
[i
] = '=';
1454 /* no match, check for a feature name used directly */
1455 if(v
->name
== NULL
){
1459 if(struncmp(arg
, "no-", 3) == 0)
1464 for(i
= 0; (feat
= feature_list(i
)) != NULL
; i
++){
1465 if(strucmp(featname
, feat
->name
) == 0){
1466 v
= &(ps_global
->vars
)[V_FEATURE_LIST
];
1476 if(v
->is_obsolete
|| !v
->is_user
){
1477 char buf
[MAILTMPLEN
];
1480 snprintf(buf
, sizeof(buf
), _("Option \"%s\" is obsolete\n"), v
->name
);
1482 snprintf(buf
, sizeof(buf
), _("Option \"%s\" is not user settable\n"), v
->name
);
1484 exceptional_exit(buf
, -1);
1489 oldlvalue
= v
->cmdline_val
.l
;
1490 v
->cmdline_val
.l
= NULL
;
1492 else if(v
->cmdline_val
.p
)
1493 fs_give((void **) &(v
->cmdline_val
.p
));
1495 /*----- Matched a variable, get its value ----*/
1496 while(*p1
== ' ' || *p1
== '\t')
1502 v
->cmdline_val
.l
= (char **)fs_get(2 * sizeof(char *));
1504 * we let people leave off the quotes on command line so that
1505 * they don't have to mess with shell quoting
1507 v
->cmdline_val
.l
[0] = cpystr("");
1508 v
->cmdline_val
.l
[1] = NULL
;
1510 free_list_array(&oldlvalue
);
1513 v
->cmdline_val
.p
= cpystr("");
1518 /*--value is non-empty--*/
1519 if(*value
== '"' && !v
->is_list
){
1521 for(p1
= value
; *p1
&& *p1
!= '"'; p1
++)
1526 removing_trailing_white_space(value
);
1528 removing_trailing_white_space(value
);
1536 for(p1
=value
; *p1
; p1
++){ /* generous count of list elements */
1537 if(*p1
== '"') /* ignore ',' if quoted */
1538 was_quoted
= (was_quoted
) ? 0 : 1;
1540 if(*p1
== ',' && !was_quoted
)
1544 lvalue
= parse_list(value
, count
, 0, &error
);
1546 char buf
[MAILTMPLEN
];
1548 snprintf(buf
, sizeof(buf
), "%s in %s = \"%s\"\n", error
, v
->name
, value
);
1549 buf
[sizeof(buf
)-1] = '\0';
1550 exceptional_exit(buf
, -1);
1553 * Special case: turn "" strings into empty strings.
1554 * This allows users to turn off default lists. For example,
1555 * if smtp-server is set then a user could override smtp-server
1556 * with smtp-server="".
1558 for(i
= 0; lvalue
[i
]; i
++)
1559 if(lvalue
[i
][0] == '"' &&
1560 lvalue
[i
][1] == '"' &&
1561 lvalue
[i
][2] == '\0')
1562 lvalue
[i
][0] = '\0';
1567 char **combinedlvalue
;
1570 /* combine old and new cmdline lists */
1571 for(count
= 0, i
= 0; oldlvalue
[i
]; i
++, count
++)
1574 for(i
= 0; lvalue
&& lvalue
[i
]; i
++, count
++)
1577 combinedlvalue
= (char **) fs_get((count
+1) * sizeof(char *));
1578 memset(combinedlvalue
, 0, (count
+1) * sizeof(*combinedlvalue
));
1580 for(i
= 0, j
= 0; oldlvalue
[i
]; i
++, j
++)
1581 combinedlvalue
[j
] = cpystr(oldlvalue
[i
]);
1583 for(i
= 0; lvalue
&& lvalue
[i
]; i
++, j
++)
1584 combinedlvalue
[j
] = cpystr(lvalue
[i
]);
1586 v
->cmdline_val
.l
= combinedlvalue
;
1588 fs_give((void **) &oldlvalue
);
1590 fs_give((void **) &lvalue
);
1593 v
->cmdline_val
.l
= lvalue
;
1596 v
->cmdline_val
.p
= cpystr(value
);