SafeAlias is now a time interval
[unix-history] / usr / src / usr.sbin / sendmail / src / alias.c
CommitLineData
d185cb11 1/*
1f7bda54 2 * Copyright (c) 1983 Eric P. Allman
31de980b
KB
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
bee79b64 5 *
417f7a11 6 * %sccs.include.redist.c%
bee79b64
KB
7 */
8
72041f93 9# include "sendmail.h"
f9344236 10# include <pwd.h>
6a2bb17b 11
bee79b64 12#ifndef lint
49de3ce1 13static char sccsid[] = "@(#)alias.c 8.18 (Berkeley) %G%";
bee79b64 14#endif /* not lint */
595aeb43
EA
15
16
36b09297 17MAP *AliasDB[MAXALIASDB + 1]; /* actual database list */
595aeb43
EA
18int NAliasDBs; /* number of alias databases */
19\f/*
b3cbe40f
EA
20** ALIAS -- Compute aliases.
21**
7338e3d4
EA
22** Scans the alias file for an alias for the given address.
23** If found, it arranges to deliver to the alias list instead.
24** Uses libdbm database if -DDBM.
b3cbe40f
EA
25**
26** Parameters:
bdfaa762 27** a -- address to alias.
d4f42161
EA
28** sendq -- a pointer to the head of the send queue
29** to put the aliases in.
8f48def8 30** e -- the current envelope.
b3cbe40f
EA
31**
32** Returns:
33** none
34**
35** Side Effects:
9e3c0a28 36** Aliases found are expanded.
b3cbe40f 37**
b3cbe40f
EA
38** Deficiencies:
39** It should complain about names that are aliased to
40** nothing.
b3cbe40f
EA
41*/
42
a4076aed 43alias(a, sendq, e)
bdfaa762 44 register ADDRESS *a;
d4f42161 45 ADDRESS **sendq;
a4076aed 46 register ENVELOPE *e;
b3cbe40f 47{
29871fef 48 register char *p;
1c7897ef 49 int naliases;
84daea29
EA
50 char *owner;
51 char obuf[MAXNAME + 6];
abae7b2d 52 extern ADDRESS *sendto();
35cc3fad 53 extern char *aliaslookup();
b3cbe40f 54
9678c96d 55 if (tTd(27, 1))
cdb17311 56 printf("alias(%s)\n", a->q_paddr);
b3cbe40f 57
cdb17311 58 /* don't realias already aliased names */
bc854e30 59 if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
cdb17311
EA
60 return;
61
595aeb43
EA
62 if (NoAlias)
63 return;
64
a4076aed 65 e->e_to = a->q_paddr;
cdb17311 66
74c5fe7c
EA
67 /*
68 ** Look up this name
69 */
70
595aeb43 71 p = aliaslookup(a->q_user, e);
cdb17311
EA
72 if (p == NULL)
73 return;
b3cbe40f 74
d916f0ca 75 /*
cdb17311
EA
76 ** Match on Alias.
77 ** Deliver to the target list.
d916f0ca
EA
78 */
79
9678c96d 80 if (tTd(27, 1))
cdb17311
EA
81 printf("%s (%s, %s) aliased to %s\n",
82 a->q_paddr, a->q_host, a->q_user, p);
8f48def8 83 if (bitset(EF_VRFYONLY, e->e_flags))
8bcce465
EA
84 {
85 a->q_flags |= QVERIFIED;
a7dc53bd 86 e->e_nrcpts++;
8f48def8 87 return;
8bcce465
EA
88 }
89 message("aliased to %s", p);
aa102c71 90#ifdef LOG
68f7099c 91 if (LogLevel > 9)
aa102c71
EA
92 syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
93#endif
1c7897ef 94 a->q_flags &= ~QSELFREF;
cdb17311 95 AliasLevel++;
abae7b2d 96 a->q_child = sendto(p, 1, a, 0);
cdb17311 97 AliasLevel--;
e8c32825 98 if (!bitset(QSELFREF, a->q_flags))
f7eca811
EA
99 {
100 if (tTd(27, 5))
101 {
102 printf("alias: QDONTSEND ");
103 printaddr(a, FALSE);
104 }
105 a->q_flags |= QDONTSEND;
106 }
84daea29
EA
107
108 /*
109 ** Look for owner of alias
110 */
111
112 (void) strcpy(obuf, "owner-");
113 if (strncmp(a->q_user, "owner-", 6) == 0)
114 (void) strcat(obuf, "owner");
115 else
116 (void) strcat(obuf, a->q_user);
117 if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
118 makelower(obuf);
595aeb43 119 owner = aliaslookup(obuf, e);
84daea29
EA
120 if (owner != NULL)
121 {
122 if (strchr(owner, ',') != NULL)
123 owner = obuf;
124 a->q_owner = newstr(owner);
125 }
cdb17311
EA
126}
127\f/*
35cc3fad
EA
128** ALIASLOOKUP -- look up a name in the alias file.
129**
130** Parameters:
131** name -- the name to look up.
132**
133** Returns:
134** the value of name.
135** NULL if unknown.
136**
137** Side Effects:
138** none.
139**
140** Warnings:
141** The return value will be trashed across calls.
142*/
143
144char *
595aeb43 145aliaslookup(name, e)
35cc3fad 146 char *name;
595aeb43 147 ENVELOPE *e;
35cc3fad 148{
595aeb43 149 register int dbno;
713c523f 150 register MAP *map;
595aeb43 151 register char *p;
35cc3fad 152
595aeb43
EA
153 for (dbno = 0; dbno < NAliasDBs; dbno++)
154 {
713c523f
EA
155 auto int stat;
156
36b09297 157 map = AliasDB[dbno];
31f1ab13 158 if (!bitset(MF_OPEN, map->map_mflags))
595aeb43 159 continue;
31f1ab13 160 p = (*map->map_class->map_lookup)(map, name, NULL, &stat);
595aeb43
EA
161 if (p != NULL)
162 return p;
163 }
164 return NULL;
165}
166\f/*
167** SETALIAS -- set up an alias map
168**
169** Called when reading configuration file.
170**
171** Parameters:
172** spec -- the alias specification
173**
174** Returns:
175** none.
176*/
698a71d9 177
595aeb43
EA
178setalias(spec)
179 char *spec;
180{
181 register char *p;
713c523f 182 register MAP *map;
595aeb43
EA
183 char *class;
184 STAB *s;
185
2248d45f
EA
186 if (tTd(27, 8))
187 printf("setalias(%s)\n", spec);
188
4f95e74e 189 for (p = spec; p != NULL; )
07c0651f 190 {
36b09297
EA
191 char aname[50];
192
4f95e74e
EA
193 while (isspace(*p))
194 p++;
54d35e43 195 if (*p == '\0')
595aeb43 196 break;
595aeb43 197 spec = p;
595aeb43 198
4f95e74e
EA
199 if (NAliasDBs >= MAXALIASDB)
200 {
201 syserr("Too many alias databases defined, %d max", MAXALIASDB);
202 return;
203 }
36b09297
EA
204 (void) sprintf(aname, "Alias%d", NAliasDBs);
205 s = stab(aname, ST_MAP, ST_ENTER);
206 map = &s->s_map;
207 AliasDB[NAliasDBs] = map;
713c523f 208 bzero(map, sizeof *map);
4f95e74e
EA
209
210 p = strpbrk(p, " ,/:");
211 if (p != NULL && *p == ':')
212 {
713c523f 213 /* map name */
4f95e74e
EA
214 *p++ = '\0';
215 class = spec;
216 spec = p;
217 }
218 else
219 {
4f95e74e 220 class = "implicit";
df88f2ef 221 map->map_mflags = MF_OPTIONAL|MF_INCLNULL;
4f95e74e
EA
222 }
223
224 /* find end of spec */
225 if (p != NULL)
226 p = strchr(p, ',');
227 if (p != NULL)
228 *p++ = '\0';
229
230 /* look up class */
713c523f 231 s = stab(class, ST_MAPCLASS, ST_FIND);
4f95e74e
EA
232 if (s == NULL)
233 {
234 if (tTd(27, 1))
235 printf("Unknown alias class %s\n", class);
236 }
31f1ab13
EA
237 else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
238 {
239 syserr("setalias: map class %s can't handle aliases",
240 class);
241 }
4f95e74e
EA
242 else
243 {
31f1ab13 244 map->map_class = &s->s_mapclass;
713c523f
EA
245 if (map->map_class->map_parse(map, spec))
246 {
31f1ab13 247 map->map_mflags |= MF_VALID|MF_ALIAS;
713c523f
EA
248 NAliasDBs++;
249 }
4f95e74e 250 }
07c0651f 251 }
35cc3fad
EA
252}
253\f/*
595aeb43
EA
254** ALIASWAIT -- wait for distinguished @:@ token to appear.
255**
256** This can decide to reopen or rebuild the alias file
fe3849ea
EA
257**
258** Parameters:
259** map -- a pointer to the map descriptor for this alias file.
260** ext -- the filename extension (e.g., ".db") for the
261** database file.
262** isopen -- if set, the database is already open, and we
263** should check for validity; otherwise, we are
264** just checking to see if it should be created.
265**
266** Returns:
267** TRUE -- if the database is open when we return.
268** FALSE -- if the database is closed when we return.
595aeb43
EA
269*/
270
fe3849ea
EA
271bool
272aliaswait(map, ext, isopen)
713c523f 273 MAP *map;
31f1ab13 274 char *ext;
fe3849ea 275 int isopen;
595aeb43
EA
276{
277 int atcnt;
278 time_t mtime;
279 struct stat stb;
280 char buf[MAXNAME];
281
2248d45f 282 if (tTd(27, 3))
31f1ab13
EA
283 printf("aliaswait(%s:%s)\n",
284 map->map_class->map_cname, map->map_file);
fd93a56c
EA
285 if (bitset(MF_ALIASWAIT, map->map_mflags))
286 return;
287 map->map_mflags |= MF_ALIASWAIT;
2248d45f 288
560a80d9
EA
289 atcnt = SafeAlias * 2;
290 if (atcnt > 0)
291 {
713c523f
EA
292 auto int st;
293
fe3849ea 294 while (isopen && atcnt-- >= 0 &&
713c523f 295 map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
a1a07282
EA
296 {
297 /*
595aeb43
EA
298 ** Close and re-open the alias database in case
299 ** the one is mv'ed instead of cp'ed in.
a1a07282
EA
300 */
301
2248d45f
EA
302 if (tTd(27, 2))
303 printf("aliaswait: sleeping\n");
304
713c523f 305 map->map_class->map_close(map);
560a80d9 306 sleep(30);
fe3849ea 307 isopen = map->map_class->map_open(map, O_RDONLY);
a1a07282 308 }
560a80d9 309 }
d6b27179 310
595aeb43 311 /* see if we need to go into auto-rebuild mode */
31f1ab13
EA
312 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
313 {
314 if (tTd(27, 3))
315 printf("aliaswait: not rebuildable\n");
fd93a56c 316 map->map_mflags &= ~MF_ALIASWAIT;
fe3849ea 317 return isopen;
31f1ab13
EA
318 }
319 if (stat(map->map_file, &stb) < 0)
320 {
321 if (tTd(27, 3))
322 printf("aliaswait: no source file\n");
fd93a56c 323 map->map_mflags &= ~MF_ALIASWAIT;
fe3849ea 324 return isopen;
31f1ab13 325 }
595aeb43 326 mtime = stb.st_mtime;
713c523f 327 (void) strcpy(buf, map->map_file);
31f1ab13
EA
328 if (ext != NULL)
329 (void) strcat(buf, ext);
595aeb43 330 if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0)
f4dbf345 331 {
595aeb43 332 /* database is out of date */
915f268d 333 if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
d6b27179 334 {
713c523f 335 message("auto-rebuilding alias database %s", buf);
fe3849ea
EA
336 if (isopen)
337 map->map_class->map_close(map);
31f1ab13 338 rebuildaliases(map, TRUE);
fe3849ea 339 isopen = map->map_class->map_open(map, O_RDONLY);
d6b27179
EA
340 }
341 else
342 {
f12e5a74 343#ifdef LOG
68f7099c 344 if (LogLevel > 3)
595aeb43 345 syslog(LOG_INFO, "alias database %s out of date",
713c523f 346 buf);
f3d8f6d6 347#endif /* LOG */
713c523f 348 message("Warning: alias database %s out of date", buf);
d6b27179
EA
349 }
350 }
fd93a56c 351 map->map_mflags &= ~MF_ALIASWAIT;
fe3849ea 352 return isopen;
595aeb43
EA
353}
354\f/*
355** REBUILDALIASES -- rebuild the alias database.
356**
357** Parameters:
713c523f 358** map -- the database to rebuild.
595aeb43 359** automatic -- set if this was automatically generated.
595aeb43
EA
360**
361** Returns:
362** none.
363**
364** Side Effects:
365** Reads the text version of the database, builds the
366** DBM or DB version.
367*/
368
31f1ab13 369rebuildaliases(map, automatic)
713c523f 370 register MAP *map;
595aeb43 371 bool automatic;
595aeb43
EA
372{
373 FILE *af;
7cd18d97 374 bool nolock = FALSE;
e88b60c9 375 sigfunc_t oldsigint;
f4dbf345 376
31f1ab13 377 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
595aeb43 378 return;
d6b27179 379
595aeb43 380 /* try to lock the source file */
713c523f 381 if ((af = fopen(map->map_file, "r+")) == NULL)
7bdc419c 382 {
7cd18d97
EA
383 if (errno != EACCES || automatic ||
384 (af = fopen(map->map_file, "r")) == NULL)
385 {
386 int saveerr = errno;
387
388 if (tTd(27, 1))
389 printf("Can't open %s: %s\n",
390 map->map_file, errstring(saveerr));
391 if (!automatic)
392 message("newaliases: cannot open %s: %s",
393 map->map_file, errstring(saveerr));
394 errno = 0;
395 return;
396 }
397 nolock = TRUE;
398 message("warning: cannot lock %s: %s",
399 map->map_file, errstring(errno));
595aeb43 400 }
9327783c 401
595aeb43 402 /* see if someone else is rebuilding the alias file */
7cd18d97
EA
403 if (!nolock &&
404 !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
595aeb43
EA
405 {
406 /* yes, they are -- wait until done */
407 message("Alias file %s is already being rebuilt",
713c523f 408 map->map_file);
595aeb43
EA
409 if (OpMode != MD_INITALIAS)
410 {
411 /* wait for other rebuild to complete */
71936fbe 412 (void) lockfile(fileno(af), map->map_file, NULL,
595aeb43 413 LOCK_EX);
9327783c 414 }
49de3ce1 415 (void) xfclose(af, "rebuildaliases1", map->map_file);
595aeb43
EA
416 errno = 0;
417 return;
7bdc419c 418 }
595aeb43 419
39270cfd 420 oldsigint = setsignal(SIGINT, SIG_IGN);
595aeb43 421
31f1ab13 422 if (map->map_class->map_open(map, O_RDWR))
713c523f 423 {
9a47e53c
EA
424#ifdef LOG
425 if (LogLevel > 7)
426 {
427 syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
428 map->map_file, automatic ? "auto" : "",
429 username());
430 }
431#endif /* LOG */
31f1ab13
EA
432 map->map_mflags |= MF_OPEN|MF_WRITABLE;
433 readaliases(map, af, automatic);
434 }
435 else
436 {
437 if (tTd(27, 1))
438 printf("Can't create database for %s: %s\n",
439 map->map_file, errstring(errno));
440 if (!automatic)
441 syserr("Cannot create database for alias file %s",
442 map->map_file);
713c523f 443 }
595aeb43
EA
444
445 /* close the file, thus releasing locks */
49de3ce1 446 xfclose(af, "rebuildaliases2", map->map_file);
595aeb43
EA
447
448 /* add distinguished entries and close the database */
31f1ab13 449 if (bitset(MF_OPEN, map->map_mflags))
713c523f 450 map->map_class->map_close(map);
595aeb43
EA
451
452 /* restore the old signal */
39270cfd 453 (void) setsignal(SIGINT, oldsigint);
f4dbf345
EA
454}
455\f/*
456** READALIASES -- read and process the alias file.
457**
458** This routine implements the part of initaliases that occurs
459** when we are not going to use the DBM stuff.
460**
461** Parameters:
713c523f 462** map -- the alias database descriptor.
595aeb43 463** af -- file to read the aliases from.
cce258e2 464** automatic -- set if this was an automatic rebuild.
f4dbf345
EA
465**
466** Returns:
467** none.
468**
469** Side Effects:
470** Reads aliasfile into the symbol table.
471** Optionally, builds the .dir & .pag files.
472*/
473
31f1ab13 474readaliases(map, af, automatic)
713c523f 475 register MAP *map;
595aeb43 476 FILE *af;
cce258e2 477 int automatic;
f4dbf345 478{
cdb17311 479 register char *p;
41173b8f 480 char *lhs;
cdb17311
EA
481 char *rhs;
482 bool skipping;
595aeb43 483 long naliases, bytes, longest;
7338e3d4 484 ADDRESS al, bl;
7338e3d4 485 char line[BUFSIZ];
e6e345fa 486
74c5fe7c
EA
487 /*
488 ** Read and interpret lines
489 */
490
713c523f 491 FileName = map->map_file;
7338e3d4 492 LineNumber = 0;
d6b27179 493 naliases = bytes = longest = 0;
cdb17311
EA
494 skipping = FALSE;
495 while (fgets(line, sizeof (line), af) != NULL)
496 {
d6b27179
EA
497 int lhssize, rhssize;
498
7338e3d4 499 LineNumber++;
f3d8f6d6 500 p = strchr(line, '\n');
3312f93c
EA
501 if (p != NULL)
502 *p = '\0';
cdb17311
EA
503 switch (line[0])
504 {
505 case '#':
cdb17311
EA
506 case '\0':
507 skipping = FALSE;
508 continue;
bdfaa762 509
cdb17311
EA
510 case ' ':
511 case '\t':
512 if (!skipping)
b6edea3d 513 syserr("554 Non-continuation line starts with space");
cdb17311 514 skipping = TRUE;
bdfaa762 515 continue;
cdb17311
EA
516 }
517 skipping = FALSE;
bdfaa762 518
74c5fe7c
EA
519 /*
520 ** Process the LHS
41173b8f 521 **
6feb509e 522 ** Find the colon separator, and parse the address.
41173b8f
EA
523 ** It should resolve to a local name.
524 **
525 ** Alternatively, it can be "@hostname" for host
526 ** aliases -- all we do here is map case. Hostname
527 ** need not be a single token.
74c5fe7c
EA
528 */
529
cdb17311 530 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
bdfaa762 531 continue;
41173b8f 532 if (*p != ':')
cdb17311 533 {
1bcdf0a2 534 syserr("%s, line %d: syntax error", aliasfile, lineno);
bdfaa762 535 continue;
cdb17311 536 }
41173b8f
EA
537 *p++ = '\0';
538 if (line[0] == '@')
cdb17311 539 {
41173b8f
EA
540 /* a host alias */
541 makelower(line);
542 lhs = line;
543 }
544 else
545 {
546 /* a user alias */
547 if (parseaddr(line, &al, 1, ':') == NULL)
548 {
549 syserr("illegal alias name");
550 continue;
551 }
552 loweraddr(&al);
553 if (al.q_mailer != LocalMailer)
554 {
555 syserr("cannot alias non-local names");
556 continue;
557 }
558 lhs = al.q_user;
cdb17311 559 }
74c5fe7c
EA
560
561 /*
562 ** Process the RHS.
563 ** 'al' is the internal form of the LHS address.
564 ** 'p' points to the text of the RHS.
1bcdf0a2
EA
565 ** 'p' may begin with a colon (i.e., the
566 ** separator was "::") which will use the
567 ** first address as the person to send
568 ** errors to -- i.e., designates the
569 ** list maintainer.
74c5fe7c
EA
570 */
571
5854bceb
EA
572 while (isascii(*p) && isspace(*p))
573 p++;
1bcdf0a2
EA
574 if (*p == ':')
575 {
576 ADDRESS *maint;
577
578 while (isspace(*++p))
579 continue;
580 rhs = p;
581 while (*p != '\0' && *p != ',')
582 p++;
583 if (*p != ',')
584 goto syntaxerr;
585 *p++ = '\0';
586 maint = parse(p, (ADDRESS *) NULL, 1);
587 if (maint == NULL)
588 syserr("Illegal list maintainer for list %s", al.q_user);
589 else if (CurEnv->e_returnto == &CurEnv->e_from)
590 {
591 CurEnv->e_returnto = maint;
592 MailBack++;
593 }
594 }
595
cdb17311 596 rhs = p;
cdb17311
EA
597 for (;;)
598 {
599 register char c;
0957ee6f
EA
600 register char *nlp;
601
602 nlp = &p[strlen(p)];
603 if (nlp[-1] == '\n')
604 *--nlp = '\0';
d916f0ca 605
595aeb43 606 if (CheckAliases)
cdb17311 607 {
f4dbf345 608 /* do parsing & compression of addresses */
3312f93c 609 while (*p != '\0')
cdb17311 610 {
9e2cf26f 611 auto char *delimptr;
3312f93c 612
2bee003d
EA
613 while ((isascii(*p) && isspace(*p)) ||
614 *p == ',')
c49d661c 615 p++;
3312f93c
EA
616 if (*p == '\0')
617 break;
28f94061
EA
618 if (parseaddr(p, &bl, RF_COPYNONE, ',',
619 &delimptr, CurEnv) == NULL)
b6edea3d 620 usrerr("553 %s... bad address", p);
9e2cf26f 621 p = delimptr;
cdb17311 622 }
cdb17311 623 }
f4dbf345 624 else
634c8ff3 625 {
0957ee6f 626 p = nlp;
634c8ff3 627 }
d916f0ca 628
cdb17311 629 /* see if there should be a continuation line */
9e25d1f0
EA
630 c = fgetc(af);
631 if (!feof(af))
74c5fe7c 632 (void) ungetc(c, af);
9e25d1f0 633 if (c != ' ' && c != '\t')
cdb17311
EA
634 break;
635
636 /* read continuation line */
cdb17311
EA
637 if (fgets(p, sizeof line - (p - line), af) == NULL)
638 break;
7338e3d4 639 LineNumber++;
07b49560
EA
640
641 /* check for line overflow */
642 if (strchr(p, '\n') == NULL)
643 {
b6edea3d 644 usrerr("554 alias too long");
07b49560
EA
645 break;
646 }
cdb17311 647 }
74c5fe7c
EA
648
649 /*
650 ** Insert alias into symbol table or DBM file
651 */
652
41173b8f 653 lhssize = strlen(lhs) + 1;
d6b27179 654
595aeb43
EA
655 lhssize = strlen(al.q_user);
656 rhssize = strlen(rhs);
713c523f 657 map->map_class->map_store(map, al.q_user, rhs);
f4dbf345 658
595aeb43
EA
659 if (al.q_paddr != NULL)
660 free(al.q_paddr);
661 if (al.q_host != NULL)
662 free(al.q_host);
663 if (al.q_user != NULL)
664 free(al.q_user);
d6b27179
EA
665
666 /* statistics */
667 naliases++;
668 bytes += lhssize + rhssize;
669 if (rhssize > longest)
670 longest = rhssize;
d916f0ca 671 }
e6e345fa 672
31f1ab13 673 CurEnv->e_to = NULL;
595aeb43 674 FileName = NULL;
cce258e2
EA
675 if (Verbose || !automatic)
676 message("%s: %d aliases, longest %d bytes, %d bytes total",
713c523f 677 map->map_file, naliases, longest, bytes);
595aeb43
EA
678# ifdef LOG
679 if (LogLevel > 7)
680 syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
713c523f 681 map->map_file, naliases, longest, bytes);
595aeb43
EA
682# endif /* LOG */
683}
684\f/*
b3cbe40f
EA
685** FORWARD -- Try to forward mail
686**
687** This is similar but not identical to aliasing.
688**
b3cbe40f 689** Parameters:
74c5fe7c
EA
690** user -- the name of the user who's mail we would like
691** to forward to. It must have been verified --
692** i.e., the q_home field must have been filled
693** in.
d4f42161
EA
694** sendq -- a pointer to the head of the send queue to
695** put this user's aliases in.
b3cbe40f
EA
696**
697** Returns:
cdb17311 698** none.
b3cbe40f
EA
699**
700** Side Effects:
9e3c0a28 701** New names are added to send queues.
b3cbe40f
EA
702*/
703
a4076aed 704forward(user, sendq, e)
a530c75f 705 ADDRESS *user;
d4f42161 706 ADDRESS **sendq;
a4076aed 707 register ENVELOPE *e;
b3cbe40f 708{
e0136832
EA
709 char *pp;
710 char *ep;
56678245 711
9678c96d 712 if (tTd(27, 1))
cdb17311 713 printf("forward(%s)\n", user->q_paddr);
cdb17311 714
179c1218 715 if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
cdb17311 716 return;
74c5fe7c 717 if (user->q_home == NULL)
c25096f0 718 {
b6edea3d 719 syserr("554 forward: no home");
c25096f0
EA
720 user->q_home = "/nosuchdirectory";
721 }
56678245 722
56678245 723 /* good address -- look for .forward file in home */
a4076aed 724 define('z', user->q_home, e);
e0136832
EA
725 define('u', user->q_user, e);
726 define('h', user->q_host, e);
727 if (ForwardPath == NULL)
2bee003d 728 ForwardPath = newstr("\201z/.forward");
e0136832
EA
729
730 for (pp = ForwardPath; pp != NULL; pp = ep)
731 {
118e6693 732 int err;
f43b04ce 733 char buf[MAXPATHLEN+1];
e0136832
EA
734
735 ep = strchr(pp, ':');
736 if (ep != NULL)
737 *ep = '\0';
738 expand(pp, buf, &buf[sizeof buf - 1], e);
739 if (ep != NULL)
740 *ep++ = ':';
741 if (tTd(27, 3))
742 printf("forward: trying %s\n", buf);
8e5c6745 743
118e6693
EA
744 err = include(buf, TRUE, user, sendq, e);
745 if (err == 0)
e0136832 746 break;
a614cf3b 747 else if (transienterror(err))
118e6693
EA
748 {
749 /* we have to suspend this message */
d50bcc17
EA
750 if (tTd(27, 2))
751 printf("forward: transient error on %s\n", buf);
752#ifdef LOG
753 if (LogLevel > 2)
3f0792d1
EA
754 syslog(LOG_ERR, "%s: forward %s: transient error: %s",
755 e->e_id, buf, errstring(err));
d50bcc17 756#endif
dd61ea05 757 message("%s: %s: message queued", buf, errstring(err));
c069e0df 758 user->q_flags |= QQUEUEUP;
118e6693
EA
759 return;
760 }
e0136832 761 }
b3cbe40f 762}
41173b8f
EA
763\f/*
764** MAPHOST -- given a host description, produce a mapping.
765**
766** This is done by looking up the name in the alias file,
767** preceeded by an "@". This can be used for UUCP mapping.
768** For example, a call with {blia, ., UUCP} as arguments
769** might return {ucsfcgl, !, blia, ., UUCP} as the result.
770**
771** We first break the input into three parts -- before the
772** lookup, the lookup itself, and after the lookup. We
773** then do the lookup, concatenate them together, and rescan
774** the result.
775**
776** Parameters:
777** pvp -- the parameter vector to map.
778**
779** Returns:
780** The result of the mapping. If nothing found, it
781** should just concatenate the three parts together and
782** return that.
783**
784** Side Effects:
785** none.
786*/
787
788char **
789maphost(pvp)
790 char **pvp;
791{
792 register char **avp;
793 register char **bvp;
794 char *p;
795 char buf1[MAXNAME];
796 char buf2[MAXNAME];
797 char buf3[MAXNAME];
798 extern char **prescan();
799
800 /*
801 ** Extract the three parts of the input as strings.
802 */
803
804 /* find the part before the lookup */
805 for (bvp = pvp; *bvp != NULL && **bvp != MATCHLOOKUP; bvp++)
806 continue;
807 if (*bvp == NULL)
808 return (pvp);
809 p = *bvp;
810 *bvp = NULL;
811 cataddr(pvp, buf1, sizeof buf1);
812 *bvp++ = p;
813
814 /* find the rest of the lookup */
815 for (avp = bvp; *pvp != NULL && **bvp != MATCHELOOKUP; bvp++)
816 continue;
817 if (*bvp == NULL)
818 return (pvp);
819 p = *bvp;
820 *bvp = NULL;
821 cataddr(avp, buf2, sizeof buf2);
822 *bvp++ = p;
823
824 /* save the part after the lookup */
825 cataddr(bvp, buf3, sizeof buf3);
826
827 /*
828 ** Now look up the middle part.
829 */
830
831 p = aliaslookup(buf2);
832 if (p != NULL)
833 strcpy(buf2, p);
834
835 /*
836 ** Put the three parts back together and break into tokens.
837 */
838
839 strcat(buf1, buf2);
840 strcat(buf1, buf3);
841 avp = prescan(buf1, '\0');
842
843 /* return this mapping */
844 return (avp);
845}