#if defined(HAVE_SYS_ITIMER_H)
#include <sys/itimer.h>
#endif
-#include <sys/time.h>
#include <signal.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
#ifdef HAVE_NET_SOCKET_H
#include <net/socket.h>
#endif
-#ifdef HESIOD
+#include <netdb.h>
+#ifdef HAVE_PKG_hesiod
#include <hesiod.h>
#endif
-#if defined(HAVE_RES_SEARCH) || defined(HAVE_GETHOSTBYNAME)
-#include <netdb.h>
-#include "mx.h"
-#endif /* defined(HAVE_RES_SEARCH) || defined(HAVE_GETHOSTBYNAME) */
+#include <langinfo.h>
#include "kerberos.h"
#ifdef KERBEROS_V4
#include "socket.h"
#include "fetchmail.h"
+#include "getaddrinfo.h"
#include "tunable.h"
/* throw types for runtime errors */
flag peek_capable; /* can we peek for better error recovery? */
int mailserver_socket_temp = -1; /* socket to free if connect timeout */
-volatile static int timeoutcount = 0; /* count consecutive timeouts */
-volatile static int idletimeout = 0; /* timeout occured in idle stage? */
+static volatile int timeoutcount = 0; /* count consecutive timeouts */
+static volatile int idletimeout = 0; /* timeout occured in idle stage? */
static jmp_buf restart;
-int isidletimeout(void)
+int is_idletimeout(void)
/* last timeout occured in idle stage? */
{
return idletimeout;
void set_timeout(int timeleft)
/* reset the nonresponse-timeout */
{
-#if !defined(__EMX__) && !defined(__BEOS__)
+#if !defined(__EMX__) && !defined(__BEOS__)
struct itimerval ntimeout;
if (timeleft == 0)
}
}
- xalloca(ticket, KTEXT, sizeof (KTEXT_ST));
+ ticket = xmalloc(sizeof (KTEXT_ST));
rem = (krb_sendauth (0L, socket, ticket,
prin ? prin : "pop",
inst ? inst : canonical,
((struct sockaddr_in *) 0),
((struct sockaddr_in *) 0),
"KPOPV0.1"));
+ free(ticket);
if (prin_copy)
{
free(prin_copy);
krb5_auth_context auth_context = NULL;
krb5_init_context(&context);
- krb5_init_ets(context);
krb5_auth_con_init(context, &auth_context);
if (retval = krb5_cc_default(context, &ccdef)) {
*/
if (open_warning_by_mail(ctl, (struct msgblk *)NULL))
return;
- stuff_warning(ctl,
- GT_("Subject: Fetchmail oversized-messages warning.\n"
- "\n"
- "The following oversized messages remain on the mail server %s:"),
- ctl->server.pollname);
-
+ stuff_warning(iana_charset, ctl,
+ GT_("Subject: Fetchmail oversized-messages warning"));
+ stuff_warning(NULL, ctl, "%s", "");
+ if (ctl->limitflush)
+ stuff_warning(NULL, ctl,
+ GT_("The following oversized messages were deleted on server %s account %s:"),
+ ctl->server.pollname, ctl->remotename);
+ else
+ stuff_warning(NULL, ctl,
+ GT_("The following oversized messages remain on server %s account %s:"),
+ ctl->server.pollname, ctl->remotename);
+
+ stuff_warning(NULL, ctl, "%s", "");
+
if (run.poll_interval == 0)
max_warning_poll_count = 0;
else
if (current->val.status.num == 0 && current->val.status.mark)
{
nbr = current->val.status.mark;
- size = atoi(current->id);
- stuff_warning(ctl,
- GT_("\t%d msg %d octets long skipped by fetchmail.\n"),
- nbr, size);
+ size = atoi((const char *)current->id);
+ if (ctl->limitflush)
+ stuff_warning(NULL, ctl,
+ GT_(" %d msg %d octets long deleted by fetchmail."),
+ nbr, size);
+ else
+ stuff_warning(NULL, ctl,
+ GT_(" %d msg %d octets long skipped by fetchmail."),
+ nbr, size);
}
current->val.status.num++;
current->val.status.mark = 0;
current->val.status.num = 0;
}
+ stuff_warning(NULL, ctl, "%s", "");
+
close_warning_by_mail(ctl, (struct msgblk *)NULL);
}
int cnt;
/* convert size to string */
-#ifdef HAVE_SNPRINTF
- snprintf(sizestr, sizeof(sizestr),
-#else
- sprintf(sizestr,
-#endif /* HAVE_SNPRINTF */
- "%d", size);
+ snprintf(sizestr, sizeof(sizestr), "%d", size);
/* build a list of skipped messages
* val.id = size of msg (string cnvt)
cnt = current ? current->val.status.num : 0;
/* if entry exists, increment the count */
- if (current && str_in_list(¤t, sizestr, FALSE))
+ if (current && (tmp = str_in_list(¤t, sizestr, FALSE)))
{
- for ( ; current; current = current->next)
- {
- if (strcmp(current->id, sizestr) == 0)
- {
- current->val.status.mark++;
- break;
- }
- }
+ tmp->val.status.mark++;
}
/* otherwise, create a new entry */
/* initialise with current poll count */
}
static int fetch_messages(int mailserver_socket, struct query *ctl,
- int count, int *msgsizes, int maxfetch,
+ int count, int **msgsizes, int maxfetch,
int *fetches, int *dispatches, int *deletions)
/* fetch messages in lockstep mode */
{
int num, firstnum = 1, lastnum = 0, err, len;
int fetchsizelimit = ctl->fetchsizelimit;
int msgsize;
+ int initialfetches = *fetches;
if (ctl->server.base_protocol->getpartialsizes && NUM_NONZERO(fetchsizelimit))
{
/* for POP3, we can get the size of one mail only! Unfortunately, this
* protocol specific test cannot be done elsewhere as the protocol
* could be "auto". */
- if (ctl->server.protocol == P_POP3)
+ switch (ctl->server.protocol)
+ {
+ case P_POP3: case P_APOP: case P_RPOP:
fetchsizelimit = 1;
+ }
/* Time to allocate memory to store the sizes */
- xalloca(msgsizes, int *, sizeof(int) * fetchsizelimit);
+ xfree(*msgsizes);
+ *msgsizes = xmalloc(sizeof(int) * fetchsizelimit);
}
/*
if (lastnum > count)
lastnum = count;
for (i = 0; i < fetchsizelimit; i++)
- msgsizes[i] = 0;
+ (*msgsizes)[i] = 0;
stage = STAGE_GETSIZES;
- err = (ctl->server.base_protocol->getpartialsizes)(mailserver_socket, num, lastnum, msgsizes);
- if (err != 0)
+ err = (ctl->server.base_protocol->getpartialsizes)(mailserver_socket, num, lastnum, *msgsizes);
+ if (err != 0) {
return err;
+ }
stage = oldstage;
}
- msgsize = msgsizes ? msgsizes[num-firstnum] : 0;
+ msgsize = *msgsizes ? (*msgsizes)[num-firstnum] : 0;
/* check if the message is oversized */
if (NUM_NONZERO(ctl->limit) && (msgsize > ctl->limit))
if (msgcode < 0)
{
- if ((msgcode == MSGLEN_TOOLARGE) && !check_only)
+ if (msgcode == MSGLEN_TOOLARGE)
{
mark_oversized(ctl, num, msgsize);
- suppress_delete = TRUE;
+ if (!ctl->limitflush)
+ suppress_delete = TRUE;
}
if (outlevel > O_SILENT)
{
num, count);
if (len > 0)
- report_build(stdout, GT_(" (%d %soctets)"),
- len, wholesize ? "" : GT_("header "));
+ report_build(stdout, wholesize ? GT_(" (%d octets)")
+ : GT_(" (%d header octets)"), len);
if (outlevel >= O_VERBOSE)
report_complete(stdout, "\n");
else
/* tell server we got it OK and resynchronize */
if (separatefetchbody && ctl->server.base_protocol->trail)
{
- if (outlevel >= O_VERBOSE && !isafile(1))
+ if (outlevel >= O_VERBOSE && !is_a_file(1))
{
fputc('\n', stdout);
fflush(stdout);
}
- if ((err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num)))
+ if ((err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num, tag)))
return(err);
}
/* tell server we got it OK and resynchronize */
if (ctl->server.base_protocol->trail)
{
- if (outlevel >= O_VERBOSE && !isafile(1))
+ if (outlevel >= O_VERBOSE && !is_a_file(1))
{
fputc('\n', stdout);
fflush(stdout);
}
- err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num);
+ err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num, tag);
if (err != 0)
return(err);
}
else if (ctl->server.base_protocol->delete
&& !suppress_delete
&& ((msgcode >= 0 && !ctl->keep)
- || (msgcode == MSGLEN_OLD && ctl->flush)))
+ || (msgcode == MSGLEN_OLD && ctl->flush)
+ || (msgcode == MSGLEN_TOOLARGE && ctl->limitflush)))
{
(*deletions)++;
if (outlevel > O_SILENT)
/* perhaps this as many as we're ready to handle */
if (maxfetch && maxfetch <= *fetches && num < count)
{
- report(stdout, GT_("fetchlimit %d reached; %d messages left on server %s account %s\n"),
- maxfetch, count - *fetches, ctl->server.truename, ctl->remotename);
+ int remcount = count - (*fetches - initialfetches);
+ report(stdout,
+ ngettext("fetchlimit %d reached; %d message left on server %s account %s\n",
+ "fetchlimit %d reached; %d messages left on server %s account %s\n", remcount),
+ maxfetch, remcount, ctl->server.truename, ctl->remotename);
return(PS_MAXFETCH);
}
- }
+ } /* for (num = 1; num <= count; num++) */
return(PS_SUCCESS);
}
-static int do_session(ctl, proto, maxfetch)
/* retrieve messages from server using given protocol method table */
-struct query *ctl; /* parsed options with merged-in defaults */
-const struct method *proto; /* protocol method table */
-const int maxfetch; /* maximum number of messages to fetch */
+static int do_session(
+ /* parsed options with merged-in defaults */
+ struct query *ctl,
+ /* protocol method table */
+ const struct method *proto,
+ /* maximum number of messages to fetch */
+ const int maxfetch)
{
- int js;
-#ifdef HAVE_VOLATILE
+ static int *msgsizes;
volatile int err, mailserver_socket = -1; /* pacifies -Wall */
-#else
- int err, mailserver_socket = -1;
-#endif /* HAVE_VOLATILE */
+ int tmperr;
+ int deletions = 0, js;
const char *msg;
SIGHANDLERTYPE pipesave;
SIGHANDLERTYPE alrmsave;
ctl->server.base_protocol = proto;
+ msgsizes = NULL;
pass = 0;
err = 0;
init_transact(proto);
if ((js = setjmp(restart)))
{
+ /* exception caught */
#ifdef HAVE_SIGPROCMASK
/*
* Don't rely on setjmp() to restore the blocked-signal mask.
if (timeoutcount > MAX_TIMEOUTS
&& !open_warning_by_mail(ctl, (struct msgblk *)NULL))
{
- stuff_warning(ctl,
- GT_("Subject: fetchmail sees repeated timeouts\n"));
- stuff_warning(ctl,
+ stuff_warning(iana_charset, ctl,
+ GT_("Subject: fetchmail sees repeated timeouts"));
+ stuff_warning(NULL, ctl, "%s", "");
+ stuff_warning(NULL, ctl,
GT_("Fetchmail saw more than %d timeouts while attempting to get mail from %s@%s.\n"),
MAX_TIMEOUTS,
- ctl->remotename,
- ctl->server.truename);
- stuff_warning(ctl,
+ ctl->remotename, ctl->server.truename);
+ stuff_warning(NULL, ctl,
GT_("This could mean that your mailserver is stuck, or that your SMTP\n" \
"server is wedged, or that your mailbox file on the server has been\n" \
"corrupted by a server error. You can run `fetchmail -v -v' to\n" \
}
else
{
+ /* setjmp returned zero -> normal operation */
char buf[MSGBUFSIZE+1], *realhost;
- int count, new, bytes, deletions = 0;
- int *msgsizes = (int *)NULL;
-#if INET6_ENABLE
+ int count, new, bytes;
int fetches, dispatches, oldphase;
-#else /* INET6_ENABLE */
- int port, fetches, dispatches, oldphase;
-#endif /* INET6_ENABLE */
struct idlist *idp;
/* execute pre-initialization command, if any */
oldphase = phase;
phase = OPEN_WAIT;
set_timeout(mytimeout);
-#if !INET6_ENABLE
-#ifdef SSL_ENABLE
- port = ctl->server.port ? ctl->server.port : ( ctl->use_ssl ? ctl->server.base_protocol->sslport : ctl->server.base_protocol->port );
-#else
- port = ctl->server.port ? ctl->server.port : ctl->server.base_protocol->port;
-#endif
-#endif /* !INET6_ENABLE */
-#ifdef HESIOD
+#ifdef HAVE_PKG_hesiod
/* If either the pollname or vianame are "hesiod" we want to
lookup the user's hesiod pobox host */
if (!strcasecmp(ctl->server.queryname, "hesiod")) {
}
#endif /* HESIOD */
-#ifdef HAVE_GETHOSTBYNAME
/*
* Canonicalize the server truename for later use. This also
* functions as a probe for whether the mailserver is accessible.
goto closeUp;
}
+ xfree(ctl->server.truename);
ctl->server.truename = xstrdup(leadname);
}
else
{
- struct hostent *namerec;
-
- /*
- * Get the host's IP, so we can report it like this:
- *
- * Received: from hostname [10.0.0.1]
- */
- errno = 0;
- namerec = gethostbyname(ctl->server.queryname);
- if (namerec == (struct hostent *)NULL)
+ struct addrinfo hints, *res;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_CANONNAME;
+
+ error = getaddrinfo(ctl->server.queryname, NULL, &hints, &res);
+ if (error)
{
report(stderr,
GT_("couldn't find canonical DNS name of %s (%s)\n"),
phase = oldphase;
goto closeUp;
}
- else
+ else
{
- ctl->server.truename=xstrdup((char *)namerec->h_name);
- ctl->server.trueaddr=xmalloc(namerec->h_length);
- memcpy(ctl->server.trueaddr,
- namerec->h_addr_list[0],
- namerec->h_length);
+ xfree(ctl->server.truename);
+ ctl->server.truename = xstrdup(res->ai_canonname);
+ ctl->server.trueaddr = xmalloc(res->ai_addrlen);
+ ctl->server.trueaddr_len = res->ai_addrlen;
+ memcpy(ctl->server.trueaddr, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
}
}
}
-#endif /* HAVE_GETHOSTBYNAME */
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_ENABLE
if ((mailserver_socket = SockOpen(realhost,
ctl->server.service ? ctl->server.service : ( ctl->use_ssl ? ctl->server.base_protocol->sslservice : ctl->server.base_protocol->service ),
- ctl->server.netsec, ctl->server.plugin)) == -1)
-#else /* INET6_ENABLE */
- if ((mailserver_socket = SockOpen(realhost, port, NULL, ctl->server.plugin)) == -1)
-#endif /* INET6_ENABLE */
+ ctl->server.plugin)) == -1)
{
char errbuf[BUFSIZ];
-#if !INET6_ENABLE
int err_no = errno;
-#ifdef HAVE_RES_SEARCH
- if (err_no != 0 && h_errno != 0)
- report(stderr, GT_("internal inconsistency\n"));
-#endif
/*
* Avoid generating a bogus error every poll cycle when we're
* in daemon mode but the connection to the outside world
{
report_build(stderr, GT_("%s connection to %s failed"),
ctl->server.base_protocol->name, ctl->server.pollname);
-#ifdef HAVE_RES_SEARCH
- if (h_errno != 0)
- {
- if (h_errno == HOST_NOT_FOUND)
- strcpy(errbuf, GT_("host is unknown."));
-#ifndef __BEOS__
- else if (h_errno == NO_ADDRESS)
- strcpy(errbuf, GT_("name is valid but has no IP address."));
-#endif
- else if (h_errno == NO_RECOVERY)
- strcpy(errbuf, GT_("unrecoverable name server error."));
- else if (h_errno == TRY_AGAIN)
- strcpy(errbuf, GT_("temporary name server error."));
- else
-#ifdef HAVE_SNPRINTF
- snprintf(errbuf, sizeof(errbuf),
-#else
- sprintf(errbuf,
-#endif /* HAVE_SNPRINTF */
- GT_("unknown DNS error %d."), h_errno);
- }
- else
-#endif /* HAVE_RES_SEARCH */
- strcpy(errbuf, strerror(err_no));
+ strlcpy(errbuf, strerror(err_no), sizeof(errbuf));
report_complete(stderr, ": %s\n", errbuf);
#ifdef __UNUSED
/* warn the system administrator */
if (open_warning_by_mail(ctl, (struct msgblk *)NULL) == 0)
{
- stuff_warning(ctl,
- GT_("Subject: Fetchmail unreachable-server warning.\n"
- "\n"
- "Fetchmail could not reach the mail server %s:")
+ 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(ctl, errbuf, ctl->server.pollname);
+ stuff_warning(NULL, ctl, errbuf, ctl->server.pollname);
close_warning_by_mail(ctl, (struct msgblk *)NULL);
}
#endif
}
-#endif /* INET6_ENABLE */
err = PS_SOCKET;
set_timeout(0);
phase = oldphase;
ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1)
{
report(stderr, GT_("SSL connection failed.\n"));
- err = PS_AUTHFAIL;
- goto closeUp;
+ err = PS_SOCKET;
+ goto cleanUp;
}
/* Fetchmail didn't hang on SSLOpen,
&& !open_warning_by_mail(ctl, (struct msgblk *)NULL))
{
ctl->wehavesentauthnote = 1;
- stuff_warning(ctl,
- GT_("Subject: fetchmail authentication failed on %s@%s\n"),
+ stuff_warning(iana_charset, ctl,
+ GT_("Subject: fetchmail authentication failed on %s@%s"),
ctl->remotename, ctl->server.truename);
- stuff_warning(ctl,
+ stuff_warning(NULL, ctl, "%s", "");
+ stuff_warning(NULL, ctl,
GT_("Fetchmail could not get mail from %s@%s.\n"),
ctl->remotename,
ctl->server.truename);
if (ctl->wehaveauthed)
- stuff_warning(ctl, GT_("\
+ stuff_warning(NULL, ctl, GT_("\
The attempt to get authorization failed.\n\
Since we have already succeeded in getting authorization for this\n\
connection, this is probably another failure mode (such as busy server)\n\
at each cycle. No future notifications will be sent until service\n\
is restored."));
else
- stuff_warning(ctl, GT_("\
+ stuff_warning(NULL, ctl, GT_("\
The attempt to get authorization failed.\n\
This probably means your password is invalid, but some servers have\n\
other failure modes that fetchmail cannot distinguish from this\n\
ctl->server.truename);
if (!open_warning_by_mail(ctl, (struct msgblk *)NULL))
{
- stuff_warning(ctl,
- GT_("Subject: fetchmail authentication OK on %s@%s\n"),
+ stuff_warning(iana_charset, ctl,
+ GT_("Subject: fetchmail authentication OK on %s@%s"),
ctl->remotename, ctl->server.truename);
- stuff_warning(ctl,
+ stuff_warning(NULL, ctl, "%s", "");
+ stuff_warning(NULL, ctl,
GT_("Fetchmail was able to log into %s@%s.\n"),
ctl->remotename,
ctl->server.truename);
- stuff_warning(ctl,
+ stuff_warning(NULL, ctl,
GT_("Service has been restored.\n"));
close_warning_by_mail(ctl, (struct msgblk *)NULL);
/* compute # of messages and number of new messages waiting */
stage = STAGE_GETRANGE;
- err = (ctl->server.base_protocol->getrange)(mailserver_socket, ctl, idp->id, &count, &new, &bytes);
+ err = (ctl->server.base_protocol->getrange)(mailserver_socket, ctl, (const char *)idp->id, &count, &new, &bytes);
if (err != 0)
goto cleanUp;
/* show user how many messages we downloaded */
if (idp->id)
-#ifdef HAVE_SNPRINTF
(void) snprintf(buf, sizeof(buf),
-#else
- (void) sprintf(buf,
-#endif /* HAVE_SNPRINTF */
GT_("%s at %s (folder %s)"),
ctl->remotename, ctl->server.pollname, idp->id);
else
-#ifdef HAVE_SNPRINTF
- (void) snprintf(buf, sizeof(buf),
-#else
- (void) sprintf(buf,
-#endif /* HAVE_SNPRINTF */
- GT_("%s at %s"),
+ (void) snprintf(buf, sizeof(buf), GT_("%s at %s"),
ctl->remotename, ctl->server.pollname);
if (outlevel > O_SILENT)
{
else if (count != 0)
{
if (new != -1 && (count - new) > 0)
- report_build(stdout, GT_("%d %s (%d %s) for %s"),
- count, count > 1 ? GT_("messages") :
- GT_("message"),
+ report_build(stdout, ngettext("%d message (%d %s) for %s", "%d messages (%d %s) for %s", (unsigned long)count),
+ count,
count-new,
- GT_("seen"),
+ ngettext("seen", "seen", (unsigned long)count-new),
buf);
else
- report_build(stdout, GT_("%d %s for %s"),
- count, count > 1 ? GT_("messages") :
- GT_("message"), buf);
+ report_build(stdout, ngettext("%d message for %s",
+ "%d messages for %s",
+ count),
+ count, buf);
if (bytes == -1)
report_complete(stdout, ".\n");
else
if (count > INT_MAX/sizeof(int))
{
report(stderr, GT_("bogus message count!"));
- return(PS_PROTOCOL);
+ err = PS_PROTOCOL;
+ goto cleanUp;
}
/*
if (proto->getsizes &&
!(proto->getpartialsizes && NUM_NONZERO(ctl->fetchsizelimit)))
{
- xalloca(msgsizes, int *, sizeof(int) * count);
+ xfree(msgsizes);
+ msgsizes = xmalloc(sizeof(int) * count);
for (i = 0; i < count; i++)
msgsizes[i] = 0;
/* fetch in lockstep mode */
err = fetch_messages(mailserver_socket, ctl,
- count, msgsizes,
+ count, &msgsizes,
maxfetch,
&fetches, &dispatches, &deletions);
- if (err)
+ if (err != PS_SUCCESS && err != PS_MAXFETCH)
goto cleanUp;
if (!check_only && ctl->skipped
send_size_warnings(ctl);
}
}
+
+ /* 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)
+ goto cleanUp;
+ }
+ /* Return now if we have reached the fetchlimit */
+ if (maxfetch && maxfetch <= fetches)
+ goto no_error;
} while
/*
* Only re-poll if we either had some actual forwards and
(dispatches && ctl->server.base_protocol->retry && !ctl->keep && !ctl->errcount);
}
- /* no_error: */
- /* ordinary termination with no errors -- officially log out */
- err = (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
+ /* XXX: From this point onwards, preserve err unless a new error has occurred */
+
+ no_error:
+ /* PS_SUCCESS, PS_MAXFETCH: ordinary termination with no errors -- officially log out */
+ stage = STAGE_LOGOUT;
+ tmperr = (ctl->server.base_protocol->logout_cmd)(mailserver_socket, ctl);
+ if (tmperr != PS_SUCCESS)
+ err = tmperr;
/*
* Hmmmm...arguably this would be incorrect if we had fetches but
* no dispatches (due to oversized messages, etc.)
*/
- if (err == 0)
- err = (fetches > 0) ? PS_SUCCESS : PS_NOMAIL;
+ else if (err == PS_SUCCESS && fetches == 0)
+ err = PS_NOMAIL;
+ /*
+ * Close all SMTP delivery sockets. For optimum performance
+ * we'd like to hold them open til end of run, but (1) this
+ * loses if our poll interval is longer than the MTA's
+ * inactivity timeout, and (2) some MTAs (like smail) don't
+ * deliver after each message, but rather queue up mail and
+ * wait to actually deliver it until the input socket is
+ * closed.
+ *
+ * don't send QUIT for ODMR case because we're acting as a
+ * proxy between the SMTP server and client.
+ */
+ smtp_close(ctl, ctl->server.protocol != P_ODMR);
cleanupSockClose(mailserver_socket);
goto closeUp;
/* try to clean up all streams */
release_sink(ctl);
+ /*
+ * Sending SMTP QUIT on signal is theoretically nice, but led
+ * to a subtle bug. If fetchmail was terminated by signal
+ * while it was shipping message text, it would hang forever
+ * waiting for a command acknowledge. In theory we could
+ * enable the QUIT only outside of the message send. In
+ * practice, we don't care. All mailservers hang up on a
+ * dropped TCP/IP connection anyway.
+ */
smtp_close(ctl, 0);
if (mailserver_socket != -1) {
cleanupSockClose(mailserver_socket);
}
}
- msg = (const char *)NULL; /* sacrifice to -Wall */
+ /* no report on PS_AUTHFAIL */
+ msg = NULL;
switch (err)
{
case PS_SOCKET:
msg = GT_("DNS lookup");
break;
case PS_UNDEFINED:
- report(stderr, GT_("undefined error\n"));
+ msg = GT_("undefined");
break;
}
- /* no report on PS_MAXFETCH or PS_UNDEFINED or PS_AUTHFAIL */
- if (err==PS_SOCKET || err==PS_SYNTAX
- || err==PS_IOERR || err==PS_ERROR || err==PS_PROTOCOL
- || err==PS_LOCKBUSY || err==PS_SMTP || err==PS_DNS)
- {
- char *stem;
-
- if (phase == FORWARDING_WAIT || phase == LISTENER_WAIT)
- stem = GT_("%s error while delivering to SMTP host %s\n");
+ if (msg) {
+ if (phase == FORWARDING_WAIT || phase == LISTENER_WAIT
+ || err == PS_SMTP)
+ report(stderr, GT_("%s error while fetching from %s@%s and delivering to SMTP host %s\n"),
+ msg, ctl->remotename, ctl->server.pollname,
+ ctl->smtphost ? ctl->smtphost : GT_("unknown"));
else
- stem = GT_("%s error while fetching from %s\n");
- report(stderr, stem, msg, ctl->server.pollname);
+ report(stderr, GT_("%s error while fetching from %s@%s\n"),
+ msg, ctl->remotename, ctl->server.pollname);
}
closeUp:
+ xfree(msgsizes);
+
/* execute wrapup command, if any */
- if (ctl->postconnect && (err = system(ctl->postconnect)))
+ if (ctl->postconnect && (tmperr = system(ctl->postconnect)))
{
- report(stderr, GT_("post-connection command failed with status %d\n"), err);
+ report(stderr, GT_("post-connection command failed with status %d\n"), tmperr);
if (err == PS_SUCCESS)
err = PS_SYNTAX;
}
return(PS_SYNTAX);
}
}
- if (!proto->getsizes && NUM_SPECIFIED(ctl->limit))
+ if (!(proto->getsizes || proto->getpartialsizes)
+ && NUM_SPECIFIED(ctl->limit))
{
report(stderr,
GT_("Option --limit is not supported with %s\n"),