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