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;
141 EXEC SQL BEGIN DECLARE SECTION;
142 int id, pid, bid, cnt, maillistp, acl, mid;
143 char name[129], type[9], fname[17], mname[17], lname[17], buf[257];
144 EXEC SQL END DECLARE SECTION;
146 register struct user *u;
147 struct list *l, *memberlist;
148 register struct member *m;
150 /* The following is declarative, not executed,
151 * and so is dependent on where it is in the file,
152 * not in the order of execution of statements.
154 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
158 EXEC SQL SELECT modtime INTO :buf FROM imembers WHERE list_id = 0;
159 EXEC SQL SELECT modtime INTO :buf FROM users WHERE users_id = 0;
160 EXEC SQL SELECT modtime INTO :buf FROM list WHERE list_id = 0;
163 machines = create_hash(1000);
165 EXEC SQL DECLARE m_cursor CURSOR FOR
170 EXEC SQL OPEN m_cursor;
172 EXEC SQL FETCH m_cursor INTO :id, :name;
173 if (sqlca.sqlcode != 0) break;
174 if (s = index(name, '.'))
179 strcat(name, ".LOCAL");
181 if (hash_store(machines, id, pstrsave(name)) < 0) {
182 fprintf(stderr, "Out of memory!\n");
187 EXEC SQL CLOSE m_cursor;
189 fprintf(stderr, "Loaded %d machines\n", cnt);
192 strings = create_hash(11001);
194 EXEC SQL DECLARE s_cursor CURSOR FOR
195 SELECT string_id, trim(string)
198 EXEC SQL OPEN s_cursor;
200 EXEC SQL FETCH s_cursor INTO :id, :name;
201 if (sqlca.sqlcode != 0) break;
202 if (hash_store(strings, id, pstrsave(name)) < 0) {
203 fprintf(stderr, "Out of memory!\n");
208 EXEC SQL CLOSE s_cursor;
210 fprintf(stderr, "Loaded %d strings\n", cnt);
213 users = create_hash(13001);
215 EXEC SQL DECLARE u_cursor CURSOR FOR
216 SELECT users_id, login, first, middle, last, potype, pop_id, box_id
220 EXEC SQL OPEN u_cursor;
222 EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
224 if (sqlca.sqlcode != 0) break;
225 u = (struct user *) perm_malloc(sizeof(struct user));
226 u->login = pstrsave(strtrim(name));
227 u->first = pstrsave(strtrim(fname));
228 u->last = pstrsave(strtrim(lname));
234 if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
235 sprintf(buf, "%s@%s", u->login, s);
236 u->pobox = pstrsave(buf);
237 } else if (type[0] == 'S') {
238 u->pobox = hash_lookup(strings, bid);
240 u->pobox = (char *) NULL;
241 if (hash_store(users, id, u) < 0) {
242 fprintf(stderr, "Out of memory!\n");
247 EXEC SQL CLOSE u_cursor;
249 fprintf(stderr, "Loaded %d users\n", cnt);
252 lists = create_hash(15000);
254 EXEC SQL DECLARE l_cursor CURSOR FOR
255 SELECT list_id, name, maillist, description, acl_type, acl_id
259 EXEC SQL OPEN l_cursor;
261 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :buf, :type, :acl;
262 if (sqlca.sqlcode != 0) break;
263 l = (struct list *) perm_malloc(sizeof(struct list));
264 l->name = pstrsave(strtrim(name));
265 l->maillist = maillistp;
266 l->description = pstrsave(strtrim(buf));
269 l->m = (struct member *) NULL;
270 if (hash_store(lists, id, l) < 0) {
271 fprintf(stderr, "Out of memory!\n");
276 EXEC SQL CLOSE l_cursor;
278 fprintf(stderr, "Loaded %d lists\n", cnt);
282 EXEC SQL DECLARE m_cursor2 CURSOR FOR
283 SELECT list_id, member_type, member_id
287 EXEC SQL OPEN m_cursor2;
289 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
290 if (sqlca.sqlcode != 0) break;
292 if (l = (struct list *) hash_lookup(lists, id)) {
293 m = (struct member *) perm_malloc(sizeof(struct member));
294 if (type[0] == 'U' &&
295 (u = (struct user *) hash_lookup(users, mid))) {
300 } else if (type[0] == 'L' &&
301 (memberlist = (struct list *) hash_lookup(lists, mid))) {
303 m->name = memberlist->name;
306 } else if (type[0] == 'S' &&
307 (s = hash_lookup(strings, mid))) {
315 EXEC SQL CLOSE m_cursor2;
316 fprintf(stderr, "Loaded %d members\n", cnt);
319 com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
320 critical_alert("DCM", "Hesiod build encountered DATABASE ERROR %d",
326 save_mlist(id, l, force)
331 register struct member *m;
332 register struct list *l1;
334 if (l->maillist > 1 ||
335 (l->maillist == 0 && !force))
338 if (l->m && l->m->next == NULL &&
339 !strcasecmp(l->name, l->m->name)) {
344 insert_name(l->name, -1, TRUE, FALSE);
347 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
348 save_mlist(0, l1, TRUE);
350 for (m = l->m; m; m = m->next) {
351 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
352 save_mlist(0, l1, TRUE);
357 insert_login(id, u, dummy)
362 if (u->pobox && u->login[0] != '#')
363 insert_name(u->login, id, TRUE, FALSE);
366 void insert_names(id, u, dummy)
373 insert_name(u->last, id, FALSE, FALSE);
374 sprintf(buffer, "%s_%s", u->first, u->last);
375 insert_name(buffer, id, FALSE, TRUE);
376 /* sprintf(buffer, "%c_%s", u->first[0], u->last);
377 insert_name(buffer, id, FALSE, TRUE); */
379 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
380 insert_name(buffer, id, FALSE, TRUE);
386 insert_name(s, id, nodups, copy)
393 register struct names *ns;
397 ns = (struct names *) hash_lookup(names, code);
399 if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
400 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
404 ns->name = pstrsave(s);
410 if (hash_store(names, code, ns) < 0) {
411 fprintf(stderr, "Out of memory!\n");
416 if (strcasecmp(ns->name, s)) {
419 if (!strcasecmp(ns->name, s))
422 if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
424 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
429 ns->name = pstrsave(s);
438 if (nodups || ns->keep) {
439 if (nodups && ns->keep)
440 fprintf(stderr, "duplicated name: %s\n", s);
447 /* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
449 static int illegalchars[] = {
450 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
451 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
452 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
453 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
454 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
455 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
456 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
457 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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,
460 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
461 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
462 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
463 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
464 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
465 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
469 /* While hashing the string, punt any illegal characters */
477 for (result = 0; c = *s; s++) {
478 if (illegalchars[c]) {
486 /* result = result * 31 + *s; */
487 result = (result << 5) - result + c - '`';
489 return(result < 0 ? -result : result);
495 names = create_hash(20001);
496 hash_step(users, insert_login, NULL);
498 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
499 hash_step(lists, save_mlist, FALSE);
500 fprintf(stderr, "Output %d lists\n", incount);
501 hash_step(users, insert_names, NULL);
502 fprintf(stderr, "Inserted %d names\n", incount);
506 output_data(dummy, nms, out)
511 register struct names *ns;
512 register struct user *u;
515 for (ns = nms; ns; ns = ns->next) {
516 if (ns->name[0] == 0 || ns->name[1] == 0) {
517 fprintf(stderr, "punting %s due to short name\n", ns->name);
521 u = (struct user *) hash_lookup(users, ns->id);
523 fprintf(out, "%s: %s\n", ns->name, u->pobox);
525 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
527 } else if (ns->id == 0) {
528 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
538 register struct list *l;
541 register struct member *m;
542 register struct user *u;
544 put_fill(out, l->description);
545 if (l->acl_t == 'L' &&
546 (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
547 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
548 else if (l->acl_t == 'U' &&
549 (u = (struct user *) hash_lookup(users, l->acl_id)))
550 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
552 fprintf(out, "%s: ", l->name);
555 lwid = strlen(l->name) + 2;
557 for (m = l->m; m; m = m->next) {
558 do_member(out, m->name);
560 if (l->m == (struct member *)NULL)
561 fprintf(out, "/dev/null");
562 fprintf(out, "\n\n");
567 /* print out strings separated by commas, doing line breaks as appropriate */
578 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
579 fprintf(out, ",\n\tcontinuation%d\ncontinuation%d: ", cont, cont);
581 awid = lwid = 17 + wwid;
593 if (lwid + wwid + 2 > ML_WID) {
594 fprintf(out, ",\n\t%s", s);
595 awid += lwid + wwid + 2;
600 fprintf(out, ", %s", s);
604 put_fill(aliases, string)
606 register char *string;
612 if (string == 0 || *string == 0) return;
613 fputs("# ", aliases);
617 while (*string && *string == ' ') string++;
618 c = (char *)index(string, ' ');
620 wwid = strlen(string);
626 if ((lwid + wwid) > ML_WID) {
627 fputs("\n# ", aliases);
629 fputs(string, aliases);
631 fputs(string, aliases);
634 if (c == (char *)0) break;
635 /* add a space after the word */
636 (void) fputc(' ', aliases);
640 /* add another if after a period */
642 (void) fputc(' ', aliases);
647 (void) fputc('\n', aliases);
654 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
655 hash_step(names, output_data, out);
656 fprintf(stderr, "Output %d entries\n", incount);
660 #define chunk_size 102400
662 char *perm_malloc(size)
665 static char *pool = NULL;
666 static unsigned pool_size = 0;
669 if (size > pool_size) {
670 pool = (char *) malloc(chunk_size);
671 pool_size = chunk_size;
675 pool = (char *)(((unsigned) (pool + 3)) & ~3);
676 pool_size -= (pool - ret);
682 * Make a (permenant) copy of a string.
690 /* Kludge for sloppy string semantics */
692 printf("NULL != \"\" !!!!\r\n");
698 p = perm_malloc((u_int)len);
699 if (p) bcopy(s, p, len);
703 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
705 /* Create a hash table. The size is just a hint, not a maximum. */
707 struct hash *create_hash(size)
712 h = (struct hash *) perm_malloc(sizeof(struct hash));
713 if (h == (struct hash *) NULL)
714 return((struct hash *) NULL);
716 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
717 if (h->data == (struct bucket **) NULL) {
719 return((struct hash *) NULL);
721 bzero(h->data, size * sizeof(char *));
725 /* Lookup an object in the hash table. Returns the value associated with
726 * the key, or NULL (thus NULL is not a very good value to store...)
729 char *hash_lookup(h, key)
733 register struct bucket *b;
735 b = h->data[hash_func(h, key)];
736 while (b && b->key != key)
738 if (b && b->key == key)
745 /* Update an existing object in the hash table. Returns 1 if the object
746 * existed, or 0 if not.
749 int hash_update(h, key, value)
754 register struct bucket *b;
756 b = h->data[hash_func(h, key)];
757 while (b && b->key != key)
759 if (b && b->key == key) {
767 /* Store an item in the hash table. Returns 0 if the key was not previously
768 * there, 1 if it was, or -1 if we ran out of memory.
771 int hash_store(h, key, value)
776 register struct bucket *b, **p;
778 p = &(h->data[hash_func(h, key)]);
780 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
781 if (b == (struct bucket *) NULL)
789 for (b = *p; b && b->key != key; b = *p)
790 p = (struct bucket **) *p;
791 if (b && b->key == key) {
795 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
796 if (b == (struct bucket *) NULL)
805 /* Search through the hash table for a given value. For each piece of
806 * data with that value, call the callback proc with the corresponding key.
809 hash_search(h, value, callback)
811 register char *value;
814 register struct bucket *b, **p;
816 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
817 for (b = *p; b; b = b->next) {
818 if (b->data == value)
825 /* Step through the hash table, calling the callback proc with each key.
828 hash_step(h, callback, hint)
833 register struct bucket *b, **p;
835 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
836 for (b = *p; b; b = b->next) {
837 (*callback)(b->key, b->data, hint);
843 /* Deallocate all of the memory associated with a table */
848 register struct bucket *b, **p, *b1;
850 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
851 for (b = *p; b; b = b1) {