]> andersk Git - moira.git/blame - gen/mailhub.pc
Command line printer manipulation client, and build goo.
[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
22bbb6f0 37FILE *out = stdout;
38
1c9c2ec8 39struct hash *users, *machines, *strings, *lists;
7ac48069 40struct user {
41 char *login;
7ac48069 42 char *pobox;
43};
44struct member {
45 struct member *next;
46 char *name;
47 int list_id;
48};
49struct list {
50 char *name;
51 char maillist;
52 char *description;
53 char acl_t;
54 int acl_id;
dd746314 55 char mailman;
56 char *mailman_server;
7ac48069 57 struct member *m;
58};
7ac48069 59
60void get_info(void);
22bbb6f0 61void save_mlist(int id, void *list, void *force);
1c9c2ec8 62int check_string(char *s);
63void output_login(int dummy, void *names, void *out);
22bbb6f0 64void output_mlist(int id, struct list *l);
7ac48069 65void put_fill(FILE *aliases, char *string);
66void do_people(void);
67
b033c6ed 68int incount = 0;
69
5eaef520 70int main(int argc, char **argv)
bac4ceaa 71{
b033c6ed 72 time_t tm = time(NULL);
dfaf9b68 73 char filename[MAXPATHLEN], *targetfile;
5eaef520 74
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);
22bbb6f0 103 hash_step(lists, save_mlist, FALSE);
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;
22bbb6f0 127 int id, pid, iid, bid, eid, 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
22bbb6f0 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
22bbb6f0 177 EXEC SQL DECLARE e_cursor CURSOR FOR
178 SELECT mach_id, name
179 FROM machine
180 WHERE status = 1
181 AND mach_id in (SELECT UNIQUE exchange_id FROM users)
182 ORDER BY mach_id;
183 EXEC SQL OPEN e_cursor;
184 while (1)
185 {
186 EXEC SQL FETCH e_cursor INTO :id, :mname;
187 if (sqlca.sqlcode)
188 break;
189 strtrim(mname);
190 if (hash_store(machines, id, strdup(mname)) < 0)
191 {
192 fprintf(stderr, "Out of memory!\n");
193 exit(MR_NO_MEM);
194 }
195 cnt++;
196 }
197 EXEC SQL CLOSE e_cursor;
198
5eaef520 199 fprintf(stderr, "Loaded %d machines\n", cnt);
200
201 cnt = 0;
202 strings = create_hash(11001);
203
204 EXEC SQL DECLARE s_cursor CURSOR FOR
205 SELECT string_id, string
206 FROM strings
207 ORDER BY string_id;
208 EXEC SQL OPEN s_cursor;
209 while (1)
210 {
dfaf9b68 211 EXEC SQL FETCH s_cursor INTO :id, :str;
5eaef520 212 if (sqlca.sqlcode)
213 break;
dfaf9b68 214 if (hash_store(strings, id, strdup(strtrim(str))) < 0)
5eaef520 215 {
216 fprintf(stderr, "Out of memory!\n");
217 exit(MR_NO_MEM);
bac4ceaa 218 }
5eaef520 219 cnt++;
bac4ceaa 220 }
5eaef520 221 EXEC SQL CLOSE s_cursor;
222
223 fprintf(stderr, "Loaded %d strings\n", cnt);
224
225 cnt = 0;
226 users = create_hash(13001);
227
228 EXEC SQL DECLARE u_cursor CURSOR FOR
22bbb6f0 229 SELECT users_id, login, potype, pop_id, imap_id, box_id, exchange_id
5eaef520 230 FROM users
231 WHERE status != 3
232 ORDER BY users_id;
233 EXEC SQL OPEN u_cursor;
234 while (1)
235 {
450849e9 236 char *saddr = NULL, *paddr = NULL;
237
22bbb6f0 238 EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :iid, :bid,
239 :eid;
5eaef520 240 if (sqlca.sqlcode)
241 break;
7ac48069 242 u = malloc(sizeof(struct user));
dfaf9b68 243 u->login = strdup(strtrim(login));
5eaef520 244
450849e9 245 if (!strcmp(strtrim(potype), "NONE"))
246 u->pobox = NULL;
247 else
5eaef520 248 {
450849e9 249 /* If SMTP or SPLIT, get SMTP address. */
250 if (potype[0] == 'S')
251 {
252 saddr = hash_lookup(strings, bid);
253
254 /* If SMTP, clear pid and iid. */
255 if (potype[1] == 'M')
22bbb6f0 256 pid = iid = eid = 0;
450849e9 257 }
258
259 /* If IMAP, or SPLIT with IMAP, set pid to mach_id. */
260 if (potype[0] == 'I' || (potype[0] == 'S' && iid))
261 {
262 EXEC SQL SELECT mach_id INTO :pid FROM filesys
263 WHERE filsys_id = :iid;
264 }
265
22bbb6f0 266 /* If EXCHANGE or SPLIT with EXCHANGE, set pid to eid. */
267 if (potype[0] == 'E' || (potype[0] == 'S' && eid))
268 pid = eid;
269
450849e9 270 if (pid && (s = hash_lookup(machines, pid)))
271 {
272 paddr = malloc(strlen(u->login) + strlen(s) + 2);
273 sprintf(paddr, "%s@%s", u->login, s);
274 }
275
276 if (paddr && saddr)
277 {
278 u->pobox = malloc(strlen(paddr) + strlen(saddr) + 3);
279 sprintf(u->pobox, "%s, %s", paddr, saddr);
280 free(paddr);
281 }
282 else if (paddr)
283 u->pobox = paddr;
284 else
285 u->pobox = saddr;
5eaef520 286 }
1c9c2ec8 287
288 check_string(u->login);
5eaef520 289 if (hash_store(users, id, u) < 0)
290 {
291 fprintf(stderr, "Out of memory!\n");
292 exit(MR_NO_MEM);
bac4ceaa 293 }
5eaef520 294 cnt++;
bac4ceaa 295 }
5eaef520 296 EXEC SQL CLOSE u_cursor;
297 fprintf(stderr, "Loaded %d users\n", cnt);
298
299 cnt = 0;
300 lists = create_hash(15000);
301
302 EXEC SQL DECLARE l_cursor CURSOR FOR
dd746314 303 SELECT l.list_id, l.name, l.maillist, l.description, l.acl_type, l.acl_id,
304 l.mailman, m.name
305 FROM list l, machine m
306 WHERE active != 0 AND l.mailman_id = m.mach_id
5eaef520 307 ORDER BY list_id;
308 EXEC SQL OPEN l_cursor;
309 while (1)
310 {
dd746314 311 EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl,
312 :mailman, :mailman_server;
5eaef520 313 if (sqlca.sqlcode)
314 break;
7ac48069 315 l = malloc(sizeof(struct list));
dfaf9b68 316 l->name = strdup(strtrim(lname));
5eaef520 317 l->maillist = maillistp;
dfaf9b68 318 l->description = strdup(strtrim(desc));
5eaef520 319 l->acl_t = type[0];
320 l->acl_id = acl;
dd746314 321 l->mailman = mailman;
a14ad8b0 322 l->mailman_server = strdup(strtrim(mailman_server));
5eaef520 323 l->m = NULL;
324 if (hash_store(lists, id, l) < 0)
325 {
326 fprintf(stderr, "Out of memory!\n");
327 exit(MR_NO_MEM);
bac4ceaa 328 }
5eaef520 329 cnt++;
bac4ceaa 330 }
5eaef520 331 EXEC SQL CLOSE l_cursor;
332 fprintf(stderr, "Loaded %d lists\n", cnt);
333
334 cnt = 0;
335
336 EXEC SQL DECLARE m_cursor2 CURSOR FOR
337 SELECT list_id, member_type, member_id
338 FROM imembers
339 WHERE direct = 1
340 ORDER BY list_id;
341 EXEC SQL OPEN m_cursor2;
342 while (1)
343 {
344 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
345 if (sqlca.sqlcode)
346 break;
347 cnt++;
7ac48069 348 if ((l = hash_lookup(lists, id)))
5eaef520 349 {
7ac48069 350 m = malloc(sizeof(struct member));
351 if (type[0] == 'U' && (u = hash_lookup(users, mid)))
5eaef520 352 {
353 m->list_id = 0;
354 m->name = u->login;
355 m->next = l->m;
356 l->m = m;
357 }
7ac48069 358 else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
5eaef520 359 {
360 m->list_id = mid;
361 m->name = memberlist->name;
362 m->next = l->m;
363 l->m = m;
364 }
365 else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
366 {
367 m->list_id = 0;
368 m->next = l->m;
369 l->m = m;
370 m->name = s;
bac4ceaa 371 }
372 }
373 }
5eaef520 374 EXEC SQL CLOSE m_cursor2;
375 fprintf(stderr, "Loaded %d members\n", cnt);
376
377 EXEC SQL COMMIT;
378 return;
379sqlerr:
380 db_error(sqlca.sqlcode);
381 exit(MR_DBMS_ERR);
bac4ceaa 382}
383
384
22bbb6f0 385void save_mlist(int id, void *list, void *force)
386{
387 struct member *m;
388 struct list *l = list, *l1;
389
390 if (l->maillist > 1 || (l->maillist == 0 && !force) ||
391 !check_string(l->name))
392 return;
393
394 /* If user group appears on list, replace with user. */
395 if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
396 {
397 l->maillist = 3;
398 return;
399 }
400 l->maillist = 2;
401 output_mlist(id, l);
402
403 if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
404 save_mlist(0, l1, (void *)TRUE);
405
406 for (m = l->m; m; m = m->next)
407 {
408 if (m->list_id && (l1 = hash_lookup(lists, m->list_id)))
409 save_mlist(0, l1, (void *)TRUE);
410 }
411}
412
496bdfea 413void output_login(int dummy, void *user, void *out)
414{
415 struct user *u = user;
416
417 incount++;
418 if (u->pobox && check_string(u->login) && u->login[0] != '#')
419 fprintf(out, "%s: %s\n", u->login, u->pobox);
420}
421
514054a9 422static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
22bbb6f0 423 "-bounces", "-confirm", "-join",
424 "-leave", "-subscribe",
425 "-unsubscribe", NULL };
496bdfea 426
22bbb6f0 427void output_mlist(int id, struct list *l)
bac4ceaa 428{
22bbb6f0 429 struct list *l1;
430 struct member *m;
496bdfea 431 struct user *u;
22bbb6f0 432 int line_width, alias_width, word_width, beginning;
433 static int cont = 1;
434 char str[8];
435 int i;
5eaef520 436
496bdfea 437 put_fill(out, l->description);
5eaef520 438
dd746314 439 if (l->mailman && strcmp(l->mailman_server, "[NONE]"))
440 {
514054a9 441 for (i = 0; mailman_suffixes[i]; i++)
442 fprintf(out, "%s%s: %s%s@%s\n", l->name, mailman_suffixes[i], l->name,
443 mailman_suffixes[i], l->mailman_server);
22bbb6f0 444 fprintf(out, "owner-%s: %s-owner@%s\n%s: ", l->name, l->name,
445 l->mailman_server, l->name);
dd746314 446 }
e4a6dc65 447 else if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
22bbb6f0 448 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
496bdfea 449 else if (l->acl_t == 'U' && (u = hash_lookup(users, l->acl_id)))
22bbb6f0 450 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
451 else
452 fprintf(out, "%s: ", l->name);
5eaef520 453
22bbb6f0 454 alias_width = line_width = strlen(l->name) + 2;
455 beginning = 1;
5eaef520 456 for (m = l->m; m; m = m->next)
b033c6ed 457 {
458 word_width = strlen(m->name);
459
22bbb6f0 460 if (!beginning && alias_width + word_width + 2 > MAX_ALIAS_WIDTH)
b033c6ed 461 {
462 /* Make a continuation. */
463 sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
464 rand() % 26 + 97, rand() % 26 + 97,
465 rand() % 26 + 97, rand() % 26 + 97);
466 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
467 cont++;
468 alias_width = line_width = 17 + word_width;
22bbb6f0 469 fputs(m->name, out);
b033c6ed 470 }
22bbb6f0 471 else if (beginning)
b033c6ed 472 {
22bbb6f0 473 /* Beginning of alias, so don't wrap. */
b033c6ed 474 line_width += word_width;
475 alias_width = line_width;
22bbb6f0 476 fputs(m->name, out);
477 beginning = 0;
b033c6ed 478 }
479 else if (line_width + word_width + 2 > MAX_LINE_WIDTH)
480 {
481 /* Wrap. */
22bbb6f0 482 fprintf(out, ",\n\t%s", m->name);
b033c6ed 483 alias_width += line_width + word_width + 2;
484 line_width = word_width + 8;
485 }
486 else
487 {
488 /* Continue line. */
489 line_width += word_width + 2;
22bbb6f0 490 fprintf(out, ", %s", m->name);
b033c6ed 491 }
492 }
5eaef520 493 if (!l->m)
494 fprintf(out, "/dev/null");
22bbb6f0 495 fprintf(out, "\n\n");
496 incount++;
bac4ceaa 497}
498
b033c6ed 499/* Write a word-wrapped list description to the aliases file as a
500 * comment. */
7ac48069 501void put_fill(FILE *aliases, char *string)
492f333e 502{
44d12d58 503 char *c;
b033c6ed 504 int line_width;
505 int word_width;
492f333e 506
5eaef520 507 if (!string || !*string)
508 return;
509 fputs("# ", aliases);
b033c6ed 510 line_width = 3;
5eaef520 511
512 while (1)
513 {
514 while (*string == ' ')
515 string++;
516 c = strchr(string, ' ');
517 if (!c)
b033c6ed 518 word_width = strlen(string);
5eaef520 519 else
520 {
b033c6ed 521 word_width = c - string;
5eaef520 522 *c = '\0';
492f333e 523 }
524
b033c6ed 525 if (line_width + word_width > MAX_LINE_WIDTH)
5eaef520 526 {
527 fputs("\n# ", aliases);
b033c6ed 528 line_width = 3;
5eaef520 529 fputs(string, aliases);
530 }
531 else
532 fputs(string, aliases);
533
534 if (!c)
535 break;
536 /* add a space after the word */
537 fputc(' ', aliases);
b033c6ed 538 word_width++;
539 line_width += word_width;
540 string += word_width;
5eaef520 541 /* add another if after a period */
542 if (*--c == '.')
543 {
544 fputc(' ', aliases);
b033c6ed 545 line_width++;
492f333e 546 }
547 }
548
5eaef520 549 fputc('\n', aliases);
492f333e 550}
551
552
22bbb6f0 553/* Illegal chars: this no longer corresponds to the array
ad392f80 554 * in setup_alis. '+' is a valid character in a string on
555 * a list, but is not a valid character in a listname.
556 */
1c9c2ec8 557
558static int illegalchars[] = {
559 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
560 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
561 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
562 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
563 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
564 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
565 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
566 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
567 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
568 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
569 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
570 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
571 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
572 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
573 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
574 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
575};
576
577int check_string(char *s)
bac4ceaa 578{
1c9c2ec8 579 for (; *s; s++)
580 {
581 if (isupper(*s))
582 *s = tolower(*s);
583
584 if (illegalchars[(unsigned) *s])
585 return 0;
586 }
587 return 1;
bac4ceaa 588}
This page took 0.400655 seconds and 5 git commands to generate.