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