]> andersk Git - moira.git/blame - gen/mailhub.pc
Need to reserve more listnames for Mailman 2.1
[moira.git] / gen / mailhub.pc
CommitLineData
7ac48069 1/* $Id$
bac4ceaa 2 *
3 * This generates the /usr/lib/aliases file for the mailhub.
4 *
7ac48069 5 * (c) Copyright 1988-1998 by the Massachusetts Institute of Technology.
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
bac4ceaa 8 */
9
10#include <mit-copyright.h>
bac4ceaa 11#include <moira.h>
12#include <moira_site.h>
7ac48069 13
bac4ceaa 14#include <sys/stat.h>
7ac48069 15
16#include <ctype.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include "util.h"
22
bac4ceaa 23EXEC SQL INCLUDE sqlca;
24
7ac48069 25RCSID("$Header$");
26
bac4ceaa 27char *whoami = "mailhub.gen";
9c04b191 28char *db = "moira/moira";
bac4ceaa 29char *divide = "##############################################################";
30
b033c6ed 31#define MAX_LINE_WIDTH 72
32#define MAX_ALIAS_WIDTH 592
bac4ceaa 33
34#define FALSE 0
35#define TRUE (!FALSE)
36
1c9c2ec8 37struct hash *users, *machines, *strings, *lists;
7ac48069 38struct user {
39 char *login;
7ac48069 40 char *pobox;
41};
42struct member {
43 struct member *next;
44 char *name;
45 int list_id;
46};
47struct list {
48 char *name;
49 char maillist;
50 char *description;
51 char acl_t;
52 int acl_id;
dd746314 53 char mailman;
54 char *mailman_server;
7ac48069 55 struct member *m;
56};
7ac48069 57
58void get_info(void);
1c9c2ec8 59int check_string(char *s);
60void output_login(int dummy, void *names, void *out);
496bdfea 61void output_mlist(int id, void *list, void *out);
62void output_membership(struct list *l, FILE *out);
7ac48069 63void put_fill(FILE *aliases, char *string);
64void do_people(void);
65
b033c6ed 66int incount = 0;
67
5eaef520 68int main(int argc, char **argv)
bac4ceaa 69{
b033c6ed 70 time_t tm = time(NULL);
dfaf9b68 71 char filename[MAXPATHLEN], *targetfile;
496bdfea 72 FILE *out = stdout;
5eaef520 73
496bdfea 74 srand(tm);
5eaef520 75 EXEC SQL CONNECT :db;
76
77 if (argc == 2)
78 {
5eaef520 79 targetfile = argv[1];
80 sprintf(filename, "%s~", targetfile);
81 if (!(out = fopen(filename, "w")))
82 {
83 fprintf(stderr, "unable to open %s for output\n", filename);
84 exit(MR_OCONFIG);
bac4ceaa 85 }
5eaef520 86 }
87 else if (argc != 1)
88 {
89 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
90 exit(MR_ARGS);
bac4ceaa 91 }
92
5eaef520 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);
bac4ceaa 96
5eaef520 97 get_info();
bac4ceaa 98
5eaef520 99 EXEC SQL COMMIT;
bac4ceaa 100
1c9c2ec8 101 incount = 0;
102 fprintf(out, "\n%s\n# Mailing lists\n%s\n\n", divide, divide);
496bdfea 103 hash_step(lists, output_mlist, out);
1c9c2ec8 104 fprintf(stderr, "Output %d lists\n", incount);
bac4ceaa 105
1c9c2ec8 106 incount = 0;
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);
bac4ceaa 110
5eaef520 111 fprintf(out, "\n%s\n# End of aliases file\n", divide);
bac4ceaa 112
5eaef520 113 if (fclose(out))
114 {
115 perror("close failed");
116 exit(MR_CCONFIG);
bac4ceaa 117 }
118
5eaef520 119 if (argc == 2)
120 fix_file(targetfile);
121 exit(MR_SUCCESS);
bac4ceaa 122}
123
7ac48069 124void get_info(void)
bac4ceaa 125{
5eaef520 126 EXEC SQL BEGIN DECLARE SECTION;
dd746314 127 int id, pid, iid, bid, cnt, maillistp, acl, mid, mailman;
dfaf9b68 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];
dd746314 131 char type[LIST_ACL_TYPE_SIZE], mailman_server[MACHINE_NAME_SIZE];
5eaef520 132 EXEC SQL END DECLARE SECTION;
133 char *s;
44d12d58 134 struct user *u;
5eaef520 135 struct list *l, *memberlist;
44d12d58 136 struct member *m;
5eaef520 137
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.
141 */
142 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
143
144 cnt = 0;
b033c6ed 145 machines = create_hash(100);
5eaef520 146
147 EXEC SQL DECLARE m_cursor CURSOR FOR
148 SELECT mach_id, name
149 FROM machine
150 WHERE status = 1
cf807728 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' ) )
5eaef520 154 ORDER BY mach_id;
155 EXEC SQL OPEN m_cursor;
156 while (1)
157 {
dfaf9b68 158 EXEC SQL FETCH m_cursor INTO :id, :mname;
5eaef520 159 if (sqlca.sqlcode)
160 break;
dfaf9b68 161 if ((s = strchr(mname, '.')))
5eaef520 162 *s = '\0';
163 else
dfaf9b68 164 strtrim(mname);
bac4ceaa 165#ifdef ATHENA
dfaf9b68 166 strcat(mname, ".LOCAL");
bac4ceaa 167#endif
dfaf9b68 168 if (hash_store(machines, id, strdup(mname)) < 0)
5eaef520 169 {
170 fprintf(stderr, "Out of memory!\n");
171 exit(MR_NO_MEM);
bac4ceaa 172 }
5eaef520 173 cnt++;
bac4ceaa 174 }
5eaef520 175 EXEC SQL CLOSE m_cursor;
176
177 fprintf(stderr, "Loaded %d machines\n", cnt);
178
179 cnt = 0;
180 strings = create_hash(11001);
181
182 EXEC SQL DECLARE s_cursor CURSOR FOR
183 SELECT string_id, string
184 FROM strings
185 ORDER BY string_id;
186 EXEC SQL OPEN s_cursor;
187 while (1)
188 {
dfaf9b68 189 EXEC SQL FETCH s_cursor INTO :id, :str;
5eaef520 190 if (sqlca.sqlcode)
191 break;
dfaf9b68 192 if (hash_store(strings, id, strdup(strtrim(str))) < 0)
5eaef520 193 {
194 fprintf(stderr, "Out of memory!\n");
195 exit(MR_NO_MEM);
bac4ceaa 196 }
5eaef520 197 cnt++;
bac4ceaa 198 }
5eaef520 199 EXEC SQL CLOSE s_cursor;
200
201 fprintf(stderr, "Loaded %d strings\n", cnt);
202
203 cnt = 0;
204 users = create_hash(13001);
205
206 EXEC SQL DECLARE u_cursor CURSOR FOR
46c8036a 207 SELECT users_id, login, potype, pop_id, imap_id, box_id
5eaef520 208 FROM users
209 WHERE status != 3
210 ORDER BY users_id;
211 EXEC SQL OPEN u_cursor;
212 while (1)
213 {
450849e9 214 char *saddr = NULL, *paddr = NULL;
215
46c8036a 216 EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :iid, :bid;
5eaef520 217 if (sqlca.sqlcode)
218 break;
7ac48069 219 u = malloc(sizeof(struct user));
dfaf9b68 220 u->login = strdup(strtrim(login));
5eaef520 221
450849e9 222 if (!strcmp(strtrim(potype), "NONE"))
223 u->pobox = NULL;
224 else
5eaef520 225 {
450849e9 226 /* If SMTP or SPLIT, get SMTP address. */
227 if (potype[0] == 'S')
228 {
229 saddr = hash_lookup(strings, bid);
230
231 /* If SMTP, clear pid and iid. */
232 if (potype[1] == 'M')
233 pid = iid = 0;
234 }
235
236 /* If IMAP, or SPLIT with IMAP, set pid to mach_id. */
237 if (potype[0] == 'I' || (potype[0] == 'S' && iid))
238 {
239 EXEC SQL SELECT mach_id INTO :pid FROM filesys
240 WHERE filsys_id = :iid;
241 }
242
243 if (pid && (s = hash_lookup(machines, pid)))
244 {
245 paddr = malloc(strlen(u->login) + strlen(s) + 2);
246 sprintf(paddr, "%s@%s", u->login, s);
247 }
248
249 if (paddr && saddr)
250 {
251 u->pobox = malloc(strlen(paddr) + strlen(saddr) + 3);
252 sprintf(u->pobox, "%s, %s", paddr, saddr);
253 free(paddr);
254 }
255 else if (paddr)
256 u->pobox = paddr;
257 else
258 u->pobox = saddr;
5eaef520 259 }
1c9c2ec8 260
261 check_string(u->login);
5eaef520 262 if (hash_store(users, id, u) < 0)
263 {
264 fprintf(stderr, "Out of memory!\n");
265 exit(MR_NO_MEM);
bac4ceaa 266 }
5eaef520 267 cnt++;
bac4ceaa 268 }
5eaef520 269 EXEC SQL CLOSE u_cursor;
270 fprintf(stderr, "Loaded %d users\n", cnt);
271
272 cnt = 0;
273 lists = create_hash(15000);
274
275 EXEC SQL DECLARE l_cursor CURSOR FOR
dd746314 276 SELECT l.list_id, l.name, l.maillist, l.description, l.acl_type, l.acl_id,
277 l.mailman, m.name
278 FROM list l, machine m
279 WHERE active != 0 AND l.mailman_id = m.mach_id
5eaef520 280 ORDER BY list_id;
281 EXEC SQL OPEN l_cursor;
282 while (1)
283 {
dd746314 284 EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl,
285 :mailman, :mailman_server;
5eaef520 286 if (sqlca.sqlcode)
287 break;
7ac48069 288 l = malloc(sizeof(struct list));
dfaf9b68 289 l->name = strdup(strtrim(lname));
5eaef520 290 l->maillist = maillistp;
dfaf9b68 291 l->description = strdup(strtrim(desc));
5eaef520 292 l->acl_t = type[0];
293 l->acl_id = acl;
dd746314 294 l->mailman = mailman;
295 if ((s = strchr(mailman_server, '.')))
296 *s = '\0';
297 else
298 strtrim(mailman_server);
299#ifdef ATHENA
300 strcat(mailman_server, ".LOCAL");
301#endif
302 l->mailman_server = strdup(mailman_server);
5eaef520 303 l->m = NULL;
304 if (hash_store(lists, id, l) < 0)
305 {
306 fprintf(stderr, "Out of memory!\n");
307 exit(MR_NO_MEM);
bac4ceaa 308 }
5eaef520 309 cnt++;
bac4ceaa 310 }
5eaef520 311 EXEC SQL CLOSE l_cursor;
312 fprintf(stderr, "Loaded %d lists\n", cnt);
313
314 cnt = 0;
315
316 EXEC SQL DECLARE m_cursor2 CURSOR FOR
317 SELECT list_id, member_type, member_id
318 FROM imembers
319 WHERE direct = 1
320 ORDER BY list_id;
321 EXEC SQL OPEN m_cursor2;
322 while (1)
323 {
324 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
325 if (sqlca.sqlcode)
326 break;
327 cnt++;
7ac48069 328 if ((l = hash_lookup(lists, id)))
5eaef520 329 {
7ac48069 330 m = malloc(sizeof(struct member));
331 if (type[0] == 'U' && (u = hash_lookup(users, mid)))
5eaef520 332 {
333 m->list_id = 0;
334 m->name = u->login;
335 m->next = l->m;
336 l->m = m;
337 }
7ac48069 338 else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
5eaef520 339 {
340 m->list_id = mid;
341 m->name = memberlist->name;
342 m->next = l->m;
343 l->m = m;
344 }
345 else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
346 {
347 m->list_id = 0;
348 m->next = l->m;
349 l->m = m;
350 m->name = s;
bac4ceaa 351 }
352 }
353 }
5eaef520 354 EXEC SQL CLOSE m_cursor2;
355 fprintf(stderr, "Loaded %d members\n", cnt);
356
357 EXEC SQL COMMIT;
358 return;
359sqlerr:
360 db_error(sqlca.sqlcode);
361 exit(MR_DBMS_ERR);
bac4ceaa 362}
363
364
496bdfea 365void output_login(int dummy, void *user, void *out)
366{
367 struct user *u = user;
368
369 incount++;
370 if (u->pobox && check_string(u->login) && u->login[0] != '#')
371 fprintf(out, "%s: %s\n", u->login, u->pobox);
372}
373
374int line_width, alias_width;
514054a9 375static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
376 "-bounces", "-confirm", "-join",
377 "-leave", "-subscribe",
378 "-unsubscribe", NULL };
496bdfea 379
380void output_mlist(int id, void *list, void *out)
bac4ceaa 381{
7ac48069 382 struct list *l = list, *l1;
496bdfea 383 struct user *u;
514054a9 384 int len = strlen(l->name), i;
bac4ceaa 385
496bdfea 386 if (!l->maillist || !check_string(l->name))
5eaef520 387 return;
bac4ceaa 388
496bdfea 389 /* If standard user group appears on a list, substitute in the user. */
5eaef520 390 if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
496bdfea 391 return;
5eaef520 392
496bdfea 393 put_fill(out, l->description);
5eaef520 394
dd746314 395 if (l->mailman && strcmp(l->mailman_server, "[NONE]"))
396 {
514054a9 397 for (i = 0; mailman_suffixes[i]; i++)
398 fprintf(out, "%s%s: %s%s@%s\n", l->name, mailman_suffixes[i], l->name,
399 mailman_suffixes[i], l->mailman_server);
dd746314 400 }
401
496bdfea 402 if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
5eaef520 403 {
496bdfea 404 fprintf(out, "owner-%s: ", l->name);
405 if ((l1->maillist) && (strcmp(l->name, l1->name)))
406 fprintf(out, "%s\n", l1->name);
407 else
408 {
409 alias_width = line_width = len + 8;
410 output_membership(l1, out);
411 fprintf(out, "\n");
412 }
bac4ceaa 413 }
496bdfea 414 else if (l->acl_t == 'U' && (u = hash_lookup(users, l->acl_id)))
415 fprintf(out, "owner-%s: %s\n", l->name, u->login);
5eaef520 416
496bdfea 417 fprintf(out, "%s: ", l->name);
418 alias_width = line_width = len + 2;
419 output_membership(l, out);
420 fprintf(out, "\n\n");
5eaef520 421 incount++;
bac4ceaa 422}
423
496bdfea 424void output_membership(struct list *l, FILE *out)
bac4ceaa 425{
44d12d58 426 struct member *m;
496bdfea 427 struct list *l1;
428 int word_width, linestart = 1;
b033c6ed 429 static int cont = 1;
430 char str[8];
5eaef520 431
5eaef520 432 for (m = l->m; m; m = m->next)
b033c6ed 433 {
434 word_width = strlen(m->name);
435
496bdfea 436 if (!linestart && alias_width + word_width + 2 > MAX_ALIAS_WIDTH)
b033c6ed 437 {
438 /* Make a continuation. */
439 sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
440 rand() % 26 + 97, rand() % 26 + 97,
441 rand() % 26 + 97, rand() % 26 + 97);
442 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
443 cont++;
444 alias_width = line_width = 17 + word_width;
b033c6ed 445 }
496bdfea 446 else if (linestart)
b033c6ed 447 {
496bdfea 448 /* First word on line, so we can't wrap. */
b033c6ed 449 line_width += word_width;
450 alias_width = line_width;
496bdfea 451 linestart = 0;
b033c6ed 452 }
453 else if (line_width + word_width + 2 > MAX_LINE_WIDTH)
454 {
455 /* Wrap. */
496bdfea 456 fputs(",\n\t", out);
b033c6ed 457 alias_width += line_width + word_width + 2;
458 line_width = word_width + 8;
459 }
460 else
461 {
462 /* Continue line. */
463 line_width += word_width + 2;
496bdfea 464 fputs(", ", out);
b033c6ed 465 }
496bdfea 466
467 if (m->list_id && (l1 = hash_lookup(lists, m->list_id)) && !l1->maillist)
468 output_membership(l1, out);
469 else
470 fputs(m->name, out);
b033c6ed 471 }
5eaef520 472 if (!l->m)
473 fprintf(out, "/dev/null");
bac4ceaa 474}
475
b033c6ed 476/* Write a word-wrapped list description to the aliases file as a
477 * comment. */
7ac48069 478void put_fill(FILE *aliases, char *string)
492f333e 479{
44d12d58 480 char *c;
b033c6ed 481 int line_width;
482 int word_width;
492f333e 483
5eaef520 484 if (!string || !*string)
485 return;
486 fputs("# ", aliases);
b033c6ed 487 line_width = 3;
5eaef520 488
489 while (1)
490 {
491 while (*string == ' ')
492 string++;
493 c = strchr(string, ' ');
494 if (!c)
b033c6ed 495 word_width = strlen(string);
5eaef520 496 else
497 {
b033c6ed 498 word_width = c - string;
5eaef520 499 *c = '\0';
492f333e 500 }
501
b033c6ed 502 if (line_width + word_width > MAX_LINE_WIDTH)
5eaef520 503 {
504 fputs("\n# ", aliases);
b033c6ed 505 line_width = 3;
5eaef520 506 fputs(string, aliases);
507 }
508 else
509 fputs(string, aliases);
510
511 if (!c)
512 break;
513 /* add a space after the word */
514 fputc(' ', aliases);
b033c6ed 515 word_width++;
516 line_width += word_width;
517 string += word_width;
5eaef520 518 /* add another if after a period */
519 if (*--c == '.')
520 {
521 fputc(' ', aliases);
b033c6ed 522 line_width++;
492f333e 523 }
524 }
525
5eaef520 526 fputc('\n', aliases);
492f333e 527}
528
529
ad392f80 530/* Illegal chars: this no longer corresponds to the array
531 * in setup_alis. '+' is a valid character in a string on
532 * a list, but is not a valid character in a listname.
533 */
1c9c2ec8 534
535static int illegalchars[] = {
536 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
537 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
538 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
539 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
540 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
541 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
542 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
543 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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,
546 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
547 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
548 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
549 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
550 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
551 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
552};
553
554int check_string(char *s)
bac4ceaa 555{
1c9c2ec8 556 for (; *s; s++)
557 {
558 if (isupper(*s))
559 *s = tolower(*s);
560
561 if (illegalchars[(unsigned) *s])
562 return 0;
563 }
564 return 1;
bac4ceaa 565}
This page took 0.177418 seconds and 5 git commands to generate.