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

headers.c

/* Headers.c - Header checking and translation for af.
   Copyright (C) 1996 - 2002 Malc Arnold.

   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., 675 Mass Ave, Cambridge, MA 02139, USA.  */


#include <stdio.h>
#include "af.h"
#include "atom.h"
#include "address.h"
#include "keyseq.h"
#include "functions.h"
#include "variable.h"
#include STRING_HDR

/****************************************************************************/
/* RCS info */

#ifndef lint
static char *RcsId = "$Id: headers.c,v 1.2 2002/08/21 23:54:48 malc Exp $";
#endif /* ! lint */

/****************************************************************************/
/* Global function declarations */

extern char *xrealloc(), *vstrcat();
extern char *get_user(), *get_vtext();
extern char *atext(), *grp_text();
extern char *grp_names();
extern int strcasecmp();
extern void free(), afree(), free_glist();
extern ATOM *tokenise(), *atoken(), *asearch();
extern ATOM *aprev(), *acut(), *adiscard();
extern ATOM *adelete(), *acopy(), *amerge();
extern ATOM *ainsert(), *aappend(), *aquote();
extern GROUP *parse_addrs(), *translate();
extern GROUP *unalias(), *remove_address();

/* Local function declarations */

static char *canon_addrs();
static void add_reference();
static ATOM *parse_refs();
static ATOM *canon_ref();

#ifdef MTA_NEEDS_ARGS
#ifdef MTA_NEEDS_UUCP
static char *uucp_text(), *uucp_route();
static char *uucp_proute();
#endif /* MTA_NEEDS_UUCP */
#endif /* MTA_NEEDS_ARGS */

/****************************************************************************/
/* Import the error flag and text for parsing and address translation */

extern int a_errno;
extern char *a_errtext;

/****************************************************************************/
/* This variable stores the list of names for the address list */

static char *a_realnames = NULL;

