]> Pileus Git - ~andy/fetchmail/blobdiff - options.c
Attempt merging from 6.3.24.
[~andy/fetchmail] / options.c
index c2d1849c976e9a6c61251901585ed9f77a562f3a..5f1739c4f6e4cdbb50c2f1975f6367ca5ff0913b 100644 (file)
--- a/options.c
+++ b/options.c
 #include <pwd.h>
 #include <string.h>
 #include <errno.h>
-#if defined(STDC_HEADERS)
 #include  <stdlib.h>
 #include  <limits.h>
-#else
-#include  <ctype.h>
-#endif
 
 #include "getopt.h"
 #include "fetchmail.h"
-#include "i18n.h"
+#include "gettext.h"
 
 enum {
     LA_INVISIBLE = 256,
+    LA_PIDFILE,
     LA_SYSLOG,
     LA_NOSYSLOG,
     LA_POSTMASTER,
@@ -44,19 +41,34 @@ enum {
     LA_SSLCERT,
     LA_SSLPROTO,
     LA_SSLCERTCK,
+    LA_SSLCERTFILE,
     LA_SSLCERTPATH,
+    LA_SSLCOMMONNAME,
     LA_SSLFINGERPRINT,
     LA_FETCHSIZELIMIT,
     LA_FASTUIDL,
     LA_LIMITFLUSH,
+    LA_IDLE,
+    LA_NOSOFTBOUNCE,
+    LA_SOFTBOUNCE,
+    LA_BADHEADER,
+    LA_RETRIEVEERROR
 };
 
-/* options still left: CgGhHjJoORTWxXYz */
-static const char *shortoptions = 
+static const char *shortoptions =
+/* options still left: ghHjJoRTWxXYz */
+#ifdef HAVE_LIBPWMD
+       "O:C:G:"
+#endif
        "?Vcsvd:NqL:f:i:p:UP:A:t:E:Q:u:akKFnl:r:S:Z:b:B:e:m:I:M:yw:D:";
 
 static const struct option longoptions[] = {
 /* this can be const because all flag fields are 0 and will never get set */
+#ifdef HAVE_LIBPWMD
+  {"pwmd-socket",      required_argument,  (int *) 0, 'C' },
+  {"pwmd-file",                required_argument,  (int *) 0, 'G' },
+  {"pinentry-timeout", required_argument,  (int *) 0, 'O' },
+#endif
   {"help",     no_argument,       (int *) 0, '?' },
   {"version",  no_argument,       (int *) 0, 'V' },
   {"check",    no_argument,       (int *) 0, 'c' },
@@ -72,23 +84,29 @@ static const struct option longoptions[] = {
   {"nosyslog", no_argument,       (int *) 0, LA_NOSYSLOG },
   {"fetchmailrc",required_argument,(int *) 0, 'f' },
   {"idfile",   required_argument, (int *) 0, 'i' },
+  {"pidfile",  required_argument, (int *) 0, LA_PIDFILE },
   {"postmaster",required_argument, (int *) 0, LA_POSTMASTER },
   {"nobounce", no_argument,       (int *) 0, LA_NOBOUNCE },
+  {"nosoftbounce", no_argument,           (int *) 0, LA_NOSOFTBOUNCE },
+  {"softbounce", no_argument,     (int *) 0, LA_SOFTBOUNCE },
 
   {"protocol", required_argument, (int *) 0, 'p' },
   {"proto",    required_argument, (int *) 0, 'p' },
   {"uidl",     no_argument,       (int *) 0, 'U' },
+  {"idle",     no_argument,       (int *) 0, LA_IDLE},
   {"port",     required_argument, (int *) 0, 'P' },
   {"service",  required_argument, (int *) 0, 'P' },
   {"auth",     required_argument, (int *) 0, LA_AUTH},
   {"timeout",  required_argument, (int *) 0, 't' },
   {"envelope", required_argument, (int *) 0, 'E' },
   {"qvirtual", required_argument, (int *) 0, 'Q' },
+  {"bad-header",required_argument, (int *) 0, LA_BADHEADER},
 
   {"user",     required_argument, (int *) 0, 'u' },
   {"username", required_argument, (int *) 0, 'u' },
 
   {"all",      no_argument,       (int *) 0, 'a' },
+  {"fetchall", no_argument,       (int *) 0, 'a' },
   {"nokeep",   no_argument,       (int *) 0, 'K' },
   {"keep",     no_argument,       (int *) 0, 'k' },
   {"flush",    no_argument,       (int *) 0, 'F' },
@@ -96,6 +114,7 @@ static const struct option longoptions[] = {
   {"norewrite",        no_argument,       (int *) 0, 'n' },
   {"limit",    required_argument, (int *) 0, 'l' },
   {"warnings", required_argument, (int *) 0, 'w' },
+  {"retrieve-error",   required_argument, (int *) 0, LA_RETRIEVEERROR },
 
   {"folder",   required_argument, (int *) 0, 'r' },
   {"smtphost", required_argument, (int *) 0, 'S' },
@@ -119,7 +138,9 @@ static const struct option longoptions[] = {
   {"sslcert",  required_argument, (int *) 0, LA_SSLCERT },
   {"sslproto",  required_argument, (int *) 0, LA_SSLPROTO },
   {"sslcertck", no_argument,      (int *) 0, LA_SSLCERTCK },
+  {"sslcertfile",   required_argument, (int *) 0, LA_SSLCERTFILE },
   {"sslcertpath",   required_argument, (int *) 0, LA_SSLCERTPATH },
+  {"sslcommonname",    required_argument, (int *) 0, LA_SSLCOMMONNAME },
   {"sslfingerprint",   required_argument, (int *) 0, LA_SSLFINGERPRINT },
 #endif
 
@@ -144,7 +165,6 @@ static const struct option longoptions[] = {
 static int xatoi(char *s, int *errflagptr)
 /* do safe conversion from string to number */
 {
-#if defined (STDC_HEADERS) && defined (LONG_MAX) && defined (INT_MAX)
     /* parse and convert numbers, but also check for invalid characters in
      * numbers
      */
@@ -175,49 +195,16 @@ static int xatoi(char *s, int *errflagptr)
     }
 
     return (int) value;  /* shut up, I know what I'm doing */
-#else
-    int        i;
-    char *dp;
-# if defined (STDC_HEADERS)
-    size_t     len;
-# else
-    int                len;
-# endif
-
-    /* We do only base 10 conversions here (atoi)! */
-
-    len = strlen(s);
-    /* check for leading white spaces */
-    for (i = 0; (i < len) && isspace((unsigned char)s[i]); i++)
-       ;
-
-    dp = &s[i];
-
-    /* check for +/- */
-    if (i < len && (s[i] == '+' || s[i] == '-'))       i++;
-
-    /* skip over digits */
-    for ( /* no init */ ; (i < len) && isdigit((unsigned char)s[i]); i++)
-       ;
-
-    /* check for trailing garbage */
-    if (i != len) {
-       (void) fprintf(stderr, GT_("String '%s' is not a valid number string.\n"), s);
-       (*errflagptr)++;
-       return 0;
-    }
-
-    /* atoi should be safe by now, except for number range over/underflow */
-    return atoi(dp);
-#endif
 }
 
-int parsecmdline (argc, argv, rctl, ctl)
-/* parse and validate the command line options */
-int argc;              /* argument count */
-char **argv;           /* argument strings */
-struct runctl *rctl;   /* global run controls to modify */
-struct query *ctl;     /* option record to be initialized */
+/** parse and validate the command line options */
+int parsecmdline (int argc /** argument count */,
+                 char **argv /** argument strings */,
+                 struct runctl *rctl /** global run controls to modify */,
+                 struct query *ctl /** option record to initialize */,
+                 flag *safewithbg /** set to whether options are
+                                    compatible with another copy
+                                    running in the background */)
 {
     /*
      * return value: if positive, argv index of last parsed option + 1
@@ -232,9 +219,12 @@ struct query *ctl; /* option record to be initialized */
     int errflag = 0;   /* TRUE when a syntax error is detected */
     int helpflag = 0;  /* TRUE when option help was explicitly requested */
     int option_index;
+    int option_safe;   /* to track if option currently parsed is safe
+                          with a background copy */
     char *buf, *cp;
 
     rctl->poll_interval = -1;
+    *safewithbg = TRUE;
 
     memset(ctl, '\0', sizeof(struct query));    /* start clean */
     ctl->smtp_socket = -1;
@@ -243,21 +233,37 @@ struct query *ctl;        /* option record to be initialized */
           (c = getopt_long(argc,argv,shortoptions,
                            longoptions, &option_index)) != -1)
     {
+       option_safe = FALSE;
+
        switch (c) {
+#ifdef HAVE_LIBPWMD
+       case 'C':
+           ctl->pwmd_socket = prependdir(optarg, currentwd);
+           break;
+       case 'G':
+           ctl->pwmd_file = xstrdup(optarg);
+           break;
+       case 'O':
+           rctl->pinentry_timeout = atoi(optarg);
+           break;
+#endif
        case 'V':
            versioninfo = TRUE;
+           option_safe = TRUE;
            break;
        case 'c':
            check_only = TRUE;
            break;
        case 's':
            outlevel = O_SILENT;
+           option_safe = 1;
            break;
        case 'v':
            if (outlevel >= O_VERBOSE)
                outlevel = O_DEBUG;
            else
                outlevel = O_VERBOSE;
+           option_safe = TRUE;
            break;
        case 'd':
            rctl->poll_interval = xatoi(optarg, &errflag);
@@ -273,7 +279,7 @@ struct query *ctl;  /* option record to be initialized */
            rctl->logfile = prependdir (optarg, currentwd);
            break;
        case LA_INVISIBLE:
-           rctl->invisible = TRUE;
+           rctl->invisible = FLAG_TRUE;
            break;
        case LA_SHOWDOTS:
            rctl->showdots = FLAG_TRUE;
@@ -285,18 +291,36 @@ struct query *ctl;        /* option record to be initialized */
        case 'i':
            rctl->idfile = prependdir (optarg, currentwd);
            break;
+       case LA_PIDFILE:
+           rctl->pidfile = prependdir (optarg, currentwd);
+           break;
        case LA_POSTMASTER:
            rctl->postmaster = (char *) xstrdup(optarg);
            break;
        case LA_NOBOUNCE:
-           run.bouncemail = FALSE;
+           rctl->bouncemail = FLAG_FALSE;
+           break;
+       case LA_NOSOFTBOUNCE:
+           rctl->softbounce = FLAG_FALSE;
            break;
+       case LA_SOFTBOUNCE:
+           rctl->softbounce = FLAG_TRUE;
+           break;
+       case LA_BADHEADER:
+           if (strcasecmp(optarg,"accept") == 0) {
+               ctl->server.badheader = BHACCEPT;
+           } else if (strcasecmp(optarg,"reject") == 0) {
+               ctl->server.badheader = BHREJECT;
+           } else {
+               fprintf(stderr,GT_("Invalid bad-header policy `%s' specified.\n"), optarg);
+               errflag++;
+           }
+           break;
+
        case 'p':
            /* XXX -- should probably use a table lookup here */
            if (strcasecmp(optarg,"auto") == 0)
                ctl->server.protocol = P_AUTO;
-           else if (strcasecmp(optarg,"pop2") == 0)
-               ctl->server.protocol = P_POP2;
 #ifdef SDPS_ENABLE
            else if (strcasecmp(optarg,"sdps") == 0)
            {
@@ -306,18 +330,12 @@ struct query *ctl;        /* option record to be initialized */
 #endif /* SDPS_ENABLE */
            else if (strcasecmp(optarg,"pop3") == 0)
                ctl->server.protocol = P_POP3;
-           else if (strcasecmp(optarg,"apop") == 0)
-               ctl->server.protocol = P_APOP;
-           else if (strcasecmp(optarg,"rpop") == 0)
-               ctl->server.protocol = P_RPOP;
            else if (strcasecmp(optarg,"kpop") == 0)
            {
                ctl->server.protocol = P_POP3;
-               ctl->server.service = KPOP_PORT;
+               ctl->server.service = xstrdup(KPOP_PORT);
 #ifdef KERBEROS_V5
                ctl->server.authenticate =  A_KERBEROS_V5;
-#else
-               ctl->server.authenticate =  A_KERBEROS_V4;
 #endif /* KERBEROS_V5 */
            }
            else if (strcasecmp(optarg,"imap") == 0)
@@ -332,7 +350,10 @@ struct query *ctl; /* option record to be initialized */
            }
            break;
        case 'U':
-           ctl->server.uidl = FLAG_TRUE;
+           /* EMPTY - removed in 7.0.0 */
+           break;
+       case LA_IDLE:
+           ctl->idle = FLAG_TRUE;
            break;
        case 'P':
            ctl->server.service = optarg;
@@ -340,18 +361,16 @@ struct query *ctl;        /* option record to be initialized */
        case LA_AUTH:
            if (strcmp(optarg, "password") == 0)
                ctl->server.authenticate = A_PASSWORD;
-           else if (strcmp(optarg, "kerberos") == 0)
 #ifdef KERBEROS_V5
+           else if (strcmp(optarg, "kerberos") == 0)
                ctl->server.authenticate = A_KERBEROS_V5;
-#else
-               ctl->server.authenticate = A_KERBEROS_V4;
-#endif /* KERBEROS_V5 */
            else if (strcmp(optarg, "kerberos_v5") == 0)
                ctl->server.authenticate = A_KERBEROS_V5;
-           else if (strcmp(optarg, "kerberos_v4") == 0)
-               ctl->server.authenticate = A_KERBEROS_V4;
+#endif /* KERBEROS_V5 */
            else if (strcmp(optarg, "ssh") == 0)
                ctl->server.authenticate = A_SSH;
+           else if (strcasecmp(optarg, "external") == 0)
+               ctl->server.authenticate = A_EXTERNAL;
            else if (strcmp(optarg, "otp") == 0)
                ctl->server.authenticate = A_OTP;
            else if (strcmp(optarg, "opie") == 0)
@@ -368,6 +387,8 @@ struct query *ctl;  /* option record to be initialized */
                ctl->server.authenticate = A_ANY;
            else if (strcmp(optarg, "msn") == 0)
                ctl->server.authenticate = A_MSN;
+           else if (strcmp(optarg, "apop") == 0)
+               ctl->server.authenticate = A_APOP;
            else {
                fprintf(stderr,GT_("Invalid authentication `%s' specified.\n"), optarg);
                errflag++;
@@ -448,7 +469,7 @@ struct query *ctl;  /* option record to be initialized */
            buf = xstrdup(optarg);
            cp = strtok(buf, ",");
            do {
-               struct idlist   *idp = save_str(&ctl->antispam, NULL, 0);;
+               struct idlist   *idp = save_str(&ctl->antispam, STRING_DUMMY, 0);
 
                idp->val.status.num = xatoi(cp, &errflag);
            } while
@@ -523,10 +544,18 @@ struct query *ctl;        /* option record to be initialized */
            ctl->sslcertck = FLAG_TRUE;
            break;
 
+       case LA_SSLCERTFILE:
+           ctl->sslcertfile = prependdir(optarg, currentwd);
+           break;
+
        case LA_SSLCERTPATH:
            ctl->sslcertpath = prependdir(optarg, currentwd);
            break;
 
+       case LA_SSLCOMMONNAME:
+           ctl->sslcommonname = xstrdup(optarg);
+           break;
+
        case LA_SSLFINGERPRINT:
            ctl->sslfingerprint = xstrdup(optarg);
            break;
@@ -547,6 +576,7 @@ struct query *ctl;  /* option record to be initialized */
 
        case LA_CONFIGDUMP:
            configdump = TRUE;
+           option_safe = TRUE;
            break;
 
        case LA_SYSLOG:
@@ -561,10 +591,25 @@ struct query *ctl;        /* option record to be initialized */
            ctl->server.tracepolls = FLAG_TRUE;
            break;
 
+       case LA_RETRIEVEERROR:
+           if (strcasecmp(optarg,"abort") == 0) {
+               ctl->server.retrieveerror = RE_ABORT;
+           } else if (strcasecmp(optarg,"continue") == 0) {
+               ctl->server.retrieveerror = RE_CONTINUE;
+           } else if (strcasecmp(optarg,"markseen") == 0) {
+               ctl->server.retrieveerror = RE_MARKSEEN;
+           } else {
+               fprintf(stderr,GT_("Invalid retrieve-error policy `%s' specified.\n"), optarg);
+               errflag++;
+           }
+           break;
+
        case '?':
+           helpflag = 1;
        default:
-           helpflag++;
+           break;
        }
+       *safewithbg &= option_safe;
     }
 
     if (errflag || ocount > 1 || helpflag) {
@@ -586,8 +631,11 @@ struct query *ctl; /* option record to be initialized */
        P(GT_("      --invisible   don't write Received & enable host spoofing\n"));
        P(GT_("  -f, --fetchmailrc specify alternate run control file\n"));
        P(GT_("  -i, --idfile      specify alternate UIDs file\n"));
+       P(GT_("      --pidfile     specify alternate PID (lock) file\n"));
        P(GT_("      --postmaster  specify recipient of last resort\n"));
        P(GT_("      --nobounce    redirect bounces from user to postmaster.\n"));
+       P(GT_("      --nosoftbounce fetchmail deletes permanently undeliverable messages.\n"));
+       P(GT_("      --softbounce  keep permanently undeliverable messages on server (default).\n"));
 #ifdef CAN_MONITOR
        P(GT_("  -I, --interface   interface required specification\n"));
        P(GT_("  -M, --monitor     monitor interface for activity\n"));
@@ -596,16 +644,27 @@ struct query *ctl;        /* option record to be initialized */
        P(GT_("      --ssl         enable ssl encrypted session\n"));
        P(GT_("      --sslkey      ssl private key file\n"));
        P(GT_("      --sslcert     ssl client certificate\n"));
-       P(GT_("      --sslcertck   strict client certificate check (recommended)\n"));
-       P(GT_("      --sslcertpath path to ssl certificates\n"));
+       P(GT_("      --sslcertck   do strict server certificate check (recommended)\n"));
+       P(GT_("      --sslcertfile path to trusted-CA ssl certificate file\n"));
+       P(GT_("      --sslcertpath path to trusted-CA ssl certificate directory\n"));
+       P(GT_("      --sslcommonname  expect this CommonName from server (discouraged)\n"));
        P(GT_("      --sslfingerprint fingerprint that must match that of the server's cert.\n"));
-       P(GT_("      --sslproto    force ssl protocol (ssl2/ssl3/tls1)\n"));
+       P(GT_("      --sslproto    force ssl protocol (SSL23/SSL3/TLS1)\n"));
 #endif
        P(GT_("      --plugin      specify external command to open connection\n"));
        P(GT_("      --plugout     specify external command to open smtp connection\n"));
+       P(GT_("      --bad-header {reject|accept}\n"
+             "                    specify policy for handling messages with bad headers\n"));
+       P(GT_("      --retrieve-error {abort|continue|markseen}\n"
+              "                        specify policy for processing messages with retrieve errors\n"));
 
        P(GT_("  -p, --protocol    specify retrieval protocol (see man page)\n"));
-       P(GT_("  -U, --uidl        force the use of UIDLs (pop3 only)\n"));
+#ifdef HAVE_LIBPWMD
+        P(GT_("  -C, --pwmd-socket pwmd socket path (~/.pwmd/socket)\n"));
+        P(GT_("  -G, --pwmd-file   filename to use on the pwmd server\n"));
+        P(GT_("  -O, --pinentry-timeout   seconds until pinentry is canceled\n"));
+#endif
+
        P(GT_("      --port        TCP port to connect to (obsolete, use --service)\n"));
        P(GT_("  -P, --service     TCP service to connect to (can be numeric TCP port)\n"));
        P(GT_("      --auth        authentication type (password/kerberos/ssh/otp)\n"));
@@ -616,7 +675,7 @@ struct query *ctl;  /* option record to be initialized */
        P(GT_("      --tracepolls  add poll-tracing information to Received header\n"));
 
        P(GT_("  -u, --username    specify users's login on server\n"));
-       P(GT_("  -a, --all         retrieve old and new messages\n"));
+       P(GT_("  -a, --[fetch]all  retrieve old and new messages\n"));
        P(GT_("  -K, --nokeep      delete new messages after retrieval\n"));
        P(GT_("  -k, --keep        save new messages after retrieval\n"));
        P(GT_("  -F, --flush       delete old messages from server\n"));