]> Pileus Git - ~andy/fetchmail/blobdiff - fetchmail.c
Attempt merging from 6.3.24.
[~andy/fetchmail] / fetchmail.c
index 1c895a0a3cc7c36a63bfe0953a4157b7772bee88..b33cf5858840a4f1ce039b8bb31355075100e177 100644 (file)
@@ -6,18 +6,12 @@
 #include "config.h"
 
 #include <stdio.h>
-#if defined(STDC_HEADERS)
 #include <stdlib.h>
-#endif
-#if defined(HAVE_UNISTD_H)
 #include <unistd.h>
-#endif
 #include <fcntl.h>
 #include <string.h>
 #include <signal.h>
-#if defined(HAVE_SYSLOG)
 #include <syslog.h>
-#endif
 #include <pwd.h>
 #ifdef __FreeBSD__
 #include <grp.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#ifdef HAVE_SETRLIMIT
 #include <sys/resource.h>
-#endif /* HAVE_SETRLIMIT */
 
 #ifdef HAVE_SOCKS
 #include <socks.h> /* SOCKSinit() */
 #endif /* HAVE_SOCKS */
 
-#ifdef HAVE_LANGINFO_H
 #include <langinfo.h>
-#endif
 
 #include "fetchmail.h"
 #include "socket.h"
 #include "tunable.h"
 #include "smtp.h"
 #include "netrc.h"
-#include "i18n.h"
+#include "gettext.h"
 #include "lock.h"
 
+/* need these (and sys/types.h) for res_init() */
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
 #ifndef ENETUNREACH
 #define ENETUNREACH   128       /* Interactive doesn't know this */
 #endif /* ENETUNREACH */
@@ -67,9 +62,9 @@ flag versioninfo;         /* emit only version info */
 char *user;                /* the name of the invoking user */
 char *home;                /* invoking user's home directory */
 char *fmhome;              /* fetchmail's home directory */
-char *program_name;        /* the name to prefix error messages with */
+const char *program_name;   /* the name to prefix error messages with */
 flag configdump;           /* dump control blocks for configurator */
-char *fetchmailhost;       /* either `localhost' or the host's FQDN */
+const char *fetchmailhost;  /* either `localhost' or the host's FQDN */
 
 static int quitonly;       /* if we should quit after killing the running daemon */
 
@@ -79,8 +74,14 @@ static int activecount;              /* count number of active entries */
 static struct runctl cmd_run;  /* global options set from command line */
 static time_t parsetime;       /* time of last parse */
 
-static RETSIGTYPE terminate_run(int);
-static RETSIGTYPE terminate_poll(int);
+static void terminate_run(int);
+static void terminate_poll(int);
+
+#ifdef HAVE_LIBPWMD
+static pwm_t *pwm;             /* the handle */
+static const char *pwmd_socket;        /* current socket */
+static const char *pwmd_file;  /* current file */
+#endif
 
 #if defined(__FreeBSD__) && defined(__FreeBSD_USE_KVM)
 /* drop SGID kmem privileage until we need it */
@@ -103,8 +104,8 @@ static void dropprivs(void)
 }
 #endif
 
-#if defined(HAVE_SETLOCALE) && defined(ENABLE_NLS) && defined(HAVE_STRFTIME)
 #include <locale.h>
+#if defined(ENABLE_NLS)
 /** returns timestamp in current locale,
  * and resets LC_TIME locale to POSIX. */
 static char *timestamp (void)
@@ -122,7 +123,7 @@ static char *timestamp (void)
 #define timestamp rfc822timestamp
 #endif
 
