| #include "common.h" | 
 |  | 
 | /* | 
 |  *  WARNING!  This turns all upper case names into lower case | 
 |  *  local ones. | 
 |  */ | 
 |  | 
 | /* predeclared */ | 
 | static String	*getdbfiles(void); | 
 | static int	translate(char*, char**, String*, String*); | 
 | static int	lookup(String**, String*, String*); | 
 | static int	compare(String*, char*); | 
 | static char*	mklower(char*); | 
 |  | 
 | static int debug; | 
 | static int from; | 
 | static char *namefiles = "namefiles"; | 
 | #define DEBUG if(debug) | 
 |  | 
 | /* loop through the names to be translated */ | 
 | void | 
 | main(int argc, char *argv[]) | 
 | { | 
 | 	String *s; | 
 | 	String *alias;		/* the alias for the name */ | 
 | 	char **names;		/* names of this system */ | 
 | 	String *files;		/* list of files to search */ | 
 | 	int i, rv; | 
 | 	char *p; | 
 |  | 
 | 	ARGBEGIN { | 
 | 	case 'd': | 
 | 		debug = 1; | 
 | 		break; | 
 | 	case 'f': | 
 | 		from = 1; | 
 | 		break; | 
 | 	case 'n': | 
 | 		namefiles = ARGF(); | 
 | 		break; | 
 | 	} ARGEND | 
 |  | 
 | 	if (chdir(UPASLIB) < 0) | 
 | 		sysfatal("aliasmail chdir %s: %r", UPASLIB); | 
 |  | 
 | 	/* get environmental info */ | 
 | 	names = sysnames_read(); | 
 | 	files = getdbfiles(); | 
 | 	alias = s_new(); | 
 |  | 
 | 	/* loop through the names to be translated (from standard input) */ | 
 | 	for(i=0; i<argc; i++) { | 
 | 		s = unescapespecial(s_copy(mklower(argv[i]))); | 
 | 		if(strchr(s_to_c(s), '!') == 0) | 
 | 			rv = translate(s_to_c(s), names, files, alias); | 
 | 		else | 
 | 			rv = -1; | 
 | 		if(from){ | 
 | 			if (rv >= 0 && *s_to_c(alias) != '\0'){ | 
 | 				p = strchr(s_to_c(alias), '\n'); | 
 | 				if(p) | 
 | 					*p = 0; | 
 | 				p = strchr(s_to_c(alias), '!'); | 
 | 				if(p) { | 
 | 					*p = 0; | 
 | 					print("%s", s_to_c(alias)); | 
 | 				} else { | 
 | 					p = strchr(s_to_c(alias), '@'); | 
 | 					if(p) | 
 | 						print("%s", p+1); | 
 | 					else | 
 | 						print("%s", s_to_c(alias)); | 
 | 				} | 
 | 			} | 
 | 		} else { | 
 | 			if (rv < 0 || *s_to_c(alias) == '\0') | 
 | 				print("local!%s\n", s_to_c(s)); | 
 | 			else { | 
 | 				/* this must be a write, not a print */ | 
 | 				write(1, s_to_c(alias), strlen(s_to_c(alias))); | 
 | 			} | 
 | 		} | 
 | 		s_free(s); | 
 | 	} | 
 | 	exits(0); | 
 | } | 
 |  | 
 | /* get the list of dbfiles to search */ | 
 | static String * | 
 | getdbfiles(void) | 
 | { | 
 | 	Sinstack *sp; | 
 | 	String *files = s_new(); | 
 | 	char *nf; | 
 |  | 
 | 	if(from) | 
 | 		nf = "fromfiles"; | 
 | 	else | 
 | 		nf = namefiles; | 
 |  | 
 | 	/* system wide aliases */ | 
 | 	if ((sp = s_allocinstack(nf)) != 0){ | 
 | 		while(s_rdinstack(sp, files)) | 
 | 			s_append(files, " "); | 
 | 		s_freeinstack(sp); | 
 | 	} | 
 |  | 
 |  | 
 | 	DEBUG print("files are %s\n", s_to_c(files)); | 
 |  | 
 | 	return files; | 
 | } | 
 |  | 
 | /* loop through the translation files */ | 
 | static int | 
 | translate(char *name,		/* name to translate */ | 
 | 	char **namev,		/* names of this system */ | 
 | 	String *files,		/* names of system alias files */ | 
 | 	String *alias)		/* where to put the alias */ | 
 | { | 
 | 	String *file = s_new(); | 
 | 	String **fullnamev; | 
 | 	int n, rv; | 
 |  | 
 | 	rv = -1; | 
 |  | 
 | 	DEBUG print("translate(%s, %s, %s)\n", name, | 
 | 		s_to_c(files), s_to_c(alias)); | 
 |  | 
 | 	/* create the full name to avoid loops (system!name) */ | 
 | 	for(n = 0; namev[n]; n++) | 
 | 		; | 
 | 	fullnamev = (String**)malloc(sizeof(String*)*(n+2)); | 
 | 	n = 0; | 
 | 	fullnamev[n++] = s_copy(name); | 
 | 	for(; *namev; namev++){ | 
 | 		fullnamev[n] = s_copy(*namev); | 
 | 		s_append(fullnamev[n], "!"); | 
 | 		s_append(fullnamev[n], name); | 
 | 		n++; | 
 | 	} | 
 | 	fullnamev[n] = 0; | 
 |  | 
 | 	/* look at system-wide names */ | 
 | 	s_restart(files); | 
 | 	while (s_parse(files, s_restart(file)) != 0) { | 
 | 		if (lookup(fullnamev, file, alias)==0) { | 
 | 			rv = 0; | 
 | 			goto out; | 
 | 		} | 
 | 	} | 
 |  | 
 | out: | 
 | 	for(n = 0; fullnamev[n]; n++) | 
 | 		s_free(fullnamev[n]); | 
 | 	s_free(file); | 
 | 	free(fullnamev); | 
 | 	return rv; | 
 | } | 
 |  | 
 | /* | 
 |  *  very dumb conversion to bang format | 
 |  */ | 
 | static String* | 
 | attobang(String *token) | 
 | { | 
 | 	char *p; | 
 | 	String *tok; | 
 |  | 
 | 	p = strchr(s_to_c(token), '@'); | 
 | 	if(p == 0) | 
 | 		return token; | 
 |  | 
 | 	p++; | 
 | 	tok = s_copy(p); | 
 | 	s_append(tok, "!"); | 
 | 	s_nappend(tok, s_to_c(token), p - s_to_c(token) - 1); | 
 |  | 
 | 	return tok; | 
 | } | 
 |  | 
 | /*  Loop through the entries in a translation file looking for a match. | 
 |  *  Return 0 if found, -1 otherwise. | 
 |  */ | 
 | static int | 
 | lookup( | 
 | 	String **namev, | 
 | 	String *file, | 
 | 	String *alias)	/* returned String */ | 
 | { | 
 | 	String *line = s_new(); | 
 | 	String *token = s_new(); | 
 | 	String *bangtoken; | 
 | 	int i, rv = -1; | 
 | 	char *name =  s_to_c(namev[0]); | 
 | 	Sinstack *sp; | 
 |  | 
 | 	DEBUG print("lookup(%s, %s, %s, %s)\n", s_to_c(namev[0]), s_to_c(namev[1]), | 
 | 		s_to_c(file), s_to_c(alias)); | 
 |  | 
 | 	s_reset(alias); | 
 | 	if ((sp = s_allocinstack(s_to_c(file))) == 0) | 
 | 		return -1; | 
 |  | 
 | 	/* look for a match */ | 
 | 	while (s_rdinstack(sp, s_restart(line))!=0) { | 
 | 		DEBUG print("line is %s\n", s_to_c(line)); | 
 | 		s_restart(token); | 
 | 		if (s_parse(s_restart(line), token)==0) | 
 | 			continue; | 
 | 		if (compare(token, "#include")==0){ | 
 | 			if(s_parse(line, s_restart(token))!=0) { | 
 | 				if(lookup(namev, line, alias) == 0) | 
 | 					break; | 
 | 			} | 
 | 			continue; | 
 | 		} | 
 | 		if (compare(token, name)!=0) | 
 | 			continue; | 
 | 		/* match found, get the alias */ | 
 | 		while(s_parse(line, s_restart(token))!=0) { | 
 | 			bangtoken = attobang(token); | 
 |  | 
 | 			/* avoid definition loops */ | 
 | 			for(i = 0; namev[i]; i++) | 
 | 				if(compare(bangtoken, s_to_c(namev[i]))==0) { | 
 | 					s_append(alias, "local"); | 
 | 					s_append(alias, "!"); | 
 | 					s_append(alias, name); | 
 | 					break; | 
 | 				} | 
 |  | 
 | 			if(namev[i] == 0) | 
 | 				s_append(alias, s_to_c(token)); | 
 | 			s_append(alias, "\n"); | 
 |  | 
 | 			if(bangtoken != token) | 
 | 				s_free(bangtoken); | 
 | 		} | 
 | 		rv = 0; | 
 | 		break; | 
 | 	} | 
 | 	s_free(line); | 
 | 	s_free(token); | 
 | 	s_freeinstack(sp); | 
 | 	return rv; | 
 | } | 
 |  | 
 | #define lower(c) ((c)>='A' && (c)<='Z' ? (c)-('A'-'a'):(c)) | 
 |  | 
 | /* compare two Strings (case insensitive) */ | 
 | static int | 
 | compare(String *s1, | 
 | 	char *p2) | 
 | { | 
 | 	char *p1 = s_to_c(s1); | 
 | 	int rv; | 
 |  | 
 | 	DEBUG print("comparing %s to %s\n", p1, p2); | 
 | 	while((rv = lower(*p1) - lower(*p2)) == 0) { | 
 | 		if (*p1 == '\0') | 
 | 			break; | 
 | 		p1++; | 
 | 		p2++; | 
 | 	} | 
 | 	return rv; | 
 | } | 
 |  | 
 | static char* | 
 | mklower(char *name) | 
 | { | 
 | 	char *p; | 
 | 	char c; | 
 |  | 
 | 	for(p = name; *p; p++){ | 
 | 		c = *p; | 
 | 		*p = lower(c); | 
 | 	} | 
 | 	return name; | 
 | } |