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