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