summaryrefslogtreecommitdiff
path: root/alpine/arg.c
diff options
context:
space:
mode:
authorEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
committerEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
commit094ca96844842928810f14844413109fc6cdd890 (patch)
treee60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /alpine/arg.c
downloadalpine-094ca96844842928810f14844413109fc6cdd890.tar.xz
Initial Alpine Version
Diffstat (limited to 'alpine/arg.c')
-rw-r--r--alpine/arg.c1325
1 files changed, 1325 insertions, 0 deletions
diff --git a/alpine/arg.c b/alpine/arg.c
new file mode 100644
index 00000000..e23853c4
--- /dev/null
+++ b/alpine/arg.c
@@ -0,0 +1,1325 @@
+#if !defined(lint) && !defined(DOS)
+static char rcsid[] = "$Id: arg.c 900 2008-01-05 01:13:26Z hubert@u.washington.edu $";
+#endif
+
+/*
+ * ========================================================================
+ * Copyright 2006-2008 University of Washington
+ * Copyright 2013 Eduardo Chappa
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * ========================================================================
+ */
+
+/*======================================================================
+ Command line argument parsing functions
+
+ ====*/
+
+#include "headers.h"
+
+#include "../pith/state.h"
+#include "../pith/init.h"
+#include "../pith/conf.h"
+#include "../pith/list.h"
+#include "../pith/util.h"
+#include "../pith/help.h"
+
+#include "imap.h"
+
+#include "arg.h"
+
+
+int process_debug_str(char *);
+void args_add_attach(PATMT **, char *, int);
+int pinerc_cmdline_opt(char *);
+
+
+/*
+ * Name started as to invoke function key mode
+ */
+#define ALPINE_FKEY_NAME "alpinef"
+
+/*
+ * Various error and informational strings..
+ */
+/* TRANSLATORS: This is a list of errors printed when something goes wrong
+ early on with the argument list. Be careful not to change literal
+ option names mentioned in the strings. */
+static char args_err_missing_pinerc[] = N_("missing argument for option \"-pinerc\" (use - for standard out)");
+#if defined(DOS) || defined(OS2)
+static char args_err_missing_aux[] = N_("missing argument for option \"-aux\"");
+#endif
+#ifdef PASSFILE
+static char args_err_missing_passfile[] = N_("missing argument for option \"-passfile\"");
+static char args_err_non_abs_passfile[] = N_("argument to \"-passfile\" should be fully-qualified");
+#endif
+static char args_err_missing_sort[] = N_("missing argument for option \"-sort\"");
+static char args_err_missing_flag_arg[] = N_("missing argument for flag \"%c\"");
+static char args_err_missing_flag_num[] = N_("Non numeric argument for flag \"%c\"");
+static char args_err_missing_debug_num[] = N_("Non numeric argument for \"%s\"");
+static char args_err_missing_url[] = N_("missing URL for \"-url\"");
+static char args_err_missing_attachment[] = N_("missing attachment for \"%s\"");
+static char args_err_conflict[] = N_("conflicting action: \"%s\"");
+static char args_err_unknown[] = N_("unknown flag \"%c\"");
+static char args_err_I_error[] = N_("-I argument \"%s\": %s");
+static char args_err_d_error[] = N_("-d argument \"%s\": %s");
+static char args_err_internal[] = "%s";
+static char args_err_missing_copyprc[] = N_("missing argument for option \"-copy_pinerc\"\nUsage: pine -copy_pinerc <local_pinerc> <remote_pinerc>");
+static char args_err_missing_copyabook[] = N_("missing argument for option \"-copy_abook\"\nUsage: pine -copy_abook <local_abook> <remote_abook>");
+
+
+static char *args_pine_args[] = {
+N_("Possible Starting Arguments for Alpine program:"),
+"",
+N_(" Argument\tMeaning"),
+N_(" <addrs>...\tGo directly into composer sending to given address"),
+N_("\t\tList multiple addresses with a single space between them."),
+N_("\t\tStandard input redirection is allowed with addresses."),
+N_("\t\tNote: Places addresses in the \"To\" field only."),
+N_(" -attach <file>\tGo directly into composer with given file"),
+N_(" -attachlist <file-list>"),
+N_(" -attach_and_delete <file>"),
+N_("\t\tGo to composer, attach file, delete when finished"),
+N_("\t\tNote: Attach options can't be used if -f, -F"),
+N_("\t\tadded to Attachment list. Attachlist must be the last"),
+N_("\t\toption on the command line"),
+N_(" -bail\t\tExit if pinerc file doesn't already exist"),
+#ifdef DEBUG
+N_(" -d n\t\tDebug - set debug level to 'n', or use the following:"),
+N_(" -d keywords...\tflush,timestamp,imap=0..4,tcp,numfiles=0..31,verbose=0..9"),
+#endif
+N_(" -f <folder>\tFolder - give folder name to open"),
+N_(" -c <number>\tContext - which context to apply to -f arg"),
+N_(" -F <file>\tFile - give file name to open and page through and"),
+N_("\t\tforward as email."),
+N_(" -h \t\tHelp - give this list of options"),
+N_(" -k \t\tKeys - Force use of function keys"),
+N_(" -z \t\tSuspend - allow use of ^Z suspension"),
+N_(" -r \t\tRestricted - can only send mail to oneself"),
+N_(" -sort <sort>\tSort - Specify sort order of folder:"),
+N_("\t\t\tarrival, subject, threaded, orderedsubject, date,"),
+N_("\t\t\tfrom, size, score, to, cc, /reverse"),
+N_(" -i\t\tIndex - Go directly to index, bypassing main menu"),
+N_(" -I <keystroke_list> Initial keystrokes to be executed"),
+N_(" -n <number>\tEntry in index to begin on"),
+N_(" -o \t\tReadOnly - Open first folder read-only"),
+N_(" -conf\t\tConfiguration - Print out fresh global configuration. The"),
+N_("\t\tvalues of your global configuration affect all Alpine users"),
+N_("\t\ton your system unless they have overridden the values in their"),
+N_("\t\tpinerc files."),
+N_(" -pinerc <file>\tConfiguration - Put fresh pinerc configuration in <file>"),
+N_(" -p <pinerc>\tUse alternate .pinerc file"),
+#if !defined(DOS) && !defined(OS2)
+N_(" -P <pine.conf>\tUse alternate pine.conf file"),
+#else
+N_(" -aux <aux_files_dir>\tUse this with remote pinerc"),
+N_(" -P <pine.conf>\tUse pine.conf file for default settings"),
+N_(" -nosplash \tDisable the PC-Alpine splash screen"),
+#endif
+
+#if defined(APPLEKEYCHAIN) || (WINCRED > 0)
+N_(" -erase_stored_passwords\tEliminate any stored passwords"),
+#endif
+
+#ifdef PASSFILE
+N_(" -passfile <fully_qualified_filename>\tSet the password file to something other"),
+N_("\t\tthan the default"),
+#endif /* PASSFILE */
+
+#ifdef LOCAL_PASSWD_CACHE
+N_(" -nowrite_password_cache\tRead from a password cache if there is one, but"),
+N_("\t\t\t\tnever offer to write a password to the cache"),
+#endif /* LOCAL_PASSWD_CACHE */
+
+N_(" -x <config>\tUse configuration exceptions in <config>."),
+N_("\t\tExceptions are used to override your default pinerc"),
+N_("\t\tsettings for a particular platform, can be a local file or"),
+N_("\t\ta remote folder."),
+N_(" -v \t\tVersion - show version information"),
+N_(" -version\tVersion - show version information"),
+N_(" -supported\tList supported options"),
+N_(" -url <url>\tOpen the given URL"),
+N_("\t\tNote: Can't be used if -f, -F"),
+N_("\t\tStandard input redirection is not allowed with URLs."),
+N_("\t\tFor mailto URLs, 'body='text should be used in place of"),
+N_("\t\tinput redirection."),
+N_(" -copy_pinerc <local_pinerc> <remote_pinerc> copy local pinerc to remote"),
+N_(" -copy_abook <local_abook> <remote_abook> copy local addressbook to remote"),
+N_(" -convert_sigs -p <pinerc> convert signatures to literal signatures"),
+#if defined(_WINDOWS)
+N_(" -install \tPrompt for some basic setup information"),
+N_(" -uninstall \tRemove traces of Alpine from Windows system settings"),
+N_(" -registry <cmd>\tWhere cmd is set,noset,clear,clearsilent,dump"),
+#endif
+" -<option>=<value> Assign <value> to the pinerc option <option>",
+"\t\t e.g. -signature-file=sig1",
+"\t\t e.g. -color-style=no-color",
+"\t\t e.g. -feature-list=enable-sigdashes",
+"\t\t Note: feature-list is additive.",
+"\t\t You may leave off the \"feature-list=\" part of that,",
+"\t\t e.g. -enable-sigdashes",
+NULL
+};
+
+
+
+/*
+ * Parse the command line args.
+ *
+ * Args: pine_state -- The pine_state structure to put results in
+ * argc, argv -- The obvious
+ * addrs -- Pointer to address list that we set for caller
+ *
+ * Result: command arguments parsed
+ * possible printing of help for command line
+ * various flags in pine_state set
+ * returns the string name of the first folder to open
+ * addrs is set
+ */
+void
+pine_args(struct pine *pine_state, int argc, char **argv, ARGDATA_S *args)
+{
+ register int ac;
+ register char **av;
+ int c;
+ char *str;
+ char *cmd_list = NULL;
+ char *debug_str = NULL;
+ char *sort = NULL;
+ char *pinerc_file = NULL;
+ char *lc = NULL;
+ int do_help = 0;
+ int do_conf = 0;
+ int usage = 0;
+ int do_use_fk = 0;
+ int do_can_suspend = 0;
+ int do_version = 0;
+ struct variable *vars = pine_state->vars;
+
+ ac = argc;
+ av = argv;
+ memset(args, 0, sizeof(ARGDATA_S));
+ args->action = aaFolder;
+
+ pine_state->pine_name = (lc = last_cmpnt(argv[0])) ? lc : (lc = argv[0]);
+#ifdef DOS
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, "%.*s", pine_state->pine_name - argv[0], argv[0]);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ pine_state->pine_dir = cpystr(tmp_20k_buf);
+#endif
+
+ /* while more arguments with leading - */
+Loop: while(--ac > 0)
+ if(**++av == '-'){
+ /* while more chars in this argument */
+ while(*++*av){
+ /* check for pinerc options */
+ if(pinerc_cmdline_opt(*av)){
+ goto Loop; /* done with this arg, go to next */
+ }
+ /* then other multi-char options */
+ else if(strcmp(*av, "conf") == 0){
+ do_conf = 1;
+ goto Loop; /* done with this arg, go to next */
+ }
+ else if(strcmp(*av, "pinerc") == 0){
+ if(--ac)
+ pinerc_file = *++av;
+ else{
+ display_args_err(_(args_err_missing_pinerc), NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+#if defined(DOS) || defined(OS2)
+ else if(strcmp(*av, "aux") == 0){
+ if(--ac){
+ if((str = *++av) != NULL)
+ pine_state->aux_files_dir = cpystr(str);
+ }
+ else{
+ display_args_err(_(args_err_missing_aux), NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+ else if(strcmp(*av, "nosplash") == 0)
+ goto Loop; /* already taken care of in WinMain */
+#endif
+
+#if defined(APPLEKEYCHAIN) || (WINCRED > 0)
+ else if(strcmp(*av, "erase_stored_passwords") == 0){
+#if (WINCRED > 0)
+ erase_windows_credentials();
+#else
+ macos_erase_keychain();
+#endif
+ goto Loop;
+ }
+#endif /* defined(APPLEKEYCHAIN) || (WINCRED > 0) */
+
+#ifdef PASSFILE
+ else if(strcmp(*av, "passfile") == 0){
+ if(--ac){
+ if((str = *++av) != NULL){
+ if(!is_absolute_path(str)){
+ display_args_err(_(args_err_non_abs_passfile),
+ NULL, 1);
+ ++usage;
+ }
+ else{
+ if(pine_state->passfile)
+ fs_give((void **)&pine_state->passfile);
+
+ pine_state->passfile = cpystr(str);
+ }
+ }
+ }
+ else{
+ display_args_err(_(args_err_missing_passfile), NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+#endif /* PASSFILE */
+
+#ifdef LOCAL_PASSWD_CACHE
+ else if(strcmp(*av, "nowrite_password_cache") == 0){
+ ps_global->nowrite_password_cache = 1;
+ goto Loop;
+ }
+#endif /* LOCAL_PASSWD_CACHE */
+
+ else if(strcmp(*av, "convert_sigs") == 0){
+ ps_global->convert_sigs = 1;
+ goto Loop;
+ }
+ else if(strcmp(*av, "supported") == 0){
+ ps_global->dump_supported_options = 1;
+ goto Loop;
+ }
+ else if(strcmp(*av, "copy_pinerc") == 0){
+ if(args->action == aaFolder && !args->data.folder){
+ args->action = aaPrcCopy;
+ if(ac > 2){
+ ac -= 2;
+ args->data.copy.local = *++av;
+ args->data.copy.remote = *++av;
+ }
+ else{
+ display_args_err(_(args_err_missing_copyprc), NULL, 1);
+ ++usage;
+ }
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-copy_pinerc");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+ else if(strcmp(*av, "copy_abook") == 0){
+ if(args->action == aaFolder && !args->data.folder){
+ args->action = aaAbookCopy;
+ if(ac > 2){
+ ac -= 2;
+ args->data.copy.local = *++av;
+ args->data.copy.remote = *++av;
+ }
+ else{
+ display_args_err(_(args_err_missing_copyabook), NULL, 1);
+ ++usage;
+ }
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-copy_abook");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+ else if(strcmp(*av, "sort") == 0){
+ if(--ac){
+ sort = *++av;
+ COM_SORT_KEY = cpystr(sort);
+ }
+ else{
+ display_args_err(_(args_err_missing_sort), NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+ else if(strcmp(*av, "url") == 0){
+ if(args->action == aaFolder && !args->data.folder){
+ args->action = aaURL;
+ if(--ac){
+ args->url = cpystr(*++av);
+ }
+ else{
+ display_args_err(_(args_err_missing_url), NULL, 1);
+ ++usage;
+ }
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-url");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+ else if(strcmp(*av, "attach") == 0){
+ if((args->action == aaFolder && !args->data.folder)
+ || args->action == aaMail
+ || args->action == aaURL){
+ if(args->action != aaURL)
+ args->action = aaMail;
+ if(--ac){
+ args_add_attach(&args->data.mail.attachlist,
+ *++av, FALSE);
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attach");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ }
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attach");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+ else if(strcmp(*av, "attachlist") == 0){
+ if((args->action == aaFolder && !args->data.folder)
+ || args->action == aaMail
+ || args->action == aaURL){
+ if(args->action != aaURL)
+ args->action = aaMail;
+ if(ac - 1){
+ do{
+ if(can_access(*(av+1), READ_ACCESS) == 0){
+ ac--;
+ args_add_attach(&args->data.mail.attachlist,
+ *++av, FALSE);
+ }
+ else
+ break;
+ }
+ while(ac);
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attachList");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ }
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attachList");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+ else if(strcmp(*av, "attach_and_delete") == 0){
+ if((args->action == aaFolder && !args->data.folder)
+ || args->action == aaMail
+ || args->action == aaURL){
+ if(args->action != aaURL)
+ args->action = aaMail;
+ if(--ac){
+ args_add_attach(&args->data.mail.attachlist,
+ *++av, TRUE);
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_attachment), "-attach_and_delete");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ }
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-attach_and_delete");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+ else if(strcmp(*av, "bail") == 0){
+ pine_state->exit_if_no_pinerc = 1;
+ goto Loop;
+ }
+ else if(strcmp(*av, "version") == 0){
+ do_version = 1;
+ goto Loop;
+ }
+#ifdef _WINDOWS
+ else if(strcmp(*av, "install") == 0){
+ pine_state->install_flag = 1;
+ pine_state->update_registry = UREG_ALWAYS_SET;
+ goto Loop;
+ }
+ else if(strcmp(*av, "uninstall") == 0){
+ /*
+ * Blast password cache, clear registry settings
+ */
+#if (WINCRED > 0)
+ erase_windows_credentials();
+#endif
+ mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0);
+ exit(0);
+ }
+ else if(strcmp(*av, "registry") == 0){
+ if(--ac){
+ if(!strucmp(*++av, "set")){
+ pine_state->update_registry = UREG_ALWAYS_SET;
+ }
+ else if(!strucmp(*av, "noset")){
+ pine_state->update_registry = UREG_NEVER_SET;
+ }
+ else if(!strucmp(*av, "clear")){
+ if(!mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0))
+ display_args_err(
+ _("Alpine related Registry values removed."),
+ NULL, 0);
+ else
+ display_args_err(
+ _("Not all Alpine related Registry values could be removed"),
+ NULL, 0);
+ exit(0);
+ }
+ else if(!strucmp(*av, "clearsilent")){
+ mswin_reg(MSWR_OP_BLAST, MSWR_NULL, NULL, 0);
+ exit(0);
+ }
+ else if(!strucmp(*av, "dump")){
+ char **pRegistry = mswin_reg_dump();
+
+ if(pRegistry){
+ display_args_err(NULL, pRegistry, 0);
+ free_list_array(&pRegistry);
+ }
+ exit(0);
+ }
+ else{
+ display_args_err(_("unknown registry command"),
+ NULL, 1);
+ ++usage;
+ }
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_flag_arg), c);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ }
+
+ goto Loop;
+ }
+#endif
+ /* single char flags */
+ else{
+ switch(c = **av){
+ case 'h':
+ do_help = 1;
+ break; /* break back to inner-while */
+ case 'k':
+ do_use_fk = 1;
+ break;
+ case 'z':
+ do_can_suspend = 1;
+ break;
+ case 'r':
+ pine_state->restricted = 1;
+ break;
+ case 'o':
+ pine_state->open_readonly_on_startup = 1;
+ break;
+ case 'i':
+ pine_state->start_in_index = 1;
+ break;
+ case 'v':
+ do_version = 1;
+ break; /* break back to inner-while */
+ /* these take arguments */
+ case 'f': case 'F': case 'p': case 'I':
+ case 'c': case 'd': case 'P': case 'x': /* string args */
+ case 'n': /* integer args */
+ if(*++*av)
+ str = *av;
+ else if(--ac)
+ str = *++av;
+ else if(c == 'f' || c == 'F')
+ str = "";
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_flag_arg), c);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ goto Loop;
+ }
+
+ switch(c){
+ case 'f':
+ if(args->action == aaFolder && !args->data.folder){
+ args->data.folder = cpystr(str);
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-f");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ usage++;
+ }
+
+ break;
+ case 'F':
+ if(args->action == aaFolder && !args->data.folder){
+ args->action = aaMore;
+ args->data.file = cpystr(str);
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), "-F");
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ usage++;
+ }
+
+ break;
+ case 'd':
+ debug_str = str;
+ break;
+ case 'I':
+ cmd_list = str;
+ break;
+ case 'p':
+ if(str){
+ char path[MAXPATH], dir[MAXPATH];
+
+ if(IS_REMOTE(str) || is_absolute_path(str)){
+ strncpy(path, str, sizeof(path)-1);
+ path[sizeof(path)-1] = '\0';
+ }
+ else{
+ getcwd(dir, sizeof(path));
+ build_path(path, dir, str, sizeof(path));
+ }
+
+ /*
+ * Pinerc used to be the name of the pinerc
+ * file. Now, since the pinerc can be remote,
+ * we've replaced the variable pinerc with the
+ * structure prc. Unfortunately, other parts of
+ * pine rely on the fact that pinerc is the
+ * name of the pinerc _file_, and use the
+ * directory that the pinerc file is located
+ * in for their own purposes. We keep that so
+ * things will keep working.
+ */
+
+ if(!IS_REMOTE(path)){
+ if(pine_state->pinerc)
+ fs_give((void **)&pine_state->pinerc);
+
+ pine_state->pinerc = cpystr(path);
+ }
+
+ /*
+ * Last one wins. This would be the place where
+ * we put multiple pinercs in a list if we
+ * were to allow that.
+ */
+ if(pine_state->prc)
+ free_pinerc_s(&pine_state->prc);
+
+ pine_state->prc = new_pinerc_s(path);
+ }
+
+ break;
+ case 'P':
+ if(str){
+ char path[MAXPATH], dir[MAXPATH];
+
+ if(IS_REMOTE(str) || is_absolute_path(str)){
+ strncpy(path, str, sizeof(path)-1);
+ path[sizeof(path)-1] = '\0';
+ }
+ else{
+ getcwd(dir, sizeof(path));
+ build_path(path, dir, str, sizeof(path));
+ }
+
+ if(pine_state->pconf)
+ free_pinerc_s(&pine_state->pconf);
+
+ pine_state->pconf = new_pinerc_s(path);
+ }
+
+ break;
+ case 'x':
+ if(str)
+ pine_state->exceptions = cpystr(str);
+
+ break;
+ case 'c':
+ if(!isdigit((unsigned char)str[0])){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF,
+ _(args_err_missing_flag_num), c);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ break;
+ }
+
+ pine_state->init_context = (short) atoi(str);
+ break;
+
+ case 'n':
+ if(!isdigit((unsigned char)str[0])){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF,
+ _(args_err_missing_flag_num), c);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ break;
+ }
+
+ pine_state->start_entry = atoi(str);
+ if(pine_state->start_entry < 1)
+ pine_state->start_entry = 1;
+
+ break;
+ }
+
+ goto Loop;
+
+ default:
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_unknown), c);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ ++usage;
+ break;
+ }
+ }
+ }
+ }
+ else if(args->action == aaMail
+ || (args->action == aaFolder && !args->data.folder)){
+ STRLIST_S *stp, **slp;
+
+ args->action = aaMail;
+
+ stp = new_strlist(*av);
+
+ for(slp = &args->data.mail.addrlist; *slp; slp = &(*slp)->next)
+ ;
+
+ *slp = stp;
+ }
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_conflict), *av);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ usage++;
+ }
+
+ if(cmd_list){
+ int commas = 0;
+ char *p = cmd_list;
+ char *error = NULL;
+
+ while(*p++)
+ if(*p == ',')
+ ++commas;
+
+ COM_INIT_CMD_LIST = parse_list(cmd_list, commas+1, 0, &error);
+ if(error){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_I_error), cmd_list, error);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ exit(-1);
+ }
+ }
+
+#ifdef DEBUG
+ pine_state->debug_nfiles = NUMDEBUGFILES;
+#endif
+ if(debug_str && process_debug_str(debug_str))
+ usage++;
+
+ if(lc && strncmp(lc, ALPINE_FKEY_NAME, sizeof(ALPINE_FKEY_NAME) - 1) == 0)
+ do_use_fk = 1;
+
+ if(do_use_fk || do_can_suspend){
+ char list[500];
+ int commas = 0;
+ char *p = list;
+ char *error = NULL;
+
+ list[0] = '\0';
+
+ if(do_use_fk){
+ if(list[0]){
+ strncat(list, ",", sizeof(list)-strlen(list)-1);
+ list[sizeof(list)-1] = '\0';
+ }
+
+ strncat(list, "use-function-keys", sizeof(list)-strlen(list)-1);
+ list[sizeof(list)-1] = '\0';
+ }
+
+ if(do_can_suspend){
+ if(list[0]){
+ strncat(list, ",", sizeof(list)-strlen(list)-1);
+ list[sizeof(list)-1] = '\0';
+ }
+
+ strncat(list, "enable-suspend", sizeof(list)-strlen(list)-1);
+ list[sizeof(list)-1] = '\0';
+ }
+
+ while(*p++)
+ if(*p == ',')
+ ++commas;
+
+ pine_state->feat_list_back_compat = parse_list(list,commas+1,0,&error);
+ if(error){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, args_err_internal, error);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ exit(-1);
+ }
+ }
+
+ if(((do_conf ? 1 : 0)+(pinerc_file ? 1 : 0)) > 1){
+ display_args_err(_("May only have one of -conf and -pinerc"),
+ NULL, 1);
+ exit(-1);
+ }
+
+ if(do_help || usage)
+ args_help();
+
+ if(usage)
+ exit(-1);
+
+ if(do_version){
+ extern char datestamp[], hoststamp[];
+ char rev[128];
+
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, "Alpine %s (%s %s) built %s on %s",
+ ALPINE_VERSION,
+ SYSTYPE ? SYSTYPE : "?",
+ get_alpine_revision_string(rev, sizeof(rev)),
+ datestamp, hoststamp);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 0);
+ exit(0);
+ }
+
+ if(do_conf)
+ dump_global_conf();
+
+ if(pinerc_file)
+ dump_new_pinerc(pinerc_file);
+
+ /*
+ * Don't NULL out argv[0] or we might crash in unexpected ways. In OS X, we were
+ * crashing when opening attachments because of this.
+ */
+ if(ac <= 0 && av != argv)
+ *av = NULL;
+}
+
+
+/*
+ * Returns 0 if ok, -1 if error.
+ */
+int
+process_debug_str(char *debug_str)
+{
+ int i, usage = 0;
+ int commas = 0;
+ int new_style_debug_arg = 0;
+ char *q = debug_str;
+ char *error = NULL;
+ char **list, **p;
+
+#ifdef DEBUG
+ if(debug_str){
+ if(!isdigit((unsigned char)debug_str[0]))
+ new_style_debug_arg++;
+
+ if(new_style_debug_arg){
+ while(*q++)
+ if(*q == ',')
+ ++commas;
+
+ list = parse_list(debug_str, commas+1, 0, &error);
+ if(error){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_d_error), debug_str, error);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ return(-1);
+ }
+
+ if(list){
+ for(p = list; *p; p++){
+ if(struncmp(*p, "timestamp", 9) == 0){
+ ps_global->debug_timestamp = 1;
+ }
+ else if(struncmp(*p, "imap", 4) == 0){
+ q = *p + 4;
+ if(!*q || !*(q+1) || *q != '=' ||
+ !isdigit((unsigned char)*(q+1))){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ usage = -1;
+ }
+ else{
+ i = atoi(q+1);
+ ps_global->debug_imap = MIN(5,MAX(0,i));
+ }
+ }
+ else if(struncmp(*p, "flush", 5) == 0){
+ ps_global->debug_flush = 1;
+ }
+ else if(struncmp(*p, "tcp", 3) == 0){
+ ps_global->debug_tcp = 1;
+ }
+ else if(struncmp(*p, "verbose", 7) == 0){
+ q = *p + 7;
+ if(!*q || !*(q+1) || *q != '=' ||
+ !isdigit((unsigned char)*(q+1))){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ usage = -1;
+ }
+ else
+ debug = atoi(q+1);
+ }
+ else if(struncmp(*p, "numfiles", 8) == 0){
+ q = *p + 8;
+ if(!*q || !*(q+1) || *q != '=' ||
+ !isdigit((unsigned char)*(q+1))){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ usage = -1;
+ }
+ else{
+ i = atoi(q+1);
+ ps_global->debug_nfiles = MIN(31,MAX(0,i));
+ }
+ }
+ else if(struncmp(*p, "malloc", 6) == 0){
+ q = *p + 6;
+ if(!*q || !*(q+1) || *q != '=' ||
+ !isdigit((unsigned char)*(q+1))){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ usage = -1;
+ }
+ else{
+ i = atoi(q+1);
+ ps_global->debug_malloc = MIN(63,MAX(0,i));
+ }
+ }
+#if defined(ENABLE_LDAP) && defined(LDAP_DEBUG)
+ else if(struncmp(*p, "ldap", 4) == 0){
+ q = *p + 4;
+ if(!*q || !*(q+1) || *q != '=' ||
+ !isdigit((unsigned char)*(q+1))){
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _(args_err_missing_debug_num), *p);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ usage = -1;
+ }
+ else{
+ i = atoi(q+1);
+ ldap_debug = i;
+ }
+ }
+#endif /* LDAP */
+ else{
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("unknown debug keyword \"%s\""), *p);
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ usage = -1;
+ }
+ }
+
+ free_list_array(&list);
+ }
+ }
+ else{
+ debug = atoi(debug_str);
+ if(debug > 9)
+ ps_global->debug_imap = 5;
+ else if(debug > 7)
+ ps_global->debug_imap = 4;
+ else if(debug > 6)
+ ps_global->debug_imap = 3;
+ else if(debug > 4)
+ ps_global->debug_imap = 2;
+ else if(debug > 2)
+ ps_global->debug_imap = 1;
+
+ if(debug > 7)
+ ps_global->debug_timestamp = 1;
+
+ if(debug > 8)
+ ps_global->debug_flush = 1;
+ }
+ }
+
+ if(!new_style_debug_arg){
+#ifdef CSRIMALLOC
+ ps_global->debug_malloc =
+ (debug <= DEFAULT_DEBUG) ? 1 : (debug < 9) ? 2 : 3;
+#else /* !CSRIMALLOC */
+#ifdef HAVE_SMALLOC
+ if(debug > 8)
+ ps_global->debug_malloc = 2;
+#else /* !HAVE_SMALLOC */
+#ifdef NXT
+ if(debug > 8)
+ ps_global->debug_malloc = 32;
+#endif /* NXT */
+#endif /* HAVE_SMALLOC */
+#endif /* CSRIMALLOC */
+ }
+
+#else /* !DEBUG */
+
+ snprintf(tmp_20k_buf, SIZEOF_20KBUF, _("unknown flag \"d\", debugging not compiled in"));
+ tmp_20k_buf[SIZEOF_20KBUF-1] = '\0';
+ display_args_err(tmp_20k_buf, NULL, 1);
+ usage = -1;
+
+#endif /* !DEBUG */
+
+ return(usage);
+}
+
+
+void
+args_add_attach(PATMT **alpp, char *s, int deleted)
+{
+ PATMT *atmp, **atmpp;
+
+ atmp = (PATMT *) fs_get(sizeof(PATMT));
+ memset(atmp, 0, sizeof(PATMT));
+ atmp->filename = cpystr(s);
+
+#if defined(DOS) || defined(OS2)
+ (void) removing_quotes(atmp->filename);
+#endif
+
+ if(deleted)
+ atmp->flags |= A_TMP;
+
+ for(atmpp = alpp; *atmpp; atmpp = &(*atmpp)->next)
+ ;
+
+ *atmpp = atmp;
+}
+
+
+/*----------------------------------------------------------------------
+ print a few lines of help for command line arguments
+
+ Args: none
+
+ Result: prints help messages
+ ----------------------------------------------------------------------*/
+void
+args_help(void)
+{
+ char *pp[2];
+#ifndef _WINDOWS
+ char **a;
+#endif
+
+ pp[1] = NULL;
+
+ /** print out possible starting arguments... **/
+
+ /*
+ * display_args_err expects already translated input
+ * so we need to translate a line at a time. Since
+ * the 1st and 3rd args are zero it is ok to call it
+ * a line at a time.
+ *
+ * Windows expects the full block of text so we'll pass
+ * it as such.
+ */
+#ifndef _WINDOWS
+ for(a=args_pine_args; a && *a; a++){
+ pp[0] = _(*a);
+ display_args_err(NULL, pp, 0);
+ }
+#else
+ display_args_err(NULL, args_pine_args, 0);
+#endif
+
+ exit(1);
+}
+
+
+/*----------------------------------------------------------------------
+ write argument error to the display...
+
+ Args: none
+
+ Result: prints help messages
+ ----------------------------------------------------------------------*/
+void
+display_args_err(char *s, char **a, int err)
+{
+ char errstr[256], *errp;
+ FILE *fp = err ? stderr : stdout;
+
+
+ if(err && s){
+ snprintf(errp = errstr, sizeof(errstr), "%s: %s", _("Argument Error"), s);
+ errstr[sizeof(errstr)-1] = '\0';
+ }
+ else
+ errp = s;
+
+#ifdef _WINDOWS
+ if(errp)
+ mswin_messagebox(errp, err);
+
+ if(a && *a){
+ os_argsdialog(a);
+ }
+#else
+ if(errp)
+ fprintf(fp, "%s\n", errp);
+
+ while(a && *a)
+ fprintf(fp, "%s\n", *a++);
+#endif
+}
+
+
+/*
+ * The argument is an argument from the command line. We check to see
+ * if it is specifying an alternate value for one of the options that is
+ * normally set in pinerc. If so, we return 1 and set the appropriate
+ * values in the variables array.
+ * The arg can be
+ * varname=value
+ * varname=value1,value2,value3
+ * feature-list=featurename these are just a special
+ * feature-list=featurename1,featurename2 case of above
+ * featurename This is equivalent to above
+ * no-featurename
+ */
+int
+pinerc_cmdline_opt(char *arg)
+{
+ struct variable *v;
+ char *p1 = NULL,
+ *value,
+ **oldlvalue = NULL,
+ **lvalue;
+ int i, count;
+
+ if(!arg || !arg[0])
+ return 0;
+
+ for(v = ps_global->vars; v->name != NULL; v++){
+ if(v->is_used && struncmp(v->name, arg, strlen(v->name)) == 0){
+ p1 = arg + strlen(v->name);
+
+ /*----- Skip to '=' -----*/
+ while(*p1 && (*p1 == '\t' || *p1 == ' '))
+ p1++;
+
+ if(*p1 != '='){
+ char buf[MAILTMPLEN];
+
+ snprintf(buf, sizeof(buf), _("Missing \"=\" after -%s\n"), v->name);
+ buf[sizeof(buf)-1] = '\0';
+ exceptional_exit(buf, -1);
+ }
+
+ p1++;
+ break;
+ }
+ }
+
+ /* no match, check for a feature name used directly */
+ if(v->name == NULL){
+ FEATURE_S *feat;
+ char *featname;
+
+ if(struncmp(arg, "no-", 3) == 0)
+ featname = arg+3;
+ else
+ featname = arg;
+
+ for(i = 0; (feat = feature_list(i)) != NULL; i++){
+ if(strucmp(featname, feat->name) == 0){
+ v = &(ps_global->vars)[V_FEATURE_LIST];
+ p1 = arg;
+ break;
+ }
+ }
+ }
+
+ if(!p1)
+ return 0;
+
+ if(v->is_obsolete || !v->is_user){
+ char buf[MAILTMPLEN];
+
+ if(v->is_obsolete)
+ snprintf(buf, sizeof(buf), _("Option \"%s\" is obsolete\n"), v->name);
+ else
+ snprintf(buf, sizeof(buf), _("Option \"%s\" is not user settable\n"), v->name);
+
+ exceptional_exit(buf, -1);
+ }
+
+ /* free mem */
+ if(v->is_list){
+ oldlvalue = v->cmdline_val.l;
+ v->cmdline_val.l = NULL;
+ }
+ else if(v->cmdline_val.p)
+ fs_give((void **) &(v->cmdline_val.p));
+
+ /*----- Matched a variable, get its value ----*/
+ while(*p1 == ' ' || *p1 == '\t')
+ p1++;
+ value = p1;
+
+ if(*value == '\0'){
+ if(v->is_list){
+ v->cmdline_val.l = (char **)fs_get(2 * sizeof(char *));
+ /*
+ * we let people leave off the quotes on command line so that
+ * they don't have to mess with shell quoting
+ */
+ v->cmdline_val.l[0] = cpystr("");
+ v->cmdline_val.l[1] = NULL;
+ if(oldlvalue)
+ free_list_array(&oldlvalue);
+
+ }else{
+ v->cmdline_val.p = cpystr("");
+ }
+ return 1;
+ }
+
+ /*--value is non-empty--*/
+ if(*value == '"' && !v->is_list){
+ value++;
+ for(p1 = value; *p1 && *p1 != '"'; p1++);
+ if(*p1 == '"')
+ *p1 = '\0';
+ else
+ removing_trailing_white_space(value);
+ }else{
+ removing_trailing_white_space(value);
+ }
+
+ if(v->is_list){
+ int was_quoted = 0;
+ char *error = NULL;
+
+ count = 1;
+ for(p1=value; *p1; p1++){ /* generous count of list elements */
+ if(*p1 == '"') /* ignore ',' if quoted */
+ was_quoted = (was_quoted) ? 0 : 1;
+
+ if(*p1 == ',' && !was_quoted)
+ count++;
+ }
+
+ lvalue = parse_list(value, count, 0, &error);
+ if(error){
+ char buf[MAILTMPLEN];
+
+ snprintf(buf, sizeof(buf), "%s in %s = \"%s\"\n", error, v->name, value);
+ buf[sizeof(buf)-1] = '\0';
+ exceptional_exit(buf, -1);
+ }
+ /*
+ * Special case: turn "" strings into empty strings.
+ * This allows users to turn off default lists. For example,
+ * if smtp-server is set then a user could override smtp-server
+ * with smtp-server="".
+ */
+ for(i = 0; lvalue[i]; i++)
+ if(lvalue[i][0] == '"' &&
+ lvalue[i][1] == '"' &&
+ lvalue[i][2] == '\0')
+ lvalue[i][0] = '\0';
+ }
+
+ if(v->is_list){
+ if(oldlvalue){
+ char **combinedlvalue;
+ int j;
+
+ /* combine old and new cmdline lists */
+ for(count = 0, i = 0; oldlvalue[i]; i++, count++)
+ ;
+
+ for(i = 0; lvalue && lvalue[i]; i++, count++)
+ ;
+
+ combinedlvalue = (char **) fs_get((count+1) * sizeof(char *));
+ memset(combinedlvalue, 0, (count+1) * sizeof(*combinedlvalue));
+
+ for(i = 0, j = 0; oldlvalue[i]; i++, j++)
+ combinedlvalue[j] = cpystr(oldlvalue[i]);
+
+ for(i = 0; lvalue && lvalue[i]; i++, j++)
+ combinedlvalue[j] = cpystr(lvalue[i]);
+
+ v->cmdline_val.l = combinedlvalue;
+
+ fs_give((void **) &oldlvalue);
+ if(lvalue)
+ fs_give((void **) &lvalue);
+ }
+ else
+ v->cmdline_val.l = lvalue;
+ }
+ else
+ v->cmdline_val.p = cpystr(value);
+
+ return 1;
+}