#endif
#if defined(HAVE_ALLOCA_H)
#include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#endif
#endif
#if defined(HAVE_SYS_ITIMER_H)
#include <sys/itimer.h>
#include <krb.h>
#define krb_get_err_text(e) (krb_err_txt[e])
#else
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__linux__)
#define krb_get_err_text(e) (krb_err_txt[e])
#include <krb.h>
#include <des.h>
#define SMTP_PORT 25 /* standard SMTP service port */
+#ifndef strstr /* glibc-2.1 declares this as a macro */
extern char *strstr(); /* needed on sysV68 R3V7.1. */
+#endif /* strstr */
int fetchlimit; /* how often to tear down the server connection */
int batchcount; /* count of messages sent in current batch */
sp = ok + 4;
if (*sp == '<')
sp++;
+ while (*sp == '@') /* skip routes */
+ while (*sp++ != ':')
+ continue;
while (*sp && *sp != '>' && *sp != '@' && *sp != ';')
if (!isspace(*sp))
*tp++ = *sp++;
{
/*
* 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.
+ * "valid principal domain name" for the client host. If we're
+ * running in invisible mode, 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
* What it will affect is the listener's logging.
*/
struct idlist *idp;
+ char *id_me = use_invisible ? ctl->server.truename : fetchmailhost;
errno = 0;
- /* run down the SMTP hunt list looking for a server that's up */
+ /*
+ * Run down the SMTP hunt list looking for a server that's up.
+ * Use both explicit hunt entries (value TRUE) and implicit
+ * (default) ones (value FALSE).
+ */
for (idp = ctl->smtphunt; idp; idp = idp->next)
{
ctl->smtphost = idp->id; /* remember last host tried. */
continue;
if (SMTP_ok(ctl->smtp_socket) == SM_OK &&
- SMTP_ehlo(ctl->smtp_socket,
- ctl->server.truename,
+ SMTP_ehlo(ctl->smtp_socket, id_me,
&ctl->server.esmtp_options) == SM_OK)
break; /* success */
continue;
if (SMTP_ok(ctl->smtp_socket) == SM_OK &&
- SMTP_helo(ctl->smtp_socket, ctl->server.truename) == SM_OK)
+ SMTP_helo(ctl->smtp_socket, id_me) == SM_OK)
break; /* success */
close(ctl->smtp_socket);
else
/* writing to SMTP, leave the byte-stuffing in place */;
}
- else /* if (!protocol->delimited) /* not byte-stuffed already */
+ else /* if (!protocol->delimited) -- not byte-stuffed already */
{
if (!ctl->mda)
SockWrite(ctl->smtp_socket, buf, 1); /* byte-stuff it */
char buf[MSGBUFSIZE+1], return_path[MSGBUFSIZE+1];
int from_offs, ctt_offs, env_offs, next_address;
char *headers, *received_for, *desthost, *rcv;
- int n, linelen, oldlen, ch, remaining;
+ int n, linelen, oldlen, ch, remaining, skipcount;
char *cp;
struct idlist *idp, *xmit_names;
flag good_addresses, bad_addresses, has_nuls;
from_offs = ctt_offs = env_offs = -1;
oldlen = 0;
msglen = 0;
+ skipcount = 0;
for (remaining = fetchlen; remaining > 0 || protocol->delimited; remaining -= linelen)
{
{
if( ctl->server.uidl )
{
- char id[IDLEN+1];
+ char id[IDLEN+1];
+ /* prevent stack overflows */
+ buf[IDLEN+12] = 0;
sscanf( buf+12, "%s", id);
- if( !str_in_list( &ctl->newsaved, id ) )
+ if( !str_find( &ctl->newsaved, num ) )
save_str(&ctl->newsaved, num, id );
}
}
if (env_offs == -1 && !strncasecmp(ctl->server.envelope,
line,
strlen(ctl->server.envelope)))
+ {
+ if (skipcount++ != ctl->server.envskip)
+ continue;
env_offs = (line - headers);
+ }
}
#ifdef HAVE_RES_SEARCH
else if (!received_for && !strncasecmp("Received:", line, 9))
+ {
+ if (skipcount++ != ctl->server.envskip)
+ continue;
received_for = parse_received(ctl, line);
+ }
#endif /* HAVE_RES_SEARCH */
}
}
map_name(received_for, ctl, &xmit_names);
else
{
- int i;
-
/*
* We haven't extracted the envelope address.
* So check all the header addresses.
desthost = "localhost";
length = strlen(ctl->mda) + 1;
- before = strdup(ctl->mda);
+ before = xstrdup(ctl->mda);
/* sub user addresses for %T (or %s for backward compatibility) */
cp = (char *)NULL;
if (strstr(before, "%s") || (cp = strstr(before, "%T")))
{
+ char *sp;
+
if (cp && cp[1] == 'T')
cp[1] = 's';
+ /* \177 had better be out-of-band for MDA commands */
+ for (sp = before; *sp; sp++)
+ if (*sp == '%' && sp[1] != 's' && sp[1] != 'T')
+ *sp = '\177';
+
/*
* We go through this in order to be able to handle very
* long lists of users and (re)implement %s.
#endif /* SNPRINTF */
free(before);
before = after;
+
+ for (sp = before; *sp; sp++)
+ if (*sp == '\177')
+ *sp = '%';
}
/* substitute From address for %F */
if ((cp = strstr(before, "%F")))
{
char *from = nxtaddr(headers + from_offs);
+ char *sp;
+
+ /* \177 had better be out-of-band for MDA commands */
+ for (sp = before; *sp; sp++)
+ if (*sp == '%' && sp[1] != 'F')
+ *sp = '\177';
length += strlen(from);
after = alloca(length);
#endif /* SNPRINTF */
free(before);
before = after;
+
+ for (sp = before; *sp; sp++)
+ if (*sp == '\177')
+ *sp = '%';
}
if (outlevel == O_VERBOSE)
n = stuffline(ctl, headers);
*rcv = 'R';
}
- if (n != -1)
+ if (!use_invisible && n != -1)
{
/* utter any per-message Received information we need here */
sprintf(buf, "Received: from %s\n", ctl->server.truename);
n = stuffline(ctl, buf);
if (n != -1)
{
- sprintf(buf, "\tby %s (fetchmail-%s %s run by %s)\n",
+ sprintf(buf, "\tby %s (fetchmail-%s %s run for %s)\n",
fetchmailhost,
RELEASE_ID,
protocol->name,
time(&now);
strcat(buf, ctime(&now));
n = stuffline(ctl, buf);
- if (n != -1)
- n = stuffline(ctl, rcv); /* ship out rest of headers */
}
}
}
+ if (n != -1)
+ n = stuffline(ctl, rcv); /* ship out rest of headers */
+
if (n == -1)
{
error(0, errno, "writing RFC822 headers");
flag forward; /* TRUE to forward */
{
int linelen;
- char buf[MSGBUFSIZE+1], *cp;
+ char buf[MSGBUFSIZE+1];
/* pass through the text lines */
while (protocol->delimited || len > 0)
struct query *ctl; /* parsed options with merged-in defaults */
const struct method *proto; /* protocol method table */
{
- int ok, js, pst, sock = -1;
- char *msg, *cp;
+ int ok, js, sock = -1;
+ char *msg;
void (*sigsave)();
#ifndef KERBEROS_V4
tagnum = 0;
tag[0] = '\0'; /* nuke any tag hanging out from previous query */
ok = 0;
- error_init(poll_interval == 0 && !logfile);
/* set up the server-nonresponse timeout */
sigsave = signal(SIGALRM, timeout_handler);
}
else
{
- char buf [POPBUFSIZE+1], *sp, *realhost;
+ char buf [POPBUFSIZE+1], *realhost;
int *msgsizes, len, num, count, new, deletions = 0;
- int port, fetches;
+ int port, fetches, dispatches;
struct idlist *idp;
/* execute pre-initialization command, if any */
/* now iterate over each folder selected */
for (idp = ctl->mailboxes; idp; idp = idp->next)
{
+ pass = 0;
do {
+ dispatches = 0;
++pass;
if (outlevel >= O_VERBOSE)
- if (idp->next)
- error(0, 0, "selecting or re-polling folder %s");
+ if (idp->id)
+ error(0, 0, "selecting or re-polling folder %s", idp->id);
else
error(0, 0, "selecting or re-polling default folder");
/* show user how many messages we downloaded */
if (idp->id)
- (void) sprintf(buf, "%s@%s:%s",
+ (void) sprintf(buf, "%s at %s (folder %s)",
ctl->remotename, ctl->server.truename, idp->id);
else
- (void) sprintf(buf, "%s@%s", ctl->remotename, ctl->server.truename);
+ (void) sprintf(buf, "%s at %s", ctl->remotename, ctl->server.truename);
if (outlevel > O_SILENT)
if (count == -1) /* only used for ETRN */
error(0, 0, "Polling %s", ctl->server.truename);
else if (count != 0)
{
if (new != -1 && (count - new) > 0)
- error(0, 0, "%d message%s (%d seen) at %s.",
+ error(0, 0, "%d message%s (%d seen) for %s.",
count, count > 1 ? "s" : "", count-new, buf);
else
- error(0, 0, "%d message%s at %s.",
+ error(0, 0, "%d message%s for %s.",
count, count > 1 ? "s" : "", buf);
}
else
{
/* these are pointless in normal daemon mode */
if (pass == 1 && (poll_interval == 0 || outlevel == O_VERBOSE))
- error(0, 0, "No mail at %s", buf);
+ error(0, 0, "No mail for %s", buf);
}
/* very important, this is where we leave the do loop */
}
}
+ /* count # messages forwarded on this pass */
+ if (!suppress_forward)
+ dispatches++;
+
/*
* Check to see if the numbers matched?
*
if (ok != 0)
goto cleanUp;
set_timeout(ctl->server.timeout);
+#ifdef POP3_ENABLE
delete_str(&ctl->newsaved, num);
+#endif /* POP3_ENABLE */
}
else if (outlevel > O_SILENT)
error_complete(0, 0, " not flushed");
}
} while
/*
- * Only re-poll if we allowed deletions and had no errors.
+ * Only re-poll if we had some actual forwards, allowed
+ * deletions and had no errors.
* Otherwise it is far too easy to get into infinite loops.
*/
- (protocol->retry && !ctl->keep && !ctl->errcount);
+ (dispatches && protocol->retry && !ctl->keep && !ctl->errcount);
}
no_error:
set_timeout(ctl->server.timeout);
ok = (protocol->logout_cmd)(sock, ctl);
+ /*
+ * Hmmmm...arguably this would be incorrect if we had fetches but
+ * no dispatches (due to oversized messages, etc.)
+ */
if (ok == 0)
ok = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
set_timeout(0);
}
#if defined(HAVE_STDARG_H)
-void gen_send(int sock, char *fmt, ... )
+void gen_send(int sock, const char *fmt, ... )
/* assemble command in printf(3) style and send to the server */
#else
void gen_send(sock, fmt, va_alist)