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 958332Seric # include "sendmail.h" 1050577Seric # include <signal.h> 1150577Seric # include <pwd.h> 1256766Seric 1333728Sbostic #ifndef lint 14*60089Seric static char sccsid[] = "@(#)alias.c 6.46 (Berkeley) 05/17/93"; 1533728Sbostic #endif /* not lint */ 1659673Seric 1759673Seric 18*60089Seric MAP AliasDB[MAXALIASDB + 1]; /* actual database list */ 1959673Seric int NAliasDBs; /* number of alias databases */ 2059673Seric /* 21292Seric ** ALIAS -- Compute aliases. 22292Seric ** 239368Seric ** Scans the alias file for an alias for the given address. 249368Seric ** If found, it arranges to deliver to the alias list instead. 259368Seric ** Uses libdbm database if -DDBM. 26292Seric ** 27292Seric ** Parameters: 284097Seric ** a -- address to alias. 294999Seric ** sendq -- a pointer to the head of the send queue 304999Seric ** to put the aliases in. 3158092Seric ** e -- the current envelope. 32292Seric ** 33292Seric ** Returns: 34292Seric ** none 35292Seric ** 36292Seric ** Side Effects: 373185Seric ** Aliases found are expanded. 38292Seric ** 39292Seric ** Deficiencies: 40292Seric ** It should complain about names that are aliased to 41292Seric ** nothing. 42292Seric */ 43292Seric 4455012Seric alias(a, sendq, e) 454097Seric register ADDRESS *a; 464999Seric ADDRESS **sendq; 4755012Seric register ENVELOPE *e; 48292Seric { 494081Seric register char *p; 5058082Seric int naliases; 5158170Seric char *owner; 5258170Seric char obuf[MAXNAME + 6]; 535701Seric extern char *aliaslookup(); 54292Seric 557671Seric if (tTd(27, 1)) 564098Seric printf("alias(%s)\n", a->q_paddr); 57292Seric 584098Seric /* don't realias already aliased names */ 5958680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) 604098Seric return; 614098Seric 6259673Seric if (NoAlias) 6359673Seric return; 6459673Seric 6555012Seric e->e_to = a->q_paddr; 664098Seric 674314Seric /* 684314Seric ** Look up this name 694314Seric */ 704314Seric 7159673Seric p = aliaslookup(a->q_user, e); 724098Seric if (p == NULL) 734098Seric return; 74292Seric 75292Seric /* 764098Seric ** Match on Alias. 774098Seric ** Deliver to the target list. 781515Seric */ 791515Seric 807671Seric if (tTd(27, 1)) 814098Seric printf("%s (%s, %s) aliased to %s\n", 824098Seric a->q_paddr, a->q_host, a->q_user, p); 8358092Seric if (bitset(EF_VRFYONLY, e->e_flags)) 8458154Seric { 8558154Seric a->q_flags |= QVERIFIED; 8658884Seric e->e_nrcpts++; 8758092Seric return; 8858154Seric } 8958154Seric message("aliased to %s", p); 9057977Seric #ifdef LOG 9158020Seric if (LogLevel > 9) 9257977Seric syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p); 9357977Seric #endif 9458082Seric a->q_flags &= ~QSELFREF; 954098Seric AliasLevel++; 9658082Seric naliases = sendtolist(p, a, sendq, e); 974098Seric AliasLevel--; 9858082Seric if (naliases > 0 && !bitset(QSELFREF, a->q_flags)) 9958065Seric { 10058065Seric if (tTd(27, 5)) 10158065Seric { 10258065Seric printf("alias: QDONTSEND "); 10358065Seric printaddr(a, FALSE); 10458065Seric } 10558065Seric a->q_flags |= QDONTSEND; 10658065Seric } 10758170Seric 10858170Seric /* 10958170Seric ** Look for owner of alias 11058170Seric */ 11158170Seric 11258170Seric (void) strcpy(obuf, "owner-"); 11358170Seric if (strncmp(a->q_user, "owner-", 6) == 0) 11458170Seric (void) strcat(obuf, "owner"); 11558170Seric else 11658170Seric (void) strcat(obuf, a->q_user); 11758170Seric if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags)) 11858170Seric makelower(obuf); 11959673Seric owner = aliaslookup(obuf, e); 12058170Seric if (owner != NULL) 12158170Seric { 12258170Seric if (strchr(owner, ',') != NULL) 12358170Seric owner = obuf; 12458170Seric a->q_owner = newstr(owner); 12558170Seric } 1264098Seric } 1274098Seric /* 1285701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1295701Seric ** 1305701Seric ** Parameters: 1315701Seric ** name -- the name to look up. 1325701Seric ** 1335701Seric ** Returns: 1345701Seric ** the value of name. 1355701Seric ** NULL if unknown. 1365701Seric ** 1375701Seric ** Side Effects: 1385701Seric ** none. 1395701Seric ** 1405701Seric ** Warnings: 1415701Seric ** The return value will be trashed across calls. 1425701Seric */ 1435701Seric 1445701Seric char * 14559673Seric aliaslookup(name, e) 1465701Seric char *name; 14759673Seric ENVELOPE *e; 1485701Seric { 14959673Seric register int dbno; 150*60089Seric register MAP *map; 15159673Seric register char *p; 152*60089Seric char *nullargv[1]; 1535701Seric 154*60089Seric nullargv[0] = NULL; 15559673Seric for (dbno = 0; dbno < NAliasDBs; dbno++) 15659673Seric { 157*60089Seric auto int stat; 158*60089Seric 159*60089Seric map = &AliasDB[dbno]; 160*60089Seric if (!bitset(MF_VALID, map->map_flags)) 16159673Seric continue; 162*60089Seric p = (*map->map_class->map_lookup)(map, name, nullargv, &stat); 16359673Seric if (p != NULL) 16459673Seric return p; 16559673Seric } 16659673Seric return NULL; 16759673Seric } 16859673Seric /* 16959673Seric ** SETALIAS -- set up an alias map 17059673Seric ** 17159673Seric ** Called when reading configuration file. 17259673Seric ** 17359673Seric ** Parameters: 17459673Seric ** spec -- the alias specification 17559673Seric ** 17659673Seric ** Returns: 17759673Seric ** none. 17859673Seric */ 17957381Seric 18059673Seric setalias(spec) 18159673Seric char *spec; 18259673Seric { 18359673Seric register char *p; 184*60089Seric register MAP *map; 18559673Seric char *class; 18659673Seric STAB *s; 18759673Seric 18859697Seric if (tTd(27, 8)) 18959697Seric printf("setalias(%s)\n", spec); 19059697Seric 19159758Seric for (p = spec; p != NULL; ) 19251756Seric { 19359758Seric while (isspace(*p)) 19459758Seric p++; 19559758Seric if (*p == NULL) 19659673Seric break; 19759673Seric spec = p; 19859673Seric 19959758Seric if (NAliasDBs >= MAXALIASDB) 20059758Seric { 20159758Seric syserr("Too many alias databases defined, %d max", MAXALIASDB); 20259758Seric return; 20359758Seric } 204*60089Seric map = &AliasDB[NAliasDBs]; 205*60089Seric bzero(map, sizeof *map); 20659758Seric 20759758Seric p = strpbrk(p, " ,/:"); 20859758Seric if (p != NULL && *p == ':') 20959758Seric { 210*60089Seric /* map name */ 21159758Seric *p++ = '\0'; 21259758Seric class = spec; 21359758Seric spec = p; 21459758Seric } 21559758Seric else 21659758Seric { 21759758Seric class = "implicit"; 218*60089Seric map->map_flags = MF_OPTIONAL; 21959758Seric } 22059758Seric 22159758Seric /* find end of spec */ 22259758Seric if (p != NULL) 22359758Seric p = strchr(p, ','); 22459758Seric if (p != NULL) 22559758Seric *p++ = '\0'; 22659758Seric 22759758Seric /* look up class */ 228*60089Seric s = stab(class, ST_MAPCLASS, ST_FIND); 22959758Seric if (s == NULL) 23059758Seric { 23159758Seric if (tTd(27, 1)) 23259758Seric printf("Unknown alias class %s\n", class); 23359758Seric } 23459758Seric else 23559758Seric { 236*60089Seric map->map_class = s->s_mapclass; 237*60089Seric if (map->map_class->map_parse(map, spec)) 238*60089Seric { 239*60089Seric map->map_flags |= MF_VALID; 240*60089Seric NAliasDBs++; 241*60089Seric } 24259758Seric } 24359756Seric } 2445701Seric } 2455701Seric /* 2464098Seric ** INITALIASES -- initialize for aliasing 2474098Seric ** 24856845Seric ** Very different depending on whether we are running NDBM or not. 2494098Seric ** 2504098Seric ** Parameters: 25159673Seric ** rebuild -- if TRUE, this rebuilds the cached versions. 25259673Seric ** e -- current envelope. 2534098Seric ** 2544098Seric ** Returns: 2554098Seric ** none. 2564098Seric ** 2574098Seric ** Side Effects: 2584098Seric ** initializes aliases: 25956845Seric ** if NDBM: opens the database. 26056845Seric ** if ~NDBM: reads the aliases into the symbol table. 2614098Seric */ 2624098Seric 26340559Sbostic # define DBMMODE 0644 2644157Seric 26559673Seric initaliases(rebuild, e) 26659673Seric bool rebuild; 26755012Seric register ENVELOPE *e; 2684098Seric { 26959673Seric int dbno; 270*60089Seric register MAP *map; 2714322Seric 27259673Seric for (dbno = 0; dbno < NAliasDBs; dbno++) 2738437Seric { 274*60089Seric map = &AliasDB[dbno]; 27559697Seric 27659697Seric if (tTd(27, 2)) 27759697Seric printf("initaliases(%s:%s)\n", 278*60089Seric map->map_class->map_cname, map->map_file); 27959697Seric 28059673Seric if (rebuild) 28150576Seric { 282*60089Seric rebuildaliases(map, FALSE, e); 28350576Seric } 28459673Seric else 28557249Seric { 286*60089Seric if (map->map_class->map_open(map, O_RDONLY)) 28759756Seric { 28859756Seric if (tTd(27, 4)) 28959756Seric printf("%s:%s: valid\n", 290*60089Seric map->map_class->map_cname, 291*60089Seric map->map_file); 292*60089Seric map->map_flags |= MF_VALID; 293*60089Seric aliaswait(map, e); 29459756Seric } 29559756Seric else if (tTd(27, 4)) 29659756Seric printf("%s:%s: invalid: %s\n", 297*60089Seric map->map_class->map_cname, map->map_file, 29859756Seric errstring(errno)); 29957249Seric } 30050575Seric } 30159673Seric } 30259673Seric /* 30359673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear. 30459673Seric ** 30559673Seric ** This can decide to reopen or rebuild the alias file 30659673Seric */ 30759673Seric 308*60089Seric aliaswait(map, e) 309*60089Seric MAP *map; 31059673Seric ENVELOPE *e; 31159673Seric { 31259673Seric int atcnt; 31359673Seric time_t mtime; 31459673Seric struct stat stb; 31559673Seric char buf[MAXNAME]; 31659673Seric 31759697Seric if (tTd(27, 3)) 31859697Seric printf("aliaswait\n"); 31959697Seric 32017471Seric atcnt = SafeAlias * 2; 32117471Seric if (atcnt > 0) 32217471Seric { 323*60089Seric auto int st; 324*60089Seric 32559673Seric while (atcnt-- >= 0 && 326*60089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 32725689Seric { 32825689Seric /* 32959673Seric ** Close and re-open the alias database in case 33059673Seric ** the one is mv'ed instead of cp'ed in. 33125689Seric */ 33225689Seric 33359697Seric if (tTd(27, 2)) 33459697Seric printf("aliaswait: sleeping\n"); 33559697Seric 336*60089Seric map->map_class->map_close(map); 33717471Seric sleep(30); 338*60089Seric map->map_class->map_open(map, O_RDONLY); 33925689Seric } 34017471Seric } 3418437Seric 34259673Seric /* see if we need to go into auto-rebuild mode */ 343*60089Seric if (map->map_class->map_rebuild == NULL || 344*60089Seric stat(map->map_file, &stb) < 0) 34559673Seric return; 34659673Seric mtime = stb.st_mtime; 347*60089Seric (void) strcpy(buf, map->map_file); 348*60089Seric if (map->map_class->map_ext != NULL) 349*60089Seric (void) strcat(buf, map->map_class->map_ext); 35059673Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0) 3514322Seric { 35259673Seric /* database is out of date */ 35340559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3544322Seric { 355*60089Seric message("auto-rebuilding alias database %s", buf); 356*60089Seric rebuildaliases(map, TRUE, e); 3574322Seric } 3584322Seric else 3594322Seric { 36019039Seric #ifdef LOG 36158020Seric if (LogLevel > 3) 36259673Seric syslog(LOG_INFO, "alias database %s out of date", 363*60089Seric buf); 36456795Seric #endif /* LOG */ 365*60089Seric message("Warning: alias database %s out of date", buf); 3664322Seric } 3674322Seric } 36859673Seric } 36959673Seric /* 37059673Seric ** REBUILDALIASES -- rebuild the alias database. 37159673Seric ** 37259673Seric ** Parameters: 373*60089Seric ** map -- the database to rebuild. 37459673Seric ** automatic -- set if this was automatically generated. 37559673Seric ** e -- current envelope. 37659673Seric ** 37759673Seric ** Returns: 37859673Seric ** none. 37959673Seric ** 38059673Seric ** Side Effects: 38159673Seric ** Reads the text version of the database, builds the 38259673Seric ** DBM or DB version. 38359673Seric */ 3844322Seric 385*60089Seric rebuildaliases(map, automatic, e) 386*60089Seric register MAP *map; 38759673Seric bool automatic; 38859673Seric register ENVELOPE *e; 38959673Seric { 39059673Seric FILE *af; 39159673Seric void (*oldsigint)(); 3924322Seric 393*60089Seric if (map->map_class->map_rebuild == NULL) 39459673Seric return; 3954322Seric 39659673Seric #ifdef LOG 39759673Seric if (LogLevel > 7) 3988437Seric { 39959673Seric extern char *username(); 40025522Seric 40159673Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 402*60089Seric map->map_file, automatic ? "auto" : "", username()); 40359673Seric } 40456795Seric #endif /* LOG */ 40559673Seric 40659673Seric /* try to lock the source file */ 407*60089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 40859673Seric { 40959756Seric if (tTd(27, 1)) 41059756Seric printf("Can't open %s: %s\n", 411*60089Seric map->map_file, errstring(errno)); 412*60089Seric map->map_flags &= ~MF_VALID; 41359673Seric errno = 0; 41459673Seric return; 4158437Seric } 41659673Seric 41759673Seric /* see if someone else is rebuilding the alias file */ 418*60089Seric if (!lockfile(fileno(af), map->map_file, LOCK_EX|LOCK_NB)) 41959673Seric { 42059673Seric /* yes, they are -- wait until done */ 42159673Seric message("Alias file %s is already being rebuilt", 422*60089Seric map->map_file); 42359673Seric if (OpMode != MD_INITALIAS) 42459673Seric { 42559673Seric /* wait for other rebuild to complete */ 426*60089Seric (void) lockfile(fileno(af), map->map_file, 42759673Seric LOCK_EX); 42859673Seric } 42959673Seric (void) fclose(af); 43059673Seric errno = 0; 43159673Seric return; 43259673Seric } 43359673Seric 43459673Seric oldsigint = signal(SIGINT, SIG_IGN); 43559673Seric 436*60089Seric map->map_class->map_open(map, O_RDWR); 437*60089Seric if (bitset(MF_VALID, map->map_flags)) 438*60089Seric { 439*60089Seric map->map_class->map_rebuild(map, af, automatic); 440*60089Seric readaliases(map, af, automatic, e); 441*60089Seric } 44259673Seric 44359673Seric /* close the file, thus releasing locks */ 44459673Seric fclose(af); 44559673Seric 44659673Seric /* add distinguished entries and close the database */ 447*60089Seric if (bitset(MF_VALID, map->map_flags)) 448*60089Seric map->map_class->map_close(map); 44959673Seric 45059673Seric /* restore the old signal */ 45159673Seric (void) signal(SIGINT, oldsigint); 4524157Seric } 4534157Seric /* 4544157Seric ** READALIASES -- read and process the alias file. 4554157Seric ** 4564157Seric ** This routine implements the part of initaliases that occurs 4574157Seric ** when we are not going to use the DBM stuff. 4584157Seric ** 4594157Seric ** Parameters: 460*60089Seric ** map -- the alias database descriptor. 46159673Seric ** af -- file to read the aliases from. 46259733Seric ** automatic -- set if this was an automatic rebuild. 463*60089Seric ** e -- the current envelope. 4644157Seric ** 4654157Seric ** Returns: 4664157Seric ** none. 4674157Seric ** 4684157Seric ** Side Effects: 4694157Seric ** Reads aliasfile into the symbol table. 4704157Seric ** Optionally, builds the .dir & .pag files. 4714157Seric */ 4724157Seric 473*60089Seric readaliases(map, af, automatic, e) 474*60089Seric register MAP *map; 47559673Seric FILE *af; 47659733Seric int automatic; 47755012Seric register ENVELOPE *e; 4784157Seric { 4794098Seric register char *p; 4804098Seric char *rhs; 4814098Seric bool skipping; 48259673Seric long naliases, bytes, longest; 4834098Seric ADDRESS al, bl; 4844106Seric register STAB *s; 4859368Seric char line[BUFSIZ]; 4864098Seric 4874314Seric /* 4884314Seric ** Read and interpret lines 4894314Seric */ 4904314Seric 491*60089Seric FileName = map->map_file; 4929368Seric LineNumber = 0; 4934322Seric naliases = bytes = longest = 0; 4944098Seric skipping = FALSE; 4954098Seric while (fgets(line, sizeof (line), af) != NULL) 4964098Seric { 4974322Seric int lhssize, rhssize; 4984322Seric 4999368Seric LineNumber++; 50056795Seric p = strchr(line, '\n'); 50125278Seric if (p != NULL) 50225278Seric *p = '\0'; 5034098Seric switch (line[0]) 5044098Seric { 5054098Seric case '#': 5064098Seric case '\0': 5074098Seric skipping = FALSE; 5084098Seric continue; 5094065Seric 5104098Seric case ' ': 5114098Seric case '\t': 5124098Seric if (!skipping) 51358151Seric syserr("554 Non-continuation line starts with space"); 5144098Seric skipping = TRUE; 5154097Seric continue; 5164098Seric } 5174098Seric skipping = FALSE; 5181874Seric 5194314Seric /* 5204314Seric ** Process the LHS 52157736Seric ** Find the colon separator, and parse the address. 52216898Seric ** It should resolve to a local name -- this will 52316898Seric ** be checked later (we want to optionally do 52416898Seric ** parsing of the RHS first to maximize error 52516898Seric ** detection). 5264314Seric */ 5274314Seric 5284098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 5294097Seric continue; 53016898Seric if (*p++ != ':') 5314098Seric { 53258151Seric syserr("554 missing colon"); 5334097Seric continue; 5344098Seric } 53558333Seric if (parseaddr(line, &al, 1, ':', NULL, e) == NULL) 5364098Seric { 53758151Seric syserr("554 illegal alias name"); 53816898Seric continue; 5394098Seric } 5404314Seric 5414314Seric /* 5424314Seric ** Process the RHS. 5434314Seric ** 'al' is the internal form of the LHS address. 5444314Seric ** 'p' points to the text of the RHS. 5454314Seric */ 5464314Seric 54758914Seric while (isascii(*p) && isspace(*p)) 54858914Seric p++; 5494098Seric rhs = p; 5504098Seric for (;;) 5514098Seric { 5524098Seric register char c; 55358662Seric register char *nlp; 5541515Seric 55558662Seric nlp = &p[strlen(p)]; 55658662Seric if (nlp[-1] == '\n') 55758662Seric *--nlp = '\0'; 55858662Seric 55959673Seric if (CheckAliases) 5604098Seric { 5614157Seric /* do parsing & compression of addresses */ 56225278Seric while (*p != '\0') 5634098Seric { 56458333Seric auto char *delimptr; 56525278Seric 56658050Seric while ((isascii(*p) && isspace(*p)) || 56758050Seric *p == ',') 5684157Seric p++; 56925278Seric if (*p == '\0') 57025278Seric break; 57158333Seric if (parseaddr(p, &bl, -1, ',', &delimptr, e) == NULL) 57258151Seric usrerr("553 %s... bad address", p); 57358333Seric p = delimptr; 5744098Seric } 5754098Seric } 5764157Seric else 57715769Seric { 57858662Seric p = nlp; 57915769Seric } 5801515Seric 5814098Seric /* see if there should be a continuation line */ 5824106Seric c = fgetc(af); 5834106Seric if (!feof(af)) 5844314Seric (void) ungetc(c, af); 5854106Seric if (c != ' ' && c != '\t') 5864098Seric break; 5874098Seric 5884098Seric /* read continuation line */ 5894098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 5904098Seric break; 5919368Seric LineNumber++; 59257135Seric 59357135Seric /* check for line overflow */ 59457135Seric if (strchr(p, '\n') == NULL) 59557135Seric { 59658151Seric usrerr("554 alias too long"); 59757135Seric break; 59857135Seric } 5994098Seric } 60016898Seric if (al.q_mailer != LocalMailer) 60116898Seric { 60258151Seric syserr("554 cannot alias non-local names"); 60316898Seric continue; 60416898Seric } 6054314Seric 6064314Seric /* 6074314Seric ** Insert alias into symbol table or DBM file 6084314Seric */ 6094314Seric 61057381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 61157381Seric makelower(al.q_user); 6124322Seric 61359673Seric lhssize = strlen(al.q_user); 61459673Seric rhssize = strlen(rhs); 615*60089Seric map->map_class->map_store(map, al.q_user, rhs); 6164157Seric 61759673Seric if (al.q_paddr != NULL) 61859673Seric free(al.q_paddr); 61959673Seric if (al.q_host != NULL) 62059673Seric free(al.q_host); 62159673Seric if (al.q_user != NULL) 62259673Seric free(al.q_user); 6234322Seric 6244322Seric /* statistics */ 6254322Seric naliases++; 6264322Seric bytes += lhssize + rhssize; 6274322Seric if (rhssize > longest) 6284322Seric longest = rhssize; 6291515Seric } 63019784Seric 63159673Seric e->e_to = NULL; 63259673Seric FileName = NULL; 63359733Seric if (Verbose || !automatic) 63459733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 635*60089Seric map->map_file, naliases, longest, bytes); 63659673Seric # ifdef LOG 63759673Seric if (LogLevel > 7) 63859673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 639*60089Seric map->map_file, naliases, longest, bytes); 64059673Seric # endif /* LOG */ 64159673Seric } 64259673Seric /* 643292Seric ** FORWARD -- Try to forward mail 644292Seric ** 645292Seric ** This is similar but not identical to aliasing. 646292Seric ** 647292Seric ** Parameters: 6484314Seric ** user -- the name of the user who's mail we would like 6494314Seric ** to forward to. It must have been verified -- 6504314Seric ** i.e., the q_home field must have been filled 6514314Seric ** in. 6524999Seric ** sendq -- a pointer to the head of the send queue to 6534999Seric ** put this user's aliases in. 654292Seric ** 655292Seric ** Returns: 6564098Seric ** none. 657292Seric ** 658292Seric ** Side Effects: 6593185Seric ** New names are added to send queues. 660292Seric */ 661292Seric 66255012Seric forward(user, sendq, e) 6632966Seric ADDRESS *user; 6644999Seric ADDRESS **sendq; 66555012Seric register ENVELOPE *e; 666292Seric { 66757136Seric char *pp; 66857136Seric char *ep; 6694069Seric 6707671Seric if (tTd(27, 1)) 6714098Seric printf("forward(%s)\n", user->q_paddr); 6724098Seric 6734594Seric if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags)) 6744098Seric return; 6754314Seric if (user->q_home == NULL) 67658059Seric { 67758151Seric syserr("554 forward: no home"); 67858059Seric user->q_home = "/nosuchdirectory"; 67958059Seric } 6804069Seric 6814069Seric /* good address -- look for .forward file in home */ 68255012Seric define('z', user->q_home, e); 68357136Seric define('u', user->q_user, e); 68457136Seric define('h', user->q_host, e); 68557136Seric if (ForwardPath == NULL) 68658050Seric ForwardPath = newstr("\201z/.forward"); 68757136Seric 68857136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 68957136Seric { 69058247Seric int err; 69157232Seric char buf[MAXPATHLEN+1]; 69257136Seric 69357136Seric ep = strchr(pp, ':'); 69457136Seric if (ep != NULL) 69557136Seric *ep = '\0'; 69657136Seric expand(pp, buf, &buf[sizeof buf - 1], e); 69757136Seric if (ep != NULL) 69857136Seric *ep++ = ':'; 69957136Seric if (tTd(27, 3)) 70057136Seric printf("forward: trying %s\n", buf); 70158247Seric err = include(buf, TRUE, user, sendq, e); 70258247Seric if (err == 0) 70357136Seric break; 70458247Seric if (transienterror(err)) 70558247Seric { 70658247Seric /* we have to suspend this message */ 70759563Seric if (tTd(27, 2)) 70859563Seric printf("forward: transient error on %s\n", buf); 70959563Seric #ifdef LOG 71059563Seric if (LogLevel > 2) 71159624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 71259624Seric e->e_id, buf, errstring(err)); 71359563Seric #endif 71459611Seric message("%s: %s: message queued", buf, errstring(err)); 71558247Seric user->q_flags |= QQUEUEUP|QDONTSEND; 71658247Seric return; 71758247Seric } 71857136Seric } 719292Seric } 720