This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.sbin / sendmail / src / alias.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1983 Eric P. Allman
6f14531a
RG
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
15637ed4
RG
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
6f14531a 35# include "sendmail.h"
6f14531a
RG
36# include <pwd.h>
37
15637ed4 38#ifndef lint
69fc843f 39static char sccsid[] = "@(#)alias.c 8.19 (Berkeley) 10/31/93";
15637ed4
RG
40#endif /* not lint */
41
15637ed4 42
6f14531a
RG
43MAP *AliasDB[MAXALIASDB + 1]; /* actual database list */
44int NAliasDBs; /* number of alias databases */
45\f/*
15637ed4
RG
46** ALIAS -- Compute aliases.
47**
48** Scans the alias file for an alias for the given address.
49** If found, it arranges to deliver to the alias list instead.
50** Uses libdbm database if -DDBM.
51**
52** Parameters:
53** a -- address to alias.
54** sendq -- a pointer to the head of the send queue
55** to put the aliases in.
6f14531a 56** e -- the current envelope.
15637ed4
RG
57**
58** Returns:
59** none
60**
61** Side Effects:
62** Aliases found are expanded.
63**
15637ed4
RG
64** Deficiencies:
65** It should complain about names that are aliased to
66** nothing.
67*/
68
6f14531a 69alias(a, sendq, e)
15637ed4
RG
70 register ADDRESS *a;
71 ADDRESS **sendq;
6f14531a 72 register ENVELOPE *e;
15637ed4
RG
73{
74 register char *p;
6f14531a
RG
75 int naliases;
76 char *owner;
77 char obuf[MAXNAME + 6];
15637ed4
RG
78 extern char *aliaslookup();
79
80 if (tTd(27, 1))
81 printf("alias(%s)\n", a->q_paddr);
82
83 /* don't realias already aliased names */
6f14531a 84 if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
15637ed4
RG
85 return;
86
6f14531a
RG
87 if (NoAlias)
88 return;
89
90 e->e_to = a->q_paddr;
15637ed4
RG
91
92 /*
93 ** Look up this name
94 */
95
6f14531a 96 p = aliaslookup(a->q_user, e);
15637ed4
RG
97 if (p == NULL)
98 return;
99
100 /*
101 ** Match on Alias.
102 ** Deliver to the target list.
103 */
104
105 if (tTd(27, 1))
106 printf("%s (%s, %s) aliased to %s\n",
107 a->q_paddr, a->q_host, a->q_user, p);
6f14531a
RG
108 if (bitset(EF_VRFYONLY, e->e_flags))
109 {
110 a->q_flags |= QVERIFIED;
111 e->e_nrcpts++;
112 return;
113 }
114 message("aliased to %s", p);
115#ifdef LOG
116 if (LogLevel > 9)
117 syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
118#endif
119 a->q_flags &= ~QSELFREF;
15637ed4 120 AliasLevel++;
6f14531a 121 naliases = sendtolist(p, a, sendq, e);
15637ed4 122 AliasLevel--;
d747e748 123 if (!bitset(QSELFREF, a->q_flags))
6f14531a
RG
124 {
125 if (tTd(27, 5))
126 {
127 printf("alias: QDONTSEND ");
128 printaddr(a, FALSE);
129 }
130 a->q_flags |= QDONTSEND;
131 }
132
133 /*
134 ** Look for owner of alias
135 */
136
137 (void) strcpy(obuf, "owner-");
138 if (strncmp(a->q_user, "owner-", 6) == 0)
139 (void) strcat(obuf, "owner");
140 else
141 (void) strcat(obuf, a->q_user);
142 if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
143 makelower(obuf);
144 owner = aliaslookup(obuf, e);
145 if (owner != NULL)
146 {
147 if (strchr(owner, ',') != NULL)
148 owner = obuf;
149 a->q_owner = newstr(owner);
150 }
15637ed4
RG
151}
152\f/*
153** ALIASLOOKUP -- look up a name in the alias file.
154**
155** Parameters:
156** name -- the name to look up.
157**
158** Returns:
159** the value of name.
160** NULL if unknown.
161**
162** Side Effects:
163** none.
164**
165** Warnings:
166** The return value will be trashed across calls.
167*/
168
169char *
6f14531a 170aliaslookup(name, e)
15637ed4 171 char *name;
6f14531a 172 ENVELOPE *e;
15637ed4 173{
6f14531a
RG
174 register int dbno;
175 register MAP *map;
176 register char *p;
177
178 for (dbno = 0; dbno < NAliasDBs; dbno++)
179 {
180 auto int stat;
181
182 map = AliasDB[dbno];
183 if (!bitset(MF_OPEN, map->map_mflags))
184 continue;
185 p = (*map->map_class->map_lookup)(map, name, NULL, &stat);
186 if (p != NULL)
187 return p;
188 }
189 return NULL;
15637ed4
RG
190}
191\f/*
6f14531a 192** SETALIAS -- set up an alias map
15637ed4 193**
6f14531a 194** Called when reading configuration file.
15637ed4
RG
195**
196** Parameters:
6f14531a 197** spec -- the alias specification
15637ed4
RG
198**
199** Returns:
200** none.
15637ed4
RG
201*/
202
6f14531a
RG
203setalias(spec)
204 char *spec;
15637ed4 205{
6f14531a
RG
206 register char *p;
207 register MAP *map;
208 char *class;
209 STAB *s;
15637ed4 210
6f14531a
RG
211 if (tTd(27, 8))
212 printf("setalias(%s)\n", spec);
15637ed4 213
6f14531a 214 for (p = spec; p != NULL; )
15637ed4 215 {
6f14531a
RG
216 char aname[50];
217
218 while (isspace(*p))
219 p++;
220 if (*p == '\0')
221 break;
222 spec = p;
223
224 if (NAliasDBs >= MAXALIASDB)
225 {
226 syserr("Too many alias databases defined, %d max", MAXALIASDB);
227 return;
228 }
229 (void) sprintf(aname, "Alias%d", NAliasDBs);
230 s = stab(aname, ST_MAP, ST_ENTER);
231 map = &s->s_map;
232 AliasDB[NAliasDBs] = map;
233 bzero(map, sizeof *map);
234
235 p = strpbrk(p, " ,/:");
236 if (p != NULL && *p == ':')
237 {
238 /* map name */
239 *p++ = '\0';
240 class = spec;
241 spec = p;
242 }
243 else
244 {
245 class = "implicit";
246 map->map_mflags = MF_OPTIONAL|MF_INCLNULL;
247 }
248
249 /* find end of spec */
250 if (p != NULL)
251 p = strchr(p, ',');
252 if (p != NULL)
253 *p++ = '\0';
254
255 /* look up class */
256 s = stab(class, ST_MAPCLASS, ST_FIND);
257 if (s == NULL)
258 {
259 if (tTd(27, 1))
260 printf("Unknown alias class %s\n", class);
261 }
262 else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
263 {
264 syserr("setalias: map class %s can't handle aliases",
265 class);
266 }
267 else
268 {
269 map->map_class = &s->s_mapclass;
270 if (map->map_class->map_parse(map, spec))
271 {
272 map->map_mflags |= MF_VALID|MF_ALIAS;
273 NAliasDBs++;
274 }
275 }
15637ed4 276 }
6f14531a
RG
277}
278\f/*
279** ALIASWAIT -- wait for distinguished @:@ token to appear.
280**
281** This can decide to reopen or rebuild the alias file
d747e748
JH
282**
283** Parameters:
284** map -- a pointer to the map descriptor for this alias file.
285** ext -- the filename extension (e.g., ".db") for the
286** database file.
287** isopen -- if set, the database is already open, and we
288** should check for validity; otherwise, we are
289** just checking to see if it should be created.
290**
291** Returns:
292** TRUE -- if the database is open when we return.
293** FALSE -- if the database is closed when we return.
6f14531a 294*/
15637ed4 295
d747e748
JH
296bool
297aliaswait(map, ext, isopen)
6f14531a
RG
298 MAP *map;
299 char *ext;
d747e748 300 int isopen;
6f14531a 301{
69fc843f 302 bool attimeout = FALSE;
6f14531a
RG
303 time_t mtime;
304 struct stat stb;
305 char buf[MAXNAME];
306
307 if (tTd(27, 3))
308 printf("aliaswait(%s:%s)\n",
309 map->map_class->map_cname, map->map_file);
d747e748 310 if (bitset(MF_ALIASWAIT, map->map_mflags))
69fc843f 311 return isopen;
d747e748 312 map->map_mflags |= MF_ALIASWAIT;
15637ed4 313
69fc843f 314 if (SafeAlias > 0)
15637ed4 315 {
6f14531a 316 auto int st;
69fc843f
AM
317 time_t toolong = curtime() + SafeAlias;
318 unsigned int sleeptime = 2;
6f14531a 319
69fc843f 320 while (isopen &&
6f14531a 321 map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
15637ed4 322 {
69fc843f
AM
323 if (curtime() > toolong)
324 {
325 /* we timed out */
326 attimeout = TRUE;
327 break;
328 }
329
15637ed4 330 /*
6f14531a
RG
331 ** Close and re-open the alias database in case
332 ** the one is mv'ed instead of cp'ed in.
15637ed4
RG
333 */
334
6f14531a 335 if (tTd(27, 2))
69fc843f
AM
336 printf("aliaswait: sleeping for %d seconds\n",
337 sleeptime);
6f14531a
RG
338
339 map->map_class->map_close(map);
69fc843f
AM
340 sleep(sleeptime);
341 sleeptime *= 2;
342 if (sleeptime > 60)
343 sleeptime = 60;
d747e748 344 isopen = map->map_class->map_open(map, O_RDONLY);
15637ed4
RG
345 }
346 }
15637ed4 347
6f14531a
RG
348 /* see if we need to go into auto-rebuild mode */
349 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
15637ed4 350 {
6f14531a
RG
351 if (tTd(27, 3))
352 printf("aliaswait: not rebuildable\n");
d747e748
JH
353 map->map_mflags &= ~MF_ALIASWAIT;
354 return isopen;
6f14531a
RG
355 }
356 if (stat(map->map_file, &stb) < 0)
357 {
358 if (tTd(27, 3))
359 printf("aliaswait: no source file\n");
d747e748
JH
360 map->map_mflags &= ~MF_ALIASWAIT;
361 return isopen;
6f14531a
RG
362 }
363 mtime = stb.st_mtime;
364 (void) strcpy(buf, map->map_file);
365 if (ext != NULL)
366 (void) strcat(buf, ext);
69fc843f 367 if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
6f14531a
RG
368 {
369 /* database is out of date */
15637ed4
RG
370 if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
371 {
6f14531a 372 message("auto-rebuilding alias database %s", buf);
d747e748
JH
373 if (isopen)
374 map->map_class->map_close(map);
6f14531a 375 rebuildaliases(map, TRUE);
d747e748 376 isopen = map->map_class->map_open(map, O_RDONLY);
15637ed4
RG
377 }
378 else
379 {
380#ifdef LOG
6f14531a
RG
381 if (LogLevel > 3)
382 syslog(LOG_INFO, "alias database %s out of date",
383 buf);
384#endif /* LOG */
385 message("Warning: alias database %s out of date", buf);
15637ed4
RG
386 }
387 }
d747e748
JH
388 map->map_mflags &= ~MF_ALIASWAIT;
389 return isopen;
15637ed4
RG
390}
391\f/*
6f14531a 392** REBUILDALIASES -- rebuild the alias database.
15637ed4
RG
393**
394** Parameters:
6f14531a
RG
395** map -- the database to rebuild.
396** automatic -- set if this was automatically generated.
15637ed4
RG
397**
398** Returns:
399** none.
400**
401** Side Effects:
6f14531a
RG
402** Reads the text version of the database, builds the
403** DBM or DB version.
15637ed4
RG
404*/
405
6f14531a
RG
406rebuildaliases(map, automatic)
407 register MAP *map;
408 bool automatic;
15637ed4 409{
15637ed4 410 FILE *af;
d747e748
JH
411 bool nolock = FALSE;
412 sigfunc_t oldsigint;
15637ed4 413
6f14531a
RG
414 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
415 return;
416
6f14531a
RG
417 /* try to lock the source file */
418 if ((af = fopen(map->map_file, "r+")) == NULL)
15637ed4 419 {
d747e748
JH
420 if (errno != EACCES || automatic ||
421 (af = fopen(map->map_file, "r")) == NULL)
422 {
423 int saveerr = errno;
424
425 if (tTd(27, 1))
426 printf("Can't open %s: %s\n",
427 map->map_file, errstring(saveerr));
428 if (!automatic)
429 message("newaliases: cannot open %s: %s",
430 map->map_file, errstring(saveerr));
431 errno = 0;
432 return;
433 }
434 nolock = TRUE;
435 message("warning: cannot lock %s: %s",
436 map->map_file, errstring(errno));
15637ed4
RG
437 }
438
6f14531a 439 /* see if someone else is rebuilding the alias file */
d747e748
JH
440 if (!nolock &&
441 !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
15637ed4 442 {
6f14531a
RG
443 /* yes, they are -- wait until done */
444 message("Alias file %s is already being rebuilt",
445 map->map_file);
15637ed4
RG
446 if (OpMode != MD_INITALIAS)
447 {
448 /* wait for other rebuild to complete */
d747e748 449 (void) lockfile(fileno(af), map->map_file, NULL,
6f14531a 450 LOCK_EX);
15637ed4 451 }
69fc843f 452 (void) xfclose(af, "rebuildaliases1", map->map_file);
15637ed4
RG
453 errno = 0;
454 return;
455 }
456
d747e748 457 oldsigint = setsignal(SIGINT, SIG_IGN);
15637ed4 458
6f14531a 459 if (map->map_class->map_open(map, O_RDWR))
15637ed4 460 {
d747e748
JH
461#ifdef LOG
462 if (LogLevel > 7)
463 {
464 syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
465 map->map_file, automatic ? "auto" : "",
466 username());
467 }
468#endif /* LOG */
6f14531a
RG
469 map->map_mflags |= MF_OPEN|MF_WRITABLE;
470 readaliases(map, af, automatic);
15637ed4 471 }
6f14531a
RG
472 else
473 {
474 if (tTd(27, 1))
475 printf("Can't create database for %s: %s\n",
476 map->map_file, errstring(errno));
477 if (!automatic)
478 syserr("Cannot create database for alias file %s",
479 map->map_file);
480 }
481
482 /* close the file, thus releasing locks */
69fc843f 483 xfclose(af, "rebuildaliases2", map->map_file);
6f14531a
RG
484
485 /* add distinguished entries and close the database */
486 if (bitset(MF_OPEN, map->map_mflags))
487 map->map_class->map_close(map);
488
489 /* restore the old signal */
d747e748 490 (void) setsignal(SIGINT, oldsigint);
6f14531a
RG
491}
492\f/*
493** READALIASES -- read and process the alias file.
494**
495** This routine implements the part of initaliases that occurs
496** when we are not going to use the DBM stuff.
497**
498** Parameters:
499** map -- the alias database descriptor.
500** af -- file to read the aliases from.
501** automatic -- set if this was an automatic rebuild.
502**
503** Returns:
504** none.
505**
506** Side Effects:
507** Reads aliasfile into the symbol table.
508** Optionally, builds the .dir & .pag files.
509*/
510
511readaliases(map, af, automatic)
512 register MAP *map;
513 FILE *af;
514 int automatic;
515{
516 register char *p;
517 char *rhs;
518 bool skipping;
519 long naliases, bytes, longest;
520 ADDRESS al, bl;
521 char line[BUFSIZ];
15637ed4
RG
522
523 /*
524 ** Read and interpret lines
525 */
526
6f14531a 527 FileName = map->map_file;
15637ed4
RG
528 LineNumber = 0;
529 naliases = bytes = longest = 0;
530 skipping = FALSE;
531 while (fgets(line, sizeof (line), af) != NULL)
532 {
533 int lhssize, rhssize;
534
535 LineNumber++;
6f14531a 536 p = strchr(line, '\n');
15637ed4
RG
537 if (p != NULL)
538 *p = '\0';
539 switch (line[0])
540 {
541 case '#':
542 case '\0':
543 skipping = FALSE;
544 continue;
545
546 case ' ':
547 case '\t':
548 if (!skipping)
6f14531a 549 syserr("554 Non-continuation line starts with space");
15637ed4
RG
550 skipping = TRUE;
551 continue;
552 }
553 skipping = FALSE;
554
555 /*
556 ** Process the LHS
6f14531a 557 ** Find the colon separator, and parse the address.
15637ed4
RG
558 ** It should resolve to a local name -- this will
559 ** be checked later (we want to optionally do
560 ** parsing of the RHS first to maximize error
561 ** detection).
562 */
563
564 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
565 continue;
566 if (*p++ != ':')
567 {
6f14531a 568 syserr("554 missing colon");
15637ed4
RG
569 continue;
570 }
d747e748 571 if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
15637ed4 572 {
d747e748 573 syserr("554 %s... illegal alias name", al.q_paddr);
15637ed4
RG
574 continue;
575 }
15637ed4
RG
576
577 /*
578 ** Process the RHS.
579 ** 'al' is the internal form of the LHS address.
580 ** 'p' points to the text of the RHS.
581 */
582
6f14531a
RG
583 while (isascii(*p) && isspace(*p))
584 p++;
15637ed4
RG
585 rhs = p;
586 for (;;)
587 {
588 register char c;
6f14531a
RG
589 register char *nlp;
590
591 nlp = &p[strlen(p)];
592 if (nlp[-1] == '\n')
593 *--nlp = '\0';
15637ed4 594
6f14531a 595 if (CheckAliases)
15637ed4
RG
596 {
597 /* do parsing & compression of addresses */
598 while (*p != '\0')
599 {
6f14531a 600 auto char *delimptr;
15637ed4 601
6f14531a
RG
602 while ((isascii(*p) && isspace(*p)) ||
603 *p == ',')
15637ed4
RG
604 p++;
605 if (*p == '\0')
606 break;
d747e748
JH
607 if (parseaddr(p, &bl, RF_COPYNONE, ',',
608 &delimptr, CurEnv) == NULL)
6f14531a
RG
609 usrerr("553 %s... bad address", p);
610 p = delimptr;
15637ed4
RG
611 }
612 }
613 else
614 {
6f14531a 615 p = nlp;
15637ed4
RG
616 }
617
618 /* see if there should be a continuation line */
619 c = fgetc(af);
620 if (!feof(af))
621 (void) ungetc(c, af);
622 if (c != ' ' && c != '\t')
623 break;
624
625 /* read continuation line */
626 if (fgets(p, sizeof line - (p - line), af) == NULL)
627 break;
628 LineNumber++;
6f14531a
RG
629
630 /* check for line overflow */
631 if (strchr(p, '\n') == NULL)
632 {
633 usrerr("554 alias too long");
634 break;
635 }
15637ed4
RG
636 }
637 if (al.q_mailer != LocalMailer)
638 {
d747e748
JH
639 syserr("554 %s... cannot alias non-local names",
640 al.q_paddr);
15637ed4
RG
641 continue;
642 }
643
644 /*
645 ** Insert alias into symbol table or DBM file
646 */
647
6f14531a
RG
648 if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
649 makelower(al.q_user);
15637ed4 650
6f14531a
RG
651 lhssize = strlen(al.q_user);
652 rhssize = strlen(rhs);
653 map->map_class->map_store(map, al.q_user, rhs);
15637ed4 654
6f14531a
RG
655 if (al.q_paddr != NULL)
656 free(al.q_paddr);
657 if (al.q_host != NULL)
658 free(al.q_host);
659 if (al.q_user != NULL)
660 free(al.q_user);
15637ed4
RG
661
662 /* statistics */
663 naliases++;
664 bytes += lhssize + rhssize;
665 if (rhssize > longest)
666 longest = rhssize;
667 }
668
15637ed4
RG
669 CurEnv->e_to = NULL;
670 FileName = NULL;
6f14531a
RG
671 if (Verbose || !automatic)
672 message("%s: %d aliases, longest %d bytes, %d bytes total",
673 map->map_file, naliases, longest, bytes);
15637ed4 674# ifdef LOG
6f14531a
RG
675 if (LogLevel > 7)
676 syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
677 map->map_file, naliases, longest, bytes);
678# endif /* LOG */
15637ed4
RG
679}
680\f/*
681** FORWARD -- Try to forward mail
682**
683** This is similar but not identical to aliasing.
684**
685** Parameters:
686** user -- the name of the user who's mail we would like
687** to forward to. It must have been verified --
688** i.e., the q_home field must have been filled
689** in.
690** sendq -- a pointer to the head of the send queue to
691** put this user's aliases in.
692**
693** Returns:
694** none.
695**
696** Side Effects:
697** New names are added to send queues.
698*/
699
6f14531a 700forward(user, sendq, e)
15637ed4
RG
701 ADDRESS *user;
702 ADDRESS **sendq;
6f14531a 703 register ENVELOPE *e;
15637ed4 704{
6f14531a
RG
705 char *pp;
706 char *ep;
15637ed4
RG
707
708 if (tTd(27, 1))
709 printf("forward(%s)\n", user->q_paddr);
710
711 if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
712 return;
713 if (user->q_home == NULL)
6f14531a
RG
714 {
715 syserr("554 forward: no home");
716 user->q_home = "/nosuchdirectory";
717 }
15637ed4
RG
718
719 /* good address -- look for .forward file in home */
6f14531a
RG
720 define('z', user->q_home, e);
721 define('u', user->q_user, e);
722 define('h', user->q_host, e);
723 if (ForwardPath == NULL)
724 ForwardPath = newstr("\201z/.forward");
15637ed4 725
6f14531a
RG
726 for (pp = ForwardPath; pp != NULL; pp = ep)
727 {
728 int err;
729 char buf[MAXPATHLEN+1];
730
731 ep = strchr(pp, ':');
732 if (ep != NULL)
733 *ep = '\0';
734 expand(pp, buf, &buf[sizeof buf - 1], e);
735 if (ep != NULL)
736 *ep++ = ':';
737 if (tTd(27, 3))
738 printf("forward: trying %s\n", buf);
3a363396 739
6f14531a
RG
740 err = include(buf, TRUE, user, sendq, e);
741 if (err == 0)
742 break;
d747e748 743 else if (transienterror(err))
6f14531a
RG
744 {
745 /* we have to suspend this message */
746 if (tTd(27, 2))
747 printf("forward: transient error on %s\n", buf);
748#ifdef LOG
749 if (LogLevel > 2)
750 syslog(LOG_ERR, "%s: forward %s: transient error: %s",
751 e->e_id, buf, errstring(err));
752#endif
753 message("%s: %s: message queued", buf, errstring(err));
d747e748 754 user->q_flags |= QQUEUEUP;
6f14531a
RG
755 return;
756 }
757 }
15637ed4 758}