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";
25 char *db = "moira/moira";
28 char *divide = "##############################################################";
31 #define AL_MAX_WID 592
44 char filename[64], *targetfile;
46 EXEC SQL BEGIN DECLARE SECTION;
48 EXEC SQL END DECLARE SECTION;
53 if (stat(argv[1], &sb) == 0) {
54 if (ModDiff (&flag, "users", sb.st_mtime))
57 fprintf(stderr, "File %s does not need to be rebuilt.\n",
63 sprintf(filename, "%s~", targetfile);
64 if ((out = fopen(filename, "w")) == NULL) {
65 fprintf(stderr, "unable to open %s for output\n", filename);
68 } else if (argc != 1) {
69 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
73 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
74 fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide);
80 fprintf(stderr, "Sorting Info\n");
83 fprintf(stderr, "Dumping information\n");
86 fprintf(out, "\n%s\n# End of aliases file\n", divide);
89 perror("close failed");
100 struct hash *users, *machines, *strings, *lists, *names;
131 EXEC SQL BEGIN DECLARE SECTION;
132 int id, pid, bid, cnt, maillistp, acl, mid;
133 char name[129], type[9], fname[17], mname[17], lname[17], buf[257];
134 EXEC SQL END DECLARE SECTION;
136 register struct user *u;
137 struct list *l, *memberlist;
138 register struct member *m;
140 /* The following is declarative, not executed,
141 * and so is dependent on where it is in the file,
142 * not in the order of execution of statements.
144 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
147 machines = create_hash(1000);
149 EXEC SQL DECLARE m_cursor CURSOR FOR
154 EXEC SQL OPEN m_cursor;
156 EXEC SQL FETCH m_cursor INTO :id, :name;
157 if (sqlca.sqlcode != 0) break;
158 if (s = strchr(name, '.'))
163 strcat(name, ".LOCAL");
165 if (hash_store(machines, id, pstrsave(name)) < 0) {
166 fprintf(stderr, "Out of memory!\n");
171 EXEC SQL CLOSE m_cursor;
173 fprintf(stderr, "Loaded %d machines\n", cnt);
176 strings = create_hash(11001);
178 EXEC SQL DECLARE s_cursor CURSOR FOR
179 SELECT string_id, string
182 EXEC SQL OPEN s_cursor;
184 EXEC SQL FETCH s_cursor INTO :id, :name;
185 if (sqlca.sqlcode != 0) break;
186 if (hash_store(strings, id, pstrsave(strtrim(name))) < 0) {
187 fprintf(stderr, "Out of memory!\n");
192 EXEC SQL CLOSE s_cursor;
194 fprintf(stderr, "Loaded %d strings\n", cnt);
197 users = create_hash(13001);
199 EXEC SQL DECLARE u_cursor CURSOR FOR
200 SELECT users_id, login, first, middle, last, potype, pop_id, box_id
204 EXEC SQL OPEN u_cursor;
206 EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
208 if (sqlca.sqlcode != 0) break;
209 u = (struct user *) perm_malloc(sizeof(struct user));
210 u->login = pstrsave(strtrim(name));
211 u->first = pstrsave(strtrim(fname));
212 u->last = pstrsave(strtrim(lname));
218 if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
219 sprintf(buf, "%s@%s", u->login, s);
220 u->pobox = pstrsave(buf);
221 } else if (type[0] == 'S') {
222 u->pobox = hash_lookup(strings, bid);
224 u->pobox = (char *) NULL;
225 if (hash_store(users, id, u) < 0) {
226 fprintf(stderr, "Out of memory!\n");
231 EXEC SQL CLOSE u_cursor;
232 fprintf(stderr, "Loaded %d users\n", cnt);
235 lists = create_hash(15000);
237 EXEC SQL DECLARE l_cursor CURSOR FOR
238 SELECT list_id, name, maillist, description, acl_type, acl_id
242 EXEC SQL OPEN l_cursor;
244 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :buf, :type, :acl;
245 if (sqlca.sqlcode != 0) break;
246 l = (struct list *) perm_malloc(sizeof(struct list));
247 l->name = pstrsave(strtrim(name));
248 l->maillist = maillistp;
249 l->description = pstrsave(strtrim(buf));
252 l->m = (struct member *) NULL;
253 if (hash_store(lists, id, l) < 0) {
254 fprintf(stderr, "Out of memory!\n");
259 EXEC SQL CLOSE l_cursor;
260 fprintf(stderr, "Loaded %d lists\n", cnt);
264 EXEC SQL DECLARE m_cursor2 CURSOR FOR
265 SELECT list_id, member_type, member_id
269 EXEC SQL OPEN m_cursor2;
271 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
272 if (sqlca.sqlcode != 0) break;
274 if (l = (struct list *) hash_lookup(lists, id)) {
275 m = (struct member *) perm_malloc(sizeof(struct member));
276 if (type[0] == 'U' &&
277 (u = (struct user *) hash_lookup(users, mid))) {
282 } else if (type[0] == 'L' &&
283 (memberlist = (struct list *) hash_lookup(lists, mid))) {
285 m->name = memberlist->name;
288 } else if (type[0] == 'S' &&
289 (s = hash_lookup(strings, mid))) {
297 EXEC SQL CLOSE m_cursor2;
298 fprintf(stderr, "Loaded %d members\n", cnt);
303 db_error(sqlca.sqlcode);
308 save_mlist(id, l, force)
313 register struct member *m;
314 register struct list *l1;
316 if (l->maillist > 1 ||
317 (l->maillist == 0 && !force))
320 if (l->m && l->m->next == NULL &&
321 !strcasecmp(l->name, l->m->name)) {
326 insert_name(l->name, -1, TRUE, FALSE);
329 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
330 save_mlist(0, l1, TRUE);
332 for (m = l->m; m; m = m->next) {
333 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
334 save_mlist(0, l1, TRUE);
339 insert_login(id, u, dummy)
344 if (u->pobox && u->login[0] != '#')
345 insert_name(u->login, id, TRUE, FALSE);
348 void insert_names(id, u, dummy)
355 insert_name(u->last, id, FALSE, FALSE);
356 sprintf(buffer, "%s_%s", u->first, u->last);
357 insert_name(buffer, id, FALSE, TRUE);
358 /* sprintf(buffer, "%c_%s", u->first[0], u->last);
359 insert_name(buffer, id, FALSE, TRUE); */
361 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
362 insert_name(buffer, id, FALSE, TRUE);
368 insert_name(s, id, nodups, copy)
375 register struct names *ns;
379 ns = (struct names *) hash_lookup(names, code);
381 if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
382 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
386 ns->name = pstrsave(s);
392 if (hash_store(names, code, ns) < 0) {
393 fprintf(stderr, "Out of memory!\n");
398 if (strcasecmp(ns->name, s)) {
401 if (!strcasecmp(ns->name, s))
404 if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
406 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
411 ns->name = pstrsave(s);
420 if (nodups || ns->keep) {
421 if (nodups && ns->keep)
422 fprintf(stderr, "duplicated name: %s\n", s);
429 /* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
431 static int illegalchars[] = {
432 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
433 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
434 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
436 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
438 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
440 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
451 /* While hashing the string, punt any illegal characters */
459 for (result = 0; c = *s; s++) {
460 if (illegalchars[c]) {
468 /* result = result * 31 + *s; */
469 result = (result << 5) - result + c - '`';
471 return(result < 0 ? -result : result);
477 names = create_hash(20001);
478 hash_step(users, insert_login, NULL);
480 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
481 hash_step(lists, save_mlist, FALSE);
482 fprintf(stderr, "Output %d lists\n", incount);
483 hash_step(users, insert_names, NULL);
484 fprintf(stderr, "Inserted %d names\n", incount);
488 output_data(dummy, nms, out)
493 register struct names *ns;
494 register struct user *u;
497 for (ns = nms; ns; ns = ns->next) {
498 if (ns->name[0] == 0 || ns->name[1] == 0) {
499 fprintf(stderr, "punting %s due to short name\n", ns->name);
503 u = (struct user *) hash_lookup(users, ns->id);
505 fprintf(out, "%s: %s\n", ns->name, u->pobox);
507 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
509 } else if (ns->id == 0) {
510 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
520 register struct list *l;
523 register struct member *m;
524 register struct user *u;
526 put_fill(out, l->description);
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 */
561 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
562 sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
563 rand() % 26 + 97, rand() % 26 + 97,
564 rand() % 26 + 97, rand() % 26 + 97);
566 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
568 awid = lwid = 17 + wwid;
580 if (lwid + wwid + 2 > ML_WID) {
581 fprintf(out, ",\n\t%s", s);
582 awid += lwid + wwid + 2;
587 fprintf(out, ", %s", s);
591 put_fill(aliases, string)
593 register char *string;
599 if (string == 0 || *string == 0) return;
600 fputs("# ", aliases);
604 while (*string && *string == ' ') string++;
605 c = (char *)strchr(string, ' ');
607 wwid = strlen(string);
613 if ((lwid + wwid) > ML_WID) {
614 fputs("\n# ", aliases);
616 fputs(string, aliases);
618 fputs(string, aliases);
621 if (c == (char *)0) break;
622 /* add a space after the word */
623 (void) fputc(' ', aliases);
627 /* add another if after a period */
629 (void) fputc(' ', aliases);
634 (void) fputc('\n', aliases);
641 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
642 hash_step(names, output_data, out);
643 fprintf(stderr, "Output %d entries\n", incount);
647 #define chunk_size 102400
649 char *perm_malloc(size)
652 static char *pool = NULL;
653 static unsigned pool_size = 0;
656 if (size > pool_size) {
657 pool = (char *) malloc(chunk_size);
658 pool_size = chunk_size;
662 pool = (char *)(((unsigned) (pool + 3)) & ~3);
663 pool_size -= (pool - ret);
669 * Make a (permenant) copy of a string.
677 /* Kludge for sloppy string semantics */
679 printf("NULL != \"\" !!!!\r\n");
685 p = perm_malloc((u_int)len);
686 if (p) memcpy(p, s, len);
690 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
692 /* Create a hash table. The size is just a hint, not a maximum. */
694 struct hash *create_hash(size)
699 h = (struct hash *) perm_malloc(sizeof(struct hash));
700 if (h == (struct hash *) NULL)
701 return((struct hash *) NULL);
703 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
704 if (h->data == (struct bucket **) NULL) {
706 return((struct hash *) NULL);
708 memset(h->data, 0, size * sizeof(char *));
712 /* Lookup an object in the hash table. Returns the value associated with
713 * the key, or NULL (thus NULL is not a very good value to store...)
716 char *hash_lookup(h, key)
720 register struct bucket *b;
722 b = h->data[hash_func(h, key)];
723 while (b && b->key != key)
725 if (b && b->key == key)
732 /* Update an existing object in the hash table. Returns 1 if the object
733 * existed, or 0 if not.
736 int hash_update(h, key, value)
741 register struct bucket *b;
743 b = h->data[hash_func(h, key)];
744 while (b && b->key != key)
746 if (b && b->key == key) {
754 /* Store an item in the hash table. Returns 0 if the key was not previously
755 * there, 1 if it was, or -1 if we ran out of memory.
758 int hash_store(h, key, value)
763 register struct bucket *b, **p;
765 p = &(h->data[hash_func(h, key)]);
767 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
768 if (b == (struct bucket *) NULL)
776 for (b = *p; b && b->key != key; b = *p)
777 p = (struct bucket **) *p;
778 if (b && b->key == key) {
782 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
783 if (b == (struct bucket *) NULL)
792 /* Search through the hash table for a given value. For each piece of
793 * data with that value, call the callback proc with the corresponding key.
796 hash_search(h, value, callback)
798 register char *value;
801 register struct bucket *b, **p;
803 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
804 for (b = *p; b; b = b->next) {
805 if (b->data == value)
812 /* Step through the hash table, calling the callback proc with each key.
815 hash_step(h, callback, hint)
820 register struct bucket *b, **p;
822 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
823 for (b = *p; b; b = b->next) {
824 (*callback)(b->key, b->data, hint);
830 /* Deallocate all of the memory associated with a table */
835 register struct bucket *b, **p, *b1;
837 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
838 for (b = *p; b; b = b1) {