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