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