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(1000);
162 EXEC SQL DECLARE m_cursor CURSOR FOR
167 EXEC SQL OPEN m_cursor;
169 EXEC SQL FETCH m_cursor INTO :id, :name;
170 if (sqlca.sqlcode != 0) break;
171 if (s = index(name, '.'))
176 strcat(name, ".LOCAL");
178 if (hash_store(machines, id, pstrsave(name)) < 0) {
179 fprintf(stderr, "Out of memory!\n");
184 EXEC SQL CLOSE m_cursor;
186 fprintf(stderr, "Loaded %d machines\n", cnt);
189 strings = create_hash(11001);
191 EXEC SQL DECLARE s_cursor CURSOR FOR
192 SELECT string_id, trim(string)
195 EXEC SQL OPEN s_cursor;
197 EXEC SQL FETCH s_cursor INTO :id, :name;
198 if (sqlca.sqlcode != 0) break;
199 if (hash_store(strings, id, pstrsave(name)) < 0) {
200 fprintf(stderr, "Out of memory!\n");
205 EXEC SQL CLOSE s_cursor;
207 fprintf(stderr, "Loaded %d strings\n", cnt);
210 users = create_hash(13001);
212 EXEC SQL DECLARE u_cursor CURSOR FOR
213 SELECT users_id, login, first, middle, last, potype, pop_id, box_id
217 EXEC SQL OPEN u_cursor;
219 EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
221 if (sqlca.sqlcode != 0) break;
222 u = (struct user *) perm_malloc(sizeof(struct user));
223 u->login = pstrsave(strtrim(name));
224 u->first = pstrsave(strtrim(fname));
225 u->last = pstrsave(strtrim(lname));
231 if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
232 sprintf(buf, "%s@%s", u->login, s);
233 u->pobox = pstrsave(buf);
234 } else if (type[0] == 'S') {
235 u->pobox = hash_lookup(strings, bid);
237 u->pobox = (char *) NULL;
238 if (hash_store(users, id, u) < 0) {
239 fprintf(stderr, "Out of memory!\n");
244 EXEC SQL CLOSE u_cursor;
246 fprintf(stderr, "Loaded %d users\n", cnt);
249 lists = create_hash(15000);
251 EXEC SQL DECLARE l_cursor CURSOR FOR
252 SELECT list_id, name, maillist, description, acl_type, acl_id
256 EXEC SQL OPEN l_cursor;
258 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :buf, :type, :acl;
259 if (sqlca.sqlcode != 0) break;
260 l = (struct list *) perm_malloc(sizeof(struct list));
261 l->name = pstrsave(strtrim(name));
262 l->maillist = maillistp;
263 l->description = pstrsave(strtrim(buf));
266 l->m = (struct member *) NULL;
267 if (hash_store(lists, id, l) < 0) {
268 fprintf(stderr, "Out of memory!\n");
273 EXEC SQL CLOSE l_cursor;
275 fprintf(stderr, "Loaded %d lists\n", cnt);
279 EXEC SQL DECLARE m_cursor2 CURSOR FOR
280 SELECT list_id, member_type, member_id
284 EXEC SQL OPEN m_cursor2;
286 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
287 if (sqlca.sqlcode != 0) break;
289 if (l = (struct list *) hash_lookup(lists, id)) {
290 m = (struct member *) perm_malloc(sizeof(struct member));
291 if (type[0] == 'U' &&
292 (u = (struct user *) hash_lookup(users, mid))) {
297 } else if (type[0] == 'L' &&
298 (memberlist = (struct list *) hash_lookup(lists, mid))) {
300 m->name = memberlist->name;
303 } else if (type[0] == 'S' &&
304 (s = hash_lookup(strings, mid))) {
312 EXEC SQL CLOSE m_cursor2;
313 fprintf(stderr, "Loaded %d members\n", cnt);
316 com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
317 critical_alert("DCM", "Hesiod build encountered DATABASE ERROR %d",
323 save_mlist(id, l, force)
328 register struct member *m;
329 register struct list *l1;
331 if (l->maillist > 1 ||
332 (l->maillist == 0 && !force))
335 if (l->m && l->m->next == NULL &&
336 !strcasecmp(l->name, l->m->name)) {
341 insert_name(l->name, -1, TRUE, FALSE);
344 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
345 save_mlist(0, l1, TRUE);
347 for (m = l->m; m; m = m->next) {
348 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
349 save_mlist(0, l1, TRUE);
354 insert_login(id, u, dummy)
359 if (u->pobox && u->login[0] != '#')
360 insert_name(u->login, id, TRUE, FALSE);
363 void insert_names(id, u, dummy)
370 insert_name(u->last, id, FALSE, FALSE);
371 sprintf(buffer, "%s_%s", u->first, u->last);
372 insert_name(buffer, id, FALSE, TRUE);
373 /* sprintf(buffer, "%c_%s", u->first[0], u->last);
374 insert_name(buffer, id, FALSE, TRUE); */
376 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
377 insert_name(buffer, id, FALSE, TRUE);
383 insert_name(s, id, nodups, copy)
390 register struct names *ns;
394 ns = (struct names *) hash_lookup(names, code);
396 if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
397 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
401 ns->name = pstrsave(s);
407 if (hash_store(names, code, ns) < 0) {
408 fprintf(stderr, "Out of memory!\n");
413 if (strcasecmp(ns->name, s)) {
416 if (!strcasecmp(ns->name, s))
419 if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
421 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
426 ns->name = pstrsave(s);
435 if (nodups || ns->keep) {
436 if (nodups && ns->keep)
437 fprintf(stderr, "duplicated name: %s\n", s);
444 /* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
446 static int illegalchars[] = {
447 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
448 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
449 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
450 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
451 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
452 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
453 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
454 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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,
462 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
466 /* While hashing the string, punt any illegal characters */
474 for (result = 0; c = *s; s++) {
475 if (illegalchars[c]) {
483 /* result = result * 31 + *s; */
484 result = (result << 5) - result + c - '`';
486 return(result < 0 ? -result : result);
492 names = create_hash(20001);
493 hash_step(users, insert_login, NULL);
495 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
496 hash_step(lists, save_mlist, FALSE);
497 fprintf(stderr, "Output %d lists\n", incount);
498 hash_step(users, insert_names, NULL);
499 fprintf(stderr, "Inserted %d names\n", incount);
503 output_data(dummy, nms, out)
508 register struct names *ns;
509 register struct user *u;
512 for (ns = nms; ns; ns = ns->next) {
513 if (ns->name[0] == 0 || ns->name[1] == 0) {
514 fprintf(stderr, "punting %s due to short name\n", ns->name);
518 u = (struct user *) hash_lookup(users, ns->id);
520 fprintf(out, "%s: %s\n", ns->name, u->pobox);
522 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
524 } else if (ns->id == 0) {
525 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
535 register struct list *l;
538 register struct member *m;
539 register struct user *u;
541 put_fill(out, l->description);
542 if (l->acl_t == 'L' &&
543 (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
544 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
545 else if (l->acl_t == 'U' &&
546 (u = (struct user *) hash_lookup(users, l->acl_id)))
547 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
549 fprintf(out, "%s: ", l->name);
552 lwid = strlen(l->name) + 2;
554 for (m = l->m; m; m = m->next) {
555 do_member(out, m->name);
557 if (l->m == (struct member *)NULL)
558 fprintf(out, "/dev/null");
559 fprintf(out, "\n\n");
564 /* print out strings separated by commas, doing line breaks as appropriate */
575 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
576 fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
578 awid = lwid = 17 + wwid;
590 if (lwid + wwid + 2 > ML_WID) {
591 fprintf(out, ",\n\t%s", s);
592 awid += lwid + wwid + 2;
597 fprintf(out, ", %s", s);
601 put_fill(aliases, string)
603 register char *string;
609 if (string == 0 || *string == 0) return;
610 fputs("# ", aliases);
614 while (*string && *string == ' ') string++;
615 c = (char *)index(string, ' ');
617 wwid = strlen(string);
623 if ((lwid + wwid) > ML_WID) {
624 fputs("\n# ", aliases);
626 fputs(string, aliases);
628 fputs(string, aliases);
631 if (c == (char *)0) break;
632 /* add a space after the word */
633 (void) fputc(' ', aliases);
637 /* add another if after a period */
639 (void) fputc(' ', aliases);
644 (void) fputc('\n', aliases);
651 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
652 hash_step(names, output_data, out);
653 fprintf(stderr, "Output %d entries\n", incount);
657 #define chunk_size 102400
659 char *perm_malloc(size)
662 static char *pool = NULL;
663 static unsigned pool_size = 0;
666 if (size > pool_size) {
667 pool = (char *) malloc(chunk_size);
668 pool_size = chunk_size;
672 pool = (char *)(((unsigned) (pool + 3)) & ~3);
673 pool_size -= (pool - ret);
679 * Make a (permenant) copy of a string.
687 /* Kludge for sloppy string semantics */
689 printf("NULL != \"\" !!!!\r\n");
695 p = perm_malloc((u_int)len);
696 if (p) bcopy(s, p, len);
700 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
702 /* Create a hash table. The size is just a hint, not a maximum. */
704 struct hash *create_hash(size)
709 h = (struct hash *) perm_malloc(sizeof(struct hash));
710 if (h == (struct hash *) NULL)
711 return((struct hash *) NULL);
713 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
714 if (h->data == (struct bucket **) NULL) {
716 return((struct hash *) NULL);
718 bzero(h->data, size * sizeof(char *));
722 /* Lookup an object in the hash table. Returns the value associated with
723 * the key, or NULL (thus NULL is not a very good value to store...)
726 char *hash_lookup(h, key)
730 register struct bucket *b;
732 b = h->data[hash_func(h, key)];
733 while (b && b->key != key)
735 if (b && b->key == key)
742 /* Update an existing object in the hash table. Returns 1 if the object
743 * existed, or 0 if not.
746 int hash_update(h, key, value)
751 register struct bucket *b;
753 b = h->data[hash_func(h, key)];
754 while (b && b->key != key)
756 if (b && b->key == key) {
764 /* Store an item in the hash table. Returns 0 if the key was not previously
765 * there, 1 if it was, or -1 if we ran out of memory.
768 int hash_store(h, key, value)
773 register struct bucket *b, **p;
775 p = &(h->data[hash_func(h, key)]);
777 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
778 if (b == (struct bucket *) NULL)
786 for (b = *p; b && b->key != key; b = *p)
787 p = (struct bucket **) *p;
788 if (b && b->key == key) {
792 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
793 if (b == (struct bucket *) NULL)
802 /* Search through the hash table for a given value. For each piece of
803 * data with that value, call the callback proc with the corresponding key.
806 hash_search(h, value, callback)
808 register char *value;
811 register struct bucket *b, **p;
813 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
814 for (b = *p; b; b = b->next) {
815 if (b->data == value)
822 /* Step through the hash table, calling the callback proc with each key.
825 hash_step(h, callback, hint)
830 register struct bucket *b, **p;
832 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
833 for (b = *p; b; b = b->next) {
834 (*callback)(b->key, b->data, hint);
840 /* Deallocate all of the memory associated with a table */
845 register struct bucket *b, **p, *b1;
847 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
848 for (b = *p; b; b = b1) {