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;
59 int check_string(char *s);
60 void output_login(int dummy, void *names, void *out);
61 void output_mlist(int id, void *list, void *out);
62 void output_membership(struct list *l, FILE *out);
63 void put_fill(FILE *aliases, char *string);
68 int main(int argc, char **argv)
70 time_t tm = time(NULL);
71 char filename[MAXPATHLEN], *targetfile;
80 sprintf(filename, "%s~", targetfile);
81 if (!(out = fopen(filename, "w")))
83 fprintf(stderr, "unable to open %s for output\n", filename);
89 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
93 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
94 fprintf(out, "# This file is automatically generated, "
95 "do not edit it directly.\n%s\n\n", divide);
102 fprintf(out, "\n%s\n# Mailing lists\n%s\n\n", divide, divide);
103 hash_step(lists, output_mlist, out);
104 fprintf(stderr, "Output %d lists\n", incount);
107 fprintf(out, "\n%s\n# People\n%s\n\n", divide, divide);
108 hash_step(users, output_login, out);
109 fprintf(stderr, "Output %d users\n", incount);
111 fprintf(out, "\n%s\n# End of aliases file\n", divide);
115 perror("close failed");
120 fix_file(targetfile);
126 EXEC SQL BEGIN DECLARE SECTION;
127 int id, pid, iid, bid, cnt, maillistp, acl, mid, mailman;
128 char mname[MACHINE_NAME_SIZE], str[STRINGS_STRING_SIZE];
129 char login[USERS_LOGIN_SIZE], potype[USERS_POTYPE_SIZE];
130 char lname[LIST_NAME_SIZE], desc[LIST_DESCRIPTION_SIZE];
131 char type[LIST_ACL_TYPE_SIZE], mailman_server[MACHINE_NAME_SIZE];
132 EXEC SQL END DECLARE SECTION;
135 struct list *l, *memberlist;
138 /* The following is declarative, not executed,
139 * and so is dependent on where it is in the file,
140 * not in the order of execution of statements.
142 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
145 machines = create_hash(100);
147 EXEC SQL DECLARE m_cursor CURSOR FOR
151 AND ( mach_id IN ( SELECT UNIQUE pop_id FROM users ) OR
152 mach_id IN ( SELECT UNIQUE mach_id FROM filesys
153 WHERE type = 'IMAP' ) )
155 EXEC SQL OPEN m_cursor;
158 EXEC SQL FETCH m_cursor INTO :id, :mname;
161 if ((s = strchr(mname, '.')))
166 strcat(mname, ".LOCAL");
168 if (hash_store(machines, id, strdup(mname)) < 0)
170 fprintf(stderr, "Out of memory!\n");
175 EXEC SQL CLOSE m_cursor;
177 fprintf(stderr, "Loaded %d machines\n", cnt);
180 strings = create_hash(11001);
182 EXEC SQL DECLARE s_cursor CURSOR FOR
183 SELECT string_id, string
186 EXEC SQL OPEN s_cursor;
189 EXEC SQL FETCH s_cursor INTO :id, :str;
192 if (hash_store(strings, id, strdup(strtrim(str))) < 0)
194 fprintf(stderr, "Out of memory!\n");
199 EXEC SQL CLOSE s_cursor;
201 fprintf(stderr, "Loaded %d strings\n", cnt);
204 users = create_hash(13001);
206 EXEC SQL DECLARE u_cursor CURSOR FOR
207 SELECT users_id, login, potype, pop_id, imap_id, box_id
211 EXEC SQL OPEN u_cursor;
214 char *saddr = NULL, *paddr = NULL;
216 EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :iid, :bid;
219 u = malloc(sizeof(struct user));
220 u->login = strdup(strtrim(login));
222 if (!strcmp(strtrim(potype), "NONE"))
226 /* If SMTP or SPLIT, get SMTP address. */
227 if (potype[0] == 'S')
229 saddr = hash_lookup(strings, bid);
231 /* If SMTP, clear pid and iid. */
232 if (potype[1] == 'M')
236 /* If IMAP, or SPLIT with IMAP, set pid to mach_id. */
237 if (potype[0] == 'I' || (potype[0] == 'S' && iid))
239 EXEC SQL SELECT mach_id INTO :pid FROM filesys
240 WHERE filsys_id = :iid;
243 if (pid && (s = hash_lookup(machines, pid)))
245 paddr = malloc(strlen(u->login) + strlen(s) + 2);
246 sprintf(paddr, "%s@%s", u->login, s);
251 u->pobox = malloc(strlen(paddr) + strlen(saddr) + 3);
252 sprintf(u->pobox, "%s, %s", paddr, saddr);
261 check_string(u->login);
262 if (hash_store(users, id, u) < 0)
264 fprintf(stderr, "Out of memory!\n");
269 EXEC SQL CLOSE u_cursor;
270 fprintf(stderr, "Loaded %d users\n", cnt);
273 lists = create_hash(15000);
275 EXEC SQL DECLARE l_cursor CURSOR FOR
276 SELECT l.list_id, l.name, l.maillist, l.description, l.acl_type, l.acl_id,
278 FROM list l, machine m
279 WHERE active != 0 AND l.mailman_id = m.mach_id
281 EXEC SQL OPEN l_cursor;
284 EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl,
285 :mailman, :mailman_server;
288 l = malloc(sizeof(struct list));
289 l->name = strdup(strtrim(lname));
290 l->maillist = maillistp;
291 l->description = strdup(strtrim(desc));
294 l->mailman = mailman;
295 l->mailman_server = strdup(strtrim(mailman_server));
297 if (hash_store(lists, id, l) < 0)
299 fprintf(stderr, "Out of memory!\n");
304 EXEC SQL CLOSE l_cursor;
305 fprintf(stderr, "Loaded %d lists\n", cnt);
309 EXEC SQL DECLARE m_cursor2 CURSOR FOR
310 SELECT list_id, member_type, member_id
314 EXEC SQL OPEN m_cursor2;
317 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
321 if ((l = hash_lookup(lists, id)))
323 m = malloc(sizeof(struct member));
324 if (type[0] == 'U' && (u = hash_lookup(users, mid)))
331 else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
334 m->name = memberlist->name;
338 else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
347 EXEC SQL CLOSE m_cursor2;
348 fprintf(stderr, "Loaded %d members\n", cnt);
353 db_error(sqlca.sqlcode);
358 void output_login(int dummy, void *user, void *out)
360 struct user *u = user;
363 if (u->pobox && check_string(u->login) && u->login[0] != '#')
364 fprintf(out, "%s: %s\n", u->login, u->pobox);
367 int line_width, alias_width;
368 static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
369 "-bounces", "-confirm", "-join",
370 "-leave", "-subscribe",
371 "-unsubscribe", NULL };
373 void output_mlist(int id, void *list, void *out)
375 struct list *l = list, *l1;
377 int len = strlen(l->name), i;
379 if (!l->maillist || !check_string(l->name))
382 /* If standard user group appears on a list, substitute in the user. */
383 if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
386 put_fill(out, l->description);
388 if (l->mailman && strcmp(l->mailman_server, "[NONE]"))
390 for (i = 0; mailman_suffixes[i]; i++)
391 fprintf(out, "%s%s: %s%s@%s\n", l->name, mailman_suffixes[i], l->name,
392 mailman_suffixes[i], l->mailman_server);
393 fprintf(out, "owner-%s: %s-owner@%s\n", l->name, l->name,
396 else if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
398 fprintf(out, "owner-%s: ", l->name);
399 if ((l1->maillist) && (strcmp(l->name, l1->name)))
400 fprintf(out, "%s\n", l1->name);
403 alias_width = line_width = len + 8;
404 output_membership(l1, out);
408 else if (l->acl_t == 'U' && (u = hash_lookup(users, l->acl_id)))
409 fprintf(out, "owner-%s: %s\n", l->name, u->login);
411 fprintf(out, "%s: ", l->name);
412 alias_width = line_width = len + 2;
413 output_membership(l, out);
414 fprintf(out, "\n\n");
418 void output_membership(struct list *l, FILE *out)
422 int word_width, linestart = 1;
426 for (m = l->m; m; m = m->next)
428 word_width = strlen(m->name);
430 if (!linestart && alias_width + word_width + 2 > MAX_ALIAS_WIDTH)
432 /* Make a continuation. */
433 sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
434 rand() % 26 + 97, rand() % 26 + 97,
435 rand() % 26 + 97, rand() % 26 + 97);
436 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
438 alias_width = line_width = 17 + word_width;
442 /* First word on line, so we can't wrap. */
443 line_width += word_width;
444 alias_width = line_width;
447 else if (line_width + word_width + 2 > MAX_LINE_WIDTH)
451 alias_width += line_width + word_width + 2;
452 line_width = word_width + 8;
457 line_width += word_width + 2;
461 if (m->list_id && (l1 = hash_lookup(lists, m->list_id)) && !l1->maillist)
462 output_membership(l1, out);
467 fprintf(out, "/dev/null");
470 /* Write a word-wrapped list description to the aliases file as a
472 void put_fill(FILE *aliases, char *string)
478 if (!string || !*string)
480 fputs("# ", aliases);
485 while (*string == ' ')
487 c = strchr(string, ' ');
489 word_width = strlen(string);
492 word_width = c - string;
496 if (line_width + word_width > MAX_LINE_WIDTH)
498 fputs("\n# ", aliases);
500 fputs(string, aliases);
503 fputs(string, aliases);
507 /* add a space after the word */
510 line_width += word_width;
511 string += word_width;
512 /* add another if after a period */
520 fputc('\n', aliases);
524 /* Illegal chars: this no longer corresponds to the array
525 * in setup_alis. '+' is a valid character in a string on
526 * a list, but is not a valid character in a listname.
529 static int illegalchars[] = {
530 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
531 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
532 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
533 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
534 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
535 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
536 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
537 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
538 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
539 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
540 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
541 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
542 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
543 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
544 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
545 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
548 int check_string(char *s)
555 if (illegalchars[(unsigned) *s])