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