]> Pileus Git - ~andy/fetchmail/blob - options.c
Added support for RFC-1725-compliant servers with UIDL and without LAST.
[~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 /* XXX -- Would like to use 'enum' here, but it causes type mismatch 
23           problems many compilers */
24 #define LA_VERSION      1 
25 #define LA_ALL          2
26 #define LA_KILL         3
27 #define LA_KEEP         4 
28 #define LA_VERBOSE      5 
29 #define LA_SILENT       6 
30 #define LA_STDOUT       7
31 #define LA_LIMIT        8
32 #define LA_FLUSH        9
33 #define LA_PROTOCOL     10
34 #define LA_DAEMON       11
35 #define LA_POPRC        12
36 #define LA_IDFILE       13
37 #define LA_USERNAME     14
38 #define LA_REMOTEFILE   15
39 #define LA_LOCALFILE    16
40 #define LA_MDA          17
41 #define LA_LOGFILE      18
42 #define LA_QUIT         19
43 #define LA_NOREWRITE    20
44 #define LA_YYDEBUG      21
45  
46 static char *shortoptions = "23VaKkvscl:Fd:f:u:r:o:m:L:qN";
47 static struct option longoptions[] = {
48   {"version",   no_argument,       (int *) 0, LA_VERSION    },
49   {"all",       no_argument,       (int *) 0, LA_ALL        },
50   {"kill",      no_argument,       (int *) 0, LA_KILL       },
51   {"keep",      no_argument,       (int *) 0, LA_KEEP       },
52   {"verbose",   no_argument,       (int *) 0, LA_VERBOSE    },
53   {"silent",    no_argument,       (int *) 0, LA_SILENT     },
54   {"stdout",    no_argument,       (int *) 0, LA_STDOUT     },
55   {"limit",     required_argument, (int *) 0, LA_LIMIT      },
56   {"flush",     no_argument,       (int *) 0, LA_FLUSH      },
57   {"protocol",  required_argument, (int *) 0, LA_PROTOCOL   },
58   {"proto",     required_argument, (int *) 0, LA_PROTOCOL   },
59   {"daemon",    required_argument, (int *) 0, LA_DAEMON     },
60   {"poprc",     required_argument, (int *) 0, LA_POPRC      },
61   {"user",      required_argument, (int *) 0, LA_USERNAME   },
62   {"username",  required_argument, (int *) 0, LA_USERNAME   },
63   {"remote",    required_argument, (int *) 0, LA_REMOTEFILE },
64   {"local",     required_argument, (int *) 0, LA_LOCALFILE  },
65   {"mda",       required_argument, (int *) 0, LA_MDA        },
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 LA_PROTOCOL:
170         /* XXX -- should probably use a table lookup here */
171         if (strcasecmp(optarg,"pop2") == 0)
172           queryctl->protocol = P_POP2;
173         else if (strcasecmp(optarg,"pop3") == 0)
174           queryctl->protocol = P_POP3;
175         else if (strcasecmp(optarg,"imap") == 0)
176           queryctl->protocol = P_IMAP;
177         else if (strcasecmp(optarg,"apop") == 0)
178           queryctl->protocol = P_APOP;
179         else if (strcasecmp(optarg,"rpop") == 0)
180           queryctl->protocol = P_RPOP;
181         else {
182           fprintf(stderr,"Invalid protocol '%s'\n specified.\n", optarg);
183           errflag++;
184         }
185         break;
186       case 'd':
187       case LA_DAEMON:
188         poll_interval = atoi(optarg);
189         break;
190       case 'f':
191       case LA_POPRC:
192         poprcfile = (char *) xmalloc(strlen(optarg)+1);
193         strcpy(poprcfile,optarg);
194         break;
195       case 'i':
196       case LA_IDFILE:
197         idfile = (char *) xmalloc(strlen(optarg)+1);
198         strcpy(idfile,optarg);
199         break;
200       case 'u':
201       case LA_USERNAME:
202         strncpy(queryctl->remotename,optarg,sizeof(queryctl->remotename)-1);
203         break;
204       case 'o':
205       case LA_LOCALFILE:
206         if (fflag) 
207           errflag++;
208         else {
209           fflag++;
210           queryctl->output = TO_FOLDER;
211           strncpy(queryctl->userfolder,optarg,sizeof(queryctl->userfolder)-1);
212         }
213         break;
214       case 'r':
215       case LA_REMOTEFILE:
216         strncpy(queryctl->remotefolder,optarg,sizeof(queryctl->remotefolder)-1);
217         break;
218       case 'm':
219       case LA_MDA:
220         strncpy(queryctl->mda,optarg,sizeof(queryctl->mda)-1);
221         break;
222       case 'L':
223       case LA_LOGFILE:
224         logfile = optarg;
225         break;
226       case 'q':
227       case LA_QUIT:
228         quitmode = 1;
229         break;
230       case 'N':
231       case LA_NOREWRITE:
232         queryctl->rewrite = 0;
233         break;
234       case LA_YYDEBUG:
235         yydebug = 1;
236         break;
237       default:
238         errflag++;
239     }
240   }
241
242   if (errflag) {
243     /* squawk if syntax errors were detected */
244     fputs("usage:  popclient [options] [server ...]\n", stderr);
245     fputs("  options\n",stderr);
246     fputs("  -2               use POP2 protocol\n", stderr);
247     fputs("  -3               use POP3 protocol\n", stderr);
248     fputs("      --protocol   specify pop2, pop3, imap, apop, or rpop\n",
249           stderr);
250     fputs("  -V, --version    display version info\n", stderr);
251     fputs("  -a, --all        retrieve old and new messages\n", stderr);
252     fputs("  -F, --flush      delete old messages from server\n", stderr);
253     fputs("  -K, --kill       delete new messages after retrieval\n", stderr);
254     fputs("  -k, --keep       save new messages after retrieval\n", stderr);
255     fputs("  -l, --limit      retrieve at most n message lines\n", stderr);
256     fputs("  -m, --mda        set mail user agent to pass to\n", stderr);
257     fputs("  -q, --quit       kill daemon process\n", stderr);
258     fputs("  -s, --silent     work silently\n", stderr);
259     fputs("  -v, --verbose    work noisily (diagnostic output)\n", stderr);
260     fputs("  -d, --daemon     run as a daemon once per n seconds\n", stderr);
261     fputs("  -f, --poprc      specify alternate config file\n", stderr);
262     fputs("  -i, --idfile     specify alternate ID database\n", stderr);
263     fputs("  -u, --username   specify server user ID\n", stderr);
264     fputs("  -c, --stdout     write received mail to stdout\n", stderr);
265     fputs("  -o, --local      specify filename for received mail\n", stderr);
266     fputs("  -r, --remote     specify remote folder name\n", stderr);
267     fputs("  -L, --logfile    specify logfile name\n", stderr);
268     return(-1);
269   }
270   else {
271     if (linelimit && !got_kill) 
272       queryctl->keep = !0;
273     else
274       ;
275     return(optind);
276   }
277 }
278          
279
280 /*********************************************************************
281   function:      setdefaults
282   description:   set reasonable default values for unspecified options.
283   arguments:     
284     options      option values parsed from the command-line; unspeci-
285                  fied options must be filled with zero.
286
287   return value:  zero if defaults were successfully set, else non-zero
288                  (indicates a problem reading /etc/passwd).
289   calls:         none.
290   globals:       writes outlevel, poprcfile, idfile.
291  *********************************************************************/
292
293 int setdefaults (queryctl)
294 struct hostrec *queryctl;
295 {
296   int uid;
297   struct passwd *pw;
298   char *mailvar;
299
300   bzero(queryctl,sizeof(*queryctl));
301
302   if ((pw = getpwuid(uid = getuid())) == NULL) {
303     fprintf(stderr,"No passwd entry for uid %d\n",uid);
304     return(-1);
305   }
306
307   queryctl->protocol = DEF_PROTOCOL;
308
309 #if defined(KEEP_IS_DEFAULT)
310   queryctl->keep = 1;
311 #else
312   queryctl->keep = 0;
313 #endif
314   queryctl->rewrite = 1;
315
316   strcpy(queryctl->localname,pw->pw_name);
317   strcpy(queryctl->remotename,pw->pw_name);
318   sprintf(queryctl->userfolder, USERFOLDER, pw->pw_name);
319   queryctl->output = TO_MDA;
320   (void) sprintf(queryctl->mda, DEF_MDA, queryctl->localname);
321
322   poprcfile = 
323       (char *) xmalloc(strlen(pw->pw_dir)+strlen(POPRC_NAME)+2);
324
325   strcpy(poprcfile, pw->pw_dir);
326   strcat(poprcfile, "/");
327   strcat(poprcfile, POPRC_NAME);
328
329   idfile = 
330       (char *) xmalloc(strlen(pw->pw_dir)+strlen(IDFILE_NAME)+2);
331
332   strcpy(idfile, pw->pw_dir);
333   strcat(idfile, "/");
334   strcat(idfile, IDFILE_NAME);
335
336   outlevel = O_NORMAL;
337
338   return(0);
339 }
340
341
342
343 /******************************************************************
344   function:     getnextserver
345   description:  read next server name from the command line.
346   arguments:    
347     argc        from main()
348     argv        from main()
349     optind      as returned by parsecmdline and this function.
350
351   ret. value:   next server name from command line or NULL if all
352                 server names have been retrieved.
353   globals:      none.
354   calls:        none.
355  *****************************************************************/
356 char *getnextserver (argc,argv,optind)
357 int argc;
358 char **argv;
359 int *optind;
360 {
361    if (*optind >= argc) {
362      /* no more servers */
363      return((char *) 0);
364    }
365    else
366      return(argv[(*optind)++]);
367 }