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