]> andersk Git - moira.git/blob - gen/aliases.qc
added ingres error & deadlock detection
[moira.git] / gen / aliases.qc
1 /* $Header$
2  *
3  * This generates the /usr/lib/aliases mail aliases file for the mailhub.
4  * The aliases file will contain:
5  *      user pobox entries
6  *      maillist expansions
7  *      sublists of maillists
8  */
9
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <sms.h>
14 #include <sms_app.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/time.h>
18
19
20 #define ML_WID  72
21 #define AL_MAX_WID 896
22
23 char *divide = "########################################################################";
24 extern int errno;
25 char *whoami = "aliases.gen";
26 char *ingres_date_and_time();
27
28
29 main(argc, argv)
30 int argc;
31 char **argv;
32 {
33     long tm = time(NULL);
34     FILE *out= stdout;
35     char filename[64], *targetfile;
36     struct stat sb;
37 ##  int flag1, flag2, flag3;
38 ##  char *filetime;
39     int ingerr();
40
41     IIseterr(ingerr);
42 ##  ingres sms
43
44     if (argc == 2) {
45         if (stat(argv[1], &sb) == 0) {
46             filetime = ingres_date_and_time(sb.st_mtime);
47 ##          retrieve (flag1 = int4(interval("min",tblstats.modtime - filetime)))
48 ##              where tblstats.table = "list"
49 ##          retrieve (flag2 = int4(interval("min",tblstats.modtime - filetime)))
50 ##              where tblstats.table = "members"
51 ##          retrieve (flag3 = int4(interval("min",tblstats.modtime - filetime)))
52 ##              where tblstats.table = "users"
53             if (flag1 < 0 && flag2 < 0 && flag3 < 0) {
54                 fprintf(stderr, "File %s does not need to be rebuilt.\n",
55                         argv[1]);
56                 exit(SMS_NO_CHANGE);
57             }
58         }
59         targetfile = argv[1];
60         sprintf(filename, "%s~", targetfile);
61         if ((out = fopen(filename, "w")) == NULL) {
62             fprintf(stderr, "unable to open %s for output\n", filename);
63             exit(SMS_OCONFIG);
64         }
65     } else if (argc != 1) {
66         fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
67         exit(SMS_ARGS);
68     }
69
70     fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
71     fprintf(out, "# This file is automatically generated, do not edit it directly.\n%s\n\n", divide);
72
73 ##  begin transaction
74     get_info();
75 ##  end transaction
76 ##  exit
77
78     fprintf(stderr, "Dumping information\n");
79     do_mlists(out);
80     do_poboxes(out);
81
82     fprintf(out, "\n%s\n# End of aliases file\n%s\n", divide, divide);
83
84
85     if (fclose(out)) {
86         perror("close failed");
87         exit(SMS_CCONFIG);
88     }
89
90     if (argc == 2)
91       fix_file(targetfile);
92     exit(SMS_SUCCESS);
93 }
94
95
96 /*
97  * ingerr: (supposedly) called when Ingres indicates an error.
98  * I have not yet been able to get this to work to intercept a
99  * database open error.
100  */
101 #define INGRES_DEADLOCK 4700
102
103 static int ingerr(num)
104     int *num;
105 {
106     char buf[256];
107     int ingres_errno;
108
109     switch (*num) {
110     case INGRES_DEADLOCK:
111         ingres_errno = SMS_DEADLOCK;
112         break;
113     default:
114         ingres_errno = SMS_INGRES_ERR;
115     }
116     com_err(whoami, SMS_INGRES_ERR, " code %d\n", *num);
117     critical_alert("DCM", "Alias build encountered INGRES ERROR %d", *num);
118     exit(ingres_errno);
119 }
120
121
122 struct hash *users, *machines, *strings, *lists;
123 struct user {
124     char login[9];
125     char *pobox;
126 };
127 struct member {
128     struct member *next;
129     char *name;
130     int list_id;
131 };
132 struct list {
133     char name[33];
134     char maillist;
135     char acl_t;
136     char description[256];
137     int acl_id;
138     struct member *m;
139 };
140
141
142 get_info()
143 ##{
144 ##  int id, maillistp, acl, pid, bid, mid;
145 ##  char name[129], type[9], buf[257];
146     char *s;
147     register struct user *u;
148     register struct list *l;
149     register struct member *m;
150     register struct list *memberlist;
151
152     fprintf(stderr, "Loading machines\n");
153     machines = create_hash(1000);
154 ##  retrieve (id = machine.mach_id, name = machine.#name) {
155       if (s = index(name, '.'))
156         *s = 0;
157       sprintf(buf, "%s.LOCAL", name);
158       hash_store(machines, id, strsave(buf));
159 ##  }
160
161     fprintf(stderr, "Loading strings\n");
162     strings = create_hash(2000);
163 ##  retrieve (id = strings.string_id, name = strings.string) {
164         hash_store(strings, id, strsave(strtrim(name)));
165 ##  }
166
167     fprintf(stderr, "Loading users\n");
168     users = create_hash(15000);
169 ##  range of u is users
170 ##  retrieve (id = u.users_id, name = u.login, type = u.potype,
171 ##            pid = u.pop_id, bid = u.box_id) where u.status = 1 {
172         u = (struct user *) malloc(sizeof(struct user));
173         strcpy(u->login, strtrim(name));
174         u->pobox = (char *) NULL;
175         if (type[0] == 'P') {
176             if (s = hash_lookup(machines, pid)) {
177                 sprintf(buf, "%s@%s", name, s);
178                 u->pobox = strsave(buf);
179             } else {
180                 fprintf(stderr, "User %s's pobox is on a missing machine!\n",
181                         u->login);
182             }
183         } else if (type[0] ==  'S') {
184             if ((u->pobox = hash_lookup(strings, bid)) == NULL)
185               fprintf(stderr, "User %s's pobox string is missing!\n", u->login);
186         }
187         hash_store(users, id, u);
188 ##  }
189
190     fprintf(stderr, "Loading lists\n");
191     lists = create_hash(15000);
192 ##  range of l is list
193 ##  retrieve (id = l.list_id, name = l.#name, maillistp = l.maillist,
194 ##            buf = l.desc, type = l.acl_type, acl = l.acl_id)
195 ##    where l.active != 0 {
196         l = (struct list *) malloc(sizeof(struct list));
197         strcpy(l->name, strtrim(name));
198         l->maillist = maillistp;
199         strcpy(l->description, strtrim(buf));
200         l->acl_t = type[0];
201         l->acl_id = acl;
202         l->m = (struct member *) NULL;
203         hash_store(lists, id, l);
204 ##  }
205
206
207     fprintf(stderr, "Loading members\n");
208 ##  range of m is members
209 ##  retrieve (id = m.list_id, type = m.member_type, mid = m.member_id) {
210         if (l = (struct list *) hash_lookup(lists, id)) {
211             m = (struct member *) malloc(sizeof(struct member));
212             m->name = (char *) NULL;
213             if (type[0] == 'U') {
214                 m->list_id = 0;
215                 if (u = (struct user *) hash_lookup(users, mid))
216                   m->name = u->login;
217             } else if (type[0] == 'L') {
218                 m->list_id = mid;
219                 if (memberlist = (struct list *) hash_lookup(lists, mid))
220                   m->name = memberlist->name;
221             } else if (type[0] == 'S') {
222                 m->list_id = 0;
223                 if (s = hash_lookup(strings, mid))
224                   m->name = s;
225             }
226             if (m->name != (char *) NULL) {
227                 m->next = l->m;
228                 l->m = m;
229             }
230         }
231 ##  }
232 ##}
233
234
235 void save_mlist(id, l, sq)
236 int id;
237 struct list *l;
238 struct save_queue *sq;
239 {
240     if (l->maillist)
241       sq_save_unique_data(sq, id);
242 }
243
244
245 /* Extract mailing lists.  Make a list of all mailinglists, then
246  * process them, adding any sub-lists or acl lists to the list of lists
247  * to be processed.  If further sublists are encountered, repeat...
248  */
249
250 int lwid, bol, awid;
251
252 do_mlists(out)
253 FILE *out;
254 {
255     register struct list *l;
256     struct list *l1;
257     register struct member *m;
258     struct user *u;
259     register struct save_queue *sq;
260     struct save_queue *sq_create();
261     int id;
262
263     sq = sq_create();
264     fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
265
266     hash_step(lists, save_mlist, sq);
267
268     while (sq_get_data(sq, &id)) {
269         l = (struct list *) hash_lookup(lists, id);
270         if (l->m &&                       /* there's at least one member */
271             l->m->next == NULL &&         /* there's only one member */
272             !strcmp(l->name, l->m->name)) /* the member is same as list */
273           continue;
274         put_fill(out, l->description);
275         if (l->acl_t ==  'L') {
276             if (l1 = (struct list *) hash_lookup(lists, l->acl_id)) {
277                 fprintf(out, "owner-%s: %s\n", l->name, l1->name);
278                 sq_save_unique_data(sq, l->acl_id);
279             }
280         } else if (l->acl_t ==  'U') {
281             if (u = (struct user *) hash_lookup(users, l->acl_id))
282               fprintf(out, "owner-%s: %s\n", l->name, u->login);
283         }
284         fprintf(out, "%s: ", l->name);
285         lwid = strlen(l->name) + 2;
286         bol = 1;
287         for (m = l->m; m; m = m->next) {
288             if (m->list_id != 0)
289               sq_save_unique_data(sq, m->list_id);
290             do_member(out, m->name);
291         }
292         fprintf(out, "\n\n");
293     }
294
295 /*  Removed for speed, since this take 10 minutes to free, and we don't
296  *  really need the memory reclaimed.
297  *  sq_destroy(sq); */
298 }
299
300
301 /* print out strings separated by commas, doing line breaks as appropriate */
302
303 do_member(out, s)
304 FILE *out;
305 register char *s;
306 {
307     register wwid;
308     static int cont = 1;
309
310     strtrim(s);
311     wwid = strlen(s);
312
313     if (!bol && awid + wwid + 2 > AL_MAX_WID) {
314         fprintf(out, ",\n\tcontinuation-%d\ncontinuation-%d: ", cont, cont);
315         cont++;
316         awid = lwid = bol = 17;
317     }
318
319     if (bol) {
320         lwid += wwid;
321         awid = lwid;
322         fprintf(out, "%s", s);
323         bol = 0;
324         return;
325     }
326     if (lwid + wwid + 2 > ML_WID) {
327         fprintf(out, ",\n\t%s", s);
328         awid += lwid + wwid + 2;
329         lwid = wwid + 8;
330         return;
331     }
332     lwid += wwid + 2;
333     fprintf(out, ", %s", s);
334 }
335
336 do_pobox(id, u, out)
337 int id;
338 register struct user *u;
339 FILE *out;
340 {
341     if (u->pobox)
342       fprintf(out, "%s: %s\n", u->login, u->pobox);
343 }
344
345
346 /* Do user poboxes.  Just step through the users table, and print any
347  * we extracted earlier.
348  */
349
350 do_poboxes(out)
351 FILE *out;
352 {
353     register char *p;
354     char *index();
355
356     fprintf(out, "\n%s\n# User Poboxes\n%s\n", divide, divide);
357
358     hash_step(users, do_pobox, out);
359 }
360
361
362 put_fill(aliases, string)
363 FILE *aliases;
364 register char *string;
365 {
366     register char *c;
367     register int lwid;
368     register int wwid;
369
370     if (*string == 0) return;
371     fputs("#  ", aliases);
372     lwid = 3;
373
374     while (1) {
375         while (*string && *string == ' ') string++;
376         c = (char *)index(string, ' ');
377         if (c == 0) {
378             wwid = strlen(string);
379         } else {
380             wwid = c - string;
381             *c = 0;
382         }
383
384         if ((lwid + wwid) > ML_WID) {
385             fputs("\n#  ", aliases);
386             lwid = 3;
387             fputs(string, aliases);
388         } else {
389             fputs(string, aliases);
390         }
391
392         if (c == (char *)0) break;
393         /* add a space after the word */
394         (void) fputc(' ', aliases);
395         wwid++;
396         lwid += wwid;
397         string += wwid;
398         /* add another if after a period */
399         if (*--c == '.') {
400             (void) fputc(' ', aliases);
401             lwid++;
402         }
403     }
404
405     (void) fputc('\n', aliases);
406 }
This page took 0.085031 seconds and 5 git commands to generate.