-static RETSIGTYPE donothing(int sig) 
+static void donothing(int sig) 
 {
     set_signal_handler(sig, donothing);
     lastsig = sig;
@@ -130,20 +131,302 @@ static RETSIGTYPE donothing(int sig)
 
 static void printcopyright(FILE *fp) {
        fprintf(fp, GT_("Copyright (C) 2002, 2003 Eric S. Raymond\n"
-                  "Copyright (C) 2004 Matthias Andree, Eric S. Raymond, Rob F. Funk, Graham Wilson\n"
-                  "Copyright (C) 2005-2006 Matthias Andree, Sunil Shetye\n"
+                  "Copyright (C) 2004 Matthias Andree, Eric S. Raymond,\n"
+                  "                   Robert M. Funk, Graham Wilson\n"
+                  "Copyright (C) 2005 - 2012 Matthias Andree, Sunil Shetye\n"
                   ));
        fprintf(fp, GT_("Fetchmail comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
                   "are welcome to redistribute it under certain conditions. For details,\n"
                   "please see the file COPYING in the source or documentation directory.\n"));
+#ifdef SSL_ENABLE
+       /* Do not translate this */
+       fprintf(fp, "This product includes software developed by the OpenSSL Project\nfor use in the OpenSSL Toolkit. (http://www.openssl.org/)\n");
+#endif
 }
 
 const char *iana_charset;
 
+#ifdef HAVE_LIBPWMD
+static void exit_with_pwmd_error(gpg_error_t error)
+{
+    gpg_err_code_t code = gpg_err_code(error);
+
+    report(stderr, GT_("pwmd: error %i: %s\n"), code, pwmd_strerror(error));
+
+    if (pwm) {
+       pwmd_close(pwm);
+       pwm = NULL;
+    }
+
+    /* Don't exit if daemonized. There may be other active accounts. */
+    if (isatty(1))
+       exit(PS_UNDEFINED);
+}
+
+static int do_pwmd_connect(const char *socketname, const char *filename)
+{
+    static int init;
+    gpg_error_t rc;
+    pwmd_socket_t s;
+
+    if (!init) {
+       pwmd_init();
+       init = 1;
+    }
+
+    if (!pwm || (pwm && socketname && !pwmd_socket) ||
+           (pwm && !socketname && pwmd_socket) ||
+           (pwm && socketname && pwmd_socket && strcmp(socketname, pwmd_socket))) {
+       if (pwm)
+           pwmd_close(pwm);
+
+       pwm = pwmd_new("Fetchmail");
+       rc = pwmd_connect_url(pwm, socketname);
+
+       if (rc) {
+           exit_with_pwmd_error(rc);
+           return 1;
+       }
+    }
+
+    if (run.pinentry_timeout > 0) {
+       rc = pwmd_setopt(pwm, PWMD_OPTION_PINENTRY_TIMEOUT,
+               run.pinentry_timeout);
+
+       if (rc) {
+           exit_with_pwmd_error(rc);
+           return 1;
+       }
+    }
+
+    rc = pwmd_socket_type(pwm, &s);
+
+    if (rc) {
+       exit_with_pwmd_error(rc);
+       return 1;
+    }
+
+    if (!pwmd_file || strcmp(filename, pwmd_file)) {
+       if (s == PWMD_SOCKET_SSH)
+           /* use a local pinentry since X11 forwarding is broken. */
+           rc = pwmd_open2(pwm, filename);
+       else
+           rc = pwmd_open(pwm, filename);
+
+       if (rc) {
+           exit_with_pwmd_error(rc);
+           return 1;
+       }
+    }
+
+    /* May be null to use the default of ~/.pwmd/socket. */
+    pwmd_socket = socketname;
+    pwmd_file = filename;
+    return 0;
+}
+
+static int get_pwmd_details(const char *pwmd_account, int protocol,
+       struct query *ctl)
+{
+    const char *prot = showproto(protocol);
+    gpg_error_t error;
+    char *result;
+    char *tmp = xstrdup(pwmd_account);
+    int i;
+
+    for (i = 0; tmp[i]; i++) {
+       if (i && tmp[i] == '^')
+           tmp[i] = '\t';
+    }
+
+    /*
+     * Get the hostname for this protocol. Element path must be
+     * account->[protocol]->hostname.
+     */
+    error = pwmd_command(pwm, &result, "GET %s\t%s\thostname", tmp, prot);
+
+    if (error) {
+       if (gpg_err_code(error) == GPG_ERR_NOT_FOUND) {
+           report(stderr, GT_("pwmd: %s->%s->hostname: %s\n"), pwmd_account, prot, pwmd_strerror(error));
+           pwmd_close(pwm);
+           pwm = NULL;
+
+           if (isatty(1))
+               exit(PS_SYNTAX);
+
+           return 1;
+       }
+       else {
+           exit_with_pwmd_error(error);
+           return 1;
+       }
+    }
+
+    if (ctl->server.pollname != ctl->server.via)
+       xfree(ctl->server.via);
+
+    ctl->server.via = xstrdup(result);
+
+    if (ctl->server.queryname)
+       xfree(ctl->server.queryname);
+
+    ctl->server.queryname = xstrdup(ctl->server.via);
+
+    if (ctl->server.truename)
+       xfree(ctl->server.truename);
+
+    ctl->server.truename = xstrdup(ctl->server.queryname);
+    pwmd_free(result);
+
+    /*
+     * Server port. Fetchmail tries standard ports for known services so it
+     * should be alright if this element isn't found. ctl->server.protocol is
+     * already set. This sets ctl->server.service.
+     */
+    error = pwmd_command(pwm, &result, "GET %s\t%s\tport", tmp, prot);
+
+    if (error) {
+       if (gpg_err_code(error) == GPG_ERR_NOT_FOUND)
+           report(stderr, GT_("pwmd: %s->%s->port: %s\n"), pwmd_account, prot, pwmd_strerror(error));
+       else {
+           exit_with_pwmd_error(error);
+           return 1;
+       }
+    }
+    else {
+       if (ctl->server.service)
+           xfree(ctl->server.service);
+
+       ctl->server.service = xstrdup(result);
+       pwmd_free(result);
+    }
+
+    /*
+     * Get the remote username. Element must be account->username.
+     */
+    error = pwmd_command(pwm, &result, "GET %s\tusername", tmp);
+
+    if (error) {
+       if (gpg_err_code(error) == GPG_ERR_NOT_FOUND) {
+           report(stderr, GT_("pwmd: %s->username: %s\n"), pwmd_account, pwmd_strerror(error));
+
+           if (!isatty(1)) {
+               pwmd_close(pwm);
+               pwm = NULL;
+               return 1;
+           }
+       }
+       else {
+           exit_with_pwmd_error(error);
+           return 1;
+       }
+    }
+    else {
+       if (ctl->remotename)
+           xfree(ctl->remotename);
+
+       if (ctl->server.esmtp_name)
+           xfree(ctl->server.esmtp_name);
+
+       ctl->remotename = xstrdup(result);
+       ctl->server.esmtp_name = xstrdup(result);
+       pwmd_free(result);
+    }
+
+    /*
+     * Get the remote password. Element must be account->password.
+     */
+    error = pwmd_command(pwm, &result, "GET %s\tpassword", tmp);
+
+    if (error) {
+       if (gpg_err_code(error) == GPG_ERR_NOT_FOUND) {
+           report(stderr, GT_("pwmd: %s->password: %s\n"), pwmd_account, pwmd_strerror(error));
+
+           if (!isatty(1)) {
+               pwmd_close(pwm);
+               pwm = NULL;
+               return 1;
+           }
+       }
+       else {
+           exit_with_pwmd_error(error);
+           return 1;
+       }
+    }
+    else {
+       if (ctl->password)
+           xfree(ctl->password);
+
+       ctl->password= xstrdup(result);
+       pwmd_free(result);
+    }
+
+#ifdef SSL_ENABLE
+    /*
+     * If there is a ssl element and set to 1, enable ssl for this account.
+     * Element path must be account->[protocol]->ssl.
+     */
+    error = pwmd_command(pwm, &result, "GET %s\t%s\tssl", tmp, prot);
+
+    if (error) {
+       if (gpg_err_code(error) == GPG_ERR_NOT_FOUND) {
+           report(stderr, GT_("pwmd: %s->%s->ssl: %s\n"), pwmd_account, prot, pwmd_strerror(error));
+
+           if (!isatty(1)) {
+               pwmd_close(pwm);
+               pwm = NULL;
+               return 1;
+           }
+       }
+       else {
+           exit_with_pwmd_error(error);
+           return 1;
+       }
+    }
+    else {
+       ctl->use_ssl = atoi(result) >= 1 ? FLAG_TRUE : FLAG_FALSE;
+       pwmd_free(result);
+    }
+
+    /*
+     * account->[protocol]->sslfingerprint.
+     */
+    error = pwmd_command(pwm, &result, "GET %s\t%s\tsslfingerprint", tmp, prot);
+
+    if (error) {
+       if (gpg_err_code(error) == GPG_ERR_NOT_FOUND) {
+           report(stderr, GT_("pwmd: %s->%s->sslfingerprint: %s\n"), pwmd_account, prot, pwmd_strerror(error));
+
+           if (!isatty(1)) {
+               pwmd_close(pwm);
+               pwm = NULL;
+               return 1;
+           }
+       }
+       else {
+           exit_with_pwmd_error(error);
+           return 1;
+       }
+    }
+    else {
+       if (ctl->sslfingerprint)
+           xfree(ctl->sslfingerprint);
+
+       ctl->sslfingerprint = xstrdup(result);
+       pwmd_free(result);
+    }
+#endif
+
+    xfree(tmp);
+    return 0;
+}
+#endif
 int main(int argc, char **argv)
 {
     int bkgd = FALSE;
     int implicitmode = FALSE;
+    flag safewithbg = FALSE; /** if parsed options are compatible with a
+                             fetchmail copy running in the background */
     struct query *ctl;
     netrc_entry *netrc_list;
     char *netrc_file, *tmpbuf;
@@ -187,7 +470,6 @@ int main(int argc, char **argv)
 
 #define IDFILE_NAME    ".fetchids"
     run.idfile = prependdir (IDFILE_NAME, fmhome);
-  
     outlevel = O_NORMAL;
 
     /*
@@ -211,7 +493,7 @@ int main(int argc, char **argv)
     {
        int i;
 
-       i = parsecmdline(argc, argv, &cmd_run, &cmd_opts);
+       i = parsecmdline(argc, argv, &cmd_run, &cmd_opts, &safewithbg);
        if (i < 0)
            exit(PS_SYNTAX);
 
@@ -222,9 +504,6 @@ int main(int argc, char **argv)
     if (versioninfo)
     {
        const char *features = 
-#ifdef POP2_ENABLE
-       "+POP2"
-#endif /* POP2_ENABLE */
 #ifndef POP3_ENABLE
        "-POP3"
 #endif /* POP3_ENABLE */
@@ -232,7 +511,7 @@ int main(int argc, char **argv)
        "-IMAP"
 #endif /* IMAP_ENABLE */
 #ifdef GSSAPI
-       "+IMAP-GSS"
+       "+GSS"
 #endif /* GSSAPI */
 #ifdef RPA_ENABLE
        "+RPA"
@@ -264,6 +543,12 @@ int main(int argc, char **argv)
 #ifdef ENABLE_NLS
        "+NLS"
 #endif /* ENABLE_NLS */
+#ifdef KERBEROS_V5
+       "+KRB5"
+#endif /* KERBEROS_V5 */
+#ifdef HAVE_LIBPWMD
+       "+PWMD"
+#endif /* HAVE_LIBPWMD */
        ".\n";
        printf(GT_("This is fetchmail release %s"), VERSION);
        fputs(features, stdout);
@@ -280,28 +565,57 @@ int main(int argc, char **argv)
        fflush(stdout);
 
        /* this is an attempt to help remote debugging */
-       system("uname -a");
+       if (system("uname -a")) { /* NOOP to quench GCC complaint */ }
     }
 
     /* avoid parsing the config file if all we're doing is killing a daemon */
     if (!quitonly)
        implicitmode = load_params(argc, argv, optind);
 
-#if defined(HAVE_SYSLOG)
+    if (run.logfile) {
+       /* nodetach -> turn off logfile option */
+       if (nodetach) {
+           if (outlevel >= O_NORMAL) { fprintf(stderr, GT_("The nodetach option is in effect, ignoring logfile option.\n")); }
+           xfree(run.logfile);
+       }
+
+#if 0
+       /* not in daemon mode -> turn off logfile option */
+       if (0 == run.poll_interval) {
+           if (outlevel >= O_NORMAL) { fprintf(stderr, GT_("Not running in daemon mode, ignoring logfile option.\n")); }
+           xfree(run.logfile);
+       }
+#endif
+
+       /* log file not writable -> turn off logfile option */
+       if (run.logfile && 0 != access(run.logfile, F_OK)) {
+           if (outlevel >= O_NORMAL) { fprintf(stderr, GT_("Logfile \"%s\" does not exist, ignoring logfile option.\n"), run.logfile); }
+           xfree(run.logfile);
+       }
+
+       /* log file not writable -> turn off logfile option */
+       if (run.logfile && 0 != access(run.logfile, W_OK)) {
+           fprintf(stderr, GT_("Logfile \"%s\" is not writable, aborting.\n"), run.logfile);
+           xfree(run.logfile);
+           exit(PS_UNDEFINED);
+       }
+    }
+
     /* logging should be set up early in case we were restarted from exec */
     if (run.use_syslog)
     {
-#if defined(LOG_MAIL)
        openlog(program_name, LOG_PID, LOG_MAIL);
-#else
-       /* Assume BSD4.2 openlog with two arguments */
-       openlog(program_name, LOG_PID);
-#endif
-       report_init(-1);
+       /* precedence: logfile (if effective) overrides syslog. */
+       if (run.logfile) {
+           syslog(LOG_ERR, GT_("syslog and logfile options are both set, ignoring syslog, and logging to %s"), run.logfile);
+           run.use_syslog = 0;
+           report_init((run.poll_interval == 0 || nodetach) && !run.logfile); /* when changing this, change copy below, too */
+       } else {
+           report_init(-1);
+       }
     }
     else
-#endif
-       report_init((run.poll_interval == 0 || nodetach) && !run.logfile);
+       report_init((run.poll_interval == 0 || nodetach) && !run.logfile); /* when changing this, change copy above, too */
 
 #ifdef POP3_ENABLE
     /* initialize UID handling */
@@ -318,7 +632,6 @@ int main(int argc, char **argv)
     /* construct the lockfile */
     fm_lock_setup(&run);
 
-#ifdef HAVE_SETRLIMIT
     /*
      * Before getting passwords, disable core dumps unless -v -d0 mode is on.
      * Core dumps could otherwise contain passwords to be scavenged by a
@@ -331,7 +644,6 @@ int main(int argc, char **argv)
        corelimit.rlim_max = 0;
        setrlimit(RLIMIT_CORE, &corelimit);
     }
-#endif /* HAVE_SETRLIMIT */
 
 #define        NETRC_FILE      ".netrc"
     /* parse the ~/.netrc file (if present) for future password lookups. */
@@ -425,8 +737,8 @@ int main(int argc, char **argv)
        }
        else if (kill(pid, SIGTERM) < 0)
        {
-           fprintf(stderr,GT_("fetchmail: error killing %s fetchmail at %d; bailing out.\n"),
-                   bkgd ? GT_("background") : GT_("foreground"), pid);
+           fprintf(stderr,GT_("fetchmail: error killing %s fetchmail at %ld; bailing out.\n"),
+                   bkgd ? GT_("background") : GT_("foreground"), (long)pid);
            exit(PS_EXCLUDE);
        }
        else
