3 * This generates the /usr/lib/aliases file for the mailhub.
5 * (c) Copyright 1988-1998 by the Massachusetts Institute of Technology.
6 * For copying and distribution information, please see the file
10 #include <mit-copyright.h>
12 #include <moira_site.h>
23 EXEC SQL INCLUDE sqlca;
27 char *whoami = "mailhub.gen";
28 char *db = "moira/moira";
29 char *divide = "##############################################################";
32 #define AL_MAX_WID 592
39 struct hash *users, *machines, *strings, *lists, *names;
65 void save_mlist(int id, void *list, void *force);
66 void insert_login(int id, void *user, void *hint);
67 void insert_name(char *s, int id, int nodups, int copy);
70 void output_data(int dummy, void *names, void *out);
71 void output_mlist(int id, struct list *l);
72 void do_member(FILE *out, char *s);
73 void put_fill(FILE *aliases, char *string);
76 int main(int argc, char **argv)
79 char filename[MAXPATHLEN], *targetfile;
81 EXEC SQL BEGIN DECLARE SECTION;
83 EXEC SQL END DECLARE SECTION;
89 if (stat(argv[1], &sb) == 0)
91 if (ModDiff (&flag, "users", sb.st_mtime))
95 fprintf(stderr, "File %s does not need to be rebuilt.\n",
100 targetfile = argv[1];
101 sprintf(filename, "%s~", targetfile);
102 if (!(out = fopen(filename, "w")))
104 fprintf(stderr, "unable to open %s for output\n", filename);
110 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
114 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
115 fprintf(out, "# This file is automatically generated, "
116 "do not edit it directly.\n%s\n\n", divide);
122 fprintf(stderr, "Sorting Info\n");
125 fprintf(stderr, "Dumping information\n");
128 fprintf(out, "\n%s\n# End of aliases file\n", divide);
132 perror("close failed");
137 fix_file(targetfile);
143 EXEC SQL BEGIN DECLARE SECTION;
144 int id, pid, bid, cnt, maillistp, acl, mid;
145 char mname[MACHINE_NAME_SIZE], str[STRINGS_STRING_SIZE];
146 char login[USERS_LOGIN_SIZE], potype[USERS_POTYPE_SIZE];
147 char lname[LIST_NAME_SIZE], desc[LIST_DESCRIPTION_SIZE];
148 char type[LIST_ACL_TYPE_SIZE];
149 EXEC SQL END DECLARE SECTION;
152 struct list *l, *memberlist;
155 /* The following is declarative, not executed,
156 * and so is dependent on where it is in the file,
157 * not in the order of execution of statements.
159 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
162 machines = create_hash(1000);
164 EXEC SQL DECLARE m_cursor CURSOR FOR
169 EXEC SQL OPEN m_cursor;
172 EXEC SQL FETCH m_cursor INTO :id, :mname;
175 if ((s = strchr(mname, '.')))
180 strcat(mname, ".LOCAL");
182 if (hash_store(machines, id, strdup(mname)) < 0)
184 fprintf(stderr, "Out of memory!\n");
189 EXEC SQL CLOSE m_cursor;
191 fprintf(stderr, "Loaded %d machines\n", cnt);
194 strings = create_hash(11001);
196 EXEC SQL DECLARE s_cursor CURSOR FOR
197 SELECT string_id, string
200 EXEC SQL OPEN s_cursor;
203 EXEC SQL FETCH s_cursor INTO :id, :str;
206 if (hash_store(strings, id, strdup(strtrim(str))) < 0)
208 fprintf(stderr, "Out of memory!\n");
213 EXEC SQL CLOSE s_cursor;
215 fprintf(stderr, "Loaded %d strings\n", cnt);
218 users = create_hash(13001);
220 EXEC SQL DECLARE u_cursor CURSOR FOR
221 SELECT users_id, login, potype, pop_id, box_id
225 EXEC SQL OPEN u_cursor;
228 EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :bid;
231 u = malloc(sizeof(struct user));
232 u->login = strdup(strtrim(login));
234 if (potype[0] == 'P' && (s = hash_lookup(machines, pid)))
236 char *buf = malloc(strlen(u->login) + strlen(s) + 2);
237 sprintf(buf, "%s@%s", u->login, s);
240 else if (potype[0] == 'S')
241 u->pobox = hash_lookup(strings, bid);
244 if (hash_store(users, id, u) < 0)
246 fprintf(stderr, "Out of memory!\n");
251 EXEC SQL CLOSE u_cursor;
252 fprintf(stderr, "Loaded %d users\n", cnt);
255 lists = create_hash(15000);
257 EXEC SQL DECLARE l_cursor CURSOR FOR
258 SELECT list_id, name, maillist, description, acl_type, acl_id
262 EXEC SQL OPEN l_cursor;
265 EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl;
268 l = malloc(sizeof(struct list));
269 l->name = strdup(strtrim(lname));
270 l->maillist = maillistp;
271 l->description = strdup(strtrim(desc));
275 if (hash_store(lists, id, l) < 0)
277 fprintf(stderr, "Out of memory!\n");
282 EXEC SQL CLOSE l_cursor;
283 fprintf(stderr, "Loaded %d lists\n", cnt);
287 EXEC SQL DECLARE m_cursor2 CURSOR FOR
288 SELECT list_id, member_type, member_id
292 EXEC SQL OPEN m_cursor2;
295 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
299 if ((l = hash_lookup(lists, id)))
301 m = malloc(sizeof(struct member));
302 if (type[0] == 'U' && (u = hash_lookup(users, mid)))
309 else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
312 m->name = memberlist->name;
316 else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
325 EXEC SQL CLOSE m_cursor2;
326 fprintf(stderr, "Loaded %d members\n", cnt);
331 db_error(sqlca.sqlcode);
336 void save_mlist(int id, void *list, void *force)
339 struct list *l = list, *l1;
341 if (l->maillist > 1 || (l->maillist == 0 && !force))
344 if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
350 insert_name(l->name, -1, TRUE, FALSE);
353 if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
354 save_mlist(0, l1, (void *)TRUE);
356 for (m = l->m; m; m = m->next)
358 if (m->list_id && (l1 = hash_lookup(lists, m->list_id)))
359 save_mlist(0, l1, (void *)TRUE);
364 void insert_login(int id, void *user, void *hint)
366 struct user *u = user;
367 if (u->pobox && u->login[0] != '#')
368 insert_name(u->login, id, TRUE, FALSE);
373 void insert_name(char *s, int id, int nodups, int copy)
380 ns = hash_lookup(names, code);
383 if (!(ns = malloc(sizeof(struct names))))
385 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
389 ns->name = strdup(s);
395 if (hash_store(names, code, ns) < 0)
397 fprintf(stderr, "Out of memory!\n");
402 if (strcasecmp(ns->name, s))
407 if (!strcasecmp(ns->name, s))
410 if (!(ns->next = malloc(sizeof(struct names))))
412 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
417 ns->name = strdup(s);
426 if (nodups || ns->keep)
428 if (nodups && ns->keep)
429 fprintf(stderr, "duplicated name: %s\n", s);
436 /* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
438 static int illegalchars[] = {
439 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
440 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
441 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
443 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
444 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
445 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
446 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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,
449 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
450 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
451 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
452 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
453 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
454 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
458 /* While hashing the string, punt any illegal characters */
465 for (result = 0; (c = *s); s++)
476 result = (result << 5) - result + c - '`';
478 return result < 0 ? -result : result;
484 names = create_hash(20001);
485 hash_step(users, insert_login, NULL);
487 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
488 hash_step(lists, save_mlist, FALSE);
489 fprintf(stderr, "Output %d lists\n", incount);
493 void output_data(int dummy, void *names, void *out)
495 struct names *ns, *nms = names;
499 for (ns = nms; ns; ns = ns->next)
501 if (!ns->name[0] || !ns->name[1])
503 fprintf(stderr, "punting %s due to short name\n", ns->name);
508 u = hash_lookup(users, ns->id);
510 fprintf(out, "%s: %s\n", ns->name, u->pobox);
518 void output_mlist(int id, struct list *l)
524 put_fill(out, l->description);
525 if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
526 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
527 else if (l->acl_t == 'U' && (u = hash_lookup(users, l->acl_id)))
528 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
530 fprintf(out, "%s: ", l->name);
532 lwid = strlen(l->name) + 2;
534 for (m = l->m; m; m = m->next)
535 do_member(out, m->name);
537 fprintf(out, "/dev/null");
538 fprintf(out, "\n\n");
543 /* print out strings separated by commas, doing line breaks as appropriate */
545 void do_member(FILE *out, char *s)
553 if (!bol && awid + wwid + 2 > AL_MAX_WID)
555 sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
556 rand() % 26 + 97, rand() % 26 + 97,
557 rand() % 26 + 97, rand() % 26 + 97);
559 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
561 awid = lwid = 17 + wwid;
574 if (lwid + wwid + 2 > ML_WID)
576 fprintf(out, ",\n\t%s", s);
577 awid += lwid + wwid + 2;
582 fprintf(out, ", %s", s);
586 void put_fill(FILE *aliases, char *string)
592 if (!string || !*string)
594 fputs("# ", aliases);
599 while (*string == ' ')
601 c = strchr(string, ' ');
603 wwid = strlen(string);
610 if ((lwid + wwid) > ML_WID)
612 fputs("\n# ", aliases);
614 fputs(string, aliases);
617 fputs(string, aliases);
621 /* add a space after the word */
626 /* add another if after a period */
634 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);