]> andersk Git - moira.git/blame - gen/mailhub.pc
service script for RT to set permissions on the generated file, and
[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;
a14ad8b0 295 l->mailman_server = strdup(strtrim(mailman_server));
5eaef520 296 l->m = NULL;
297 if (hash_store(lists, id, l) < 0)
298 {
299 fprintf(stderr, "Out of memory!\n");
300 exit(MR_NO_MEM);
bac4ceaa 301 }
5eaef520 302 cnt++;
bac4ceaa 303 }
5eaef520 304 EXEC SQL CLOSE l_cursor;
305 fprintf(stderr, "Loaded %d lists\n", cnt);
306
307 cnt = 0;
308
309 EXEC SQL DECLARE m_cursor2 CURSOR FOR
310 SELECT list_id, member_type, member_id
311 FROM imembers
312 WHERE direct = 1
313 ORDER BY list_id;
314 EXEC SQL OPEN m_cursor2;
315 while (1)
316 {
317 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
318 if (sqlca.sqlcode)
319 break;
320 cnt++;
7ac48069 321 if ((l = hash_lookup(lists, id)))
5eaef520 322 {
7ac48069 323 m = malloc(sizeof(struct member));
324 if (type[0] == 'U' && (u = hash_lookup(users, mid)))
5eaef520 325 {
326 m->list_id = 0;
327 m->name = u->login;
328 m->next = l->m;
329 l->m = m;
330 }
7ac48069 331 else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
5eaef520 332 {
333 m->list_id = mid;
334 m->name = memberlist->name;
335 m->next = l->m;
336 l->m = m;
337 }
338 else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
339 {
340 m->list_id = 0;
341 m->next = l->m;
342 l->m = m;
343 m->name = s;
bac4ceaa 344 }
345 }
346 }
5eaef520 347 EXEC SQL CLOSE m_cursor2;
348 fprintf(stderr, "Loaded %d members\n", cnt);
349
350 EXEC SQL COMMIT;
351 return;
352sqlerr:
353 db_error(sqlca.sqlcode);
354 exit(MR_DBMS_ERR);
bac4ceaa 355}
356
357
496bdfea 358void output_login(int dummy, void *user, void *out)
359{
360 struct user *u = user;
361
362 incount++;
363 if (u->pobox && check_string(u->login) && u->login[0] != '#')
364 fprintf(out, "%s: %s\n", u->login, u->pobox);
365}
366
367int line_width, alias_width;
514054a9 368static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
369 "-bounces", "-confirm", "-join",
370 "-leave", "-subscribe",
371 "-unsubscribe", NULL };
496bdfea 372
373void output_mlist(int id, void *list, void *out)
bac4ceaa 374{
7ac48069 375 struct list *l = list, *l1;
496bdfea 376 struct user *u;
514054a9 377 int len = strlen(l->name), i;
bac4ceaa 378
496bdfea 379 if (!l->maillist || !check_string(l->name))
5eaef520 380 return;
bac4ceaa 381
496bdfea 382 /* If standard user group appears on a list, substitute in the user. */
5eaef520 383 if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
496bdfea 384 return;
5eaef520 385
496bdfea 386 put_fill(out, l->description);
5eaef520 387
dd746314 388 if (l->mailman && strcmp(l->mailman_server, "[NONE]"))
389 {
514054a9 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);
e4a6dc65 393 fprintf(out, "owner-%s: %s-owner@%s\n", l->name, l->name,
394 l->mailman_server);
dd746314 395 }
e4a6dc65 396 else if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
5eaef520 397 {
496bdfea 398 fprintf(out, "owner-%s: ", l->name);
399 if ((l1->maillist) && (strcmp(l->name, l1->name)))
400 fprintf(out, "%s\n", l1->name);
401 else
402 {
403 alias_width = line_width = len + 8;
404 output_membership(l1, out);
405 fprintf(out, "\n");
406 }
bac4ceaa 407 }
496bdfea 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);
5eaef520 410
496bdfea 411 fprintf(out, "%s: ", l->name);
412 alias_width = line_width = len + 2;
413 output_membership(l, out);
414 fprintf(out, "\n\n");
5eaef520 415 incount++;
bac4ceaa 416}
417
496bdfea 418void output_membership(struct list *l, FILE *out)
bac4ceaa 419{
44d12d58 420 struct member *m;
496bdfea 421 struct list *l1;
422 int word_width, linestart = 1;
b033c6ed 423 static int cont = 1;
424 char str[8];
5eaef520 425
5eaef520 426 for (m = l->m; m; m = m->next)
b033c6ed 427 {
428 word_width = strlen(m->name);
429
496bdfea 430 if (!linestart && alias_width + word_width + 2 > MAX_ALIAS_WIDTH)
b033c6ed 431 {
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);
437 cont++;
438 alias_width = line_width = 17 + word_width;
b033c6ed 439 }
496bdfea 440 else if (linestart)
b033c6ed 441 {
496bdfea 442 /* First word on line, so we can't wrap. */
b033c6ed 443 line_width += word_width;
444 alias_width = line_width;
496bdfea 445 linestart = 0;
b033c6ed 446 }
447 else if (line_width + word_width + 2 > MAX_LINE_WIDTH)
448 {
449 /* Wrap. */
496bdfea 450 fputs(",\n\t", out);
b033c6ed 451 alias_width += line_width + word_width + 2;
452 line_width = word_width + 8;
453 }
454 else
455 {
456 /* Continue line. */
457 line_width += word_width + 2;
496bdfea 458 fputs(", ", out);
b033c6ed 459 }
496bdfea 460
461 if (m->list_id && (l1 = hash_lookup(lists, m->list_id)) && !l1->maillist)
462 output_membership(l1, out);
463 else
464 fputs(m->name, out);
b033c6ed 465 }
5eaef520 466 if (!l->m)
467 fprintf(out, "/dev/null");
bac4ceaa 468}
469
b033c6ed 470/* Write a word-wrapped list description to the aliases file as a
471 * comment. */
7ac48069 472void put_fill(FILE *aliases, char *string)
492f333e 473{
44d12d58 474 char *c;
b033c6ed 475 int line_width;
476 int word_width;
492f333e 477
5eaef520 478 if (!string || !*string)
479 return;
480 fputs("# ", aliases);
b033c6ed 481 line_width = 3;
5eaef520 482
483 while (1)
484 {
485 while (*string == ' ')
486 string++;
487 c = strchr(string, ' ');
488 if (!c)
b033c6ed 489 word_width = strlen(string);
5eaef520 490 else
491 {
b033c6ed 492 word_width = c - string;
5eaef520 493 *c = '\0';
492f333e 494 }
495
b033c6ed 496 if (line_width + word_width > MAX_LINE_WIDTH)
5eaef520 497 {
498 fputs("\n# ", aliases);
b033c6ed 499 line_width = 3;
5eaef520 500 fputs(string, aliases);
501 }
502 else
503 fputs(string, aliases);
504
505 if (!c)
506 break;
507 /* add a space after the word */
508 fputc(' ', aliases);
b033c6ed 509 word_width++;
510 line_width += word_width;
511 string += word_width;
5eaef520 512 /* add another if after a period */
513 if (*--c == '.')
514 {
515 fputc(' ', aliases);
b033c6ed 516 line_width++;
492f333e 517 }
518 }
519
5eaef520 520 fputc('\n', aliases);
492f333e 521}
522
523
ad392f80 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.
527 */
1c9c2ec8 528
529static 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,
546};
547
548int check_string(char *s)
bac4ceaa 549{
1c9c2ec8 550 for (; *s; s++)
551 {
552 if (isupper(*s))
553 *s = tolower(*s);
554
555 if (illegalchars[(unsigned) *s])
556 return 0;
557 }
558 return 1;
bac4ceaa 559}
This page took 0.163517 seconds and 5 git commands to generate.