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 users WHERE users_id = 0;
159 EXEC SQL SELECT modtime INTO :buf FROM list WHERE list_id = 0;
162 machines = create_hash(1000);
164 EXEC SQL DECLARE m_cursor CURSOR FOR
169 EXEC SQL OPEN m_cursor;
171 EXEC SQL FETCH m_cursor INTO :id, :name;
172 if (sqlca.sqlcode != 0) break;
173 if (s = index(name, '.'))
178 strcat(name, ".LOCAL");
180 if (hash_store(machines, id, pstrsave(name)) < 0) {
181 fprintf(stderr, "Out of memory!\n");
186 EXEC SQL CLOSE m_cursor;
188 fprintf(stderr, "Loaded %d machines\n", cnt);
191 strings = create_hash(11001);
193 EXEC SQL DECLARE s_cursor CURSOR FOR
194 SELECT string_id, trim(string)
197 EXEC SQL OPEN s_cursor;
199 EXEC SQL FETCH s_cursor INTO :id, :name;
200 if (sqlca.sqlcode != 0) break;
201 if (hash_store(strings, id, pstrsave(name)) < 0) {
202 fprintf(stderr, "Out of memory!\n");
207 EXEC SQL CLOSE s_cursor;
209 fprintf(stderr, "Loaded %d strings\n", cnt);
212 users = create_hash(13001);
214 EXEC SQL DECLARE u_cursor CURSOR FOR
215 SELECT users_id, login, first, middle, last, potype, pop_id, box_id
219 EXEC SQL OPEN u_cursor;
221 EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
223 if (sqlca.sqlcode != 0) break;
224 u = (struct user *) perm_malloc(sizeof(struct user));
225 u->login = pstrsave(strtrim(name));
226 u->first = pstrsave(strtrim(fname));
227 u->last = pstrsave(strtrim(lname));
233 if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
234 sprintf(buf, "%s@%s", u->login, s);
235 u->pobox = pstrsave(buf);
236 } else if (type[0] == 'S') {
237 u->pobox = hash_lookup(strings, bid);
239 u->pobox = (char *) NULL;
240 if (hash_store(users, id, u) < 0) {
241 fprintf(stderr, "Out of memory!\n");
246 EXEC SQL CLOSE u_cursor;
248 fprintf(stderr, "Loaded %d users\n", cnt);
251 lists = create_hash(15000);
253 EXEC SQL DECLARE l_cursor CURSOR FOR
254 SELECT list_id, name, maillist, description, acl_type, acl_id
258 EXEC SQL OPEN l_cursor;
260 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :buf, :type, :acl;
261 if (sqlca.sqlcode != 0) break;
262 l = (struct list *) perm_malloc(sizeof(struct list));
263 l->name = pstrsave(strtrim(name));
264 l->maillist = maillistp;
265 l->description = pstrsave(strtrim(buf));
268 l->m = (struct member *) NULL;
269 if (hash_store(lists, id, l) < 0) {
270 fprintf(stderr, "Out of memory!\n");
275 EXEC SQL CLOSE l_cursor;
277 fprintf(stderr, "Loaded %d lists\n", cnt);
281 EXEC SQL DECLARE m_cursor2 CURSOR FOR
282 SELECT list_id, member_type, member_id
286 EXEC SQL OPEN m_cursor2;
288 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
289 if (sqlca.sqlcode != 0) break;
291 if (l = (struct list *) hash_lookup(lists, id)) {
292 m = (struct member *) perm_malloc(sizeof(struct member));
293 if (type[0] == 'U' &&
294 (u = (struct user *) hash_lookup(users, mid))) {
299 } else if (type[0] == 'L' &&
300 (memberlist = (struct list *) hash_lookup(lists, mid))) {
302 m->name = memberlist->name;
305 } else if (type[0] == 'S' &&
306 (s = hash_lookup(strings, mid))) {
314 EXEC SQL CLOSE m_cursor2;
315 fprintf(stderr, "Loaded %d members\n", cnt);
318 com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode);
319 critical_alert("DCM", "Mailhub build encountered DATABASE ERROR %d",
325 save_mlist(id, l, force)
330 register struct member *m;
331 register struct list *l1;
333 if (l->maillist > 1 ||
334 (l->maillist == 0 && !force))
337 if (l->m && l->m->next == NULL &&
338 !strcasecmp(l->name, l->m->name)) {
343 insert_name(l->name, -1, TRUE, FALSE);
346 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
347 save_mlist(0, l1, TRUE);
349 for (m = l->m; m; m = m->next) {
350 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
351 save_mlist(0, l1, TRUE);
356 insert_login(id, u, dummy)
361 if (u->pobox && u->login[0] != '#')
362 insert_name(u->login, id, TRUE, FALSE);
365 void insert_names(id, u, dummy)
372 insert_name(u->last, id, FALSE, FALSE);
373 sprintf(buffer, "%s_%s", u->first, u->last);
374 insert_name(buffer, id, FALSE, TRUE);
375 /* sprintf(buffer, "%c_%s", u->first[0], u->last);
376 insert_name(buffer, id, FALSE, TRUE); */
378 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
379 insert_name(buffer, id, FALSE, TRUE);
385 insert_name(s, id, nodups, copy)
392 register struct names *ns;
396 ns = (struct names *) hash_lookup(names, code);
398 if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
399 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
403 ns->name = pstrsave(s);
409 if (hash_store(names, code, ns) < 0) {
410 fprintf(stderr, "Out of memory!\n");
415 if (strcasecmp(ns->name, s)) {
418 if (!strcasecmp(ns->name, s))
421 if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
423 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
428 ns->name = pstrsave(s);
437 if (nodups || ns->keep) {
438 if (nodups && ns->keep)
439 fprintf(stderr, "duplicated name: %s\n", s);
446 /* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
448 static int illegalchars[] = {
449 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
450 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
451 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
452 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
453 1, 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, 1, 0, /* P - _ */
455 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
456 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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,
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,
468 /* While hashing the string, punt any illegal characters */
476 for (result = 0; c = *s; s++) {
477 if (illegalchars[c]) {
485 /* result = result * 31 + *s; */
486 result = (result << 5) - result + c - '`';
488 return(result < 0 ? -result : result);
494 names = create_hash(20001);
495 hash_step(users, insert_login, NULL);
497 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
498 hash_step(lists, save_mlist, FALSE);
499 fprintf(stderr, "Output %d lists\n", incount);
500 hash_step(users, insert_names, NULL);
501 fprintf(stderr, "Inserted %d names\n", incount);
505 output_data(dummy, nms, out)
510 register struct names *ns;
511 register struct user *u;
514 for (ns = nms; ns; ns = ns->next) {
515 if (ns->name[0] == 0 || ns->name[1] == 0) {
516 fprintf(stderr, "punting %s due to short name\n", ns->name);
520 u = (struct user *) hash_lookup(users, ns->id);
522 fprintf(out, "%s: %s\n", ns->name, u->pobox);
524 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
526 } else if (ns->id == 0) {
527 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
537 register struct list *l;
540 register struct member *m;
541 register struct user *u;
543 put_fill(out, l->description);
544 if (l->acl_t == 'L' &&
545 (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
546 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
547 else if (l->acl_t == 'U' &&
548 (u = (struct user *) hash_lookup(users, l->acl_id)))
549 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
551 fprintf(out, "%s: ", l->name);
554 lwid = strlen(l->name) + 2;
556 for (m = l->m; m; m = m->next) {
557 do_member(out, m->name);
559 if (l->m == (struct member *)NULL)
560 fprintf(out, "/dev/null");
561 fprintf(out, "\n\n");
566 /* print out strings separated by commas, doing line breaks as appropriate */
578 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
579 sprintf(str, "%c%c%c%c%c%c", random() % 26 + 97, random() % 26 + 97,
580 random() % 26 + 97, random() % 26 + 97,
581 random() % 26 + 97, random() % 26 + 97);
583 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
585 awid = lwid = 17 + wwid;
597 if (lwid + wwid + 2 > ML_WID) {
598 fprintf(out, ",\n\t%s", s);
599 awid += lwid + wwid + 2;
604 fprintf(out, ", %s", s);
608 put_fill(aliases, string)
610 register char *string;
616 if (string == 0 || *string == 0) return;
617 fputs("# ", aliases);
621 while (*string && *string == ' ') string++;
622 c = (char *)index(string, ' ');
624 wwid = strlen(string);
630 if ((lwid + wwid) > ML_WID) {
631 fputs("\n# ", aliases);
633 fputs(string, aliases);
635 fputs(string, aliases);
638 if (c == (char *)0) break;
639 /* add a space after the word */
640 (void) fputc(' ', aliases);
644 /* add another if after a period */
646 (void) fputc(' ', aliases);
651 (void) fputc('\n', aliases);
658 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
659 hash_step(names, output_data, out);
660 fprintf(stderr, "Output %d entries\n", incount);
664 #define chunk_size 102400
666 char *perm_malloc(size)
669 static char *pool = NULL;
670 static unsigned pool_size = 0;
673 if (size > pool_size) {
674 pool = (char *) malloc(chunk_size);
675 pool_size = chunk_size;
679 pool = (char *)(((unsigned) (pool + 3)) & ~3);
680 pool_size -= (pool - ret);
686 * Make a (permenant) copy of a string.
694 /* Kludge for sloppy string semantics */
696 printf("NULL != \"\" !!!!\r\n");
702 p = perm_malloc((u_int)len);
703 if (p) bcopy(s, p, len);
707 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
709 /* Create a hash table. The size is just a hint, not a maximum. */
711 struct hash *create_hash(size)
716 h = (struct hash *) perm_malloc(sizeof(struct hash));
717 if (h == (struct hash *) NULL)
718 return((struct hash *) NULL);
720 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
721 if (h->data == (struct bucket **) NULL) {
723 return((struct hash *) NULL);
725 bzero(h->data, size * sizeof(char *));
729 /* Lookup an object in the hash table. Returns the value associated with
730 * the key, or NULL (thus NULL is not a very good value to store...)
733 char *hash_lookup(h, key)
737 register struct bucket *b;
739 b = h->data[hash_func(h, key)];
740 while (b && b->key != key)
742 if (b && b->key == key)
749 /* Update an existing object in the hash table. Returns 1 if the object
750 * existed, or 0 if not.
753 int hash_update(h, key, value)
758 register struct bucket *b;
760 b = h->data[hash_func(h, key)];
761 while (b && b->key != key)
763 if (b && b->key == key) {
771 /* Store an item in the hash table. Returns 0 if the key was not previously
772 * there, 1 if it was, or -1 if we ran out of memory.
775 int hash_store(h, key, value)
780 register struct bucket *b, **p;
782 p = &(h->data[hash_func(h, key)]);
784 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
785 if (b == (struct bucket *) NULL)
793 for (b = *p; b && b->key != key; b = *p)
794 p = (struct bucket **) *p;
795 if (b && b->key == key) {
799 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
800 if (b == (struct bucket *) NULL)
809 /* Search through the hash table for a given value. For each piece of
810 * data with that value, call the callback proc with the corresponding key.
813 hash_search(h, value, callback)
815 register char *value;
818 register struct bucket *b, **p;
820 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
821 for (b = *p; b; b = b->next) {
822 if (b->data == value)
829 /* Step through the hash table, calling the callback proc with each key.
832 hash_step(h, callback, hint)
837 register struct bucket *b, **p;
839 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
840 for (b = *p; b; b = b->next) {
841 (*callback)(b->key, b->data, hint);
847 /* Deallocate all of the memory associated with a table */
852 register struct bucket *b, **p, *b1;
854 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
855 for (b = *p; b; b = b1) {