Logo Search packages:      
Sourcecode: zmailer version File versions  Download package

shliaise.c

/*
 *    Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
 *    This will be free software, but only when it is finished.
 */

#include "hostenv.h"
#include "mailer.h"

#include "prototypes.h"

conscell **return_valuep = NULL;
conscell *s_value        = NULL;

int
l_apply(fname, l)
      const char *fname;
      conscell *l;
{
      int retval;
      conscell *retvp = NULL;
      conscell **oretvp = return_valuep;
      GCVARS2;

      GCPRO2(l, retvp);

      return_valuep = &retvp;

      retval = lapply(fname, l);
      s_value = retvp;

      return_valuep = oretvp;
      UNGCPRO2;
      return retval;
}


int
s_apply(argc, argv)
      int argc;
      const char *argv[];
{
      int retval;
      conscell *retvp = NULL;
      conscell **oretvp = return_valuep;
      GCVARS1;

      GCPRO1(retvp);

      return_valuep = &retvp;

      retval = apply(argc, argv);
      s_value = retvp;
      return_valuep = oretvp;
      UNGCPRO1;
      return retval;
}

int
n_apply(cpp, argc, argv)
      int argc;
      char **cpp;
      const char *argv[];
{
      int retval;

      sb_external(FILENO(stdout));  /* set up for retrieval of stdout */
      retval = apply(argc, argv);
      *cpp = sb_retrieve(FILENO(stdout)); /* safe alloc'ed memory */
      return retval;
}

/*
 * Call func with tokenlist t as the argument.
 * This is used to rewrite an address.
 */

static int s_rewrite __((const char *func, token822 *t,
                   const char *sender, const char *argx));

static int
s_rewrite(func, t, sender, argx)
      const char *func, *sender, *argx;
      token822 *t;
{
      register char *cp, *bp;
      const char *av[4];
      char *buf = malloc(4000);
      int bufspc = 4000;
      int rc;

      if (t == NULL)
            return 0;
      cp = buf;
      cp += printdToken(&buf, &bufspc, t, (token822 *)NULL, 0);
      /* Was it a quote-containing string ?  If so, strip the quotes,
         and undo back-slash quoting */
      if (t->t_next == NULL && t->t_type == String && buf[0] == '"') {
            *(cp-1) = '\0';
            cp = buf + 1;
            bp = buf;
            for (bp = buf, cp = buf + 1 ; *cp != '\0' ; ++cp) {
                  if (*cp == '\\' && *(cp+1) != '\0')
                        *bp++ = *++cp;
                  else
                        *bp++ = *cp;
            }
            *bp = '\0';
      }

      /* shell interface - we want stdout to show up here */
      av[0] = func;
      av[1] = buf;
      av[2] = argx;
      av[3] = NULL;
      rc = s_apply(argx == NULL ? 2 : 3, av);
      free(buf);
      return rc;
}


/*
 * The transformed message header addresses must be merged with their
 * original format (including comments, etc). We want to change the 'look'
 * of a message header address as little as possible, so we merge the new
 * pure address with the old version. RFC822 mumbles something about all
 * addresses being transmitted in a canonical format (without comments
 * embedded in route-addr's for example), but since we aren't generating
 * anything the original UA wouldn't generate, that requirement is blithely
 * ignored.
 */

static struct addr *mergeAddress __((struct addr *pp, token822 *t));

static struct addr *
mergeAddress(pp, t)
      struct addr *pp;
      token822 *t;
{
      struct addr *ppp, *npp, *fpp;
      token822 *nt, *pt;

      pt = NULL;
      for (ppp = fpp = NULL; pp != NULL; pp = pp->p_next, ppp = npp) {
            npp = (struct addr *)tmalloc(sizeof (struct addr));
            if (ppp != NULL)
                  ppp->p_next = npp;
            else
                  fpp = npp;
            if (pp->p_type != anAddress) {
                  /* copy non-address portions unchanged */
                  *npp = *pp;
            } else if (t != NULL) {
                  /* copy the same number of tokens as was there */
                  /* ... this is not terribly sophisticated ... */
                  npp->p_type = anAddress;
                  npp->p_tokens = t;
                  for (nt = pp->p_tokens; nt != NULL && t != NULL;
                                    nt = nt->t_next, t = t->t_next)
                        pt = t;
                  if (t != NULL)
                        pt->t_next = NULL;
            }
            npp->p_next = NULL;
      }
      if (t != NULL && pt != NULL)
            pt->t_next = t;
      return fpp;
}

/*
 * Rewrite a header nicely...
 */

struct header *
hdr_rewrite(name, h)
      const char *name;
      struct header *h;
{
      register struct address *ap;
      register struct addr *pp;
      register token822 *t;
      struct address *nap = NULL, *pap;
      token822 *nt, *pt, *addrtokens;
      struct header *nh;
      const char *cp, *eocp;
      char *s, buf[4096], *eobuf;   /* XX */

