]> Pileus Git - ~andy/fetchmail/blob - driver.c
Caching via aka list.
[~andy/fetchmail] / driver.c
1 /*
2  * driver.c -- generic driver for mail fetch method protocols
3  *
4  * Copyright 1996 by Eric S. Raymond
5  * All rights reserved.
6  * For license terms, see the file COPYING in this directory.
7  */
8
9 #include  <config.h>
10 #include  <stdio.h>
11 #include  <setjmp.h>
12 #include  <ctype.h>
13 #include  <string.h>
14 #if defined(STDC_HEADERS)
15 #include  <stdlib.h>
16 #endif
17 #if defined(HAVE_UNISTD_H)
18 #include <unistd.h>
19 #endif
20 #if defined(HAVE_STDARG_H)
21 #include  <stdarg.h>
22 #else
23 #include  <varargs.h>
24 #endif
25 #include  <sys/time.h>
26 #include  <signal.h>
27
28 #ifdef HAVE_GETHOSTBYNAME
29 #include <netdb.h>
30 #include "mx.h"
31 #endif /* HAVE_GETHOSTBYNAME */
32
33 #ifdef KERBEROS_V4
34 #include <krb.h>
35 #include <des.h>
36 #include <netinet/in.h>         /* must be included before "socket.h".*/
37 #include <netdb.h>
38 #endif /* KERBEROS_V4 */
39 #include  "socket.h"
40 #include  "fetchmail.h"
41 #include  "smtp.h"
42
43 #define SMTP_PORT       25      /* standard SMTP service port */
44
45 int batchlimit;         /* how often to tear down the delivery connection */
46 int batchcount;         /* count of messages sent in current batch */
47
48 static const struct method *protocol;
49 static jmp_buf  restart;
50
51 char tag[TAGLEN];
52 static int tagnum;
53 #define GENSYM  (sprintf(tag, "a%04d", ++tagnum), tag)
54
55 static char *shroud;    /* string to shroud in debug output, if  non-NULL */
56 static int mytimeout;   /* value of nonreponse timeout */
57
58 static int strcrlf(dst, src, count)
59 /* replace LFs with CR-LF; return length of string with replacements */
60 char *dst;      /* new string with CR-LFs */
61 char *src;      /* original string with LFs */
62 int count;      /* length of src */
63 {
64   int len = count;
65
66   while (count--)
67   {
68       if (*src == '\n')
69       {
70           *dst++ = '\r';
71           len++;
72       }
73       *dst++ = *src++;
74   }
75   *dst = '\0';
76   return len;
77 }
78
79 static void vtalarm(int timeleft)
80 /* reset the nonresponse-timeout */
81 {
82     struct itimerval ntimeout;
83
84     ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
85     ntimeout.it_value.tv_sec  = timeleft;
86     ntimeout.it_value.tv_usec = 0;
87     setitimer(ITIMER_VIRTUAL, &ntimeout, (struct itimerval *)NULL);
88 }
89
90 static void vtalarm_handler (int signal)
91 /* handle server-timeout SIGVTALARM signal */
92 {
93     longjmp(restart, 1);
94 }
95
96 #ifdef HAVE_RES_SEARCH
97 #define MX_RETRIES      3
98
99 static int is_host_alias(const char *name, struct query *ctl)
100 /* determine whether name is a DNS alias of the hostname */
101 {
102     struct hostent      *he;
103     struct mxentry      *mxp, *mxrecords;
104
105     /*
106      * The first two checks are optimizations that will catch a good
107      * many cases.  First, check against the hostname the user specified.
108      * Odds are good this will either be the mailserver's FQDN or a
109      * suffix of it with the mailserver's domain's default host name
110      * omitted.  Next, check against the mailserver's FQDN, in case
111      * it's not the same as the declared hostname.
112      *
113      * Either of these on a mail address is definitive.  Only if the
114      * name doesn't match either is it time to call the bind library.
115      * If this happens odds are good we're looking at an MX name.
116      */
117     if (strcmp(name, ctl->servername) == 0)
118         return(TRUE);
119     else if (strcmp(name, ctl->canonical_name) == 0)
120         return(TRUE);
121
122     /*
123      * Is it in the `also known as' cache accumulated by previous DNS checks?
124      * This cache may someday be primed by an aka option.
125      */
126     else if (uid_in_list(&ctl->lead_server->aka, name))
127         return(TRUE);
128
129     /*
130      * We know DNS service was up at the beginning of this poll cycle.
131      * If it's down, our nameserver has crashed.  We don't want to try
132      * delivering the current message or anything else from this
133      * mailbox until it's back up.
134      */
135     else if ((he = gethostbyname(name)) != (struct hostent *)NULL)
136     {
137         if (strcmp(ctl->canonical_name, he->h_name) == 0)
138             goto match;
139         else
140             return(FALSE);
141     }
142     else
143         switch (h_errno)
144         {
145         case HOST_NOT_FOUND:    /* specified host is unknown */
146         case NO_ADDRESS:        /* valid, but does not have an IP address */
147             break;
148
149         case NO_RECOVERY:       /* non-recoverable name server error */
150         case TRY_AGAIN:         /* temporary error on authoritative server */
151         default:
152             if (outlevel != O_SILENT)
153                 putchar('\n');  /* terminate the progress message */
154             fprintf(stderr,
155                 "fetchmail: nameserver failure while looking for `%s' during poll of %s.\n",
156                 name, ctl->servername);
157             ctl->errcount++;
158             longjmp(restart, 2);        /* try again next poll cycle */
159             break;
160         }
161
162     /*
163      * We're only here if DNS was OK but the gethostbyname() failed
164      * with a HOST_NOT_FOUND or NO_ADDRESS error.
165      * Search for a name match on MX records pointing to the server.
166      */
167     h_errno = 0;
168     if ((mxrecords = getmxrecords(name)) == (struct mxentry *)NULL)
169         switch (h_errno)
170         {
171         case HOST_NOT_FOUND:    /* specified host is unknown */
172             return(FALSE);
173
174         case NO_ADDRESS:        /* valid, but does not have an IP address */
175             for (mxp = mxrecords; mxp->name; mxp++)
176                 if (strcmp(name, mxp->name) == 0)
177                     goto match;
178             break;
179
180         case NO_RECOVERY:       /* non-recoverable name server error */
181         case TRY_AGAIN:         /* temporary error on authoritative server */
182         default:
183             fprintf(stderr,
184                 "fetchmail: nameserver failure while looking for `%s' during poll of %s.\n",
185                 name, ctl->servername);
186             ctl->errcount++;
187             longjmp(restart, 2);        /* try again next poll cycle */
188             break;
189         }
190
191     return(FALSE);
192
193 match:
194     /* add this name to relevant server's `also known as' list */
195     save_uid(&ctl->lead_server->aka, -1, name);
196     return(TRUE);
197 }
198
199 void find_server_names(hdr, ctl, xmit_names)
200 /* parse names out of a RFC822 header into an ID list */
201 const char *hdr;                /* RFC822 header in question */
202 struct query *ctl;              /* list of permissible aliases */
203 struct idlist **xmit_names;     /* list of recipient names parsed out */
204 {
205     if (hdr == (char *)NULL)
206         return;
207     else
208     {
209         char    *cp, *lname;
210
211         if ((cp = nxtaddr(hdr)) != (char *)NULL)
212             do {
213                 char    *atsign;
214
215                 if ((atsign = strchr(cp, '@')))
216                 {
217                     /*
218                      * Address has an @. Check to see if the right-hand part
219                      * is an alias or MX equivalent of the mailserver.  If it's
220                      * not, skip this name.  If it is, we'll keep going and try
221                      * to find a mapping to a client name.
222                      */
223                     if (!is_host_alias(atsign+1, ctl))
224                         continue;
225                     atsign[0] = '\0';
226                 }
227
228                 lname = idpair_find(&ctl->localnames, cp);
229                 if (lname != (char *)NULL)
230                 {
231                     if (outlevel == O_VERBOSE)
232                         fprintf(stderr,
233                                 "fetchmail: mapped %s to local %s\n",
234                                 cp, lname);
235                     save_uid(xmit_names, -1, lname);
236                 }
237             } while
238                 ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
239     }
240 }
241 #endif /* HAVE_RES_SEARCH */
242
243 static FILE *smtp_open(struct query *ctl)
244 /* try to open a socket to the appropriate SMTP server for this query */ 
245 {
246     ctl = ctl->lead_smtp; /* go to the SMTP leader for this query */
247
248     /* maybe it's time to close the socket in order to force delivery */
249     if (batchlimit && ctl->smtp_sockfp && batchcount++ == batchlimit)
250     {
251         fclose(ctl->smtp_sockfp);
252         ctl->smtp_sockfp = (FILE *)NULL;
253         batchcount = 0;
254     }
255
256     /* if no socket to this host is already set up, try to open one */
257     if (ctl->smtp_sockfp == (FILE *)NULL)
258     {
259         if ((ctl->smtp_sockfp = Socket(ctl->smtphost, SMTP_PORT)) == (FILE *)NULL)
260             return((FILE *)NULL);
261         else if (SMTP_ok(ctl->smtp_sockfp) != SM_OK
262                  || SMTP_helo(ctl->smtp_sockfp, ctl->servername) != SM_OK)
263         {
264             fclose(ctl->smtp_sockfp);
265             ctl->smtp_sockfp = (FILE *)NULL;
266         }
267     }
268
269     return(ctl->smtp_sockfp);
270 }
271
272 static int gen_readmsg (sockfp, len, delimited, ctl)
273 /* read message content and ship to SMTP or MDA */
274 FILE *sockfp;           /* to which the server is connected */
275 long len;               /* length of message */
276 int delimited;          /* does the protocol use a message delimiter? */
277 struct query *ctl;      /* query control record */
278 {
279     char buf [MSGBUFSIZE+1]; 
280     char *bufp, *headers, *fromhdr, *tohdr, *cchdr, *bcchdr, *received_for;
281     int n, oldlen, mboxfd;
282     int inheaders,lines,sizeticker;
283     FILE *sinkfp;
284 #ifdef HAVE_GETHOSTBYNAME
285     char rbuf[HOSTLEN + USERNAMELEN + 4]; 
286 #endif /* HAVE_GETHOSTBYNAME */
287
288     /* read the message content from the server */
289     inheaders = 1;
290     headers = fromhdr = tohdr = cchdr = bcchdr = received_for = NULL;
291     lines = 0;
292     sizeticker = 0;
293     oldlen = 0;
294     while (delimited || len > 0)
295     {
296         if ((n = SockGets(buf,sizeof(buf),sockfp)) < 0)
297             return(PS_SOCKET);
298         vtalarm(ctl->timeout);
299
300         /* write the message size dots */
301         if (n > 0)
302         {
303             sizeticker += n;
304             while (sizeticker >= SIZETICKER)
305             {
306                 if (outlevel > O_SILENT)
307                     fputc('.',stderr);
308                 sizeticker -= SIZETICKER;
309             }
310         }
311         len -= n;
312         bufp = buf;
313         if (buf[0] == '\0' || buf[0] == '\r' || buf[0] == '\n')
314             inheaders = 0;
315         if (delimited && *bufp == '.') {
316             bufp++;
317             if (*bufp == 0)
318                 break;  /* end of message */
319         }
320         strcat(bufp, "\n");
321      
322         if (inheaders)
323         {
324             if (!ctl->norewrite)
325                 reply_hack(bufp, ctl->servername);
326
327             if (!lines)
328             {
329                 oldlen = strlen(bufp);
330                 headers = xmalloc(oldlen + 1);
331                 (void) strcpy(headers, bufp);
332                 bufp = headers;
333             }
334             else
335             {
336                 int     newlen;
337
338                 /*
339                  * We deal with RFC822 continuation lines here.
340                  * Replace previous '\n' with '\r' so nxtaddr 
341                  * and reply_hack will be able to see past it.
342                  * (We know this is safe because SocketGets stripped
343                  * out all carriage returns in the read loop above
344                  * and we haven't reintroduced any since then.)
345                  * We'll undo this before writing the header.
346                  */
347                 if (isspace(bufp[0]))
348                     headers[oldlen-1] = '\r';
349
350                 newlen = oldlen + strlen(bufp);
351                 headers = realloc(headers, newlen + 1);
352                 if (headers == NULL)
353                     return(PS_IOERR);
354                 strcpy(headers + oldlen, bufp);
355                 bufp = headers + oldlen;
356                 oldlen = newlen;
357             }
358
359             if (!strncasecmp("From:", bufp, 5))
360                 fromhdr = bufp;
361             else if (!fromhdr && !strncasecmp("Resent-From:", bufp, 12))
362                 fromhdr = bufp;
363             else if (!fromhdr && !strncasecmp("Apparently-From:", bufp, 16))
364                 fromhdr = bufp;
365             else if (!strncasecmp("To:", bufp, 3))
366                 tohdr = bufp;
367             else if (!strncasecmp("Apparently-To:", bufp, 14))
368                 tohdr = bufp;
369             else if (!strncasecmp("Cc:", bufp, 3))
370                 cchdr = bufp;
371             else if (!strncasecmp("Bcc:", bufp, 4))
372                 bcchdr = bufp;
373 #ifdef HAVE_GETHOSTBYNAME
374             else if (MULTIDROP(ctl) && !strncasecmp("Received:", bufp, 9))
375             {
376                 char *ok;
377
378                 /*
379                  * Try to extract the real envelope addressee.  We look here
380                  * specifically for the mailserver's Received line.
381                  * Note: this will only work for sendmail, or an MTA that
382                  * shares sendmail's convention of embedding the envelope
383                  * address in the Received line.
384                  */
385                 strcpy(rbuf, "by ");
386                 strcat(rbuf, ctl->canonical_name);
387                 if ((ok = strstr(bufp, rbuf)))
388                     ok = strstr(ok, "for <");
389                 else
390                     ok = (char *)NULL;
391                 if (ok)
392                 {
393                     char        *sp, *tp;
394
395                     tp = rbuf;
396                     for (sp = ok + 5; *sp && *sp != '>' && *sp != '@'; sp++)
397                         *tp++ = *sp;
398                     *tp = '\0';
399                     if (*sp != ';' && *sp != '@')
400                         ok = (char *)NULL;
401                 }
402
403                 if (ok)
404                 {
405                     received_for = alloca(strlen(rbuf)+1);
406                     strcpy(received_for, rbuf);
407                     if (outlevel == O_VERBOSE)
408                         fprintf(stderr, 
409                                 "fetchmail: found Received address `%s'\n",
410                                 received_for);
411                 }
412             }
413 #endif /* HAVE_GETHOSTBYNAME */
414
415             goto skipwrite;
416         }
417         else if (headers)       /* OK, we're at end of headers now */
418         {
419             char                *cp;
420             struct idlist       *idp, *xmit_names;
421             int                 good_addresses, bad_addresses;
422 #ifdef HAVE_RES_SEARCH
423             int                 no_local_matches = FALSE;
424 #endif /* HAVE_RES_SEARCH */
425
426             /* cons up a list of local recipients */
427             xmit_names = (struct idlist *)NULL;
428             bad_addresses = good_addresses = 0;
429 #ifdef HAVE_RES_SEARCH
430             /* is this a multidrop box? */
431             if (MULTIDROP(ctl))
432             {
433                 if (received_for)
434                     /*
435                      * We have the actual envelope addressee.  
436                      * It has to be a mailserver address, or we
437                      * wouldn't have got here.
438                      */
439                     find_server_names(received_for, ctl, &xmit_names);
440                 else
441                 {
442                     /*
443                      * We haven't extracted the envelope address.
444                      * So check all the header addresses.
445                      */
446                     find_server_names(tohdr,  ctl, &xmit_names);
447                     find_server_names(cchdr,  ctl, &xmit_names);
448                     find_server_names(bcchdr, ctl, &xmit_names);
449                 }
450                 if (!xmit_names)
451                 {
452                     no_local_matches = TRUE;
453                     save_uid(&xmit_names, -1, user);
454                     if (outlevel == O_VERBOSE)
455                         fprintf(stderr, 
456                                 "fetchmail: no local matches, forwarding to %s\n",
457                                 user);
458                 }
459             }
460             else        /* it's a single-drop box, use first localname */
461 #endif /* HAVE_RES_SEARCH */
462                 save_uid(&xmit_names, -1, ctl->localnames->id);
463
464             /* time to address the message */
465             if (ctl->mda[0])    /* we have a declared MDA */
466             {
467                 int     i, nlocals = 0;
468                 char    **sargv, **sp;
469
470                 /*
471                  * We go through this in order to be able to handle very
472                  * long lists of users and (re)implement %s.
473                  */
474                 for (idp = xmit_names; idp; idp = idp->next)
475                     nlocals++;
476                 sp = sargv = (char **)alloca(sizeof(char **) * ctl->mda_argcount+nlocals+2);
477                 for (i = 0; i < ctl->mda_argcount; i++)
478                     if (strcmp("%s", ctl->mda_argv[i]))
479                         *sp++ = ctl->mda_argv[i];
480                     else
481                         for (idp = xmit_names; idp; idp = idp->next)
482                             *sp++ = idp->id;
483                 *sp =  (char *)NULL;
484
485 #ifdef HAVE_SETEUID
486                 /*
487                  * Arrange to run with user's permissions if we're root.
488                  * This will initialize the ownership of any files the
489                  * MDA creates properly.  (The seteuid call is available
490                  * under all BSDs and Linux)
491                  */
492                 seteuid(ctl->uid);
493 #endif /* HAVE_SETEUID */
494
495                 mboxfd = openmailpipe(sargv);
496
497 #ifdef HAVE_SETEUID
498                 /* this will fail quietly if we didn't start as root */
499                 seteuid(0);
500 #endif /* HAVE_SETEUID */
501
502                 if (mboxfd < 0)
503                 {
504                     fprintf(stderr, "fetchmail: MDA open failed\n");
505                     return(PS_IOERR);
506                 }
507             }
508             else
509             {
510                 char    *ap;
511
512                 /* build a connection to the SMTP listener */
513                 if (ctl->mda[0] == '\0' && ((sinkfp = smtp_open(ctl)) == NULL))
514                 {
515                     free_uid_list(&xmit_names);
516                     fprintf(stderr, "fetchmail: SMTP connect failed\n");
517                     return(PS_SMTP);
518                 }
519
520                 /*
521                  * Try to get the SMTP listener to take the header
522                  * From address as MAIL FROM (this makes the logging
523                  * nicer).  If it won't, fall back on the calling-user
524                  * ID.  This won't affect replies, which use the header
525                  * From address anyway.
526                  */
527                 if (!fromhdr || !(ap = nxtaddr(fromhdr)) 
528                                         || SMTP_from(sinkfp, ap) != SM_OK)
529                     if (SMTP_from(sinkfp, user) != SM_OK)
530                         return(PS_SMTP);        /* should never happen */
531
532                 /* now list the recipient addressees */
533                 for (idp = xmit_names; idp; idp = idp->next)
534                     if (SMTP_rcpt(sinkfp, idp->id) == SM_OK)
535                         good_addresses++;
536                     else
537                     {
538                         bad_addresses++;
539                         idp->val.num = 0;
540                         fprintf(stderr, 
541                                 "fetchmail: SMTP listener doesn't like recipient address `%s'\n", idp->id);
542                     }
543                 if (!good_addresses && SMTP_rcpt(sinkfp, user) != SM_OK)
544                 {
545                     fprintf(stderr, 
546                             "fetchmail: can't even send to calling user!\n");
547                     return(PS_SMTP);
548                 }
549
550                 /* tell it we're ready to send data */
551                 SMTP_data(sinkfp);
552                 if (outlevel == O_VERBOSE)
553                     fputs("SMTP> ", stderr);
554             }
555
556             /* change continuation markers back to regular newlines */
557             for (cp = headers; cp < headers + oldlen; cp++)
558                 if (*cp == '\r')
559                     *cp = '\n';
560
561             /* replace all LFs with CR-LF before sending to the SMTP server */
562             if (!ctl->mda[0])
563             {
564                 char *newheaders = xmalloc(1 + oldlen * 2);
565
566                 oldlen = strcrlf(newheaders, headers, oldlen);
567                 free(headers);
568                 headers = newheaders;
569             }
570
571             /* write all the headers */
572             if (ctl->mda[0])
573                 n = write(mboxfd,headers,oldlen);
574             else
575                 n = SockWrite(headers, oldlen, sinkfp);
576
577             if (n < 0)
578             {
579                 free(headers);
580                 headers = NULL;
581                 perror("fetchmail: writing RFC822 headers");
582                 return(PS_IOERR);
583             }
584             else if (outlevel == O_VERBOSE)
585                 fputs("#", stderr);
586             free(headers);
587             headers = NULL;
588
589             /* write error notifications */
590 #ifdef HAVE_RES_SEARCH
591             if (no_local_matches || bad_addresses)
592 #else
593             if (bad_addresses)
594 #endif /* HAVE_RES_SEARCH */
595             {
596                 int     errlen = 0;
597                 char    errhd[USERNAMELEN + POPBUFSIZE], *errmsg;
598
599                 errmsg = errhd;
600                 (void) strcpy(errhd, "X-Fetchmail-Warning: ");
601 #ifdef HAVE_RES_SEARCH
602                 if (no_local_matches)
603                 {
604                     strcat(errhd, "no recipient addresses matched declared local names");
605                     if (bad_addresses)
606                         strcat(errhd, "; ");
607                 }
608 #endif /* HAVE_RES_SEARCH */
609
610                 if (bad_addresses)
611                 {
612                     strcat(errhd, "SMTP listener rejected local recipient addresses: ");
613                     errlen = strlen(errhd);
614                     for (idp = xmit_names; idp; idp = idp->next)
615                         if (!idp->val.num)
616                             errlen += strlen(idp->id) + 2;
617
618                     errmsg = alloca(errlen+3);
619                     (void) strcpy(errmsg, errhd);
620                     for (idp = xmit_names; idp; idp = idp->next)
621                         if (!idp->val.num)
622                         {
623                             strcat(errmsg, idp->id);
624                             if (idp->next)
625                                 strcat(errmsg, ", ");
626                         }
627                 }
628
629                 strcat(errmsg, "\n");
630
631                 if (ctl->mda[0])
632                     write(mboxfd, errmsg, strlen(errmsg));
633                 else
634                     SockWrite(errmsg, strlen(errmsg), sinkfp);
635             }
636
637             free_uid_list(&xmit_names);
638         }
639
640         /* SMTP byte-stuffing */
641         if (*bufp == '.' && ctl->mda[0] == 0)
642             SockWrite(".", 1, sinkfp);
643
644         /* replace all LFs with CR-LF  in the line */
645         if (!ctl->mda[0])
646         {
647             char *newbufp = xmalloc(1 + strlen(bufp) * 2);
648
649             strcrlf(newbufp, bufp, strlen(bufp));
650             bufp = newbufp;
651         }
652
653         /* ship out the text line */
654         if (ctl->mda[0])
655             n = write(mboxfd,bufp,strlen(bufp));
656         else
657             n = SockWrite(bufp, strlen(bufp), sinkfp);
658
659         if (!ctl->mda[0])
660             free(bufp);
661         if (n < 0)
662         {
663             perror("fetchmail: writing message text");
664             return(PS_IOERR);
665         }
666         else if (outlevel == O_VERBOSE)
667             fputc('*', stderr);
668
669     skipwrite:;
670         lines++;
671     }
672
673     if (ctl->mda[0])
674     {
675         /* close the delivery pipe, we'll reopen before next message */
676         if (closemailpipe(mboxfd))
677             return(PS_IOERR);
678     }
679     else
680     {
681         /* write message terminator */
682         if (SMTP_eom(sinkfp) != SM_OK)
683         {
684             fputs("fetchmail: SMTP listener refused delivery\n", stderr);
685             return(PS_SMTP);
686         }
687     }
688
689     return(0);
690 }
691
692 #ifdef KERBEROS_V4
693 int
694 kerberos_auth (socket, canonical) 
695 /* authenticate to the server host using Kerberos V4 */
696 int socket;             /* socket to server host */
697 const char *canonical;  /* server name */
698 {
699     char * host_primary;
700     KTEXT ticket;
701     MSG_DAT msg_data;
702     CREDENTIALS cred;
703     Key_schedule schedule;
704     int rem;
705   
706     ticket = ((KTEXT) (malloc (sizeof (KTEXT_ST))));
707     rem = (krb_sendauth (0L, socket, ticket, "pop",
708                          canonical,
709                          ((char *) (krb_realmofhost (canonical))),
710                          ((unsigned long) 0),
711                          (&msg_data),
712                          (&cred),
713                          (schedule),
714                          ((struct sockaddr_in *) 0),
715                          ((struct sockaddr_in *) 0),
716                          "KPOPV0.1"));
717     free (ticket);
718     if (rem != KSUCCESS)
719     {
720         fprintf (stderr, "fetchmail: kerberos error %s\n", (krb_get_err_text (rem)));
721         return (PS_ERROR);
722     }
723     return (0);
724 }
725 #endif /* KERBEROS_V4 */
726
727 int do_protocol(ctl, proto)
728 /* retrieve messages from server using given protocol method table */
729 struct query *ctl;              /* parsed options with merged-in defaults */
730 const struct method *proto;     /* protocol method table */
731 {
732     int ok, js;
733     void (*sigsave)();
734
735 #ifndef KERBEROS_V4
736     if (ctl->authenticate == A_KERBEROS)
737     {
738         fputs("fetchmail: Kerberos support not linked.\n", stderr);
739         return(PS_ERROR);
740     }
741 #endif /* KERBEROS_V4 */
742
743     /* lacking methods, there are some options that may fail */
744     if (!proto->is_old)
745     {
746         /* check for unsupported options */
747         if (ctl->flush) {
748             fprintf(stderr,
749                     "Option --flush is not supported with %s\n",
750                     proto->name);
751             return(PS_SYNTAX);
752         }
753         else if (ctl->fetchall) {
754             fprintf(stderr,
755                     "Option --all is not supported with %s\n",
756                     proto->name);
757             return(PS_SYNTAX);
758         }
759     }
760     if (!proto->getsizes && ctl->limit)
761     {
762         fprintf(stderr,
763                 "Option --limit is not supported with %s\n",
764                 proto->name);
765         return(PS_SYNTAX);
766     }
767
768     protocol = proto;
769     tagnum = 0;
770     tag[0] = '\0';      /* nuke any tag hanging out from previous query */
771     ok = 0;
772
773     /* set up the server-nonresponse timeout */
774     sigsave = signal(SIGVTALRM, vtalarm_handler);
775     vtalarm(mytimeout = ctl->timeout);
776
777     if ((js = setjmp(restart)) == 1)
778     {
779         fprintf(stderr,
780                 "fetchmail: timeout after %d seconds waiting for %s.\n",
781                 ctl->timeout, ctl->servername);
782         ok = PS_ERROR;
783     }
784     else if (js == 2)
785     {
786         /* error message printed at point of longjmp */
787         ok = PS_ERROR;
788     }
789     else
790     {
791         char buf [POPBUFSIZE+1];
792         int *msgsizes, len, num, count, new, deletions = 0;
793         FILE *sockfp;
794
795         /* open a socket to the mail server */
796         if ((sockfp = Socket(ctl->servername,
797                              ctl->port ? ctl->port : protocol->port)) == NULL)
798         {
799             perror("fetchmail, connecting to host");
800             ok = PS_SOCKET;
801             goto closeUp;
802         }
803
804 #ifdef KERBEROS_V4
805         if (ctl->authenticate == A_KERBEROS)
806         {
807             ok = (kerberos_auth (fileno(sockfp), ctl->canonical_name));
808             vtalarm(ctl->timeout);
809             if (ok != 0)
810                 goto cleanUp;
811         }
812 #endif /* KERBEROS_V4 */
813
814         /* accept greeting message from mail server */
815         ok = (protocol->parse_response)(sockfp, buf);
816         vtalarm(ctl->timeout);
817         if (ok != 0)
818             goto cleanUp;
819
820         /* try to get authorized to fetch mail */
821         shroud = ctl->password;
822         ok = (protocol->getauth)(sockfp, ctl, buf);
823         vtalarm(ctl->timeout);
824         shroud = (char *)NULL;
825         if (ok == PS_ERROR)
826             ok = PS_AUTHFAIL;
827         if (ok != 0)
828             goto cleanUp;
829
830         /* compute number of messages and number of new messages waiting */
831         if ((protocol->getrange)(sockfp, ctl, &count, &new) != 0)
832             goto cleanUp;
833         vtalarm(ctl->timeout);
834
835         /* show user how many messages we downloaded */
836         if (outlevel > O_SILENT)
837             if (count == 0)
838                 fprintf(stderr, "No mail from %s@%s\n", 
839                         ctl->remotename,
840                         ctl->servername);
841             else
842             {
843                 fprintf(stderr, "%d message%s", count, count > 1 ? "s" : ""); 
844                 if (new != -1 && (count - new) > 0)
845                     fprintf(stderr, " (%d seen)", count-new);
846                 fprintf(stderr,
847                         " from %s@%s.\n",
848                         ctl->remotename,
849                         ctl->servername);
850             }
851
852         /* we may need to get sizes in order to check message limits */
853         msgsizes = (int *)NULL;
854         if (!ctl->fetchall && proto->getsizes && ctl->limit)
855         {
856             msgsizes = (int *)alloca(sizeof(int) * count);
857
858             if ((ok = (proto->getsizes)(sockfp, count, msgsizes)) != 0)
859                 return(PS_ERROR);
860         }
861
862
863         if (check_only)
864         {
865             if (new == -1 || ctl->fetchall)
866                 new = count;
867             ok = ((new > 0) ? PS_SUCCESS : PS_NOMAIL);
868             goto closeUp;
869         }
870         else if (count > 0)
871         {    
872             /*
873              * What forces this code is that in POP3 you can't fetch a
874              * message without having it marked `seen'.
875              *
876              * The result is that if there's any kind of transient error
877              * (DNS lookup failure, or sendmail refusing delivery due to
878              * process-table limits) the message will be marked "seen" on
879              * the server without having been delivered.  This is not a
880              * big problem if fetchmail is running in foreground, because
881              * the user will see a "skipped" message when it next runs and
882              * get clued in.
883              *
884              * But in daemon mode this leads to the message being silently
885              * ignored forever.  This is not acceptable.
886              *
887              * We compensate for this by checking the error count from the 
888              * previous pass and forcing all messages to be considered new
889              * if it's nonzero.
890              */
891             int force_retrieval = (ctl->errcount > 0);
892
893             ctl->errcount = 0;
894
895             /* read, forward, and delete messages */
896             for (num = 1; num <= count; num++)
897             {
898                 int     toolarge = msgsizes && (msgsizes[num-1] > ctl->limit);
899                 int     fetch_it = ctl->fetchall ||
900                     (!toolarge && (force_retrieval || !(protocol->is_old && (protocol->is_old)(sockfp,ctl,num))));
901
902                 /* we may want to reject this message if it's old */
903                 if (!fetch_it)
904                 {
905                     if (outlevel > O_SILENT)
906                     {
907                         fprintf(stderr, "skipping message %d", num);
908                         if (toolarge)
909                             fprintf(stderr, " (oversized, %d bytes)", msgsizes[num-1]);
910                     }
911                 }
912                 else
913                 {
914                     /* request a message */
915                     (protocol->fetch)(sockfp, num, &len);
916                     vtalarm(ctl->timeout);
917
918                     if (outlevel > O_SILENT)
919                     {
920                         fprintf(stderr, "reading message %d", num);
921                         if (len > 0)
922                             fprintf(stderr, " (%d bytes)", len);
923                         if (outlevel == O_VERBOSE)
924                             fputc('\n', stderr);
925                         else
926                             fputc(' ', stderr);
927                     }
928
929                     /* read the message and ship it to the output sink */
930                     ok = gen_readmsg(sockfp,
931                                      len, 
932                                      protocol->delimited,
933                                      ctl);
934                     vtalarm(ctl->timeout);
935                     if (ok != 0)
936                         goto cleanUp;
937
938                     /* tell the server we got it OK and resynchronize */
939                     if (protocol->trail)
940                         (protocol->trail)(sockfp, ctl, num);
941                 }
942
943                 /*
944                  * At this point in flow of control, either we've bombed
945                  * on a protocol error or had delivery refused by the SMTP
946                  * server (unlikely -- I've never seen it) or we've seen
947                  * `accepted for delivery' and the message is shipped.
948                  * It's safe to mark the message seen and delete it on the
949                  * server now.
950                  */
951
952                 /* maybe we delete this message now? */
953                 if (protocol->delete
954                     && (fetch_it ? !ctl->keep : ctl->flush))
955                 {
956                     deletions++;
957                     if (outlevel > O_SILENT) 
958                         fprintf(stderr, " flushed\n");
959                     ok = (protocol->delete)(sockfp, ctl, num);
960                     vtalarm(ctl->timeout);
961                     if (ok != 0)
962                         goto cleanUp;
963                     delete_uid(&ctl->newsaved, num);
964                 }
965                 else if (outlevel > O_SILENT) 
966                     fprintf(stderr, " not flushed\n");
967             }
968
969             /* remove all messages flagged for deletion */
970             if (protocol->expunge_cmd && deletions > 0)
971             {
972                 ok = gen_transact(sockfp, protocol->expunge_cmd);
973                 if (ok != 0)
974                     goto cleanUp;
975             }
976
977             ok = gen_transact(sockfp, protocol->exit_cmd);
978             if (ok == 0)
979                 ok = PS_SUCCESS;
980             fclose(sockfp);
981             goto closeUp;
982         }
983         else {
984             ok = gen_transact(sockfp, protocol->exit_cmd);
985             if (ok == 0)
986                 ok = PS_NOMAIL;
987             fclose(sockfp);
988             goto closeUp;
989         }
990
991     cleanUp:
992         if (ok != 0 && ok != PS_SOCKET)
993         {
994             gen_transact(sockfp, protocol->exit_cmd);
995             fclose(sockfp);
996         }
997     }
998
999     switch (ok)
1000     {
1001     case PS_SOCKET:
1002         fputs("fetchmail: socket", stderr);
1003         break;
1004     case PS_AUTHFAIL:
1005         fputs("fetchmail: authorization", stderr);
1006         break;
1007     case PS_SYNTAX:
1008         fputs("fetchmail: missing or bad RFC822 header", stderr);
1009         break;
1010     case PS_IOERR:
1011         fputs("fetchmail: MDA", stderr);
1012         break;
1013     case PS_ERROR:
1014         fputs("fetchmail: client/server synchronization", stderr);
1015         break;
1016     case PS_PROTOCOL:
1017         fputs("fetchmail: client/server protocol", stderr);
1018         break;
1019     case PS_SMTP:
1020         fputs("fetchmail: SMTP transaction", stderr);
1021         break;
1022     case PS_UNDEFINED:
1023         fputs("fetchmail: undefined", stderr);
1024         break;
1025     }
1026     if (ok==PS_SOCKET || ok==PS_AUTHFAIL || ok==PS_SYNTAX || ok==PS_IOERR
1027                 || ok==PS_ERROR || ok==PS_PROTOCOL || ok==PS_SMTP)
1028         fprintf(stderr, " error while talking to %s\n", ctl->servername);
1029
1030 closeUp:
1031     signal(SIGVTALRM, sigsave);
1032     return(ok);
1033 }
1034
1035 #if defined(HAVE_STDARG_H)
1036 void gen_send(FILE *sockfp, char *fmt, ... )
1037 /* assemble command in printf(3) style and send to the server */
1038 {
1039 #else
1040 void gen_send(sockfp, fmt, va_alist)
1041 /* assemble command in printf(3) style and send to the server */
1042 FILE *sockfp;           /* socket to which server is connected */
1043 const char *fmt;        /* printf-style format */
1044 va_dcl {
1045 #endif
1046
1047     char buf [POPBUFSIZE+1];
1048     va_list ap;
1049
1050     if (protocol->tagged)
1051         (void) sprintf(buf, "%s ", GENSYM);
1052     else
1053         buf[0] = '\0';
1054
1055 #if defined(HAVE_STDARG_H)
1056     va_start(ap, fmt) ;
1057 #else
1058     va_start(ap);
1059 #endif
1060     vsprintf(buf + strlen(buf), fmt, ap);
1061     va_end(ap);
1062
1063     strcat(buf, "\r\n");
1064     SockWrite(buf, strlen(buf), sockfp);
1065
1066     if (outlevel == O_VERBOSE)
1067     {
1068         char *cp;
1069
1070         if (shroud && (cp = strstr(buf, shroud)))
1071             memset(cp, '*', strlen(shroud));
1072         fprintf(stderr,"> %s", buf);
1073     }
1074 }
1075
1076 #if defined(HAVE_STDARG_H)
1077 int gen_transact(FILE *sockfp, char *fmt, ... )
1078 /* assemble command in printf(3) style, send to server, accept a response */
1079 {
1080 #else
1081 int gen_transact(sockfp, fmt, va_alist)
1082 /* assemble command in printf(3) style, send to server, accept a response */
1083 FILE *sockfp;           /* socket to which server is connected */
1084 const char *fmt;        /* printf-style format */
1085 va_dcl {
1086 #endif
1087
1088   int ok;
1089   char buf [POPBUFSIZE+1];
1090   va_list ap;
1091
1092   if (protocol->tagged)
1093       (void) sprintf(buf, "%s ", GENSYM);
1094   else
1095       buf[0] = '\0';
1096
1097 #if defined(HAVE_STDARG_H)
1098   va_start(ap, fmt) ;
1099 #else
1100   va_start(ap);
1101 #endif
1102   vsprintf(buf + strlen(buf), fmt, ap);
1103   va_end(ap);
1104
1105   strcat(buf, "\r\n");
1106   SockWrite(buf, strlen(buf), sockfp);
1107   if (outlevel == O_VERBOSE)
1108   {
1109       char *cp;
1110
1111       if (shroud && (cp = strstr(buf, shroud)))
1112           memset(cp, '*', strlen(shroud));
1113       fprintf(stderr,"> %s", buf);
1114   }
1115
1116   /* we presume this does its own response echoing */
1117   ok = (protocol->parse_response)(sockfp, buf);
1118   vtalarm(mytimeout);
1119
1120   return(ok);
1121 }
1122
1123 /* driver.c ends here */