/* $Header$ * * This generates the /usr/lib/aliases file for the mailhub. * * (c) Copyright 1988 by the Massachusetts Institute of Technology. * For copying and distribution information, please see the file * . */ #include #include #include #include #include #include #include #include #include extern int errno; char *whoami = "mailhub.gen"; char *ingres_date_and_time(); char *divide = "##############################################################"; #define ML_WID 72 #define AL_MAX_WID 896 #define FALSE 0 #define TRUE (!FALSE) main(argc, argv) int argc; char **argv; { long tm = time(NULL); FILE *out= stdout; char filename[64], *targetfile; struct stat sb; ## int flag; ## char *filetime; int ingerr(); IIseterr(ingerr); ## ingres sms ## set lockmode session where level = table if (argc == 2) { if (stat(argv[1], &sb) == 0) { filetime = ingres_date_and_time(sb.st_mtime); ## retrieve (flag = int4(interval("min",tblstats.modtime - filetime))) ## where tblstats.table = "users" if (flag < 0) { fprintf(stderr, "File %s does not need to be rebuilt.\n", argv[1]); exit(SMS_NO_CHANGE); } } targetfile = argv[1]; sprintf(filename, "%s~", targetfile); if ((out = fopen(filename, "w")) == NULL) { fprintf(stderr, "unable to open %s for output\n", filename); exit(SMS_OCONFIG); } } else if (argc != 1) { fprintf(stderr, "usage: %s [outfile]\n", argv[0]); exit(SMS_ARGS); } fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm)); fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide); ## begin transaction get_info(); ## end transaction ## exit fprintf(stderr, "Sorting Info\n"); sort_info(); fprintf(stderr, "Dumping information\n"); do_lists(out); do_people(out); fprintf(out, "\n%s\n# End of aliases file\n", divide); if (fclose(out)) { perror("close failed"); exit(SMS_CCONFIG); } if (argc == 2) fix_file(targetfile); exit(SMS_SUCCESS); } /* * ingerr: (supposedly) called when Ingres indicates an error. * I have not yet been able to get this to work to intercept a * database open error. */ #define INGRES_DEADLOCK 4700 static int ingerr(num) int *num; { char buf[256]; int ingres_errno; switch (*num) { case INGRES_DEADLOCK: ingres_errno = SMS_DEADLOCK; break; default: ingres_errno = SMS_INGRES_ERR; } com_err(whoami, SMS_INGRES_ERR, " code %d\n", *num); critical_alert("DCM", "Alias build encountered INGRES ERROR %d", *num); exit(ingres_errno); } struct hash *users, *machines, *strings, *lists, *names; struct user { char *login; char *first; char *last; char mi; char *pobox; }; struct member { struct member *next; char *name; int list_id; }; struct list { char *name; char maillist; char acl_t; int acl_id; struct member *m; }; struct names { char *name; struct names *next; int keep:1; int id:31; }; get_info() ##{ ## int id, pid, bid, stat, cnt, maillistp, acl, mid; ## char name[129], type[9], fname[17], mname[17], lname[17], buf[257]; char *s; register struct user *u; struct list *l, *memberlist; register struct member *m; /* get locks */ ## retrieve (buf = users.modtime) where users.users_id = 0 ## retrieve (buf = list.modtime) where list.list_id = 0 cnt = 0; machines = create_hash(1000); ## retrieve (id = machine.mach_id, name = machine.#name) { if (s = index(name, '.')) *s = 0; sprintf(buf, "%s.LOCAL", name); if (hash_store(machines, id, strsave(buf)) < 0) { fprintf(stderr, "Out of memory!\n"); exit(SMS_NO_MEM); } cnt++; ## } fprintf(stderr, "Loaded %d machines\n", cnt); cnt = 0; strings = create_hash(2000); ## retrieve (id = strings.string_id, name = strings.string) { if (hash_store(strings, id, strsave(strtrim(name))) < 0) { fprintf(stderr, "Out of memory!\n"); exit(SMS_NO_MEM); } cnt++; ## } fprintf(stderr, "Loaded %d strings\n", cnt); cnt = 0; users = create_hash(12001); ## range of u is users ## retrieve (id = u.users_id, name = u.login, fname = u.first, ## mname = u.middle, lname = u.last, ## type = u.potype, pid = u.pop_id, bid = u.box_id) ## where u.status != 3 { u = (struct user *) malloc(sizeof(struct user)); u->login = strsave(strtrim(name)); u->first = strsave(strtrim(fname)); u->last = strsave(strtrim(lname)); if (mname[0] != ' ') u->mi = mname[0]; else u->mi = 0; if (type[0] == 'P' && (s = hash_lookup(machines, pid))) { sprintf(buf, "%s@%s", strtrim(name), s); u->pobox = strsave(buf); } else if (type[0] == 'S') { u->pobox = hash_lookup(strings, bid); } else u->pobox = (char *) NULL; if (hash_store(users, id, u) < 0) { fprintf(stderr, "Out of memory!\n"); exit(SMS_NO_MEM); } cnt++; ## } fprintf(stderr, "Loaded %d users\n", cnt); cnt = 0; lists = create_hash(15000); ## range of l is list ## retrieve (id = l.list_id, name = l.#name, maillistp = l.maillist, ## type = l.acl_type, acl = l.acl_id) ## where l.active != 0 { l = (struct list *) malloc(sizeof(struct list)); l->name = strsave(strtrim(name)); l->maillist = maillistp; l->acl_t = type[0]; l->acl_id = acl; l->m = (struct member *) NULL; if (hash_store(lists, id, l) < 0) { fprintf(stderr, "Out of memory!\n"); exit(SMS_NO_MEM); } cnt++; ## } fprintf(stderr, "Loaded %d lists\n", cnt); cnt = 0; ## range of m is imembers ## retrieve (id = m.list_id, type = m.member_type, mid = m.member_id) ## where m.direct = 1 { cnt++; if (l = (struct list *) hash_lookup(lists, id)) { m = (struct member *) malloc(sizeof(struct member)); if (type[0] == 'U' && (u = (struct user *) hash_lookup(users, mid))) { m->list_id = 0; m->name = u->login; m->next = l->m; l->m = m; } else if (type[0] == 'L' && (memberlist = (struct list *) hash_lookup(lists, mid))) { m->list_id = mid; m->name = memberlist->name; m->next = l->m; l->m = m; } else if (type[0] == 'S' && (s = hash_lookup(strings, mid))) { m->list_id = 0; m->next = l->m; l->m = m; m->name = s; } } ## } fprintf(stderr, "Loaded %d members\n", cnt); ##} save_mlist(id, l, force) int id; struct list *l; int force; { register struct member *m; register struct list *l1; if (l->maillist == 2 || l->maillist == 3 || (l->maillist == 0 && !force)) return; if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name)) { l->maillist = 3; return; } l->maillist = 2; insert_name(l->name, -id, TRUE, FALSE); if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id))) save_mlist(0, l1, TRUE); for (m = l->m; m; m = m->next) { if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id))) save_mlist(0, l1, TRUE); } } insert_login(id, u, dummy) int id; struct user *u; int dummy; { if (u->pobox && u->login[0] != '#') insert_name(u->login, id, TRUE, FALSE); } void insert_names(id, u, dummy) int id; struct user *u; int dummy; { char buffer[256]; insert_name(u->last, id, FALSE, FALSE); sprintf(buffer, "%s_%s", u->first, u->last); insert_name(buffer, id, FALSE, TRUE); sprintf(buffer, "%c_%s", u->first[0], u->last); insert_name(buffer, id, FALSE, TRUE); if (u->mi) { sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last); insert_name(buffer, id, FALSE, TRUE); } } int incount = 0; insert_name(s, id, nodups, copy) char *s; int id; int nodups; int copy; { int code; register struct names *ns; register int count; register struct idblock *ra; incount++; code = hashstr(s); ns = (struct names *) hash_lookup(names, code); if (ns == NULL) { if ((ns = (struct names *) malloc(sizeof(struct names))) == NULL) { fprintf(stderr, "ran out of memory inserting name (sorting)\n"); exit(SMS_NO_MEM); } if (copy) ns->name = strsave(s); else ns->name = s; ns->keep = nodups; ns->id = id; if (hash_store(names, code, ns) < 0) { fprintf(stderr, "Out of memory!\n"); exit(SMS_NO_MEM); } return; } if (strcasecmp(ns->name, s)) { while (ns->next) { ns = ns->next; if (!strcasecmp(ns->name, s)) goto foundns; } if ((ns->next = (struct names *)malloc(sizeof(struct names))) == NULL) { fprintf(stderr, "ran out of memory insterting name (sorting)\n"); exit(SMS_NO_MEM); } ns = ns->next; if (copy) ns->name = strsave(s); else ns->name = s; ns->keep = nodups; ns->id = id; return; } foundns: if (nodups || ns->keep) return; ns->id = 0; } int hashstr(s) register char *s; { register int result; register int c; for (result = 0; c = *s; s++) { if (isupper(c)) c = *s = tolower(c); /* result = result * 31 + *s; */ result = (result << 5) - result + c - '`'; } return(result < 0 ? -result : result); } sort_info() { names = create_hash(20001); hash_step(users, insert_login, NULL); hash_step(lists, save_mlist, FALSE); hash_step(users, insert_names, NULL); fprintf(stderr, "Inserted %d names\n", incount); } output_data(dummy, nms, out) int dummy; struct names *nms; FILE *out; { register struct names *ns; register struct user *u; int i; incount++; for (ns = nms; ns; ns = ns->next) { if (ns->name[0] == 0 || ns->name[1] == 0) { fprintf(stderr, "punting %s due to short name\n", ns->name); continue; } if (ns->id > 0) { u = (struct user *) hash_lookup(users, ns->id); if (u->pobox) { fprintf(out, "%s: %s\n", ns->name, u->pobox); } else { fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name); } } else if (ns->id == 0) { fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name); } } } int lwid, bol, awid; output_mlist(id, l, out) int id; register struct list *l; FILE *out; { struct list *l1; register struct member *m; register struct user *u; if (l->maillist != 2) return; if (l->acl_t == 'L' && (l1 = (struct list *) hash_lookup(lists, l->acl_id))) fprintf(out, "owner-%s: %s\n", l->name, l1->name); else if (l->acl_t == 'U' && (u = (struct user *) hash_lookup(users, l->acl_id))) fprintf(out, "owner-%s: %s\n", l->name, u->login); fprintf(out, "%s: ", l->name); lwid = strlen(l->name) + 2; bol = 1; for (m = l->m; m; m = m->next) { do_member(out, m->name); } if (l->m == (struct member *)NULL) fprintf(out, "/dev/null"); fprintf(out, "\n\n"); incount++; } /* print out strings separated by commas, doing line breaks as appropriate */ do_member(out, s) FILE *out; register char *s; { register wwid; static int cont = 1; wwid = strlen(s); if (!bol && awid + wwid + 2 > AL_MAX_WID) { fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont); cont++; awid = lwid = 17 + wwid; fputs(s, out); return; } if (bol) { lwid += wwid; awid = lwid; fputs(s, out); bol = 0; return; } if (lwid + wwid + 2 > ML_WID) { fprintf(out, ",\n\t%s", s); awid += lwid + wwid + 2; lwid = wwid + 8; return; } lwid += wwid + 2; fprintf(out, ", %s", s); } do_lists(out) FILE *out; { incount = 0; fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide); hash_step(lists, output_mlist, out); fprintf(stderr, "Output %d lists\n", incount); } do_people(out) FILE *out; { incount = 0; fprintf(out, "\n%s\n# People\n%s\n", divide, divide); hash_step(names, output_data, out); fprintf(stderr, "Output %d entries\n", incount); }