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