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