]> Pileus Git - ~andy/fetchmail/blobdiff - fetchmail.c
Clarify IMAP BYE response logging.
[~andy/fetchmail] / fetchmail.c
index 9ee0d62734e9f9a383338aa5d791c874df252bc6..37abf44baf93e0f03733f9acc79e260e078f2bc0 100644 (file)
 #include "smtp.h"
 #include "netrc.h"
 #include "i18n.h"
+#include "lock.h"
+
+/* need these (and sys/types.h) for res_init() */
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
 
 #ifndef ENETUNREACH
 #define ENETUNREACH   128       /* Interactive doesn't know this */
@@ -127,6 +133,17 @@ static RETSIGTYPE donothing(int sig)
     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, Robert M. Funk, Graham Wilson\n"
+                  "Copyright (C) 2005 - 2006 Sunil Shetye\n"
+                  "Copyright (C) 2005 - 2009 Matthias Andree\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"));
+}
+
 const char *iana_charset;
 
 int main(int argc, char **argv)
@@ -187,7 +204,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 */
@@ -221,7 +238,7 @@ int main(int argc, char **argv)
        "-IMAP"
 #endif /* IMAP_ENABLE */
 #ifdef GSSAPI
-       "+IMAP-GSS"
+       "+GSS"
 #endif /* GSSAPI */
 #ifdef RPA_ENABLE
        "+RPA"
@@ -253,9 +270,21 @@ int main(int argc, char **argv)
 #ifdef ENABLE_NLS
        "+NLS"
 #endif /* ENABLE_NLS */
-       "\n";
+#ifdef KERBEROS_V4
+       "+KRB4"
+#endif /* KERBEROS_V4 */
+#ifdef KERBEROS_V5
+       "+KRB5"
+#endif /* KERBEROS_V5 */
+#ifndef HAVE_RES_SEARCH
+       "-DNS"
+#endif
+       ".\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);
@@ -266,13 +295,18 @@ int main(int argc, char **argv)
        fflush(stdout);
 
        /* this is an attempt to help remote debugging */
-       system("uname -a");
+       if (system("uname -a")) { /* NOOP to quench GCC complaint */ }
     }
 
     /* avoid parsing the config file if all we're doing is killing a daemon */
     if (!quitonly)
        implicitmode = load_params(argc, argv, optind);
 
+    /* precedence: logfile (if effective) overrides syslog. */
+    if (run.logfile && run.poll_interval && !nodetach) {
+       run.use_syslog = 0;
+    }
+
 #if defined(HAVE_SYSLOG)
     /* logging should be set up early in case we were restarted from exec */
     if (run.use_syslog)
@@ -289,8 +323,20 @@ int main(int argc, char **argv)
 #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
     /*
@@ -346,6 +392,9 @@ int main(int argc, char **argv)
        }
     }
 
+    free_netrc(netrc_list);
+    netrc_list = 0;
+
     /* perhaps we just want to check options? */
     if (versioninfo)
     {
@@ -372,7 +421,7 @@ 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;
 
@@ -447,7 +496,7 @@ int main(int argc, char **argv)
        }
        else if (getpid() == pid)
            /* this test enables re-execing on a changed rcfile */
-           lock_assert();
+           fm_lock_assert();
        else if (argc > 1)
        {
            fprintf(stderr,
@@ -491,7 +540,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));
@@ -512,13 +561,28 @@ 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);
+       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);
 
        /*
@@ -531,12 +595,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);
            if (!freopen(run.logfile, "a", stderr))
                    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"));
        }
     }
 
@@ -548,11 +615,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
@@ -568,8 +639,9 @@ int main(int argc, char **argv)
         */
        struct stat     rcstat;
 
-       if (stat(rcfile, &rcstat) == -1)
-       {
+       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"),
@@ -612,19 +684,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;
@@ -734,10 +808,6 @@ 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 */
-
        /* close connections cleanly */
        terminate_poll(0);
 
@@ -766,9 +836,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 
@@ -778,7 +849,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);
 
            /*
@@ -801,11 +872,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"),
@@ -909,6 +980,7 @@ static void optmerge(struct query *h2, struct query *h1, int force)
     FLAG_MERGE(sslproto);
     FLAG_MERGE(sslcertck);
     FLAG_MERGE(sslcertpath);
+    FLAG_MERGE(sslcommonname);
     FLAG_MERGE(sslfingerprint);
 #endif
     FLAG_MERGE(expunge);
@@ -929,6 +1001,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));
@@ -942,12 +1015,12 @@ static int load_params(int argc, char **argv, int optind)
     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 '/' */
@@ -957,7 +1030,7 @@ 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)
+    if (strcmp(rcfile, "-") == 0 || stat(rcfile, &rcstat) != -1)
        parsetime = rcstat.st_mtime;
     else if (errno != ENOENT)
        report(stderr, GT_("couldn't time-check the run-control file\n"));
@@ -992,7 +1065,7 @@ 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;
@@ -1039,6 +1112,8 @@ 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;
@@ -1052,6 +1127,8 @@ static int load_params(int argc, char **argv, int optind)
        run.postmaster = cmd_run.postmaster;
     if (cmd_run.bouncemail)
        run.bouncemail = cmd_run.bouncemail;
+    if (cmd_run.softbounce)
+       run.softbounce = cmd_run.softbounce;
 
     /* check and daemon options are not compatible */
     if (check_only && run.poll_interval)
@@ -1090,8 +1167,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)
@@ -1151,6 +1226,24 @@ static int load_params(int argc, char **argv, int optind)
            }
 #endif /* SSL_ENABLE */
 #undef DEFAULT
+#ifndef KERBEROS_V4
+           if (ctl->server.authenticate == A_KERBEROS_V4) {
+               report(stderr, GT_("KERBEROS v4 support is configured, but not compiled in.\n"));
+               exit(PS_SYNTAX);
+           }
+#endif
+#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.
@@ -1226,9 +1319,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"),
@@ -1242,23 +1335,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.
@@ -1343,7 +1427,8 @@ static const int autoprobe[] =
 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.
@@ -1468,6 +1553,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 messsages).\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))
@@ -1568,6 +1658,8 @@ static void dump_params (struct runctl *runp,
            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
@@ -1588,7 +1680,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
@@ -1678,7 +1770,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)"));
            }
@@ -1698,7 +1790,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)"));
                }
@@ -1756,9 +1848,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);
                    }
@@ -1797,7 +1889,7 @@ static void dump_params (struct runctl *runp,
 
                            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)
@@ -1806,7 +1898,7 @@ static void dump_params (struct runctl *runp,
 
                            printf(GT_("  Local domains:"));
                            for (idp = ctl->server.localdomains; idp; idp = idp->next)
-                               printf(" %s", (char *)idp->id);
+                               printf(" %s", idp->id);
                            putchar('\n');
                        }
                    }
@@ -1847,7 +1939,7 @@ static void dump_params (struct runctl *runp,
                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);
+                       printf("\t%s\n", idp->id);
            }
        }