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