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;
156 EXEC SQL SELECT modtime INTO :buf FROM users WHERE users_id = 0;
157 EXEC SQL SELECT modtime INTO :buf FROM list WHERE list_id = 0;
160 machines = create_hash(10);
162 EXEC SQL DECLARE m_cursor CURSOR FOR
166 EXEC SQL OPEN m_cursor;
168 EXEC SQL FETCH m_cursor INTO :id, :name;
169 if (sqlca.sqlcode != 0) break;
170 if (s = index(name, '.'))
175 strcat(name, ".LOCAL");
177 if (hash_store(machines, id, pstrsave(name)) < 0) {
178 fprintf(stderr, "Out of memory!\n");
183 EXEC SQL CLOSE m_cursor;
185 fprintf(stderr, "Loaded %d machines\n", cnt);
188 strings = create_hash(11001);
190 EXEC SQL DECLARE s_cursor CURSOR FOR
191 SELECT string_id, trim(string)
194 EXEC SQL OPEN s_cursor;
196 EXEC SQL FETCH s_cursor INTO :id, :name;
197 if (sqlca.sqlcode != 0) break;
198 if (hash_store(strings, id, pstrsave(name)) < 0) {
199 fprintf(stderr, "Out of memory!\n");
204 EXEC SQL CLOSE s_cursor;
206 fprintf(stderr, "Loaded %d strings\n", cnt);
209 users = create_hash(13001);
211 EXEC SQL DECLARE u_cursor CURSOR FOR
212 SELECT users_id, login, first, middle, last, potype, pop_id, box_id
216 EXEC SQL OPEN u_cursor;
218 EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
220 if (sqlca.sqlcode != 0) break;
221 u = (struct user *) perm_malloc(sizeof(struct user));
222 u->login = pstrsave(strtrim(name));
223 u->first = pstrsave(strtrim(fname));
224 u->last = pstrsave(strtrim(lname));
230 if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
231 sprintf(buf, "%s@%s", u->login, s);
232 u->pobox = pstrsave(buf);
233 } else if (type[0] == 'S') {
234 u->pobox = hash_lookup(strings, bid);
236 u->pobox = (char *) NULL;
237 if (hash_store(users, id, u) < 0) {
238 fprintf(stderr, "Out of memory!\n");
243 EXEC SQL CLOSE u_cursor;
245 fprintf(stderr, "Loaded %d users\n", cnt);
248 lists = create_hash(15000);
250 EXEC SQL DECLARE l_cursor CURSOR FOR
251 SELECT list_id, name, maillist, description, acl_type, acl_id
255 EXEC SQL OPEN l_cursor;
257 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :buf, :type, :acl;
258 if (sqlca.sqlcode != 0) break;
259 l = (struct list *) perm_malloc(sizeof(struct list));
260 l->name = pstrsave(strtrim(name));
261 l->maillist = maillistp;
262 l->description = pstrsave(strtrim(buf));
265 l->m = (struct member *) NULL;
266 if (hash_store(lists, id, l) < 0) {
267 fprintf(stderr, "Out of memory!\n");
272 EXEC SQL CLOSE l_cursor;
274 fprintf(stderr, "Loaded %d lists\n", cnt);
278 EXEC SQL DECLARE m_cursor2 CURSOR FOR
279 SELECT list_id, member_type, member_id
283 EXEC SQL OPEN m_cursor2;
285 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
286 if (sqlca.sqlcode != 0) break;
288 if (l = (struct list *) hash_lookup(lists, id)) {
289 m = (struct member *) perm_malloc(sizeof(struct member));
290 if (type[0] == 'U' &&
291 (u = (struct user *) hash_lookup(users, mid))) {
296 } else if (type[0] == 'L' &&
297 (memberlist = (struct list *) hash_lookup(lists, mid))) {
299 m->name = memberlist->name;
302 } else if (type[0] == 'S' &&
303 (s = hash_lookup(strings, mid))) {
311 EXEC SQL CLOSE m_cursor2;
312 fprintf(stderr, "Loaded %d members\n", cnt);
315 com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
316 critical_alert("DCM", "Hesiod build encountered DATABASE ERROR %d",
322 save_mlist(id, l, force)
327 register struct member *m;
328 register struct list *l1;
330 if (l->maillist > 1 ||
331 (l->maillist == 0 && !force))
334 if (l->m && l->m->next == NULL &&
335 !strcasecmp(l->name, l->m->name)) {
340 insert_name(l->name, -1, TRUE, FALSE);
343 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
344 save_mlist(0, l1, TRUE);
346 for (m = l->m; m; m = m->next) {
347 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
348 save_mlist(0, l1, TRUE);
353 insert_login(id, u, dummy)
358 if (u->pobox && u->login[0] != '#')
359 insert_name(u->login, id, TRUE, FALSE);
362 void insert_names(id, u, dummy)
369 insert_name(u->last, id, FALSE, FALSE);
370 sprintf(buffer, "%s_%s", u->first, u->last);
371 insert_name(buffer, id, FALSE, TRUE);
372 /* sprintf(buffer, "%c_%s", u->first[0], u->last);
373 insert_name(buffer, id, FALSE, TRUE); */
375 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
376 insert_name(buffer, id, FALSE, TRUE);
382 insert_name(s, id, nodups, copy)
389 register struct names *ns;
393 ns = (struct names *) hash_lookup(names, code);
395 if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
396 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
400 ns->name = pstrsave(s);
406 if (hash_store(names, code, ns) < 0) {
407 fprintf(stderr, "Out of memory!\n");
412 if (strcasecmp(ns->name, s)) {
415 if (!strcasecmp(ns->name, s))
418 if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
420 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
425 ns->name = pstrsave(s);
434 if (nodups || ns->keep) {
435 if (nodups && ns->keep)
436 fprintf(stderr, "duplicated name: %s\n", s);
443 /* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
445 static int illegalchars[] = {
446 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
447 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
448 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
449 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
450 1, 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, 1, 0, /* P - _ */
452 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
453 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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,
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,
465 /* While hashing the string, punt any illegal characters */
473 for (result = 0; c = *s; s++) {
474 if (illegalchars[c]) {
482 /* result = result * 31 + *s; */
483 result = (result << 5) - result + c - '`';
485 return(result < 0 ? -result : result);
491 names = create_hash(20001);
492 hash_step(users, insert_login, NULL);
494 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
495 hash_step(lists, save_mlist, FALSE);
496 fprintf(stderr, "Output %d lists\n", incount);
497 hash_step(users, insert_names, NULL);
498 fprintf(stderr, "Inserted %d names\n", incount);
502 output_data(dummy, nms, out)
507 register struct names *ns;
508 register struct user *u;
511 for (ns = nms; ns; ns = ns->next) {
512 if (ns->name[0] == 0 || ns->name[1] == 0) {
513 fprintf(stderr, "punting %s due to short name\n", ns->name);
517 u = (struct user *) hash_lookup(users, ns->id);
519 fprintf(out, "%s: %s\n", ns->name, u->pobox);
521 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
523 } else if (ns->id == 0) {
524 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
534 register struct list *l;
537 register struct member *m;
538 register struct user *u;
540 put_fill(out, l->description);
541 if (l->acl_t == 'L' &&
542 (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
543 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
544 else if (l->acl_t == 'U' &&
545 (u = (struct user *) hash_lookup(users, l->acl_id)))
546 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
548 fprintf(out, "%s: ", l->name);
551 lwid = strlen(l->name) + 2;
553 for (m = l->m; m; m = m->next) {
554 do_member(out, m->name);
556 if (l->m == (struct member *)NULL)
557 fprintf(out, "/dev/null");
558 fprintf(out, "\n\n");
563 /* print out strings separated by commas, doing line breaks as appropriate */
574 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
575 fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
577 awid = lwid = 17 + wwid;
589 if (lwid + wwid + 2 > ML_WID) {
590 fprintf(out, ",\n\t%s", s);
591 awid += lwid + wwid + 2;
596 fprintf(out, ", %s", s);
600 put_fill(aliases, string)
602 register char *string;
608 if (string == 0 || *string == 0) return;
609 fputs("# ", aliases);
613 while (*string && *string == ' ') string++;
614 c = (char *)index(string, ' ');
616 wwid = strlen(string);
622 if ((lwid + wwid) > ML_WID) {
623 fputs("\n# ", aliases);
625 fputs(string, aliases);
627 fputs(string, aliases);
630 if (c == (char *)0) break;
631 /* add a space after the word */
632 (void) fputc(' ', aliases);
636 /* add another if after a period */
638 (void) fputc(' ', aliases);
643 (void) fputc('\n', aliases);
650 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
651 hash_step(names, output_data, out);
652 fprintf(stderr, "Output %d entries\n", incount);
656 #define chunk_size 102400
658 char *perm_malloc(size)
661 static char *pool = NULL;
662 static unsigned pool_size = 0;
665 if (size > pool_size) {
666 pool = (char *) malloc(chunk_size);
667 pool_size = chunk_size;
671 pool = (char *)(((unsigned) (pool + 3)) & ~3);
672 pool_size -= (pool - ret);
678 * Make a (permenant) copy of a string.
686 /* Kludge for sloppy string semantics */
688 printf("NULL != \"\" !!!!\r\n");
694 p = perm_malloc((u_int)len);
695 if (p) bcopy(s, p, len);
699 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
701 /* Create a hash table. The size is just a hint, not a maximum. */
703 struct hash *create_hash(size)
708 h = (struct hash *) perm_malloc(sizeof(struct hash));
709 if (h == (struct hash *) NULL)
710 return((struct hash *) NULL);
712 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
713 if (h->data == (struct bucket **) NULL) {
715 return((struct hash *) NULL);
717 bzero(h->data, size * sizeof(char *));
721 /* Lookup an object in the hash table. Returns the value associated with
722 * the key, or NULL (thus NULL is not a very good value to store...)
725 char *hash_lookup(h, key)
729 register struct bucket *b;
731 b = h->data[hash_func(h, key)];
732 while (b && b->key != key)
734 if (b && b->key == key)
741 /* Update an existing object in the hash table. Returns 1 if the object
742 * existed, or 0 if not.
745 int hash_update(h, key, value)
750 register struct bucket *b;
752 b = h->data[hash_func(h, key)];
753 while (b && b->key != key)
755 if (b && b->key == key) {
763 /* Store an item in the hash table. Returns 0 if the key was not previously
764 * there, 1 if it was, or -1 if we ran out of memory.
767 int hash_store(h, key, value)
772 register struct bucket *b, **p;
774 p = &(h->data[hash_func(h, key)]);
776 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
777 if (b == (struct bucket *) NULL)
785 for (b = *p; b && b->key != key; b = *p)
786 p = (struct bucket **) *p;
787 if (b && b->key == key) {
791 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
792 if (b == (struct bucket *) NULL)
801 /* Search through the hash table for a given value. For each piece of
802 * data with that value, call the callback proc with the corresponding key.
805 hash_search(h, value, callback)
807 register char *value;
810 register struct bucket *b, **p;
812 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
813 for (b = *p; b; b = b->next) {
814 if (b->data == value)
821 /* Step through the hash table, calling the callback proc with each key.
824 hash_step(h, callback, hint)
829 register struct bucket *b, **p;
831 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
832 for (b = *p; b; b = b->next) {
833 (*callback)(b->key, b->data, hint);
839 /* Deallocate all of the memory associated with a table */
844 register struct bucket *b, **p, *b1;
846 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
847 for (b = *p; b; b = b1) {