]> Pileus Git - ~andy/fetchmail/blob - driver.c
1e27943d2b397f77fce7af386544d780b28d0ff1
[~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                 /* XXX FIXME: the gettext stuff needs to list "octets" or
605                  * "header octets" as a unit, and also provide for
606                  * proper plural form */
607                 if (len > 0)
608                     report_build(stdout, GT_(" (%d %soctets)"),
609                                  len, wholesize ? "" : GT_("header "));
610                 if (outlevel >= O_VERBOSE)
611                     report_complete(stdout, "\n");
612                 else
613                     report_complete(stdout, " ");
614             }
615
616             /* 
617              * Read the message headers and ship them to the
618              * output sink.  
619              */
620             err = readheaders(mailserver_socket, len, msgsize,
621                              ctl, num,
622                              /* pass the suppress_readbody flag only if the underlying
623                               * protocol does not fetch the body separately */
624                              separatefetchbody ? 0 : &suppress_readbody);
625             if (err == PS_RETAINED)
626                 suppress_forward = suppress_delete = retained = TRUE;
627             else if (err == PS_TRANSIENT)
628                 suppress_delete = suppress_forward = TRUE;
629             else if (err == PS_REFUSED)
630                 suppress_forward = TRUE;
631             else if (err == PS_TRUNCATED)
632                 suppress_readbody = TRUE;
633             else if (err)
634                 return(err);
635
636             /* tell server we got it OK and resynchronize */
637             if (separatefetchbody && ctl->server.base_protocol->trail)
638             {
639                 if (outlevel >= O_VERBOSE && !isafile(1))
640                 {
641                     fputc('\n', stdout);
642                     fflush(stdout);
643                 }
644
645                 if ((err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num)))
646                     return(err);
647             }
648
649             /* do not read the body which is not being forwarded only if
650              * the underlying protocol allows the body to be fetched
651              * separately */
652             if (separatefetchbody && suppress_forward)
653                 suppress_readbody = TRUE;
654
655             /* 
656              * If we're using IMAP4 or something else that
657              * can fetch headers separately from bodies,
658              * it's time to request the body now.  This
659              * fetch may be skipped if we got an anti-spam
660              * or other PS_REFUSED error response during
661              * readheaders.
662              */
663             if (!suppress_readbody)
664             {
665                 if (separatefetchbody)
666                 {
667                     len = -1;
668                     if ((err=(ctl->server.base_protocol->fetch_body)(mailserver_socket,ctl,num,&len)))
669                         return(err);
670                     /*
671                      * Work around a bug in Novell's
672                      * broken GroupWise IMAP server;
673                      * its body FETCH response is missing
674                      * the required length for the data
675                      * string.  This violates RFC2060.
676                      */
677                     if (len == -1)
678                         len = msgsize - msgblk.msglen;
679                     if (outlevel > O_SILENT && !wholesize)
680                         report_complete(stdout,
681                                         GT_(" (%d body octets) "), len);
682                 }
683
684                 /* process the body now */
685                 err = readbody(mailserver_socket,
686                               ctl,
687                               !suppress_forward,
688                               len);
689                 if (err == PS_TRANSIENT)
690                     suppress_delete = suppress_forward = TRUE;
691                 else if (err)
692                     return(err);
693
694                 /* tell server we got it OK and resynchronize */
695                 if (ctl->server.base_protocol->trail)
696                 {
697                     if (outlevel >= O_VERBOSE && !isafile(1))
698                     {
699                         fputc('\n', stdout);
700                         fflush(stdout);
701                     }
702
703                     err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num);
704                     if (err != 0)
705                         return(err);
706                 }
707             }
708
709             /* count # messages forwarded on this pass */
710             if (!suppress_forward)
711                 (*dispatches)++;
712
713             /*
714              * Check to see if the numbers matched?
715              *
716              * Yes, some servers foo this up horribly.
717              * All IMAP servers seem to get it right, and
718              * so does Eudora QPOP at least in 2.xx
719              * versions.
720              *
721              * Microsoft Exchange gets it completely
722              * wrong, reporting compressed rather than
723              * actual sizes (so the actual length of
724              * message is longer than the reported size).
725              * Another fine example of Microsoft brain death!
726              *
727              * Some older POP servers, like the old UCB
728              * POP server and the pre-QPOP QUALCOMM
729              * versions, report a longer size in the LIST
730              * response than actually gets shipped up.
731              * It's unclear what is going on here, as the
732              * QUALCOMM server (at least) seems to be
733              * reporting the on-disk size correctly.
734              */
735             if (msgblk.msglen != msgsize)
736             {
737                 if (outlevel >= O_DEBUG)
738                     report(stdout,
739                            GT_("message %s@%s:%d was not the expected length (%d actual != %d expected)\n"),
740                            ctl->remotename, ctl->server.truename, num,
741                            msgblk.msglen, msgsize);
742             }
743
744             /* end-of-message processing starts here */
745             if (!close_sink(ctl, &msgblk, !suppress_forward))
746             {
747                 ctl->errcount++;
748                 suppress_delete = TRUE;
749             }
750             if (!retained)
751                 (*fetches)++;
752         }
753
754 flagthemail:
755         /*
756          * At this point in flow of control, either
757          * we've bombed on a protocol error or had
758          * delivery refused by the SMTP server
759          * (unlikely -- I've never seen it) or we've
760          * seen `accepted for delivery' and the
761          * message is shipped.  It's safe to mark the
762          * message seen and delete it on the server
763          * now.
764          */
765
766         /* maybe we delete this message now? */
767         if (retained)
768         {
769             if (outlevel > O_SILENT) 
770                 report(stdout, GT_(" retained\n"));
771         }
772         else if (ctl->server.base_protocol->delete
773                  && !suppress_delete
774                  && ((msgcode >= 0 && !ctl->keep)
775                      || (msgcode == MSGLEN_OLD && ctl->flush)))
776         {
777             (*deletions)++;
778             if (outlevel > O_SILENT) 
779                 report_complete(stdout, GT_(" flushed\n"));
780             err = (ctl->server.base_protocol->delete)(mailserver_socket, ctl, num);
781             if (err != 0)
782                 return(err);
783         }
784         else
785         {
786             if (   (outlevel >= O_VERBOSE) ||
787                         /* To avoid flooding the syslog when using --keep,
788                          * report "Skipped message" only when:
789                          *  1) --verbose is on, or
790                          *  2) fetchmail does not use syslog, or
791                          *  3) the message was skipped for some other
792                          *     reason than just being old.
793                          */
794                    (outlevel > O_SILENT && (!run.use_syslog || msgcode != MSGLEN_OLD))
795                )
796             report_complete(stdout, GT_(" not flushed\n"));
797
798             /* maybe we mark this message as seen now? */
799             if (ctl->server.base_protocol->mark_seen
800                 && !suppress_delete
801                 && (msgcode >= 0 && ctl->keep))
802             {
803                 err = (ctl->server.base_protocol->mark_seen)(mailserver_socket, ctl, num);
804                 if (err != 0)
805                     return(err);
806             }
807         }
808
809         /* perhaps this as many as we're ready to handle */
810         if (maxfetch && maxfetch <= *fetches && num < count)
811         {
812             report(stdout, GT_("fetchlimit %d reached; %d messages left on server %s account %s\n"),
813                    maxfetch, count - *fetches, ctl->server.truename, ctl->remotename);
814             return(PS_MAXFETCH);
815         }
816     }
817
818     return(PS_SUCCESS);
819 }
820
821 /* retrieve messages from server using given protocol method table */
822 static int do_session(
823         /* parsed options with merged-in defaults */
824         struct query *ctl,
825         /* protocol method table */
826         const struct method *proto,
827         /* maximum number of messages to fetch */
828         const int maxfetch)
829 {
830     static int *msgsizes;
831     volatile int err, mailserver_socket = -1;   /* pacifies -Wall */
832     int deletions = 0, js;
833     const char *msg;
834     SIGHANDLERTYPE pipesave;
835     SIGHANDLERTYPE alrmsave;
836
837     ctl->server.base_protocol = proto;
838
839     msgsizes = NULL;
840     pass = 0;
841     err = 0;
842     init_transact(proto);
843
844     /* set up the server-nonresponse timeout */
845     alrmsave = set_signal_handler(SIGALRM, timeout_handler);
846     mytimeout = ctl->server.timeout;
847
848     /* set up the broken-pipe timeout */
849     pipesave = set_signal_handler(SIGPIPE, sigpipe_handler);
850
851     if ((js = setjmp(restart)))
852     {
853 #ifdef HAVE_SIGPROCMASK
854         /*
855          * Don't rely on setjmp() to restore the blocked-signal mask.
856          * It does this under BSD but is required not to under POSIX.
857          *
858          * If your Unix doesn't have sigprocmask, better hope it has
859          * BSD-like behavior.  Otherwise you may see fetchmail get
860          * permanently wedged after a second timeout on a bad read,
861          * because alarm signals were blocked after the first.
862          */
863         sigset_t        allsigs;
864
865         sigfillset(&allsigs);
866         sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
867 #endif /* HAVE_SIGPROCMASK */
868         
869         if (js == THROW_SIGPIPE)
870         {
871             set_signal_handler(SIGPIPE, SIG_IGN);
872             report(stdout,
873                    GT_("SIGPIPE thrown from an MDA or a stream socket error\n"));
874             wait(0);
875         }
876         else if (js == THROW_TIMEOUT)
877         {
878             if (phase == OPEN_WAIT)
879                 report(stdout,
880                        GT_("timeout after %d seconds waiting to connect to server %s.\n"),
881                        ctl->server.timeout, ctl->server.pollname);
882             else if (phase == SERVER_WAIT)
883                 report(stdout,
884                        GT_("timeout after %d seconds waiting for server %s.\n"),
885                        ctl->server.timeout, ctl->server.pollname);
886             else if (phase == FORWARDING_WAIT)
887                 report(stdout,
888                        GT_("timeout after %d seconds waiting for %s.\n"),
889                        ctl->server.timeout,
890                        ctl->mda ? "MDA" : "SMTP");
891             else if (phase == LISTENER_WAIT)
892                 report(stdout,
893                        GT_("timeout after %d seconds waiting for listener to respond.\n"), ctl->server.timeout);
894             else
895                 report(stdout, 
896                        GT_("timeout after %d seconds.\n"), ctl->server.timeout);
897
898             /*
899              * If we've exceeded our threshold for consecutive timeouts, 
900              * try to notify the user, then mark the connection wedged.
901              * Don't do this if the connection can idle, though; idle
902              * timeouts just mean the frequency of mail is low.
903              */
904             if (timeoutcount > MAX_TIMEOUTS 
905                 && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
906             {
907                 stuff_warning(ctl,
908                               GT_("Subject: fetchmail sees repeated timeouts\n"));
909                 stuff_warning(ctl,
910                               GT_("Fetchmail saw more than %d timeouts while attempting to get mail from %s@%s.\n"), 
911                               MAX_TIMEOUTS,
912                               ctl->remotename,
913                               ctl->server.truename);
914                 stuff_warning(ctl, 
915     GT_("This could mean that your mailserver is stuck, or that your SMTP\n" \
916     "server is wedged, or that your mailbox file on the server has been\n" \
917     "corrupted by a server error.  You can run `fetchmail -v -v' to\n" \
918     "diagnose the problem.\n\n" \
919     "Fetchmail won't poll this mailbox again until you restart it.\n"));
920                 close_warning_by_mail(ctl, (struct msgblk *)NULL);
921                 ctl->wedged = TRUE;
922             }
923         }
924
925         err = PS_SOCKET;
926         goto cleanUp;
927     }
928     else
929     {
930         char buf[MSGBUFSIZE+1], *realhost;
931         int count, new, bytes;
932 #ifdef INET6_ENABLE
933         int fetches, dispatches, oldphase;
934 #else /* INET6_ENABLE */
935         int port, fetches, dispatches, oldphase;
936 #endif /* INET6_ENABLE */
937         struct idlist *idp;
938
939         /* execute pre-initialization command, if any */
940         if (ctl->preconnect && (err = system(ctl->preconnect)))
941         {
942             report(stderr, 
943                    GT_("pre-connection command failed with status %d\n"), err);
944             err = PS_SYNTAX;
945             goto closeUp;
946         }
947
948         /* open a socket to the mail server */
949         oldphase = phase;
950         phase = OPEN_WAIT;
951         set_timeout(mytimeout);
952 #ifndef INET6_ENABLE
953 #ifdef SSL_ENABLE
954         port = ctl->server.port ? ctl->server.port : ( ctl->use_ssl ? ctl->server.base_protocol->sslport : ctl->server.base_protocol->port );
955 #else
956         port = ctl->server.port ? ctl->server.port : ctl->server.base_protocol->port;
957 #endif
958 #endif /* !INET6_ENABLE */
959
960 #ifdef HAVE_PKG_hesiod
961         /* If either the pollname or vianame are "hesiod" we want to
962            lookup the user's hesiod pobox host */
963         if (!strcasecmp(ctl->server.queryname, "hesiod")) {
964             struct hes_postoffice *hes_p;
965             hes_p = hes_getmailhost(ctl->remotename);
966             if (hes_p != NULL && strcmp(hes_p->po_type, "POP") == 0) {
967                  free(ctl->server.queryname);
968                  ctl->server.queryname = xstrdup(hes_p->po_host);
969                  if (ctl->server.via)
970                      free(ctl->server.via);
971                  ctl->server.via = xstrdup(hes_p->po_host);
972             } else {
973                  report(stderr,
974                         GT_("couldn't find HESIOD pobox for %s\n"),
975                         ctl->remotename);
976             }
977         }
978 #endif /* HESIOD */
979
980 #ifdef HAVE_GETHOSTBYNAME
981         /*
982          * Canonicalize the server truename for later use.  This also
983          * functions as a probe for whether the mailserver is accessible.
984          * We try it on each poll cycle until we get a result.  This way,
985          * fetchmail won't fail if started up when the network is inaccessible.
986          */
987         if (ctl->server.dns && !ctl->server.trueaddr)
988         {
989             if (ctl->server.lead_server)
990             {
991                 char    *leadname = ctl->server.lead_server->truename;
992
993                 /* prevent core dump from ill-formed or duplicate entry */
994                 if (!leadname)
995                 {
996                     report(stderr, GT_("Lead server has no name.\n"));
997                     err = PS_DNS;
998                     set_timeout(0);
999                     phase = oldphase;
1000                     goto closeUp;
1001                 }
1002
1003                 ctl->server.truename = xstrdup(leadname);
1004             }
1005             else
1006             {
1007                 struct hostent  *namerec;
1008                     
1009                 /* 
1010                  * Get the host's IP, so we can report it like this:
1011                  *
1012                  * Received: from hostname [10.0.0.1]
1013                  */
1014                 errno = 0;
1015                 namerec = gethostbyname(ctl->server.queryname);
1016                 if (namerec == (struct hostent *)NULL)
1017                 {
1018                     report(stderr,
1019                            GT_("couldn't find canonical DNS name of %s (%s)\n"),
1020                            ctl->server.pollname, ctl->server.queryname);
1021                     err = PS_DNS;
1022                     set_timeout(0);
1023                     phase = oldphase;
1024                     goto closeUp;
1025                 }
1026                 else 
1027                 {
1028                     ctl->server.truename=xstrdup((char *)namerec->h_name);
1029                     ctl->server.trueaddr=xmalloc(namerec->h_length);
1030                     memcpy(ctl->server.trueaddr, 
1031                            namerec->h_addr_list[0],
1032                            namerec->h_length);
1033                 }
1034             }
1035         }
1036 #endif /* HAVE_GETHOSTBYNAME */
1037
1038         realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
1039
1040         /* allow time for the port to be set up if we have a plugin */
1041         if (ctl->server.plugin)
1042             (void)sleep(1);
1043 #ifdef INET6_ENABLE
1044         if ((mailserver_socket = SockOpen(realhost, 
1045                              ctl->server.service ? ctl->server.service : ( ctl->use_ssl ? ctl->server.base_protocol->sslservice : ctl->server.base_protocol->service ),
1046                              ctl->server.netsec, ctl->server.plugin)) == -1)
1047 #else /* INET6_ENABLE */
1048         if ((mailserver_socket = SockOpen(realhost, port, NULL, ctl->server.plugin)) == -1)
1049 #endif /* INET6_ENABLE */
1050         {
1051             char        errbuf[BUFSIZ];
1052 #ifndef INET6_ENABLE
1053             int err_no = errno;
1054 #ifdef HAVE_RES_SEARCH
1055             if (err_no != 0 && h_errno != 0)
1056                 report(stderr, GT_("internal inconsistency\n"));
1057 #endif
1058             /*
1059              * Avoid generating a bogus error every poll cycle when we're
1060              * in daemon mode but the connection to the outside world
1061              * is down.
1062              */
1063             if (!((err_no == EHOSTUNREACH || err_no == ENETUNREACH) 
1064                   && run.poll_interval))
1065             {
1066                 report_build(stderr, GT_("%s connection to %s failed"), 
1067                              ctl->server.base_protocol->name, ctl->server.pollname);
1068 #ifdef HAVE_RES_SEARCH
1069                 if (h_errno != 0)
1070                 {
1071                     if (h_errno == HOST_NOT_FOUND)
1072                         strcpy(errbuf, GT_("host is unknown."));
1073 #ifndef __BEOS__
1074                     else if (h_errno == NO_ADDRESS)
1075                         strcpy(errbuf, GT_("name is valid but has no IP address."));
1076 #endif
1077                     else if (h_errno == NO_RECOVERY)
1078                         strcpy(errbuf, GT_("unrecoverable name server error."));
1079                     else if (h_errno == TRY_AGAIN)
1080                         strcpy(errbuf, GT_("temporary name server error."));
1081                     else
1082 #ifdef HAVE_SNPRINTF
1083                         snprintf(errbuf, sizeof(errbuf),
1084 #else
1085                         sprintf(errbuf,
1086 #endif /* HAVE_SNPRINTF */
1087                           GT_("unknown DNS error %d."), h_errno);
1088                 }
1089                 else
1090 #endif /* HAVE_RES_SEARCH */
1091                     strcpy(errbuf, strerror(err_no));
1092                 report_complete(stderr, ": %s\n", errbuf);
1093
1094 #ifdef __UNUSED
1095                 /* 
1096                  * Don't use this.  It was an attempt to address Debian bug
1097                  * #47143 (Notify user by mail when pop server nonexistent).
1098                  * Trouble is, that doesn't work; you trip over the case 
1099                  * where your SLIP or PPP link is down...
1100                  */
1101                 /* warn the system administrator */
1102                 if (open_warning_by_mail(ctl, (struct msgblk *)NULL) == 0)
1103                 {
1104                     stuff_warning(ctl,
1105                          GT_("Subject: Fetchmail unreachable-server warning.\n"
1106                            "\n"
1107                            "Fetchmail could not reach the mail server %s:")
1108                                   ctl->server.pollname);
1109                     stuff_warning(ctl, errbuf, ctl->server.pollname);
1110                     close_warning_by_mail(ctl, (struct msgblk *)NULL);
1111                 }
1112 #endif
1113             }
1114 #endif /* INET6_ENABLE */
1115             err = PS_SOCKET;
1116             set_timeout(0);
1117             phase = oldphase;
1118             goto closeUp;
1119         }
1120
1121 #ifdef SSL_ENABLE
1122         /* Save the socket opened. Useful if Fetchmail hangs on SSLOpen 
1123          * because the socket can be closed.
1124          */
1125         mailserver_socket_temp = mailserver_socket;
1126         set_timeout(mytimeout);
1127
1128         /* perform initial SSL handshake on open connection */
1129         /* Note:  We pass the realhost name over for certificate
1130                 verification.  We may want to make this configurable */
1131         if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslcert,ctl->sslkey,ctl->sslproto,ctl->sslcertck,
1132             ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1) 
1133         {
1134             report(stderr, GT_("SSL connection failed.\n"));
1135             err = PS_AUTHFAIL;
1136             goto closeUp;
1137         }
1138         
1139         /* Fetchmail didn't hang on SSLOpen, 
1140          * then no need to set mailserver_socket_temp 
1141          */
1142         mailserver_socket_temp = -1;
1143 #endif
1144         
1145         /* A timeout is still defined before SSLOpen, 
1146          * then Fetchmail hanging on SSLOpen is handled.
1147          */
1148         set_timeout(0);
1149         phase = oldphase;
1150 #ifdef KERBEROS_V4
1151         if (ctl->server.authenticate == A_KERBEROS_V4 && (strcasecmp(proto->name,"IMAP") != 0))
1152         {
1153             set_timeout(mytimeout);
1154             err = kerberos_auth(mailserver_socket, ctl->server.truename,
1155                                ctl->server.principal);
1156             set_timeout(0);
1157             if (err != 0)
1158                 goto cleanUp;
1159         }
1160 #endif /* KERBEROS_V4 */
1161
1162 #ifdef KERBEROS_V5
1163         if (ctl->server.authenticate == A_KERBEROS_V5)
1164         {
1165             set_timeout(mytimeout);
1166             err = kerberos5_auth(mailserver_socket, ctl->server.truename);
1167             set_timeout(0);
1168             if (err != 0)
1169                 goto cleanUp;
1170         }
1171 #endif /* KERBEROS_V5 */
1172
1173         /* accept greeting message from mail server */
1174         err = (ctl->server.base_protocol->parse_response)(mailserver_socket, buf);
1175         if (err != 0)
1176             goto cleanUp;
1177
1178         /* try to get authorized to fetch mail */
1179         stage = STAGE_GETAUTH;
1180         if (ctl->server.base_protocol->getauth)
1181         {
1182             err = (ctl->server.base_protocol->getauth)(mailserver_socket, ctl, buf);
1183
1184             if (err != 0)
1185             {
1186                 if (err == PS_LOCKBUSY)
1187                     report(stderr, GT_("Lock-busy error on %s@%s\n"),
1188                           ctl->remotename,
1189                           ctl->server.truename);
1190                 else if (err == PS_SERVBUSY)
1191                     report(stderr, GT_("Server busy error on %s@%s\n"),
1192                           ctl->remotename,
1193                           ctl->server.truename);
1194                 else if (err == PS_AUTHFAIL)
1195                 {
1196                     report(stderr, GT_("Authorization failure on %s@%s%s\n"), 
1197                            ctl->remotename,
1198                            ctl->server.truename,
1199                            (ctl->wehaveauthed ? GT_(" (previously authorized)") : "")
1200                         );
1201
1202                     /*
1203                      * If we're running in background, try to mail the
1204                      * calling user a heads-up about the authentication 
1205                      * failure once it looks like this isn't a fluke 
1206                      * due to the server being temporarily inaccessible.
1207                      * When we get third succesive failure, we notify the user
1208                      * but only if we haven't already managed to get
1209                      * authorization.  After that, once we get authorization
1210                      * we let the user know service is restored.
1211                      */
1212                     if (run.poll_interval
1213                         && !ctl->wehavesentauthnote
1214                         && ((ctl->wehaveauthed && ++ctl->authfailcount >= 10)
1215                             || (!ctl->wehaveauthed && ++ctl->authfailcount >= 3))
1216                         && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
1217                     {
1218                         ctl->wehavesentauthnote = 1;
1219                         stuff_warning(ctl,
1220                                       GT_("Subject: fetchmail authentication failed on %s@%s\n"),
1221                             ctl->remotename, ctl->server.truename);
1222                         stuff_warning(ctl,
1223                                       GT_("Fetchmail could not get mail from %s@%s.\n"), 
1224                                       ctl->remotename,
1225                                       ctl->server.truename);
1226                         if (ctl->wehaveauthed)
1227                             stuff_warning(ctl, GT_("\
1228 The attempt to get authorization failed.\n\
1229 Since we have already succeeded in getting authorization for this\n\
1230 connection, this is probably another failure mode (such as busy server)\n\
1231 that fetchmail cannot distinguish because the server didn't send a useful\n\
1232 error message.\n\
1233 \n\
1234 However, if you HAVE changed your account details since starting the\n\
1235 fetchmail daemon, you need to stop the daemon, change your configuration\n\
1236 of fetchmail, and then restart the daemon.\n\
1237 \n\
1238 The fetchmail daemon will continue running and attempt to connect\n\
1239 at each cycle.  No future notifications will be sent until service\n\
1240 is restored."));
1241                         else
1242                             stuff_warning(ctl, GT_("\
1243 The attempt to get authorization failed.\n\
1244 This probably means your password is invalid, but some servers have\n\
1245 other failure modes that fetchmail cannot distinguish from this\n\
1246 because they don't send useful error messages on login failure.\n\
1247 \n\
1248 The fetchmail daemon will continue running and attempt to connect\n\
1249 at each cycle.  No future notifications will be sent until service\n\
1250 is restored."));
1251                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1252                     }
1253                 }
1254                 else if (err == PS_REPOLL)
1255                 {
1256                   if (outlevel >= O_VERBOSE)
1257                     report(stderr, GT_("Repoll immediately on %s@%s\n"),
1258                            ctl->remotename,
1259                            ctl->server.truename);
1260                 }
1261                 else
1262                     report(stderr, GT_("Unknown login or authentication error on %s@%s\n"),
1263                            ctl->remotename,
1264                            ctl->server.truename);
1265                     
1266                 goto cleanUp;
1267             }
1268             else
1269             {
1270                 /*
1271                  * This connection has given us authorization at least once.
1272                  *
1273                  * There are dodgy server (clubinternet.fr for example) that
1274                  * give spurious authorization failures on patently good
1275                  * account/password details, then 5 minutes later let you in!
1276                  *
1277                  * This is meant to build in some tolerance of such nasty bits
1278                  * of work.
1279                  */
1280                 ctl->wehaveauthed = 1;
1281                 /*if (ctl->authfailcount >= 3)*/
1282                 if (ctl->wehavesentauthnote)
1283                 {
1284                     ctl->wehavesentauthnote = 0;
1285                     report(stderr,
1286                            GT_("Authorization OK on %s@%s\n"),
1287                            ctl->remotename,
1288                            ctl->server.truename);
1289                     if (!open_warning_by_mail(ctl, (struct msgblk *)NULL))
1290                     {
1291                         stuff_warning(ctl,
1292                               GT_("Subject: fetchmail authentication OK on %s@%s\n"),
1293                                       ctl->remotename, ctl->server.truename);
1294                         stuff_warning(ctl,
1295                               GT_("Fetchmail was able to log into %s@%s.\n"), 
1296                                       ctl->remotename,
1297                                       ctl->server.truename);
1298                         stuff_warning(ctl, 
1299                                       GT_("Service has been restored.\n"));
1300                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1301                     
1302                     }
1303                 }
1304                 /*
1305                  * Reporting only after the first three
1306                  * consecutive failures, or ten consecutive
1307                  * failures after we have managed to get
1308                  * authorization.
1309                  */
1310                 ctl->authfailcount = 0;
1311             }
1312         }
1313
1314         ctl->errcount = fetches = 0;
1315
1316         /* now iterate over each folder selected */
1317         for (idp = ctl->mailboxes; idp; idp = idp->next)
1318         {
1319             pass = 0;
1320             do {
1321                 dispatches = 0;
1322                 ++pass;
1323
1324                 /* reset timeout, in case we did an IDLE */
1325                 mytimeout = ctl->server.timeout;
1326
1327                 if (outlevel >= O_DEBUG)
1328                 {
1329                     if (idp->id)
1330                         report(stdout, GT_("selecting or re-polling folder %s\n"), idp->id);
1331                     else
1332                         report(stdout, GT_("selecting or re-polling default folder\n"));
1333                 }
1334
1335                 /* compute # of messages and number of new messages waiting */
1336                 stage = STAGE_GETRANGE;
1337                 err = (ctl->server.base_protocol->getrange)(mailserver_socket, ctl, idp->id, &count, &new, &bytes);
1338                 if (err != 0)
1339                     goto cleanUp;
1340
1341                 /* show user how many messages we downloaded */
1342                 if (idp->id)
1343 #ifdef HAVE_SNPRINTF
1344                     (void) snprintf(buf, sizeof(buf),
1345 #else
1346                     (void) sprintf(buf,
1347 #endif /* HAVE_SNPRINTF */
1348                                    GT_("%s at %s (folder %s)"),
1349                                    ctl->remotename, ctl->server.pollname, idp->id);
1350                 else
1351 #ifdef HAVE_SNPRINTF
1352                     (void) snprintf(buf, sizeof(buf),
1353 #else
1354                     (void) sprintf(buf,
1355 #endif /* HAVE_SNPRINTF */
1356                                GT_("%s at %s"),
1357                                    ctl->remotename, ctl->server.pollname);
1358                 if (outlevel > O_SILENT)
1359                 {
1360                     if (count == -1)            /* only used for ETRN */
1361                         report(stdout, GT_("Polling %s\n"), ctl->server.truename);
1362                     else if (count != 0)
1363                     {
1364                         if (new != -1 && (count - new) > 0)
1365                             report_build(stdout, ngettext("%d message (%d %s) for %s", "%d messages (%d %s) for %s", (unsigned long)count),
1366                                   count,
1367                                   count-new, 
1368                                   ngettext("seen", "seen", (unsigned long)count-new),
1369                                   buf);
1370                         else
1371                             report_build(stdout, ngettext("%d message for %s",
1372                                                           "%d messages for %s",
1373                                                           count), 
1374                                   count, buf);
1375                         if (bytes == -1)
1376                             report_complete(stdout, ".\n");
1377                         else
1378                             report_complete(stdout, GT_(" (%d octets).\n"), bytes);
1379                     }
1380                     else
1381                     {
1382                         /* these are pointless in normal daemon mode */
1383                         if (pass == 1 && (run.poll_interval == 0 || outlevel >= O_VERBOSE))
1384                             report(stdout, GT_("No mail for %s\n"), buf); 
1385                     }
1386                 }
1387
1388                 /* very important, this is where we leave the do loop */ 
1389                 if (count == 0)
1390                     break;
1391
1392                 if (check_only)
1393                 {
1394                     if (new == -1 || ctl->fetchall)
1395                         new = count;
1396                     fetches = new;      /* set error status correctly */
1397                     /*
1398                      * There used to be a `goto noerror' here, but this
1399                      * prevented checking of multiple folders.  This
1400                      * comment is a reminder in case I introduced some
1401                      * subtle bug by removing it...
1402                      */
1403                 }
1404                 else if (count > 0)
1405                 {    
1406                     int         i;
1407
1408                     /*
1409                      * Don't trust the message count passed by the server.
1410                      * Without this check, it might be possible to do a
1411                      * DNS-spoofing attack that would pass back a ridiculous 
1412                      * count, and allocate a malloc area that would overlap
1413                      * a portion of the stack.
1414                      */
1415                     if (count > INT_MAX/sizeof(int))
1416                     {
1417                         report(stderr, GT_("bogus message count!"));
1418                         return(PS_PROTOCOL);
1419                     }
1420
1421                     /* 
1422                      * We need the size of each message before it's
1423                      * loaded in order to pass it to the ESMTP SIZE
1424                      * option.  If the protocol has a getsizes method,
1425                      * we presume this means it doesn't get reliable
1426                      * sizes from message fetch responses.
1427                      *
1428                      * If the protocol supports getting sizes of subset of
1429                      * messages, we skip this step now.
1430                      */
1431                     if (proto->getsizes &&
1432                         !(proto->getpartialsizes && NUM_NONZERO(ctl->fetchsizelimit)))
1433                     {
1434                         xalloca(msgsizes, int *, sizeof(int) * count);
1435                         for (i = 0; i < count; i++)
1436                             msgsizes[i] = 0;
1437
1438                         stage = STAGE_GETSIZES;
1439                         err = (proto->getsizes)(mailserver_socket, count, msgsizes);
1440                         if (err != 0)
1441                             goto cleanUp;
1442
1443                         if (bytes == -1)
1444                         {
1445                             bytes = 0;
1446                             for (i = 0; i < count; i++)
1447                                 bytes += msgsizes[i];
1448                         }
1449                     }
1450
1451                     /* read, forward, and delete messages */
1452                     stage = STAGE_FETCH;
1453
1454                     /* fetch in lockstep mode */
1455                     err = fetch_messages(mailserver_socket, ctl, 
1456                                          count, msgsizes,
1457                                          maxfetch,
1458                                          &fetches, &dispatches, &deletions);
1459                     if (err)
1460                         goto cleanUp;
1461
1462                     if (!check_only && ctl->skipped
1463                         && run.poll_interval > 0 && !nodetach)
1464                     {
1465                         clean_skipped_list(&ctl->skipped);
1466                         send_size_warnings(ctl);
1467                     }
1468                 }
1469             } while
1470                   /*
1471                    * Only re-poll if we either had some actual forwards and 
1472                    * either allowed deletions and had no errors.
1473                    * Otherwise it is far too easy to get into infinite loops.
1474                    */
1475                   (dispatches && ctl->server.base_protocol->retry && !ctl->keep && !ctl->errcount);
1476         }
1477
1478     /* no_error: */
1479         /* ordinary termination with no errors -- officially log out */
1480         err = (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
1481         /*
1482          * Hmmmm...arguably this would be incorrect if we had fetches but
1483          * no dispatches (due to oversized messages, etc.)
1484          */
1485         if (err == 0)
1486             err = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
1487         cleanupSockClose(mailserver_socket);
1488         goto closeUp;
1489
1490     cleanUp:
1491         /* we only get here on error */
1492         if (err != 0 && err != PS_SOCKET && err != PS_REPOLL)
1493         {
1494             stage = STAGE_LOGOUT;
1495             (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
1496         }
1497
1498         /* try to clean up all streams */
1499         release_sink(ctl);
1500         smtp_close(ctl, 0);
1501         if (mailserver_socket != -1) {
1502             cleanupSockClose(mailserver_socket);
1503             mailserver_socket = -1;
1504         }
1505         /* If there was a connect timeout, the socket should be closed.
1506          * mailserver_socket_temp contains the socket to close.
1507          */
1508         if (mailserver_socket_temp != -1) {
1509             cleanupSockClose(mailserver_socket_temp);
1510             mailserver_socket_temp = -1;
1511         }
1512     }
1513
1514     msg = (const char *)NULL;   /* sacrifice to -Wall */
1515     switch (err)
1516     {
1517     case PS_SOCKET:
1518         msg = GT_("socket");
1519         break;
1520     case PS_SYNTAX:
1521         msg = GT_("missing or bad RFC822 header");
1522         break;
1523     case PS_IOERR:
1524         msg = GT_("MDA");
1525         break;
1526     case PS_ERROR:
1527         msg = GT_("client/server synchronization");
1528         break;
1529     case PS_PROTOCOL:
1530         msg = GT_("client/server protocol");
1531         break;
1532     case PS_LOCKBUSY:
1533         msg = GT_("lock busy on server");
1534         break;
1535     case PS_SMTP:
1536         msg = GT_("SMTP transaction");
1537         break;
1538     case PS_DNS:
1539         msg = GT_("DNS lookup");
1540         break;
1541     case PS_UNDEFINED:
1542         report(stderr, GT_("undefined error\n"));
1543         break;
1544     }
1545     /* no report on PS_MAXFETCH or PS_UNDEFINED or PS_AUTHFAIL */
1546     if (err==PS_SOCKET || err==PS_SYNTAX
1547                 || err==PS_IOERR || err==PS_ERROR || err==PS_PROTOCOL 
1548                 || err==PS_LOCKBUSY || err==PS_SMTP || err==PS_DNS)
1549     {
1550         char    *stem;
1551
1552         if (phase == FORWARDING_WAIT || phase == LISTENER_WAIT)
1553             stem = GT_("%s error while delivering to SMTP host %s\n");
1554         else
1555             stem = GT_("%s error while fetching from %s\n");
1556         report(stderr, stem, msg, ctl->server.pollname);
1557     }
1558
1559 closeUp:
1560     /* execute wrapup command, if any */
1561     if (ctl->postconnect && (err = system(ctl->postconnect)))
1562     {
1563         report(stderr, GT_("post-connection command failed with status %d\n"), err);
1564         if (err == PS_SUCCESS)
1565             err = PS_SYNTAX;
1566     }
1567
1568     set_timeout(0); /* cancel any pending alarm */
1569     set_signal_handler(SIGALRM, alrmsave);
1570     set_signal_handler(SIGPIPE, pipesave);
1571     return(err);
1572 }
1573
1574 int do_protocol(ctl, proto)
1575 /* retrieve messages from server using given protocol method table */
1576 struct query *ctl;              /* parsed options with merged-in defaults */
1577 const struct method *proto;     /* protocol method table */
1578 {
1579     int err;
1580
1581 #ifndef KERBEROS_V4
1582     if (ctl->server.authenticate == A_KERBEROS_V4)
1583     {
1584         report(stderr, GT_("Kerberos V4 support not linked.\n"));
1585         return(PS_ERROR);
1586     }
1587 #endif /* KERBEROS_V4 */
1588
1589 #ifndef KERBEROS_V5
1590     if (ctl->server.authenticate == A_KERBEROS_V5)
1591     {
1592         report(stderr, GT_("Kerberos V5 support not linked.\n"));
1593         return(PS_ERROR);
1594     }
1595 #endif /* KERBEROS_V5 */
1596
1597     /* lacking methods, there are some options that may fail */
1598     if (!proto->is_old)
1599     {
1600         /* check for unsupported options */
1601         if (ctl->flush) {
1602             report(stderr,
1603                     GT_("Option --flush is not supported with %s\n"),
1604                     proto->name);
1605             return(PS_SYNTAX);
1606         }
1607         else if (ctl->fetchall) {
1608             report(stderr,
1609                     GT_("Option --all is not supported with %s\n"),
1610                     proto->name);
1611             return(PS_SYNTAX);
1612         }
1613     }
1614     if (!proto->getsizes && NUM_SPECIFIED(ctl->limit))
1615     {
1616         report(stderr,
1617                 GT_("Option --limit is not supported with %s\n"),
1618                 proto->name);
1619         return(PS_SYNTAX);
1620     }
1621
1622     /*
1623      * If no expunge limit or we do expunges within the driver,
1624      * then just do one session, passing in any fetchlimit.
1625      */
1626     if ((ctl->keep && !ctl->flush) ||
1627         proto->retry || !NUM_SPECIFIED(ctl->expunge))
1628         return(do_session(ctl, proto, NUM_VALUE_OUT(ctl->fetchlimit)));
1629     /*
1630      * There's an expunge limit, and it isn't handled in the driver itself.
1631      * OK; do multiple sessions, each fetching a limited # of messages.
1632      * Stop if the total count of retrieved messages exceeds ctl->fetchlimit
1633      * (if it was nonzero).
1634      */
1635     else
1636     {
1637         int totalcount = 0; 
1638         int lockouts   = 0;
1639         int expunge    = NUM_VALUE_OUT(ctl->expunge);
1640         int fetchlimit = NUM_VALUE_OUT(ctl->fetchlimit);
1641
1642         do {
1643             if (fetchlimit > 0 && (expunge == 0 || expunge > fetchlimit - totalcount))
1644                 expunge = fetchlimit - totalcount;
1645             err = do_session(ctl, proto, expunge);
1646             totalcount += expunge;
1647             if (NUM_SPECIFIED(ctl->fetchlimit) && totalcount >= fetchlimit)
1648                 break;
1649             if (err != PS_LOCKBUSY)
1650                 lockouts = 0;
1651             else if (lockouts >= MAX_LOCKOUTS)
1652                 break;
1653             else /* err == PS_LOCKBUSY */
1654             {
1655                 /*
1656                  * Allow time for the server lock to release.  if we
1657                  * don't do this, we'll often hit a locked-mailbox
1658                  * condition and fail.
1659                  */
1660                 lockouts++;
1661                 sleep(3);
1662             }
1663         } while
1664             (err == PS_MAXFETCH || err == PS_LOCKBUSY);
1665
1666         return(err);
1667     }
1668 }
1669
1670
1671 /* driver.c ends here */