]> Pileus Git - ~andy/fetchmail/blobdiff - fetchmail.c
Deal with Post Office/NT.
[~andy/fetchmail] / fetchmail.c
index dfd0c30098f1c800e458986b9570fd97d2bb8f04..54dc45c66640782b019071ace28b48cf27b5e5d6 100644 (file)
 #include <netdb.h>
 #endif /* HAVE_GETHOSTBYNAME */
 
-#ifdef SUNOS
-#include <stdlib.h>
-#endif
-
 #include "fetchmail.h"
 #include "tunable.h"
 #include "smtp.h"
 
 #define DROPDEAD       6       /* maximum bad socket opens */
 
+#ifndef ENETUNREACH
+#define ENETUNREACH   128       /* Interactive doesn't know this */
+#endif /* ENETUNREACH */
+
 /* prototypes for internal functions */
 static int load_params(int, char **, int);
 static void dump_params (struct query *);
@@ -64,6 +64,7 @@ int cmd_daemon;       /* if --daemon was set */
 char *idfile;          /* UID list file */
 flag versioninfo;      /* emit only version info */
 char *user;            /* the name of the invoking user */
+char *home;
 char *fetchmailhost;   /* the name of the host running fetchmail */
 char *program_name;    /* the name to prefix error messages with */
 
@@ -76,10 +77,10 @@ static void termhook();             /* forward declaration of exit hook */
 
 RETSIGTYPE donothing(sig) int sig; {signal(sig, donothing); lastsig = sig;}
 
-#ifdef HAVE_ATEXIT
-static void unlockit(void)
-#else  /* use on_exit(), e.g. on SunOS */
+#ifdef HAVE_ON_EXIT
 static void unlockit(int n, void *p)