@@ -434,8 +746,8 @@ int main(int argc, char **argv)
            int maxwait;
 
            if (outlevel > O_SILENT)
-               fprintf(stderr,GT_("fetchmail: %s fetchmail at %d killed.\n"),
-                       bkgd ? GT_("background") : GT_("foreground"), pid);
+               fprintf(stderr,GT_("fetchmail: %s fetchmail at %ld killed.\n"),
+                       bkgd ? GT_("background") : GT_("foreground"), (long)pid);
            /* We used to nuke the other process's lock here, with
             * fm_lock_release(), which is broken. The other process
             * needs to clear its lock by itself. */
@@ -463,31 +775,37 @@ int main(int argc, char **argv)
        else if (!implicitmode)
        {
            fprintf(stderr,
-                GT_("fetchmail: can't poll specified hosts with another fetchmail running at %d.\n"),
-                pid);
+                GT_("fetchmail: can't poll specified hosts with another fetchmail running at %ld.\n"),
+                (long)pid);
                return(PS_EXCLUDE);
        }
        else if (!bkgd)
        {
            fprintf(stderr,
-                GT_("fetchmail: another foreground fetchmail is running at %d.\n"),
-                pid);
+                GT_("fetchmail: another foreground fetchmail is running at %ld.\n"),
+                (long)pid);
                return(PS_EXCLUDE);
        }
        else if (getpid() == pid)
            /* this test enables re-execing on a changed rcfile */
            fm_lock_assert();
