]> andersk Git - moira.git/blob - gen/mailhub.qc
use private version of strsave that calls perm_malloc();
[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
36 main(argc, argv)
37 int argc;
38 char **argv;
39 {
40     long tm = time(NULL);
41     FILE *out= stdout;
42     char filename[64], *targetfile;
43     struct stat sb;
44 ##  int flag;
45 ##  char *filetime;
46     int ingerr();
47
48     IIseterr(ingerr);
49 ##  ingres sms
50 ##  set lockmode session where level = table
51
52     if (argc == 2) {
53         if (stat(argv[1], &sb) == 0) {
54             filetime = ingres_date_and_time(sb.st_mtime);
55 ##          retrieve (flag = int4(interval("min",tblstats.modtime - filetime)))
56 ##              where tblstats.table = "users"
57             if (flag < 0) {
58                 fprintf(stderr, "File %s does not need to be rebuilt.\n",
59                         argv[1]);
60                 exit(MR_NO_CHANGE);
61             }
62         }
63         targetfile = argv[1];
64         sprintf(filename, "%s~", targetfile);
65         if ((out = fopen(filename, "w")) == NULL) {
66             fprintf(stderr, "unable to open %s for output\n", filename);
67             exit(MR_OCONFIG);
68         }
69     } else if (argc != 1) {
70         fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
71         exit(MR_ARGS);
72     }
73
74     fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
75     fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide);
76
77 ##  begin transaction
78     get_info();
79 ##  end transaction
80 ##  exit
81
82     fprintf(stderr, "Sorting Info\n");
83     sort_info();
84
85     fprintf(stderr, "Dumping information\n");
86     do_lists(out);
87     do_people(out);
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(1000);
170 ##  retrieve (id = machine.mach_id, name = machine.#name) {
171       if (s = index(name, '.'))
172         *s = 0;
173 #ifdef ATHENA
174       strcat(name, ".LOCAL");
175 #endif
176       if (hash_store(machines, id, pstrsave(name)) < 0) {
177           fprintf(stderr, "Out of memory!\n");
178           exit(MR_NO_MEM);
179       }
180       cnt++;
181 ##  }
182     fprintf(stderr, "Loaded %d machines\n", cnt);
183
184     cnt = 0;
185     strings = create_hash(2000);
186 ##  retrieve (id = strings.string_id, name = strings.string) {
187         if (hash_store(strings, id, pstrsave(strtrim(name))) < 0) {
188             fprintf(stderr, "Out of memory!\n");
189             exit(MR_NO_MEM);
190         }
191         cnt++;
192 ##  }
193     fprintf(stderr, "Loaded %d strings\n", cnt);
194
195     cnt = 0;
196     users = create_hash(12001);
197 ##  range of u is users
198 ##  retrieve (id = u.users_id, name = u.login, fname = u.first,
199 ##            mname = u.middle, lname = u.last,
200 ##            type = u.potype, pid = u.pop_id, bid = u.box_id) 
201 ##      where u.status != 3 {
202         u = (struct user *) perm_malloc(sizeof(struct user));
203         u->login = pstrsave(strtrim(name));
204         u->first = pstrsave(strtrim(fname));
205         u->last  = pstrsave(strtrim(lname));
206         if (mname[0] != ' ')
207           u->mi = mname[0];
208         else
209           u->mi = 0;
210
211         if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
212             sprintf(buf, "%s@%s", strtrim(name), s);
213             u->pobox = pstrsave(buf);
214         } else if (type[0] ==  'S') {
215             u->pobox = hash_lookup(strings, bid);
216         } else
217           u->pobox = (char *) NULL;
218         if (hash_store(users, id, u) < 0) {
219             fprintf(stderr, "Out of memory!\n");
220             exit(MR_NO_MEM);
221         }
222         cnt++;
223 ##  }
224     fprintf(stderr, "Loaded %d users\n", cnt);
225
226     cnt = 0;
227     lists = create_hash(15000);
228 ##  range of l is list
229 ##  retrieve (id = l.list_id, name = l.#name, maillistp = l.maillist,
230 ##            type = l.acl_type, acl = l.acl_id)
231 ##    where l.active != 0 {
232         l = (struct list *) perm_malloc(sizeof(struct list));
233         l->name = pstrsave(strtrim(name));
234         l->maillist = maillistp;
235         l->acl_t = type[0];
236         l->acl_id = acl;
237         l->m = (struct member *) NULL;
238         if (hash_store(lists, id, l) < 0) {
239             fprintf(stderr, "Out of memory!\n");
240             exit(MR_NO_MEM);
241         }
242         cnt++;
243 ##  }
244     fprintf(stderr, "Loaded %d lists\n", cnt);
245
246     cnt = 0;
247 ##  range of m is imembers
248 ##  retrieve (id = m.list_id, type = m.member_type, mid = m.member_id)
249 ##      where m.direct = 1  {
250         cnt++;
251         if (l = (struct list *) hash_lookup(lists, id)) {
252             m = (struct member *) perm_malloc(sizeof(struct member));
253             if (type[0] == 'U' &&
254                 (u = (struct user *) hash_lookup(users, mid))) {
255                 m->list_id = 0;
256                 m->name = u->login;
257                 m->next = l->m;
258                 l->m = m;
259             } else if (type[0] == 'L' && 
260                        (memberlist = (struct list *) hash_lookup(lists, mid))) {
261                 m->list_id = mid;
262                 m->name = memberlist->name;
263                 m->next = l->m;
264                 l->m = m;
265             } else if (type[0] == 'S' &&
266                        (s = hash_lookup(strings, mid))) {
267                 m->list_id = 0;
268                 m->next = l->m;
269                 l->m = m;
270                 m->name = s;
271             }
272         }
273 ##  }
274     fprintf(stderr, "Loaded %d members\n", cnt);
275 ##}
276
277
278 save_mlist(id, l, force)
279 int id;
280 struct list *l;
281 int force;
282 {
283     register struct member *m;
284     register struct list *l1;
285
286     if (l->maillist == 2 ||
287         l->maillist == 3 ||
288         (l->maillist == 0 && !force))
289       return;
290
291     if (l->m && l->m->next == NULL &&
292         !strcasecmp(l->name, l->m->name)) {
293         l->maillist = 3;
294         return;
295     }
296     l->maillist = 2;
297     insert_name(l->name, -id, TRUE, FALSE);
298
299     if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
300       save_mlist(0, l1, TRUE);
301     
302     for (m = l->m; m; m = m->next) {
303         if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
304           save_mlist(0, l1, TRUE);
305     }
306 }
307
308
309 insert_login(id, u, dummy)
310 int id;
311 struct user *u;
312 int dummy;
313 {
314     if (u->pobox && u->login[0] != '#')
315       insert_name(u->login, id, TRUE, FALSE);
316 }
317
318 void insert_names(id, u, dummy)
319 int id;
320 struct user *u;
321 int dummy;
322 {
323     char buffer[256];
324
325     insert_name(u->last, id, FALSE, FALSE);
326     sprintf(buffer, "%s_%s", u->first, u->last);
327     insert_name(buffer, id, FALSE, TRUE);
328 /*    sprintf(buffer, "%c_%s", u->first[0], u->last);
329     insert_name(buffer, id, FALSE, TRUE); */
330     if (u->mi) {
331         sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
332         insert_name(buffer, id, FALSE, TRUE);
333     }
334 }
335
336 int incount = 0;
337
338 insert_name(s, id, nodups, copy)
339 char *s;
340 int id;
341 int nodups;
342 int copy;
343 {
344     int code;
345     register struct names *ns;
346     register int count;
347     register struct idblock *ra;
348
349     incount++;
350     code = hashstr(s);
351     ns = (struct names *) hash_lookup(names, code);
352     if (ns == NULL) {
353         if ((ns = (struct names *) perm_malloc(sizeof(struct names))) == NULL) {
354             fprintf(stderr, "ran out of memory inserting name (sorting)\n");
355             exit(MR_NO_MEM);
356         }
357         if (copy)
358           ns->name = pstrsave(s);
359         else
360           ns->name = s;
361         ns->keep = nodups;
362         ns->id = id;
363         if (hash_store(names, code, ns) < 0) {
364             fprintf(stderr, "Out of memory!\n");
365             exit(MR_NO_MEM);
366         }
367         return;
368     }
369     if (strcasecmp(ns->name, s)) {
370         while (ns->next) {
371             ns = ns->next;
372             if (!strcasecmp(ns->name, s))
373               goto foundns;
374         }
375         if ((ns->next = (struct names *) perm_malloc(sizeof(struct names)))
376                 == NULL) {
377             fprintf(stderr, "ran out of memory insterting name (sorting)\n");
378             exit(MR_NO_MEM);
379         }
380         ns = ns->next;
381         if (copy)
382           ns->name = pstrsave(s);
383         else
384           ns->name = s;
385         ns->keep = nodups;
386         ns->id = id;
387         return;
388     }
389  foundns:
390     if (nodups || ns->keep)
391       return;
392     ns->id = 0;
393 }
394
395
396 /* Illegal chars: ! " % ( ) , . / : ; < = > @ [ \ ] ^ { | } */
397
398 static int illegalchars[] = {
399     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
400     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
401     0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, /* SPACE - / */
402     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
403     1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
404     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
405     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
406     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
407     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
408     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
409     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
410     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
411     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
412     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
413     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
414     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
415 };
416
417
418 /* While hashing the string, punt any illegal characters */
419
420 int hashstr(s)
421 register char *s;
422 {
423     register int result;
424     register int c;
425
426     for (result = 0; c = *s; s++) {
427         if (illegalchars[c]) {
428             register char *p;
429             for (p = s; *p; p++)
430               *p = p[1];
431             continue;
432         }
433         if (isupper(c))
434           c = *s = tolower(c);
435 /*      result = result * 31 + *s; */
436         result = (result << 5) - result + c - '`';
437     }
438     return(result < 0 ? -result : result);
439 }
440
441
442 sort_info()
443 {
444     names = create_hash(20001);
445     hash_step(users, insert_login, NULL);
446     hash_step(lists, save_mlist, FALSE);
447     hash_step(users, insert_names, NULL);
448     fprintf(stderr, "Inserted %d names\n", incount);
449 }
450
451
452 output_data(dummy, nms, out)
453 int dummy;
454 struct names *nms;
455 FILE *out;
456 {
457     register struct names *ns;
458     register struct user *u;
459
460     incount++;
461     for (ns = nms; ns; ns = ns->next) {
462         if (ns->name[0] == 0 || ns->name[1] == 0) {
463             fprintf(stderr, "punting %s due to short name\n", ns->name);
464             continue;
465         }
466         if (ns->id > 0) {
467             u = (struct user *) hash_lookup(users, ns->id);
468             if (u->pobox) {
469                 fprintf(out, "%s: %s\n", ns->name, u->pobox);
470             } else {
471                 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
472             }
473         } else if (ns->id == 0) {
474             fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
475         }
476     }
477 }
478
479
480 int lwid, bol, awid;
481
482 output_mlist(id, l, out)
483 int id;
484 register struct list *l;
485 FILE *out;
486 {
487     struct list *l1;
488     register struct member *m;
489     register struct user *u;
490
491     if (l->maillist != 2)
492       return;
493     if (l->acl_t ==  'L' &&
494         (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
495       fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
496     else if (l->acl_t ==  'U' &&
497              (u = (struct user *) hash_lookup(users, l->acl_id)))
498       fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
499     else
500       fprintf(out, "%s: ", l->name);
501       
502
503     lwid = strlen(l->name) + 2;
504     bol = 1;
505     for (m = l->m; m; m = m->next) {
506         do_member(out, m->name);
507     }
508     if (l->m == (struct member *)NULL)
509       fprintf(out, "/dev/null");
510     fprintf(out, "\n\n");
511     incount++;
512 }
513
514
515 /* print out strings separated by commas, doing line breaks as appropriate */
516
517 do_member(out, s)
518 FILE *out;
519 register char *s;
520 {
521     register wwid;
522     static int cont = 1;
523
524     wwid = strlen(s);
525
526     if (!bol && awid + wwid + 2 > AL_MAX_WID) {
527         fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
528         cont++;
529         awid = lwid = 17 + wwid;
530         fputs(s, out);
531         return;
532     }
533
534     if (bol) {
535         lwid += wwid;
536         awid = lwid;
537         fputs(s, out);
538         bol = 0;
539         return;
540     }
541     if (lwid + wwid + 2 > ML_WID) {
542         fprintf(out, ",\n\t%s", s);
543         awid += lwid + wwid + 2;
544         lwid = wwid + 8;
545         return;
546     }
547     lwid += wwid + 2;
548     fprintf(out, ", %s", s);
549 }
550
551
552 do_lists(out)
553 FILE *out;
554 {
555     incount = 0;
556     fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
557     hash_step(lists, output_mlist, out);
558     fprintf(stderr, "Output %d lists\n", incount);
559 }
560
561 do_people(out)
562 FILE *out;
563 {
564     incount = 0;
565     fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
566     hash_step(names, output_data, out);
567     fprintf(stderr, "Output %d entries\n", incount);
568 }
569
570
571 #define chunk_size      102400
572
573 char *perm_malloc(size)
574 unsigned size;
575 {
576     static char *pool = NULL;
577     static unsigned pool_size = 0;
578     register char *ret;
579
580     if (size > pool_size) {
581         pool = (char *) malloc(chunk_size);
582         pool_size = chunk_size;
583     }
584     ret = pool;
585     pool += size;
586     pool = (char *)(((unsigned) (pool + 1)) & ~1);
587     pool_size -= (pool - ret);
588     return(ret);
589 }
590
591
592 /*
593  * Make a (permenant) copy of a string.
594  */
595 char *
596 pstrsave(s)
597     char *s;
598 {
599     register int len;
600     register char *p;
601     /* Kludge for sloppy string semantics */
602     if (!s) {
603             printf("NULL != \"\" !!!!\r\n");
604             p = perm_malloc(1);
605             *p = '\0';
606             return p;
607     }
608     len = strlen(s) + 1;
609     p = perm_malloc((u_int)len);
610     if (p) bcopy(s, p, len);
611     return p;
612 }
This page took 0.086771 seconds and 5 git commands to generate.