--*.o
*~
--.autotools
--.cproject
--.deps/
--.project
--.rsyncs
-ABOUT-NLS
-Makefile
-Makefile.in
+ \#*#
+ABOUT-NLS
aclocal.m4
autobuild/
autom4te.cache
++.autotools
build*
build*/
compile
config.sub
configure
configure.lineno
++.cproject
cscope.out
depcomp
++.deps/
dox/
+FAQ
+FEATURES
fetchmail
- fetchmail-*.tar.*
+ fetchmailconf
+fetchmail-FAQ.pdf
+fetchmail-man.html
+fetchmail.spec
- fetchmailconf
++fetchmail-*.tar.*
++fetchmail-*.tar.xz
genlsm.sh
++IMAPCapa
install-sh
libfm.a
m4/
+Mailbox-Names-UTF7.html
+Makefile
+Makefile.in
missing
mkinstalldirs
+mxget
netrc
+NOTES
++*.o
po/Makefile
po/POTFILES
++po/remove-potcdate.sed
po/stamp-po
++.project
py-compile
rcfile_l.c
rcfile_y.c
rfc2047e
rfc822
rfc822valid
++.rsyncs
stamp-h1
tags
+TODO
unmime
x509_name_match
ylwrap
- \#*#
-FAQ
-FEATURES
-IMAPCapa
-Mailbox-Names-UTF7.html
-NOTES
-TODO
-config.cache
-fetchmail-*.tar.xz
-fetchmail-FAQ.pdf
-fetchmail-man.html
-fetchmail.spec
-po/remove-potcdate.sed
* The --bsmtp - mode of operation may be removed in a future release.
* Given that OpenSSL is severely underdocumented, and needs license exceptions,
fetchmail may switch to a different SSL library.
+* SSLv2 support will be removed from a future fetchmail release. It has been
+ obsolete for more than a decade.
--------------------------------------------------------------------------------
+
+ fetchmail-7.0.0 (not yet released):
+
+ NOTE THIS IS AN ALPHA RELEASE THAT HAS NOT BEEN THOROUGHLY TESTED!
+
+ # MAJOR CHANGES
+ * The UIDL handler code is now much faster, especially noticable with lots of
+ mail kept on a POP3 server. Where the 6.3.X code was of O(n^2) complexity,
+ we're down to O(n log n).
+ Contributed by Rainer Weikusat, MAD Partners Ltd./MSS GmbH.
+ * The POP3 code now always uses UIDL, except if "fetchall" is in effect.
+ Fixes BerliOS Bug #16172.
+
+ # FEATURES ADDED
+ * Fetchmail can now retrieve credentials from PWMD. This needs to be enabled at
+ compile-time and requires run-time configuration. See README.PWMD for details.
+ Contributed by Ben Kibbey, author of libpwmd and pwmd.
+ * Fetchmail now supports a retrieve-error command line or rcfile option that
+ takes exactly one argument, abort (default), continue or markseen. This
+ specifies the policy used by fetchmail to handle messages whose bodies
+ fail to be retrieved due to server errors. Both the continue and markseen
+ options will skip the message with errors and allow the session to
+ continue so that subsequent messages can be retrieved. The markseen
+ option will also mark the message with errors as seen.
+ The default policy is to abort the session whenever a server error occurs.
+ Contributed by Craig Brown.
+
+ # REMOVED FEATURES
+ * IMAP2 protocol support was removed.
+ * POP2 protocol support was removed.
+ * RPOP (not actually a protocol, but a variant of POP3) was removed
+ * POP3: the uidl option has been removed. It is always on.
+ * POP3: LAST is no longer used. It was removed from POP3 in 1994, and it could
+ cause mail loss when the connection was interrupted or if clients besides
+ fetchmail polled the mailbox.
+ * Trio was removed, fetchmail expects reasonable stdio.h quality levels.
+ * Support for systems that do not conform to C89 and POSIX 2001 was removed,
+ this means that BeOS, EMX, NeXTSTEP quirks are no longer worked around.
+ * The MX and host alias DNS lookups that fetchmail performs in multidrop mode
+ have been removed. They were based on the mistaken assumption that the
+ IMAP/POP3 server was also the MX server, which is rarely the case. They have
+ never supported IPv6 (including IPv6-mapped IPv4) either.
+ Non-DNS based alias keywords such as "aka" remain.
+ * Kerberos IV support was removed.
+
+ # CHANGES
+ * A foreground fetchmail can now accept a few more options while another copy is
+ running in the background.
+
+ --------------------------------------------------------------------------------
fetchmail-6.3.20 (not yet released):
dnl
dnl XXX - if bumping version here, check fetchmail.man, too!
- AC_INIT([fetchmail],[6.3.20-pre1],[fetchmail-users@lists.berlios.de])
-AC_INIT([fetchmail],[7.0.0-alpha1],[fetchmail-devel@lists.berlios.de])
++AC_INIT([fetchmail],[6.4.0-alpha1],[fetchmail-devel@lists.berlios.de])
AC_CONFIG_SRCDIR([fetchmail.h])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_LIBOBJ_DIR([.])
static int cleanupSockClose (int fd)
/* close sockets in maximum CLEANUP_TIMEOUT seconds during cleanup */
{
- int scerror;
- SIGHANDLERTYPE alrmsave;
- alrmsave = set_signal_handler(SIGALRM, null_signal_handler);
- set_timeout(CLEANUP_TIMEOUT);
- scerror = SockClose(fd);
- set_timeout(0);
- set_signal_handler(SIGALRM, alrmsave);
- return (scerror);
+ (void)SockTimeout(fd, CLEANUP_TIMEOUT); /* ignore errors */
+ return SockClose(fd);
}
- #ifdef KERBEROS_V4
- static int kerberos_auth(socket, canonical, principal)
- /* authenticate to the server host using Kerberos V4 */
- int socket; /* socket to server host */
- char *canonical; /* server name */
- char *principal;
- {
- KTEXT ticket;
- MSG_DAT msg_data;
- CREDENTIALS cred;
- Key_schedule schedule;
- int rem;
- char * prin_copy = (char *) NULL;
- char * prin = (char *) NULL;
- char * inst = (char *) NULL;
- char * realm = (char *) NULL;
-
- if (principal != (char *)NULL && *principal)
- {
- char *cp;
- prin = prin_copy = xstrdup(principal);
- for (cp = prin_copy; *cp && *cp != '.'; ++cp)
- ;
- if (*cp)
- {
- *cp++ = '\0';
- inst = cp;
- while (*cp && *cp != '@')
- ++cp;
- if (*cp)
- {
- *cp++ = '\0';
- realm = cp;
- }
- }
- }
-
- ticket = xmalloc(sizeof (KTEXT_ST));
- rem = (krb_sendauth (0L, socket, ticket,
- prin ? prin : "pop",
- inst ? inst : canonical,
- realm ? realm : ((char *) (krb_realmofhost (canonical))),
- ((unsigned long) 0),
- (&msg_data),
- (&cred),
- (schedule),
- ((struct sockaddr_in *) 0),
- ((struct sockaddr_in *) 0),
- "KPOPV0.1"));
- free(ticket);
- if (prin_copy)
- {
- free(prin_copy);
- }
- if (rem != KSUCCESS)
- {
- report(stderr, GT_("kerberos error %s\n"), (krb_get_err_text (rem)));
- return (PS_AUTHFAIL);
- }
- return (0);
- }
- #endif /* KERBEROS_V4 */
-
#ifdef KERBEROS_V5
- static int kerberos5_auth(socket, canonical)
- /* authenticate to the server host using Kerberos V5 */
- int socket; /* socket to server host */
- const char *canonical; /* server name */
+ /** authenticate to the server host using Kerberos V5 */
+ static int kerberos5_auth(int socket /** socket to server host */, const char *canonical /** server name */)
{
krb5_error_code retval;
krb5_context context;
* higher and only when keeping mails. This flag will have an
* effect only when user has marked some unread mails for deletion
* using another e-mail client. */
- flag skipdeleted = (imap_version >= IMAP4) && ctl->keep;
+ flag skipdeleted = ctl->keep;
const char *undeleted;
- /* Skip range search if there are less than or equal to
- * IMAP_SEARCH_MAX mails. */
- flag skiprangesearch = (count <= IMAP_SEARCH_MAX);
+ /* structure to keep the end portion of the incomplete response */
+ struct RecvSplit rs;
/* startcount is higher than count so that if there are no
* unseen messages, imap_getsizes() will not need to do
(void) close(fds[0]);
return fds[1];
}
- #endif /* HAVE_SOCKETPAIR */
+static int setsocktimeout(int sock, int which, int timeout) {
+ struct timeval tv;
+ int rc;
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ rc = setsockopt(sock, SOL_SOCKET, which, &tv, sizeof(tv));
+ if (rc) {
+ report(stderr, GT_("setsockopt(%d, SOL_SOCKET) failed: %s"), sock, strerror(errno));
+ }
+ return rc;
+}
+
+/** Configure socket options such as send/receive timeout at the socket
+ * level, to avoid network-induced stalls. \return 0 for success, 1 for
+ * error.
+ */
+int SockTimeout(int sock, int timeout)
+{
+ int err = 0;
+
+ if (setsocktimeout(sock, SO_RCVTIMEO, timeout)) err = 1;
+ if (setsocktimeout(sock, SO_SNDTIMEO, timeout)) err = 1;
+ return err;
+}
+
+/** Set socket to SO_KEEPALIVE. \return 0 for success. */
+int SockKeepalive(int sock) {
+ int keepalive = 1;
+ return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof keepalive);
+}
+
int UnixOpen(const char *path)
{
int sock = -1;
return i;
}
++<<<<<<< HEAD
+#if defined(HAVE_STDARG_H)
++=======
+
++>>>>>>> before-cpp
int SockPrintf(int sock, const char* format, ...)
{
- #else
- int SockPrintf(sock,format,va_alist)
- int sock;
- char *format;
- va_dcl {
- #endif
-
va_list ap;
char buf[8192];
#include <stdio.h>
#include <string.h>
#include <ctype.h>
- #ifdef HAVE_MEMORY_H
- #include <memory.h>
- #endif /* HAVE_MEMORY_H */
- #if defined(STDC_HEADERS)
#include <stdlib.h>
- #endif
- #if defined(HAVE_UNISTD_H)
#include <unistd.h>
- #endif
- #if defined(HAVE_STDARG_H)
#include <stdarg.h>
- #else
- #include <varargs.h>
- #endif
#include <limits.h>
+#include <assert.h>
- #ifdef HAVE_NET_SOCKET_H
- #include <net/socket.h>
- #endif
#include <sys/socket.h>
#include <netdb.h>
#include "fm_md5.h"
}
}
- #if defined(HAVE_STDARG_H)
-void gen_send(int sock, const char *fmt, ... )
-/* assemble command in printf(3) style and send to the server */
+/** assemble command in printf(3) style and send to the server */
- void gen_send(int sock, const char *fmt, ... )
- #else
- void gen_send(sock, fmt, va_alist)
- int sock; /** socket to which server is connected */
- const char *fmt; /** printf-style format */
- va_dcl
- #endif
++void gen_send(int sock/** socket to which server is connected */,
++ const char *fmt /** printf-style format */,
++ ...)
{
char buf [MSGBUFSIZE+1];
va_list ap;
else
{
set_timeout(0);
- if (buf[strlen(buf)-1] == '\n')
- buf[strlen(buf)-1] = '\0';
- if (buf[strlen(buf)-1] == '\r')
- buf[strlen(buf)-1] = '\0';
+ n = strlen(buf);
+ if (n > 0 && buf[n-1] == '\n')
+ buf[--n] = '\0';
+ if (n > 0 && buf[n-1] == '\r')
+ buf[--n] = '\0';
if (outlevel >= O_MONITOR)
report(stdout, "%s< %s\n", protocol->name, buf);
+ return(PS_SUCCESS);
+ }
+}
+
+/** \addtogroup gen_recv_split
+ * @{
+ * gen_recv_split() splits the response from a server which is too
+ * long to fit into the buffer into multiple lines. If the prefix is
+ * set as "MY FEATURES" and the response from the server is too long
+ * to fit in the buffer, as in:
+ *
+ * "MY FEATURES ABC DEF GHI JKLMNOPQRS TU VWX YZ"
+ *
+ * Repeated calls to gen_recv_split() may return:
+ *
+ * "MY FEATURES ABC DEF GHI"
+ * "MY FEATURES JKLMNOPQRS"
+ * "MY FEATURES TU VWX YZ"
+ *
+ * A response not beginning with the prefix "MY FEATURES" will not be
+ * split.
+ *
+ * To use:
+ * - Declare a variable of type struct RecvSplit
+ * - Call gen_recv_split_init() once
+ * - Call gen_recv_split() in a loop, preferably with the same buffer
+ * size as the "buf" array in struct RecvSplit
+ */
+
+static void overrun(const char *f, size_t l) __attribute__((noreturn));
+
+/** Internal error report function. If this happens, the calling site
+ * needs to be adjusted to set a shorter prefix, or the prefix capacity
+ * needs to be raised in struct RecvSplit. */
+static void overrun(const char *f, size_t l)
+{
+ report(stderr, GT_("Buffer too small. This is a bug in the caller of %s:%lu.\n"), f, (unsigned long)l);
+ abort();
+}
+
+/** Initialize \a rs for later use by gen_recv_split. */
+void gen_recv_split_init (const char *prefix /** prefix to match/repeat */,
+ struct RecvSplit *rs /** structure to be initialized */)
+{
+ if (strlcpy(rs->prefix, prefix, sizeof(rs->prefix)) > sizeof(rs->prefix))
+ overrun(__FILE__, __LINE__);
+ rs->cached = 0;
+ rs->buf[0] = '\0';
+}
+
+/** Function to split replies at blanks, and duplicate prefix.
+ * gen_recv_split_init() must be called before this can be used. */
+int gen_recv_split(int sock /** socket to which server is connected */,
+ char *buf /** buffer to receive input */,
+ int size /** length of buffer, must be the same for all calls */,
+ struct RecvSplit *rs /** cached information across calls */)
+{
+ size_t n = 0;
+ int foundnewline = 0;
+ char *p;
+ int oldphase = phase; /* we don't have to be re-entrant */
+
+ assert(size > 0);
+
+ /* if this is not our first call, prepare the buffer */
+ if (rs->cached)
+ {
+ /*
+ * if this condition is not met, we lose data
+ * because the cached data does not fit into the buffer.
+ * this cannot happen if size is the same throughout all calls.
+ */
+ assert(strlen(rs->prefix) + strlen(rs->buf) + 1 <= (size_t)size);
+
+ if ((strlcpy(buf, rs->prefix, size) >= (size_t)size)
+ || (strlcat(buf, rs->buf, size) >= (size_t)size)) {
+ overrun(__FILE__, __LINE__);
+ }
+
+ n = strlen(buf);
+ /* clear the cache for the next call */
+ rs->cached = 0;
+ rs->buf[0] = '\0';
+ }
+
+ if ((size_t)size > n) {
+ int rr;
+
+ phase = SERVER_WAIT;
+ set_timeout(mytimeout);
+ rr = SockRead(sock, buf + n, size - n);
+ set_timeout(0);
phase = oldphase;
+ if (rr == -1)
+ return PS_SOCKET;
+ }
+
+ n = strlen(buf);
+ if (n > 0 && buf[n-1] == '\n')
+ {
+ buf[--n] = '\0';
+ foundnewline = 1;
+ }
+ if (n > 0 && buf[n-1] == '\r')
+ buf[--n] = '\0';
+
+ if (foundnewline /* we have found a complete line */
+ || strncasecmp(buf, rs->prefix, strlen(rs->prefix)) /* mismatch in prefix */
+ || !(p = strrchr(buf, ' ')) /* no space found in response */
+ || p < buf + strlen(rs->prefix)) /* space is at the wrong location */
+ {
+ if (outlevel >= O_MONITOR)
+ report(stdout, "%s< %s\n", protocol->name, buf);
return(PS_SUCCESS);
}
+
+ /* we are ready to cache some information now. */
+ rs->cached = 1;
+ if (strlcpy(rs->buf, p, sizeof(rs->buf)) >= sizeof(rs->buf)) {
+ overrun(__FILE__, __LINE__);
+ }
+ *p = '\0'; /* chop off what we've cached */
+ if (outlevel >= O_MONITOR)
+ report(stdout, "%s< %s\n", protocol->name, buf);
+ if (outlevel >= O_DEBUG)
+ report(stdout, "%s< %s%s...\n", protocol->name, rs->prefix, rs->buf);
+ return(PS_SUCCESS);
}
+/** @} */
- #if defined(HAVE_STDARG_H)
--int gen_transact(int sock, const char *fmt, ... )
- #else
- int gen_transact(int sock, fmt, va_alist)
- int sock; /** socket to which server is connected */
- const char *fmt; /** printf-style format */
- va_dcl
- #endif
-/* assemble command in printf(3) style, send to server, accept a response */
+/** assemble command in printf(3) style, send to server, fetch a response */
++int gen_transact(int sock /** socket to which server is connected */,
++ const char *fmt /** printf-style format */,
++ ...)
{
int ok;
char buf [MSGBUFSIZE+1];