URI: 
       tmore changes - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 5cc53af92d6bfae8b930d3c9154c8ed44e1feb09
   DIR parent d0d15c12d43d201cf916ebfff157b976c8f3b6a1
  HTML Author: rsc <devnull@localhost>
       Date:   Sun, 12 Feb 2006 19:40:23 +0000
       
       more changes
       
       Diffstat:
         M src/cmd/upas/common/common.h        |       2 ++
         M src/cmd/upas/common/libsys.c        |     221 ++++++++++++++-----------------
         M src/cmd/upas/marshal/marshal.c      |       2 +-
         M src/cmd/upas/q/runq.c               |       2 +-
         M src/cmd/upas/send/message.c         |       2 +-
         M src/cmd/upas/send/rewrite.c         |       1 +
         M src/cmd/upas/smtp/greylist.c        |       3 +--
         M src/cmd/upas/smtp/mxdial.c          |     173 +++++--------------------------
         M src/cmd/upas/smtp/rfc822.tab.h      |     123 +++++++------------------------
         M src/cmd/upas/smtp/smtp.c            |      89 ++++++++++++++++++++-----------
         M src/cmd/upas/smtp/smtpd.c           |      28 +++++++++++++++++-----------
       
       11 files changed, 234 insertions(+), 412 deletions(-)
       ---
   DIR diff --git a/src/cmd/upas/common/common.h b/src/cmd/upas/common/common.h
       t@@ -18,6 +18,8 @@ enum
                Elemlen= 28,
                Errlen=        128,
                Pathlen= 256,
       +        
       +        RetryCode = 2,
        };
        
        /*
   DIR diff --git a/src/cmd/upas/common/libsys.c b/src/cmd/upas/common/libsys.c
       t@@ -1,3 +1,7 @@
       +#include <u.h>
       +#include <sys/types.h>
       +#include <pwd.h>
       +#include <netdb.h>
        #include "common.h"
        #include <auth.h>
        #include <ndb.h>
       t@@ -407,6 +411,7 @@ sysdirreadall(int fd, Dir **d)
        /*
         *  read in the system name
         */
       +static char *unix_hostname_read(void);
        extern char *
        sysname_read(void)
        {
       t@@ -424,19 +429,26 @@ sysname_read(void)
        extern char *
        alt_sysname_read(void)
        {
       +        char *cp;
                static char name[128];
       -        int n, fd;
        
       -        fd = open("/dev/sysname", OREAD);
       -        if(fd < 0)
       -                return 0;
       -        n = read(fd, name, sizeof(name)-1);
       -        close(fd);
       -        if(n <= 0)
       +        cp = getenv("sysname");
       +        if(cp == 0 || *cp == 0)
       +                cp = unix_hostname_read();
       +        if(cp == 0 || *cp == 0)
                        return 0;
       -        name[n] = 0;
       +        strecpy(name, name+sizeof name, cp);
                return name;
        }
       +static char *
       +unix_hostname_read(void)
       +{
       +        static char hostname[256];
       +
       +        if(gethostname(hostname, sizeof hostname) < 0)
       +                return nil;
       +        return hostname;
       +}
        
        /*
         *  get all names
       t@@ -445,57 +457,49 @@ extern char**
        sysnames_read(void)
        {
                static char **namev;
       -        Ndbtuple *t, *nt;
       -        Ndb* db;
       -        Ndbs s;
       -        int n;
       -        char *cp;
       +        struct hostent *h;
       +        char **p, **a;
        
                if(namev)
                        return namev;
        
       -/* XXX */
       -        /* free(csgetvalue(0, "sys", alt_sysname_read(), "dom", &t));  jpc */
       -        db = ndbopen(unsharp("#9/ndb/local"));
       -        free(ndbgetvalue(db, &s, "sys", sysname(),"dom", &t));
       -        /* t = nil; /* jpc */
       -        /* fprint(2,"csgetvalue called: fixme"); /* jpc */
       -
       -        n = 0;
       -        for(nt = t; nt; nt = nt->entry)
       -                if(strcmp(nt->attr, "dom") == 0)
       -                        n++;
       -
       -        namev = (char**)malloc(sizeof(char *)*(n+3));
       +        h = gethostbyname(alt_sysname_read());
       +        for(p=h->h_aliases; *p; p++)
       +                ;
       +        
       +        namev = malloc((2+p-h->h_aliases)*sizeof namev[0]);
       +        if(namev == 0)
       +                return 0;
        
       -        if(namev){
       -                n = 0;
       -                namev[n++] = strdup(sysname_read());
       -                cp = alt_sysname_read();
       -                if(cp)
       -                        namev[n++] = strdup(cp);
       -                for(nt = t; nt; nt = nt->entry)
       -                        if(strcmp(nt->attr, "dom") == 0)
       -                                namev[n++] = strdup(nt->val);
       -                namev[n] = 0;
       -        }
       -        if(t)
       -                ndbfree(t);
       +        a = namev;
       +        *a++ = strdup(h->h_name);
       +        for(p=h->h_aliases; *p; p++)
       +                *a++ = strdup(*p);
       +        *a = 0;
        
                return namev;
        }
        
        /*
       - *  read in the domain name
       + *  read in the domain name.
       + *  chop off beginning pieces until we find one with an mx record.
         */
        extern char *
        domainname_read(void)
        {
       -        char **namev;
       +        char **namev, *p;
       +        Ndbtuple *t;
        
       -        for(namev = sysnames_read(); *namev; namev++)
       -                if(strchr(*namev, '.'))
       -                        return *namev;
       +        for(namev = sysnames_read(); *namev; namev++){
       +                if(strchr(*namev, '.')){
       +                        for(p=*namev-1; p && *++p; p=strchr(p, '.')){
       +                                if((t = dnsquery(nil, p, "mx")) != nil){
       +                                        ndbfree(t);
       +                                        return p;
       +                                }
       +                        }
       +                }
       +        }
                return 0;
        }
        
       t@@ -608,36 +612,12 @@ sysisdir(char *file)
        }
        
        /*
       - * kill a process or process group
       - */
       -
       -static int
       -stomp(int pid, char *file)
       -{
       -        char name[64];
       -        int fd;
       -
       -        snprint(name, sizeof(name), "/proc/%d/%s", pid, file);
       -        fd = open(name, 1);
       -        if(fd < 0)
       -                return -1;
       -        if(write(fd, "die: yankee pig dog\n", sizeof("die: yankee pig dog\n") - 1) <= 0){
       -                close(fd);
       -                return -1;
       -        }
       -        close(fd);
       -        return 0;
       -        
       -}
       -
       -/*
         *  kill a process
         */
        extern int
        syskill(int pid)
        {
       -        return stomp(pid, "note");
       -        
       +        return postnote(PNPROC, pid, "kill");
        }
        
        /*
       t@@ -646,7 +626,7 @@ syskill(int pid)
        extern int
        syskillpg(int pid)
        {
       -        return stomp(pid, "notepg");
       +        return postnote(PNGROUP, pid, "kill");
        }
        
        extern int
       t@@ -723,12 +703,24 @@ sysfiles(void)
        extern String *
        mboxpath(char *path, char *user, String *to, int dot)
        {
       -        upasconfig();
       -
       +        char *dir;
       +        String *s;
       +        
                if (dot || *path=='/' || strncmp(path, "./", 2) == 0
                                      || strncmp(path, "../", 3) == 0) {
                        to = s_append(to, path);
                } else {
       +                if ((dir = homedir(user)) != nil) {
       +                        s = s_copy(dir);
       +                        s_append(s, "/mail/");
       +                        if(access(s_to_c(s), AEXIST) >= 0){
       +                                to = s_append(to, s_to_c(s));
       +                                s_free(s);
       +                                to = s_append(to, path);
       +                                return to;
       +                        }
       +                        s_free(s);
       +                }
                        to = s_append(to, MAILROOT);
                        to = s_append(to, "/box/");
                        to = s_append(to, user);
       t@@ -755,13 +747,6 @@ deadletter(String *to)                /* pass in sender??? */
                return mboxpath("dead.letter", cp, to, 0);
        }
        
       -char *
       -homedir(char *user)
       -{
       -        USED(user);
       -        return getenv("home");
       -}
       -
        String *
        readlock(String *file)
        {
       t@@ -776,56 +761,48 @@ readlock(String *file)
        String *
        username(String *from)
        {
       -        int n;
       -        Biobuf *bp;
       -        char *p, *q;
       -        String *s;
       +        String* s;
       +        struct passwd* pw;
       +
       +        setpwent();
       +        while((pw = getpwent()) != nil){
       +                if(strcmp(s_to_c(from), pw->pw_name) == 0){
       +                        s = s_new();
       +                        s_append(s, "\"");
       +                        s_append(s, pw->pw_gecos);
       +                        s_append(s, "\"");
       +                        return s;
       +                }
       +        }
       +        return nil;
       +}
        
       -        bp = Bopen("/adm/keys.who", OREAD);
       -        if(bp == 0)
       -                bp = Bopen("/adm/netkeys.who", OREAD);
       -        if(bp == 0)
       -                return 0;
       +char *
       +homedir(char *user)
       +{
       +        static char buf[1024];
       +        struct passwd* pw;
        
       -        s = 0;
       -        n = strlen(s_to_c(from));
       -        for(;;) {
       -                p = Brdline(bp, '\n');
       -                if(p == 0)
       -                        break;
       -                p[Blinelen(bp)-1] = 0;
       -                if(strncmp(p, s_to_c(from), n))
       -                        continue;
       -                p += n;
       -                if(*p != ' ' && *p != '\t')        /* must be full match */
       -                        continue;
       -                while(*p && (*p == ' ' || *p == '\t'))
       -                                p++;
       -                if(*p == 0)
       -                        continue;
       -                for(q = p; *q; q++)
       -                        if(('0' <= *q && *q <= '9') || *q == '<')
       -                                break;
       -                while(q > p && q[-1] != ' ' && q[-1] != '\t')
       -                        q--;
       -                while(q > p && (q[-1] == ' ' || q[-1] == '\t'))
       -                        q--;
       -                *q = 0;
       -                s = s_new();
       -                s_append(s, "\"");
       -                s_append(s, p);
       -                s_append(s, "\"");
       -                break;
       -        }
       -        Bterm(bp);
       -        return s;
       +        setpwent();
       +        while((pw = getpwent()) != nil)
       +                if(strcmp(user, pw->pw_name) == 0){
       +                        strecpy(buf, buf+sizeof buf, pw->pw_dir);
       +                        return buf;
       +                }
       +        return nil;
        }
        
        char *
        remoteaddr(int fd, char *dir)
        {
       -        /* XXX should call netconninfo */
       -        return "";
       +        char *raddr;
       +        NetConnInfo *nci;
       +        
       +        if((nci = getnetconninfo(dir, fd)) == nil)
       +                return nil;
       +        raddr = strdup(nci->raddr);
       +        freenetconninfo(nci);
       +        return raddr;
        }
        
        //  create a file and 
   DIR diff --git a/src/cmd/upas/marshal/marshal.c b/src/cmd/upas/marshal/marshal.c
       t@@ -1104,7 +1104,7 @@ sendmail(Addr *to, Addr *cc, int *pid, char *rcvr)
                        exec(s_to_c(cmd), av);
                        exec("myupassend", av);
                        exec(unsharp("#9/bin/upas/send"), av);
       -                fatal("execing: %r");
       +                fatal("exec: %r");
                        break;
                default:
                        if(rcvr != nil)
   DIR diff --git a/src/cmd/upas/q/runq.c b/src/cmd/upas/q/runq.c
       t@@ -513,7 +513,7 @@ dofile(Dir *dp)
                        if(wm->msg[0]){
                                if(debug)
                                        fprint(2, "[%d] wm->msg == %s\n", getpid(), wm->msg);
       -                        if(!Rflag && strstr(wm->msg, "Retry")==0){
       +                        if(!Rflag && atoi(wm->msg) != RetryCode){
                                        /* return the message and remove it */
                                        if(returnmail(av, dp->name, wm->msg) != 0)
                                                logit("returnmail failed", dp->name, av);
   DIR diff --git a/src/cmd/upas/send/message.c b/src/cmd/upas/send/message.c
       t@@ -2,7 +2,7 @@
        #include "send.h"
        
        #include "../smtp/smtp.h"
       -#include "../smtp/y.tab.h"
       +#include "../smtp/rfc822.tab.h"
        
        /* global to this file */
        static Reprog *rfprog;
   DIR diff --git a/src/cmd/upas/send/rewrite.c b/src/cmd/upas/send/rewrite.c
       t@@ -301,6 +301,7 @@ substitute(String *source, Resub *subexp, message *mp)
                                sp = getrcvar(sp+1, &s);
                                s_append(stp, s);
                                free(s);
       +                        sp--;        /* counter sp++ below */
                        } else
                                s_putc(stp, *sp);
                        sp++;
   DIR diff --git a/src/cmd/upas/smtp/greylist.c b/src/cmd/upas/smtp/greylist.c
       t@@ -241,7 +241,6 @@ isrcptrecent(char *rcpt)
        void
        vfysenderhostok(void)
        {
       -        char *fqdn;
                int recent = 0;
                Link *l;
        
       t@@ -258,7 +257,7 @@ vfysenderhostok(void)
        
                        if (fd >= 0) {
                                seek(fd, 0, 2);                        /* paranoia */
       -                        fprint(fd, "# %s\n%s\n\n", fqdn, nci->rsys);
       +                        fprint(fd, "# unknown\n%s\n\n", nci->rsys);
                                close(fd);
                        }
                } else {
   DIR diff --git a/src/cmd/upas/smtp/mxdial.c b/src/cmd/upas/smtp/mxdial.c
       t@@ -22,7 +22,6 @@ Ndb *db;
        extern int debug;
        
        static int        mxlookup(DS*, char*);
       -static int        mxlookup1(DS*, char*);
        static int        compar(const void*, const void*);
        static int        callmx(DS*, char*, char*);
        static void expand_meta(DS *ds);
       t@@ -113,83 +112,28 @@ callmx(DS *ds, char *dest, char *domain)
        }
        
        /*
       - *  call the dns process and have it try to resolve the mx request
       - *
       - *  this routine knows about the firewall and tries inside and outside
       - *  dns's seperately.
       + *  use dns to resolve the mx request
         */
        static int
        mxlookup(DS *ds, char *domain)
        {
       -        int n;
       -
       -        /* just in case we find no domain name */
       -        strcpy(domain, ds->host);
       -
       -        if(ds->netdir){
       -                n = mxlookup1(ds, domain);
       -        } else {
       -                ds->netdir = "/net";
       -                n = mxlookup1(ds, domain);
       -                if(n == 0) {
       -                        ds->netdir = "/net.alt";
       -                        n = mxlookup1(ds, domain);
       -                }
       -        }
       -
       -        return n;
       -}
       -
       -static int
       -mxlookup1(DS *ds, char *domain)
       -{
       -        char buf[1024];
       -        char dnsname[Maxstring];
       -        char *fields[4];
       -        int i, n, fd, nmx;
       -
       -        snprint(dnsname, sizeof dnsname, "%s/dns", ds->netdir);
       -
       -        fd = open(dnsname, ORDWR);
       -        if(fd < 0)
       -                return 0;
       -
       +        int i, n, nmx;
       +        Ndbtuple *t, *tmx, *tpref, *tip;
       +        
       +        ds->netdir = "/net";
                nmx = 0;
       -        snprint(buf, sizeof(buf), "%s mx", ds->host);
       -        if(debug)
       -                fprint(2, "sending %s '%s'\n", dnsname, buf);
       -        n = write(fd, buf, strlen(buf));
       -        if(n < 0){
       -                rerrstr(buf, sizeof buf);
       -                if(debug)
       -                        fprint(2, "dns: %s\n", buf);
       -                if(strstr(buf, "dns failure")){
       -                        /* if dns fails for the mx lookup, we have to stop */
       -                        close(fd);
       -                        return -1;
       +        if((t = dnsquery(nil, ds->host, "mx")) != nil){
       +                for(tmx=t; (tmx=ndbfindattr(tmx->entry, nil, "mx")) != nil && nmx<Nmx; ){
       +                        for(tpref=tmx->line; tpref != tmx; tpref=tmx->line){
       +                                if(strcmp(tpref->attr, "pref") == 0){
       +                                        strncpy(mx[nmx].host, tmx->val, sizeof(mx[n].host)-1);
       +                                        mx[nmx].pref = atoi(tpref->val);
       +                                        nmx++;
       +                                        break;
       +                                }
       +                        }        
                        }
       -        } else {
       -                /*
       -                 *  get any mx entries
       -                 */
       -                seek(fd, 0, 0);
       -                while(nmx < Nmx && (n = read(fd, buf, sizeof(buf)-1)) > 0){
       -                        buf[n] = 0;
       -                        if(debug)
       -                                fprint(2, "dns mx: %s\n", buf);
       -                        n = getfields(buf, fields, 4, 1, " \t");
       -                        if(n < 4)
       -                                continue;
       -
       -                        if(strchr(domain, '.') == 0)
       -                                strcpy(domain, fields[0]);
       -
       -                        strncpy(mx[nmx].host, fields[3], sizeof(mx[n].host)-1);
       -                        mx[nmx].pref = atoi(fields[2]);
       -                        nmx++;
       -                }
       -                if(debug)
       -                        fprint(2, "dns mx; got %d entries\n", nmx);
       +                ndbfree(t);
                }
        
                /*
       t@@ -210,20 +154,16 @@ mxlookup1(DS *ds, char *domain)
                 * look up all ip addresses
                 */
                for(i = 0; i < nmx; i++){
       -                seek(fd, 0, 0);
       -                snprint(buf, sizeof buf, "%s ip", mx[i].host);
       -                mx[i].ip[0] = 0;
       -                if(write(fd, buf, strlen(buf)) < 0)
       +                if((t = dnsquery(nil, mx[i].host, "ip")) == nil)
                                goto no;
       -                seek(fd, 0, 0);
       -                if((n = read(fd, buf, sizeof buf-1)) < 0)
       +                if((tip = ndbfindattr(t, nil, "ip")) == nil){
       +                        ndbfree(t);
                                goto no;
       -                buf[n] = 0;
       -                if(getfields(buf, fields, 4, 1, " \t") < 3)
       -                        goto no;
       -                strncpy(mx[i].ip, fields[2], sizeof(mx[i].ip)-1);
       +                }
       +                strncpy(mx[i].ip, tip->val, sizeof(mx[i].ip)-1);
       +                ndbfree(t);
                        continue;
       -
       +        
                no:
                        /* remove mx[i] and go around again */
                        nmx--;
       t@@ -274,74 +214,17 @@ dial_string_parse(char *str, DS *ds)
                        expand_meta(ds);
        }
        
       -#if 0 /* jpc */
       -static void
       -expand_meta(DS *ds)
       -{
       -        char buf[128], cs[128], *net, *p;
       -        int fd, n;
       -
       -        net = ds->netdir;
       -        if(!net)
       -                net = "/net";
       -
       -        if(debug)
       -                fprint(2, "expanding %s!%s\n", net, ds->host);
       -        snprint(cs, sizeof(cs), "%s/cs", net);
       -        if((fd = open(cs, ORDWR)) == -1){
       -                if(debug)
       -                        fprint(2, "open %s: %r\n", cs);
       -                syslog(0, "smtp", "cannot open %s: %r", cs);
       -                return;
       -        }
       -
       -        snprint(buf, sizeof(buf), "!ipinfo %s", ds->host+1);        // +1 to skip $
       -        if(write(fd, buf, strlen(buf)) <= 0){
       -                if(debug)
       -                        fprint(2, "write %s: %r\n", cs);
       -                syslog(0, "smtp", "%s to %s - write failed: %r", buf, cs);
       -                close(fd);
       -                return;
       -        }
       -
       -        seek(fd, 0, 0);
       -        if((n = read(fd, ds->expand, sizeof(ds->expand)-1)) < 0){
       -                if(debug)
       -                        fprint(2, "read %s: %r\n", cs);
       -                syslog(0, "smtp", "%s - read failed: %r", cs);
       -                close(fd);
       -                return;
       -        }
       -        close(fd);
       -
       -        ds->expand[n] = 0;
       -        if((p = strchr(ds->expand, '=')) == nil){
       -                if(debug)
       -                        fprint(2, "response %s: %s\n", cs, ds->expand);
       -                syslog(0, "smtp", "%q from %s - bad response: %r", ds->expand, cs);
       -                return;
       -        }
       -        ds->host = p+1;
       -
       -        /* take only first one returned (quasi-bug) */
       -        if((p = strchr(ds->host, ' ')) != nil)
       -                *p = 0;
       -}
       -#endif /* jpc */
       -
       -/* XXX */
        static void
        expand_meta(DS *ds)
        {
       -        Ndb *db;
       +        static Ndb *db;
                Ndbs s;
                char *sys, *smtpserver;
        
       +        /* can't ask cs, so query database directly. */
                sys = sysname();
       -        db = ndbopen(unsharp("#9/ndb/local"));
       -        fprint(2,"%s",ds->host);
       +        if(db == nil)
       +                db = ndbopen(0);
                smtpserver = ndbgetvalue(db, &s, "sys", sys, "smtp", nil);
       -        snprint(ds->host,128,"%s",smtpserver);
       -        fprint(2," exanded to %s\n",ds->host);
       -
       +        snprint(ds->host, 128, "%s", smtpserver);
        }
   DIR diff --git a/src/cmd/upas/smtp/rfc822.tab.h b/src/cmd/upas/smtp/rfc822.tab.h
       t@@ -1,98 +1,25 @@
       -/* A Bison parser, made by GNU Bison 2.0.  */
       -
       -/* Skeleton parser for Yacc-like parsing with Bison,
       -   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
       -
       -   This program is free software; you can redistribute it and/or modify
       -   it under the terms of the GNU General Public License as published by
       -   the Free Software Foundation; either version 2, or (at your option)
       -   any later version.
       -
       -   This program is distributed in the hope that it will be useful,
       -   but WITHOUT ANY WARRANTY; without even the implied warranty of
       -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       -   GNU General Public License for more details.
       -
       -   You should have received a copy of the GNU General Public License
       -   along with this program; if not, write to the Free Software
       -   Foundation, Inc., 59 Temple Place - Suite 330,
       -   Boston, MA 02111-1307, USA.  */
       -
       -/* As a special exception, when this file is copied by Bison into a
       -   Bison output file, you may use that output file without restriction.
       -   This special exception was added by the Free Software Foundation
       -   in version 1.24 of Bison.  */
       -
       -/* Tokens.  */
       -#ifndef YYTOKENTYPE
       -# define YYTOKENTYPE
       -   /* Put the tokens into the symbol table, so that GDB and other debuggers
       -      know about them.  */
       -   enum yytokentype {
       -     WORD = 258,
       -     DATE = 259,
       -     RESENT_DATE = 260,
       -     RETURN_PATH = 261,
       -     FROM = 262,
       -     SENDER = 263,
       -     REPLY_TO = 264,
       -     RESENT_FROM = 265,
       -     RESENT_SENDER = 266,
       -     RESENT_REPLY_TO = 267,
       -     SUBJECT = 268,
       -     TO = 269,
       -     CC = 270,
       -     BCC = 271,
       -     RESENT_TO = 272,
       -     RESENT_CC = 273,
       -     RESENT_BCC = 274,
       -     REMOTE = 275,
       -     PRECEDENCE = 276,
       -     MIMEVERSION = 277,
       -     CONTENTTYPE = 278,
       -     MESSAGEID = 279,
       -     RECEIVED = 280,
       -     MAILER = 281,
       -     BADTOKEN = 282
       -   };
       -#endif
       -#define WORD 258
       -#define DATE 259
       -#define RESENT_DATE 260
       -#define RETURN_PATH 261
       -#define FROM 262
       -#define SENDER 263
       -#define REPLY_TO 264
       -#define RESENT_FROM 265
       -#define RESENT_SENDER 266
       -#define RESENT_REPLY_TO 267
       -#define SUBJECT 268
       -#define TO 269
       -#define CC 270
       -#define BCC 271
       -#define RESENT_TO 272
       -#define RESENT_CC 273
       -#define RESENT_BCC 274
       -#define REMOTE 275
       -#define PRECEDENCE 276
       -#define MIMEVERSION 277
       -#define CONTENTTYPE 278
       -#define MESSAGEID 279
       -#define RECEIVED 280
       -#define MAILER 281
       -#define BADTOKEN 282
       -
       -
       -
       -
       -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
       -typedef int YYSTYPE;
       -# define yystype YYSTYPE /* obsolescent; will be withdrawn */
       -# define YYSTYPE_IS_DECLARED 1
       -# define YYSTYPE_IS_TRIVIAL 1
       -#endif
       -
       -extern YYSTYPE yylval;
       -
       -
       -
       +#define        WORD        57346
       +#define        DATE        57347
       +#define        RESENT_DATE        57348
       +#define        RETURN_PATH        57349
       +#define        FROM        57350
       +#define        SENDER        57351
       +#define        REPLY_TO        57352
       +#define        RESENT_FROM        57353
       +#define        RESENT_SENDER        57354
       +#define        RESENT_REPLY_TO        57355
       +#define        SUBJECT        57356
       +#define        TO        57357
       +#define        CC        57358
       +#define        BCC        57359
       +#define        RESENT_TO        57360
       +#define        RESENT_CC        57361
       +#define        RESENT_BCC        57362
       +#define        REMOTE        57363
       +#define        PRECEDENCE        57364
       +#define        MIMEVERSION        57365
       +#define        CONTENTTYPE        57366
       +#define        MESSAGEID        57367
       +#define        RECEIVED        57368
       +#define        MAILER        57369
       +#define        BADTOKEN        57370
   DIR diff --git a/src/cmd/upas/smtp/smtp.c b/src/cmd/upas/smtp/smtp.c
       t@@ -5,6 +5,7 @@
        #include <libsec.h>
        #include <auth.h>
        #include <ndb.h>
       +#include <thread.h>
        
        static        char*        connect(char*);
        static        char*        dotls(char*);
       t@@ -59,7 +60,7 @@ void
        usage(void)
        {
                fprint(2, "usage: smtp [-adips] [-uuser] [-hhost] [.domain] net!host[!service] sender rcpt-list\n");
       -        exits(Giveup); 
       +        threadexitsall(Giveup); 
        }
        
        int
       t@@ -70,17 +71,16 @@ timeout(void *x, char *msg)
                if(strstr(msg, "alarm")){
                        fprint(2, "smtp timeout: connection to %s timed out\n", farend);
                        if(quitting)
       -                        exits(quitrv);
       -                exits(Retry);
       +                        threadexitsall(quitrv);
       +                threadexitsall(Retry);
                }
                if(strstr(msg, "closed pipe")){
       -                        /* call _exits() to prevent Bio from trying to flush closed pipe */
                        fprint(2, "smtp timeout: connection closed to %s\n", farend);
                        if(quitting){
                                syslog(0, "smtp.fail", "closed pipe to %s", farend);
       -                        _exits(quitrv);
       +                        threadexitsall(quitrv);
                        }
       -                _exits(Retry);
       +                threadexitsall(Retry);
                }
                return 0;
        }
       t@@ -96,6 +96,14 @@ removenewline(char *p)
                        p[n] = 0;
        }
        
       +int
       +exitcode(char *s)
       +{
       +        if(strstr(s, "Retry"))        /* known to runq */
       +                return RetryCode;
       +        return 1;
       +}
       +
        void
        threadmain(int argc, char **argv)
        {
       t@@ -171,7 +179,7 @@ threadmain(int argc, char **argv)
                if(*argv == 0)
                        usage();
                addr = *argv++; argc--;
       -        // expand $smtp if necessary XXX
       +        // expand $smtp if necessary
                addr = expand_addr(addr);
                farend = addr;
        
       t@@ -199,12 +207,12 @@ threadmain(int argc, char **argv)
                        rv = data(from, &bfile);
                        if(rv != 0)
                                goto error;
       -                exits(0);
       +                threadexitsall(0);
                }
        
                /* mxdial uses its own timeout handler */
                if((rv = connect(addr)) != 0)
       -                exits(rv);
       +                threadexitsall(rv);
        
                /* 10 minutes to get through the initial handshake */
                atnotify(timeout, 1);
       t@@ -238,7 +246,7 @@ threadmain(int argc, char **argv)
        
                if(ping){
                        quit(0);
       -                exits(0);
       +                threadexitsall(0);
                }
        
                rv = data(from, &bfile);
       t@@ -246,7 +254,7 @@ threadmain(int argc, char **argv)
                        goto error;
                quit(0);
                if(rcvrs == ok)
       -                exits(0);
       +                threadexitsall(0);
        
                /*
                 *  here when some but not all rcvrs failed
       t@@ -258,7 +266,7 @@ threadmain(int argc, char **argv)
                                fprint(2, "  mail to %s failed: %s", argv[i], errs[i]);
                        }
                }
       -        exits(Giveup);
       +        threadexitsall(Giveup);
        
                /*
                 *  here when all rcvrs failed
       t@@ -271,7 +279,7 @@ error:
                fprint(2, "%s connect to %s:\n%s\n", thedate(), addr, s_to_c(reply));
                if(!filter)
                        quit(rv);
       -        exits(rv);
       +        threadexitsall(rv);
        }
        
        /*
       t@@ -319,6 +327,8 @@ dotls(char *me)
                int fd;
                uchar hash[SHA1dlen];
        
       +        return Giveup;
       +
                c = mallocz(sizeof(*c), 1);        /* Note: not freed on success */
                if (c == nil)
                        return Giveup;
       t@@ -1097,27 +1107,44 @@ dBputc(int x)
                return Bputc(&bout, x);
        }
        
       -/* XXX */
        char* 
       -expand_addr(char* a)
       +expand_addr(char *addr)
        {
       +        static char buf[256];
       +        char *p, *q, *name, *sys;
       +        Ndbtuple *t;
                Ndb *db;
       -        Ndbs s;
       -        char *sys, *ret, *proto, *host;
       -
       -        proto = strtok(a,"!");
       -        if ( strcmp(proto,"net") != 0 ) {
       -                fprint(2,"unknown proto %s\n",proto);
       +        
       +        p = strchr(addr, '!');
       +        if(p){
       +                q = strchr(p+1, '!');
       +                name = p+1;
       +        }else{
       +                name = addr;
       +                q = nil;
                }
       -        host = strtok(0,"!");
       -        if ( strcmp(host,"$smtp") == 0 ) {
       -                sys = sysname();
       -                db = ndbopen(unsharp("#9/ndb/local"));
       -                host = ndbgetvalue(db, &s, "sys", sys, "smtp", nil);
       -        }
       -        ret = malloc(strlen(proto)+strlen(host)+2);
       -        sprint(ret,"%s!%s",proto,host);
       -
       -        return ret;
        
       +        if(name[0] != '$')
       +                return addr;
       +        name++;
       +        if(q)
       +                *q = 0;
       +                
       +        sys = sysname();
       +        db = ndbopen(0);
       +        t = ndbipinfo(db, "sys", sys, &name, 1);
       +        if(t == nil){
       +                ndbclose(db);
       +                if(q)
       +                        *q = '!';
       +                return addr;
       +        }
       +        
       +        *(name-1) = 0;
       +        if(q)
       +                *q = '!';
       +        else
       +                q = "";
       +        snprint(buf, sizeof buf, "%s%s%s", addr, t->val, q);
       +        return buf;
        }
   DIR diff --git a/src/cmd/upas/smtp/smtpd.c b/src/cmd/upas/smtp/smtpd.c
       t@@ -7,6 +7,7 @@
        #include <mp.h>
        #include <libsec.h>
        #include <auth.h>
       +#include <thread.h>
        #include "../smtp/rfc822.tab.h"
        
        #define DBGMX 1
       t@@ -84,11 +85,11 @@ s_error(char *f, char *status)
                else
                        reply("452 out of memory %s\r\n", errbuf);
                syslog(0, "smtpd", "++Malloc failure %s [%s]", him, nci->rsys);
       -        exits(status);
       +        threadexitsall(status);
        }
        
        void
       -main(int argc, char **argv)
       +threadmain(int argc, char **argv)
        {
                char *p, buf[1024];
                char *netdir;
       t@@ -137,6 +138,8 @@ main(int argc, char **argv)
                        passwordinclear = 1;
                        break;
                case 'c':
       +                fprint(2, "tls is not available\n");
       +                threadexitsall("no tls");
                        tlscert = ARGF();
                        break;
                case 't':
       t@@ -145,7 +148,7 @@ main(int argc, char **argv)
                        break;
                default:
                        fprint(2, "usage: smtpd [-dfhrs] [-n net] [-c cert]\n");
       -                exits("usage");
       +                threadexitsall("usage");
                }ARGEND;
        
                nci = getnetconninfo(netdir, 0);
       t@@ -179,7 +182,7 @@ main(int argc, char **argv)
                atnotify(catchalarm, 1);
                alarm(45*60*1000);
                zzparse();
       -        exits(0);
       +        threadexitsall(0);
        }
        
        void
       t@@ -276,7 +279,7 @@ hello(String *himp, int extended)
                                        syslog(0, "smtpd", "Hung up on %s; claimed to be %s",
                                                nci->rsys, him);
                                        reply("554 Liar!\r\n");
       -                                exits("client pretended to be us");
       +                                threadexitsall("client pretended to be us");
                                        return;
                                }
                        }
       t@@ -533,7 +536,7 @@ quit(void)
        {
                reply("221 Successful termination\r\n");
                close(0);
       -        exits(0);
       +        threadexitsall(0);
        }
        
        void
       t@@ -1063,6 +1066,7 @@ sendermxcheck(void)
                char *who;
                int pid;
                Waitmsg *w;
       +        static char *validate;
        
                who = s_to_c(senders.first->p);
                if(strcmp(who, "/dev/null") == 0){
       t@@ -1074,7 +1078,9 @@ sendermxcheck(void)
                        return 0;
                }
        
       -        if(access("/mail/lib/validatesender", AEXEC) < 0)
       +        if(validate == nil)
       +                validate = unsharp("#9/mail/lib/validatesender");
       +        if(access(validate, AEXEC) < 0)
                        return 0;
        
                senddom = strdup(who);
       t@@ -1095,9 +1101,9 @@ sendermxcheck(void)
                         * Could add an option with the remote IP address
                         * to allow validatesender to implement SPF eventually.
                         */
       -                execl("/mail/lib/validatesender", "validatesender", 
       +                execl(validate, "validatesender", 
                                "-n", nci->root, senddom, user, nil);
       -                _exits("exec validatesender: %r");
       +                threadexitsall("exec validatesender: %r");
                default:
                        break;
                }
       t@@ -1265,7 +1271,7 @@ rejectcheck(void)
                if(rejectcount > MAXREJECTS){
                        syslog(0, "smtpd", "Rejected (%s/%s)", him, nci->rsys);
                        reply("554 too many errors.  transaction failed.\r\n");
       -                exits("errcount");
       +                threadexitsall("errcount");
                }
                if(hardreject){
                        rejectcount++;
       t@@ -1344,7 +1350,7 @@ starttls(void)
                        /* force the client to hang up */
                        close(Bfildes(&bin));                /* probably fd 0 */
                        close(1);
       -                exits("tls failed");
       +                threadexitsall("tls failed");
                }
                Bterm(&bin);
                Binit(&bin, fd, OREAD);