      eobuf = buf + sizeof(buf)-1;

      if (D_hdr_rewrite) {
            printf("---------------------------\n");
            printf("Sending this through %s:\n", name);
            dumpHeader(h);
      }
      nh = (struct header *)tmalloc(sizeof (struct header));
      *nh = *h;
      nh->h_contents.a = NULL;
      nh->h_next = NULL;
      pap = NULL; /* shut up lint */
      for (ap = h->h_contents.a; ap != NULL; ap = ap->a_next) {
            addrtokens = NULL;
            pt = NULL;
            for (pp = ap->a_tokens; pp != NULL; pp = pp->p_next) {
                  if (pp->p_type != anAddress)
                        continue;
                  for (t = pp->p_tokens; t != NULL; t = t->t_next) {
                        nt = copyToken(t);
                        if (pt != NULL)
                              pt->t_next = nt;
                        pt = nt;
                        if (addrtokens == NULL)
                              addrtokens = nt;
                  }
            }
            if (addrtokens != NULL
                && addrtokens->t_next == NULL
                && addrtokens->t_type == String) {
                  eocp = addrtokens->t_pname + TOKENLEN(addrtokens);
                  for (cp = addrtokens->t_pname, s=buf; cp < eocp; ++cp) {
                        if (*cp == '\\' && cp < eocp - 1 && *(cp+1) == '"')
                              continue;
                        if (s < eobuf)
                          *s++ = *cp;
                  }
                  *s = 0;
                  addrtokens->t_pname = strsave(buf);
            }
            nap = (struct address *)tmalloc(sizeof (struct address));
            nap->a_pname = NULL;
            nap->a_stamp = newAddress;
            nap->a_tokens = NULL;
            /* don't bother initializing a_uid/a_mode here, no use */
            nap->a_next = NULL;
            nap->a_dsn  = NULL;
            deferit = 0;
            v_set(DEFER, "");
            /*
             * Header rewrite routines "intramachine", "null", and
             * "internet" in script  crossbar.cf  can take header
             * name (for debug purposes).
             */
            if (addrtokens == NULL)
                  s_value = NULL;
            else if (s_rewrite(name, addrtokens, NULL, h->h_pname) != 0) {
                  if (s_value != NULL) {
                    /* s_free_tree(s_value); */
                    s_value = NULL;
                  }
                  if (deferit
                      && s_rewrite(DEFERHDR, addrtokens, NULL, h->h_pname)
                      && s_value != NULL) {
                    /* s_free_tree(s_value); */
                    s_value = NULL;
                  }
            }
            if (s_value != NULL
                && (LIST(s_value) || *(s_value->string) == '\0')) {
              /* s_free_tree(s_value); */
              s_value = NULL;
            }
            if (s_value == NULL) {
                  /* copy this address unchanged */
                  nap->a_tokens = ap->a_tokens;
            } else {
                  /* integrate result with original address form */

                  const char *cs = s_value->cstring;
                  char *s;
                  memtypes osticky = stickymem;
                  stickymem = MEM_TEMP;

                  /* This really does need long-term storage! */
                  s = tmalloc(strlen(cs)+1);
                  strcpy(s, cs);
                  /* t = HDR_SCANNER(cs); */
                  t = scan822((const char**)&s, strlen(s),
                            '!', '%', 0, &ap->a_tokens->p_tokens);

                  stickymem = osticky;

                  /* X: check for errors! */
                  nap->a_tokens = mergeAddress(ap->a_tokens, t);
            }
            if (nh->h_contents.a == NULL)
                  nh->h_contents.a = nap;
            else
                  pap->a_next = nap;
            pap = nap;
      }
      if (D_hdr_rewrite) {
            printf("Resulting in this header:\n");
            dumpHeader(nh);
            hdr_print(nh, stdout);
      }
      return nh;
}

void
setenvinfo(e)
      struct envelope *e;
{
      struct header *h;
      conscell *pl, *plhead;
      char buf[20];
      GCVARS1;
      int slen;

      /* include header size ("headersize"), message size ("size"),
         message body size ("bodysize"), now ("now"), resent ("resent")
         trusted ("trusted"), message file name ("file"), message id
         ("message-id") */

#define     CONSTSTR(s) slen = strlen(s); cdr(pl) = conststring(s, slen); pl = cdr(pl)
#define     NEWSTR(s)   slen = strlen(s); cdr(pl) = newstring(s, slen);   pl = cdr(pl)
#define     NEWDUPSTR(s)      slen = strlen(s); cdr(pl) = newstring(dupnstr(s, slen), slen);   pl = cdr(pl)
#define     NEWSTRD(d)  sprintf(buf, "%ld", (long)(d)); NEWDUPSTR(buf)

