]> Pileus Git - ~andy/fetchmail/commitdiff
Support for multidrop mailboxes.
authorEric S. Raymond <esr@thyrsus.com>
Thu, 24 Oct 1996 20:41:57 +0000 (20:41 -0000)
committerEric S. Raymond <esr@thyrsus.com>
Thu, 24 Oct 1996 20:41:57 +0000 (20:41 -0000)
svn path=/trunk/; revision=374

NEWS
README
configure.in
driver.c
fetchmail.c
fetchmail.h
fetchmail.man
rcfile_l.l
rcfile_y.y
uid.c

diff --git a/NEWS b/NEWS
index 0148fd23f4828cc6bdcfb451c4bed95f6e4e7161..9d19d43b71668348f48ad4ccf2ca6aea33964b5d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,13 @@ fetchmail-1.9 (Mon Oct 21 13:42:07 EDT 1996):
 
 features --
 
+* It is now possible to specify multiple local recipients by giving a list
+  of names following "to" or "is".  Each local recipient is checked for in the
+  To:, Cc: and Bcc: headers of each message; if a match is found, the message
+  is sent to that local recipient.  This makes it possible to do mailing
+  lists and multidrop mailboxes.  See the man page for details (and note
+  the caveat in the BUGS AND KNOWN PROBLEMS section).
+
 * The first message from a query now includes the number of old messages
   when this can be determined (that is not under POP2).
 
diff --git a/README b/README
index 35ee9746d83e5920bfde0fea25a6f8df7c122b1b..d7f8fc3d14bdf4d2482503932d6241f0e2978566 100644 (file)
--- a/README
+++ b/README
@@ -51,6 +51,9 @@ with **.
 
        ** Timeout if server connection is dropped.
 
+       ** Support for retrieving and forwarding from multi-drop mailboxes
+          that is guaranteed not to cause mail loops.
+
        *  Easy control via command line or free-format run control file.
 
        *  Daemon mode -- fetchmail can be run in background to poll
index 736068cd357473352673e43d26846d8386b6c7bf..2c5f573deafb8ad315cb29838a6cf1d593a96955 100644 (file)
@@ -61,7 +61,7 @@ dnl All AC_CHECK_FUNCs must precede the following AC_SUBSTs
 AC_SUBST(EXTRASRC)
 AC_SUBST(EXTRAOBJ)
 
-AC_CHECK_FUNCS(tcsetattr stty setsid seteuid rresvport)
+AC_CHECK_FUNCS(tcsetattr stty setsid seteuid gethostbyname)
 
 dnl AC_FUNC_SETVBUF_REVERSED
 
index 7d2e281a832e0cd9885811e3b0eb81b5a95a102f..3d38b8d9910eae62d06464abfe7f02875e90f9b0 100644 (file)
--- a/driver.c
+++ b/driver.c
 #include  <sys/time.h>
 #include  <signal.h>
 
+#ifdef HAVE_GETHOSTBYNAME
+#include <netdb.h>
+#endif /* HAVE_GETHOSTBYNAME */
+
 #ifdef KERBEROS_V4
 #include <krb.h>
 #include <des.h>
@@ -295,6 +299,86 @@ char *hdr; /* header line to be parsed, NUL to continue in previous hdr */
     return(NULL);
 }
 
