]> andersk Git - moira.git/blame_incremental - gen/mailhub.pc
Once more.
[moira.git] / gen / mailhub.pc
... / ...
CommitLineData
1/* $Id$
2 *
3 * This generates the /usr/lib/aliases file for the mailhub.
4 *
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>.
8 */
9
10#include <mit-copyright.h>
11#include <moira.h>
12#include <moira_site.h>
13
14#include <sys/stat.h>
15
16#include <ctype.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include "util.h"
22
23EXEC SQL INCLUDE sqlca;
24
25RCSID("$Header$");
26
27char *whoami = "mailhub.gen";
28char *db = "moira/moira";
29char *divide = "##############################################################";
30
31#define MAX_LINE_WIDTH 72
32#define MAX_ALIAS_WIDTH 592
33
34#define FALSE 0
35#define TRUE (!FALSE)
36
37struct hash *users, *machines, *strings, *lists;
38struct user {
39 char *login;
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;
53 char mailman;
54 char *mailman_server;
55 struct member *m;
56};
57
58void get_info(void);
59int check_string(char *s);
60void output_login(int dummy, void *names, void *out);
61void output_mlist(int id, void *list, void *out);
62void output_membership(struct list *l, FILE *out);
63void put_fill(FILE *aliases, char *string);
64void do_people(void);
65
66int incount = 0;
67
68int main(int argc, char **argv)
69{
70 time_t tm = time(NULL);
71 char filename[MAXPATHLEN], *targetfile;
72 FILE *out = stdout;
73
74 srand(tm);
75 EXEC SQL CONNECT :db;
76
77 if (argc == 2)
78 {
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);
85 }
86 }
87 else if (argc != 1)
88 {
89 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
90 exit(MR_ARGS);
91 }
92
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);
96
97 get_info();
98
99 EXEC SQL COMMIT;
100
101 incount = 0;
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);
105
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);
110
111 fprintf(out, "\n%s\n# End of aliases file\n", divide);
112
113 if (fclose(out))
114 {
115 perror("close failed");
116 exit(MR_CCONFIG);
117 }
118
119 if (argc == 2)
120 fix_file(targetfile);
121 exit(MR_SUCCESS);
122}
123
124void get_info(void)
125{
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;
133 char *s;
134 struct user *u;
135 struct list *l, *memberlist;
136 struct member *m;
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;
145 machines = create_hash(100);
146
147 EXEC SQL DECLARE m_cursor CURSOR FOR
148 SELECT mach_id, name
149 FROM machine
150 WHERE status = 1
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' ) )
154 ORDER BY mach_id;
155 EXEC SQL OPEN m_cursor;
156 while (1)
157 {
158 EXEC SQL FETCH m_cursor INTO :id, :mname;
159 if (sqlca.sqlcode)
160 break;
161 if ((s = strchr(mname, '.')))
162 *s = '\0';
163 else
164 strtrim(mname);
165#ifdef ATHENA
166 strcat(mname, ".LOCAL");
167#endif
168 if (hash_store(machines, id, strdup(mname)) < 0)
169 {
170 fprintf(stderr, "Out of memory!\n");
171 exit(MR_NO_MEM);
172 }
173 cnt++;
174 }
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 {
189 EXEC SQL FETCH s_cursor INTO :id, :str;
190 if (sqlca.sqlcode)
191 break;
192 if (hash_store(strings, id, strdup(strtrim(str))) < 0)
193 {
194 fprintf(stderr, "Out of memory!\n");
195 exit(MR_NO_MEM);
196 }
197 cnt++;
198 }
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
207 SELECT users_id, login, potype, pop_id, imap_id, box_id
208 FROM users
209 WHERE status != 3
210 ORDER BY users_id;
211 EXEC SQL OPEN u_cursor;
212 while (1)
213 {
214 char *saddr = NULL, *paddr = NULL;
215
216 EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :iid, :bid;
217 if (sqlca.sqlcode)
218 break;
219 u = malloc(sizeof(struct user));
220 u->login = strdup(strtrim(login));
221
222 if (!strcmp(strtrim(potype), "NONE"))
223 u->pobox = NULL;
224 else
225 {
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;
259 }
260
261 check_string(u->login);
262 if (hash_store(users, id, u) < 0)
263 {
264 fprintf(stderr, "Out of memory!\n");
265 exit(MR_NO_MEM);
266 }
267 cnt++;
268 }
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
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
280 ORDER BY list_id;
281 EXEC SQL OPEN l_cursor;
282 while (1)
283 {
284 EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl,
285 :mailman, :mailman_server;
286 if (sqlca.sqlcode)
287 break;
288 l = malloc(sizeof(struct list));
289 l->name = strdup(strtrim(lname));
290 l->maillist = maillistp;
291 l->description = strdup(strtrim(desc));
292 l->acl_t = type[0];
293 l->acl_id = acl;
294 l->mailman = mailman;
295 l->mailman_server = strdup(strtrim(mailman_server));
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);
301 }
302 cnt++;
303 }
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++;
321 if ((l = hash_lookup(lists, id)))
322 {
323 m = malloc(sizeof(struct member));
324 if (type[0] == 'U' && (u = hash_lookup(users, mid)))
325 {
326 m->list_id = 0;
327 m->name = u->login;
328 m->next = l->m;
329 l->m = m;
330 }
331 else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
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;
344 }
345 }
346 }
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);
355}
356
357
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;
368static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
369 "-bounces", "-confirm", "-join",
370 "-leave", "-subscribe",
371 "-unsubscribe", NULL };
372
373void output_mlist(int id, void *list, void *out)
374{
375 struct list *l = list, *l1;
376 struct user *u;
377 int len = strlen(l->name), i;
378
379 if (!l->maillist || !check_string(l->name))
380 return;
381
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))
384 return;
385
386 put_fill(out, l->description);
387
388 if (l->mailman && strcmp(l->mailman_server, "[NONE]"))
389 {
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,
394 l->mailman_server);
395 }
396 else if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
397 {
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 }
407 }
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);
410
411 fprintf(out, "%s: ", l->name);
412 alias_width = line_width = len + 2;
413 output_membership(l, out);
414 fprintf(out, "\n\n");
415 incount++;
416}
417
418void output_membership(struct list *l, FILE *out)
419{
420 struct member *m;
421 struct list *l1;
422 int word_width, linestart = 1;
423 static int cont = 1;
424 char str[8];
425
426 for (m = l->m; m; m = m->next)
427 {
428 word_width = strlen(m->name);
429
430 if (!linestart && alias_width + word_width + 2 > MAX_ALIAS_WIDTH)
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;
439 }
440 else if (linestart)
441 {
442 /* First word on line, so we can't wrap. */
443 line_width += word_width;
444 alias_width = line_width;
445 linestart = 0;
446 }
447 else if (line_width + word_width + 2 > MAX_LINE_WIDTH)
448 {
449 /* Wrap. */
450 fputs(",\n\t", out);
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;
458 fputs(", ", out);
459 }
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);
465 }
466 if (!l->m)
467 fprintf(out, "/dev/null");
468}
469
470/* Write a word-wrapped list description to the aliases file as a
471 * comment. */
472void put_fill(FILE *aliases, char *string)
473{
474 char *c;
475 int line_width;
476 int word_width;
477
478 if (!string || !*string)
479 return;
480 fputs("# ", aliases);
481 line_width = 3;
482
483 while (1)
484 {
485 while (*string == ' ')
486 string++;
487 c = strchr(string, ' ');
488 if (!c)
489 word_width = strlen(string);
490 else
491 {
492 word_width = c - string;
493 *c = '\0';
494 }
495
496 if (line_width + word_width > MAX_LINE_WIDTH)
497 {
498 fputs("\n# ", aliases);
499 line_width = 3;
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);
509 word_width++;
510 line_width += word_width;
511 string += word_width;
512 /* add another if after a period */
513 if (*--c == '.')
514 {
515 fputc(' ', aliases);
516 line_width++;
517 }
518 }
519
520 fputc('\n', aliases);
521}
522
523
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 */
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)
549{
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;
559}
This page took 0.037786 seconds and 5 git commands to generate.