]> andersk Git - moira.git/blame_incremental - gen/mailhub.qc
Used /bin/sh format instead of /bin/csh format, by accident.
[moira.git] / gen / mailhub.qc
... / ...
CommitLineData
1
2/* $Header$
3 *
4 * This generates the /usr/lib/aliases file for the mailhub.
5 *
6 * (c) Copyright 1988 by the Massachusetts Institute of Technology.
7 * For copying and distribution information, please see the file
8 * <mit-copyright.h>.
9 */
10
11#include <mit-copyright.h>
12#include <stdio.h>
13#include <string.h>
14#include <ctype.h>
15#include <moira.h>
16#include <moira_site.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/time.h>
20
21
22extern int errno;
23char *whoami = "mailhub.gen";
24char *ingres_date_and_time();
25char *perm_malloc();
26char *pstrsave();
27char *divide = "##############################################################";
28
29#define ML_WID 72
30#define AL_MAX_WID 896
31
32#define FALSE 0
33#define TRUE (!FALSE)
34
35FILE *out= stdout;
36
37
38main(argc, argv)
39int argc;
40char **argv;
41{
42 long tm = time(NULL);
43 char filename[64], *targetfile;
44 struct stat sb;
45## int flag;
46## char *filetime;
47 int ingerr();
48
49 IIseterr(ingerr);
50## ingres sms
51## set lockmode session where level = table
52
53 if (argc == 2) {
54 if (stat(argv[1], &sb) == 0) {
55 filetime = ingres_date_and_time(sb.st_mtime);
56## retrieve (flag = int4(interval("min",tblstats.modtime - filetime)))
57## where tblstats.table = "users"
58 if (flag < 0) {
59 fprintf(stderr, "File %s does not need to be rebuilt.\n",
60 argv[1]);
61 exit(MR_NO_CHANGE);
62 }
63 }
64 targetfile = argv[1];
65 sprintf(filename, "%s~", targetfile);
66 if ((out = fopen(filename, "w")) == NULL) {
67 fprintf(stderr, "unable to open %s for output\n", filename);
68 exit(MR_OCONFIG);
69 }
70 } else if (argc != 1) {
71 fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
72 exit(MR_ARGS);
73 }
74
75 fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
76 fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide);
77
78## begin transaction
79 get_info();
80## end transaction
81## exit
82
83 fprintf(stderr, "Sorting Info\n");
84 sort_info();
85
86 fprintf(stderr, "Dumping information\n");
87 do_people();
88
89 fprintf(out, "\n%s\n# End of aliases file\n", divide);
90
91 if (fclose(out)) {
92 perror("close failed");
93 exit(MR_CCONFIG);
94 }
95
96 if (argc == 2)
97 fix_file(targetfile);
98 exit(MR_SUCCESS);
99}
100
101
102/*
103 * ingerr: (supposedly) called when Ingres indicates an error.
104 * I have not yet been able to get this to work to intercept a
105 * database open error.
106 */
107#define INGRES_DEADLOCK 4700
108
109static int ingerr(num)
110 int *num;
111{
112 char buf[256];
113 int ingres_errno;
114
115 switch (*num) {
116 case INGRES_DEADLOCK:
117 ingres_errno = MR_DEADLOCK;
118 break;
119 default:
120 ingres_errno = MR_INGRES_ERR;
121 }
122 com_err(whoami, MR_INGRES_ERR, " code %d\n", *num);
123 critical_alert("DCM", "Alias build encountered INGRES ERROR %d", *num);
124 exit(ingres_errno);
125}
126
127struct hash *users, *machines, *strings, *lists, *names;
128struct user {
129 char *login;
130 char *first;
131 char *last;
132 char mi;
133 char *pobox;
134};
135struct member {
136 struct member *next;
137 char *name;
138 int list_id;
139};
140struct list {
141 char *name;
142 char maillist;
143 char acl_t;
144 int acl_id;
145 struct member *m;
146};
147struct names {
148 char *name;
149 struct names *next;
150 int keep:1;
151 int id:31;
152};
153
154
155get_info()
156##{
157## int id, pid, bid, stat, cnt, maillistp, acl, mid;
158## char name[129], type[9], fname[17], mname[17], lname[17], buf[257];
159 char *s;
160 register struct user *u;
161 struct list *l, *memberlist;
162 register struct member *m;
163
164 /* get locks */
165## retrieve (buf = users.modtime) where users.users_id = 0
166## retrieve (buf = list.modtime) where list.list_id = 0
167
168 cnt = 0;
169 machines = create_hash(10);
170## retrieve (id = machine.mach_id, name = machine.#name)
171## where machine.mach_id = users.pop_id {
172 if (s = index(name, '.'))
173 *s = 0;
174 else
175 strtrim(name);
176#ifdef ATHENA
177 strcat(name, ".LOCAL");
178#endif
179 if (hash_store(machines, id, pstrsave(name)) < 0) {
180 fprintf(stderr, "Out of memory!\n");
181 exit(MR_NO_MEM);
182 }
183 cnt++;
184## }
185 fprintf(stderr, "Loaded %d machines\n", cnt);
186
187 cnt = 0;
188 strings = create_hash(4000);
189## retrieve (id = strings.string_id, name = strings.string) {
190 if (hash_store(strings, id, pstrsave(strtrim(name))) < 0) {
191 fprintf(stderr, "Out of memory!\n");
192 exit(MR_NO_MEM);
193 }
194 cnt++;
195## }
196 fprintf(stderr, "Loaded %d strings\n", cnt);
197
198 cnt = 0;
199 users = create_hash(12001);
200## range of u is users
201## retrieve (id = u.users_id, name = u.login, fname = u.first,
202## mname = u.middle, lname = u.last,
203## type = u.potype, pid = u.pop_id, bid = u.box_id)
204## where u.status != 3 {
205 u = (struct user *) perm_malloc(sizeof(struct user));
206 u->login = pstrsave(strtrim(name));
207 u->first = pstrsave(strtrim(fname));
208 u->last = pstrsave(strtrim(lname));
209 if (mname[0] != ' ')
210 u->mi = mname[0];
211 else
212 u->mi = 0;
213
214 if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
215 sprintf(buf, "%s@%s", u->login, s);
216 u->pobox = pstrsave(buf);
217 } else if (type[0] == 'S') {
218 u->pobox = hash_lookup(strings, bid);
219 } else
220 u->pobox = (char *) NULL;
221 if (hash_store(users, id, u) < 0) {
222 fprintf(stderr, "Out of memory!\n");
223 exit(MR_NO_MEM);
224 }
225 cnt++;
226## }
227 fprintf(stderr, "Loaded %d users\n", cnt);
228
229 cnt = 0;
230 lists = create_hash(15000);
231## range of l is list
232## retrieve (id = l.list_id, name = l.#name, maillistp = l.maillist,
233## type = l.acl_type, acl = l.acl_id)
234## where l.active != 0 {
235 l = (struct list *) perm_malloc(sizeof(struct list));
236 l->name = pstrsave(strtrim(name));
237 l->maillist = maillistp;
238 l->acl_t = type[0];
239 l->acl_id = acl;
240 l->m = (struct member *) NULL;
241 if (hash_store(lists, id, l) < 0) {
242 fprintf(stderr, "Out of memory!\n");
243 exit(MR_NO_MEM);
244 }
245 cnt++;
246## }
247 fprintf(stderr, "Loaded %d lists\n", cnt);
248
249 cnt = 0;
250## range of m is imembers
251## retrieve (id = m.list_id, type = m.member_type, mid = m.member_id)
252## where m.direct = 1 {
253 cnt++;
254 if (l = (struct list *) hash_lookup(lists, id)) {
255 m = (struct member *) perm_malloc(sizeof(struct member));
256 if (type[0] == 'U' &&
257 (u = (struct user *) hash_lookup(users, mid))) {
258 m->list_id = 0;
259 m->name = u->login;
260 m->next = l->m;
261 l->m = m;
262 } else if (type[0] == 'L' &&
263 (memberlist = (struct list *) hash_lookup(lists, mid))) {
264 m->list_id = mid;
265 m->name = memberlist->name;
266 m->next = l->m;
267 l->m = m;
268 } else if (type[0] == 'S' &&
269 (s = hash_lookup(strings, mid))) {
270 m->list_id = 0;
271 m->next = l->m;
272 l->m = m;
273 m->name = s;
274 }
275 }
276## }
277 fprintf(stderr, "Loaded %d members\n", cnt);
278##}
279
280
281save_mlist(id, l, force)
282int id;
283struct list *l;
284int force;
285{
286 register struct member *m;
287 register struct list *l1;
288
289 if (l->maillist > 1 ||
290 (l->maillist == 0 && !force))
291 return;
292
293 if (l->m && l->m->next == NULL &&
294 !strcasecmp(l->name, l->m->name)) {
295 l->maillist = 3;
296 return;
297 }
298 l->maillist = 2;
299 insert_name(l->name, -1, TRUE, FALSE);
300 output_mlist(id, l);
301
302 if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
303 save_mlist(0, l1, TRUE);
304
305 for (m = l->m; m; m = m->next) {
306 if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
307 save_mlist(0, l1, TRUE);
308 }
309}
310
311
312insert_login(id, u, dummy)
313int id;
314struct user *u;
315int dummy;
316{
317 if (u->pobox && u->login[0] != '#')
318 insert_name(u->login, id, TRUE, FALSE);
319}
320
321void insert_names(id, u, dummy)
322int id;
323struct user *u;
324int dummy;
325{
326 char buffer[256];
327
328 insert_name(u->last, id, FALSE, FALSE);
329 sprintf(buffer, "%s_%s", u->first, u->last);
330 insert_name(buffer, id, FALSE, TRUE);
331/* sprintf(buffer, "%c_%s", u->first[0], u->last);
332 insert_name(buffer, id, FALSE, TRUE); */
333 if (u->mi) {
334 sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
335 insert_name(buffer, id, FALSE, TRUE);
336 }
337}
338
339int incount = 0;
340
341insert_name(s, id, nodups, copy)
342char *s;
343int id;
344int nodups;
345int copy;
346{
347 int code;
348 register struct names *ns;
349 register int count;
350 register struct idblock *ra;
351
352 incount++;
353 code = hashstr(s);
354 ns = (struct names *) hash_lookup(names, code);
355 if (ns == NULL) {
356 if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
357 fprintf(stderr, "ran out of memory inserting name (sorting)\n");
358 exit(MR_NO_MEM);
359 }
360 if (copy)
361 ns->name = pstrsave(s);
362 else
363 ns->name = s;
364 ns->keep = nodups;
365 ns->id = id;
366 ns->next = NULL;
367 if (hash_store(names, code, ns) < 0) {
368 fprintf(stderr, "Out of memory!\n");
369 exit(MR_NO_MEM);
370 }
371 return;
372 }
373 if (strcasecmp(ns->name, s)) {
374 while (ns->next) {
375 ns = ns->next;
376 if (!strcasecmp(ns->name, s))
377 goto foundns;
378 }
379 if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
380 == NULL) {
381 fprintf(stderr, "ran out of memory insterting name (sorting)\n");
382 exit(MR_NO_MEM);
383 }
384 ns = ns->next;
385 if (copy)
386 ns->name = pstrsave(s);
387 else
388 ns->name = s;
389 ns->keep = nodups;
390 ns->id = id;
391 ns->next = NULL;
392 return;
393 }
394 foundns:
395 if (nodups || ns->keep) {
396 if (nodups && ns->keep)
397 fprintf(stderr, "duplicated named: %s\n", s);
398 return;
399 }
400 ns->id = 0;
401}
402
403
404/* Illegal chars: ! " % ( ) , . / : ; < = > @ [ \ ] ^ { | } */
405
406static int illegalchars[] = {
407 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
408 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
409 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, /* SPACE - / */
410 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
411 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
412 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
415 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
419 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
420 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
421 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
422 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
423};
424
425
426/* While hashing the string, punt any illegal characters */
427
428int hashstr(s)
429register char *s;
430{
431 register int result;
432 register int c;
433
434 for (result = 0; c = *s; s++) {
435 if (illegalchars[c]) {
436 register char *p;
437 for (p = s; *p; p++)
438 *p = p[1];
439 continue;
440 }
441 if (isupper(c))
442 c = *s = tolower(c);
443/* result = result * 31 + *s; */
444 result = (result << 5) - result + c - '`';
445 }
446 return(result < 0 ? -result : result);
447}
448
449
450sort_info()
451{
452 names = create_hash(20001);
453 hash_step(users, insert_login, NULL);
454 incount = 0;
455 fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
456 hash_step(lists, save_mlist, FALSE);
457 fprintf(stderr, "Output %d lists\n", incount);
458 hash_step(users, insert_names, NULL);
459 fprintf(stderr, "Inserted %d names\n", incount);
460}
461
462
463output_data(dummy, nms, out)
464int dummy;
465struct names *nms;
466FILE *out;
467{
468 register struct names *ns;
469 register struct user *u;
470
471 incount++;
472 for (ns = nms; ns; ns = ns->next) {
473 if (ns->name[0] == 0 || ns->name[1] == 0) {
474 fprintf(stderr, "punting %s due to short name\n", ns->name);
475 continue;
476 }
477 if (ns->id > 0) {
478 u = (struct user *) hash_lookup(users, ns->id);
479 if (u->pobox) {
480 fprintf(out, "%s: %s\n", ns->name, u->pobox);
481 } else {
482 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
483 }
484 } else if (ns->id == 0) {
485 fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
486 }
487 }
488}
489
490
491int lwid, bol, awid;
492
493output_mlist(id, l)
494int id;
495register struct list *l;
496{
497 struct list *l1;
498 register struct member *m;
499 register struct user *u;
500
501 if (l->acl_t == 'L' &&
502 (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
503 fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
504 else if (l->acl_t == 'U' &&
505 (u = (struct user *) hash_lookup(users, l->acl_id)))
506 fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
507 else
508 fprintf(out, "%s: ", l->name);
509
510
511 lwid = strlen(l->name) + 2;
512 bol = 1;
513 for (m = l->m; m; m = m->next) {
514 do_member(out, m->name);
515 }
516 if (l->m == (struct member *)NULL)
517 fprintf(out, "/dev/null");
518 fprintf(out, "\n\n");
519 incount++;
520}
521
522
523/* print out strings separated by commas, doing line breaks as appropriate */
524
525do_member(out, s)
526FILE *out;
527register char *s;
528{
529 register wwid;
530 static int cont = 1;
531
532 wwid = strlen(s);
533
534 if (!bol && awid + wwid + 2 > AL_MAX_WID) {
535 fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
536 cont++;
537 awid = lwid = 17 + wwid;
538 fputs(s, out);
539 return;
540 }
541
542 if (bol) {
543 lwid += wwid;
544 awid = lwid;
545 fputs(s, out);
546 bol = 0;
547 return;
548 }
549 if (lwid + wwid + 2 > ML_WID) {
550 fprintf(out, ",\n\t%s", s);
551 awid += lwid + wwid + 2;
552 lwid = wwid + 8;
553 return;
554 }
555 lwid += wwid + 2;
556 fprintf(out, ", %s", s);
557}
558
559
560do_people()
561{
562 incount = 0;
563 fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
564 hash_step(names, output_data, out);
565 fprintf(stderr, "Output %d entries\n", incount);
566}
567
568
569#define chunk_size 102400
570
571char *perm_malloc(size)
572unsigned size;
573{
574 static char *pool = NULL;
575 static unsigned pool_size = 0;
576 register char *ret;
577
578 if (size > pool_size) {
579 pool = (char *) malloc(chunk_size);
580 pool_size = chunk_size;
581 }
582 ret = pool;
583 pool += size;
584 pool = (char *)(((unsigned) (pool + 1)) & ~1);
585 pool_size -= (pool - ret);
586 return(ret);
587}
588
589
590/*
591 * Make a (permenant) copy of a string.
592 */
593char *
594pstrsave(s)
595 char *s;
596{
597 register int len;
598 register char *p;
599 /* Kludge for sloppy string semantics */
600 if (!s) {
601 printf("NULL != \"\" !!!!\r\n");
602 p = perm_malloc(1);
603 *p = '\0';
604 return p;
605 }
606 len = strlen(s) + 1;
607 p = perm_malloc((u_int)len);
608 if (p) bcopy(s, p, len);
609 return p;
610}
611
612#define hash_func(h, key) (key >= 0 ? (key % h->size) : (-key % h->size))
613
614/* Create a hash table. The size is just a hint, not a maximum. */
615
616struct hash *create_hash(size)
617int size;
618{
619 struct hash *h;
620
621 h = (struct hash *) perm_malloc(sizeof(struct hash));
622 if (h == (struct hash *) NULL)
623 return((struct hash *) NULL);
624 h->size = size;
625 h->data = (struct bucket **) perm_malloc(size * sizeof(char *));
626 if (h->data == (struct bucket **) NULL) {
627 free(h);
628 return((struct hash *) NULL);
629 }
630 bzero(h->data, size * sizeof(char *));
631 return(h);
632}
633
634/* Lookup an object in the hash table. Returns the value associated with
635 * the key, or NULL (thus NULL is not a very good value to store...)
636 */
637
638char *hash_lookup(h, key)
639struct hash *h;
640register int key;
641{
642 register struct bucket *b;
643
644 b = h->data[hash_func(h, key)];
645 while (b && b->key != key)
646 b = b->next;
647 if (b && b->key == key)
648 return(b->data);
649 else
650 return(NULL);
651}
652
653
654/* Update an existing object in the hash table. Returns 1 if the object
655 * existed, or 0 if not.
656 */
657
658int hash_update(h, key, value)
659struct hash *h;
660register int key;
661char *value;
662{
663 register struct bucket *b;
664
665 b = h->data[hash_func(h, key)];
666 while (b && b->key != key)
667 b = b->next;
668 if (b && b->key == key) {
669 b->data = value;
670 return(1);
671 } else
672 return(0);
673}
674
675
676/* Store an item in the hash table. Returns 0 if the key was not previously
677 * there, 1 if it was, or -1 if we ran out of memory.
678 */
679
680int hash_store(h, key, value)
681struct hash *h;
682register int key;
683char *value;
684{
685 register struct bucket *b, **p;
686
687 p = &(h->data[hash_func(h, key)]);
688 if (*p == NULL) {
689 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
690 if (b == (struct bucket *) NULL)
691 return(-1);
692 b->next = NULL;
693 b->key = key;
694 b->data = value;
695 return(0);
696 }
697
698 for (b = *p; b && b->key != key; b = *p)
699 p = (struct bucket **) *p;
700 if (b && b->key == key) {
701 b->data = value;
702 return(1);
703 }
704 b = *p = (struct bucket *) perm_malloc(sizeof(struct bucket));
705 if (b == (struct bucket *) NULL)
706 return(-1);
707 b->next = NULL;
708 b->key = key;
709 b->data = value;
710 return(0);
711}
712
713
714/* Search through the hash table for a given value. For each piece of
715 * data with that value, call the callback proc with the corresponding key.
716 */
717
718hash_search(h, value, callback)
719struct hash *h;
720register char *value;
721void (*callback)();
722{
723 register struct bucket *b, **p;
724
725 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
726 for (b = *p; b; b = b->next) {
727 if (b->data == value)
728 (*callback)(b->key);
729 }
730 }
731}
732
733
734/* Step through the hash table, calling the callback proc with each key.
735 */
736
737hash_step(h, callback, hint)
738struct hash *h;
739void (*callback)();
740char *hint;
741{
742 register struct bucket *b, **p;
743
744 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
745 for (b = *p; b; b = b->next) {
746 (*callback)(b->key, b->data, hint);
747 }
748 }
749}
750
751
752/* Deallocate all of the memory associated with a table */
753
754hash_destroy(h)
755struct hash *h;
756{
757 register struct bucket *b, **p, *b1;
758
759 for (p = &(h->data[h->size - 1]); p >= h->data; p--) {
760 for (b = *p; b; b = b1) {
761 b1 = b->next;
762 free(b);
763 }
764 }
765}
This page took 0.050286 seconds and 5 git commands to generate.