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