home *** CD-ROM | disk | FTP | other *** search
- /*
- * malias: Decode mail aliases. Returns true address of all arguments,
- * decoded from alias lines in your .mailrc.
- *
- * Usage: malias <alias> [alias] ...
- *
- * Results are returned in stream form, so
- * % malias mark larry
- * might return
- * msir_ltd@uhura.cc.rochester.edu lm03_ltd@uhura.cc.rochester.edu
- * so that the results can be passed on to some other program, as in
- * finger `malias cif`
- * to finger everyone you know on CIF.
- *
- * Mark Sirota (msir_cif@uhura.cc.rochester.edu), Fall 1988
- */
-
- /*
- * The program reads the .mailrc and saves the aliases in trie format.
- * The leaves of the trie are linked lists of addresses. Each address may
- * itself be an alias.
- *
- * The name of the .mailrc is determined by the environment variable MAILRC.
- * If not present, $HOME/.mailrc is assumed. The "-f" option overrides this.
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <malloc.h>
-
- /*
- * Aliases are maintained as a binding of a name to a mailing list (which may
- * contain one or more names). Names in a list may themselves be aliases.
- * This structure is one of the names in a mailing list.
- */
- struct address {
- char *address;
- struct address *next,
- *prev;
- };
-
- /*
- * Ways of finding an alias in the trie.
- */
- #define A_NOTFOUND -1 /* Not in the trie */
- #define A_USED 0 /* Found, but already seen */
- #define A_FOUND 1 /* Found and okay */
-
- #define FALSE 0
- #define TRUE 1
-
- void
- usage(progname)
- char *progname;
- {
- fprintf(stderr, "Usage: %s [-,] [-1] [-f filename] <alias ...>\n", progname);
- }
-
- void
- main(argc, argv)
- int argc;
- char **argv;
- {
- int c;
- extern int optind;
- extern char *optarg;
- int commaflag = FALSE;
- int oneflag = FALSE;
- char *filename = (char *) NULL;
- char **root;
- extern char *calloc();
- void mailrc();
- struct address *list = (struct address *) NULL,
- *l,
- *lprev;
- void lookup();
-
- /*
- * Parse the arguments.
- */
- while ((c = getopt(argc, argv, ",1f:")) != EOF)
- switch (c) {
- case ',':
- commaflag = TRUE;
- break;
- case '1':
- oneflag = TRUE;
- break;
- case 'f':
- filename = optarg;
- break;
- case '?':
- default:
- usage(argv[0]);
- exit(1);
- }
-
- /*
- * If there are no aliases to process, just exit. This is so that
- * malias can be used as a front end for other programs, which don't
- * necessarily take arguments, like finger.
- */
- if (optind == argc)
- exit(0);
-
- /*
- * Allocate memory for the root node of the trie
- */
- if (!(root = (char **) calloc(128, sizeof (char *)))) {
- fprintf(stderr, "Out of memory.\n");
- exit(1);
- }
-
- /*
- * Read lines out of the .mailrc, and add each alias to the trie
- */
- mailrc(filename, root);
-
- /*
- * Translate argv to a linked list.
- */
- for (; optind < argc; optind++) {
- if (!(l = (struct address *) malloc(sizeof (struct address)))) {
- fprintf(stderr, "Out of memory.\n");
- break;
- }
-
- if (!list) {
- list = l;
- list->prev = (struct address *) NULL;
- } else {
- l->prev = lprev;
- lprev->next = l;
- }
- l->address = argv[optind];
- l->next = (struct address *) NULL;
- lprev = l;
- }
-
- /*
- * Now look up the list
- */
- lookup(root, &list);
-
- /*
- * Print the results.
- */
- for (l = list; l; l = l->next) {
- fputs(l->address, stdout);
- if (l->next) {
- if (commaflag)
- putchar(',');
- if (oneflag)
- putchar('\n');
- else
- putchar(' ');
- }
- }
- putchar('\n');
- }
-
- /*
- * Open the user's .mailrc and add each alias to the trie. The .mailrc is
- * defined by the environment variable MAILRC. If not found, $HOME/.mailrc
- * is assumed.
- *
- * The mail command "source", if found in the mailrc, is followed.
- */
- void
- mailrc(filename, root)
- char *filename;
- char **root;
- {
- extern char *getenv();
- char buffer[BUFSIZ];
- FILE *fp;
- char line[BUFSIZ];
- char *command;
- char *alias;
- char *salloc();
- struct address *real;
- struct address *lalloc();
- void addalias();
-
- if (!filename && !(filename = getenv("MAILRC"))) {
- sprintf(buffer, "%s/.mailrc", getenv("HOME"));
- filename = buffer;
- }
-
- if (!(fp = fopen(filename, "r"))) {
- perror(filename);
- exit(1);
- }
-
- while (fgets(line, sizeof line, fp)) {
- if (!(command = strtok(line, " \t\n")))
- continue;
-
- if (strcmp(command, "source") == 0)
- mailrc(strtok((char *) NULL, "\n"), root);
- else if (strcmp(command, "alias") == 0) {
- alias = salloc(strtok((char *) NULL, " \t"));
- real = lalloc(strtok((char *) NULL, "\n"));
- addalias(root, alias, real);
- }
- }
-
- fclose(fp);
- }
-
- /*
- * Add an alias to the trie
- */
- void
- addalias(root, alias, real)
- char **root;
- char *alias;
- struct address *real;
- {
- char **tp;
- extern char *calloc();
-
- /*
- * Scan down the existing trie as far as we can
- */
- tp = root;
- for (; *alias; alias++) {
- if (!tp[*alias])
- break;
- tp = (char **) tp[*alias];
- }
-
- /*
- * Add the rest of the alias to the trie
- */
- for (; *alias; alias++) {
- if (!(tp[*alias] = calloc(128, sizeof (char *)))) {
- fprintf(stderr, "Out of memory.\n");
- exit(1);
- }
- tp = (char **) tp[*alias];
- }
-
- /*
- * Set the end of the alias to point to the real name
- */
- tp[NULL] = (char *) real;
- }
-
- /*
- * Look up an alias list in the trie. When finished, the list will contain
- * only resolved names.
- */
- void
- lookup(root, aliasl)
- char **root;
- struct address **aliasl;
- {
- struct address *alias; /* Current alias pointer */
- struct address *list,
- *l; /* list associated with alias */
-
- /*
- * Look up each alias in this list
- */
- alias = *aliasl;
- while (alias) {
- switch (findalias(root, alias->address, &list)) {
- case A_NOTFOUND:
- /*
- * Leave this one alone.
- */
- alias = alias->next;
- break;
- case A_USED:
- /*
- * This alias has been processed before.
- * just remove this alias and move on.
- */
- if (alias->prev)
- alias->prev->next = alias->next;
- else
- *aliasl = alias->next;
- if (alias->next)
- alias->next->prev = alias->prev;
- alias = alias->next;
- break;
- case A_FOUND:
- /*
- * Splice the list in here in place of the alias.
- */
- if (alias->prev)
- alias->prev->next = list;
- else
- *aliasl = list;
- list->prev = alias->prev;
- for (l = list; l->next; l = l->next)
- ;
- l->next = alias->next;
- if (alias->next)
- alias->next->prev = l;
- alias = list;
- break;
- }
- }
- }
-
- /*
- * Find an alias in the trie. When an alias is fonund, the alias is removed
- * so that it will not be repeated. The result is placed in list, and the
- * status is returned (NOTFOUND, USED, or FOUND).
- */
- int
- findalias(root, alias, list)
- char **root;
- char *alias;
- struct address **list;
- {
- char **tp;
-
- /*
- * Scan down the trie
- */
- tp = root;
- for (; *alias; alias++) {
- if (!tp[*alias])
- break;
- tp = (char **) tp[*alias];
- }
-
- /*
- * If we didn't make it to the end of the alias, return NOTFOUND.
- * Otherwise, return the list.
- */
- if (*alias) {
- *list = (struct address *) NULL;
- return A_NOTFOUND;
- }
-
- /*
- * Found. If used, the leaf will be NULL, and so we'll return USED.
- */
- if ((struct address *) tp[NULL] == (struct address *) NULL) {
- *list = (struct address *) NULL;
- return A_USED;
- }
-
- /*
- * Save a pointer to the list and then remove the trie
- * reference. Next time this alias is referenced, it will return a
- * NULL list.
- */
- *list = (struct address *) tp[NULL];
- tp[NULL] = (char *) NULL;
- return A_FOUND;
- }
-
- /*
- * Allocate enough new memory to hold string, copy it there, and return a
- * pointer to the new copy.
- */
- char *
- salloc(string)
- char *string;
- {
- return strcpy(malloc((unsigned) strlen(string) + 1), string);
- }
-
- /*
- * Take a string and turn it into a linked list of addresses, using spaces
- * and tabs as delimiters.
- */
- struct address *
- lalloc(string)
- char *string;
- {
- char *s;
- struct address *l,
- *lprev,
- *list = (struct address *) NULL;
- char *salloc();
-
- for (s = strtok(string, " \t"); s; s = strtok((char *) NULL, " \t")) {
- if (!(l = (struct address *) malloc(sizeof (struct address)))) {
- fprintf(stderr, "Out of memory.\n");
- return (struct address *) NULL;
- }
- if (!list) {
- list = l;
- list->prev = (struct address *) NULL;
- } else {
- list->prev = lprev;
- lprev->next = l;
- }
- l->address = salloc(s);
- l->next = (struct address *) NULL;
- lprev = l;
- }
-
- return list;
- }
-