4 * This generates the /usr/lib/aliases file for the mailhub.
6 * (c) Copyright 1988 by the Massachusetts Institute of Technology.
7 * For copying and distribution information, please see the file
11 #include <mit-copyright.h>
16 #include <moira_site.h>
17 #include <sys/types.h>
23 char *whoami = "mailhub.gen";
24 char *ingres_date_and_time();
27 char *divide = "##############################################################";
30 #define AL_MAX_WID 896
43 char filename[64], *targetfile;
51 ## set lockmode session where level = table
54 if (stat(argv[1], &sb) == 0) {
55 filetime = ingres_date_and_time(sb.st_mtime);
56 ## retrieve (flag = int4(interval("min",tblstats.modtime - filetime)))
57 ## where tblstats.table = "users"
59 fprintf(stderr, "File %s does not need to be rebuilt.\n",
65 sprintf(filename, "%s~", targetfile);
66 if ((out = fopen(filename, "w")) == NULL) {
67 fprintf(stderr, "unable to open %s for output\n", filename);
70 } else if (argc != 1) {
71 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
75 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
76 fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide);
83 fprintf(stderr, "Sorting Info\n");
86 fprintf(stderr, "Dumping information\n");
89 fprintf(out, "\n%s\n# End of aliases file\n", divide);
92 perror("close failed");
103 * ingerr: (supposedly) called when Ingres indicates an error.
104 * I have not yet been able to get this to work to intercept a
105 * database open error.
107 #define INGRES_DEADLOCK 4700
109 static int ingerr(num)
116 case INGRES_DEADLOCK:
117 ingres_errno = MR_DEADLOCK;
120 ingres_errno = MR_INGRES_ERR;
122 com_err(whoami, MR_INGRES_ERR, " code %d\n", *num);
123 critical_alert("DCM", "Alias build encountered INGRES ERROR %d", *num);
127 struct hash *users, *machines, *strings, *lists, *names;
157 ## int id, pid, bid, stat, cnt, maillistp, acl, mid;
158 ## char name[129], type[9], fname[17], mname[17], lname[17], buf[257];
160 register struct user *u;
161 struct list *l, *memberlist;
162 register struct member *m;
165 ## retrieve (buf = users.modtime) where users.users_id = 0
166 ## retrieve (buf = list.modtime) where list.list_id = 0
169 machines = create_hash(10);
170 ## retrieve (id = machine.mach_id, name = machine.#name)
171 ## where machine.mach_id = users.pop_id {
172 if (s = index(name, '.'))
177 strcat(name, ".LOCAL");
179 if (hash_store(machines, id, pstrsave(name)) < 0) {
180 fprintf(stderr, "Out of memory!\n");
185 fprintf(stderr, "Loaded %d machines\n", cnt);
188 strings = create_hash(4000);
189 ## retrieve (id = strings.string_id, name = strings.string) {
190 if (hash_store(strings, id, pstrsave(strtrim(name))) < 0) {
191 fprintf(stderr, "Out of memory!\n");
196 fprintf(stderr, "Loaded %d strings\n", cnt);
199 users = create_hash(12001);
200 ## range of u is users
201 ## retrieve (id = u.users_id, name = u.login, fname = u.first,
202 ## mname = u.middle, lname = u.last,
203 ## type = u.potype, pid = u.pop_id, bid = u.box_id)
204 ## where u.status != 3 {
205 u = (struct user *) perm_malloc(sizeof(struct user));
206 u->login = pstrsave(strtrim(name));
207 u->first = pstrsave(strtrim(fname));
208 u->last = pstrsave(strtrim(lname));
214 if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
215 sprintf(buf, "%s@%s", u->login, s);
216 u->pobox = pstrsave(buf);
217 } else if (type[0] == 'S') {
218 u->pobox = hash_lookup(strings, bid);
220 u->pobox = (char *) NULL;
221 if (hash_store(users, id, u) < 0) {
222 fprintf(stderr, "Out of memory!\n");
227 fprintf(stderr, "Loaded %d users\n", cnt);
230 lists = create_hash(15000);
231 ## range of l is list
232 ## retrieve (id = l.list_id, name = l.#name, maillistp = l.maillist,
233 ## type = l.acl_type, acl = l.acl_id)
234 ## where l.active != 0 {
235 l = (struct list *) perm_malloc(sizeof(struct list));
236 l->name = pstrsave(strtrim(name));
237 l->maillist = maillistp;
240 l->m = (struct member *) NULL;
241 if (hash_store(lists, id, l) < 0) {
242 fprintf(stderr, "Out of memory!\n");
247 fprintf(stderr, "Loaded %d lists\n", cnt);
250 ## range of m is imembers
251 ## retrieve (id = m.list_id, type = m.member_type, mid = m.member_id)
252 ## where m.direct = 1 {
254 if (l = (struct list *) hash_lookup(lists, id)) {
255 m = (struct member *) perm_malloc(sizeof(struct member));
256 if (type[0] == 'U' &&
257 (u = (struct user *) hash_lookup(users, mid))) {
262 } else if (type[0] == 'L' &&
263 (memberlist = (struct list *) hash_lookup(lists, mid))) {
265 m->name = memberlist->name;
268 } else if (type[0] == 'S' &&
269 (s = hash_lookup(strings, mid))) {
277 fprintf(stderr, "Loaded %d members\n", cnt);
281 save_mlist(id, l, force)
286 register struct member *m;
287 register struct list *l1;
289 if (l->maillist > 1 ||
290 (l->maillist == 0 && !force))
293 if (l->m && l->m->next == NULL &&
294 !strcasecmp(l->name, l->m->name)) {
299 insert_name(l->name, -1, TRUE, FALSE);
302 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
303 save_mlist(0, l1, TRUE);
305 for (m = l->m; m; m = m->next) {
306 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
307 save_mlist(0, l1, TRUE);
312 insert_login(id, u, dummy)
317 if (u->pobox && u->login[0] != '#')
318 insert_name(u->login, id, TRUE, FALSE);
321 void insert_names(id, u, dummy)
328 insert_name(u->last, id, FALSE, FALSE);
329 sprintf(buffer, "%s_%s", u->first, u->last);
330 insert_name(buffer, id, FALSE, TRUE);
331 /* sprintf(buffer, "%c_%s", u->first[0], u->last);
332 insert_name(buffer, id, FALSE, TRUE); */
334 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
335 insert_name(buffer, id, FALSE, TRUE);
341 insert_name(s, id, nodups, copy)
348 register struct names *ns;
350 register struct idblock *ra;
354 ns = (struct names *) hash_lookup(names, code);
356 if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
357 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
361 ns->name = pstrsave(s);
367 if (hash_store(names, code, ns) < 0) {
368 fprintf(stderr, "Out of memory!\n");
373 if (strcasecmp(ns->name, s)) {
376 if (!strcasecmp(ns->name, s))
379 if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
381 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
386 ns->name = pstrsave(s);
395 if (nodups || ns->keep) {
396 if (nodups && ns->keep)
397 fprintf(stderr, "duplicated named: %s\n", s);
404 /* Illegal chars: ! " % ( ) , . / : ; < = > @ [ \ ] ^ { | } */
406 static int illegalchars[] = {
407 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
408 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
409 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, /* SPACE - / */
410 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
411 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
412 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
415 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
419 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
420 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
421 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
422 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
426 /* While hashing the string, punt any illegal characters */
434 for (result = 0; c = *s; s++) {
435 if (illegalchars[c]) {
443 /* result = result * 31 + *s; */
444 result = (result << 5) - result + c - '`';
446 return(result < 0 ? -result : result);
452 names = create_hash(20001);
453 hash_step(users, insert_login, NULL);
455 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
456 hash_step(lists, save_mlist, FALSE);
457 fprintf(stderr, "Output %d lists\n", incount);
458 hash_step(users, insert_names, NULL);
459 fprintf(stderr, "Inserted %d names\n", incount);
463 output_data(dummy, nms, out)
468 register struct names *ns;
469 register struct user *u;
472 for (ns = nms; ns; ns = ns->next) {
473 if (ns->name[0] == 0 || ns->name[1] == 0) {
474 fprintf(stderr, "punting %s due to short name\n", ns->name);
478 u = (struct user *) hash_lookup(users, ns->id);
480 fprintf(out, "%s: %s\n", ns->name, u->pobox);
482 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
484 } else if (ns->id == 0) {
485 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
495 register struct list *l;
498 register struct member *m;
499 register struct user *u;
501 if (l->acl_t == 'L' &&
502 (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
503 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
504 else if (l->acl_t == 'U' &&
505 (u = (struct user *) hash_lookup(users, l->acl_id)))
506 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
508 fprintf(out, "%s: ", l->name);
511 lwid = strlen(l->name) + 2;
513 for (m = l->m; m; m = m->next) {
514 do_member(out, m->name);
516 if (l->m == (struct member *)NULL)
517 fprintf(out, "/dev/null");
518 fprintf(out, "\n\n");
523 /* print out strings separated by commas, doing line breaks as appropriate */
534 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
535 fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
537 awid = lwid = 17 + wwid;
549 if (lwid + wwid + 2 > ML_WID) {
550 fprintf(out, ",\n\t%s", s);
551 awid += lwid + wwid + 2;
556 fprintf(out, ", %s", s);
563 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
564 hash_step(names, output_data, out);
565 fprintf(stderr, "Output %d entries\n", incount);
569 #define chunk_size 102400
571 char *perm_malloc(size)
574 static char *pool = NULL;
575 static unsigned pool_size = 0;
578 if (size > pool_size) {
579 pool = (char *) malloc(chunk_size);
580 pool_size = chunk_size;
584 pool = (char *)(((unsigned) (pool + 1)) & ~1);
585 pool_size -= (pool - ret);
591 * Make a (permenant) copy of a string.
599 /* Kludge for sloppy string semantics */
601 printf("NULL != \"\" !!!!\r\n");
607 p = perm_malloc((u_int)len);
608 if (p) bcopy(s, p, len);
612 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
614 /* Create a hash table. The size is just a hint, not a maximum. */
616 struct hash *create_hash(size)
621 h = (struct hash *) perm_malloc(sizeof(struct hash));
622 if (h == (struct hash *) NULL)
623 return((struct hash *) NULL);
625 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
626 if (h->data == (struct bucket **) NULL) {
628 return((struct hash *) NULL);
630 bzero(h->data, size * sizeof(char *));
634 /* Lookup an object in the hash table. Returns the value associated with
635 * the key, or NULL (thus NULL is not a very good value to store...)
638 char *hash_lookup(h, key)
642 register struct bucket *b;
644 b = h->data[hash_func(h, key)];
645 while (b && b->key != key)
647 if (b && b->key == key)
654 /* Update an existing object in the hash table. Returns 1 if the object
655 * existed, or 0 if not.
658 int hash_update(h, key, value)
663 register struct bucket *b;
665 b = h->data[hash_func(h, key)];
666 while (b && b->key != key)
668 if (b && b->key == key) {
676 /* Store an item in the hash table. Returns 0 if the key was not previously
677 * there, 1 if it was, or -1 if we ran out of memory.
680 int hash_store(h, key, value)
685 register struct bucket *b, **p;
687 p = &(h->data[hash_func(h, key)]);
689 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
690 if (b == (struct bucket *) NULL)
698 for (b = *p; b && b->key != key; b = *p)
699 p = (struct bucket **) *p;
700 if (b && b->key == key) {
704 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
705 if (b == (struct bucket *) NULL)
714 /* Search through the hash table for a given value. For each piece of
715 * data with that value, call the callback proc with the corresponding key.
718 hash_search(h, value, callback)
720 register char *value;
723 register struct bucket *b, **p;
725 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
726 for (b = *p; b; b = b->next) {
727 if (b->data == value)
734 /* Step through the hash table, calling the callback proc with each key.
737 hash_step(h, callback, hint)
742 register struct bucket *b, **p;
744 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
745 for (b = *p; b; b = b->next) {
746 (*callback)(b->key, b->data, hint);
752 /* Deallocate all of the memory associated with a table */
757 register struct bucket *b, **p, *b1;
759 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
760 for (b = *p; b; b = b1) {