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