X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=fetchmail.c;h=e30486f5f1c6cb62eecb5733379eed50aeae18bc;hb=b7514d6e1ccc83edb5023dc0335168a5a899de24;hp=6d1b34e180e93a2c7309fc432123466a1e8aa9c9;hpb=eaf2ce1dd214a1d8716179a25036427096c7c24e;p=~andy%2Ffetchmail diff --git a/fetchmail.c b/fetchmail.c index 6d1b34e1..e30486f5 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -6,18 +6,12 @@ #include "config.h" #include -#if defined(STDC_HEADERS) #include -#endif -#if defined(HAVE_UNISTD_H) #include -#endif #include #include #include -#if defined(HAVE_SYSLOG) #include -#endif #include #ifdef __FreeBSD__ #include @@ -25,24 +19,26 @@ #include #include #include -#ifdef HAVE_SETRLIMIT #include -#endif /* HAVE_SETRLIMIT */ #ifdef HAVE_SOCKS #include /* SOCKSinit() */ #endif /* HAVE_SOCKS */ -#ifdef HAVE_LANGINFO_H #include -#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 +#include +#include #ifndef ENETUNREACH #define ENETUNREACH 128 /* Interactive doesn't know this */ @@ -60,14 +56,17 @@ int outlevel; /* see the O_.* constants above */ struct runctl run; /* global controls for this run */ flag nodetach; /* if TRUE, don't detach daemon process */ flag quitmode; /* if --quit was set */ +int quitind; /* optind after position of last --quit option */ flag check_only; /* if --probe was set */ 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 */ static int querystatus; /* status of query */ static int successes; /* count number of successful polls */ @@ -75,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 */ @@ -99,8 +104,8 @@ static void dropprivs(void) } #endif -#if defined(HAVE_SETLOCALE) && defined(ENABLE_NLS) && defined(HAVE_STRFTIME) #include +#if defined(ENABLE_NLS) /** returns timestamp in current locale, * and resets LC_TIME locale to POSIX. */ static char *timestamp (void) @@ -118,18 +123,311 @@ 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; } +static void printcopyright(FILE *fp) { + fprintf(fp, GT_("Copyright (C) 2002, 2003 Eric S. Raymond\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; @@ -173,7 +471,7 @@ int main(int argc, char **argv) #define IDFILE_NAME ".fetchids" run.idfile = prependdir (IDFILE_NAME, fmhome); - + outlevel = O_NORMAL; /* @@ -184,7 +482,7 @@ int main(int argc, char **argv) * call near the beginning of the polling loop for details). We want * to be sure the lock gets nuked on any error exit, basically. */ - lock_dispose(); + fm_lock_dispose(); #ifdef HAVE_GETCWD /* save the current directory */ @@ -194,15 +492,20 @@ int main(int argc, char **argv) } #endif - if ((parsecmdline(argc,argv, &cmd_run, &cmd_opts)) < 0) - exit(PS_SYNTAX); + { + int i; + + i = parsecmdline(argc, argv, &cmd_run, &cmd_opts, &safewithbg); + if (i < 0) + exit(PS_SYNTAX); + + if (quitmode && quitind == argc) + quitonly = 1; + } if (versioninfo) { const char *features = -#ifdef POP2_ENABLE - "+POP2" -#endif /* POP2_ENABLE */ #ifndef POP3_ENABLE "-POP3" #endif /* POP3_ENABLE */ @@ -210,7 +513,7 @@ int main(int argc, char **argv) "-IMAP" #endif /* IMAP_ENABLE */ #ifdef GSSAPI - "+IMAP-GSS" + "+GSS" #endif /* GSSAPI */ #ifdef RPA_ENABLE "+RPA" @@ -242,9 +545,18 @@ int main(int argc, char **argv) #ifdef ENABLE_NLS "+NLS" #endif /* ENABLE_NLS */ - "\n"; +#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); + puts(""); + printcopyright(stdout); + puts(""); fputs("Fallback MDA: ", stdout); #ifdef FALLBACK_MDA fputs(FALLBACK_MDA, stdout); @@ -255,33 +567,42 @@ 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 (!(quitmode && argc == 2)) + /* 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) + /* precedence: logfile (if effective) overrides syslog. */ + if (run.logfile && run.poll_interval && !nodetach) { + run.use_syslog = 0; + } + /* 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); } else -#endif report_init((run.poll_interval == 0 || nodetach) && !run.logfile); +#ifdef POP3_ENABLE + /* initialize UID handling */ + { + int st; + + if (!versioninfo && (st = prc_filecheck(run.idfile, !versioninfo)) != 0) + exit(st); + else + initialize_saved_lists(querylist, run.idfile); + } +#endif /* POP3_ENABLE */ + /* construct the lockfile */ - lock_setup(); + 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 @@ -294,7 +615,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. */ @@ -335,6 +655,9 @@ int main(int argc, char **argv) } } + free_netrc(netrc_list); + netrc_list = 0; + /* perhaps we just want to check options? */ if (versioninfo) { @@ -361,12 +684,12 @@ int main(int argc, char **argv) } /* check for another fetchmail running concurrently */ - pid = lock_state(); + pid = fm_lock_state(); bkgd = (pid < 0); pid = bkgd ? -pid : pid; /* if no mail servers listed and nothing in background, we're done */ - if (!(quitmode && argc == 2) && pid == 0 && querylist == NULL) { + if (!quitonly && pid == 0 && querylist == NULL) { (void)fputs(GT_("fetchmail: no mailservers have been specified.\n"),stderr); exit(PS_SYNTAX); } @@ -374,36 +697,40 @@ int main(int argc, char **argv) /* perhaps user asked us to kill the other fetchmail */ if (quitmode) { - if (pid == 0) - { - fprintf(stderr,GT_("fetchmail: no other fetchmail is running\n")); - if (argc == 2) - exit(PS_EXCLUDE); - } - else if (getpid() == pid) + if (pid == 0 || pid == getpid()) + /* this test enables re-execing on a changed rcfile + * for pid == getpid() */ { - /* this test enables re-execing on a changed rcfile */ - if (argc == 2) - { + if (quitonly) { fprintf(stderr,GT_("fetchmail: no other fetchmail is running\n")); exit(PS_EXCLUDE); } } 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 { - fprintf(stderr,GT_("fetchmail: %s fetchmail at %d killed.\n"), - bkgd ? GT_("background") : GT_("foreground"), pid); - fm_lock_release(); - if (argc == 2) + int maxwait; + + if (outlevel > O_SILENT) + 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. */ + if (quitonly) exit(0); - else - pid = 0; + + /* wait for other process to exit */ + maxwait = 10; /* seconds */ + while (kill(pid, 0) == 0 && --maxwait >= 0) { + sleep(1); + } + pid = 0; } } @@ -419,31 +746,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 */ - lock_assert(); - else if (argc > 1) + fm_lock_assert(); + 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 @@ -454,8 +787,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); } } @@ -476,7 +809,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)); @@ -497,14 +830,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, terminate_run); - 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, @@ -516,12 +864,15 @@ int main(int argc, char **argv) } else { + /* not in daemon mode */ if (run.logfile && !nodetach && access(run.logfile, F_OK) == 0) { 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); + if (run.use_syslog) + report(stdout, GT_("fetchmail: Warning: syslog and logfile are set. Check both for logs!\n")); } } @@ -533,11 +884,15 @@ 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 */ - lock_or_die(); + 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 @@ -552,15 +907,29 @@ int main(int argc, char **argv) * leaks... */ struct stat rcstat; +#ifdef HAVE_LIBPWMD + time_t now; - if (stat(rcfile, &rcstat) == -1) - { + time(&now); +#endif + + if (strcmp(rcfile, "-") == 0) { + /* do nothing */ + } else if (stat(rcfile, &rcstat) == -1) { if (errno != ENOENT) report(stderr, 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); @@ -597,19 +966,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; @@ -651,6 +1022,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)) @@ -719,9 +1103,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); @@ -751,9 +1138,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 @@ -763,7 +1151,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); /* @@ -786,11 +1174,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"), @@ -845,7 +1233,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 @@ -857,6 +1244,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); @@ -893,7 +1282,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); @@ -902,6 +1293,9 @@ static void optmerge(struct query *h2, struct query *h1, int force) #undef FLAG_MERGE } +/** Load configuration files. + * \return - true if no servers found on the command line + * - false if servers found on the command line */ static int load_params(int argc, char **argv, int optind) { int implicitmode, st; @@ -911,6 +1305,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)); @@ -920,16 +1315,17 @@ 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; def_opts.fetchsizelimit = 100; - def_opts.fastuidl = 10; + def_opts.fastuidl = 4; /* get the location of rcfile */ rcfiledir[0] = 0; p = strrchr (rcfile, '/'); - if (p && (p - rcfile) < sizeof (rcfiledir)) { + if (p && (size_t)(p - rcfile) < sizeof (rcfiledir)) { *p = 0; /* replace '/' by '0' */ strlcpy (rcfiledir, rcfile, sizeof(rcfiledir)); *p = '/'; /* restore '/' */ @@ -938,11 +1334,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 (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) @@ -956,8 +1355,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++) @@ -974,10 +1401,31 @@ static int load_params(int argc, char **argv, int optind) || str_in_list(&ctl->server.akalist, argv[optind], TRUE)) { /* Is this correct? */ - if (predeclared && outlevel == O_VERBOSE) + if (predeclared && outlevel >= O_VERBOSE) 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) @@ -988,8 +1436,32 @@ 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; } @@ -997,18 +1469,27 @@ 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 */ - for (ctl = querylist; ctl; ctl = ctl->next) - if (ctl != querylist && strcmp(ctl->server.pollname, "defaults") == 0) + for (ctl = querylist; ctl; ctl = ctl->next) { + if (ctl != querylist && strcmp(ctl->server.pollname, "defaults") == 0) { + fprintf(stderr, GT_("fetchmail: Error: multiple \"defaults\" records in config file.\n")); exit(PS_SYNTAX); + } + } /* use localhost if we never fetch the FQDN of this host */ fetchmailhost = "localhost"; @@ -1018,19 +1499,23 @@ static int load_params(int argc, char **argv, int optind) run.logfile = cmd_run.logfile; if (cmd_run.idfile) run.idfile = cmd_run.idfile; + if (cmd_run.pidfile) + run.pidfile = cmd_run.pidfile; /* do this before the keep/fetchall test below, otherwise -d0 may fail */ 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) @@ -1052,13 +1537,15 @@ 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(); + fetchmailhost = host_fqdn(1); break; } + if (!ctl) /* list exhausted */ + fetchmailhost = host_fqdn(0); + /* this code enables flags to be turned off */ #define DEFAULT(flag, dflt) if (flag == FLAG_TRUE)\ flag = TRUE;\ @@ -1066,8 +1553,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) @@ -1111,7 +1596,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); @@ -1127,12 +1611,24 @@ 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. */ if (!ctl->smtphunt) - save_str(&ctl->smtphunt, fetchmailhost, FALSE); + save_str(&ctl->smtphunt, "localhost", FALSE); /* * Make sure we have a nonempty list of domains to fetch from. @@ -1148,15 +1644,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" * option, this causes truckloads full of support complaints @@ -1182,14 +1669,7 @@ static int load_params(int argc, char **argv, int optind) if (port < 0) { (void) fprintf(stderr, - GT_("%s configuration invalid, port number cannot be negative\n"), - ctl->server.pollname); - exit(PS_SYNTAX); - } - if (ctl->server.protocol == P_RPOP && port >= 1024) - { - (void) fprintf(stderr, - GT_("%s configuration invalid, RPOP requires a privileged port\n"), + GT_("fetchmail: %s configuration invalid, specify positive port number for service or port\n"), ctl->server.pollname); exit(PS_SYNTAX); } @@ -1202,9 +1682,9 @@ static int load_params(int argc, char **argv, int optind) { char *cp; - if (!(cp = strrchr(idp->id, '/')) || - ++cp, (0 == strcmp(cp, SMTP_PORT)) - || servport(cp) == SMTP_PORT_NUM) + if (!(cp = strrchr(idp->id, '/')) + || (0 == strcmp(cp + 1, SMTP_PORT)) + || servport(cp + 1) == SMTP_PORT_NUM) { (void) fprintf(stderr, GT_("%s configuration invalid, LMTP can't use default SMTP port\n"), @@ -1218,23 +1698,14 @@ static int load_params(int argc, char **argv, int optind) * "I beg to you, have mercy on the we[a]k minds like myself." * wrote Pehr Anderson. Your petition is granted. */ - if (ctl->fetchall && ctl->keep && run.poll_interval && !nodetach) + if (ctl->fetchall && ctl->keep && (run.poll_interval || ctl->idle) && !nodetach && !configdump) { (void) fprintf(stderr, - GT_("Both fetchall and keep on in daemon mode is a mistake!\n")); - exit(PS_SYNTAX); + GT_("Both fetchall and keep on in daemon or idle mode is a mistake!\n")); } } } -#ifdef POP3_ENABLE - /* initialize UID handling */ - if (!versioninfo && (st = prc_filecheck(run.idfile, !versioninfo)) != 0) - exit(st); - else - initialize_saved_lists(querylist, run.idfile); -#endif /* POP3_ENABLE */ - /* * If the user didn't set a last-resort user to get misaddressed * multidrop mail, set an appropriate default here. @@ -1250,41 +1721,12 @@ 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 */ { - /* - * 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. - * - * 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. - */ if (sig != 0) report(stdout, GT_("terminated with signal %d\n"), sig); - else - { - struct query *ctl; - - /* terminate all SMTP connections cleanly */ - for (ctl = querylist; ctl; ctl = ctl->next) - if (ctl->smtp_socket != -1) - { - /* 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); - } - } #ifdef POP3_ENABLE /* @@ -1297,7 +1739,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; @@ -1319,10 +1761,6 @@ static RETSIGTYPE terminate_run(int sig) if (ctl->password) memset(ctl->password, '\0', strlen(ctl->password)); -#if !defined(HAVE_ATEXIT) && !defined(HAVE_ON_EXIT) - fm_lock_release(); -#endif - if (activecount == 0) exit(PS_NOMAIL); else @@ -1340,15 +1778,13 @@ 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) /* perform fetch transaction with single host */ { - int i, st = 0; + size_t i; + int st = 0; /* * If we're syslogging the progress messages are automatically timestamped. @@ -1377,17 +1813,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); @@ -1444,6 +1870,14 @@ 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 */ @@ -1456,10 +1890,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) @@ -1473,6 +1905,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)) @@ -1500,22 +1937,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 @@ -1524,8 +1953,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) @@ -1546,20 +1973,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); @@ -1570,9 +1999,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 @@ -1593,7 +2026,7 @@ static void dump_params (struct runctl *runp, printf(GT_(" Selected mailboxes are:")); for (idp = ctl->mailboxes; idp; idp = idp->next) - printf(" %s", (char *)idp->id); + printf(" %s", idp->id); printf("\n"); } printf(ctl->fetchall @@ -1683,7 +2116,7 @@ static void dump_params (struct runctl *runp, printf(GT_(" Domains for which mail will be fetched are:")); for (idp = ctl->domainlist; idp; idp = idp->next) { - printf(" %s", (char *)idp->id); + printf(" %s", idp->id); if (!idp->val.status.mark) printf(GT_(" (default)")); } @@ -1703,7 +2136,7 @@ static void dump_params (struct runctl *runp, ctl->listener); for (idp = ctl->smtphunt; idp; idp = idp->next) { - printf(" %s", (char *)idp->id); + printf(" %s", idp->id); if (!idp->val.status.mark) printf(GT_(" (default)")); } @@ -1761,9 +2194,9 @@ static void dump_params (struct runctl *runp, { for (idp = ctl->localnames; idp; idp = idp->next) if (idp->val.id2) - printf("\t%s -> %s\n", (char *)idp->id, (char *)idp->val.id2); + printf("\t%s -> %s\n", idp->id, idp->val.id2); else - printf("\t%s\n", (char *)idp->id); + printf("\t%s\n", idp->id); if (ctl->wildcard) fputs("\t*\n", stdout); } @@ -1785,9 +2218,9 @@ static void dump_params (struct runctl *runp, else { printf(GT_(" Envelope header is assumed to be: %s\n"), - ctl->server.envelope ? ctl->server.envelope:GT_("Received")); - if (ctl->server.envskip > 1 || outlevel >= O_VERBOSE) - printf(GT_(" Number of envelope header to be parsed: %d\n"), + ctl->server.envelope ? ctl->server.envelope : "Received"); + if (ctl->server.envskip || outlevel >= O_VERBOSE) + printf(GT_(" Number of envelope headers to be skipped over: %d\n"), ctl->server.envskip); if (ctl->server.qvirtual) printf(GT_(" Prefix %s will be removed from user id\n"), @@ -1798,20 +2231,17 @@ 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", (char *)idp->id); + 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", (char *)idp->id); + printf(" %s", idp->id); putchar('\n'); } } @@ -1837,29 +2267,46 @@ 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", (char *)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"),