]> Pileus Git - ~andy/fetchmail/blob - fetchmail.c
7a04ca2c4bace710d427c0e41e3d3b119a0b45a5
[~andy/fetchmail] / fetchmail.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:       popclient.c
20   project:      popclient
21   programmer:   Carl Harris, ceharris@mal.com
22   description:  main driver module for popclient
23
24   $Log: fetchmail.c,v $
25   Revision 1.1  1996/06/24 18:32:00  esr
26   Initial revision
27
28   Revision 1.7  1995/09/07 22:37:34  ceharris
29   Preparation for 3.0b4 release.
30
31   Revision 1.6  1995/08/14 18:36:43  ceharris
32   Patches to support POP3's LAST command.
33   Final revisions for beta3 release.
34
35   Revision 1.5  1995/08/10 00:32:39  ceharris
36   Preparation for 3.0b3 beta release:
37   -     added code for --kill/--keep, --limit, --protocol, --flush
38         options; --pop2 and --pop3 options now obsoleted by --protocol.
39   -     added support for APOP authentication, including --with-APOP
40         argument for configure.
41   -     provisional and broken support for RPOP
42   -     added buffering to SockGets and SockRead functions.
43   -     fixed problem of command-line options not being correctly
44         carried into the merged options record.
45
46   Revision 1.4  1995/08/09 01:32:56  ceharris
47   Version 3.0 beta 2 release.
48   Added
49   -     .poprc functionality
50   -     GNU long options
51   -     multiple servers on the command line.
52   Fixed
53   -     Passwords showing up in ps output.
54
55   Revision 1.3  1995/08/08 01:01:25  ceharris
56   Added GNU-style long options processing.
57   Fixed password in 'ps' output problem.
58   Fixed various RCS tag blunders.
59   Integrated .poprc parser, lexer, etc into Makefile processing.
60
61  ***********************************************************************/
62
63
64 #include <config.h>
65
66 #include <stdio.h>
67
68 #if defined(STDC_HEADERS)
69 #include <stdlib.h>
70 #include <string.h>
71 #endif
72
73 #if defined(HAVE_UNISTD_H)
74 #include <unistd.h>
75 #endif
76
77 #include <signal.h>
78 #include <pwd.h>
79 #include <errno.h>
80
81 #include <sys/types.h>
82 #include <sys/file.h>
83 #include <sys/wait.h>
84 #include <sys/stat.h>
85 #include <fcntl.h>
86
87 #include "popclient.h"
88
89 /* release info */
90 #define         RELEASE_TAG     "3.0b6"
91
92 #ifdef HAVE_PROTOTYPES
93 /* prototypes for internal functions */
94 int showoptions (struct optrec *options);
95 int parseMDAargs (struct optrec *options);
96 int showversioninfo (void);
97 #endif
98
99 /* Controls the detail of status/progress messages written to stderr */
100 int outlevel;      /* see the O_.* constants in popclient.h */
101
102 /* args for the MDA, parsed out in the usual fashion by parseMDAargs() */
103 #ifdef MDA_ARGS
104 char *mda_argv [MDA_ARGCOUNT + 2];
105 #else
106 char *mda_argv [2];
107 #endif
108
109
110 /*********************************************************************
111   function:      main
112   description:   main driver routine 
113   arguments:     
114     argc         argument count as passed by runtime startup code.
115     argv         argument strings as passed by runtime startup code.
116
117   return value:  an exit status code for the shell -- see the 
118                  PS_.* constants defined above.
119   calls:         parsecmdline, setdefaults, openuserfolder, doPOP2.
120   globals:       none.
121  *********************************************************************/
122
123 main (argc,argv)
124 int argc;
125 char **argv;
126
127   int mboxfd;
128   struct optrec cmd_opts, def_opts, merged_opts;
129   int popstatus;
130   int parsestatus;
131   char *servername; 
132
133   parsestatus = parsecmdline(argc,argv,&cmd_opts);
134   if (parsestatus >= 0) {
135     setoutlevel(&cmd_opts);
136     if (!cmd_opts.versioninfo)
137       if (setdefaults(&def_opts) == 0) {
138         if (prc_parse_file(prc_getpathname(&cmd_opts,&def_opts)) == 0) {
139           while ((servername = getnextserver(argc, argv, &parsestatus)) 
140                  != (char *) 0) {
141             if (outlevel != O_SILENT) 
142               fprintf(stderr, "querying %s\n", servername);
143             else
144               ;
145             prc_mergeoptions(servername, &cmd_opts, &def_opts, &merged_opts);
146             parseMDAargs(&merged_opts);
147             switch (merged_opts.whichpop) {
148               case P_POP2:
149                 popstatus = doPOP2(servername, &merged_opts);
150                 break;
151               case P_POP3:
152               case P_APOP:
153                 popstatus = doPOP3(servername, &merged_opts);
154                 break;
155               default:
156                 fprintf(stderr,"unsupported protocol selected.\n");
157             }
158           }
159         }
160         else
161           popstatus = PS_SYNTAX;
162       } 
163       else
164         popstatus = PS_UNDEFINED;
165     else
166       showversioninfo();
167   }
168   else
169     popstatus = PS_SYNTAX;
170
171   exit(popstatus);
172 }
173     
174
175  
176 /*********************************************************************
177   function:      showversioninfo
178   description:   display program release and compiler info
179   arguments:     none.
180   return value:  none.
181   calls:         none.
182   globals:       none.
183  *********************************************************************/
184
185 int showversioninfo()
186 {
187   printf("popclient release %s\n",RELEASE_TAG);
188 }
189
190
191
192
193 /******************************************************************
194   function:     setoutlevel
195   description:  set output verbosity level.
196   arguments:
197     options     command-line options.
198
199   ret. value:   none.
200   globals:      writes outlevel.
201   calls:        none.
202  *****************************************************************/
203
204 int setoutlevel (options)
205 struct optrec *options;
206 {
207   if (options->verbose) 
208     outlevel = O_VERBOSE;
209   else if (options->silent)
210     outlevel = O_SILENT;
211   else
212     outlevel = O_NORMAL;
213 }
214
215
216
217 /*********************************************************************
218   function:      openuserfolder
219   description:   open the file to which the retrieved messages will
220                  be appended.  Do NOT call when options->foldertype
221                  is OF_SYSMBOX.
222
223   arguments:     
224     options      fully-determined options (i.e. parsed, defaults invoked,
225                  etc).
226
227   return value:  file descriptor for the open file, else -1.
228   calls:         none.
229   globals:       none.
230  *********************************************************************/
231
232 int openuserfolder (options)
233 struct optrec *options;
234 {
235   int fd;
236
237   if (options->foldertype == OF_STDOUT)
238     return(1);
239   else    /* options->foldertype == OF_USERMBOX */
240     if ((fd = open(options->userfolder,O_CREAT|O_WRONLY|O_APPEND,0600)) >= 0) {
241       return(fd);
242     }
243     else {
244       perror("popclient: openuserfolder: open()");
245       return(-1);
246     }
247   
248 }
249
250
251
252 /*********************************************************************
253   function:      openmailpipe
254   description:   open a one-way pipe to the mail delivery agent.
255   arguments:     
256     options      fully-determined options (i.e. parsed, defaults invoked,
257                  etc).
258
259   return value:  open file descriptor for the pipe or -1.
260   calls:         none.
261   globals:       reads mda_argv.
262  *********************************************************************/
263
264 int openmailpipe (options)
265 struct optrec *options;
266 {
267   int pipefd [2];
268   int childpid;
269   char binmailargs [80];
270
271   if (pipe(pipefd) < 0) {
272     perror("popclient: openmailpipe: pipe");
273     return(-1);
274   }
275   if ((childpid = fork()) < 0) {
276     perror("popclient: openmailpipe: fork");
277     return(-1);
278   }
279   else if (childpid == 0) {
280
281     /* in child process space */
282     close(pipefd[1]);  /* close the 'write' end of the pipe */
283     close(0);          /* get rid of inherited stdin */
284     if (dup(pipefd[0]) != 0) {
285       fputs("popclient: openmailpipe: dup() failed\n",stderr);
286       exit(1);
287     }
288
289     execv(MDA_PATH,mda_argv);
290
291     /* if we got here, an error occurred */
292     perror("popclient: openmailpipe: exec");
293     return(-1);
294
295   }
296
297   /* in the parent process space */
298   close(pipefd[0]);  /* close the 'read' end of the pipe */
299   return(pipefd[1]);
300 }
301
302
303
304 /*********************************************************************
305   function:      closeuserfolder
306   description:   close the user-specified mail folder.
307   arguments:     
308     fd           mail folder descriptor.
309
310   return value:  zero if success else -1.
311   calls:         none.
312   globals:       none.
313  *********************************************************************/
314
315 int closeuserfolder(fd)
316 int fd;
317 {
318   int err;
319
320   if (fd != 1) {   /* not stdout */
321     err = close(fd);
322   }   
323   else
324     err = 0;
325   
326   if (err)
327     perror("popclient: closeuserfolder: close");
328
329   return(err);
330 }
331
332
333
334 /*********************************************************************
335   function:      closemailpipe
336   description:   close pipe to the mail delivery agent.
337   arguments:     
338     options      fully-determined options record
339     fd           pipe descriptor.
340
341   return value:  0 if success, else -1.
342   calls:         none.
343   globals:       none.
344  *********************************************************************/
345
346 int closemailpipe (fd)
347 int fd;
348 {
349   int err;
350   int childpid;
351
352   err = close(fd);
353 #if defined(STDC_HEADERS)
354   childpid = wait(NULL);
355 #else
356   childpid = wait((int *) 0);
357 #endif
358   if (err)
359     perror("popclient: closemailpipe: close");
360
361   return(err);
362 }
363
364
365
366 /*********************************************************************
367   function:      parseMDAargs
368   description:   parse the argument string given in MDA_ARGS into
369                  a regular *argv[] array.
370   arguments:
371     options      fully-determined options record pointer.
372
373   return value:  none.
374   calls:         none.
375   globals:       writes mda_argv.
376  *********************************************************************/
377
378 int parseMDAargs (options)
379 struct optrec *options;
380 {
381   int argi;
382   char *argp;
383
384   /* first put the MDA alias in as argv[0] */
385   mda_argv[0] = MDA_ALIAS;
386   
387 #ifdef MDA_ARGS
388
389   /* make a writeable copy of MDA_ARGS */
390   argp = strcpy((char *) malloc(strlen(MDA_ARGS)+1), MDA_ARGS);
391   
392   while (*argp != '\0' && isspace(*argp))       /* skip null first arg */
393     argp++;                                     
394
395   /* now punch nulls into the delimiting whitespace in the args */
396   for (argi = 1;  
397        *argp != '\0';
398        argi++) {
399
400     mda_argv[argi] = argp;     /* store pointer to this argument */
401
402     /* find end of this argument */
403     while (!(*argp == '\0' || isspace(*argp)))
404       argp++;
405
406     /* punch in a null terminator */
407     if (*argp != '\0')
408       *(argp++) = '\0';  
409  
410     /* check for macros */
411     if (strcmp(mda_argv[argi],"$u") == 0)
412       mda_argv[argi] = 
413         strcpy((char *) malloc(strlen(options->loginid)+1),options->loginid);
414     else
415       ;  /* no macros to expand */
416
417   }
418   mda_argv[argi] = (char *) 0;
419
420 #else 
421
422   mda_argv[1] = (char *) 0;
423
424 #endif
425
426 }