      pl = plhead = conststring("file", 4);
      GCPRO1(plhead);

      CONSTSTR(e->e_file);

      if (e->e_messageid != NULL) {
            CONSTSTR("message-id");
            CONSTSTR(e->e_messageid);
      }

      CONSTSTR("uid");
      NEWSTRD(e->e_statbuf.st_uid);

      CONSTSTR("gid");
      NEWSTRD(e->e_statbuf.st_gid);

      CONSTSTR("size");
      NEWSTRD(e->e_statbuf.st_size - e->e_hdrOffset);

      CONSTSTR("headersize");
      NEWSTRD(e->e_msgOffset - e->e_hdrOffset);

      CONSTSTR("bodysize");
      NEWSTRD(e->e_statbuf.st_size - e->e_msgOffset);

      CONSTSTR("now");
      NEWSTRD(e->e_nowtime);

      CONSTSTR("delay");
      NEWSTRD(e->e_nowtime - e->e_statbuf.st_mtime);

      CONSTSTR("resent");
      CONSTSTR(e->e_resent ? "yes" : "no");

      CONSTSTR("trusted");
      CONSTSTR(e->e_trusted ? "yes" : "no");

      /* for every non-address envelope header, include
         header-name header-value pair in property list */

      for (h = e->e_eHeaders; h != NULL; h = h->h_next) {
            if (h->h_descriptor->user_type != nilUserType)
                  continue;
            CONSTSTR(h->h_descriptor->hdr_name);
            if (h->h_lines == NULL || *h->h_lines->t_pname == '\0') {
                  CONSTSTR(h->h_descriptor->hdr_name);
            } else {
                  CONSTSTR(h->h_lines->t_pname);
            }
      }
      cdr(pl) = NULL;
      plhead = ncons(plhead);
      v_setl("envelopeinfo", plhead);
      UNGCPRO1;
}

static char gsbuf[30];
/*
 *  newattribute_2()
 */
char *newattribute_2(onam,nam,val)
     const char *onam, *nam, *val;
{
      conscell *l, *lc, *tmp, **pl;
      conscell    *l1;
      GCVARS4;
      int slen;

      l1 = v_find(onam);
      if (!l1)
        return NULL;
      l = copycell(cdr(l1));
      lc = tmp = l1 = NULL;
      GCPRO4(l, lc, tmp, l1);

      cdr(l) = NULL;
      car(l) = s_copy_chain(car(l));
      pl = &car(l);
      l1 = *pl;
      for (lc = l1; lc && cdr(lc); pl = &cddr(lc),lc = *pl) {
        if (!STRING(lc)) {
          UNGCPRO4;
          return NULL; /* ?? */
        }
        if (STREQ(nam,lc->string)) {
          if (!cdr(lc)) {
            UNGCPRO4;
            return NULL;
          }
          *pl = cddr(lc) /* Skip this in chain */;
        }
      }

      /* Prepend in reverse order */
      slen = strlen(val);
      tmp = newstring(dupnstr(val, slen), slen);
      cdr(tmp) = car(l);
      car(l) = tmp;
      slen = strlen(nam);
      tmp = newstring(dupnstr(nam, slen), slen);
      cdr(tmp) = car(l);
      car(l) = tmp;

      sprintf(gsbuf, gs_name, gensym++);
      /* gX (name in gsbuf) will be freed by free_gensym() later */
      v_setl(gsbuf, l);
      UNGCPRO4;
      return gsbuf;
}

/*
 * Build gensym
 */
static char  *build_gensym __((int, const char*, const char*, const char*, const char*, const char*, const char*));

static char *
build_gensym(uid, type, DSNstr, DSNret, DSNenv, errorsto, sender)
     int uid;
     const char *type, *DSNstr, *DSNret, *DSNenv, *errorsto, *sender;
{
      char buf[20];
      conscell *l, *pl;
      GCVARS1;
      int slen;

      /* assemble the default attribute list: (privilege <uid>) */
      l = conststring("privilege", 9);
      GCPRO1(l);
      sprintf(buf, "%d", uid);
      pl = l;
      NEWDUPSTR(buf);
      if (type) {
            CONSTSTR("type");
            CONSTSTR(type); /* Always a constant string */
      }
      if (DSNstr) {
            CONSTSTR("DSN");
            NEWDUPSTR(DSNstr);
      }
      if (DSNret) {
            CONSTSTR("DSNr");
            NEWDUPSTR(DSNret);
      }
      if (DSNenv) {
            CONSTSTR("DSNe");
            NEWDUPSTR(DSNenv);
      }
      /* See if some "errorsto" definition is available.. */
      if (errorsto) {
            CONSTSTR("ERR");
            NEWDUPSTR(errorsto);
      }
      /* See if some "sender" definition is available.. */
      if (sender) {
            CONSTSTR("sender");
            NEWDUPSTR(sender);
      }
      cdr(pl) = NULL; /* not needed in reality */
      l = ncons(l);
      sprintf(gsbuf, gs_name, gensym++);
      /* gX (name in gsbuf) will be freed by free_gensym() later */
      v_setl(gsbuf, l);
      UNGCPRO1;
      return gsbuf;
}