/****************************************************************************/
char *alias(addrs)
char *addrs;
{
      /*
       * Form an RFC 822 address list from the string passed in
       * addrs, and return it in a newly-allocated string.
       *
       * All addresses are converted to RFC 822, if not already
       * in that format, and any aliases are expanded.
       */

      return(canon_addrs(addrs, TRUE, AC_TRIM));
}
/****************************************************************************/
char *alias_mailboxes(addrs)
char *addrs;
{
      /*
       * Form an RFC 822 address list from the string passed in
       * addrs, and return it in a newly-allocated string.
       *
       * All addresses are converted to RFC 822, if not already
       * in that format, and any aliases are expanded.  Groups
       * are not valid in the address list.
       */

      return(canon_addrs(addrs, TRUE, AC_ORIGINATOR));
}
/****************************************************************************/
char *canonical(addrs)
char *addrs;
{
      /*
       * Form an RFC 822 address list from the string passed in
       * addrs, and return it in a newly-allocated string.
       * 
       * All addresses are converted to canonical RFC 822, if not
       * already in that format, but aliases are not expanded.
       */

      return(canon_addrs(addrs, FALSE, AC_FULL));
}
/****************************************************************************/
char *mailboxes(addrs)
char *addrs;
{
      /*
       * Form an RFC 822 address list from the string passed in
       * addrs, and return it in a newly-allocated string.
       *
       * All addresses are converted to canonical RFC 822, if not
       * already in that format, but aliases are not expanded,
       * and groups are flattened to a plain address list.
       */

      return(canon_addrs(addrs, FALSE, AC_MAILBOXES));
}
/****************************************************************************/
char *nonnull_groups(addrs)
char *addrs;
{
      /*
       * Form an RFC 822 address list from the string passed in
       * addrs, and return it in a newly-allocated string.
       *
       * All addresses are converted to canonical RFC 822, if not
       * already in that format, but aliases are not expanded,
       * and any empty groups are removed from the list.
       */

      return(canon_addrs(addrs, FALSE, AC_GROUPS));
}
/****************************************************************************/
char *mail_addresses(addrs)
char *addrs;
{
      /*
       * Form an RFC 822 address list from the string passed in
       * addrs, and return it in a newly-allocated string.
       *
       * All addresses are converted to canonical RFC 822, if not
       * already in that format, but aliases are not expanded,
       * groups are flattened and full names are discarded.
       */

      return(canon_addrs(addrs, FALSE, AC_TERSE));
}
/****************************************************************************/
char *local_part(addrs)
char *addrs;
{
      /*
       * Return the local part of the first address in addrs, and
       * return it in a newly-allocated string.
       *
       * The address is converted to canonical RFC 822, if not
       * already in that format, but aliases are not expanded.
       */

      return(canon_addrs(addrs, FALSE, AC_FIRST_LOCAL));
}
/****************************************************************************/
char *subtract_addresses(addrs, ignored)
char *addrs, *ignored;
{
      /*
       * Takes two previously checked and canonicalised address
       * lists and subtracts the second from the first, returning
       * the new addresses in an allocated string.  Assumes that
       * both of the addresses passed are valid.
       */

      char *result = NULL;
      GROUP *glist, *i_glist, *g;
      ADDRESS *grp_addrs, *a;

      /* Tokenise and parse the address lists */

      glist = parse_addrs(aappend(tokenise(addrs), ",", AT_COMMA));
      i_glist = parse_addrs(aappend(tokenise(ignored), ",", AT_COMMA));
      grp_addrs = (glist != NULL) ? glist->addresses : NULL;

      /* Remove all addresses in the ignored group */

      for (g = i_glist; g != NULL; g = g->next) {
            for (a = g->addresses; a != NULL; a = a->next) {
                  glist = remove_address(glist, glist, grp_addrs, a);
            }
      }

      /* Generate the text of the new group */

      result = (glist != NULL) ? grp_text(glist, AC_FULL) : NULL;

      /* Clean up and return the resulting addresses */

      free_glist(glist);
      free_glist(i_glist);
      return(result);
}
/****************************************************************************/
int count_addresses(addrs)
char *addrs;
{
      /* Return the number of addresses specified in addrs */

      int naddrs = 0;
      ATOM *alist;
      GROUP *glist, *g;
      ADDRESS *a;

      /* Tokenise the address list and terminate with a comma */

      if ((alist = tokenise(addrs)) != NULL) {
            alist = aappend(alist, ",", AT_COMMA);
      }

      /* Parse the atom list and convert to RFC 822 */

      if (alist != NULL && (glist = parse_addrs(alist)) != NULL) {
            /* Loop over the available groups looking for addresses */

            for (g = glist; g != NULL; g = g->next) {
                  for (a = g->addresses; a != NULL; a = a->next) {
                        naddrs++;
                  }
            }

            /* And free the group list */

            free_glist(glist);
      }

      /* Return the address count */

      return(naddrs);
}
/****************************************************************************/
char *addrnames()
{
      /* Return the real names of the last addresses parsed */

      return(a_realnames);
}
/****************************************************************************/
char *realname(name)
char *name;
{
      /* Return a string containing name, or NULL if name is invalid */

      char *namebuf;
      ATOM *alist, *qlist, *atom;

      /* Tokenise the name */

      if ((alist = tokenise(name)) == NULL) {
            return(NULL);
      }

      /* Names can only contain white space, atoms or quoted strings */

      for (atom = alist; atom != NULL; atom = atom->next) {
            /* Check if this atom needs quoting */

            if (!IS_WS(atom) && !IS_PHRASE(atom)) {
                  /* Quote the atom list */

                  qlist = aquote(alist);
                  afree(alist);
                  alist = qlist;
                  break;
            }
      }

      /* Build and return the trimmed string */

      namebuf = atext(NULL, alist, AC_TRIM);
      afree(alist);
      return(namebuf);
}
/****************************************************************************/
char *get_addr()
{
      /* Return the user's real mail address in a static buffer */

      static char *addrbuf = NULL;
      char *username, *domain;

      /* If the buffer is set then just return it */

      if (addrbuf != NULL) {
            return(addrbuf);
      }

      /* Get the real user and domain */

      username = get_user();
      domain = get_vtext(V_DOMAIN);

      /* Now build and return the address */

      addrbuf = vstrcat(username, "@", domain, NULL);
      return(addrbuf);
}
/****************************************************************************/
static char *canon_addrs(addrs, aliasing, canon)
char *addrs;
int aliasing, canon;
{
      /*
       * Actually handle address translation, canonicalisation
       * and checking.  Does aliasing if the parameter is TRUE,
       * and uses the canonicalisation level set in canon.
       */

      char *new_addrs = NULL;
      ATOM *alist;
      GROUP *glist;

      /* No real names associated with this list */

      if (a_realnames != NULL) {
            free(a_realnames);
            a_realnames = NULL;
      }

      /* Tokenise the address list and terminate with a comma */

      if ((alist = tokenise(addrs)) != NULL) {
            alist = aappend(alist, ",", AT_COMMA);
      }

      /* Parse the atom list and convert to RFC 822 */

      if (alist != NULL && (glist = parse_addrs(alist)) != NULL) {
            /* Check if groups are valid in the addresses */

            if (canon == AC_ORIGINATOR && glist->name != NULL
                || glist->next != NULL) {
                  /* Group found in originator; set the error */

                  a_errno = AERR_GROUP;
                  if (a_errtext != NULL) {
                        free(a_errtext);
                  }
                  a_errtext = NULL;

                  /* Clean up and return failure */

                  free_glist(glist);
                  return(NULL);
            }

            /* Expand aliases in the addresses if required */

            glist = (aliasing) ? unalias(glist, NULL) : glist;

            /* Translate the addresses to RFC 822 form */

            glist = translate(glist);

            /* Build the new address text and real names */

            new_addrs = grp_text(glist, canon);
            a_realnames = grp_names(glist);

            /* And free the group list */

            free_glist(glist);
      } else if (a_errno == AERR_NONE) {
            /* No addresses in the group */

            a_errno = AERR_NULL;
      }

      /* Return the canonicalised addresses */

      return(new_addrs);
}
/****************************************************************************/
char *references(refs)
char *refs;
{
      /*
       * Return the canonical form of the references given in refs,
       * or NULL if refs does not contain valid references.
       */

      char *rtext;
      ATOM *alist;

      /* Now tokenise and check the references */

      if ((alist = parse_refs(refs, TRUE)) == NULL) {
            /* Error canonicalising refs */

            return(NULL);
      }

      /* Now generate and return the canonical text */

      rtext = atext(NULL, alist, AC_TRIM);
      afree(alist);
      return(rtext);
}
/****************************************************************************/
int extract_references(msg_refs, refs, one_reference)
char **msg_refs, *refs;
int one_reference;
{
      /* 
       * Extract any message IDs in refs, and if the string is
       * valid then copy the canonical forms into the references
       * array, msg_refs.  Returns TRUE on success, or FALSE if
       * the string wasn't valid.
       */

      char *cref;
      int ref_found = FALSE;
      ATOM *alist, *start, *end;

      /* First tokenise and canonicalise the references */

      if ((alist = parse_refs(refs, FALSE)) == NULL) {
            /* Invalid references; return failure */

            return(FALSE);
      }

      /* Loop through the atom list finding references */

      while ((start = asearch(alist, AT_LANGLEB)) != NULL
             && (end = asearch(start, AT_RANGLEB)) != NULL
             && (!ref_found || !one_reference)) {
            /* Cut the reference out of the atom list */

            alist = adelete(alist, alist, start);
            alist = acut(alist, start, end->next);

            /* Form the reference text and add it to the list */

            cref = atext(NULL, start, AC_FULL);
            add_reference(msg_refs, cref, one_reference);
            ref_found = TRUE;
            afree(start);
      }

      /* Free any trailing tokens in alist and return status */

      afree(alist);
      return(ref_found);
}
/****************************************************************************/
static ATOM *parse_refs(refs, strict)
char *refs;
int strict;
{
      /* 
       * Canonicalise the references, returning the canonical atoms
       * for the references, or NULL if they aren't valid.
       */

      ATOM *alist, *atom;

      /* Tokenise the reference string */

      if ((alist = tokenise(refs)) == NULL) {
            return(NULL);
      }

      /* Loop through the list and check the tokens */

      for (atom = alist; atom != NULL; atom = atom->next) {
            /* Now process the atom according to type */

            if (atom->type == AT_LANGLEB) {
                  if ((alist = canon_ref(alist, &atom)) == NULL) {
                        /* Invalid reference; return failure */

                        return(NULL);
                  }
            } else if (strict && !IS_WS(atom) && !IS_PHRASE(atom)) {
                  /* Invalid token; set the error */

                  alist = adelete(alist, atom->next, NULL);
                  a_errno = RERR_TOKEN;
                  if (a_errtext != NULL) {
                        free(a_errtext);
                  }
                  a_errtext = atext(NULL, alist, AC_NONE);

                  /* Clean up and return failure */

                  afree(alist);
                  return(NULL);
            }
      }

      /* Return the canonicalised list */

      return(alist);
}
/****************************************************************************/
static ATOM *canon_ref(alist, atom)
ATOM *alist, **atom;
{
      /* Return the canonical form of a reference */

      char *reftext;
      ATOM *end, *next, *rlist;
      GROUP *glist;

      /* Find the end of the reference */

      if ((end = asearch(*atom, AT_RANGLEB)) == NULL) {
            /* Invalid brackets; set the error and fail */

            a_errno = RERR_BRACKET;
            if (a_errtext != NULL) {
                  free(a_errtext);
                  a_errtext = NULL;
            }
            afree(alist);
            return(NULL);
      }

      /* Extract the reference, followed by a comma, from the list */

      next = end->next;
      alist = acut(alist, *atom, next);
      rlist = aappend(acopy(*atom), ",", AT_COMMA);

      /* Get the canonical form of the reference */

      if ((glist = parse_addrs(rlist)) == NULL) {
            /* Invalid reference; set the error */

            a_errno = RERR_REFERENCE;
            if (a_errtext != NULL) {
                  free(a_errtext);
            }
            a_errtext = atext(NULL, *atom, AC_NONE);

            /* Now clean up and fail */

            afree(alist);
            afree(*atom);
            return(NULL);
      }
      afree(*atom);

      /* Generate the canonical reference text */

      reftext = grp_text(glist, AC_FULL);
      free_glist(glist);

      /* Set up the atom list for the reference */

      rlist = tokenise(reftext);
      rlist = ainsert(rlist, rlist, "<", AT_LANGLEB);
      rlist = aappend(rlist, ">", AT_RANGLEB);
      free(reftext);

      /* And insert the canonical reference into the list */

      alist = amerge(alist, next, rlist);

      /* Update atom and return the list */

      *atom = aprev(alist, next);
      return(alist);
}
/****************************************************************************/
static void add_reference(msg_refs, ref, one_reference)
char **msg_refs, *ref;
int one_reference;
{
      /* Add a reference to the node's references */

      int last, r;

      /* Check if the reference was already defined */

      for (r = 0; r < NO_REFERENCES; r++) {
            /* Check if this reference matches the new one */

            if (msg_refs[r] != NULL && !strcmp(msg_refs[r], ref)) {
                  /* The reference is already defined */

                  free(ref);
                  return;
            }
      }

      /* Which references are we allowed to modify? */

      last = (one_reference || msg_refs[NO_REFERENCES - 1] == NULL)
            ? NO_REFERENCES - 1 : NO_REFERENCES - 2;

      /* Free the oldest reference if set */

      if (msg_refs[0] != NULL) {
            free(msg_refs[0]);
      }

      /* Shift the references as required */

      for (r = 0; r < last; r++) {
            msg_refs[r] = msg_refs[r + 1];
      }

      /* And add the new value to the references */

      msg_refs[last] = ref;
      return;
}
/****************************************************************************/
#ifdef MTA_NEEDS_ARGS
/****************************************************************************/
char **addr_args(args, addrs)
char **args, *addrs;
{
      /* Append each address in addrs to the argument vector args */

      int no_args, no_addrs;
      ATOM *alist;
      GROUP *glist, *g;
      ADDRESS *a;

      /* Tokenise the address list and terminate with a comma */

      if ((alist = tokenise(addrs)) != NULL) {
            alist = aappend(alist, ",", AT_COMMA);
      }

      /* Parse the atom list and convert to RFC 822 */

      if (alist != NULL && (glist = parse_addrs(alist)) != NULL) {
            /* Count the original number of arguments in the vector */

            for (no_args = 0; args[no_args] != NULL; no_args++) {
                  /* NULL LOOP */
            }

            /* Count the number of addresses to be added */

            no_addrs = 0;
            for (g = glist; g != NULL; g = g->next) {
                  for (a = g->addresses; a != NULL; a = a->next) {
                        no_addrs++;
                  }
            }

            /* Reallocate the argument vector */

            args = (char **) xrealloc(args, (no_args + no_addrs + 1)
                                * sizeof(char *));

            /* Now add each address as an argument */

            for (g = glist; g != NULL; g = g->next) {
                  for (a = g->addresses; a != NULL; a = a->next) {
#ifdef MTA_NEEDS_UUCP
                        args[no_args++] = uucp_text(a);
#else /* ! MTA_NEEDS_UUCP */
                        args[no_args++] = addr_text(NULL, a, AC_FULL);
#endif /* ! MTA_NEEDS_UUCP */
                  }
            }

            /* Add the terminating NULL to the vector */

            args[no_args] = NULL;

            /* Free the group list */

            free_glist(glist);
      } else if (a_errno == AERR_NONE) {
            a_errno = AERR_NULL;
      }

      /* Return the modified argument list */

      return(args);
}
/****************************************************************************/
#ifdef MTA_NEEDS_UUCP
/****************************************************************************/
static char *uucp_text(address)
ADDRESS *address;
{
      /* Return an allocated string containing address in UUCP form */

      char *uu_addr = NULL, *domain;

      /* Get the local domain */

      domain = get_vtext(V_DOMAIN);

      /* Prepend any route, switching '@' to '!' */

      uu_addr = uucp_route(uu_addr, address->route);

      /* Set the domain if required */

      uu_addr = atext(uu_addr, address->domain, AC_FULL);
      if (address->proute == NULL && !strcasecmp(uu_addr, domain)) {
            free(uu_addr);
            uu_addr = NULL;
      } else {
            uu_addr = xrealloc(uu_addr, strlen(uu_addr) + 2);
            (void) strcat(uu_addr, "!");
      }

      /* Append any percent route */

      uu_addr = uucp_proute(uu_addr, address->proute);

      /* Append the local-part */

      uu_addr = atext(uu_addr, address->local, AC_FULL);

      /* Return the UUCP address text */

      return(uu_addr);
}
/****************************************************************************/
static char *uucp_route(buf, rt)
char *buf;
ATOM *rt;
{
      /* Append an RFC 822 route in UUCP form to buf */

      ATOM *new_route, *a;

      /* Find the initial '@' */

      if ((a = atoken(rt)) == NULL) {
            return(buf);
      }

      /* Find the first token after the '@' */

      if ((a = atoken(a->next)) == NULL) {
            return(buf);
      }

      /* Make a copy of the route */

      new_route = acopy(a);

      /* Loop through the route replacing @ with ! */

      for (a = new_route; a != NULL; a = a->next) {
            if (a->type == AT_AT) {
                  (void) strcpy(a->text, "!");
            }
      }

      /* Append the canonical text to buf */

      buf = atext(buf, new_route, AC_FULL);

      /* Append a '!' to the route */

      buf = xrealloc(buf, strlen(buf) + 2);
      (void) strcat(buf, "!");

      /* Free the copied route and return */

      afree(new_route);
      return(buf);
}
/****************************************************************************/
static char *uucp_proute(buf, rt)
char *buf;
ATOM *rt;
{
      /* Append an RFC 733 percent route in UUCP form to buf */

      char *domain, *rstr = NULL;
      ATOM *new_route, *a, *pct;

      /* Find the first token after the initial '%' */

      a = asearch(rt, AT_PERCENT);
      a = atoken(a->next);

      /* Make a copy of the route */

      new_route = acopy(a);

      /* Loop through the route prepending each entry */

      a = new_route;
      while (a != NULL) {
            /* Cut out the next domain */

            if ((pct = asearch(a, AT_PERCENT)) != NULL) {
                  a = acut(a, pct, NULL);
            }

            /* Form the canonical name for this address */

            domain = atext(NULL, a, AC_FULL);

            /* Prepend the domain to the route */

            if (rstr == NULL) {
                  domain = xrealloc(domain, strlen(domain) + 2);
                  (void) strcat(domain, "!");
            } else {
                  domain = xrealloc(domain, strlen(domain)
                              + strlen(rstr) + 1);
                  (void) strcat(domain, "!");
                  (void) strcat(domain, rstr);
                  free(rstr);
            }
            rstr = domain;

            /* Free the section of the route we cut out */

            afree(a);

            /* Move a on to the next token */

            a = (pct != NULL) ? adiscard(pct, pct) : NULL;
      }

      /* Append the canonical text to buf */

      if (buf == NULL) {
            buf = rstr;
      } else {
            buf = xrealloc(buf, strlen(buf) + strlen(rstr) + 1);
            (void) strcat(buf, rstr);
            free(rstr);
      }

      /* Return the modified buffer */

      return(buf);
}
/****************************************************************************/
#endif /* MTA_NEEDS_UUCP */
#endif /* MTA_NEEDS_ARGS */
/****************************************************************************/

Generated by  Doxygen 1.6.0   Back to index