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