-       else if (argc > 1)
+       else if (argc > 1 && !safewithbg)
        {
            fprintf(stderr,
                    GT_("fetchmail: can't accept options while a background fetchmail is running.\n"));
+           {
+               int i;
+               fprintf(stderr, "argc = %d, arg list:\n", argc);
+               for (i = 1; i < argc; i++) fprintf(stderr, "arg %d = \"%s\"\n", i, argv[i]);
+           }
            return(PS_EXCLUDE);
        }
        else if (kill(pid, SIGUSR1) == 0)
        {
-           fprintf(stderr,
-                   GT_("fetchmail: background fetchmail at %d awakened.\n"),
-                   pid);
+           if (outlevel > O_SILENT)
+               fprintf(stderr,
+                       GT_("fetchmail: background fetchmail at %ld awakened.\n"),
+                       (long)pid);
            return(0);
        }
        else
@@ -498,8 +816,8 @@ int main(int argc, char **argv)
             * SIGUSR1/SIGHUP transmission.
             */
            fprintf(stderr,
-                   GT_("fetchmail: elder sibling at %d died mysteriously.\n"),
-                   pid);
+                   GT_("fetchmail: elder sibling at %ld died mysteriously.\n"),
+                   (long)pid);
            return(PS_UNDEFINED);
        }
     }
@@ -520,7 +838,7 @@ int main(int argc, char **argv)
                const char* password_prompt = GT_("Enter password for %s@%s: ");
                size_t pplen = strlen(password_prompt) + strlen(ctl->remotename) + strlen(ctl->server.pollname) + 1;
 
-               tmpbuf = xmalloc(pplen);
+               tmpbuf = (char *)xmalloc(pplen);
                snprintf(tmpbuf, pplen, password_prompt,
                        ctl->remotename, ctl->server.pollname);
                ctl->password = xstrdup((char *)fm_getpassword(tmpbuf));
@@ -541,14 +859,29 @@ int main(int argc, char **argv)
     /* avoid zombies from plugins */
     deal_with_sigchld();
 
+    /* Fix up log destination - if the if() is true, the precedence rule
+     * above hasn't killed off the syslog option, because the logfile
+     * option is ineffective (because we're not detached or not in
+     * deamon mode), so kill it for the benefit of other parts of the
+     * code. */
+    if (run.logfile && run.use_syslog)
+       run.logfile = 0;
+
     /*
      * Maybe time to go to demon mode...
      */
     if (run.poll_interval)
     {
-       if (!nodetach)
-           daemonize(run.logfile);
-       report(stdout, GT_("starting fetchmail %s daemon \n"), VERSION);
+       if (!nodetach) {
+           int rc;
+
+           rc = daemonize(run.logfile);
+           if (rc) {
+               report(stderr, GT_("fetchmail: Cannot detach into background. Aborting.\n"));
+               exit(rc);
+           }
+       }
+       report(stdout, GT_("starting fetchmail %s daemon\n"), VERSION);
 
        /*
         * We'll set up a handler for these when we're sleeping,
@@ -560,12 +893,13 @@ int main(int argc, char **argv)
     }
     else
     {
-       if (run.logfile && !nodetach && access(run.logfile, F_OK) == 0)
-       {
+       /* not in daemon mode */
+       if (run.logfile)
+       {
            if (!freopen(run.logfile, "a", stdout))
-                   report(stderr, GT_("could not open %s to append logs to \n"), run.logfile);
+                   report(stderr, GT_("could not open %s to append logs to\n"), run.logfile);
            if (!freopen(run.logfile, "a", stderr))
-                   report(stdout, GT_("could not open %s to append logs to \n"), run.logfile);
+                   report(stdout, GT_("could not open %s to append logs to\n"), run.logfile);
        }
     }
 
@@ -577,12 +911,16 @@ int main(int argc, char **argv)
     set_signal_handler(SIGINT, terminate_run);
     set_signal_handler(SIGTERM, terminate_run);
     set_signal_handler(SIGALRM, terminate_run);
-    set_signal_handler(SIGPIPE, terminate_run);
+    set_signal_handler(SIGPIPE, SIG_IGN);
     set_signal_handler(SIGQUIT, terminate_run);
 
     /* here's the exclusion lock */
     fm_lock_or_die();
 
+    if (check_only && outlevel >= O_VERBOSE) {
+       report(stdout, GT_("--check mode enabled, not fetching mail\n"));
+    }
+
     /*
      * Query all hosts. If there's only one, the error return will
      * reflect the status of that transaction.
@@ -596,6 +934,11 @@ int main(int argc, char **argv)
         * leaks...
         */
        struct stat     rcstat;
+#ifdef HAVE_LIBPWMD
+       time_t now;
+
+       time(&now);
+#endif
 
        if (strcmp(rcfile, "-") == 0) {
            /* do nothing */
@@ -605,7 +948,15 @@ int main(int argc, char **argv)
                       GT_("couldn't time-check %s (error %d)\n"),
                       rcfile, errno);
        }
+#ifdef HAVE_LIBPWMD
+       /*
+        * isatty() to make sure this is a background process since the
+        * lockfile is removed after each invokation.
+        */
+       else if (!isatty(1) && rcstat.st_mtime > parsetime)
+#else
        else if (rcstat.st_mtime > parsetime)
+#endif
        {
            report(stdout, GT_("restarting fetchmail (%s changed)\n"), rcfile);
 
@@ -642,19 +993,21 @@ int main(int argc, char **argv)
            report(stderr, GT_("attempt to re-exec fetchmail failed\n"));
        }
 
