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