]> Pileus Git - ~andy/fetchmail/blobdiff - fetchmail.c
NTLM support integrated.
[~andy/fetchmail] / fetchmail.c
index 5636e803b08b164a079c5c750afb1a2f00cae35a..ceccfacf1b604c0a8078c90e268317268d36a2d6 100644 (file)
 #if defined(HAVE_UNISTD_H)
 #include <unistd.h>
 #endif
+#include <fcntl.h>
 #include <string.h>
 #include <signal.h>
+#include <getopt.h>
 #if defined(HAVE_SYSLOG)
 #include <syslog.h>
 #endif
 #include <pwd.h>
+#ifdef __FreeBSD__
+#include <grp.h>
+#endif
 #include <errno.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -28,7 +33,7 @@
 #endif /* HAVE_SETRLIMIT */
 #ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>
-#endif
+#endif /* HAVE_SYS_WAIT_H */
 
 #ifdef HAVE_GETHOSTBYNAME
 #include <netdb.h>
@@ -41,7 +46,6 @@
 #include "fetchmail.h"
 #include "tunable.h"
 #include "smtp.h"
-#include "getopt.h"
 #include "netrc.h"
 #include "i18n.h"
 
@@ -68,6 +72,7 @@ char *home;               /* invoking user'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 */
+volatile int lastsig;          /* last signal received */
 
 #if NET_SECURITY
 void *request = NULL;
@@ -77,7 +82,6 @@ int requestlen = 0;
 static char *lockfile;         /* name of lockfile */
 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 void termhook(int);             /* forward declaration of exit hook */
@@ -137,7 +141,28 @@ void itimerthread(void* dummy) {
 }
 #endif
 
-int main (int argc, char **argv)
+#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 st, bkgd = FALSE;
     int parsestatus, implicitmode = FALSE;
@@ -147,6 +172,10 @@ int main (int argc, char **argv)
     char *netrc_file, *tmpbuf;
     pid_t pid;
 
+#ifdef __FreeBSD__
+    dropprivs();
+#endif
+
     envquery(argc, argv);
 #ifdef ENABLE_NLS
     bindtextdomain(PACKAGE, LOCALEDIR);
@@ -182,6 +211,9 @@ 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 */
@@ -229,6 +261,67 @@ int main (int argc, char **argv)
     }
 #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) + strlen(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 ||
+#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)
     {
@@ -360,79 +453,25 @@ 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 ||
-#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);
-               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);
-               }
-           }
-
-           if (ctl->server.protocol != P_ETRN && ctl->server.protocol != P_IMAP_K4
+       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->password)
-           {
-               char* password_prompt = _("Enter password for %s@%s: ");
-
-               xalloca(tmpbuf, char *, strlen(password_prompt) +
-                                       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)
+       {
+           char* password_prompt = _("Enter password for %s@%s: ");
+
+           xalloca(tmpbuf, char *, strlen(password_prompt) +
+                   strlen(ctl->remotename) +
+                   strlen(ctl->server.pollname) + 1);
+           (void) sprintf(tmpbuf, password_prompt,
+                          ctl->remotename, ctl->server.pollname);
+           ctl->password = xstrdup((char *)getpassword(tmpbuf));
        }
     }
 
@@ -454,17 +493,17 @@ int main (int argc, char **argv)
     if (run.use_syslog)
     {
        openlog(program_name, LOG_PID, LOG_MAIL);
-       error_init(-1);
+       report_init(-1);
     }
     else
 #endif
