home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume17 / malias / malias.c < prev    next >
C/C++ Source or Header  |  1989-02-08  |  8KB  |  402 lines

  1. /*
  2.  * malias: Decode mail aliases.  Returns true address of all arguments,
  3.  * decoded from alias lines in your .mailrc.
  4.  *
  5.  * Usage: malias <alias> [alias] ...
  6.  *
  7.  * Results are returned in stream form, so
  8.  *     % malias mark larry
  9.  * might return
  10.  *    msir_ltd@uhura.cc.rochester.edu lm03_ltd@uhura.cc.rochester.edu
  11.  * so that the results can be passed on to some other program, as in
  12.  *    finger `malias cif`
  13.  * to finger everyone you know on CIF.
  14.  *
  15.  * Mark Sirota (msir_cif@uhura.cc.rochester.edu), Fall 1988
  16.  */
  17.  
  18. /*
  19.  * The program reads the .mailrc and saves the aliases in trie format.
  20.  * The leaves of the trie are linked lists of addresses.  Each address may
  21.  * itself be an alias.
  22.  *
  23.  * The name of the .mailrc is determined by the environment variable MAILRC.
  24.  * If not present, $HOME/.mailrc is assumed.  The "-f" option overrides this.
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <malloc.h>
  30.  
  31. /*
  32.  * Aliases are maintained as a binding of a name to a mailing list (which may
  33.  * contain one or more names).  Names in a list may themselves be aliases.
  34.  * This structure is one of the names in a mailing list.
  35.  */
  36. struct address {
  37.     char        *address;
  38.     struct address    *next,
  39.             *prev;
  40. };
  41.  
  42. /*
  43.  * Ways of finding an alias in the trie.
  44.  */
  45. #define A_NOTFOUND    -1            /* Not in the trie */
  46. #define A_USED        0            /* Found, but already seen */
  47. #define A_FOUND        1            /* Found and okay */
  48.  
  49. #define FALSE    0
  50. #define TRUE    1
  51.  
  52. void
  53. usage(progname)
  54. char    *progname;
  55. {
  56.     fprintf(stderr, "Usage: %s [-,] [-1] [-f filename] <alias ...>\n", progname);
  57. }
  58.  
  59. void
  60. main(argc, argv)
  61. int    argc;
  62. char    **argv;
  63. {
  64.     int        c;
  65.     extern int    optind;
  66.     extern char    *optarg;
  67.     int        commaflag = FALSE;
  68.     int        oneflag = FALSE;
  69.     char        *filename = (char *) NULL;
  70.     char        **root;
  71.     extern char    *calloc();
  72.     void        mailrc();
  73.     struct address    *list = (struct address *) NULL,
  74.             *l,
  75.             *lprev;
  76.     void        lookup();
  77.  
  78.     /*
  79.      * Parse the arguments.
  80.      */
  81.     while ((c = getopt(argc, argv, ",1f:")) != EOF)
  82.         switch (c) {
  83.             case ',':
  84.             commaflag = TRUE;
  85.             break;
  86.             case '1':
  87.             oneflag = TRUE;
  88.             break;
  89.             case 'f':
  90.             filename = optarg;
  91.             break;
  92.             case '?':
  93.             default:
  94.             usage(argv[0]);
  95.             exit(1);
  96.         }
  97.  
  98.     /*
  99.      * If there are no aliases to process, just exit.  This is so that
  100.      * malias can be used as a front end for other programs, which don't
  101.      * necessarily take arguments, like finger.
  102.      */
  103.     if (optind == argc)
  104.         exit(0);
  105.  
  106.     /*
  107.      * Allocate memory for the root node of the trie
  108.      */
  109.     if (!(root = (char **) calloc(128, sizeof (char *)))) {
  110.         fprintf(stderr, "Out of memory.\n");
  111.         exit(1);
  112.     }
  113.  
  114.     /*
  115.      * Read lines out of the .mailrc, and add each alias to the trie
  116.      */
  117.     mailrc(filename, root);
  118.  
  119.     /*
  120.      * Translate argv to a linked list.
  121.      */
  122.     for (; optind < argc; optind++) {
  123.         if (!(l = (struct address *) malloc(sizeof (struct address)))) {
  124.             fprintf(stderr, "Out of memory.\n");
  125.             break;
  126.         }
  127.  
  128.         if (!list) {
  129.             list = l;
  130.             list->prev = (struct address *) NULL;
  131.         } else {
  132.             l->prev = lprev;
  133.             lprev->next = l;
  134.         }
  135.         l->address = argv[optind];
  136.         l->next = (struct address *) NULL;
  137.         lprev = l;
  138.     }
  139.  
  140.     /*
  141.      * Now look up the list
  142.      */
  143.     lookup(root, &list);
  144.  
  145.     /*
  146.      * Print the results.
  147.      */
  148.     for (l = list; l; l = l->next) {
  149.         fputs(l->address, stdout);
  150.         if (l->next) {
  151.             if (commaflag)
  152.                 putchar(',');
  153.             if (oneflag)
  154.                 putchar('\n');
  155.             else
  156.                 putchar(' ');
  157.         }
  158.     }
  159.     putchar('\n');
  160. }
  161.  
  162. /*
  163.  * Open the user's .mailrc and add each alias to the trie.  The .mailrc is
  164.  * defined by the environment variable MAILRC.  If not found, $HOME/.mailrc
  165.  * is assumed.
  166.  *
  167.  * The mail command "source", if found in the mailrc, is followed.
  168.  */
  169. void
  170. mailrc(filename, root)
  171. char    *filename;
  172. char    **root;
  173. {
  174.     extern char    *getenv();
  175.     char        buffer[BUFSIZ];
  176.     FILE        *fp;
  177.     char        line[BUFSIZ];
  178.     char        *command;
  179.     char        *alias;
  180.     char        *salloc();
  181.     struct address    *real;
  182.     struct address    *lalloc();
  183.     void        addalias();
  184.  
  185.     if (!filename && !(filename = getenv("MAILRC"))) {
  186.         sprintf(buffer, "%s/.mailrc", getenv("HOME"));
  187.         filename = buffer;
  188.     }
  189.  
  190.     if (!(fp = fopen(filename, "r"))) {
  191.         perror(filename);
  192.         exit(1);
  193.     }
  194.  
  195.     while (fgets(line, sizeof line, fp)) {
  196.         if (!(command = strtok(line, " \t\n")))
  197.             continue;
  198.  
  199.         if (strcmp(command, "source") == 0)
  200.             mailrc(strtok((char *) NULL, "\n"), root);
  201.         else if (strcmp(command, "alias") == 0) {
  202.             alias = salloc(strtok((char *) NULL, " \t"));
  203.             real = lalloc(strtok((char *) NULL, "\n"));
  204.             addalias(root, alias, real);
  205.         }
  206.     }
  207.  
  208.     fclose(fp);
  209. }
  210.  
  211. /*
  212.  * Add an alias to the trie
  213.  */
  214. void
  215. addalias(root, alias, real)
  216. char        **root;
  217. char        *alias;
  218. struct address    *real;
  219. {
  220.     char        **tp;
  221.     extern char    *calloc();
  222.  
  223.     /*
  224.      * Scan down the existing trie as far as we can
  225.      */
  226.     tp = root;
  227.     for (; *alias; alias++) {
  228.         if (!tp[*alias])
  229.             break;
  230.         tp = (char **) tp[*alias];
  231.     }
  232.  
  233.     /*
  234.      * Add the rest of the alias to the trie
  235.      */
  236.     for (; *alias; alias++) {
  237.         if (!(tp[*alias] = calloc(128, sizeof (char *)))) {
  238.             fprintf(stderr, "Out of memory.\n");
  239.             exit(1);
  240.         }
  241.         tp = (char **) tp[*alias];
  242.     }
  243.  
  244.     /*
  245.      * Set the end of the alias to point to the real name
  246.      */
  247.     tp[NULL] = (char *) real;
  248. }
  249.  
  250. /*
  251.  * Look up an alias list in the trie.  When finished, the list will contain
  252.  * only resolved names.
  253.  */
  254. void
  255. lookup(root, aliasl)
  256. char        **root;
  257. struct address    **aliasl;
  258. {
  259.     struct address    *alias;        /* Current alias pointer */
  260.     struct address    *list,
  261.             *l;        /* list associated with alias */
  262.  
  263.     /*
  264.      * Look up each alias in this list
  265.      */
  266.     alias = *aliasl;
  267.     while (alias) {
  268.         switch (findalias(root, alias->address, &list)) {
  269.             case A_NOTFOUND:
  270.             /*
  271.              * Leave this one alone.
  272.              */
  273.             alias = alias->next;
  274.             break;
  275.             case A_USED:
  276.             /*
  277.              * This alias has been processed before.
  278.              * just remove this alias and move on.
  279.              */
  280.             if (alias->prev)
  281.                 alias->prev->next = alias->next;
  282.             else
  283.                 *aliasl = alias->next;
  284.             if (alias->next)
  285.                 alias->next->prev = alias->prev;
  286.             alias = alias->next;
  287.             break;
  288.             case A_FOUND:
  289.             /*
  290.              * Splice the list in here in place of the alias.
  291.              */
  292.             if (alias->prev)
  293.                 alias->prev->next = list;
  294.             else
  295.                 *aliasl = list;
  296.             list->prev = alias->prev;
  297.             for (l = list; l->next; l = l->next)
  298.                 ;
  299.             l->next = alias->next;
  300.             if (alias->next)
  301.                 alias->next->prev = l;
  302.             alias = list;
  303.             break;
  304.         }
  305.     }
  306. }
  307.  
  308. /*
  309.  * Find an alias in the trie.  When an alias is fonund, the alias is removed
  310.  * so that it will not be repeated.  The result is placed in list, and the
  311.  * status is returned (NOTFOUND, USED, or FOUND).
  312.  */
  313. int
  314. findalias(root, alias, list)
  315. char        **root;
  316. char        *alias;
  317. struct address    **list;
  318. {
  319.     char    **tp;
  320.  
  321.     /*
  322.      * Scan down the trie
  323.      */
  324.     tp = root;
  325.     for (; *alias; alias++) {
  326.         if (!tp[*alias])
  327.             break;
  328.         tp = (char **) tp[*alias];
  329.     }
  330.  
  331.     /*
  332.      * If we didn't make it to the end of the alias, return NOTFOUND.
  333.      * Otherwise, return the list.
  334.      */
  335.     if (*alias) {
  336.         *list = (struct address *) NULL;
  337.         return A_NOTFOUND;
  338.     }
  339.  
  340.     /*
  341.      * Found.  If used, the leaf will be NULL, and so we'll return USED.
  342.      */
  343.     if ((struct address *) tp[NULL] == (struct address *) NULL) {
  344.         *list = (struct address *) NULL;
  345.         return A_USED;
  346.     }
  347.  
  348.     /*
  349.      * Save a pointer to the list and then remove the trie
  350.      * reference.  Next time this alias is referenced, it will return a
  351.      * NULL list.
  352.      */
  353.     *list = (struct address *) tp[NULL];
  354.     tp[NULL] = (char *) NULL;
  355.     return A_FOUND;
  356. }
  357.  
  358. /*
  359.  * Allocate enough new memory to hold string, copy it there, and return a
  360.  * pointer to the new copy.
  361.  */
  362. char *
  363. salloc(string)
  364. char    *string;
  365. {
  366.     return strcpy(malloc((unsigned) strlen(string) + 1), string);
  367. }
  368.  
  369. /*
  370.  * Take a string and turn it into a linked list of addresses, using spaces
  371.  * and tabs as delimiters.
  372.  */
  373. struct address *
  374. lalloc(string)
  375. char    *string;
  376. {
  377.     char        *s;
  378.     struct address    *l,
  379.             *lprev,
  380.             *list = (struct address *) NULL;
  381.     char        *salloc();
  382.  
  383.     for (s = strtok(string, " \t"); s; s = strtok((char *) NULL, " \t")) {
  384.         if (!(l = (struct address *) malloc(sizeof (struct address)))) {
  385.             fprintf(stderr, "Out of memory.\n");
  386.             return (struct address *) NULL;
  387.         }
  388.         if (!list) {
  389.             list = l;
  390.             list->prev = (struct address *) NULL;
  391.         } else {
  392.             list->prev = lprev;
  393.             lprev->next = l;
  394.         }
  395.         l->address = salloc(s);
  396.         l->next = (struct address *) NULL;
  397.         lprev = l;
  398.     }
  399.  
  400.     return list;
  401. }
  402.