]> Pileus Git - ~andy/fetchmail/blob - options.c
*** empty log message ***
[~andy/fetchmail] / options.c
1 /* Copyright 1993-95 by Carl Harris, Jr. Copyright 1996 by Eric S. Raymond
2  * All rights reserved.
3  * For license terms, see the file COPYING in this directory.
4  */
5
6 /***********************************************************************
7   module:       options.c
8   project:      fetchmail
9   programmer:   Carl Harris, ceharris@mal.com
10   description:  command-line option processing
11
12  ***********************************************************************/
13
14 #include <config.h>
15 #include <stdio.h>
16
17 #include <pwd.h>
18 #include "getopt.h"
19 #include "fetchmail.h"
20
21 #define LA_VERSION      1 
22 #define LA_ALL          2
23 #define LA_KILL         3
24 #define LA_KEEP         4 
25 #define LA_VERBOSE      5 
26 #define LA_SILENT       6 
27 #define LA_STDOUT       7
28 #define LA_LIMIT        8
29 #define LA_FLUSH        9
30 #define LA_PROTOCOL     10
31 #define LA_DAEMON       11
32 #define LA_FETCHRC      12
33 #define LA_IDFILE       13
34 #define LA_USERNAME     14
35 #define LA_REMOTEFILE   15
36 #define LA_LOCALFILE    16
37 #define LA_MDA          17
38 #define LA_PORT         18
39 #define LA_SMTPHOST     19
40 #define LA_LOGFILE      20
41 #define LA_QUIT         21
42 #define LA_NOREWRITE    22
43 #define LA_YYDEBUG      23
44  
45 static char *shortoptions = "23PVaKkvS:scl:Fd:f:u:r:o:m:L:qN";
46 static struct option longoptions[] = {
47   {"version",   no_argument,       (int *) 0, LA_VERSION    },
48   {"all",       no_argument,       (int *) 0, LA_ALL        },
49   {"kill",      no_argument,       (int *) 0, LA_KILL       },
50   {"keep",      no_argument,       (int *) 0, LA_KEEP       },
51   {"verbose",   no_argument,       (int *) 0, LA_VERBOSE    },
52   {"silent",    no_argument,       (int *) 0, LA_SILENT     },
53   {"stdout",    no_argument,       (int *) 0, LA_STDOUT     },
54   {"limit",     required_argument, (int *) 0, LA_LIMIT      },
55   {"flush",     no_argument,       (int *) 0, LA_FLUSH      },
56   {"protocol",  required_argument, (int *) 0, LA_PROTOCOL   },
57   {"proto",     required_argument, (int *) 0, LA_PROTOCOL   },
58   {"daemon",    required_argument, (int *) 0, LA_DAEMON     },
59   {"fetchrc",   required_argument, (int *) 0, LA_FETCHRC      },
60   {"user",      required_argument, (int *) 0, LA_USERNAME   },
61   {"username",  required_argument, (int *) 0, LA_USERNAME   },
62   {"remote",    required_argument, (int *) 0, LA_REMOTEFILE },
63   {"local",     required_argument, (int *) 0, LA_LOCALFILE  },
64   {"mda",       required_argument, (int *) 0, LA_MDA        },
65   {"port",      required_argument, (int *) 0, LA_PORT       },
66   {"smtphost",  required_argument, (int *) 0, LA_SMTPHOST   },
67   {"logfile",   required_argument, (int *) 0, LA_LOGFILE    },
68   {"idfile",    required_argument, (int *) 0, LA_IDFILE     },
69   {"quit",      no_argument,       (int *) 0, LA_QUIT       },
70   {"norewrite", no_argument,       (int *) 0, LA_NOREWRITE  },
71   {"yydebug",   no_argument,       (int *) 0, LA_YYDEBUG    },
72   {(char *) 0,  no_argument,       (int *) 0, 0             }
73 };
74
75
76 /*********************************************************************
77   function:      parsecmdline
78   description:   parse/validate the command line options.
79   arguments:
80     argc         argument count.
81     argv         argument strings.
82     queryctl     pointer to a struct hostrec to receive the parsed 
83                  options.
84
85   return value:  if positive, argv index of last parsed option + 1
86                  (presumes one or more server names follows).
87                  if zero, the command line switches are such that
88                  no server names are required (e.g. --version).
89                  if negative, the command line is has one or more
90                  syntax errors.
91   calls:         none.  
92   globals:       writes outlevel, versioninfo, yydebug, logfile, 
93                  poll_interval, quitmode, rcfile, idfile, linelimit.  
94  *********************************************************************/
95
96 int parsecmdline (argc,argv,queryctl)
97 int argc;
98 char **argv;
99 struct hostrec *queryctl;
100 {
101   int c,i;
102   int fflag = 0;     /* TRUE when -o or -c has been specified */
103   int errflag = 0;   /* TRUE when a syntax error is detected */
104   int option_index;
105   int got_kill = 0;  /* TRUE when --kill is specified */
106
107   extern int optind, opterr;     /* defined in getopt(2) */
108   extern char *optarg;          /* defined in getopt(2) */
109
110   memset(queryctl, '\0', sizeof(struct hostrec));    /* start clean */
111
112   while (!errflag && 
113          (c = getopt_long(argc,argv,shortoptions,
114                           longoptions,&option_index)) != -1) {
115
116     switch (c) {
117       case '2':
118         queryctl->protocol = P_POP2;
119         break;
120       case '3':
121         queryctl->protocol = P_POP3;
122         break;
123       case 'V':
124       case LA_VERSION:
125         versioninfo = !0;
126         break;
127       case 'a':
128       case LA_ALL:
129         queryctl->fetchall = !0;
130         break;
131       case 'K':
132       case LA_KILL:
133         queryctl->keep = 0;
134         got_kill = 1;
135         break;
136       case 'k':
137       case LA_KEEP:
138         queryctl->keep = !0;
139         got_kill = 0;
140         break;
141       case 'v':
142       case LA_VERBOSE:
143         outlevel = O_VERBOSE;
144         break;
145       case 's':
146       case LA_SILENT:
147         outlevel = O_SILENT;
148         break;
149       case 'c':
150       case LA_STDOUT:
151         if (fflag)
152           errflag++;
153         else {
154           fflag++;
155           queryctl->output = TO_STDOUT;
156         }
157         break;
158       case 'l':
159       case LA_LIMIT:
160         linelimit = atoi(optarg);
161         if (linelimit < 0) {
162           fprintf(stderr,"Line count limit must be non-negative");
163           errflag++;
164         }
165         break;
166       case 'F':
167       case LA_FLUSH:
168         queryctl->flush = !0;
169         break;
170       case 'p':
171       case LA_PROTOCOL:
172         /* XXX -- should probably use a table lookup here */
173         if (strcasecmp(optarg,"pop2") == 0)
174           queryctl->protocol = P_POP2;
175         else if (strcasecmp(optarg,"pop3") == 0)
176           queryctl->protocol = P_POP3;
177         else if (strcasecmp(optarg,"imap") == 0)
178           queryctl->protocol = P_IMAP;
179         else if (strcasecmp(optarg,"apop") == 0)
180           queryctl->protocol = P_APOP;
181         else if (strcasecmp(optarg,"rpop") == 0)
182           queryctl->protocol = P_RPOP;
183         else {
184           fprintf(stderr,"Invalid protocol '%s'\n specified.\n", optarg);
185           errflag++;
186         }
187         break;
188       case 'd':
189       case LA_DAEMON:
190         poll_interval = atoi(optarg);
191         break;
192       case 'f':
193       case LA_FETCHRC:
194         rcfile = (char *) xmalloc(strlen(optarg)+1);
195         strcpy(rcfile,optarg);
196         break;
197       case 'i':
198       case LA_IDFILE:
199         idfile = (char *) xmalloc(strlen(optarg)+1);
200         strcpy(idfile,optarg);
201         break;
202       case 'u':
203       case LA_USERNAME:
204         strncpy(queryctl->remotename,optarg,sizeof(queryctl->remotename)-1);
205         break;
206       case 'o':
207       case LA_LOCALFILE:
208         if (fflag) 
209           errflag++;
210         else {
211           fflag++;
212           queryctl->output = TO_FOLDER;
213           strncpy(queryctl->userfolder,optarg,sizeof(queryctl->userfolder)-1);
214         }
215         break;
216       case 'r':
217       case LA_REMOTEFILE:
218         strncpy(queryctl->remotefolder,optarg,sizeof(queryctl->remotefolder)-1);
219         break;
220       case 'm':
221       case LA_MDA:
222         queryctl->output = TO_MDA;
223         strncpy(queryctl->mda,optarg,sizeof(queryctl->mda)-1);
224         break;
225       case 'P':
226       case LA_PORT:
227         queryctl->port = atoi(optarg);
228         break;
229       case 'S':
230       case LA_SMTPHOST:
231         if (fflag) 
232           errflag++;
233         else {
234           fflag++;
235           queryctl->output = TO_SMTP;
236           strncpy(queryctl->smtphost,optarg,sizeof(queryctl->smtphost)-1);
237         }
238         break;
239       case 'L':
240       case LA_LOGFILE:
241         logfile = optarg;
242         break;
243       case 'q':
244       case LA_QUIT:
245         quitmode = 1;
246         break;
247       case 'N':
248       case LA_NOREWRITE:
249         queryctl->norewrite = 1;
250         break;
251       case LA_YYDEBUG:
252         yydebug = 1;
253         break;
254       default:
255         errflag++;
256     }
257   }
258
259   if (errflag) {
260     /* squawk if syntax errors were detected */
261     fputs("usage:  fetchmail [options] [server ...]\n", stderr);
262     fputs("  options\n",stderr);
263     fputs("  -2               use POP2 protocol\n", stderr);
264     fputs("  -3               use POP3 protocol\n", stderr);
265     fputs("  -p,  --protocol   specify pop2, pop3, imap, apop, or rpop\n",
266           stderr);
267     fputs("  -V, --version    display version info\n", stderr);
268     fputs("  -a, --all        retrieve old and new messages\n", stderr);
269     fputs("  -F, --flush      delete old messages from server\n", stderr);
270     fputs("  -K, --kill       delete new messages after retrieval\n", stderr);
271     fputs("  -k, --keep       save new messages after retrieval\n", stderr);
272     fputs("  -l, --limit      retrieve at most n message lines\n", stderr);
273     fputs("  -m, --mda        set mail user agent to pass to\n", stderr);
274     fputs("  -S, --smtphost   set SMTP forwarding host\n", stderr);
275     fputs("  -q, --quit       kill daemon process\n", stderr);
276     fputs("  -s, --silent     work silently\n", stderr);
277     fputs("  -v, --verbose    work noisily (diagnostic output)\n", stderr);
278     fputs("  -d, --daemon     run as a daemon once per n seconds\n", stderr);
279     fputs("  -f, --fetchrc      specify alternate config file\n", stderr);
280     fputs("  -i, --idfile     specify alternate ID database\n", stderr);
281     fputs("  -u, --username   specify server user ID\n", stderr);
282     fputs("  -c, --stdout     write received mail to stdout\n", stderr);
283     fputs("  -o, --local      specify filename for received mail\n", stderr);
284     fputs("  -r, --remote     specify remote folder name\n", stderr);
285     fputs("  -L, --logfile    specify logfile name\n", stderr);
286     return(-1);
287   }
288   else {
289     if (linelimit && !got_kill) 
290       queryctl->keep = !0;
291     else
292       ;
293     return(optind);
294   }
295 }
296          
297
298 /*********************************************************************
299   function:      setdefaults
300   description:   set reasonable default values for unspecified options.
301   arguments:     
302     options      option values parsed from the command-line; unspeci-
303                  fied options must be filled with zero.
304
305   return value:  zero if defaults were successfully set, else non-zero
306                  (indicates a problem reading /etc/passwd).
307   calls:         none.
308   globals:       writes outlevel, rcfile, idfile.
309  *********************************************************************/
310 #include <stdlib.h>
311
312 int setdefaults (queryctl)
313 struct hostrec *queryctl;
314 {
315     char *user, *home;
316
317     memset(queryctl, '\0', sizeof(*queryctl));
318
319     if ((user = getenv("USER")) == (char *)NULL
320                 || (home = getenv("HOME")) == (char *)NULL)
321     {
322         struct passwd *pw;
323
324         if ((pw = getpwuid(getuid())) != NULL)
325         {
326             user = pw->pw_name;
327             home = pw->pw_dir;
328         }
329         else
330         {
331             fprintf(stderr,"I can't find your name and home directory!\n");
332             return(-1);
333         }
334     }
335
336     queryctl->protocol = DEF_PROTOCOL;
337
338 #if defined(KEEP_IS_DEFAULT)
339     queryctl->keep = 1;
340 #else
341     queryctl->keep = 0;
342 #endif
343     queryctl->norewrite = 0;
344
345     strcpy(queryctl->localname, user);
346     strcpy(queryctl->remotename, user);
347     sprintf(queryctl->userfolder, USERFOLDER, user);
348     strcpy(queryctl->smtphost, "localhost");
349     queryctl->output = TO_SMTP;
350     (void) sprintf(queryctl->mda, DEF_MDA, queryctl->localname);
351
352     rcfile = 
353         (char *) xmalloc(strlen(home)+strlen(FETCHRC_NAME)+2);
354
355     strcpy(rcfile, home);
356     strcat(rcfile, "/");
357     strcat(rcfile, FETCHRC_NAME);
358
359     idfile = 
360         (char *) xmalloc(strlen(home)+strlen(IDFILE_NAME)+2);
361
362     strcpy(idfile, home);
363     strcat(idfile, "/");
364     strcat(idfile, IDFILE_NAME);
365
366     outlevel = O_NORMAL;
367
368     return(0);
369 }
370
371
372
373 /******************************************************************
374   function:     getnextserver
375   description:  read next server name from the command line.
376   arguments:    
377     argc        from main()
378     argv        from main()
379     optind      as returned by parsecmdline and this function.
380
381   ret. value:   next server name from command line or NULL if all
382                 server names have been retrieved.
383   globals:      none.
384   calls:        none.
385  *****************************************************************/
386 char *getnextserver (argc,argv,optind)
387 int argc;
388 char **argv;
389 int *optind;
390 {
391    if (*optind >= argc) {
392      /* no more servers */
393      return((char *) 0);
394    }
395    else
396      return(argv[(*optind)++]);
397 }