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