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