#if defined(HAVE_ALLOCA_H)
#include <alloca.h>
#endif
+#if defined(HAVE_SYS_ITIMER_H)
+#include <sys/itimer.h>
+#endif
#include <sys/time.h>
#include <signal.h>
extern char *strstr(); /* needed on sysV68 R3V7.1. */
-int batchlimit; /* how often to tear down the delivery connection */
int fetchlimit; /* how often to tear down the server connection */
int batchcount; /* count of messages sent in current batch */
int peek_capable; /* can we peek for better error recovery? */
static char *shroud; /* string to shroud in debug output, if non-NULL */
static int mytimeout; /* value of nonreponse timeout */
-static void vtalarm(int timeleft)
+static void set_timeout(int timeleft)
/* reset the nonresponse-timeout */
{
struct itimerval ntimeout;
ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0;
ntimeout.it_value.tv_sec = timeleft;
ntimeout.it_value.tv_usec = 0;
- setitimer(ITIMER_VIRTUAL, &ntimeout, (struct itimerval *)NULL);
+ setitimer(ITIMER_REAL, &ntimeout, (struct itimerval *)NULL);
}
-static void vtalarm_handler (int signal)
-/* handle server-timeout SIGVTALARM signal */
+static void timeout_handler (int signal)
+/* handle server-timeout SIGALRM signal */
{
longjmp(restart, 1);
}
+#define XMIT_ACCEPT 1
+#define XMIT_REJECT 2
+#define XMIT_ANTISPAM 3
+static int accept_count, reject_count;
+
#ifdef HAVE_RES_SEARCH
#define MX_RETRIES 3
return(TRUE);
else if (strcmp(name, ctl->server.canonical_name) == 0)
return(TRUE);
- else if (ctl->server.no_dns)
+ else if (!ctl->server.dns)
return(FALSE);
/*
"nameserver failure while looking for `%s' during poll of %s.",
name, ctl->server.names->id);
ctl->errcount++;
- longjmp(restart, 2); /* try again next poll cycle */
break;
}
"nameserver failure while looking for `%s' during poll of %s.",
name, ctl->server.names->id);
ctl->errcount++;
- longjmp(restart, 2); /* try again next poll cycle */
break;
}
}
{
if (outlevel == O_VERBOSE)
error(0, 0, "mapped %s to local %s", name, lname);
- save_str(xmit_names, -1, lname);
+ save_str(xmit_names, XMIT_ACCEPT, lname);
+ accept_count++;
}
}
{
char *rhs;
- rhs = atsign + 1 + (strlen(atsign) - strlen(idp->id));
+ rhs = atsign + (strlen(atsign) - strlen(idp->id));
if ((rhs[-1] == '.' || rhs[-1] == '@')
- && strcmp(rhs, idp->id) == 0)
+ && strcasecmp(rhs, idp->id) == 0)
{
if (outlevel == O_VERBOSE)
error(0, 0, "passed through %s matching %s",
cp, idp->id);
- save_str(xmit_names, -1, cp);
+ save_str(xmit_names, XMIT_ACCEPT, cp);
+ accept_count++;
continue;
}
}
* going and try to find a mapping to a client name.
*/
if (!is_host_alias(atsign+1, ctl))
+ {
+ save_str(xmit_names, XMIT_REJECT, cp);
+ reject_count++;
continue;
+ }
atsign[0] = '\0';
}
}
char *parse_received(struct query *ctl, char *bufp)
-/* try to extract */
+/* try to extract real addressee from the Received line */
{
char *ok;
static char rbuf[HOSTLEN + USERNAMELEN + 4];
static FILE *smtp_open(struct query *ctl)
/* try to open a socket to the appropriate SMTP server for this query */
{
- struct query *lead;
-
- lead = ctl->lead_smtp; /* go to the SMTP leader for this query */
+ struct idlist *idp;
/* maybe it's time to close the socket in order to force delivery */
- if (batchlimit && lead->smtp_sockfp && batchcount++ == batchlimit)
+ if (ctl->batchlimit && ctl->smtp_sockfp && batchcount++ == ctl->batchlimit)
{
- fclose(lead->smtp_sockfp);
- lead->smtp_sockfp = (FILE *)NULL;
+ fclose(ctl->smtp_sockfp);
+ ctl->smtp_sockfp = (FILE *)NULL;
batchcount = 0;
}
- /*
- * RFC 1123 requires that the domain name in HELO address is a
- * "valid principal domain name" for the client host. We
- * violate this with malice aforethought in order to make the
- * Received headers and logging look right.
- *
- * In fact this code relies on the RFC1123 requirement that the
- * SMTP listener must accept messages even if verification of the
- * HELO name fails (RFC1123 section 5.2.5, paragraph 2).
- */
-
- /* if no socket to this host is already set up, try to open ESMTP */
- if (lead->smtp_sockfp == (FILE *)NULL)
+ /* run down the SMTP hunt list looking for a server that's up */
+ for (idp = ctl->smtphunt; idp; idp = idp->next)
{
- if ((lead->smtp_sockfp = SockOpen(lead->smtphost, SMTP_PORT)) == (FILE *)NULL)
- return((FILE *)NULL);
- else if (SMTP_ok(lead->smtp_sockfp) != SM_OK
- || SMTP_ehlo(lead->smtp_sockfp,
- ctl->server.names->id,
- &lead->server.esmtp_options) != SM_OK)
+ /*
+ * RFC 1123 requires that the domain name in HELO address is a
+ * "valid principal domain name" for the client host. We
+ * violate this with malice aforethought in order to make the
+ * Received headers and logging look right.
+ *
+ * In fact this code relies on the RFC1123 requirement that the
+ * SMTP listener must accept messages even if verification of the
+ * HELO name fails (RFC1123 section 5.2.5, paragraph 2).
+ */
+
+ /* if no socket to this host is already set up, try to open ESMTP */
+ if (ctl->smtp_sockfp == (FILE *)NULL)
{
- /*
- * RFC 1869 warns that some listeners hang up on a failed EHLO,
- * so it's safest not to assume the socket will still be good.
- */
- fclose(lead->smtp_sockfp);
- lead->smtp_sockfp = (FILE *)NULL;
+ if ((ctl->smtp_sockfp = SockOpen(idp->id,SMTP_PORT))==(FILE *)NULL)
+ continue;
+ else if (SMTP_ok(ctl->smtp_sockfp) != SM_OK
+ || SMTP_ehlo(ctl->smtp_sockfp,
+ ctl->server.names->id,
+ &ctl->server.esmtp_options) != SM_OK)
+ {
+ /*
+ * RFC 1869 warns that some listeners hang up on a failed EHLO,
+ * so it's safest not to assume the socket will still be good.
+ */
+ fclose(ctl->smtp_sockfp);
+ ctl->smtp_sockfp = (FILE *)NULL;
+ }
+ else
+ {
+ ctl->smtphost = idp->id;
+ break;
+ }
}
- }
- /* if opening for ESMTP failed, try SMTP */
- if (lead->smtp_sockfp == (FILE *)NULL)
- {
- if ((lead->smtp_sockfp = SockOpen(lead->smtphost, SMTP_PORT)) == (FILE *)NULL)
- return((FILE *)NULL);
- else if (SMTP_ok(lead->smtp_sockfp) != SM_OK
- || SMTP_helo(lead->smtp_sockfp, ctl->server.names->id) != SM_OK)
+ /* if opening for ESMTP failed, try SMTP */
+ if (ctl->smtp_sockfp == (FILE *)NULL)
{
- fclose(lead->smtp_sockfp);
- lead->smtp_sockfp = (FILE *)NULL;
+ if ((ctl->smtp_sockfp = SockOpen(idp->id,SMTP_PORT))==(FILE *)NULL)
+ continue;
+ else if (SMTP_ok(ctl->smtp_sockfp) != SM_OK
+ || SMTP_helo(ctl->smtp_sockfp, ctl->server.names->id) != SM_OK)
+ {
+ fclose(ctl->smtp_sockfp);
+ ctl->smtp_sockfp = (FILE *)NULL;
+ }
+ else
+ {
+ ctl->smtphost = idp->id;
+ break;
+ }
}
}
- return(lead->smtp_sockfp);
+ return(ctl->smtp_sockfp);
}
static int gen_readmsg(sockfp, len, delimited, ctl, realname)
{
char buf [MSGBUFSIZE+1];
int from_offs, to_offs, cc_offs, bcc_offs, ctt_offs, env_offs;
- char *headers, *received_for;
- int n, oldlen, ch, sizeticker, delete_ok;
+ char *headers, *received_for, *return_path;
+ int n, oldlen, ch, sizeticker, delete_ok, remaining;
FILE *sinkfp;
RETSIGTYPE (*sigchld)();
#ifdef HAVE_GETHOSTBYNAME
#ifdef HAVE_RES_SEARCH
int no_local_matches = FALSE;
#endif /* HAVE_RES_SEARCH */
+ int olderrs;
sizeticker = 0;
delete_ok = TRUE;
+ remaining = len;
+ olderrs = ctl->errcount;
/* read message headers */
- headers = received_for = NULL;
+ headers = received_for = return_path = NULL;
from_offs = to_offs = cc_offs = bcc_offs = ctt_offs = env_offs = -1;
oldlen = 0;
for (;;)
do {
if (!SockGets(buf, sizeof(buf)-1, sockfp))
return(PS_SOCKET);
- vtalarm(ctl->server.timeout);
+
+ /* lines may not be properly CRLF terminated; fix this for qmail */
+ if (ctl->forcecr)
+ {
+ cp = buf + strlen(buf) - 1;
+ if (cp > buf && *cp == '\n' && cp[-1] != '\r')
+ {
+ *cp++ = '\r';
+ *cp++ = '\n';
+ *cp++ = '\0';
+ }
+ }
+
+ set_timeout(ctl->server.timeout);
/* leave extra room for reply_hack to play with */
line = realloc(line, strlen(line) + strlen(buf) + HOSTLEN + 1);
strcat(line, buf);
((ch = SockPeek(sockfp)) == ' ' || ch == '\t');
/* write the message size dots */
- if ((n = strlen(line)) > 0)
+ n = strlen(line);
+ if ((outlevel > O_SILENT && outlevel < O_VERBOSE) && n > 0)
{
sizeticker += n;
while (sizeticker >= SIZETICKER)
{
- if (outlevel > O_SILENT)
- error_build(".");
+ error_build(".");
sizeticker -= SIZETICKER;
}
}
- len -= n;
+ remaining -= n;
/* check for end of headers; don't save terminating line */
if (line[0] == '\r' && line[1] == '\n')
break;
}
- if (!ctl->no_rewrite)
+
+ /*
+ * OK, this is messy. If we're forwarding by SMTP, it's the
+ * SMTP-receiver's job (according to RFC821, page 22, section
+ * 4.1.1) to generate a Return-Path line on final delivery.
+ * The trouble is, we've already got one because the
+ * mailserver's SMTP thought *it* was responsible for final
+ * delivery.
+ *
+ * Stash away the contents of Return-Path for use in generating
+ * MAIL FROM later on, then prevent the header from being saved
+ * with the others. In effect, we strip it off here.
+ *
+ * If the SMTP server conforms to the standards, and fetchmail gets the
+ * envelope sender from the Return-Path, the new Return-Path should be
+ * exactly the same as the original one.
+ */
+ if (!ctl->mda && !strncasecmp("Return-Path:", line, 12))
+ {
+ return_path = xstrdup(nxtaddr(line));
+ continue;
+ }
+
+ if (ctl->rewrite)
reply_hack(line, realname);
if (!headers)
else if (!strncasecmp("To:", line, 3))
to_offs = (line - headers);
- else if (env_offs == -1 && !strncasecmp(ctl->server.envelope,
+ else if (ctl->server.envelope != STRING_DISABLED && env_offs == -1
+ && !strncasecmp(ctl->server.envelope,
line,
strlen(ctl->server.envelope)))
env_offs = (line - headers);
ctt_offs = (line - headers);
#ifdef HAVE_RES_SEARCH
- else if (MULTIDROP(ctl) && !received_for && !strncasecmp("Received:", line, 9))
+ else if (ctl->server.envelope != STRING_DISABLED && MULTIDROP(ctl) && !received_for && !strncasecmp("Received:", line, 9))
received_for = parse_received(ctl, line);
#endif /* HAVE_RES_SEARCH */
}
+ /*
+ * Hack time. If the first line of the message was blank, with no headers
+ * (this happens occasionally due to bad gatewaying software) cons up
+ * a set of fake headers.
+ *
+ * If you modify the fake header template below, be sure you don't
+ * make either From or To address @-less, otherwise the reply_hack
+ * logic will do bad things.
+ */
+ if (headers == (char *)NULL)
+ {
+ sprintf(buf,
+ "From: <FETCHMAIL-DAEMON@%s>\r\nTo: %s@localhost\r\nSubject: Headerless mail from %s's mailbox on %s\r\n",
+ fetchmailhost, user, ctl->remotename, realname);
+ headers = xstrdup(buf);
+ }
+
/*
* We can now process message headers before reading the text.
* In fact we have to, as this will tell us where to forward to.
/* cons up a list of local recipients */
xmit_names = (struct idlist *)NULL;
- bad_addresses = good_addresses = 0;
+ bad_addresses = good_addresses = accept_count = reject_count = 0;
#ifdef HAVE_RES_SEARCH
/* is this a multidrop box? */
if (MULTIDROP(ctl))
if (bcc_offs > -1)
find_server_names(headers + bcc_offs, ctl, &xmit_names);
}
- if (!xmit_names)
+ if (!accept_count)
{
no_local_matches = TRUE;
- save_str(&xmit_names, -1, user);
+ save_str(&xmit_names, XMIT_ACCEPT, user);
if (outlevel == O_VERBOSE)
error(0, 0,
"no local matches, forwarding to %s",
}
else /* it's a single-drop box, use first localname */
#endif /* HAVE_RES_SEARCH */
- save_str(&xmit_names, -1, ctl->localnames->id);
+ save_str(&xmit_names, XMIT_ACCEPT, ctl->localnames->id);
+
- /* time to address the message */
- if (ctl->mda) /* we have a declared MDA */
+ /*
+ * Time to either address the message or decide we can't deliver it yet.
+ */
+ if (ctl->errcount > olderrs) /* there were DNS errors above */
+ {
+ delete_ok = FALSE;
+ sinkfp = (FILE *)NULL;
+ if (outlevel == O_VERBOSE)
+ error(0,0, "forwarding and deletion suppressed due to DNS errors");
+ }
+ else if (ctl->mda) /* we have a declared MDA */
{
int length = 0;
char *names, *cmd;
* long lists of users and (re)implement %s.
*/
for (idp = xmit_names; idp; idp = idp->next)
- length += (strlen(idp->id) + 1);
+ if (idp->val.num == XMIT_ACCEPT)
+ length += (strlen(idp->id) + 1);
names = (char *)alloca(length);
names[0] = '\0';
for (idp = xmit_names; idp; idp = idp->next)
- {
- strcat(names, idp->id);
- strcat(names, " ");
- }
+ if (idp->val.num == XMIT_ACCEPT)
+ {
+ strcat(names, idp->id);
+ strcat(names, " ");
+ }
cmd = (char *)alloca(strlen(ctl->mda) + length);
sprintf(cmd, ctl->mda, names);
if (outlevel == O_VERBOSE)
if (!sinkfp)
{
- error(0, 0, "MDA open failed");
+ error(0, -1, "MDA open failed");
return(PS_IOERR);
}
if (!ctl->mda && ((sinkfp = smtp_open(ctl)) == NULL))
{
free_str_list(&xmit_names);
- error(0, 0, "SMTP connect failed");
+ error(0, -1, "SMTP connect to %s failed",
+ ctl->smtphost ? ctl->smtphost : "localhost");
+ if (return_path)
+ free(return_path);
return(PS_SMTP);
}
sprintf(options + strlen(options), " SIZE=%d", len);
/*
- * Try to get the SMTP listener to take the header
- * From address as MAIL FROM (this makes the logging
- * nicer). If it won't, fall back on the calling-user
- * ID. This won't affect replies, which use the header
- * From address anyway.
+ * If there is a Return-Path address on the message, this was
+ * almost certainly the MAIL FROM address given the originating
+ * sendmail. This is the best thing to use for logging the
+ * message origin (it sets up the right behavior for bounces and
+ * mailing lists). Otherwise, take the From address.
+ *
+ * Try to get the SMTP listener to take the Return-Path or
+ * From address as MAIL FROM . If it won't, fall back on the
+ * calling-user ID. This won't affect replies, which use the
+ * header From address anyway.
*
* RFC 1123 requires that the domain name part of the
* MAIL FROM address be "canonicalized", that is a
* is if rewrite is on). RFC 1123 is silent on whether
* a nonexistent hostname part is considered canonical.
*
- * This is a potential problem if the MTAs further
- * upstream didn't pass canonicalized From lines, *and*
- * the local SMTP listener insists on them.
+ * This is a potential problem if the MTAs further upstream
+ * didn't pass canonicalized From/Return-Path lines, *and* the
+ * local SMTP listener insists on them.
*/
- if (from_offs == -1 || !(ap = nxtaddr(headers + from_offs)))
+ ap = (char *)NULL;
+ if (return_path)
+ ap = return_path;
+ else if (from_offs == -1 || !(ap = nxtaddr(headers + from_offs)))
ap = user;
if (SMTP_from(sinkfp, ap, options) != SM_OK)
{
int smtperr = atoi(smtp_response);
if (smtperr >= 400)
- error(0, 0, "SMTP error: %s", smtp_response);
+ error(0, -1, "SMTP error: %s", smtp_response);
/*
- * There'a one problem with this flow of control;
+ * There's one problem with this flow of control;
* there's no way to avoid reading the whole message
* off the server, even if the MAIL FROM response
* tells us that it's just to be discarded. We could
default: /* retry with invoking user's address */
if (SMTP_from(sinkfp, user, options) != SM_OK)
{
- error(0,0,"SMTP error: %s", smtp_response);
+ error(0, -1, "SMTP error: %s", smtp_response);
+ if (return_path)
+ free(return_path);
return(PS_SMTP); /* should never happen */
}
}
* problem.
*/
for (idp = xmit_names; idp; idp = idp->next)
- if (SMTP_rcpt(sinkfp, idp->id) == SM_OK)
- good_addresses++;
- else
- {
- bad_addresses++;
- idp->val.num = 0;
- error(0, 0,
- "SMTP listener doesn't like recipient address `%s'", idp->id);
- }
+ if (idp->val.num == XMIT_ACCEPT)
+ if (SMTP_rcpt(sinkfp, idp->id) == SM_OK)
+ good_addresses++;
+ else
+ {
+ bad_addresses++;
+ idp->val.num = XMIT_ANTISPAM;
+ error(0, 0,
+ "SMTP listener doesn't like recipient address `%s'", idp->id);
+ }
if (!good_addresses && SMTP_rcpt(sinkfp, user) != SM_OK)
{
error(0, 0,
"can't even send to calling user!");
+ if (return_path)
+ free(return_path);
return(PS_SMTP);
}
SMTP_data(sinkfp);
skiptext:;
+ if (return_path)
+ free(return_path);
}
/* we may need to strip carriage returns */
#ifdef HAVE_RES_SEARCH
if (no_local_matches)
{
- strcat(errhd, "no recipient addresses matched declared local names");
+ if (reject_count != 1)
+ strcat(errhd, "no recipient addresses matched declared local names");
+ else
+ {
+ for (idp = xmit_names; idp; idp = idp->next)
+ if (idp->val.num == XMIT_REJECT)
+ break;
+ sprintf(errhd+strlen(errhd), "recipient address %s didn't match any local name", idp->id);
+ }
+
if (bad_addresses)
strcat(errhd, "; ");
}
strcat(errhd, "SMTP listener rejected local recipient addresses: ");
errlen = strlen(errhd);
for (idp = xmit_names; idp; idp = idp->next)
- if (!idp->val.num)
+ if (idp->val.num == XMIT_ANTISPAM)
errlen += strlen(idp->id) + 2;
errmsg = alloca(errlen+3);
(void) strcpy(errmsg, errhd);
for (idp = xmit_names; idp; idp = idp->next)
- if (!idp->val.num)
+ if (idp->val.num == XMIT_ANTISPAM)
{
strcat(errmsg, idp->id);
if (idp->next)
*/
/* pass through the text lines */
- while (delimited || len > 0)
+ while (delimited || remaining > 0)
{
if (!SockGets(buf, sizeof(buf)-1, sockfp))
return(PS_SOCKET);
- vtalarm(ctl->server.timeout);
+ set_timeout(ctl->server.timeout);
/* write the message size dots */
if ((n = strlen(buf)) > 0)
sizeticker -= SIZETICKER;
}
}
- len -= n;
+ remaining -= n;
+
+ /* fix messages that have only \n line-termination (for qmail) */
+ if (ctl->forcecr)
+ {
+ cp = buf + strlen(buf) - 1;
+ if (cp > buf && *cp == '\n' && cp[-1] != '\r')
+ {
+ *cp++ = '\r';
+ *cp++ = '\n';
+ *cp++ = '\0';
+ }
+ }
/* check for end of message */
if (delimited && *buf == '.')
signal(SIGCHLD, sigchld);
if (rc)
{
- error(0, 0, "MDA exited abnormally or returned nonzero status");
+ error(0, -1, "MDA exited abnormally or returned nonzero status");
return(PS_IOERR);
}
}
/* write message terminator */
if (SMTP_eom(sinkfp) != SM_OK)
{
- error(0, 0, "SMTP listener refused delivery");
+ error(0, -1, "SMTP listener refused delivery");
+ ctl->errcount++;
return(PS_TRANSIENT);
}
}
free (ticket);
if (rem != KSUCCESS)
{
- error(0, 0, "kerberos error %s", (krb_get_err_text (rem)));
+ error(0, -1, "kerberos error %s", (krb_get_err_text (rem)));
return (PS_ERROR);
}
return (0);
#ifndef KERBEROS_V4
if (ctl->server.authenticate == A_KERBEROS)
{
- error(0, 0, "Kerberos support not linked.");
+ error(0, -1, "Kerberos support not linked.");
return(PS_ERROR);
}
#endif /* KERBEROS_V4 */
error_init(poll_interval == 0 && !logfile);
/* set up the server-nonresponse timeout */
- sigsave = signal(SIGVTALRM, vtalarm_handler);
- vtalarm(mytimeout = ctl->server.timeout);
+ sigsave = signal(SIGALRM, timeout_handler);
+ set_timeout(mytimeout = ctl->server.timeout);
if ((js = setjmp(restart)) == 1)
{
ctl->server.timeout, ctl->server.names->id);
ok = PS_ERROR;
}
- else if (js == 2)
- {
- /* error message printed at point of longjmp */
- ok = PS_ERROR;
- }
else
{
char buf [POPBUFSIZE+1];
#ifndef EHOSTUNREACH
#define EHOSTUNREACH (-1)
#endif
- if (errno != EHOSTUNREACH)
+ if (outlevel == O_VERBOSE || errno != EHOSTUNREACH)
error(0, errno, "connecting to host");
ok = PS_SOCKET;
goto closeUp;
}
#ifdef KERBEROS_V4
- if (ctl->authenticate == A_KERBEROS)
+ if (ctl->server.authenticate == A_KERBEROS)
{
ok = kerberos_auth(fileno(sockfp), ctl->server.canonical_name);
if (ok != 0)
goto cleanUp;
- vtalarm(ctl->server.timeout);
+ set_timeout(ctl->server.timeout);
}
#endif /* KERBEROS_V4 */
ok = (protocol->parse_response)(sockfp, buf);
if (ok != 0)
goto cleanUp;
- vtalarm(ctl->server.timeout);
+ set_timeout(ctl->server.timeout);
/*
* Try to parse the host's actual name out of the greeting
strcpy(realname, ctl->server.names->id);
/* try to get authorized to fetch mail */
- shroud = ctl->password;
- ok = (protocol->getauth)(sockfp, ctl, buf);
- shroud = (char *)NULL;
- if (ok == PS_ERROR)
- ok = PS_AUTHFAIL;
- if (ok != 0)
+ if (protocol->getauth)
{
- error(0, 0, "Authorization failure on %s@%s",
- ctl->remotename,
- realname);
- goto cleanUp;
+ shroud = ctl->password;
+ ok = (protocol->getauth)(sockfp, ctl, buf);
+ shroud = (char *)NULL;
+ if (ok == PS_ERROR)
+ ok = PS_AUTHFAIL;
+ if (ok != 0)
+ {
+ error(0, -1, "Authorization failure on %s@%s",
+ ctl->remotename,
+ realname);
+ goto cleanUp;
+ }
+ set_timeout(ctl->server.timeout);
}
- vtalarm(ctl->server.timeout);
/* compute number of messages and number of new messages waiting */
ok = (protocol->getrange)(sockfp, ctl, &count, &new);
if (ok != 0)
goto cleanUp;
- vtalarm(ctl->server.timeout);
+ set_timeout(ctl->server.timeout);
/* show user how many messages we downloaded */
if (outlevel > O_SILENT)
- if (count == 0)
+ if (count == -1) /* only used for ETRN */
+ error(0, 0, "Polling %s@%s",
+ ctl->remotename,
+ realname);
+ else if (count == 0)
error(0, 0, "No mail at %s@%s",
ctl->remotename,
realname);
ok = (proto->getsizes)(sockfp, count, msgsizes);
if (ok != 0)
goto cleanUp;
- vtalarm(ctl->server.timeout);
+ set_timeout(ctl->server.timeout);
}
if (check_only)
}
else if (count > 0)
{
+ int force_retrieval, fetches;
+
/*
* What forces this code is that in POP3 and IMAP2BIS you can't
* fetch a message without having it marked `seen'. In IMAP4,
* previous pass and forcing all messages to be considered new
* if it's nonzero.
*/
- int force_retrieval = !peek_capable && (ctl->errcount > 0);
+ force_retrieval = !peek_capable && (ctl->errcount > 0);
- ctl->errcount = 0;
+ ctl->errcount = fetches = 0;
/* read, forward, and delete messages */
for (num = 1; num <= count; num++)
ok = (protocol->fetch)(sockfp, ctl, num, &len);
if (ok != 0)
goto cleanUp;
- vtalarm(ctl->server.timeout);
+ set_timeout(ctl->server.timeout);
if (outlevel > O_SILENT)
{
suppress_delete = TRUE;
else if (ok)
goto cleanUp;
- vtalarm(ctl->server.timeout);
+ set_timeout(ctl->server.timeout);
/* tell the server we got it OK and resynchronize */
if (protocol->trail)
ok = (protocol->trail)(sockfp, ctl, num);
if (ok != 0)
goto cleanUp;
- vtalarm(ctl->server.timeout);
+ set_timeout(ctl->server.timeout);
}
+
+ fetches++;
}
/*
ok = (protocol->delete)(sockfp, ctl, num);
if (ok != 0)
goto cleanUp;
- vtalarm(ctl->server.timeout);
+ set_timeout(ctl->server.timeout);
delete_str(&ctl->newsaved, num);
}
else if (outlevel > O_SILENT)
error_complete(0, 0, " not flushed");
/* perhaps this as many as we're ready to handle */
- if (ctl->fetchlimit && ctl->fetchlimit <= num)
+ if (ctl->fetchlimit && ctl->fetchlimit <= fetches)
break;
}
ok = gen_transact(sockfp, protocol->exit_cmd);
if (ok == 0)
- ok = PS_SUCCESS;
- vtalarm(0);
+ ok = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
+ set_timeout(0);
fclose(sockfp);
goto closeUp;
}
ok = gen_transact(sockfp, protocol->exit_cmd);
if (ok == 0)
ok = PS_NOMAIL;
- vtalarm(0);
+ set_timeout(0);
fclose(sockfp);
goto closeUp;
}
cleanUp:
- vtalarm(ctl->server.timeout);
+ set_timeout(ctl->server.timeout);
if (ok != 0 && ok != PS_SOCKET)
gen_transact(sockfp, protocol->exit_cmd);
- vtalarm(0);
+ set_timeout(0);
fclose(sockfp);
}
}
if (ok==PS_SOCKET || ok==PS_AUTHFAIL || ok==PS_SYNTAX || ok==PS_IOERR
|| ok==PS_ERROR || ok==PS_PROTOCOL || ok==PS_SMTP)
- error(0, 0, "%s error while fetching from %s", msg, ctl->server.names->id);
+ error(0, -1, "%s error while fetching from %s", msg, ctl->server.names->id);
closeUp:
- signal(SIGVTALRM, sigsave);
+ signal(SIGALRM, sigsave);
return(ok);
}
{
char *cp;
- if (shroud && (cp = strstr(buf, shroud)))
+ if (shroud && shroud[0] && (cp = strstr(buf, shroud)))
{
char *sp;
*cp++ = '*';
while (*sp)
*cp++ = *sp++;
- *sp = '\0';
+ *cp = '\0';
}
buf[strlen(buf)-2] = '\0';
error(0, 0, "%s> %s", protocol->name, buf);
{
char *cp;
- if (shroud && (cp = strstr(buf, shroud)))
+ if (shroud && shroud[0] && (cp = strstr(buf, shroud)))
{
char *sp;
*cp++ = '*';
while (*sp)
*cp++ = *sp++;
- *sp = '\0';
+ *cp = '\0';
}
buf[strlen(buf)-1] = '\0';
error(0, 0, "%s> %s", protocol->name, buf);
/* we presume this does its own response echoing */
ok = (protocol->parse_response)(sockfp, buf);
- vtalarm(mytimeout);
+ set_timeout(mytimeout);
return(ok);
}
/* driver.c ends here */
-