]> Pileus Git - ~andy/fetchmail/blob - options.c
f8bda4b275df433031000ef6e755b4e93929ed2a
[~andy/fetchmail] / options.c
1 /* Copyright 1993-95 by Carl Harris, Jr.
2  * All rights reserved
3  *
4  * Distribute freely, except: don't remove my name from the source or
5  * documentation (don't take credit for my work), mark your changes (don't
6  * get me blamed for your possible bugs), don't alter or remove this
7  * notice.  May be sold if buildable source is provided to buyer.  No
8  * warrantee of any kind, express or implied, is included with this
9  * software; use at your own risk, responsibility for damages (if any) to
10  * anyone resulting from the use of this software rests entirely with the
11  * user.
12  *
13  * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
14  * I'll try to keep a version up to date.  I can be reached as follows:
15  * Carl Harris <ceharris@mal.com>
16  */
17
18 /***********************************************************************
19   module:       options.c
20   project:      popclient
21   programmer:   Carl Harris, ceharris@mal.com
22   description:  command-line option processing
23   
24   $Log: options.c,v $
25   Revision 1.1  1996/06/24 18:11:08  esr
26   Initial revision
27
28   Revision 1.4  1995/08/14 18:36:39  ceharris
29   Patches to support POP3's LAST command.
30   Final revisions for beta3 release.
31
32   Revision 1.3  1995/08/10 00:32:34  ceharris
33   Preparation for 3.0b3 beta release:
34   -     added code for --kill/--keep, --limit, --protocol, --flush
35         options; --pop2 and --pop3 options now obsoleted by --protocol.
36   -     added support for APOP authentication, including --with-APOP
37         argument for configure.
38   -     provisional and broken support for RPOP
39   -     added buffering to SockGets and SockRead functions.
40   -     fixed problem of command-line options not being correctly
41         carried into the merged options record.
42
43   Revision 1.2  1995/08/09 01:32:51  ceharris
44   Version 3.0 beta 2 release.
45   Added
46   -     .poprc functionality
47   -     GNU long options
48   -     multiple servers on the command line.
49   Fixed
50   -     Passwords showing up in ps output.
51
52   Revision 1.1  1995/08/08 01:01:21  ceharris
53   Added GNU-style long options processing.
54   Fixed password in 'ps' output problem.
55   Fixed various RCS tag blunders.
56   Integrated .poprc parser, lexer, etc into Makefile processing.
57
58  ***********************************************************************/
59
60 #include <config.h>
61 #include <stdio.h>
62
63 #include <pwd.h>
64 #include "getopt.h"
65 #include "popclient.h"
66 #include "bzero.h"
67
68 /* XXX -- Would like to use 'enum' here, but it causes type mismatch 
69           problems many compilers */
70 #define LA_VERSION      1 
71 #define LA_ALL          2
72 #define LA_KILL         3
73 #define LA_KEEP         4 
74 #define LA_VERBOSE      5 
75 #define LA_SILENT       6 
76 #define LA_STDOUT       7
77 #define LA_LIMIT        8
78 #define LA_FLUSH        9
79 #define LA_PROTOCOL     10
80 #define LA_DAEMON       11
81 #define LA_POPRC        12
82 #define LA_USERNAME     13
83 #define LA_PASSWORD     14
84 #define LA_REMOTEFILE   15
85 #define LA_LOCALFILE    16
86
87  
88 static char *shortoptions = "23VaKkvscl:Fd:f:u:p:r:o:";
89 static struct option longoptions[] = {
90   {"version",   no_argument,       (int *) 0, LA_VERSION    },
91   {"all",       no_argument,       (int *) 0, LA_ALL        },
92   {"kill",      no_argument,       (int *) 0, LA_KILL       },
93   {"keep",      no_argument,       (int *) 0, LA_KEEP       },
94   {"verbose",   no_argument,       (int *) 0, LA_VERBOSE    },
95   {"silent",    no_argument,       (int *) 0, LA_SILENT     },
96   {"stdout",    no_argument,       (int *) 0, LA_STDOUT     },
97   {"limit",     required_argument, (int *) 0, LA_LIMIT      },
98   {"flush",     no_argument,       (int *) 0, LA_FLUSH      },
99   {"protocol",  required_argument, (int *) 0, LA_PROTOCOL   },
100   {"proto",     required_argument, (int *) 0, LA_PROTOCOL   },
101   {"daemon",    required_argument, (int *) 0, LA_DAEMON     },
102   {"poprc",     required_argument, (int *) 0, LA_POPRC      },
103   {"user",      required_argument, (int *) 0, LA_USERNAME   },
104   {"username",  required_argument, (int *) 0, LA_USERNAME   },
105   {"password",  required_argument, (int *) 0, LA_PASSWORD   },
106   {"remote",    required_argument, (int *) 0, LA_REMOTEFILE },
107   {"local",     required_argument, (int *) 0, LA_LOCALFILE  },
108   {(char *) 0,  no_argument,       (int *) 0, 0             }
109 };
110
111
112 /*********************************************************************
113   function:      parsecmdline
114   description:   parse/validate the command line options.
115   arguments:
116     argc         argument count.
117     argv         argument strings.
118     options      pointer to a struct optrec to receive the parsed 
119                  options.
120
121   return value:  if positive, argv index of last parsed option + 1
122                  (presumes one or more server names follows).
123                  if zero, the command line switches are such that
124                  no server names are required (e.g. --version).
125                  if negative, the command line is has one or more
126                  syntax errors.
127   calls:         none.  
128   globals:       none.  
129  *********************************************************************/
130
131 int parsecmdline (argc,argv,options)
132 int argc;
133 char **argv;
134 struct optrec *options;
135 {
136   int c,i;
137   int fflag = 0;     /* TRUE when -o or -c has been specified */
138   int errflag = 0;   /* TRUE when a syntax error is detected */
139   int option_index;
140   int got_kill = 0;  /* TRUE when --kill is specified */
141
142   extern int optind, opterr;     /* defined in getopt(2) */
143   extern char *optarg;          /* defined in getopt(2) */
144
145   bzero(options,sizeof(struct optrec));    /* start clean */
146
147   while (!errflag && 
148          (c = getopt_long(argc,argv,shortoptions,
149                           longoptions,&option_index)) != -1) {
150
151     switch (c) {
152       case '2':
153         options->whichpop = P_POP2;
154         break;
155       case '3':
156         options->whichpop = P_POP3;
157         break;
158       case 'V':
159       case LA_VERSION:
160         options->versioninfo = !0;
161         break;
162       case 'a':
163       case LA_ALL:
164         options->fetchall = !0;
165         break;
166       case 'K':
167       case LA_KILL:
168         options->keep = 0;
169         got_kill = 1;
170         break;
171       case 'k':
172       case LA_KEEP:
173         options->keep = !0;
174         got_kill = 0;
175         break;
176       case 'v':
177       case LA_VERBOSE:
178         options->verbose = !0;
179         break;
180       case 's':
181       case LA_SILENT:
182         options->silent = !0;
183         break;
184       case 'c':
185       case LA_STDOUT:
186         if (fflag)
187           errflag++;
188         else {
189           fflag++;
190           options->foldertype = OF_STDOUT;
191         }
192         break;
193       case 'l':
194       case LA_LIMIT:
195         options->limit = atoi(optarg);
196         if (options->limit < 0) {
197           fprintf(stderr,"Line count limit must be non-negative");
198           errflag++;
199         }
200         break;
201       case 'F':
202       case LA_FLUSH:
203         options->flush = !0;
204         break;
205       case LA_PROTOCOL:
206         /* XXX -- should probably use a table lookup here */
207         if (strcasecmp(optarg,"pop2") == 0)
208           options->whichpop = P_POP2;
209         else if (strcasecmp(optarg,"pop3") == 0)
210           options->whichpop = P_POP3;
211         else if (strcasecmp(optarg,"imap") == 0)
212           options->whichpop = P_IMAP;
213         else if (strcasecmp(optarg,"apop") == 0)
214           options->whichpop = P_APOP;
215         else if (strcasecmp(optarg,"rpop") == 0)
216           options->whichpop = P_RPOP;
217         else {
218           fprintf(stderr,"Invalid protocol '%s'\n specified.\n", optarg);
219           errflag++;
220         }
221         break;
222       case 'd':
223       case LA_DAEMON:
224         fprintf(stderr,"Got daemonize option with argument '%s'\n",optarg);
225         break;
226       case 'f':
227       case LA_POPRC:
228         options->poprcfile = (char *) xmalloc(strlen(optarg)+1);
229         strcpy(options->poprcfile,optarg);
230         break;
231       case 'u':
232       case LA_USERNAME:
233         strncpy(options->userid,optarg,sizeof(options->userid)-1);
234         break;
235       case 'p':
236       case LA_PASSWORD:
237         strncpy(options->password,optarg,sizeof(options->password)-1);
238         for (i = strlen(options->password)-1;  i >= 0;  i--) 
239           argv[optind-1][i] = '*';
240         break;
241       case 'o':
242       case LA_LOCALFILE:
243         if (fflag) 
244           errflag++;
245         else {
246           fflag++;
247           options->foldertype = OF_USERMBOX;
248           strncpy(options->userfolder,optarg,sizeof(options->userfolder)-1);
249         }
250         break;
251       case 'r':
252       case LA_REMOTEFILE:
253         strncpy(options->remotefolder,optarg,sizeof(options->remotefolder)-1);
254         break;
255       default:
256         errflag++;
257     }
258   }
259
260   if (!options->versioninfo) 
261     /* if options don't obviate the need, we must have server name(s)
262        left on the command line. */
263     if (optind >= argc) 
264       errflag++;
265     else
266       ;
267   else
268     optind = 0;
269  
270   if (errflag) {
271     /* squawk if syntax errors were detected */
272     fputs("usage:  popclient [options] server [server ...]\n", stderr);
273     fputs("  options\n",stderr);
274     fputs("  -2               use POP2 protocol\n", stderr);
275     fputs("  -3               use POP3 protocol\n", stderr);
276     fputs("      --protocol   specify pop2, pop3, imap, apop, or rpop\n",
277           stderr);
278     fputs("  -V, --version    display version info\n", stderr);
279     fputs("  -a, --all        retrieve old and new messages\n", stderr);
280     fputs("  -F, --flush      delete old messages from server\n", stderr);
281     fputs("  -K, --kill       delete new messages after retrieval\n", stderr);
282     fputs("  -k, --keep       save new messages after retrieval\n", stderr);
283     fputs("  -l, --limit      retrieve at most n message lines\n", stderr);
284     fputs("  -s, --silent     work silently\n", stderr);
285     fputs("  -v, --verbose    work noisily (diagnostic output)\n", stderr);
286     fputs("  -d, --daemon     run as a daemon\n", stderr);
287     fputs("  -f, --poprc      specify alternate config file\n", stderr);
288     fputs("  -u, --username   specify server user ID\n", stderr);
289     fputs("  -p, --password   specify server password\n", stderr);
290     fputs("  -c, --stdout     write received mail to stdout\n", stderr);
291     fputs("  -o, --local      specify filename for received mail\n", stderr);
292     fputs("  -r, --remote     specify remote folder name\n", stderr);
293     return(-1);
294   }
295   else {
296     if (options->limit && !got_kill) 
297       options->keep = !0;
298     else
299       ;
300     return(optind);
301   }
302 }
303          
304
305 /*********************************************************************
306   function:      setdefaults
307   description:   set reasonable default values for unspecified options.
308   arguments:     
309     options      option values parsed from the command-line; unspeci-
310                  fied options must be filled with zero.
311
312   return value:  zero if defaults were successfully set, else non-zero
313                  (indicates a problem reading /etc/passwd).
314   calls:         none.
315   globals:       writes outlevel.
316  *********************************************************************/
317
318 int setdefaults (options)
319 struct optrec *options;
320 {
321   int uid;
322   struct passwd *pw;
323   char *mailvar;
324
325   bzero(options,sizeof(*options));
326
327   if ((pw = getpwuid(uid = getuid())) == NULL) {
328     fprintf(stderr,"No passwd entry for uid %d\n",uid);
329     return(-1);
330   }
331   /* save the login name for delivery use */
332   strcpy(options->loginid,pw->pw_name);
333
334   options->whichpop = DEF_PROTOCOL;
335   options->foldertype = OF_SYSMBOX;
336
337 #if defined(KEEP_IS_DEFAULT)
338   options->keep = 1;
339 #else
340   options->keep = 0;
341 #endif
342
343   strcpy(options->userid,pw->pw_name);
344
345   options->poprcfile = 
346       (char *) xmalloc(strlen(pw->pw_dir)+strlen(POPRC_NAME)+2);
347
348   strcpy(options->poprcfile, pw->pw_dir);
349   strcat(options->poprcfile, "/");
350   strcat(options->poprcfile, POPRC_NAME);
351
352   return(0);
353 }
354
355
356
357 /******************************************************************
358   function:     getnextserver
359   description:  read next server name from the command line.
360   arguments:    
361     argc        from main()
362     argv        from main()
363     optind      as returned by parsecmdline and this function.
364
365   ret. value:   next server name from command line or NULL if all
366                 server names have been retrieved.
367   globals:      none.
368   calls:        none.
369  *****************************************************************/
370 char *getnextserver (argc,argv,optind)
371 int argc;
372 char **argv;
373 int *optind;
374 {
375    if (*optind >= argc) {
376      /* no more servers */
377      return((char *) 0);
378    }
379    else
380      return(argv[(*optind)++]);
381 }