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