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