/*--------------------------------------------------------------------*/ /* alias.c */ /* */ /* Smart routing and alias routines for pcmail. */ /* */ /* Copyright (C) 1989 Andrew H. Derbyshire */ /* */ /* Additional code */ /* Copyright (c) Richard H. Lamb 1985, 1986, 1987 */ /* Changes Copyright (c) Stuart Lynne 1987 */ /* */ /* Updates: */ /* */ /* 02 Oct 89 Alter large strings/structures to use */ /* malloc()/free() ahd */ /* 08 Feb 90 Correct failure of ExtractAddress to return */ /* non-names ahd */ /* 18 Mar 90 Move checkname() and associated routines into */ /* hostable.c ahd */ /* 22 Apr 90 Modify user_at_node to correctly handle .UUCP */ /* alias on local host. ahd */ /*--------------------------------------------------------------------*/ /* * $Id: ALIAS.C 1.3 1993/04/11 00:33:05 ahd Exp $ * * $Log: ALIAS.C $ * Revision 1.3 1993/04/11 00:33:05 ahd * Global edits for year, TEXT, etc. * * Revision 1.2 1992/11/22 21:06:14 ahd * Use strpool for memory allocation * */ #include #include #include #include #include #ifndef __TURBOC__ #include #endif #include "lib.h" #include "hostable.h" #include "security.h" #include "usertabl.h" #include "hlib.h" #include "alias.h" #include "address.h" static size_t AliasCount = 0; static struct AliasTable *alias = NULL; int nickcmp( const void *a, const void *b ); static size_t LoadAliases( void ) ; currentfile(); /*--------------------------------------------------------------------*/ /* I n i t R o u t e r */ /* */ /* Verify, initialize the global routing data */ /*--------------------------------------------------------------------*/ boolean InitRouter() { boolean success = TRUE; /* Assume the input data is good */ struct HostTable *Hptr; /*--------------------------------------------------------------------*/ /* Verify that the user gave us a good name server */ /*--------------------------------------------------------------------*/ Hptr = checkreal(E_mailserv); if (Hptr == BADHOST) { printmsg(0,"mail server '%s' must be listed in SYSTEMS file", E_mailserv); success = FALSE; } else if (Hptr->hstatus == localhost) /* local system? */ { printmsg(0,"'%s' is name of this host and cannot be mail server", E_mailserv); success = FALSE; } /*--------------------------------------------------------------------*/ /* Return to caller */ /*--------------------------------------------------------------------*/ return success; } /* InitRouter */ /*--------------------------------------------------------------------*/ /* E x t r a c t N a m e */ /* */ /* Returns full name of user, and returns address if name */ /* is not available. */ /*--------------------------------------------------------------------*/ void ExtractName(char *result, char *column) { static int recursion = 0; recursion++; printmsg((recursion > 2) ? 1:8, "ExtractName: Getting name from '%s'",column); ExtractAddress(result, column, TRUE); /* Get the full name */ if (!strlen(result)) /* Did we get the name? */ { /* No --> Get the e-mail address */ char addr[MAXADDR]; char path[MAXADDR]; char node[MAXADDR]; char *fullname; ExtractAddress(addr,column, FALSE); user_at_node(addr,path,node,result); /* Reduce address to basics */ fullname = AliasByAddr(node,result); if (fullname == NULL) { strcat(result,"@"); strcat(result,node); } else strcpy(result,fullname); } printmsg((recursion > 2) ? 1: 8,"ExtractName: name is '%s'",result); recursion--; return; } /*ExtractName*/ /*--------------------------------------------------------------------*/ /* B u i l d A d d r e s s */ /* */ /* Builds a standard address format, with aliasing as */ /* required. */ /*--------------------------------------------------------------------*/ void BuildAddress(char *result, const char *input) { char addr[MAXADDR]; char name[MAXADDR]; char user[MAXADDR]; char path[MAXADDR]; char node[MAXADDR]; char *fulladdr; /*--------------------------------------------------------------------*/ /* It must be a real address, possibly with a name attached; get */ /* the address portion, break the address into user and node, and */ /* then see if we know the person by address */ /*--------------------------------------------------------------------*/ ExtractAddress(addr,input,FALSE); /* Get user e-mail addr */ user_at_node(addr,path,node,user); /* Break address down */ fulladdr = AliasByAddr(node,user); /* Alias for the address? */ if (fulladdr != NULL) /* Yes --> Use it */ { strcpy(result,fulladdr); return; } /* if */ /*--------------------------------------------------------------------*/ /* We don't know the address yet; get the name the user provided, */ /* and then normalize the address */ /*--------------------------------------------------------------------*/ ExtractAddress(name,input,TRUE); /* Also get their name */ if (strlen(name)) /* Did we find a name for user? */ { /* Yes --> Return it */ char *s = strchr(node, '.'); if ((s == NULL) || equalni( s, ".UUCP", 5)) /* Simple name or UUCP domain? */ { /* Yes--> Use original address */ size_t pathlen = strlen(path);/* Save len of orig path */ if ((pathlen > strlen(addr)) && (!equal(node,path)) && /* Target not a known host? */ equaln(addr,path, strlen(path)) && /* & host starts */ (addr[pathlen] == '!')) /* ...the address? */ fulladdr = &addr[pathlen + 1]; /* Yes --> Drop it */ else fulladdr = addr; /* No --> Use full address */ sprintf(result,"(%s) %s", name, addr); } /* (strchr(node, '.') == NULL) */ else /* No --> Use RFC-822 format */ sprintf(result,"\"%s\" <%s@%s>", name, user, node); } /* if strlen(name) */ else strcpy(result,addr); /* No name, just use the original */ } /* BuildAddress */ /*--------------------------------------------------------------------*/ /* A l i a s B y N i c k */ /* */ /* Locate a mail address by search the alias table. Returns TRUE */ /* if alias found and has address, otherwise FALSE. */ /*--------------------------------------------------------------------*/ char *AliasByNick(const char *nick) { int upper; int lower; if (!AliasCount) AliasCount = LoadAliases(); upper = AliasCount - 1; lower = 0; while (upper >= lower) { int midpoint; int hit; midpoint = ( upper + lower ) / 2; hit = stricmp(nick,alias[midpoint].anick); if (!hit) return alias[midpoint].afull; if ( hit > 0 ) lower = midpoint + 1; else upper = midpoint - 1; } return NULL; } /*--------------------------------------------------------------------*/ /* A l i a s B y A d d r */ /* */ /* Locate a mail address by search the alias table. Returns TRUE */ /* if alias found and has address, otherwise FALSE */ /*--------------------------------------------------------------------*/ char *AliasByAddr(const char *node, const char *user) { size_t current = 0; if (!AliasCount) AliasCount = LoadAliases(); while (current < AliasCount) { int hit; hit = stricmp(node,alias[current].anode); if (!hit) { hit = stricmp(user,alias[current].auser); if (!hit) return alias[current].afull; } current++; } return NULL; } /*--------------------------------------------------------------------*/ /* L o a d A l i a s e s */ /* */ /* Initializes the address alias table; returns number of aliases */ /* loaded */ /*--------------------------------------------------------------------*/ size_t LoadAliases(void) { FILE *ff; char buf[BUFSIZ]; char *token; size_t elements = 0; size_t max_elements = UserElements + 20; size_t subscript; struct AliasTable *hit; /* temporary pointer for searching */ struct AliasTable target; checkuser( E_mailbox ); /* Force the table to be loaded */ alias = calloc(max_elements, sizeof(*alias)); checkref(alias); /*--------------------------------------------------------------------*/ /* Actually load the alias table */ /*--------------------------------------------------------------------*/ if (E_aliases != NULL ) /* Did the user specify aliases file? */ { ff = FOPEN(E_aliases, "r",TEXT_MODE); if (ff == NULL) { printerr(E_aliases); return elements; } /* if */ while (! feof(ff)) { if (fgets(buf,BUFSIZ,ff) == NULL) /* Try to read a line */ break; /* Exit if end of file */ token = strtok(buf," \t\n"); if (token == NULL) /* Any data? */ continue; /* No --> read another line */ if (token[0] == '#') continue; /* Line is a comment; loop again */ /* Add the alias to the table. Note that we must add the nick */ /* to the table ourselves (rather than use lsearch) because */ /* we must make a copy of the string; the *token we use for */ /* the search is in the middle of our I/O buffer! */ /* /* I was burned, _you_ have been warned. */ target.anick = token; hit = (void *) lfind(&target, alias, &elements , sizeof(alias[0]), nickcmp); if (hit == NULL) { char node[MAXADDR]; char user[MAXADDR]; char path[MAXADDR]; char addr[MAXADDR]; char *eos; if (elements == max_elements) { max_elements = max_elements * 2; alias = realloc(alias, max_elements * sizeof(*alias)); checkref(alias); } alias[elements].anick = newstr(token); token = strtok(NULL,""); /* Get rest of string */ while ( strlen(token) && isspace(*token)) token++; eos = token + strlen(token) - 1; while ( strlen(token) && isspace(*eos)) { *eos = '\0'; eos--; } alias[elements].afull = newstr(token); ExtractAddress(addr,alias[elements].afull,FALSE); user_at_node(addr,path,node,user); alias[elements].anode = newstr(node); alias[elements].auser = newstr(user); elements += 1; } else printmsg(0,"LoadAliases: Duplicate alias '%s' in table",token); } fclose(ff); } /* if (E_aliases != NULL ) */ /*--------------------------------------------------------------------*/ /* Add the local users as final aliases in table */ /*--------------------------------------------------------------------*/ alias = realloc(alias, (elements + UserElements) * sizeof(*alias)); /* Resize table to final known size */ checkref(alias); for ( subscript = 0; subscript < UserElements; subscript++, elements++) { alias[elements].anick = ""; /* No nickname, only good for addr */ if (bflag[F_BANG]) sprintf(buf, "(%s) %s!%s", users[subscript].realname, E_fdomain, users[subscript].uid); else sprintf(buf, "\"%s\" <%s@%s>", users[subscript].realname, users[subscript].uid, E_fdomain ); alias[elements].afull = newstr(buf); alias[elements].anode = E_nodename; alias[elements].auser = users[subscript].uid; } /* for */ /*--------------------------------------------------------------------*/ /* Now sort the table */ /*--------------------------------------------------------------------*/ qsort(alias, elements ,sizeof(alias[0]) , nickcmp); return (elements) ; } /*LoadAliases*/ /*--------------------------------------------------------------------*/ /* n i c k c m p */ /* */ /* Accepts indirect pointers to two strings and compares them using */ /* stricmp (case insensitive string compare) */ /*--------------------------------------------------------------------*/ int nickcmp( const void *a, const void *b ) { return stricmp(((struct AliasTable *)a)->anick, ((struct AliasTable *)b)->anick); } /*nickcmp*/