]> Pileus Git - ~andy/fetchmail/blob - driver.c
Justin Guyett's fix.
[~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, _("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, _("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, _("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            _("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                     _("\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                              _("skipping message %d (%d octets)"),
401                              num, msgsizes[num-1]);
402                 switch (msgcodes[num-1])
403                 {
404                 case MSGLEN_INVALID:
405                     /*
406                      * Invalid lengths are produced by Post Office/NT's
407                      * annoying habit of randomly prepending bogus
408                      * LIST items of length -1.  Patrick Audley
409                      * <paudley@pobox.com> tells us: LIST shows a
410                      * size of -1, RETR and TOP return "-ERR
411                      * System error - couldn't open message", and
412                      * DELE succeeds but doesn't actually delete
413                      * the message.
414                      */
415                     report_build(stdout, _(" (length -1)"));
416                     break;
417                 case MSGLEN_TOOLARGE:
418                     report_build(stdout, 
419                                  _(" (oversized, %d octets)"),
420                                  msgsizes[num-1]);
421                     break;
422                 }
423             }
424         }
425         else
426         {
427             flag wholesize = !ctl->server.base_protocol->fetch_body;
428
429             /* request a message */
430             err = (ctl->server.base_protocol->fetch_headers)(mailserver_socket,ctl,num, &len);
431             if (err == PS_TRANSIENT)    /* server is probably Exchange */
432             {
433                 report_build(stdout,
434                              _("couldn't fetch headers, msg %d (%d octets)"),
435                              num, msgsizes[num-1]);
436                 continue;
437             }
438             else if (err != 0)
439                 return(err);
440
441             /* -1 means we didn't see a size in the response */
442             if (len == -1)
443             {
444                 len = msgsizes[num - 1];
445                 wholesize = TRUE;
446             }
447
448             if (outlevel > O_SILENT)
449             {
450                 report_build(stdout, _("reading message %d of %d"),
451                              num,count);
452
453                 if (len > 0)
454                     report_build(stdout, _(" (%d %soctets)"),
455                                  len, wholesize ? "" : _("header "));
456                 if (outlevel >= O_VERBOSE)
457                     report_complete(stdout, "\n");
458                 else
459                     report_complete(stdout, " ");
460             }
461
462             /* 
463              * Read the message headers and ship them to the
464              * output sink.  
465              */
466             err = readheaders(mailserver_socket, len, msgsizes[num-1],
467                              ctl, num);
468             if (err == PS_RETAINED)
469                 suppress_forward = retained = TRUE;
470             else if (err == PS_TRANSIENT)
471                 suppress_delete = suppress_forward = TRUE;
472             else if (err == PS_REFUSED)
473                 suppress_forward = TRUE;
474             else if (err == PS_TRUNCATED)
475                 suppress_readbody = TRUE;
476             else if (err)
477                 return(err);
478
479             /* 
480              * If we're using IMAP4 or something else that
481              * can fetch headers separately from bodies,
482              * it's time to request the body now.  This
483              * fetch may be skipped if we got an anti-spam
484              * or other PS_REFUSED error response during
485              * readheaders.
486              */
487             if (ctl->server.base_protocol->fetch_body && !suppress_readbody) 
488             {
489                 if (outlevel >= O_VERBOSE && !isafile(1))
490                 {
491                     fputc('\n', stdout);
492                     fflush(stdout);
493                 }
494
495                 if ((err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num)))
496                     return(err);
497                 len = 0;
498                 if (!suppress_forward)
499                 {
500                     if ((err=(ctl->server.base_protocol->fetch_body)(mailserver_socket,ctl,num,&len)))
501                         return(err);
502                     /*
503                      * Work around a bug in Novell's
504                      * broken GroupWise IMAP server;
505                      * its body FETCH response is missing
506                      * the required length for the data
507                      * string.  This violates RFC2060.
508                      */
509                     if (len == -1)
510                         len = msgsizes[num-1] - msgblk.msglen;
511                     if (outlevel > O_SILENT && !wholesize)
512                         report_complete(stdout,
513                                         _(" (%d body octets) "), len);
514                 }
515             }
516
517             /* process the body now */
518             if (len > 0)
519             {
520                 if (suppress_readbody)
521                 {
522                     /* When readheaders returns PS_TRUNCATED,
523                      * the body (which has no content)
524                      * has already been read by readheaders,
525                      * so we say readbody returned PS_SUCCESS
526                      */
527                     err = PS_SUCCESS;
528                 }
529                 else
530                 {
531                     err = readbody(mailserver_socket,
532                                   ctl,
533                                   !suppress_forward,
534                                   len);
535                 }
536                 if (err == PS_TRANSIENT)
537                     suppress_delete = suppress_forward = TRUE;
538                 else if (err)
539                     return(err);
540
541                 /* tell server we got it OK and resynchronize */
542                 if (ctl->server.base_protocol->trail)
543                 {
544                     if (outlevel >= O_VERBOSE && !isafile(1))
545                     {
546                         fputc('\n', stdout);
547                         fflush(stdout);
548                     }
549
550                     err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num);
551                     if (err != 0)
552                         return(err);
553                 }
554             }
555
556             /* count # messages forwarded on this pass */
557             if (!suppress_forward)
558                 (*dispatches)++;
559
560             /*
561              * Check to see if the numbers matched?
562              *
563              * Yes, some servers foo this up horribly.
564              * All IMAP servers seem to get it right, and
565              * so does Eudora QPOP at least in 2.xx
566              * versions.
567              *
568              * Microsoft Exchange gets it completely
569              * wrong, reporting compressed rather than
570              * actual sizes (so the actual length of
571              * message is longer than the reported size).
572              * Another fine example of Microsoft brain death!
573              *
574              * Some older POP servers, like the old UCB
575              * POP server and the pre-QPOP QUALCOMM
576              * versions, report a longer size in the LIST
577              * response than actually gets shipped up.
578              * It's unclear what is going on here, as the
579              * QUALCOMM server (at least) seems to be
580              * reporting the on-disk size correctly.
581              */
582             if (msgblk.msglen != msgsizes[num-1])
583             {
584                 if (outlevel >= O_DEBUG)
585                     report(stdout,
586                            _("message %d was not the expected length (%d actual != %d expected)\n"),
587                            num, msgblk.msglen, msgsizes[num-1]);
588             }
589
590             /* end-of-message processing starts here */
591             if (!close_sink(ctl, &msgblk, !suppress_forward))
592             {
593                 ctl->errcount++;
594                 suppress_delete = TRUE;
595             }
596             (*fetches)++;
597         }
598
599         /*
600          * At this point in flow of control, either
601          * we've bombed on a protocol error or had
602          * delivery refused by the SMTP server
603          * (unlikely -- I've never seen it) or we've
604          * seen `accepted for delivery' and the
605          * message is shipped.  It's safe to mark the
606          * message seen and delete it on the server
607          * now.
608          */
609
610         /* tell the UID code we've seen this */
611         if (ctl->newsaved)
612         {
613             struct idlist       *sdp;
614
615             for (sdp = ctl->newsaved; sdp; sdp = sdp->next)
616                 if ((sdp->val.status.num == num) && (msgcodes[num-1] >= 0))
617                 {
618                     sdp->val.status.mark = UID_SEEN;
619                     save_str(&ctl->oldsaved, sdp->id,UID_SEEN);
620                 }
621         }
622
623         /* maybe we delete this message now? */
624         if (retained)
625         {
626             if (outlevel > O_SILENT) 
627                 report(stdout, _(" retained\n"));
628         }
629         else if (ctl->server.base_protocol->delete
630                  && !suppress_delete
631                  && ((msgcodes[num-1] >= 0) ? !ctl->keep : ctl->flush))
632         {
633             (*deletions)++;
634             if (outlevel > O_SILENT) 
635                 report_complete(stdout, _(" flushed\n"));
636             err = (ctl->server.base_protocol->delete)(mailserver_socket, ctl, num);
637             if (err != 0)
638                 return(err);
639 #ifdef POP3_ENABLE
640             delete_str(&ctl->newsaved, num);
641 #endif /* POP3_ENABLE */
642         }
643         else if (outlevel > O_SILENT) 
644             report_complete(stdout, _(" not flushed\n"));
645
646         /* perhaps this as many as we're ready to handle */
647         if (maxfetch && maxfetch <= *fetches && *fetches < count)
648         {
649             report(stdout, _("fetchlimit %d reached; %d messages left on server\n"),
650                    maxfetch, count - *fetches);
651             return(PS_MAXFETCH);
652         }
653     }
654
655     return(PS_SUCCESS);
656 }
657
658 static int do_session(ctl, proto, maxfetch)
659 /* retrieve messages from server using given protocol method table */
660 struct query *ctl;              /* parsed options with merged-in defaults */
661 const struct method *proto;     /* protocol method table */
662 const int maxfetch;             /* maximum number of messages to fetch */
663 {
664     int js;
665 #ifdef HAVE_VOLATILE
666     volatile int err, mailserver_socket = -1;   /* pacifies -Wall */
667 #else
668     int err, mailserver_socket = -1;
669 #endif /* HAVE_VOLATILE */
670     const char *msg;
671     void (*pipesave)(int);
672     void (*alrmsave)(int);
673
674     ctl->server.base_protocol = proto;
675
676     pass = 0;
677     err = 0;
678     init_transact(proto);
679
680     /* set up the server-nonresponse timeout */
681     alrmsave = signal(SIGALRM, timeout_handler);
682     mytimeout = ctl->server.timeout;
683
684     /* set up the broken-pipe timeout */
685     pipesave = signal(SIGPIPE, sigpipe_handler);
686
687     if ((js = setjmp(restart)))
688     {
689 #ifdef HAVE_SIGPROCMASK
690         /*
691          * Don't rely on setjmp() to restore the blocked-signal mask.
692          * It does this under BSD but is required not to under POSIX.
693          *
694          * If your Unix doesn't have sigprocmask, better hope it has
695          * BSD-like behavior.  Otherwise you may see fetchmail get
696          * permanently wedged after a second timeout on a bad read,
697          * because alarm signals were blocked after the first.
698          */
699         sigset_t        allsigs;
700
701         sigfillset(&allsigs);
702         sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
703 #endif /* HAVE_SIGPROCMASK */
704
705         if (js == THROW_SIGPIPE)
706         {
707             signal(SIGPIPE, SIG_IGN);
708             report(stdout,
709                    _("SIGPIPE thrown from an MDA or a stream socket error\n"));
710             err = PS_SOCKET;
711             goto cleanUp;
712         }
713         else if (js == THROW_TIMEOUT)
714         {
715             if (phase == OPEN_WAIT)
716                 report(stdout,
717                        _("timeout after %d seconds waiting to connect to server %s.\n"),
718                        ctl->server.timeout, ctl->server.pollname);
719             else if (phase == SERVER_WAIT)
720                 report(stdout,
721                        _("timeout after %d seconds waiting for server %s.\n"),
722                        ctl->server.timeout, ctl->server.pollname);
723             else if (phase == FORWARDING_WAIT)
724                 report(stdout,
725                        _("timeout after %d seconds waiting for %s.\n"),
726                        ctl->server.timeout,
727                        ctl->mda ? "MDA" : "SMTP");
728             else if (phase == LISTENER_WAIT)
729                 report(stdout,
730                        _("timeout after %d seconds waiting for listener to respond.\n"), ctl->server.timeout);
731             else
732                 report(stdout, 
733                        _("timeout after %d seconds.\n"), ctl->server.timeout);
734
735             /*
736              * If we've exceeded our threshold for consecutive timeouts, 
737              * try to notify the user, then mark the connection wedged.
738              * Don't do this if the connection can idle, though; idle
739              * timeouts just mean the frequency of mail is low.
740              */
741             if (timeoutcount > MAX_TIMEOUTS 
742                 && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
743             {
744                 stuff_warning(ctl,
745                               _("Subject: fetchmail sees repeated timeouts\r\n"));
746                 stuff_warning(ctl,
747                               _("Fetchmail saw more than %d timeouts while attempting to get mail from %s@%s.\r\n"), 
748                               MAX_TIMEOUTS,
749                               ctl->remotename,
750                               ctl->server.truename);
751                 stuff_warning(ctl, 
752     _("This could mean that your mailserver is stuck, or that your SMTP\r\n" \
753     "server is wedged, or that your mailbox file on the server has been\r\n" \
754     "corrupted by a server error.  You can run `fetchmail -v -v' to\r\n" \
755     "diagnose the problem.\r\n\r\n" \
756     "Fetchmail won't poll this mailbox again until you restart it.\r\n"));
757                 close_warning_by_mail(ctl, (struct msgblk *)NULL);
758                 ctl->wedged = TRUE;
759             }
760
761             err = PS_ERROR;
762         }
763
764         /* try to clean up all streams */
765         release_sink(ctl);
766         if (ctl->smtp_socket != -1)
767             SockClose(ctl->smtp_socket);
768         if (mailserver_socket != -1)
769             SockClose(mailserver_socket);
770     }
771     else
772     {
773         char buf[MSGBUFSIZE+1], *realhost;
774         int count, new, bytes, deletions = 0;
775         int *msgsizes = (int *)NULL;
776         int *msgcodes = (int *)NULL;
777 #if INET6_ENABLE
778         int fetches, dispatches, oldphase;
779 #else /* INET6_ENABLE */
780         int port, fetches, dispatches, oldphase;
781 #endif /* INET6_ENABLE */
782         struct idlist *idp;
783
784         /* execute pre-initialization command, if any */
785         if (ctl->preconnect && (err = system(ctl->preconnect)))
786         {
787             report(stderr, 
788                    _("pre-connection command failed with status %d\n"), err);
789             err = PS_SYNTAX;
790             goto closeUp;
791         }
792
793         /* open a socket to the mail server */
794         oldphase = phase;
795         phase = OPEN_WAIT;
796         set_timeout(mytimeout);
797 #if !INET6_ENABLE
798 #ifdef SSL_ENABLE
799         port = ctl->server.port ? ctl->server.port : ( ctl->use_ssl ? ctl->server.base_protocol->sslport : ctl->server.base_protocol->port );
800 #else
801         port = ctl->server.port ? ctl->server.port : ctl->server.base_protocol->port;
802 #endif
803 #endif /* !INET6_ENABLE */
804         realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
805
806         /* allow time for the port to be set up if we have a plugin */
807         if (ctl->server.plugin)
808             (void)sleep(1);
809 #if INET6_ENABLE
810         if ((mailserver_socket = SockOpen(realhost, 
811                              ctl->server.service ? ctl->server.service : ( ctl->use_ssl ? ctl->server.base_protocol->sslservice : ctl->server.base_protocol->service ),
812                              ctl->server.netsec, ctl->server.plugin)) == -1)
813 #else /* INET6_ENABLE */
814         if ((mailserver_socket = SockOpen(realhost, port, NULL, ctl->server.plugin)) == -1)
815 #endif /* INET6_ENABLE */
816         {
817             char        errbuf[BUFSIZ];
818 #if !INET6_ENABLE
819             int err_no = errno;
820 #ifdef HAVE_RES_SEARCH
821             if (err_no != 0 && h_errno != 0)
822                 report(stderr, _("internal inconsistency\n"));
823 #endif
824             /*
825              * Avoid generating a bogus error every poll cycle when we're
826              * in daemon mode but the connection to the outside world
827              * is down.
828              */
829             if (!((err_no == EHOSTUNREACH || err_no == ENETUNREACH) 
830                   && run.poll_interval))
831             {
832                 report_build(stderr, _("%s connection to %s failed"), 
833                              ctl->server.base_protocol->name, ctl->server.pollname);
834 #ifdef HAVE_RES_SEARCH
835                 if (h_errno != 0)
836                 {
837                     if (h_errno == HOST_NOT_FOUND)
838                         strcpy(errbuf, _("host is unknown."));
839 #ifndef __BEOS__
840                     else if (h_errno == NO_ADDRESS)
841                         strcpy(errbuf, _("name is valid but has no IP address."));
842 #endif
843                     else if (h_errno == NO_RECOVERY)
844                         strcpy(errbuf, _("unrecoverable name server error."));
845                     else if (h_errno == TRY_AGAIN)
846                         strcpy(errbuf, _("temporary name server error."));
847                     else
848 #ifdef HAVE_SNPRINTF
849                         snprintf(errbuf, sizeof(errbuf),
850 #else
851                         sprintf(errbuf,
852 #endif /* HAVE_SNPRINTF */
853                           _("unknown DNS error %d."), h_errno);
854                 }
855                 else
856 #endif /* HAVE_RES_SEARCH */
857                     strcpy(errbuf, strerror(err_no));
858                 report_complete(stderr, ": %s\n", errbuf);
859
860 #ifdef __UNUSED
861                 /* 
862                  * Don't use this.  It was an attempt to address Debian bug
863                  * #47143 (Notify user by mail when pop server nonexistent).
864                  * Trouble is, that doesn't work; you trip over the case 
865                  * where your SLIP or PPP link is down...
866                  */
867                 /* warn the system administrator */
868                 if (open_warning_by_mail(ctl, (struct msgblk *)NULL) == 0)
869                 {
870                     stuff_warning(ctl,
871                          _("Subject: Fetchmail unreachable-server warning.\r\n"
872                            "\r\n"
873                            "Fetchmail could not reach the mail server %s:")
874                                   ctl->server.pollname);
875                     stuff_warning(ctl, errbuf, ctl->server.pollname);
876                     close_warning_by_mail(ctl, (struct msgblk *)NULL);
877                 }
878 #endif
879             }
880 #endif /* INET6_ENABLE */
881             err = PS_SOCKET;
882             set_timeout(0);
883             phase = oldphase;
884             goto closeUp;
885         }
886         set_timeout(0);
887         phase = oldphase;
888
889 #ifdef SSL_ENABLE
890         /* perform initial SSL handshake on open connection */
891         /* Note:  We pass the realhost name over for certificate
892                 verification.  We may want to make this configurable */
893         if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslkey,ctl->sslcert,ctl->sslproto,ctl->sslcertck,
894             ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1) 
895         {
896             report(stderr, _("SSL connection failed.\n"));
897             goto closeUp;
898         }
899 #endif
900
901 #ifdef KERBEROS_V4
902         if (ctl->server.authenticate == A_KERBEROS_V4)
903         {
904             set_timeout(mytimeout);
905             err = kerberos_auth(mailserver_socket, ctl->server.truename,
906                                ctl->server.principal);
907             set_timeout(0);
908             if (err != 0)
909                 goto cleanUp;
910         }
911 #endif /* KERBEROS_V4 */
912
913 #ifdef KERBEROS_V5
914         if (ctl->server.authenticate == A_KERBEROS_V5)
915         {
916             set_timeout(mytimeout);
917             err = kerberos5_auth(mailserver_socket, ctl->server.truename);
918             set_timeout(0);
919             if (err != 0)
920                 goto cleanUp;
921         }
922 #endif /* KERBEROS_V5 */
923
924         /* accept greeting message from mail server */
925         err = (ctl->server.base_protocol->parse_response)(mailserver_socket, buf);
926         if (err != 0)
927             goto cleanUp;
928
929         /* try to get authorized to fetch mail */
930         stage = STAGE_GETAUTH;
931         if (ctl->server.base_protocol->getauth)
932         {
933             err = (ctl->server.base_protocol->getauth)(mailserver_socket, ctl, buf);
934
935             if (err != 0)
936             {
937                 if (err == PS_LOCKBUSY)
938                     report(stderr, _("Lock-busy error on %s@%s\n"),
939                           ctl->remotename,
940                           ctl->server.truename);
941                 else if (err == PS_SERVBUSY)
942                     report(stderr, _("Server busy error on %s@%s\n"),
943                           ctl->remotename,
944                           ctl->server.truename);
945                 else if (err == PS_AUTHFAIL)
946                 {
947                     report(stderr, _("Authorization failure on %s@%s%s\n"), 
948                            ctl->remotename,
949                            ctl->server.truename,
950                            (ctl->wehaveauthed ? _(" (previously authorized)") : "")
951                         );
952
953                     /*
954                      * If we're running in background, try to mail the
955                      * calling user a heads-up about the authentication 
956                      * failure once it looks like this isn't a fluke 
957                      * due to the server being temporarily inaccessible.
958                      * When we get third succesive failure, we notify the user
959                      * but only if we haven't already managed to get
960                      * authorization.  After that, once we get authorization
961                      * we let the user know service is restored.
962                      */
963                     if (run.poll_interval
964                         && ctl->wehavesentauthnote
965                         && ((ctl->wehaveauthed && ++ctl->authfailcount == 10)
966                             || ++ctl->authfailcount == 3)
967                         && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
968                     {
969                         ctl->wehavesentauthnote = 1;
970                         stuff_warning(ctl,
971                                       _("Subject: fetchmail authentication failed on %s@%s\r\n"),
972                             ctl->remotename, ctl->server.truename);
973                         stuff_warning(ctl,
974                                       _("Fetchmail could not get mail from %s@%s.\r\n"), 
975                                       ctl->remotename,
976                                       ctl->server.truename);
977                         if (ctl->wehaveauthed)
978                             stuff_warning(ctl, _("\
979 The attempt to get authorization failed.\r\n\
980 Since we have already succeeded in getting authorization for this\r\n\
981 connection, this is probably another failure mode (such as busy server)\r\n\
982 that fetchmail cannot distinguish because the server didn't send a useful\r\n\
983 error message.\r\n\
984 \r\n\
985 However, if you HAVE changed you account details since starting the\r\n\
986 fetchmail daemon, you need to stop the daemon, change your configuration\r\n\
987 of fetchmail, and then restart the daemon.\r\n\
988 \r\n\
989 The fetchmail daemon will continue running and attempt to connect\r\n\
990 at each cycle.  No future notifications will be sent until service\r\n\
991 is restored."));
992                         else
993                             stuff_warning(ctl, _("\
994 The attempt to get authorization failed.\r\n\
995 This probably means your password is invalid, but some servers have\r\n\
996 other failure modes that fetchmail cannot distinguish from this\r\n\
997 because they don't send useful error messages on login failure.\r\n\
998 \r\n\
999 The fetchmail daemon will continue running and attempt to connect\r\n\
1000 at each cycle.  No future notifications will be sent until service\r\n\
1001 is restored."));
1002                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1003                     }
1004                 }
1005                 else
1006                     report(stderr, _("Unknown login or authentication error on %s@%s\n"),
1007                            ctl->remotename,
1008                            ctl->server.truename);
1009                     
1010                 goto cleanUp;
1011             }
1012             else
1013             {
1014                 /*
1015                  * This connection has given us authorization at least once.
1016                  *
1017                  * There are dodgy server (clubinternet.fr for example) that
1018                  * give spurious authorization failures on patently good
1019                  * account/password details, then 5 minutes later let you in!
1020                  *
1021                  * This is meant to build in some tolerance of such nasty bits
1022                  * of work.
1023                  */
1024                 ctl->wehaveauthed = 1;
1025                 /*if (ctl->authfailcount >= 3)*/
1026                 if (ctl->wehavesentauthnote)
1027                 {
1028                     ctl->wehavesentauthnote = 0;
1029                     report(stderr,
1030                            _("Authorization OK on %s@%s\n"),
1031                            ctl->remotename,
1032                            ctl->server.truename);
1033                     if (!open_warning_by_mail(ctl, (struct msgblk *)NULL))
1034                     {
1035                         stuff_warning(ctl,
1036                               _("Subject: fetchmail authentication OK on %s@%s\r\n"),
1037                                       ctl->remotename, ctl->server.truename);
1038                         stuff_warning(ctl,
1039                               _("Fetchmail was able to log into %s@%s.\r\n"), 
1040                                       ctl->remotename,
1041                                       ctl->server.truename);
1042                         stuff_warning(ctl, 
1043                                       _("Service has been restored.\r\n"));
1044                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1045                     
1046                     }
1047                 }
1048                 /*
1049                  * Reporting only after the first three
1050                  * consecutive failures, or ten consecutive
1051                  * failures after we have managed to get
1052                  * authorization.
1053                  */
1054                 ctl->authfailcount = 0;
1055             }
1056         }
1057
1058         ctl->errcount = fetches = 0;
1059
1060         /* now iterate over each folder selected */
1061         for (idp = ctl->mailboxes; idp; idp = idp->next)
1062         {
1063             pass = 0;
1064             do {
1065                 dispatches = 0;
1066                 ++pass;
1067
1068                 /* reset timeout, in case we did an IDLE */
1069                 mytimeout = ctl->server.timeout;
1070
1071                 if (outlevel >= O_DEBUG)
1072                 {
1073                     if (idp->id)
1074                         report(stdout, _("selecting or re-polling folder %s\n"), idp->id);
1075                     else
1076                         report(stdout, _("selecting or re-polling default folder\n"));
1077                 }
1078
1079                 /* compute # of messages and number of new messages waiting */
1080                 stage = STAGE_GETRANGE;
1081                 err = (ctl->server.base_protocol->getrange)(mailserver_socket, ctl, idp->id, &count, &new, &bytes);
1082                 if (err != 0)
1083                     goto cleanUp;
1084
1085                 /* show user how many messages we downloaded */
1086                 if (idp->id)
1087 #ifdef HAVE_SNPRINTF
1088                     (void) snprintf(buf, sizeof(buf),
1089 #else
1090                     (void) sprintf(buf,
1091 #endif /* HAVE_SNPRINTF */
1092                                    _("%s at %s (folder %s)"),
1093                                    ctl->remotename, ctl->server.truename, idp->id);
1094                 else
1095 #ifdef HAVE_SNPRINTF
1096                     (void) snprintf(buf, sizeof(buf),
1097 #else
1098                     (void) sprintf(buf,
1099 #endif /* HAVE_SNPRINTF */
1100                                _("%s at %s"),
1101                                    ctl->remotename, ctl->server.truename);
1102                 if (outlevel > O_SILENT)
1103                 {
1104                     if (count == -1)            /* only used for ETRN */
1105                         report(stdout, _("Polling %s\n"), ctl->server.truename);
1106                     else if (count != 0)
1107                     {
1108                         if (new != -1 && (count - new) > 0)
1109                             report_build(stdout, _("%d %s (%d seen) for %s"),
1110                                   count, count > 1 ? _("messages") :
1111                                                      _("message"),
1112                                   count-new, buf);
1113                         else
1114                             report_build(stdout, _("%d %s for %s"), 
1115                                   count, count > 1 ? _("messages") :
1116                                                      _("message"), buf);
1117                         if (bytes == -1)
1118                             report_complete(stdout, ".\n");
1119                         else
1120                             report_complete(stdout, _(" (%d octets).\n"), bytes);
1121                     }
1122                     else
1123                     {
1124                         /* these are pointless in normal daemon mode */
1125                         if (pass == 1 && (run.poll_interval == 0 || outlevel >= O_VERBOSE))
1126                             report(stdout, _("No mail for %s\n"), buf); 
1127                     }
1128                 }
1129
1130                 /* very important, this is where we leave the do loop */ 
1131                 if (count == 0)
1132                     break;
1133
1134                 if (check_only)
1135                 {
1136                     if (new == -1 || ctl->fetchall)
1137                         new = count;
1138                     fetches = new;      /* set error status correctly */
1139                     /*
1140                      * There used to be a `goto noerror' here, but this
1141                      * prevneted checking of multiple folders.  This
1142                      * comment is a reminder in case I introduced some
1143                      * subtle bug by removing it...
1144                      */
1145                 }
1146                 else if (count > 0)
1147                 {    
1148                     flag        force_retrieval;
1149                     int         i, num;
1150
1151                     /*
1152                      * What forces this code is that in POP2 and
1153                      * IMAP2bis you can't fetch a message without
1154                      * having it marked `seen'.  In POP3 and IMAP4, on the
1155                      * other hand, you can (peek_capable is set by 
1156                      * each driver module to convey this; it's not a
1157                      * method constant because of the difference between
1158                      * IMAP2bis and IMAP4, and because POP3 doesn't  peek
1159                      * if fetchall is on).
1160                      *
1161                      * The result of being unable to peek is that if there's
1162                      * any kind of transient error (DNS lookup failure, or
1163                      * sendmail refusing delivery due to process-table limits)
1164                      * the message will be marked "seen" on the server without
1165                      * having been delivered.  This is not a big problem if
1166                      * fetchmail is running in foreground, because the user
1167                      * will see a "skipped" message when it next runs and get
1168                      * clued in.
1169                      *
1170                      * But in daemon mode this leads to the message
1171                      * being silently ignored forever.  This is not
1172                      * acceptable.
1173                      *
1174                      * We compensate for this by checking the error
1175                      * count from the previous pass and forcing all
1176                      * messages to be considered new if it's nonzero.
1177                      */
1178                     force_retrieval = !peek_capable && (ctl->errcount > 0);
1179
1180                     /* OK, we're going to gather size info next */
1181                     xalloca(msgsizes, int *, sizeof(int) * count);
1182                     xalloca(msgcodes, int *, sizeof(int) * count);
1183                     for (i = 0; i < count; i++)
1184                         msgcodes[i] = MSGLEN_UNKNOWN;
1185
1186                     /* 
1187                      * We need the size of each message before it's
1188                      * loaded in order to pass it to the ESMTP SIZE
1189                      * option.  If the protocol has a getsizes method,
1190                      * we presume this means it doesn't get reliable
1191                      * sizes from message fetch responses.
1192                      */
1193                     if (proto->getsizes)
1194                     {
1195                         stage = STAGE_GETSIZES;
1196                         err = (proto->getsizes)(mailserver_socket, count, msgsizes);
1197                         if (err != 0)
1198                             goto cleanUp;
1199
1200                         if (bytes == -1)
1201                         {
1202                             bytes = 0;
1203                             for (i = 0; i < count; i++)
1204                                 bytes += msgsizes[i];
1205                         }
1206                     }
1207
1208                     /* mark some messages not to be retrieved */
1209                     for (num = 1; num <= count; num++)
1210                     {
1211                         if (NUM_NONZERO(ctl->limit) && (msgsizes[num-1] > ctl->limit))
1212                             msgcodes[num-1] = MSGLEN_TOOLARGE;
1213                         else if (ctl->fetchall || force_retrieval)
1214                             continue;
1215                         else if (ctl->server.base_protocol->is_old && (ctl->server.base_protocol->is_old)(mailserver_socket,ctl,num))
1216                             msgcodes[num-1] = MSGLEN_OLD;
1217                     }
1218
1219                     /* read, forward, and delete messages */
1220                     stage = STAGE_FETCH;
1221
1222                     /* fetch in lockstep mode */
1223                     err = fetch_messages(mailserver_socket, ctl, 
1224                                          count, msgsizes, msgcodes,
1225                                          maxfetch,
1226                                          &fetches, &dispatches, &deletions);
1227                     if (err)
1228                         goto cleanUp;
1229
1230                     if (!check_only && ctl->skipped
1231                         && run.poll_interval > 0 && !nodetach)
1232                     {
1233                         clean_skipped_list(&ctl->skipped);
1234                         send_size_warnings(ctl);
1235                     }
1236                 }
1237             } while
1238                   /*
1239                    * Only re-poll if we either had some actual forwards and 
1240                    * either allowed deletions and had no errors.
1241                    * Otherwise it is far too easy to get into infinite loops.
1242                    */
1243                   (dispatches && ctl->server.base_protocol->retry && !ctl->keep && !ctl->errcount);
1244         }
1245
1246     /* no_error: */
1247         /* ordinary termination with no errors -- officially log out */
1248         err = (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
1249         /*
1250          * Hmmmm...arguably this would be incorrect if we had fetches but
1251          * no dispatches (due to oversized messages, etc.)
1252          */
1253         if (err == 0)
1254             err = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
1255         SockClose(mailserver_socket);
1256         goto closeUp;
1257
1258     cleanUp:
1259         /* we only get here on error */
1260         if (err != 0 && err != PS_SOCKET)
1261         {
1262             stage = STAGE_LOGOUT;
1263             (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
1264         }
1265         SockClose(mailserver_socket);
1266     }
1267
1268     msg = (const char *)NULL;   /* sacrifice to -Wall */
1269     switch (err)
1270     {
1271     case PS_SOCKET:
1272         msg = _("socket");
1273         break;
1274     case PS_SYNTAX:
1275         msg = _("missing or bad RFC822 header");
1276         break;
1277     case PS_IOERR:
1278         msg = _("MDA");
1279         break;
1280     case PS_ERROR:
1281         msg = _("client/server synchronization");
1282         break;
1283     case PS_PROTOCOL:
1284         msg = _("client/server protocol");
1285         break;
1286     case PS_LOCKBUSY:
1287         msg = _("lock busy on server");
1288         break;
1289     case PS_SMTP:
1290         msg = _("SMTP transaction");
1291         break;
1292     case PS_DNS:
1293         msg = _("DNS lookup");
1294         break;
1295     case PS_UNDEFINED:
1296         report(stderr, _("undefined error\n"));
1297         break;
1298     }
1299     /* no report on PS_MAXFETCH or PS_UNDEFINED or PS_AUTHFAIL */
1300     if (err==PS_SOCKET || err==PS_SYNTAX
1301                 || err==PS_IOERR || err==PS_ERROR || err==PS_PROTOCOL 
1302                 || err==PS_LOCKBUSY || err==PS_SMTP || err==PS_DNS)
1303     {
1304         char    *stem;
1305
1306         if (phase == FORWARDING_WAIT || phase == LISTENER_WAIT)
1307             stem = _("%s error while delivering to SMTP host %s\n");
1308         else
1309             stem = _("%s error while fetching from %s\n");
1310         report(stderr, stem, msg, ctl->server.pollname);
1311     }
1312
1313 closeUp:
1314     /* execute wrapup command, if any */
1315     if (ctl->postconnect && (err = system(ctl->postconnect)))
1316     {
1317         report(stderr, _("post-connection command failed with status %d\n"), err);
1318         if (err == PS_SUCCESS)
1319             err = PS_SYNTAX;
1320     }
1321
1322     signal(SIGALRM, alrmsave);
1323     signal(SIGPIPE, pipesave);
1324     return(err);
1325 }
1326
1327 int do_protocol(ctl, proto)
1328 /* retrieve messages from server using given protocol method table */
1329 struct query *ctl;              /* parsed options with merged-in defaults */
1330 const struct method *proto;     /* protocol method table */
1331 {
1332     int err;
1333
1334 #ifndef KERBEROS_V4
1335     if (ctl->server.authenticate == A_KERBEROS_V4)
1336     {
1337         report(stderr, _("Kerberos V4 support not linked.\n"));
1338         return(PS_ERROR);
1339     }
1340 #endif /* KERBEROS_V4 */
1341
1342 #ifndef KERBEROS_V5
1343     if (ctl->server.authenticate == A_KERBEROS_V5)
1344     {
1345         report(stderr, _("Kerberos V5 support not linked.\n"));
1346         return(PS_ERROR);
1347     }
1348 #endif /* KERBEROS_V5 */
1349
1350     /* lacking methods, there are some options that may fail */
1351     if (!proto->is_old)
1352     {
1353         /* check for unsupported options */
1354         if (ctl->flush) {
1355             report(stderr,
1356                     _("Option --flush is not supported with %s\n"),
1357                     proto->name);
1358             return(PS_SYNTAX);
1359         }
1360         else if (ctl->fetchall) {
1361             report(stderr,
1362                     _("Option --all is not supported with %s\n"),
1363                     proto->name);
1364             return(PS_SYNTAX);
1365         }
1366     }
1367     if (!proto->getsizes && NUM_SPECIFIED(ctl->limit))
1368     {
1369         report(stderr,
1370                 _("Option --limit is not supported with %s\n"),
1371                 proto->name);
1372         return(PS_SYNTAX);
1373     }
1374
1375     /*
1376      * If no expunge limit or we do expunges within the driver,
1377      * then just do one session, passing in any fetchlimit.
1378      */
1379     if (proto->retry || !NUM_SPECIFIED(ctl->expunge))
1380         return(do_session(ctl, proto, NUM_VALUE_OUT(ctl->fetchlimit)));
1381     /*
1382      * There's an expunge limit, and it isn't handled in the driver itself.
1383      * OK; do multiple sessions, each fetching a limited # of messages.
1384      * Stop if the total count of retrieved messages exceeds ctl->fetchlimit
1385      * (if it was nonzero).
1386      */
1387     else
1388     {
1389         int totalcount = 0; 
1390         int lockouts   = 0;
1391         int expunge    = NUM_VALUE_OUT(ctl->expunge);
1392         int fetchlimit = NUM_VALUE_OUT(ctl->fetchlimit);
1393
1394         do {
1395             if (fetchlimit > 0 && (expunge == 0 || expunge > fetchlimit - totalcount))
1396                 expunge = fetchlimit - totalcount;
1397             err = do_session(ctl, proto, expunge);
1398             totalcount += expunge;
1399             if (NUM_SPECIFIED(ctl->fetchlimit) && totalcount >= fetchlimit)
1400                 break;
1401             if (err != PS_LOCKBUSY)
1402                 lockouts = 0;
1403             else if (lockouts >= MAX_LOCKOUTS)
1404                 break;
1405             else /* err == PS_LOCKBUSY */
1406             {
1407                 /*
1408                  * Allow time for the server lock to release.  if we
1409                  * don't do this, we'll often hit a locked-mailbox
1410                  * condition and fail.
1411                  */
1412                 lockouts++;
1413                 sleep(3);
1414             }
1415         } while
1416             (err == PS_MAXFETCH || err == PS_LOCKBUSY);
1417
1418         return(err);
1419     }
1420 }
1421
1422
1423 /* driver.c ends here */