driver.c
上传用户:xxcykj
上传日期:2007-01-04
资源大小:727k
文件大小:69k
源码类别:

Email客户端

开发平台:

Unix_Linux

  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. #include  "config.h"
  8. #include  <stdio.h>
  9. #include  <setjmp.h>
  10. #include  <errno.h>
  11. #include  <ctype.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. #endif
  19. #if defined(HAVE_UNISTD_H)
  20. #include <unistd.h>
  21. #endif
  22. #if defined(HAVE_STDARG_H)
  23. #include  <stdarg.h>
  24. #else
  25. #include  <varargs.h>
  26. #endif
  27. #if defined(HAVE_SYS_ITIMER_H)
  28. #include <sys/itimer.h>
  29. #endif
  30. #include  <sys/time.h>
  31. #include  <signal.h>
  32. #ifdef HAVE_RES_SEARCH
  33. #include <netdb.h>
  34. #include "mx.h"
  35. #endif /* HAVE_RES_SEARCH */
  36. #ifdef KERBEROS_V4
  37. #ifdef KERBEROS_V5
  38. #include <kerberosIV/des.h>
  39. #include <kerberosIV/krb.h>
  40. #else
  41. #if defined (__bsdi__)
  42. #include <des.h> /* order of includes matters */
  43. #include <krb.h>
  44. #define krb_get_err_text(e) (krb_err_txt[e])
  45. #else
  46. #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__)
  47. #define krb_get_err_text(e) (krb_err_txt[e])
  48. #include <krb.h>
  49. #include <des.h>
  50. #else
  51. #include <krb.h>
  52. #include <des.h>
  53. #endif /* ! defined (__FreeBSD__) */
  54. #endif /* ! defined (__bsdi__) */
  55. #endif /* KERBEROS_V5 */
  56. #include <netinet/in.h>
  57. #include <netdb.h>
  58. #endif /* KERBEROS_V4 */
  59. #ifdef KERBEROS_V5
  60. #include <krb5.h>
  61. #include <com_err.h>
  62. #endif /* KERBEROS_V5 */
  63. #include "i18n.h"
  64. #include "socket.h"
  65. #include "fetchmail.h"
  66. #include "tunable.h"
  67. /* throw types for runtime errors */
  68. #define THROW_TIMEOUT 1 /* server timed out */
  69. #define THROW_SIGPIPE 2 /* SIGPIPE on stream socket */
  70. #ifndef strstr /* glibc-2.1 declares this as a macro */
  71. extern char *strstr(); /* needed on sysV68 R3V7.1. */
  72. #endif /* strstr */
  73. int batchcount; /* count of messages sent in current batch */
  74. flag peek_capable; /* can we peek for better error recovery? */
  75. int pass; /* how many times have we re-polled? */
  76. int stage; /* where are we? */
  77. int phase; /* where are we, for error-logging purposes? */
  78. static const struct method *protocol;
  79. static jmp_buf restart;
  80. char tag[TAGLEN];
  81. static int tagnum;
  82. #define GENSYM (sprintf(tag, "A%04d", ++tagnum % TAGMOD), tag)
  83. static char shroud[PASSWORDLEN]; /* string to shroud in debug output */
  84. static int mytimeout; /* value of nonreponse timeout */
  85. static int timeoutcount; /* count consecutive timeouts */
  86. static int msglen; /* actual message length */
  87. void set_timeout(int timeleft)
  88. /* reset the nonresponse-timeout */
  89. {
  90. #ifndef __EMX__
  91.     struct itimerval ntimeout;
  92.     if (timeleft == 0)
  93. timeoutcount = 0;
  94.     ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
  95.     ntimeout.it_value.tv_sec  = timeleft;
  96.     ntimeout.it_value.tv_usec = 0;
  97.     setitimer(ITIMER_REAL, &ntimeout, (struct itimerval *)NULL);
  98. #endif
  99. }
  100. static void timeout_handler (int signal)
  101. /* handle SIGALRM signal indicating a server timeout */
  102. {
  103.     timeoutcount++;
  104.     longjmp(restart, THROW_TIMEOUT);
  105. }
  106. static void sigpipe_handler (int signal)
  107. /* handle SIGPIPE signal indicating a broken stream socket */
  108. {
  109.     longjmp(restart, THROW_SIGPIPE);
  110. }
  111. static int accept_count, reject_count;
  112. static void map_name(const char *name, struct query *ctl, struct idlist **xmit_names)
  113. /* add given name to xmit_names if it matches declared localnames */
  114. /*   name:  name to map */
  115. /*   ctl:  list of permissible aliases */
  116. /*   xmit_names: list of recipient names parsed out */
  117. {
  118.     const char *lname;
  119.     int off = 0;
  120.     
  121.     lname = idpair_find(&ctl->localnames, name+off);
  122.     if (!lname && ctl->wildcard)
  123. lname = name+off;
  124.     if (lname != (char *)NULL)
  125.     {
  126. if (outlevel >= O_DEBUG)
  127.     report(stdout, _("mapped %s to local %sn"), name, lname);
  128. save_str(xmit_names, lname, XMIT_ACCEPT);
  129. accept_count++;
  130.     }
  131. }
  132. static void find_server_names(const char *hdr,
  133.       struct query *ctl,
  134.       struct idlist **xmit_names)
  135. /* parse names out of a RFC822 header into an ID list */
  136. /*   hdr: RFC822 header in question */
  137. /*   ctl: list of permissible aliases */
  138. /*   xmit_names: list of recipient names parsed out */
  139. {
  140.     if (hdr == (char *)NULL)
  141. return;
  142.     else
  143.     {
  144. char *cp;
  145. for (cp = nxtaddr(hdr);
  146.      cp != NULL;
  147.      cp = nxtaddr(NULL))
  148. {
  149.     char *atsign;
  150.     /*
  151.      * If the name of the user begins with a qmail virtual
  152.      * domain prefix, ignore the prefix.  Doing this here
  153.      * means qvirtual will work either with ordinary name
  154.      * mapping or with a localdomains option.
  155.      */
  156.     if (ctl->server.qvirtual)
  157.     {
  158. int sl = strlen(ctl->server.qvirtual);
  159.  
  160. if (!strncasecmp(cp, ctl->server.qvirtual, sl))
  161.     cp += sl;
  162.     }
  163.     if ((atsign = strchr(cp, '@'))) {
  164. struct idlist *idp;
  165. /*
  166.  * Does a trailing segment of the hostname match something
  167.  * on the localdomains list?  If so, save the whole name
  168.  * and keep going.
  169.  */
  170. for (idp = ctl->server.localdomains; idp; idp = idp->next) {
  171.     char *rhs;
  172.     rhs = atsign + (strlen(atsign) - strlen(idp->id));
  173.     if (rhs > atsign &&
  174. (rhs[-1] == '.' || rhs[-1] == '@') &&
  175. strcasecmp(rhs, idp->id) == 0)
  176.     {
  177. if (outlevel >= O_DEBUG)
  178.     report(stdout, _("passed through %s matching %sn"), 
  179.   cp, idp->id);
  180. save_str(xmit_names, cp, XMIT_ACCEPT);
  181. accept_count++;
  182. goto nomap;
  183.     }
  184. }
  185. /* if we matched a local domain, idp != NULL */
  186. if (!idp)
  187. {
  188.     /*
  189.      * Check to see if the right-hand part is an alias
  190.      * or MX equivalent of the mailserver.  If it's
  191.      * not, skip this name.  If it is, we'll keep
  192.      * going and try to find a mapping to a client name.
  193.      */
  194.     if (!is_host_alias(atsign+1, ctl))
  195.     {
  196. save_str(xmit_names, cp, XMIT_REJECT);
  197. reject_count++;
  198. continue;
  199.     }
  200. }
  201. atsign[0] = '';
  202. map_name(cp, ctl, xmit_names);
  203.     nomap:;
  204.     }
  205. }
  206.     }
  207. }
  208. /*
  209.  * Return zero on a syntactically invalid address, nz on a valid one.
  210.  *
  211.  * This used to be strchr(a, '.'), but it turns out that lines like this
  212.  *
  213.  * Received: from punt-1.mail.demon.net by mailstore for markb@ordern.com
  214.  *          id 938765929:10:27223:2; Fri, 01 Oct 99 08:18:49 GMT
  215.  *
  216.  * are not uncommon.  So now we just check that the following token is
  217.  * not itself an email address.
  218.  */
  219. #define VALID_ADDRESS(a) !strchr(a, '@')
  220. static char *parse_received(struct query *ctl, char *bufp)
  221. /* try to extract real address from the Received line */
  222. /* If a valid Received: line is found, we return the full address in
  223.  * a buffer which can be parsed from nxtaddr().  This is to ansure that
  224.  * the local domain part of the address can be passed along in 
  225.  * find_server_names() if it contains one.
  226.  * Note: We should return a dummy header containing the address 
  227.  * which makes nxtaddr() behave correctly. 
  228.  */
  229. {
  230.     char *base, *ok = (char *)NULL;
  231.     static char rbuf[HOSTLEN + USERNAMELEN + 4]; 
  232.     /*
  233.      * Try to extract the real envelope addressee.  We look here
  234.      * specifically for the mailserver's Received line.
  235.      * Note: this will only work for sendmail, or an MTA that
  236.      * shares sendmail's convention for embedding the envelope
  237.      * address in the Received line.  Sendmail itself only
  238.      * does this when the mail has a single recipient.
  239.      */
  240.     if (outlevel >= O_DEBUG)
  241. report(stdout, _("analyzing Received line:n%s"), bufp);
  242.     /* search for whitepace-surrounded "by" followed by valid address */
  243.     for (base = bufp;  ; base = ok + 2)
  244.     {
  245. if (!(ok = strstr(base, "by")))
  246.     break;
  247. else if (!isspace(ok[-1]) || !isspace(ok[2]))
  248.     continue;
  249. else
  250. {
  251.     char *sp, *tp;
  252.     /* extract space-delimited token after "by" */
  253.     for (sp = ok + 2; isspace(*sp); sp++)
  254. continue;
  255.     tp = rbuf;
  256.     for (; !isspace(*sp); sp++)
  257. *tp++ = *sp;
  258.     *tp = '';
  259.     /* look for valid address */
  260.     if (VALID_ADDRESS(rbuf))
  261. break;
  262.     else
  263. ok = sp - 1; /* arrange to skip this token */
  264. }
  265.     }
  266.     if (ok)
  267.     {
  268. /*
  269.  * If it's a DNS name of the mail server, look for the
  270.  * recipient name after a following "for".  Otherwise
  271.  * punt.
  272.  */
  273. if (is_host_alias(rbuf, ctl))
  274. {
  275.     if (outlevel >= O_DEBUG)
  276. report(stdout, 
  277.       _("line accepted, %s is an alias of the mailservern"), rbuf);
  278. }
  279. else
  280. {
  281.     if (outlevel >= O_DEBUG)
  282. report(stdout, 
  283.       _("line rejected, %s is not an alias of the mailservern"), 
  284.       rbuf);
  285.     return(NULL);
  286. }
  287. /* search for whitepace-surrounded "for" followed by xxxx@yyyy */
  288. for (base = ok + 4 + strlen(rbuf);  ; base = ok + 2)
  289. {
  290.     if (!(ok = strstr(base, "for")))
  291. break;
  292.     else if (!isspace(ok[-1]) || !isspace(ok[3]))
  293. continue;
  294.     else
  295.     {
  296. char *sp, *tp;
  297. /* extract space-delimited token after "for" */
  298. for (sp = ok + 3; isspace(*sp); sp++)
  299.     continue;
  300. tp = rbuf;
  301. for (; !isspace(*sp); sp++)
  302.     *tp++ = *sp;
  303. *tp = '';
  304. if (strchr(rbuf, '@'))
  305.     break;
  306. else
  307.     ok = sp - 1; /* arrange to skip this token */
  308.     }
  309. }
  310. if (ok)
  311. {
  312.     flag want_gt = FALSE;
  313.     char *sp, *tp;
  314.     /* char after "for" could be space or a continuation newline */
  315.     for (sp = ok + 4; isspace(*sp); sp++)
  316. continue;
  317.     tp = rbuf;
  318.     *tp++ = ':'; /* Here is the hack.  This is to be friends */
  319.     *tp++ = ' '; /* with nxtaddr()... */
  320.     if (*sp == '<')
  321.     {
  322. want_gt = TRUE;
  323. sp++;
  324.     }
  325.     while (*sp == '@') /* skip routes */
  326. while (*sp && *sp++ != ':')
  327.     continue;
  328.             while (*sp
  329.                    && (want_gt ? (*sp != '>') : !isspace(*sp))
  330.                    && *sp != ';')
  331. if (!isspace(*sp))
  332.     *tp++ = *sp++;
  333. else
  334. {
  335.     /* uh oh -- whitespace here can't be right! */
  336.     ok = (char *)NULL;
  337.     break;
  338. }
  339.     *tp++ = 'n';
  340.     *tp = '';
  341.     if (strlen(rbuf) <= 3) /* apparently nothing has been found */
  342. ok = NULL;
  343. } else
  344.     ok = (char *)NULL;
  345.     }
  346.     if (!ok)
  347.     {
  348. if (outlevel >= O_DEBUG)
  349.     report(stdout, _("no Received address foundn"));
  350. return(NULL);
  351.     }
  352.     else
  353.     {
  354. if (outlevel >= O_DEBUG) {
  355.     char *lf = rbuf + strlen(rbuf)-1;
  356.     *lf = '';
  357.     if (outlevel >= O_DEBUG)
  358. report(stdout, _("found Received address `%s'n"), rbuf+2);
  359.     *lf = 'n';
  360. }
  361. return(rbuf);
  362.     }
  363. }
  364. /* shared by readheaders and readbody */
  365. static int sizeticker;
  366. static struct msgblk msgblk;
  367. #define EMPTYLINE(s) ((s)[0] == 'r' && (s)[1] == 'n' && (s)[2] == '')
  368. static int readheaders(int sock,
  369.        long fetchlen,
  370.        long reallen,
  371.        struct query *ctl,
  372.        int num)
  373. /* read message headers and ship to SMTP or MDA */
  374. /*   sock: to which the server is connected */
  375. /*   fetchlen: length of message according to fetch response */
  376. /*   reallen: length of message according to getsizes */
  377. /*   ctl: query control record */
  378. /*   num: index of message */
  379. {
  380.     struct addrblk
  381.     {
  382. int offset;
  383. struct addrblk *next;
  384.     };
  385.     struct addrblk *to_addrchain = NULL;
  386.     struct addrblk **to_chainptr = &to_addrchain;
  387.     struct addrblk *resent_to_addrchain = NULL;
  388.     struct addrblk **resent_to_chainptr = &resent_to_addrchain;
  389.     char buf[MSGBUFSIZE+1];
  390.     int from_offs, reply_to_offs, resent_from_offs;
  391.     int app_from_offs, sender_offs, resent_sender_offs;
  392.     int env_offs;
  393.     char *received_for, *rcv, *cp;
  394.     int  n, linelen, oldlen, ch, remaining, skipcount;
  395.     struct idlist  *idp;
  396.     flag no_local_matches = FALSE;
  397.     flag headers_ok, has_nuls;
  398.     int olderrs, good_addresses, bad_addresses;
  399.     sizeticker = 0;
  400.     has_nuls = headers_ok = FALSE;
  401.     msgblk.return_path[0] = '';
  402.     olderrs = ctl->errcount;
  403.     /* read message headers */
  404.     msgblk.reallen = reallen;
  405.     msgblk.headers = received_for = NULL;
  406.     from_offs = reply_to_offs = resent_from_offs = app_from_offs = 
  407. sender_offs = resent_sender_offs = env_offs = -1;
  408.     oldlen = 0;
  409.     msglen = 0;
  410.     skipcount = 0;
  411.     ctl->mimemsg = 0;
  412.     for (remaining = fetchlen; remaining > 0 || protocol->delimited; remaining -= linelen)
  413.     {
  414. char *line;
  415. line = xmalloc(sizeof(buf));
  416. linelen = 0;
  417. line[0] = '';
  418. do {
  419.     set_timeout(mytimeout);
  420.     if ((n = SockRead(sock, buf, sizeof(buf)-1)) == -1) {
  421. set_timeout(0);
  422. free(line);
  423. free(msgblk.headers);
  424. return(PS_SOCKET);
  425.     }
  426.     set_timeout(0);
  427.     linelen += n;
  428.     msglen += n;
  429.     /* lines may not be properly CRLF terminated; fix this for qmail */
  430.     if (ctl->forcecr)
  431.     {
  432. cp = buf + strlen(buf) - 1;
  433. if (*cp == 'n' && (cp == buf || cp[-1] != 'r'))
  434. {
  435.     *cp++ = 'r';
  436.     *cp++ = 'n';
  437.     *cp++ = '';
  438. }
  439.     }
  440.     /*
  441.      * Decode MIME encoded headers. We MUST do this before
  442.      * looking at the Content-Type / Content-Transfer-Encoding
  443.      * headers (RFC 2046).
  444.      */
  445.     if (ctl->mimedecode)
  446. UnMimeHeader(buf);
  447.     line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
  448.     strcat(line, buf);
  449.     /* check for end of headers */
  450.     if (EMPTYLINE(line))
  451.     {
  452. headers_ok = TRUE;
  453. has_nuls = (linelen != strlen(line));
  454. free(line);
  455. goto process_headers;
  456.     }
  457.     /*
  458.      * Check for end of message immediately.  If one of your folders
  459.      * has been mangled, the delimiter may occur directly after the
  460.      * header.
  461.      */
  462.     if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1))
  463.     {
  464. free(line);
  465. has_nuls = (linelen != strlen(line));
  466. goto process_headers;
  467.     }
  468.     /* check for RFC822 continuations */
  469.     set_timeout(mytimeout);
  470.     ch = SockPeek(sock);
  471.     set_timeout(0);
  472. } while
  473.     (ch == ' ' || ch == 't'); /* continuation to next line? */
  474. /* write the message size dots */
  475. if ((outlevel > O_SILENT && outlevel < O_VERBOSE) && linelen > 0)
  476. {
  477.     sizeticker += linelen;
  478.     while (sizeticker >= SIZETICKER)
  479.     {
  480. if (!run.use_syslog)
  481. {
  482.     fputc('.', stdout);
  483.     fflush(stdout);
  484. }
  485. sizeticker -= SIZETICKER;
  486.     }
  487. }
  488. /* we see an ordinary (non-header, non-message-delimiter line */
  489. has_nuls = (linelen != strlen(line));
  490. /*
  491.  * When mail delivered to a multidrop mailbox on the server is
  492.  * addressed to multiple people on the client machine, there
  493.  * will be one copy left in the box for each recipient.  Thus,
  494.  * if the mail is addressed to N people, each recipient will
  495.  * get N copies.
  496.  *
  497.  * Foil this by suppressing all but one copy of a message with
  498.  * a given Message-ID.  Note: This implementation only catches
  499.  * runs of successive identical messages, but that should be
  500.  * good enough. 
  501.  * 
  502.  * The accept_count test ensures that multiple pieces of identical 
  503.  * email, each with a *single* addressee, won't be suppressed.
  504.  */
  505. if (MULTIDROP(ctl) && accept_count > 1 && !strncasecmp(line, "Message-ID:", 11))
  506. {
  507.     if (ctl->lastid && !strcasecmp(ctl->lastid, line))
  508. return(PS_REFUSED);
  509.     else
  510.     {
  511. if (ctl->lastid)
  512.     free(ctl->lastid);
  513. ctl->lastid = strdup(line);
  514.     }
  515. }
  516. /*
  517.  * The University of Washington IMAP server (the reference
  518.  * implementation of IMAP4 written by Mark Crispin) relies
  519.  * on being able to keep base-UID information in a special
  520.  * message at the head of the mailbox.  This message should
  521.  * neither be deleted nor forwarded.
  522.  */
  523. #ifdef POP2_ENABLE
  524. /*
  525.  * We disable this check under POP2 because there's no way to
  526.  * prevent deletion of the message.  So at least we ought to 
  527.  * forward it to the user so he or she will have some clue
  528.  * that things have gone awry.
  529.  */
  530. #if INET6_ENABLE
  531. if (strncmp(protocol->service, "pop2", 4))
  532. #else /* INET6_ENABLE */
  533. if (protocol->port != 109)
  534. #endif /* INET6_ENABLE */
  535. #endif /* POP2_ENABLE */
  536.     if (num == 1 && !strncasecmp(line, "X-IMAP:", 7)) {
  537. free(line);
  538. free(msgblk.headers);
  539. return(PS_RETAINED);
  540.     }
  541. /*
  542.  * This code prevents fetchmail from becoming an accessory after
  543.  * the fact to upstream sendmails with the `E' option on.  It also
  544.  * copes with certain brain-dead POP servers (like NT's) that pass
  545.  * through Unix from_ lines.
  546.  *
  547.  * Either of these bugs can result in a non-RFC822 line at the
  548.  * beginning of the headers.  If fetchmail just passes it
  549.  * through, the client listener may think the message has *no*
  550.  * headers (since the first) line it sees doesn't look
  551.  * RFC822-conformant) and fake up a set.
  552.  *
  553.  * What the user would see in this case is bogus (synthesized)
  554.  * headers, followed by a blank line, followed by the >From, 
  555.  * followed by the real headers, followed by a blank line,
  556.  * followed by text.
  557.  *
  558.  * We forestall this lossage by tossing anything that looks
  559.  * like an escaped or passed-through From_ line in headers.
  560.  * These aren't RFC822 so our conscience is clear...
  561.  */
  562. if (!strncasecmp(line, ">From ", 6) || !strncasecmp(line, "From ", 5))
  563. {
  564.     free(line);
  565.     continue;
  566. }
  567. /*
  568.  * If we see a Status line, it may have been inserted by an MUA
  569.  * on the mail host, or it may have been inserted by the server
  570.  * program after the headers in the transaction stream.  This
  571.  * can actually hose some new-mail notifiers such as xbuffy,
  572.  * which assumes any Status line came from a *local* MDA and
  573.  * therefore indicates that the message has been seen.
  574.  *
  575.  * Some buggy POP servers (including at least the 3.3(20)
  576.  * version of the one distributed with IMAP) insert empty
  577.  * Status lines in the transaction stream; we'll chuck those
  578.  * unconditionally.  Nonempty ones get chucked if the user
  579.  * turns on the dropstatus flag.
  580.  */
  581. {
  582.     char *cp;
  583.     if (!strncasecmp(line, "Status:", 7))
  584. cp = line + 7;
  585.     else if (!strncasecmp(line, "X-Mozilla-Status:", 17))
  586. cp = line + 17;
  587.     else
  588. cp = NULL;
  589.     if (cp) {
  590. while (*cp && isspace(*cp)) cp++;
  591. if (!*cp || ctl->dropstatus)
  592. {
  593.     free(line);
  594.     continue;
  595. }
  596.     }
  597. }
  598. if (ctl->rewrite)
  599.     line = reply_hack(line, ctl->server.truename);
  600. /*
  601.  * OK, this is messy.  If we're forwarding by SMTP, it's the
  602.  * SMTP-receiver's job (according to RFC821, page 22, section
  603.  * 4.1.1) to generate a Return-Path line on final delivery.
  604.  * The trouble is, we've already got one because the
  605.  * mailserver's SMTP thought *it* was responsible for final
  606.  * delivery.
  607.  *
  608.  * Stash away the contents of Return-Path (as modified by reply_hack)
  609.  * for use in generating MAIL FROM later on, then prevent the header
  610.  * from being saved with the others.  In effect, we strip it off here.
  611.  *
  612.  * If the SMTP server conforms to the standards, and fetchmail gets the
  613.  * envelope sender from the Return-Path, the new Return-Path should be
  614.  * exactly the same as the original one.
  615.  *
  616.  * We do *not* want to ignore empty Return-Path headers.  These should
  617.  * be passed through as a way of indicating that a message should
  618.  * not trigger bounces if delivery fails.  What we *do* need to do is
  619.  * make sure we never try to rewrite such a blank Return-Path.  We
  620.  * handle this with a check for <> in the rewrite logic above.
  621.  */
  622. if (!strncasecmp("Return-Path:", line, 12) && (cp = nxtaddr(line)))
  623. {
  624.     strcpy(msgblk.return_path, cp);
  625.     if (!ctl->mda) {
  626. free(line);
  627. continue;
  628.     }
  629. }
  630. if (!msgblk.headers)
  631. {
  632.     oldlen = strlen(line);
  633.     msgblk.headers = xmalloc(oldlen + 1);
  634.     (void) strcpy(msgblk.headers, line);
  635.     free(line);
  636.     line = msgblk.headers;
  637. }
  638. else
  639. {
  640.     int newlen;
  641.     newlen = oldlen + strlen(line);
  642.     msgblk.headers = (char *) realloc(msgblk.headers, newlen + 1);
  643.     if (msgblk.headers == NULL) {
  644. free(line);
  645. return(PS_IOERR);
  646.     }
  647.     strcpy(msgblk.headers + oldlen, line);
  648.     free(line);
  649.     line = msgblk.headers + oldlen;
  650.     oldlen = newlen;
  651. }
  652. if (!strncasecmp("From:", line, 5))
  653.     from_offs = (line - msgblk.headers);
  654. else if (!strncasecmp("Reply-To:", line, 9))
  655.     reply_to_offs = (line - msgblk.headers);
  656. else if (!strncasecmp("Resent-From:", line, 12))
  657.     resent_from_offs = (line - msgblk.headers);
  658. else if (!strncasecmp("Apparently-From:", line, 16))
  659.     app_from_offs = (line - msgblk.headers);
  660. else if (!strncasecmp("Sender:", line, 7))
  661.     sender_offs = (line - msgblk.headers);
  662. else if (!strncasecmp("Resent-Sender:", line, 14))
  663.     resent_sender_offs = (line - msgblk.headers);
  664.   else if (!strncasecmp("Message-Id:", buf, 11))
  665. {
  666.     if (ctl->server.uidl)
  667.       {
  668.         char id[IDLEN+1];
  669. buf[IDLEN+12] = 0; /* prevent stack overflow */
  670.   sscanf(buf+12, "%s", id);
  671.           if (!str_find( &ctl->newsaved, num))
  672. {
  673.       struct idlist *new = save_str(&ctl->newsaved,id,UID_SEEN);
  674.     new->val.status.num = num;
  675. }
  676.       }
  677.   }
  678. else if (!MULTIDROP(ctl))
  679.     continue;
  680. else if (!strncasecmp("To:", line, 3)
  681. || !strncasecmp("Cc:", line, 3)
  682. || !strncasecmp("Bcc:", line, 4)
  683. || !strncasecmp("Apparently-To:", line, 14))
  684. {
  685.     *to_chainptr = xmalloc(sizeof(struct addrblk));
  686.     (*to_chainptr)->offset = (line - msgblk.headers);
  687.     to_chainptr = &(*to_chainptr)->next; 
  688.     *to_chainptr = NULL;
  689. }
  690. else if (!strncasecmp("Resent-To:", line, 10)
  691. || !strncasecmp("Resent-Cc:", line, 10)
  692. || !strncasecmp("Resent-Bcc:", line, 11))
  693. {
  694.     *resent_to_chainptr = xmalloc(sizeof(struct addrblk));
  695.     (*resent_to_chainptr)->offset = (line - msgblk.headers);
  696.     resent_to_chainptr = &(*resent_to_chainptr)->next; 
  697.     *resent_to_chainptr = NULL;
  698. }
  699. else if (ctl->server.envelope != STRING_DISABLED)
  700. {
  701.     if (ctl->server.envelope 
  702. && strcasecmp(ctl->server.envelope, "Received"))
  703.     {
  704. if (env_offs == -1 && !strncasecmp(ctl->server.envelope,
  705. line,
  706. strlen(ctl->server.envelope)))
  707. {
  708.     if (skipcount++ != ctl->server.envskip)
  709. continue;
  710.     env_offs = (line - msgblk.headers);
  711. }    
  712.     }
  713.     else if (!received_for && !strncasecmp("Received:", line, 9))
  714.     {
  715. if (skipcount++ != ctl->server.envskip)
  716.     continue;
  717. received_for = parse_received(ctl, line);
  718.     }
  719. }
  720.     }
  721.  process_headers:
  722.     /*
  723.      * We want to detect this early in case there are so few headers that the
  724.      * dispatch logic barfs.
  725.      */
  726.     if (!headers_ok)
  727.     {
  728. if (outlevel > O_SILENT)
  729.     report(stdout,
  730.    _("message delimiter found while scanning headersn"));
  731.     }
  732.     /*
  733.      * Hack time.  If the first line of the message was blank, with no headers
  734.      * (this happens occasionally due to bad gatewaying software) cons up
  735.      * a set of fake headers.  
  736.      *
  737.      * If you modify the fake header template below, be sure you don't
  738.      * make either From or To address @-less, otherwise the reply_hack
  739.      * logic will do bad things.
  740.      */
  741.     if (msgblk.headers == (char *)NULL)
  742.     {
  743. #ifdef HAVE_SNPRINTF
  744. snprintf(buf, sizeof(buf),
  745. #else
  746. sprintf(buf, 
  747. #endif /* HAVE_SNPRINTF */
  748. "From: FETCHMAIL-DAEMONrnTo: %s@%srnSubject: Headerless mail from %s's mailbox on %srn",
  749. user, fetchmailhost, ctl->remotename, ctl->server.truename);
  750. msgblk.headers = xstrdup(buf);
  751.     }
  752.     /*
  753.      * We can now process message headers before reading the text.
  754.      * In fact we have to, as this will tell us where to forward to.
  755.      */
  756.     /* Check for MIME headers indicating possible 8-bit data */
  757.     ctl->mimemsg = MimeBodyType(msgblk.headers, ctl->mimedecode);
  758. #ifdef SDPS_ENABLE
  759.     if (ctl->server.sdps && sdps_envfrom)
  760.     {
  761. /* We have the real envelope return-path, stored out of band by
  762.  * SDPS - that's more accurate than any header is going to be.
  763.  */
  764. strcpy(msgblk.return_path, sdps_envfrom);
  765. free(sdps_envfrom);
  766.     } else
  767. #endif /* SDPS_ENABLE */
  768.     /*
  769.      * If there is a Return-Path address on the message, this was
  770.      * almost certainly the MAIL FROM address given the originating
  771.      * sendmail.  This is the best thing to use for logging the
  772.      * message origin (it sets up the right behavior for bounces and
  773.      * mailing lists).  Otherwise, fall down to the next available 
  774.      * envelope address (which is the most probable real sender).
  775.      * *** The order is important! ***
  776.      * This is especially useful when receiving mailing list
  777.      * messages in multidrop mode.  if a local address doesn't
  778.      * exist, the bounce message won't be returned blindly to the 
  779.      * author or to the list itself but rather to the list manager
  780.      * (ex: specified by "Sender:") which is much less annoying.  This 
  781.      * is true for most mailing list packages.
  782.      */
  783.     if( !msgblk.return_path[0] ){
  784. char *ap = NULL;
  785. if (resent_sender_offs >= 0 && (ap = nxtaddr(msgblk.headers + resent_sender_offs)));
  786. else if (sender_offs >= 0 && (ap = nxtaddr(msgblk.headers + sender_offs)));
  787. else if (resent_from_offs >= 0 && (ap = nxtaddr(msgblk.headers + resent_from_offs)));
  788. else if (from_offs >= 0 && (ap = nxtaddr(msgblk.headers + from_offs)));
  789. else if (reply_to_offs >= 0 && (ap = nxtaddr(msgblk.headers + reply_to_offs)));
  790. else if (app_from_offs >= 0 && (ap = nxtaddr(msgblk.headers + app_from_offs)));
  791. if (ap) strcpy( msgblk.return_path, ap );
  792.     }
  793.     /* cons up a list of local recipients */
  794.     msgblk.recipients = (struct idlist *)NULL;
  795.     accept_count = reject_count = 0;
  796.     /* is this a multidrop box? */
  797.     if (MULTIDROP(ctl))
  798.     {
  799. #ifdef SDPS_ENABLE
  800. if (ctl->server.sdps && sdps_envto)
  801. {
  802.     /* We have the real envelope recipient, stored out of band by
  803.      * SDPS - that's more accurate than any header is going to be.
  804.      */
  805.     find_server_names(sdps_envto, ctl, &msgblk.recipients);
  806.     free(sdps_envto);
  807. } else
  808. #endif /* SDPS_ENABLE */ 
  809. if (env_offs > -1)     /* We have the actual envelope addressee */
  810.     find_server_names(msgblk.headers + env_offs, ctl, &msgblk.recipients);
  811. else if (received_for)
  812.     /*
  813.      * We have the Received for addressee.  
  814.      * It has to be a mailserver address, or we
  815.      * wouldn't have got here.
  816.      * We use find_server_names() to let local 
  817.      * hostnames go through.
  818.      */
  819.     find_server_names(received_for, ctl, &msgblk.recipients);
  820. else
  821. {
  822.     /*
  823.      * We haven't extracted the envelope address.
  824.      * So check all the "Resent-To" header addresses if 
  825.      * they exist.  If and only if they don't, consider
  826.      * the "To" addresses.
  827.      */
  828.     register struct addrblk *nextptr;
  829.     if (resent_to_addrchain) {
  830. /* delete the "To" chain and substitute it 
  831.  * with the "Resent-To" list 
  832.  */
  833. while (to_addrchain) {
  834.     nextptr = to_addrchain->next;
  835.     free(to_addrchain);
  836.     to_addrchain = nextptr;
  837. }
  838. to_addrchain = resent_to_addrchain;
  839. resent_to_addrchain = NULL;
  840.     }
  841.     /* now look for remaining adresses */
  842.     while (to_addrchain) {
  843. find_server_names(msgblk.headers+to_addrchain->offset, ctl, &msgblk.recipients);
  844. nextptr = to_addrchain->next;
  845. free(to_addrchain);
  846. to_addrchain = nextptr;
  847.     }
  848. }
  849. if (!accept_count)
  850. {
  851.     no_local_matches = TRUE;
  852.     save_str(&msgblk.recipients, run.postmaster, XMIT_ACCEPT);
  853.     if (outlevel >= O_DEBUG)
  854. report(stdout,
  855.       _("no local matches, forwarding to %sn"),
  856.       run.postmaster);
  857. }
  858.     }
  859.     else /* it's a single-drop box, use first localname */
  860. save_str(&msgblk.recipients, ctl->localnames->id, XMIT_ACCEPT);
  861.     /*
  862.      * Time to either address the message or decide we can't deliver it yet.
  863.      */
  864.     if (ctl->errcount > olderrs) /* there were DNS errors above */
  865.     {
  866. if (outlevel >= O_DEBUG)
  867.     report(stdout,
  868.    _("forwarding and deletion suppressed due to DNS errorsn"));
  869. free(msgblk.headers);
  870. free_str_list(&msgblk.recipients);
  871. return(PS_TRANSIENT);
  872.     }
  873.     else
  874.     {
  875. /* set up stuffline() so we can deliver the message body through it */ 
  876. if ((n = open_sink(ctl, &msgblk,
  877.    &good_addresses, &bad_addresses)) != PS_SUCCESS)
  878. {
  879.     free(msgblk.headers);
  880.     free_str_list(&msgblk.recipients);
  881.     return(n);
  882. }
  883.     }
  884.     n = 0;
  885.     /*
  886.      * Some server/sendmail combinations cause problems when our
  887.      * synthetic Received line is before the From header.  Cope
  888.      * with this...
  889.      */
  890.     if ((rcv = strstr(msgblk.headers, "Received:")) == (char *)NULL)
  891. rcv = msgblk.headers;
  892.     /* handle ">Received:" lines too */
  893.     while (rcv > msgblk.headers && rcv[-1] != 'n')
  894. rcv--;
  895.     if (rcv > msgblk.headers)
  896.     {
  897. char c = *rcv;
  898. *rcv = '';
  899. n = stuffline(ctl, msgblk.headers);
  900. *rcv = c;
  901.     }
  902.     if (!run.invisible && n != -1)
  903.     {
  904. /* utter any per-message Received information we need here */
  905. sprintf(buf, "Received: from %srn", ctl->server.truename);
  906. n = stuffline(ctl, buf);
  907. if (n != -1)
  908. {
  909.     /*
  910.      * This header is technically invalid under RFC822.
  911.      * POP3, IMAP, etc. are not legal mail-parameter values.
  912.      *
  913.      * We used to include ctl->remotename in this log line,
  914.      * but this can be secure information that would be bad
  915.      * to reveal.
  916.      */
  917.     sprintf(buf, "tby %s with %s (fetchmail-%s)rn",
  918.     fetchmailhost,
  919.     protocol->name,
  920.     VERSION);
  921.     n = stuffline(ctl, buf);
  922.     if (n != -1)
  923.     {
  924. buf[0] = 't';
  925. if (good_addresses == 0)
  926. {
  927.     sprintf(buf+1, 
  928.     "for %s@%s (by default); ",
  929.     user, ctl->destaddr);
  930. }
  931. else if (good_addresses == 1)
  932. {
  933.     for (idp = msgblk.recipients; idp; idp = idp->next)
  934. if (idp->val.status.mark == XMIT_ACCEPT)
  935.     break; /* only report first address */
  936.     if (strchr(idp->id, '@'))
  937. sprintf(buf+1, "for %s", idp->id);
  938.     else
  939. /*
  940.  * This could be a bit misleading, as destaddr is
  941.  * the forwarding host rather than the actual 
  942.  * destination.  Most of the time they coincide.
  943.  */
  944. sprintf(buf+1, "for %s@%s", idp->id, ctl->destaddr);
  945.     sprintf(buf+strlen(buf), " (%s); ",
  946.     MULTIDROP(ctl) ? "multi-drop" : "single-drop");
  947. }
  948. else
  949.     buf[1] = '';
  950. strcat(buf, rfc822timestamp());
  951. strcat(buf, "rn");
  952. n = stuffline(ctl, buf);
  953.     }
  954. }
  955.     }
  956.     if (n != -1)
  957. n = stuffline(ctl, rcv); /* ship out rest of msgblk.headers */
  958.     if (n == -1)
  959.     {
  960. report(stdout, _("writing RFC822 msgblk.headersn"));
  961. release_sink(ctl);
  962. free(msgblk.headers);
  963. free_str_list(&msgblk.recipients);
  964. return(PS_IOERR);
  965.     }
  966.     else if ((run.poll_interval == 0 || nodetach) && outlevel >= O_VERBOSE)
  967. fputs("#", stderr);
  968.     /* write error notifications */
  969.     if (no_local_matches || has_nuls || bad_addresses)
  970.     {
  971. int errlen = 0;
  972. char errhd[USERNAMELEN + POPBUFSIZE], *errmsg;
  973. errmsg = errhd;
  974. (void) strcpy(errhd, "X-Fetchmail-Warning: ");
  975. if (no_local_matches)
  976. {
  977.     if (reject_count != 1)
  978. strcat(errhd, _("no recipient addresses matched declared local names"));
  979.     else
  980.     {
  981. for (idp = msgblk.recipients; idp; idp = idp->next)
  982.     if (idp->val.status.mark == XMIT_REJECT)
  983. break;
  984. sprintf(errhd+strlen(errhd), _("recipient address %s didn't match any local name"), idp->id);
  985.     }
  986. }
  987. if (has_nuls)
  988. {
  989.     if (errhd[sizeof("X-Fetchmail-Warning: ")])
  990. strcat(errhd, "; ");
  991.     strcat(errhd, _("message has embedded NULs"));
  992. }
  993. if (bad_addresses)
  994. {
  995.     if (errhd[sizeof("X-Fetchmail-Warning: ")])
  996. strcat(errhd, "; ");
  997.     strcat(errhd, _("SMTP listener rejected local recipient addresses: "));
  998.     errlen = strlen(errhd);
  999.     for (idp = msgblk.recipients; idp; idp = idp->next)
  1000. if (idp->val.status.mark == XMIT_RCPTBAD)
  1001.     errlen += strlen(idp->id) + 2;
  1002.     xalloca(errmsg, char *, errlen+3);
  1003.     (void) strcpy(errmsg, errhd);
  1004.     for (idp = msgblk.recipients; idp; idp = idp->next)
  1005. if (idp->val.status.mark == XMIT_RCPTBAD)
  1006. {
  1007.     strcat(errmsg, idp->id);
  1008.     if (idp->next)
  1009. strcat(errmsg, ", ");
  1010. }
  1011. }
  1012. strcat(errmsg, "rn");
  1013. /* ship out the error line */
  1014. stuffline(ctl, errmsg);
  1015.     }
  1016.     /* issue the delimiter line */
  1017.     cp = buf;
  1018.     *cp++ = 'r';
  1019.     *cp++ = 'n';
  1020.     *cp++ = '';
  1021.     stuffline(ctl, buf);
  1022.     free(msgblk.headers);
  1023.     free_str_list(&msgblk.recipients);
  1024.     return(headers_ok ? PS_SUCCESS : PS_TRUNCATED);
  1025. }
  1026. static int readbody(int sock, struct query *ctl, flag forward, int len)
  1027. /* read and dispose of a message body presented on sock */
  1028. /*   ctl: query control record */
  1029. /*   sock: to which the server is connected */
  1030. /*   len: length of message */
  1031. /*   forward: TRUE to forward */
  1032. {
  1033.     int linelen;
  1034.     unsigned char buf[MSGBUFSIZE+4];
  1035.     unsigned char *inbufp = buf;
  1036.     flag issoftline = FALSE;
  1037.     /*
  1038.      * Pass through the text lines in the body.
  1039.      *
  1040.      * Yes, this wants to be ||, not &&.  The problem is that in the most
  1041.      * important delimited protocol, POP3, the length is not reliable.
  1042.      * As usual, the problem is Microsoft brain damage; see FAQ item S2.
  1043.      * So, for delimited protocols we need to ignore the length here and
  1044.      * instead drop out of the loop with a break statement when we see
  1045.      * the message delimiter.
  1046.      */
  1047.     while (protocol->delimited || len > 0)
  1048.     {
  1049. set_timeout(mytimeout);
  1050. if ((linelen = SockRead(sock, inbufp, sizeof(buf)-4-(inbufp-buf)))==-1)
  1051. {
  1052.     set_timeout(0);
  1053.     release_sink(ctl);
  1054.     return(PS_SOCKET);
  1055. }
  1056. set_timeout(0);
  1057. /* write the message size dots */
  1058. if (linelen > 0)
  1059. {
  1060.     sizeticker += linelen;
  1061.     while (sizeticker >= SIZETICKER)
  1062.     {
  1063. if ((run.poll_interval == 0 || nodetach) && outlevel > O_SILENT)
  1064. {
  1065.     fputc('.', stdout);
  1066.     fflush(stdout);
  1067. }
  1068. sizeticker -= SIZETICKER;
  1069.     }
  1070. }
  1071. len -= linelen;
  1072. /* check for end of message */
  1073. if (protocol->delimited && *inbufp == '.')
  1074. {
  1075.     if (inbufp[1] == 'r' && inbufp[2] == 'n' && inbufp[3] == '')
  1076. break;
  1077.     else if (inbufp[1] == 'n' && inbufp[2] == '')
  1078. break;
  1079.     else
  1080. msglen--; /* subtract the size of the dot escape */
  1081. }
  1082. msglen += linelen;
  1083. if (ctl->mimedecode && (ctl->mimemsg & MSG_NEEDS_DECODE)) {
  1084.     issoftline = UnMimeBodyline(&inbufp, protocol->delimited, issoftline);
  1085.     if (issoftline && (sizeof(buf)-1-(inbufp-buf) < 200))
  1086.     {
  1087. /*
  1088.  * Soft linebreak, but less than 200 bytes left in
  1089.  * input buffer. Rather than doing a buffer overrun,
  1090.  * ignore the soft linebreak, NL-terminate data and
  1091.  * deliver what we have now.
  1092.  * (Who writes lines longer than 2K anyway?)
  1093.  */
  1094. *inbufp = 'n'; *(inbufp+1) = '';
  1095. issoftline = 0;
  1096.     }
  1097. }
  1098. /* ship out the text line */
  1099. if (forward && (!issoftline))
  1100. {
  1101.     int n;
  1102.     inbufp = buf;
  1103.     /* guard against very long lines */
  1104.     buf[MSGBUFSIZE+1] = 'r';
  1105.     buf[MSGBUFSIZE+2] = 'n';
  1106.     buf[MSGBUFSIZE+3] = '';
  1107.     n = stuffline(ctl, buf);
  1108.     if (n < 0)
  1109.     {
  1110. report(stdout, _("writing message textn"));
  1111. release_sink(ctl);
  1112. return(PS_IOERR);
  1113.     }
  1114.     else if (outlevel >= O_VERBOSE)
  1115.     {
  1116. fputc('*', stdout);
  1117. fflush(stdout);
  1118.     }
  1119. }
  1120.     }
  1121.     return(PS_SUCCESS);
  1122. }
  1123. #ifdef KERBEROS_V4
  1124. int
  1125. kerberos_auth (socket, canonical) 
  1126. /* authenticate to the server host using Kerberos V4 */
  1127. int socket; /* socket to server host */
  1128. #if defined(__FreeBSD__) || defined(__OpenBSD__)
  1129. char *canonical; /* server name */
  1130. #else
  1131. const char *canonical; /* server name */
  1132. #endif
  1133. {
  1134.     char * host_primary;
  1135.     KTEXT ticket;
  1136.     MSG_DAT msg_data;
  1137.     CREDENTIALS cred;
  1138.     Key_schedule schedule;
  1139.     int rem;
  1140.   
  1141.     xalloca(ticket, KTEXT, sizeof (KTEXT_ST));
  1142.     rem = (krb_sendauth (0L, socket, ticket, "pop",
  1143.  canonical,
  1144.  ((char *) (krb_realmofhost (canonical))),
  1145.  ((unsigned long) 0),
  1146.  (&msg_data),
  1147.  (&cred),
  1148.  (schedule),
  1149.  ((struct sockaddr_in *) 0),
  1150.  ((struct sockaddr_in *) 0),
  1151.  "KPOPV0.1"));
  1152.     if (rem != KSUCCESS)
  1153.     {
  1154. report(stderr, _("kerberos error %sn"), (krb_get_err_text (rem)));
  1155. return (PS_AUTHFAIL);
  1156.     }
  1157.     return (0);
  1158. }
  1159. #endif /* KERBEROS_V4 */
  1160. #ifdef KERBEROS_V5
  1161. static int kerberos5_auth(socket, canonical)
  1162. /* authenticate to the server host using Kerberos V5 */
  1163. int socket;             /* socket to server host */
  1164. const char *canonical;  /* server name */
  1165. {
  1166.     krb5_error_code retval;
  1167.     krb5_context context;
  1168.     krb5_ccache ccdef;
  1169.     krb5_principal client = NULL, server = NULL;
  1170.     krb5_error *err_ret = NULL;
  1171.     krb5_auth_context auth_context = NULL;
  1172.     krb5_init_context(&context);
  1173.     krb5_init_ets(context);
  1174.     krb5_auth_con_init(context, &auth_context);
  1175.     if (retval = krb5_cc_default(context, &ccdef)) {
  1176.         report(stderr, "krb5_cc_default: %sn", error_message(retval));
  1177.         return(PS_ERROR);
  1178.     }
  1179.     if (retval = krb5_cc_get_principal(context, ccdef, &client)) {
  1180.         report(stderr, "krb5_cc_get_principal: %sn", error_message(retval));
  1181.         return(PS_ERROR);
  1182.     }
  1183.     if (retval = krb5_sname_to_principal(context, canonical, "pop",
  1184.            KRB5_NT_UNKNOWN,
  1185.            &server)) {
  1186.         report(stderr, "krb5_sname_to_principal: %sn", error_message(retval));
  1187.         return(PS_ERROR);
  1188.     }
  1189.     retval = krb5_sendauth(context, &auth_context, (krb5_pointer) &socket,
  1190.          "KPOPV1.0", client, server,
  1191.          AP_OPTS_MUTUAL_REQUIRED,
  1192.          NULL,  /* no data to checksum */
  1193.          0,   /* no creds, use ccache instead */
  1194.          ccdef,
  1195.          &err_ret, 0,
  1196.          NULL); /* don't need reply */
  1197.     krb5_free_principal(context, server);
  1198.     krb5_free_principal(context, client);
  1199.     krb5_auth_con_free(context, auth_context);
  1200.     if (retval) {
  1201. #ifdef HEIMDAL
  1202.       if (err_ret && err_ret->e_text) {
  1203.           report(stderr, _("krb5_sendauth: %s [server says '%*s'] n"),
  1204.                  error_message(retval),
  1205.                  err_ret->e_text);
  1206. #else
  1207.       if (err_ret && err_ret->text.length) {
  1208.           report(stderr, _("krb5_sendauth: %s [server says '%*s'] n"),
  1209.  error_message(retval),
  1210.  err_ret->text.length,
  1211.  err_ret->text.data);
  1212. #endif
  1213.   krb5_free_error(context, err_ret);
  1214.       } else
  1215.           report(stderr, "krb5_sendauth: %sn", error_message(retval));
  1216.       return(PS_ERROR);
  1217.     }
  1218.     return 0;
  1219. }
  1220. #endif /* KERBEROS_V5 */
  1221. static void clean_skipped_list(struct idlist **skipped_list)
  1222. /* struct "idlist" contains no "prev" ptr; we must remove unused items first */
  1223. {
  1224.     struct idlist *current=NULL, *prev=NULL, *tmp=NULL, *head=NULL;
  1225.     prev = current = head = *skipped_list;
  1226.     if (!head)
  1227. return;
  1228.     do
  1229.     {
  1230. /* if item has no reference, remove it */
  1231. if (current && current->val.status.mark == 0)
  1232. {
  1233.     if (current == head) /* remove first item (head) */
  1234.     {
  1235. head = current->next;
  1236. if (current->id) free(current->id);
  1237. free(current);
  1238. prev = current = head;
  1239.     }
  1240.     else /* remove middle/last item */
  1241.     {
  1242. tmp = current->next;
  1243. prev->next = tmp;
  1244. if (current->id) free(current->id);
  1245. free(current);
  1246. current = tmp;
  1247.     }
  1248. }
  1249. else /* skip this item */
  1250. {
  1251.     prev = current;
  1252.     current = current->next;
  1253. }
  1254.     } while(current);
  1255.     *skipped_list = head;
  1256. }
  1257. static void send_size_warnings(struct query *ctl)
  1258. /* send warning mail with skipped msg; reset msg count when user notified */
  1259. {
  1260.     int size, nbr;
  1261.     int msg_to_send = FALSE;
  1262.     struct idlist *head=NULL, *current=NULL;
  1263.     int max_warning_poll_count;
  1264. #define OVERHD "Subject: Fetchmail oversized-messages warning.rnrnThe following oversized messages remain on the mail server %s:"
  1265.     head = ctl->skipped;
  1266.     if (!head)
  1267. return;
  1268.     /* don't start a notification message unless we need to */
  1269.     for (current = head; current; current = current->next)
  1270. if (current->val.status.num == 0 && current->val.status.mark)
  1271.     msg_to_send = TRUE;
  1272.     if (!msg_to_send)
  1273. return;
  1274.     /*
  1275.      * There's no good way to recover if we can't send notification mail, 
  1276.      * but it's not a disaster, either, since the skipped mail will not
  1277.      * be deleted.
  1278.      */
  1279.     if (open_warning_by_mail(ctl, (struct msgblk *)NULL))
  1280. return;
  1281.     stuff_warning(ctl, OVERHD, ctl->server.pollname);
  1282.  
  1283.     if (run.poll_interval == 0)
  1284. max_warning_poll_count = 0;
  1285.     else
  1286. max_warning_poll_count = ctl->warnings/run.poll_interval;
  1287.     /* parse list of skipped msg, adding items to the mail */
  1288.     for (current = head; current; current = current->next)
  1289.     {
  1290. if (current->val.status.num == 0 && current->val.status.mark)
  1291. {
  1292.     nbr = current->val.status.mark;
  1293.     size = atoi(current->id);
  1294.     stuff_warning(ctl, 
  1295.     _("t%d msg %d octets long skipped by fetchmail.n"),
  1296.     nbr, size);
  1297. }
  1298. current->val.status.num++;
  1299. current->val.status.mark = 0;
  1300. if (current->val.status.num >= max_warning_poll_count)
  1301.     current->val.status.num = 0;
  1302.     }
  1303.     close_warning_by_mail(ctl, (struct msgblk *)NULL);
  1304. #undef OVERHD
  1305. }
  1306. static int do_session(ctl, proto, maxfetch)
  1307. /* retrieve messages from server using given protocol method table */
  1308. struct query *ctl; /* parsed options with merged-in defaults */
  1309. const struct method *proto; /* protocol method table */
  1310. const int maxfetch; /* maximum number of messages to fetch */
  1311. {
  1312.     int js;
  1313. #ifdef HAVE_VOLATILE
  1314.     volatile int ok, mailserver_socket = -1; /* pacifies -Wall */
  1315. #else
  1316.     int ok, mailserver_socket = -1;
  1317. #endif /* HAVE_VOLATILE */
  1318.     const char *msg;
  1319.     void (*pipesave)(int);
  1320.     void (*alrmsave)(int);
  1321.     struct idlist *current=NULL, *tmp=NULL;
  1322.     protocol = proto;
  1323.     ctl->server.base_protocol = protocol;
  1324.     pass = 0;
  1325.     tagnum = 0;
  1326.     tag[0] = ''; /* nuke any tag hanging out from previous query */
  1327.     ok = 0;
  1328.     /* set up the server-nonresponse timeout */
  1329.     alrmsave = signal(SIGALRM, timeout_handler);
  1330.     mytimeout = ctl->server.timeout;
  1331.     /* set up the broken-pipe timeout */
  1332.     pipesave = signal(SIGPIPE, sigpipe_handler);
  1333.     if ((js = setjmp(restart)))
  1334.     {
  1335. #ifdef HAVE_SIGPROCMASK
  1336. /*
  1337.  * Don't rely on setjmp() to restore the blocked-signal mask.
  1338.  * It does this under BSD but is required not to under POSIX.
  1339.  *
  1340.  * If your Unix doesn't have sigprocmask, better hope it has
  1341.  * BSD-like behavior.  Otherwise you may see fetchmail get
  1342.  * permanently wedged after a second timeout on a bad read,
  1343.  * because alarm signals were blocked after the first.
  1344.  */
  1345. sigset_t allsigs;
  1346. sigfillset(&allsigs);
  1347. sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
  1348. #endif /* HAVE_SIGPROCMASK */
  1349. if (js == THROW_SIGPIPE)
  1350. {
  1351.     report(stdout,
  1352.    _("SIGPIPE thrown from an MDA or a stream socket error"));
  1353.     ok = PS_SOCKET;
  1354. }
  1355. else if (js == THROW_TIMEOUT)
  1356. {
  1357.     if (phase == OPEN_WAIT)
  1358. report(stdout,
  1359.        _("timeout after %d seconds waiting to connect to server %s.n"),
  1360.        ctl->server.timeout, ctl->server.pollname);
  1361.     else if (phase == SERVER_WAIT)
  1362. report(stdout,
  1363.        _("timeout after %d seconds waiting for server %s.n"),
  1364.        ctl->server.timeout, ctl->server.pollname);
  1365.     else if (phase == FORWARDING_WAIT)
  1366. report(stdout,
  1367.        _("timeout after %d seconds waiting for %s.n"),
  1368.        ctl->server.timeout,
  1369.        ctl->mda ? "MDA" : "SMTP");
  1370.     else if (phase == LISTENER_WAIT)
  1371. report(stdout,
  1372.        _("timeout after %d seconds waiting for listener to respond.n"));
  1373.     else
  1374. report(stdout, 
  1375.        _("timeout after %d seconds.n"), ctl->server.timeout);
  1376.     /*
  1377.      * If we've exceeded our threshold for consecutive timeouts, 
  1378.      * try to notify the user, then mark the connection wedged.
  1379.      */
  1380.     if (timeoutcount > MAX_TIMEOUTS 
  1381. && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
  1382.     {
  1383. stuff_warning(ctl,
  1384.       _("Subject: fetchmail sees repeated timeoutsrn"));
  1385. stuff_warning(ctl,
  1386.       _("Fetchmail saw more than %d timeouts while attempting to get mail from %s@%s.rn"), 
  1387.       MAX_TIMEOUTS,
  1388.       ctl->remotename,
  1389.       ctl->server.truename);
  1390. stuff_warning(ctl, 
  1391.     _("This could mean that your mailserver is stuck, or that your SMTPrn" 
  1392.     "server is wedged, or that your mailbox file on the server has beenrn" 
  1393.     "corrupted by a server error.  You can run `fetchmail -v -v' torn" 
  1394.     "diagnose the problem.rnrn" 
  1395.     "Fetchmail won't poll this mailbox again until you restart it.rn"));
  1396. close_warning_by_mail(ctl, (struct msgblk *)NULL);
  1397. ctl->wedged = TRUE;
  1398.     }
  1399.     ok = PS_ERROR;
  1400. }
  1401. /* try to clean up all streams */
  1402. release_sink(ctl);
  1403. if (ctl->smtp_socket != -1)
  1404.     SockClose(ctl->smtp_socket);
  1405. if (mailserver_socket != -1)
  1406.     SockClose(mailserver_socket);
  1407.     }
  1408.     else
  1409.     {
  1410. char buf[POPBUFSIZE+1], *realhost;
  1411. int len, num, count, new, bytes, deletions = 0, *msgsizes = NULL;
  1412. #if INET6_ENABLE
  1413. int fetches, dispatches, oldphase;
  1414. #else /* INET6_ENABLE */
  1415. int port, fetches, dispatches, oldphase;
  1416. #endif /* INET6_ENABLE */
  1417. struct idlist *idp;
  1418. /* execute pre-initialization command, if any */
  1419. if (ctl->preconnect && (ok = system(ctl->preconnect)))
  1420. {
  1421.     report(stderr, 
  1422.    _("pre-connection command failed with status %dn"), ok);
  1423.     ok = PS_SYNTAX;
  1424.     goto closeUp;
  1425. }
  1426. /* open a socket to the mail server */
  1427. oldphase = phase;
  1428. phase = OPEN_WAIT;
  1429. set_timeout(mytimeout);
  1430. #if !INET6_ENABLE
  1431. #ifdef SSL_ENABLE
  1432. port = ctl->server.port ? ctl->server.port : ( ctl->use_ssl ? protocol->sslport : protocol->port );
  1433. #else
  1434. port = ctl->server.port ? ctl->server.port : protocol->port;
  1435. #endif
  1436. #endif /* !INET6_ENABLE */
  1437. realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
  1438. /* allow time for the port to be set up if we have a plugin */
  1439. if (ctl->server.plugin)
  1440.     (void)sleep(1);
  1441. #if INET6_ENABLE
  1442. if ((mailserver_socket = SockOpen(realhost, 
  1443.      ctl->server.service ? ctl->server.service : protocol->service,
  1444.      ctl->server.netsec, ctl->server.plugin)) == -1)
  1445. #else /* INET6_ENABLE */
  1446. if ((mailserver_socket = SockOpen(realhost, port, NULL, ctl->server.plugin)) == -1)
  1447. #endif /* INET6_ENABLE */
  1448. {
  1449.     char errbuf[BUFSIZ];
  1450. #if !INET6_ENABLE
  1451.     int err_no = errno;
  1452. #ifdef HAVE_RES_SEARCH
  1453.     if (err_no != 0 && h_errno != 0)
  1454. report(stderr, _("fetchmail: internal inconsistencyn"));
  1455. #endif
  1456.     /*
  1457.      * Avoid generating a bogus error every poll cycle when we're
  1458.      * in daemon mode but the connection to the outside world
  1459.      * is down.
  1460.      */
  1461.     if (!(err_no == EHOSTUNREACH && run.poll_interval))
  1462.     {
  1463. report_build(stderr, _("fetchmail: %s connection to %s failed"), 
  1464.      protocol->name, ctl->server.pollname);
  1465. #ifdef HAVE_RES_SEARCH
  1466. if (h_errno != 0)
  1467. {
  1468.     if (h_errno == HOST_NOT_FOUND)
  1469. strcpy(errbuf, _("host is unknown."));
  1470.     else if (h_errno == NO_ADDRESS)
  1471. strcpy(errbuf, _("name is valid but has no IP address."));
  1472.     else if (h_errno == NO_RECOVERY)
  1473. strcpy(errbuf, _("unrecoverable name server error."));
  1474.     else if (h_errno == TRY_AGAIN)
  1475. strcpy(errbuf, _("temporary name server error."));
  1476.     else
  1477. sprintf(errbuf, _("unknown DNS error %d."), h_errno);
  1478. }
  1479. else
  1480. #endif /* HAVE_RES_SEARCH */
  1481.     strcpy(errbuf, strerror(err_no));
  1482. report_complete(stderr, ": %sn", errbuf);
  1483. #ifdef __UNUSED
  1484. /* 
  1485.  * Don't use this.  It was an attempt to address Debian bug
  1486.  * #47143 (Notify user by mail when pop server nonexistent).
  1487.  * Trouble is, that doesn't work; you trip over the case 
  1488.  * where your SLIP or PPP link is down...
  1489.  */
  1490. /* warn the system administrator */
  1491. if (open_warning_by_mail(ctl, (struct msgblk *)NULL) == 0)
  1492. {
  1493. #define OPENFAIL "Subject: Fetchmail unreachable-server warning.rnrnFetchmail could not reach the mail server %s:"
  1494.     stuff_warning(ctl, OPENFAIL, ctl->server.pollname);
  1495.     stuff_warning(ctl, errbuf, ctl->server.pollname);
  1496.     close_warning_by_mail(ctl, (struct msgblk *)NULL);
  1497. #undef OPENFAIL
  1498. }
  1499. #endif
  1500.     }
  1501. #endif /* INET6_ENABLE */
  1502.     ok = PS_SOCKET;
  1503.     set_timeout(0);
  1504.     phase = oldphase;
  1505.     goto closeUp;
  1506. }
  1507. set_timeout(0);
  1508. phase = oldphase;
  1509. #ifdef SSL_ENABLE
  1510. /* perform initial SSL handshake on open connection */
  1511. /* Note:  We pass the realhost name over for certificate
  1512. verification.  We may want to make this configurable */
  1513. if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslkey,ctl->sslcert,realhost) == -1) 
  1514. {
  1515.     report(stderr, "SSL connection failed.");
  1516.     goto closeUp;
  1517. }
  1518. #endif
  1519. #ifdef KERBEROS_V4
  1520. if (ctl->server.preauthenticate == A_KERBEROS_V4)
  1521. {
  1522.     set_timeout(mytimeout);
  1523.     ok = kerberos_auth(mailserver_socket, ctl->server.truename);
  1524.     set_timeout(0);
  1525.       if (ok != 0)
  1526. goto cleanUp;
  1527. }
  1528. #endif /* KERBEROS_V4 */
  1529. #ifdef KERBEROS_V5
  1530. if (ctl->server.preauthenticate == A_KERBEROS_V5)
  1531. {
  1532.     set_timeout(mytimeout);
  1533.     ok = kerberos5_auth(mailserver_socket, ctl->server.truename);
  1534.     set_timeout(0);
  1535.       if (ok != 0)
  1536. goto cleanUp;
  1537. }
  1538. #endif /* KERBEROS_V5 */
  1539. /* accept greeting message from mail server */
  1540. ok = (protocol->parse_response)(mailserver_socket, buf);
  1541. if (ok != 0)
  1542.     goto cleanUp;
  1543. /* try to get authorized to fetch mail */
  1544. stage = STAGE_GETAUTH;
  1545. if (protocol->getauth)
  1546. {
  1547.     if (protocol->password_canonify)
  1548. (protocol->password_canonify)(shroud, ctl->password, PASSWORDLEN);
  1549.     else
  1550. strcpy(shroud, ctl->password);
  1551.     ok = (protocol->getauth)(mailserver_socket, ctl, buf);
  1552.     if (ok != 0)
  1553.     {
  1554. if (ok == PS_LOCKBUSY)
  1555.     report(stderr, _("Lock-busy error on %s@%sn"),
  1556.   ctl->remotename,
  1557.   ctl->server.truename);
  1558. else if (ok == PS_AUTHFAIL)
  1559. {
  1560.     report(stderr, _("Authorization failure on %s@%sn"), 
  1561.   ctl->remotename,
  1562.   ctl->server.truename);
  1563.     /*
  1564.      * If we're running in background, try to mail the
  1565.      * calling user a heads-up about the authentication 
  1566.      * failure once it looks like this isn't a fluke 
  1567.      * due to the server being temporarily inaccessible.
  1568.      */
  1569.     if (run.poll_interval
  1570. && ctl->authfailcount++ > MAX_AUTHFAILS 
  1571. && !open_warning_by_mail(ctl, (struct msgblk *)NULL))
  1572.     {
  1573. stuff_warning(ctl,
  1574.     _("Subject: fetchmail authentication failedrn"));
  1575. stuff_warning(ctl,
  1576.     _("Fetchmail could not get mail from %s@%s.rn"), 
  1577.     ctl->remotename,
  1578.     ctl->server.truename);
  1579. stuff_warning(ctl, 
  1580.     _("The attempt to get authorization failed.rn" 
  1581.     "This probably means your password is invalid, but POP3 servers havern" 
  1582.     "other failure modes that fetchmail cannot distinguish from thisrn" 
  1583.     "because they don't send useful error messages on login failure.rn"));
  1584. close_warning_by_mail(ctl, (struct msgblk *)NULL);
  1585. ctl->wedged = TRUE;
  1586.     }
  1587. }
  1588. else
  1589.     report(stderr, _("Unknown login or authentication error on %s@%sn"),
  1590.   ctl->remotename,
  1591.   ctl->server.truename);
  1592.     
  1593. goto cleanUp;
  1594.     }
  1595. }
  1596. ctl->errcount = fetches = 0;
  1597. /* now iterate over each folder selected */
  1598. for (idp = ctl->mailboxes; idp; idp = idp->next)
  1599. {
  1600.     pass = 0;
  1601.     do {
  1602. dispatches = 0;
  1603. ++pass;
  1604. if (outlevel >= O_DEBUG)
  1605. {
  1606.     if (idp->id)
  1607. report(stdout, _("selecting or re-polling folder %sn"), idp->id);
  1608.     else
  1609. report(stdout, _("selecting or re-polling default foldern"));
  1610. }
  1611. /* compute # of messages and number of new messages waiting */
  1612. stage = STAGE_GETRANGE;
  1613. ok = (protocol->getrange)(mailserver_socket, ctl, idp->id, &count, &new, &bytes);
  1614. if (ok != 0)
  1615.     goto cleanUp;
  1616. /* show user how many messages we downloaded */
  1617. if (idp->id)
  1618.     (void) sprintf(buf, _("%s at %s (folder %s)"),
  1619.    ctl->remotename, ctl->server.truename, idp->id);
  1620. else
  1621.     (void) sprintf(buf, _("%s at %s"),
  1622.    ctl->remotename, ctl->server.truename);
  1623. if (outlevel > O_SILENT)
  1624. {
  1625.     if (count == -1) /* only used for ETRN */
  1626. report(stdout, _("Polling %sn"), ctl->server.truename);
  1627.     else if (count != 0)
  1628.     {
  1629. if (new != -1 && (count - new) > 0)
  1630.     report_build(stdout, _("%d %s (%d seen) for %s"),
  1631.   count, count > 1 ? _("messages") :
  1632.                      _("message"),
  1633.   count-new, buf);
  1634. else
  1635.     report_build(stdout, _("%d %s for %s"), 
  1636.   count, count > 1 ? _("messages") :
  1637.                      _("message"), buf);
  1638. if (bytes == -1)
  1639.     report_complete(stdout, ".n");
  1640. else
  1641.     report_complete(stdout, _(" (%d octets).n"), bytes);
  1642.     }
  1643.     else
  1644.     {
  1645. /* these are pointless in normal daemon mode */
  1646. if (pass == 1 && (run.poll_interval == 0 || outlevel >= O_VERBOSE))
  1647.     report(stdout, _("No mail for %sn"), buf); 
  1648.     }
  1649. }
  1650. /* very important, this is where we leave the do loop */ 
  1651. if (count == 0)
  1652.     break;
  1653. if (check_only)
  1654. {
  1655.     if (new == -1 || ctl->fetchall)
  1656. new = count;
  1657.     fetches = new; /* set error status ccorrectly */
  1658.     goto no_error;
  1659. }
  1660. else if (count > 0)
  1661. {    
  1662.     flag force_retrieval;
  1663.     /*
  1664.      * What forces this code is that in POP2 and
  1665.      * IMAP2bis you can't fetch a message without
  1666.      * having it marked `seen'.  In POP3 and IMAP4, on the
  1667.      * other hand, you can (peek_capable is set by 
  1668.      * each driver module to convey this; it's not a
  1669.      * method constant because of the difference between
  1670.      * IMAP2bis and IMAP4, and because POP3 doesn't  peek
  1671.      * if fetchall is on).
  1672.      *
  1673.      * The result of being unable to peek is that if there's
  1674.      * any kind of transient error (DNS lookup failure, or
  1675.      * sendmail refusing delivery due to process-table limits)
  1676.      * the message will be marked "seen" on the server without
  1677.      * having been delivered.  This is not a big problem if
  1678.      * fetchmail is running in foreground, because the user
  1679.      * will see a "skipped" message when it next runs and get
  1680.      * clued in.
  1681.      *
  1682.      * But in daemon mode this leads to the message
  1683.      * being silently ignored forever.  This is not
  1684.      * acceptable.
  1685.      *
  1686.      * We compensate for this by checking the error
  1687.      * count from the previous pass and forcing all
  1688.      * messages to be considered new if it's nonzero.
  1689.      */
  1690.     force_retrieval = !peek_capable && (ctl->errcount > 0);
  1691.     /* 
  1692.      * We need the size of each message before it's
  1693.      * loaded in order to pass it to the ESMTP SIZE
  1694.      * option.  If the protocol has a getsizes method,
  1695.      * we presume this means it doesn't get reliable
  1696.      * sizes from message fetch responses.
  1697.      */
  1698.     if (proto->getsizes)
  1699.     {
  1700. int i;
  1701. xalloca(msgsizes, int *, sizeof(int) * count);
  1702. for (i = 0; i < count; i++)
  1703.     msgsizes[i] = -1;
  1704. stage = STAGE_GETSIZES;
  1705. ok = (proto->getsizes)(mailserver_socket, count, msgsizes);
  1706. if (ok != 0)
  1707.     goto cleanUp;
  1708. if (bytes == -1)
  1709. {
  1710.     bytes = 0;
  1711.     for (i = 0; i < count; i++)
  1712. bytes += msgsizes[i];
  1713. }
  1714.     }
  1715.     /* read, forward, and delete messages */
  1716.     stage = STAGE_FETCH;
  1717.     for (num = 1; num <= count; num++)
  1718.     {
  1719. flag toolarge = NUM_NONZERO(ctl->limit)
  1720.     && msgsizes && (msgsizes[num-1] > ctl->limit);
  1721. flag oldmsg = (!new) || (protocol->is_old && (protocol->is_old)(mailserver_socket,ctl,num));
  1722. flag fetch_it = !toolarge 
  1723.     && (ctl->fetchall || force_retrieval || !oldmsg);
  1724. flag suppress_delete = FALSE;
  1725. flag suppress_forward = FALSE;
  1726. flag suppress_readbody = FALSE;
  1727. flag retained = FALSE;
  1728. /*
  1729.  * This check copes with Post Office/NT's
  1730.  * annoying habit of randomly prepending bogus
  1731.  * LIST items of length -1.  Patrick Audley
  1732.  * <paudley@pobox.com> tells us: LIST shows a
  1733.  * size of -1, RETR and TOP return "-ERR
  1734.  * System error - couldn't open message", and
  1735.  * DELE succeeds but doesn't actually delete
  1736.  * the message.
  1737.  */
  1738. if (msgsizes && msgsizes[num-1] == -1)
  1739. {
  1740.     if (outlevel >= O_VERBOSE)
  1741. report(stdout, 
  1742.       _("Skipping message %d, length -1n"),
  1743.       num);
  1744.     continue;
  1745. }
  1746. /*
  1747.  * We may want to reject this message if it's old
  1748.  * or oversized, and we're not forcing retrieval.
  1749.  */
  1750. if (!fetch_it)
  1751. {
  1752.     if (outlevel > O_SILENT)
  1753.     {
  1754. report_build(stdout, _("skipping message %d"), num);
  1755. if (toolarge && !check_only) 
  1756. {
  1757.     char size[32];
  1758.     int cnt;
  1759.     /* convert sz to string */
  1760.     sprintf(size, "%d", msgsizes[num-1]);
  1761.     /* build a list of skipped messages
  1762.      * val.id = size of msg (string cnvt)
  1763.      * val.status.num = warning_poll_count
  1764.      * val.status.mask = nbr of msg this size
  1765.      */
  1766.     current = ctl->skipped;
  1767.     /* initialise warning_poll_count to the
  1768.      * current value so that all new msg will
  1769.      * be included in the next mail
  1770.      */
  1771.     cnt = current? current->val.status.num : 0;
  1772.     /* if entry exists, increment the count */
  1773.     if (current && 
  1774. str_in_list(&current, size, FALSE))
  1775.     {
  1776. for ( ; current; 
  1777. current = current->next)
  1778. {
  1779.     if (strcmp(current->id, size) == 0)
  1780.     {
  1781.         current->val.status.mark++;
  1782. break;
  1783.     }
  1784. }
  1785.     }
  1786.     /* otherwise, create a new entry */
  1787.     /* initialise with current poll count */
  1788.     else
  1789.     {
  1790. tmp = save_str(&ctl->skipped, size, 1);
  1791. tmp->val.status.num = cnt;
  1792.     }
  1793.     report_build(stdout, _(" (oversized, %d octets)"),
  1794. msgsizes[num-1]);
  1795. }
  1796.     }
  1797. }
  1798. else
  1799. {
  1800.     flag wholesize = !protocol->fetch_body;
  1801.     /* request a message */
  1802.     ok = (protocol->fetch_headers)(mailserver_socket,ctl,num, &len);
  1803.     if (ok != 0)
  1804. goto cleanUp;
  1805.     /* -1 means we didn't see a size in the response */
  1806.     if (len == -1 && msgsizes)
  1807.     {
  1808. len = msgsizes[num - 1];
  1809. wholesize = TRUE;
  1810.     }
  1811.     if (outlevel > O_SILENT)
  1812.     {
  1813. report_build(stdout, _("reading message %d of %d"),
  1814.     num,count);
  1815. if (len > 0)
  1816.     report_build(stdout, _(" (%d %soctets)"),
  1817. len, wholesize ? "" : _("header "));
  1818. if (outlevel >= O_VERBOSE)
  1819.     report_complete(stdout, "n");
  1820. else
  1821.     report_complete(stdout, " ");
  1822.     }
  1823.     /* 
  1824.      * Read the message headers and ship them to the
  1825.      * output sink.  
  1826.      */
  1827.     ok = readheaders(mailserver_socket, len, msgsizes[num-1],
  1828.      ctl, num);
  1829.     if (ok == PS_RETAINED)
  1830. suppress_forward = retained = TRUE;
  1831.     else if (ok == PS_TRANSIENT)
  1832. suppress_delete = suppress_forward = TRUE;
  1833.     else if (ok == PS_REFUSED)
  1834. suppress_forward = TRUE;
  1835.     else if (ok == PS_TRUNCATED)
  1836. suppress_readbody = TRUE;
  1837.     else if (ok)
  1838. goto cleanUp;
  1839.     /* 
  1840.      * If we're using IMAP4 or something else that
  1841.      * can fetch headers separately from bodies,
  1842.      * it's time to request the body now.  This
  1843.      * fetch may be skipped if we got an anti-spam
  1844.      * or other PS_REFUSED error response during
  1845.      * readheaders.
  1846.      */
  1847.     if (protocol->fetch_body && !suppress_readbody) 
  1848.     {
  1849. if (outlevel >= O_VERBOSE)
  1850. {
  1851.     fputc('n', stdout);
  1852.     fflush(stdout);
  1853. }
  1854. if ((ok = (protocol->trail)(mailserver_socket, ctl, num)))
  1855.     goto cleanUp;
  1856. len = 0;
  1857. if (!suppress_forward)
  1858. {
  1859.     if ((ok=(protocol->fetch_body)(mailserver_socket,ctl,num,&len)))
  1860. goto cleanUp;
  1861.                                     /*
  1862.                                      * Work around a bug in Novell's
  1863.      * broken GroupWise IMAP server;
  1864.                                      * its body FETCH response is missing
  1865.      * the required length for the data
  1866.      * string.  This violates RFC2060.
  1867.                                      */
  1868.                                     if (len == -1)
  1869.                                        len = msgsizes[num-1] - msglen;
  1870.     if (outlevel > O_SILENT && !wholesize)
  1871. report_complete(stdout,
  1872.        _(" (%d body octets) "), len);
  1873. }
  1874.     }
  1875.     /* process the body now */
  1876.     if (len > 0)
  1877.     {
  1878.         if (suppress_readbody)
  1879. {
  1880.   /* When readheaders returns PS_TRUNCATED,
  1881.      the body (which has no content
  1882.      has already been read by readheaders,
  1883.      so we say readbody returned PS_SUCCESS */
  1884.   ok = PS_SUCCESS;
  1885. }
  1886. else
  1887. {
  1888.   ok = readbody(mailserver_socket,
  1889.         ctl,
  1890.         !suppress_forward,
  1891.         len);
  1892. }
  1893.         if (ok == PS_TRANSIENT)
  1894.     suppress_delete = suppress_forward = TRUE;
  1895. else if (ok)
  1896.     goto cleanUp;
  1897. /* tell server we got it OK and resynchronize */
  1898. if (protocol->trail)
  1899. {
  1900.     if (outlevel >= O_VERBOSE)
  1901.     {
  1902. fputc('n', stdout);
  1903. fflush(stdout);
  1904.     }
  1905.     ok = (protocol->trail)(mailserver_socket, ctl, num);
  1906.     if (ok != 0)
  1907. goto cleanUp;
  1908. }
  1909.     }
  1910.     /* count # messages forwarded on this pass */
  1911.     if (!suppress_forward)
  1912. dispatches++;
  1913.     /*
  1914.      * Check to see if the numbers matched?
  1915.      *
  1916.      * Yes, some servers foo this up horribly.
  1917.      * All IMAP servers seem to get it right, and
  1918.      * so does Eudora QPOP at least in 2.xx
  1919.      * versions.
  1920.      *
  1921.      * Microsoft Exchange gets it completely
  1922.      * wrong, reporting compressed rather than
  1923.      * actual sizes (so the actual length of
  1924.      * message is longer than the reported size).
  1925.      * Another fine example of Microsoft brain death!
  1926.      *
  1927.      * Some older POP servers, like the old UCB
  1928.      * POP server and the pre-QPOP QUALCOMM
  1929.      * versions, report a longer size in the LIST
  1930.      * response than actually gets shipped up.
  1931.      * It's unclear what is going on here, as the
  1932.      * QUALCOMM server (at least) seems to be
  1933.      * reporting the on-disk size correctly.
  1934.      */
  1935.     if (msgsizes && msglen != msgsizes[num-1])
  1936.     {
  1937. if (outlevel >= O_DEBUG)
  1938.     report(stdout,
  1939.   _("message %d was not the expected length (%d actual != %d expected)n"),
  1940.   num, msglen, msgsizes[num-1]);
  1941.     }
  1942.     /* end-of-message processing starts here */
  1943.     if (!close_sink(ctl, &msgblk, !suppress_forward))
  1944.     {
  1945. ctl->errcount++;
  1946. suppress_delete = TRUE;
  1947.     }
  1948.     fetches++;
  1949. }
  1950. /*
  1951.  * At this point in flow of control, either
  1952.  * we've bombed on a protocol error or had
  1953.  * delivery refused by the SMTP server
  1954.  * (unlikely -- I've never seen it) or we've
  1955.  * seen `accepted for delivery' and the
  1956.  * message is shipped.  It's safe to mark the
  1957.  * message seen and delete it on the server
  1958.  * now.
  1959.  */
  1960. /* tell the UID code we've seen this */
  1961. if (ctl->newsaved)
  1962. {
  1963.     struct idlist *sdp;
  1964.     for (sdp = ctl->newsaved; sdp; sdp = sdp->next)
  1965. if (sdp->val.status.num == num)
  1966.     sdp->val.status.mark = UID_SEEN;
  1967. }
  1968. /* maybe we delete this message now? */
  1969. if (retained)
  1970. {
  1971.     if (outlevel > O_SILENT) 
  1972. report(stdout, _(" retainedn"));
  1973. }
  1974. else if (protocol->delete
  1975.  && !suppress_delete
  1976.  && (fetch_it ? !ctl->keep : ctl->flush))
  1977. {
  1978.     deletions++;
  1979.     if (outlevel > O_SILENT) 
  1980. report_complete(stdout, _(" flushedn"));
  1981.     ok = (protocol->delete)(mailserver_socket, ctl, num);
  1982.     if (ok != 0)
  1983. goto cleanUp;
  1984. #ifdef POP3_ENABLE
  1985.     delete_str(&ctl->newsaved, num);
  1986. #endif /* POP3_ENABLE */
  1987. }
  1988. else if (outlevel > O_SILENT) 
  1989.     report_complete(stdout, _(" not flushedn"));
  1990. /* perhaps this as many as we're ready to handle */
  1991. if (maxfetch && maxfetch <= fetches && fetches < count)
  1992. {
  1993.     report(stdout, _("fetchlimit %d reached; %d messages left on servern"),
  1994.   maxfetch, count - fetches);
  1995.     ok = PS_MAXFETCH;
  1996.     goto cleanUp;
  1997. }
  1998.     }
  1999.     if (!check_only && ctl->skipped
  2000. && run.poll_interval > 0 && !nodetach)
  2001.     {
  2002. clean_skipped_list(&ctl->skipped);
  2003. send_size_warnings(ctl);
  2004.     }
  2005. }
  2006.     } while
  2007.   /*
  2008.    * Only re-poll if we had some actual forwards, allowed
  2009.    * deletions and had no errors.
  2010.    * Otherwise it is far too easy to get into infinite loops.
  2011.    */
  2012.   (dispatches && protocol->retry && !ctl->keep && !ctl->errcount);
  2013. }
  2014.    no_error:
  2015. /* ordinary termination with no errors -- officially log out */
  2016. ok = (protocol->logout_cmd)(mailserver_socket, ctl);
  2017. /*
  2018.  * Hmmmm...arguably this would be incorrect if we had fetches but
  2019.  * no dispatches (due to oversized messages, etc.)
  2020.  */
  2021. if (ok == 0)
  2022.     ok = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
  2023. SockClose(mailserver_socket);
  2024. goto closeUp;
  2025.     cleanUp:
  2026. /* we only get here on error */
  2027. if (ok != 0 && ok != PS_SOCKET)
  2028. {
  2029.     stage = STAGE_LOGOUT;
  2030.     (protocol->logout_cmd)(mailserver_socket, ctl);
  2031. }
  2032. SockClose(mailserver_socket);
  2033.     }
  2034.     msg = (const char *)NULL; /* sacrifice to -Wall */
  2035.     switch (ok)
  2036.     {
  2037.     case PS_SOCKET:
  2038. msg = _("socket");
  2039. break;
  2040.     case PS_AUTHFAIL:
  2041. msg = _("authorization");
  2042. break;
  2043.     case PS_SYNTAX:
  2044. msg = _("missing or bad RFC822 header");
  2045. break;
  2046.     case PS_IOERR:
  2047. msg = _("MDA");
  2048. break;
  2049.     case PS_ERROR:
  2050. msg = _("client/server synchronization");
  2051. break;
  2052.     case PS_PROTOCOL:
  2053. msg = _("client/server protocol");
  2054. break;
  2055.     case PS_LOCKBUSY:
  2056. msg = _("lock busy on server");
  2057. break;
  2058.     case PS_SMTP:
  2059. msg = _("SMTP transaction");
  2060. break;
  2061.     case PS_DNS:
  2062. msg = _("DNS lookup");
  2063. break;
  2064.     case PS_UNDEFINED:
  2065. report(stderr, _("undefined errorn"));
  2066. break;
  2067.     }
  2068.     /* no report on PS_MAXFETCH or PS_UNDEFINED */
  2069.     if (ok==PS_SOCKET || ok==PS_AUTHFAIL || ok==PS_SYNTAX 
  2070. || ok==PS_IOERR || ok==PS_ERROR || ok==PS_PROTOCOL 
  2071. || ok==PS_LOCKBUSY || ok==PS_SMTP || ok==PS_DNS)
  2072. report(stderr, _("%s error while fetching from %sn"), msg, ctl->server.pollname);
  2073. closeUp:
  2074.     /* execute post-initialization command, if any */
  2075.     if (ctl->postconnect && (ok = system(ctl->postconnect)))
  2076.     {
  2077. report(stderr, _("post-connection command failed with status %dn"), ok);
  2078. if (ok == PS_SUCCESS)
  2079.     ok = PS_SYNTAX;
  2080.     }
  2081.     signal(SIGALRM, alrmsave);
  2082.     signal(SIGPIPE, pipesave);
  2083.     return(ok);
  2084. }
  2085. int do_protocol(ctl, proto)
  2086. /* retrieve messages from server using given protocol method table */
  2087. struct query *ctl; /* parsed options with merged-in defaults */
  2088. const struct method *proto; /* protocol method table */
  2089. {
  2090.     int ok;
  2091. #ifndef KERBEROS_V4
  2092.     if (ctl->server.preauthenticate == A_KERBEROS_V4)
  2093.     {
  2094. report(stderr, _("Kerberos V4 support not linked.n"));
  2095. return(PS_ERROR);
  2096.     }
  2097. #endif /* KERBEROS_V4 */
  2098. #ifndef KERBEROS_V5
  2099.     if (ctl->server.preauthenticate == A_KERBEROS_V5)
  2100.     {
  2101. report(stderr, _("Kerberos V5 support not linked.n"));
  2102. return(PS_ERROR);
  2103.     }
  2104. #endif /* KERBEROS_V5 */
  2105.     /* lacking methods, there are some options that may fail */
  2106.     if (!proto->is_old)
  2107.     {
  2108. /* check for unsupported options */
  2109. if (ctl->flush) {
  2110.     report(stderr,
  2111.     _("Option --flush is not supported with %sn"),
  2112.     proto->name);
  2113.     return(PS_SYNTAX);
  2114. }
  2115. else if (ctl->fetchall) {
  2116.     report(stderr,
  2117.     _("Option --all is not supported with %sn"),
  2118.     proto->name);
  2119.     return(PS_SYNTAX);
  2120. }
  2121.     }
  2122.     if (!proto->getsizes && NUM_SPECIFIED(ctl->limit))
  2123.     {
  2124. report(stderr,
  2125. _("Option --limit is not supported with %sn"),
  2126. proto->name);
  2127. return(PS_SYNTAX);
  2128.     }
  2129.     /*
  2130.      * If no expunge limit or we do expunges within the driver,
  2131.      * then just do one session, passing in any fetchlimit.
  2132.      */
  2133.     if (proto->retry || !NUM_SPECIFIED(ctl->expunge))
  2134. return(do_session(ctl, proto, NUM_VALUE_OUT(ctl->fetchlimit)));
  2135.     /*
  2136.      * There's an expunge limit, and it isn't handled in the driver itself.
  2137.      * OK; do multiple sessions, each fetching a limited # of messages.
  2138.      * Stop if the total count of retrieved messages exceeds ctl->fetchlimit
  2139.      * (if it was nonzero).
  2140.      */
  2141.     else
  2142.     {
  2143. int totalcount = 0; 
  2144. int lockouts   = 0;
  2145. int expunge    = NUM_VALUE_OUT(ctl->expunge);
  2146. int fetchlimit = NUM_VALUE_OUT(ctl->fetchlimit);
  2147. do {
  2148.     ok = do_session(ctl, proto, expunge);
  2149.     totalcount += expunge;
  2150.     if (NUM_SPECIFIED(ctl->fetchlimit) && totalcount >= fetchlimit)
  2151. break;
  2152.     if (ok != PS_LOCKBUSY)
  2153. lockouts = 0;
  2154.     else if (lockouts >= MAX_LOCKOUTS)
  2155. break;
  2156.     else /* ok == PS_LOCKBUSY */
  2157.     {
  2158. /*
  2159.  * Allow time for the server lock to release.  if we
  2160.  * don't do this, we'll often hit a locked-mailbox
  2161.  * condition and fail.
  2162.  */
  2163. lockouts++;
  2164. sleep(3);
  2165.     }
  2166. } while
  2167.     (ok == PS_MAXFETCH || ok == PS_LOCKBUSY);
  2168. return(ok);
  2169.     }
  2170. }
  2171. #if defined(HAVE_STDARG_H)
  2172. void gen_send(int sock, const char *fmt, ... )
  2173. #else
  2174. void gen_send(sock, fmt, va_alist)
  2175. int sock; /* socket to which server is connected */
  2176. const char *fmt; /* printf-style format */
  2177. va_dcl
  2178. #endif
  2179. /* assemble command in printf(3) style and send to the server */
  2180. {
  2181.     char buf [MSGBUFSIZE+1];
  2182.     va_list ap;
  2183.     if (protocol->tagged)
  2184. (void) sprintf(buf, "%s ", GENSYM);
  2185.     else
  2186. buf[0] = '';
  2187. #if defined(HAVE_STDARG_H)
  2188.     va_start(ap, fmt) ;
  2189. #else
  2190.     va_start(ap);
  2191. #endif
  2192. #ifdef HAVE_VSNPRINTF
  2193.     vsnprintf(buf + strlen(buf), sizeof(buf), fmt, ap);
  2194. #else
  2195.     vsprintf(buf + strlen(buf), fmt, ap);
  2196. #endif
  2197.     va_end(ap);
  2198.     strcat(buf, "rn");
  2199.     SockWrite(sock, buf, strlen(buf));
  2200.     if (outlevel >= O_MONITOR)
  2201.     {
  2202. char *cp;
  2203. if (shroud && shroud[0] && (cp = strstr(buf, shroud)))
  2204. {
  2205.     char *sp;
  2206.     sp = cp + strlen(shroud);
  2207.     *cp++ = '*';
  2208.     while (*sp)
  2209. *cp++ = *sp++;
  2210.     *cp = '';
  2211. }
  2212. buf[strlen(buf)-2] = '';
  2213. report(stdout, "%s> %sn", protocol->name, buf);
  2214.     }
  2215. }
  2216. int gen_recv(sock, buf, size)
  2217. /* get one line of input from the server */
  2218. int sock; /* socket to which server is connected */
  2219. char *buf; /* buffer to receive input */
  2220. int size; /* length of buffer */
  2221. {
  2222.     int oldphase = phase; /* we don't have to be re-entrant */
  2223.     phase = SERVER_WAIT;
  2224.     set_timeout(mytimeout);
  2225.     if (SockRead(sock, buf, size) == -1)
  2226.     {
  2227. set_timeout(0);
  2228. phase = oldphase;
  2229. return(PS_SOCKET);
  2230.     }
  2231.     else
  2232.     {
  2233. set_timeout(0);
  2234. if (buf[strlen(buf)-1] == 'n')
  2235.     buf[strlen(buf)-1] = '';
  2236. if (buf[strlen(buf)-1] == 'r')
  2237.     buf[strlen(buf)-1] = '';
  2238. if (outlevel >= O_MONITOR)
  2239.     report(stdout, "%s< %sn", protocol->name, buf);
  2240. phase = oldphase;
  2241. return(PS_SUCCESS);
  2242.     }
  2243. }
  2244. #if defined(HAVE_STDARG_H)
  2245. int gen_transact(int sock, const char *fmt, ... )
  2246. #else
  2247. int gen_transact(int sock, fmt, va_alist)
  2248. int sock; /* socket to which server is connected */
  2249. const char *fmt; /* printf-style format */
  2250. va_dcl
  2251. #endif
  2252. /* assemble command in printf(3) style, send to server, accept a response */
  2253. {
  2254.     int ok;
  2255.     char buf [MSGBUFSIZE+1];
  2256.     va_list ap;
  2257.     int oldphase = phase; /* we don't have to be re-entrant */
  2258.     phase = SERVER_WAIT;
  2259.     if (protocol->tagged)
  2260. (void) sprintf(buf, "%s ", GENSYM);
  2261.     else
  2262. buf[0] = '';
  2263. #if defined(HAVE_STDARG_H)
  2264.     va_start(ap, fmt) ;
  2265. #else
  2266.     va_start(ap);
  2267. #endif
  2268. #ifdef HAVE_VSNPRINTF
  2269.     vsnprintf(buf + strlen(buf), sizeof(buf), fmt, ap);
  2270. #else
  2271.     vsprintf(buf + strlen(buf), fmt, ap);
  2272. #endif
  2273.     va_end(ap);
  2274.     strcat(buf, "rn");
  2275.     SockWrite(sock, buf, strlen(buf));
  2276.     if (outlevel >= O_MONITOR)
  2277.     {
  2278. char *cp;
  2279. if (shroud && shroud[0] && (cp = strstr(buf, shroud)))
  2280. {
  2281.     char *sp;
  2282.     sp = cp + strlen(shroud);
  2283.     *cp++ = '*';
  2284.     while (*sp)
  2285. *cp++ = *sp++;
  2286.     *cp = '';
  2287. }
  2288. buf[strlen(buf)-1] = '';
  2289. report(stdout, "%s> %sn", protocol->name, buf);
  2290.     }
  2291.     /* we presume this does its own response echoing */
  2292.     ok = (protocol->parse_response)(sock, buf);
  2293.     phase = oldphase;
  2294.     return(ok);
  2295. }
  2296. /* driver.c ends here */