int batchcount; /* count of messages sent in current batch */
flag peek_capable; /* can we peek for better error recovery? */
int pass; /* how many times have we re-polled? */
+int stage; /* where are we? */
int phase; /* where are we, for error-logging purposes? */
+int mytimeout; /* value of nonreponse timeout */
static const struct method *protocol;
static jmp_buf restart;
#define GENSYM (sprintf(tag, "A%04d", ++tagnum % TAGMOD), tag)
static char shroud[PASSWORDLEN]; /* string to shroud in debug output */
-static int mytimeout; /* value of nonreponse timeout */
static int timeoutcount; /* count consecutive timeouts */
static int msglen; /* actual message length */
* are not uncommon. So now we just check that the following token is
* not itself an email address.
*/
-#define VALID_ADDRESS(a) !strchr(rbuf, '@')
+#define VALID_ADDRESS(a) !strchr(a, '@')
static char *parse_received(struct query *ctl, char *bufp)
/* try to extract real address from the Received line */
sizeticker += linelen;
while (sizeticker >= SIZETICKER)
{
- if (!run.use_syslog)
+ if (!run.use_syslog && isatty(1))
{
fputc('.', stdout);
fflush(stdout);
/*
* When mail delivered to a multidrop mailbox on the server is
- * addressed to multiple people, there will be one copy left
- * in the box for each recipient. Thus, if the mail is addressed
- * to N people, each recipient would get N copies.
+ * 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.
*
* Foil this by suppressing all but one copy of a message with
* a given Message-ID. Note: This implementation only catches
* runs of successive identical messages, but that should be
- * good enough.
+ * good enough.
+ *
+ * The accept_count test ensures that multiple pieces of identical
+ * email, each with a *single* addressee, won't be suppressed.
*/
- if (MULTIDROP(ctl) && !strncasecmp(line, "Message-ID:", 11))
+ if (MULTIDROP(ctl) && accept_count > 1 && !strncasecmp(line, "Message-ID:", 11))
{
if (ctl->lastid && !strcasecmp(ctl->lastid, line))
return(PS_REFUSED);
* forward it to the user so he or she will have some clue
* that things have gone awry.
*/
+#if INET6_ENABLE
+ if (strncmp(protocol->service, "pop2", 4))
+#else /* INET6_ENABLE */
if (protocol->port != 109)
+#endif /* INET6_ENABLE */
#endif /* POP2_ENABLE */
if (num == 1 && !strncasecmp(line, "X-IMAP:", 7)) {
free(line);
else if (!strncasecmp("Resent-Sender:", line, 14))
resent_sender_offs = (line - msgblk.headers);
- else if (!strncasecmp("Message-Id:", buf, 11))
+#ifdef __UNUSED__
+ else if (!strncasecmp("Message-Id:", line, 11))
{
if (ctl->server.uidl)
{
char id[IDLEN+1];
- buf[IDLEN+12] = 0; /* prevent stack overflow */
- sscanf(buf+12, "%s", id);
+ line[IDLEN+12] = 0; /* prevent stack overflow */
+ sscanf(line+12, "%s", id);
if (!str_find( &ctl->newsaved, num))
{
struct idlist *new = save_str(&ctl->newsaved,id,UID_SEEN);
}
}
}
+#endif /* __UNUSED__ */
else if (!MULTIDROP(ctl))
continue;
* We haven't extracted the envelope address.
* So check all the "Resent-To" header addresses if
* they exist. If and only if they don't, consider
- * the "To" adresses.
+ * the "To" addresses.
*/
register struct addrblk *nextptr;
if (resent_to_addrchain) {
free_str_list(&msgblk.recipients);
return(PS_IOERR);
}
- else if (!run.use_syslog && outlevel >= O_VERBOSE)
+ else if ((run.poll_interval == 0 || nodetach) && outlevel >= O_VERBOSE && isatty(2))
fputs("#", stderr);
/* write error notifications */
sizeticker += linelen;
while (sizeticker >= SIZETICKER)
{
- if (!run.use_syslog && outlevel > O_SILENT)
+ if ((run.poll_interval == 0 || nodetach) && outlevel > O_SILENT && isatty(1))
{
fputc('.', stdout);
fflush(stdout);
release_sink(ctl);
return(PS_IOERR);
}
- else if (outlevel >= O_VERBOSE)
- fputc('*', stderr);
+ else if (outlevel >= O_VERBOSE && isatty(1))
+ {
+ fputc('*', stdout);
+ fflush(stdout);
+ }
}
}
nbr = current->val.status.mark;
size = atoi(current->id);
stuff_warning(ctl,
- _("\t%d msg %d octets long skipped by fetchmail.\n"),
+ _("\t%d msg %d octets long skipped by fetchmail.\r\n"),
nbr, size);
}
current->val.status.num++;
if (js == THROW_SIGPIPE)
{
report(stdout,
- _("SIGPIPE thrown from an MDA or a stream socket error"));
+ _("SIGPIPE thrown from an MDA or a stream socket error\n"));
ok = PS_SOCKET;
+ goto cleanUp;
}
else if (js == THROW_TIMEOUT)
{
ctl->mda ? "MDA" : "SMTP");
else if (phase == LISTENER_WAIT)
report(stdout,
- _("timeout after %d seconds waiting for listener to respond.\n"));
+ _("timeout after %d seconds waiting for listener to respond.\n"), ctl->server.timeout);
else
report(stdout,
_("timeout after %d seconds.\n"), ctl->server.timeout);
/*
* If we've exceeded our threshold for consecutive timeouts,
* try to notify the user, then mark the connection wedged.
+ * Don't do this if the connection can idle, though; idle
+ * timeouts just mean the frequency of mail is low.
*/
if (timeoutcount > MAX_TIMEOUTS
&& !open_warning_by_mail(ctl, (struct msgblk *)NULL))
stuff_warning(ctl,
_("Subject: fetchmail sees repeated timeouts\r\n"));
stuff_warning(ctl,
- _("Fetchmail saw more than %d timouts while attempting to get mail from %s@%s.\n"),
+ _("Fetchmail saw more than %d timeouts while attempting to get mail from %s@%s.\r\n"),
MAX_TIMEOUTS,
ctl->remotename,
ctl->server.truename);
stuff_warning(ctl,
- _("This could mean that your mailserver is stuck, or that your SMTP listener"));
- stuff_warning(ctl,
- _("is wedged, or that your mailbox file on the server has been corrupted by"));
- stuff_warning(ctl,
- _("a server error. You can run `fetchmail -v -v' to diagnose the problem."));
- stuff_warning(ctl,
- _("Fetchmail won't poll this mailbox again until you restart it."));
+ _("This could mean that your mailserver is stuck, or that your SMTP\r\n" \
+ "server is wedged, or that your mailbox file on the server has been\r\n" \
+ "corrupted by a server error. You can run `fetchmail -v -v' to\r\n" \
+ "diagnose the problem.\r\n\r\n" \
+ "Fetchmail won't poll this mailbox again until you restart it.\r\n"));
close_warning_by_mail(ctl, (struct msgblk *)NULL);
ctl->wedged = TRUE;
}
/* try to clean up all streams */
release_sink(ctl);
if (ctl->smtp_socket != -1)
- close(ctl->smtp_socket);
+ SockClose(ctl->smtp_socket);
if (mailserver_socket != -1)
SockClose(mailserver_socket);
}
else
{
- char buf[POPBUFSIZE+1], *realhost;
+ char buf[MSGBUFSIZE+1], *realhost;
int len, num, count, new, bytes, deletions = 0, *msgsizes = NULL;
-#if INET6
+#if INET6_ENABLE
int fetches, dispatches, oldphase;
-#else /* INET6 */
+#else /* INET6_ENABLE */
int port, fetches, dispatches, oldphase;
-#endif /* INET6 */
+#endif /* INET6_ENABLE */
struct idlist *idp;
/* execute pre-initialization command, if any */
oldphase = phase;
phase = OPEN_WAIT;
set_timeout(mytimeout);
-#if !INET6
+#if !INET6_ENABLE
#ifdef SSL_ENABLE
port = ctl->server.port ? ctl->server.port : ( ctl->use_ssl ? protocol->sslport : protocol->port );
#else
port = ctl->server.port ? ctl->server.port : protocol->port;
#endif
-#endif /* !INET6 */
+#endif /* !INET6_ENABLE */
realhost = ctl->server.via ? ctl->server.via : ctl->server.pollname;
/* allow time for the port to be set up if we have a plugin */
if (ctl->server.plugin)
(void)sleep(1);
-#if INET6
+#if INET6_ENABLE
if ((mailserver_socket = SockOpen(realhost,
ctl->server.service ? ctl->server.service : protocol->service,
ctl->server.netsec, ctl->server.plugin)) == -1)
-#else /* INET6 */
+#else /* INET6_ENABLE */
if ((mailserver_socket = SockOpen(realhost, port, NULL, ctl->server.plugin)) == -1)
-#endif /* INET6 */
+#endif /* INET6_ENABLE */
{
-#if !INET6
+ char errbuf[BUFSIZ];
+#if !INET6_ENABLE
int err_no = errno;
#ifdef HAVE_RES_SEARCH
if (err_no != 0 && h_errno != 0)
* in daemon mode but the connection to the outside world
* is down.
*/
- if (err_no == EHOSTUNREACH && run.poll_interval)
- goto ehostunreach;
-
- report_build(stderr, _("fetchmail: %s connection to %s failed"),
- protocol->name, ctl->server.pollname);
-#ifdef HAVE_RES_SEARCH
- if (h_errno != 0)
+ if (!((err_no == EHOSTUNREACH || err_no == ENETUNREACH)
+ && run.poll_interval))
{
- if (h_errno == HOST_NOT_FOUND)
- report_complete(stderr, _(": host is unknown\n"));
- else if (h_errno == NO_ADDRESS)
- report_complete(stderr, _(": name is valid but has no IP address\n"));
- else if (h_errno == NO_RECOVERY)
- report_complete(stderr, _(": unrecoverable name server error\n"));
- else if (h_errno == TRY_AGAIN)
- report_complete(stderr, _(": temporary name server error\n"));
+ report_build(stderr, _("fetchmail: %s connection to %s failed"),
+ protocol->name, ctl->server.pollname);
+#ifdef HAVE_RES_SEARCH
+ if (h_errno != 0)
+ {
+ if (h_errno == HOST_NOT_FOUND)
+ strcpy(errbuf, _("host is unknown."));
+ else if (h_errno == NO_ADDRESS)
+ strcpy(errbuf, _("name is valid but has no IP address."));
+ else if (h_errno == NO_RECOVERY)
+ strcpy(errbuf, _("unrecoverable name server error."));
+ else if (h_errno == TRY_AGAIN)
+ strcpy(errbuf, _("temporary name server error."));
+ else
+ sprintf(errbuf, _("unknown DNS error %d."), h_errno);
+ }
else
- report_complete(stderr, _(": unknown DNS error %d\n"), h_errno);
- }
- else
#endif /* HAVE_RES_SEARCH */
- report_complete(stderr, ": %s\n", strerror(err_no));
-
- ehostunreach:
-#endif /* INET6 */
+ strcpy(errbuf, strerror(err_no));
+ report_complete(stderr, ": %s\n", errbuf);
+
+#ifdef __UNUSED
+ /*
+ * Don't use this. It was an attempt to address Debian bug
+ * #47143 (Notify user by mail when pop server nonexistent).
+ * Trouble is, that doesn't work; you trip over the case
+ * where your SLIP or PPP link is down...
+ */
+ /* warn the system administrator */
+ if (open_warning_by_mail(ctl, (struct msgblk *)NULL) == 0)
+ {
+#define OPENFAIL "Subject: Fetchmail unreachable-server warning.\r\n\r\nFetchmail could not reach the mail server %s:"
+ stuff_warning(ctl, OPENFAIL, ctl->server.pollname);
+ stuff_warning(ctl, errbuf, ctl->server.pollname);
+ close_warning_by_mail(ctl, (struct msgblk *)NULL);
+#undef OPENFAIL
+ }
+#endif
+ }
+#endif /* INET6_ENABLE */
ok = PS_SOCKET;
set_timeout(0);
phase = oldphase;
goto cleanUp;
/* try to get authorized to fetch mail */
+ stage = STAGE_GETAUTH;
if (protocol->getauth)
{
if (protocol->password_canonify)
report(stderr, _("Lock-busy error on %s@%s\n"),
ctl->remotename,
ctl->server.truename);
- else
+ else if (ok == PS_AUTHFAIL)
{
- if (ok == PS_ERROR)
- ok = PS_AUTHFAIL;
report(stderr, _("Authorization failure on %s@%s\n"),
ctl->remotename,
ctl->server.truename);
&& !open_warning_by_mail(ctl, (struct msgblk *)NULL))
{
stuff_warning(ctl,
- _("Subject: fetchmail authentication failed\r\n"));
+ _("Subject: fetchmail authentication failed\r\n"));
stuff_warning(ctl,
- _("Fetchmail could not get mail from %s@%s."),
- ctl->remotename,
- ctl->server.truename);
- stuff_warning(ctl,
- _("The attempt to get authorization failed."));
+ _("Fetchmail could not get mail from %s@%s.\r\n"),
+ ctl->remotename,
+ ctl->server.truename);
stuff_warning(ctl,
- _("This probably means your password is invalid."));
+ _("The attempt to get authorization failed.\r\n" \
+ "This probably means your password is invalid, but POP3 servers have\r\n" \
+ "other failure modes that fetchmail cannot distinguish from this\r\n" \
+ "because they don't send useful error messages on login failure.\r\n"));
close_warning_by_mail(ctl, (struct msgblk *)NULL);
ctl->wedged = TRUE;
}
}
+ else
+ report(stderr, _("Unknown login or authentication error on %s@%s\n"),
+ ctl->remotename,
+ ctl->server.truename);
+
goto cleanUp;
}
}
dispatches = 0;
++pass;
+ /* reset timeout, in case we did an IDLE */
+ mytimeout = ctl->server.timeout;
+
if (outlevel >= O_DEBUG)
{
if (idp->id)
}
/* compute # of messages and number of new messages waiting */
+ stage = STAGE_GETRANGE;
ok = (protocol->getrange)(mailserver_socket, ctl, idp->id, &count, &new, &bytes);
if (ok != 0)
goto cleanUp;
if (new == -1 || ctl->fetchall)
new = count;
fetches = new; /* set error status ccorrectly */
- goto no_error;
+ /*
+ * There used to be a `got noerror' here, but this
+ * prevneted checking of multiple folders. This
+ * comment is a reminder in case I introduced some
+ * subtle bug by removing it...
+ */
}
else if (count > 0)
{
for (i = 0; i < count; i++)
msgsizes[i] = -1;
+ stage = STAGE_GETSIZES;
ok = (proto->getsizes)(mailserver_socket, count, msgsizes);
if (ok != 0)
goto cleanUp;
}
/* read, forward, and delete messages */
+ stage = STAGE_FETCH;
for (num = 1; num <= count; num++)
{
flag toolarge = NUM_NONZERO(ctl->limit)
*/
if (protocol->fetch_body && !suppress_readbody)
{
- if (outlevel >= O_VERBOSE)
+ if (outlevel >= O_VERBOSE && isatty(1))
{
fputc('\n', stdout);
fflush(stdout);
/* tell server we got it OK and resynchronize */
if (protocol->trail)
{
- if (outlevel >= O_VERBOSE)
+ if (outlevel >= O_VERBOSE && isatty(1))
{
fputc('\n', stdout);
fflush(stdout);
}
} while
/*
- * Only re-poll if we had some actual forwards, allowed
- * deletions and had no errors.
+ * Only re-poll if we either had some actual forwards and
+ * either allowed deletions and had no errors.
* Otherwise it is far too easy to get into infinite loops.
*/
(dispatches && protocol->retry && !ctl->keep && !ctl->errcount);
cleanUp:
/* we only get here on error */
if (ok != 0 && ok != PS_SOCKET)
+ {
+ stage = STAGE_LOGOUT;
(protocol->logout_cmd)(mailserver_socket, ctl);
+ }
SockClose(mailserver_socket);
}