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>
18 #include <moira_site.h>
19 #include <sys/types.h>
22 EXEC SQL INCLUDE sqlca;
24 char *whoami = "mailhub.gen";
25 char *db = "moira/moira";
28 char *divide = "##############################################################";
31 #define AL_MAX_WID 592
38 int main(int argc, char **argv)
41 char filename[64], *targetfile;
43 EXEC SQL BEGIN DECLARE SECTION;
45 EXEC SQL END DECLARE SECTION;
51 if (stat(argv[1], &sb) == 0)
53 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")))
66 fprintf(stderr, "unable to open %s for output\n", filename);
72 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
76 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
77 fprintf(out, "# This file is automatically generated, "
78 "do not edit it directly.\n%s\n\n", divide);
84 fprintf(stderr, "Sorting Info\n");
87 fprintf(stderr, "Dumping information\n");
90 fprintf(out, "\n%s\n# End of aliases file\n", divide);
94 perror("close failed");
105 struct hash *users, *machines, *strings, *lists, *names;
136 EXEC SQL BEGIN DECLARE SECTION;
137 int id, pid, bid, cnt, maillistp, acl, mid;
138 char name[129], type[9], fname[17], mname[17], lname[17], buf[257];
139 EXEC SQL END DECLARE SECTION;
141 register struct user *u;
142 struct list *l, *memberlist;
143 register struct member *m;
145 /* The following is declarative, not executed,
146 * and so is dependent on where it is in the file,
147 * not in the order of execution of statements.
149 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
152 machines = create_hash(1000);
154 EXEC SQL DECLARE m_cursor CURSOR FOR
159 EXEC SQL OPEN m_cursor;
162 EXEC SQL FETCH m_cursor INTO :id, :name;
165 if (s = strchr(name, '.'))
170 strcat(name, ".LOCAL");
172 if (hash_store(machines, id, pstrsave(name)) < 0)
174 fprintf(stderr, "Out of memory!\n");
179 EXEC SQL CLOSE m_cursor;
181 fprintf(stderr, "Loaded %d machines\n", cnt);
184 strings = create_hash(11001);
186 EXEC SQL DECLARE s_cursor CURSOR FOR
187 SELECT string_id, string
190 EXEC SQL OPEN s_cursor;
193 EXEC SQL FETCH s_cursor INTO :id, :name;
196 if (hash_store(strings, id, pstrsave(strtrim(name))) < 0)
198 fprintf(stderr, "Out of memory!\n");
203 EXEC SQL CLOSE s_cursor;
205 fprintf(stderr, "Loaded %d strings\n", cnt);
208 users = create_hash(13001);
210 EXEC SQL DECLARE u_cursor CURSOR FOR
211 SELECT users_id, login, first, middle, last, potype, pop_id, box_id
215 EXEC SQL OPEN u_cursor;
218 EXEC SQL FETCH u_cursor INTO :id, :name, :fname, :mname, :lname,
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)))
233 sprintf(buf, "%s@%s", u->login, s);
234 u->pobox = pstrsave(buf);
236 else if (type[0] == 'S')
237 u->pobox = hash_lookup(strings, bid);
240 if (hash_store(users, id, u) < 0)
242 fprintf(stderr, "Out of memory!\n");
247 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;
261 EXEC SQL FETCH l_cursor INTO :id, :name, :maillistp, :buf, :type, :acl;
264 l = (struct list *) perm_malloc(sizeof(struct list));
265 l->name = pstrsave(strtrim(name));
266 l->maillist = maillistp;
267 l->description = pstrsave(strtrim(buf));
271 if (hash_store(lists, id, l) < 0)
273 fprintf(stderr, "Out of memory!\n");
278 EXEC SQL CLOSE l_cursor;
279 fprintf(stderr, "Loaded %d lists\n", cnt);
283 EXEC SQL DECLARE m_cursor2 CURSOR FOR
284 SELECT list_id, member_type, member_id
288 EXEC SQL OPEN m_cursor2;
291 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
295 if ((l = (struct list *) hash_lookup(lists, id)))
297 m = (struct member *) perm_malloc(sizeof(struct member));
298 if (type[0] == 'U' && (u = (struct user *) hash_lookup(users, mid)))
305 else if (type[0] == 'L' &&
306 (memberlist = (struct list *) hash_lookup(lists, mid)))
309 m->name = memberlist->name;
313 else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
322 EXEC SQL CLOSE m_cursor2;
323 fprintf(stderr, "Loaded %d members\n", cnt);
328 db_error(sqlca.sqlcode);
333 save_mlist(int id, struct list *l, int force)
335 register struct member *m;
336 register struct list *l1;
338 if (l->maillist > 1 || (l->maillist == 0 && !force))
341 if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
347 insert_name(l->name, -1, TRUE, FALSE);
350 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
351 save_mlist(0, l1, TRUE);
353 for (m = l->m; m; m = m->next)
355 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
356 save_mlist(0, l1, TRUE);
361 insert_login(int id, struct user *u, int dummy)
363 if (u->pobox && u->login[0] != '#')
364 insert_name(u->login, id, TRUE, FALSE);
367 void insert_names(int id, struct user *u, int dummy)
371 insert_name(u->last, id, FALSE, FALSE);
372 sprintf(buffer, "%s_%s", u->first, u->last);
373 insert_name(buffer, id, FALSE, TRUE);
375 sprintf(buffer, "%c_%s", u->first[0], u->last);
376 insert_name(buffer, id, FALSE, TRUE);
380 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
381 insert_name(buffer, id, FALSE, TRUE);
387 insert_name(char *s, int id, int nodups, int copy)
390 register struct names *ns;
394 ns = (struct names *) hash_lookup(names, code);
397 if (!(ns = (struct names *) perm_malloc(sizeof(struct names))))
399 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
403 ns->name = pstrsave(s);
409 if (hash_store(names, code, ns) < 0)
411 fprintf(stderr, "Out of memory!\n");
416 if (strcasecmp(ns->name, s))
421 if (!strcasecmp(ns->name, s))
424 if (!(ns->next = (struct names *) perm_malloc(sizeof(struct names))))
426 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
431 ns->name = pstrsave(s);
440 if (nodups || ns->keep)
442 if (nodups && ns->keep)
443 fprintf(stderr, "duplicated name: %s\n", s);
450 /* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
452 static int illegalchars[] = {
453 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
454 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
455 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
456 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
457 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
458 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
459 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
460 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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,
465 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
466 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
467 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
468 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
472 /* While hashing the string, punt any illegal characters */
474 int hashstr(register char *s)
479 for (result = 0; c = *s; s++)
490 result = (result << 5) - result + c - '`';
492 return result < 0 ? -result : result;
498 names = create_hash(20001);
499 hash_step(users, insert_login, NULL);
501 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
502 hash_step(lists, save_mlist, FALSE);
503 fprintf(stderr, "Output %d lists\n", incount);
504 hash_step(users, insert_names, NULL);
505 fprintf(stderr, "Inserted %d names\n", incount);
509 output_data(int dummy, struct names *nms, FILE *out)
511 register struct names *ns;
512 register struct user *u;
515 for (ns = nms; ns; ns = ns->next)
517 if (!ns->name[0] || !ns->name[1])
519 fprintf(stderr, "punting %s due to short name\n", ns->name);
524 u = (struct user *) hash_lookup(users, ns->id);
526 fprintf(out, "%s: %s\n", ns->name, u->pobox);
528 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
530 else if (ns->id == 0)
531 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
538 output_mlist(int id, register struct list *l)
541 register struct member *m;
542 register struct user *u;
544 put_fill(out, l->description);
545 if (l->acl_t == 'L' && (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);
553 lwid = strlen(l->name) + 2;
555 for (m = l->m; m; m = m->next)
556 do_member(out, m->name);
558 fprintf(out, "/dev/null");
559 fprintf(out, "\n\n");
564 /* print out strings separated by commas, doing line breaks as appropriate */
566 do_member(FILE *out, register char *s)
574 if (!bol && awid + wwid + 2 > AL_MAX_WID)
576 sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
577 rand() % 26 + 97, rand() % 26 + 97,
578 rand() % 26 + 97, rand() % 26 + 97);
580 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
582 awid = lwid = 17 + wwid;
595 if (lwid + wwid + 2 > ML_WID)
597 fprintf(out, ",\n\t%s", s);
598 awid += lwid + wwid + 2;
603 fprintf(out, ", %s", s);
607 put_fill(FILE *aliases, register char *string)
613 if (!string || !*string)
615 fputs("# ", aliases);
620 while (*string == ' ')
622 c = strchr(string, ' ');
624 wwid = strlen(string);
631 if ((lwid + wwid) > ML_WID)
633 fputs("\n# ", aliases);
635 fputs(string, aliases);
638 fputs(string, aliases);
642 /* add a space after the word */
647 /* add another if after a period */
655 fputc('\n', aliases);
662 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
663 hash_step(names, output_data, out);
664 fprintf(stderr, "Output %d entries\n", incount);
668 #define chunk_size 102400
670 char *perm_malloc(unsigned size)
672 static char *pool = NULL;
673 static unsigned pool_size = 0;
676 if (size > pool_size)
678 pool = malloc(chunk_size);
679 pool_size = chunk_size;
683 pool = (char *)(((unsigned) (pool + 3)) & ~3);
684 pool_size -= (pool - ret);
690 * Make a (permenant) copy of a string.
692 char *pstrsave(char *s)
696 /* Kludge for sloppy string semantics */
699 printf("NULL != \"\" !!!!\r\n");
705 p = perm_malloc((u_int)len);
711 #define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
713 /* Create a hash table. The size is just a hint, not a maximum. */
715 struct hash *create_hash(int size)
719 h = (struct hash *) perm_malloc(sizeof(struct hash));
723 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
726 memset(h->data, 0, size * sizeof(char *));
730 /* Lookup an object in the hash table. Returns the value associated with
731 * the key, or NULL (thus NULL is not a very good value to store...)
734 char *hash_lookup(struct hash *h, register int key)
736 register struct bucket *b;
738 b = h->data[hash_func(h, key)];
739 while (b && b->key != key)
741 if (b && b->key == key)
748 /* Update an existing object in the hash table. Returns 1 if the object
749 * existed, or 0 if not.
752 int hash_update(struct hash *h, register int key, char *value)
754 register struct bucket *b;
756 b = h->data[hash_func(h, key)];
757 while (b && b->key != key)
759 if (b && b->key == key)
769 /* Store an item in the hash table. Returns 0 if the key was not previously
770 * there, 1 if it was, or -1 if we ran out of memory.
773 int hash_store(struct hash *h, register int key, char *value)
775 register struct bucket *b, **p;
777 p = &(h->data[hash_func(h, key)]);
780 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
789 for (b = *p; b && b->key != key; b = *p)
790 p = (struct bucket **) *p;
791 if (b && b->key == key)
796 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
806 /* Search through the hash table for a given value. For each piece of
807 * data with that value, call the callback proc with the corresponding key.
810 hash_search(struct hash *h, register char *value, void (*callback)())
812 register struct bucket *b, **p;
814 for (p = &(h->data[h->size - 1]); p >= h->data; p--)
816 for (b = *p; b; b = b->next)
818 if (b->data == value)
825 /* Step through the hash table, calling the callback proc with each key.
828 hash_step(struct hash *h, void (*callback)(), char *hint)
830 register struct bucket *b, **p;
832 for (p = &(h->data[h->size - 1]); p >= h->data; p--)
834 for (b = *p; b; b = b->next)
835 (*callback)(b->key, b->data, hint);