-#if defined(HAVE_RES_SEARCH) && defined(USE_TCPIP_FOR_DNS)
-       /*
-        * This was an efficiency hack that backfired.  The theory
-        * was that using TCP/IP for DNS queries would get us better
-        * reliability and shave off some per-UDP-packet costs.
-        * Unfortunately it interacted badly with diald, which effectively 
-        * filters out DNS queries over TCP/IP for reasons having to do
-        * with some obscure Linux kernel problem involving bootstrapping of
-        * dynamically-addressed links.  I don't understand this mess
-        * and don't want to, so it's "See ya!" to this hack.
-        */
-       sethostent(TRUE);       /* use TCP/IP for mailserver queries */
-#endif /* HAVE_RES_SEARCH */
+#ifdef HAVE_RES_SEARCH
+       /* Boldly assume that we also have res_init() if we have
+        * res_search(), and call res_init() to re-read the resolv.conf
+        * file, so that we can pick up changes to that file that are
+        * written by dhpccd, dhclient, pppd, openvpn and similar. */
+
+       /* NOTE: This assumes that /etc/resolv.conf is written
+        * atomically (i. e. a temporary file is written, flushed and
+        * then renamed into place). To fix Debian Bug#389270. */
+
+       /* NOTE: If this leaks memory or doesn't re-read
+        * /etc/resolv.conf, we're in trouble. The res_init() interface
+        * is only lightly documented :-( */
+       res_init();
+#endif
 
        activecount = 0;
        batchcount = 0;
@@ -696,6 +1049,19 @@ int main(int argc, char **argv)
 
                    dofastuidl = 0; /* this is reset in the driver if required */
 
+#ifdef HAVE_LIBPWMD
+                   /*
+                    * At each poll interval, check the pwmd server for
+                    * changes in host and auth settings.
+                    */
+                   if (ctl->pwmd_file) {
+                       if (do_pwmd_connect(ctl->pwmd_socket, ctl->pwmd_file))
+                           continue;
+
+                       if (get_pwmd_details(ctl->server.pollname, ctl->server.protocol, ctl))
+                           continue;
+                   }
+#endif
                    querystatus = query_host(ctl);
 
                    if (NUM_NONZERO(ctl->fastuidl))
@@ -764,10 +1130,12 @@ int main(int argc, char **argv)
                }
            }
 
-#if defined(HAVE_RES_SEARCH) && defined(USE_TCPIP_FOR_DNS)
-       endhostent();           /* release TCP/IP connection to nameserver */
-#endif /* HAVE_RES_SEARCH */
-
+#ifdef HAVE_LIBPWMD
+       if (pwm) {
+           pwmd_close(pwm);
+           pwm = NULL;
+       }
+#endif
        /* close connections cleanly */
        terminate_poll(0);
 
@@ -796,9 +1164,10 @@ int main(int argc, char **argv)
                exit(PS_AUTHFAIL);
            }
 
-           if (outlevel > O_SILENT)
-               report(stdout, 
-                      GT_("sleeping at %s\n"), timestamp());
+           if ((outlevel > O_SILENT && !run.use_syslog && isatty(1))
+                   || outlevel > O_NORMAL)
+               report(stdout,
+                      GT_("sleeping at %s for %d seconds\n"), timestamp(), run.poll_interval);
 
            /*
             * With this simple hack, we make it possible for a foreground 
@@ -808,7 +1177,7 @@ int main(int argc, char **argv)
             * for people who think all system daemons wake up on SIGHUP.
             */
            set_signal_handler(SIGUSR1, donothing);
-           if (getuid() != ROOT_UID)
+           if (getuid() == ROOT_UID)
                set_signal_handler(SIGHUP, donothing);
 
            /*
@@ -831,11 +1200,11 @@ int main(int argc, char **argv)
                    ctl->wedged = FALSE;
            }
 
-           if (outlevel > O_SILENT)
+           if ((outlevel > O_SILENT && !run.use_syslog && isatty(1))
+                   || outlevel > O_NORMAL)
                report(stdout, GT_("awakened at %s\n"), timestamp());
        }
-    } while
-       (run.poll_interval);
+    } while (run.poll_interval);
 
     if (outlevel >= O_VERBOSE)
        report(stdout, GT_("normal termination, status %d\n"),
@@ -890,7 +1259,6 @@ static void optmerge(struct query *h2, struct query *h1, int force)
     FLAG_MERGE(server.skip);
     FLAG_MERGE(server.dns);
     FLAG_MERGE(server.checkalias);
-    FLAG_MERGE(server.uidl);
     FLAG_MERGE(server.principal);
 
 #ifdef CAN_MONITOR
@@ -902,6 +1270,8 @@ static void optmerge(struct query *h2, struct query *h1, int force)
     FLAG_MERGE(server.plugin);
     FLAG_MERGE(server.plugout);
     FLAG_MERGE(server.tracepolls);
+    FLAG_MERGE(server.badheader);
+    FLAG_MERGE(server.retrieveerror);
 
     FLAG_MERGE(wildcard);
     FLAG_MERGE(remotename);
@@ -938,7 +1308,9 @@ static void optmerge(struct query *h2, struct query *h1, int force)
     FLAG_MERGE(sslcert);
     FLAG_MERGE(sslproto);
     FLAG_MERGE(sslcertck);
+    FLAG_MERGE(sslcertfile);
     FLAG_MERGE(sslcertpath);
+    FLAG_MERGE(sslcommonname);
     FLAG_MERGE(sslfingerprint);
 #endif
     FLAG_MERGE(expunge);
@@ -959,6 +1331,7 @@ static int load_params(int argc, char **argv, int optind)
     char *p;
 
     run.bouncemail = TRUE;
+    run.softbounce = TRUE;     /* treat permanent errors as temporary */
     run.spambounce = FALSE;    /* don't bounce back to innocent bystanders */
 
     memset(&def_opts, '\0', sizeof(struct query));
@@ -968,6 +1341,7 @@ static int load_params(int argc, char **argv, int optind)
     def_opts.server.protocol = P_AUTO;
     def_opts.server.timeout = CLIENT_TIMEOUT;
     def_opts.server.esmtp_name = user;
+    def_opts.server.badheader = BHREJECT;
     def_opts.warnings = WARNING_INTERVAL;
     def_opts.remotename = user;
     def_opts.listener = SMTP_MODE;
@@ -986,11 +1360,14 @@ static int load_params(int argc, char **argv, int optind)
     }
 
     /* note the parse time, so we can pick up on modifications */