+#else
+static void unlockit(void)
 #endif
 /* must-do actions for exit (but we can't count on being able to do malloc) */
 {
@@ -90,7 +91,6 @@ int main (int argc, char **argv)
 {
     int st, bkgd = FALSE;
     int parsestatus, implicitmode = FALSE;
-    struct passwd *pw;
     struct query *ctl;
     FILE       *lockfp;
     netrc_entry *netrc_list;
@@ -114,15 +114,20 @@ int main (int argc, char **argv)
     setvbuf(stdout, NULL, _IOLBF, POPBUFSIZE);
 
     if (versioninfo)
+    {
        printf("This is fetchmail release %s\n", RELEASE_ID);
 
+       /* this is an attempt to help remote debugging */
+       system("uname -a");
+    }
+
     /* avoid parsing the config file if all we're doing is killing a daemon */ 
     if (!quitmode)
        implicitmode = load_params(argc, argv, optind);
 
     /* set up to do lock protocol */
     if (!getuid())
-       strcpy(tmpbuf, "/var/run/fetchmail.pid");
+       sprintf(tmpbuf, "%s/fetchmail.pid", PID_DIR);
     else {
        strcpy(tmpbuf, home);
        strcat(tmpbuf, "/.fetchmail");
@@ -269,7 +274,7 @@ int main (int argc, char **argv)
            else
            {
                /* look up the host and account in the .netrc file. */
-               netrc_entry *p = search_netrc(netrc_list,ctl->server.names->id);
+               netrc_entry *p = search_netrc(netrc_list,ctl->server.pollname);
                while (p && strcmp(p->account, ctl->remotename))
                    p = search_netrc(p->next, ctl->remotename);
 
@@ -281,7 +286,7 @@ int main (int argc, char **argv)
            if (ctl->server.protocol != P_ETRN && ctl->server.protocol != P_IMAP_K4 && !ctl->password)
            {
                (void) sprintf(tmpbuf, "Enter password for %s@%s: ",
-                              ctl->remotename, ctl->server.names->id);
+                              ctl->remotename, ctl->server.pollname);
                ctl->password = xstrdup((char *)getpassword(tmpbuf));
            }
        }
@@ -331,7 +336,8 @@ int main (int argc, char **argv)
 
 #ifdef HAVE_ATEXIT
        atexit(unlockit);
-#else
+#endif
+#ifdef HAVE_ON_EXIT
        on_exit(unlockit, (char *)NULL);
 #endif
     }
@@ -350,6 +356,19 @@ int main (int argc, char **argv)
        {
            if (ctl->active && !(implicitmode && ctl->server.skip))
            {
+               /* check skip interval first so that it counts all polls */
+               if (poll_interval && ctl->server.interval) 
+               {
+                   if (ctl->server.poll_count++ % ctl->server.interval) 
+                   {
+                       if (outlevel == O_VERBOSE)
+                           fprintf(stderr,
+                                   "fetchmail: interval not reached, not querying %s\n",
+                                   ctl->server.pollname);
+                       continue;
+                   }
+               }
+
 #ifdef linux
                /* interface_approve() does its own error logging */
                if (!interface_approve(&ctl->server))
@@ -358,9 +377,9 @@ int main (int argc, char **argv)
 
 #ifdef HAVE_GETHOSTBYNAME
                /*
-                * This functions partly as an optimization and partly
-                * as a probe to make sure our nameserver is still up.
-                * The multidrop case (especially) needs it.
+                * This functions partly as a probe to make sure our
+                * nameserver is still up.  The multidrop case
+                * (especially) needs it.
                 */
                if (ctl->server.preauthenticate==A_KERBEROS_V4 || MULTIDROP(ctl))
                {
@@ -368,12 +387,12 @@ int main (int argc, char **argv)
 
                    /* compute the canonical name of the host */
                    errno = 0;
-                   namerec = gethostbyname(ctl->server.names->id);
+                   namerec = gethostbyname(ctl->server.queryname);
                    if (namerec == (struct hostent *)NULL)
                    {
                        error(0, errno,
                                "skipping %s poll, ",
-                               ctl->server.names->id);
+                               ctl->server.pollname);
                        if (errno)
                        {
                            if (errno == ENETUNREACH)
@@ -387,19 +406,19 @@ int main (int argc, char **argv)
                    }
                    else
                    {
-                       free(ctl->server.canonical_name);
-                       ctl->server.canonical_name = xstrdup((char *)namerec->h_name);
+                       free(ctl->server.truename);
+                       ctl->server.truename=xstrdup((char *)namerec->h_name);
                    }
                }
 #endif /* HAVE_GETHOSTBYNAME */
 
                querystatus = query_host(ctl);
 
-               if (querystatus == PS_SUCCESS)
+               if (querystatus == PS_SUCCESS) {
                    successes++;
-
-               if (!check_only)
-                   update_str_lists(ctl);
+                   if (!check_only)
+                     update_str_lists(ctl);
+               }
 #ifdef linux
                if (ctl->server.monitor)
                    {
@@ -498,7 +517,7 @@ static int load_params(int argc, char **argv, int optind)
 {
     int        implicitmode, st;
     struct passwd *pw;
-    struct query def_opts, *ctl, *mp;
+    struct query def_opts, *ctl;
 
     memset(&def_opts, '\0', sizeof(struct query));
     def_opts.smtp_socket = -1;
@@ -506,7 +525,8 @@ static int load_params(int argc, char **argv, int optind)
     def_opts.server.protocol = P_AUTO;
     def_opts.server.timeout = CLIENT_TIMEOUT;
     def_opts.remotename = user;
-    save_str(&def_opts.smtphunt, -1, fetchmailhost);
+    save_str(&def_opts.smtphunt, TRUE, fetchmailhost);
+    save_str(&def_opts.smtphunt, FALSE, "localhost");
 
     /* this builds the host list */
     if (prc_parse_file(rcfile, !versioninfo) != 0)
@@ -526,18 +546,19 @@ static int load_params(int argc, char **argv, int optind)
             * record from command line and defaults
             */
            for (ctl = querylist; ctl; ctl = ctl->next)
-               if (str_in_list(&ctl->server.names, argv[optind]))
+               if (!strcmp(ctl->server.pollname, argv[optind])
+                       || str_in_list(&ctl->server.akalist, argv[optind]))
                    goto foundit;
 
            ctl = hostalloc(&cmd_opts);
-           save_str(&ctl->server.names, -1, argv[optind]);
+           ctl->server.pollname = xstrdup(argv[optind]);
 
        foundit:
            ctl->active = TRUE;
        }
 
     /* if there's a defaults record, merge it and lose it */ 
-    if (querylist && strcmp(querylist->server.names->id, "defaults") == 0)
+    if (querylist && strcmp(querylist->server.pollname, "defaults") == 0)
     {
        for (ctl = querylist->next; ctl; ctl = ctl->next)
            optmerge(ctl, querylist);
@@ -546,7 +567,7 @@ static int load_params(int argc, char **argv, int optind)
 
     /* don't allow a defaults record after the first */
     for (ctl = querylist; ctl; ctl = ctl->next)
-       if (ctl != querylist && strcmp(ctl->server.names->id, "defaults") == 0)
+       if (ctl != querylist && strcmp(ctl->server.pollname, "defaults") == 0)
            exit(PS_SYNTAX);
 
     /* merge in wired defaults, do sanity checks and prepare internal fields */
@@ -602,13 +623,36 @@ static int load_params(int argc, char **argv, int optind)
            DEFAULT(ctl->stripcr, (ctl->mda != (char *)NULL)); 
            DEFAULT(ctl->forcecr, FALSE);
            DEFAULT(ctl->pass8bits, FALSE);
+           DEFAULT(ctl->dropstatus, FALSE);
            DEFAULT(ctl->server.dns, TRUE);
            DEFAULT(ctl->server.uidl, FALSE);
 #undef DEFAULT
 
-           /* plug in the semi-standard way of indicating a mail address */
-           if (ctl->server.envelope == (char *)NULL)
-               ctl->server.envelope = "X-Envelope-To:";
+           /*
+            *
+            * Compute the true name of the mailserver host.  
+            * There are two clashing cases here:
+            *
+            * (1) The poll name is a label, possibly on one of several
+            *     poll configurations for the same host.  In this case 
+            *     the `via' option will be present and give the true name.
+            *
+            * (2) The poll name is the true one, the via name is 
+            *     localhost.   This is going to be typical for ssh-using
+            *     configurations.
+            *
+            * We're going to assume the via name is true unless it's
+            * localhost.
+            *
+            * Each poll cycle, if we've got DNS, we'll try to canonicalize
+            * the name.  This will function as a probe to ensure the
+            * host's nameserver is up.
+            */
+           if (ctl->server.via && strcmp(ctl->server.via, "localhost"))
+               ctl->server.queryname = xstrdup(ctl->server.via);
+           else
+               ctl->server.queryname = xstrdup(ctl->server.pollname);
+           ctl->server.truename = xstrdup(ctl->server.queryname);
 
            /* if no folders were specified, set up the null one as default */
            if (!ctl->mailboxes)
@@ -623,14 +667,14 @@ static int load_params(int argc, char **argv, int optind)
            {
                (void) fprintf(stderr,
                               "%s configuration invalid, port number cannot be negative",
-                              ctl->server.names->id);
+                              ctl->server.pollname);
                exit(PS_SYNTAX);
            }
            if (ctl->server.protocol == P_RPOP && ctl->server.port >= 1024)
            {
                (void) fprintf(stderr,
                               "%s configuration invalid, RPOP requires a privileged port",
-                              ctl->server.names->id);
+                              ctl->server.pollname);
                exit(PS_SYNTAX);
            }
        }
@@ -662,21 +706,6 @@ void termhook(int sig)
 {
     struct query       *ctl;
 
-    /* 
-     * Craig Metz, the RFC1938 one-time-password guy, points out:
-     * "Remember that most kernels don't zero pages before handing them to the
-     * next process and many kernels share pages between user and kernel space.
-     * You'd be very surprised what you can find from a short program to do a
-     * malloc() and then dump the contents of the pages you got. By zeroing
-     * the secrets at end of run (earlier if you can), you make sure the next
-     * guy can't get the password/pass phrase."
-     *
-     * Right you are, Craig!
-     */
-    for (ctl = querylist; ctl; ctl = ctl->next)
-       if (ctl->password)
-           memset(ctl->password, '\0', strlen(ctl->password));
-
     /*
      * Sending SMTP QUIT on signal is theoretically nice, but led to a 
      * subtle bug.  If fetchmail was terminated by signal while it was 
@@ -698,6 +727,25 @@ void termhook(int sig)
     if (!check_only)
        write_saved_lists(querylist, idfile);
 
+    /* 
+     * Craig Metz, the RFC1938 one-time-password guy, points out:
+     * "Remember that most kernels don't zero pages before handing them to the
+     * next process and many kernels share pages between user and kernel space.
+     * You'd be very surprised what you can find from a short program to do a
+     * malloc() and then dump the contents of the pages you got. By zeroing
+     * the secrets at end of run (earlier if you can), you make sure the next
+     * guy can't get the password/pass phrase."
+     *
+     * Right you are, Craig!
+     */
+    for (ctl = querylist; ctl; ctl = ctl->next)
+       if (ctl->password)
+         memset(ctl->password, '\0', strlen(ctl->password));
+
+#if !defined(HAVE_ATEXIT) && !defined(HAVE_ON_EXIT)
+    unlockit();
+#endif
+
     exit(successes ? PS_SUCCESS : querystatus);
 }
 
@@ -715,18 +763,6 @@ static int query_host(struct query *ctl)
 {
     int i, st;
 
-    if (poll_interval && ctl->server.interval) 
-    {
-       if (ctl->server.poll_count++ % ctl->server.interval) 
-       {
-           if (outlevel == O_VERBOSE)
-               fprintf(stderr,
-                   "fetchmail: interval not reached, not querying %s\n",
-                   ctl->server.names->id);
-           return PS_NOMAIL;
-       }
-    }
-
     if (outlevel == O_VERBOSE)
     {
        time_t now;
@@ -734,14 +770,14 @@ static int query_host(struct query *ctl)
        time(&now);
        fprintf(stderr, "fetchmail: %s querying %s (protocol %s) at %s",
            RELEASE_ID,
-           ctl->server.names->id, showproto(ctl->server.protocol), ctime(&now));
+           ctl->server.pollname, showproto(ctl->server.protocol), ctime(&now));
     }
     switch (ctl->server.protocol) {
     case P_AUTO:
        for (i = 0; i < sizeof(autoprobe)/sizeof(autoprobe[0]); i++)
        {
            ctl->server.protocol = autoprobe[i];
-           if ((st = query_host(ctl)) == PS_SUCCESS || st == PS_NOMAIL || st == PS_AUTHFAIL || st == PS_LOCKBUSY)
+           if ((st = query_host(ctl)) == PS_SUCCESS || st == PS_NOMAIL || st == PS_AUTHFAIL || st == PS_LOCKBUSY || st == PS_SMTP)
                break;
        }
        ctl->server.protocol = P_AUTO;
@@ -781,7 +817,7 @@ void dump_params (struct query *ctl)
 /* display query parameters in English */
 {
     printf("Options for retrieving from %s@%s:\n",
-          ctl->remotename, visbuf(ctl->server.names->id));
+          ctl->remotename, visbuf(ctl->server.pollname));
 
     if (ctl->server.via)
        printf("  Mail will be retrieved via %s\n", ctl->server.via);
@@ -789,16 +825,14 @@ void dump_params (struct query *ctl)
     if (ctl->server.interval)
        printf("  Poll of this server will occur every %d intervals.\n",
               ctl->server.interval);
-#ifdef HAVE_GETHOSTBYNAME
-    if (ctl->server.canonical_name)
-       printf("  Canonical DNS name of server is %s.\n", ctl->server.canonical_name);
-#endif /* HAVE_GETHOSTBYNAME */
-    if (ctl->server.names->next)
+    if (ctl->server.truename)
+       printf("  True name of server is %s.\n", ctl->server.truename);
+    if (ctl->server.akalist)
     {
        struct idlist *idp;
 
        printf("  Predeclared mailserver aliases:");
-       for (idp = ctl->server.names->next; idp; idp = idp->next)
+       for (idp = ctl->server.akalist; idp; idp = idp->next)
            printf(" %s", idp->id);
        putchar('\n');
     }
@@ -878,6 +912,9 @@ void dump_params (struct query *ctl)
     printf("  Interpretation of Content-Transfer-Encoding is %sabled (pass8bits %s).\n",
           ctl->pass8bits ? "dis" : "en",
           ctl->pass8bits ? "on" : "off");
+    printf("  Nonempty Status lines will be %s (dropstatus %s)\n",
+          ctl->dropstatus ? "discarded" : "kept",
+          ctl->dropstatus ? "on" : "off");
     if (ctl->limit > 0)
        printf("  Message size limit is %d bytes (--limit %d).\n", 
               ctl->limit, ctl->limit);
@@ -904,9 +941,15 @@ void dump_params (struct query *ctl)
        printf("\n");
     }
     if (ctl->preconnect)
-       printf("  Server connection will be preinitialized with '%s.'\n", visbuf(ctl->preconnect));
+       printf("  Server connection will be brought up with '%s.'\n",
+              visbuf(ctl->preconnect));
+    else if (outlevel == O_VERBOSE)
+       printf("  No pre-connection command.\n");
+    if (ctl->postconnect)
+       printf("  Server connection will be taken down with '%s.'\n",
+              visbuf(ctl->postconnect));
     else if (outlevel == O_VERBOSE)
-       printf("  No preinitialization command.\n");
+       printf("  No post-connection command.\n");
     if (!ctl->localnames)
        printf("  No localnames declared for this host.\n");
     else