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