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