-    parsetime = 0;     /* foil compiler warnings */
-    if (strcmp(rcfile, "-") == 0 || stat(rcfile, &rcstat) != -1)
-       parsetime = rcstat.st_mtime;
-    else if (errno != ENOENT)
-       report(stderr, GT_("couldn't time-check the run-control file\n"));
+    if (strcmp(rcfile, "-") == 0)
+       parsetime = time(NULL);
+    else {
+       if (stat(rcfile, &rcstat) != -1)
+           parsetime = rcstat.st_mtime;
+       else if (errno != ENOENT)
+           report(stderr, GT_("couldn't time-check the run-control file\n"));
+    }
 
     /* this builds the host list */
     if ((st = prc_parse_file(rcfile, !versioninfo)) != 0)
@@ -1004,8 +1381,36 @@ static int load_params(int argc, char **argv, int optind)
 
     if ((implicitmode = (optind >= argc)))
     {
+#ifdef HAVE_LIBPWMD
+       for (ctl = querylist; ctl; ctl = ctl->next) {
+           ctl->active = !ctl->server.skip;
+
+           if (ctl->pwmd_file) {
+               /*
+                * Cannot get an element path without a service.
+                */
+               if (ctl->server.protocol <= 1) {
+                   report(stderr, GT_("fetchmail: %s configuration invalid, pwmd_file requires a protocol specification\n"),
+                           ctl->server.pollname);
+                   pwmd_close(pwm);
+                   exit(PS_SYNTAX);
+               }
+
+               if (do_pwmd_connect(ctl->pwmd_socket, ctl->pwmd_file))
+                   continue;
+
+               if (get_pwmd_details(ctl->server.pollname, ctl->server.protocol,
+                           ctl))
+                   continue;
+
+               time(&rcstat.st_mtime);
+           }
+       }
+
+#else
        for (ctl = querylist; ctl; ctl = ctl->next)
            ctl->active = !ctl->server.skip;
+#endif
     }
     else
        for (; optind < argc; optind++) 
@@ -1026,6 +1431,26 @@ static int load_params(int argc, char **argv, int optind)
                        fprintf(stderr,GT_("Warning: multiple mentions of host %s in config file\n"),argv[optind]);
                    ctl->active = TRUE;
                    predeclared = TRUE;
+#ifdef HAVE_LIBPWMD
+                   if (ctl->pwmd_file) {
+                       /*
+                        * Cannot get an element path without a service.
+                        */
+                       if (ctl->server.protocol <= 1) {
+                           report(stderr, GT_("%s configuration invalid, pwmd_file requires a protocol specification\n"),
+                                  ctl->server.pollname);
+                           exit(PS_SYNTAX);
+                       }
+
+                       fprintf(stderr, "%s(%i): %s\n", __FILE__, __LINE__, __FUNCTION__);
+                       if (do_pwmd_connect(ctl->pwmd_socket, ctl->pwmd_file))
+                           continue;
+
+                       if (get_pwmd_details(ctl->server.pollname,
+                                   ctl->server.protocol, ctl))
+                           continue;
+                   }
+#endif
                }
 
            if (!predeclared)
@@ -1036,8 +1461,31 @@ static int load_params(int argc, char **argv, int optind)
                 * call later on.
                 */
                ctl = hostalloc((struct query *)NULL);
+#ifdef HAVE_LIBPWMD
+               if (cmd_opts.pwmd_file) {
+                   /*
+                    * Cannot get an element path without a service.
+                    */
+                   if (cmd_opts.server.protocol == 0 || cmd_opts.server.protocol == 1) {
+                       report(stderr, GT_("Option --pwmd-file needs a service (-p) parameter.\n"));
+                       exit(PS_SYNTAX);
+                   }
+
+                       fprintf(stderr, "%s(%i): %s\n", __FILE__, __LINE__, __FUNCTION__);
+                   if (do_pwmd_connect(cmd_opts.pwmd_socket, cmd_opts.pwmd_file))
+                       continue;
+
+                   if (get_pwmd_details(argv[optind], cmd_opts.server.protocol,
+                           ctl))
+                       continue;
+               }
+               else
+                   ctl->server.via =
+                       ctl->server.pollname = xstrdup(argv[optind]);
+#else
                ctl->server.via =
                    ctl->server.pollname = xstrdup(argv[optind]);
+#endif
                ctl->active = TRUE;
                ctl->server.lead_server = (struct hostdata *)NULL;
            }
@@ -1045,12 +1493,18 @@ static int load_params(int argc, char **argv, int optind)
 
     /*
      * If there's a defaults record, merge it and lose it.
+     * FIXME: we don't currently free all entries that might be in struct query.
      */ 
     if (querylist && strcmp(querylist->server.pollname, "defaults") == 0)
     {
+       struct query *tmpq;
+
        for (ctl = querylist->next; ctl; ctl = ctl->next)
            optmerge(ctl, querylist, FALSE);
+       tmpq = querylist;
        querylist = querylist->next;
+       free(tmpq->server.pollname);
+       free(tmpq);
     }
 
     /* don't allow a defaults record after the first */
@@ -1075,15 +1529,17 @@ static int load_params(int argc, char **argv, int optind)
     if (cmd_run.poll_interval >= 0)
        run.poll_interval = cmd_run.poll_interval;
     if (cmd_run.invisible)
-       run.invisible = cmd_run.invisible;
+       run.invisible = (cmd_run.invisible == FLAG_TRUE);
     if (cmd_run.showdots)
-       run.showdots = cmd_run.showdots;
+       run.showdots = (cmd_run.showdots == FLAG_TRUE);
     if (cmd_run.use_syslog)
        run.use_syslog = (cmd_run.use_syslog == FLAG_TRUE);
     if (cmd_run.postmaster)
        run.postmaster = cmd_run.postmaster;
     if (cmd_run.bouncemail)
-       run.bouncemail = cmd_run.bouncemail;
+       run.bouncemail = (cmd_run.bouncemail == FLAG_TRUE);
+    if (cmd_run.softbounce)
+       run.softbounce = (cmd_run.softbounce == FLAG_TRUE);
 
     /* check and daemon options are not compatible */
     if (check_only && run.poll_interval)
