home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / ida / aux / xalparse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-12  |  9.2 KB  |  379 lines

  1. /*
  2. **  XALPARSE -- Xaliases file parser.
  3. **  Copyright (c) 1987 Lennart Lovstrand
  4. **  CIS Dept, Univ of Linkoping, Sweden
  5. **
  6. **  Use it, abuse it, but don't sell it.
  7. */
  8.  
  9. #include "sendmail.h"
  10.  
  11. #ifndef lint
  12. static char    rcsid[] = "$Header: /usr/local/src/mail/sendmail/ida/aux/RCS/xalparse.c,v 1.3 1991/07/13 04:40:12 paul Exp $";
  13. #endif /* !lint */
  14.  
  15. struct alias {
  16.   bool a_in, a_out;
  17.   char *a_name;
  18. };
  19.  
  20. #define ANULL    (struct alias *) NULL
  21.  
  22. /*
  23. **  XPARSE -- Parse an xaliases file, producing aliases + generics files.
  24. **
  25. **    This program parses a file in ``xaliases'' format, producing
  26. **    a standard aliases file + a generics file.  The xaliases input
  27. **    file has entry of the following format:
  28. **        generic_list: mbox_list
  29. **    where elements in both lists are separated by commas.  In
  30. **    addition, each element in the mbox_list may be prefixed with
  31. **    either or both of the ``redirection characters,'' "<" and ">".
  32.  
  33. **    In its simplest form, the generic_list has just one member and
  34. **    the mbox_list uses no redirection characters.  This
  35. **    corresponds exactly to the standard aliases format and
  36. **    function.
  37.  
  38. **    The first extention is made by allowing more than one entry on
  39. **    the left hand side, thus making "a, b: c" as shorthand for the
  40. **    two entries "a: c" and "b: c".
  41.  
  42. **    The second extension is made by adding the previously
  43. **    mentioned redirection characters to the addresses on the right
  44. **    hand side.  These control in what direction the aliases should
  45. **    be used.
  46. **
  47. **    etc.
  48. */
  49.  
  50. int iflag = FALSE, Iflag = FALSE, Oflag = FALSE;
  51. static char *routing_host;
  52. static bool translate_generics = FALSE;
  53.  
  54. main(argc, argv)
  55.      int argc;
  56.      char **argv;
  57. {
  58.   extern int optind;
  59.   extern char *optarg;
  60.   char c;
  61.   char *Command_Name;
  62.   FILE *xaliases, *aliases, *generics;
  63.  
  64.   routing_host = NULL;
  65.   Command_Name = argv[0];
  66.  
  67.   while (argc > 1 && *argv[1] == '-') {
  68.     if (argv[1][1] != 'r' && argv[1][1] != 't') break;
  69.     if (argv[1][1] == 'r') {
  70.         routing_host=2+argv[1];
  71.         if ( *routing_host == 0 ) routing_host = "localhost";
  72.         }
  73.         else translate_generics = TRUE;
  74.     ++argv ;
  75.     --argc ;
  76.     }
  77.  
  78.   if (argc != 4) {
  79.     fprintf(stderr, "usage: %s [-r[host]] [-t] xaliases aliases generics\n",
  80.             Command_Name);
  81.     exit(1);
  82.   }
  83.  
  84.   if (strcmp(argv[1], "-") == 0)
  85.     xaliases = stdin;
  86.   else {
  87.     xaliases = fopen(argv[1], "r");
  88.     if (xaliases == NULL)
  89.       perror(argv[1]), exit(2);
  90.   }
  91.   if (strcmp(argv[2], "-") == 0) aliases = stdout;
  92.     else {
  93.         aliases = fopen(argv[2], "w");
  94.         if (aliases == NULL)
  95.           perror(argv[2]), exit(2);
  96.         }
  97.   if (strcmp(argv[3], "-") == 0) generics = stdout;
  98.     else {
  99.         generics = fopen(argv[3], "w");
  100.         if (generics == NULL)
  101.           perror(argv[3]), exit(2);
  102.         }
  103.   
  104.   parsefile(xaliases, aliases, generics);
  105.   exit(0);
  106. }
  107.  
  108.  /*
  109.   *  Called for each address on the LHS of an alias entry.  It routes
  110.   *  the address through the host in routing_host.  This puts the address in
  111.   *  the form that the IDA sendmail rules require for building the
  112.   *  aliases database.
  113.   *
  114.   *  Purely local addresses - those without any '%' or '!' or '@' are passed
  115.   *  through without change.
  116.   *
  117.   *  Restrictions:  Assumes no deep nesting <<of> angle <brackets>> occurs,
  118.   *  but does support enclosure in a single set of <angles>.  DECNET address
  119.   *  such as NODE::USER should work, although they will have to be
  120.   *  <bracketed> to satisfy the need for no ':'.  ('Twere better to use 
  121.   *  USER@NODE.dnet).
  122.   */
  123.  char * route_addr(adr)
  124.  char * adr;
  125. {
  126.   static char buf[BUFSIZ];
  127.   int quoted_char, in_string;
  128.   char *p, *left, *right, *rtch;
  129.  
  130.   if (routing_host == NULL) return (adr); /* No routing host - pass through */
  131.  
  132.   quoted_char = FALSE; in_string = FALSE;
  133.   left = NULL; right = NULL, rtch = NULL;
  134.  
  135.   for (p=adr; *p; p++) {
  136.  /* Handle ! specially, since sendmail treats \! as equivalent to ! */
  137.       if (!in_string && rtch == NULL && *p == '!') {rtch = p; continue;}
  138.       if (quoted_char) {quoted_char = FALSE; continue;}
  139.           else quoted_char = (*p == '\\');
  140.       if (!in_string) {
  141.          if (*p == '>') {right = p; break;} /* Only comments after brackets */
  142.          switch (*p) {
  143.             case '<':left=p;
  144.                      rtch=NULL; /* Everything before brackets is comment */
  145.                      break;
  146.             case '%':if (rtch == NULL) rtch=p;
  147.                      break;
  148.             case '@':if (rtch == NULL || *rtch != '@') rtch=p;
  149.                      break;
  150.             case ':': if (rtch == NULL && p[1] == ':') rtch=p;
  151.                      break;
  152.             }
  153.           }
  154.        if (*p == '"') in_string = !in_string;
  155.        }
  156.  
  157.   if (rtch == NULL) return(adr); /* Local address is passed thru */
  158.   if (left == NULL) {
  159.      sprintf(buf,"%s@%s",adr,routing_host); /* Change 'addr' to 'addr@host' */
  160.      if (*rtch == '@') buf[rtch-adr] = '%';  /* and u@addr to u%addr@host */
  161.      return(buf);
  162.      }
  163.   if (right == NULL) return (adr); /* Unbalanced <> - pass through */
  164.   strcpy(buf,adr);
  165.   if (*rtch == '@') { /* Add routing to a source route */
  166.      sprintf(buf+(left-adr)+1,"@%s%c%s",routing_host,
  167.               (left[1] == '@') ? ',':':', left+1);
  168.      } else { /* but just add '@host' to end of uucp or decnet address */
  169.      sprintf(buf+(right-adr),"@%s%s",routing_host,right);
  170.      }
  171.   return(buf);
  172. }
  173.  
  174. parsefile(xaliases, aliases, generics)
  175.      FILE *xaliases, *aliases, *generics;
  176. {
  177.   extern char *index();
  178.   char line[BUFSIZ];
  179.   struct alias *rhs[BUFSIZ], *lhs[BUFSIZ];
  180.   struct alias **a, **r, **first;
  181.  
  182.   while (readline(line, sizeof(line), xaliases) >= 0) {
  183.     parseline(line, lhs, rhs);
  184.  
  185.     for (first = rhs; *first != ANULL; first++)
  186.       if ((*first)->a_in)
  187.     break;
  188.     if (*first != ANULL || first == rhs)
  189.       for (a = lhs; *a != ANULL; a++) {
  190.     fprintf(aliases, "%s:%s", route_addr((*a)->a_name),
  191.         (*first == ANULL) ? "" : (*first)->a_name );
  192.     for (r = first+1; *r != ANULL; r++)
  193.       if ((*r)->a_in)
  194.         fprintf(aliases, ",%s", (*r)->a_name);
  195.     fprintf(aliases, "\n");
  196.       }
  197.  
  198.     for (first=rhs; *first != ANULL; first++)
  199.       if ((*first)->a_out)
  200.         if (translate_generics)
  201.            {
  202.             char *p;
  203.             for (p=(*first)->a_name; *p; p++)
  204.                  if (isupper(*p)) *p = tolower(*p);
  205.             fprintf(generics, "%s\t%s\n",
  206.                      (*first)->a_name,lhs[0]->a_name);
  207.             }
  208.            else break;
  209.  
  210.     if (*first != ANULL) {
  211.       fprintf(generics, "%s\t%s", lhs[0]->a_name, (*first)->a_name);
  212.       for (r = first+1; *r != ANULL; r++)
  213.     if ((*r)->a_out)
  214.       fprintf(generics, " %s", (*r)->a_name);
  215.       fprintf(generics, "\n");
  216.     }
  217.  
  218.     freebufs(lhs, rhs);
  219.   }
  220. }
  221.  
  222. /**
  223.  **    PEEKC -- Return the next char to be read.
  224.  **/
  225.  
  226. peekc(stream)
  227.      FILE *stream;
  228. {
  229.   int c;
  230.  
  231.   c = getc(stream);
  232.   if (c != EOF)
  233.     ungetc(c, stream);
  234.   return c;
  235. }
  236.  
  237. /**
  238.  **    READLINE -- Read a (logical) line and return the # of chars read
  239.  **/
  240.  
  241. readline(buf, bufsiz, stream)
  242.      char *buf;
  243.      int bufsiz;
  244.      FILE *stream;
  245. {
  246.   int len;
  247.   char *sharp;
  248.  
  249.   if (fgets(buf, bufsiz, stream) == NULL)
  250.     return -1;
  251.   buf[strlen(buf)-1] = '\0';
  252.  
  253.   /*
  254.   if ((sharp = index(buf, '#')) != NULL)
  255.     *sharp = '\0';
  256.   */
  257.   if (buf[0] == '#')
  258.     buf[0] = '\0';
  259.  
  260.   len = strlen(buf);
  261.   if (isspace(peekc(stream)))
  262.     return len + readline(&buf[len], bufsiz-len, stream);
  263.   else
  264.     return len;
  265. }
  266.  
  267. /**
  268.  **    PARSETHING
  269.  **/
  270.  
  271.  
  272. #define LHS    1
  273. #define RHS    2
  274.  
  275. char *
  276. parsething(line, thing, side)
  277.      char *line;
  278.      struct alias **thing;
  279.      int side;
  280. {
  281.   register char *s, *d;
  282.   register bool
  283.     insideroute = FALSE,
  284.     insidestring = FALSE,
  285.     quotedchar = FALSE;
  286.   bool i_mark, o_mark;
  287.   char buf[BUFSIZ];
  288.  
  289.   s = line;
  290.   d = buf;
  291.  
  292.   while (*s != '\0' && isspace(*s)) s++;
  293.   if (side == RHS) {
  294.     if (o_mark = (*s == '<')) s++;
  295.     if (i_mark = (*s == '>')) s++;
  296.     i_mark = i_mark || !o_mark;            /* default to '>' */
  297.     while (*s != '\0' && isspace(*s)) s++;
  298.   }
  299.  
  300.   for (;*s != '\0'; s++) {
  301.     /* exit if non-quoted comma (or colon & LHS) */
  302.     if (!insidestring && !quotedchar && !insideroute &&
  303.     *s == ',' || ((side == LHS) && *s == ':'))
  304.       break;
  305.  
  306.     /* copy if not unquoted whitespace */
  307.     if (insidestring || quotedchar || !isspace(*s))
  308.       *d++ = *s;
  309.  
  310.     /* special quote character handling */
  311.     if (quotedchar)
  312.       quotedchar = FALSE;
  313.     else {
  314.       quotedchar = (*s == '\\');
  315.       if (!insidestring)
  316.     if (*s == '<')
  317.       insideroute = TRUE;
  318.     else if (*s == '>')
  319.       insideroute = FALSE;
  320.       if (*s == '"')
  321.     insidestring = !insidestring;
  322.     }
  323.   }
  324.   while (d > buf && isspace(d[-1])) d--;
  325.   *d = '\0';
  326.  
  327.   if (d == buf && *s == '\0') {
  328.     *thing = ANULL;
  329.     return NULL;
  330.   } else {
  331.     *thing = (struct alias *) malloc(sizeof(struct alias));
  332.     (*thing)->a_in = i_mark;
  333.     (*thing)->a_out = o_mark;
  334.     (*thing)->a_name = malloc(strlen(buf) + 1);
  335.     strcpy((*thing)->a_name, buf);
  336.     return s;
  337.   }
  338. }
  339.  
  340. /**
  341.  **    PARSELINE
  342.  **/
  343.  
  344. parseline(line, lhs, rhs)
  345.      char *line;
  346.      struct alias **lhs, **rhs;
  347. {
  348.   line--;
  349.  
  350.   while ((line = parsething(line+1, lhs++, LHS)) != NULL)
  351.     if (*line == ':')
  352.       break;
  353.   *lhs = NULL;
  354.  
  355.   if (line != NULL)
  356.     while ((line = parsething(line+1, rhs++, RHS)) != NULL);
  357.   *rhs = ANULL;
  358. }
  359.  
  360. /**
  361.  **    FREEBUFS
  362.  **/
  363.  
  364. freebufs(lhs, rhs)
  365.      struct alias **lhs, **rhs;
  366. {
  367.   while (*lhs != ANULL) {
  368.     free((*lhs)->a_name);
  369.     free(*lhs);
  370.     lhs++;
  371.   }
  372.   while (*rhs != ANULL) {
  373.     free((*rhs)->a_name);
  374.     free(*rhs);
  375.     rhs++;
  376.   }
  377. }
  378.  
  379.