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