]> Pileus Git - ~andy/fetchmail/blob - driver.c
Fix miscellaneous warnings.
[~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_NET_SOCKET_H
32 #include <net/socket.h>
33 #endif
34 #ifdef HAVE_PKG_hesiod
35 #include <hesiod.h>
36 #endif
37
38 #include <langinfo.h>
39
40 #if defined(HAVE_RES_SEARCH) || defined(HAVE_GETHOSTBYNAME)
41 #include <netdb.h>
42 #include "mx.h"
43 #endif /* defined(HAVE_RES_SEARCH) || defined(HAVE_GETHOSTBYNAME) */
44
45 #include "kerberos.h"
46 #ifdef KERBEROS_V4
47 #include <netinet/in.h>
48 #endif /* KERBEROS_V4 */
49
50 #include "i18n.h"
51 #include "socket.h"
52
53 #include "fetchmail.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 isidletimeout(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     xalloca(ticket, KTEXT, 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     if (prin_copy)
187     {
188         free(prin_copy);
189     }
190     if (rem != KSUCCESS)
191     {
192         report(stderr, GT_("kerberos error %s\n"), (krb_get_err_text (rem)));
193         return (PS_AUTHFAIL);
194     }
195     return (0);
196 }
197 #endif /* KERBEROS_V4 */
198
199 #ifdef KERBEROS_V5
200 static int kerberos5_auth(socket, canonical)
201 /* authenticate to the server host using Kerberos V5 */
202 int socket;             /* socket to server host */
203 const char *canonical;  /* server name */
204 {
205     krb5_error_code retval;
206     krb5_context context;
207     krb5_ccache ccdef;
208     krb5_principal client = NULL, server = NULL;
209     krb5_error *err_ret = NULL;
210
211     krb5_auth_context auth_context = NULL;
212
213     krb5_init_context(&context);
214     krb5_init_ets(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(ctl,
337             rfc2047e(
338            GT_("Subject: Fetchmail oversized-messages warning"), nl_langinfo(CODESET)));
339     stuff_warning(ctl, "");
340     stuff_warning(ctl,
341             GT_("The following oversized messages remain on the mail server %s:"),
342             ctl->server.pollname);
343
344     stuff_warning(ctl, "");
345
346     if (run.poll_interval == 0)
347         max_warning_poll_count = 0;
348     else
349         max_warning_poll_count = ctl->warnings/run.poll_interval;
350
351     /* parse list of skipped msg, adding items to the mail */
352     for (current = head; current; current = current->next)
353     {
354         if (current->val.status.num == 0 && current->val.status.mark)
355         {
356             nbr = current->val.status.mark;
357             size = atoi(current->id);
358             stuff_warning(ctl, 
359                     GT_("  %d msg %d octets long skipped by fetchmail."),
360                     nbr, size);
361         }
362         current->val.status.num++;
363         current->val.status.mark = 0;
364
365         if (current->val.status.num >= max_warning_poll_count)
366             current->val.status.num = 0;
367     }
368
369     stuff_warning(ctl, "");
370
371     close_warning_by_mail(ctl, (struct msgblk *)NULL);
372 }
373
374 static void mark_oversized(struct query *ctl, int num, int size)
375 /* mark a message oversized */
376 {
377     struct idlist *current=NULL, *tmp=NULL;
378     char sizestr[32];
379     int cnt;
380
381     /* convert size to string */
382 #ifdef HAVE_SNPRINTF
383     snprintf(sizestr, sizeof(sizestr),
384 #else
385     sprintf(sizestr,
386 #endif /* HAVE_SNPRINTF */
387       "%d", size);
388
389     /* build a list of skipped messages
390      * val.id = size of msg (string cnvt)
391      * val.status.num = warning_poll_count
392      * val.status.mask = nbr of msg this size
393      */
394
395     current = ctl->skipped;
396
397     /* initialise warning_poll_count to the
398      * current value so that all new msg will
399      * be included in the next mail
400      */
401     cnt = current ? current->val.status.num : 0;
402
403     /* if entry exists, increment the count */
404     if (current && str_in_list(&current, sizestr, FALSE))
405     {
406         for ( ; current; current = current->next)
407         {
408             if (strcmp(current->id, sizestr) == 0)
409             {
410                 current->val.status.mark++;
411                 break;
412             }
413         }
414     }
415     /* otherwise, create a new entry */
416     /* initialise with current poll count */
417     else
418     {
419         tmp = save_str(&ctl->skipped, sizestr, 1);
420         tmp->val.status.num = cnt;
421     }
422 }
423
424 static int fetch_messages(int mailserver_socket, struct query *ctl, 
425                           int count, int *msgsizes, int maxfetch,
426                           int *fetches, int *dispatches, int *deletions)
427 /* fetch messages in lockstep mode */
428 {
429     flag force_retrieval;
430     int num, firstnum = 1, lastnum = 0, err, len;
431     int fetchsizelimit = ctl->fetchsizelimit;
432     int msgsize;
433
434     if (ctl->server.base_protocol->getpartialsizes && NUM_NONZERO(fetchsizelimit))
435     {
436         /* for POP3, we can get the size of one mail only! Unfortunately, this
437          * protocol specific test cannot be done elsewhere as the protocol
438          * could be "auto". */
439         switch (ctl->server.protocol)
440         {
441             case P_POP3: case P_APOP: case P_RPOP:
442             fetchsizelimit = 1;
443         }
444
445         /* Time to allocate memory to store the sizes */
446         xalloca(msgsizes, int *, sizeof(int) * fetchsizelimit);
447     }
448
449     /*
450      * What forces this code is that in POP2 and
451      * IMAP2bis you can't fetch a message without
452      * having it marked `seen'.  In POP3 and IMAP4, on the
453      * other hand, you can (peek_capable is set by 
454      * each driver module to convey this; it's not a
455      * method constant because of the difference between
456      * IMAP2bis and IMAP4, and because POP3 doesn't  peek
457      * if fetchall is on).
458      *
459      * The result of being unable to peek is that if there's
460      * any kind of transient error (DNS lookup failure, or
461      * sendmail refusing delivery due to process-table limits)
462      * the message will be marked "seen" on the server without
463      * having been delivered.  This is not a big problem if
464      * fetchmail is running in foreground, because the user
465      * will see a "skipped" message when it next runs and get
466      * clued in.
467      *
468      * But in daemon mode this leads to the message
469      * being silently ignored forever.  This is not
470      * acceptable.
471      *
472      * We compensate for this by checking the error
473      * count from the previous pass and forcing all
474      * messages to be considered new if it's nonzero.
475      */
476     force_retrieval = !peek_capable && (ctl->errcount > 0);
477
478     for (num = 1; num <= count; num++)
479     {
480         flag suppress_delete = FALSE;
481         flag suppress_forward = FALSE;
482         flag suppress_readbody = FALSE;
483         flag retained = FALSE;
484         int msgcode = MSGLEN_UNKNOWN;
485
486         /* check if the message is old
487          * Note: the size of the message may not be known here */
488         if (ctl->fetchall || force_retrieval)
489             ;
490         else if (ctl->server.base_protocol->is_old && (ctl->server.base_protocol->is_old)(mailserver_socket,ctl,num))
491             msgcode = MSGLEN_OLD;
492         if (msgcode == MSGLEN_OLD)
493         {
494                 /* To avoid flooding the syslog when using --keep,
495                  * report "Skipped message" only when:
496                  *  1) --verbose is on, or
497                  *  2) fetchmail does not use syslog
498                  */
499             if (   (outlevel >= O_VERBOSE) ||
500                    (outlevel > O_SILENT && !run.use_syslog)
501                )
502             {
503                 report_build(stdout, 
504                              GT_("skipping message %s@%s:%d"),
505                              ctl->remotename, ctl->server.truename, num);
506             }
507
508             goto flagthemail;
509         }
510
511         if (ctl->server.base_protocol->getpartialsizes && NUM_NONZERO(fetchsizelimit) &&
512             lastnum < num)
513         {
514             /* Instead of getting the sizes of all mails at the start, we get
515              * the sizes in blocks of fetchsizelimit. This leads to better
516              * performance when there are too many mails (say, 10000) in
517              * the mailbox and either we are not getting all the mails at
518              * one go (--fetchlimit 100) or there is a frequent socket
519              * error while just getting the sizes of all mails! */
520
521             int i;
522             int oldstage = stage;
523             firstnum = num;
524             lastnum = num + fetchsizelimit - 1;
525             if (lastnum > count)
526                 lastnum = count;
527             for (i = 0; i < fetchsizelimit; i++)
528                 msgsizes[i] = 0;
529
530             stage = STAGE_GETSIZES;
531             err = (ctl->server.base_protocol->getpartialsizes)(mailserver_socket, num, lastnum, msgsizes);
532             if (err != 0)
533                 return err;
534             stage = oldstage;
535         }
536
537         msgsize = msgsizes ? msgsizes[num-firstnum] : 0;
538
539         /* check if the message is oversized */
540         if (NUM_NONZERO(ctl->limit) && (msgsize > ctl->limit))
541             msgcode = MSGLEN_TOOLARGE;
542 /*      else if (msgsize == 512)
543             msgcode = MSGLEN_OLD;  (hmh) sample code to skip message */
544
545         if (msgcode < 0)
546         {
547             if ((msgcode == MSGLEN_TOOLARGE) && !check_only)
548             {
549                 mark_oversized(ctl, num, msgsize);
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                 /* XXX FIXME: the gettext stuff needs to list "octets" or
612                  * "header octets" as a unit, and also provide for
613                  * proper plural form */
614                 if (len > 0)
615                     report_build(stdout, GT_(" (%d %soctets)"),
616                                  len, wholesize ? "" : GT_("header "));
617                 if (outlevel >= O_VERBOSE)
618                     report_complete(stdout, "\n");
619                 else
620                     report_complete(stdout, " ");
621             }
622
623             /* 
624              * Read the message headers and ship them to the
625              * output sink.  
626              */
627             err = readheaders(mailserver_socket, len, msgsize,
628                              ctl, num,
629                              /* pass the suppress_readbody flag only if the underlying
630                               * protocol does not fetch the body separately */
631                              separatefetchbody ? 0 : &suppress_readbody);
632             if (err == PS_RETAINED)
633                 suppress_forward = suppress_delete = retained = TRUE;
634             else if (err == PS_TRANSIENT)
635                 suppress_delete = suppress_forward = TRUE;
636             else if (err == PS_REFUSED)
637                 suppress_forward = TRUE;
638             else if (err == PS_TRUNCATED)
639                 suppress_readbody = TRUE;
640             else if (err)
641                 return(err);
642
643             /* tell server we got it OK and resynchronize */
644             if (separatefetchbody && ctl->server.base_protocol->trail)
645             {
646                 if (outlevel >= O_VERBOSE && !isafile(1))
647                 {
648                     fputc('\n', stdout);
649                     fflush(stdout);
650                 }
651
652                 if ((err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num)))
653                     return(err);
654             }
655
656             /* do not read the body which is not being forwarded only if
657              * the underlying protocol allows the body to be fetched
658              * separately */
659             if (separatefetchbody && suppress_forward)
660                 suppress_readbody = TRUE;
661
662             /* 
663              * If we're using IMAP4 or something else that
664              * can fetch headers separately from bodies,
665              * it's time to request the body now.  This
666              * fetch may be skipped if we got an anti-spam
667              * or other PS_REFUSED error response during
668              * readheaders.
669              */
670             if (!suppress_readbody)
671             {
672                 if (separatefetchbody)
673                 {
674                     len = -1;
675                     if ((err=(ctl->server.base_protocol->fetch_body)(mailserver_socket,ctl,num,&len)))
676                         return(err);
677                     /*
678                      * Work around a bug in Novell's
679                      * broken GroupWise IMAP server;
680                      * its body FETCH response is missing
681                      * the required length for the data
682                      * string.  This violates RFC2060.
683                      */
684                     if (len == -1)
685                         len = msgsize - msgblk.msglen;
686                     if (outlevel > O_SILENT && !wholesize)
687                         report_complete(stdout,
688                                         GT_(" (%d body octets) "), len);
689                 }
690
691                 /* process the body now */
692                 err = readbody(mailserver_socket,
693                               ctl,
694                               !suppress_forward,
695                               len);
696                 if (err == PS_TRANSIENT)
697                     suppress_delete = suppress_forward = TRUE;
698                 else if (err)
699                     return(err);
700
701                 /* tell server we got it OK and resynchronize */
702                 if (ctl->server.base_protocol->trail)
703                 {
704                     if (outlevel >= O_VERBOSE && !isafile(1))
705                     {
706                         fputc('\n', stdout);
707                         fflush(stdout);
708                     }
709
710                     err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num);
711                     if (err != 0)
712                         return(err);
713                 }
714             }
715
716             /* count # messages forwarded on this pass */
717             if (!suppress_forward)
718                 (*dispatches)++;
719
720             /*
721              * Check to see if the numbers matched?
722              *
723              * Yes, some servers foo this up horribly.
724              * All IMAP servers seem to get it right, and
725              * so does Eudora QPOP at least in 2.xx
726              * versions.
727              *
728              * Microsoft Exchange gets it completely
729              * wrong, reporting compressed rather than
730              * actual sizes (so the actual length of
731              * message is longer than the reported size).
732              * Another fine example of Microsoft brain death!
733              *
734              * Some older POP servers, like the old UCB
735              * POP server and the pre-QPOP QUALCOMM
736              * versions, report a longer size in the LIST
737              * response than actually gets shipped up.
738              * It's unclear what is going on here, as the
739              * QUALCOMM server (at least) seems to be
740              * reporting the on-disk size correctly.
741              */
742             if (msgblk.msglen != msgsize)
743             {
744                 if (outlevel >= O_DEBUG)
745                     report(stdout,
746                            GT_("message %s@%s:%d was not the expected length (%d actual != %d expected)\n"),
747                            ctl->remotename, ctl->server.truename, num,
748                            msgblk.msglen, msgsize);
749             }
750
751             /* end-of-message processing starts here */
752             if (!close_sink(ctl, &msgblk, !suppress_forward))
753             {
754                 ctl->errcount++;
755                 suppress_delete = TRUE;
756             }
757             if (!retained)
758                 (*fetches)++;
759         }
760
761 flagthemail:
762         /*
763          * At this point in flow of control, either
764          * we've bombed on a protocol error or had
765          * delivery refused by the SMTP server
766          * (unlikely -- I've never seen it) or we've
767          * seen `accepted for delivery' and the
768          * message is shipped.  It's safe to mark the
769          * message seen and delete it on the server
770          * now.
771          */
772
773         /* maybe we delete this message now? */
774         if (retained)
775         {
776             if (outlevel > O_SILENT) 
777                 report(stdout, GT_(" retained\n"));
778         }
779         else if (ctl->server.base_protocol->delete
780                  && !suppress_delete
781                  && ((msgcode >= 0 && !ctl->keep)
782                      || (msgcode == MSGLEN_OLD && ctl->flush)))
783         {
784             (*deletions)++;
785             if (outlevel > O_SILENT) 
786                 report_complete(stdout, GT_(" flushed\n"));
787             err = (ctl->server.base_protocol->delete)(mailserver_socket, ctl, num);
788             if (err != 0)
789                 return(err);
790         }
791         else
792         {
793             if (   (outlevel >= O_VERBOSE) ||
794                         /* To avoid flooding the syslog when using --keep,
795                          * report "Skipped message" only when:
796                          *  1) --verbose is on, or
797                          *  2) fetchmail does not use syslog, or
798                          *  3) the message was skipped for some other
799                          *     reason than just being old.
800                          */
801                    (outlevel > O_SILENT && (!run.use_syslog || msgcode != MSGLEN_OLD))
802                )
803             report_complete(stdout, GT_(" not flushed\n"));
804
805             /* maybe we mark this message as seen now? */
806             if (ctl->server.base_protocol->mark_seen
807                 && !suppress_delete
808                 && (msgcode >= 0 && ctl->keep))
809             {
810                 err = (ctl->server.base_protocol->mark_seen)(mailserver_socket, ctl, num);
811                 if (err != 0)
812                     return(err);
813             }
814         }
815
816         /* perhaps this as many as we're ready to handle */
817         if (maxfetch && maxfetch <= *fetches && num < count)
818         {
819             report(stdout, GT_("fetchlimit %d reached; %d messages left on server %s account %s\n"),
820                    maxfetch, count - *fetches, ctl->server.truename, ctl->remotename);
821             return(PS_MAXFETCH);
822         }
823     }
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 #ifdef HAVE_SIGPROCMASK
861         /*
862          * Don't rely on setjmp() to restore the blocked-signal mask.
863          * It does this under BSD but is required not to under POSIX.
864          *
865          * If your Unix doesn't have sigprocmask, better hope it has
866          * BSD-like behavior.  Otherwise you may see fetchmail get
867          * permanently wedged after a second timeout on a bad read,
868          * because alarm signals were blocked after the first.
869          */
870         sigset_t        allsigs;
871
872         sigfillset(&allsigs);
873         sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
874 #endif /* HAVE_SIGPROCMASK */
875         
876         if (js == THROW_SIGPIPE)
877         {
878             set_signal_handler(SIGPIPE, SIG_IGN);
879             report(stdout,
880                    GT_("SIGPIPE thrown from an MDA or a stream socket error\n"));
881             wait(0);
882         }
883         else if (js == THROW_TIMEOUT)
884         {
885             if (phase == OPEN_WAIT)
886                 report(stdout,
887                        GT_("timeout after %d seconds waiting to connect to server %s.\n"),
888                        ctl->server.timeout, ctl->server.pollname);
889             else if (phase == SERVER_WAIT)
890                 report(stdout,
891                        GT_("timeout after %d seconds waiting for server %s.\n"),
892                        ctl->server.timeout, ctl->server.pollname);
893             else if (phase == FORWARDING_WAIT)
894                 report(stdout,
895                        GT_("timeout after %d seconds waiting for %s.\n"),
896                        ctl->server.timeout,
897                        ctl->mda ? "MDA" : "SMTP");
898             else if (phase == LISTENER_WAIT)
899                 report(stdout,
900                        GT_("timeout after %d seconds waiting for listener to respond.\n"), ctl->server.timeout);
901             else
902                 report(stdout, 
903                        GT_("timeout after %d seconds.\n"), ctl->server.timeout);
904
905             /*
906              * If we've exceeded our threshold for consecutive timeouts, 
907              * try to notify the user, then mark the connection wedged.
908              * Don't do this if the connection can idle, though; idle
909              * timeouts just mean the frequency of mail is low.
910              */
911             if (timeoutcount > MAX_TIMEOUTS 
912                 && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
913             {
914                 stuff_warning(ctl,
915                               rfc2047e(GT_("Subject: fetchmail sees repeated timeouts"),nl_langinfo(CODESET)));
916                 stuff_warning(ctl, "");
917                 stuff_warning(ctl,
918                               GT_("Fetchmail saw more than %d timeouts while attempting to get mail from %s@%s.\n"), 
919                               MAX_TIMEOUTS,
920                               ctl->remotename,
921                               ctl->server.truename);
922                 stuff_warning(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         char buf[MSGBUFSIZE+1], *realhost;
939         int count, new, bytes;
940 #ifdef INET6_ENABLE
941         int fetches, dispatches, oldphase;
942 #else /* INET6_ENABLE */
943         int port, fetches, dispatches, oldphase;
944 #endif /* INET6_ENABLE */
945         struct idlist *idp;
946
947         /* execute pre-initialization command, if any */
948         if (ctl->preconnect && (err = system(ctl->preconnect)))
949         {
950             report(stderr, 
951                    GT_("pre-connection command failed with status %d\n"), err);
952             err = PS_SYNTAX;
953             goto closeUp;
954         }
955
956         /* open a socket to the mail server */
957         oldphase = phase;
958         phase = OPEN_WAIT;
959         set_timeout(mytimeout);
960 #ifndef INET6_ENABLE
961 #ifdef SSL_ENABLE
962         port = ctl->server.port ? ctl->server.port : ( ctl->use_ssl ? ctl->server.base_protocol->sslport : ctl->server.base_protocol->port );
963 #else
964         port = ctl->server.port ? ctl->server.port : ctl->server.base_protocol->port;
965 #endif
966 #endif /* !INET6_ENABLE */
967
968 #ifdef HAVE_PKG_hesiod
969         /* If either the pollname or vianame are "hesiod" we want to
970            lookup the user's hesiod pobox host */
971         if (!strcasecmp(ctl->server.queryname, "hesiod")) {
972             struct hes_postoffice *hes_p;
973             hes_p = hes_getmailhost(ctl->remotename);
974             if (hes_p != NULL && strcmp(hes_p->po_type, "POP") == 0) {
975                  free(ctl->server.queryname);
976                  ctl->server.queryname = xstrdup(hes_p->po_host);
977                  if (ctl->server.via)
978                      free(ctl->server.via);
979                  ctl->server.via = xstrdup(hes_p->po_host);
980             } else {
981                  report(stderr,
982                         GT_("couldn't find HESIOD pobox for %s\n"),
983                         ctl->remotename);
984             }
985         }
986 #endif /* HESIOD */
987
988 #ifdef HAVE_GETHOSTBYNAME
989         /*
990          * Canonicalize the server truename for later use.  This also
991          * functions as a probe for whether the mailserver is accessible.
992          * We try it on each poll cycle until we get a result.  This way,
993          * fetchmail won't fail if started up when the network is inaccessible.
994          */
995         if (ctl->server.dns && !ctl->server.trueaddr)
996         {
997             if (ctl->server.lead_server)
998             {
999                 char    *leadname = ctl->server.lead_server->truename;
1000
1001                 /* prevent core dump from ill-formed or duplicate entry */
1002                 if (!leadname)
1003                 {
1004                     report(stderr, GT_("Lead server has no name.\n"));
1005                     err = PS_DNS;
1006                     set_timeout(0);
1007                     phase = oldphase;
1008                     goto closeUp;
1009                 }
1010
1011                 ctl->server.truename = xstrdup(leadname);
1012             }
1013             else
1014             {
1015                 struct hostent  *namerec;
1016                     
1017                 /* 
1018                  * Get the host's IP, so we can report it like this:
1019                  *
1020                  * Received: from hostname [10.0.0.1]
1021                  */
1022                 errno = 0;
1023                 namerec = gethostbyname(ctl->server.queryname);
1024                 if (namerec == (struct hostent *)NULL)
1025                 {
1026                     report(stderr,
1027                            GT_("couldn't find canonical DNS name of %s (%s)\n"),
1028                            ctl->server.pollname, ctl->server.queryname);
1029                     err = PS_DNS;
1030                     set_timeout(0);
1031                     phase = oldphase;
1032                     goto closeUp;
1033                 }
1034                 else 
1035                 {
1036                     ctl->server.truename=xstrdup((char *)namerec->h_name);
1037                     ctl->server.trueaddr=xmalloc(namerec->h_length);
1038                     memcpy(ctl->server.trueaddr, 
1039                            namerec->h_addr_list[0],
1040                            namerec->h_length);
1041                 }
1042             }
1043         }
1044 #endif /* HAVE_GETHOSTBYNAME */
1045
1046         realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
1047
1048         /* allow time for the port to be set up if we have a plugin */
1049         if (ctl->server.plugin)
1050             (void)sleep(1);
1051 #ifdef INET6_ENABLE
1052         if ((mailserver_socket = SockOpen(realhost, 
1053                              ctl->server.service ? ctl->server.service : ( ctl->use_ssl ? ctl->server.base_protocol->sslservice : ctl->server.base_protocol->service ),
1054                              ctl->server.netsec, ctl->server.plugin)) == -1)
1055 #else /* INET6_ENABLE */
1056         if ((mailserver_socket = SockOpen(realhost, port, NULL, ctl->server.plugin)) == -1)
1057 #endif /* INET6_ENABLE */
1058         {
1059             char        errbuf[BUFSIZ];
1060 #ifndef INET6_ENABLE
1061             int err_no = errno;
1062 #ifdef HAVE_RES_SEARCH
1063             if (err_no != 0 && h_errno != 0)
1064                 report(stderr, GT_("internal inconsistency\n"));
1065 #endif
1066             /*
1067              * Avoid generating a bogus error every poll cycle when we're
1068              * in daemon mode but the connection to the outside world
1069              * is down.
1070              */
1071             if (!((err_no == EHOSTUNREACH || err_no == ENETUNREACH) 
1072                   && run.poll_interval))
1073             {
1074                 report_build(stderr, GT_("%s connection to %s failed"), 
1075                              ctl->server.base_protocol->name, ctl->server.pollname);
1076 #ifdef HAVE_RES_SEARCH
1077                 if (h_errno != 0)
1078                 {
1079                     if (h_errno == HOST_NOT_FOUND)
1080                         strcpy(errbuf, GT_("host is unknown."));
1081 #ifndef __BEOS__
1082                     else if (h_errno == NO_ADDRESS)
1083                         strcpy(errbuf, GT_("name is valid but has no IP address."));
1084 #endif
1085                     else if (h_errno == NO_RECOVERY)
1086                         strcpy(errbuf, GT_("unrecoverable name server error."));
1087                     else if (h_errno == TRY_AGAIN)
1088                         strcpy(errbuf, GT_("temporary name server error."));
1089                     else
1090 #ifdef HAVE_SNPRINTF
1091                         snprintf(errbuf, sizeof(errbuf),
1092 #else
1093                         sprintf(errbuf,
1094 #endif /* HAVE_SNPRINTF */
1095                           GT_("unknown DNS error %d."), h_errno);
1096                 }
1097                 else
1098 #endif /* HAVE_RES_SEARCH */
1099                     strcpy(errbuf, strerror(err_no));
1100                 report_complete(stderr, ": %s\n", errbuf);
1101
1102 #ifdef __UNUSED
1103                 /* 
1104                  * Don't use this.  It was an attempt to address Debian bug
1105                  * #47143 (Notify user by mail when pop server nonexistent).
1106                  * Trouble is, that doesn't work; you trip over the case 
1107                  * where your SLIP or PPP link is down...
1108                  */
1109                 /* warn the system administrator */
1110                 if (open_warning_by_mail(ctl, (struct msgblk *)NULL) == 0)
1111                 {
1112                     stuff_warning(ctl,
1113                          rfc2047e(GT_("Subject: Fetchmail unreachable-server warning."), nl_langinfo(CODESET)));
1114                     stuff_warning(ctl, "");
1115                     stuff_warning(ctl, GT_("Fetchmail could not reach the mail server %s:"),
1116                                   ctl->server.pollname);
1117                     stuff_warning(ctl, errbuf, ctl->server.pollname);
1118                     close_warning_by_mail(ctl, (struct msgblk *)NULL);
1119                 }
1120 #endif
1121             }
1122 #endif /* INET6_ENABLE */
1123             err = PS_SOCKET;
1124             set_timeout(0);
1125             phase = oldphase;
1126             goto closeUp;
1127         }
1128
1129 #ifdef SSL_ENABLE
1130         /* Save the socket opened. Useful if Fetchmail hangs on SSLOpen 
1131          * because the socket can be closed.
1132          */
1133         mailserver_socket_temp = mailserver_socket;
1134         set_timeout(mytimeout);
1135
1136         /* perform initial SSL handshake on open connection */
1137         /* Note:  We pass the realhost name over for certificate
1138                 verification.  We may want to make this configurable */
1139         if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslcert,ctl->sslkey,ctl->sslproto,ctl->sslcertck,
1140             ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1) 
1141         {
1142             report(stderr, GT_("SSL connection failed.\n"));
1143             err = PS_AUTHFAIL;
1144             goto closeUp;
1145         }
1146         
1147         /* Fetchmail didn't hang on SSLOpen, 
1148          * then no need to set mailserver_socket_temp 
1149          */
1150         mailserver_socket_temp = -1;
1151 #endif
1152         
1153         /* A timeout is still defined before SSLOpen, 
1154          * then Fetchmail hanging on SSLOpen is handled.
1155          */
1156         set_timeout(0);
1157         phase = oldphase;
1158 #ifdef KERBEROS_V4
1159         if (ctl->server.authenticate == A_KERBEROS_V4 && (strcasecmp(proto->name,"IMAP") != 0))
1160         {
1161             set_timeout(mytimeout);
1162             err = kerberos_auth(mailserver_socket, ctl->server.truename,
1163                                ctl->server.principal);
1164             set_timeout(0);
1165             if (err != 0)
1166                 goto cleanUp;
1167         }
1168 #endif /* KERBEROS_V4 */
1169
1170 #ifdef KERBEROS_V5
1171         if (ctl->server.authenticate == A_KERBEROS_V5)
1172         {
1173             set_timeout(mytimeout);
1174             err = kerberos5_auth(mailserver_socket, ctl->server.truename);
1175             set_timeout(0);
1176             if (err != 0)
1177                 goto cleanUp;
1178         }
1179 #endif /* KERBEROS_V5 */
1180
1181         /* accept greeting message from mail server */
1182         err = (ctl->server.base_protocol->parse_response)(mailserver_socket, buf);
1183         if (err != 0)
1184             goto cleanUp;
1185
1186         /* try to get authorized to fetch mail */
1187         stage = STAGE_GETAUTH;
1188         if (ctl->server.base_protocol->getauth)
1189         {
1190             err = (ctl->server.base_protocol->getauth)(mailserver_socket, ctl, buf);
1191
1192             if (err != 0)
1193             {
1194                 if (err == PS_LOCKBUSY)
1195                     report(stderr, GT_("Lock-busy error on %s@%s\n"),
1196                           ctl->remotename,
1197                           ctl->server.truename);
1198                 else if (err == PS_SERVBUSY)
1199                     report(stderr, GT_("Server busy error on %s@%s\n"),
1200                           ctl->remotename,
1201                           ctl->server.truename);
1202                 else if (err == PS_AUTHFAIL)
1203                 {
1204                     report(stderr, GT_("Authorization failure on %s@%s%s\n"), 
1205                            ctl->remotename,
1206                            ctl->server.truename,
1207                            (ctl->wehaveauthed ? GT_(" (previously authorized)") : "")
1208                         );
1209
1210                     /*
1211                      * If we're running in background, try to mail the
1212                      * calling user a heads-up about the authentication 
1213                      * failure once it looks like this isn't a fluke 
1214                      * due to the server being temporarily inaccessible.
1215                      * When we get third succesive failure, we notify the user
1216                      * but only if we haven't already managed to get
1217                      * authorization.  After that, once we get authorization
1218                      * we let the user know service is restored.
1219                      */
1220                     if (run.poll_interval
1221                         && !ctl->wehavesentauthnote
1222                         && ((ctl->wehaveauthed && ++ctl->authfailcount >= 10)
1223                             || (!ctl->wehaveauthed && ++ctl->authfailcount >= 3))
1224                         && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
1225                     {
1226                         ctl->wehavesentauthnote = 1;
1227                         stuff_warning(ctl,
1228                                       rfc2047e(GT_("Subject: fetchmail authentication failed on %s@%s"), nl_langinfo(CODESET)),
1229                             ctl->remotename, ctl->server.truename);
1230                         stuff_warning(ctl, "");
1231                         stuff_warning(ctl,
1232                                       GT_("Fetchmail could not get mail from %s@%s.\n"), 
1233                                       ctl->remotename,
1234                                       ctl->server.truename);
1235                         if (ctl->wehaveauthed)
1236                             stuff_warning(ctl, GT_("\
1237 The attempt to get authorization failed.\n\
1238 Since we have already succeeded in getting authorization for this\n\
1239 connection, this is probably another failure mode (such as busy server)\n\
1240 that fetchmail cannot distinguish because the server didn't send a useful\n\
1241 error message.\n\
1242 \n\
1243 However, if you HAVE changed your account details since starting the\n\
1244 fetchmail daemon, you need to stop the daemon, change your configuration\n\
1245 of fetchmail, and then restart the daemon.\n\
1246 \n\
1247 The fetchmail daemon will continue running and attempt to connect\n\
1248 at each cycle.  No future notifications will be sent until service\n\
1249 is restored."));
1250                         else
1251                             stuff_warning(ctl, GT_("\
1252 The attempt to get authorization failed.\n\
1253 This probably means your password is invalid, but some servers have\n\
1254 other failure modes that fetchmail cannot distinguish from this\n\
1255 because they don't send useful error messages on login failure.\n\
1256 \n\
1257 The fetchmail daemon will continue running and attempt to connect\n\
1258 at each cycle.  No future notifications will be sent until service\n\
1259 is restored."));
1260                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1261                     }
1262                 }
1263                 else if (err == PS_REPOLL)
1264                 {
1265                   if (outlevel >= O_VERBOSE)
1266                     report(stderr, GT_("Repoll immediately on %s@%s\n"),
1267                            ctl->remotename,
1268                            ctl->server.truename);
1269                 }
1270                 else
1271                     report(stderr, GT_("Unknown login or authentication error on %s@%s\n"),
1272                            ctl->remotename,
1273                            ctl->server.truename);
1274                     
1275                 goto cleanUp;
1276             }
1277             else
1278             {
1279                 /*
1280                  * This connection has given us authorization at least once.
1281                  *
1282                  * There are dodgy server (clubinternet.fr for example) that
1283                  * give spurious authorization failures on patently good
1284                  * account/password details, then 5 minutes later let you in!
1285                  *
1286                  * This is meant to build in some tolerance of such nasty bits
1287                  * of work.
1288                  */
1289                 ctl->wehaveauthed = 1;
1290                 /*if (ctl->authfailcount >= 3)*/
1291                 if (ctl->wehavesentauthnote)
1292                 {
1293                     ctl->wehavesentauthnote = 0;
1294                     report(stderr,
1295                            GT_("Authorization OK on %s@%s\n"),
1296                            ctl->remotename,
1297                            ctl->server.truename);
1298                     if (!open_warning_by_mail(ctl, (struct msgblk *)NULL))
1299                     {
1300                         stuff_warning(ctl,
1301                               rfc2047e(GT_("Subject: fetchmail authentication OK on %s@%s"), nl_langinfo(CODESET)),
1302                                       ctl->remotename, ctl->server.truename);
1303                         stuff_warning(ctl, "");
1304                         stuff_warning(ctl,
1305                               GT_("Fetchmail was able to log into %s@%s.\n"), 
1306                                       ctl->remotename,
1307                                       ctl->server.truename);
1308                         stuff_warning(ctl, 
1309                                       GT_("Service has been restored.\n"));
1310                         close_warning_by_mail(ctl, (struct msgblk *)NULL);
1311                     
1312                     }
1313                 }
1314                 /*
1315                  * Reporting only after the first three
1316                  * consecutive failures, or ten consecutive
1317                  * failures after we have managed to get
1318                  * authorization.
1319                  */
1320                 ctl->authfailcount = 0;
1321             }
1322         }
1323
1324         ctl->errcount = fetches = 0;
1325
1326         /* now iterate over each folder selected */
1327         for (idp = ctl->mailboxes; idp; idp = idp->next)
1328         {
1329             pass = 0;
1330             do {
1331                 dispatches = 0;
1332                 ++pass;
1333
1334                 /* reset timeout, in case we did an IDLE */
1335                 mytimeout = ctl->server.timeout;
1336
1337                 if (outlevel >= O_DEBUG)
1338                 {
1339                     if (idp->id)
1340                         report(stdout, GT_("selecting or re-polling folder %s\n"), idp->id);
1341                     else
1342                         report(stdout, GT_("selecting or re-polling default folder\n"));
1343                 }
1344
1345                 /* compute # of messages and number of new messages waiting */
1346                 stage = STAGE_GETRANGE;
1347                 err = (ctl->server.base_protocol->getrange)(mailserver_socket, ctl, idp->id, &count, &new, &bytes);
1348                 if (err != 0)
1349                     goto cleanUp;
1350
1351                 /* show user how many messages we downloaded */
1352                 if (idp->id)
1353 #ifdef HAVE_SNPRINTF
1354                     (void) snprintf(buf, sizeof(buf),
1355 #else
1356                     (void) sprintf(buf,
1357 #endif /* HAVE_SNPRINTF */
1358                                    GT_("%s at %s (folder %s)"),
1359                                    ctl->remotename, ctl->server.pollname, idp->id);
1360                 else
1361 #ifdef HAVE_SNPRINTF
1362                     (void) snprintf(buf, sizeof(buf),
1363 #else
1364                     (void) sprintf(buf,
1365 #endif /* HAVE_SNPRINTF */
1366                                GT_("%s at %s"),
1367                                    ctl->remotename, ctl->server.pollname);
1368                 if (outlevel > O_SILENT)
1369                 {
1370                     if (count == -1)            /* only used for ETRN */
1371                         report(stdout, GT_("Polling %s\n"), ctl->server.truename);
1372                     else if (count != 0)
1373                     {
1374                         if (new != -1 && (count - new) > 0)
1375                             report_build(stdout, ngettext("%d message (%d %s) for %s", "%d messages (%d %s) for %s", (unsigned long)count),
1376                                   count,
1377                                   count-new, 
1378                                   ngettext("seen", "seen", (unsigned long)count-new),
1379                                   buf);
1380                         else
1381                             report_build(stdout, ngettext("%d message for %s",
1382                                                           "%d messages for %s",
1383                                                           count), 
1384                                   count, buf);
1385                         if (bytes == -1)
1386                             report_complete(stdout, ".\n");
1387                         else
1388                             report_complete(stdout, GT_(" (%d octets).\n"), bytes);
1389                     }
1390                     else
1391                     {
1392                         /* these are pointless in normal daemon mode */
1393                         if (pass == 1 && (run.poll_interval == 0 || outlevel >= O_VERBOSE))
1394                             report(stdout, GT_("No mail for %s\n"), buf); 
1395                     }
1396                 }
1397
1398                 /* very important, this is where we leave the do loop */ 
1399                 if (count == 0)
1400                     break;
1401
1402                 if (check_only)
1403                 {
1404                     if (new == -1 || ctl->fetchall)
1405                         new = count;
1406                     fetches = new;      /* set error status correctly */
1407                     /*
1408                      * There used to be a `goto noerror' here, but this
1409                      * prevented checking of multiple folders.  This
1410                      * comment is a reminder in case I introduced some
1411                      * subtle bug by removing it...
1412                      */
1413                 }
1414                 else if (count > 0)
1415                 {    
1416                     int         i;
1417
1418                     /*
1419                      * Don't trust the message count passed by the server.
1420                      * Without this check, it might be possible to do a
1421                      * DNS-spoofing attack that would pass back a ridiculous 
1422                      * count, and allocate a malloc area that would overlap
1423                      * a portion of the stack.
1424                      */
1425                     if (count > INT_MAX/sizeof(int))
1426                     {
1427                         report(stderr, GT_("bogus message count!"));
1428                         return(PS_PROTOCOL);
1429                     }
1430
1431                     /* 
1432                      * We need the size of each message before it's
1433                      * loaded in order to pass it to the ESMTP SIZE
1434                      * option.  If the protocol has a getsizes method,
1435                      * we presume this means it doesn't get reliable
1436                      * sizes from message fetch responses.
1437                      *
1438                      * If the protocol supports getting sizes of subset of
1439                      * messages, we skip this step now.
1440                      */
1441                     if (proto->getsizes &&
1442                         !(proto->getpartialsizes && NUM_NONZERO(ctl->fetchsizelimit)))
1443                     {
1444                         xalloca(msgsizes, int *, sizeof(int) * count);
1445                         for (i = 0; i < count; i++)
1446                             msgsizes[i] = 0;
1447
1448                         stage = STAGE_GETSIZES;
1449                         err = (proto->getsizes)(mailserver_socket, count, msgsizes);
1450                         if (err != 0)
1451                             goto cleanUp;
1452
1453                         if (bytes == -1)
1454                         {
1455                             bytes = 0;
1456                             for (i = 0; i < count; i++)
1457                                 bytes += msgsizes[i];
1458                         }
1459                     }
1460
1461                     /* read, forward, and delete messages */
1462                     stage = STAGE_FETCH;
1463
1464                     /* fetch in lockstep mode */
1465                     err = fetch_messages(mailserver_socket, ctl, 
1466                                          count, msgsizes,
1467                                          maxfetch,
1468                                          &fetches, &dispatches, &deletions);
1469                     if (err)
1470                         goto cleanUp;
1471
1472                     if (!check_only && ctl->skipped
1473                         && run.poll_interval > 0 && !nodetach)
1474                     {
1475                         clean_skipped_list(&ctl->skipped);
1476                         send_size_warnings(ctl);
1477                     }
1478                 }
1479             } while
1480                   /*
1481                    * Only re-poll if we either had some actual forwards and 
1482                    * either allowed deletions and had no errors.
1483                    * Otherwise it is far too easy to get into infinite loops.
1484                    */
1485                   (dispatches && ctl->server.base_protocol->retry && !ctl->keep && !ctl->errcount);
1486         }
1487
1488     /* no_error: */
1489         /* ordinary termination with no errors -- officially log out */
1490         err = (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
1491         /*
1492          * Hmmmm...arguably this would be incorrect if we had fetches but
1493          * no dispatches (due to oversized messages, etc.)
1494          */
1495         if (err == 0)
1496             err = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
1497         cleanupSockClose(mailserver_socket);
1498         goto closeUp;
1499
1500     cleanUp:
1501         /* we only get here on error */
1502         if (err != 0 && err != PS_SOCKET && err != PS_REPOLL)
1503         {
1504             stage = STAGE_LOGOUT;
1505             (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
1506         }
1507
1508         /* try to clean up all streams */
1509         release_sink(ctl);
1510         smtp_close(ctl, 0);
1511         if (mailserver_socket != -1) {
1512             cleanupSockClose(mailserver_socket);
1513             mailserver_socket = -1;
1514         }
1515         /* If there was a connect timeout, the socket should be closed.
1516          * mailserver_socket_temp contains the socket to close.
1517          */
1518         if (mailserver_socket_temp != -1) {
1519             cleanupSockClose(mailserver_socket_temp);
1520             mailserver_socket_temp = -1;
1521         }
1522     }
1523
1524     msg = (const char *)NULL;   /* sacrifice to -Wall */
1525     switch (err)
1526     {
1527     case PS_SOCKET:
1528         msg = GT_("socket");
1529         break;
1530     case PS_SYNTAX:
1531         msg = GT_("missing or bad RFC822 header");
1532         break;
1533     case PS_IOERR:
1534         msg = GT_("MDA");
1535         break;
1536     case PS_ERROR:
1537         msg = GT_("client/server synchronization");
1538         break;
1539     case PS_PROTOCOL:
1540         msg = GT_("client/server protocol");
1541         break;
1542     case PS_LOCKBUSY:
1543         msg = GT_("lock busy on server");
1544         break;
1545     case PS_SMTP:
1546         msg = GT_("SMTP transaction");
1547         break;
1548     case PS_DNS:
1549         msg = GT_("DNS lookup");
1550         break;
1551     case PS_UNDEFINED:
1552         report(stderr, GT_("undefined error\n"));
1553         break;
1554     }
1555     /* no report on PS_MAXFETCH or PS_UNDEFINED or PS_AUTHFAIL */
1556     if (err==PS_SOCKET || err==PS_SYNTAX
1557                 || err==PS_IOERR || err==PS_ERROR || err==PS_PROTOCOL 
1558                 || err==PS_LOCKBUSY || err==PS_SMTP || err==PS_DNS)
1559     {
1560         char    *stem;
1561
1562         if (phase == FORWARDING_WAIT || phase == LISTENER_WAIT)
1563             stem = GT_("%s error while delivering to SMTP host %s\n");
1564         else
1565             stem = GT_("%s error while fetching from %s\n");
1566         report(stderr, stem, msg, ctl->server.pollname);
1567     }
1568
1569 closeUp:
1570     /* execute wrapup command, if any */
1571     if (ctl->postconnect && (err = system(ctl->postconnect)))
1572     {
1573         report(stderr, GT_("post-connection command failed with status %d\n"), err);
1574         if (err == PS_SUCCESS)
1575             err = PS_SYNTAX;
1576     }
1577
1578     set_timeout(0); /* cancel any pending alarm */
1579     set_signal_handler(SIGALRM, alrmsave);
1580     set_signal_handler(SIGPIPE, pipesave);
1581     return(err);
1582 }
1583
1584 int do_protocol(ctl, proto)
1585 /* retrieve messages from server using given protocol method table */
1586 struct query *ctl;              /* parsed options with merged-in defaults */
1587 const struct method *proto;     /* protocol method table */
1588 {
1589     int err;
1590
1591 #ifndef KERBEROS_V4
1592     if (ctl->server.authenticate == A_KERBEROS_V4)
1593     {
1594         report(stderr, GT_("Kerberos V4 support not linked.\n"));
1595         return(PS_ERROR);
1596     }
1597 #endif /* KERBEROS_V4 */
1598
1599 #ifndef KERBEROS_V5
1600     if (ctl->server.authenticate == A_KERBEROS_V5)
1601     {
1602         report(stderr, GT_("Kerberos V5 support not linked.\n"));
1603         return(PS_ERROR);
1604     }
1605 #endif /* KERBEROS_V5 */
1606
1607     /* lacking methods, there are some options that may fail */
1608     if (!proto->is_old)
1609     {
1610         /* check for unsupported options */
1611         if (ctl->flush) {
1612             report(stderr,
1613                     GT_("Option --flush is not supported with %s\n"),
1614                     proto->name);
1615             return(PS_SYNTAX);
1616         }
1617         else if (ctl->fetchall) {
1618             report(stderr,
1619                     GT_("Option --all is not supported with %s\n"),
1620                     proto->name);
1621             return(PS_SYNTAX);
1622         }
1623     }
1624     if (!proto->getsizes && NUM_SPECIFIED(ctl->limit))
1625     {
1626         report(stderr,
1627                 GT_("Option --limit is not supported with %s\n"),
1628                 proto->name);
1629         return(PS_SYNTAX);
1630     }
1631
1632     /*
1633      * If no expunge limit or we do expunges within the driver,
1634      * then just do one session, passing in any fetchlimit.
1635      */
1636     if ((ctl->keep && !ctl->flush) ||
1637         proto->retry || !NUM_SPECIFIED(ctl->expunge))
1638         return(do_session(ctl, proto, NUM_VALUE_OUT(ctl->fetchlimit)));
1639     /*
1640      * There's an expunge limit, and it isn't handled in the driver itself.
1641      * OK; do multiple sessions, each fetching a limited # of messages.
1642      * Stop if the total count of retrieved messages exceeds ctl->fetchlimit
1643      * (if it was nonzero).
1644      */
1645     else
1646     {
1647         int totalcount = 0; 
1648         int lockouts   = 0;
1649         int expunge    = NUM_VALUE_OUT(ctl->expunge);
1650         int fetchlimit = NUM_VALUE_OUT(ctl->fetchlimit);
1651
1652         do {
1653             if (fetchlimit > 0 && (expunge == 0 || expunge > fetchlimit - totalcount))
1654                 expunge = fetchlimit - totalcount;
1655             err = do_session(ctl, proto, expunge);
1656             totalcount += expunge;
1657             if (NUM_SPECIFIED(ctl->fetchlimit) && totalcount >= fetchlimit)
1658                 break;
1659             if (err != PS_LOCKBUSY)
1660                 lockouts = 0;
1661             else if (lockouts >= MAX_LOCKOUTS)
1662                 break;
1663             else /* err == PS_LOCKBUSY */
1664             {
1665                 /*
1666                  * Allow time for the server lock to release.  if we
1667                  * don't do this, we'll often hit a locked-mailbox
1668                  * condition and fail.
1669                  */
1670                 lockouts++;
1671                 sleep(3);
1672             }
1673         } while
1674             (err == PS_MAXFETCH || err == PS_LOCKBUSY);
1675
1676         return(err);
1677     }
1678 }
1679
1680
1681 /* driver.c ends here */