#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_SYSLOG,
- LA_NOSYSLOG,
- LA_POSTMASTER,
- LA_NOBOUNCE,
- LA_AUTH,
- LA_FETCHDOMAINS,
- LA_BSMTP,
- LA_LMTP,
- LA_PLUGIN,
- LA_PLUGOUT,
- LA_CONFIGDUMP,
- LA_SMTPNAME,
- LA_SHOWDOTS,
- LA_PRINCIPAL,
- LA_TRACEPOLLS,
- LA_SSL,
- LA_SSLKEY,
- LA_SSLCERT,
- LA_SSLPROTO,
- LA_SSLCERTCK,
- LA_SSLCERTPATH,
- LA_SSLFINGERPRINT,
- LA_FETCHSIZELIMIT,
- LA_FASTUIDL,
- LA_LIMITFLUSH,
+ LA_PIDFILE,
+ LA_SYSLOG,
+ LA_NOSYSLOG,
+ LA_POSTMASTER,
+ LA_NOBOUNCE,
+ LA_AUTH,
+ LA_FETCHDOMAINS,
+ LA_BSMTP,
+ LA_LMTP,
+ LA_PLUGIN,
+ LA_PLUGOUT,
+ LA_CONFIGDUMP,
+ LA_SMTPNAME,
+ LA_SHOWDOTS,
+ LA_PRINCIPAL,
+ LA_TRACEPOLLS,
+ LA_SSL,
+ LA_SSLKEY,
+ 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' },
{"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' },
{"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' },
{"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
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
*/
}
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
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;
(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)
+ if (outlevel >= O_VERBOSE)
outlevel = O_DEBUG;
else
outlevel = O_VERBOSE;
+ option_safe = TRUE;
break;
case 'd':
rctl->poll_interval = xatoi(optarg, &errflag);
rctl->logfile = prependdir (optarg, currentwd);
break;
case LA_INVISIBLE:
- rctl->invisible = TRUE;
+ rctl->invisible = FLAG_TRUE;
break;
case LA_SHOWDOTS:
rctl->showdots = FLAG_TRUE;
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)
{
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)
}
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;
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)
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
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;
case LA_CONFIGDUMP:
configdump = TRUE;
+ option_safe = TRUE;
break;
case LA_SYSLOG:
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) {
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"));
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_(" --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"));
- P(GT_(" -P, --port TCP port to connect to (obsolete, use --service)\n"));
- P(GT_(" --service TCP service to connect to (can be numeric TCP port)\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"));
P(GT_(" -t, --timeout server nonresponse timeout\n"));
P(GT_(" -E, --envelope envelope address header\n"));
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"));
P(GT_(" -r, --folder specify remote folder name\n"));
P(GT_(" --showdots show progress dots even in logfiles\n"));
#undef P
+ /* undocumented:
+ * --configdump (internal use by fetchmailconf, dumps
+ * configuration as Python source code)
+ * --yydebug (developer use, enables parser debugging) */
if (helpflag)
exit(PS_SUCCESS);