]> Pileus Git - ~andy/fetchmail/blob - driver.c
Various minor fixes.
[~andy/fetchmail] / driver.c
1 /*
2  * driver.c -- generic driver for mail fetch method protocols
3  *
4  * Copyright 1997 by Eric S. Raymond
5  * For license terms, see the file COPYING in this directory.
6  */
7
8 #include  "config.h"
9 #include  <stdio.h>
10 #include  <setjmp.h>
11 #include  <errno.h>
12 #include  <ctype.h>
13 #include  <string.h>
14 #ifdef HAVE_MEMORY_H
15 #include  <memory.h>
16 #endif /* HAVE_MEMORY_H */
17 #if defined(STDC_HEADERS)
18 #include  <stdlib.h>
19 #endif
20 #if defined(HAVE_UNISTD_H)
21 #include <unistd.h>
22 #endif
23 #if defined(HAVE_STDARG_H)
24 #include  <stdarg.h>
25 #else
26 #include  <varargs.h>
27 #endif
28 #if defined(HAVE_SYS_ITIMER_H)
29 #include <sys/itimer.h>
30 #endif
31 #include  <sys/time.h>
32 #include  <signal.h>
33
34 #ifdef HAVE_RES_SEARCH
35 #include <netdb.h>
36 #include "mx.h"
37 #endif /* HAVE_RES_SEARCH */
38
39 #ifdef KERBEROS_V4
40 #ifdef KERBEROS_V5
41 #include <kerberosIV/des.h>
42 #include <kerberosIV/krb.h>
43 #else
44 #if defined (__bsdi__)
45 #include <des.h> /* order of includes matters */
46 #include <krb.h>
47 #define krb_get_err_text(e) (krb_err_txt[e])
48 #else
49 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__)
50 #define krb_get_err_text(e) (krb_err_txt[e])
51 #include <krb.h>
52 #include <des.h>
53 #else
54 #include <krb.h>
55 #include <des.h>
56 #endif /* ! defined (__FreeBSD__) */
57 #endif /* ! defined (__bsdi__) */
58 #endif /* KERBEROS_V5 */
59 #include <netinet/in.h>
60 #include <netdb.h>
61 #endif /* KERBEROS_V4 */
62 #ifdef KERBEROS_V5
63 #include <krb5.h>
64 #include <com_err.h>
65 #endif /* KERBEROS_V5 */
66 #include "i18n.h"
67
68 #include "socket.h"
69 #include "fetchmail.h"
70 #include "tunable.h"
71
72 /* throw types for runtime errors */
73 #define THROW_TIMEOUT   1               /* server timed out */
74 #define THROW_SIGPIPE   2               /* SIGPIPE on stream socket */
75
76 #ifndef strstr          /* glibc-2.1 declares this as a macro */
77 extern char *strstr();  /* needed on sysV68 R3V7.1. */
78 #endif /* strstr */
79
80 int batchcount;         /* count of messages sent in current batch */
81 flag peek_capable;      /* can we peek for better error recovery? */
82 int pass;               /* how many times have we re-polled? */
83 int phase;              /* where are we, for error-logging purposes? */
84
85 static const struct method *protocol;
86 static jmp_buf  restart;
87
88 char tag[TAGLEN];
89 static int tagnum;
90 #define GENSYM  (sprintf(tag, "A%04d", ++tagnum % TAGMOD), tag)
91
92 static char shroud[PASSWORDLEN];        /* string to shroud in debug output */
93 static int mytimeout;                   /* value of nonreponse timeout */
94 static int timeoutcount;                /* count consecutive timeouts */
95 static int msglen;                      /* actual message length */
96
97 void set_timeout(int timeleft)
98 /* reset the nonresponse-timeout */
99 {
100 #ifndef __EMX__
101     struct itimerval ntimeout;
102
103     if (timeleft == 0)
104         timeoutcount = 0;
105
106     ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
107     ntimeout.it_value.tv_sec  = timeleft;
108     ntimeout.it_value.tv_usec = 0;
109     setitimer(ITIMER_REAL, &ntimeout, (struct itimerval *)NULL);
110 #endif
111 }
112
113 static void timeout_handler (int signal)
114 /* handle SIGALRM signal indicating a server timeout */
115 {
116     timeoutcount++;
117     longjmp(restart, THROW_TIMEOUT);
118 }
119
120 static void sigpipe_handler (int signal)
121 /* handle SIGPIPE signal indicating a broken stream socket */
122 {
123     longjmp(restart, THROW_SIGPIPE);
124 }
125
126 static int accept_count, reject_count;
127
128 static void map_name(const char *name, struct query *ctl, struct idlist **xmit_names)
129 /* add given name to xmit_names if it matches declared localnames */
130 /*   name:       name to map */
131 /*   ctl:        list of permissible aliases */
132 /*   xmit_names: list of recipient names parsed out */
133 {
134     const char  *lname;
135     int off = 0;
136     
137     lname = idpair_find(&ctl->localnames, name+off);
138     if (!lname && ctl->wildcard)
139         lname = name+off;
140
141     if (lname != (char *)NULL)
142     {
143         if (outlevel >= O_DEBUG)
144             report(stdout, _("mapped %s to local %s\n"), name, lname);
145         save_str(xmit_names, lname, XMIT_ACCEPT);
146         accept_count++;
147     }
148 }
149
150 static void find_server_names(const char *hdr,
151                               struct query *ctl,
152                               struct idlist **xmit_names)
153 /* parse names out of a RFC822 header into an ID list */
154 /*   hdr:               RFC822 header in question */
155 /*   ctl:               list of permissible aliases */
156 /*   xmit_names:        list of recipient names parsed out */
157 {
158     if (hdr == (char *)NULL)
159         return;
160     else
161     {
162         char    *cp;
163
164         for (cp = nxtaddr(hdr);
165              cp != NULL;
166              cp = nxtaddr(NULL))
167         {
168             char        *atsign;
169
170             /*
171              * If the name of the user begins with a qmail virtual
172              * domain prefix, ignore the prefix.  Doing this here
173              * means qvirtual will work either with ordinary name
174              * mapping or with a localdomains option.
175              */
176             if (ctl->server.qvirtual)
177             {
178                 int sl = strlen(ctl->server.qvirtual);
179  
180                 if (!strncasecmp(cp, ctl->server.qvirtual, sl))
181                     cp += sl;
182             }
183
184             if ((atsign = strchr(cp, '@'))) {
185                 struct idlist   *idp;
186
187                 /*
188                  * Does a trailing segment of the hostname match something
189                  * on the localdomains list?  If so, save the whole name
190                  * and keep going.
191                  */
192                 for (idp = ctl->server.localdomains; idp; idp = idp->next) {
193                     char        *rhs;
194
195                     rhs = atsign + (strlen(atsign) - strlen(idp->id));
196                     if (rhs > atsign &&
197                         (rhs[-1] == '.' || rhs[-1] == '@') &&
198                         strcasecmp(rhs, idp->id) == 0)
199                     {
200                         if (outlevel >= O_DEBUG)
201                             report(stdout, _("passed through %s matching %s\n"), 
202                                   cp, idp->id);
203                         save_str(xmit_names, cp, XMIT_ACCEPT);
204                         accept_count++;
205                         goto nomap;
206                     }
207                 }
208
209                 /* if we matched a local domain, idp != NULL */
210                 if (!idp)
211                 {
212                     /*
213                      * Check to see if the right-hand part is an alias
214                      * or MX equivalent of the mailserver.  If it's
215                      * not, skip this name.  If it is, we'll keep
216                      * going and try to find a mapping to a client name.
217                      */
218                     if (!is_host_alias(atsign+1, ctl))
219                     {
220                         save_str(xmit_names, cp, XMIT_REJECT);
221                         reject_count++;
222                         continue;
223                     }
224                 }
225                 atsign[0] = '\0';
226                 map_name(cp, ctl, xmit_names);
227             nomap:;
228             }
229         }
230     }
231 }
232
233 /*
234  * Return zero on a syntactically invalid address, nz on a valid one.
235  *
236  * This used to be strchr(a, '.'), but it turns out that lines like this
237  *
238  * Received: from punt-1.mail.demon.net by mailstore for markb@ordern.com
239  *          id 938765929:10:27223:2; Fri, 01 Oct 99 08:18:49 GMT
240  *
241  * are not uncommon.  So now we just check that the following token is
242  * not itself an email address.
243  */
244 #define VALID_ADDRESS(a)        !strchr(a, '@')
245
246 static char *parse_received(struct query *ctl, char *bufp)
247 /* try to extract real address from the Received line */
248 /* If a valid Received: line is found, we return the full address in
249  * a buffer which can be parsed from nxtaddr().  This is to ansure that
250  * the local domain part of the address can be passed along in 
251  * find_server_names() if it contains one.
252  * Note: We should return a dummy header containing the address 
253  * which makes nxtaddr() behave correctly. 
254  */
255 {
256     char *base, *ok = (char *)NULL;
257     static char rbuf[HOSTLEN + USERNAMELEN + 4]; 
258
259     /*
260      * Try to extract the real envelope addressee.  We look here
261      * specifically for the mailserver's Received line.
262      * Note: this will only work for sendmail, or an MTA that
263      * shares sendmail's convention for embedding the envelope
264      * address in the Received line.  Sendmail itself only
265      * does this when the mail has a single recipient.
266      */
267     if (outlevel >= O_DEBUG)
268         report(stdout, _("analyzing Received line:\n%s"), bufp);
269
270     /* search for whitepace-surrounded "by" followed by valid address */
271     for (base = bufp;  ; base = ok + 2)
272     {
273         if (!(ok = strstr(base, "by")))
274             break;
275         else if (!isspace(ok[-1]) || !isspace(ok[2]))
276             continue;
277         else
278         {
279             char        *sp, *tp;
280
281             /* extract space-delimited token after "by" */
282             for (sp = ok + 2; isspace(*sp); sp++)
283                 continue;
284             tp = rbuf;
285             for (; !isspace(*sp); sp++)
286                 *tp++ = *sp;
287             *tp = '\0';
288
289             /* look for valid address */
290             if (VALID_ADDRESS(rbuf))
291                 break;
292             else
293                 ok = sp - 1;    /* arrange to skip this token */
294         }
295     }
296     if (ok)
297     {
298         /*
299          * If it's a DNS name of the mail server, look for the
300          * recipient name after a following "for".  Otherwise
301          * punt.
302          */
303         if (is_host_alias(rbuf, ctl))
304         {
305             if (outlevel >= O_DEBUG)
306                 report(stdout, 
307                       _("line accepted, %s is an alias of the mailserver\n"), rbuf);
308         }
309         else
310         {
311             if (outlevel >= O_DEBUG)
312                 report(stdout, 
313                       _("line rejected, %s is not an alias of the mailserver\n"), 
314                       rbuf);
315             return(NULL);
316         }
317
318         /* search for whitepace-surrounded "for" followed by xxxx@yyyy */
319         for (base = ok + 4 + strlen(rbuf);  ; base = ok + 2)
320         {
321             if (!(ok = strstr(base, "for")))
322                 break;
323             else if (!isspace(ok[-1]) || !isspace(ok[3]))
324                 continue;
325             else
326             {
327                 char    *sp, *tp;
328
329                 /* extract space-delimited token after "for" */
330                 for (sp = ok + 3; isspace(*sp); sp++)
331                     continue;
332                 tp = rbuf;
333                 for (; !isspace(*sp); sp++)
334                     *tp++ = *sp;
335                 *tp = '\0';
336
337                 if (strchr(rbuf, '@'))
338                     break;
339                 else
340                     ok = sp - 1;        /* arrange to skip this token */
341             }
342         }
343         if (ok)
344         {
345             flag        want_gt = FALSE;
346             char        *sp, *tp;
347
348             /* char after "for" could be space or a continuation newline */
349             for (sp = ok + 4; isspace(*sp); sp++)
350                 continue;
351             tp = rbuf;
352             *tp++ = ':';        /* Here is the hack.  This is to be friends */
353             *tp++ = ' ';        /* with nxtaddr()... */
354             if (*sp == '<')
355             {
356                 want_gt = TRUE;
357                 sp++;
358             }
359             while (*sp == '@')          /* skip routes */
360                 while (*sp && *sp++ != ':')
361                     continue;
362             while (*sp
363                    && (want_gt ? (*sp != '>') : !isspace(*sp))
364                    && *sp != ';')
365                 if (!isspace(*sp))
366                     *tp++ = *sp++;
367                 else
368                 {
369                     /* uh oh -- whitespace here can't be right! */
370                     ok = (char *)NULL;
371                     break;
372                 }
373             *tp++ = '\n';
374             *tp = '\0';
375             if (strlen(rbuf) <= 3)      /* apparently nothing has been found */
376                 ok = NULL;
377         } else
378             ok = (char *)NULL;
379     }
380
381     if (!ok)
382     {
383         if (outlevel >= O_DEBUG)
384             report(stdout, _("no Received address found\n"));
385         return(NULL);
386     }
387     else
388     {
389         if (outlevel >= O_DEBUG) {
390             char *lf = rbuf + strlen(rbuf)-1;
391             *lf = '\0';
392             if (outlevel >= O_DEBUG)
393                 report(stdout, _("found Received address `%s'\n"), rbuf+2);
394             *lf = '\n';
395         }
396         return(rbuf);
397     }
398 }
399
400 /* shared by readheaders and readbody */
401 static int sizeticker;
402 static struct msgblk msgblk;
403
404 #define EMPTYLINE(s)    ((s)[0] == '\r' && (s)[1] == '\n' && (s)[2] == '\0')
405
406 static int readheaders(int sock,
407                        long fetchlen,
408                        long reallen,
409                        struct query *ctl,
410                        int num)
411 /* read message headers and ship to SMTP or MDA */
412 /*   sock:              to which the server is connected */
413 /*   fetchlen:          length of message according to fetch response */
414 /*   reallen:           length of message according to getsizes */
415 /*   ctl:               query control record */
416 /*   num:               index of message */
417 {
418     struct addrblk
419     {
420         int             offset;
421         struct addrblk  *next;
422     };
423     struct addrblk      *to_addrchain = NULL;
424     struct addrblk      **to_chainptr = &to_addrchain;
425     struct addrblk      *resent_to_addrchain = NULL;
426     struct addrblk      **resent_to_chainptr = &resent_to_addrchain;
427
428     char                buf[MSGBUFSIZE+1];
429     int                 from_offs, reply_to_offs, resent_from_offs;
430     int                 app_from_offs, sender_offs, resent_sender_offs;
431     int                 env_offs;
432     char                *received_for, *rcv, *cp;
433     int                 n, linelen, oldlen, ch, remaining, skipcount;
434     struct idlist       *idp;
435     flag                no_local_matches = FALSE;
436     flag                headers_ok, has_nuls;
437     int                 olderrs, good_addresses, bad_addresses;
438
439     sizeticker = 0;
440     has_nuls = headers_ok = FALSE;
441     msgblk.return_path[0] = '\0';
442     olderrs = ctl->errcount;
443
444     /* read message headers */
445     msgblk.reallen = reallen;
446     msgblk.headers = received_for = NULL;
447     from_offs = reply_to_offs = resent_from_offs = app_from_offs = 
448         sender_offs = resent_sender_offs = env_offs = -1;
449     oldlen = 0;
450     msglen = 0;
451     skipcount = 0;
452     ctl->mimemsg = 0;
453
454     for (remaining = fetchlen; remaining > 0 || protocol->delimited; remaining -= linelen)
455     {
456         char *line;
457
458         line = xmalloc(sizeof(buf));
459         linelen = 0;
460         line[0] = '\0';
461         do {
462             set_timeout(mytimeout);
463             if ((n = SockRead(sock, buf, sizeof(buf)-1)) == -1) {
464                 set_timeout(0);
465                 free(line);
466                 free(msgblk.headers);
467                 return(PS_SOCKET);
468             }
469             set_timeout(0);
470             linelen += n;
471             msglen += n;
472
473             /* lines may not be properly CRLF terminated; fix this for qmail */
474             if (ctl->forcecr)
475             {
476                 cp = buf + strlen(buf) - 1;
477                 if (*cp == '\n' && (cp == buf || cp[-1] != '\r'))
478                 {
479                     *cp++ = '\r';
480                     *cp++ = '\n';
481                     *cp++ = '\0';
482                 }
483             }
484
485             /*
486              * Decode MIME encoded headers. We MUST do this before
487              * looking at the Content-Type / Content-Transfer-Encoding
488              * headers (RFC 2046).
489              */
490             if (ctl->mimedecode)
491                 UnMimeHeader(buf);
492
493             line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
494
495             strcat(line, buf);
496
497             /* check for end of headers */
498             if (EMPTYLINE(line))
499             {
500                 headers_ok = TRUE;
501                 has_nuls = (linelen != strlen(line));
502                 free(line);
503                 goto process_headers;
504             }
505
506             /*
507              * Check for end of message immediately.  If one of your folders
508              * has been mangled, the delimiter may occur directly after the
509              * header.
510              */
511             if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1))
512             {
513                 free(line);
514                 has_nuls = (linelen != strlen(line));
515                 goto process_headers;
516             }
517
518             /* check for RFC822 continuations */
519             set_timeout(mytimeout);
520             ch = SockPeek(sock);
521             set_timeout(0);
522         } while
523             (ch == ' ' || ch == '\t');  /* continuation to next line? */
524
525         /* write the message size dots */
526         if ((outlevel > O_SILENT && outlevel < O_VERBOSE) && linelen > 0)
527         {
528             sizeticker += linelen;
529             while (sizeticker >= SIZETICKER)
530             {
531                 if (!run.use_syslog)
532                 {
533                     fputc('.', stdout);
534                     fflush(stdout);
535                 }
536                 sizeticker -= SIZETICKER;
537             }
538         }
539
540         /* we see an ordinary (non-header, non-message-delimiter line */
541         has_nuls = (linelen != strlen(line));
542
543         /*
544          * When mail delivered to a multidrop mailbox on the server is
545          * addressed to multiple people on the client machine, there
546          * will be one copy left in the box for each recipient.  Thus,
547          * if the mail is addressed to N people, each recipient will
548          * get N copies.
549          *
550          * Foil this by suppressing all but one copy of a message with
551          * a given Message-ID.  Note: This implementation only catches
552          * runs of successive identical messages, but that should be
553          * good enough. 
554          * 
555          * The accept_count test ensures that multiple pieces of identical 
556          * email, each with a *single* addressee, won't be suppressed.
557          */
558         if (MULTIDROP(ctl) && accept_count > 1 && !strncasecmp(line, "Message-ID:", 11))
559         {
560             if (ctl->lastid && !strcasecmp(ctl->lastid, line))
561                 return(PS_REFUSED);
562             else
563             {
564                 if (ctl->lastid)
565                     free(ctl->lastid);
566                 ctl->lastid = strdup(line);
567             }
568         }
569
570         /*
571          * The University of Washington IMAP server (the reference
572          * implementation of IMAP4 written by Mark Crispin) relies
573          * on being able to keep base-UID information in a special
574          * message at the head of the mailbox.  This message should
575          * neither be deleted nor forwarded.
576          */
577 #ifdef POP2_ENABLE
578         /*
579          * We disable this check under POP2 because there's no way to
580          * prevent deletion of the message.  So at least we ought to 
581          * forward it to the user so he or she will have some clue
582          * that things have gone awry.
583          */
584 #if INET6_ENABLE
585         if (strncmp(protocol->service, "pop2", 4))
586 #else /* INET6_ENABLE */
587         if (protocol->port != 109)
588 #endif /* INET6_ENABLE */
589 #endif /* POP2_ENABLE */
590             if (num == 1 && !strncasecmp(line, "X-IMAP:", 7)) {
591                 free(line);
592                 free(msgblk.headers);
593                 return(PS_RETAINED);
594             }
595
596         /*
597          * This code prevents fetchmail from becoming an accessory after
598          * the fact to upstream sendmails with the `E' option on.  It also
599          * copes with certain brain-dead POP servers (like NT's) that pass
600          * through Unix from_ lines.
601          *
602          * Either of these bugs can result in a non-RFC822 line at the
603          * beginning of the headers.  If fetchmail just passes it
604          * through, the client listener may think the message has *no*
605          * headers (since the first) line it sees doesn't look
606          * RFC822-conformant) and fake up a set.
607          *
608          * What the user would see in this case is bogus (synthesized)
609          * headers, followed by a blank line, followed by the >From, 
610          * followed by the real headers, followed by a blank line,
611          * followed by text.
612          *
613          * We forestall this lossage by tossing anything that looks
614          * like an escaped or passed-through From_ line in headers.
615          * These aren't RFC822 so our conscience is clear...
616          */
617         if (!strncasecmp(line, ">From ", 6) || !strncasecmp(line, "From ", 5))
618         {
619             free(line);
620             continue;
621         }
622
623         /*
624          * If we see a Status line, it may have been inserted by an MUA
625          * on the mail host, or it may have been inserted by the server
626          * program after the headers in the transaction stream.  This
627          * can actually hose some new-mail notifiers such as xbuffy,
628          * which assumes any Status line came from a *local* MDA and
629          * therefore indicates that the message has been seen.
630          *
631          * Some buggy POP servers (including at least the 3.3(20)
632          * version of the one distributed with IMAP) insert empty
633          * Status lines in the transaction stream; we'll chuck those
634          * unconditionally.  Nonempty ones get chucked if the user
635          * turns on the dropstatus flag.
636          */
637         {
638             char        *cp;
639
640             if (!strncasecmp(line, "Status:", 7))
641                 cp = line + 7;
642             else if (!strncasecmp(line, "X-Mozilla-Status:", 17))
643                 cp = line + 17;
644             else
645                 cp = NULL;
646             if (cp) {
647                 while (*cp && isspace(*cp)) cp++;
648                 if (!*cp || ctl->dropstatus)
649                 {
650                     free(line);
651                     continue;
652                 }
653             }
654         }
655
656         if (ctl->rewrite)
657             line = reply_hack(line, ctl->server.truename);
658
659         /*
660          * OK, this is messy.  If we're forwarding by SMTP, it's the
661          * SMTP-receiver's job (according to RFC821, page 22, section
662          * 4.1.1) to generate a Return-Path line on final delivery.
663          * The trouble is, we've already got one because the
664          * mailserver's SMTP thought *it* was responsible for final
665          * delivery.
666          *
667          * Stash away the contents of Return-Path (as modified by reply_hack)
668          * for use in generating MAIL FROM later on, then prevent the header
669          * from being saved with the others.  In effect, we strip it off here.
670          *
671          * If the SMTP server conforms to the standards, and fetchmail gets the
672          * envelope sender from the Return-Path, the new Return-Path should be
673          * exactly the same as the original one.
674          *
675          * We do *not* want to ignore empty Return-Path headers.  These should
676          * be passed through as a way of indicating that a message should
677          * not trigger bounces if delivery fails.  What we *do* need to do is
678          * make sure we never try to rewrite such a blank Return-Path.  We
679          * handle this with a check for <> in the rewrite logic above.
680          */
681         if (!strncasecmp("Return-Path:", line, 12) && (cp = nxtaddr(line)))
682         {
683             strcpy(msgblk.return_path, cp);
684             if (!ctl->mda) {
685                 free(line);
686                 continue;
687             }
688         }
689
690         if (!msgblk.headers)
691         {
692             oldlen = strlen(line);
693             msgblk.headers = xmalloc(oldlen + 1);
694             (void) strcpy(msgblk.headers, line);
695             free(line);
696             line = msgblk.headers;
697         }
698         else
699         {
700             int newlen;
701
702             newlen = oldlen + strlen(line);
703             msgblk.headers = (char *) realloc(msgblk.headers, newlen + 1);
704             if (msgblk.headers == NULL) {
705                 free(line);
706                 return(PS_IOERR);
707             }
708             strcpy(msgblk.headers + oldlen, line);
709             free(line);
710             line = msgblk.headers + oldlen;
711             oldlen = newlen;
712         }
713
714         if (!strncasecmp("From:", line, 5))
715             from_offs = (line - msgblk.headers);
716         else if (!strncasecmp("Reply-To:", line, 9))
717             reply_to_offs = (line - msgblk.headers);
718         else if (!strncasecmp("Resent-From:", line, 12))
719             resent_from_offs = (line - msgblk.headers);
720         else if (!strncasecmp("Apparently-From:", line, 16))
721             app_from_offs = (line - msgblk.headers);
722         else if (!strncasecmp("Sender:", line, 7))
723             sender_offs = (line - msgblk.headers);
724         else if (!strncasecmp("Resent-Sender:", line, 14))
725             resent_sender_offs = (line - msgblk.headers);
726
727         else if (!strncasecmp("Message-Id:", buf, 11))
728         {
729             if (ctl->server.uidl)
730             {
731                 char id[IDLEN+1];
732
733                 buf[IDLEN+12] = 0;              /* prevent stack overflow */
734                 sscanf(buf+12, "%s", id);
735                 if (!str_find( &ctl->newsaved, num))
736                 {
737                     struct idlist *new = save_str(&ctl->newsaved,id,UID_SEEN);
738                     new->val.status.num = num;
739                 }
740             }
741         }
742
743         else if (!MULTIDROP(ctl))
744             continue;
745
746         else if (!strncasecmp("To:", line, 3)
747                         || !strncasecmp("Cc:", line, 3)
748                         || !strncasecmp("Bcc:", line, 4)
749                         || !strncasecmp("Apparently-To:", line, 14))
750         {
751             *to_chainptr = xmalloc(sizeof(struct addrblk));
752             (*to_chainptr)->offset = (line - msgblk.headers);
753             to_chainptr = &(*to_chainptr)->next; 
754             *to_chainptr = NULL;
755         }
756
757         else if (!strncasecmp("Resent-To:", line, 10)
758                         || !strncasecmp("Resent-Cc:", line, 10)
759                         || !strncasecmp("Resent-Bcc:", line, 11))
760         {
761             *resent_to_chainptr = xmalloc(sizeof(struct addrblk));
762             (*resent_to_chainptr)->offset = (line - msgblk.headers);
763             resent_to_chainptr = &(*resent_to_chainptr)->next; 
764             *resent_to_chainptr = NULL;
765         }
766
767         else if (ctl->server.envelope != STRING_DISABLED)
768         {
769             if (ctl->server.envelope 
770                         && strcasecmp(ctl->server.envelope, "Received"))
771             {
772                 if (env_offs == -1 && !strncasecmp(ctl->server.envelope,
773                                                 line,
774                                                 strlen(ctl->server.envelope)))
775                 {                               
776                     if (skipcount++ != ctl->server.envskip)
777                         continue;
778                     env_offs = (line - msgblk.headers);
779                 }    
780             }
781             else if (!received_for && !strncasecmp("Received:", line, 9))
782             {
783                 if (skipcount++ != ctl->server.envskip)
784                     continue;
785                 received_for = parse_received(ctl, line);
786             }
787         }
788     }
789
790  process_headers:
791     /*
792      * We want to detect this early in case there are so few headers that the
793      * dispatch logic barfs.
794      */
795     if (!headers_ok)
796     {
797         if (outlevel > O_SILENT)
798             report(stdout,
799                    _("message delimiter found while scanning headers\n"));
800     }
801
802     /*
803      * Hack time.  If the first line of the message was blank, with no headers
804      * (this happens occasionally due to bad gatewaying software) cons up
805      * a set of fake headers.  
806      *
807      * If you modify the fake header template below, be sure you don't
808      * make either From or To address @-less, otherwise the reply_hack
809      * logic will do bad things.
810      */
811     if (msgblk.headers == (char *)NULL)
812     {
813 #ifdef HAVE_SNPRINTF
814         snprintf(buf, sizeof(buf),
815 #else
816         sprintf(buf, 
817 #endif /* HAVE_SNPRINTF */
818         "From: FETCHMAIL-DAEMON\r\nTo: %s@%s\r\nSubject: Headerless mail from %s's mailbox on %s\r\n",
819                 user, fetchmailhost, ctl->remotename, ctl->server.truename);
820         msgblk.headers = xstrdup(buf);
821     }
822
823     /*
824      * We can now process message headers before reading the text.
825      * In fact we have to, as this will tell us where to forward to.
826      */
827
828     /* Check for MIME headers indicating possible 8-bit data */
829     ctl->mimemsg = MimeBodyType(msgblk.headers, ctl->mimedecode);
830
831 #ifdef SDPS_ENABLE
832     if (ctl->server.sdps && sdps_envfrom)
833     {
834         /* We have the real envelope return-path, stored out of band by
835          * SDPS - that's more accurate than any header is going to be.
836          */
837         strcpy(msgblk.return_path, sdps_envfrom);
838         free(sdps_envfrom);
839     } else
840 #endif /* SDPS_ENABLE */
841     /*
842      * If there is a Return-Path address on the message, this was
843      * almost certainly the MAIL FROM address given the originating
844      * sendmail.  This is the best thing to use for logging the
845      * message origin (it sets up the right behavior for bounces and
846      * mailing lists).  Otherwise, fall down to the next available 
847      * envelope address (which is the most probable real sender).
848      * *** The order is important! ***
849      * This is especially useful when receiving mailing list
850      * messages in multidrop mode.  if a local address doesn't
851      * exist, the bounce message won't be returned blindly to the 
852      * author or to the list itself but rather to the list manager
853      * (ex: specified by "Sender:") which is much less annoying.  This 
854      * is true for most mailing list packages.
855      */
856     if( !msgblk.return_path[0] ){
857         char *ap = NULL;
858         if (resent_sender_offs >= 0 && (ap = nxtaddr(msgblk.headers + resent_sender_offs)));
859         else if (sender_offs >= 0 && (ap = nxtaddr(msgblk.headers + sender_offs)));
860         else if (resent_from_offs >= 0 && (ap = nxtaddr(msgblk.headers + resent_from_offs)));
861         else if (from_offs >= 0 && (ap = nxtaddr(msgblk.headers + from_offs)));
862         else if (reply_to_offs >= 0 && (ap = nxtaddr(msgblk.headers + reply_to_offs)));
863         else if (app_from_offs >= 0 && (ap = nxtaddr(msgblk.headers + app_from_offs)));
864         if (ap) strcpy( msgblk.return_path, ap );
865     }
866
867     /* cons up a list of local recipients */
868     msgblk.recipients = (struct idlist *)NULL;
869     accept_count = reject_count = 0;
870     /* is this a multidrop box? */
871     if (MULTIDROP(ctl))
872     {
873 #ifdef SDPS_ENABLE
874         if (ctl->server.sdps && sdps_envto)
875         {
876             /* We have the real envelope recipient, stored out of band by
877              * SDPS - that's more accurate than any header is going to be.
878              */
879             find_server_names(sdps_envto, ctl, &msgblk.recipients);
880             free(sdps_envto);
881         } else
882 #endif /* SDPS_ENABLE */ 
883         if (env_offs > -1)          /* We have the actual envelope addressee */
884             find_server_names(msgblk.headers + env_offs, ctl, &msgblk.recipients);
885         else if (received_for)
886             /*
887              * We have the Received for addressee.  
888              * It has to be a mailserver address, or we
889              * wouldn't have got here.
890              * We use find_server_names() to let local 
891              * hostnames go through.
892              */
893             find_server_names(received_for, ctl, &msgblk.recipients);
894         else
895         {
896             /*
897              * We haven't extracted the envelope address.
898              * So check all the "Resent-To" header addresses if 
899              * they exist.  If and only if they don't, consider
900              * the "To" addresses.
901              */
902             register struct addrblk *nextptr;
903             if (resent_to_addrchain) {
904                 /* delete the "To" chain and substitute it 
905                  * with the "Resent-To" list 
906                  */
907                 while (to_addrchain) {
908                     nextptr = to_addrchain->next;
909                     free(to_addrchain);
910                     to_addrchain = nextptr;
911                 }
912                 to_addrchain = resent_to_addrchain;
913                 resent_to_addrchain = NULL;
914             }
915             /* now look for remaining adresses */
916             while (to_addrchain) {
917                 find_server_names(msgblk.headers+to_addrchain->offset, ctl, &msgblk.recipients);
918                 nextptr = to_addrchain->next;
919                 free(to_addrchain);
920                 to_addrchain = nextptr;
921             }
922         }
923         if (!accept_count)
924         {
925             no_local_matches = TRUE;
926             save_str(&msgblk.recipients, run.postmaster, XMIT_ACCEPT);
927             if (outlevel >= O_DEBUG)
928                 report(stdout,
929                       _("no local matches, forwarding to %s\n"),
930                       run.postmaster);
931         }
932     }
933     else        /* it's a single-drop box, use first localname */
934         save_str(&msgblk.recipients, ctl->localnames->id, XMIT_ACCEPT);
935
936
937     /*
938      * Time to either address the message or decide we can't deliver it yet.
939      */
940     if (ctl->errcount > olderrs)        /* there were DNS errors above */
941     {
942         if (outlevel >= O_DEBUG)
943             report(stdout,
944                    _("forwarding and deletion suppressed due to DNS errors\n"));
945         free(msgblk.headers);
946         free_str_list(&msgblk.recipients);
947         return(PS_TRANSIENT);
948     }
949     else
950     {
951         /* set up stuffline() so we can deliver the message body through it */ 
952         if ((n = open_sink(ctl, &msgblk,
953                            &good_addresses, &bad_addresses)) != PS_SUCCESS)
954         {
955             free(msgblk.headers);
956             free_str_list(&msgblk.recipients);
957             return(n);
958         }
959     }
960
961     n = 0;
962     /*
963      * Some server/sendmail combinations cause problems when our
964      * synthetic Received line is before the From header.  Cope
965      * with this...
966      */
967     if ((rcv = strstr(msgblk.headers, "Received:")) == (char *)NULL)
968         rcv = msgblk.headers;
969     /* handle ">Received:" lines too */
970     while (rcv > msgblk.headers && rcv[-1] != '\n')
971         rcv--;
972     if (rcv > msgblk.headers)
973     {
974         char    c = *rcv;
975
976         *rcv = '\0';
977         n = stuffline(ctl, msgblk.headers);
978         *rcv = c;
979     }
980     if (!run.invisible && n != -1)
981     {
982         /* utter any per-message Received information we need here */
983         sprintf(buf, "Received: from %s\r\n", ctl->server.truename);
984         n = stuffline(ctl, buf);
985         if (n != -1)
986         {
987             /*
988              * This header is technically invalid under RFC822.
989              * POP3, IMAP, etc. are not legal mail-parameter values.
990              *
991              * We used to include ctl->remotename in this log line,
992              * but this can be secure information that would be bad
993              * to reveal.
994              */
995             sprintf(buf, "\tby %s with %s (fetchmail-%s)\r\n",
996                     fetchmailhost,
997                     protocol->name,
998                     VERSION);
999             n = stuffline(ctl, buf);
1000             if (n != -1)
1001             {
1002                 buf[0] = '\t';
1003                 if (good_addresses == 0)
1004                 {
1005                     sprintf(buf+1, 
1006                             "for %s@%s (by default); ",
1007                             user, ctl->destaddr);
1008                 }
1009                 else if (good_addresses == 1)
1010                 {
1011                     for (idp = msgblk.recipients; idp; idp = idp->next)
1012                         if (idp->val.status.mark == XMIT_ACCEPT)
1013                             break;      /* only report first address */
1014                     if (strchr(idp->id, '@'))
1015                         sprintf(buf+1, "for %s", idp->id);
1016                     else
1017                         /*
1018                          * This could be a bit misleading, as destaddr is
1019                          * the forwarding host rather than the actual 
1020                          * destination.  Most of the time they coincide.
1021                          */
1022                         sprintf(buf+1, "for %s@%s", idp->id, ctl->destaddr);
1023                     sprintf(buf+strlen(buf), " (%s); ",
1024                             MULTIDROP(ctl) ? "multi-drop" : "single-drop");
1025                 }
1026                 else
1027                     buf[1] = '\0';
1028
1029                 strcat(buf, rfc822timestamp());
1030                 strcat(buf, "\r\n");
1031                 n = stuffline(ctl, buf);
1032             }
1033         }
1034     }
1035
1036     if (n != -1)
1037         n = stuffline(ctl, rcv);        /* ship out rest of msgblk.headers */
1038
1039     if (n == -1)
1040     {
1041         report(stdout, _("writing RFC822 msgblk.headers\n"));
1042         release_sink(ctl);
1043         free(msgblk.headers);
1044         free_str_list(&msgblk.recipients);
1045         return(PS_IOERR);
1046     }
1047     else if (!run.use_syslog && outlevel >= O_VERBOSE)
1048         fputs("#", stderr);
1049
1050     /* write error notifications */
1051     if (no_local_matches || has_nuls || bad_addresses)
1052     {
1053         int     errlen = 0;
1054         char    errhd[USERNAMELEN + POPBUFSIZE], *errmsg;
1055
1056         errmsg = errhd;
1057         (void) strcpy(errhd, "X-Fetchmail-Warning: ");
1058         if (no_local_matches)
1059         {
1060             if (reject_count != 1)
1061                 strcat(errhd, _("no recipient addresses matched declared local names"));
1062             else
1063             {
1064                 for (idp = msgblk.recipients; idp; idp = idp->next)
1065                     if (idp->val.status.mark == XMIT_REJECT)
1066                         break;
1067                 sprintf(errhd+strlen(errhd), _("recipient address %s didn't match any local name"), idp->id);
1068             }
1069         }
1070
1071         if (has_nuls)
1072         {
1073             if (errhd[sizeof("X-Fetchmail-Warning: ")])
1074                 strcat(errhd, "; ");
1075             strcat(errhd, _("message has embedded NULs"));
1076         }
1077
1078         if (bad_addresses)
1079         {
1080             if (errhd[sizeof("X-Fetchmail-Warning: ")])
1081                 strcat(errhd, "; ");
1082             strcat(errhd, _("SMTP listener rejected local recipient addresses: "));
1083             errlen = strlen(errhd);
1084             for (idp = msgblk.recipients; idp; idp = idp->next)
1085                 if (idp->val.status.mark == XMIT_RCPTBAD)
1086                     errlen += strlen(idp->id) + 2;
1087
1088             xalloca(errmsg, char *, errlen+3);
1089             (void) strcpy(errmsg, errhd);
1090             for (idp = msgblk.recipients; idp; idp = idp->next)
1091                 if (idp->val.status.mark == XMIT_RCPTBAD)
1092                 {
1093                     strcat(errmsg, idp->id);
1094                     if (idp->next)
1095                         strcat(errmsg, ", ");
1096                 }
1097
1098         }
1099
1100         strcat(errmsg, "\r\n");
1101
1102         /* ship out the error line */
1103         stuffline(ctl, errmsg);
1104     }
1105
1106     /* issue the delimiter line */
1107     cp = buf;
1108     *cp++ = '\r';
1109     *cp++ = '\n';
1110     *cp++ = '\0';
1111     stuffline(ctl, buf);
1112
1113     free(msgblk.headers);
1114     free_str_list(&msgblk.recipients);
1115     return(headers_ok ? PS_SUCCESS : PS_TRUNCATED);
1116 }
1117
1118 static int readbody(int sock, struct query *ctl, flag forward, int len)
1119 /* read and dispose of a message body presented on sock */
1120 /*   ctl:               query control record */
1121 /*   sock:              to which the server is connected */
1122 /*   len:               length of message */
1123 /*   forward:           TRUE to forward */
1124 {
1125     int linelen;
1126     unsigned char buf[MSGBUFSIZE+4];
1127     unsigned char *inbufp = buf;
1128     flag issoftline = FALSE;
1129
1130     /*
1131      * Pass through the text lines in the body.
1132      *
1133      * Yes, this wants to be ||, not &&.  The problem is that in the most
1134      * important delimited protocol, POP3, the length is not reliable.
1135      * As usual, the problem is Microsoft brain damage; see FAQ item S2.
1136      * So, for delimited protocols we need to ignore the length here and
1137      * instead drop out of the loop with a break statement when we see
1138      * the message delimiter.
1139      */
1140     while (protocol->delimited || len > 0)
1141     {
1142         set_timeout(mytimeout);
1143         if ((linelen = SockRead(sock, inbufp, sizeof(buf)-4-(inbufp-buf)))==-1)
1144         {
1145             set_timeout(0);
1146             release_sink(ctl);
1147             return(PS_SOCKET);
1148         }
1149         set_timeout(0);
1150
1151         /* write the message size dots */
1152         if (linelen > 0)
1153         {
1154             sizeticker += linelen;
1155             while (sizeticker >= SIZETICKER)
1156             {
1157                 if (!run.use_syslog && outlevel > O_SILENT)
1158                 {
1159                     fputc('.', stdout);
1160                     fflush(stdout);
1161                 }
1162                 sizeticker -= SIZETICKER;
1163             }
1164         }
1165         len -= linelen;
1166
1167         /* check for end of message */
1168         if (protocol->delimited && *inbufp == '.')
1169         {
1170             if (inbufp[1] == '\r' && inbufp[2] == '\n' && inbufp[3] == '\0')
1171                 break;
1172             else if (inbufp[1] == '\n' && inbufp[2] == '\0')
1173                 break;
1174             else
1175                 msglen--;       /* subtract the size of the dot escape */
1176         }
1177
1178         msglen += linelen;
1179
1180         if (ctl->mimedecode && (ctl->mimemsg & MSG_NEEDS_DECODE)) {
1181             issoftline = UnMimeBodyline(&inbufp, protocol->delimited, issoftline);
1182             if (issoftline && (sizeof(buf)-1-(inbufp-buf) < 200))
1183             {
1184                 /*
1185                  * Soft linebreak, but less than 200 bytes left in
1186                  * input buffer. Rather than doing a buffer overrun,
1187                  * ignore the soft linebreak, NL-terminate data and
1188                  * deliver what we have now.
1189                  * (Who writes lines longer than 2K anyway?)
1190                  */
1191                 *inbufp = '\n'; *(inbufp+1) = '\0';
1192                 issoftline = 0;
1193             }
1194         }
1195
1196         /* ship out the text line */
1197         if (forward && (!issoftline))
1198         {
1199             int n;
1200             inbufp = buf;
1201
1202             /* guard against very long lines */
1203             buf[MSGBUFSIZE+1] = '\r';
1204             buf[MSGBUFSIZE+2] = '\n';
1205             buf[MSGBUFSIZE+3] = '\0';
1206
1207             n = stuffline(ctl, buf);
1208
1209             if (n < 0)
1210             {
1211                 report(stdout, _("writing message text\n"));
1212                 release_sink(ctl);
1213                 return(PS_IOERR);
1214             }
1215             else if (outlevel >= O_VERBOSE)
1216                 fputc('*', stderr);
1217         }
1218     }
1219
1220     return(PS_SUCCESS);
1221 }
1222
1223 #ifdef KERBEROS_V4
1224 int
1225 kerberos_auth (socket, canonical) 
1226 /* authenticate to the server host using Kerberos V4 */
1227 int socket;             /* socket to server host */
1228 #if defined(__FreeBSD__) || defined(__OpenBSD__)
1229 char *canonical;        /* server name */
1230 #else
1231 const char *canonical;  /* server name */
1232 #endif
1233 {
1234     char * host_primary;
1235     KTEXT ticket;
1236     MSG_DAT msg_data;
1237     CREDENTIALS cred;
1238     Key_schedule schedule;
1239     int rem;
1240   
1241     xalloca(ticket, KTEXT, sizeof (KTEXT_ST));
1242     rem = (krb_sendauth (0L, socket, ticket, "pop",
1243                          canonical,
1244                          ((char *) (krb_realmofhost (canonical))),
1245                          ((unsigned long) 0),
1246                          (&msg_data),
1247                          (&cred),
1248                          (schedule),
1249                          ((struct sockaddr_in *) 0),
1250                          ((struct sockaddr_in *) 0),
1251                          "KPOPV0.1"));
1252     if (rem != KSUCCESS)
1253     {
1254         report(stderr, _("kerberos error %s\n"), (krb_get_err_text (rem)));
1255         return (PS_AUTHFAIL);
1256     }
1257     return (0);
1258 }
1259 #endif /* KERBEROS_V4 */
1260
1261 #ifdef KERBEROS_V5
1262 static int kerberos5_auth(socket, canonical)
1263 /* authenticate to the server host using Kerberos V5 */
1264 int socket;             /* socket to server host */
1265 const char *canonical;  /* server name */
1266 {
1267     krb5_error_code retval;
1268     krb5_context context;
1269     krb5_ccache ccdef;
1270     krb5_principal client = NULL, server = NULL;
1271     krb5_error *err_ret = NULL;
1272
1273     krb5_auth_context auth_context = NULL;
1274
1275     krb5_init_context(&context);
1276     krb5_init_ets(context);
1277     krb5_auth_con_init(context, &auth_context);
1278
1279     if (retval = krb5_cc_default(context, &ccdef)) {
1280         report(stderr, "krb5_cc_default: %s\n", error_message(retval));
1281         return(PS_ERROR);
1282     }
1283
1284     if (retval = krb5_cc_get_principal(context, ccdef, &client)) {
1285         report(stderr, "krb5_cc_get_principal: %s\n", error_message(retval));
1286         return(PS_ERROR);
1287     }
1288
1289     if (retval = krb5_sname_to_principal(context, canonical, "pop",
1290            KRB5_NT_UNKNOWN,
1291            &server)) {
1292         report(stderr, "krb5_sname_to_principal: %s\n", error_message(retval));
1293         return(PS_ERROR);
1294     }
1295
1296     retval = krb5_sendauth(context, &auth_context, (krb5_pointer) &socket,
1297          "KPOPV1.0", client, server,
1298          AP_OPTS_MUTUAL_REQUIRED,
1299          NULL,  /* no data to checksum */
1300          0,   /* no creds, use ccache instead */
1301          ccdef,
1302          &err_ret, 0,
1303
1304          NULL); /* don't need reply */
1305
1306     krb5_free_principal(context, server);
1307     krb5_free_principal(context, client);
1308     krb5_auth_con_free(context, auth_context);
1309
1310     if (retval) {
1311 #ifdef HEIMDAL
1312       if (err_ret && err_ret->e_text) {
1313           report(stderr, _("krb5_sendauth: %s [server says '%*s'] \n"),
1314                  error_message(retval),
1315                  err_ret->e_text);
1316 #else
1317       if (err_ret && err_ret->text.length) {
1318           report(stderr, _("krb5_sendauth: %s [server says '%*s'] \n"),
1319                  error_message(retval),
1320                  err_ret->text.length,
1321                  err_ret->text.data);
1322 #endif
1323           krb5_free_error(context, err_ret);
1324       } else
1325           report(stderr, "krb5_sendauth: %s\n", error_message(retval));
1326       return(PS_ERROR);
1327     }
1328
1329     return 0;
1330 }
1331 #endif /* KERBEROS_V5 */
1332
1333 static void clean_skipped_list(struct idlist **skipped_list)
1334 /* struct "idlist" contains no "prev" ptr; we must remove unused items first */
1335 {
1336     struct idlist *current=NULL, *prev=NULL, *tmp=NULL, *head=NULL;
1337     prev = current = head = *skipped_list;
1338
1339     if (!head)
1340         return;
1341     do
1342     {
1343         /* if item has no reference, remove it */
1344         if (current && current->val.status.mark == 0)
1345         {
1346             if (current == head) /* remove first item (head) */
1347             {
1348                 head = current->next;
1349                 if (current->id) free(current->id);
1350                 free(current);
1351                 prev = current = head;
1352             }
1353             else /* remove middle/last item */
1354             {
1355                 tmp = current->next;
1356                 prev->next = tmp;
1357                 if (current->id) free(current->id);
1358                 free(current);
1359                 current = tmp;
1360             }
1361         }
1362         else /* skip this item */
1363         {
1364             prev = current;
1365             current = current->next;
1366         }
1367     } while(current);
1368
1369     *skipped_list = head;
1370 }
1371
1372 static void send_size_warnings(struct query *ctl)
1373 /* send warning mail with skipped msg; reset msg count when user notified */
1374 {
1375     int size, nbr;
1376     int msg_to_send = FALSE;
1377     struct idlist *head=NULL, *current=NULL;
1378     int max_warning_poll_count;
1379 #define OVERHD  "Subject: Fetchmail oversized-messages warning.\r\n\r\nThe following oversized messages remain on the mail server %s:"
1380
1381     head = ctl->skipped;
1382     if (!head)
1383         return;
1384
1385     /* don't start a notification message unless we need to */
1386     for (current = head; current; current = current->next)
1387         if (current->val.status.num == 0 && current->val.status.mark)
1388             msg_to_send = TRUE;
1389     if (!msg_to_send)
1390         return;
1391
1392     /*
1393      * There's no good way to recover if we can't send notification mail, 
1394      * but it's not a disaster, either, since the skipped mail will not
1395      * be deleted.
1396      */
1397     if (open_warning_by_mail(ctl, (struct msgblk *)NULL))
1398         return;
1399     stuff_warning(ctl, OVERHD, ctl->server.pollname);
1400  
1401     if (run.poll_interval == 0)
1402         max_warning_poll_count = 0;
1403     else
1404         max_warning_poll_count = ctl->warnings/run.poll_interval;
1405
1406     /* parse list of skipped msg, adding items to the mail */
1407     for (current = head; current; current = current->next)
1408     {
1409         if (current->val.status.num == 0 && current->val.status.mark)
1410         {
1411             nbr = current->val.status.mark;
1412             size = atoi(current->id);
1413             stuff_warning(ctl, 
1414                     _("\t%d msg %d octets long skipped by fetchmail.\n"),
1415                     nbr, size);
1416         }
1417         current->val.status.num++;
1418         current->val.status.mark = 0;
1419
1420         if (current->val.status.num >= max_warning_poll_count)
1421             current->val.status.num = 0;
1422     }
1423
1424     close_warning_by_mail(ctl, (struct msgblk *)NULL);
1425 #undef OVERHD
1426 }
1427
1428 static int do_session(ctl, proto, maxfetch)
1429 /* retrieve messages from server using given protocol method table */
1430 struct query *ctl;              /* parsed options with merged-in defaults */
1431 const struct method *proto;     /* protocol method table */
1432 const int maxfetch;             /* maximum number of messages to fetch */
1433 {
1434     int js;
1435 #ifdef HAVE_VOLATILE
1436     volatile int ok, mailserver_socket = -1;    /* pacifies -Wall */
1437 #else
1438     int ok, mailserver_socket = -1;
1439 #endif /* HAVE_VOLATILE */
1440     const char *msg;
1441     void (*pipesave)(int);
1442     void (*alrmsave)(int);
1443     struct idlist *current=NULL, *tmp=NULL;
1444
1445     protocol = proto;
1446     ctl->server.base_protocol = protocol;
1447
1448     pass = 0;
1449     tagnum = 0;
1450     tag[0] = '\0';      /* nuke any tag hanging out from previous query */
1451     ok = 0;
1452
1453     /* set up the server-nonresponse timeout */
1454     alrmsave = signal(SIGALRM, timeout_handler);
1455     mytimeout = ctl->server.timeout;
1456
1457     /* set up the broken-pipe timeout */
1458     pipesave = signal(SIGPIPE, sigpipe_handler);
1459
1460     if ((js = setjmp(restart)))
1461     {
1462 #ifdef HAVE_SIGPROCMASK
1463         /*
1464          * Don't rely on setjmp() to restore the blocked-signal mask.
1465          * It does this under BSD but is required not to under POSIX.
1466          *
1467          * If your Unix doesn't have sigprocmask, better hope it has
1468          * BSD-like behavior.  Otherwise you may see fetchmail get
1469          * permanently wedged after a second timeout on a bad read,
1470          * because alarm signals were blocked after the first.
1471          */
1472         sigset_t        allsigs;
1473
1474         sigfillset(&allsigs);
1475         sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
1476 #endif /* HAVE_SIGPROCMASK */
1477
1478         if (js == THROW_SIGPIPE)
1479         {
1480             report(stdout,
1481                    _("SIGPIPE thrown from an MDA or a stream socket error"));
1482             ok = PS_SOCKET;
1483         }
1484         else if (js == THROW_TIMEOUT)
1485         {
1486             if (phase == OPEN_WAIT)
1487                 report(stdout,
1488                        _("timeout after %d seconds waiting to connect to server %s.\n"),
1489                        ctl->server.timeout, ctl->server.pollname);
1490             else if (phase == SERVER_WAIT)
1491                 report(stdout,
1492                        _("timeout after %d seconds waiting for server %s.\n"),
1493                        ctl->server.timeout, ctl->server.pollname);
1494             else if (phase == FORWARDING_WAIT)
1495                 report(stdout,
1496                        _("timeout after %d seconds waiting for %s.\n"),
1497                        ctl->server.timeout,
1498                        ctl->mda ? "MDA" : "SMTP");
1499             else if (phase == LISTENER_WAIT)
1500                 report(stdout,
1501                        _("timeout after %d seconds waiting for listener to respond.\n"));
1502             else
1503                 report(stdout, 
1504                        _("timeout after %d seconds.\n"), ctl->server.timeout);
1505
1506             /*
1507              * If we've exceeded our threshold for consecutive timeouts, 
1508              * try to notify the user, then mark the connection wedged.
1509              */
1510             if (timeoutcount > MAX_TIMEOUTS 
1511                 && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
1512             {
1513                 stuff_warning(ctl,
1514                               _("Subject: fetchmail sees repeated timeouts\r\n"));
1515                 stuff_warning(ctl,
1516                               _("Fetchmail saw more than %d timeouts while attempting to get mail from %s@%s.\r\n"), 
1517                               MAX_TIMEOUTS,
1518                               ctl->remotename,
1519                               ctl->server.truename);
1520                 stuff_warning(ctl, 
1521     _("This could mean that your mailserver is stuck, or that your SMTP\r\n" \
1522     "server is wedged, or that your mailbox file on the server has been\r\n" \
1523     "corrupted by a server error.  You can run `fetchmail -v -v' to\r\n" \
1524     "diagnose the problem.\r\n\r\n" \
1525     "Fetchmail won't poll this mailbox again until you restart it.\r\n"));
1526                 close_warning_by_mail(ctl, (struct msgblk *)NULL);
1527                 ctl->wedged = TRUE;
1528             }
1529
1530             ok = PS_ERROR;
1531         }
1532
1533         /* try to clean up all streams */
1534         release_sink(ctl);
1535         if (ctl->smtp_socket != -1)
1536             close(ctl->smtp_socket);
1537         if (mailserver_socket != -1)
1538             SockClose(mailserver_socket);
1539     }
1540     else
1541     {
1542         char buf[POPBUFSIZE+1], *realhost;
1543         int len, num, count, new, bytes, deletions = 0, *msgsizes = NULL;
1544 #if INET6_ENABLE
1545         int fetches, dispatches, oldphase;
1546 #else /* INET6_ENABLE */
1547         int port, fetches, dispatches, oldphase;
1548 #endif /* INET6_ENABLE */
1549         struct idlist *idp;
1550
1551         /* execute pre-initialization command, if any */
1552         if (ctl->preconnect && (ok = system(ctl->preconnect)))
1553         {
1554             report(stderr, 
1555                    _("pre-connection command failed with status %d\n"), ok);
1556             ok = PS_SYNTAX;
1557             goto closeUp;
1558         }
1559
1560         /* open a socket to the mail server */
1561         oldphase = phase;
1562         phase = OPEN_WAIT;
1563         set_timeout(mytimeout);
1564 #if !INET6_ENABLE
1565 #ifdef SSL_ENABLE
1566         port = ctl->server.port ? ctl->server.port : ( ctl->use_ssl ? protocol->sslport : protocol->port );
1567 #else
1568         port = ctl->server.port ? ctl->server.port : protocol->port;
1569 #endif
1570 #endif /* !INET6_ENABLE */
1571         realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
1572
1573         /* allow time for the port to be set up if we have a plugin */
1574         if (ctl->server.plugin)
1575             (void)sleep(1);
1576 #if INET6_ENABLE
1577         if ((mailserver_socket = SockOpen(realhost, 
1578                              ctl->server.service ? ctl->server.service : protocol->service,
1579                              ctl->server.netsec, ctl->server.plugin)) == -1)
1580 #else /* INET6_ENABLE */
1581         if ((mailserver_socket = SockOpen(realhost, port, NULL, ctl->server.plugin)) == -1)
1582 #endif /* INET6_ENABLE */
1583         {
1584 #if !INET6_ENABLE
1585             int err_no = errno;
1586 #ifdef HAVE_RES_SEARCH
1587             if (err_no != 0 && h_errno != 0)
1588                 report(stderr, _("fetchmail: internal inconsistency\n"));
1589 #endif
1590             /*
1591              * Avoid generating a bogus error every poll cycle when we're
1592              * in daemon mode but the connection to the outside world
1593              * is down.
1594              */
1595             if (err_no == EHOSTUNREACH && run.poll_interval)
1596                 goto ehostunreach;
1597
1598             report_build(stderr, _("fetchmail: %s connection to %s failed"), 
1599                          protocol->name, ctl->server.pollname);
1600 #ifdef HAVE_RES_SEARCH
1601             if (h_errno != 0)
1602             {
1603                 if (h_errno == HOST_NOT_FOUND)
1604                     report_complete(stderr, _(": host is unknown\n"));
1605                 else if (h_errno == NO_ADDRESS)
1606                     report_complete(stderr, _(": name is valid but has no IP address\n"));
1607                 else if (h_errno == NO_RECOVERY)
1608                     report_complete(stderr, _(": unrecoverable name server error\n"));
1609                 else if (h_errno == TRY_AGAIN)
1610                     report_complete(stderr, _(": temporary name server error\n"));
1611                 else
1612                     report_complete(stderr, _(": unknown DNS error %d\n"), h_errno);
1613             }
1614             else
1615 #endif /* HAVE_RES_SEARCH */
1616                 report_complete(stderr, ": %s\n", strerror(err_no));
1617
1618         ehostunreach:
1619 #endif /* INET6_ENABLE */
1620             ok = PS_SOCKET;
1621             set_timeout(0);
1622             phase = oldphase;
1623             goto closeUp;
1624         }
1625         set_timeout(0);
1626         phase = oldphase;
1627
1628 #ifdef SSL_ENABLE
1629         /* perform initial SSL handshake on open connection */
1630         /* Note:  We pass the realhost name over for certificate
1631                 verification.  We may want to make this configurable */
1632         if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslkey,ctl->sslcert,realhost) == -1) 
1633         {
1634             report(stderr, "SSL connection failed.");
1635             goto closeUp;
1636         }
1637 #endif
1638
1639 #ifdef KERBEROS_V4
1640         if (ctl->server.preauthenticate == A_KERBEROS_V4)
1641         {
1642             set_timeout(mytimeout);
1643             ok = kerberos_auth(mailserver_socket, ctl->server.truename);
1644             set_timeout(0);
1645             if (ok != 0)
1646                 goto cleanUp;
1647         }
1648 #endif /* KERBEROS_V4 */
1649
1650 #ifdef KERBEROS_V5
1651         if (ctl->server.preauthenticate == A_KERBEROS_V5)
1652         {
1653             set_timeout(mytimeout);
1654             ok = kerberos5_auth(mailserver_socket, ctl->server.truename);
1655             set_timeout(0);
1656             if (ok != 0)
1657                 goto cleanUp;
1658         }
1659 #endif /* KERBEROS_V5 */
1660
1661         /* accept greeting message from mail server */
1662         ok = (protocol->parse_response)(mailserver_socket, buf);
1663         if (ok != 0)
1664             goto cleanUp;
1665
1666         /* try to get authorized to fetch mail */
1667         if (protocol->getauth)
1668         {
1669             if (protocol->password_canonify)
1670                 (protocol->password_canonify)(shroud, ctl->password, PASSWORDLEN);
1671             else
1672                 strcpy(shroud, ctl->password);
1673
1674             ok = (protocol->getauth)(mailserver_socket, ctl, buf);
1675             if (ok != 0)
1676             {
1677                 if (ok == PS_LOCKBUSY)
1678                     report(stderr, _("Lock-busy error on %s@%s\n"),
1679                           ctl->remotename,
1680                           ctl->server.truename);
1681                 else
1682                 {
1683                     if (ok == PS_ERROR)
1684                         ok = PS_AUTHFAIL;
1685                     report(stderr, _("Authorization failure on %s@%s\n"), 
1686                           ctl->remotename,
1687                           ctl->server.truename);
1688
1689                     /*
1690                      * If we're running in background, try to mail the
1691                      * calling user a heads-up about the authentication 
1692                      * failure once it looks like this isn't a fluke 
1693                      * due to the server being temporarily inaccessible.
1694                      */
1695                     if (run.poll_interval
1696                         && ctl->authfailcount++ > MAX_AUTHFAILS 
1697                         && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
1698                     {
1699                         stuff_warning(ctl,
1700                             _("Subject: fetchmail authentication failed\r\n"));
1701                         stuff_warning(ctl,
1702                             _("Fetchmail could not get mail from %s@%s.\r\n"), 
1703                             ctl->remotename,
1704                             ctl->server.truename);
1705                         stuff_warning(ctl, 
1706     _("The attempt to get authorization failed.\r\n" \
1707     "This probably means your password is invalid, but POP3 servers have\r\n" \
1708     "other failure modes that fetchmail cannot distinguish from this\r\n" \
1709     "because they don't send useful error messages on login failure.\r\n"));
1710                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1711                         ctl->wedged = TRUE;
1712                     }
1713                 }
1714                 goto cleanUp;
1715             }
1716         }
1717
1718         ctl->errcount = fetches = 0;
1719
1720         /* now iterate over each folder selected */
1721         for (idp = ctl->mailboxes; idp; idp = idp->next)
1722         {
1723             pass = 0;
1724             do {
1725                 dispatches = 0;
1726                 ++pass;
1727
1728                 if (outlevel >= O_DEBUG)
1729                 {
1730                     if (idp->id)
1731                         report(stdout, _("selecting or re-polling folder %s\n"), idp->id);
1732                     else
1733                         report(stdout, _("selecting or re-polling default folder\n"));
1734                 }
1735
1736                 /* compute # of messages and number of new messages waiting */
1737                 ok = (protocol->getrange)(mailserver_socket, ctl, idp->id, &count, &new, &bytes);
1738                 if (ok != 0)
1739                     goto cleanUp;
1740
1741                 /* show user how many messages we downloaded */
1742                 if (idp->id)
1743                     (void) sprintf(buf, _("%s at %s (folder %s)"),
1744                                    ctl->remotename, ctl->server.truename, idp->id);
1745                 else
1746                     (void) sprintf(buf, _("%s at %s"),
1747                                    ctl->remotename, ctl->server.truename);
1748                 if (outlevel > O_SILENT)
1749                 {
1750                     if (count == -1)            /* only used for ETRN */
1751                         report(stdout, _("Polling %s\n"), ctl->server.truename);
1752                     else if (count != 0)
1753                     {
1754                         if (new != -1 && (count - new) > 0)
1755                             report_build(stdout, _("%d %s (%d seen) for %s"),
1756                                   count, count > 1 ? _("messages") :
1757                                                      _("message"),
1758                                   count-new, buf);
1759                         else
1760                             report_build(stdout, _("%d %s for %s"), 
1761                                   count, count > 1 ? _("messages") :
1762                                                      _("message"), buf);
1763                         if (bytes == -1)
1764                             report_complete(stdout, ".\n");
1765                         else
1766                             report_complete(stdout, _(" (%d octets).\n"), bytes);
1767                     }
1768                     else
1769                     {
1770                         /* these are pointless in normal daemon mode */
1771                         if (pass == 1 && (run.poll_interval == 0 || outlevel >= O_VERBOSE))
1772                             report(stdout, _("No mail for %s\n"), buf); 
1773                     }
1774                 }
1775
1776                 /* very important, this is where we leave the do loop */ 
1777                 if (count == 0)
1778                     break;
1779
1780                 if (check_only)
1781                 {
1782                     if (new == -1 || ctl->fetchall)
1783                         new = count;
1784                     fetches = new;      /* set error status ccorrectly */
1785                     goto no_error;
1786                 }
1787                 else if (count > 0)
1788                 {    
1789                     flag        force_retrieval;
1790
1791                     /*
1792                      * What forces this code is that in POP2 and
1793                      * IMAP2bis you can't fetch a message without
1794                      * having it marked `seen'.  In POP3 and IMAP4, on the
1795                      * other hand, you can (peek_capable is set by 
1796                      * each driver module to convey this; it's not a
1797                      * method constant because of the difference between
1798                      * IMAP2bis and IMAP4, and because POP3 doesn't  peek
1799                      * if fetchall is on).
1800                      *
1801                      * The result of being unable to peek is that if there's
1802                      * any kind of transient error (DNS lookup failure, or
1803                      * sendmail refusing delivery due to process-table limits)
1804                      * the message will be marked "seen" on the server without
1805                      * having been delivered.  This is not a big problem if
1806                      * fetchmail is running in foreground, because the user
1807                      * will see a "skipped" message when it next runs and get
1808                      * clued in.
1809                      *
1810                      * But in daemon mode this leads to the message
1811                      * being silently ignored forever.  This is not
1812                      * acceptable.
1813                      *
1814                      * We compensate for this by checking the error
1815                      * count from the previous pass and forcing all
1816                      * messages to be considered new if it's nonzero.
1817                      */
1818                     force_retrieval = !peek_capable && (ctl->errcount > 0);
1819
1820                     /* 
1821                      * We need the size of each message before it's
1822                      * loaded in order to pass it to the ESMTP SIZE
1823                      * option.  If the protocol has a getsizes method,
1824                      * we presume this means it doesn't get reliable
1825                      * sizes from message fetch responses.
1826                      */
1827                     if (proto->getsizes)
1828                     {
1829                         int     i;
1830
1831                         xalloca(msgsizes, int *, sizeof(int) * count);
1832                         for (i = 0; i < count; i++)
1833                             msgsizes[i] = -1;
1834
1835                         ok = (proto->getsizes)(mailserver_socket, count, msgsizes);
1836                         if (ok != 0)
1837                             goto cleanUp;
1838
1839                         if (bytes == -1)
1840                         {
1841                             bytes = 0;
1842                             for (i = 0; i < count; i++)
1843                                 bytes += msgsizes[i];
1844                         }
1845                     }
1846
1847                     /* read, forward, and delete messages */
1848                     for (num = 1; num <= count; num++)
1849                     {
1850                         flag toolarge = NUM_NONZERO(ctl->limit)
1851                             && msgsizes && (msgsizes[num-1] > ctl->limit);
1852                         flag oldmsg = (!new) || (protocol->is_old && (protocol->is_old)(mailserver_socket,ctl,num));
1853                         flag fetch_it = !toolarge 
1854                             && (ctl->fetchall || force_retrieval || !oldmsg);
1855                         flag suppress_delete = FALSE;
1856                         flag suppress_forward = FALSE;
1857                         flag suppress_readbody = FALSE;
1858                         flag retained = FALSE;
1859
1860                         /*
1861                          * This check copes with Post Office/NT's
1862                          * annoying habit of randomly prepending bogus
1863                          * LIST items of length -1.  Patrick Audley
1864                          * <paudley@pobox.com> tells us: LIST shows a
1865                          * size of -1, RETR and TOP return "-ERR
1866                          * System error - couldn't open message", and
1867                          * DELE succeeds but doesn't actually delete
1868                          * the message.
1869                          */
1870                         if (msgsizes && msgsizes[num-1] == -1)
1871                         {
1872                             if (outlevel >= O_VERBOSE)
1873                                 report(stdout, 
1874                                       _("Skipping message %d, length -1\n"),
1875                                       num);
1876                             continue;
1877                         }
1878
1879                         /*
1880                          * We may want to reject this message if it's old
1881                          * or oversized, and we're not forcing retrieval.
1882                          */
1883                         if (!fetch_it)
1884                         {
1885                             if (outlevel > O_SILENT)
1886                             {
1887                                 report_build(stdout, _("skipping message %d"), num);
1888                                 if (toolarge && !check_only) 
1889                                 {
1890                                     char size[32];
1891                                     int cnt;
1892
1893                                     /* convert sz to string */
1894                                     sprintf(size, "%d", msgsizes[num-1]);
1895
1896                                     /* build a list of skipped messages
1897                                      * val.id = size of msg (string cnvt)
1898                                      * val.status.num = warning_poll_count
1899                                      * val.status.mask = nbr of msg this size
1900                                      */
1901
1902                                     current = ctl->skipped;
1903
1904                                     /* initialise warning_poll_count to the
1905                                      * current value so that all new msg will
1906                                      * be included in the next mail
1907                                      */
1908                                     cnt = current? current->val.status.num : 0;
1909
1910                                     /* if entry exists, increment the count */
1911                                     if (current && 
1912                                         str_in_list(&current, size, FALSE))
1913                                     {
1914                                         for ( ; current; 
1915                                                 current = current->next)
1916                                         {
1917                                             if (strcmp(current->id, size) == 0)
1918                                             {
1919                                                 current->val.status.mark++;
1920                                                 break;
1921                                             }
1922                                         }
1923                                     }
1924                                     /* otherwise, create a new entry */
1925                                     /* initialise with current poll count */
1926                                     else
1927                                     {
1928                                         tmp = save_str(&ctl->skipped, size, 1);
1929                                         tmp->val.status.num = cnt;
1930                                     }
1931
1932                                     report_build(stdout, _(" (oversized, %d octets)"),
1933                                                 msgsizes[num-1]);
1934                                 }
1935                             }
1936                         }
1937                         else
1938                         {
1939                             flag wholesize = !protocol->fetch_body;
1940
1941                             /* request a message */
1942                             ok = (protocol->fetch_headers)(mailserver_socket,ctl,num, &len);
1943                             if (ok != 0)
1944                                 goto cleanUp;
1945
1946                             /* -1 means we didn't see a size in the response */
1947                             if (len == -1 && msgsizes)
1948                             {
1949                                 len = msgsizes[num - 1];
1950                                 wholesize = TRUE;
1951                             }
1952
1953                             if (outlevel > O_SILENT)
1954                             {
1955                                 report_build(stdout, _("reading message %d of %d"),
1956                                             num,count);
1957
1958                                 if (len > 0)
1959                                     report_build(stdout, _(" (%d %soctets)"),
1960                                         len, wholesize ? "" : _("header "));
1961                                 if (outlevel >= O_VERBOSE)
1962                                     report_complete(stdout, "\n");
1963                                 else
1964                                     report_complete(stdout, " ");
1965                             }
1966
1967                             /* 
1968                              * Read the message headers and ship them to the
1969                              * output sink.  
1970                              */
1971                             ok = readheaders(mailserver_socket, len, msgsizes[num-1],
1972                                              ctl, num);
1973                             if (ok == PS_RETAINED)
1974                                 suppress_forward = retained = TRUE;
1975                             else if (ok == PS_TRANSIENT)
1976                                 suppress_delete = suppress_forward = TRUE;
1977                             else if (ok == PS_REFUSED)
1978                                 suppress_forward = TRUE;
1979                             else if (ok == PS_TRUNCATED)
1980                                 suppress_readbody = TRUE;
1981                             else if (ok)
1982                                 goto cleanUp;
1983
1984                             /* 
1985                              * If we're using IMAP4 or something else that
1986                              * can fetch headers separately from bodies,
1987                              * it's time to request the body now.  This
1988                              * fetch may be skipped if we got an anti-spam
1989                              * or other PS_REFUSED error response during
1990                              * readheaders.
1991                              */
1992                             if (protocol->fetch_body && !suppress_readbody) 
1993                             {
1994                                 if (outlevel >= O_VERBOSE)
1995                                 {
1996                                     fputc('\n', stdout);
1997                                     fflush(stdout);
1998                                 }
1999
2000                                 if ((ok = (protocol->trail)(mailserver_socket, ctl, num)))
2001                                     goto cleanUp;
2002                                 len = 0;
2003                                 if (!suppress_forward)
2004                                 {
2005                                     if ((ok=(protocol->fetch_body)(mailserver_socket,ctl,num,&len)))
2006                                         goto cleanUp;
2007                                     /*
2008                                      * Work around a bug in Novell's
2009                                      * broken GroupWise IMAP server;
2010                                      * its body FETCH response is missing
2011                                      * the required length for the data
2012                                      * string.  This violates RFC2060.
2013                                      */
2014                                     if (len == -1)
2015                                        len = msgsizes[num-1] - msglen;
2016                                     if (outlevel > O_SILENT && !wholesize)
2017                                         report_complete(stdout,
2018                                                _(" (%d body octets) "), len);
2019                                 }
2020                             }
2021
2022                             /* process the body now */
2023                             if (len > 0)
2024                             {
2025                                 if (suppress_readbody)
2026                                 {
2027                                   /* When readheaders returns PS_TRUNCATED,
2028                                      the body (which has no content
2029                                      has already been read by readheaders,
2030                                      so we say readbody returned PS_SUCCESS */
2031                                   ok = PS_SUCCESS;
2032                                 }
2033                                 else
2034                                 {
2035                                   ok = readbody(mailserver_socket,
2036                                                 ctl,
2037                                                 !suppress_forward,
2038                                                 len);
2039                                 }
2040                                 if (ok == PS_TRANSIENT)
2041                                     suppress_delete = suppress_forward = TRUE;
2042                                 else if (ok)
2043                                     goto cleanUp;
2044
2045                                 /* tell server we got it OK and resynchronize */
2046                                 if (protocol->trail)
2047                                 {
2048                                     if (outlevel >= O_VERBOSE)
2049                                     {
2050                                         fputc('\n', stdout);
2051                                         fflush(stdout);
2052                                     }
2053
2054                                     ok = (protocol->trail)(mailserver_socket, ctl, num);
2055                                     if (ok != 0)
2056                                         goto cleanUp;
2057                                 }
2058                             }
2059
2060                             /* count # messages forwarded on this pass */
2061                             if (!suppress_forward)
2062                                 dispatches++;
2063
2064                             /*
2065                              * Check to see if the numbers matched?
2066                              *
2067                              * Yes, some servers foo this up horribly.
2068                              * All IMAP servers seem to get it right, and
2069                              * so does Eudora QPOP at least in 2.xx
2070                              * versions.
2071                              *
2072                              * Microsoft Exchange gets it completely
2073                              * wrong, reporting compressed rather than
2074                              * actual sizes (so the actual length of
2075                              * message is longer than the reported size).
2076                              * Another fine example of Microsoft brain death!
2077                              *
2078                              * Some older POP servers, like the old UCB
2079                              * POP server and the pre-QPOP QUALCOMM
2080                              * versions, report a longer size in the LIST
2081                              * response than actually gets shipped up.
2082                              * It's unclear what is going on here, as the
2083                              * QUALCOMM server (at least) seems to be
2084                              * reporting the on-disk size correctly.
2085                              */
2086                             if (msgsizes && msglen != msgsizes[num-1])
2087                             {
2088                                 if (outlevel >= O_DEBUG)
2089                                     report(stdout,
2090                                           _("message %d was not the expected length (%d actual != %d expected)\n"),
2091                                           num, msglen, msgsizes[num-1]);
2092                             }
2093
2094                             /* end-of-message processing starts here */
2095                             if (!close_sink(ctl, &msgblk, !suppress_forward))
2096                             {
2097                                 ctl->errcount++;
2098                                 suppress_delete = TRUE;
2099                             }
2100                             fetches++;
2101                         }
2102
2103                         /*
2104                          * At this point in flow of control, either
2105                          * we've bombed on a protocol error or had
2106                          * delivery refused by the SMTP server
2107                          * (unlikely -- I've never seen it) or we've
2108                          * seen `accepted for delivery' and the
2109                          * message is shipped.  It's safe to mark the
2110                          * message seen and delete it on the server
2111                          * now.
2112                          */
2113
2114                         /* tell the UID code we've seen this */
2115                         if (ctl->newsaved)
2116                         {
2117                             struct idlist       *sdp;
2118
2119                             for (sdp = ctl->newsaved; sdp; sdp = sdp->next)
2120                                 if (sdp->val.status.num == num)
2121                                     sdp->val.status.mark = UID_SEEN;
2122                         }
2123
2124                         /* maybe we delete this message now? */
2125                         if (retained)
2126                         {
2127                             if (outlevel > O_SILENT) 
2128                                 report(stdout, _(" retained\n"));
2129                         }
2130                         else if (protocol->delete
2131                                  && !suppress_delete
2132                                  && (fetch_it ? !ctl->keep : ctl->flush))
2133                         {
2134                             deletions++;
2135                             if (outlevel > O_SILENT) 
2136                                 report_complete(stdout, _(" flushed\n"));
2137                             ok = (protocol->delete)(mailserver_socket, ctl, num);
2138                             if (ok != 0)
2139                                 goto cleanUp;
2140 #ifdef POP3_ENABLE
2141                             delete_str(&ctl->newsaved, num);
2142 #endif /* POP3_ENABLE */
2143                         }
2144                         else if (outlevel > O_SILENT) 
2145                             report_complete(stdout, _(" not flushed\n"));
2146
2147                         /* perhaps this as many as we're ready to handle */
2148                         if (maxfetch && maxfetch <= fetches && fetches < count)
2149                         {
2150                             report(stdout, _("fetchlimit %d reached; %d messages left on server\n"),
2151                                   maxfetch, count - fetches);
2152                             ok = PS_MAXFETCH;
2153                             goto cleanUp;
2154                         }
2155                     }
2156
2157                     if (!check_only && ctl->skipped
2158                         && run.poll_interval > 0 && !nodetach)
2159                     {
2160                         clean_skipped_list(&ctl->skipped);
2161                         send_size_warnings(ctl);
2162                     }
2163                 }
2164             } while
2165                   /*
2166                    * Only re-poll if we had some actual forwards, allowed
2167                    * deletions and had no errors.
2168                    * Otherwise it is far too easy to get into infinite loops.
2169                    */
2170                   (dispatches && protocol->retry && !ctl->keep && !ctl->errcount);
2171         }
2172
2173    no_error:
2174         /* ordinary termination with no errors -- officially log out */
2175         ok = (protocol->logout_cmd)(mailserver_socket, ctl);
2176         /*
2177          * Hmmmm...arguably this would be incorrect if we had fetches but
2178          * no dispatches (due to oversized messages, etc.)
2179          */
2180         if (ok == 0)
2181             ok = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
2182         SockClose(mailserver_socket);
2183         goto closeUp;
2184
2185     cleanUp:
2186         /* we only get here on error */
2187         if (ok != 0 && ok != PS_SOCKET)
2188             (protocol->logout_cmd)(mailserver_socket, ctl);
2189         SockClose(mailserver_socket);
2190     }
2191
2192     msg = (const char *)NULL;   /* sacrifice to -Wall */
2193     switch (ok)
2194     {
2195     case PS_SOCKET:
2196         msg = _("socket");
2197         break;
2198     case PS_AUTHFAIL:
2199         msg = _("authorization");
2200         break;
2201     case PS_SYNTAX:
2202         msg = _("missing or bad RFC822 header");
2203         break;
2204     case PS_IOERR:
2205         msg = _("MDA");
2206         break;
2207     case PS_ERROR:
2208         msg = _("client/server synchronization");
2209         break;
2210     case PS_PROTOCOL:
2211         msg = _("client/server protocol");
2212         break;
2213     case PS_LOCKBUSY:
2214         msg = _("lock busy on server");
2215         break;
2216     case PS_SMTP:
2217         msg = _("SMTP transaction");
2218         break;
2219     case PS_DNS:
2220         msg = _("DNS lookup");
2221         break;
2222     case PS_UNDEFINED:
2223         report(stderr, _("undefined error\n"));
2224         break;
2225     }
2226     /* no report on PS_MAXFETCH or PS_UNDEFINED */
2227     if (ok==PS_SOCKET || ok==PS_AUTHFAIL || ok==PS_SYNTAX 
2228                 || ok==PS_IOERR || ok==PS_ERROR || ok==PS_PROTOCOL 
2229                 || ok==PS_LOCKBUSY || ok==PS_SMTP || ok==PS_DNS)
2230         report(stderr, _("%s error while fetching from %s\n"), msg, ctl->server.pollname);
2231
2232 closeUp:
2233     /* execute post-initialization command, if any */
2234     if (ctl->postconnect && (ok = system(ctl->postconnect)))
2235     {
2236         report(stderr, _("post-connection command failed with status %d\n"), ok);
2237         if (ok == PS_SUCCESS)
2238             ok = PS_SYNTAX;
2239     }
2240
2241     signal(SIGALRM, alrmsave);
2242     signal(SIGPIPE, pipesave);
2243     return(ok);
2244 }
2245
2246 int do_protocol(ctl, proto)
2247 /* retrieve messages from server using given protocol method table */
2248 struct query *ctl;              /* parsed options with merged-in defaults */
2249 const struct method *proto;     /* protocol method table */
2250 {
2251     int ok;
2252
2253 #ifndef KERBEROS_V4
2254     if (ctl->server.preauthenticate == A_KERBEROS_V4)
2255     {
2256         report(stderr, _("Kerberos V4 support not linked.\n"));
2257         return(PS_ERROR);
2258     }
2259 #endif /* KERBEROS_V4 */
2260
2261 #ifndef KERBEROS_V5
2262     if (ctl->server.preauthenticate == A_KERBEROS_V5)
2263     {
2264         report(stderr, _("Kerberos V5 support not linked.\n"));
2265         return(PS_ERROR);
2266     }
2267 #endif /* KERBEROS_V5 */
2268
2269     /* lacking methods, there are some options that may fail */
2270     if (!proto->is_old)
2271     {
2272         /* check for unsupported options */
2273         if (ctl->flush) {
2274             report(stderr,
2275                     _("Option --flush is not supported with %s\n"),
2276                     proto->name);
2277             return(PS_SYNTAX);
2278         }
2279         else if (ctl->fetchall) {
2280             report(stderr,
2281                     _("Option --all is not supported with %s\n"),
2282                     proto->name);
2283             return(PS_SYNTAX);
2284         }
2285     }
2286     if (!proto->getsizes && NUM_SPECIFIED(ctl->limit))
2287     {
2288         report(stderr,
2289                 _("Option --limit is not supported with %s\n"),
2290                 proto->name);
2291         return(PS_SYNTAX);
2292     }
2293
2294     /*
2295      * If no expunge limit or we do expunges within the driver,
2296      * then just do one session, passing in any fetchlimit.
2297      */
2298     if (proto->retry || !NUM_SPECIFIED(ctl->expunge))
2299         return(do_session(ctl, proto, NUM_VALUE_OUT(ctl->fetchlimit)));
2300     /*
2301      * There's an expunge limit, and it isn't handled in the driver itself.
2302      * OK; do multiple sessions, each fetching a limited # of messages.
2303      * Stop if the total count of retrieved messages exceeds ctl->fetchlimit
2304      * (if it was nonzero).
2305      */
2306     else
2307     {
2308         int totalcount = 0; 
2309         int lockouts   = 0;
2310         int expunge    = NUM_VALUE_OUT(ctl->expunge);
2311         int fetchlimit = NUM_VALUE_OUT(ctl->fetchlimit);
2312
2313         do {
2314             ok = do_session(ctl, proto, expunge);
2315             totalcount += expunge;
2316             if (NUM_SPECIFIED(ctl->fetchlimit) && totalcount >= fetchlimit)
2317                 break;
2318             if (ok != PS_LOCKBUSY)
2319                 lockouts = 0;
2320             else if (lockouts >= MAX_LOCKOUTS)
2321                 break;
2322             else /* ok == PS_LOCKBUSY */
2323             {
2324                 /*
2325                  * Allow time for the server lock to release.  if we
2326                  * don't do this, we'll often hit a locked-mailbox
2327                  * condition and fail.
2328                  */
2329                 lockouts++;
2330                 sleep(3);
2331             }
2332         } while
2333             (ok == PS_MAXFETCH || ok == PS_LOCKBUSY);
2334
2335         return(ok);
2336     }
2337 }
2338
2339 #if defined(HAVE_STDARG_H)
2340 void gen_send(int sock, const char *fmt, ... )
2341 #else
2342 void gen_send(sock, fmt, va_alist)
2343 int sock;               /* socket to which server is connected */
2344 const char *fmt;        /* printf-style format */
2345 va_dcl
2346 #endif
2347 /* assemble command in printf(3) style and send to the server */
2348 {
2349     char buf [MSGBUFSIZE+1];
2350     va_list ap;
2351
2352     if (protocol->tagged)
2353         (void) sprintf(buf, "%s ", GENSYM);
2354     else
2355         buf[0] = '\0';
2356
2357 #if defined(HAVE_STDARG_H)
2358     va_start(ap, fmt) ;
2359 #else
2360     va_start(ap);
2361 #endif
2362 #ifdef HAVE_VSNPRINTF
2363     vsnprintf(buf + strlen(buf), sizeof(buf), fmt, ap);
2364 #else
2365     vsprintf(buf + strlen(buf), fmt, ap);
2366 #endif
2367     va_end(ap);
2368
2369     strcat(buf, "\r\n");
2370     SockWrite(sock, buf, strlen(buf));
2371
2372     if (outlevel >= O_MONITOR)
2373     {
2374         char *cp;
2375
2376         if (shroud && shroud[0] && (cp = strstr(buf, shroud)))
2377         {
2378             char        *sp;
2379
2380             sp = cp + strlen(shroud);
2381             *cp++ = '*';
2382             while (*sp)
2383                 *cp++ = *sp++;
2384             *cp = '\0';
2385         }
2386         buf[strlen(buf)-2] = '\0';
2387         report(stdout, "%s> %s\n", protocol->name, buf);
2388     }
2389 }
2390
2391 int gen_recv(sock, buf, size)
2392 /* get one line of input from the server */
2393 int sock;       /* socket to which server is connected */
2394 char *buf;      /* buffer to receive input */
2395 int size;       /* length of buffer */
2396 {
2397     int oldphase = phase;       /* we don't have to be re-entrant */
2398
2399     phase = SERVER_WAIT;
2400     set_timeout(mytimeout);
2401     if (SockRead(sock, buf, size) == -1)
2402     {
2403         set_timeout(0);
2404         phase = oldphase;
2405         return(PS_SOCKET);
2406     }
2407     else
2408     {
2409         set_timeout(0);
2410         if (buf[strlen(buf)-1] == '\n')
2411             buf[strlen(buf)-1] = '\0';
2412         if (buf[strlen(buf)-1] == '\r')
2413             buf[strlen(buf)-1] = '\0';
2414         if (outlevel >= O_MONITOR)
2415             report(stdout, "%s< %s\n", protocol->name, buf);
2416         phase = oldphase;
2417         return(PS_SUCCESS);
2418     }
2419 }
2420
2421 #if defined(HAVE_STDARG_H)
2422 int gen_transact(int sock, const char *fmt, ... )
2423 #else
2424 int gen_transact(int sock, fmt, va_alist)
2425 int sock;               /* socket to which server is connected */
2426 const char *fmt;        /* printf-style format */
2427 va_dcl
2428 #endif
2429 /* assemble command in printf(3) style, send to server, accept a response */
2430 {
2431     int ok;
2432     char buf [MSGBUFSIZE+1];
2433     va_list ap;
2434     int oldphase = phase;       /* we don't have to be re-entrant */
2435
2436     phase = SERVER_WAIT;
2437
2438     if (protocol->tagged)
2439         (void) sprintf(buf, "%s ", GENSYM);
2440     else
2441         buf[0] = '\0';
2442
2443 #if defined(HAVE_STDARG_H)
2444     va_start(ap, fmt) ;
2445 #else
2446     va_start(ap);
2447 #endif
2448 #ifdef HAVE_VSNPRINTF
2449     vsnprintf(buf + strlen(buf), sizeof(buf), fmt, ap);
2450 #else
2451     vsprintf(buf + strlen(buf), fmt, ap);
2452 #endif
2453     va_end(ap);
2454
2455     strcat(buf, "\r\n");
2456     SockWrite(sock, buf, strlen(buf));
2457
2458     if (outlevel >= O_MONITOR)
2459     {
2460         char *cp;
2461
2462         if (shroud && shroud[0] && (cp = strstr(buf, shroud)))
2463         {
2464             char        *sp;
2465
2466             sp = cp + strlen(shroud);
2467             *cp++ = '*';
2468             while (*sp)
2469                 *cp++ = *sp++;
2470             *cp = '\0';
2471         }
2472         buf[strlen(buf)-1] = '\0';
2473         report(stdout, "%s> %s\n", protocol->name, buf);
2474     }
2475
2476     /* we presume this does its own response echoing */
2477     ok = (protocol->parse_response)(sock, buf);
2478
2479     phase = oldphase;
2480     return(ok);
2481 }
2482
2483 /* driver.c ends here */