3 * aliasbr.c -- new aliasing mechanism
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
11 #include <h/aliasbr.h>
12 #include <h/addrsbr.h>
20 struct aka *akahead = NULL;
21 struct aka *akatail = NULL;
23 struct home *homehead = NULL;
24 struct home *hometail = NULL;
32 char *akresult (struct aka *);
33 char *akvalue (char *);
36 static char *akval (struct aka *, char *);
37 static int aleq (char *, char *);
38 static char *scanp (unsigned char *);
39 static char *getp (char *);
40 static char *seekp (char *, char *, char **);
41 static int addfile (struct aka *, char *);
42 static int addgroup (struct aka *, char *);
43 static int addmember (struct aka *, char *);
44 static int addall (struct aka *);
45 static char *getalias (char *);
46 static void add_aka (struct aka *, char *);
47 static struct aka *akalloc (char *);
48 static struct home *hmalloc (struct passwd *);
49 struct home *seek_home (char *);
52 /* Do mh alias substitution on 's' and return the results. */
62 v = akval (akahead, s);
77 akresult (struct aka *ak)
79 register char *cp = NULL, *dp, *pp;
80 register struct adr *ad;
82 for (ad = ak->ak_addr; ad; ad = ad->ad_next) {
83 pp = ad->ad_local ? akval (ak->ak_next, ad->ad_text)
84 : getcpy (ad->ad_text);
88 cp = concat (cp, ",", pp, NULL);
97 akvis = ak->ak_visible;
103 akval (struct aka *ak, char *s)
108 for (; ak; ak = ak->ak_next) {
109 if (aleq (s, ak->ak_name)) {
110 return akresult (ak);
111 } else if (strchr (s, ':')) {
112 /* The first address in a blind list will contain the
113 alias name, so try to match, but just with just the
114 address (not including the list name). If there's a
115 match, then replace the alias part with its
118 char *name = getname (s);
122 /* s is of the form "Blind list: address". If address
123 is an alias, expand it. */
124 struct mailname *mp = getm (name, NULL, 0, AD_NAME, NULL);
126 if (mp && mp->m_ingrp) {
127 char *gname = add (mp->m_gname, NULL);
129 if (gname && aleq (name, ak->ak_name)) {
131 cp = concat (gname, akresult (ak), NULL);
139 /* Need to flush getname after use. */
140 while (getname ("")) continue;
153 aleq (char *string, char *aliasent)
157 while ((c = *string++))
158 if (*aliasent == '*')
161 if ((c | 040) != (*aliasent | 040))
166 return (*aliasent == 0 || *aliasent == '*');
174 register char *bp, *cp, *pp;
176 register struct aka *ak = NULL;
180 && (strncmp (file, "./", 2) && strncmp (file, "../", 3)))
181 file = etcpath (file);
182 if ((fp = fopen (file, "r")) == NULL) {
187 while (vfgets (fp, &ap) == OK) {
189 switch (*(pp = scanp (bp))) {
190 case '<': /* recurse a level */
191 if (!*(cp = getp (pp + 1))) {
192 akerrst = "'<' without alias-file";
196 if ((i = alias (cp)) != AK_OK) {
201 case ':': /* comment */
209 if (!*(cp = seekp (pp, &lc, &ap))) {
213 if (!(ak = akalloc (cp))) {
231 switch (*(pp = scanp (ap))) {
236 case '<': /* read values from file */
237 if (!*(cp = getp (pp + 1))) {
241 if (!addfile (ak, cp)) {
247 case '=': /* UNIX group */
248 if (!*(cp = getp (pp + 1))) {
252 if (!addgroup (ak, cp)) {
258 case '+': /* UNIX group members */
259 if (!*(cp = getp (pp + 1))) {
263 if (!addmember (ak, cp)) {
269 case '*': /* Everyone */
274 while ((cp = getalias (pp)))
288 static char buffer[BUFSIZ];
292 snprintf (buffer, sizeof(buffer), "unable to read '%s'", akerrst);
296 snprintf (buffer, sizeof(buffer), "error in line '%s'", akerrst);
300 snprintf (buffer, sizeof(buffer), "out of memory while on '%s'", akerrst);
304 snprintf (buffer, sizeof(buffer), "no such group as '%s'", akerrst);
308 snprintf (buffer, sizeof(buffer), "unknown error (%d)", i);
317 scanp (unsigned char *p)
328 register unsigned char *cp = scanp (p);
331 while (!isspace (*cp) && *cp)
340 seekp (char *p, char *c, char **a)
342 register unsigned char *cp;
345 while (!isspace (*cp) && *cp && *cp != ':' && *cp != ';')
356 addfile (struct aka *ak, char *file)
362 if (!(fp = fopen (etcpath (file), "r"))) {
367 while (fgets (buffer, sizeof buffer, fp))
368 while ((cp = getalias (buffer)))
377 addgroup (struct aka *ak, char *grp)
380 register struct group *gr = getgrnam (grp);
381 register struct home *hm = NULL;
384 gr = getgrgid (atoi (grp));
390 while ((gp = *gr->gr_mem++))
393 for (hm = homehead; hm; hm = hm->h_next)
394 if (!strcmp (hm->h_name, gp)) {
395 add_aka (ak, hm->h_name);
398 if ((pw = getpwnam(gp)))
410 addmember (struct aka *ak, char *grp)
413 register struct group *gr = getgrnam (grp);
414 register struct home *hm = NULL;
429 for (hm = homehead; hm; hm = hm->h_next)
430 if (hm->h_gid == gid)
431 add_aka (ak, hm->h_name);
438 addall (struct aka *ak)
440 int noshell = NoShell == NULL || *NoShell == 0;
441 register struct home *hm;
448 for (hm = homehead; hm; hm = hm->h_next)
449 if ((int) hm->h_uid > Everyone
450 && (noshell || strcmp (hm->h_shell, NoShell)))
451 add_aka (ak, hm->h_name);
453 return homehead != NULL;
458 getalias (char *addrs)
460 register unsigned char *pp, *qp;
461 static char *cp = NULL;
469 /* Remove leading any space from the address. */
470 for (pp = cp; isspace (*pp); pp++)
474 /* Find the end of the address. */
475 for (qp = pp; *qp != 0 && *qp != ','; qp++)
477 /* Set cp to point to the remainder of the addresses. */
480 for (cp = qp, qp--; qp > pp; qp--)
493 add_aka (struct aka *ak, char *pp)
495 register struct adr *ad, *ld;
497 for (ad = ak->ak_addr, ld = NULL; ad; ld = ad, ad = ad->ad_next)
498 if (!strcmp (pp, ad->ad_text))
501 ad = (struct adr *) mh_xmalloc (sizeof(*ad));
502 ad->ad_text = getcpy (pp);
503 ad->ad_local = strchr(pp, '@') == NULL && strchr(pp, '!') == NULL;
515 register struct passwd *pw;
520 /* if the list has yet to be initialized */
521 /* zap the list, and rebuild from scratch */
528 while ((pw = getpwent ()))
540 register struct aka *p;
542 p = (struct aka *) mh_xmalloc (sizeof(*p));
544 p->ak_name = getcpy (id);
549 akatail->ak_next = p;
559 hmalloc (struct passwd *pw)
561 register struct home *p;
563 p = (struct home *) mh_xmalloc (sizeof(*p));
565 p->h_name = getcpy (pw->pw_name);
566 p->h_uid = pw->pw_uid;
567 p->h_gid = pw->pw_gid;
568 p->h_home = getcpy (pw->pw_dir);
569 p->h_shell = getcpy (pw->pw_shell);
572 if (hometail != NULL)
573 hometail->h_next = p;
574 if (homehead == NULL)
583 seek_home (char *name)
585 register struct home *hp;
591 for (hp = homehead; hp; hp = hp->h_next)
592 if (!mh_strcasecmp (name, hp->h_name))
596 * The only place where there might be problems.
597 * This assumes that ALL usernames are kept in lowercase.
599 for (c = name, c1 = lname;
600 *c && (c1 - lname < (int) sizeof(lname) - 1);
602 if (isalpha(*c) && isupper(*c))
608 if ((pw = getpwnam(lname)))