/*
 * The router function must return three values,
 *    a (channel, host, user) triple.
 *
 * If we get a deferral while routing, call a deferral
 * function to deal with it.
 */

conscell *
router(a, uid, type, senderstr)
      struct address *a;
      int uid;
      const char *type, *senderstr;
{
      register token822 *t, *tt;
      int r;
      token822 *last;
      struct addr *p;
      conscell *l;
      const char *gsym;
      struct notary *DSN = NULL;
      const char *DSNstr;
      const char *DSNret;
      const char *DSNenv;
      GCVARS1;

      if (a == NULL)
            return NULL;
      t = last = NULL;
      DSN = a->a_dsn;
      DSNstr = DSNret = DSNenv = NULL;
      if (DSN) {
        DSNstr = DSN->dsn;
        DSNret = DSN->ret;
        DSNenv = DSN->envid;
      }
      for (p = a->a_tokens; p != NULL; p = p->p_next)
            if (p->p_type == anAddress) {
                  /* link up all address tokens together */
                  for (tt = p->p_tokens; tt != NULL; tt = tt->t_next) {
                        if (t == NULL) {
                              t = copyToken(tt);
                              last = t;
                        } else {
                              last->t_next = copyToken(tt);
                              last = last->t_next;
                        }
                  }
            }
      if (D_router) {
            printf("Routing:\n");
            for (tt = t; tt != NULL; tt = tt->t_next)
                  printf("\t\t%s\n", formatToken(tt));
      }
      if (t == NULL)
            return NULL;
      if (t->t_pname[0] == '<' && TOKENLEN(t) == 1 && t->t_next == NULL)
            abort();

      gsym = build_gensym(uid, type, DSNstr, DSNret, DSNenv, errors_to, senderstr);

      deferit = 0;
      v_set(DEFER, "");
      r = s_rewrite(ROUTER, t, NULL, gsym);
#if 0
      if (deferit) {
        /* s_free_tree(s_value); */
        s_value = NULL;
        r = s_rewrite(DEFERENV, t, NULL, gsym);
      }
#endif
      if (r != 0 || s_value == NULL || !LIST(s_value)) {
        /* router returned something invalid */
        /* s_free_tree(s_value); */
        s_value = NULL;
        return NULL;
      }

      /*
       * We expect router to either return
       * (local - user attributes) or (((local - user attributes)))
       */
      l = NULL;
      GCPRO1(l);
      if (car(s_value) && LIST(car(s_value))) {
            if (!LIST(caar(s_value)) || !STRING(caaar(s_value))) {
                  fprintf(stderr,
                        "%s: '%s' returned invalid 2-level list: ",
                        progname, ROUTER);
                  s_grind(s_value, stderr);
                  /* s_free_tree(s_value); */
                  s_value = NULL;
                  UNGCPRO1;
                  return NULL;
            }
            l = s_copy_chain(s_value);
      } else {
            l = s_copy_chain(s_value);
            l = ncons(l);
            l = ncons(l);
      }

      /* s_free_tree(s_value); */
      s_value = NULL;
      UNGCPRO1;

      return l;
}

/*
 * Crossbar switch. That's the closest metaphor I can think of that describes
 * what this function actually does --- which is looking at the sender and
 * recipient addresses, or more precisely the (channel, host, user) triples,
 * and munging them both appropriately using whatever criteria it wishes.
 *
 * The crossbar configuration file function should return 7 values, as
 * shown below. The first six are its munged calling parameters, the
 * seventh if non-null is the name of another configuration file function
 * which will be called for munging the message header addresses.
 * The munged parameters will eventually find their way onto the envelopes.
 */

conscell *
crossbar(from, to)
      conscell *from, *to;
{
      conscell *l = NULL;
      GCVARS3;

      GCPRO3(l, from, to);

      l = copycell(from);
      l = ncons(l);

      cdar(l) = to;

      if (l_apply(CROSSBAR, l) != 0 || s_value == NULL) {
        s_value = NULL;
        return NULL;
      }

      /*
       * We expect to see something like
       * (rewrite (fc fh fu) (tc th tu)) or
       * ((address-rewrite header-rewrite) (fc fh fu) (tc th tu))
       * back from the crossbar function.
       */

      l = s_value;
      s_value = NULL;
      UNGCPRO3;

      return l;
}

Generated by  Doxygen 1.6.0   Back to index