4 * This generates the /usr/lib/aliases file for the mailhub.
6 * (c) Copyright 1988, 1990 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>
20 EXEC SQL INCLUDE sqlca;
24 char *whoami = "mailhub.gen";
27 char *divide = "##############################################################";
30 #define AL_MAX_WID 592
43 char filename[64], *targetfile;
45 EXEC SQL BEGIN DECLARE SECTION;
47 EXEC SQL END DECLARE SECTION;
50 EXEC SQL CONNECT moira;
51 EXEC SQL SET LOCKMODE SESSION WHERE LEVEL=TABLE, READLOCK=SHARED;
54 EXEC SQL DATABASE moira;
58 if (stat(argv[1], &sb) == 0) {
59 if (ModDiff (&flag, "users", sb.st_mtime))
62 fprintf(stderr, "File %s does not need to be rebuilt.\n",
68 sprintf(filename, "%s~", targetfile);
69 if ((out = fopen(filename, "w")) == NULL) {
70 fprintf(stderr, "unable to open %s for output\n", filename);
73 } else if (argc != 1) {
74 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
78 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
79 fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide);
87 EXEC SQL CLOSE DATABASE;
90 fprintf(stderr, "Sorting Info\n");
93 fprintf(stderr, "Dumping information\n");
96 fprintf(out, "\n%s\n# End of aliases file\n", divide);
99 perror("close failed");
104 fix_file(targetfile);
110 struct hash *users, *machines, *strings, *lists, *names;
140 EXEC SQL BEGIN DECLARE SECTION;
141 int id, pid, bid, cnt, maillistp, acl, mid;
142 char name[129], type[9], fname[17], mname[17], lname[17], buf[257];
143 EXEC SQL END DECLARE SECTION;
145 register struct user *u;
146 struct list *l, *memberlist;
147 register struct member *m;
149 /* The following is declarative, not executed,
150 * and so is dependent on where it is in the file,
151 * not in the order of execution of statements.
153 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
155 EXEC SQL SELECT modtime INTO :buf FROM users WHERE users_id = 0;
156 EXEC SQL SELECT modtime INTO :buf FROM list WHERE list_id = 0;
159 machines = create_hash(10);
161 EXEC SQL DECLARE m_cursor CURSOR FOR
165 EXEC SQL OPEN m_cursor;
167 EXEC SQL FETCH m_cursor INTO :id, :name;
168 if (sqlca.sqlcode != 0) break;
169 if (s = index(name, '.'))
174 strcat(name, ".LOCAL");
176 if (hash_store(machines, id, pstrsave(name)) < 0) {
177 fprintf(stderr, "Out of memory!\n");
182 EXEC SQL CLOSE m_cursor;
184 fprintf(stderr, "Loaded %d machines\n", cnt);
187 strings = create_hash(11001);
189 EXEC SQL DECLARE s_cursor CURSOR FOR
190 SELECT string_id, trim(string)
193 EXEC SQL OPEN s_cursor;
195 EXEC SQL FETCH s_cursor INTO :id, :name;
196 if (sqlca.sqlcode != 0) break;
197 if (hash_store(strings, id, pstrsave(name)) < 0) {
198 fprintf(stderr, "Out of memory!\n");
203 EXEC SQL CLOSE s_cursor;
205 fprintf(stderr, "Loaded %d strings\n", cnt);
208 users = create_hash(13001);
210 EXEC SQL DECLARE u_cursor CURSOR FOR
211 SELECT users_id, login, first, middle, last, potype, pop_id, box_id
215 EXEC SQL OPEN u_cursor;
217 EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
219 if (sqlca.sqlcode != 0) break;
220 u = (struct user *) perm_malloc(sizeof(struct user));
221 u->login = pstrsave(strtrim(name));
222 u->first = pstrsave(strtrim(fname));
223 u->last = pstrsave(strtrim(lname));
229 if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
230 sprintf(buf, "%s@%s", u->login, s);
231 u->pobox = pstrsave(buf);
232 } else if (type[0] == 'S') {
233 u->pobox = hash_lookup(strings, bid);
235 u->pobox = (char *) NULL;
236 if (hash_store(users, id, u) < 0) {
237 fprintf(stderr, "Out of memory!\n");
242 EXEC SQL CLOSE u_cursor;
244 fprintf(stderr, "Loaded %d users\n", cnt);
247 lists = create_hash(15000);
249 EXEC SQL DECLARE l_cursor CURSOR FOR
250 SELECT list_id, name, maillist, acl_type, acl_id
254 EXEC SQL OPEN l_cursor;
256 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :type, :acl;
257 if (sqlca.sqlcode != 0) break;
258 l = (struct list *) perm_malloc(sizeof(struct list));
259 l->name = pstrsave(strtrim(name));
260 l->maillist = maillistp;
263 l->m = (struct member *) NULL;
264 if (hash_store(lists, id, l) < 0) {
265 fprintf(stderr, "Out of memory!\n");
270 EXEC SQL CLOSE l_cursor;
272 fprintf(stderr, "Loaded %d lists\n", cnt);
276 EXEC SQL DECLARE m_cursor2 CURSOR FOR
277 SELECT list_id, member_type, member_id
281 EXEC SQL OPEN m_cursor2;
283 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
284 if (sqlca.sqlcode != 0) break;
286 if (l = (struct list *) hash_lookup(lists, id)) {
287 m = (struct member *) perm_malloc(sizeof(struct member));
288 if (type[0] == 'U' &&
289 (u = (struct user *) hash_lookup(users, mid))) {
294 } else if (type[0] == 'L' &&
295 (memberlist = (struct list *) hash_lookup(lists, mid))) {
297 m->name = memberlist->name;
300 } else if (type[0] == 'S' &&
301 (s = hash_lookup(strings, mid))) {
309 EXEC SQL CLOSE m_cursor2;
310 fprintf(stderr, "Loaded %d members\n", cnt);
313 com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
314 critical_alert("DCM", "Hesiod build encountered DATABASE ERROR %d",
320 save_mlist(id, l, force)
325 register struct member *m;
326 register struct list *l1;
328 if (l->maillist > 1 ||
329 (l->maillist == 0 && !force))
332 if (l->m && l->m->next == NULL &&
333 !strcasecmp(l->name, l->m->name)) {
338 insert_name(l->name, -1, TRUE, FALSE);
341 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
342 save_mlist(0, l1, TRUE);
344 for (m = l->m; m; m = m->next) {
345 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
346 save_mlist(0, l1, TRUE);
351 insert_login(id, u, dummy)
356 if (u->pobox && u->login[0] != '#')
357 insert_name(u->login, id, TRUE, FALSE);
360 void insert_names(id, u, dummy)
367 insert_name(u->last, id, FALSE, FALSE);
368 sprintf(buffer, "%s_%s", u->first, u->last);
369 insert_name(buffer, id, FALSE, TRUE);
370 /* sprintf(buffer, "%c_%s", u->first[0], u->last);
371 insert_name(buffer, id, FALSE, TRUE); */
373 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
374 insert_name(buffer, id, FALSE, TRUE);
380 insert_name(s, id, nodups, copy)
387 register struct names *ns;
391 ns = (struct names *) hash_lookup(names, code);
393 if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
394 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
398 ns->name = pstrsave(s);
404 if (hash_store(names, code, ns) < 0) {
405 fprintf(stderr, "Out of memory!\n");
410 if (strcasecmp(ns->name, s)) {
413 if (!strcasecmp(ns->name, s))
416 if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
418 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
423 ns->name = pstrsave(s);
432 if (nodups || ns->keep) {
433 if (nodups && ns->keep)
434 fprintf(stderr, "duplicated name: %s\n", s);
441 /* Illegal chars: ! " % ( ) , . / : ; < = > @ [ \ ] ^ { | } */
443 static int illegalchars[] = {
444 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
445 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
446 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, /* SPACE - / */
447 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
448 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
449 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
450 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
451 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
452 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
453 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
454 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
455 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
456 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
457 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
458 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
459 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
463 /* While hashing the string, punt any illegal characters */
471 for (result = 0; c = *s; s++) {
472 if (illegalchars[c]) {
480 /* result = result * 31 + *s; */
481 result = (result << 5) - result + c - '`';
483 return(result < 0 ? -result : result);
489 names = create_hash(20001);
490 hash_step(users, insert_login, NULL);
492 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
493 hash_step(lists, save_mlist, FALSE);
494 fprintf(stderr, "Output %d lists\n", incount);
495 hash_step(users, insert_names, NULL);
496 fprintf(stderr, "Inserted %d names\n", incount);
500 output_data(dummy, nms, out)
505 register struct names *ns;
506 register struct user *u;
509 for (ns = nms; ns; ns = ns->next) {
510 if (ns->name[0] == 0 || ns->name[1] == 0) {
511 fprintf(stderr, "punting %s due to short name\n", ns->name);
515 u = (struct user *) hash_lookup(users, ns->id);
517 fprintf(out, "%s: %s\n", ns->name, u->pobox);
519 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
521 } else if (ns->id == 0) {
522 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
532 register struct list *l;
535 register struct member *m;
536 register struct user *u;
538 if (l->acl_t == 'L' &&
539 (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
540 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
541 else if (l->acl_t == 'U' &&
542 (u = (struct user *) hash_lookup(users, l->acl_id)))
543 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
545 fprintf(out, "%s: ", l->name);
548 lwid = strlen(l->name) + 2;
550 for (m = l->m; m; m = m->next) {
551 do_member(out, m->name);
553 if (l->m == (struct member *)NULL)
554 fprintf(out, "/dev/null");
555 fprintf(out, "\n\n");
560 /* print out strings separated by commas, doing line breaks as appropriate */
571 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
572 fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
574 awid = lwid = 17 + wwid;
586 if (lwid + wwid + 2 > ML_WID) {
587 fprintf(out, ",\n\t%s", s);
588 awid += lwid + wwid + 2;
593 fprintf(out, ", %s", s);
600 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
601 hash_step(names, output_data, out);
602 fprintf(stderr, "Output %d entries\n", incount);
606 #define chunk_size 102400
608 char *perm_malloc(size)
611 static char *pool = NULL;
612 static unsigned pool_size = 0;
615 if (size > pool_size) {
616 pool = (char *) malloc(chunk_size);
617 pool_size = chunk_size;
621 pool = (char *)(((unsigned) (pool + 1)) & ~1);
622 pool_size -= (pool - ret);
628 * Make a (permenant) copy of a string.
636 /* Kludge for sloppy string semantics */
638 printf("NULL != \"\" !!!!\r\n");
644 p = perm_malloc((u_int)len);
645 if (p) bcopy(s, p, len);
649 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
651 /* Create a hash table. The size is just a hint, not a maximum. */
653 struct hash *create_hash(size)
658 h = (struct hash *) perm_malloc(sizeof(struct hash));
659 if (h == (struct hash *) NULL)
660 return((struct hash *) NULL);
662 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
663 if (h->data == (struct bucket **) NULL) {
665 return((struct hash *) NULL);
667 bzero(h->data, size * sizeof(char *));
671 /* Lookup an object in the hash table. Returns the value associated with
672 * the key, or NULL (thus NULL is not a very good value to store...)
675 char *hash_lookup(h, key)
679 register struct bucket *b;
681 b = h->data[hash_func(h, key)];
682 while (b && b->key != key)
684 if (b && b->key == key)
691 /* Update an existing object in the hash table. Returns 1 if the object
692 * existed, or 0 if not.
695 int hash_update(h, key, value)
700 register struct bucket *b;
702 b = h->data[hash_func(h, key)];
703 while (b && b->key != key)
705 if (b && b->key == key) {
713 /* Store an item in the hash table. Returns 0 if the key was not previously
714 * there, 1 if it was, or -1 if we ran out of memory.
717 int hash_store(h, key, value)
722 register struct bucket *b, **p;
724 p = &(h->data[hash_func(h, key)]);
726 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
727 if (b == (struct bucket *) NULL)
735 for (b = *p; b && b->key != key; b = *p)
736 p = (struct bucket **) *p;
737 if (b && b->key == key) {
741 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
742 if (b == (struct bucket *) NULL)
751 /* Search through the hash table for a given value. For each piece of
752 * data with that value, call the callback proc with the corresponding key.
755 hash_search(h, value, callback)
757 register char *value;
760 register struct bucket *b, **p;
762 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
763 for (b = *p; b; b = b->next) {
764 if (b->data == value)
771 /* Step through the hash table, calling the callback proc with each key.
774 hash_step(h, callback, hint)
779 register struct bucket *b, **p;
781 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
782 for (b = *p; b; b = b->next) {
783 (*callback)(b->key, b->data, hint);
789 /* Deallocate all of the memory associated with a table */
794 register struct bucket *b, **p, *b1;
796 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
797 for (b = *p; b; b = b1) {