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