X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=fetchmail.c;h=dd83b671fdbb26a51a86dfa710555c9d88733324;hb=bdf8ed139a586f3ef1d11574c59813f982ca0698;hp=7284477c05c21905ff4cd3f5f727dfafc81946f0;hpb=e6e5c6c4ddffa8199225c76cd46e34ab58aec2ca;p=~andy%2Ffetchmail diff --git a/fetchmail.c b/fetchmail.c index 7284477c..dd83b671 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -6,30 +6,34 @@ #include "config.h" #include -#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 +#endif #include -#include #include #include +#include /* needed for Sun 4.1.2 */ #ifdef HAVE_SETRLIMIT #include #endif /* HAVE_SETRLIMIT */ -#ifdef HAVE_SYS_WAIT_H -#include -#endif +#include +#ifdef HAVE_NET_SOCKET_H +#include +#endif #ifdef HAVE_GETHOSTBYNAME #include #endif /* HAVE_GETHOSTBYNAME */ @@ -38,10 +42,10 @@ #include #endif +#include "getopt.h" #include "fetchmail.h" #include "tunable.h" #include "smtp.h" -#include "getopt.h" #include "netrc.h" #include "i18n.h" @@ -65,6 +69,7 @@ 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 */ flag configdump; /* dump control blocks for configurator */ const char *fetchmailhost; /* either `localhost' or the host's FQDN */ @@ -75,44 +80,14 @@ int requestlen = 0; #endif /* NET_SECURITY */ static char *lockfile; /* name of lockfile */ +static int lock_acquired; /* have we acquired a lock */ static int querystatus; /* status of query */ static int successes; /* count number of successful polls */ -static int lastsig; /* last signal received */ static struct runctl cmd_run; /* global options set from command line */ +static time_t parsetime; /* time of last parse */ -static void termhook(int); /* forward declaration of exit hook */ - -#if 0 -#define SLEEP_WITH_ALARM -#endif - -#ifdef SLEEP_WITH_ALARM -/* - * The function of this variable is to remove the window during which a - * SIGALRM can hose the code (ALARM is triggered *before* pause() is called). - * This is a bit of a kluge; the real right thing would use sigprocmask(), - * sigsuspend(). - * This work around lets the interval timer trigger the first alarm after the - * required interval and will then generate alarms all 5 seconds, until it - * is certain, that the critical section (ie., the window) is left. - */ -#if defined(STDC_HEADERS) -static sig_atomic_t alarm_latch = FALSE; -#else -/* assume int can be written in one atomic operation on non ANSI-C systems */ -static int alarm_latch = FALSE; -#endif - -RETSIGTYPE gotsigalrm(sig) -int sig; -{ - signal(sig, gotsigalrm); - lastsig = sig; - alarm_latch = TRUE; -} -#endif /* SLEEP_WITH_ALARM */ - -RETSIGTYPE donothing(int sig) {signal(sig, donothing); lastsig = sig;} +static void terminate_run(int); +static void terminate_poll(int); #ifdef HAVE_ON_EXIT static void unlockit(int n, void *p) @@ -121,23 +96,32 @@ static void unlockit(void) #endif /* must-do actions for exit (but we can't count on being able to do malloc) */ { - unlink(lockfile); + if (lockfile && lock_acquired) + unlink(lockfile); } -#ifdef __EMX__ -/* Various EMX-specific definitions */ -int itimerflag; -void itimerthread(void* dummy) { - if (outlevel >= O_VERBOSE) - fprintf(stderr, _("fetchmail: thread sleeping for %d sec.\n"), poll_interval); - while(1) { - _sleep2(poll_interval*1000); - kill((getpid()), SIGALRM); - } +#ifdef __FreeBSD__ +/* drop SGID kmem privileage until we need it */ +static void dropprivs(void) +{ + struct group *gr; + gid_t egid; + gid_t rgid; + + egid = getegid(); + rgid = getgid(); + gr = getgrgid(egid); + + if (gr && !strcmp(gr->gr_name, "kmem")) + { + extern void interface_set_gids(gid_t egid, gid_t rgid); + interface_set_gids(egid, rgid); + setegid(rgid); + } } #endif -int main (int argc, char **argv) +int main(int argc, char **argv) { int st, bkgd = FALSE; int parsestatus, implicitmode = FALSE; @@ -146,6 +130,11 @@ int main (int argc, char **argv) netrc_entry *netrc_list; char *netrc_file, *tmpbuf; pid_t pid; + int lastsig = 0; + +#ifdef __FreeBSD__ + dropprivs(); +#endif envquery(argc, argv); #ifdef ENABLE_NLS @@ -153,14 +142,44 @@ int main (int argc, char **argv) textdomain(PACKAGE); #endif + /* + * Note: because we can't initialize reporting before we know whether + * syslog is supposed to be on, this message will go to stdout and + * be lost when running in background. + */ + if (outlevel >= O_VERBOSE) + { + int i; + + report(stdout, "fetchmail: invoked with"); + for (i = 0; i < argc; i++) + report(stdout, " %s", argv[i]); + report(stdout, "\n"); + } + #define IDFILE_NAME ".fetchids" - run.idfile = (char *) xmalloc(strlen(home)+strlen(IDFILE_NAME)+2); - strcpy(run.idfile, home); + run.idfile = (char *) xmalloc(strlen(fmhome)+sizeof(IDFILE_NAME)+2); + strcpy(run.idfile, fmhome); strcat(run.idfile, "/"); strcat(run.idfile, IDFILE_NAME); outlevel = O_NORMAL; + /* + * We used to arrange for the lockfile to be removed on exit close + * to where the lock was asserted. Now we need to do it here, because + * we might have re-executed in background with an existing lockfile + * as the result of a changed rcfile (see the code near the execvp(3) + * call near the beginning of the polling loop for details). We want + * to be sure the lockfile gets nuked on any error exit, basically. + */ +#ifdef HAVE_ATEXIT + atexit(unlockit); +#endif +#ifdef HAVE_ON_EXIT + on_exit(unlockit, (char *)NULL); +#endif + if ((parsestatus = parsecmdline(argc,argv, &cmd_run, &cmd_opts)) < 0) exit(PS_SYNTAX); @@ -182,30 +201,35 @@ int main (int argc, char **argv) #ifdef RPA_ENABLE printf("+RPA"); #endif /* RPA_ENABLE */ +#ifdef NTLM_ENABLE + printf("+NTLM"); +#endif /* NTLM_ENABLE */ #ifdef SDPS_ENABLE printf("+SDPS"); #endif /* SDPS_ENABLE */ #ifndef ETRN_ENABLE printf("-ETRN"); #endif /* ETRN_ENABLE */ -#if OPIE +#ifdef SSL_ENABLE + printf("+SSL"); +#endif +#if OPIE_ENABLE printf("+OPIE"); -#endif /* OPIE */ -#if INET6 +#endif /* OPIE_ENABLE */ +#if INET6_ENABLE printf("+INET6"); -#endif /* INET6 */ +#endif /* INET6_ENABLE */ #if NET_SECURITY printf("+NETSEC"); #endif /* NET_SECURITY */ #ifdef HAVE_SOCKS - #if HAVE_SOCKS printf("+SOCKS"); - #endif #endif /* HAVE_SOCKS */ #if ENABLE_NLS printf("+NLS"); #endif /* ENABLE_NLS */ putchar('\n'); + fflush(stdout); /* this is an attempt to help remote debugging */ system("uname -a"); @@ -215,34 +239,116 @@ int main (int argc, char **argv) if (!(quitmode && argc == 2)) implicitmode = load_params(argc, argv, optind); +#if defined(HAVE_SYSLOG) + /* 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); + /* set up to do lock protocol */ #define FETCHMAIL_PIDFILE "fetchmail.pid" if (!getuid()) { xalloca(tmpbuf, char *, - strlen(PID_DIR) + strlen(FETCHMAIL_PIDFILE) + 2); + sizeof(PID_DIR) + sizeof(FETCHMAIL_PIDFILE)); sprintf(tmpbuf, "%s/%s", PID_DIR, FETCHMAIL_PIDFILE); } else { - xalloca(tmpbuf, char *, strlen(home) + strlen(FETCHMAIL_PIDFILE) + 3); - strcpy(tmpbuf, home); - strcat(tmpbuf, "/."); + xalloca(tmpbuf, char *, strlen(fmhome) + sizeof(FETCHMAIL_PIDFILE) + 2); + strcpy(tmpbuf, fmhome); + strcat(tmpbuf, "/"); + if (fmhome == home) + strcat(tmpbuf, "."); strcat(tmpbuf, FETCHMAIL_PIDFILE); } #undef FETCHMAIL_PIDFILE +#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 + * cracker. + */ + if (outlevel < O_VERBOSE || run.poll_interval > 0) + { + struct rlimit corelimit; + corelimit.rlim_cur = 0; + 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. */ + xalloca(netrc_file, char *, strlen(home) + sizeof(NETRC_FILE) + 2); + strcpy (netrc_file, home); + strcat (netrc_file, "/"); + strcat (netrc_file, NETRC_FILE); + netrc_list = parse_netrc(netrc_file); +#undef NETRC_FILE + + /* pick up passwords where we can */ + for (ctl = querylist; ctl; ctl = ctl->next) + { + if (ctl->active && !(implicitmode && ctl->server.skip)&&!ctl->password) + { + if (ctl->server.preauthenticate == A_KERBEROS_V4 || + ctl->server.preauthenticate == A_KERBEROS_V5 || + ctl->server.preauthenticate == A_SSH || +#ifdef GSSAPI + ctl->server.protocol == P_IMAP_GSS || +#endif /* GSSAPI */ + ctl->server.protocol == P_IMAP_K4) + /* Server won't care what the password is, but there + must be some non-null string here. */ + ctl->password = ctl->remotename; + else + { + netrc_entry *p; + + /* look up the pollname and account in the .netrc file. */ + p = search_netrc(netrc_list, + ctl->server.pollname, ctl->remotename); + /* if we find a matching entry with a password, use it */ + if (p && p->password) + ctl->password = xstrdup(p->password); + + /* otherwise try with "via" name if there is one */ + else if (ctl->server.via) + { + p = search_netrc(netrc_list, + ctl->server.via, ctl->remotename); + if (p && p->password) + ctl->password = xstrdup(p->password); + } + } + } + } + /* perhaps we just want to check options? */ if (versioninfo) { - printf(_("Taking options from command line")); - if (access(rcfile, 0)) - printf("\n"); - else - printf(_(" and %s\n"), rcfile); + int havercfile = access(rcfile, 0); + + printf(_("Taking options from command line%s%s\n"), + havercfile ? "" : _(" and "), + havercfile ? "" : rcfile); + if (outlevel >= O_VERBOSE) printf(_("Lockfile at %s\n"), tmpbuf); if (querylist == NULL) - (void) fprintf(stderr, - _("No mailservers set up -- perhaps %s is missing?\n"), rcfile); + fprintf(stderr, + _("No mailservers set up -- perhaps %s is missing?\n"), + rcfile); else dump_params(&run, querylist, implicitmode); exit(0); @@ -259,7 +365,7 @@ int main (int argc, char **argv) pid = -1; if ((lockfile = (char *) malloc(strlen(tmpbuf) + 1)) == NULL) { - fprintf(stderr,_("fetchmail: cannot allocate memory for lock name.\n")); + report(stderr,_("fetchmail: cannot allocate memory for lock name.\n")); exit(PS_EXCLUDE); } else @@ -274,7 +380,7 @@ int main (int argc, char **argv) bkgd = FALSE; unlink(lockfile); } - fclose(lockfp); + fclose(lockfp); /* not checking should be safe, file mode was "r" */ } /* if no mail servers listed and nothing in background, we're done */ @@ -335,9 +441,15 @@ int main (int argc, char **argv) } else if (argc > 1) { - fprintf(stderr, - _("fetchmail: can't accept options while a background fetchmail is running.\n")); - return(PS_EXCLUDE); + /* this test enables re-execing on a changed rcfile */ + if (getpid() == pid) + lock_acquired = TRUE; + else + { + fprintf(stderr, + _("fetchmail: can't accept options while a background fetchmail is running.\n")); + return(PS_EXCLUDE); + } } else if (kill(pid, SIGUSR1) == 0) { @@ -360,111 +472,53 @@ int main (int argc, char **argv) } } - /* parse the ~/.netrc file (if present) for future password lookups. */ - xalloca(netrc_file, char *, strlen (home) + 8); - strcpy (netrc_file, home); - strcat (netrc_file, "/.netrc"); - netrc_list = parse_netrc(netrc_file); - -#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 - * cracker. - */ - if (outlevel < O_VERBOSE || run.poll_interval > 0) - { - struct rlimit corelimit; - corelimit.rlim_cur = 0; - corelimit.rlim_max = 0; - setrlimit(RLIMIT_CORE, &corelimit); - } -#endif /* HAVE_SETRLIMIT */ - /* pick up interactively any passwords we need but don't have */ for (ctl = querylist; ctl; ctl = ctl->next) { - if (ctl->active && !(implicitmode && ctl->server.skip)&&!ctl->password) - { - if (ctl->server.preauthenticate == A_KERBEROS_V4 || - ctl->server.preauthenticate == A_KERBEROS_V5 || + if (ctl->active && !(implicitmode && ctl->server.skip) + && ctl->server.protocol != P_ETRN + && ctl->server.protocol != P_IMAP_K4 #ifdef GSSAPI - ctl->server.protocol == P_IMAP_GSS || + && ctl->server.protocol != P_IMAP_GSS #endif /* GSSAPI */ - ctl->server.protocol == P_IMAP_K4) - /* Server won't care what the password is, but there - must be some non-null string here. */ - ctl->password = ctl->remotename; - else + && !ctl->password) + if (!isatty(0)) { - netrc_entry *p; - - /* look up the pollname and account in the .netrc file. */ - p = search_netrc(netrc_list, ctl->server.pollname); - while (p && strcmp(p->account, ctl->remotename)) - p = search_netrc(p->next, ctl->remotename); - /* if we find a matching entry with a password, use it */ - if (p && p->password) - ctl->password = xstrdup(p->password); - - /* otherwise try with "via" name if there is one */ - else if (ctl->server.via) - { - p = search_netrc(netrc_list, ctl->server.via); - while (p && strcmp(p->account, ctl->remotename)) - p = search_netrc(p->next, ctl->remotename); - if (p && p->password) - ctl->password = xstrdup(p->password); - } + fprintf(stderr, + _("fetchmail: can't find a password for %s@s.\n"), + ctl->remotename, ctl->server.pollname); + return(PS_AUTHFAIL); } - - if (ctl->server.protocol != P_ETRN && ctl->server.protocol != P_IMAP_K4 -#ifdef GSSAPI - && ctl->server.protocol != P_IMAP_GSS -#endif /* GSSAPI */ - && !ctl->password) + else { char* password_prompt = _("Enter password for %s@%s: "); xalloca(tmpbuf, char *, strlen(password_prompt) + - strlen(ctl->remotename) + - strlen(ctl->server.pollname) + 1); + strlen(ctl->remotename) + + strlen(ctl->server.pollname) + 1); (void) sprintf(tmpbuf, password_prompt, ctl->remotename, ctl->server.pollname); - ctl->password = xstrdup((char *)getpassword(tmpbuf)); + ctl->password = xstrdup((char *)fm_getpassword(tmpbuf)); } - } } -/* Time to initiate the SOCKS library (this is not mandatory: it just - registers the correct application name for logging purpose. If you - have some problem, comment these lines). */ + /* + * Time to initiate the SOCKS library (this is not mandatory: it just + * registers the correct application name for logging purpose. If you + * have some problem, comment out these lines). + */ #ifdef HAVE_SOCKS - #if HAVE_SOCKS -/* Mmmh... I don't like hardcoded application names, - but "fetchmail" is everywhere... */ SOCKSinit("fetchmail"); - #endif #endif /* HAVE_SOCKS */ /* * Maybe time to go to demon mode... */ -#if defined(HAVE_SYSLOG) - if (run.use_syslog) - { - openlog(program_name, LOG_PID, LOG_MAIL); - report_init(-1); - } - else -#endif - report_init((run.poll_interval == 0 || nodetach) && !run.logfile); - if (run.poll_interval) { if (!nodetach) - daemonize(run.logfile, termhook); - report(stdout, 0, _("starting fetchmail %s daemon "), VERSION); + daemonize(run.logfile, terminate_run); + report(stdout, _("starting fetchmail %s daemon \n"), VERSION); /* * We'll set up a handler for these when we're sleeping, @@ -474,29 +528,41 @@ int main (int argc, char **argv) if (run.poll_interval && !getuid()) signal(SIGHUP, SIG_IGN); } + else if (run.logfile && access(run.logfile, F_OK) == 0) + { + freopen(run.logfile, "a", stdout); + freopen(run.logfile, "a", stderr); + } + + +#ifdef linux + interface_init(); +#endif /* linux */ /* beyond here we don't want more than one fetchmail running per user */ umask(0077); - signal(SIGABRT, termhook); - signal(SIGINT, termhook); - signal(SIGTERM, termhook); - signal(SIGALRM, termhook); - signal(SIGPIPE, termhook); - signal(SIGQUIT, termhook); + signal(SIGABRT, terminate_run); + signal(SIGINT, terminate_run); + signal(SIGTERM, terminate_run); + signal(SIGALRM, terminate_run); + signal(SIGPIPE, terminate_run); + signal(SIGQUIT, terminate_run); /* here's the exclusion lock */ - if ((lockfp = fopen(lockfile,"w")) != NULL) { - fprintf(lockfp,"%d",getpid()); - if (run.poll_interval) - fprintf(lockfp," %d", run.poll_interval); - fclose(lockfp); - -#ifdef HAVE_ATEXIT - atexit(unlockit); -#endif -#ifdef HAVE_ON_EXIT - on_exit(unlockit, (char *)NULL); +#ifndef O_SYNC +#define O_SYNC 0 /* use it if we have it */ #endif + if ((st = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_SYNC, 0666)) != -1) + { + sprintf(tmpbuf,"%d", getpid()); + write(st, tmpbuf, strlen(tmpbuf)); + if (run.poll_interval) + { + sprintf(tmpbuf," %d", run.poll_interval); + write(st, tmpbuf, strlen(tmpbuf)); + } + close(st); /* should be safe, fd was opened with O_SYNC */ + lock_acquired = TRUE; } /* @@ -504,6 +570,29 @@ int main (int argc, char **argv) * reflect the status of that transaction. */ do { + /* + * Check to see if the rcfile has been touched. If so, + * re-exec so the file will be reread. Doing it this way + * avoids all the complications of trying to deallocate the + * in-core control structures -- and the potential memory + * leaks... + */ + struct stat rcstat; + + if (stat(rcfile, &rcstat) == -1) + { + if (errno != ENOENT) + report(stderr, + _("couldn't time-check %s (error %d)\n"), + rcfile, errno); + } + else if (rcstat.st_mtime > parsetime) + { + report(stdout, _("restarting fetchmail (%s changed)\n"), rcfile); + execvp("fetchmail", argv); + report(stderr, _("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 @@ -525,8 +614,8 @@ int main (int argc, char **argv) { if (ctl->wedged) { - report(stderr, 0, - _("poll of %s skipped (failed authentication or too many timeouts)"), + report(stderr, + _("poll of %s skipped (failed authentication or too many timeouts)\n"), ctl->server.pollname); continue; } @@ -537,43 +626,68 @@ int main (int argc, char **argv) if (ctl->server.poll_count++ % ctl->server.interval) { if (outlevel >= O_VERBOSE) - report(stdout, 0, - _("interval not reached, not querying %s"), + report(stdout, + _("interval not reached, not querying %s\n"), ctl->server.pollname); continue; } } -#if defined(linux) && !INET6 - /* interface_approve() does its own error logging */ - if (!interface_approve(&ctl->server)) +#if (defined(linux) && !INET6_ENABLE) || defined(__FreeBSD__) + /* + * Don't do monitoring if we were woken by a signal. + * Note that interface_approve() does its own error logging. + */ + if (!interface_approve(&ctl->server, !lastsig)) continue; -#endif /* defined(linux) && !INET6 */ +#endif /* (defined(linux) && !INET6_ENABLE) || defined(__FreeBSD__) */ querystatus = query_host(ctl); - if (querystatus == PS_SUCCESS) - { - successes++; #ifdef POP3_ENABLE - if (!check_only) - update_str_lists(ctl); - - /* Save UID list to prevent re-fetch in case fetchmail - recover from crash */ - if (!check_only) - { - write_saved_lists(querylist, run.idfile); - if (outlevel >= O_DEBUG) - report(stdout, 0, _("saved UID List")); - } + if (!check_only) + uid_end_query(ctl); #endif /* POP3_ENABLE */ - } + + if (querystatus == PS_SUCCESS) + successes++; else if (!check_only && ((querystatus!=PS_NOMAIL) || (outlevel==O_DEBUG))) - report(stdout, 0, _("Query status=%d"), querystatus); + switch(querystatus) + { + case PS_SUCCESS: + report(stdout, "Query status=0 (SUCCESS)\n"); break ; + case PS_NOMAIL: + report(stdout, "Query status=1 (NOMAIL)\n"); break ; + case PS_SOCKET: + report(stdout, "Query status=2 (SOCKET)\n"); break ; + case PS_AUTHFAIL: + report(stdout, "Query status=3 (AUTHFAIL)\n"); break ; + case PS_PROTOCOL: + report(stdout, "Query status=4 (PROTOCOL)\n"); break ; + case PS_SYNTAX: + report(stdout, "Query status=5 (SYNTAX)\n"); break ; + case PS_IOERR: + report(stdout, "Query status=6 (IOERR)\n"); break ; + case PS_ERROR: + report(stdout, "Query status=7 (ERROR)\n"); break ; + case PS_EXCLUDE: + report(stdout, "Query status=8 (EXCLUDE)\n"); break ; + case PS_LOCKBUSY: + report(stdout, "Query status=9 (LOCKBUSY)\n"); break ; + case PS_SMTP: + report(stdout, "Query status=10 (SMTP)\n"); break ; + case PS_DNS: + report(stdout, "Query status=11 (DNS)\n"); break ; + case PS_BSMTP: + report(stdout, "Query status=12 (BSMTP)\n"); break ; + case PS_MAXFETCH: + report(stdout, "Query status=13 (MAXFETCH)\n"); break ; + default: + report(stdout, _("Query status=%d\n"), querystatus); break; + } -#if defined(linux) && !INET6 +#if (defined(linux) && !INET6_ENABLE) || defined (__FreeBSD__) if (ctl->server.monitor) { /* @@ -584,7 +698,7 @@ int main (int argc, char **argv) sleep(3); interface_note_activity(&ctl->server); } -#endif /* defined(linux) && !INET6 */ +#endif /* (defined(linux) && !INET6_ENABLE) || defined(__FreeBSD__) */ } } @@ -592,21 +706,8 @@ int main (int argc, char **argv) endhostent(); /* release TCP/IP connection to nameserver */ #endif /* HAVE_RES_SEARCH */ - /* - * 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. - */ - for (ctl = querylist; ctl; ctl = ctl->next) - if (ctl->smtp_socket != -1) - { - SMTP_quit(ctl->smtp_socket); - close(ctl->smtp_socket); - ctl->smtp_socket = -1; - } + /* close connections cleanly */ + terminate_poll(0); /* * OK, we've polled. Now sleep. @@ -628,163 +729,81 @@ int main (int argc, char **argv) unwedged++; if (!unwedged) { - report(stderr, 0, _("All connections are wedged. Exiting.")); + report(stderr, _("All connections are wedged. Exiting.\n")); + /* FIXME: someday, send notification mail */ exit(PS_AUTHFAIL); } if (outlevel >= O_VERBOSE) - report(stdout, 0, _("fetchmail: sleeping at %s"), rfc822timestamp()); + report(stdout, + _("fetchmail: sleeping at %s\n"), rfc822timestamp()); /* - * With this simple hack, we make it possible for a foreground - * fetchmail to wake up one in daemon mode. What we want is the - * side effect of interrupting any sleep that may be going on, - * forcing fetchmail to re-poll its hosts. The second line is - * for people who think all system daemons wake up on SIGHUP. + * OK, now pause util it's time for the next poll cycle. + * A nonzero return indicates we received a wakeup signal; + * unwedge all servers in case the problem has been + * manually repaired. */ - signal(SIGUSR1, donothing); - if (!getuid()) - signal(SIGHUP, donothing); - - /* time for a pause in the action... */ + if ((lastsig = interruptible_idle(run.poll_interval))) { -#ifndef __EMX__ -#ifdef SLEEP_WITH_ALARM /* not normally on */ - /* - * We can't use sleep(3) here because we need an alarm(3) - * equivalent in order to implement server nonresponse timeout. - * We'll just assume setitimer(2) is available since fetchmail - * has to have a BSDoid socket layer to work at all. - */ - /* - * This code stopped working under glibc-2, apparently due - * to the change in signal(2) semantics. (The siginterrupt - * line, added later, should fix this problem.) John Stracke - * wrote: - * - * The problem seems to be that, after hitting the interval - * timer while talking to the server, the process no longer - * responds to SIGALRM. I put in printf()s to see when it - * reached the pause() for the poll interval, and I checked - * the return from setitimer(), and everything seemed to be - * working fine, except that the pause() just ignored SIGALRM. - * I thought maybe the itimer wasn't being fired, so I hit - * it with a SIGALRM from the command line, and it ignored - * that, too. SIGUSR1 woke it up just fine, and it proceeded - * to repoll--but, when the dummy server didn't respond, it - * never timed out, and SIGALRM wouldn't make it. - * - * (continued below...) - */ - struct itimerval ntimeout; - - ntimeout.it_interval.tv_sec = 5; /* repeat alarm every 5 secs */ - ntimeout.it_interval.tv_usec = 0; - ntimeout.it_value.tv_sec = run.poll_interval; - ntimeout.it_value.tv_usec = 0; - - siginterrupt(SIGALRM, 1); - alarm_latch = FALSE; - signal(SIGALRM, gotsigalrm); /* first trap signals */ - setitimer(ITIMER_REAL,&ntimeout,NULL); /* then start timer */ - /* there is a very small window between the next two lines */ - /* which could result in a deadlock. But this will now be */ - /* caught by periodical alarms (see it_interval) */ - if (!alarm_latch) - pause(); - /* stop timer */ - ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0; - ntimeout.it_value.tv_sec = ntimeout.it_value.tv_usec = 0; - setitimer(ITIMER_REAL,&ntimeout,NULL); /* now stop timer */ - signal(SIGALRM, SIG_IGN); -#else - /* - * So the workaround I used is to make it sleep by using - * select() instead of setitimer()/pause(). select() is - * perfectly happy being called with a timeout and - * no file descriptors; it just sleeps until it hits the - * timeout. The only concern I had was that it might - * implement its timeout with SIGALRM--there are some - * Unices where this is done, because select() is a library - * function--but apparently not. - */ - struct timeval timeout; - - timeout.tv_sec = run.poll_interval; - timeout.tv_usec = 0; - lastsig = 0; - select(0,0,0,0, &timeout); -#endif -#else /* EMX */ - alarm_latch = FALSE; - signal(SIGALRM, gotsigalrm); - _beginthread(itimerthread, NULL, 32768, NULL); - /* see similar code above */ - if (!alarm_latch) - pause(); - signal(SIGALRM, SIG_IGN); -#endif /* ! EMX */ - if (lastsig == SIGUSR1 - || ((run.poll_interval && !getuid()) && lastsig == SIGHUP)) - { #ifdef SYS_SIGLIST_DECLARED - report(stdout, 0, _("awakened by %s"), sys_siglist[lastsig]); + report(stdout, + _("awakened by %s\n"), sys_siglist[lastsig]); #else - report(stdout, 0, _("awakened by signal %d"), lastsig); + report(stdout, + _("awakened by signal %d\n"), lastsig); #endif - /* received a wakeup - unwedge all servers in case */ - /* the problem has been manually repaired */ - for (ctl = querylist; ctl; ctl = ctl->next) - ctl->wedged = FALSE; - } + for (ctl = querylist; ctl; ctl = ctl->next) + ctl->wedged = FALSE; } - /* now lock out interrupts again */ - signal(SIGUSR1, SIG_IGN); - if (!getuid()) - signal(SIGHUP, SIG_IGN); - if (outlevel >= O_VERBOSE) - report(stdout, 0, _("awakened at %s"), rfc822timestamp()); + report(stdout, _("awakened at %s\n"), rfc822timestamp()); } } while (run.poll_interval); if (outlevel >= O_VERBOSE) - report(stdout, 0, _("normal termination, status %d"), + report(stdout, _("normal termination, status %d\n"), successes ? PS_SUCCESS : querystatus); - termhook(0); + terminate_run(0); exit(successes ? PS_SUCCESS : querystatus); } -static void optmerge(struct query *h2, struct query *h1, int force) -/* merge two options records */ +static void list_merge(struct idlist **dstl, struct idlist **srcl, int force) { /* - * If force is off, modify h2 fields only when they're empty (treat h1 - * as defaults). If force is on, modify each h2 field whenever h1 - * is nonempty (treat h1 as an override). + * If force is off, modify dstl fields only when they're empty (treat srcl + * as defaults). If force is on, modify each dstl field whenever scrcl + * is nonempty (treat srcl as an override). */ -#define LIST_MERGE(dstl, srcl) if (force ? !!srcl : !dstl) \ - free_str_list(&dstl), \ - append_str_list(&dstl, &srcl) - LIST_MERGE(h2->server.localdomains, h1->server.localdomains); - LIST_MERGE(h2->localnames, h1->localnames); - LIST_MERGE(h2->mailboxes, h1->mailboxes); - LIST_MERGE(h2->smtphunt, h1->smtphunt); - LIST_MERGE(h2->antispam, h1->antispam); -#undef LIST_MERGE + if (force ? !!*srcl : !*dstl) + { + struct idlist *cpl = copy_str_list(*srcl); + + append_str_list(dstl, &cpl); + } +} + +static void optmerge(struct query *h2, struct query *h1, int force) +/* merge two options records */ +{ + list_merge(&h2->server.localdomains, &h1->server.localdomains, force); + list_merge(&h2->localnames, &h1->localnames, force); + list_merge(&h2->mailboxes, &h1->mailboxes, force); + list_merge(&h2->smtphunt, &h1->smtphunt, force); + list_merge(&h2->antispam, &h1->antispam, force); #define FLAG_MERGE(fld) if (force ? !!h1->fld : !h2->fld) h2->fld = h1->fld FLAG_MERGE(server.via); FLAG_MERGE(server.protocol); -#if INET6 +#if INET6_ENABLE FLAG_MERGE(server.service); FLAG_MERGE(server.netsec); -#else /* INET6 */ +#else /* INET6_ENABLE */ FLAG_MERGE(server.port); -#endif /* INET6 */ +#endif /* INET6_ENABLE */ FLAG_MERGE(server.interval); FLAG_MERGE(server.preauthenticate); FLAG_MERGE(server.timeout); @@ -796,14 +815,15 @@ static void optmerge(struct query *h2, struct query *h1, int force) FLAG_MERGE(server.checkalias); FLAG_MERGE(server.uidl); -#ifdef linux +#if defined(linux) || defined(__FreeBSD__) FLAG_MERGE(server.interface); FLAG_MERGE(server.monitor); FLAG_MERGE(server.interface_pair); -#endif /* linux */ +#endif /* linux || defined(__FreeBSD__) */ FLAG_MERGE(server.plugin); FLAG_MERGE(server.plugout); + FLAG_MERGE(wildcard); FLAG_MERGE(remotename); FLAG_MERGE(password); @@ -811,6 +831,7 @@ static void optmerge(struct query *h2, struct query *h1, int force) FLAG_MERGE(bsmtp); FLAG_MERGE(listener); FLAG_MERGE(smtpaddress); + FLAG_MERGE(smtpname); FLAG_MERGE(preconnect); FLAG_MERGE(postconnect); @@ -823,10 +844,16 @@ static void optmerge(struct query *h2, struct query *h1, int force) FLAG_MERGE(pass8bits); FLAG_MERGE(dropstatus); FLAG_MERGE(mimedecode); + FLAG_MERGE(idle); FLAG_MERGE(limit); FLAG_MERGE(warnings); FLAG_MERGE(fetchlimit); FLAG_MERGE(batchlimit); +#ifdef SSL_ENABLE + FLAG_MERGE(use_ssl); + FLAG_MERGE(sslkey); + FLAG_MERGE(sslcert); +#endif FLAG_MERGE(expunge); FLAG_MERGE(properties); @@ -838,24 +865,42 @@ static int load_params(int argc, char **argv, int optind) int implicitmode, st; struct passwd *pw; struct query def_opts, *ctl; + struct stat rcstat; + + run.bouncemail = TRUE; memset(&def_opts, '\0', sizeof(struct query)); def_opts.smtp_socket = -1; def_opts.smtpaddress = (char *)0; - save_str(&def_opts.antispam, STRING_DUMMY, 0)->val.status.num = 571; - save_str(&def_opts.antispam, STRING_DUMMY, 0)->val.status.num = 550; - save_str(&def_opts.antispam, STRING_DUMMY, 0)->val.status.num = 501; +#define ANTISPAM(n) save_str(&def_opts.antispam, STRING_DUMMY, 0)->val.status.num = (n) + ANTISPAM(571); /* sendmail */ + ANTISPAM(550); /* old exim */ + ANTISPAM(501); /* new exim */ + ANTISPAM(554); /* Postfix */ +#undef ANTISPAM def_opts.server.protocol = P_AUTO; def_opts.server.timeout = CLIENT_TIMEOUT; def_opts.warnings = WARNING_INTERVAL; def_opts.remotename = user; - def_opts.expunge = 1; def_opts.listener = SMTP_MODE; + /* 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, _("couldn't time-check the run-control file\n")); + /* this builds the host list */ - if (prc_parse_file(rcfile, !versioninfo) != 0) - exit(PS_SYNTAX); + if ((st = prc_parse_file(rcfile, !versioninfo)) != 0) + /* + * FIXME: someday, send notification mail here if backgrounded. + * Right now, that can happen if the user changes the rcfile + * while the fetchmail is running in background. Do similarly + * for the other exit() calls in this function. + */ + exit(st); if ((implicitmode = (optind >= argc))) { @@ -916,6 +961,27 @@ static int load_params(int argc, char **argv, int optind) /* use localhost if we never fetch the FQDN of this host */ fetchmailhost = "localhost"; + /* here's where we override globals */ + if (cmd_run.logfile) + run.logfile = cmd_run.logfile; + if (cmd_run.idfile) + run.idfile = cmd_run.idfile; + /* 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; + 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; + + /* check and daemon options are not compatible */ + if (check_only && run.poll_interval) + run.poll_interval = 0; + /* merge in wired defaults, do sanity checks and prepare internal fields */ for (ctl = querylist; ctl; ctl = ctl->next) { @@ -945,13 +1011,19 @@ static int load_params(int argc, char **argv, int optind) DEFAULT(ctl->pass8bits, FALSE); DEFAULT(ctl->dropstatus, FALSE); DEFAULT(ctl->mimedecode, FALSE); + DEFAULT(ctl->idle, FALSE); DEFAULT(ctl->server.dns, TRUE); DEFAULT(ctl->server.uidl, FALSE); +#ifdef SSL_ENABLE + DEFAULT(ctl->use_ssl, FALSE); +#endif DEFAULT(ctl->server.checkalias, FALSE); #undef DEFAULT /* - * DNS support is required for some protocols. + * DNS support is required for some protocols. We used to + * do this unconditionally, but it made fetchmail excessively + * vulnerable to misconfigured DNS setups. * * If we're using ETRN, the smtp hunt list is the list of * systems we're polling on behalf of; these have to be @@ -986,7 +1058,7 @@ static int load_params(int argc, char **argv, int optind) if (ctl->localnames && ctl->localnames->next && ctl->server.dns) { ctl->server.dns = FALSE; - fprintf(stderr, _("fetchmail: warning: no DNS available to check multidrop fetches from %s\n"), ctl->server.pollname); + report(stderr, _("fetchmail: warning: no DNS available to check multidrop fetches from %s\n"), ctl->server.pollname); } #endif /* !HAVE_GETHOSTBYNAME || !HAVE_RES_SEARCH */ @@ -1025,8 +1097,9 @@ static int load_params(int argc, char **argv, int optind) free(ctl->server.via); ctl->server.via = xstrdup(hes_p->po_host); } else { - report(stderr, errno, _("couldn't find HESIOD pobox for %s"), - ctl->remotename); + report(stderr, + _("couldn't find HESIOD pobox for %s\n"), + ctl->remotename); } } #endif /* HESIOD */ @@ -1037,11 +1110,23 @@ static int load_params(int argc, char **argv, int optind) * to minimize DNS round trips. */ if (ctl->server.lead_server) - ctl->server.truename = xstrdup(ctl->server.lead_server->truename); + { + char *leadname = ctl->server.lead_server->truename; + + /* prevent core dump from ill-formed or duplicate entry */ + if (!leadname) + { + report(stderr, + _("Lead server has no name.\n")); + exit(PS_SYNTAX); + } + + ctl->server.truename = xstrdup(leadname); + } #ifdef HAVE_GETHOSTBYNAME - else if (ctl->server.preauthenticate==A_KERBEROS_V4 || + else if (!configdump && (ctl->server.preauthenticate==A_KERBEROS_V4 || ctl->server.preauthenticate==A_KERBEROS_V5 || - (ctl->server.dns && MULTIDROP(ctl))) + (ctl->server.dns && MULTIDROP(ctl)))) { struct hostent *namerec; @@ -1050,8 +1135,8 @@ static int load_params(int argc, char **argv, int optind) namerec = gethostbyname(ctl->server.queryname); if (namerec == (struct hostent *)NULL) { - report(stderr, errno, - _("couldn't find canonical DNS name of %s"), + report(stderr, + _("couldn't find canonical DNS name of %s\n"), ctl->server.pollname); exit(PS_DNS); } @@ -1059,8 +1144,40 @@ static int load_params(int argc, char **argv, int optind) ctl->server.truename=xstrdup((char *)namerec->h_name); } #endif /* HAVE_GETHOSTBYNAME */ - else - ctl->server.truename = xstrdup(ctl->server.queryname); + else { +#ifdef HAVE_GETHOSTBYNAME + struct hostent *namerec; + + /* + Get the host's IP, so we can report it like this: + + Received: from hostname [10.0.0.1] + + do we actually need to gethostbyname to find the IP? + it seems like it would be faster to do this later, when + we are actually resolving the hostname for a connection, + but I ain't that smart, so I don't know where to make + the change later.. + */ + errno = 0; + namerec = gethostbyname(ctl->server.queryname); + if (namerec == (struct hostent *)NULL) + { + report(stderr, + _("couldn't find canonical DNS name of %s\n"), + ctl->server.pollname); + exit(PS_DNS); + } + else { + ctl->server.truename=xstrdup((char *)namerec->h_name); + ctl->server.trueaddr=xmalloc(namerec->h_length); + memcpy(ctl->server.trueaddr, + namerec->h_addr_list[0], + namerec->h_length); + } +#endif /* HAVE_GETHOSTBYNAME */ + ctl->server.truename = xstrdup(ctl->server.queryname); + } /* if no folders were specified, set up the null one as default */ if (!ctl->mailboxes) @@ -1070,7 +1187,7 @@ static int load_params(int argc, char **argv, int optind) if (ctl->server.timeout == -1) ctl->server.timeout = CLIENT_TIMEOUT; -#if !INET6 +#if !INET6_ENABLE /* sanity checks */ if (ctl->server.port < 0) { @@ -1095,11 +1212,7 @@ static int load_params(int argc, char **argv, int optind) char *cp; if (!(cp = strrchr(idp->id, '/')) || -#ifdef INET6 - (strcmp(++cp, SMTP_PORT) == 0)) -#else (atoi(++cp) == SMTP_PORT)) -#endif /* INET6 */ { (void) fprintf(stderr, _("%s configuration invalid, LMTP can't use default SMTP port\n"), @@ -1108,28 +1221,21 @@ static int load_params(int argc, char **argv, int optind) } } } -#endif /* !INET6 */ +#endif /* !INET6_ENABLE */ + + /* + * "I beg to you, have mercy on the week minds like myself." + * wrote Pehr Anderson. Your petition is granted. + */ + if (ctl->fetchall && ctl->keep && run.poll_interval && !nodetach) + { + (void) fprintf(stderr, + _("Both fetchall and keep on in daemon mode is a mistake!\n")); + exit(PS_SYNTAX); + } } } - /* here's where we override globals */ - if (cmd_run.logfile) - run.logfile = cmd_run.logfile; - if (cmd_run.idfile) - run.idfile = cmd_run.idfile; - if (cmd_run.poll_interval >= 0) - run.poll_interval = cmd_run.poll_interval; - if (cmd_run.invisible) - run.invisible = cmd_run.invisible; - if (cmd_run.use_syslog) - run.use_syslog = (cmd_run.use_syslog == FLAG_TRUE); - if (cmd_run.postmaster) - run.postmaster = cmd_run.postmaster; - - /* check and daemon options are not compatible */ - if (check_only && run.poll_interval) - run.poll_interval = 0; - #ifdef POP3_ENABLE /* initialize UID handling */ if (!versioninfo && (st = prc_filecheck(run.idfile, !versioninfo)) != 0) @@ -1143,20 +1249,27 @@ static int load_params(int argc, char **argv, int optind) * multidrop mail, set an appropriate default here. */ if (!run.postmaster) + { if (getuid()) /* ordinary user */ run.postmaster = user; else /* root */ run.postmaster = "postmaster"; + } return(implicitmode); } -static void termhook(int sig) -/* to be executed on normal or signal-induced termination */ +static void terminate_poll(int sig) +/* to be executed at the end of a poll cycle */ { - struct query *ctl; - /* + * 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 @@ -1167,17 +1280,38 @@ static void termhook(int sig) */ if (sig != 0) - report(stdout, 0, _("terminated with signal %d"), sig); + report(stdout, _("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) + { SMTP_quit(ctl->smtp_socket); + SockClose(ctl->smtp_socket); + ctl->smtp_socket = -1; + } + } #ifdef POP3_ENABLE + /* + * Update UID information at end of each poll, rather than at end + * of run, because that way we don't lose all UIDL information since + * the beginning of time if fetchmail crashes. + */ if (!check_only) write_saved_lists(querylist, run.idfile); #endif /* POP3_ENABLE */ +} + +static void terminate_run(int sig) +/* to be executed on normal or signal-induced termination */ +{ + struct query *ctl; + + terminate_poll(sig); /* * Craig Metz, the RFC1938 one-time-password guy, points out: @@ -1222,14 +1356,17 @@ static int query_host(struct query *ctl) { int i, st; - if (outlevel >= O_VERBOSE) + /* + * If we're syslogging the progress messages are automatically timestamped. + * Force timestamping if we're going to a logfile. + */ + if (outlevel >= O_VERBOSE || (run.logfile && outlevel > O_SILENT)) { - time_t now; - - time(&now); - report(stdout, 0, _("%s querying %s (protocol %s) at %s"), - VERSION, - ctl->server.pollname, showproto(ctl->server.protocol), ctime(&now)); + report(stdout, _("%s querying %s (protocol %s) at %s\n"), + VERSION, + ctl->server.pollname, + showproto(ctl->server.protocol), + rfc822timestamp()); } switch (ctl->server.protocol) { case P_AUTO: @@ -1241,12 +1378,11 @@ static int query_host(struct query *ctl) } ctl->server.protocol = P_AUTO; return(st); - break; case P_POP2: #ifdef POP2_ENABLE return(doPOP2(ctl)); #else - report(stderr, 0, _("POP2 support is not configured.\n")); + report(stderr, _("POP2 support is not configured.\n")); return(PS_PROTOCOL); #endif /* POP2_ENABLE */ break; @@ -1256,36 +1392,37 @@ static int query_host(struct query *ctl) #ifdef POP3_ENABLE return(doPOP3(ctl)); #else - report(stderr, 0, _("POP3 support is not configured.\n")); + report(stderr, _("POP3 support is not configured.\n")); return(PS_PROTOCOL); #endif /* POP3_ENABLE */ break; case P_IMAP: case P_IMAP_K4: + case P_IMAP_CRAM_MD5: + case P_IMAP_LOGIN: #ifdef GSSAPI case P_IMAP_GSS: #endif /* GSSAPI */ #ifdef IMAP_ENABLE return(doIMAP(ctl)); #else - report(stderr, 0, _("IMAP support is not configured.\n")); + report(stderr, _("IMAP support is not configured.\n")); return(PS_PROTOCOL); #endif /* IMAP_ENABLE */ - break; case P_ETRN: #ifndef ETRN_ENABLE - report(stderr, 0, _("ETRN support is not configured.\n")); + report(stderr, _("ETRN support is not configured.\n")); return(PS_PROTOCOL); #else #ifdef HAVE_GETHOSTBYNAME return(doETRN(ctl)); #else - report(stderr, 0, _("Cannot support ETRN without gethostbyname(2).\n")); + report(stderr, _("Cannot support ETRN without gethostbyname(2).\n")); return(PS_PROTOCOL); #endif /* HAVE_GETHOSTBYNAME */ #endif /* ETRN_ENABLE */ default: - report(stderr, 0, _("unsupported protocol selected.")); + report(stderr, _("unsupported protocol selected.\n")); return(PS_PROTOCOL); } } @@ -1312,6 +1449,11 @@ static void dump_params (struct runctl *runp, printf(_("Fetchmail will forward misaddressed multidrop messages to %s.\n"), runp->postmaster); + if (!runp->bouncemail) + printf(_("Fetchmail will direct error mail to the postmaster.\n")); + else if (outlevel >= O_VERBOSE) + printf(_("Fetchmail will direct error mail to the sender.\n")); + for (ctl = querylist; ctl; ctl = ctl->next) { if (!ctl->active || (implicit && ctl->server.skip)) @@ -1335,40 +1477,49 @@ static void dump_params (struct runctl *runp, * Don't poll for password when there is one or when using the ETRN * or IMAP-GSS protocol */ - if (!ctl->password && (ctl->server.protocol != P_ETRN) + /* ETRN, IMAP_GSS, and IMAP_K4 do not need a password, so skip this */ + if ( (ctl->server.protocol != P_ETRN) #ifdef GSSAPI - && (ctl->server.protocol != P_IMAP_GSS) + && (ctl->server.protocol != P_IMAP_GSS) #endif /* GSSAPI */ - ) - printf(_(" Password will be prompted for.\n")); - else if (outlevel >= O_VERBOSE) - if (ctl->server.protocol == P_APOP) - printf(_(" APOP secret = \"%s\".\n"), visbuf(ctl->password)); - else if (ctl->server.protocol == P_RPOP) - printf(_(" RPOP id = \"%s\".\n"), visbuf(ctl->password)); - else - printf(_(" Password = \"%s\".\n"), visbuf(ctl->password)); + && (ctl->server.protocol != P_IMAP_K4) ) { + if (!ctl->password) + printf(_(" Password will be prompted for.\n")); + else if (outlevel >= O_VERBOSE) + { + if (ctl->server.protocol == P_APOP) + printf(_(" APOP secret = \"%s\".\n"), + visbuf(ctl->password)); + else if (ctl->server.protocol == P_RPOP) + printf(_(" RPOP id = \"%s\".\n"), + visbuf(ctl->password)); + else + printf(_(" Password = \"%s\".\n"), + visbuf(ctl->password)); + } + } + if (ctl->server.protocol == P_POP3 -#if INET6 - && !strcmp(ctl->server.service, KPOP_PORT) -#else /* INET6 */ +#if INET6_ENABLE + && ctl->server.service && !strcmp(ctl->server.service, KPOP_PORT) +#else /* INET6_ENABLE */ && ctl->server.port == KPOP_PORT -#endif /* INET6 */ +#endif /* INET6_ENABLE */ && (ctl->server.preauthenticate == A_KERBEROS_V4 || ctl->server.preauthenticate == A_KERBEROS_V5)) printf(_(" Protocol is KPOP with Kerberos %s authentication"), ctl->server.preauthenticate == A_KERBEROS_V5 ? "V" : "IV"); else printf(_(" Protocol is %s"), showproto(ctl->server.protocol)); -#if INET6 +#if INET6_ENABLE if (ctl->server.service) printf(_(" (using service %s)"), ctl->server.service); if (ctl->server.netsec) printf(_(" (using network security options %s)"), ctl->server.netsec); -#else /* INET6 */ +#else /* INET6_ENABLE */ if (ctl->server.port) printf(_(" (using port %d)"), ctl->server.port); -#endif /* INET6 */ +#endif /* INET6_ENABLE */ else if (outlevel >= O_VERBOSE) printf(_(" (using default port)")); if (ctl->server.uidl && (ctl->server.protocol != P_ETRN)) @@ -1377,8 +1528,14 @@ static void dump_params (struct runctl *runp, putchar('\n'); if (ctl->server.preauthenticate == A_KERBEROS_V4) printf(_(" Kerberos V4 preauthentication enabled.\n")); - if (ctl->server.preauthenticate == A_KERBEROS_V5) + else if (ctl->server.preauthenticate == A_KERBEROS_V5) printf(_(" Kerberos V5 preauthentication enabled.\n")); + else if (ctl->server.preauthenticate == A_SSH) + printf(_(" End-to-end encryption assumed.\n")); +#ifdef SSL_ENABLE + if (ctl->use_ssl) + printf(" SSL encrypted sessions enabled.\n"); +#endif if (ctl->server.timeout > 0) printf(_(" Server nonresponse timeout is %d seconds"), ctl->server.timeout); if (ctl->server.timeout == CLIENT_TIMEOUT) @@ -1422,6 +1579,9 @@ static void dump_params (struct runctl *runp, printf(_(" MIME decoding is %s (mimedecode %s).\n"), ctl->mimedecode ? _("enabled") : _("disabled"), ctl->mimedecode ? "on" : "off"); + printf(_(" Idle after poll is %s (idle %s).\n"), + ctl->idle ? _("enabled") : _("disabled"), + ctl->idle ? "on" : "off"); printf(_(" Nonempty Status lines will be %s (dropstatus %s)\n"), ctl->dropstatus ? _("discarded") : _("kept"), ctl->dropstatus ? "on" : "off"); @@ -1448,10 +1608,12 @@ static void dump_params (struct runctl *runp, else if (outlevel >= O_VERBOSE) printf(_(" No SMTP message batch limit (--batchlimit 0).\n")); if (ctl->server.protocol == P_IMAP) + { if (NUM_NONZERO(ctl->expunge)) - printf(_(" Deletion interval between expunges is %d (--expunge %d).\n"), ctl->expunge, ctl->expunge); + printf(_(" Deletion interval between expunges forced to %d (--expunge %d).\n"), ctl->expunge, ctl->expunge); else if (outlevel >= O_VERBOSE) - printf(_(" No expunges (--expunge 0).\n")); + printf(_(" No forced expunges (--expunge 0).\n")); + } } if (ctl->bsmtp) printf(_(" Messages will be appended to %s as BSMTP\n"), visbuf(ctl->bsmtp)); @@ -1574,7 +1736,7 @@ static void dump_params (struct runctl *runp, } } } -#ifdef linux +#if defined(linux) || defined(__FreeBSD__) if (ctl->server.interface) printf(_(" Connection must be through interface %s.\n"), ctl->server.interface); else if (outlevel >= O_VERBOSE) @@ -1586,15 +1748,16 @@ static void dump_params (struct runctl *runp, #endif if (ctl->server.plugin) - printf(_(" Server connections will be mode via plugin %s (--plugin %s).\n"), ctl->server.plugin, ctl->server.plugin); + printf(_(" Server connections will be made via plugin %s (--plugin %s).\n"), ctl->server.plugin, ctl->server.plugin); else if (outlevel >= O_VERBOSE) printf(_(" No plugin command specified.\n")); if (ctl->server.plugout) - printf(_(" Listener connections will be mode via plugout %s (--plugout %s).\n"), ctl->server.plugout, ctl->server.plugout); + printf(_(" Listener connections will be made via plugout %s (--plugout %s).\n"), ctl->server.plugout, ctl->server.plugout); else if (outlevel >= O_VERBOSE) printf(_(" No plugout command specified.\n")); if (ctl->server.protocol > P_POP2 && (ctl->server.protocol != P_ETRN)) + { if (!ctl->oldsaved) printf(_(" No UIDs saved from this host.\n")); else @@ -1610,6 +1773,7 @@ static void dump_params (struct runctl *runp, for (idp = ctl->oldsaved; idp; idp = idp->next) printf("\t%s\n", idp->id); } + } if (ctl->properties) printf(_(" Pass-through properties \"%s\".\n"),