]> andersk Git - moira.git/blame - gen/mailhub.pc
Use moira_schema.h
[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
31#define ML_WID 72
9e1513ae 32#define AL_MAX_WID 592
bac4ceaa 33
34#define FALSE 0
35#define TRUE (!FALSE)
36
5eaef520 37FILE *out = stdout;
bac4ceaa 38
7ac48069 39struct hash *users, *machines, *strings, *lists, *names;
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;
55 struct member *m;
56};
57struct names {
58 char *name;
59 struct names *next;
60 int keep;
61 int id;
62};
63
64void get_info(void);
65void save_mlist(int id, void *list, void *force);
66void insert_login(int id, void *user, void *hint);
7ac48069 67void insert_name(char *s, int id, int nodups, int copy);
68int hashstr(char *s);
69void sort_info(void);
70void output_data(int dummy, void *names, void *out);
71void output_mlist(int id, struct list *l);
72void do_member(FILE *out, char *s);
73void put_fill(FILE *aliases, char *string);
74void do_people(void);
75
5eaef520 76int main(int argc, char **argv)
bac4ceaa 77{
5eaef520 78 long tm = time(NULL);
dfaf9b68 79 char filename[MAXPATHLEN], *targetfile;
5eaef520 80 struct stat sb;
81 EXEC SQL BEGIN DECLARE SECTION;
82 int flag;
83 EXEC SQL END DECLARE SECTION;
84
85 EXEC SQL CONNECT :db;
86
87 if (argc == 2)
88 {
89 if (stat(argv[1], &sb) == 0)
90 {
91 if (ModDiff (&flag, "users", sb.st_mtime))
92 exit(MR_DATE);
93 if (flag < 0)
94 {
95 fprintf(stderr, "File %s does not need to be rebuilt.\n",
96 argv[1]);
97 exit(MR_NO_CHANGE);
bac4ceaa 98 }
99 }
5eaef520 100 targetfile = argv[1];
101 sprintf(filename, "%s~", targetfile);
102 if (!(out = fopen(filename, "w")))
103 {
104 fprintf(stderr, "unable to open %s for output\n", filename);
105 exit(MR_OCONFIG);
bac4ceaa 106 }
5eaef520 107 }
108 else if (argc != 1)
109 {
110 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
111 exit(MR_ARGS);
bac4ceaa 112 }
113
5eaef520 114 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
115 fprintf(out, "# This file is automatically generated, "
116 "do not edit it directly.\n%s\n\n", divide);
bac4ceaa 117
5eaef520 118 get_info();
bac4ceaa 119
5eaef520 120 EXEC SQL COMMIT;
bac4ceaa 121
5eaef520 122 fprintf(stderr, "Sorting Info\n");
123 sort_info();
bac4ceaa 124
5eaef520 125 fprintf(stderr, "Dumping information\n");
126 do_people();
bac4ceaa 127
5eaef520 128 fprintf(out, "\n%s\n# End of aliases file\n", divide);
bac4ceaa 129
5eaef520 130 if (fclose(out))
131 {
132 perror("close failed");
133 exit(MR_CCONFIG);
bac4ceaa 134 }
135
5eaef520 136 if (argc == 2)
137 fix_file(targetfile);
138 exit(MR_SUCCESS);
bac4ceaa 139}
140
7ac48069 141void get_info(void)
bac4ceaa 142{
5eaef520 143 EXEC SQL BEGIN DECLARE SECTION;
144 int id, pid, bid, cnt, maillistp, acl, mid;
dfaf9b68 145 char mname[MACHINE_NAME_SIZE], str[STRINGS_STRING_SIZE];
146 char login[USERS_LOGIN_SIZE], potype[USERS_POTYPE_SIZE];
147 char lname[LIST_NAME_SIZE], desc[LIST_DESCRIPTION_SIZE];
148 char type[LIST_ACL_TYPE_SIZE];
5eaef520 149 EXEC SQL END DECLARE SECTION;
150 char *s;
44d12d58 151 struct user *u;
5eaef520 152 struct list *l, *memberlist;
44d12d58 153 struct member *m;
5eaef520 154
155 /* The following is declarative, not executed,
156 * and so is dependent on where it is in the file,
157 * not in the order of execution of statements.
158 */
159 EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
160
161 cnt = 0;
162 machines = create_hash(1000);
163
164 EXEC SQL DECLARE m_cursor CURSOR FOR
165 SELECT mach_id, name
166 FROM machine
167 WHERE status = 1
168 ORDER BY mach_id;
169 EXEC SQL OPEN m_cursor;
170 while (1)
171 {
dfaf9b68 172 EXEC SQL FETCH m_cursor INTO :id, :mname;
5eaef520 173 if (sqlca.sqlcode)
174 break;
dfaf9b68 175 if ((s = strchr(mname, '.')))
5eaef520 176 *s = '\0';
177 else
dfaf9b68 178 strtrim(mname);
bac4ceaa 179#ifdef ATHENA
dfaf9b68 180 strcat(mname, ".LOCAL");
bac4ceaa 181#endif
dfaf9b68 182 if (hash_store(machines, id, strdup(mname)) < 0)
5eaef520 183 {
184 fprintf(stderr, "Out of memory!\n");
185 exit(MR_NO_MEM);
bac4ceaa 186 }
5eaef520 187 cnt++;
bac4ceaa 188 }
5eaef520 189 EXEC SQL CLOSE m_cursor;
190
191 fprintf(stderr, "Loaded %d machines\n", cnt);
192
193 cnt = 0;
194 strings = create_hash(11001);
195
196 EXEC SQL DECLARE s_cursor CURSOR FOR
197 SELECT string_id, string
198 FROM strings
199 ORDER BY string_id;
200 EXEC SQL OPEN s_cursor;
201 while (1)
202 {
dfaf9b68 203 EXEC SQL FETCH s_cursor INTO :id, :str;
5eaef520 204 if (sqlca.sqlcode)
205 break;
dfaf9b68 206 if (hash_store(strings, id, strdup(strtrim(str))) < 0)
5eaef520 207 {
208 fprintf(stderr, "Out of memory!\n");
209 exit(MR_NO_MEM);
bac4ceaa 210 }
5eaef520 211 cnt++;
bac4ceaa 212 }
5eaef520 213 EXEC SQL CLOSE s_cursor;
214
215 fprintf(stderr, "Loaded %d strings\n", cnt);
216
217 cnt = 0;
218 users = create_hash(13001);
219
220 EXEC SQL DECLARE u_cursor CURSOR FOR
dfaf9b68 221 SELECT users_id, login, potype, pop_id, box_id
5eaef520 222 FROM users
223 WHERE status != 3
224 ORDER BY users_id;
225 EXEC SQL OPEN u_cursor;
226 while (1)
227 {
dfaf9b68 228 EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :bid;
5eaef520 229 if (sqlca.sqlcode)
230 break;
7ac48069 231 u = malloc(sizeof(struct user));
dfaf9b68 232 u->login = strdup(strtrim(login));
5eaef520 233
dfaf9b68 234 if (potype[0] == 'P' && (s = hash_lookup(machines, pid)))
5eaef520 235 {
dfaf9b68 236 char *buf = malloc(strlen(u->login) + strlen(s) + 2);
5eaef520 237 sprintf(buf, "%s@%s", u->login, s);
dfaf9b68 238 u->pobox = buf;
5eaef520 239 }
dfaf9b68 240 else if (potype[0] == 'S')
5eaef520 241 u->pobox = hash_lookup(strings, bid);
242 else
243 u->pobox = NULL;
244 if (hash_store(users, id, u) < 0)
245 {
246 fprintf(stderr, "Out of memory!\n");
247 exit(MR_NO_MEM);
bac4ceaa 248 }
5eaef520 249 cnt++;
bac4ceaa 250 }
5eaef520 251 EXEC SQL CLOSE u_cursor;
252 fprintf(stderr, "Loaded %d users\n", cnt);
253
254 cnt = 0;
255 lists = create_hash(15000);
256
257 EXEC SQL DECLARE l_cursor CURSOR FOR
258 SELECT list_id, name, maillist, description, acl_type, acl_id
259 FROM list
260 WHERE active != 0
261 ORDER BY list_id;
262 EXEC SQL OPEN l_cursor;
263 while (1)
264 {
dfaf9b68 265 EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl;
5eaef520 266 if (sqlca.sqlcode)
267 break;
7ac48069 268 l = malloc(sizeof(struct list));
dfaf9b68 269 l->name = strdup(strtrim(lname));
5eaef520 270 l->maillist = maillistp;
dfaf9b68 271 l->description = strdup(strtrim(desc));
5eaef520 272 l->acl_t = type[0];
273 l->acl_id = acl;
274 l->m = NULL;
275 if (hash_store(lists, id, l) < 0)
276 {
277 fprintf(stderr, "Out of memory!\n");
278 exit(MR_NO_MEM);
bac4ceaa 279 }
5eaef520 280 cnt++;
bac4ceaa 281 }
5eaef520 282 EXEC SQL CLOSE l_cursor;
283 fprintf(stderr, "Loaded %d lists\n", cnt);
284
285 cnt = 0;
286
287 EXEC SQL DECLARE m_cursor2 CURSOR FOR
288 SELECT list_id, member_type, member_id
289 FROM imembers
290 WHERE direct = 1
291 ORDER BY list_id;
292 EXEC SQL OPEN m_cursor2;
293 while (1)
294 {
295 EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
296 if (sqlca.sqlcode)
297 break;
298 cnt++;
7ac48069 299 if ((l = hash_lookup(lists, id)))
5eaef520 300 {
7ac48069 301 m = malloc(sizeof(struct member));
302 if (type[0] == 'U' && (u = hash_lookup(users, mid)))
5eaef520 303 {
304 m->list_id = 0;
305 m->name = u->login;
306 m->next = l->m;
307 l->m = m;
308 }
7ac48069 309 else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
5eaef520 310 {
311 m->list_id = mid;
312 m->name = memberlist->name;
313 m->next = l->m;
314 l->m = m;
315 }
316 else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
317 {
318 m->list_id = 0;
319 m->next = l->m;
320 l->m = m;
321 m->name = s;
bac4ceaa 322 }
323 }
324 }
5eaef520 325 EXEC SQL CLOSE m_cursor2;
326 fprintf(stderr, "Loaded %d members\n", cnt);
327
328 EXEC SQL COMMIT;
329 return;
330sqlerr:
331 db_error(sqlca.sqlcode);
332 exit(MR_DBMS_ERR);
bac4ceaa 333}
334
335
7ac48069 336void save_mlist(int id, void *list, void *force)
bac4ceaa 337{
44d12d58 338 struct member *m;
7ac48069 339 struct list *l = list, *l1;
bac4ceaa 340
5eaef520 341 if (l->maillist > 1 || (l->maillist == 0 && !force))
342 return;
bac4ceaa 343
5eaef520 344 if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
345 {
346 l->maillist = 3;
347 return;
bac4ceaa 348 }
5eaef520 349 l->maillist = 2;
350 insert_name(l->name, -1, TRUE, FALSE);
351 output_mlist(id, l);
352
7ac48069 353 if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
354 save_mlist(0, l1, (void *)TRUE);
5eaef520 355
356 for (m = l->m; m; m = m->next)
357 {
7ac48069 358 if (m->list_id && (l1 = hash_lookup(lists, m->list_id)))
359 save_mlist(0, l1, (void *)TRUE);
bac4ceaa 360 }
361}
362
363
7ac48069 364void insert_login(int id, void *user, void *hint)
bac4ceaa 365{
7ac48069 366 struct user *u = user;
5eaef520 367 if (u->pobox && u->login[0] != '#')
368 insert_name(u->login, id, TRUE, FALSE);
bac4ceaa 369}
370
bac4ceaa 371int incount = 0;
372
7ac48069 373void insert_name(char *s, int id, int nodups, int copy)
bac4ceaa 374{
5eaef520 375 int code;
44d12d58 376 struct names *ns;
5eaef520 377
378 incount++;
379 code = hashstr(s);
7ac48069 380 ns = hash_lookup(names, code);
5eaef520 381 if (!ns)
382 {
7ac48069 383 if (!(ns = malloc(sizeof(struct names))))
5eaef520 384 {
385 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
386 exit(MR_NO_MEM);
bac4ceaa 387 }
5eaef520 388 if (copy)
7ac48069 389 ns->name = strdup(s);
5eaef520 390 else
391 ns->name = s;
392 ns->keep = nodups;
393 ns->id = id;
394 ns->next = NULL;
395 if (hash_store(names, code, ns) < 0)
396 {
397 fprintf(stderr, "Out of memory!\n");
398 exit(MR_NO_MEM);
bac4ceaa 399 }
5eaef520 400 return;
bac4ceaa 401 }
5eaef520 402 if (strcasecmp(ns->name, s))
403 {
404 while (ns->next)
405 {
406 ns = ns->next;
407 if (!strcasecmp(ns->name, s))
408 goto foundns;
bac4ceaa 409 }
7ac48069 410 if (!(ns->next = malloc(sizeof(struct names))))
5eaef520 411 {
412 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
413 exit(MR_NO_MEM);
bac4ceaa 414 }
5eaef520 415 ns = ns->next;
416 if (copy)
7ac48069 417 ns->name = strdup(s);
5eaef520 418 else
419 ns->name = s;
420 ns->keep = nodups;
421 ns->id = id;
422 ns->next = NULL;
423 return;
bac4ceaa 424 }
5eaef520 425foundns:
426 if (nodups || ns->keep)
427 {
428 if (nodups && ns->keep)
429 fprintf(stderr, "duplicated name: %s\n", s);
430 return;
bac4ceaa 431 }
5eaef520 432 ns->id = 0;
bac4ceaa 433}
434
435
3ce369ab 436/* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
bac4ceaa 437
438static int illegalchars[] = {
5eaef520 439 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
440 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
441 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
443 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
444 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
445 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
446 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
447 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
448 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
449 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
450 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
451 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
452 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
453 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
454 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
bac4ceaa 455};
456
457
458/* While hashing the string, punt any illegal characters */
459
44d12d58 460int hashstr(char *s)
bac4ceaa 461{
44d12d58 462 int result;
463 int c;
5eaef520 464
7ac48069 465 for (result = 0; (c = *s); s++)
5eaef520 466 {
467 if (illegalchars[c])
468 {
44d12d58 469 char *p;
5eaef520 470 for (p = s; *p; p++)
471 *p = p[1];
472 continue;
bac4ceaa 473 }
5eaef520 474 if (isupper(c))
475 c = *s = tolower(c);
476 result = (result << 5) - result + c - '`';
bac4ceaa 477 }
5eaef520 478 return result < 0 ? -result : result;
bac4ceaa 479}
480
481
7ac48069 482void sort_info(void)
bac4ceaa 483{
5eaef520 484 names = create_hash(20001);
485 hash_step(users, insert_login, NULL);
486 incount = 0;
487 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
488 hash_step(lists, save_mlist, FALSE);
489 fprintf(stderr, "Output %d lists\n", incount);
bac4ceaa 490}
491
492
7ac48069 493void output_data(int dummy, void *names, void *out)
bac4ceaa 494{
7ac48069 495 struct names *ns, *nms = names;
44d12d58 496 struct user *u;
5eaef520 497
498 incount++;
499 for (ns = nms; ns; ns = ns->next)
500 {
501 if (!ns->name[0] || !ns->name[1])
502 {
503 fprintf(stderr, "punting %s due to short name\n", ns->name);
504 continue;
bac4ceaa 505 }
5eaef520 506 if (ns->id > 0)
507 {
7ac48069 508 u = hash_lookup(users, ns->id);
5eaef520 509 if (u->pobox)
510 fprintf(out, "%s: %s\n", ns->name, u->pobox);
bac4ceaa 511 }
512 }
513}
514
515
516int lwid, bol, awid;
517
7ac48069 518void output_mlist(int id, struct list *l)
bac4ceaa 519{
5eaef520 520 struct list *l1;
44d12d58 521 struct member *m;
522 struct user *u;
5eaef520 523
524 put_fill(out, l->description);
7ac48069 525 if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
5eaef520 526 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
7ac48069 527 else if (l->acl_t == 'U' && (u = hash_lookup(users, l->acl_id)))
5eaef520 528 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
529 else
530 fprintf(out, "%s: ", l->name);
531
532 lwid = strlen(l->name) + 2;
533 bol = 1;
534 for (m = l->m; m; m = m->next)
535 do_member(out, m->name);
536 if (!l->m)
537 fprintf(out, "/dev/null");
538 fprintf(out, "\n\n");
539 incount++;
bac4ceaa 540}
541
542
543/* print out strings separated by commas, doing line breaks as appropriate */
544
7ac48069 545void do_member(FILE *out, char *s)
bac4ceaa 546{
7ac48069 547 int wwid;
5eaef520 548 static int cont = 1;
549 char str[8];
550
551 wwid = strlen(s);
552
553 if (!bol && awid + wwid + 2 > AL_MAX_WID)
554 {
555 sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
556 rand() % 26 + 97, rand() % 26 + 97,
557 rand() % 26 + 97, rand() % 26 + 97);
558 str[6] = '\0';
559 fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
560 cont++;
561 awid = lwid = 17 + wwid;
562 fputs(s, out);
563 return;
bac4ceaa 564 }
565
5eaef520 566 if (bol)
567 {
568 lwid += wwid;
569 awid = lwid;
570 fputs(s, out);
571 bol = 0;
572 return;
bac4ceaa 573 }
5eaef520 574 if (lwid + wwid + 2 > ML_WID)
575 {
576 fprintf(out, ",\n\t%s", s);
577 awid += lwid + wwid + 2;
578 lwid = wwid + 8;
579 return;
bac4ceaa 580 }
5eaef520 581 lwid += wwid + 2;
582 fprintf(out, ", %s", s);
bac4ceaa 583}
584
585
7ac48069 586void put_fill(FILE *aliases, char *string)
492f333e 587{
44d12d58 588 char *c;
589 int lwid;
590 int wwid;
492f333e 591
5eaef520 592 if (!string || !*string)
593 return;
594 fputs("# ", aliases);
595 lwid = 3;
596
597 while (1)
598 {
599 while (*string == ' ')
600 string++;
601 c = strchr(string, ' ');
602 if (!c)
603 wwid = strlen(string);
604 else
605 {
606 wwid = c - string;
607 *c = '\0';
492f333e 608 }
609
5eaef520 610 if ((lwid + wwid) > ML_WID)
611 {
612 fputs("\n# ", aliases);
613 lwid = 3;
614 fputs(string, aliases);
615 }
616 else
617 fputs(string, aliases);
618
619 if (!c)
620 break;
621 /* add a space after the word */
622 fputc(' ', aliases);
623 wwid++;
624 lwid += wwid;
625 string += wwid;
626 /* add another if after a period */
627 if (*--c == '.')
628 {
629 fputc(' ', aliases);
630 lwid++;
492f333e 631 }
632 }
633
5eaef520 634 fputc('\n', aliases);
492f333e 635}
636
637
7ac48069 638void do_people(void)
bac4ceaa 639{
5eaef520 640 incount = 0;
641 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
642 hash_step(names, output_data, out);
643 fprintf(stderr, "Output %d entries\n", incount);
bac4ceaa 644}
This page took 0.743217 seconds and 5 git commands to generate.