+#ifdef HAVE_GETHOSTBYNAME
+static int is_host_alias(name, host, canonical)
+/* determine whether name is a DNS alias of either following hostname */
+const char *name, *host, *canonical;
+{
+    struct hostent     *he;
+
+    /*
+
+     * The first two checks are optimizations that will catch a good
+     * many cases.  First, check against the hostname the user specified.
+     * Odds are good this will either be the mailserver's FQDN or a
+     * suffix of it with the mailserver's domain's default host name
+     * omitted.  Next, check against the mailserver's FQDN, in case
+     * it's not the same as the declared hostname.
+     *
+     * Either of these on a mail address is definitive.  Only if the
+     * name doesn't match either is it time to call the bind library.
+     * If this happens odds are good we're looking at an MX name.
+     */
+    if (strcmp(name, host) == 0)
+       return(1);
+    else if (strcmp(name, canonical) == 0)
+       return(1);
+    else if ((he = gethostbyname(name)) == (struct hostent *)NULL)
+    {
+       /*
+        * We treat lookup failure as a negative on the theory that
+        * the mailserver's DNS server is `nearby' and should be able
+        * to respond quickly and reliably.  Ergo if we get failure,
+        * the name isn't a mailserver alias.
+        */
+       if (outlevel == O_VERBOSE)
+           fprintf(stderr, "fetchmail: DNS lookup of %s failed\n", name);
+       return(FALSE);
+    }
+    else
+       return(strcmp(name, he->h_name) == 0);
+}
+
+void find_server_names(hdr, queryctl, xmit_names)
+/* parse names out of a RFC822 header into an ID list */
+const char *hdr;               /* RFC822 header in question */
+struct hostrec *queryctl;      /* list of permissible aliases */
+struct idlist **xmit_names;    /* list of recipient names parsed out */
+{
+    if (hdr == (char *)NULL)
+       return;
+    else
+    {
+       char    *cp = nxtaddr(hdr), *lname;
+
+       do {
+           char        *atsign = strchr(cp, '@');
+
+           if (atsign)
+               if (queryctl->norewrite)
+                   continue;
+               else
+               {
+                   if (!is_host_alias(atsign+1, 
+                                      queryctl->servername,
+                                      queryctl->canonical_name))
+                       continue;
+                   atsign[0] = '\0';
+               }
+           if ((lname = idpair_find(&queryctl->localnames, cp))!=(char *)NULL)
+           {
+               if (outlevel == O_VERBOSE)
+                   fprintf(stderr,
+                           "fetchmail: mapped %s to local %s\n",
+                           cp, lname);
+               save_uid(xmit_names, -1, lname);
+           }
+       } while
+           ((cp = nxtaddr((char *)NULL)) != (char *)NULL);
+    }
+}
+#endif /* HAVE_GETHOSTBYNAME */
+
 static int gen_readmsg (socket, mboxfd, len, delimited, queryctl)
 /* read message content and ship to SMTP or MDA */
 int socket;    /* to which the server is connected */
