]> Pileus Git - ~andy/fetchmail/blob - driver.c
Hide the REPOLL message.
[~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.\r\n"
325              "\r\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.\r\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                 suppress_readbody = suppress_forward = suppress_delete = retained = TRUE;
497             else if (err == PS_TRANSIENT)
498                 suppress_delete = suppress_forward = TRUE;
499             else if (err == PS_REFUSED)
500                 suppress_forward = TRUE;
501 #if 0
502             /* 
503              * readheaders does not read the body when it
504              * hits a non-header. It has been recently
505              * fixed to return PS_TRUNCATED (properly) when
506              * that happens, but apparently fixing that bug
507              * opened this one here (which looks like an 
508              * inproper fix from some ancient thinko)
509              */
510             else if (err == PS_TRUNCATED)
511                 suppress_readbody = TRUE;
512             else if (err)
513                 return(err);
514 #else
515             else if (err && err != PS_TRUNCATED)
516                 return(err);
517 #endif
518
519             /* 
520              * If we're using IMAP4 or something else that
521              * can fetch headers separately from bodies,
522              * it's time to request the body now.  This
523              * fetch may be skipped if we got an anti-spam
524              * or other PS_REFUSED error response during
525              * readheaders.
526              */
527             if (ctl->server.base_protocol->fetch_body && !suppress_readbody) 
528             {
529                 if (outlevel >= O_VERBOSE && !isafile(1))
530                 {
531                     fputc('\n', stdout);
532                     fflush(stdout);
533                 }
534
535                 if ((err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num)))
536                     return(err);
537                 len = 0;
538                 if (!suppress_forward)
539                 {
540                     if ((err=(ctl->server.base_protocol->fetch_body)(mailserver_socket,ctl,num,&len)))
541                         return(err);
542                     /*
543                      * Work around a bug in Novell's
544                      * broken GroupWise IMAP server;
545                      * its body FETCH response is missing
546                      * the required length for the data
547                      * string.  This violates RFC2060.
548                      */
549                     if (len == -1)
550                         len = msgsizes[num-1] - msgblk.msglen;
551                     if (outlevel > O_SILENT && !wholesize)
552                         report_complete(stdout,
553                                         GT_(" (%d body octets) "), len);
554                 }
555             }
556
557             /* process the body now */
558             if (len > 0)
559             {
560                 if (suppress_readbody)
561                 {
562                     err = PS_SUCCESS;
563                 }
564                 else
565                 {
566                     err = readbody(mailserver_socket,
567                                   ctl,
568                                   !suppress_forward,
569                                   len);
570                 }
571                 if (err == PS_TRANSIENT)
572                     suppress_delete = suppress_forward = TRUE;
573                 else if (err)
574                     return(err);
575
576                 /* tell server we got it OK and resynchronize */
577                 if (ctl->server.base_protocol->trail)
578                 {
579                     if (outlevel >= O_VERBOSE && !isafile(1))
580                     {
581                         fputc('\n', stdout);
582                         fflush(stdout);
583                     }
584
585                     err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num);
586                     if (err != 0)
587                         return(err);
588                 }
589             }
590
591             /* count # messages forwarded on this pass */
592             if (!suppress_forward)
593                 (*dispatches)++;
594
595             /*
596              * Check to see if the numbers matched?
597              *
598              * Yes, some servers foo this up horribly.
599              * All IMAP servers seem to get it right, and
600              * so does Eudora QPOP at least in 2.xx
601              * versions.
602              *
603              * Microsoft Exchange gets it completely
604              * wrong, reporting compressed rather than
605              * actual sizes (so the actual length of
606              * message is longer than the reported size).
607              * Another fine example of Microsoft brain death!
608              *
609              * Some older POP servers, like the old UCB
610              * POP server and the pre-QPOP QUALCOMM
611              * versions, report a longer size in the LIST
612              * response than actually gets shipped up.
613              * It's unclear what is going on here, as the
614              * QUALCOMM server (at least) seems to be
615              * reporting the on-disk size correctly.
616              */
617             if (msgblk.msglen != msgsizes[num-1])
618             {
619                 if (outlevel >= O_DEBUG)
620                     report(stdout,
621                            GT_("message %s@%s:%d was not the expected length (%d actual != %d expected)\n"),
622                            ctl->remotename, ctl->server.truename, num,
623                            msgblk.msglen, msgsizes[num-1]);
624             }
625
626             /* end-of-message processing starts here */
627             if (!close_sink(ctl, &msgblk, !suppress_forward))
628             {
629                 ctl->errcount++;
630                 suppress_delete = TRUE;
631             }
632             if (!retained)
633                 (*fetches)++;
634         }
635
636         /*
637          * At this point in flow of control, either
638          * we've bombed on a protocol error or had
639          * delivery refused by the SMTP server
640          * (unlikely -- I've never seen it) or we've
641          * seen `accepted for delivery' and the
642          * message is shipped.  It's safe to mark the
643          * message seen and delete it on the server
644          * now.
645          */
646
647         /*
648          * Tell the UID code we've seen this.
649          * Matthias Andree: only register the UID if we could actually
650          * forward this mail. If we omit this !suppress_delete check,
651          * fetchmail will never retry mail that the local listener
652          * refused temporarily.
653          */
654         if (ctl->newsaved && !suppress_delete)
655         {
656             struct idlist       *sdp;
657
658             for (sdp = ctl->newsaved; sdp; sdp = sdp->next)
659                 if ((sdp->val.status.num == num) && (msgcodes[num-1] >= 0))
660                 {
661                     sdp->val.status.mark = UID_SEEN;
662                     save_str(&ctl->oldsaved, sdp->id,UID_SEEN);
663                 }
664         }
665
666         /* maybe we delete this message now? */
667         if (retained)
668         {
669             if (outlevel > O_SILENT) 
670                 report(stdout, GT_(" retained\n"));
671         }
672         else if (ctl->server.base_protocol->delete
673                  && !suppress_delete
674                  && ((msgcodes[num-1] >= 0) ? !ctl->keep : ctl->flush))
675         {
676             (*deletions)++;
677             if (outlevel > O_SILENT) 
678                 report_complete(stdout, GT_(" flushed\n"));
679             err = (ctl->server.base_protocol->delete)(mailserver_socket, ctl, num);
680             if (err != 0)
681                 return(err);
682 #ifdef POP3_ENABLE
683             delete_str(&ctl->newsaved, num);
684 #endif /* POP3_ENABLE */
685         }
686         else if (outlevel > O_SILENT)
687             report_complete(stdout, GT_(" not flushed\n"));
688
689         /* perhaps this as many as we're ready to handle */
690         if (maxfetch && maxfetch <= *fetches && *fetches < count)
691         {
692             report(stdout, GT_("fetchlimit %d reached; %d messages left on server %s account %s\n"),
693                    maxfetch, count - *fetches, ctl->server.truename, ctl->remotename);
694             return(PS_MAXFETCH);
695         }
696     }
697
698     return(PS_SUCCESS);
699 }
700
701 static int do_session(ctl, proto, maxfetch)
702 /* retrieve messages from server using given protocol method table */
703 struct query *ctl;              /* parsed options with merged-in defaults */
704 const struct method *proto;     /* protocol method table */
705 const int maxfetch;             /* maximum number of messages to fetch */
706 {
707     int js;
708 #ifdef HAVE_VOLATILE
709     volatile int err, mailserver_socket = -1;   /* pacifies -Wall */
710 #else
711     int err, mailserver_socket = -1;
712 #endif /* HAVE_VOLATILE */
713     const char *msg;
714     void (*pipesave)(int);
715     void (*alrmsave)(int);
716
717     ctl->server.base_protocol = proto;
718
719     pass = 0;
720     err = 0;
721     init_transact(proto);
722
723     /* set up the server-nonresponse timeout */
724     alrmsave = signal(SIGALRM, timeout_handler);
725     mytimeout = ctl->server.timeout;
726
727     /* set up the broken-pipe timeout */
728     pipesave = signal(SIGPIPE, sigpipe_handler);
729
730     if ((js = setjmp(restart)))
731     {
732 #ifdef HAVE_SIGPROCMASK
733         /*
734          * Don't rely on setjmp() to restore the blocked-signal mask.
735          * It does this under BSD but is required not to under POSIX.
736          *
737          * If your Unix doesn't have sigprocmask, better hope it has
738          * BSD-like behavior.  Otherwise you may see fetchmail get
739          * permanently wedged after a second timeout on a bad read,
740          * because alarm signals were blocked after the first.
741          */
742         sigset_t        allsigs;
743
744         sigfillset(&allsigs);
745         sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
746 #endif /* HAVE_SIGPROCMASK */
747         
748         if (js == THROW_SIGPIPE)
749         {
750             signal(SIGPIPE, SIG_IGN);
751             report(stdout,
752                    GT_("SIGPIPE thrown from an MDA or a stream socket error\n"));
753             wait(0);
754         }
755         else if (js == THROW_TIMEOUT)
756         {
757             if (phase == OPEN_WAIT)
758                 report(stdout,
759                        GT_("timeout after %d seconds waiting to connect to server %s.\n"),
760                        ctl->server.timeout, ctl->server.pollname);
761             else if (phase == SERVER_WAIT)
762                 report(stdout,
763                        GT_("timeout after %d seconds waiting for server %s.\n"),
764                        ctl->server.timeout, ctl->server.pollname);
765             else if (phase == FORWARDING_WAIT)
766                 report(stdout,
767                        GT_("timeout after %d seconds waiting for %s.\n"),
768                        ctl->server.timeout,
769                        ctl->mda ? "MDA" : "SMTP");
770             else if (phase == LISTENER_WAIT)
771                 report(stdout,
772                        GT_("timeout after %d seconds waiting for listener to respond.\n"), ctl->server.timeout);
773             else
774                 report(stdout, 
775                        GT_("timeout after %d seconds.\n"), ctl->server.timeout);
776
777             /*
778              * If we've exceeded our threshold for consecutive timeouts, 
779              * try to notify the user, then mark the connection wedged.
780              * Don't do this if the connection can idle, though; idle
781              * timeouts just mean the frequency of mail is low.
782              */
783             if (timeoutcount > MAX_TIMEOUTS 
784                 && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
785             {
786                 stuff_warning(ctl,
787                               GT_("Subject: fetchmail sees repeated timeouts\r\n"));
788                 stuff_warning(ctl,
789                               GT_("Fetchmail saw more than %d timeouts while attempting to get mail from %s@%s.\r\n"), 
790                               MAX_TIMEOUTS,
791                               ctl->remotename,
792                               ctl->server.truename);
793                 stuff_warning(ctl, 
794     GT_("This could mean that your mailserver is stuck, or that your SMTP\r\n" \
795     "server is wedged, or that your mailbox file on the server has been\r\n" \
796     "corrupted by a server error.  You can run `fetchmail -v -v' to\r\n" \
797     "diagnose the problem.\r\n\r\n" \
798     "Fetchmail won't poll this mailbox again until you restart it.\r\n"));
799                 close_warning_by_mail(ctl, (struct msgblk *)NULL);
800                 ctl->wedged = TRUE;
801             }
802         }
803
804         err = PS_SOCKET;
805         goto cleanUp;
806     }
807     else
808     {
809         char buf[MSGBUFSIZE+1], *realhost;
810         int count, new, bytes, deletions = 0;
811         int *msgsizes = (int *)NULL;
812         int *msgcodes = (int *)NULL;
813 #if INET6_ENABLE
814         int fetches, dispatches, oldphase;
815 #else /* INET6_ENABLE */
816         int port, fetches, dispatches, oldphase;
817 #endif /* INET6_ENABLE */
818         struct idlist *idp;
819
820         /* execute pre-initialization command, if any */
821         if (ctl->preconnect && (err = system(ctl->preconnect)))
822         {
823             report(stderr, 
824                    GT_("pre-connection command failed with status %d\n"), err);
825             err = PS_SYNTAX;
826             goto closeUp;
827         }
828
829         /* open a socket to the mail server */
830         oldphase = phase;
831         phase = OPEN_WAIT;
832         set_timeout(mytimeout);
833 #if !INET6_ENABLE
834 #ifdef SSL_ENABLE
835         port = ctl->server.port ? ctl->server.port : ( ctl->use_ssl ? ctl->server.base_protocol->sslport : ctl->server.base_protocol->port );
836 #else
837         port = ctl->server.port ? ctl->server.port : ctl->server.base_protocol->port;
838 #endif
839 #endif /* !INET6_ENABLE */
840
841 #ifdef HESIOD
842         /* If either the pollname or vianame are "hesiod" we want to
843            lookup the user's hesiod pobox host */
844         if (!strcasecmp(ctl->server.queryname, "hesiod")) {
845             struct hes_postoffice *hes_p;
846             hes_p = hes_getmailhost(ctl->remotename);
847             if (hes_p != NULL && strcmp(hes_p->po_type, "POP") == 0) {
848                  free(ctl->server.queryname);
849                  ctl->server.queryname = xstrdup(hes_p->po_host);
850                  if (ctl->server.via)
851                      free(ctl->server.via);
852                  ctl->server.via = xstrdup(hes_p->po_host);
853             } else {
854                  report(stderr,
855                         GT_("couldn't find HESIOD pobox for %s\n"),
856                         ctl->remotename);
857             }
858         }
859 #endif /* HESIOD */
860
861 #ifdef HAVE_GETHOSTBYNAME
862         /*
863          * Canonicalize the server truename for later use.  This also
864          * functions as a probe for whether the mailserver is accessible.
865          * We try it on each poll cycle until we get a result.  This way,
866          * fetchmail won't fail if started up when the network is inaccessible.
867          */
868         if (ctl->server.dns && !ctl->server.trueaddr)
869         {
870             if (ctl->server.lead_server)
871             {
872                 char    *leadname = ctl->server.lead_server->truename;
873
874                 /* prevent core dump from ill-formed or duplicate entry */
875                 if (!leadname)
876                 {
877                     report(stderr, GT_("Lead server has no name.\n"));
878                     err = PS_DNS;
879                     set_timeout(0);
880                     phase = oldphase;
881                     goto closeUp;
882                 }
883
884                 ctl->server.truename = xstrdup(leadname);
885             }
886             else
887             {
888                 struct hostent  *namerec;
889                     
890                 /* 
891                  * Get the host's IP, so we can report it like this:
892                  *
893                  * Received: from hostname [10.0.0.1]
894                  */
895                 errno = 0;
896                 namerec = gethostbyname(ctl->server.queryname);
897                 if (namerec == (struct hostent *)NULL)
898                 {
899                     report(stderr,
900                            GT_("couldn't find canonical DNS name of %s\n"),
901                            ctl->server.pollname);
902                     err = PS_DNS;
903                     set_timeout(0);
904                     phase = oldphase;
905                     goto closeUp;
906                 }
907                 else 
908                 {
909                     ctl->server.truename=xstrdup((char *)namerec->h_name);
910                     ctl->server.trueaddr=xmalloc(namerec->h_length);
911                     memcpy(ctl->server.trueaddr, 
912                            namerec->h_addr_list[0],
913                            namerec->h_length);
914                 }
915             }
916         }
917 #endif /* HAVE_GETHOSTBYNAME */
918
919         realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
920
921         /* allow time for the port to be set up if we have a plugin */
922         if (ctl->server.plugin)
923             (void)sleep(1);
924 #if INET6_ENABLE
925         if ((mailserver_socket = SockOpen(realhost, 
926                              ctl->server.service ? ctl->server.service : ( ctl->use_ssl ? ctl->server.base_protocol->sslservice : ctl->server.base_protocol->service ),
927                              ctl->server.netsec, ctl->server.plugin)) == -1)
928 #else /* INET6_ENABLE */
929         if ((mailserver_socket = SockOpen(realhost, port, NULL, ctl->server.plugin)) == -1)
930 #endif /* INET6_ENABLE */
931         {
932             char        errbuf[BUFSIZ];
933 #if !INET6_ENABLE
934             int err_no = errno;
935 #ifdef HAVE_RES_SEARCH
936             if (err_no != 0 && h_errno != 0)
937                 report(stderr, GT_("internal inconsistency\n"));
938 #endif
939             /*
940              * Avoid generating a bogus error every poll cycle when we're
941              * in daemon mode but the connection to the outside world
942              * is down.
943              */
944             if (!((err_no == EHOSTUNREACH || err_no == ENETUNREACH) 
945                   && run.poll_interval))
946             {
947                 report_build(stderr, GT_("%s connection to %s failed"), 
948                              ctl->server.base_protocol->name, ctl->server.pollname);
949 #ifdef HAVE_RES_SEARCH
950                 if (h_errno != 0)
951                 {
952                     if (h_errno == HOST_NOT_FOUND)
953                         strcpy(errbuf, GT_("host is unknown."));
954 #ifndef __BEOS__
955                     else if (h_errno == NO_ADDRESS)
956                         strcpy(errbuf, GT_("name is valid but has no IP address."));
957 #endif
958                     else if (h_errno == NO_RECOVERY)
959                         strcpy(errbuf, GT_("unrecoverable name server error."));
960                     else if (h_errno == TRY_AGAIN)
961                         strcpy(errbuf, GT_("temporary name server error."));
962                     else
963 #ifdef HAVE_SNPRINTF
964                         snprintf(errbuf, sizeof(errbuf),
965 #else
966                         sprintf(errbuf,
967 #endif /* HAVE_SNPRINTF */
968                           GT_("unknown DNS error %d."), h_errno);
969                 }
970                 else
971 #endif /* HAVE_RES_SEARCH */
972                     strcpy(errbuf, strerror(err_no));
973                 report_complete(stderr, ": %s\n", errbuf);
974
975 #ifdef __UNUSED
976                 /* 
977                  * Don't use this.  It was an attempt to address Debian bug
978                  * #47143 (Notify user by mail when pop server nonexistent).
979                  * Trouble is, that doesn't work; you trip over the case 
980                  * where your SLIP or PPP link is down...
981                  */
982                 /* warn the system administrator */
983                 if (open_warning_by_mail(ctl, (struct msgblk *)NULL) == 0)
984                 {
985                     stuff_warning(ctl,
986                          GT_("Subject: Fetchmail unreachable-server warning.\r\n"
987                            "\r\n"
988                            "Fetchmail could not reach the mail server %s:")
989                                   ctl->server.pollname);
990                     stuff_warning(ctl, errbuf, ctl->server.pollname);
991                     close_warning_by_mail(ctl, (struct msgblk *)NULL);
992                 }
993 #endif
994             }
995 #endif /* INET6_ENABLE */
996             err = PS_SOCKET;
997             set_timeout(0);
998             phase = oldphase;
999             goto closeUp;
1000         }
1001
1002 #ifdef SSL_ENABLE
1003         /* Save the socket opened. Usefull if Fetchmail hangs on SSLOpen 
1004          * because the socket can be closed
1005          */
1006         mailserver_socket_temp = mailserver_socket;
1007         set_timeout(mytimeout);
1008
1009         /* perform initial SSL handshake on open connection */
1010         /* Note:  We pass the realhost name over for certificate
1011                 verification.  We may want to make this configurable */
1012         if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslcert,ctl->sslkey,ctl->sslproto,ctl->sslcertck,
1013             ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1) 
1014         {
1015             report(stderr, GT_("SSL connection failed.\n"));
1016             goto closeUp;
1017         }
1018         
1019         /* Fetchmail didn't hang on SSLOpen, 
1020          * then no need to set mailserver_socket_temp 
1021          */
1022         mailserver_socket_temp = -1;
1023 #endif
1024         
1025         /* A timeout is still defined before SSLOpen, 
1026          * then Fetchmail hanging on SSLOpen is handled.
1027          */
1028         set_timeout(0);
1029         phase = oldphase;
1030 #ifdef KERBEROS_V4
1031         if (ctl->server.authenticate == A_KERBEROS_V4 && (strcasecmp(proto->name,"IMAP") != 0))
1032         {
1033             set_timeout(mytimeout);
1034             err = kerberos_auth(mailserver_socket, ctl->server.truename,
1035                                ctl->server.principal);
1036             set_timeout(0);
1037             if (err != 0)
1038                 goto cleanUp;
1039         }
1040 #endif /* KERBEROS_V4 */
1041
1042 #ifdef KERBEROS_V5
1043         if (ctl->server.authenticate == A_KERBEROS_V5)
1044         {
1045             set_timeout(mytimeout);
1046             err = kerberos5_auth(mailserver_socket, ctl->server.truename);
1047             set_timeout(0);
1048             if (err != 0)
1049                 goto cleanUp;
1050         }
1051 #endif /* KERBEROS_V5 */
1052
1053         /* accept greeting message from mail server */
1054         err = (ctl->server.base_protocol->parse_response)(mailserver_socket, buf);
1055         if (err != 0)
1056             goto cleanUp;
1057
1058         /* try to get authorized to fetch mail */
1059         stage = STAGE_GETAUTH;
1060         if (ctl->server.base_protocol->getauth)
1061         {
1062             err = (ctl->server.base_protocol->getauth)(mailserver_socket, ctl, buf);
1063
1064             if (err != 0)
1065             {
1066                 if (err == PS_LOCKBUSY)
1067                     report(stderr, GT_("Lock-busy error on %s@%s\n"),
1068                           ctl->remotename,
1069                           ctl->server.truename);
1070                 else if (err == PS_SERVBUSY)
1071                     report(stderr, GT_("Server busy error on %s@%s\n"),
1072                           ctl->remotename,
1073                           ctl->server.truename);
1074                 else if (err == PS_AUTHFAIL)
1075                 {
1076                     report(stderr, GT_("Authorization failure on %s@%s%s\n"), 
1077                            ctl->remotename,
1078                            ctl->server.truename,
1079                            (ctl->wehaveauthed ? GT_(" (previously authorized)") : "")
1080                         );
1081
1082                     /*
1083                      * If we're running in background, try to mail the
1084                      * calling user a heads-up about the authentication 
1085                      * failure once it looks like this isn't a fluke 
1086                      * due to the server being temporarily inaccessible.
1087                      * When we get third succesive failure, we notify the user
1088                      * but only if we haven't already managed to get
1089                      * authorization.  After that, once we get authorization
1090                      * we let the user know service is restored.
1091                      */
1092                     if (run.poll_interval
1093                         && ctl->wehavesentauthnote
1094                         && ((ctl->wehaveauthed && ++ctl->authfailcount == 10)
1095                             || ++ctl->authfailcount == 3)
1096                         && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
1097                     {
1098                         ctl->wehavesentauthnote = 1;
1099                         stuff_warning(ctl,
1100                                       GT_("Subject: fetchmail authentication failed on %s@%s\r\n"),
1101                             ctl->remotename, ctl->server.truename);
1102                         stuff_warning(ctl,
1103                                       GT_("Fetchmail could not get mail from %s@%s.\r\n"), 
1104                                       ctl->remotename,
1105                                       ctl->server.truename);
1106                         if (ctl->wehaveauthed)
1107                             stuff_warning(ctl, GT_("\
1108 The attempt to get authorization failed.\r\n\
1109 Since we have already succeeded in getting authorization for this\r\n\
1110 connection, this is probably another failure mode (such as busy server)\r\n\
1111 that fetchmail cannot distinguish because the server didn't send a useful\r\n\
1112 error message.\r\n\
1113 \r\n\
1114 However, if you HAVE changed you account details since starting the\r\n\
1115 fetchmail daemon, you need to stop the daemon, change your configuration\r\n\
1116 of fetchmail, and then restart the daemon.\r\n\
1117 \r\n\
1118 The fetchmail daemon will continue running and attempt to connect\r\n\
1119 at each cycle.  No future notifications will be sent until service\r\n\
1120 is restored."));
1121                         else
1122                             stuff_warning(ctl, GT_("\
1123 The attempt to get authorization failed.\r\n\
1124 This probably means your password is invalid, but some servers have\r\n\
1125 other failure modes that fetchmail cannot distinguish from this\r\n\
1126 because they don't send useful error messages on login failure.\r\n\
1127 \r\n\
1128 The fetchmail daemon will continue running and attempt to connect\r\n\
1129 at each cycle.  No future notifications will be sent until service\r\n\
1130 is restored."));
1131                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1132                     }
1133                 }
1134                 else if (err == PS_REPOLL)
1135                 {
1136                   if (outlevel >= O_VERBOSE)
1137                     report(stderr, GT_("Repoll immediately on %s@%s\n"),
1138                            ctl->remotename,
1139                            ctl->server.truename);
1140                 }
1141                 else
1142                     report(stderr, GT_("Unknown login or authentication error on %s@%s\n"),
1143                            ctl->remotename,
1144                            ctl->server.truename);
1145                     
1146                 goto cleanUp;
1147             }
1148             else
1149             {
1150                 /*
1151                  * This connection has given us authorization at least once.
1152                  *
1153                  * There are dodgy server (clubinternet.fr for example) that
1154                  * give spurious authorization failures on patently good
1155                  * account/password details, then 5 minutes later let you in!
1156                  *
1157                  * This is meant to build in some tolerance of such nasty bits
1158                  * of work.
1159                  */
1160                 ctl->wehaveauthed = 1;
1161                 /*if (ctl->authfailcount >= 3)*/
1162                 if (ctl->wehavesentauthnote)
1163                 {
1164                     ctl->wehavesentauthnote = 0;
1165                     report(stderr,
1166                            GT_("Authorization OK on %s@%s\n"),
1167                            ctl->remotename,
1168                            ctl->server.truename);
1169                     if (!open_warning_by_mail(ctl, (struct msgblk *)NULL))
1170                     {
1171                         stuff_warning(ctl,
1172                               GT_("Subject: fetchmail authentication OK on %s@%s\r\n"),
1173                                       ctl->remotename, ctl->server.truename);
1174                         stuff_warning(ctl,
1175                               GT_("Fetchmail was able to log into %s@%s.\r\n"), 
1176                                       ctl->remotename,
1177                                       ctl->server.truename);
1178                         stuff_warning(ctl, 
1179                                       GT_("Service has been restored.\r\n"));
1180                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1181                     
1182                     }
1183                 }
1184                 /*
1185                  * Reporting only after the first three
1186                  * consecutive failures, or ten consecutive
1187                  * failures after we have managed to get
1188                  * authorization.
1189                  */
1190                 ctl->authfailcount = 0;
1191             }
1192         }
1193
1194         ctl->errcount = fetches = 0;
1195
1196         /* now iterate over each folder selected */
1197         for (idp = ctl->mailboxes; idp; idp = idp->next)
1198         {
1199             pass = 0;
1200             do {
1201                 dispatches = 0;
1202                 ++pass;
1203
1204                 /* reset timeout, in case we did an IDLE */
1205                 mytimeout = ctl->server.timeout;
1206
1207                 if (outlevel >= O_DEBUG)
1208                 {
1209                     if (idp->id)
1210                         report(stdout, GT_("selecting or re-polling folder %s\n"), idp->id);
1211                     else
1212                         report(stdout, GT_("selecting or re-polling default folder\n"));
1213                 }
1214
1215                 /* compute # of messages and number of new messages waiting */
1216                 stage = STAGE_GETRANGE;
1217                 err = (ctl->server.base_protocol->getrange)(mailserver_socket, ctl, idp->id, &count, &new, &bytes);
1218                 if (err != 0)
1219                     goto cleanUp;
1220
1221                 /* show user how many messages we downloaded */
1222                 if (idp->id)
1223 #ifdef HAVE_SNPRINTF
1224                     (void) snprintf(buf, sizeof(buf),
1225 #else
1226                     (void) sprintf(buf,
1227 #endif /* HAVE_SNPRINTF */
1228                                    GT_("%s at %s (folder %s)"),
1229                                    ctl->remotename, ctl->server.truename, idp->id);
1230                 else
1231 #ifdef HAVE_SNPRINTF
1232                     (void) snprintf(buf, sizeof(buf),
1233 #else
1234                     (void) sprintf(buf,
1235 #endif /* HAVE_SNPRINTF */
1236                                GT_("%s at %s"),
1237                                    ctl->remotename, ctl->server.truename);
1238                 if (outlevel > O_SILENT)
1239                 {
1240                     if (count == -1)            /* only used for ETRN */
1241                         report(stdout, GT_("Polling %s\n"), ctl->server.truename);
1242                     else if (count != 0)
1243                     {
1244                         if (new != -1 && (count - new) > 0)
1245                             report_build(stdout, GT_("%d %s (%d seen) for %s"),
1246                                   count, count > 1 ? GT_("messages") :
1247                                                      GT_("message"),
1248                                   count-new, buf);
1249                         else
1250                             report_build(stdout, GT_("%d %s for %s"), 
1251                                   count, count > 1 ? GT_("messages") :
1252                                                      GT_("message"), buf);
1253                         if (bytes == -1)
1254                             report_complete(stdout, ".\n");
1255                         else
1256                             report_complete(stdout, GT_(" (%d octets).\n"), bytes);
1257                     }
1258                     else
1259                     {
1260                         /* these are pointless in normal daemon mode */
1261                         if (pass == 1 && (run.poll_interval == 0 || outlevel >= O_VERBOSE))
1262                             report(stdout, GT_("No mail for %s\n"), buf); 
1263                     }
1264                 }
1265
1266                 /* very important, this is where we leave the do loop */ 
1267                 if (count == 0)
1268                     break;
1269
1270                 if (check_only)
1271                 {
1272                     if (new == -1 || ctl->fetchall)
1273                         new = count;
1274                     fetches = new;      /* set error status correctly */
1275                     /*
1276                      * There used to be a `goto noerror' here, but this
1277                      * prevented checking of multiple folders.  This
1278                      * comment is a reminder in case I introduced some
1279                      * subtle bug by removing it...
1280                      */
1281                 }
1282                 else if (count > 0)
1283                 {    
1284                     flag        force_retrieval;
1285                     int         i, num;
1286
1287                     /*
1288                      * What forces this code is that in POP2 and
1289                      * IMAP2bis you can't fetch a message without
1290                      * having it marked `seen'.  In POP3 and IMAP4, on the
1291                      * other hand, you can (peek_capable is set by 
1292                      * each driver module to convey this; it's not a
1293                      * method constant because of the difference between
1294                      * IMAP2bis and IMAP4, and because POP3 doesn't  peek
1295                      * if fetchall is on).
1296                      *
1297                      * The result of being unable to peek is that if there's
1298                      * any kind of transient error (DNS lookup failure, or
1299                      * sendmail refusing delivery due to process-table limits)
1300                      * the message will be marked "seen" on the server without
1301                      * having been delivered.  This is not a big problem if
1302                      * fetchmail is running in foreground, because the user
1303                      * will see a "skipped" message when it next runs and get
1304                      * clued in.
1305                      *
1306                      * But in daemon mode this leads to the message
1307                      * being silently ignored forever.  This is not
1308                      * acceptable.
1309                      *
1310                      * We compensate for this by checking the error
1311                      * count from the previous pass and forcing all
1312                      * messages to be considered new if it's nonzero.
1313                      */
1314                     force_retrieval = !peek_capable && (ctl->errcount > 0);
1315
1316                     /*
1317                      * Don't trust the message count passed by the server.
1318                      * Without this check, it might be possible to do a
1319                      * DNS-spoofing attack that would pass back a ridiculous 
1320                      * count, and allocate a malloc area that would overlap
1321                      * a portion of the stack.
1322                      */
1323                     if (count > INT_MAX/sizeof(int))
1324                     {
1325                         report(stderr, GT_("bogus message count!"));
1326                         return(PS_PROTOCOL);
1327                     }
1328
1329                     /* OK, we're going to gather size info next */
1330                     xalloca(msgsizes, int *, sizeof(int) * count);
1331                     xalloca(msgcodes, int *, sizeof(int) * count);
1332                     for (i = 0; i < count; i++) {
1333                         msgsizes[i] = 0;
1334                         msgcodes[i] = MSGLEN_UNKNOWN;
1335                     }
1336
1337                     /* 
1338                      * We need the size of each message before it's
1339                      * loaded in order to pass it to the ESMTP SIZE
1340                      * option.  If the protocol has a getsizes method,
1341                      * we presume this means it doesn't get reliable
1342                      * sizes from message fetch responses.
1343                      */
1344                     if (proto->getsizes)
1345                     {
1346                         stage = STAGE_GETSIZES;
1347                         err = (proto->getsizes)(mailserver_socket, count, msgsizes);
1348                         if (err != 0)
1349                             goto cleanUp;
1350
1351                         if (bytes == -1)
1352                         {
1353                             bytes = 0;
1354                             for (i = 0; i < count; i++)
1355                                 bytes += msgsizes[i];
1356                         }
1357                     }
1358
1359                     /* mark some messages not to be retrieved */
1360                     for (num = 1; num <= count; num++)
1361                     {
1362                         if (NUM_NONZERO(ctl->limit) && (msgsizes[num-1] > ctl->limit))
1363                             msgcodes[num-1] = MSGLEN_TOOLARGE;
1364                         else if (ctl->fetchall || force_retrieval)
1365                             continue;
1366                         else if (ctl->server.base_protocol->is_old && (ctl->server.base_protocol->is_old)(mailserver_socket,ctl,num))
1367                             msgcodes[num-1] = MSGLEN_OLD;
1368 /*                      else if (msgsizes[num-1] == 512)
1369                                 msgcodes[num-1] = MSGLEN_OLD;  (hmh) sample code to skip message */
1370                     }
1371
1372                     /* read, forward, and delete messages */
1373                     stage = STAGE_FETCH;
1374
1375                     /* fetch in lockstep mode */
1376                     err = fetch_messages(mailserver_socket, ctl, 
1377                                          count, msgsizes, msgcodes,
1378                                          maxfetch,
1379                                          &fetches, &dispatches, &deletions);
1380                     if (err)
1381                         goto cleanUp;
1382
1383                     if (!check_only && ctl->skipped
1384                         && run.poll_interval > 0 && !nodetach)
1385                     {
1386                         clean_skipped_list(&ctl->skipped);
1387                         send_size_warnings(ctl);
1388                     }
1389                 }
1390             } while
1391                   /*
1392                    * Only re-poll if we either had some actual forwards and 
1393                    * either allowed deletions and had no errors.
1394                    * Otherwise it is far too easy to get into infinite loops.
1395                    */
1396                   (dispatches && ctl->server.base_protocol->retry && !ctl->keep && !ctl->errcount);
1397         }
1398
1399     /* no_error: */
1400         /* ordinary termination with no errors -- officially log out */
1401         err = (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
1402         /*
1403          * Hmmmm...arguably this would be incorrect if we had fetches but
1404          * no dispatches (due to oversized messages, etc.)
1405          */
1406         if (err == 0)
1407             err = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
1408         cleanupSockClose(mailserver_socket);
1409         goto closeUp;
1410
1411     cleanUp:
1412         /* we only get here on error */
1413         if (err != 0 && err != PS_SOCKET && err != PS_REPOLL)
1414         {
1415             stage = STAGE_LOGOUT;
1416             (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
1417         }
1418
1419         /* try to clean up all streams */
1420         release_sink(ctl);
1421         smtp_close(ctl, 0);
1422         if (mailserver_socket != -1) {
1423             cleanupSockClose(mailserver_socket);
1424             mailserver_socket = -1;
1425         }
1426         /* If there was a connect timeout, the socket should be closed.
1427          * mailserver_socket_temp contains the socket to close.
1428          */
1429         if (mailserver_socket_temp != -1) {
1430             cleanupSockClose(mailserver_socket_temp);
1431             mailserver_socket_temp = -1;
1432         }
1433     }
1434
1435     msg = (const char *)NULL;   /* sacrifice to -Wall */
1436     switch (err)
1437     {
1438     case PS_SOCKET:
1439         msg = GT_("socket");
1440         break;
1441     case PS_SYNTAX:
1442         msg = GT_("missing or bad RFC822 header");
1443         break;
1444     case PS_IOERR:
1445         msg = GT_("MDA");
1446         break;
1447     case PS_ERROR:
1448         msg = GT_("client/server synchronization");
1449         break;
1450     case PS_PROTOCOL:
1451         msg = GT_("client/server protocol");
1452         break;
1453     case PS_LOCKBUSY:
1454         msg = GT_("lock busy on server");
1455         break;
1456     case PS_SMTP:
1457         msg = GT_("SMTP transaction");
1458         break;
1459     case PS_DNS:
1460         msg = GT_("DNS lookup");
1461         break;
1462     case PS_UNDEFINED:
1463         report(stderr, GT_("undefined error\n"));
1464         break;
1465     }
1466     /* no report on PS_MAXFETCH or PS_UNDEFINED or PS_AUTHFAIL */
1467     if (err==PS_SOCKET || err==PS_SYNTAX
1468                 || err==PS_IOERR || err==PS_ERROR || err==PS_PROTOCOL 
1469                 || err==PS_LOCKBUSY || err==PS_SMTP || err==PS_DNS)
1470     {
1471         char    *stem;
1472
1473         if (phase == FORWARDING_WAIT || phase == LISTENER_WAIT)
1474             stem = GT_("%s error while delivering to SMTP host %s\n");
1475         else
1476             stem = GT_("%s error while fetching from %s\n");
1477         report(stderr, stem, msg, ctl->server.pollname);
1478     }
1479
1480 closeUp:
1481     /* execute wrapup command, if any */
1482     if (ctl->postconnect && (err = system(ctl->postconnect)))
1483     {
1484         report(stderr, GT_("post-connection command failed with status %d\n"), err);
1485         if (err == PS_SUCCESS)
1486             err = PS_SYNTAX;
1487     }
1488
1489     signal(SIGALRM, alrmsave);
1490     signal(SIGPIPE, pipesave);
1491     return(err);
1492 }
1493
1494 int do_protocol(ctl, proto)
1495 /* retrieve messages from server using given protocol method table */
1496 struct query *ctl;              /* parsed options with merged-in defaults */
1497 const struct method *proto;     /* protocol method table */
1498 {
1499     int err;
1500
1501 #ifndef KERBEROS_V4
1502     if (ctl->server.authenticate == A_KERBEROS_V4)
1503     {
1504         report(stderr, GT_("Kerberos V4 support not linked.\n"));
1505         return(PS_ERROR);
1506     }
1507 #endif /* KERBEROS_V4 */
1508
1509 #ifndef KERBEROS_V5
1510     if (ctl->server.authenticate == A_KERBEROS_V5)
1511     {
1512         report(stderr, GT_("Kerberos V5 support not linked.\n"));
1513         return(PS_ERROR);
1514     }
1515 #endif /* KERBEROS_V5 */
1516
1517     /* lacking methods, there are some options that may fail */
1518     if (!proto->is_old)
1519     {
1520         /* check for unsupported options */
1521         if (ctl->flush) {
1522             report(stderr,
1523                     GT_("Option --flush is not supported with %s\n"),
1524                     proto->name);
1525             return(PS_SYNTAX);
1526         }
1527         else if (ctl->fetchall) {
1528             report(stderr,
1529                     GT_("Option --all is not supported with %s\n"),
1530                     proto->name);
1531             return(PS_SYNTAX);
1532         }
1533     }
1534     if (!proto->getsizes && NUM_SPECIFIED(ctl->limit))
1535     {
1536         report(stderr,
1537                 GT_("Option --limit is not supported with %s\n"),
1538                 proto->name);
1539         return(PS_SYNTAX);
1540     }
1541
1542     /*
1543      * If no expunge limit or we do expunges within the driver,
1544      * then just do one session, passing in any fetchlimit.
1545      */
1546     if (proto->retry || !NUM_SPECIFIED(ctl->expunge))
1547         return(do_session(ctl, proto, NUM_VALUE_OUT(ctl->fetchlimit)));
1548     /*
1549      * There's an expunge limit, and it isn't handled in the driver itself.
1550      * OK; do multiple sessions, each fetching a limited # of messages.
1551      * Stop if the total count of retrieved messages exceeds ctl->fetchlimit
1552      * (if it was nonzero).
1553      */
1554     else
1555     {
1556         int totalcount = 0; 
1557         int lockouts   = 0;
1558         int expunge    = NUM_VALUE_OUT(ctl->expunge);
1559         int fetchlimit = NUM_VALUE_OUT(ctl->fetchlimit);
1560
1561         do {
1562             if (fetchlimit > 0 && (expunge == 0 || expunge > fetchlimit - totalcount))
1563                 expunge = fetchlimit - totalcount;
1564             err = do_session(ctl, proto, expunge);
1565             totalcount += expunge;
1566             if (NUM_SPECIFIED(ctl->fetchlimit) && totalcount >= fetchlimit)
1567                 break;
1568             if (err != PS_LOCKBUSY)
1569                 lockouts = 0;
1570             else if (lockouts >= MAX_LOCKOUTS)
1571                 break;
1572             else /* err == PS_LOCKBUSY */
1573             {
1574                 /*
1575                  * Allow time for the server lock to release.  if we
1576                  * don't do this, we'll often hit a locked-mailbox
1577                  * condition and fail.
1578                  */
1579                 lockouts++;
1580                 sleep(3);
1581             }
1582         } while
1583             (err == PS_MAXFETCH || err == PS_LOCKBUSY);
1584
1585         return(err);
1586     }
1587 }
1588
1589
1590 /* driver.c ends here */