]> Pileus Git - ~andy/fetchmail/blob - driver.c
Shrouding is now done over a narrower scope.
[~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\r\n"));
1850                         stuff_warning(ctl,
1851                                       _("Fetchmail could not get mail from %s@%s.\r\n"), 
1852                                       ctl->remotename,
1853                                       ctl->server.truename);
1854                         if (ctl->wehaveauthed)
1855                             stuff_warning(ctl, _("\
1856 The attempt to get authorization failed.\r\n\
1857 Since we have already succeeded in getting authorization for this\r\n\
1858 connection, this is probably another failure mode (such as busy server)\r\n\
1859 that fetchmail cannot distinguish because the server didn't send a useful\r\n\
1860 error message.\r\n\
1861 \r\n\
1862 However, if you HAVE changed you account details since starting the\r\n\
1863 fetchmail daemon, you need to stop the daemon, change your configuration\r\n\
1864 of fetchmail, and then restart the daemon.\r\n\
1865 \r\n\
1866 The fetchmail daemon will continue running and attempt to connect\r\n\
1867 at each cycle.  No future notifications will be sent until service\r\n\
1868 is restored."));
1869                         else
1870                             stuff_warning(ctl, _("\
1871 The attempt to get authorization failed.\r\n\
1872 This probably means your password is invalid, but some servers have\r\n\
1873 other failure modes that fetchmail cannot distinguish from this\r\n\
1874 because they don't send useful error messages on login failure.\r\n\
1875 \r\n\
1876 The fetchmail daemon will continue running and attempt to connect\r\n\
1877 at each cycle.  No future notifications will be sent until service\r\n\
1878 is restored."));
1879                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1880                     }
1881                 }
1882                 else
1883                     report(stderr, _("Unknown login or authentication error on %s@%s\n"),
1884                            ctl->remotename,
1885                            ctl->server.truename);
1886                     
1887                 goto cleanUp;
1888             }
1889             else
1890             {
1891                 /*
1892                  * This connection has given us authorization at least once.
1893                  *
1894                  * There are dodgy server (clubinternet.fr for example) that
1895                  * give spurious authorization failures on patently good
1896                  * account/password details, then 5 minutes later let you in!
1897                  *
1898                  * This is meant to build in some tolerance of such nasty bits
1899                  * of work.
1900                  */
1901                 ctl->wehaveauthed = 1;
1902                 /*if (ctl->authfailcount >= 3)*/
1903                 if (ctl->wehavesentauthnote)
1904                 {
1905                     ctl->wehavesentauthnote = 0;
1906                     report(stderr,
1907                            _("Authorization OK on %s@%s\n"),
1908                            ctl->remotename,
1909                            ctl->server.truename);
1910                     if (!open_warning_by_mail(ctl, (struct msgblk *)NULL))
1911                     {
1912                         stuff_warning(ctl,
1913                               _("Subject: fetchmail authentication OK\r\n"));
1914                         stuff_warning(ctl,
1915                               _("Fetchmail was able to log into %s@%s.\r\n"), 
1916                                       ctl->remotename,
1917                                       ctl->server.truename);
1918                         stuff_warning(ctl, 
1919                                       _("Service has been restored.\r\n"));
1920                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1921                     
1922                     }
1923                 }
1924                 /*
1925                  * Reporting only after the first three
1926                  * consecutive failures, or ten consecutive
1927                  * failures after we have managed to get
1928                  * authorization.
1929                  */
1930                 ctl->authfailcount = 0;
1931             }
1932         }
1933
1934         ctl->errcount = fetches = 0;
1935
1936         /* now iterate over each folder selected */
1937         for (idp = ctl->mailboxes; idp; idp = idp->next)
1938         {
1939             pass = 0;
1940             do {
1941                 dispatches = 0;
1942                 ++pass;
1943
1944                 /* reset timeout, in case we did an IDLE */
1945                 mytimeout = ctl->server.timeout;
1946
1947                 if (outlevel >= O_DEBUG)
1948                 {
1949                     if (idp->id)
1950                         report(stdout, _("selecting or re-polling folder %s\n"), idp->id);
1951                     else
1952                         report(stdout, _("selecting or re-polling default folder\n"));
1953                 }
1954
1955                 /* compute # of messages and number of new messages waiting */
1956                 stage = STAGE_GETRANGE;
1957                 ok = (protocol->getrange)(mailserver_socket, ctl, idp->id, &count, &new, &bytes);
1958                 if (ok != 0)
1959                     goto cleanUp;
1960
1961                 /* show user how many messages we downloaded */
1962                 if (idp->id)
1963                     (void) sprintf(buf, _("%s at %s (folder %s)"),
1964                                    ctl->remotename, ctl->server.truename, idp->id);
1965                 else
1966                     (void) sprintf(buf, _("%s at %s"),
1967                                    ctl->remotename, ctl->server.truename);
1968                 if (outlevel > O_SILENT)
1969                 {
1970                     if (count == -1)            /* only used for ETRN */
1971                         report(stdout, _("Polling %s\n"), ctl->server.truename);
1972                     else if (count != 0)
1973                     {
1974                         if (new != -1 && (count - new) > 0)
1975                             report_build(stdout, _("%d %s (%d seen) for %s"),
1976                                   count, count > 1 ? _("messages") :
1977                                                      _("message"),
1978                                   count-new, buf);
1979                         else
1980                             report_build(stdout, _("%d %s for %s"), 
1981                                   count, count > 1 ? _("messages") :
1982                                                      _("message"), buf);
1983                         if (bytes == -1)
1984                             report_complete(stdout, ".\n");
1985                         else
1986                             report_complete(stdout, _(" (%d octets).\n"), bytes);
1987                     }
1988                     else
1989                     {
1990                         /* these are pointless in normal daemon mode */
1991                         if (pass == 1 && (run.poll_interval == 0 || outlevel >= O_VERBOSE))
1992                             report(stdout, _("No mail for %s\n"), buf); 
1993                     }
1994                 }
1995
1996                 /* very important, this is where we leave the do loop */ 
1997                 if (count == 0)
1998                     break;
1999
2000                 if (check_only)
2001                 {
2002                     if (new == -1 || ctl->fetchall)
2003                         new = count;
2004                     fetches = new;      /* set error status ccorrectly */
2005                     /*
2006                      * There used to be a `got noerror' here, but this
2007                      * prevneted checking of multiple folders.  This
2008                      * comment is a reminder in case I introduced some
2009                      * subtle bug by removing it...
2010                      */
2011                 }
2012                 else if (count > 0)
2013                 {    
2014                     flag        force_retrieval;
2015
2016                     /*
2017                      * What forces this code is that in POP2 and
2018                      * IMAP2bis you can't fetch a message without
2019                      * having it marked `seen'.  In POP3 and IMAP4, on the
2020                      * other hand, you can (peek_capable is set by 
2021                      * each driver module to convey this; it's not a
2022                      * method constant because of the difference between
2023                      * IMAP2bis and IMAP4, and because POP3 doesn't  peek
2024                      * if fetchall is on).
2025                      *
2026                      * The result of being unable to peek is that if there's
2027                      * any kind of transient error (DNS lookup failure, or
2028                      * sendmail refusing delivery due to process-table limits)
2029                      * the message will be marked "seen" on the server without
2030                      * having been delivered.  This is not a big problem if
2031                      * fetchmail is running in foreground, because the user
2032                      * will see a "skipped" message when it next runs and get
2033                      * clued in.
2034                      *
2035                      * But in daemon mode this leads to the message
2036                      * being silently ignored forever.  This is not
2037                      * acceptable.
2038                      *
2039                      * We compensate for this by checking the error
2040                      * count from the previous pass and forcing all
2041                      * messages to be considered new if it's nonzero.
2042                      */
2043                     force_retrieval = !peek_capable && (ctl->errcount > 0);
2044
2045                     /* 
2046                      * We need the size of each message before it's
2047                      * loaded in order to pass it to the ESMTP SIZE
2048                      * option.  If the protocol has a getsizes method,
2049                      * we presume this means it doesn't get reliable
2050                      * sizes from message fetch responses.
2051                      */
2052                     if (proto->getsizes)
2053                     {
2054                         int     i;
2055
2056                         xalloca(msgsizes, int *, sizeof(int) * count);
2057                         for (i = 0; i < count; i++)
2058                             msgsizes[i] = -1;
2059
2060                         stage = STAGE_GETSIZES;
2061                         ok = (proto->getsizes)(mailserver_socket, count, msgsizes);
2062                         if (ok != 0)
2063                             goto cleanUp;
2064
2065                         if (bytes == -1)
2066                         {
2067                             bytes = 0;
2068                             for (i = 0; i < count; i++)
2069                                 bytes += msgsizes[i];
2070                         }
2071                     }
2072
2073                     /* read, forward, and delete messages */
2074                     stage = STAGE_FETCH;
2075                     for (num = 1; num <= count; num++)
2076                     {
2077                         flag toolarge = NUM_NONZERO(ctl->limit)
2078                             && msgsizes && (msgsizes[num-1] > ctl->limit);
2079                         flag oldmsg = (!new) || (protocol->is_old && (protocol->is_old)(mailserver_socket,ctl,num));
2080                         flag fetch_it = !toolarge 
2081                             && (ctl->fetchall || force_retrieval || !oldmsg);
2082                         flag suppress_delete = FALSE;
2083                         flag suppress_forward = FALSE;
2084                         flag suppress_readbody = FALSE;
2085                         flag retained = FALSE;
2086
2087                         /*
2088                          * This check copes with Post Office/NT's
2089                          * annoying habit of randomly prepending bogus
2090                          * LIST items of length -1.  Patrick Audley
2091                          * <paudley@pobox.com> tells us: LIST shows a
2092                          * size of -1, RETR and TOP return "-ERR
2093                          * System error - couldn't open message", and
2094                          * DELE succeeds but doesn't actually delete
2095                          * the message.
2096                          */
2097                         if (msgsizes && msgsizes[num-1] == -1)
2098                         {
2099                             if (outlevel >= O_VERBOSE)
2100                                 report(stdout, 
2101                                       _("Skipping message %d, length -1\n"),
2102                                       num);
2103                             continue;
2104                         }
2105
2106                         /*
2107                          * We may want to reject this message if it's old
2108                          * or oversized, and we're not forcing retrieval.
2109                          */
2110                         if (!fetch_it)
2111                         {
2112                             if (outlevel > O_SILENT)
2113                             {
2114                                 report_build(stdout, 
2115                                      _("skipping message %d (%d octets)"),
2116                                      num, msgsizes[num-1]);
2117                                 if (toolarge && !check_only) 
2118                                 {
2119                                     char size[32];
2120                                     int cnt;
2121
2122                                     /* convert sz to string */
2123                                     sprintf(size, "%d", msgsizes[num-1]);
2124
2125                                     /* build a list of skipped messages
2126                                      * val.id = size of msg (string cnvt)
2127                                      * val.status.num = warning_poll_count
2128                                      * val.status.mask = nbr of msg this size
2129                                      */
2130
2131                                     current = ctl->skipped;
2132
2133                                     /* initialise warning_poll_count to the
2134                                      * current value so that all new msg will
2135                                      * be included in the next mail
2136                                      */
2137                                     cnt = current? current->val.status.num : 0;
2138
2139                                     /* if entry exists, increment the count */
2140                                     if (current && 
2141                                         str_in_list(&current, size, FALSE))
2142                                     {
2143                                         for ( ; current; 
2144                                                 current = current->next)
2145                                         {
2146                                             if (strcmp(current->id, size) == 0)
2147                                             {
2148                                                 current->val.status.mark++;
2149                                                 break;
2150                                             }
2151                                         }
2152                                     }
2153                                     /* otherwise, create a new entry */
2154                                     /* initialise with current poll count */
2155                                     else
2156                                     {
2157                                         tmp = save_str(&ctl->skipped, size, 1);
2158                                         tmp->val.status.num = cnt;
2159                                     }
2160
2161                                     report_build(stdout, _(" (oversized, %d octets)"),
2162                                                 msgsizes[num-1]);
2163                                 }
2164                             }
2165                         }
2166                         else
2167                         {
2168                             flag wholesize = !protocol->fetch_body;
2169
2170                             /* request a message */
2171                             ok = (protocol->fetch_headers)(mailserver_socket,ctl,num, &len);
2172                             if (ok != 0)
2173                                 goto cleanUp;
2174
2175                             /* -1 means we didn't see a size in the response */
2176                             if (len == -1 && msgsizes)
2177                             {
2178                                 len = msgsizes[num - 1];
2179                                 wholesize = TRUE;
2180                             }
2181
2182                             if (outlevel > O_SILENT)
2183                             {
2184                                 report_build(stdout, _("reading message %d of %d"),
2185                                             num,count);
2186
2187                                 if (len > 0)
2188                                     report_build(stdout, _(" (%d %soctets)"),
2189                                         len, wholesize ? "" : _("header "));
2190                                 if (outlevel >= O_VERBOSE)
2191                                     report_complete(stdout, "\n");
2192                                 else
2193                                     report_complete(stdout, " ");
2194                             }
2195
2196                             /* 
2197                              * Read the message headers and ship them to the
2198                              * output sink.  
2199                              */
2200                             ok = readheaders(mailserver_socket, len, msgsizes[num-1],
2201                                              ctl, num);
2202                             if (ok == PS_RETAINED)
2203                                 suppress_forward = retained = TRUE;
2204                             else if (ok == PS_TRANSIENT)
2205                                 suppress_delete = suppress_forward = TRUE;
2206                             else if (ok == PS_REFUSED)
2207                                 suppress_forward = TRUE;
2208                             else if (ok == PS_TRUNCATED)
2209                                 suppress_readbody = TRUE;
2210                             else if (ok)
2211                                 goto cleanUp;
2212
2213                             /* 
2214                              * If we're using IMAP4 or something else that
2215                              * can fetch headers separately from bodies,
2216                              * it's time to request the body now.  This
2217                              * fetch may be skipped if we got an anti-spam
2218                              * or other PS_REFUSED error response during
2219                              * readheaders.
2220                              */
2221                             if (protocol->fetch_body && !suppress_readbody) 
2222                             {
2223                                 if (outlevel >= O_VERBOSE && !isafile(1))
2224                                 {
2225                                     fputc('\n', stdout);
2226                                     fflush(stdout);
2227                                 }
2228
2229                                 if ((ok = (protocol->trail)(mailserver_socket, ctl, num)))
2230                                     goto cleanUp;
2231                                 len = 0;
2232                                 if (!suppress_forward)
2233                                 {
2234                                     if ((ok=(protocol->fetch_body)(mailserver_socket,ctl,num,&len)))
2235                                         goto cleanUp;
2236                                     /*
2237                                      * Work around a bug in Novell's
2238                                      * broken GroupWise IMAP server;
2239                                      * its body FETCH response is missing
2240                                      * the required length for the data
2241                                      * string.  This violates RFC2060.
2242                                      */
2243                                     if (len == -1)
2244                                        len = msgsizes[num-1] - msglen;
2245                                     if (outlevel > O_SILENT && !wholesize)
2246                                         report_complete(stdout,
2247                                                _(" (%d body octets) "), len);
2248                                 }
2249                             }
2250
2251                             /* process the body now */
2252                             if (len > 0)
2253                             {
2254                                 if (suppress_readbody)
2255                                 {
2256                                   /* When readheaders returns PS_TRUNCATED,
2257                                      the body (which has no content
2258                                      has already been read by readheaders,
2259                                      so we say readbody returned PS_SUCCESS */
2260                                   ok = PS_SUCCESS;
2261                                 }
2262                                 else
2263                                 {
2264                                   ok = readbody(mailserver_socket,
2265                                                 ctl,
2266                                                 !suppress_forward,
2267                                                 len);
2268                                 }
2269                                 if (ok == PS_TRANSIENT)
2270                                     suppress_delete = suppress_forward = TRUE;
2271                                 else if (ok)
2272                                     goto cleanUp;
2273
2274                                 /* tell server we got it OK and resynchronize */
2275                                 if (protocol->trail)
2276                                 {
2277                                     if (outlevel >= O_VERBOSE && !isafile(1))
2278                                     {
2279                                         fputc('\n', stdout);
2280                                         fflush(stdout);
2281                                     }
2282
2283                                     ok = (protocol->trail)(mailserver_socket, ctl, num);
2284                                     if (ok != 0)
2285                                         goto cleanUp;
2286                                 }
2287                             }
2288
2289                             /* count # messages forwarded on this pass */
2290                             if (!suppress_forward)
2291                                 dispatches++;
2292
2293                             /*
2294                              * Check to see if the numbers matched?
2295                              *
2296                              * Yes, some servers foo this up horribly.
2297                              * All IMAP servers seem to get it right, and
2298                              * so does Eudora QPOP at least in 2.xx
2299                              * versions.
2300                              *
2301                              * Microsoft Exchange gets it completely
2302                              * wrong, reporting compressed rather than
2303                              * actual sizes (so the actual length of
2304                              * message is longer than the reported size).
2305                              * Another fine example of Microsoft brain death!
2306                              *
2307                              * Some older POP servers, like the old UCB
2308                              * POP server and the pre-QPOP QUALCOMM
2309                              * versions, report a longer size in the LIST
2310                              * response than actually gets shipped up.
2311                              * It's unclear what is going on here, as the
2312                              * QUALCOMM server (at least) seems to be
2313                              * reporting the on-disk size correctly.
2314                              */
2315                             if (msgsizes && msglen != msgsizes[num-1])
2316                             {
2317                                 if (outlevel >= O_DEBUG)
2318                                     report(stdout,
2319                                           _("message %d was not the expected length (%d actual != %d expected)\n"),
2320                                           num, msglen, msgsizes[num-1]);
2321                             }
2322
2323                             /* end-of-message processing starts here */
2324                             if (!close_sink(ctl, &msgblk, !suppress_forward))
2325                             {
2326                                 ctl->errcount++;
2327                                 suppress_delete = TRUE;
2328                             }
2329                             fetches++;
2330                         }
2331
2332                         /*
2333                          * At this point in flow of control, either
2334                          * we've bombed on a protocol error or had
2335                          * delivery refused by the SMTP server
2336                          * (unlikely -- I've never seen it) or we've
2337                          * seen `accepted for delivery' and the
2338                          * message is shipped.  It's safe to mark the
2339                          * message seen and delete it on the server
2340                          * now.
2341                          */
2342
2343                         /* tell the UID code we've seen this */
2344                         if (ctl->newsaved)
2345                         {
2346                             struct idlist       *sdp;
2347
2348                             for (sdp = ctl->newsaved; sdp; sdp = sdp->next)
2349                                 if ((sdp->val.status.num == num)
2350                                                 && (!toolarge || oldmsg))
2351                                     sdp->val.status.mark = UID_SEEN;
2352                         }
2353
2354                         /* maybe we delete this message now? */
2355                         if (retained)
2356                         {
2357                             if (outlevel > O_SILENT) 
2358                                 report(stdout, _(" retained\n"));
2359                         }
2360                         else if (protocol->delete
2361                                  && !suppress_delete
2362                                  && (fetch_it ? !ctl->keep : ctl->flush))
2363                         {
2364                             deletions++;
2365                             if (outlevel > O_SILENT) 
2366                                 report_complete(stdout, _(" flushed\n"));
2367                             ok = (protocol->delete)(mailserver_socket, ctl, num);
2368                             if (ok != 0)
2369                                 goto cleanUp;
2370 #ifdef POP3_ENABLE
2371                             delete_str(&ctl->newsaved, num);
2372 #endif /* POP3_ENABLE */
2373                         }
2374                         else if (outlevel > O_SILENT) 
2375                             report_complete(stdout, _(" not flushed\n"));
2376
2377                         /* perhaps this as many as we're ready to handle */
2378                         if (maxfetch && maxfetch <= fetches && fetches < count)
2379                         {
2380                             report(stdout, _("fetchlimit %d reached; %d messages left on server\n"),
2381                                   maxfetch, count - fetches);
2382                             ok = PS_MAXFETCH;
2383                             goto cleanUp;
2384                         }
2385                     }
2386
2387                     if (!check_only && ctl->skipped
2388                         && run.poll_interval > 0 && !nodetach)
2389                     {
2390                         clean_skipped_list(&ctl->skipped);
2391                         send_size_warnings(ctl);
2392                     }
2393                 }
2394             } while
2395                   /*
2396                    * Only re-poll if we either had some actual forwards and 
2397                    * either allowed deletions and had no errors.
2398                    * Otherwise it is far too easy to get into infinite loops.
2399                    */
2400                   (dispatches && protocol->retry && !ctl->keep && !ctl->errcount);
2401         }
2402
2403     /* no_error: */
2404         /* ordinary termination with no errors -- officially log out */
2405         ok = (protocol->logout_cmd)(mailserver_socket, ctl);
2406         /*
2407          * Hmmmm...arguably this would be incorrect if we had fetches but
2408          * no dispatches (due to oversized messages, etc.)
2409          */
2410         if (ok == 0)
2411             ok = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
2412         SockClose(mailserver_socket);
2413         goto closeUp;
2414
2415     cleanUp:
2416         /* we only get here on error */
2417         if (ok != 0 && ok != PS_SOCKET)
2418         {
2419             stage = STAGE_LOGOUT;
2420             (protocol->logout_cmd)(mailserver_socket, ctl);
2421         }
2422         SockClose(mailserver_socket);
2423     }
2424
2425     msg = (const char *)NULL;   /* sacrifice to -Wall */
2426     switch (ok)
2427     {
2428     case PS_SOCKET:
2429         msg = _("socket");
2430         break;
2431     case PS_SYNTAX:
2432         msg = _("missing or bad RFC822 header");
2433         break;
2434     case PS_IOERR:
2435         msg = _("MDA");
2436         break;
2437     case PS_ERROR:
2438         msg = _("client/server synchronization");
2439         break;
2440     case PS_PROTOCOL:
2441         msg = _("client/server protocol");
2442         break;
2443     case PS_LOCKBUSY:
2444         msg = _("lock busy on server");
2445         break;
2446     case PS_SMTP:
2447         msg = _("SMTP transaction");
2448         break;
2449     case PS_DNS:
2450         msg = _("DNS lookup");
2451         break;
2452     case PS_UNDEFINED:
2453         report(stderr, _("undefined error\n"));
2454         break;
2455     }
2456     /* no report on PS_MAXFETCH or PS_UNDEFINED or PS_AUTHFAIL */
2457     if (ok==PS_SOCKET || ok==PS_SYNTAX
2458                 || ok==PS_IOERR || ok==PS_ERROR || ok==PS_PROTOCOL 
2459                 || ok==PS_LOCKBUSY || ok==PS_SMTP || ok==PS_DNS)
2460     {
2461         char    *stem;
2462
2463         if (phase == FORWARDING_WAIT || phase == LISTENER_WAIT)
2464             stem = _("%s error while delivering to SMTP host %s\n");
2465         else
2466             stem = _("%s error while fetching from %s\n");
2467         report(stderr, stem, msg, ctl->server.pollname);
2468     }
2469
2470 closeUp:
2471     /* execute wrapup command, if any */
2472     if (ctl->postconnect && (ok = system(ctl->postconnect)))
2473     {
2474         report(stderr, _("post-connection command failed with status %d\n"), ok);
2475         if (ok == PS_SUCCESS)
2476             ok = PS_SYNTAX;
2477     }
2478
2479     signal(SIGALRM, alrmsave);
2480     signal(SIGPIPE, pipesave);
2481     return(ok);
2482 }
2483
2484 int do_protocol(ctl, proto)
2485 /* retrieve messages from server using given protocol method table */
2486 struct query *ctl;              /* parsed options with merged-in defaults */
2487 const struct method *proto;     /* protocol method table */
2488 {
2489     int ok;
2490
2491 #ifndef KERBEROS_V4
2492     if (ctl->server.authenticate == A_KERBEROS_V4)
2493     {
2494         report(stderr, _("Kerberos V4 support not linked.\n"));
2495         return(PS_ERROR);
2496     }
2497 #endif /* KERBEROS_V4 */
2498
2499 #ifndef KERBEROS_V5
2500     if (ctl->server.authenticate == A_KERBEROS_V5)
2501     {
2502         report(stderr, _("Kerberos V5 support not linked.\n"));
2503         return(PS_ERROR);
2504     }
2505 #endif /* KERBEROS_V5 */
2506
2507     /* lacking methods, there are some options that may fail */
2508     if (!proto->is_old)
2509     {
2510         /* check for unsupported options */
2511         if (ctl->flush) {
2512             report(stderr,
2513                     _("Option --flush is not supported with %s\n"),
2514                     proto->name);
2515             return(PS_SYNTAX);
2516         }
2517         else if (ctl->fetchall) {
2518             report(stderr,
2519                     _("Option --all is not supported with %s\n"),
2520                     proto->name);
2521             return(PS_SYNTAX);
2522         }
2523     }
2524     if (!proto->getsizes && NUM_SPECIFIED(ctl->limit))
2525     {
2526         report(stderr,
2527                 _("Option --limit is not supported with %s\n"),
2528                 proto->name);
2529         return(PS_SYNTAX);
2530     }
2531
2532     /*
2533      * If no expunge limit or we do expunges within the driver,
2534      * then just do one session, passing in any fetchlimit.
2535      */
2536     if (proto->retry || !NUM_SPECIFIED(ctl->expunge))
2537         return(do_session(ctl, proto, NUM_VALUE_OUT(ctl->fetchlimit)));
2538     /*
2539      * There's an expunge limit, and it isn't handled in the driver itself.
2540      * OK; do multiple sessions, each fetching a limited # of messages.
2541      * Stop if the total count of retrieved messages exceeds ctl->fetchlimit
2542      * (if it was nonzero).
2543      */
2544     else
2545     {
2546         int totalcount = 0; 
2547         int lockouts   = 0;
2548         int expunge    = NUM_VALUE_OUT(ctl->expunge);
2549         int fetchlimit = NUM_VALUE_OUT(ctl->fetchlimit);
2550
2551         do {
2552             ok = do_session(ctl, proto, expunge);
2553             totalcount += expunge;
2554             if (NUM_SPECIFIED(ctl->fetchlimit) && totalcount >= fetchlimit)
2555                 break;
2556             if (ok != PS_LOCKBUSY)
2557                 lockouts = 0;
2558             else if (lockouts >= MAX_LOCKOUTS)
2559                 break;
2560             else /* ok == PS_LOCKBUSY */
2561             {
2562                 /*
2563                  * Allow time for the server lock to release.  if we
2564                  * don't do this, we'll often hit a locked-mailbox
2565                  * condition and fail.
2566                  */
2567                 lockouts++;
2568                 sleep(3);
2569             }
2570         } while
2571             (ok == PS_MAXFETCH || ok == PS_LOCKBUSY);
2572
2573         return(ok);
2574     }
2575 }
2576
2577 #if defined(HAVE_STDARG_H)
2578 void gen_send(int sock, const char *fmt, ... )
2579 #else
2580 void gen_send(sock, fmt, va_alist)
2581 int sock;               /* socket to which server is connected */
2582 const char *fmt;        /* printf-style format */
2583 va_dcl
2584 #endif
2585 /* assemble command in printf(3) style and send to the server */
2586 {
2587     char buf [MSGBUFSIZE+1];
2588     va_list ap;
2589
2590     if (protocol->tagged && !suppress_tags)
2591         (void) sprintf(buf, "%s ", GENSYM);
2592     else
2593         buf[0] = '\0';
2594
2595 #if defined(HAVE_STDARG_H)
2596     va_start(ap, fmt) ;
2597 #else
2598     va_start(ap);
2599 #endif
2600 #ifdef HAVE_VSNPRINTF
2601     vsnprintf(buf + strlen(buf), sizeof(buf), fmt, ap);
2602 #else
2603     vsprintf(buf + strlen(buf), fmt, ap);
2604 #endif
2605     va_end(ap);
2606
2607     strcat(buf, "\r\n");
2608     SockWrite(sock, buf, strlen(buf));
2609
2610     if (outlevel >= O_MONITOR)
2611     {
2612         char *cp;
2613
2614         if (shroud[0] && (cp = strstr(buf, shroud)))
2615         {
2616             char        *sp;
2617
2618             sp = cp + strlen(shroud);
2619             *cp++ = '*';
2620             while (*sp)
2621                 *cp++ = *sp++;
2622             *cp = '\0';
2623         }
2624         buf[strlen(buf)-2] = '\0';
2625         report(stdout, "%s> %s\n", protocol->name, buf);
2626     }
2627 }
2628
2629 int gen_recv(sock, buf, size)
2630 /* get one line of input from the server */
2631 int sock;       /* socket to which server is connected */
2632 char *buf;      /* buffer to receive input */
2633 int size;       /* length of buffer */
2634 {
2635     int oldphase = phase;       /* we don't have to be re-entrant */
2636
2637     phase = SERVER_WAIT;
2638     set_timeout(mytimeout);
2639     if (SockRead(sock, buf, size) == -1)
2640     {
2641         set_timeout(0);
2642         phase = oldphase;
2643         return(PS_SOCKET);
2644     }
2645     else
2646     {
2647         set_timeout(0);
2648         if (buf[strlen(buf)-1] == '\n')
2649             buf[strlen(buf)-1] = '\0';
2650         if (buf[strlen(buf)-1] == '\r')
2651             buf[strlen(buf)-1] = '\0';
2652         if (outlevel >= O_MONITOR)
2653             report(stdout, "%s< %s\n", protocol->name, buf);
2654         phase = oldphase;
2655         return(PS_SUCCESS);
2656     }
2657 }
2658
2659 #if defined(HAVE_STDARG_H)
2660 int gen_transact(int sock, const char *fmt, ... )
2661 #else
2662 int gen_transact(int sock, fmt, va_alist)
2663 int sock;               /* socket to which server is connected */
2664 const char *fmt;        /* printf-style format */
2665 va_dcl
2666 #endif
2667 /* assemble command in printf(3) style, send to server, accept a response */
2668 {
2669     int ok;
2670     char buf [MSGBUFSIZE+1];
2671     va_list ap;
2672     int oldphase = phase;       /* we don't have to be re-entrant */
2673
2674     phase = SERVER_WAIT;
2675
2676     if (protocol->tagged && !suppress_tags)
2677         (void) sprintf(buf, "%s ", GENSYM);
2678     else
2679         buf[0] = '\0';
2680
2681 #if defined(HAVE_STDARG_H)
2682     va_start(ap, fmt) ;
2683 #else
2684     va_start(ap);
2685 #endif
2686 #ifdef HAVE_VSNPRINTF
2687     vsnprintf(buf + strlen(buf), sizeof(buf), fmt, ap);
2688 #else
2689     vsprintf(buf + strlen(buf), fmt, ap);
2690 #endif
2691     va_end(ap);
2692
2693     strcat(buf, "\r\n");
2694     SockWrite(sock, buf, strlen(buf));
2695
2696     if (outlevel >= O_MONITOR)
2697     {
2698         char *cp;
2699
2700         if (shroud && shroud[0] && (cp = strstr(buf, shroud)))
2701         {
2702             char        *sp;
2703
2704             sp = cp + strlen(shroud);
2705             *cp++ = '*';
2706             while (*sp)
2707                 *cp++ = *sp++;
2708             *cp = '\0';
2709         }
2710         buf[strlen(buf)-1] = '\0';
2711         report(stdout, "%s> %s\n", protocol->name, buf);
2712     }
2713
2714     /* we presume this does its own response echoing */
2715     ok = (protocol->parse_response)(sock, buf);
2716
2717     phase = oldphase;
2718     return(ok);
2719 }
2720
2721 /* driver.c ends here */