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 896
43 char filename[64], *targetfile;
45 EXEC SQL BEGIN DECLARE SECTION;
47 EXEC SQL END DECLARE SECTION;
53 EXEC SQL DATABASE sms;
57 if (stat(argv[1], &sb) == 0) {
58 if (ModDiff (&flag, "users", sb.st_mtime))
61 fprintf(stderr, "File %s does not need to be rebuilt.\n",
67 sprintf(filename, "%s~", targetfile);
68 if ((out = fopen(filename, "w")) == NULL) {
69 fprintf(stderr, "unable to open %s for output\n", filename);
72 } else if (argc != 1) {
73 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
77 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
78 fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide);
86 EXEC SQL CLOSE DATABASE;
89 fprintf(stderr, "Sorting Info\n");
92 fprintf(stderr, "Dumping information\n");
95 fprintf(out, "\n%s\n# End of aliases file\n", divide);
98 perror("close failed");
103 fix_file(targetfile);
109 struct hash *users, *machines, *strings, *lists, *names;
139 EXEC SQL BEGIN DECLARE SECTION;
140 int id, pid, bid, cnt, maillistp, acl, mid;
141 char name[129], type[9], fname[17], mname[17], lname[17], buf[257];
142 EXEC SQL END DECLARE SECTION;
144 register struct user *u;
145 struct list *l, *memberlist;
146 register struct member *m;
148 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
150 EXEC SQL SELECT modtime INTO :buf FROM users WHERE users_id = 0;
151 EXEC SQL SELECT modtime INTO :buf FROM list WHERE list_id = 0;
154 machines = create_hash(10);
156 EXEC SQL DECLARE m_cursor CURSOR FOR
157 SELECT m.mach_id, m.name
158 FROM machine m, users u
159 WHERE m.mach_id = u.pop_id;
160 EXEC SQL OPEN m_cursor;
162 EXEC SQL FETCH m_cursor INTO :id, :name;
163 if (sqlca.sqlcode != 0) break;
164 if (s = index(name, '.'))
169 strcat(name, ".LOCAL");
171 if (hash_store(machines, id, pstrsave(name)) < 0) {
172 fprintf(stderr, "Out of memory!\n");
177 EXEC SQL CLOSE m_cursor;
179 fprintf(stderr, "Loaded %d machines\n", cnt);
182 strings = create_hash(4000);
184 EXEC SQL DECLARE s_cursor CURSOR FOR
185 SELECT string_id, string
187 EXEC SQL OPEN s_cursor;
189 EXEC SQL FETCH s_cursor INTO :id, :name;
190 if (sqlca.sqlcode != 0) break;
191 if (hash_store(strings, id, pstrsave(strtrim(name))) < 0) {
192 fprintf(stderr, "Out of memory!\n");
197 EXEC SQL CLOSE s_cursor;
199 fprintf(stderr, "Loaded %d strings\n", cnt);
202 users = create_hash(12001);
204 EXEC SQL DECLARE u_cursor CURSOR FOR
205 SELECT users_id, login, first, middle, last, potype, pop_id, box_id
208 EXEC SQL OPEN u_cursor;
210 EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
212 if (sqlca.sqlcode != 0) break;
213 u = (struct user *) perm_malloc(sizeof(struct user));
214 u->login = pstrsave(strtrim(name));
215 u->first = pstrsave(strtrim(fname));
216 u->last = pstrsave(strtrim(lname));
222 if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
223 sprintf(buf, "%s@%s", u->login, s);
224 u->pobox = pstrsave(buf);
225 } else if (type[0] == 'S') {
226 u->pobox = hash_lookup(strings, bid);
228 u->pobox = (char *) NULL;
229 if (hash_store(users, id, u) < 0) {
230 fprintf(stderr, "Out of memory!\n");
235 EXEC SQL CLOSE u_cursor;
236 fprintf(stderr, "Loaded %d users\n", cnt);
239 lists = create_hash(15000);
241 EXEC SQL DECLARE l_cursor CURSOR FOR
242 SELECT list_id, name, maillist, acl_type, acl_id
245 EXEC SQL OPEN l_cursor;
247 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :type, :acl;
248 if (sqlca.sqlcode != 0) break;
249 l = (struct list *) perm_malloc(sizeof(struct list));
250 l->name = pstrsave(strtrim(name));
251 l->maillist = maillistp;
254 l->m = (struct member *) NULL;
255 if (hash_store(lists, id, l) < 0) {
256 fprintf(stderr, "Out of memory!\n");
261 EXEC SQL CLOSE l_cursor;
262 fprintf(stderr, "Loaded %d lists\n", cnt);
266 EXEC SQL DECLARE m_cursor2 CURSOR FOR
267 SELECT list_id, member_type, member_id
270 EXEC SQL OPEN m_cursor2;
272 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
273 if (sqlca.sqlcode != 0) break;
275 if (l = (struct list *) hash_lookup(lists, id)) {
276 m = (struct member *) perm_malloc(sizeof(struct member));
277 if (type[0] == 'U' &&
278 (u = (struct user *) hash_lookup(users, mid))) {
283 } else if (type[0] == 'L' &&
284 (memberlist = (struct list *) hash_lookup(lists, mid))) {
286 m->name = memberlist->name;
289 } else if (type[0] == 'S' &&
290 (s = hash_lookup(strings, mid))) {
298 EXEC SQL CLOSE m_cursor2;
299 fprintf(stderr, "Loaded %d members\n", cnt);
302 com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
303 critical_alert("DCM", "Hesiod build encountered DATABASE ERROR %d",
309 save_mlist(id, l, force)
314 register struct member *m;
315 register struct list *l1;
317 if (l->maillist > 1 ||
318 (l->maillist == 0 && !force))
321 if (l->m && l->m->next == NULL &&
322 !strcasecmp(l->name, l->m->name)) {
327 insert_name(l->name, -1, TRUE, FALSE);
330 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
331 save_mlist(0, l1, TRUE);
333 for (m = l->m; m; m = m->next) {
334 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
335 save_mlist(0, l1, TRUE);
340 insert_login(id, u, dummy)
345 if (u->pobox && u->login[0] != '#')
346 insert_name(u->login, id, TRUE, FALSE);
349 void insert_names(id, u, dummy)
356 insert_name(u->last, id, FALSE, FALSE);
357 sprintf(buffer, "%s_%s", u->first, u->last);
358 insert_name(buffer, id, FALSE, TRUE);
359 /* sprintf(buffer, "%c_%s", u->first[0], u->last);
360 insert_name(buffer, id, FALSE, TRUE); */
362 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
363 insert_name(buffer, id, FALSE, TRUE);
369 insert_name(s, id, nodups, copy)
376 register struct names *ns;
380 ns = (struct names *) hash_lookup(names, code);
382 if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
383 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
387 ns->name = pstrsave(s);
393 if (hash_store(names, code, ns) < 0) {
394 fprintf(stderr, "Out of memory!\n");
399 if (strcasecmp(ns->name, s)) {
402 if (!strcasecmp(ns->name, s))
405 if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
407 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
412 ns->name = pstrsave(s);
421 if (nodups || ns->keep) {
422 if (nodups && ns->keep)
423 fprintf(stderr, "duplicated name: %s\n", s);
430 /* Illegal chars: ! " % ( ) , . / : ; < = > @ [ \ ] ^ { | } */
432 static int illegalchars[] = {
433 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
434 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
435 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, /* SPACE - / */
436 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
437 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
438 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
441 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
442 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
443 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
452 /* While hashing the string, punt any illegal characters */
460 for (result = 0; c = *s; s++) {
461 if (illegalchars[c]) {
469 /* result = result * 31 + *s; */
470 result = (result << 5) - result + c - '`';
472 return(result < 0 ? -result : result);
478 names = create_hash(20001);
479 hash_step(users, insert_login, NULL);
481 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
482 hash_step(lists, save_mlist, FALSE);
483 fprintf(stderr, "Output %d lists\n", incount);
484 hash_step(users, insert_names, NULL);
485 fprintf(stderr, "Inserted %d names\n", incount);
489 output_data(dummy, nms, out)
494 register struct names *ns;
495 register struct user *u;
498 for (ns = nms; ns; ns = ns->next) {
499 if (ns->name[0] == 0 || ns->name[1] == 0) {
500 fprintf(stderr, "punting %s due to short name\n", ns->name);
504 u = (struct user *) hash_lookup(users, ns->id);
506 fprintf(out, "%s: %s\n", ns->name, u->pobox);
508 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
510 } else if (ns->id == 0) {
511 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
521 register struct list *l;
524 register struct member *m;
525 register struct user *u;
527 if (l->acl_t == 'L' &&
528 (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
529 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
530 else if (l->acl_t == 'U' &&
531 (u = (struct user *) hash_lookup(users, l->acl_id)))
532 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
534 fprintf(out, "%s: ", l->name);
537 lwid = strlen(l->name) + 2;
539 for (m = l->m; m; m = m->next) {
540 do_member(out, m->name);
542 if (l->m == (struct member *)NULL)
543 fprintf(out, "/dev/null");
544 fprintf(out, "\n\n");
549 /* print out strings separated by commas, doing line breaks as appropriate */
560 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
561 fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
563 awid = lwid = 17 + wwid;
575 if (lwid + wwid + 2 > ML_WID) {
576 fprintf(out, ",\n\t%s", s);
577 awid += lwid + wwid + 2;
582 fprintf(out, ", %s", s);
589 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
590 hash_step(names, output_data, out);
591 fprintf(stderr, "Output %d entries\n", incount);
595 #define chunk_size 102400
597 char *perm_malloc(size)
600 static char *pool = NULL;
601 static unsigned pool_size = 0;
604 if (size > pool_size) {
605 pool = (char *) malloc(chunk_size);
606 pool_size = chunk_size;
610 pool = (char *)(((unsigned) (pool + 1)) & ~1);
611 pool_size -= (pool - ret);
617 * Make a (permenant) copy of a string.
625 /* Kludge for sloppy string semantics */
627 printf("NULL != \"\" !!!!\r\n");
633 p = perm_malloc((u_int)len);
634 if (p) bcopy(s, p, len);
638 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
640 /* Create a hash table. The size is just a hint, not a maximum. */
642 struct hash *create_hash(size)
647 h = (struct hash *) perm_malloc(sizeof(struct hash));
648 if (h == (struct hash *) NULL)
649 return((struct hash *) NULL);
651 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
652 if (h->data == (struct bucket **) NULL) {
654 return((struct hash *) NULL);
656 bzero(h->data, size * sizeof(char *));
660 /* Lookup an object in the hash table. Returns the value associated with
661 * the key, or NULL (thus NULL is not a very good value to store...)
664 char *hash_lookup(h, key)
668 register struct bucket *b;
670 b = h->data[hash_func(h, key)];
671 while (b && b->key != key)
673 if (b && b->key == key)
680 /* Update an existing object in the hash table. Returns 1 if the object
681 * existed, or 0 if not.
684 int hash_update(h, key, value)
689 register struct bucket *b;
691 b = h->data[hash_func(h, key)];
692 while (b && b->key != key)
694 if (b && b->key == key) {
702 /* Store an item in the hash table. Returns 0 if the key was not previously
703 * there, 1 if it was, or -1 if we ran out of memory.
706 int hash_store(h, key, value)
711 register struct bucket *b, **p;
713 p = &(h->data[hash_func(h, key)]);
715 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
716 if (b == (struct bucket *) NULL)
724 for (b = *p; b && b->key != key; b = *p)
725 p = (struct bucket **) *p;
726 if (b && b->key == key) {
730 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
731 if (b == (struct bucket *) NULL)
740 /* Search through the hash table for a given value. For each piece of
741 * data with that value, call the callback proc with the corresponding key.
744 hash_search(h, value, callback)
746 register char *value;
749 register struct bucket *b, **p;
751 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
752 for (b = *p; b; b = b->next) {
753 if (b->data == value)
760 /* Step through the hash table, calling the callback proc with each key.
763 hash_step(h, callback, hint)
768 register struct bucket *b, **p;
770 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
771 for (b = *p; b; b = b->next) {
772 (*callback)(b->key, b->data, hint);
778 /* Deallocate all of the memory associated with a table */
783 register struct bucket *b, **p, *b1;
785 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
786 for (b = *p; b; b = b1) {