3 * This generates the /usr/lib/aliases file for the mailhub.
5 * (c) Copyright 1988, 1990 by the Massachusetts Institute of Technology.
6 * For copying and distribution information, please see the file
10 #include <mit-copyright.h>
15 #include <moira_site.h>
16 #include <sys/types.h>
19 EXEC SQL INCLUDE sqlca;
23 char *whoami = "mailhub.gen";
26 char *divide = "##############################################################";
29 #define AL_MAX_WID 896
42 char filename[64], *targetfile;
44 EXEC SQL BEGIN DECLARE SECTION;
46 EXEC SQL END DECLARE SECTION;
49 EXEC SQL CONNECT moira;
52 EXEC SQL DATABASE moira;
56 if (stat(argv[1], &sb) == 0) {
57 if (ModDiff (&flag, "users", sb.st_mtime))
60 fprintf(stderr, "File %s does not need to be rebuilt.\n",
66 sprintf(filename, "%s~", targetfile);
67 if ((out = fopen(filename, "w")) == NULL) {
68 fprintf(stderr, "unable to open %s for output\n", filename);
71 } else if (argc != 1) {
72 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
76 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
77 fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide);
85 EXEC SQL CLOSE DATABASE;
88 fprintf(stderr, "Sorting Info\n");
91 fprintf(stderr, "Dumping information\n");
94 fprintf(out, "\n%s\n# End of aliases file\n", divide);
97 perror("close failed");
102 fix_file(targetfile);
108 struct hash *users, *machines, *strings, *lists, *names;
138 EXEC SQL BEGIN DECLARE SECTION;
139 int id, pid, bid, cnt, maillistp, acl, mid;
140 char name[129], type[9], fname[17], mname[17], lname[17], buf[257];
141 EXEC SQL END DECLARE SECTION;
143 register struct user *u;
144 struct list *l, *memberlist;
145 register struct member *m;
147 /* The following is declarative, not executed,
148 * and so is dependent on where it is in the file,
149 * not in the order of execution of statements.
151 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
153 EXEC SQL SELECT modtime INTO :buf FROM users WHERE users_id = 0;
154 EXEC SQL SELECT modtime INTO :buf FROM list WHERE list_id = 0;
157 machines = create_hash(10);
159 EXEC SQL DECLARE m_cursor CURSOR FOR
160 SELECT m.mach_id, m.name
161 FROM machine m, users u
162 WHERE m.mach_id = u.pop_id;
163 EXEC SQL OPEN m_cursor;
165 EXEC SQL FETCH m_cursor INTO :id, :name;
166 if (sqlca.sqlcode != 0) break;
167 if (s = index(name, '.'))
172 strcat(name, ".LOCAL");
174 if (hash_store(machines, id, pstrsave(name)) < 0) {
175 fprintf(stderr, "Out of memory!\n");
180 EXEC SQL CLOSE m_cursor;
182 fprintf(stderr, "Loaded %d machines\n", cnt);
185 strings = create_hash(4000);
187 EXEC SQL DECLARE s_cursor CURSOR FOR
188 SELECT string_id, string
190 EXEC SQL OPEN s_cursor;
192 EXEC SQL FETCH s_cursor INTO :id, :name;
193 if (sqlca.sqlcode != 0) break;
194 if (hash_store(strings, id, pstrsave(strtrim(name))) < 0) {
195 fprintf(stderr, "Out of memory!\n");
200 EXEC SQL CLOSE s_cursor;
202 fprintf(stderr, "Loaded %d strings\n", cnt);
205 users = create_hash(12001);
207 EXEC SQL DECLARE u_cursor CURSOR FOR
208 SELECT users_id, login, first, middle, last, potype, pop_id, box_id
211 EXEC SQL OPEN u_cursor;
213 EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
215 if (sqlca.sqlcode != 0) break;
216 u = (struct user *) perm_malloc(sizeof(struct user));
217 u->login = pstrsave(strtrim(name));
218 u->first = pstrsave(strtrim(fname));
219 u->last = pstrsave(strtrim(lname));
225 if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
226 sprintf(buf, "%s@%s", u->login, s);
227 u->pobox = pstrsave(buf);
228 } else if (type[0] == 'S') {
229 u->pobox = hash_lookup(strings, bid);
231 u->pobox = (char *) NULL;
232 if (hash_store(users, id, u) < 0) {
233 fprintf(stderr, "Out of memory!\n");
238 EXEC SQL CLOSE u_cursor;
239 fprintf(stderr, "Loaded %d users\n", cnt);
242 lists = create_hash(15000);
244 EXEC SQL DECLARE l_cursor CURSOR FOR
245 SELECT list_id, name, maillist, acl_type, acl_id
248 EXEC SQL OPEN l_cursor;
250 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :type, :acl;
251 if (sqlca.sqlcode != 0) break;
252 l = (struct list *) perm_malloc(sizeof(struct list));
253 l->name = pstrsave(strtrim(name));
254 l->maillist = maillistp;
257 l->m = (struct member *) NULL;
258 if (hash_store(lists, id, l) < 0) {
259 fprintf(stderr, "Out of memory!\n");
264 EXEC SQL CLOSE l_cursor;
265 fprintf(stderr, "Loaded %d lists\n", cnt);
269 EXEC SQL DECLARE m_cursor2 CURSOR FOR
270 SELECT list_id, member_type, member_id
273 EXEC SQL OPEN m_cursor2;
275 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
276 if (sqlca.sqlcode != 0) break;
278 if (l = (struct list *) hash_lookup(lists, id)) {
279 m = (struct member *) perm_malloc(sizeof(struct member));
280 if (type[0] == 'U' &&
281 (u = (struct user *) hash_lookup(users, mid))) {
286 } else if (type[0] == 'L' &&
287 (memberlist = (struct list *) hash_lookup(lists, mid))) {
289 m->name = memberlist->name;
292 } else if (type[0] == 'S' &&
293 (s = hash_lookup(strings, mid))) {
301 EXEC SQL CLOSE m_cursor2;
302 fprintf(stderr, "Loaded %d members\n", cnt);
305 com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
306 critical_alert("DCM", "Hesiod build encountered DATABASE ERROR %d",
312 save_mlist(id, l, force)
317 register struct member *m;
318 register struct list *l1;
320 if (l->maillist > 1 ||
321 (l->maillist == 0 && !force))
324 if (l->m && l->m->next == NULL &&
325 !strcasecmp(l->name, l->m->name)) {
330 insert_name(l->name, -1, TRUE, FALSE);
333 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
334 save_mlist(0, l1, TRUE);
336 for (m = l->m; m; m = m->next) {
337 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
338 save_mlist(0, l1, TRUE);
343 insert_login(id, u, dummy)
348 if (u->pobox && u->login[0] != '#')
349 insert_name(u->login, id, TRUE, FALSE);
352 void insert_names(id, u, dummy)
359 insert_name(u->last, id, FALSE, FALSE);
360 sprintf(buffer, "%s_%s", u->first, u->last);
361 insert_name(buffer, id, FALSE, TRUE);
362 /* sprintf(buffer, "%c_%s", u->first[0], u->last);
363 insert_name(buffer, id, FALSE, TRUE); */
365 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
366 insert_name(buffer, id, FALSE, TRUE);
372 insert_name(s, id, nodups, copy)
379 register struct names *ns;
383 ns = (struct names *) hash_lookup(names, code);
385 if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
386 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
390 ns->name = pstrsave(s);
396 if (hash_store(names, code, ns) < 0) {
397 fprintf(stderr, "Out of memory!\n");
402 if (strcasecmp(ns->name, s)) {
405 if (!strcasecmp(ns->name, s))
408 if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
410 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
415 ns->name = pstrsave(s);
424 if (nodups || ns->keep) {
425 if (nodups && ns->keep)
426 fprintf(stderr, "duplicated name: %s\n", s);
433 /* Illegal chars: ! " % ( ) , . / : ; < = > @ [ \ ] ^ { | } */
435 static int illegalchars[] = {
436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
437 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
438 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, /* SPACE - / */
439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
440 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
444 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
445 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
446 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
447 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
448 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
449 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
450 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
451 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
455 /* While hashing the string, punt any illegal characters */
463 for (result = 0; c = *s; s++) {
464 if (illegalchars[c]) {
472 /* result = result * 31 + *s; */
473 result = (result << 5) - result + c - '`';
475 return(result < 0 ? -result : result);
481 names = create_hash(20001);
482 hash_step(users, insert_login, NULL);
484 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
485 hash_step(lists, save_mlist, FALSE);
486 fprintf(stderr, "Output %d lists\n", incount);
487 hash_step(users, insert_names, NULL);
488 fprintf(stderr, "Inserted %d names\n", incount);
492 output_data(dummy, nms, out)
497 register struct names *ns;
498 register struct user *u;
501 for (ns = nms; ns; ns = ns->next) {
502 if (ns->name[0] == 0 || ns->name[1] == 0) {
503 fprintf(stderr, "punting %s due to short name\n", ns->name);
507 u = (struct user *) hash_lookup(users, ns->id);
509 fprintf(out, "%s: %s\n", ns->name, u->pobox);
511 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
513 } else if (ns->id == 0) {
514 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
524 register struct list *l;
527 register struct member *m;
528 register struct user *u;
530 if (l->acl_t == 'L' &&
531 (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
532 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
533 else if (l->acl_t == 'U' &&
534 (u = (struct user *) hash_lookup(users, l->acl_id)))
535 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
537 fprintf(out, "%s: ", l->name);
540 lwid = strlen(l->name) + 2;
542 for (m = l->m; m; m = m->next) {
543 do_member(out, m->name);
545 if (l->m == (struct member *)NULL)
546 fprintf(out, "/dev/null");
547 fprintf(out, "\n\n");
552 /* print out strings separated by commas, doing line breaks as appropriate */
563 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
564 fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
566 awid = lwid = 17 + wwid;
578 if (lwid + wwid + 2 > ML_WID) {
579 fprintf(out, ",\n\t%s", s);
580 awid += lwid + wwid + 2;
585 fprintf(out, ", %s", s);
592 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
593 hash_step(names, output_data, out);
594 fprintf(stderr, "Output %d entries\n", incount);
598 #define chunk_size 102400
600 char *perm_malloc(size)
603 static char *pool = NULL;
604 static unsigned pool_size = 0;
607 if (size > pool_size) {
608 pool = (char *) malloc(chunk_size);
609 pool_size = chunk_size;
613 pool = (char *)(((unsigned) (pool + 1)) & ~1);
614 pool_size -= (pool - ret);
620 * Make a (permenant) copy of a string.
628 /* Kludge for sloppy string semantics */
630 printf("NULL != \"\" !!!!\r\n");
636 p = perm_malloc((u_int)len);
637 if (p) bcopy(s, p, len);
641 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
643 /* Create a hash table. The size is just a hint, not a maximum. */
645 struct hash *create_hash(size)
650 h = (struct hash *) perm_malloc(sizeof(struct hash));
651 if (h == (struct hash *) NULL)
652 return((struct hash *) NULL);
654 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
655 if (h->data == (struct bucket **) NULL) {
657 return((struct hash *) NULL);
659 bzero(h->data, size * sizeof(char *));
663 /* Lookup an object in the hash table. Returns the value associated with
664 * the key, or NULL (thus NULL is not a very good value to store...)
667 char *hash_lookup(h, key)
671 register struct bucket *b;
673 b = h->data[hash_func(h, key)];
674 while (b && b->key != key)
676 if (b && b->key == key)
683 /* Update an existing object in the hash table. Returns 1 if the object
684 * existed, or 0 if not.
687 int hash_update(h, key, value)
692 register struct bucket *b;
694 b = h->data[hash_func(h, key)];
695 while (b && b->key != key)
697 if (b && b->key == key) {
705 /* Store an item in the hash table. Returns 0 if the key was not previously
706 * there, 1 if it was, or -1 if we ran out of memory.
709 int hash_store(h, key, value)
714 register struct bucket *b, **p;
716 p = &(h->data[hash_func(h, key)]);
718 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
719 if (b == (struct bucket *) NULL)
727 for (b = *p; b && b->key != key; b = *p)
728 p = (struct bucket **) *p;
729 if (b && b->key == key) {
733 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
734 if (b == (struct bucket *) NULL)
743 /* Search through the hash table for a given value. For each piece of
744 * data with that value, call the callback proc with the corresponding key.
747 hash_search(h, value, callback)
749 register char *value;
752 register struct bucket *b, **p;
754 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
755 for (b = *p; b; b = b->next) {
756 if (b->data == value)
763 /* Step through the hash table, calling the callback proc with each key.
766 hash_step(h, callback, hint)
771 register struct bucket *b, **p;
773 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
774 for (b = *p; b; b = b->next) {
775 (*callback)(b->key, b->data, hint);
781 /* Deallocate all of the memory associated with a table */
786 register struct bucket *b, **p, *b1;
788 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
789 for (b = *p; b; b = b1) {