@@ -1105,7 +1561,6 @@ static int load_params(int argc, char **argv, int optind)
     for (ctl = querylist; ctl; ctl = ctl->next)
        if (ctl->active && 
                (ctl->server.protocol==P_ETRN || ctl->server.protocol==P_ODMR
-                || ctl->server.authenticate == A_KERBEROS_V4
                 || ctl->server.authenticate == A_KERBEROS_V5))
        {
            fetchmailhost = host_fqdn(1);
@@ -1122,8 +1577,6 @@ static int load_params(int argc, char **argv, int optind)
                                        flag = FALSE;\
                                else\
                                        flag = (dflt)
-    /* one global gets treated specially */
-    DEFAULT(run.showdots, run.poll_interval==0 || nodetach);
 
     /* merge in wired defaults, do sanity checks and prepare internal fields */
     for (ctl = querylist; ctl; ctl = ctl->next)
@@ -1167,7 +1620,6 @@ static int load_params(int argc, char **argv, int optind)
            DEFAULT(ctl->mimedecode, FALSE);
            DEFAULT(ctl->idle, FALSE);
            DEFAULT(ctl->server.dns, TRUE);
-           DEFAULT(ctl->server.uidl, FALSE);
            DEFAULT(ctl->use_ssl, FALSE);
            DEFAULT(ctl->sslcertck, FALSE);
            DEFAULT(ctl->server.checkalias, FALSE);
@@ -1183,6 +1635,18 @@ static int load_params(int argc, char **argv, int optind)
            }
 #endif /* SSL_ENABLE */
 #undef DEFAULT
+#ifndef KERBEROS_V5
+           if (ctl->server.authenticate == A_KERBEROS_V5) {
+               report(stderr, GT_("KERBEROS v5 support is configured, but not compiled in.\n"));
+               exit(PS_SYNTAX);
+           }
+#endif
+#ifndef GSSAPI
+           if (ctl->server.authenticate == A_GSSAPI) {
+               report(stderr, GT_("GSSAPI support is configured, but not compiled in.\n"));
+               exit(PS_SYNTAX);
+           }
+#endif
 
            /*
             * Make sure we have a nonempty host list to forward to.
@@ -1204,14 +1668,6 @@ static int load_params(int argc, char **argv, int optind)
            if (!ctl->localnames)       /* for local delivery via SMTP */
                save_str_pair(&ctl->localnames, user, NULL);
 
-#ifndef HAVE_RES_SEARCH
-           /* can't handle multidrop mailboxes unless we can do DNS lookups */
-           if (MULTIDROP(ctl) && ctl->server.dns)
-           {
-               ctl->server.dns = FALSE;
-               report(stderr, GT_("fetchmail: warning: no DNS available to check multidrop fetches from %s\n"), ctl->server.pollname);
-           }
-#endif /* !HAVE_RES_SEARCH */
 
            /*
             * can't handle multidrop mailboxes without "envelope"
@@ -1242,13 +1698,6 @@ static int load_params(int argc, char **argv, int optind)
                                   ctl->server.pollname);
                    exit(PS_SYNTAX);
                }
-               if (ctl->server.protocol == P_RPOP && port >= 1024)
-               {
-                   (void) fprintf(stderr,
-                                  GT_("fetchmail: %s configuration invalid, RPOP requires a privileged port\n"),
-                                  ctl->server.pollname);
-                   exit(PS_SYNTAX);
-               }
            }
            if (ctl->listener == LMTP_MODE)
            {
@@ -1297,7 +1746,7 @@ static int load_params(int argc, char **argv, int optind)
     return(implicitmode);
 }
 
-static RETSIGTYPE terminate_poll(int sig)
+static void terminate_poll(int sig)
 /* to be executed at the end of a poll cycle */
 {
 
@@ -1315,7 +1764,7 @@ static RETSIGTYPE terminate_poll(int sig)
 #endif /* POP3_ENABLE */
 }
 
-static RETSIGTYPE terminate_run(int sig)
+static void terminate_run(int sig)
 /* to be executed on normal or signal-induced termination */
 {
     struct query       *ctl;
@@ -1337,9 +1786,6 @@ static RETSIGTYPE terminate_run(int sig)
        if (ctl->password)
          memset(ctl->password, '\0', strlen(ctl->password));
 
-#if !defined(HAVE_ATEXIT)
-    fm_lock_release();
-#endif
 
     if (activecount == 0)
        exit(PS_NOMAIL);
@@ -1358,9 +1804,6 @@ static const int autoprobe[] =
 #ifdef POP3_ENABLE
     P_POP3,
 #endif /* POP3_ENABLE */
-#ifdef POP2_ENABLE
-    P_POP2
-#endif /* POP2_ENABLE */
 };
 
 static int query_host(struct query *ctl)
@@ -1396,17 +1839,7 @@ static int query_host(struct query *ctl)
        }
        ctl->server.protocol = P_AUTO;
        break;
-    case P_POP2:
-#ifdef POP2_ENABLE
-       st = doPOP2(ctl);
-#else
-       report(stderr, GT_("POP2 support is not configured.\n"));
-       st = PS_PROTOCOL;
-#endif /* POP2_ENABLE */
-       break;
     case P_POP3:
-    case P_APOP:
-    case P_RPOP:
 #ifdef POP3_ENABLE
        do {
            st = doPOP3(ctl);
@@ -1463,6 +1896,13 @@ static int query_host(struct query *ctl)
     return(st);
 }
 
+static int print_id_of(struct uid_db_record *rec, void *unused)
+{
+    (void)unused;
+
+    printf("\t%s\n", rec->id);
+    return 0;
+}
 static void dump_params (struct runctl *runp,
                         struct query *querylist, flag implicit)
 /* display query parameters in English */
