]> Pileus Git - ~andy/fetchmail/blob - driver.c
Sunil Shetye's header-read fix.
[~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  <string.h>
13 #ifdef HAVE_MEMORY_H
14 #include  <memory.h>
15 #endif /* HAVE_MEMORY_H */
16 #if defined(STDC_HEADERS)
17 #include  <stdlib.h>
18 #include  <limits.h>
19 #endif
20 #if defined(HAVE_UNISTD_H)
21 #include <unistd.h>
22 #endif
23 #if defined(HAVE_SYS_ITIMER_H)
24 #include <sys/itimer.h>
25 #endif
26 #include  <sys/time.h>
27 #include  <signal.h>
28 #ifdef HAVE_SYS_WAIT_H
29 #include <sys/wait.h>
30 #endif
31
32 #ifdef HAVE_NET_SOCKET_H
33 #include <net/socket.h>
34 #endif
35 #ifdef HESIOD
36 #include <hesiod.h>
37 #endif
38
39 #if defined(HAVE_RES_SEARCH) || defined(HAVE_GETHOSTBYNAME)
40 #include <netdb.h>
41 #include "mx.h"
42 #endif /* defined(HAVE_RES_SEARCH) || defined(HAVE_GETHOSTBYNAME) */
43
44 #include "kerberos.h"
45 #ifdef KERBEROS_V4
46 #include <netinet/in.h>
47 #endif /* KERBEROS_V4 */
48
49 #include "i18n.h"
50 #include "socket.h"
51
52 #include "fetchmail.h"
53 #include "tunable.h"
54
55 /* throw types for runtime errors */
56 #define THROW_TIMEOUT   1               /* server timed out */
57 #define THROW_SIGPIPE   2               /* SIGPIPE on stream socket */
58
59 /* magic values for the message length array */
60 #define MSGLEN_UNKNOWN  0               /* length unknown (0 is impossible) */
61 #define MSGLEN_INVALID  -1              /* length passed back is invalid */
62 #define MSGLEN_TOOLARGE -2              /* message is too large */
63 #define MSGLEN_OLD      -3              /* message is old */
64
65 int pass;               /* how many times have we re-polled? */
66 int stage;              /* where are we? */
67 int phase;              /* where are we, for error-logging purposes? */
68 int batchcount;         /* count of messages sent in current batch */
69 flag peek_capable;      /* can we peek for better error recovery? */
70 int mailserver_socket_temp = -1;        /* socket to free if connect timeout */ 
71
72 static int timeoutcount;                /* count consecutive timeouts */
73
74 static jmp_buf  restart;
75
76 void set_timeout(int timeleft)
77 /* reset the nonresponse-timeout */
78 {
79 #if !defined(__EMX__) && !defined(__BEOS__) 
80     struct itimerval ntimeout;
81
82     if (timeleft == 0)
83         timeoutcount = 0;
84
85     ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
86     ntimeout.it_value.tv_sec  = timeleft;
87     ntimeout.it_value.tv_usec = 0;
88     setitimer(ITIMER_REAL, &ntimeout, (struct itimerval *)NULL);
89 #endif
90 }
91
92 static void timeout_handler (int signal)
93 /* handle SIGALRM signal indicating a server timeout */
94 {
95     timeoutcount++;
96     longjmp(restart, THROW_TIMEOUT);
97 }
98
99 static void sigpipe_handler (int signal)
100 /* handle SIGPIPE signal indicating a broken stream socket */
101 {
102     longjmp(restart, THROW_SIGPIPE);
103 }
104
105 /* ignore SIGALRM signal indicating a timeout during cleanup */
106 static void cleanup_timeout_handler (int signal) { }
107
108 #define CLEANUP_TIMEOUT 60 /* maximum timeout during cleanup */
109
110 static int cleanupSockClose (int fd)
111 /* close sockets in maximum CLEANUP_TIMEOUT seconds during cleanup */
112 {
113     int scerror;
114     void (*alrmsave)(int);
115     alrmsave = signal(SIGALRM, cleanup_timeout_handler);
116     set_timeout(CLEANUP_TIMEOUT);
117     scerror = SockClose(fd);
118     set_timeout(0);
119     signal(SIGALRM, alrmsave);
120     return (scerror);
121 }
122
123 #ifdef KERBEROS_V4
124 static int kerberos_auth(socket, canonical, principal) 
125 /* authenticate to the server host using Kerberos V4 */
126 int socket;             /* socket to server host */
127 char *canonical;        /* server name */
128 char *principal;
129 {
130     char * host_primary;
131     KTEXT ticket;
132     MSG_DAT msg_data;
133     CREDENTIALS cred;
134     Key_schedule schedule;
135     int rem;
136     char * prin_copy = (char *) NULL;
137     char * prin = (char *) NULL;
138     char * inst = (char *) NULL;
139     char * realm = (char *) NULL;
140
141     if (principal != (char *)NULL && *principal)
142     {
143         char *cp;
144         prin = prin_copy = xstrdup(principal);
145         for (cp = prin_copy; *cp && *cp != '.'; ++cp)
146             ;
147         if (*cp)
148         {
149             *cp++ = '\0';
150             inst = cp;
151             while (*cp && *cp != '@')
152                 ++cp;
153             if (*cp)
154             {
155                 *cp++ = '\0';
156                 realm = cp;
157             }
158         }
159     }
160   
161     xalloca(ticket, KTEXT, sizeof (KTEXT_ST));
162     rem = (krb_sendauth (0L, socket, ticket,
163                          prin ? prin : "pop",
164                          inst ? inst : canonical,
165                          realm ? realm : ((char *) (krb_realmofhost (canonical))),
166                          ((unsigned long) 0),
167                          (&msg_data),
168                          (&cred),
169                          (schedule),
170                          ((struct sockaddr_in *) 0),
171                          ((struct sockaddr_in *) 0),
172                          "KPOPV0.1"));
173     if (prin_copy)
174     {
175         free(prin_copy);
176     }
177     if (rem != KSUCCESS)
178     {
179         report(stderr, GT_("kerberos error %s\n"), (krb_get_err_text (rem)));
180         return (PS_AUTHFAIL);
181     }
182     return (0);
183 }
184 #endif /* KERBEROS_V4 */
185
186 #ifdef KERBEROS_V5
187 static int kerberos5_auth(socket, canonical)
188 /* authenticate to the server host using Kerberos V5 */
189 int socket;             /* socket to server host */
190 const char *canonical;  /* server name */
191 {
192     krb5_error_code retval;
193     krb5_context context;
194     krb5_ccache ccdef;
195     krb5_principal client = NULL, server = NULL;
196     krb5_error *err_ret = NULL;
197
198     krb5_auth_context auth_context = NULL;
199
200     krb5_init_context(&context);
201     krb5_init_ets(context);
202     krb5_auth_con_init(context, &auth_context);
203
204     if (retval = krb5_cc_default(context, &ccdef)) {
205         report(stderr, "krb5_cc_default: %s\n", error_message(retval));
206         return(PS_ERROR);
207     }
208
209     if (retval = krb5_cc_get_principal(context, ccdef, &client)) {
210         report(stderr, "krb5_cc_get_principal: %s\n", error_message(retval));
211         return(PS_ERROR);
212     }
213
214     if (retval = krb5_sname_to_principal(context, canonical, "pop",
215            KRB5_NT_UNKNOWN,
216            &server)) {
217         report(stderr, "krb5_sname_to_principal: %s\n", error_message(retval));
218         return(PS_ERROR);
219     }
220
221     retval = krb5_sendauth(context, &auth_context, (krb5_pointer) &socket,
222          "KPOPV1.0", client, server,
223          AP_OPTS_MUTUAL_REQUIRED,
224          NULL,  /* no data to checksum */
225          0,   /* no creds, use ccache instead */
226          ccdef,
227          &err_ret, 0,
228
229          NULL); /* don't need reply */
230
231     krb5_free_principal(context, server);
232     krb5_free_principal(context, client);
233     krb5_auth_con_free(context, auth_context);
234
235     if (retval) {
236 #ifdef HEIMDAL
237       if (err_ret && err_ret->e_text) {
238           report(stderr, GT_("krb5_sendauth: %s [server says '%*s'] \n"),
239                  error_message(retval),
240                  err_ret->e_text);
241 #else
242       if (err_ret && err_ret->text.length) {
243           report(stderr, GT_("krb5_sendauth: %s [server says '%*s'] \n"),
244                  error_message(retval),
245                  err_ret->text.length,
246                  err_ret->text.data);
247 #endif
248           krb5_free_error(context, err_ret);
249       } else
250           report(stderr, "krb5_sendauth: %s\n", error_message(retval));
251       return(PS_ERROR);
252     }
253
254     return 0;
255 }
256 #endif /* KERBEROS_V5 */
257
258 static void clean_skipped_list(struct idlist **skipped_list)
259 /* struct "idlist" contains no "prev" ptr; we must remove unused items first */
260 {
261     struct idlist *current=NULL, *prev=NULL, *tmp=NULL, *head=NULL;
262     prev = current = head = *skipped_list;
263
264     if (!head)
265         return;
266     do
267     {
268         /* if item has no reference, remove it */
269         if (current && current->val.status.mark == 0)
270         {
271             if (current == head) /* remove first item (head) */
272             {
273                 head = current->next;
274                 if (current->id) free(current->id);
275                 free(current);
276                 prev = current = head;
277             }
278             else /* remove middle/last item */
279             {
280                 tmp = current->next;
281                 prev->next = tmp;
282                 if (current->id) free(current->id);
283                 free(current);
284                 current = tmp;
285             }
286         }
287         else /* skip this item */
288         {
289             prev = current;
290             current = current->next;
291         }
292     } while(current);
293
294     *skipped_list = head;
295 }
296
297 static void send_size_warnings(struct query *ctl)
298 /* send warning mail with skipped msg; reset msg count when user notified */
299 {
300     int size, nbr;
301     int msg_to_send = FALSE;
302     struct idlist *head=NULL, *current=NULL;
303     int max_warning_poll_count;
304
305     head = ctl->skipped;
306     if (!head)
307         return;
308
309     /* don't start a notification message unless we need to */
310     for (current = head; current; current = current->next)
311         if (current->val.status.num == 0 && current->val.status.mark)
312             msg_to_send = TRUE;
313     if (!msg_to_send)
314         return;
315
316     /*
317      * There's no good way to recover if we can't send notification mail, 
318      * but it's not a disaster, either, since the skipped mail will not
319      * be deleted.
320      */
321     if (open_warning_by_mail(ctl, (struct msgblk *)NULL))
322         return;
323     stuff_warning(ctl,
324            GT_("Subject: Fetchmail oversized-messages warning.\n"
325              "\n"
326              "The following oversized messages remain on the mail server %s:"),
327                   ctl->server.pollname);
328  
329     if (run.poll_interval == 0)
330         max_warning_poll_count = 0;
331     else
332         max_warning_poll_count = ctl->warnings/run.poll_interval;
333
334     /* parse list of skipped msg, adding items to the mail */
335     for (current = head; current; current = current->next)
336     {
337         if (current->val.status.num == 0 && current->val.status.mark)
338         {
339             nbr = current->val.status.mark;
340             size = atoi(current->id);
341             stuff_warning(ctl, 
342                     GT_("\t%d msg %d octets long skipped by fetchmail.\n"),
343                     nbr, size);
344         }
345         current->val.status.num++;
346         current->val.status.mark = 0;
347
348         if (current->val.status.num >= max_warning_poll_count)
349             current->val.status.num = 0;
350     }
351
352     close_warning_by_mail(ctl, (struct msgblk *)NULL);
353 }
354
355 static void mark_oversized(struct query *ctl, int num, int size)
356 /* mark a message oversized */
357 {
358     struct idlist *current=NULL, *tmp=NULL;
359     char sizestr[32];
360     int cnt;
361
362     /* convert size to string */
363 #ifdef HAVE_SNPRINTF
364     snprintf(sizestr, sizeof(sizestr),
365 #else
366     sprintf(sizestr,
367 #endif /* HAVE_SNPRINTF */
368       "%d", size);
369
370     /* build a list of skipped messages
371      * val.id = size of msg (string cnvt)
372      * val.status.num = warning_poll_count
373      * val.status.mask = nbr of msg this size
374      */
375
376     current = ctl->skipped;
377
378     /* initialise warning_poll_count to the
379      * current value so that all new msg will
380      * be included in the next mail
381      */
382     cnt = current ? current->val.status.num : 0;
383
384     /* if entry exists, increment the count */
385     if (current && str_in_list(&current, sizestr, FALSE))
386     {
387         for ( ; current; current = current->next)
388         {
389             if (strcmp(current->id, sizestr) == 0)
390             {
391                 current->val.status.mark++;
392                 break;
393             }
394         }
395     }
396     /* otherwise, create a new entry */
397     /* initialise with current poll count */
398     else
399     {
400         tmp = save_str(&ctl->skipped, sizestr, 1);
401         tmp->val.status.num = cnt;
402     }
403 }
404
405 static int fetch_messages(int mailserver_socket, struct query *ctl, 
406                           int count, int *msgsizes, int *msgcodes, int maxfetch,
407                           int *fetches, int *dispatches, int *deletions)
408 /* fetch messages in lockstep mode */
409 {
410     int num, err, len;
411
412     for (num = 1; num <= count; num++)
413     {
414         flag suppress_delete = FALSE;
415         flag suppress_forward = FALSE;
416         flag suppress_readbody = FALSE;
417         flag retained = FALSE;
418
419         if (msgcodes[num-1] < 0)
420         {
421             if ((msgcodes[num-1] == MSGLEN_TOOLARGE) && !check_only)
422                 mark_oversized(ctl, num, msgsizes[num-1]);
423             if (outlevel > O_SILENT)
424             {
425                 report_build(stdout, 
426                              GT_("skipping message %s@%s:%d (%d octets)"),
427                              ctl->remotename, ctl->server.truename, num,
428                              msgsizes[num-1]);
429                 switch (msgcodes[num-1])
430                 {
431                 case MSGLEN_INVALID:
432                     /*
433                      * Invalid lengths are produced by Post Office/NT's
434                      * annoying habit of randomly prepending bogus
435                      * LIST items of length -1.  Patrick Audley
436                      * <paudley@pobox.com> tells us: LIST shows a
437                      * size of -1, RETR and TOP return "-ERR
438                      * System error - couldn't open message", and
439                      * DELE succeeds but doesn't actually delete
440                      * the message.
441                      */
442                     report_build(stdout, GT_(" (length -1)"));
443                     break;
444                 case MSGLEN_TOOLARGE:
445                     report_build(stdout, GT_(" (oversized)"));
446                     break;
447                 }
448             }
449         }
450         else
451         {
452             flag wholesize = !ctl->server.base_protocol->fetch_body;
453
454             /* request a message */
455             err = (ctl->server.base_protocol->fetch_headers)(mailserver_socket,ctl,num, &len);
456             if (err == PS_TRANSIENT)    /* server is probably Exchange */
457             {
458                 report(stdout,
459                              GT_("couldn't fetch headers, message %s@%s:%d (%d octets)\n"),
460                              ctl->remotename, ctl->server.truename, num,
461                              msgsizes[num-1]);
462                 continue;
463             }
464             else if (err != 0)
465                 return(err);
466
467             /* -1 means we didn't see a size in the response */
468             if (len == -1)
469             {
470                 len = msgsizes[num - 1];
471                 wholesize = TRUE;
472             }
473
474             if (outlevel > O_SILENT)
475             {
476                 report_build(stdout, GT_("reading message %s@%s:%d of %d"),
477                              ctl->remotename, ctl->server.truename,
478                              num, count);
479
480                 if (len > 0)
481                     report_build(stdout, GT_(" (%d %soctets)"),
482                                  len, wholesize ? "" : GT_("header "));
483                 if (outlevel >= O_VERBOSE)
484                     report_complete(stdout, "\n");
485                 else
486                     report_complete(stdout, " ");
487             }
488
489             /* 
490              * Read the message headers and ship them to the
491              * output sink.  
492              */
493             err = readheaders(mailserver_socket, len, msgsizes[num-1],
494                              ctl, num);
495             if (err == PS_RETAINED)
496             {
497                 suppress_forward = suppress_delete = retained = TRUE;
498                 /* do not read the body only if the underlying protocol
499                  * allows the body to be fetched separately */
500                 if (ctl->server.base_protocol->fetch_body)
501                     suppress_readbody = TRUE;
502             }
503             else if (err == PS_TRANSIENT)
504             {
505                 suppress_delete = suppress_forward = TRUE;
506                 if (ctl->server.base_protocol->fetch_body)
507                     suppress_readbody = TRUE;
508             }
509             else if (err == PS_REFUSED)
510             {
511                 suppress_forward = TRUE;
512                 if (ctl->server.base_protocol->fetch_body)
513                     suppress_readbody = TRUE;
514             }
515 #if 0
516             /* 
517              * readheaders does not read the body when it
518              * hits a non-header. It has been recently
519              * fixed to return PS_TRUNCATED (properly) when
520              * that happens, but apparently fixing that bug
521              * opened this one here (which looks like an 
522              * inproper fix from some ancient thinko)
523              */
524             else if (err == PS_TRUNCATED)
525                 suppress_readbody = TRUE;
526             else if (err)
527                 return(err);
528 #else
529             else if (err && err != PS_TRUNCATED)
530                 return(err);
531 #endif
532
533             /* 
534              * If we're using IMAP4 or something else that
535              * can fetch headers separately from bodies,
536              * it's time to request the body now.  This
537              * fetch may be skipped if we got an anti-spam
538              * or other PS_REFUSED error response during
539              * readheaders.
540              */
541             if (ctl->server.base_protocol->fetch_body && !suppress_readbody) 
542             {
543                 if (outlevel >= O_VERBOSE && !isafile(1))
544                 {
545                     fputc('\n', stdout);
546                     fflush(stdout);
547                 }
548
549                 if ((err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num)))
550                     return(err);
551                 len = 0;
552                 if (!suppress_forward)
553                 {
554                     if ((err=(ctl->server.base_protocol->fetch_body)(mailserver_socket,ctl,num,&len)))
555                         return(err);
556                     /*
557                      * Work around a bug in Novell's
558                      * broken GroupWise IMAP server;
559                      * its body FETCH response is missing
560                      * the required length for the data
561                      * string.  This violates RFC2060.
562                      */
563                     if (len == -1)
564                         len = msgsizes[num-1] - msgblk.msglen;
565                     if (outlevel > O_SILENT && !wholesize)
566                         report_complete(stdout,
567                                         GT_(" (%d body octets) "), len);
568                 }
569             }
570
571             /* process the body now */
572             if (len > 0)
573             {
574                 if (suppress_readbody)
575                 {
576                     err = PS_SUCCESS;
577                 }
578                 else
579                 {
580                     err = readbody(mailserver_socket,
581                                   ctl,
582                                   !suppress_forward,
583                                   len);
584                 }
585                 if (err == PS_TRANSIENT)
586                     suppress_delete = suppress_forward = TRUE;
587                 else if (err)
588                     return(err);
589
590                 /* tell server we got it OK and resynchronize */
591                 if (ctl->server.base_protocol->trail)
592                 {
593                     if (outlevel >= O_VERBOSE && !isafile(1))
594                     {
595                         fputc('\n', stdout);
596                         fflush(stdout);
597                     }
598
599                     err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num);
600                     if (err != 0)
601                         return(err);
602                 }
603             }
604
605             /* count # messages forwarded on this pass */
606             if (!suppress_forward)
607                 (*dispatches)++;
608
609             /*
610              * Check to see if the numbers matched?
611              *
612              * Yes, some servers foo this up horribly.
613              * All IMAP servers seem to get it right, and
614              * so does Eudora QPOP at least in 2.xx
615              * versions.
616              *
617              * Microsoft Exchange gets it completely
618              * wrong, reporting compressed rather than
619              * actual sizes (so the actual length of
620              * message is longer than the reported size).
621              * Another fine example of Microsoft brain death!
622              *
623              * Some older POP servers, like the old UCB
624              * POP server and the pre-QPOP QUALCOMM
625              * versions, report a longer size in the LIST
626              * response than actually gets shipped up.
627              * It's unclear what is going on here, as the
628              * QUALCOMM server (at least) seems to be
629              * reporting the on-disk size correctly.
630              */
631             if (msgblk.msglen != msgsizes[num-1])
632             {
633                 if (outlevel >= O_DEBUG)
634                     report(stdout,
635                            GT_("message %s@%s:%d was not the expected length (%d actual != %d expected)\n"),
636                            ctl->remotename, ctl->server.truename, num,
637                            msgblk.msglen, msgsizes[num-1]);
638             }
639
640             /* end-of-message processing starts here */
641             if (!close_sink(ctl, &msgblk, !suppress_forward))
642             {
643                 ctl->errcount++;
644                 suppress_delete = TRUE;
645             }
646             if (!retained)
647                 (*fetches)++;
648         }
649
650         /*
651          * At this point in flow of control, either
652          * we've bombed on a protocol error or had
653          * delivery refused by the SMTP server
654          * (unlikely -- I've never seen it) or we've
655          * seen `accepted for delivery' and the
656          * message is shipped.  It's safe to mark the
657          * message seen and delete it on the server
658          * now.
659          */
660
661         /*
662          * Tell the UID code we've seen this.
663          * Matthias Andree: only register the UID if we could actually
664          * forward this mail. If we omit this !suppress_delete check,
665          * fetchmail will never retry mail that the local listener
666          * refused temporarily.
667          */
668         if (ctl->newsaved && !suppress_delete)
669         {
670             struct idlist       *sdp;
671
672             for (sdp = ctl->newsaved; sdp; sdp = sdp->next)
673                 if ((sdp->val.status.num == num) && (msgcodes[num-1] >= 0))
674                 {
675                     sdp->val.status.mark = UID_SEEN;
676                     save_str(&ctl->oldsaved, sdp->id,UID_SEEN);
677                 }
678         }
679
680         /* maybe we delete this message now? */
681         if (retained)
682         {
683             if (outlevel > O_SILENT) 
684                 report(stdout, GT_(" retained\n"));
685         }
686         else if (ctl->server.base_protocol->delete
687                  && !suppress_delete
688                  && ((msgcodes[num-1] >= 0) ? !ctl->keep : ctl->flush))
689         {
690             (*deletions)++;
691             if (outlevel > O_SILENT) 
692                 report_complete(stdout, GT_(" flushed\n"));
693             err = (ctl->server.base_protocol->delete)(mailserver_socket, ctl, num);
694             if (err != 0)
695                 return(err);
696 #ifdef POP3_ENABLE
697             delete_str(&ctl->newsaved, num);
698 #endif /* POP3_ENABLE */
699         }
700         else if (outlevel > O_SILENT)
701             report_complete(stdout, GT_(" not flushed\n"));
702
703         /* perhaps this as many as we're ready to handle */
704         if (maxfetch && maxfetch <= *fetches && *fetches < count)
705         {
706             report(stdout, GT_("fetchlimit %d reached; %d messages left on server %s account %s\n"),
707                    maxfetch, count - *fetches, ctl->server.truename, ctl->remotename);
708             return(PS_MAXFETCH);
709         }
710     }
711
712     return(PS_SUCCESS);
713 }
714
715 static int do_session(ctl, proto, maxfetch)
716 /* retrieve messages from server using given protocol method table */
717 struct query *ctl;              /* parsed options with merged-in defaults */
718 const struct method *proto;     /* protocol method table */
719 const int maxfetch;             /* maximum number of messages to fetch */
720 {
721     int js;
722 #ifdef HAVE_VOLATILE
723     volatile int err, mailserver_socket = -1;   /* pacifies -Wall */
724 #else
725     int err, mailserver_socket = -1;
726 #endif /* HAVE_VOLATILE */
727     const char *msg;
728     void (*pipesave)(int);
729     void (*alrmsave)(int);
730
731     ctl->server.base_protocol = proto;
732
733     pass = 0;
734     err = 0;
735     init_transact(proto);
736
737     /* set up the server-nonresponse timeout */
738     alrmsave = signal(SIGALRM, timeout_handler);
739     mytimeout = ctl->server.timeout;
740
741     /* set up the broken-pipe timeout */
742     pipesave = signal(SIGPIPE, sigpipe_handler);
743
744     if ((js = setjmp(restart)))
745     {
746 #ifdef HAVE_SIGPROCMASK
747         /*
748          * Don't rely on setjmp() to restore the blocked-signal mask.
749          * It does this under BSD but is required not to under POSIX.
750          *
751          * If your Unix doesn't have sigprocmask, better hope it has
752          * BSD-like behavior.  Otherwise you may see fetchmail get
753          * permanently wedged after a second timeout on a bad read,
754          * because alarm signals were blocked after the first.
755          */
756         sigset_t        allsigs;
757
758         sigfillset(&allsigs);
759         sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
760 #endif /* HAVE_SIGPROCMASK */
761         
762         if (js == THROW_SIGPIPE)
763         {
764             signal(SIGPIPE, SIG_IGN);
765             report(stdout,
766                    GT_("SIGPIPE thrown from an MDA or a stream socket error\n"));
767             wait(0);
768         }
769         else if (js == THROW_TIMEOUT)
770         {
771             if (phase == OPEN_WAIT)
772                 report(stdout,
773                        GT_("timeout after %d seconds waiting to connect to server %s.\n"),
774                        ctl->server.timeout, ctl->server.pollname);
775             else if (phase == SERVER_WAIT)
776                 report(stdout,
777                        GT_("timeout after %d seconds waiting for server %s.\n"),
778                        ctl->server.timeout, ctl->server.pollname);
779             else if (phase == FORWARDING_WAIT)
780                 report(stdout,
781                        GT_("timeout after %d seconds waiting for %s.\n"),
782                        ctl->server.timeout,
783                        ctl->mda ? "MDA" : "SMTP");
784             else if (phase == LISTENER_WAIT)
785                 report(stdout,
786                        GT_("timeout after %d seconds waiting for listener to respond.\n"), ctl->server.timeout);
787             else
788                 report(stdout, 
789                        GT_("timeout after %d seconds.\n"), ctl->server.timeout);
790
791             /*
792              * If we've exceeded our threshold for consecutive timeouts, 
793              * try to notify the user, then mark the connection wedged.
794              * Don't do this if the connection can idle, though; idle
795              * timeouts just mean the frequency of mail is low.
796              */
797             if (timeoutcount > MAX_TIMEOUTS 
798                 && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
799             {
800                 stuff_warning(ctl,
801                               GT_("Subject: fetchmail sees repeated timeouts\n"));
802                 stuff_warning(ctl,
803                               GT_("Fetchmail saw more than %d timeouts while attempting to get mail from %s@%s.\n"), 
804                               MAX_TIMEOUTS,
805                               ctl->remotename,
806                               ctl->server.truename);
807                 stuff_warning(ctl, 
808     GT_("This could mean that your mailserver is stuck, or that your SMTP\n" \
809     "server is wedged, or that your mailbox file on the server has been\n" \
810     "corrupted by a server error.  You can run `fetchmail -v -v' to\n" \
811     "diagnose the problem.\n\n" \
812     "Fetchmail won't poll this mailbox again until you restart it.\n"));
813                 close_warning_by_mail(ctl, (struct msgblk *)NULL);
814                 ctl->wedged = TRUE;
815             }
816         }
817
818         err = PS_SOCKET;
819         goto cleanUp;
820     }
821     else
822     {
823         char buf[MSGBUFSIZE+1], *realhost;
824         int count, new, bytes, deletions = 0;
825         int *msgsizes = (int *)NULL;
826         int *msgcodes = (int *)NULL;
827 #if INET6_ENABLE
828         int fetches, dispatches, oldphase;
829 #else /* INET6_ENABLE */
830         int port, fetches, dispatches, oldphase;
831 #endif /* INET6_ENABLE */
832         struct idlist *idp;
833
834         /* execute pre-initialization command, if any */
835         if (ctl->preconnect && (err = system(ctl->preconnect)))
836         {
837             report(stderr, 
838                    GT_("pre-connection command failed with status %d\n"), err);
839             err = PS_SYNTAX;
840             goto closeUp;
841         }
842
843         /* open a socket to the mail server */
844         oldphase = phase;
845         phase = OPEN_WAIT;
846         set_timeout(mytimeout);
847 #if !INET6_ENABLE
848 #ifdef SSL_ENABLE
849         port = ctl->server.port ? ctl->server.port : ( ctl->use_ssl ? ctl->server.base_protocol->sslport : ctl->server.base_protocol->port );
850 #else
851         port = ctl->server.port ? ctl->server.port : ctl->server.base_protocol->port;
852 #endif
853 #endif /* !INET6_ENABLE */
854
855 #ifdef HESIOD
856         /* If either the pollname or vianame are "hesiod" we want to
857            lookup the user's hesiod pobox host */
858         if (!strcasecmp(ctl->server.queryname, "hesiod")) {
859             struct hes_postoffice *hes_p;
860             hes_p = hes_getmailhost(ctl->remotename);
861             if (hes_p != NULL && strcmp(hes_p->po_type, "POP") == 0) {
862                  free(ctl->server.queryname);
863                  ctl->server.queryname = xstrdup(hes_p->po_host);
864                  if (ctl->server.via)
865                      free(ctl->server.via);
866                  ctl->server.via = xstrdup(hes_p->po_host);
867             } else {
868                  report(stderr,
869                         GT_("couldn't find HESIOD pobox for %s\n"),
870                         ctl->remotename);
871             }
872         }
873 #endif /* HESIOD */
874
875 #ifdef HAVE_GETHOSTBYNAME
876         /*
877          * Canonicalize the server truename for later use.  This also
878          * functions as a probe for whether the mailserver is accessible.
879          * We try it on each poll cycle until we get a result.  This way,
880          * fetchmail won't fail if started up when the network is inaccessible.
881          */
882         if (ctl->server.dns && !ctl->server.trueaddr)
883         {
884             if (ctl->server.lead_server)
885             {
886                 char    *leadname = ctl->server.lead_server->truename;
887
888                 /* prevent core dump from ill-formed or duplicate entry */
889                 if (!leadname)
890                 {
891                     report(stderr, GT_("Lead server has no name.\n"));
892                     err = PS_DNS;
893                     set_timeout(0);
894                     phase = oldphase;
895                     goto closeUp;
896                 }
897
898                 ctl->server.truename = xstrdup(leadname);
899             }
900             else
901             {
902                 struct hostent  *namerec;
903                     
904                 /* 
905                  * Get the host's IP, so we can report it like this:
906                  *
907                  * Received: from hostname [10.0.0.1]
908                  */
909                 errno = 0;
910                 namerec = gethostbyname(ctl->server.queryname);
911                 if (namerec == (struct hostent *)NULL)
912                 {
913                     report(stderr,
914                            GT_("couldn't find canonical DNS name of %s\n"),
915                            ctl->server.pollname);
916                     err = PS_DNS;
917                     set_timeout(0);
918                     phase = oldphase;
919                     goto closeUp;
920                 }
921                 else 
922                 {
923                     ctl->server.truename=xstrdup((char *)namerec->h_name);
924                     ctl->server.trueaddr=xmalloc(namerec->h_length);
925                     memcpy(ctl->server.trueaddr, 
926                            namerec->h_addr_list[0],
927                            namerec->h_length);
928                 }
929             }
930         }
931 #endif /* HAVE_GETHOSTBYNAME */
932
933         realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
934
935         /* allow time for the port to be set up if we have a plugin */
936         if (ctl->server.plugin)
937             (void)sleep(1);
938 #if INET6_ENABLE
939         if ((mailserver_socket = SockOpen(realhost, 
940                              ctl->server.service ? ctl->server.service : ( ctl->use_ssl ? ctl->server.base_protocol->sslservice : ctl->server.base_protocol->service ),
941                              ctl->server.netsec, ctl->server.plugin)) == -1)
942 #else /* INET6_ENABLE */
943         if ((mailserver_socket = SockOpen(realhost, port, NULL, ctl->server.plugin)) == -1)
944 #endif /* INET6_ENABLE */
945         {
946             char        errbuf[BUFSIZ];
947 #if !INET6_ENABLE
948             int err_no = errno;
949 #ifdef HAVE_RES_SEARCH
950             if (err_no != 0 && h_errno != 0)
951                 report(stderr, GT_("internal inconsistency\n"));
952 #endif
953             /*
954              * Avoid generating a bogus error every poll cycle when we're
955              * in daemon mode but the connection to the outside world
956              * is down.
957              */
958             if (!((err_no == EHOSTUNREACH || err_no == ENETUNREACH) 
959                   && run.poll_interval))
960             {
961                 report_build(stderr, GT_("%s connection to %s failed"), 
962                              ctl->server.base_protocol->name, ctl->server.pollname);
963 #ifdef HAVE_RES_SEARCH
964                 if (h_errno != 0)
965                 {
966                     if (h_errno == HOST_NOT_FOUND)
967                         strcpy(errbuf, GT_("host is unknown."));
968 #ifndef __BEOS__
969                     else if (h_errno == NO_ADDRESS)
970                         strcpy(errbuf, GT_("name is valid but has no IP address."));
971 #endif
972                     else if (h_errno == NO_RECOVERY)
973                         strcpy(errbuf, GT_("unrecoverable name server error."));
974                     else if (h_errno == TRY_AGAIN)
975                         strcpy(errbuf, GT_("temporary name server error."));
976                     else
977 #ifdef HAVE_SNPRINTF
978                         snprintf(errbuf, sizeof(errbuf),
979 #else
980                         sprintf(errbuf,
981 #endif /* HAVE_SNPRINTF */
982                           GT_("unknown DNS error %d."), h_errno);
983                 }
984                 else
985 #endif /* HAVE_RES_SEARCH */
986                     strcpy(errbuf, strerror(err_no));
987                 report_complete(stderr, ": %s\n", errbuf);
988
989 #ifdef __UNUSED
990                 /* 
991                  * Don't use this.  It was an attempt to address Debian bug
992                  * #47143 (Notify user by mail when pop server nonexistent).
993                  * Trouble is, that doesn't work; you trip over the case 
994                  * where your SLIP or PPP link is down...
995                  */
996                 /* warn the system administrator */
997                 if (open_warning_by_mail(ctl, (struct msgblk *)NULL) == 0)
998                 {
999                     stuff_warning(ctl,
1000                          GT_("Subject: Fetchmail unreachable-server warning.\n"
1001                            "\n"
1002                            "Fetchmail could not reach the mail server %s:")
1003                                   ctl->server.pollname);
1004                     stuff_warning(ctl, errbuf, ctl->server.pollname);
1005                     close_warning_by_mail(ctl, (struct msgblk *)NULL);
1006                 }
1007 #endif
1008             }
1009 #endif /* INET6_ENABLE */
1010             err = PS_SOCKET;
1011             set_timeout(0);
1012             phase = oldphase;
1013             goto closeUp;
1014         }
1015
1016 #ifdef SSL_ENABLE
1017         /* Save the socket opened. Usefull if Fetchmail hangs on SSLOpen 
1018          * because the socket can be closed
1019          */
1020         mailserver_socket_temp = mailserver_socket;
1021         set_timeout(mytimeout);
1022
1023         /* perform initial SSL handshake on open connection */
1024         /* Note:  We pass the realhost name over for certificate
1025                 verification.  We may want to make this configurable */
1026         if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslcert,ctl->sslkey,ctl->sslproto,ctl->sslcertck,
1027             ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1) 
1028         {
1029             report(stderr, GT_("SSL connection failed.\n"));
1030             goto closeUp;
1031         }
1032         
1033         /* Fetchmail didn't hang on SSLOpen, 
1034          * then no need to set mailserver_socket_temp 
1035          */
1036         mailserver_socket_temp = -1;
1037 #endif
1038         
1039         /* A timeout is still defined before SSLOpen, 
1040          * then Fetchmail hanging on SSLOpen is handled.
1041          */
1042         set_timeout(0);
1043         phase = oldphase;
1044 #ifdef KERBEROS_V4
1045         if (ctl->server.authenticate == A_KERBEROS_V4 && (strcasecmp(proto->name,"IMAP") != 0))
1046         {
1047             set_timeout(mytimeout);
1048             err = kerberos_auth(mailserver_socket, ctl->server.truename,
1049                                ctl->server.principal);
1050             set_timeout(0);
1051             if (err != 0)
1052                 goto cleanUp;
1053         }
1054 #endif /* KERBEROS_V4 */
1055
1056 #ifdef KERBEROS_V5
1057         if (ctl->server.authenticate == A_KERBEROS_V5)
1058         {
1059             set_timeout(mytimeout);
1060             err = kerberos5_auth(mailserver_socket, ctl->server.truename);
1061             set_timeout(0);
1062             if (err != 0)
1063                 goto cleanUp;
1064         }
1065 #endif /* KERBEROS_V5 */
1066
1067         /* accept greeting message from mail server */
1068         err = (ctl->server.base_protocol->parse_response)(mailserver_socket, buf);
1069         if (err != 0)
1070             goto cleanUp;
1071
1072         /* try to get authorized to fetch mail */
1073         stage = STAGE_GETAUTH;
1074         if (ctl->server.base_protocol->getauth)
1075         {
1076             err = (ctl->server.base_protocol->getauth)(mailserver_socket, ctl, buf);
1077
1078             if (err != 0)
1079             {
1080                 if (err == PS_LOCKBUSY)
1081                     report(stderr, GT_("Lock-busy error on %s@%s\n"),
1082                           ctl->remotename,
1083                           ctl->server.truename);
1084                 else if (err == PS_SERVBUSY)
1085                     report(stderr, GT_("Server busy error on %s@%s\n"),
1086                           ctl->remotename,
1087                           ctl->server.truename);
1088                 else if (err == PS_AUTHFAIL)
1089                 {
1090                     report(stderr, GT_("Authorization failure on %s@%s%s\n"), 
1091                            ctl->remotename,
1092                            ctl->server.truename,
1093                            (ctl->wehaveauthed ? GT_(" (previously authorized)") : "")
1094                         );
1095
1096                     /*
1097                      * If we're running in background, try to mail the
1098                      * calling user a heads-up about the authentication 
1099                      * failure once it looks like this isn't a fluke 
1100                      * due to the server being temporarily inaccessible.
1101                      * When we get third succesive failure, we notify the user
1102                      * but only if we haven't already managed to get
1103                      * authorization.  After that, once we get authorization
1104                      * we let the user know service is restored.
1105                      */
1106                     if (run.poll_interval
1107                         && !ctl->wehavesentauthnote
1108                         && ((ctl->wehaveauthed && ++ctl->authfailcount == 10)
1109                             || ++ctl->authfailcount == 3)
1110                         && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
1111                     {
1112                         ctl->wehavesentauthnote = 1;
1113                         stuff_warning(ctl,
1114                                       GT_("Subject: fetchmail authentication failed on %s@%s\n"),
1115                             ctl->remotename, ctl->server.truename);
1116                         stuff_warning(ctl,
1117                                       GT_("Fetchmail could not get mail from %s@%s.\n"), 
1118                                       ctl->remotename,
1119                                       ctl->server.truename);
1120                         if (ctl->wehaveauthed)
1121                             stuff_warning(ctl, GT_("\
1122 The attempt to get authorization failed.\n\
1123 Since we have already succeeded in getting authorization for this\n\
1124 connection, this is probably another failure mode (such as busy server)\n\
1125 that fetchmail cannot distinguish because the server didn't send a useful\n\
1126 error message.\n\
1127 \n\
1128 However, if you HAVE changed your account details since starting the\n\
1129 fetchmail daemon, you need to stop the daemon, change your configuration\n\
1130 of fetchmail, and then restart the daemon.\n\
1131 \n\
1132 The fetchmail daemon will continue running and attempt to connect\n\
1133 at each cycle.  No future notifications will be sent until service\n\
1134 is restored."));
1135                         else
1136                             stuff_warning(ctl, GT_("\
1137 The attempt to get authorization failed.\n\
1138 This probably means your password is invalid, but some servers have\n\
1139 other failure modes that fetchmail cannot distinguish from this\n\
1140 because they don't send useful error messages on login failure.\n\
1141 \n\
1142 The fetchmail daemon will continue running and attempt to connect\n\
1143 at each cycle.  No future notifications will be sent until service\n\
1144 is restored."));
1145                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1146                     }
1147                 }
1148                 else if (err == PS_REPOLL)
1149                 {
1150                   if (outlevel >= O_VERBOSE)
1151                     report(stderr, GT_("Repoll immediately on %s@%s\n"),
1152                            ctl->remotename,
1153                            ctl->server.truename);
1154                 }
1155                 else
1156                     report(stderr, GT_("Unknown login or authentication error on %s@%s\n"),
1157                            ctl->remotename,
1158                            ctl->server.truename);
1159                     
1160                 goto cleanUp;
1161             }
1162             else
1163             {
1164                 /*
1165                  * This connection has given us authorization at least once.
1166                  *
1167                  * There are dodgy server (clubinternet.fr for example) that
1168                  * give spurious authorization failures on patently good
1169                  * account/password details, then 5 minutes later let you in!
1170                  *
1171                  * This is meant to build in some tolerance of such nasty bits
1172                  * of work.
1173                  */
1174                 ctl->wehaveauthed = 1;
1175                 /*if (ctl->authfailcount >= 3)*/
1176                 if (ctl->wehavesentauthnote)
1177                 {
1178                     ctl->wehavesentauthnote = 0;
1179                     report(stderr,
1180                            GT_("Authorization OK on %s@%s\n"),
1181                            ctl->remotename,
1182                            ctl->server.truename);
1183                     if (!open_warning_by_mail(ctl, (struct msgblk *)NULL))
1184                     {
1185                         stuff_warning(ctl,
1186                               GT_("Subject: fetchmail authentication OK on %s@%s\n"),
1187                                       ctl->remotename, ctl->server.truename);
1188                         stuff_warning(ctl,
1189                               GT_("Fetchmail was able to log into %s@%s.\n"), 
1190                                       ctl->remotename,
1191                                       ctl->server.truename);
1192                         stuff_warning(ctl, 
1193                                       GT_("Service has been restored.\n"));
1194                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1195                     
1196                     }
1197                 }
1198                 /*
1199                  * Reporting only after the first three
1200                  * consecutive failures, or ten consecutive
1201                  * failures after we have managed to get
1202                  * authorization.
1203                  */
1204                 ctl->authfailcount = 0;
1205             }
1206         }
1207
1208         ctl->errcount = fetches = 0;
1209
1210         /* now iterate over each folder selected */
1211         for (idp = ctl->mailboxes; idp; idp = idp->next)
1212         {
1213             pass = 0;
1214             do {
1215                 dispatches = 0;
1216                 ++pass;
1217
1218                 /* reset timeout, in case we did an IDLE */
1219                 mytimeout = ctl->server.timeout;
1220
1221                 if (outlevel >= O_DEBUG)
1222                 {
1223                     if (idp->id)
1224                         report(stdout, GT_("selecting or re-polling folder %s\n"), idp->id);
1225                     else
1226                         report(stdout, GT_("selecting or re-polling default folder\n"));
1227                 }
1228
1229                 /* compute # of messages and number of new messages waiting */
1230                 stage = STAGE_GETRANGE;
1231                 err = (ctl->server.base_protocol->getrange)(mailserver_socket, ctl, idp->id, &count, &new, &bytes);
1232                 if (err != 0)
1233                     goto cleanUp;
1234
1235                 /* show user how many messages we downloaded */
1236                 if (idp->id)
1237 #ifdef HAVE_SNPRINTF
1238                     (void) snprintf(buf, sizeof(buf),
1239 #else
1240                     (void) sprintf(buf,
1241 #endif /* HAVE_SNPRINTF */
1242                                    GT_("%s at %s (folder %s)"),
1243                                    ctl->remotename, ctl->server.truename, idp->id);
1244                 else
1245 #ifdef HAVE_SNPRINTF
1246                     (void) snprintf(buf, sizeof(buf),
1247 #else
1248                     (void) sprintf(buf,
1249 #endif /* HAVE_SNPRINTF */
1250                                GT_("%s at %s"),
1251                                    ctl->remotename, ctl->server.truename);
1252                 if (outlevel > O_SILENT)
1253                 {
1254                     if (count == -1)            /* only used for ETRN */
1255                         report(stdout, GT_("Polling %s\n"), ctl->server.truename);
1256                     else if (count != 0)
1257                     {
1258                         if (new != -1 && (count - new) > 0)
1259                             report_build(stdout, GT_("%d %s (%d seen) for %s"),
1260                                   count, count > 1 ? GT_("messages") :
1261                                                      GT_("message"),
1262                                   count-new, buf);
1263                         else
1264                             report_build(stdout, GT_("%d %s for %s"), 
1265                                   count, count > 1 ? GT_("messages") :
1266                                                      GT_("message"), buf);
1267                         if (bytes == -1)
1268                             report_complete(stdout, ".\n");
1269                         else
1270                             report_complete(stdout, GT_(" (%d octets).\n"), bytes);
1271                     }
1272                     else
1273                     {
1274                         /* these are pointless in normal daemon mode */
1275                         if (pass == 1 && (run.poll_interval == 0 || outlevel >= O_VERBOSE))
1276                             report(stdout, GT_("No mail for %s\n"), buf); 
1277                     }
1278                 }
1279
1280                 /* very important, this is where we leave the do loop */ 
1281                 if (count == 0)
1282                     break;
1283
1284                 if (check_only)
1285                 {
1286                     if (new == -1 || ctl->fetchall)
1287                         new = count;
1288                     fetches = new;      /* set error status correctly */
1289                     /*
1290                      * There used to be a `goto noerror' here, but this
1291                      * prevented checking of multiple folders.  This
1292                      * comment is a reminder in case I introduced some
1293                      * subtle bug by removing it...
1294                      */
1295                 }
1296                 else if (count > 0)
1297                 {    
1298                     flag        force_retrieval;
1299                     int         i, num;
1300
1301                     /*
1302                      * What forces this code is that in POP2 and
1303                      * IMAP2bis you can't fetch a message without
1304                      * having it marked `seen'.  In POP3 and IMAP4, on the
1305                      * other hand, you can (peek_capable is set by 
1306                      * each driver module to convey this; it's not a
1307                      * method constant because of the difference between
1308                      * IMAP2bis and IMAP4, and because POP3 doesn't  peek
1309                      * if fetchall is on).
1310                      *
1311                      * The result of being unable to peek is that if there's
1312                      * any kind of transient error (DNS lookup failure, or
1313                      * sendmail refusing delivery due to process-table limits)
1314                      * the message will be marked "seen" on the server without
1315                      * having been delivered.  This is not a big problem if
1316                      * fetchmail is running in foreground, because the user
1317                      * will see a "skipped" message when it next runs and get
1318                      * clued in.
1319                      *
1320                      * But in daemon mode this leads to the message
1321                      * being silently ignored forever.  This is not
1322                      * acceptable.
1323                      *
1324                      * We compensate for this by checking the error
1325                      * count from the previous pass and forcing all
1326                      * messages to be considered new if it's nonzero.
1327                      */
1328                     force_retrieval = !peek_capable && (ctl->errcount > 0);
1329
1330                     /*
1331                      * Don't trust the message count passed by the server.
1332                      * Without this check, it might be possible to do a
1333                      * DNS-spoofing attack that would pass back a ridiculous 
1334                      * count, and allocate a malloc area that would overlap
1335                      * a portion of the stack.
1336                      */
1337                     if (count > INT_MAX/sizeof(int))
1338                     {
1339                         report(stderr, GT_("bogus message count!"));
1340                         return(PS_PROTOCOL);
1341                     }
1342
1343                     /* OK, we're going to gather size info next */
1344                     xalloca(msgsizes, int *, sizeof(int) * count);
1345                     xalloca(msgcodes, int *, sizeof(int) * count);
1346                     for (i = 0; i < count; i++) {
1347                         msgsizes[i] = 0;
1348                         msgcodes[i] = MSGLEN_UNKNOWN;
1349                     }
1350
1351                     /* 
1352                      * We need the size of each message before it's
1353                      * loaded in order to pass it to the ESMTP SIZE
1354                      * option.  If the protocol has a getsizes method,
1355                      * we presume this means it doesn't get reliable
1356                      * sizes from message fetch responses.
1357                      */
1358                     if (proto->getsizes)
1359                     {
1360                         stage = STAGE_GETSIZES;
1361                         err = (proto->getsizes)(mailserver_socket, count, msgsizes);
1362                         if (err != 0)
1363                             goto cleanUp;
1364
1365                         if (bytes == -1)
1366                         {
1367                             bytes = 0;
1368                             for (i = 0; i < count; i++)
1369                                 bytes += msgsizes[i];
1370                         }
1371                     }
1372
1373                     /* mark some messages not to be retrieved */
1374                     for (num = 1; num <= count; num++)
1375                     {
1376                         if (NUM_NONZERO(ctl->limit) && (msgsizes[num-1] > ctl->limit))
1377                             msgcodes[num-1] = MSGLEN_TOOLARGE;
1378                         else if (ctl->fetchall || force_retrieval)
1379                             continue;
1380                         else if (ctl->server.base_protocol->is_old && (ctl->server.base_protocol->is_old)(mailserver_socket,ctl,num))
1381                             msgcodes[num-1] = MSGLEN_OLD;
1382 /*                      else if (msgsizes[num-1] == 512)
1383                                 msgcodes[num-1] = MSGLEN_OLD;  (hmh) sample code to skip message */
1384                     }
1385
1386                     /* read, forward, and delete messages */
1387                     stage = STAGE_FETCH;
1388
1389                     /* fetch in lockstep mode */
1390                     err = fetch_messages(mailserver_socket, ctl, 
1391                                          count, msgsizes, msgcodes,
1392                                          maxfetch,
1393                                          &fetches, &dispatches, &deletions);
1394                     if (err)
1395                         goto cleanUp;
1396
1397                     if (!check_only && ctl->skipped
1398                         && run.poll_interval > 0 && !nodetach)
1399                     {
1400                         clean_skipped_list(&ctl->skipped);
1401                         send_size_warnings(ctl);
1402                     }
1403                 }
1404             } while
1405                   /*
1406                    * Only re-poll if we either had some actual forwards and 
1407                    * either allowed deletions and had no errors.
1408                    * Otherwise it is far too easy to get into infinite loops.
1409                    */
1410                   (dispatches && ctl->server.base_protocol->retry && !ctl->keep && !ctl->errcount);
1411         }
1412
1413     /* no_error: */
1414         /* ordinary termination with no errors -- officially log out */
1415         err = (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
1416         /*
1417          * Hmmmm...arguably this would be incorrect if we had fetches but
1418          * no dispatches (due to oversized messages, etc.)
1419          */
1420         if (err == 0)
1421             err = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
1422         cleanupSockClose(mailserver_socket);
1423         goto closeUp;
1424
1425     cleanUp:
1426         /* we only get here on error */
1427         if (err != 0 && err != PS_SOCKET && err != PS_REPOLL)
1428         {
1429             stage = STAGE_LOGOUT;
1430             (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
1431         }
1432
1433         /* try to clean up all streams */
1434         release_sink(ctl);
1435         smtp_close(ctl, 0);
1436         if (mailserver_socket != -1) {
1437             cleanupSockClose(mailserver_socket);
1438             mailserver_socket = -1;
1439         }
1440         /* If there was a connect timeout, the socket should be closed.
1441          * mailserver_socket_temp contains the socket to close.
1442          */
1443         if (mailserver_socket_temp != -1) {
1444             cleanupSockClose(mailserver_socket_temp);
1445             mailserver_socket_temp = -1;
1446         }
1447     }
1448
1449     msg = (const char *)NULL;   /* sacrifice to -Wall */
1450     switch (err)
1451     {
1452     case PS_SOCKET:
1453         msg = GT_("socket");
1454         break;
1455     case PS_SYNTAX:
1456         msg = GT_("missing or bad RFC822 header");
1457         break;
1458     case PS_IOERR:
1459         msg = GT_("MDA");
1460         break;
1461     case PS_ERROR:
1462         msg = GT_("client/server synchronization");
1463         break;
1464     case PS_PROTOCOL:
1465         msg = GT_("client/server protocol");
1466         break;
1467     case PS_LOCKBUSY:
1468         msg = GT_("lock busy on server");
1469         break;
1470     case PS_SMTP:
1471         msg = GT_("SMTP transaction");
1472         break;
1473     case PS_DNS:
1474         msg = GT_("DNS lookup");
1475         break;
1476     case PS_UNDEFINED:
1477         report(stderr, GT_("undefined error\n"));
1478         break;
1479     }
1480     /* no report on PS_MAXFETCH or PS_UNDEFINED or PS_AUTHFAIL */
1481     if (err==PS_SOCKET || err==PS_SYNTAX
1482                 || err==PS_IOERR || err==PS_ERROR || err==PS_PROTOCOL 
1483                 || err==PS_LOCKBUSY || err==PS_SMTP || err==PS_DNS)
1484     {
1485         char    *stem;
1486
1487         if (phase == FORWARDING_WAIT || phase == LISTENER_WAIT)
1488             stem = GT_("%s error while delivering to SMTP host %s\n");
1489         else
1490             stem = GT_("%s error while fetching from %s\n");
1491         report(stderr, stem, msg, ctl->server.pollname);
1492     }
1493
1494 closeUp:
1495     /* execute wrapup command, if any */
1496     if (ctl->postconnect && (err = system(ctl->postconnect)))
1497     {
1498         report(stderr, GT_("post-connection command failed with status %d\n"), err);
1499         if (err == PS_SUCCESS)
1500             err = PS_SYNTAX;
1501     }
1502
1503     signal(SIGALRM, alrmsave);
1504     signal(SIGPIPE, pipesave);
1505     return(err);
1506 }
1507
1508 int do_protocol(ctl, proto)
1509 /* retrieve messages from server using given protocol method table */
1510 struct query *ctl;              /* parsed options with merged-in defaults */
1511 const struct method *proto;     /* protocol method table */
1512 {
1513     int err;
1514
1515 #ifndef KERBEROS_V4
1516     if (ctl->server.authenticate == A_KERBEROS_V4)
1517     {
1518         report(stderr, GT_("Kerberos V4 support not linked.\n"));
1519         return(PS_ERROR);
1520     }
1521 #endif /* KERBEROS_V4 */
1522
1523 #ifndef KERBEROS_V5
1524     if (ctl->server.authenticate == A_KERBEROS_V5)
1525     {
1526         report(stderr, GT_("Kerberos V5 support not linked.\n"));
1527         return(PS_ERROR);
1528     }
1529 #endif /* KERBEROS_V5 */
1530
1531     /* lacking methods, there are some options that may fail */
1532     if (!proto->is_old)
1533     {
1534         /* check for unsupported options */
1535         if (ctl->flush) {
1536             report(stderr,
1537                     GT_("Option --flush is not supported with %s\n"),
1538                     proto->name);
1539             return(PS_SYNTAX);
1540         }
1541         else if (ctl->fetchall) {
1542             report(stderr,
1543                     GT_("Option --all is not supported with %s\n"),
1544                     proto->name);
1545             return(PS_SYNTAX);
1546         }
1547     }
1548     if (!proto->getsizes && NUM_SPECIFIED(ctl->limit))
1549     {
1550         report(stderr,
1551                 GT_("Option --limit is not supported with %s\n"),
1552                 proto->name);
1553         return(PS_SYNTAX);
1554     }
1555
1556     /*
1557      * If no expunge limit or we do expunges within the driver,
1558      * then just do one session, passing in any fetchlimit.
1559      */
1560     if (proto->retry || !NUM_SPECIFIED(ctl->expunge))
1561         return(do_session(ctl, proto, NUM_VALUE_OUT(ctl->fetchlimit)));
1562     /*
1563      * There's an expunge limit, and it isn't handled in the driver itself.
1564      * OK; do multiple sessions, each fetching a limited # of messages.
1565      * Stop if the total count of retrieved messages exceeds ctl->fetchlimit
1566      * (if it was nonzero).
1567      */
1568     else
1569     {
1570         int totalcount = 0; 
1571         int lockouts   = 0;
1572         int expunge    = NUM_VALUE_OUT(ctl->expunge);
1573         int fetchlimit = NUM_VALUE_OUT(ctl->fetchlimit);
1574
1575         do {
1576             if (fetchlimit > 0 && (expunge == 0 || expunge > fetchlimit - totalcount))
1577                 expunge = fetchlimit - totalcount;
1578             err = do_session(ctl, proto, expunge);
1579             totalcount += expunge;
1580             if (NUM_SPECIFIED(ctl->fetchlimit) && totalcount >= fetchlimit)
1581                 break;
1582             if (err != PS_LOCKBUSY)
1583                 lockouts = 0;
1584             else if (lockouts >= MAX_LOCKOUTS)
1585                 break;
1586             else /* err == PS_LOCKBUSY */
1587             {
1588                 /*
1589                  * Allow time for the server lock to release.  if we
1590                  * don't do this, we'll often hit a locked-mailbox
1591                  * condition and fail.
1592                  */
1593                 lockouts++;
1594                 sleep(3);
1595             }
1596         } while
1597             (err == PS_MAXFETCH || err == PS_LOCKBUSY);
1598
1599         return(err);
1600     }
1601 }
1602
1603
1604 /* driver.c ends here */