static int fetch_messages(int mailserver_socket, struct query *ctl,
int count, int **msgsizes, int maxfetch,
- int *fetches, int *dispatches, int *deletions)
+ int *fetches, int *dispatches, int *deletions,
+ int *transient_errors)
/* fetch messages in lockstep mode */
{
flag force_retrieval;
* could be "auto". */
switch (ctl->server.protocol)
{
- case P_POP3: case P_APOP:
+ case P_POP3:
fetchsizelimit = 1;
}
}
if (msgcode == MSGLEN_OLD)
{
- /* To avoid flooding the syslog when using --keep,
- * report "Skipped message" only when:
- * 1) --verbose is on, or
- * 2) fetchmail does not use syslog
- */
- if ( (outlevel >= O_VERBOSE) ||
- (outlevel > O_SILENT && !run.use_syslog)
- )
+ /*
+ * To avoid flooding the logs when using --keep, report
+ * skipping for old messages only when --flush is on.
+ */
+ if (outlevel > O_SILENT && ctl->flush)
{
report_build(stdout,
GT_("skipping message %s@%s:%d"),
GT_("couldn't fetch headers, message %s@%s:%d (%d octets)\n"),
ctl->remotename, ctl->server.truename, num,
msgsize);
+ (*transient_errors)++;
continue;
}
else if (err != 0)
if (err == PS_RETAINED)
suppress_forward = suppress_delete = retained = TRUE;
else if (err == PS_TRANSIENT)
+ {
suppress_delete = suppress_forward = TRUE;
+ (*transient_errors)++;
+ }
else if (err == PS_REFUSED)
suppress_forward = TRUE;
else if (err)
if (separatefetchbody)
{
len = -1;
- if ((err=(ctl->server.base_protocol->fetch_body)(mailserver_socket,ctl,num,&len)))
+ if ((err=(ctl->server.base_protocol->fetch_body)(mailserver_socket,ctl,num,&len))) {
+ if (err == PS_ERROR && ctl->server.retrieveerror) {
+ /*
+ * Mark a message with a protocol error as seen.
+ * This can be used to see which messages we've attempted
+ * to download, but failed.
+ */
+ if (ctl->server.retrieveerror == RE_MARKSEEN) {
+ if ((ctl->server.base_protocol->mark_seen)(mailserver_socket,ctl,num)) {
+ return(err);
+ }
+ }
+
+ if (ctl->server.retrieveerror != RE_ABORT) {
+ /*
+ * Do not abort download session. Continue with the next message.
+ *
+ * Prevents a malformed message from blocking all other messages
+ * behind it in the mailbox from being downloaded.
+ *
+ * Reconnect to SMTP to force this incomplete message to be dropped.
+ * Required because we've already begun the DATA portion of the
+ * interaction with the SMTP server (commands are ignored/
+ * considered part of the message data).
+ */
+ abort_message_sink(ctl);
+
+ // Ensure we don't delete the failed message from the server.
+ suppress_delete = TRUE;
+
+ // Bookkeeping required before next message can be downloaded.
+ goto flagthemail;
+ }
+ }
+
return(err);
+ }
+
/*
* Work around a bug in Novell's
* broken GroupWise IMAP server;
len);
if (err == PS_TRANSIENT)
+ {
suppress_delete = suppress_forward = TRUE;
+ (*transient_errors)++;
+ }
else if (err)
return(err);
}
else
{
- if ( (outlevel >= O_VERBOSE) ||
- /* To avoid flooding the syslog when using --keep,
- * report "Skipped message" only when:
- * 1) --verbose is on, or
- * 2) fetchmail does not use syslog, or
- * 3) the message was skipped for some other
- * reason than just being old.
- */
- (outlevel > O_SILENT && (!run.use_syslog || msgcode != MSGLEN_OLD))
- )
+ /*
+ * To avoid flooding the logs when using --keep, report
+ * skipping of new messages only.
+ */
+ if (outlevel > O_SILENT && msgcode != MSGLEN_OLD)
report_complete(stdout, GT_(" not flushed\n"));
/* maybe we mark this message as seen now? */
/* sigsetjmp returned zero -> normal operation */
char buf[MSGBUFSIZE+1], *realhost;
int count, newm, bytes;
- int fetches, dispatches, oldphase;
+ int fetches, dispatches, transient_errors, oldphase;
struct idlist *idp;
/* execute pre-initialization command, if any */
ctl->sslcommonname : realhost, ctl->server.pollname,
&ctl->remotename) == -1)
{
+ set_timeout(0);
report(stderr, GT_("SSL connection failed.\n"));
err = PS_SOCKET;
goto cleanUp;
pass = 0;
do {
dispatches = 0;
+ transient_errors = 0;
++pass;
/* reset timeout, in case we did an IDLE */
err = fetch_messages(mailserver_socket, ctl,
count, &msgsizes,
maxfetch,
- &fetches, &dispatches, &deletions);
+ &fetches, &dispatches, &deletions,
+ &transient_errors);
if (err != PS_SUCCESS && err != PS_MAXFETCH)
goto cleanUp;
+ if (transient_errors > MAX_TRANSIENT_ERRORS)
+ {
+ if (outlevel > O_SILENT)
+ {
+ report(stderr, GT_("Too many mails skipped (%d > %d) due to transient errors for %s\n"),
+ transient_errors, MAX_TRANSIENT_ERRORS, buf);
+ }
+ }
+
if (!check_only && ctl->skipped
&& run.poll_interval > 0 && !nodetach)
{
msg = GT_("socket");
break;
case PS_SYNTAX:
- msg = GT_("missing or bad RFC822 header");
+ msg = GT_("missing or bad RFC822 header or command line option");
break;
case PS_IOERR:
msg = GT_("MDA");