@@ -1475,10 +1915,8 @@ static void dump_params (struct runctl *runp,
        printf(GT_("Logfile is %s\n"), runp->logfile);
     if (strcmp(runp->idfile, IDFILE_NAME))
        printf(GT_("Idfile is %s\n"), runp->idfile);
-#if defined(HAVE_SYSLOG)
     if (runp->use_syslog)
        printf(GT_("Progress messages will be logged via syslog\n"));
-#endif
     if (runp->invisible)
        printf(GT_("Fetchmail will masquerade and will not generate Received\n"));
     if (runp->showdots)
@@ -1492,6 +1930,11 @@ static void dump_params (struct runctl *runp,
     else if (outlevel >= O_VERBOSE)
        printf(GT_("Fetchmail will direct error mail to the sender.\n"));
 
+    if (!runp->softbounce)
+       printf(GT_("Fetchmail will treat permanent errors as permanent (drop messages).\n"));
+    else if (outlevel >= O_VERBOSE)
+       printf(GT_("Fetchmail will treat permanent errors as temporary (keep messages).\n"));
+
     for (ctl = querylist; ctl; ctl = ctl->next)
     {
        if (!ctl->active || (implicit && ctl->server.skip))
@@ -1519,22 +1962,14 @@ static void dump_params (struct runctl *runp,
                printf(GT_("  Password will be prompted for.\n"));
            else if (outlevel >= O_VERBOSE)
            {
-               if (ctl->server.protocol == P_APOP)
-                   printf(GT_("  APOP secret = \"%s\".\n"),
-                          visbuf(ctl->password));
-               else if (ctl->server.protocol == P_RPOP)
-                   printf(GT_("  RPOP id = \"%s\".\n"),
-                          visbuf(ctl->password));
-               else
-                   printf(GT_("  Password = \"%s\".\n"),
-                                                       visbuf(ctl->password));
+               printf(GT_("  Password = \"%s\".\n"),
+                                   visbuf(ctl->password));
            }
        }
 
        if (ctl->server.protocol == P_POP3 
            && ctl->server.service && !strcmp(ctl->server.service, KPOP_PORT)
-           && (ctl->server.authenticate == A_KERBEROS_V4 ||
-               ctl->server.authenticate == A_KERBEROS_V5))
+           && (ctl->server.authenticate == A_KERBEROS_V5))
            printf(GT_("  Protocol is KPOP with Kerberos %s authentication"),
                   ctl->server.authenticate == A_KERBEROS_V5 ? "V" : "IV");
        else
@@ -1543,8 +1978,6 @@ static void dump_params (struct runctl *runp,
            printf(GT_(" (using service %s)"), ctl->server.service);
        else if (outlevel >= O_VERBOSE)
            printf(GT_(" (using default port)"));
-       if (ctl->server.uidl && MAILBOX_PROTOCOL(ctl))
-           printf(GT_(" (forcing UIDL use)"));
        putchar('.');
        putchar('\n');
        switch (ctl->server.authenticate)
@@ -1565,20 +1998,22 @@ static void dump_params (struct runctl *runp,
            printf(GT_("  OTP authentication will be forced.\n"));
            break;
        case A_CRAM_MD5:
-           printf(GT_("  CRAM-Md5 authentication will be forced.\n"));
+           printf(GT_("  CRAM-MD5 authentication will be forced.\n"));
            break;
        case A_GSSAPI:
            printf(GT_("  GSSAPI authentication will be forced.\n"));
            break;
-       case A_KERBEROS_V4:
-           printf(GT_("  Kerberos V4 authentication will be forced.\n"));
-           break;
        case A_KERBEROS_V5:
            printf(GT_("  Kerberos V5 authentication will be forced.\n"));
            break;
        case A_SSH:
            printf(GT_("  End-to-end encryption assumed.\n"));
            break;
+       case A_APOP:
+           printf(GT_("  APOP authentication will be forced.\n"));
+           break;
+       default:
+           abort();
        }
        if (ctl->server.principal != (char *) NULL)
            printf(GT_("  Mail service principal is: %s\n"), ctl->server.principal);
@@ -1589,9 +2024,13 @@ static void dump_params (struct runctl *runp,
            printf(GT_("  SSL protocol: %s.\n"), ctl->sslproto);
        if (ctl->sslcertck) {
            printf(GT_("  SSL server certificate checking enabled.\n"));
-           if (ctl->sslcertpath != NULL)
-               printf(GT_("  SSL trusted certificate directory: %s\n"), ctl->sslcertpath);
        }
+       if (ctl->sslcertfile != NULL)
+               printf(GT_("  SSL trusted certificate file: %s\n"), ctl->sslcertfile);
+       if (ctl->sslcertpath != NULL)
+               printf(GT_("  SSL trusted certificate directory: %s\n"), ctl->sslcertpath);
+       if (ctl->sslcommonname != NULL)
+               printf(GT_("  SSL server CommonName: %s\n"), ctl->sslcommonname);
        if (ctl->sslfingerprint != NULL)
                printf(GT_("  SSL key fingerprint (checked against the server key): %s\n"), ctl->sslfingerprint);
 #endif
@@ -1817,17 +2256,14 @@ static void dump_params (struct runctl *runp,
 
                        if (ctl->server.akalist)
                        {
-                           struct idlist *idp;
-
                            printf(GT_("  Predeclared mailserver aliases:"));
                            for (idp = ctl->server.akalist; idp; idp = idp->next)
                                printf(" %s", idp->id);
                            putchar('\n');
                        }
+
                        if (ctl->server.localdomains)
                        {
-                           struct idlist *idp;
-
                            printf(GT_("  Local domains:"));
                            for (idp = ctl->server.localdomains; idp; idp = idp->next)
                                printf(" %s", idp->id);
@@ -1856,29 +2292,47 @@ static void dump_params (struct runctl *runp,
        else if (outlevel >= O_VERBOSE)
            printf(GT_("  No plugout command specified.\n"));
 
-       if (ctl->server.protocol > P_POP2 && MAILBOX_PROTOCOL(ctl))
+       if (MAILBOX_PROTOCOL(ctl))
        {
-           if (!ctl->oldsaved)
+           int count;
+
+           if (!(count = uid_db_n_records(&ctl->oldsaved)))
                printf(GT_("  No UIDs saved from this host.\n"));
            else
            {
-               struct idlist *idp;
-               int count = 0;
-
-               for (idp = ctl->oldsaved; idp; idp = idp->next)
-                   ++count;
 
                printf(GT_("  %d UIDs saved.\n"), count);
-               if (outlevel >= O_VERBOSE)
-                   for (idp = ctl->oldsaved; idp; idp = idp->next)
-                       printf("\t%s\n", idp->id);
+               traverse_uid_db(&ctl->oldsaved, print_id_of, NULL);
            }
        }
 
         if (ctl->server.tracepolls)
             printf(GT_("  Poll trace information will be added to the Received header.\n"));
         else if (outlevel >= O_VERBOSE)
-            printf(GT_("  No poll trace information will be added to the Received header.\n.\n"));
+            printf(GT_("  No poll trace information will be added to the Received header.\n"));
+
+       switch (ctl->server.badheader) {
+           case BHREJECT:
+               if (outlevel >= O_VERBOSE)
+                   printf(GT_("  Messages with bad headers will be rejected.\n"));
+               break;
+           case BHACCEPT:
+               printf(GT_("  Messages with bad headers will be passed on.\n"));
+               break;
+       }
+
+       switch (ctl->server.retrieveerror) {
+           case RE_ABORT:
+               if (outlevel >= O_VERBOSE)
+                   printf(GT_("  Messages with fetch body errors will cause the session to abort.\n"));
+               break;
+           case RE_CONTINUE:
+               printf(GT_("  Messages with fetch body errors will be skipped, the session will continue.\n"));
+               break;
+           case RE_MARKSEEN:
+               printf(GT_("  Messages with fetch body errors will be marked seen, the session will continue.\n"));
+               break;
+       }
 
        if (ctl->properties)
            printf(GT_("  Pass-through properties \"%s\".\n"),