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