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