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