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