#include "config.h"
#include <stdio.h>
#include <string.h>
+#include <ctype.h> /* isspace() */
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif /* HAVE_MEMORY_H */
if (lname != (char *)NULL)
{
if (outlevel >= O_DEBUG)
- report(stdout, _("mapped %s to local %s\n"), name, lname);
+ report(stdout, GT_("mapped %s to local %s\n"), name, lname);
save_str(xmit_names, lname, XMIT_ACCEPT);
accept_count++;
}
strcasecmp(rhs, idp->id) == 0)
{
if (outlevel >= O_DEBUG)
- report(stdout, _("passed through %s matching %s\n"),
+ report(stdout, GT_("passed through %s matching %s\n"),
cp, idp->id);
save_str(xmit_names, cp, XMIT_ACCEPT);
accept_count++;
* does this when the mail has a single recipient.
*/
if (outlevel >= O_DEBUG)
- report(stdout, _("analyzing Received line:\n%s"), bufp);
+ report(stdout, GT_("analyzing Received line:\n%s"), bufp);
/* search for whitepace-surrounded "by" followed by valid address */
for (base = bufp; ; base = ok + 2)
{
if (outlevel >= O_DEBUG)
report(stdout,
- _("line accepted, %s is an alias of the mailserver\n"), rbuf);
+ GT_("line accepted, %s is an alias of the mailserver\n"), rbuf);
}
else
{
if (outlevel >= O_DEBUG)
report(stdout,
- _("line rejected, %s is not an alias of the mailserver\n"),
+ GT_("line rejected, %s is not an alias of the mailserver\n"),
rbuf);
return(NULL);
}
if (!ok)
{
if (outlevel >= O_DEBUG)
- report(stdout, _("no Received address found\n"));
+ report(stdout, GT_("no Received address found\n"));
return(NULL);
}
else
char *lf = rbuf + strlen(rbuf)-1;
*lf = '\0';
if (outlevel >= O_DEBUG)
- report(stdout, _("found Received address `%s'\n"), rbuf+2);
+ report(stdout, GT_("found Received address `%s'\n"), rbuf+2);
*lf = '\n';
}
return(rbuf);
if (msgblk.headers)
free(msgblk.headers);
+ /* initially, no message ID */
+ if (ctl->thisid)
+ free(ctl->thisid);
+ ctl->thisid = NULL;
+
msgblk.headers = received_for = delivered_to = NULL;
from_offs = reply_to_offs = resent_from_offs = app_from_offs =
sender_offs = resent_sender_offs = env_offs = -1;
for (remaining = fetchlen; remaining > 0 || protocol->delimited; remaining -= linelen)
{
char *line;
+ int overlong = FALSE;
line = xmalloc(sizeof(buf));
linelen = 0;
linelen += n;
msgblk.msglen += n;
+ /*
+ * Try to gracefully handle the case, where the length of a
+ * line exceeds MSGBUFSIZE.
+ */
+ if ( n && buf[n-1] != '\n' ) {
+ unsigned int llen = strlen(line);
+ overlong = TRUE;
+ line = realloc(line, llen + n + 1);
+ strcpy(line + llen, buf);
+ ch = ' '; /* So the next iteration starts */
+ continue;
+ }
+
/* lines may not be properly CRLF terminated; fix this for qmail */
if (ctl->forcecr)
{
}
}
- /*
- * Decode MIME encoded headers. We MUST do this before
- * looking at the Content-Type / Content-Transfer-Encoding
- * headers (RFC 2046).
- */
- if (ctl->mimedecode)
- UnMimeHeader(buf);
-
- line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
+ /*
+ * Decode MIME encoded headers. We MUST do this before
+ * looking at the Content-Type / Content-Transfer-Encoding
+ * headers (RFC 2046).
+ */
+ if ( ctl->mimedecode && overlong ) {
+ /*
+ * If we received an overlong line, we have to decode the
+ * whole line at once.
+ */
+ line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
+ strcat(line, buf);
+ UnMimeHeader(line);
+ }
+ else {
+ if ( ctl->mimedecode )
+ UnMimeHeader(buf);
- strcat(line, buf);
+ line = (char *) realloc(line, strlen(line) + strlen(buf) +1);
+ strcat(line, buf);
+ }
/* check for end of headers */
if (EMPTYLINE(line))
*/
if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1))
{
- free(line);
has_nuls = (linelen != strlen(line));
+ free(line);
goto process_headers;
}
*/
if (!isspace(line[0]) && !strchr(line, ':'))
{
- headers_ok = TRUE;
+ headers_ok = FALSE;
has_nuls = (linelen != strlen(line));
free(line);
goto process_headers;
/* we see an ordinary (non-header, non-message-delimiter line */
has_nuls = (linelen != strlen(line));
- /*
- * When mail delivered to a multidrop mailbox on the server is
- * addressed to multiple people on the client machine, there
- * will be one copy left in the box for each recipient. Thus,
- * if the mail is addressed to N people, each recipient will
- * get N copies. This is bad when N > 1.
- *
- * Foil this by suppressing all but one copy of a message with
- * a given Message-ID. The accept_count test ensures that
- * multiple pieces of email with the same Message-ID, each
- * with a *single* addressee (the N == 1 case), won't be
- * suppressed.
- *
- * Note: This implementation only catches runs of successive
- * messages with the same ID, but that should be good
- * enough. A more general implementation would have to store
- * ever-growing lists of seen message-IDs; in a long-running
- * daemon this would turn into a memory leak even if the
- * implementation were perfect.
- *
- * Don't mess with this code casually. It would be way too easy
- * to break it in a way that blackholed mail. Better to pass
- * the occasional duplicate than to do that...
- */
+ /* save the message's ID, we may use it for killing duplicates later */
if (MULTIDROP(ctl) && !strncasecmp(line, "Message-ID:", 11))
- {
- if (ctl->lastid && !strcasecmp(ctl->lastid, line))
- {
- if (accept_count > 1)
- return(PS_REFUSED);
- }
- else
- {
- if (ctl->lastid)
- free(ctl->lastid);
- ctl->lastid = strdup(line);
- }
- }
+ ctl->thisid = xstrdup(line);
/*
* The University of Washington IMAP server (the reference
* (RFC2822 says the condents of Sender must be a valid mailbox
* address, which is also what RFC822 4.4.4 implies.)
*/
- else if (!strncasecmp("Sender:", line, 7) && strchr(line, '@'))
+ else if (!strncasecmp("Sender:", line, 7) && (strchr(line, '@') || strchr(line, '!')))
sender_offs = (line - msgblk.headers);
- else if (!strncasecmp("Resent-Sender:", line, 14) && strchr(line, '@'))
+ else if (!strncasecmp("Resent-Sender:", line, 14) && (strchr(line, '@') || strchr(line, '!')))
resent_sender_offs = (line - msgblk.headers);
#ifdef __UNUSED__
line,
strlen(ctl->server.envelope)))
{
- if (skipcount++ != ctl->server.envskip)
+ if (skipcount++ < ctl->server.envskip)
continue;
env_offs = (line - msgblk.headers);
}
}
else if (!received_for && !strncasecmp("Received:", line, 9))
{
- if (skipcount++ != ctl->server.envskip)
+ if (skipcount++ < ctl->server.envskip)
continue;
received_for = parse_received(ctl, line);
}
}
}
- process_headers:
+ process_headers:
+ /*
+ * When mail delivered to a multidrop mailbox on the server is
+ * addressed to multiple people on the client machine, there will
+ * be one copy left in the box for each recipient. This is not a
+ * problem if we have the actual recipient address to dispatch on
+ * (e.g. because we've mined it out of sendmail trace headers, or
+ * a qmail Delivered-To line, or a declared sender envelope line).
+ *
+ * But if we're mining addressees out of the To/Cc/Bcc fields, and
+ * if the mail is addressed to N people, each recipient will
+ * get N copies. This is bad when N > 1.
+ *
+ * Foil this by suppressing all but one copy of a message with
+ * a given Message-ID. The accept_count test ensures that
+ * multiple pieces of email with the same Message-ID, each
+ * with a *single* addressee (the N == 1 case), won't be
+ * suppressed.
+ *
+ * Note: This implementation only catches runs of successive
+ * messages with the same ID, but that should be good
+ * enough. A more general implementation would have to store
+ * ever-growing lists of seen message-IDs; in a long-running
+ * daemon this would turn into a memory leak even if the
+ * implementation were perfect.
+ *
+ * Don't mess with this code casually. It would be way too easy
+ * to break it in a way that blackholed mail. Better to pass
+ * the occasional duplicate than to do that...
+ */
+ if (!received_for && env_offs == -1 && !delivered_to)
+ {
+ if (ctl->lastid && ctl->thisid && !strcasecmp(ctl->lastid, ctl->thisid))
+ {
+ if (accept_count > 1)
+ return(PS_REFUSED);
+ }
+ else
+ {
+ if (ctl->lastid)
+ free(ctl->lastid);
+ ctl->lastid = ctl->thisid;
+ ctl->thisid = NULL;
+ }
+ }
+
/*
* We want to detect this early in case there are so few headers that the
* dispatch logic barfs.
{
if (outlevel > O_SILENT)
report(stdout,
- _("message delimiter found while scanning headers\n"));
+ GT_("message delimiter found while scanning headers\n"));
}
/*
save_str(&msgblk.recipients, run.postmaster, XMIT_ACCEPT);
if (outlevel >= O_DEBUG)
report(stdout,
- _("no local matches, forwarding to %s\n"),
+ GT_("no local matches, forwarding to %s\n"),
run.postmaster);
}
}
{
if (outlevel >= O_DEBUG)
report(stdout,
- _("forwarding and deletion suppressed due to DNS errors\n"));
+ GT_("forwarding and deletion suppressed due to DNS errors\n"));
free(msgblk.headers);
msgblk.headers = NULL;
free_str_list(&msgblk.recipients);
{
/* utter any per-message Received information we need here */
if (ctl->server.trueaddr) {
- sprintf(buf, "Received: from %s [%u.%u.%u.%u]\r\n",
+#ifdef HAVE_SNPRINTF
+ snprintf(buf, sizeof(buf),
+#else
+ sprintf(buf,
+#endif /* HAVE_SNPRINTF */
+ "Received: from %s [%u.%u.%u.%u]\r\n",
ctl->server.truename,
(unsigned char)ctl->server.trueaddr[0],
(unsigned char)ctl->server.trueaddr[1],
(unsigned char)ctl->server.trueaddr[2],
(unsigned char)ctl->server.trueaddr[3]);
} else {
- sprintf(buf, "Received: from %s\r\n", ctl->server.truename);
+#ifdef HAVE_SNPRINTF
+ snprintf(buf, sizeof(buf),
+#else
+ sprintf(buf,
+#endif /* HAVE_SNPRINTF */
+ "Received: from %s\r\n", ctl->server.truename);
}
n = stuffline(ctl, buf);
if (n != -1)
* This header is technically invalid under RFC822.
* POP3, IMAP, etc. are not legal mail-parameter values.
*/
- sprintf(buf, "\tby %s with %s (fetchmail-%s)",
+#ifdef HAVE_SNPRINTF
+ snprintf(buf, sizeof(buf),
+#else
+ sprintf(buf,
+#endif /* HAVE_SNPRINTF */
+ "\tby %s with %s (fetchmail-%s",
fetchmailhost,
protocol->name,
VERSION);
ctl->server.pollname,
ctl->remotename);
}
- strcat(buf, "\r\n");
+#ifdef HAVE_SNPRINTF
+ snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), ")\r\n");
+#else
+ strcat(buf, ")\r\n");
+#endif /* HAVE_SNPRINTF */
n = stuffline(ctl, buf);
if (n != -1)
{
buf[0] = '\t';
if (good_addresses == 0)
{
- sprintf(buf+1,
+#ifdef HAVE_SNPRINTF
+ snprintf(buf+1, sizeof(buf)-1,
+#else
+ sprintf(buf+1,
+#endif /* HAVE_SNPRINTF */
"for %s@%s (by default); ",
user, ctl->destaddr);
}
if (idp->val.status.mark == XMIT_ACCEPT)
break; /* only report first address */
if (strchr(idp->id, '@'))
- sprintf(buf+1, "for %s", idp->id);
+#ifdef HAVE_SNPRINTF
+ snprintf(buf+1, sizeof(buf)-1,
+#else
+ sprintf(buf+1,
+#endif /* HAVE_SNPRINTF */
+ "for %s", idp->id);
else
/*
* This could be a bit misleading, as destaddr is
* the forwarding host rather than the actual
* destination. Most of the time they coincide.
*/
- sprintf(buf+1, "for %s@%s", idp->id, ctl->destaddr);
+#ifdef HAVE_SNPRINTF
+ snprintf(buf+1, sizeof(buf)-1,
+#else
+ sprintf(buf+1,
+#endif /* HAVE_SNPRINTF */
+ "for %s@%s", idp->id, ctl->destaddr);
sprintf(buf+strlen(buf), " (%s); ",
MULTIDROP(ctl) ? "multi-drop" : "single-drop");
}
else
buf[1] = '\0';
+#ifdef HAVE_SNPRINTF
+ snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s\r\n",
+ rfc822timestamp());
+#else
strcat(buf, rfc822timestamp());
strcat(buf, "\r\n");
+#endif /* HAVE_SNPRINTF */
n = stuffline(ctl, buf);
}
}
if (n == -1)
{
- report(stdout, _("writing RFC822 msgblk.headers\n"));
+ report(stdout, GT_("writing RFC822 msgblk.headers\n"));
release_sink(ctl);
free(msgblk.headers);
msgblk.headers = NULL;
return(PS_IOERR);
}
else if ((run.poll_interval == 0 || nodetach) && outlevel >= O_VERBOSE && !isafile(2))
- fputs("#", stderr);
+ fputs("#", stdout);
/* write error notifications */
if (no_local_matches || has_nuls || bad_addresses)
if (no_local_matches)
{
if (reject_count != 1)
- strcat(errhd, _("no recipient addresses matched declared local names"));
+ strcat(errhd, GT_("no recipient addresses matched declared local names"));
else
{
for (idp = msgblk.recipients; idp; idp = idp->next)
if (idp->val.status.mark == XMIT_REJECT)
break;
- sprintf(errhd+strlen(errhd), _("recipient address %s didn't match any local name"), idp->id);
+ sprintf(errhd+strlen(errhd), GT_("recipient address %s didn't match any local name"), idp->id);
}
}
{
if (errhd[sizeof("X-Fetchmail-Warning: ")])
strcat(errhd, "; ");
- strcat(errhd, _("message has embedded NULs"));
+ strcat(errhd, GT_("message has embedded NULs"));
}
if (bad_addresses)
{
if (errhd[sizeof("X-Fetchmail-Warning: ")])
strcat(errhd, "; ");
- strcat(errhd, _("SMTP listener rejected local recipient addresses: "));
+ strcat(errhd, GT_("SMTP listener rejected local recipient addresses: "));
errlen = strlen(errhd);
for (idp = msgblk.recipients; idp; idp = idp->next)
if (idp->val.status.mark == XMIT_RCPTBAD)
if (n < 0)
{
- report(stdout, _("writing message text\n"));
+ report(stdout, GT_("writing message text\n"));
release_sink(ctl);
return(PS_IOERR);
}
#endif
va_end(ap);
+#ifdef HAVE_SNPRINTF
+ snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\r\n");
+#else
strcat(buf, "\r\n");
+#endif /* HAVE_SNPRINTF */
SockWrite(sock, buf, strlen(buf));
if (outlevel >= O_MONITOR)
#endif
va_end(ap);
+#ifdef HAVE_SNPRINTF
+ snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\r\n");
+#else
strcat(buf, "\r\n");
+#endif /* HAVE_SNPRINTF */
SockWrite(sock, buf, strlen(buf));
if (outlevel >= O_MONITOR)