-       error_init((run.poll_interval == 0 || nodetach) && !run.logfile);
+       report_init((run.poll_interval == 0 || nodetach) && !run.logfile);
 
     if (run.poll_interval)
     {
        if (!nodetach)
            daemonize(run.logfile, termhook);
-       progress( 0, 0, _("starting fetchmail %s daemon "), VERSION);
+       report(stdout, _("starting fetchmail %s daemon \n"), VERSION);
 
        /*
         * We'll set up a handler for these when we're sleeping,
@@ -475,6 +514,10 @@ int main (int argc, char **argv)
            signal(SIGHUP, SIG_IGN);
     }
 
+#ifdef linux
+    interface_init();
+#endif /* linux */
+
     /* beyond here we don't want more than one fetchmail running per user */
     umask(0077);
     signal(SIGABRT, termhook);
@@ -485,11 +528,15 @@ int main (int argc, char **argv)
     signal(SIGQUIT, termhook);
 
     /* here's the exclusion lock */
-    if ((lockfp = fopen(lockfile,"w")) != NULL) {
-       fprintf(lockfp,"%d",getpid());
+    if ((st = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0666)) != -1) {
+       sprintf(tmpbuf,"%d", getpid());
+       write(st, tmpbuf, strlen(tmpbuf));
        if (run.poll_interval)
-           fprintf(lockfp," %d", run.poll_interval);
-       fclose(lockfp);
+       {
+           sprintf(tmpbuf," %d", run.poll_interval);
+           write(st, tmpbuf, strlen(tmpbuf));
+       }
+       close(st);
 
 #ifdef HAVE_ATEXIT
        atexit(unlockit);
@@ -525,8 +572,8 @@ int main (int argc, char **argv)
            {
                if (ctl->wedged)
                {
-                   error(0, -1
-                         _("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,18 +584,18 @@ int main (int argc, char **argv)
                    if (ctl->server.poll_count++ % ctl->server.interval) 
                    {
                        if (outlevel >= O_VERBOSE)
-                           progress(0, -1,
-                                   _("interval not reached, not querying %s"),
+                           report(stdout,
+                                   _("interval not reached, not querying %s\n"),
                                    ctl->server.pollname);
                        continue;
                    }
                }
 
-#if defined(linux) && !INET6
+#if (defined(linux) && !INET6) || defined(__FreeBSD__)
                /* interface_approve() does its own error logging */
                if (!interface_approve(&ctl->server))
                    continue;
-#endif /* defined(linux) && !INET6 */
+#endif /* (defined(linux) && !INET6) || defined(__FreeBSD__) */
 
                querystatus = query_host(ctl);
 
@@ -565,15 +612,15 @@ int main (int argc, char **argv)
                    {
                        write_saved_lists(querylist, run.idfile);
                        if (outlevel >= O_DEBUG)
-                           progress(0, 0, _("saved UID List"));
+                           report(stdout, _("saved UID List\n"));
                    }
 #endif  /* POP3_ENABLE */
                }
                else if (!check_only && 
                         ((querystatus!=PS_NOMAIL) || (outlevel==O_DEBUG)))
-                   progress(0, 0, _("Query status=%d"), querystatus);
+                   report(stdout, _("Query status=%d\n"), querystatus);
 
-#if defined(linux) && !INET6
+#if (defined(linux) && !INET6) || defined (__FreeBSD__)
                if (ctl->server.monitor)
                {
                    /*
@@ -584,7 +631,7 @@ int main (int argc, char **argv)
                    sleep(3);
                    interface_note_activity(&ctl->server);
                }
-#endif /* defined(linux) && !INET6 */
+#endif /* (defined(linux) && !INET6) || defined(__FreeBSD__) */
            }
        }
 
@@ -628,12 +675,13 @@ int main (int argc, char **argv)
                        unwedged++;
            if (!unwedged)
            {
-               error(0, -1, _("All connections are wedged.  Exiting."));
+               report(stderr, _("All connections are wedged.  Exiting.\n"));
                exit(PS_AUTHFAIL);
            }
 
            if (outlevel >= O_VERBOSE)
-               progress(0, -1, _("fetchmail: sleeping at %s"), rfc822timestamp());
+               report(stdout, 
+                      _("fetchmail: sleeping at %s\n"), rfc822timestamp());
 
            /*
             * With this simple hack, we make it possible for a foreground 
@@ -712,8 +760,10 @@ int main (int argc, char **argv)
 
                 timeout.tv_sec = run.poll_interval;
                 timeout.tv_usec = 0;
-               lastsig = 0;
-                select(0,0,0,0, &timeout);
+                do {
+                    lastsig = 0;
+                    select(0,0,0,0, &timeout);
+                } while (lastsig == SIGCHLD);
 #endif
 #else /* EMX */
                alarm_latch = FALSE;
@@ -728,9 +778,11 @@ int main (int argc, char **argv)
                        || ((run.poll_interval && !getuid()) && lastsig == SIGHUP))
                {
 #ifdef SYS_SIGLIST_DECLARED
-                   progress(0, 0, _("awakened by %s"), sys_siglist[lastsig]);
+                   report(stdout, 
+                          _("awakened by %s\n"), sys_siglist[lastsig]);
 #else
-                   progress(0, 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          */
@@ -745,13 +797,13 @@ int main (int argc, char **argv)
                signal(SIGHUP, SIG_IGN);
 
            if (outlevel >= O_VERBOSE)
-               progress(0, -1, _("awakened at %s"), rfc822timestamp());
+               report(stdout, _("awakened at %s\n"), rfc822timestamp());
        }
     } while
        (run.poll_interval);
 
     if (outlevel >= O_VERBOSE)
-       progress(0, -1, _("normal termination, status %d"),
+       report(stdout, _("normal termination, status %d\n"),
                successes ? PS_SUCCESS : querystatus);
 
     termhook(0);
@@ -796,11 +848,11 @@ 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);
@@ -839,18 +891,22 @@ static int load_params(int argc, char **argv, int optind)
     struct passwd *pw;
     struct query def_opts, *ctl;
 
+    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;
 
     /* this builds the host list */
@@ -944,7 +1000,7 @@ static int load_params(int argc, char **argv, int optind)
            DEFAULT(ctl->forcecr, FALSE);
            DEFAULT(ctl->pass8bits, FALSE);
            DEFAULT(ctl->dropstatus, FALSE);
-           DEFAULT(ctl->mimedecode, FALSE);
+           DEFAULT(ctl->mimedecode, TRUE);
            DEFAULT(ctl->server.dns, TRUE);
            DEFAULT(ctl->server.uidl, FALSE);
            DEFAULT(ctl->server.checkalias, FALSE);
@@ -1025,8 +1081,9 @@ static int load_params(int argc, char **argv, int optind)
                      free(ctl->server.via);
                  ctl->server.via = xstrdup(hes_p->po_host);
             } else {
-                 error(0, errno, _("couldn't find HESIOD pobox for %s"),
-                     ctl->remotename);
+                 report(stderr,
+                       _("couldn't find HESIOD pobox for %s\n"),
+                       ctl->remotename);
             }
         }
 #endif /* HESIOD */
@@ -1050,8 +1107,8 @@ static int load_params(int argc, char **argv, int optind)
                namerec = gethostbyname(ctl->server.queryname);
                if (namerec == (struct hostent *)NULL)
                {
-                   error(0, 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);
                }
@@ -1125,6 +1182,8 @@ static int load_params(int argc, char **argv, int optind)
        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)
