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