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 = "##############################################################";
31 #define MAX_LINE_WIDTH 72
32 #define MAX_ALIAS_WIDTH 592
37 struct hash *users, *machines, *strings, *lists;
57 int check_string(char *s);
58 void output_login(int dummy, void *names, void *out);
59 void output_mlist(int id, void *list, void *out);
60 void output_membership(struct list *l, FILE *out);
61 void put_fill(FILE *aliases, char *string);
66 int main(int argc, char **argv)
68 time_t tm = time(NULL);
69 char filename[MAXPATHLEN], *targetfile;
78 sprintf(filename, "%s~", targetfile);
79 if (!(out = fopen(filename, "w")))
81 fprintf(stderr, "unable to open %s for output\n", filename);
87 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
91 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
92 fprintf(out, "# This file is automatically generated, "
93 "do not edit it directly.\n%s\n\n", divide);
100 fprintf(out, "\n%s\n# Mailing lists\n%s\n\n", divide, divide);
101 hash_step(lists, output_mlist, out);
102 fprintf(stderr, "Output %d lists\n", incount);
105 fprintf(out, "\n%s\n# People\n%s\n\n", divide, divide);
106 hash_step(users, output_login, out);
107 fprintf(stderr, "Output %d users\n", incount);
109 fprintf(out, "\n%s\n# End of aliases file\n", divide);
113 perror("close failed");
118 fix_file(targetfile);
124 EXEC SQL BEGIN DECLARE SECTION;
125 int id, pid, iid, bid, cnt, maillistp, acl, mid;
126 char mname[MACHINE_NAME_SIZE], str[STRINGS_STRING_SIZE];
127 char login[USERS_LOGIN_SIZE], potype[USERS_POTYPE_SIZE];
128 char lname[LIST_NAME_SIZE], desc[LIST_DESCRIPTION_SIZE];
129 char type[LIST_ACL_TYPE_SIZE];
130 EXEC SQL END DECLARE SECTION;
133 struct list *l, *memberlist;
136 /* The following is declarative, not executed,
137 * and so is dependent on where it is in the file,
138 * not in the order of execution of statements.
140 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
143 machines = create_hash(100);
145 EXEC SQL DECLARE m_cursor CURSOR FOR
149 AND ( mach_id IN ( SELECT UNIQUE pop_id FROM users ) OR
150 mach_id IN ( SELECT UNIQUE mach_id FROM filesys
151 WHERE type = 'IMAP' ) )
153 EXEC SQL OPEN m_cursor;
156 EXEC SQL FETCH m_cursor INTO :id, :mname;
159 if ((s = strchr(mname, '.')))
164 strcat(mname, ".LOCAL");
166 if (hash_store(machines, id, strdup(mname)) < 0)
168 fprintf(stderr, "Out of memory!\n");
173 EXEC SQL CLOSE m_cursor;
175 fprintf(stderr, "Loaded %d machines\n", cnt);
178 strings = create_hash(11001);
180 EXEC SQL DECLARE s_cursor CURSOR FOR
181 SELECT string_id, string
184 EXEC SQL OPEN s_cursor;
187 EXEC SQL FETCH s_cursor INTO :id, :str;
190 if (hash_store(strings, id, strdup(strtrim(str))) < 0)
192 fprintf(stderr, "Out of memory!\n");
197 EXEC SQL CLOSE s_cursor;
199 fprintf(stderr, "Loaded %d strings\n", cnt);
202 users = create_hash(13001);
204 EXEC SQL DECLARE u_cursor CURSOR FOR
205 SELECT users_id, login, potype, pop_id, imap_id, box_id
209 EXEC SQL OPEN u_cursor;
212 char *saddr = NULL, *paddr = NULL;
214 EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :iid, :bid;
217 u = malloc(sizeof(struct user));
218 u->login = strdup(strtrim(login));
220 if (!strcmp(strtrim(potype), "NONE"))
224 /* If SMTP or SPLIT, get SMTP address. */
225 if (potype[0] == 'S')
227 saddr = hash_lookup(strings, bid);
229 /* If SMTP, clear pid and iid. */
230 if (potype[1] == 'M')
234 /* If IMAP, or SPLIT with IMAP, set pid to mach_id. */
235 if (potype[0] == 'I' || (potype[0] == 'S' && iid))
237 EXEC SQL SELECT mach_id INTO :pid FROM filesys
238 WHERE filsys_id = :iid;
241 if (pid && (s = hash_lookup(machines, pid)))
243 paddr = malloc(strlen(u->login) + strlen(s) + 2);
244 sprintf(paddr, "%s@%s", u->login, s);
249 u->pobox = malloc(strlen(paddr) + strlen(saddr) + 3);
250 sprintf(u->pobox, "%s, %s", paddr, saddr);
259 check_string(u->login);
260 if (hash_store(users, id, u) < 0)
262 fprintf(stderr, "Out of memory!\n");
267 EXEC SQL CLOSE u_cursor;
268 fprintf(stderr, "Loaded %d users\n", cnt);
271 lists = create_hash(15000);
273 EXEC SQL DECLARE l_cursor CURSOR FOR
274 SELECT list_id, name, maillist, description, acl_type, acl_id
278 EXEC SQL OPEN l_cursor;
281 EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl;
284 l = malloc(sizeof(struct list));
285 l->name = strdup(strtrim(lname));
286 l->maillist = maillistp;
287 l->description = strdup(strtrim(desc));
291 if (hash_store(lists, id, l) < 0)
293 fprintf(stderr, "Out of memory!\n");
298 EXEC SQL CLOSE l_cursor;
299 fprintf(stderr, "Loaded %d lists\n", cnt);
303 EXEC SQL DECLARE m_cursor2 CURSOR FOR
304 SELECT list_id, member_type, member_id
308 EXEC SQL OPEN m_cursor2;
311 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
315 if ((l = hash_lookup(lists, id)))
317 m = malloc(sizeof(struct member));
318 if (type[0] == 'U' && (u = hash_lookup(users, mid)))
325 else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
328 m->name = memberlist->name;
332 else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
341 EXEC SQL CLOSE m_cursor2;
342 fprintf(stderr, "Loaded %d members\n", cnt);
347 db_error(sqlca.sqlcode);
352 void output_login(int dummy, void *user, void *out)
354 struct user *u = user;
357 if (u->pobox && check_string(u->login) && u->login[0] != '#')
358 fprintf(out, "%s: %s\n", u->login, u->pobox);
361 int line_width, alias_width;
363 void output_mlist(int id, void *list, void *out)
365 struct list *l = list, *l1;
367 int len = strlen(l->name);
369 if (!l->maillist || !check_string(l->name))
372 /* If standard user group appears on a list, substitute in the user. */
373 if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
376 put_fill(out, l->description);
378 if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
380 fprintf(out, "owner-%s: ", l->name);
381 if ((l1->maillist) && (strcmp(l->name, l1->name)))
382 fprintf(out, "%s\n", l1->name);
385 alias_width = line_width = len + 8;
386 output_membership(l1, out);
390 else if (l->acl_t == 'U' && (u = hash_lookup(users, l->acl_id)))
391 fprintf(out, "owner-%s: %s\n", l->name, u->login);
393 fprintf(out, "%s: ", l->name);
394 alias_width = line_width = len + 2;
395 output_membership(l, out);
396 fprintf(out, "\n\n");
400 void output_membership(struct list *l, FILE *out)
404 int word_width, linestart = 1;
408 for (m = l->m; m; m = m->next)
410 word_width = strlen(m->name);
412 if (!linestart && alias_width + word_width + 2 > MAX_ALIAS_WIDTH)
414 /* Make a continuation. */
415 sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
416 rand() % 26 + 97, rand() % 26 + 97,
417 rand() % 26 + 97, rand() % 26 + 97);
418 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
420 alias_width = line_width = 17 + word_width;
424 /* First word on line, so we can't wrap. */
425 line_width += word_width;
426 alias_width = line_width;
429 else if (line_width + word_width + 2 > MAX_LINE_WIDTH)
433 alias_width += line_width + word_width + 2;
434 line_width = word_width + 8;
439 line_width += word_width + 2;
443 if (m->list_id && (l1 = hash_lookup(lists, m->list_id)) && !l1->maillist)
444 output_membership(l1, out);
449 fprintf(out, "/dev/null");
452 /* Write a word-wrapped list description to the aliases file as a
454 void put_fill(FILE *aliases, char *string)
460 if (!string || !*string)
462 fputs("# ", aliases);
467 while (*string == ' ')
469 c = strchr(string, ' ');
471 word_width = strlen(string);
474 word_width = c - string;
478 if (line_width + word_width > MAX_LINE_WIDTH)
480 fputs("\n# ", aliases);
482 fputs(string, aliases);
485 fputs(string, aliases);
489 /* add a space after the word */
492 line_width += word_width;
493 string += word_width;
494 /* add another if after a period */
502 fputc('\n', aliases);
506 /* Illegal chars: this no longer corresponds to the array
507 * in setup_alis. '+' is a valid character in a string on
508 * a list, but is not a valid character in a listname.
511 static int illegalchars[] = {
512 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
513 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
514 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
515 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
516 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
517 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
518 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
519 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
520 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
521 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
522 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
523 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
524 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
525 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
526 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
527 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
530 int check_string(char *s)
537 if (illegalchars[(unsigned) *s])