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