2 ** aliasbr.c -- new aliasing mechanism
4 ** This code is Copyright (c) 2002, by the authors of nmh. See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
10 #include <h/aliasbr.h>
11 #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 char *getalias(char *);
45 static void add_aka(struct aka *, char *);
46 static struct aka *akalloc(char *);
47 static struct home *hmalloc(struct passwd *);
48 struct home *seek_home(char *);
51 /* Do mh alias substitution on 's' and return the results. */
58 v = akval(akahead, s);
73 akresult(struct aka *ak)
75 char *cp = NULL, *dp, *pp;
78 for (ad = ak->ak_addr; ad; ad = ad->ad_next) {
79 pp = ad->ad_local ? akval(ak->ak_next, ad->ad_text)
80 : mh_xstrdup(ad->ad_text);
84 cp = concat(cp, ",", pp, NULL);
92 akvis = ak->ak_visible;
98 akval(struct aka *ak, char *s)
103 for (; ak; ak = ak->ak_next) {
104 if (aleq (s, ak->ak_name)) {
105 return akresult (ak);
106 } else if (strchr (s, ':')) {
108 ** The first address in a blind list will contain the
109 ** alias name, so try to match, but just with just the
110 ** address (not including the list name). If there's a
111 ** match, then replace the alias part with its
115 char *name = getname(s);
120 ** s is of the form "Blind list: address". If address
121 ** is an alias, expand it.
123 struct mailname *mp = getm(name, NULL, 0, AD_NAME, NULL);
125 if (mp && mp->m_ingrp) {
126 char *gname = add (mp->m_gname, NULL);
128 if (gname && aleq(name, ak->ak_name)) {
130 cp = concat (gname, akresult (ak), NULL);
136 /* Need to flush getname after use. */
137 while (getname("")) continue;
145 return mh_xstrdup(s);
150 aleq(char *string, char *aliasent)
154 while ((c = *string++))
155 if (*aliasent == '*')
157 else if ((c | 040) != (*aliasent | 040))
162 return (*aliasent == 0 || *aliasent == '*');
167 ** file needs to be absolute or relative to cwd
175 struct aka *ak = NULL;
178 if ((fp = fopen(file, "r")) == NULL) {
183 while (vfgets(fp, &ap) == OK) {
185 switch (*(pp = scanp(bp))) {
186 case '<': /* recurse a level */
187 if (!*(cp = getp(pp + 1))) {
188 akerrst = "'<' without alias-file";
192 if ((i = alias(cp)) != AK_OK) {
197 case ':': /* comment */
205 if (!*(cp = seekp(pp, &lc, &ap))) {
209 if (!(ak = akalloc(cp))) {
227 switch (*(pp = scanp(ap))) {
232 case '<': /* read values from file */
233 if (!*(cp = getp(pp + 1))) {
237 if (!addfile(ak, cp)) {
243 case '=': /* UNIX group */
244 if (!*(cp = getp(pp + 1))) {
248 if (!addgroup(ak, cp)) {
254 case '+': /* UNIX group members */
255 if (!*(cp = getp(pp + 1))) {
259 if (!addmember(ak, cp)) {
266 while ((cp = getalias(pp)))
280 static char buffer[BUFSIZ];
284 snprintf(buffer, sizeof(buffer), "unable to read '%s'",
289 snprintf(buffer, sizeof(buffer), "error in line '%s'",
294 snprintf(buffer, sizeof(buffer), "out of memory while on '%s'",
299 snprintf(buffer, sizeof(buffer), "no such group as '%s'",
304 snprintf(buffer, sizeof(buffer), "unknown error (%d)", i);
313 scanp(unsigned char *p)
324 unsigned char *cp = scanp(p);
327 while (!isspace(*cp) && *cp)
336 seekp(char *p, char *c, char **a)
341 while (!isspace(*cp) && *cp && *cp != ':' && *cp != ';')
352 addfile(struct aka *ak, char *file)
358 if (!(fp = fopen(etcpath(file), "r"))) {
363 while (fgets(buffer, sizeof buffer, fp))
364 while ((cp = getalias(buffer)))
373 addgroup(struct aka *ak, char *grp)
376 struct group *gr = getgrnam(grp);
377 struct home *hm = NULL;
380 gr = getgrgid(atoi(grp));
386 while ((gp = *gr->gr_mem++))
389 for (hm = homehead; hm; hm = hm->h_next)
390 if (strcmp(hm->h_name, gp)==0) {
391 add_aka(ak, hm->h_name);
394 if ((pw = getpwnam(gp))) {
405 addmember(struct aka *ak, char *grp)
408 struct group *gr = getgrnam(grp);
409 struct home *hm = NULL;
424 for (hm = homehead; hm; hm = hm->h_next)
425 if (hm->h_gid == gid)
426 add_aka(ak, hm->h_name);
433 getalias(char *addrs)
435 unsigned char *pp, *qp;
436 static char *cp = NULL;
444 for (pp = cp; isspace(*pp); pp++)
448 for (qp = pp; *qp != 0 && *qp != ','; qp++)
452 for (cp = qp, qp--; qp > pp; qp--)
465 add_aka(struct aka *ak, char *pp)
469 for (ad = ak->ak_addr, ld = NULL; ad; ld = ad, ad = ad->ad_next)
470 if (strcmp(pp, ad->ad_text)==0)
473 ad = mh_xcalloc(1, sizeof(*ad));
474 ad->ad_text = mh_xstrdup(pp);
475 ad->ad_local = strchr(pp, '@') == NULL;
491 /* read the passwd database and build a list */
493 while ((pw = getpwent())) {
500 init++; /* now we're initialized */
510 p = mh_xcalloc(1, sizeof(*p));
512 p->ak_name = mh_xstrdup(id);
517 akatail->ak_next = p;
527 hmalloc(struct passwd *pw)
531 p = mh_xcalloc(1, sizeof(*p));
533 p->h_name = mh_xstrdup(pw->pw_name);
534 p->h_uid = pw->pw_uid;
535 p->h_gid = pw->pw_gid;
536 p->h_home = mh_xstrdup(pw->pw_dir);
537 p->h_shell = mh_xstrdup(pw->pw_shell);
544 hometail->h_next = p;
552 seek_home(char *name)
560 for (hp = homehead; hp; hp = hp->h_next)
561 if (!mh_strcasecmp(name, hp->h_name))
565 ** The only place where there might be problems.
566 ** This assumes that ALL usernames are kept in lowercase.
568 for (c = name, c1 = lname; *c && (c1 - lname < (int)sizeof(lname) - 1);
570 if (isalpha(*c) && isupper(*c))
576 if ((pw = getpwnam(lname)))