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