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