122694Sdist /* 235073Sbostic * Copyright (c) 1983 Eric P. Allman 333728Sbostic * Copyright (c) 1988 Regents of the University of California. 433728Sbostic * All rights reserved. 533728Sbostic * 642824Sbostic * %sccs.include.redist.c% 733728Sbostic */ 822694Sdist 950577Seric # include <sys/types.h> 1050577Seric # include <sys/stat.h> 1150577Seric # include <signal.h> 1250577Seric # include <errno.h> 1350577Seric # include "sendmail.h" 1450577Seric # include <sys/file.h> 1550577Seric # include <pwd.h> 1651937Seric # ifdef LOCKF 1751937Seric # include <fcntl.h> 1851937Seric # endif 1950577Seric 2050577Seric # ifdef NEWDB 2150577Seric # include <db.h> 2250577Seric # endif 2350577Seric 2433728Sbostic #ifndef lint 2551756Seric #ifdef NEWDB 26*53742Seric static char sccsid[] = "@(#)alias.c 5.33 (Berkeley) 05/29/92 (with NEWDB)"; 2751756Seric #else 2833728Sbostic #ifdef DBM 29*53742Seric static char sccsid[] = "@(#)alias.c 5.33 (Berkeley) 05/29/92 (with DBM)"; 3033728Sbostic #else 31*53742Seric static char sccsid[] = "@(#)alias.c 5.33 (Berkeley) 05/29/92 (without DBM)"; 3233728Sbostic #endif 3350575Seric #endif 3433728Sbostic #endif /* not lint */ 3551756Seric /* 36292Seric ** ALIAS -- Compute aliases. 37292Seric ** 389368Seric ** Scans the alias file for an alias for the given address. 399368Seric ** If found, it arranges to deliver to the alias list instead. 409368Seric ** Uses libdbm database if -DDBM. 41292Seric ** 42292Seric ** Parameters: 434097Seric ** a -- address to alias. 444999Seric ** sendq -- a pointer to the head of the send queue 454999Seric ** to put the aliases in. 46292Seric ** 47292Seric ** Returns: 48292Seric ** none 49292Seric ** 50292Seric ** Side Effects: 513185Seric ** Aliases found are expanded. 52292Seric ** 53292Seric ** Notes: 54292Seric ** If NoAlias (the "-n" flag) is set, no aliasing is 55292Seric ** done. 56292Seric ** 57292Seric ** Deficiencies: 58292Seric ** It should complain about names that are aliased to 59292Seric ** nothing. 60292Seric */ 61292Seric 62292Seric 63*53742Seric /* 64*53742Seric ** Sun YP servers read the dbm files directly, so we have to build them 65*53742Seric ** even if NEWDB 66*53742Seric */ 67*53742Seric 681503Smark #ifdef DBM 69*53742Seric # ifndef NEWDB 70*53742Seric # define IF_MAKEDBMFILES 71*53742Seric # else 72*53742Seric # ifdef YPCOMPAT 73*53742Seric # define IF_MAKEDBMFILES if (makedbmfiles) 74*53742Seric # endif 75*53742Seric # endif 76*53742Seric #endif 77*53742Seric 78*53742Seric #ifdef DBM 7951756Seric #ifndef NEWDB 802966Seric typedef struct 812966Seric { 8250575Seric char *data; 8350575Seric int size; 8450575Seric } DBT; 8551756Seric #endif 8650575Seric extern DBT fetch(); 8750575Seric #endif /* DBM */ 88292Seric 8950575Seric #ifdef NEWDB 9050575Seric static DB *AliasDBptr; 9150575Seric #endif 9250575Seric 934999Seric alias(a, sendq) 944097Seric register ADDRESS *a; 954999Seric ADDRESS **sendq; 96292Seric { 974081Seric register char *p; 985701Seric extern char *aliaslookup(); 99292Seric 1007671Seric if (tTd(27, 1)) 1014098Seric printf("alias(%s)\n", a->q_paddr); 102292Seric 1034098Seric /* don't realias already aliased names */ 1044098Seric if (bitset(QDONTSEND, a->q_flags)) 1054098Seric return; 1064098Seric 1076898Seric CurEnv->e_to = a->q_paddr; 1084098Seric 1094314Seric /* 1104314Seric ** Look up this name 1114314Seric */ 1124314Seric 11324944Seric if (NoAlias) 11424944Seric p = NULL; 11524944Seric else 11624944Seric p = aliaslookup(a->q_user); 1174098Seric if (p == NULL) 1184098Seric return; 119292Seric 120292Seric /* 1214098Seric ** Match on Alias. 1224098Seric ** Deliver to the target list. 1231515Seric */ 1241515Seric 1257671Seric if (tTd(27, 1)) 1264098Seric printf("%s (%s, %s) aliased to %s\n", 1274098Seric a->q_paddr, a->q_host, a->q_user, p); 1287051Seric message(Arpa_Info, "aliased to %s", p); 1294098Seric AliasLevel++; 1309614Seric sendtolist(p, a, sendq); 1314098Seric AliasLevel--; 1324098Seric } 1334098Seric /* 1345701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1355701Seric ** 1365701Seric ** Parameters: 1375701Seric ** name -- the name to look up. 1385701Seric ** 1395701Seric ** Returns: 1405701Seric ** the value of name. 1415701Seric ** NULL if unknown. 1425701Seric ** 1435701Seric ** Side Effects: 1445701Seric ** none. 1455701Seric ** 1465701Seric ** Warnings: 1475701Seric ** The return value will be trashed across calls. 1485701Seric */ 1495701Seric 1505701Seric char * 1515701Seric aliaslookup(name) 1525701Seric char *name; 1535701Seric { 15450575Seric # if defined(NEWDB) || defined(DBM) 15550575Seric DBT rhs, lhs; 15650575Seric int s; 1575701Seric 1585701Seric /* create a key for fetch */ 15950575Seric lhs.data = name; 16050575Seric lhs.size = strlen(name) + 1; 16150575Seric # ifdef NEWDB 16251756Seric if (AliasDBptr != NULL) 16351756Seric { 16451756Seric s = AliasDBptr->get(AliasDBptr, &lhs, &rhs, 0); 16551756Seric if (s == 0) 16651756Seric return (rhs.data); 16751756Seric } 16851756Seric # ifdef DBM 16951756Seric else 17051756Seric { 17151756Seric rhs = fetch(lhs); 17251756Seric return (rhs.data); 17351756Seric } 17451756Seric # endif 17550575Seric # else 1765701Seric rhs = fetch(lhs); 17751756Seric return (rhs.data); 17850575Seric # endif 17951756Seric # else /* neither NEWDB nor DBM */ 1805701Seric register STAB *s; 1815701Seric 1825701Seric s = stab(name, ST_ALIAS, ST_FIND); 18351756Seric if (s != NULL) 18451756Seric return (s->s_alias); 18551756Seric # endif 18651756Seric return (NULL); 1875701Seric } 1885701Seric /* 1894098Seric ** INITALIASES -- initialize for aliasing 1904098Seric ** 1914098Seric ** Very different depending on whether we are running DBM or not. 1924098Seric ** 1934098Seric ** Parameters: 1944098Seric ** aliasfile -- location of aliases. 1954157Seric ** init -- if set and if DBM, initialize the DBM files. 1964098Seric ** 1974098Seric ** Returns: 1984098Seric ** none. 1994098Seric ** 2004098Seric ** Side Effects: 2014098Seric ** initializes aliases: 2024098Seric ** if DBM: opens the database. 2034098Seric ** if ~DBM: reads the aliases into the symbol table. 2044098Seric */ 2054098Seric 20640559Sbostic # define DBMMODE 0644 2074157Seric 2084157Seric initaliases(aliasfile, init) 2094098Seric char *aliasfile; 2104157Seric bool init; 2114098Seric { 21250575Seric #if defined(DBM) || defined(NEWDB) 2138437Seric int atcnt; 21425522Seric time_t modtime; 21525522Seric bool automatic = FALSE; 2164322Seric char buf[MAXNAME]; 21750575Seric #endif 2189368Seric struct stat stb; 21927176Seric static bool initialized = FALSE; 22046928Sbostic static int readaliases(); 2214322Seric 22227176Seric if (initialized) 22327176Seric return; 22427176Seric initialized = TRUE; 22527176Seric 22617984Seric if (aliasfile == NULL || stat(aliasfile, &stb) < 0) 2278437Seric { 22825522Seric if (aliasfile != NULL && init) 22925522Seric syserr("Cannot open %s", aliasfile); 2308437Seric NoAlias = TRUE; 23111937Seric errno = 0; 2328437Seric return; 2338437Seric } 2348437Seric 23550575Seric # if defined(DBM) || defined(NEWDB) 2364322Seric /* 2378437Seric ** Check to see that the alias file is complete. 2388437Seric ** If not, we will assume that someone died, and it is up 2398437Seric ** to us to rebuild it. 2408437Seric */ 2418437Seric 24225689Seric if (!init) 24350575Seric { 24450575Seric # ifdef NEWDB 24550575Seric (void) strcpy(buf, aliasfile); 24650575Seric (void) strcat(buf, ".db"); 24751171Sbostic AliasDBptr = dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 24850576Seric if (AliasDBptr == NULL) 24950576Seric { 25051756Seric # ifdef DBM 25151756Seric dbminit(aliasfile); 25251756Seric # else 25350576Seric syserr("initaliases: cannot open %s", buf); 25450576Seric NoAlias = TRUE; 25550576Seric return; 25651756Seric # endif 25750576Seric } 25850575Seric # else 25925689Seric dbminit(aliasfile); 26050575Seric # endif 26150575Seric } 26217471Seric atcnt = SafeAlias * 2; 26317471Seric if (atcnt > 0) 26417471Seric { 26517471Seric while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL) 26625689Seric { 26725689Seric /* 26825689Seric ** Reinitialize alias file in case the new 26925689Seric ** one is mv'ed in instead of cp'ed in. 27025689Seric ** 27125689Seric ** Only works with new DBM -- old one will 27225689Seric ** just consume file descriptors forever. 27325689Seric ** If you have a dbmclose() it can be 27425689Seric ** added before the sleep(30). 27525689Seric */ 27625689Seric 27750575Seric # ifdef NEWDB 27851756Seric if (AliasDBptr != NULL) 27951756Seric AliasDBptr->close(AliasDBptr); 28050575Seric # endif 28150575Seric 28217471Seric sleep(30); 28350575Seric # ifdef NEWDB 28450575Seric (void) strcpy(buf, aliasfile); 28550575Seric (void) strcat(buf, ".db"); 28651171Sbostic AliasDBptr = 28751171Sbostic dbopen(buf, O_RDONLY, DBMMODE, DB_HASH, NULL); 28850576Seric if (AliasDBptr == NULL) 28950576Seric { 29051756Seric # ifdef NDBM 29151756Seric dbminit(aliasfile); 29251756Seric # else 29350576Seric syserr("initaliases: cannot open %s", buf); 29450576Seric NoAlias = TRUE; 29550576Seric return; 29651756Seric # endif 29750576Seric } 29850575Seric # else 29925689Seric # ifdef NDBM 30025689Seric dbminit(aliasfile); 30150575Seric # endif 30250575Seric # endif 30325689Seric } 30417471Seric } 30517471Seric else 30617471Seric atcnt = 1; 3078437Seric 3088437Seric /* 3094322Seric ** See if the DBM version of the file is out of date with 3104322Seric ** the text version. If so, go into 'init' mode automatically. 31140559Sbostic ** This only happens if our effective userid owns the DBM. 31240559Sbostic ** Note the unpalatable hack to see if the stat succeeded. 3134322Seric */ 3144322Seric 3154322Seric modtime = stb.st_mtime; 3164322Seric (void) strcpy(buf, aliasfile); 31750575Seric # ifdef NEWDB 31850575Seric (void) strcat(buf, ".db"); 31950575Seric # else 3204322Seric (void) strcat(buf, ".pag"); 32150575Seric # endif 3224322Seric stb.st_ino = 0; 32319039Seric if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0)) 3244322Seric { 32511937Seric errno = 0; 32640559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3274322Seric { 3284322Seric init = TRUE; 32925522Seric automatic = TRUE; 3307051Seric message(Arpa_Info, "rebuilding alias database"); 33124944Seric #ifdef LOG 33224944Seric if (LogLevel >= 7) 33324944Seric syslog(LOG_INFO, "rebuilding alias database"); 33424944Seric #endif LOG 3354322Seric } 3364322Seric else 3374322Seric { 33819039Seric #ifdef LOG 33924944Seric if (LogLevel >= 7) 34024944Seric syslog(LOG_INFO, "alias database out of date"); 34119039Seric #endif LOG 3424322Seric message(Arpa_Info, "Warning: alias database out of date"); 3434322Seric } 3444322Seric } 3454322Seric 3464322Seric 3474322Seric /* 3488437Seric ** If necessary, load the DBM file. 3494322Seric ** If running without DBM, load the symbol table. 3504322Seric */ 3514322Seric 3524157Seric if (init) 3538437Seric { 35425522Seric #ifdef LOG 35525522Seric if (LogLevel >= 6) 35625522Seric { 35725522Seric extern char *username(); 35825522Seric 35925522Seric syslog(LOG_NOTICE, "alias database %srebuilt by %s", 36025522Seric automatic ? "auto" : "", username()); 36125522Seric } 36225522Seric #endif LOG 3634157Seric readaliases(aliasfile, TRUE); 3648437Seric } 3654098Seric # else DBM 3664157Seric readaliases(aliasfile, init); 3674157Seric # endif DBM 3684157Seric } 3694157Seric /* 3704157Seric ** READALIASES -- read and process the alias file. 3714157Seric ** 3724157Seric ** This routine implements the part of initaliases that occurs 3734157Seric ** when we are not going to use the DBM stuff. 3744157Seric ** 3754157Seric ** Parameters: 3764157Seric ** aliasfile -- the pathname of the alias file master. 3774157Seric ** init -- if set, initialize the DBM stuff. 3784157Seric ** 3794157Seric ** Returns: 3804157Seric ** none. 3814157Seric ** 3824157Seric ** Side Effects: 3834157Seric ** Reads aliasfile into the symbol table. 3844157Seric ** Optionally, builds the .dir & .pag files. 3854157Seric */ 3864157Seric 3874157Seric static 3884157Seric readaliases(aliasfile, init) 3894157Seric char *aliasfile; 3904157Seric bool init; 3914157Seric { 3924098Seric register char *p; 3934098Seric char *rhs; 3944098Seric bool skipping; 3959368Seric int naliases, bytes, longest; 3969368Seric FILE *af; 397*53742Seric bool makedbmfiles; 39840970Sbostic void (*oldsigint)(); 3994098Seric ADDRESS al, bl; 4004106Seric register STAB *s; 40150575Seric # ifdef NEWDB 40250575Seric DB *dbp; 40350575Seric # endif 40451937Seric # ifdef LOCKF 40551937Seric struct flock fld; 40651937Seric # endif 4079368Seric char line[BUFSIZ]; 4084098Seric 40951937Seric if ((af = fopen(aliasfile, "r+")) == NULL) 4101515Seric { 4117671Seric if (tTd(27, 1)) 4124106Seric printf("Can't open %s\n", aliasfile); 4134098Seric errno = 0; 4144098Seric NoAlias++; 4154098Seric return; 4164098Seric } 4174314Seric 41850575Seric # if defined(DBM) || defined(NEWDB) 41919784Seric /* see if someone else is rebuilding the alias file already */ 42051835Seric # ifdef LOCKF 42151937Seric fld.l_type = F_WRLCK; 42251937Seric fld.l_whence = fld.l_start = fld.l_len = 0; 42351937Seric if (fcntl(fileno(af), F_SETLK, &fld) < 0) 42451835Seric # else 42519784Seric if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK) 42651835Seric # endif 42719784Seric { 42819784Seric /* yes, they are -- wait until done and then return */ 42919784Seric message(Arpa_Info, "Alias file is already being rebuilt"); 43019784Seric if (OpMode != MD_INITALIAS) 43119784Seric { 43219784Seric /* wait for other rebuild to complete */ 43351835Seric # ifdef LOCKF 43451937Seric (void) fcntl(fileno(af), F_SETLKW, &fld); 43551835Seric # else 43619784Seric (void) flock(fileno(af), LOCK_EX); 43751835Seric # endif 43819784Seric } 43923108Seric (void) fclose(af); 44019784Seric errno = 0; 44119784Seric return; 44219784Seric } 44319784Seric # endif DBM 44419784Seric 4454314Seric /* 44619784Seric ** If initializing, create the new DBM files. 44719784Seric */ 44819784Seric 44919784Seric if (init) 45019784Seric { 45119784Seric oldsigint = signal(SIGINT, SIG_IGN); 45251756Seric # ifdef NEWDB 45351756Seric (void) strcpy(line, aliasfile); 45451756Seric (void) strcat(line, ".db"); 45551756Seric dbp = dbopen(line, 45651756Seric O_RDWR|O_CREAT|O_TRUNC, DBMMODE, DB_HASH, NULL); 45751756Seric if (dbp == NULL) 45851756Seric { 45951756Seric syserr("readaliases: cannot create %s", line); 46051756Seric (void) signal(SIGINT, oldsigint); 46151756Seric return; 46251756Seric } 463*53742Seric # endif 464*53742Seric # ifdef IF_MAKEDBMFILES 465*53742Seric # ifdef NEWDB 466*53742Seric makedbmfiles = access("/var/yp/Makefile", R_OK) == 0; 467*53742Seric # endif 468*53742Seric IF_MAKEDBMFILES 46919784Seric { 470*53742Seric (void) strcpy(line, aliasfile); 471*53742Seric (void) strcat(line, ".dir"); 472*53742Seric if (close(creat(line, DBMMODE)) < 0) 473*53742Seric { 474*53742Seric syserr("cannot make %s", line); 475*53742Seric (void) signal(SIGINT, oldsigint); 476*53742Seric return; 477*53742Seric } 478*53742Seric (void) strcpy(line, aliasfile); 479*53742Seric (void) strcat(line, ".pag"); 480*53742Seric if (close(creat(line, DBMMODE)) < 0) 481*53742Seric { 482*53742Seric syserr("cannot make %s", line); 483*53742Seric (void) signal(SIGINT, oldsigint); 484*53742Seric return; 485*53742Seric } 486*53742Seric dbminit(aliasfile); 48719784Seric } 48850575Seric # endif 48919784Seric } 49019784Seric 49119784Seric /* 4924314Seric ** Read and interpret lines 4934314Seric */ 4944314Seric 4959368Seric FileName = aliasfile; 4969368Seric LineNumber = 0; 4974322Seric naliases = bytes = longest = 0; 4984098Seric skipping = FALSE; 4994098Seric while (fgets(line, sizeof (line), af) != NULL) 5004098Seric { 5014322Seric int lhssize, rhssize; 5024322Seric 5039368Seric LineNumber++; 50425278Seric p = index(line, '\n'); 50525278Seric if (p != NULL) 50625278Seric *p = '\0'; 5074098Seric switch (line[0]) 5084098Seric { 5094098Seric case '#': 5104098Seric case '\0': 5114098Seric skipping = FALSE; 5124098Seric continue; 5134065Seric 5144098Seric case ' ': 5154098Seric case '\t': 5164098Seric if (!skipping) 5179368Seric syserr("Non-continuation line starts with space"); 5184098Seric skipping = TRUE; 5194097Seric continue; 5204098Seric } 5214098Seric skipping = FALSE; 5221874Seric 5234314Seric /* 5244314Seric ** Process the LHS 5254314Seric ** Find the final colon, and parse the address. 52616898Seric ** It should resolve to a local name -- this will 52716898Seric ** be checked later (we want to optionally do 52816898Seric ** parsing of the RHS first to maximize error 52916898Seric ** detection). 5304314Seric */ 5314314Seric 5324098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5334097Seric continue; 53416898Seric if (*p++ != ':') 5354098Seric { 5369368Seric syserr("missing colon"); 5374097Seric continue; 5384098Seric } 53916898Seric if (parseaddr(line, &al, 1, ':') == NULL) 5404098Seric { 54116898Seric syserr("illegal alias name"); 54216898Seric continue; 5434098Seric } 54416898Seric loweraddr(&al); 5454314Seric 5464314Seric /* 5474314Seric ** Process the RHS. 5484314Seric ** 'al' is the internal form of the LHS address. 5494314Seric ** 'p' points to the text of the RHS. 5504314Seric */ 5514314Seric 5524098Seric rhs = p; 5534098Seric for (;;) 5544098Seric { 5554098Seric register char c; 5561515Seric 55725821Seric if (init && CheckAliases) 5584098Seric { 5594157Seric /* do parsing & compression of addresses */ 56025278Seric while (*p != '\0') 5614098Seric { 56225278Seric extern char *DelimChar; 56325278Seric 56425278Seric while (isspace(*p) || *p == ',') 5654157Seric p++; 56625278Seric if (*p == '\0') 56725278Seric break; 56825278Seric if (parseaddr(p, &bl, -1, ',') == NULL) 56925278Seric usrerr("%s... bad address", p); 57025278Seric p = DelimChar; 5714098Seric } 5724098Seric } 5734157Seric else 57415769Seric { 57516898Seric p = &p[strlen(p)]; 57616898Seric if (p[-1] == '\n') 57716898Seric *--p = '\0'; 57815769Seric } 5791515Seric 5804098Seric /* see if there should be a continuation line */ 5814106Seric c = fgetc(af); 5824106Seric if (!feof(af)) 5834314Seric (void) ungetc(c, af); 5844106Seric if (c != ' ' && c != '\t') 5854098Seric break; 5864098Seric 5874098Seric /* read continuation line */ 5884098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 5894098Seric break; 5909368Seric LineNumber++; 5914098Seric } 59216898Seric if (al.q_mailer != LocalMailer) 59316898Seric { 59416898Seric syserr("cannot alias non-local names"); 59516898Seric continue; 59616898Seric } 5974314Seric 5984314Seric /* 5994314Seric ** Insert alias into symbol table or DBM file 6004314Seric */ 6014314Seric 60216898Seric lhssize = strlen(al.q_user) + 1; 6034322Seric rhssize = strlen(rhs) + 1; 6044322Seric 60550575Seric # if defined(DBM) || defined(NEWDB) 6064157Seric if (init) 6074157Seric { 60850575Seric DBT key, content; 6094157Seric 61050575Seric key.size = lhssize; 61150575Seric key.data = al.q_user; 61250575Seric content.size = rhssize; 61350575Seric content.data = rhs; 61451756Seric # ifdef NEWDB 61551171Sbostic if (dbp->put(dbp, &key, &content, 0) != 0) 61650576Seric syserr("readaliases: db put (%s)", al.q_user); 61750575Seric # endif 618*53742Seric # ifdef IF_MAKEDBMFILES 619*53742Seric IF_MAKEDBMFILES 620*53742Seric store(key, content); 621*53742Seric # endif 6224157Seric } 6234157Seric else 6244157Seric # endif DBM 6254157Seric { 6264157Seric s = stab(al.q_user, ST_ALIAS, ST_ENTER); 6274157Seric s->s_alias = newstr(rhs); 6284157Seric } 6294322Seric 6304322Seric /* statistics */ 6314322Seric naliases++; 6324322Seric bytes += lhssize + rhssize; 6334322Seric if (rhssize > longest) 6344322Seric longest = rhssize; 6351515Seric } 63619784Seric 63750575Seric # if defined(DBM) || defined(NEWDB) 63819784Seric if (init) 63919784Seric { 64019784Seric /* add the distinquished alias "@" */ 64150575Seric DBT key; 64219784Seric 64350575Seric key.size = 2; 64450575Seric key.data = "@"; 64550575Seric # ifdef NEWDB 64650576Seric if (dbp->sync(dbp) != 0 || 64751171Sbostic dbp->put(dbp, &key, &key, 0) != 0 || 64850576Seric dbp->close(dbp) != 0) 64950576Seric syserr("readaliases: db close failure"); 650*53742Seric # endif 651*53742Seric # ifdef MAKEDBMFILES 65219784Seric store(key, key); 65350575Seric # endif 65419784Seric 65519784Seric /* restore the old signal */ 65619784Seric (void) signal(SIGINT, oldsigint); 65719784Seric } 65819784Seric # endif DBM 65919784Seric 66019784Seric /* closing the alias file drops the lock */ 6614098Seric (void) fclose(af); 6626898Seric CurEnv->e_to = NULL; 6639368Seric FileName = NULL; 6647051Seric message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total", 6654322Seric naliases, longest, bytes); 66624944Seric # ifdef LOG 66724944Seric if (LogLevel >= 8) 66824944Seric syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total", 66924944Seric naliases, longest, bytes); 67024944Seric # endif LOG 671292Seric } 672292Seric /* 673292Seric ** FORWARD -- Try to forward mail 674292Seric ** 675292Seric ** This is similar but not identical to aliasing. 676292Seric ** 677292Seric ** Parameters: 6784314Seric ** user -- the name of the user who's mail we would like 6794314Seric ** to forward to. It must have been verified -- 6804314Seric ** i.e., the q_home field must have been filled 6814314Seric ** in. 6824999Seric ** sendq -- a pointer to the head of the send queue to 6834999Seric ** put this user's aliases in. 684292Seric ** 685292Seric ** Returns: 6864098Seric ** none. 687292Seric ** 688292Seric ** Side Effects: 6893185Seric ** New names are added to send queues. 690292Seric */ 691292Seric 6924999Seric forward(user, sendq) 6932966Seric ADDRESS *user; 6944999Seric ADDRESS **sendq; 695292Seric { 6964078Seric char buf[60]; 6974536Seric extern bool safefile(); 6984069Seric 6997671Seric if (tTd(27, 1)) 7004098Seric printf("forward(%s)\n", user->q_paddr); 7014098Seric 7024594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 7034098Seric return; 7044314Seric if (user->q_home == NULL) 7054314Seric syserr("forward: no home"); 7064069Seric 7074069Seric /* good address -- look for .forward file in home */ 7089368Seric define('z', user->q_home, CurEnv); 70916154Seric expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv); 71053037Seric include(buf, TRUE, user, sendq); 711292Seric } 712