]> andersk Git - moira.git/blame - gen/mailhub.pc
Revert incremental code until we actually have an incremental (not yet)
[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;
375
376void output_mlist(int id, void *list, void *out)
bac4ceaa 377{
7ac48069 378 struct list *l = list, *l1;
496bdfea 379 struct user *u;
380 int len = strlen(l->name);
bac4ceaa 381
496bdfea 382 if (!l->maillist || !check_string(l->name))
5eaef520 383 return;
bac4ceaa 384
496bdfea 385 /* If standard user group appears on a list, substitute in the user. */
5eaef520 386 if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
496bdfea 387 return;
5eaef520 388
496bdfea 389 put_fill(out, l->description);
5eaef520 390
dd746314 391 if (l->mailman && strcmp(l->mailman_server, "[NONE]"))
392 {
393 fprintf(out, "%s-admin: %s-admin@%s\n", l->name, l->name,
394 l->mailman_server);
395 fprintf(out, "%s-owner: %s-owner@%s\n", l->name, l->name,
396 l->mailman_server);
397 fprintf(out, "%s-request: %s-request@%s\n", l->name, l->name,
398 l->mailman_server);
dd746314 399 }
400
496bdfea 401 if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
5eaef520 402 {
496bdfea 403 fprintf(out, "owner-%s: ", l->name);
404 if ((l1->maillist) && (strcmp(l->name, l1->name)))
405 fprintf(out, "%s\n", l1->name);
406 else
407 {
408 alias_width = line_width = len + 8;
409 output_membership(l1, out);
410 fprintf(out, "\n");
411 }
bac4ceaa 412 }
496bdfea 413 else if (l->acl_t == 'U' && (u = hash_lookup(users, l->acl_id)))
414 fprintf(out, "owner-%s: %s\n", l->name, u->login);
5eaef520 415
496bdfea 416 fprintf(out, "%s: ", l->name);
417 alias_width = line_width = len + 2;
418 output_membership(l, out);
419 fprintf(out, "\n\n");
5eaef520 420 incount++;
bac4ceaa 421}
422
496bdfea 423void output_membership(struct list *l, FILE *out)
bac4ceaa 424{
44d12d58 425 struct member *m;
496bdfea 426 struct list *l1;
427 int word_width, linestart = 1;
b033c6ed 428 static int cont = 1;
429 char str[8];
5eaef520 430
5eaef520 431 for (m = l->m; m; m = m->next)
b033c6ed 432 {
433 word_width = strlen(m->name);
434
496bdfea 435 if (!linestart && alias_width + word_width + 2 > MAX_ALIAS_WIDTH)
b033c6ed 436 {
437 /* Make a continuation. */
438 sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
439 rand() % 26 + 97, rand() % 26 + 97,
440 rand() % 26 + 97, rand() % 26 + 97);
441 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
442 cont++;
443 alias_width = line_width = 17 + word_width;
b033c6ed 444 }
496bdfea 445 else if (linestart)
b033c6ed 446 {
496bdfea 447 /* First word on line, so we can't wrap. */
b033c6ed 448 line_width += word_width;
449 alias_width = line_width;
496bdfea 450 linestart = 0;
b033c6ed 451 }
452 else if (line_width + word_width + 2 > MAX_LINE_WIDTH)
453 {
454 /* Wrap. */
496bdfea 455 fputs(",\n\t", out);
b033c6ed 456 alias_width += line_width + word_width + 2;
457 line_width = word_width + 8;
458 }
459 else
460 {
461 /* Continue line. */
462 line_width += word_width + 2;
496bdfea 463 fputs(", ", out);
b033c6ed 464 }
496bdfea 465
466 if (m->list_id && (l1 = hash_lookup(lists, m->list_id)) && !l1->maillist)
467 output_membership(l1, out);
468 else
469 fputs(m->name, out);
b033c6ed 470 }
5eaef520 471 if (!l->m)
472 fprintf(out, "/dev/null");
bac4ceaa 473}
474
b033c6ed 475/* Write a word-wrapped list description to the aliases file as a
476 * comment. */
7ac48069 477void put_fill(FILE *aliases, char *string)
492f333e 478{
44d12d58 479 char *c;
b033c6ed 480 int line_width;
481 int word_width;
492f333e 482
5eaef520 483 if (!string || !*string)
484 return;
485 fputs("# ", aliases);
b033c6ed 486 line_width = 3;
5eaef520 487
488 while (1)
489 {
490 while (*string == ' ')
491 string++;
492 c = strchr(string, ' ');
493 if (!c)
b033c6ed 494 word_width = strlen(string);
5eaef520 495 else
496 {
b033c6ed 497 word_width = c - string;
5eaef520 498 *c = '\0';
492f333e 499 }
500
b033c6ed 501 if (line_width + word_width > MAX_LINE_WIDTH)
5eaef520 502 {
503 fputs("\n# ", aliases);
b033c6ed 504 line_width = 3;
5eaef520 505 fputs(string, aliases);
506 }
507 else
508 fputs(string, aliases);
509
510 if (!c)
511 break;
512 /* add a space after the word */
513 fputc(' ', aliases);
b033c6ed 514 word_width++;
515 line_width += word_width;
516 string += word_width;
5eaef520 517 /* add another if after a period */
518 if (*--c == '.')
519 {
520 fputc(' ', aliases);
b033c6ed 521 line_width++;
492f333e 522 }
523 }
524
5eaef520 525 fputc('\n', aliases);
492f333e 526}
527
528
ad392f80 529/* Illegal chars: this no longer corresponds to the array
530 * in setup_alis. '+' is a valid character in a string on
531 * a list, but is not a valid character in a listname.
532 */
1c9c2ec8 533
534static int illegalchars[] = {
535 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
536 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
537 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
538 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
539 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
540 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
541 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
542 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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,
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};
552
553int check_string(char *s)
bac4ceaa 554{
1c9c2ec8 555 for (; *s; s++)
556 {
557 if (isupper(*s))
558 *s = tolower(*s);
559
560 if (illegalchars[(unsigned) *s])
561 return 0;
562 }
563 return 1;
bac4ceaa 564}
This page took 0.181551 seconds and 5 git commands to generate.