#endif
#include <netdb.h>
#ifdef HAVE_PKG_hesiod
+#ifdef __cplusplus
+extern "C" {
+#endif
#include <hesiod.h>
+#ifdef __cplusplus
+}
+#endif
#endif
#include <langinfo.h>
#include "getaddrinfo.h"
#include "tunable.h"
+#include "sdump.h"
+
/* throw types for runtime errors */
#define THROW_TIMEOUT 1 /* server timed out */
if (retval) {
#ifdef HEIMDAL
if (err_ret && err_ret->e_text) {
- report(stderr, GT_("krb5_sendauth: %s [server says '%*s'] \n"),
- error_message(retval),
- err_ret->e_text);
+ char *t = err_ret->e_text;
+ char *tt = sdump(t, strlen(t));
+ report(stderr, GT_("krb5_sendauth: %s [server says '%s']\n"),
+ error_message(retval), tt);
+ free(tt);
#else
if (err_ret && err_ret->text.length) {
- report(stderr, GT_("krb5_sendauth: %s [server says '%*s'] \n"),
- error_message(retval),
- err_ret->text.length,
- err_ret->text.data);
+ char *tt = sdump(err_ret->text.data, err_ret->text.length);
+ report(stderr, GT_("krb5_sendauth: %s [server says '%s']\n"),
+ error_message(retval), tt);
+ free(tt);
#endif
krb5_free_error(context, err_ret);
} else
}
}
+static int eat_trailer(int sock, struct query *ctl)
+{
+ /* we only need this LF if we're printing ticker dots
+ * AND we are dumping protocol traces. */
+ if (outlevel >= O_VERBOSE && want_progress()) fputc('\n', stdout);
+ return (ctl->server.base_protocol->trail)(sock, ctl, tag);
+}
+
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;
/* check if the message is old
* Note: the size of the message may not be known here */
- if (ctl->fetchall || force_retrieval)
- ;
- else if (ctl->server.base_protocol->is_old && (ctl->server.base_protocol->is_old)(mailserver_socket,ctl,num))
- msgcode = MSGLEN_OLD;
+ if (ctl->fetchall || force_retrieval) {
+ /* empty */
+ } else {
+ if (ctl->server.base_protocol->is_old && (ctl->server.base_protocol->is_old)(mailserver_socket,ctl,num)) {
+ msgcode = MSGLEN_OLD;
+ }
+ }
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 (len > 0)
report_build(stdout, wholesize ? GT_(" (%d octets)")
: GT_(" (%d header octets)"), len);
- if (outlevel >= O_VERBOSE)
- report_complete(stdout, "\n");
+ if (want_progress()) {
+ /* flush and add a blank to append ticker dots */
+ report_flush(stdout);
+ putchar(' ');
+ }
}
/*
/* pass the suppress_readbody flag only if the underlying
* protocol does not fetch the body separately */
separatefetchbody ? 0 : &suppress_readbody);
+
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)
/* tell server we got it OK and resynchronize */
if (separatefetchbody && ctl->server.base_protocol->trail)
{
- if (outlevel >= O_VERBOSE && !is_a_file(1) && !run.use_syslog)
- {
- fputc('\n', stdout);
- fflush(stdout);
- }
-
- if ((err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, tag)))
- return(err);
+ err = eat_trailer(mailserver_socket, ctl);
+ if (err) return(err);
}
/* do not read the body which is not being forwarded only if
*/
if (len == -1)
len = msgsize - msgblk.msglen;
- if (outlevel > O_SILENT && !wholesize)
- report_build(stdout,
- GT_(" (%d body octets)"), len);
+ if (!wholesize) {
+ if (outlevel > O_SILENT)
+ report_build(stdout,
+ GT_(" (%d body octets)"), len);
+ if (want_progress()) {
+ report_flush(stdout);
+ putchar(' ');
+ }
+ }
}
/* process the body now */
ctl,
!suppress_forward,
len);
+
if (err == PS_TRANSIENT)
+ {
suppress_delete = suppress_forward = TRUE;
+ (*transient_errors)++;
+ }
else if (err)
return(err);
/* tell server we got it OK and resynchronize */
- if (ctl->server.base_protocol->trail)
- {
- if (outlevel >= O_VERBOSE && !is_a_file(1) && !run.use_syslog)
- {
- fputc('\n', stdout);
- fflush(stdout);
- }
-
- err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, tag);
- if (err != 0)
- return(err);
+ if (ctl->server.base_protocol->trail) {
+ err = eat_trailer(mailserver_socket, ctl);
+ if (err) return(err);
}
}
flagthemail:
/*
- * At this point in flow of control, either
- * we've bombed on a protocol error or had
- * delivery refused by the SMTP server
- * (unlikely -- I've never seen it) or we've
- * seen `accepted for delivery' and the
- * message is shipped. It's safe to mark the
- * message seen and delete it on the server
- * now.
+ * At this point in flow of control,
+ * either we've bombed on a protocol error
+ * or had delivery refused by the SMTP server
+ * or we've seen `accepted for delivery' and the message is shipped.
+ * It's safe to mark the message seen and delete it on the server now.
*/
+ /* in softbounce mode, suppress deletion and marking as seen */
+ if (suppress_forward)
+ suppress_delete = suppress_delete || run.softbounce;
+
/* maybe we delete this message now? */
if (retained)
{
}
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 */
if (ctl->preconnect && (err = system(ctl->preconnect)))
{
- report(stderr,
- GT_("pre-connection command failed with status %d\n"), err);
+ if (WIFSIGNALED(err))
+ report(stderr,
+ GT_("pre-connection command terminated with signal %d\n"), WTERMSIG(err));
+ else
+ report(stderr,
+ GT_("pre-connection command failed with status %d\n"), WEXITSTATUS(err));
err = PS_SYNTAX;
goto closeUp;
}
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_CANONNAME;
+#ifdef AI_ADDRCONFIG
+ hints.ai_flags |= AI_ADDRCONFIG;
+#endif
error = fm_getaddrinfo(ctl->server.queryname, NULL, &hints, &res);
if (error)
strlcpy(errbuf, strerror(err_no), sizeof(errbuf));
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) == 0)
- {
- stuff_warning(iana_charset, ctl,
- GT_("Subject: Fetchmail unreachable-server warning."));
- stuff_warning(NULL, ctl, "");
- stuff_warning(NULL, ctl, GT_("Fetchmail could not reach the mail server %s:"),
- ctl->server.pollname);
- stuff_warning(NULL, ctl, errbuf, ctl->server.pollname);
- close_warning_by_mail(ctl, (struct msgblk *)NULL);
- }
-#endif
}
err = PS_SOCKET;
set_timeout(0);
/* perform initial SSL handshake on open connection */
if (ctl->use_ssl &&
SSLOpen(mailserver_socket, ctl->sslcert, ctl->sslkey,
- ctl->sslproto, ctl->sslcertck, ctl->sslcertpath,
+ ctl->sslproto, ctl->sslcertck,
+ ctl->sslcertfile, ctl->sslcertpath,
ctl->sslfingerprint, ctl->sslcommonname ?
ctl->sslcommonname : realhost, ctl->server.pollname,
&ctl->remotename) == -1)
{
+ set_timeout(0);
report(stderr, GT_("SSL connection failed.\n"));
err = PS_SOCKET;
goto cleanUp;
stage = STAGE_GETAUTH;
if (ctl->server.base_protocol->getauth)
{
+ set_timeout(mytimeout);
err = (ctl->server.base_protocol->getauth)(mailserver_socket, ctl, buf);
+ set_timeout(0);
if (err != 0)
{
ctl->server.truename,
(ctl->wehaveauthed ? GT_(" (previously authorized)") : "")
);
+ if (ctl->server.authenticate == A_ANY && !ctl->wehaveauthed) {
+ report(stderr, GT_("For help, see http://www.fetchmail.info/fetchmail-FAQ.html#R15\n"));
+ }
/*
* If we're running in background, try to mail the
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)
{
/* end-of-mailbox processing before we repoll or switch to another one */
if (ctl->server.base_protocol->end_mailbox_poll)
{
- err = (ctl->server.base_protocol->end_mailbox_poll)(mailserver_socket, ctl);
- if (err)
+ tmperr = (ctl->server.base_protocol->end_mailbox_poll)(mailserver_socket, ctl);
+ if (tmperr) {
+ err = tmperr;
goto cleanUp;
+ }
}
/* Return now if we have reached the fetchlimit */
if (maxfetch && maxfetch <= fetches)
smtp_close(ctl, 0);
if (mailserver_socket != -1) {
cleanupSockClose(mailserver_socket);
- mailserver_socket = -1;
}
/* If there was a connect timeout, the socket should be closed.
* mailserver_socket_temp contains the socket to close.
/* execute wrapup command, if any */
if (ctl->postconnect && (tmperr = system(ctl->postconnect)))
{
- report(stderr, GT_("post-connection command failed with status %d\n"), tmperr);
+ if (WIFSIGNALED(tmperr))
+ report(stderr, GT_("post-connection command terminated with signal %d\n"), WTERMSIG(tmperr));
+ else
+ report(stderr, GT_("post-connection command failed with status %d\n"), WEXITSTATUS(tmperr));
if (err == PS_SUCCESS)
err = PS_SYNTAX;
}