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