-/* Copyright 1993-95 by Carl Harris, Jr. Copyright 1996 by Eric S. Raymond
- * All rights reserved.
+/*
+ * options.c -- command-line option processing
+ *
* For license terms, see the file COPYING in this directory.
*/
-/***********************************************************************
- module: options.c
- project: popclient
- programmer: Carl Harris, ceharris@mal.com
- description: command-line option processing
-
- ***********************************************************************/
-
#include <config.h>
-#include <stdio.h>
+#include <stdio.h>
#include <pwd.h>
+#include <string.h>
+#if defined(STDC_HEADERS)
+#include <stdlib.h>
+#endif
+
#include "getopt.h"
-#include "popclient.h"
-#include "bzero.h"
+#include "fetchmail.h"
-/* XXX -- Would like to use 'enum' here, but it causes type mismatch
- problems many compilers */
-#define LA_VERSION 1
-#define LA_ALL 2
-#define LA_KILL 3
-#define LA_KEEP 4
+#define LA_HELP 1
+#define LA_VERSION 2
+#define LA_CHECK 3
+#define LA_SILENT 4
#define LA_VERBOSE 5
-#define LA_SILENT 6
-#define LA_STDOUT 7
-#define LA_LIMIT 8
-#define LA_FLUSH 9
-#define LA_PROTOCOL 10
-#define LA_DAEMON 11
-#define LA_POPRC 12
-#define LA_USERNAME 13
-#define LA_REMOTEFILE 14
-#define LA_LOCALFILE 15
-#define LA_MDA 16
-#define LA_LOGFILE 17
-#define LA_QUIT 18
-#define LA_YYDEBUG 19
-
-static char *shortoptions = "23VaKkvscl:Fd:f:u:r:o:m:";
+#define LA_DAEMON 6
+#define LA_NODETACH 7
+#define LA_QUIT 8
+#define LA_LOGFILE 9
+#define LA_SYSLOG 10
+#define LA_RCFILE 11
+#define LA_IDFILE 12
+#define LA_PROTOCOL 13
+#define LA_PORT 14
+#define LA_AUTHENTICATE 15
+#define LA_TIMEOUT 16
+#define LA_ENVELOPE 17
+#define LA_USERNAME 18
+#define LA_ALL 19
+#define LA_KILL 20
+#define LA_KEEP 21
+#define LA_FLUSH 22
+#define LA_NOREWRITE 23
+#define LA_LIMIT 24
+#define LA_REMOTEFILE 25
+#define LA_SMTPHOST 26
+#define LA_BATCHLIMIT 27
+#define LA_FETCHLIMIT 28
+#define LA_MDA 29
+#define LA_INTERFACE 30
+#define LA_MONITOR 31
+#define LA_YYDEBUG 32
+
+static char *shortoptions = "?Vcsvd:NqL:f:i:p:P:A:t:E:u:akKFnl:r:S:b:B:m:I:M:y";
static struct option longoptions[] = {
- {"version", no_argument, (int *) 0, LA_VERSION },
- {"all", no_argument, (int *) 0, LA_ALL },
- {"kill", no_argument, (int *) 0, LA_KILL },
- {"keep", no_argument, (int *) 0, LA_KEEP },
- {"verbose", no_argument, (int *) 0, LA_VERBOSE },
- {"silent", no_argument, (int *) 0, LA_SILENT },
- {"stdout", no_argument, (int *) 0, LA_STDOUT },
- {"limit", required_argument, (int *) 0, LA_LIMIT },
- {"flush", no_argument, (int *) 0, LA_FLUSH },
- {"protocol", required_argument, (int *) 0, LA_PROTOCOL },
- {"proto", required_argument, (int *) 0, LA_PROTOCOL },
- {"daemon", required_argument, (int *) 0, LA_DAEMON },
- {"poprc", required_argument, (int *) 0, LA_POPRC },
- {"user", required_argument, (int *) 0, LA_USERNAME },
- {"username", required_argument, (int *) 0, LA_USERNAME },
- {"remote", required_argument, (int *) 0, LA_REMOTEFILE },
- {"local", required_argument, (int *) 0, LA_LOCALFILE },
- {"mda", required_argument, (int *) 0, LA_MDA },
- {"logfile", required_argument, (int *) 0, LA_LOGFILE },
- {"quit", no_argument, (int *) 0, LA_QUIT },
- {"yydebug", no_argument, (int *) 0, LA_YYDEBUG },
- {(char *) 0, no_argument, (int *) 0, 0 }
-};
-
-
-/*********************************************************************
- function: parsecmdline
- description: parse/validate the command line options.
- arguments:
- argc argument count.
- argv argument strings.
- options pointer to a struct hostrec to receive the parsed
- options.
-
- return value: if positive, argv index of last parsed option + 1
- (presumes one or more server names follows).
- if zero, the command line switches are such that
- no server names are required (e.g. --version).
- if negative, the command line is has one or more
- syntax errors.
- calls: none.
- globals: writes outlevel, versioninfo, yydebug, logfile,
- poll_interval, quitmode, poprcfile, linelimit.
- *********************************************************************/
-
-int parsecmdline (argc,argv,options)
-int argc;
-char **argv;
-struct hostrec *options;
-{
- int c,i;
- int fflag = 0; /* TRUE when -o or -c has been specified */
- int errflag = 0; /* TRUE when a syntax error is detected */
- int option_index;
- int got_kill = 0; /* TRUE when --kill is specified */
+ {"help", no_argument, (int *) 0, LA_HELP },
+ {"version", no_argument, (int *) 0, LA_VERSION },
+ {"check", no_argument, (int *) 0, LA_CHECK },
+ {"silent", no_argument, (int *) 0, LA_SILENT },
+ {"verbose", no_argument, (int *) 0, LA_VERBOSE },
+ {"daemon", required_argument, (int *) 0, LA_DAEMON },
+ {"nodetach", no_argument, (int *) 0, LA_NODETACH },
+ {"quit", no_argument, (int *) 0, LA_QUIT },
+ {"logfile", required_argument, (int *) 0, LA_LOGFILE },
+ {"syslog", no_argument, (int *) 0, LA_SYSLOG },
+ {"fetchmailrc",required_argument,(int *) 0, LA_RCFILE },
+ {"idfile", required_argument, (int *) 0, LA_IDFILE },
+#ifdef linux
+ {"interface", required_argument, (int *) 0, LA_INTERFACE },
+ {"monitor", required_argument, (int *) 0, LA_MONITOR },
+#endif
- extern int optind, opterr; /* defined in getopt(2) */
- extern char *optarg; /* defined in getopt(2) */
+ {"protocol", required_argument, (int *) 0, LA_PROTOCOL },
+ {"proto", required_argument, (int *) 0, LA_PROTOCOL },
+ {"port", required_argument, (int *) 0, LA_PORT },
+ {"auth", required_argument, (int *) 0, LA_AUTHENTICATE},
+ {"timeout", required_argument, (int *) 0, LA_TIMEOUT },
+ {"envelope", required_argument, (int *) 0, LA_ENVELOPE },
- bzero(options,sizeof(struct hostrec)); /* start clean */
+ {"user", required_argument, (int *) 0, LA_USERNAME },
+ {"username", required_argument, (int *) 0, LA_USERNAME },
- while (!errflag &&
- (c = getopt_long(argc,argv,shortoptions,
- longoptions,&option_index)) != -1) {
+ {"all", no_argument, (int *) 0, LA_ALL },
+ {"kill", no_argument, (int *) 0, LA_KILL },
+ {"keep", no_argument, (int *) 0, LA_KEEP },
+ {"flush", no_argument, (int *) 0, LA_FLUSH },
+ {"norewrite", no_argument, (int *) 0, LA_NOREWRITE },
+ {"limit", required_argument, (int *) 0, LA_LIMIT },
- switch (c) {
- case '2':
- options->protocol = P_POP2;
- break;
- case '3':
- options->protocol = P_POP3;
- break;
- case 'V':
- case LA_VERSION:
- versioninfo = !0;
- break;
- case 'a':
- case LA_ALL:
- options->fetchall = !0;
- break;
- case 'K':
- case LA_KILL:
- options->keep = 0;
- got_kill = 1;
- break;
- case 'k':
- case LA_KEEP:
- options->keep = !0;
- got_kill = 0;
- break;
- case 'v':
- case LA_VERBOSE:
- outlevel = O_VERBOSE;
- break;
- case 's':
- case LA_SILENT:
- outlevel = O_SILENT;
- break;
- case 'c':
- case LA_STDOUT:
- if (fflag)
- errflag++;
- else {
- fflag++;
- options->output = TO_STDOUT;
- }
- break;
- case 'l':
- case LA_LIMIT:
- linelimit = atoi(optarg);
- if (linelimit < 0) {
- fprintf(stderr,"Line count limit must be non-negative");
- errflag++;
- }
- break;
- case 'F':
- case LA_FLUSH:
- options->flush = !0;
- break;
- case LA_PROTOCOL:
- /* XXX -- should probably use a table lookup here */
- if (strcasecmp(optarg,"pop2") == 0)
- options->protocol = P_POP2;
- else if (strcasecmp(optarg,"pop3") == 0)
- options->protocol = P_POP3;
- else if (strcasecmp(optarg,"imap") == 0)
- options->protocol = P_IMAP;
- else if (strcasecmp(optarg,"apop") == 0)
- options->protocol = P_APOP;
- else if (strcasecmp(optarg,"rpop") == 0)
- options->protocol = P_RPOP;
- else {
- fprintf(stderr,"Invalid protocol '%s'\n specified.\n", optarg);
- errflag++;
- }
- break;
- case 'd':
- case LA_DAEMON:
- poll_interval = atoi(optarg);
- break;
- case 'f':
- case LA_POPRC:
- poprcfile = (char *) xmalloc(strlen(optarg)+1);
- strcpy(poprcfile,optarg);
- break;
- case 'u':
- case LA_USERNAME:
- strncpy(options->remotename,optarg,sizeof(options->remotename)-1);
- break;
- case 'o':
- case LA_LOCALFILE:
- if (fflag)
- errflag++;
- else {
- fflag++;
- options->output = TO_FOLDER;
- strncpy(options->userfolder,optarg,sizeof(options->userfolder)-1);
- }
- break;
- case 'r':
- case LA_REMOTEFILE:
- strncpy(options->remotefolder,optarg,sizeof(options->remotefolder)-1);
- break;
- case 'm':
- case LA_MDA:
- strncpy(options->mda,optarg,sizeof(options->mda)-1);
- break;
- case 'L':
- case LA_LOGFILE:
- logfile = optarg;
- break;
- case 'q':
- case LA_QUIT:
- quitmode = 1;
- break;
- case LA_YYDEBUG:
- yydebug = 1;
- break;
- default:
- errflag++;
- }
- }
+ {"remote", required_argument, (int *) 0, LA_REMOTEFILE },
+ {"smtphost", required_argument, (int *) 0, LA_SMTPHOST },
+ {"batchlimit",required_argument, (int *) 0, LA_BATCHLIMIT },
+ {"fetchlimit",required_argument, (int *) 0, LA_FETCHLIMIT },
+ {"mda", required_argument, (int *) 0, LA_MDA },
- if (errflag) {
- /* squawk if syntax errors were detected */
- fputs("usage: popclient [options] [server ...]\n", stderr);
- fputs(" options\n",stderr);
- fputs(" -2 use POP2 protocol\n", stderr);
- fputs(" -3 use POP3 protocol\n", stderr);
- fputs(" --protocol specify pop2, pop3, imap, apop, or rpop\n",
- stderr);
- fputs(" -V, --version display version info\n", stderr);
- fputs(" -a, --all retrieve old and new messages\n", stderr);
- fputs(" -F, --flush delete old messages from server\n", stderr);
- fputs(" -K, --kill delete new messages after retrieval\n", stderr);
- fputs(" -k, --keep save new messages after retrieval\n", stderr);
- fputs(" -l, --limit retrieve at most n message lines\n", stderr);
- fputs(" -m, --mda set mail user agent to pass to\n", stderr);
- fputs(" -q, --quit kill daemon process\n", stderr);
- fputs(" -s, --silent work silently\n", stderr);
- fputs(" -v, --verbose work noisily (diagnostic output)\n", stderr);
- fputs(" -d, --daemon run as a daemon once per n seconds\n", stderr);
- fputs(" -f, --poprc specify alternate config file\n", stderr);
- fputs(" -u, --username specify server user ID\n", stderr);
- fputs(" -c, --stdout write received mail to stdout\n", stderr);
- fputs(" -o, --local specify filename for received mail\n", stderr);
- fputs(" -r, --remote specify remote folder name\n", stderr);
- fputs(" -L, --logfile specify logfile name\n", stderr);
- return(-1);
- }
- else {
- if (linelimit && !got_kill)
- options->keep = !0;
- else
- ;
- return(optind);
- }
-}
-
+ {"interface", required_argument, (int *) 0, LA_INTERFACE },
+ {"monitor", required_argument, (int *) 0, LA_MONITOR },
-/*********************************************************************
- function: setdefaults
- description: set reasonable default values for unspecified options.
- arguments:
- options option values parsed from the command-line; unspeci-
- fied options must be filled with zero.
+ {"yydebug", no_argument, (int *) 0, LA_YYDEBUG },
- return value: zero if defaults were successfully set, else non-zero
- (indicates a problem reading /etc/passwd).
- calls: none.
- globals: writes outlevel, poprcfile.
- *********************************************************************/
+ {(char *) 0, no_argument, (int *) 0, 0 }
+};
-int setdefaults (options)
-struct hostrec *options;
+int parsecmdline (argc, argv, ctl)
+/* parse and validate the command line options */
+int argc; /* argument count */
+char **argv; /* argument strings */
+struct query *ctl; /* option record to be initialized */
{
- int uid;
- struct passwd *pw;
- char *mailvar;
+ /*
+ * return value: if positive, argv index of last parsed option + 1
+ * (presumes one or more server names follows). if zero, the
+ * command line switches are such that no server names are
+ * required (e.g. --version). if negative, the command line is
+ * has one or more syntax errors.
+ */
+
+ int c;
+ int ocount = 0; /* count of destinations specified */
+ int errflag = 0; /* TRUE when a syntax error is detected */
+ int option_index;
+
+ memset(ctl, '\0', sizeof(struct query)); /* start clean */
+
+ while (!errflag &&
+ (c = getopt_long(argc,argv,shortoptions,
+ longoptions,&option_index)) != -1) {
+
+ switch (c) {
+ case 'V':
+ case LA_VERSION:
+ versioninfo = TRUE;
+ break;
+ case 'c':
+ case LA_CHECK:
+ check_only = TRUE;
+ break;
+ case 's':
+ case LA_SILENT:
+ outlevel = O_SILENT;
+ break;
+ case 'v':
+ case LA_VERBOSE:
+ outlevel = O_VERBOSE;
+ break;
+ case 'd':
+ case LA_DAEMON:
+ poll_interval = atoi(optarg);
+ break;
+ case 'N':
+ case LA_NODETACH:
+ nodetach = TRUE;
+ break;
+ case 'q':
+ case LA_QUIT:
+ quitmode = TRUE;
+ break;
+ case 'L':
+ case LA_LOGFILE:
+ cmd_logfile = optarg;
+ break;
+ case 'f':
+ case LA_RCFILE:
+ rcfile = (char *) xmalloc(strlen(optarg)+1);
+ strcpy(rcfile,optarg);
+ break;
+ case 'i':
+ case LA_IDFILE:
+ idfile = (char *) xmalloc(strlen(optarg)+1);
+ strcpy(idfile,optarg);
+ break;
+ case 'p':
+ case LA_PROTOCOL:
+ /* XXX -- should probably use a table lookup here */
+ if (strcasecmp(optarg,"pop2") == 0)
+ ctl->server.protocol = P_POP2;
+ else if (strcasecmp(optarg,"pop3") == 0)
+ ctl->server.protocol = P_POP3;
+ else if (strcasecmp(optarg,"imap") == 0)
+ ctl->server.protocol = P_IMAP;
+ else if (strcasecmp(optarg,"apop") == 0)
+ ctl->server.protocol = P_APOP;
+ else if (strcasecmp(optarg,"kpop") == 0)
+ {
+ ctl->server.protocol = P_POP3;
+ ctl->server.port = KPOP_PORT;
+ ctl->server.authenticate = A_KERBEROS;
+ }
+ else {
+ fprintf(stderr,"Invalid protocol `%s' specified.\n", optarg);
+ errflag++;
+ }
+ break;
+ case 'P':
+ case LA_PORT:
+ ctl->server.port = atoi(optarg);
+ break;
+ case 'A':
+ case LA_AUTHENTICATE:
+ if (strcmp(optarg, "password") == 0)
+ ctl->server.authenticate = A_PASSWORD;
+ else if (strcmp(optarg, "kerberos") == 0)
+ ctl->server.authenticate = A_KERBEROS;
+ else {
+ fprintf(stderr,"Invalid authentication `%s' specified.\n", optarg);
+ errflag++;
+ }
+ break;
+ case 't':
+ case LA_TIMEOUT:
+ ctl->server.timeout = atoi(optarg);
+ break;
+ case 'E':
+ case LA_ENVELOPE:
+ ctl->server.envelope = xstrdup(optarg);
+ break;
+
+ case 'u':
+ case LA_USERNAME:
+ ctl->remotename = xstrdup(optarg);
+ break;
+ case 'a':
+ case LA_ALL:
+ ctl->fetchall = TRUE;
+ break;
+ case 'K':
+ case LA_KILL:
+ ctl->keep = FALSE;
+ break;
+ case 'k':
+ case LA_KEEP:
+ ctl->keep = TRUE;
+ break;
+ case 'F':
+ case LA_FLUSH:
+ ctl->flush = TRUE;
+ break;
+ case 'n':
+ case LA_NOREWRITE:
+ ctl->no_rewrite = TRUE;
+ break;
+ case 'l':
+ case LA_LIMIT:
+ ctl->limit = atoi(optarg);
+ break;
+ case 'r':
+ case LA_REMOTEFILE:
+ ctl->mailbox = xstrdup(optarg);
+ break;
+ case 'S':
+ case LA_SMTPHOST:
+ ctl->smtphost = xstrdup(optarg);
+ ocount++;
+ break;
+ case 'b':
+ case LA_BATCHLIMIT:
+ ctl->batchlimit = atoi(optarg);
+ break;
+ case 'B':
+ case LA_FETCHLIMIT:
+ ctl->fetchlimit = atoi(optarg);
+ break;
+ case 'm':
+ case LA_MDA:
+ ctl->mda = xstrdup(optarg);
+ ocount++;
+ break;
+
+#ifdef linux
+ case 'I':
+ case LA_INTERFACE:
+ ctl->server.interface = xstrdup(optarg);
+ break;
+ case 'M':
+ case LA_MONITOR:
+ ctl->server.monitor = xstrdup(optarg);
+ break;
+#endif
- bzero(options,sizeof(*options));
+ case 'y':
+ case LA_YYDEBUG:
+ yydebug = TRUE;
+ break;
- if ((pw = getpwuid(uid = getuid())) == NULL) {
- fprintf(stderr,"No passwd entry for uid %d\n",uid);
- return(-1);
- }
+ case LA_SYSLOG:
+ use_syslog = TRUE;
+ break;
- options->protocol = DEF_PROTOCOL;
+ case '?':
+ case LA_HELP:
+ default:
+ errflag++;
+ }
+ }
-#if defined(KEEP_IS_DEFAULT)
- options->keep = 1;
-#else
- options->keep = 0;
-#endif
+ if (check_only && poll_interval)
+ {
+ fputs("The --check and --daemon options aren't compatible.\n", stderr);
+ return(-1);
+ }
- strcpy(options->localname,pw->pw_name);
- strcpy(options->remotename,pw->pw_name);
+ if (poll_interval == 0 && use_syslog)
+ {
+ fputs("The --syslog option is only valid with the --daemon option.\n", stderr);
+ return(-1);
+ }
-#if defined(USERFOLDER) && defined(HAVE_FLOCK)
- options->output = TO_FOLDER;
- sprintf(options->userfolder, USERFOLDER, pw->pw_name);
-#else
- options->output = TO_MDA;
+ if (errflag || ocount > 1) {
+ /* squawk if syntax errors were detected */
+ fputs("usage: fetchmail [options] [server ...]\n", stderr);
+ fputs(" Options are as follows:\n",stderr);
+ fputs(" -?, --help display this option help\n", stderr);
+ fputs(" -V, --version display version info\n", stderr);
+
+ fputs(" -c, --check check for messages without fetching\n", stderr);
+ fputs(" -s, --silent work silently\n", stderr);
+ fputs(" -v, --verbose work noisily (diagnostic output)\n", stderr);
+ fputs(" -d, --daemon run as a daemon once per n seconds\n", stderr);
+ fputs(" -N, --nodetach don't detach daemon process\n", stderr);
+ fputs(" -q, --quit kill daemon process\n", stderr);
+ fputs(" -L, --logfile specify logfile name\n", stderr);
+ fputs(" --syslog use syslog(3) for most messages when running as a daemon\n", stderr);
+ fputs(" -f, --fetchmailrc specify alternate run control file\n", stderr);
+ fputs(" -i, --idfile specify alternate UIDs file\n", stderr);
+#ifdef linux
+ fputs(" -I, --interface interface required specification\n",stderr);
+ fputs(" -M, --monitor monitor interface for activity\n",stderr);
#endif
- (void) sprintf(options->mda, DEF_MDA, options->localname);
-
- poprcfile =
- (char *) xmalloc(strlen(pw->pw_dir)+strlen(POPRC_NAME)+2);
-
- strcpy(poprcfile, pw->pw_dir);
- strcat(poprcfile, "/");
- strcat(poprcfile, POPRC_NAME);
-
- outlevel = O_NORMAL;
+ fputs(" -p, --protocol specify pop2, pop3, imap, apop, rpop, kpop\n", stderr);
+ fputs(" -P, --port TCP/IP service port to connect to\n",stderr);
+ fputs(" -A, --auth authentication type (password or kerberos)\n",stderr);
+ fputs(" -t, --timeout server nonresponse timeout\n",stderr);
+ fputs(" -E, --envelope envelope address header\n",stderr);
+
+ fputs(" -u, --username specify users's login on server\n", stderr);
+ fputs(" -a, --all retrieve old and new messages\n", stderr);
+ fputs(" -K, --kill delete new messages after retrieval\n", stderr);
+ fputs(" -k, --keep save new messages after retrieval\n", stderr);
+ fputs(" -F, --flush delete old messages from server\n", stderr);
+ fputs(" -n, --norewrite don't rewrite header addresses\n", stderr);
+ fputs(" -l, --limit don't fetch messages over given size\n", stderr);
+
+ fputs(" -S, --smtphost set SMTP forwarding host\n", stderr);
+ fputs(" -b, --batchlimit set batch limit for SMTP connections\n", stderr);
+ fputs(" -B, --fetchlimit set fetch limit for server connections\n", stderr);
+ fputs(" -r, --remote specify remote folder name\n", stderr);
+ return(-1);
+ }
- return(0);
+ return(optind);
}
-
-
-/******************************************************************
- function: getnextserver
- description: read next server name from the command line.
- arguments:
- argc from main()
- argv from main()
- optind as returned by parsecmdline and this function.
-
- ret. value: next server name from command line or NULL if all
- server names have been retrieved.
- globals: none.
- calls: none.
- *****************************************************************/
-char *getnextserver (argc,argv,optind)
-int argc;
-char **argv;
-int *optind;
-{
- if (*optind >= argc) {
- /* no more servers */
- return((char *) 0);
- }
- else
- return(argv[(*optind)++]);
-}
+/* options.c ends here */