@@ -1167,7 +1226,7 @@ static void termhook(int sig)
      */
 
     if (sig != 0)
-        progress(0, 0, _("terminated with signal %d"), sig);
+        report(stdout, _("terminated with signal %d\n"), sig);
     else
        /* terminate all SMTP connections cleanly */
        for (ctl = querylist; ctl; ctl = ctl->next)
@@ -1222,14 +1281,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);
-       progress(0, -1, _("%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 +1303,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
-       error(0, -1, _("POP2 support is not configured.\n"));
+       report(stderr, _("POP2 support is not configured.\n"));
        return(PS_PROTOCOL);
 #endif /* POP2_ENABLE */
        break;
@@ -1256,7 +1317,7 @@ static int query_host(struct query *ctl)
 #ifdef POP3_ENABLE
        return(doPOP3(ctl));
 #else
-       error(0, -1, _("POP3 support is not configured.\n"));
+       report(stderr, _("POP3 support is not configured.\n"));
        return(PS_PROTOCOL);
 #endif /* POP3_ENABLE */
        break;
@@ -1268,24 +1329,23 @@ static int query_host(struct query *ctl)
 #ifdef IMAP_ENABLE
        return(doIMAP(ctl));
 #else
-       error(0, -1, _("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
-       error(0, -1, _("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
-       error(0, -1, _("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:
-       error(0, 0, _("unsupported protocol selected."));
+       report(stderr, _("unsupported protocol selected.\n"));
        return(PS_PROTOCOL);
     }
 }
@@ -1312,6 +1372,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,19 +1400,26 @@ 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)
@@ -1449,9 +1521,9 @@ static void dump_params (struct runctl *runp,
                    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 +1646,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)