]> andersk Git - moira.git/blob - gen/mailhub.qc
Major changes to get it to do the right thing. It's mostly finished now.
[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 <sms.h>
16 #include <sms_app.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 *divide = "##############################################################";
26
27 #define ML_WID  72
28 #define AL_MAX_WID 896
29
30 #define FALSE 0
31 #define TRUE (!FALSE)
32
33
34 main(argc, argv)
35 int argc;
36 char **argv;
37 {
38     long tm = time(NULL);
39     FILE *out= stdout;
40     char filename[64], *targetfile;
41     struct stat sb;
42 ##  int flag;
43 ##  char *filetime;
44     int ingerr();
45
46     IIseterr(ingerr);
47 ##  ingres sms
48 ##  set lockmode session where level = table
49
50     if (argc == 2) {
51         if (stat(argv[1], &sb) == 0) {
52             filetime = ingres_date_and_time(sb.st_mtime);
53 ##          retrieve (flag = int4(interval("min",tblstats.modtime - filetime)))
54 ##              where tblstats.table = "users"
55             if (flag < 0) {
56                 fprintf(stderr, "File %s does not need to be rebuilt.\n",
57                         argv[1]);
58                 exit(SMS_NO_CHANGE);
59             }
60         }
61         targetfile = argv[1];
62         sprintf(filename, "%s~", targetfile);
63         if ((out = fopen(filename, "w")) == NULL) {
64             fprintf(stderr, "unable to open %s for output\n", filename);
65             exit(SMS_OCONFIG);
66         }
67     } else if (argc != 1) {
68         fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
69         exit(SMS_ARGS);
70     }
71
72     fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
73     fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide);
74
75 ##  begin transaction
76     get_info();
77 ##  end transaction
78 ##  exit
79
80     fprintf(stderr, "Sorting Info\n");
81     sort_info();
82
83     fprintf(stderr, "Dumping information\n");
84     do_lists(out);
85     do_people(out);
86
87     fprintf(out, "\n%s\n# End of aliases file\n", divide);
88
89     if (fclose(out)) {
90         perror("close failed");
91         exit(SMS_CCONFIG);
92     }
93
94     if (argc == 2)
95       fix_file(targetfile);
96     exit(SMS_SUCCESS);
97 }
98
99
100 /*
101  * ingerr: (supposedly) called when Ingres indicates an error.
102  * I have not yet been able to get this to work to intercept a
103  * database open error.
104  */
105 #define INGRES_DEADLOCK 4700
106
107 static int ingerr(num)
108     int *num;
109 {
110     char buf[256];
111     int ingres_errno;
112
113     switch (*num) {
114     case INGRES_DEADLOCK:
115         ingres_errno = SMS_DEADLOCK;
116         break;
117     default:
118         ingres_errno = SMS_INGRES_ERR;
119     }
120     com_err(whoami, SMS_INGRES_ERR, " code %d\n", *num);
121     critical_alert("DCM", "Alias build encountered INGRES ERROR %d", *num);
122     exit(ingres_errno);
123 }
124
125 struct hash *users, *machines, *strings, *lists, *names;
126 struct user {
127     char *login;
128     char *first;
129     char *last;
130     char mi;
131     char *pobox;
132 };
133 struct member {
134     struct member *next;
135     char *name;
136     int list_id;
137 };
138 struct list {
139     char *name;
140     char maillist;
141     char acl_t;
142     int acl_id;
143     struct member *m;
144 };
145 struct names {
146     char *name;
147     struct names *next;
148     int keep:1;
149     int id:31;
150 };
151
152
153 get_info()
154 ##{
155 ##  int id, pid, bid, stat, cnt, maillistp, acl, mid;
156 ##  char name[129], type[9], fname[17], mname[17], lname[17], buf[257];
157     char *s;
158     register struct user *u;
159     struct list *l, *memberlist;
160     register struct member *m;
161
162     /* get locks */
163 ##  retrieve (buf = users.modtime) where users.users_id = 0
164 ##  retrieve (buf = list.modtime) where list.list_id = 0
165
166     cnt = 0;
167     machines = create_hash(1000);
168 ##  retrieve (id = machine.mach_id, name = machine.#name) {
169       if (s = index(name, '.'))
170         *s = 0;
171       sprintf(buf, "%s.LOCAL", name);
172       if (hash_store(machines, id, strsave(buf)) < 0) {
173           fprintf(stderr, "Out of memory!\n");
174           exit(SMS_NO_MEM);
175       }
176       cnt++;
177 ##  }
178     fprintf(stderr, "Loaded %d machines\n", cnt);
179
180     cnt = 0;
181     strings = create_hash(2000);
182 ##  retrieve (id = strings.string_id, name = strings.string) {
183         if (hash_store(strings, id, strsave(strtrim(name))) < 0) {
184             fprintf(stderr, "Out of memory!\n");
185             exit(SMS_NO_MEM);
186         }
187         cnt++;
188 ##  }
189     fprintf(stderr, "Loaded %d strings\n", cnt);
190
191     cnt = 0;
192     users = create_hash(12001);
193 ##  range of u is users
194 ##  retrieve (id = u.users_id, name = u.login, fname = u.first,
195 ##            mname = u.middle, lname = u.last,
196 ##            type = u.potype, pid = u.pop_id, bid = u.box_id) 
197 ##      where u.status != 3 {
198         u = (struct user *) malloc(sizeof(struct user));
199         u->login = strsave(strtrim(name));
200         u->first = strsave(strtrim(fname));
201         u->last  = strsave(strtrim(lname));
202         if (mname[0] != ' ')
203           u->mi = mname[0];
204         else
205           u->mi = 0;
206
207         if (type[0] == 'P' && (s = hash_lookup(machines, pid))) {
208             sprintf(buf, "%s@%s", strtrim(name), s);
209             u->pobox = strsave(buf);
210         } else if (type[0] ==  'S') {
211             u->pobox = hash_lookup(strings, bid);
212         } else
213           u->pobox = (char *) NULL;
214         if (hash_store(users, id, u) < 0) {
215             fprintf(stderr, "Out of memory!\n");
216             exit(SMS_NO_MEM);
217         }
218         cnt++;
219 ##  }
220     fprintf(stderr, "Loaded %d users\n", cnt);
221
222     cnt = 0;
223     lists = create_hash(15000);
224 ##  range of l is list
225 ##  retrieve (id = l.list_id, name = l.#name, maillistp = l.maillist,
226 ##            type = l.acl_type, acl = l.acl_id)
227 ##    where l.active != 0 {
228         l = (struct list *) malloc(sizeof(struct list));
229         l->name = strsave(strtrim(name));
230         l->maillist = maillistp;
231         l->acl_t = type[0];
232         l->acl_id = acl;
233         l->m = (struct member *) NULL;
234         if (hash_store(lists, id, l) < 0) {
235             fprintf(stderr, "Out of memory!\n");
236             exit(SMS_NO_MEM);
237         }
238         cnt++;
239 ##  }
240     fprintf(stderr, "Loaded %d lists\n", cnt);
241
242     cnt = 0;
243 ##  range of m is imembers
244 ##  retrieve (id = m.list_id, type = m.member_type, mid = m.member_id)
245 ##      where m.direct = 1  {
246         cnt++;
247         if (l = (struct list *) hash_lookup(lists, id)) {
248             m = (struct member *) malloc(sizeof(struct member));
249             if (type[0] == 'U' &&
250                 (u = (struct user *) hash_lookup(users, mid))) {
251                 m->list_id = 0;
252                 m->name = u->login;
253                 m->next = l->m;
254                 l->m = m;
255             } else if (type[0] == 'L' && 
256                        (memberlist = (struct list *) hash_lookup(lists, mid))) {
257                 m->list_id = mid;
258                 m->name = memberlist->name;
259                 m->next = l->m;
260                 l->m = m;
261             } else if (type[0] == 'S' &&
262                        (s = hash_lookup(strings, mid))) {
263                 m->list_id = 0;
264                 m->next = l->m;
265                 l->m = m;
266                 m->name = s;
267             }
268         }
269 ##  }
270     fprintf(stderr, "Loaded %d members\n", cnt);
271 ##}
272
273
274 save_mlist(id, l, force)
275 int id;
276 struct list *l;
277 int force;
278 {
279     register struct member *m;
280     register struct list *l1;
281
282     if (l->maillist == 2 ||
283         l->maillist == 3 ||
284         (l->maillist == 0 && !force))
285       return;
286
287     if (l->m && l->m->next == NULL &&
288         !strcasecmp(l->name, l->m->name)) {
289         l->maillist = 3;
290         return;
291     }
292     l->maillist = 2;
293     insert_name(l->name, -id, TRUE, FALSE);
294
295     if (l->acl_t == 'L' && (l1 = (struct list *)hash_lookup(lists, l->acl_id)))
296       save_mlist(0, l1, TRUE);
297     
298     for (m = l->m; m; m = m->next) {
299         if (m->list_id && (l1 = (struct list *)hash_lookup(lists, m->list_id)))
300           save_mlist(0, l1, TRUE);
301     }
302 }
303
304
305 insert_login(id, u, dummy)
306 int id;
307 struct user *u;
308 int dummy;
309 {
310     if (u->pobox && u->login[0] != '#')
311       insert_name(u->login, id, TRUE, FALSE);
312 }
313
314 void insert_names(id, u, dummy)
315 int id;
316 struct user *u;
317 int dummy;
318 {
319     char buffer[256];
320
321     insert_name(u->last, id, FALSE, FALSE);
322     sprintf(buffer, "%s_%s", u->first, u->last);
323     insert_name(buffer, id, FALSE, TRUE);
324     sprintf(buffer, "%c_%s", u->first[0], u->last);
325     insert_name(buffer, id, FALSE, TRUE);
326     if (u->mi) {
327         sprintf(buffer, "%s_%c_%s", u->first, u->mi, u->last);
328         insert_name(buffer, id, FALSE, TRUE);
329     }
330 }
331
332 int incount = 0;
333
334 insert_name(s, id, nodups, copy)
335 char *s;
336 int id;
337 int nodups;
338 int copy;
339 {
340     int code;
341     register struct names *ns;
342     register int count;
343     register struct idblock *ra;
344
345     incount++;
346     code = hashstr(s);
347     ns = (struct names *) hash_lookup(names, code);
348     if (ns == NULL) {
349         if ((ns = (struct names *) malloc(sizeof(struct names))) == NULL) {
350             fprintf(stderr, "ran out of memory inserting name (sorting)\n");
351             exit(SMS_NO_MEM);
352         }
353         if (copy)
354           ns->name = strsave(s);
355         else
356           ns->name = s;
357         ns->keep = nodups;
358         ns->id = id;
359         if (hash_store(names, code, ns) < 0) {
360             fprintf(stderr, "Out of memory!\n");
361             exit(SMS_NO_MEM);
362         }
363         return;
364     }
365     if (strcasecmp(ns->name, s)) {
366         while (ns->next) {
367             ns = ns->next;
368             if (!strcasecmp(ns->name, s))
369               goto foundns;
370         }
371         if ((ns->next = (struct names *)malloc(sizeof(struct names))) == NULL) {
372             fprintf(stderr, "ran out of memory insterting name (sorting)\n");
373             exit(SMS_NO_MEM);
374         }
375         ns = ns->next;
376         if (copy)
377           ns->name = strsave(s);
378         else
379           ns->name = s;
380         ns->keep = nodups;
381         ns->id = id;
382         return;
383     }
384  foundns:
385     if (nodups || ns->keep)
386       return;
387     ns->id = 0;
388 }
389
390
391 int hashstr(s)
392 register char *s;
393 {
394     register int result;
395     register int c;
396
397     for (result = 0; c = *s; s++) {
398         if (isupper(c))
399           c = *s = tolower(c);
400 /*      result = result * 31 + *s; */
401         result = (result << 5) - result + c - '`';
402     }
403     return(result < 0 ? -result : result);
404 }
405
406
407 sort_info()
408 {
409     names = create_hash(20001);
410     hash_step(users, insert_login, NULL);
411     hash_step(lists, save_mlist, FALSE);
412     hash_step(users, insert_names, NULL);
413     fprintf(stderr, "Inserted %d names\n", incount);
414 }
415
416
417 output_data(dummy, nms, out)
418 int dummy;
419 struct names *nms;
420 FILE *out;
421 {
422     register struct names *ns;
423     register struct user *u;
424     int i;
425
426     incount++;
427     for (ns = nms; ns; ns = ns->next) {
428         if (ns->name[0] == 0 || ns->name[1] == 0) {
429             fprintf(stderr, "punting %s due to short name\n", ns->name);
430             continue;
431         }
432         if (ns->id > 0) {
433             u = (struct user *) hash_lookup(users, ns->id);
434             if (u->pobox) {
435                 fprintf(out, "%s: %s\n", ns->name, u->pobox);
436             } else {
437                 fprintf(out, "%s: =%s=@nobox\n", ns->name, ns->name);
438             }
439         } else if (ns->id == 0) {
440             fprintf(out, "%s: =%s=@ambig\n", ns->name, ns->name);
441         }
442     }
443 }
444
445
446 int lwid, bol, awid;
447
448 output_mlist(id, l, out)
449 int id;
450 register struct list *l;
451 FILE *out;
452 {
453     struct list *l1;
454     register struct member *m;
455     register struct user *u;
456
457     if (l->maillist != 2)
458       return;
459     if (l->acl_t ==  'L' &&
460         (l1 = (struct list *) hash_lookup(lists, l->acl_id)))
461       fprintf(out, "owner-%s: %s\n", l->name, l1->name);
462     else if (l->acl_t ==  'U' &&
463              (u = (struct user *) hash_lookup(users, l->acl_id)))
464       fprintf(out, "owner-%s: %s\n", l->name, u->login);
465
466     fprintf(out, "%s: ", l->name);
467     lwid = strlen(l->name) + 2;
468     bol = 1;
469     for (m = l->m; m; m = m->next) {
470         do_member(out, m->name);
471     }
472     if (l->m == (struct member *)NULL)
473       fprintf(out, "/dev/null");
474     fprintf(out, "\n\n");
475     incount++;
476 }
477
478
479 /* print out strings separated by commas, doing line breaks as appropriate */
480
481 do_member(out, s)
482 FILE *out;
483 register char *s;
484 {
485     register wwid;
486     static int cont = 1;
487
488     wwid = strlen(s);
489
490     if (!bol && awid + wwid + 2 > AL_MAX_WID) {
491         fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
492         cont++;
493         awid = lwid = 17 + wwid;
494         fputs(s, out);
495         return;
496     }
497
498     if (bol) {
499         lwid += wwid;
500         awid = lwid;
501         fputs(s, out);
502         bol = 0;
503         return;
504     }
505     if (lwid + wwid + 2 > ML_WID) {
506         fprintf(out, ",\n\t%s", s);
507         awid += lwid + wwid + 2;
508         lwid = wwid + 8;
509         return;
510     }
511     lwid += wwid + 2;
512     fprintf(out, ", %s", s);
513 }
514
515
516 do_lists(out)
517 FILE *out;
518 {
519     incount = 0;
520     fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
521     hash_step(lists, output_mlist, out);
522     fprintf(stderr, "Output %d lists\n", incount);
523 }
524
525 do_people(out)
526 FILE *out;
527 {
528     incount = 0;
529     fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
530     hash_step(names, output_data, out);
531     fprintf(stderr, "Output %d entries\n", incount);
532 }
This page took 0.083814 seconds and 5 git commands to generate.