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