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