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