@@ -398,14 +482,47 @@ struct hostrec *queryctl; /* query control record */
        }
        else if (headers)
        {
-           char        *cp;
+           char                *cp;
 
            if (!queryctl->mda[0])
            {
                if (SMTP_from(mboxfd, nxtaddr(fromhdr)) != SM_OK)
                    return(PS_SMTP);
-               if (SMTP_rcpt(mboxfd, queryctl->localname) != SM_OK)
-                   return(PS_SMTP);
+
+#ifdef HAVE_GETHOSTBYNAME
+               /* is this a multidrop box? */
+               if (queryctl->localnames != (struct idlist *)NULL
+                   && queryctl->localnames->next != (struct idlist *)NULL)
+               {
+                   struct idlist       *idp, *xmit_names;
+
+                   /* compute the local address list */
+                   xmit_names = (struct idlist *)NULL;
+                   find_server_names(tohdr,  queryctl, &xmit_names);
+                   find_server_names(cchdr,  queryctl, &xmit_names);
+                   find_server_names(bcchdr, queryctl, &xmit_names);
+
+                   /* if nothing supplied localnames, default appropriately */
+                   if (!xmit_names)
+                       save_uid(&xmit_names, -1, dfltuser);
+
+                   for (idp = xmit_names; idp; idp = idp->next)
+                       if (SMTP_rcpt(mboxfd, idp->id) != SM_OK)
+                           return(PS_SMTP);
+                   free_uid_list(&xmit_names);
+               }
+               else    /* it's a single-drop box, use first localname */
+#endif /* HAVE_GETHOSTBYNAME */
+               {
+                   if (queryctl->localnames)
+                       cp = queryctl->localnames->id;
+                   else
+                       cp = dfltuser;
+
+                   if (SMTP_rcpt(mboxfd, cp) != SM_OK)
+                       return(PS_SMTP);
+               }
+
                SMTP_data(mboxfd);
                if (outlevel == O_VERBOSE)
                    fputs("SMTP> ", stderr);
@@ -618,9 +735,8 @@ struct method *proto;               /* protocol method table */
     /* show user how many messages we downloaded */
     if (outlevel > O_SILENT && outlevel < O_VERBOSE)
        if (count == 0)
-           fprintf(stderr, "No mail for %s from %s@%s\n", 
+           fprintf(stderr, "No mail from %s@%s\n", 
                    queryctl->remotename,
-                   queryctl->localname,
                    queryctl->servername);
        else
        {
@@ -628,9 +744,8 @@ struct method *proto;               /* protocol method table */
            if (new != -1 && (count - new) > 0)
                fprintf(stderr, " (%d seen)", count-new);
            fprintf(stderr,
-                   " from %s for %s@%s.\n",
+                   " from %s@%s.\n",
                    queryctl->remotename,
-                   queryctl->localname,
                    queryctl->servername);
        }
 
index 3e5a991d27453ca6fdb4027a0ab970e658de65a8..bbef5002ed922557fc82919f40f5fc22231c4ff4 100644 (file)
 #include <sys/stat.h>
 #include <fcntl.h>
 
+#ifdef HAVE_GETHOSTBYNAME
+#include <netdb.h>
+#endif /* HAVE_GETHOSTBYNAME */
+
 #include "fetchmail.h"
 #include "getopt.h"
 
-#define DROPDEAD       6       /* maximum bad socjet opens */
+#define DROPDEAD       6       /* maximum bad socket opens */
 
 #ifdef HAVE_PROTOTYPES
 /* prototypes for internal functions */
@@ -52,6 +56,7 @@ int check_only;               /* if --probe was set */
 char *rcfile;          /* path name of rc file */
 char *idfile;          /* UID list file */
 int versioninfo;       /* emit only version info */
+char *dfltuser;                /* invoking user */
 
 static void termhook();
 static char *lockfile;
@@ -166,26 +171,51 @@ char **argv;
        if (strcmp(hostp->servername, "defaults") == 0)
            exit(PS_SYNTAX);
 
+    /* figure out who the default recipient should be */
+    if (getuid() == 0)
+       dfltuser = hostp->remotename;
+    else
+       dfltuser = user;
+
     /* merge in wired defaults, do sanity checks and prepare internal fields */
     for (hostp = hostlist; hostp; hostp = hostp->next)
        if (hostp->active && !(implicitmode && hostp->skip))
        {
+#ifdef HAVE_GETHOSTBYNAME
+           struct hostent      *namerec;
+#endif /* HAVE_GETHOSTBYNAME */
+
            /* merge in defaults */
            optmerge(hostp, &def_opts);
 
-           /* if rc file didn't supply a localname, default appropriately */
-           if (!hostp->localname[0])
-               if (getuid() == 0)
-                   strcpy(hostp->localname, hostp->remotename);
-               else
-                   strcpy(hostp->localname, user);
-
            /* check that delivery is going to a real local user */
            if ((pw = getpwnam(user)) == (struct passwd *)NULL)
                exit(PS_SYNTAX);        /* has to be from bad rc file */
            else
                hostp->uid = pw->pw_uid;
 
+#ifdef HAVE_GETHOSTBYNAME
+           /* compute the canonical name of the host */
+           namerec = gethostbyname(hostp->servername);
+           if (namerec == (struct hostent *)NULL)
+           {
+               fprintf(stderr,
+                       "fetchmail: can't get canonical name of host %s\n",
+                       hostp->servername);
+               exit(PS_SYNTAX);
+           }
+           else
+               hostp->canonical_name = xstrdup((char *)namerec->h_name);
+#else
+           /* can't handle multidrop mailboxes unless we can do DNS lookups */
+           if (hostp->localnames && hostp->localnames->next)
+           {
+               fputs("fetchmail: can't handle multidrop mailboxes without DNS\n",
+                       stderr);
+               exit(PS_SYNTAX);
+           }
+#endif /* HAVE_GETHOSTBYNAME */
+
            /* sanity checks */
            if (hostp->port < 0)
            {
@@ -201,10 +231,7 @@ char **argv;
                int argi;
                char *argp;
 
-               /* expand the %s escape if any before parsing */
-               sprintf(hostp->mdabuf, hostp->mda, hostp->localname);
-
-               /* now punch nulls into the delimiting whitespace in the args */
+               /* punch nulls into the delimiting whitespace in the args */
                for (argp = hostp->mdabuf, argi = 1; *argp != '\0'; argi++)
                {
                    hostp->mda_argv[argi] = argp;
@@ -398,6 +425,11 @@ char **argv;
      */
     lossage = 0;
     do {
+
+#ifdef HAVE_GETHOSTBYNAME
+       sethostent(TRUE);       /* use TCP/IP for mailserver queries */
+#endif /* HAVE_GETHOSTBYNAME */
+
        for (hostp = hostlist; hostp; hostp = hostp->next)
        {
            if (hostp->active && !(implicitmode && hostp->skip))
@@ -433,6 +465,10 @@ char **argv;
            }
        }
 
+#ifdef HAVE_GETHOSTBYNAME
+       endhostent();           /* release TCP/IP connection to nameserver */
+#endif /* HAVE_GETHOSTBYNAME */
+
        if (sleep(poll_interval))
            (void) fputs("fetchmail: awakened by SIGHUP\n", stderr);
     } while
@@ -523,12 +559,14 @@ int dump_params (queryctl)
 /* display query parameters in English */
 struct hostrec *queryctl;      /* query parameter block */
 {
-    printf("Options for %s retrieving from %s:\n",
-          hostp->localname, visbuf(hostp->servername));
+    printf("Options for retrieving from %s@%s:\n",
+          hostp->remotename, visbuf(hostp->servername));
+#ifdef HAVE_GETHOSTBYNAME
+    printf("  Canonical DNS name of server is %s.\n", hostp->canonical_name);
+#endif /* HAVE_GETHOSTBYNAME */
     if (queryctl->skip || outlevel == O_VERBOSE)
        printf("  This host will%s be queried when no host is specified.\n",
               queryctl->skip ? " not" : "");
-    printf("  Username = '%s'.\n", visbuf(queryctl->remotename));
     if (queryctl->password[0] == '\0')
        printf("  Password will be prompted for.\n");
     else if (outlevel == O_VERBOSE)
@@ -583,6 +621,25 @@ struct hostrec *queryctl;  /* query parameter block */
     else
        printf("  Messages will be SMTP-forwarded to '%s'.\n",
               visbuf(queryctl->smtphost));
+    if (!queryctl->localnames)
+       printf("  No localnames declared for this host.\n");
+    else
+    {
+       struct idlist *idp;
+       int count = 0;
+
+       for (idp = hostp->localnames; idp; idp = idp->next)
+           ++count;
+
+       printf("  %d local names recognized.\n", count);
+       if (outlevel == O_VERBOSE)
+           for (idp = hostp->localnames; idp; idp = idp->next)
+               if (idp->val.id2)
+                   fprintf(stderr, "\t%s -> %s\n", idp->id, idp->val.id2);
+               else
+                   fprintf(stderr, "\t%s\n", idp->id);
+    }
+
     if (queryctl->protocol > P_POP2)
        if (!queryctl->oldsaved)
            printf("  No UIDs saved from this host.\n");
index c5ef2496588ac028e6f1c3953123f998709dd8e1..baaa6f881489b05075e9173612bf1371b574a300 100644 (file)
 
 struct idlist
 {
-    int num;
     char *id;
+    union
+    {
+       int num;
+       char *id2;
+    } val;
     struct idlist *next;
 };
 
@@ -65,12 +69,12 @@ struct hostrec
 {
     /* per-host data */
     char servername [HOSTLEN+1];
-    char localname [USERNAMELEN+1];
     char remotename [USERNAMELEN+1];
     char password [PASSWORDLEN+1];
     char mailbox [FOLDERLEN];
     char smtphost[HOSTLEN+1];
     char mda [MDALEN+1];
+    struct idlist *localnames;
     int protocol;
     int port;
     int authenticate;
@@ -95,6 +99,9 @@ struct hostrec
     struct hostrec *next;      /* next host in chain */
     unsigned int uid;          /* UID of user to deliver to */
     char digest [DIGESTLEN];
+#ifdef HAVE_GETHOSTBYNAME
+    char *canonical_name;      /* DNS canonical name of server host */
+#endif /* HAVE_GETHOSTBYNAME */
 };
 
 struct method
@@ -135,6 +142,7 @@ extern char *rcfile;                /* path name of rc file */
 extern char *idfile;           /* path name of UID file */
 extern int linelimit;          /* limit # lines retrieved per site */
 extern int versioninfo;                /* emit only version info */
+extern char *dfltuser;         /* invoking user */
 
 #ifdef HAVE_PROTOTYPES
 
@@ -157,9 +165,13 @@ int doIMAP (struct hostrec *);
 void initialize_saved_lists(struct hostrec *, char *);
 void save_uid(struct idlist **, int, char *);
 void free_uid_list(struct idlist **);
+void save_id_pair(struct idlist **, char *, char *);
+void free_idpair_list(struct idlist **);
 int delete_uid(struct idlist **, int);
 int uid_in_list(struct idlist **, char *);
 char *uid_find(struct idlist **, int);
+char *idpair_find(struct idlist **, char *);
+void append_uid_list(struct idlist **, struct idlist **);
 void update_uid_lists(struct hostrec *);
 void write_saved_lists(struct hostrec *, char *);
 
index b2165186484273ab0511351ab65ee92925cb8f4d..5cab1cf571da0935b9a07e3c8fa9645aa3c26ffd 100644 (file)
@@ -408,19 +408,32 @@ Legal user options are
     norewrite
 .PP
 All options correspond to the obvious command-line arguments except
-four: \fBis\fR, \fBto\fR, \fBpassword\fR and \fBskip\fR.
+five: \fBis\fR, \fBto\fR, \fBpassword\fR, and \fBskip\fR.
 .PP
-The \fBis\fR or \fIto\fR keywords associate a following local
-username with the mailserver user name in the entry.  They are intended
-to be used in configurations where \fIfetchmail\fR runs as root and
-retrieves mail for multiple local users.  If no \fBis\fR or \fIto\fR 
-clause is present, the default local username is the calling user,
-unless the calling user is root in which case it is the remote user
-name of the current entry.
+The \fBis\fR or \fIto\fR keywords associate the following local (client)
+name(s) (or server-name to client-name mappings separated by =) with
+the mailserver user name in the entry.
+.PP
+A single local name can be used to support redirecting your mail when
+your username on the client machine is different from your name on the
+mailserver.  When there is only a single local name, mail is forwarded
+to that username regardless of the message's To, Cc, and Bcc headers.
+.PP
+When there is more than one local name (or name mapping) the
+\fIfetchmail\fR code does look at the To, Cc, and Bcc headers of
+retrieved mail. When a declared mailserver username is recognized, its
+local mapping is added to the list of local recipients.  If
+\fIfetchmail\fR cannot recognize any mailserver usernames, the default
+recipient is the calling user, unless the calling user is root in
+which case it is the remote user name of the current entry.
 .PP
 The \fBpassword\fR option requires a string argument, which is the password
 to be used with the entry's server.
 .PP
+The \fBaliases\fR option declares names that are recognized as OK for
+local delivery.  Your local name is automatically one of these; the
+aliases directive can be used to declare others.   
+.PP
 The \fBskip\fR option tells
 .I fetchmail 
 not to query this host unless it is explicitly named on the command
@@ -552,6 +565,21 @@ to be specifying multiple users per server unless running it as root
 pop-provider.net, which is probably not what you want).
 In any case, we strongly recommend always having an explicit
 \fBuser\fR clause when specifying multiple users for server.
+.PP
+Here's what a simple retrieval configuration for a multi-drop mailbox
+looks like:
+
+.nf
+  server pop.provider.net:
+        user maildrop with pass secret1 to golux hurkle=happy snark here
+.fi
+
+This says that the mailbox of account `maildrop' on the server is a
+multi-drop box, and that messages in it should be parsed for the
+server user names `golux', `hurkle', and `snark'.  It further
+specifies that `golux' and `snark' have the same name on the
+client as on the server, but mail for server user `hurkle' should be
+delivered to client user `happy'.
 .SH EXIT CODES
 To facilitate the use of 
 .I fetchmail
@@ -598,6 +626,19 @@ When
 .I fetchmail
 queries more than one host, the returned status is that of the last
 host queried.
+.SH NOTE
+Multiple local names can be used to support forwarding from a
+"multi-drop" mailbox accumulating mail on the server for several
+client-machine users.  Local names can also be used to administer a
+mailing list from the client side of a \fIfetchmail\fR collection.
+Suppose your name is `esr', and you maintain a mailing list called
+(say) "fetchmail-friends", and you want to keep the alias list on your
+client machine.  On your server, you can alias fetchmail-friends to
+esr; then, in your \fI.fetchmailrc\fR, declare `to esr
+fetchmail-friends here'.  Then, when mail including that alias in any
+of its recpient lines line gets fetched, the alias will be appended to
+the list of recipients your SMTP listener sees.  Therefore it will
+undergo alias expansion locally.
 .SH AUTHORS
 .I fetchmail
 was originated (under the name `popclient') by Carl Harris at Virginia
@@ -642,6 +683,15 @@ to the mailserver.  This creates a risk that name/password pairs
 might be snaffled with a packet sniffer or more sophisticated
 monitoring software.
 .PP
+Retrieval and forwarding from multi-drop server mailboxes is only as
+reliable as your mail server host's DNS service.  Each host
+address part in each message of a multi-drop mailbox is checked 
+with
+.BR gethostbyname (2)
+to see if it's an alias of the mail server.  If it is, but the
+lookup fails due to network congestion or a crashed server, forwarding
+will not get done correctly. 
+.PP
 Under Linux, if fetchmail is run in daemon mode with the network
 inaccessible, each poll leaves a socket allocated but in CLOSE state
 (this is visible in netstat(1)'s output).  For some reason, these
index 5ef8722d9e957ae8601aa2c236b287f17e719136..701edd577458fa9f584dd3445e90bcadde2e197a 100644 (file)
@@ -13,6 +13,8 @@
 int prc_lineno = 1;
 %}
 
+%o 4000
+
 %%
 
 defaults       { return DEFAULTS; }
@@ -32,6 +34,7 @@ is            { return IS; }
 here           { return HERE; }
 there          { return THERE; }
 to             { return TO; }
+=              { return MAP; }
 
 keep           { yylval.flag = FLAG_TRUE;  return KEEP; }
 flush          { yylval.flag = FLAG_TRUE;  return FLUSH; }
index 5f9be831b3482b9e367dc581672695d677248619..6582a31cbc42bb7b1d9bf5342afad3f0498337e0 100644 (file)
@@ -31,7 +31,7 @@ static int prc_errflag;
 }
 
 %token DEFAULTS SERVER PROTOCOL AUTHENTICATE TIMEOUT KPOP KERBEROS
-%token USERNAME PASSWORD FOLDER SMTPHOST MDA IS HERE THERE TO
+%token USERNAME PASSWORD FOLDER SMTPHOST MDA IS HERE THERE TO MAP
 %token <proto> PROTO
 %token <sval>  STRING
 %token <number> NUMBER
@@ -91,7 +91,7 @@ explicitdef   : userdef user0opts
                ;
 
 userdef                : USERNAME STRING       {strcpy(current.remotename, $2);}
-               | USERNAME STRING HERE  {strcpy(current.localname, $2);}
+               | USERNAME mapping_list HERE
                | USERNAME STRING THERE {strcpy(current.remotename, $2);}
                ;
 
@@ -103,10 +103,20 @@ user1opts : user_option
                | user1opts user_option
                ;
 
-user_option    : TO STRING             {strcpy(current.localname, $2);}
-               | TO STRING HERE        {strcpy(current.localname, $2);}
-               | IS STRING             {strcpy(current.localname, $2);}
-               | IS STRING HERE        {strcpy(current.localname, $2);}
+mapping_list   : mapping               
+               | mapping_list mapping
+               ;
+
+mapping                : STRING        
+                               {save_id_pair(&current.localnames, $1, NULL);}
+               | STRING MAP STRING
+                               {save_id_pair(&current.localnames, $1, $3);}
+               ;
+
+user_option    : TO mapping_list HERE
+               | TO mapping_list
+               | IS mapping_list HERE
+               | IS mapping_list
                | IS STRING THERE       {strcpy(current.remotename, $2);}
                | PASSWORD STRING       {strcpy(current.password, $2);}
                | FOLDER STRING         {strcpy(current.mailbox, $2);}
@@ -256,7 +266,6 @@ int prc_register()
 {
 #define STR_FORCE(fld, len) if (cmd_opts.fld[0]) \
                                        strcpy(current.fld, cmd_opts.fld)
-    STR_FORCE(localname, USERNAMELEN);
     STR_FORCE(remotename, USERNAMELEN);
     STR_FORCE(password, PASSWORDLEN);
     STR_FORCE(mailbox, FOLDERLEN);
@@ -284,8 +293,11 @@ void optmerge(h2, h1)
 struct hostrec *h1;
 struct hostrec *h2;
 {
+    struct idlist *idp;
+
+    append_uid_list(&h2->localnames, &h1->localnames);
+
 #define STR_MERGE(fld, len) if (*(h2->fld) == '\0') strcpy(h2->fld, h1->fld)
-    STR_MERGE(localname, USERNAMELEN);
     STR_MERGE(remotename, USERNAMELEN);
     STR_MERGE(password, PASSWORDLEN);
     STR_MERGE(mailbox, FOLDERLEN);
@@ -304,6 +316,7 @@ struct hostrec *h2;
     FLAG_MERGE(authenticate);
     FLAG_MERGE(timeout);
 #undef FLAG_MERGE
+
 }
 
 /* easier to do this than cope with variations in where the library lives */
diff --git a/uid.c b/uid.c
index ad043af690c7b9cbdf2591e0e0eaa7ddea075392..8ad4215f05526404d3ccc75513c0c2e5690086ce 100644 (file)
--- a/uid.c
+++ b/uid.c
@@ -110,7 +110,7 @@ char *str;
     struct idlist *new;
 
     new = (struct idlist *)xmalloc(sizeof(struct idlist));
-    new->num = num;
+    new->val.num = num;
     new->id = xstrdup(str);
     new->next = *idl;
     *idl = new;
@@ -129,6 +129,39 @@ struct idlist **idl;
     *idl = (struct idlist *)NULL;
 }
 
+void save_id_pair(idl, str1, str2)
+/* save an ID pair on the given list */
+struct idlist **idl;
+char *str1, *str2;
+{
+    struct idlist *new;
+
+    new = (struct idlist *)xmalloc(sizeof(struct idlist));
+    new->id = xstrdup(str1);
+    if (str2)
+       new->val.id2 = xstrdup(str2);
+    else
+       new->val.id2 = (char *)NULL;
+    new->next = *idl;
+    *idl = new;
+}
+
+#ifdef __UNUSED__
+void free_idpair_list(idl)
+/* free the given ID pair list */
+struct idlist **idl;
+{
+    if (*idl == (struct idlist *)NULL)
+       return;
+
+    free_idpair_list(&(*idl)->next);
+    free ((*idl)->id);
+    free ((*idl)->val.id2);
+    free(*idl);
+    *idl = (struct idlist *)NULL;
+}
+#endif
+
 int uid_in_list(idl, str)
 /* is a given ID in the given list? */
 struct idlist **idl;
@@ -149,12 +182,25 @@ int number;
 {
     if (*idl == (struct idlist *) 0)
        return((char *) 0);
-    else if (number == (*idl)->num)
+    else if (number == (*idl)->val.num)
        return((*idl)->id);
     else
        return(uid_find(&(*idl)->next, number));
 }
 
+char *idpair_find(idl, id)
+/* return the id of the given number in the given list. */
+struct idlist **idl;
+char *id;
+{
+    if (*idl == (struct idlist *) 0)
+       return((char *) 0);
+    else if (strcmp(id, (*idl)->id))
+       return((*idl)->val.id2 ? (*idl)->val.id2 : (*idl)->id);
+    else
+       return(idpair_find(&(*idl)->next, id));
+}
+
 int delete_uid(idl, num)
 /* delete given message from given list */
 struct idlist **idl;
@@ -162,7 +208,7 @@ int num;
 {
     if (*idl == (struct idlist *)NULL)
        return(0);
-    else if ((*idl)->num == num)
+    else if ((*idl)->val.num == num)
     {
        struct idlist   *next = (*idl)->next;
 
@@ -176,6 +222,19 @@ int num;
     return(0);
 }
 
+void append_uid_list(idl, nidl)
+/* append nidl to idl (does not copy *) */
+struct idlist **idl;
+struct idlist **nidl;
+{
+    if ((*idl) == (struct idlist *)NULL)
+       *idl = *nidl;
+    else if ((*idl)->next == (struct idlist *)NULL)
+       (*idl)->next = *nidl;
+    else
+       append_uid_list(&(*idl)->next, nidl);
+}
+
 void update_uid_lists(hostp)
 /* perform end-of-query actions on UID lists */
 struct hostrec *hostp;