]> andersk Git - moira.git/blob - gen/mailhub.qc
Used /bin/sh format instead of /bin/csh format, by accident.
[moira.git] / gen / mailhub.qc
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
22 extern int errno;
23 char *whoami = "mailhub.gen";
24 char *ingres_date_and_time();
25 char *perm_malloc();
26 char *pstrsave();
27 char *divide = "##############################################################";
28
29 #define ML_WID  72
30 #define AL_MAX_WID 896
31
32 #define FALSE 0
33 #define TRUE (!FALSE)
34
35 FILE *out= stdout;
36
37
38 main(argc, argv)
39 int argc;
40 char **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
109 static 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
127 struct hash *users, *machines, *strings, *lists, *names;
128 struct user {
129     char *login;
130     char *first;
131     char *last;
132     char mi;
133     char *pobox;
134 };
135 struct member {
136     struct member *next;
137     char *name;
138     int list_id;
139 };
140 struct list {
141     char *name;
142     char maillist;
143     char acl_t;
144     int acl_id;
145     struct member *m;
146 };
147 struct names {
148     char *name;
149     struct names *next;
150     int keep:1;
151     int id:31;
152 };
153
154
155 get_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
281 save_mlist(id, l, force)
282 int id;
283 struct list *l;
284 int 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
312 insert_login(id, u, dummy)
313 int id;
314 struct user *u;
315 int dummy;
316 {
317     if (u->pobox && u->login[0] != '#')
318       insert_name(u->login, id, TRUE, FALSE);
319 }
320
321 void insert_names(id, u, dummy)
322 int id;
323 struct user *u;
324 int 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
339 int incount = 0;
340
341 insert_name(s, id, nodups, copy)
342 char *s;
343 int id;
344 int nodups;
345 int 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
406 static 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
428 int hashstr(s)
429 register 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
450 sort_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
463 output_data(dummy, nms, out)
464 int dummy;
465 struct names *nms;
466 FILE *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
491 int lwid, bol, awid;
492
493 output_mlist(id, l)
494 int id;
495 register 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
525 do_member(out, s)
526 FILE *out;
527 register 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
560 do_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
571 char *perm_malloc(size)
572 unsigned 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  */
593 char *
594 pstrsave(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
616 struct hash *create_hash(size)
617 int 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
638 char *hash_lookup(h, key)
639 struct hash *h;
640 register 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
658 int hash_update(h, key, value)
659 struct hash *h;
660 register int key;
661 char *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
680 int hash_store(h, key, value)
681 struct hash *h;
682 register int key;
683 char *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
718 hash_search(h, value, callback)
719 struct hash *h;
720 register char *value;
721 void (*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
737 hash_step(h, callback, hint)
738 struct hash *h;
739 void (*callback)();
740 char *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
754 hash_destroy(h)
755 struct 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.185269 seconds and 5 git commands to generate.