]> Pileus Git - ~andy/fetchmail/blob - options.c
More from Gunter.
[~andy/fetchmail] / options.c
1 /*
2  * options.c -- command-line option processing
3  *
4  * For license terms, see the file COPYING in this directory.
5  */
6
7 #include "config.h"
8
9 #include <stdio.h>
10 #include <pwd.h>
11 #include <string.h>
12 #include <errno.h>
13 #if defined(STDC_HEADERS)
14 #include  <stdlib.h>
15 #include  <limits.h>
16 #else
17 #include  <ctype.h>
18 #endif
19
20 #include "getopt.h"
21 #include "fetchmail.h"
22
23 #define LA_HELP         1
24 #define LA_VERSION      2 
25 #define LA_CHECK        3
26 #define LA_SILENT       4 
27 #define LA_VERBOSE      5 
28 #define LA_DAEMON       6
29 #define LA_NODETACH     7
30 #define LA_QUIT         8
31 #define LA_LOGFILE      9
32 #define LA_INVISIBLE    10
33 #define LA_SYSLOG       11
34 #define LA_RCFILE       12
35 #define LA_IDFILE       13
36 #define LA_PROTOCOL     14
37 #define LA_UIDL         15
38 #define LA_PORT         16
39 #define LA_AUTHENTICATE 17
40 #define LA_TIMEOUT      18
41 #define LA_ENVELOPE     19
42 #define LA_QVIRTUAL     20
43 #define LA_USERNAME     21
44 #define LA_ALL          22
45 #define LA_NOKEEP       23
46 #define LA_KEEP         24
47 #define LA_FLUSH        25
48 #define LA_NOREWRITE    26
49 #define LA_LIMIT        27
50 #define LA_FOLDER       28
51 #define LA_SMTPHOST     29
52 #define LA_SMTPADDR     30
53 #define LA_ANTISPAM     31
54 #define LA_BATCHLIMIT   32
55 #define LA_FETCHLIMIT   33
56 #define LA_EXPUNGE      34
57 #define LA_MDA          35
58 #define LA_NETSEC       36
59 #define LA_INTERFACE    37
60 #define LA_MONITOR      38
61 #define LA_CONFIGDUMP   39
62 #define LA_YYDEBUG      40
63
64 /* options still left: CgGhHjJoORUwWxXYz */
65 static const char *shortoptions = 
66         "?Vcsvd:NqL:f:i:p:UP:A:t:E:Q:u:akKFnl:r:S:Z:b:B:e:m:T:I:M:y";
67
68 static const struct option longoptions[] = {
69 /* this can be const because all flag fields are 0 and will never get set */
70   {"help",      no_argument,       (int *) 0, LA_HELP        },
71   {"version",   no_argument,       (int *) 0, LA_VERSION     },
72   {"check",     no_argument,       (int *) 0, LA_CHECK       },
73   {"silent",    no_argument,       (int *) 0, LA_SILENT      },
74   {"verbose",   no_argument,       (int *) 0, LA_VERBOSE     },
75   {"daemon",    required_argument, (int *) 0, LA_DAEMON      },
76   {"nodetach",  no_argument,       (int *) 0, LA_NODETACH    },
77   {"quit",      no_argument,       (int *) 0, LA_QUIT        },
78   {"logfile",   required_argument, (int *) 0, LA_LOGFILE     },
79   {"invisible", no_argument,       (int *) 0, LA_INVISIBLE   },
80   {"syslog",    no_argument,       (int *) 0, LA_SYSLOG      },
81   {"fetchmailrc",required_argument,(int *) 0, LA_RCFILE      },
82   {"idfile",    required_argument, (int *) 0, LA_IDFILE      },
83
84   {"protocol",  required_argument, (int *) 0, LA_PROTOCOL    },
85   {"proto",     required_argument, (int *) 0, LA_PROTOCOL    },
86   {"uidl",      no_argument,       (int *) 0, LA_UIDL        },
87   {"port",      required_argument, (int *) 0, LA_PORT        },
88   {"auth",      required_argument, (int *) 0, LA_AUTHENTICATE},
89   {"timeout",   required_argument, (int *) 0, LA_TIMEOUT     },
90   {"envelope",  required_argument, (int *) 0, LA_ENVELOPE    },
91   {"qvirtual",  required_argument, (int *) 0, LA_QVIRTUAL    },
92
93   {"user",      required_argument, (int *) 0, LA_USERNAME    },
94   {"username",  required_argument, (int *) 0, LA_USERNAME    },
95
96   {"all",       no_argument,       (int *) 0, LA_ALL         },
97   {"nokeep",    no_argument,       (int *) 0, LA_NOKEEP      },
98   {"keep",      no_argument,       (int *) 0, LA_KEEP        },
99   {"flush",     no_argument,       (int *) 0, LA_FLUSH       },
100   {"norewrite", no_argument,       (int *) 0, LA_NOREWRITE   },
101   {"limit",     required_argument, (int *) 0, LA_LIMIT       },
102
103   {"folder",    required_argument, (int *) 0, LA_FOLDER      },
104   {"smtphost",  required_argument, (int *) 0, LA_SMTPHOST    },
105   {"smtpaddress", required_argument, (int *) 0, LA_SMTPADDR  },
106   {"antispam",  required_argument, (int *) 0, LA_ANTISPAM    },
107   
108   {"batchlimit",required_argument, (int *) 0, LA_BATCHLIMIT  },
109   {"fetchlimit",required_argument, (int *) 0, LA_FETCHLIMIT  },
110   {"expunge",   required_argument, (int *) 0, LA_EXPUNGE     },
111   {"mda",       required_argument, (int *) 0, LA_MDA         },
112
113 #ifdef INET6
114   {"netsec",    required_argument, (int *) 0, LA_NETSEC    },
115 #endif /* INET6 */
116
117 #if defined(linux) && !INET6
118   {"interface", required_argument, (int *) 0, LA_INTERFACE   },
119   {"monitor",   required_argument, (int *) 0, LA_MONITOR     },
120 #endif /* defined(linux) && !INET6 */
121
122   {"configdump",no_argument,       (int *) 0, LA_CONFIGDUMP  },
123
124   {"yydebug",   no_argument,       (int *) 0, LA_YYDEBUG     },
125
126   {(char *) 0,  no_argument,       (int *) 0, 0              }
127 };
128
129 static int xatoi(char *s, int *errflagptr)
130 /* do safe conversion from string to number */
131 {
132 #if defined (STDC_HEADERS) && defined (LONG_MAX) && defined (INT_MAX)
133     /* parse and convert numbers, but also check for invalid characters in
134      * numbers
135      */
136
137     char *endptr;
138     long value;
139
140     errno = 0;
141
142     value = strtol(s, &endptr, 0);
143
144     /* any invalid chars in string? */
145     if ( (endptr == s) || (*endptr != '\0') ) {
146         (void) fprintf(stderr, "String '%s' is not a valid number string.\n", s);
147         (*errflagptr)++;
148         return 0;
149     }
150
151     /* is the range valid? */
152     if ( (((value == LONG_MAX) || (value == LONG_MIN)) && (errno == ERANGE)) ||
153                                 (value > INT_MAX) || (value < INT_MIN)) {
154
155         (void) fprintf(stderr, "Value of string '%s' is %s than %d.\n", s,
156                                         (value < 0) ? "smaller": "larger",
157                                         (value < 0) ? INT_MIN : INT_MAX);
158         (*errflagptr)++;
159         return 0;
160     }
161
162     return (int) value;  /* shut up, I know what I'm doing */
163 #else
164     int i;
165     char *dp;
166 # if defined (STDC_HEADERS)
167     size_t      len;
168 # else
169     int         len;
170 # endif
171
172     /* We do only base 10 conversions here (atoi)! */
173
174     len = strlen(s);
175     /* check for leading white spaces */
176     for (i = 0; (i < len) && isspace(s[i]); i++)
177         ;
178
179     dp = &s[i];
180
181     /* check for +/- */
182     if (i < len && (s[i] == '+' || s[i] == '-'))        i++;
183
184     /* skip over digits */
185     for ( /* no init */ ; (i < len) && isdigit(s[i]); i++)
186         ;
187
188     /* check for trailing garbage */
189     if (i != len) {
190         (void) fprintf(stderr, "String '%s' is not a valid number string.\n", s);
191         (*errflagptr)++;
192         return 0;
193     }
194
195     /* atoi should be safe by now, except for number range over/underflow */
196     return atoi(dp);
197 #endif
198 }
199
200 int parsecmdline (argc, argv, rctl, ctl)
201 /* parse and validate the command line options */
202 int argc;               /* argument count */
203 char **argv;            /* argument strings */
204 struct runctl *rctl;    /* global run controls to modify */
205 struct query *ctl;      /* option record to be initialized */
206 {
207     /*
208      * return value: if positive, argv index of last parsed option + 1
209      * (presumes one or more server names follows).  if zero, the
210      * command line switches are such that no server names are
211      * required (e.g. --version).  if negative, the command line is
212      * has one or more syntax errors.
213      */
214
215     int c;
216     int ocount = 0;     /* count of destinations specified */
217     int errflag = 0;   /* TRUE when a syntax error is detected */
218     int option_index;
219     char *buf, *cp;
220
221     rctl->poll_interval = -1;
222
223     memset(ctl, '\0', sizeof(struct query));    /* start clean */
224     ctl->smtp_socket = -1;
225
226     while (!errflag && 
227            (c = getopt_long(argc,argv,shortoptions,
228                             longoptions,&option_index)) != -1) {
229
230         switch (c) {
231         case 'V':
232         case LA_VERSION:
233             versioninfo = TRUE;
234             break;
235         case 'c':
236         case LA_CHECK:
237             check_only = TRUE;
238             break;
239         case 's':
240         case LA_SILENT:
241             outlevel = O_SILENT;
242             break;
243         case 'v':
244         case LA_VERBOSE:
245             outlevel = O_VERBOSE;
246             break;
247         case 'd':
248         case LA_DAEMON:
249             rctl->poll_interval = xatoi(optarg, &errflag);
250             break;
251         case 'N':
252         case LA_NODETACH:
253             nodetach = TRUE;
254             break;
255         case 'q':
256         case LA_QUIT:
257             quitmode = TRUE;
258             break;
259         case 'L':
260         case LA_LOGFILE:
261             rctl->logfile = optarg;
262             break;
263         case LA_INVISIBLE:
264             rctl->invisible = TRUE;
265             break;
266         case 'f':
267         case LA_RCFILE:
268             rcfile = (char *) xmalloc(strlen(optarg)+1);
269             strcpy(rcfile,optarg);
270             break;
271         case 'i':
272         case LA_IDFILE:
273             rctl->idfile = (char *) xmalloc(strlen(optarg)+1);
274             strcpy(rctl->idfile,optarg);
275             break;
276         case 'p':
277         case LA_PROTOCOL:
278             /* XXX -- should probably use a table lookup here */
279             if (strcasecmp(optarg,"pop2") == 0)
280                 ctl->server.protocol = P_POP2;
281             else if (strcasecmp(optarg,"pop3") == 0)
282                 ctl->server.protocol = P_POP3;
283             else if (strcasecmp(optarg,"apop") == 0)
284                 ctl->server.protocol = P_APOP;
285             else if (strcasecmp(optarg,"rpop") == 0)
286                 ctl->server.protocol = P_RPOP;
287             else if (strcasecmp(optarg,"kpop") == 0)
288             {
289                 ctl->server.protocol = P_POP3;
290 #if INET6
291                 ctl->server.service = KPOP_PORT;
292 #else /* INET6 */
293                 ctl->server.port = KPOP_PORT;
294 #endif /* INET6 */
295 #ifdef KERBEROS_V5
296                 ctl->server.preauthenticate =  A_KERBEROS_V5;
297 #else
298                 ctl->server.preauthenticate =  A_KERBEROS_V4;
299 #endif /* KERBEROS_V5 */
300             }
301             else if (strcasecmp(optarg,"imap") == 0)
302                 ctl->server.protocol = P_IMAP;
303 #ifdef KERBEROS_V4
304             else if (strcasecmp(optarg,"imap-k4") == 0)
305                 ctl->server.protocol = P_IMAP_K4;
306 #endif /* KERBEROS_V4 */
307             else if (strcasecmp(optarg,"etrn") == 0)
308                 ctl->server.protocol = P_ETRN;
309             else {
310                 fprintf(stderr,"Invalid protocol `%s' specified.\n", optarg);
311                 errflag++;
312             }
313             break;
314         case 'U':
315         case LA_UIDL:
316             ctl->server.uidl = FLAG_TRUE;
317             break;
318         case 'P':
319         case LA_PORT:
320 #if INET6
321             ctl->server.service = optarg;
322 #else /* INET6 */
323             ctl->server.port = xatoi(optarg, &errflag);
324 #endif /* INET6 */
325             break;
326         case 'A':
327         case LA_AUTHENTICATE:
328             if (strcmp(optarg, "password") == 0)
329                 ctl->server.preauthenticate = A_PASSWORD;
330             else if (strcmp(optarg, "kerberos") == 0)
331 #ifdef KERBEROS_V5
332                 ctl->server.preauthenticate = A_KERBEROS_V5;
333             else if (strcmp(optarg, "kerberos_v5") == 0)
334                 ctl->server.preauthenticate = A_KERBEROS_V5;
335 #else
336                 ctl->server.preauthenticate = A_KERBEROS_V4;
337             else if (strcmp(optarg, "kerberos_v4") == 0)
338                 ctl->server.preauthenticate = A_KERBEROS_V4;
339 #endif /* KERBEROS_V5 */
340             else {
341                 fprintf(stderr,"Invalid preauthentication `%s' specified.\n", optarg);
342                 errflag++;
343             }
344             break;
345         case 't':
346         case LA_TIMEOUT:
347             ctl->server.timeout = xatoi(optarg, &errflag);
348             if (ctl->server.timeout == 0)
349                 ctl->server.timeout = -1;
350             break;
351         case 'E':
352         case LA_ENVELOPE:
353             ctl->server.envelope = xstrdup(optarg);
354             break;
355         case 'Q':    
356         case LA_QVIRTUAL:
357             ctl->server.qvirtual = xstrdup(optarg);
358             break;
359
360         case 'u':
361         case LA_USERNAME:
362             ctl->remotename = xstrdup(optarg);
363             break;
364         case 'a':
365         case LA_ALL:
366             ctl->fetchall = FLAG_TRUE;
367             break;
368         case 'K':
369         case LA_NOKEEP:
370             ctl->keep = FLAG_FALSE;
371             break;
372         case 'k':
373         case LA_KEEP:
374             ctl->keep = FLAG_TRUE;
375             break;
376         case 'F':
377         case LA_FLUSH:
378             ctl->flush = FLAG_TRUE;
379             break;
380         case 'n':
381         case LA_NOREWRITE:
382             ctl->rewrite = FLAG_FALSE;
383             break;
384         case 'l':
385         case LA_LIMIT:
386             c = xatoi(optarg, &errflag);
387             ctl->limit = NUM_VALUE(c);
388             break;
389         case 'r':
390         case LA_FOLDER:
391             buf = xmalloc(strlen(optarg));
392             strcpy(buf, optarg);
393             cp = strtok(buf, ",");
394             do {
395                 save_str(&ctl->mailboxes, cp, 0);
396             } while
397                 ((cp = strtok((char *)NULL, ",")));
398             free(buf);
399             break;
400         case 'S':
401         case LA_SMTPHOST:
402             buf = xmalloc(strlen(optarg));
403             strcpy(buf, optarg);
404             cp = strtok(buf, ",");
405             do {
406                 save_str(&ctl->smtphunt, cp, TRUE);
407             } while
408                 ((cp = strtok((char *)NULL, ",")));
409             ocount++;
410             free(buf);
411             break;
412         case 'D':
413         case LA_SMTPADDR:
414             ctl->smtpaddress = xstrdup(optarg);
415             break;
416         case 'Z':
417         case LA_ANTISPAM:
418             c = xatoi(optarg, &errflag);
419             ctl->antispam = NUM_VALUE(c);
420         case 'b':
421         case LA_BATCHLIMIT:
422             c = xatoi(optarg, &errflag);
423             ctl->batchlimit = NUM_VALUE(c);
424             break;
425         case 'B':
426         case LA_FETCHLIMIT:
427             c = xatoi(optarg, &errflag);
428             ctl->fetchlimit = NUM_VALUE(c);
429             break;
430         case 'e':
431         case LA_EXPUNGE:
432             c = xatoi(optarg, &errflag);
433             ctl->expunge = NUM_VALUE(c);
434             break;
435         case 'm':
436         case LA_MDA:
437             ctl->mda = xstrdup(optarg);
438             ocount++;
439             break;
440
441         case 'T':
442         case LA_NETSEC:
443 #if NET_SECURITY
444             ctl->server.netsec = (void *)optarg;
445 #else
446             fprintf(stderr, "fetchmail: network security support is disabled\n");
447             errflag++;
448 #endif /* NET_SECURITY */
449             break;
450
451 #if defined(linux) && !INET6
452         case 'I':
453         case LA_INTERFACE:
454             interface_parse(optarg, &ctl->server);
455             break;
456         case 'M':
457         case LA_MONITOR:
458             ctl->server.monitor = xstrdup(optarg);
459             break;
460 #endif /* defined(linux) && !INET6 */
461
462         case 'y':
463         case LA_YYDEBUG:
464             yydebug = TRUE;
465             break;
466
467         case LA_CONFIGDUMP:
468             configdump = TRUE;
469             break;
470
471         case LA_SYSLOG:
472             rctl->use_syslog = TRUE;
473             break;
474
475         case '?':
476         case LA_HELP:
477         default:
478             errflag++;
479         }
480     }
481
482     if (errflag || ocount > 1) {
483         /* squawk if syntax errors were detected */
484         fputs("usage:  fetchmail [options] [server ...]\n", stderr);
485         fputs("  Options are as follows:\n",stderr);
486         fputs("  -?, --help        display this option help\n", stderr);
487         fputs("  -V, --version     display version info\n", stderr);
488
489         fputs("  -c, --check       check for messages without fetching\n", stderr);
490         fputs("  -s, --silent      work silently\n", stderr);
491         fputs("  -v, --verbose     work noisily (diagnostic output)\n", stderr);
492         fputs("  -d, --daemon      run as a daemon once per n seconds\n", stderr);
493         fputs("  -N, --nodetach    don't detach daemon process\n", stderr);
494         fputs("  -q, --quit        kill daemon process\n", stderr);
495         fputs("  -L, --logfile     specify logfile name\n", stderr);
496         fputs("      --syslog      use syslog(3) for most messages when running as a daemon\n", stderr);
497         fputs("      --invisible   suppress Received line & enable host spoofing\n", stderr);
498         fputs("  -f, --fetchmailrc specify alternate run control file\n", stderr);
499         fputs("  -i, --idfile      specify alternate UIDs file\n", stderr);
500 #if defined(linux) && !INET6
501         fputs("  -I, --interface   interface required specification\n",stderr);
502         fputs("  -M, --monitor     monitor interface for activity\n",stderr);
503 #endif
504
505 #ifdef KERBEROS_V4
506         fputs("  -p, --protocol    specify pop2, pop3, imap, apop, rpop, kpop, etrn, imap-k4\n", stderr);
507 #else
508         fputs("  -p, --protocol    specify pop2, pop3, imap, apop, rpop, kpop, etrn\n", stderr);
509 #endif /* KERBEROS_V4 */
510         fputs("  -U, --uidl        force the use of UIDLs (pop3 only)\n", stderr);
511         fputs("  -P, --port        TCP/IP service port to connect to\n",stderr);
512         fputs("  -A, --auth        authentication type (password or kerberos)\n",stderr);
513         fputs("  -t, --timeout     server nonresponse timeout\n",stderr);
514         fputs("  -E, --envelope    envelope address header\n",stderr);
515         fputs("  -Q, --qvirtual    prefix to remove from local user id\n",stderr);
516
517         fputs("  -u, --username    specify users's login on server\n", stderr);
518         fputs("  -a, --all         retrieve old and new messages\n", stderr);
519         fputs("  -K, --nokeep      delete new messages after retrieval\n", stderr);
520         fputs("  -k, --keep        save new messages after retrieval\n", stderr);
521         fputs("  -F, --flush       delete old messages from server\n", stderr);
522         fputs("  -n, --norewrite   don't rewrite header addresses\n", stderr);
523         fputs("  -l, --limit       don't fetch messages over given size\n", stderr);
524
525 #if NET_SECURITY
526         fputs("  -T, --netsec      set IP security request\n", stderr);
527 #endif /* NET_SECURITY */
528         fputs("  -S, --smtphost    set SMTP forwarding host\n", stderr);
529         fputs("  -D, --smtpaddress set SMTP delivery domain to use\n", stderr);
530         fputs("  -Z, --antispam,   set antispam response value\n", stderr);
531         fputs("  -b, --batchlimit  set batch limit for SMTP connections\n", stderr);
532         fputs("  -B, --fetchlimit  set fetch limit for server connections\n", stderr);
533         fputs("  -e, --expunge     set max deletions between expunges\n", stderr);
534         fputs("  -r, --folder      specify remote folder name\n", stderr);
535         return(-1);
536     }
537
538     return(optind);
539 }
540
541 /* options.c ends here */