]> andersk Git - moira.git/blob - gen/mailhub.pc
Make the flow of control more obvious by removing a lot of code that
[moira.git] / gen / mailhub.pc
1 /* $Id$
2  *
3  * This generates the /usr/lib/aliases file for the mailhub.
4  *
5  * (c) Copyright 1988-1998 by the Massachusetts Institute of Technology.
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include <moira.h>
12 #include <moira_site.h>
13
14 #include <sys/stat.h>
15
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "util.h"
22
23 EXEC SQL INCLUDE sqlca;
24
25 RCSID("$Header$");
26
27 char *whoami = "mailhub.gen";
28 char *db = "moira/moira";
29 char *divide = "##############################################################";
30
31 #define MAX_LINE_WIDTH  72
32 #define MAX_ALIAS_WIDTH 592
33
34 #define FALSE 0
35 #define TRUE (!FALSE)
36
37 FILE *out = stdout;
38
39 struct hash *users, *machines, *strings, *lists;
40 struct user {
41   char *login;
42   char *pobox;
43 };
44 struct member {
45   struct member *next;
46   char *name;
47   int list_id;
48 };
49 struct list {
50   char *name;
51   char maillist;
52   char *description;
53   char acl_t;
54   int acl_id;
55   struct member *m;
56 };
57
58 void get_info(void);
59 void save_mlist(int id, void *list, void *force);
60 int check_string(char *s);
61 void output_login(int dummy, void *names, void *out);
62 void output_mlist(int id, struct list *l);
63 void put_fill(FILE *aliases, char *string);
64 void do_people(void);
65
66 int incount = 0;
67
68 int main(int argc, char **argv)
69 {
70   time_t tm = time(NULL);
71   char filename[MAXPATHLEN], *targetfile;
72   struct stat sb;
73   int flag1, flag2;
74
75   EXEC SQL CONNECT :db;
76
77   if (argc == 2)
78     {
79       if (stat(argv[1], &sb) == 0)
80         {
81           if (ModDiff(&flag1, "users", sb.st_mtime) ||
82               ModDiff(&flag2, "list", sb.st_mtime))
83             exit(MR_DATE);
84           if (flag1 < 0 && flag2 < 0)
85             {
86               fprintf(stderr, "File %s does not need to be rebuilt.\n",
87                       argv[1]);
88               exit(MR_NO_CHANGE);
89             }
90         }
91       targetfile = argv[1];
92       sprintf(filename, "%s~", targetfile);
93       if (!(out = fopen(filename, "w")))
94         {
95           fprintf(stderr, "unable to open %s for output\n", filename);
96           exit(MR_OCONFIG);
97         }
98     }
99   else if (argc != 1)
100     {
101       fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
102       exit(MR_ARGS);
103     }
104
105   fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
106   fprintf(out, "# This file is automatically generated, "
107           "do not edit it directly.\n%s\n\n", divide);
108
109   get_info();
110
111   EXEC SQL COMMIT;
112
113   incount = 0;
114   fprintf(out, "\n%s\n# Mailing lists\n%s\n\n", divide, divide);
115   hash_step(lists, save_mlist, FALSE);
116   fprintf(stderr, "Output %d lists\n", incount);
117
118   incount = 0;
119   fprintf(out, "\n%s\n# People\n%s\n\n", divide, divide);
120   hash_step(users, output_login, out);
121   fprintf(stderr, "Output %d users\n", incount);
122
123   fprintf(out, "\n%s\n# End of aliases file\n", divide);
124
125   if (fclose(out))
126     {
127       perror("close failed");
128       exit(MR_CCONFIG);
129     }
130
131   if (argc == 2)
132     fix_file(targetfile);
133   exit(MR_SUCCESS);
134 }
135
136 void get_info(void)
137 {
138   EXEC SQL BEGIN DECLARE SECTION;
139   int id, pid, bid, cnt, maillistp, acl, mid;
140   char mname[MACHINE_NAME_SIZE], str[STRINGS_STRING_SIZE];
141   char login[USERS_LOGIN_SIZE], potype[USERS_POTYPE_SIZE];
142   char lname[LIST_NAME_SIZE], desc[LIST_DESCRIPTION_SIZE];
143   char type[LIST_ACL_TYPE_SIZE];
144   EXEC SQL END DECLARE SECTION;
145   char *s;
146   struct user *u;
147   struct list *l, *memberlist;
148   struct member *m;
149
150   /* The following is declarative, not executed,
151    * and so is dependent on where it is in the file,
152    * not in the order of execution of statements.
153    */
154   EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
155
156   cnt = 0;
157   machines = create_hash(100);
158
159   EXEC SQL DECLARE m_cursor CURSOR FOR
160     SELECT mach_id, name
161     FROM machine
162     WHERE status = 1
163     AND mach_id IN ( SELECT UNIQUE pop_id FROM users )
164     ORDER BY mach_id;
165   EXEC SQL OPEN m_cursor;
166   while (1)
167     {
168       EXEC SQL FETCH m_cursor INTO :id, :mname;
169       if (sqlca.sqlcode)
170         break;
171       if ((s = strchr(mname, '.')))
172         *s = '\0';
173       else
174         strtrim(mname);
175 #ifdef ATHENA
176       strcat(mname, ".LOCAL");
177 #endif
178       if (hash_store(machines, id, strdup(mname)) < 0)
179         {
180           fprintf(stderr, "Out of memory!\n");
181           exit(MR_NO_MEM);
182         }
183       cnt++;
184     }
185   EXEC SQL CLOSE m_cursor;
186
187   fprintf(stderr, "Loaded %d machines\n", cnt);
188
189   cnt = 0;
190   strings = create_hash(11001);
191
192   EXEC SQL DECLARE s_cursor CURSOR FOR
193     SELECT string_id, string
194     FROM strings
195     ORDER BY string_id;
196   EXEC SQL OPEN s_cursor;
197   while (1)
198     {
199       EXEC SQL FETCH s_cursor INTO :id, :str;
200       if (sqlca.sqlcode)
201         break;
202       if (hash_store(strings, id, strdup(strtrim(str))) < 0)
203         {
204           fprintf(stderr, "Out of memory!\n");
205           exit(MR_NO_MEM);
206         }
207       cnt++;
208     }
209   EXEC SQL CLOSE s_cursor;
210
211   fprintf(stderr, "Loaded %d strings\n", cnt);
212
213   cnt = 0;
214   users = create_hash(13001);
215
216   EXEC SQL DECLARE u_cursor CURSOR FOR
217     SELECT users_id, login, potype, pop_id, box_id
218     FROM users
219     WHERE status != 3
220     ORDER BY users_id;
221   EXEC SQL OPEN u_cursor;
222   while (1)
223     {
224       EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :bid;
225       if (sqlca.sqlcode)
226         break;
227       u = malloc(sizeof(struct user));
228       u->login = strdup(strtrim(login));
229
230       if (potype[0] == 'P' && (s = hash_lookup(machines, pid)))
231         {
232           char *buf = malloc(strlen(u->login) + strlen(s) + 2);
233           sprintf(buf, "%s@%s", u->login, s);
234           u->pobox = buf;
235         }
236       else if (potype[0] ==  'S')
237         u->pobox = hash_lookup(strings, bid);
238       else
239         u->pobox = NULL;
240
241       check_string(u->login);
242       if (hash_store(users, id, u) < 0)
243         {
244           fprintf(stderr, "Out of memory!\n");
245           exit(MR_NO_MEM);
246         }
247       cnt++;
248     }
249   EXEC SQL CLOSE u_cursor;
250   fprintf(stderr, "Loaded %d users\n", cnt);
251
252   cnt = 0;
253   lists = create_hash(15000);
254
255   EXEC SQL DECLARE l_cursor CURSOR FOR
256     SELECT list_id, name, maillist, description, acl_type, acl_id
257     FROM list
258     WHERE active != 0
259     ORDER BY list_id;
260   EXEC SQL OPEN l_cursor;
261   while (1)
262     {
263       EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl;
264       if (sqlca.sqlcode)
265         break;
266       l = malloc(sizeof(struct list));
267       l->name = strdup(strtrim(lname));
268       l->maillist = maillistp;
269       l->description = strdup(strtrim(desc));
270       l->acl_t = type[0];
271       l->acl_id = acl;
272       l->m = NULL;
273       if (hash_store(lists, id, l) < 0)
274         {
275           fprintf(stderr, "Out of memory!\n");
276           exit(MR_NO_MEM);
277         }
278       cnt++;
279     }
280   EXEC SQL CLOSE l_cursor;
281   fprintf(stderr, "Loaded %d lists\n", cnt);
282
283   cnt = 0;
284
285   EXEC SQL DECLARE m_cursor2 CURSOR FOR
286     SELECT list_id, member_type, member_id
287     FROM imembers
288     WHERE direct = 1
289     ORDER BY list_id;
290   EXEC SQL OPEN m_cursor2;
291   while (1)
292     {
293       EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
294       if (sqlca.sqlcode)
295         break;
296       cnt++;
297       if ((l = hash_lookup(lists, id)))
298         {
299           m = malloc(sizeof(struct member));
300           if (type[0] == 'U' && (u = hash_lookup(users, mid)))
301             {
302               m->list_id = 0;
303               m->name = u->login;
304               m->next = l->m;
305               l->m = m;
306             }
307           else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
308             {
309               m->list_id = mid;
310               m->name = memberlist->name;
311               m->next = l->m;
312               l->m = m;
313             }
314           else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
315             {
316               m->list_id = 0;
317               m->next = l->m;
318               l->m = m;
319               m->name = s;
320             }
321         }
322     }
323   EXEC SQL CLOSE m_cursor2;
324   fprintf(stderr, "Loaded %d members\n", cnt);
325
326   EXEC SQL COMMIT;
327   return;
328 sqlerr:
329   db_error(sqlca.sqlcode);
330   exit(MR_DBMS_ERR);
331 }
332
333
334 void save_mlist(int id, void *list, void *force)
335 {
336   struct member *m;
337   struct list *l = list, *l1;
338
339   if (l->maillist > 1 || (l->maillist == 0 && !force) ||
340       !check_string(l->name))
341     return;
342
343   /* If user group appears on list, replace with user. */
344   if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
345     {
346       l->maillist = 3;
347       return;
348     }
349   l->maillist = 2;
350   output_mlist(id, l);
351
352   if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
353     save_mlist(0, l1, (void *)TRUE);
354
355   for (m = l->m; m; m = m->next)
356     {
357       if (m->list_id && (l1 = hash_lookup(lists, m->list_id)))
358         save_mlist(0, l1, (void *)TRUE);
359     }
360 }
361
362 void output_login(int dummy, void *user, void *out)
363 {
364   struct user *u = user;
365
366   incount++;
367   if (u->pobox && check_string(u->login) && u->login[0] != '#')
368     fprintf(out, "%s: %s\n", u->login, u->pobox);
369 }
370
371 void output_mlist(int id, struct list *l)
372 {
373   struct list *l1;
374   struct member *m;
375   struct user *u;
376   int line_width, alias_width, word_width, beginning;
377   static int cont = 1;
378   char str[8];
379
380   put_fill(out, l->description);
381   if (l->acl_t ==  'L' && (l1 = hash_lookup(lists, l->acl_id)))
382     fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
383   else if (l->acl_t ==  'U' && (u = hash_lookup(users, l->acl_id)))
384     fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
385   else
386     fprintf(out, "%s: ", l->name);
387
388   alias_width = line_width = strlen(l->name) + 2;
389   beginning = 1;
390   for (m = l->m; m; m = m->next)
391     {
392       word_width = strlen(m->name);
393
394       if (!beginning && alias_width + word_width + 2 > MAX_ALIAS_WIDTH)
395         {
396           /* Make a continuation. */
397           sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
398                   rand() % 26 + 97, rand() % 26 + 97,
399                   rand() % 26 + 97, rand() % 26 + 97);
400           fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
401           cont++;
402           alias_width = line_width = 17 + word_width;
403           fputs(m->name, out);
404         }
405       else if (beginning)
406         {
407           /* Beginning of alias, so don't wrap. */
408           line_width += word_width;
409           alias_width = line_width;
410           fputs(m->name, out);
411           beginning = 0;
412         }
413       else if (line_width + word_width + 2 > MAX_LINE_WIDTH)
414         {
415           /* Wrap. */
416           fprintf(out, ",\n\t%s", m->name);
417           alias_width += line_width + word_width + 2;
418           line_width = word_width + 8;
419         }
420       else
421         {
422           /* Continue line. */
423           line_width += word_width + 2;
424           fprintf(out, ", %s", m->name);
425         }
426     }
427   if (!l->m)
428     fprintf(out, "/dev/null");
429   fprintf(out, "\n\n");
430   incount++;
431 }
432
433 /* Write a word-wrapped list description to the aliases file as a
434  * comment. */
435 void put_fill(FILE *aliases, char *string)
436 {
437   char *c;
438   int line_width;
439   int word_width;
440
441   if (!string || !*string)
442     return;
443   fputs("#  ", aliases);
444   line_width = 3;
445
446   while (1)
447     {
448       while (*string == ' ')
449         string++;
450       c = strchr(string, ' ');
451       if (!c)
452         word_width = strlen(string);
453       else
454         {
455           word_width = c - string;
456           *c = '\0';
457         }
458
459       if (line_width + word_width > MAX_LINE_WIDTH)
460         {
461           fputs("\n#  ", aliases);
462           line_width = 3;
463           fputs(string, aliases);
464         }
465       else
466         fputs(string, aliases);
467
468       if (!c)
469         break;
470       /* add a space after the word */
471       fputc(' ', aliases);
472       word_width++;
473       line_width += word_width;
474       string += word_width;
475       /* add another if after a period */
476       if (*--c == '.')
477         {
478           fputc(' ', aliases);
479           line_width++;
480         }
481     }
482
483   fputc('\n', aliases);
484 }
485
486
487 /* Illegal chars: this should correspond to the array used by
488  * setup_alis. */
489
490 static int illegalchars[] = {
491   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
492   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
493   1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
494   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
495   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
496   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
497   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
498   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
499   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
500   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
501   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
502   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
503   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
504   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
505   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
506   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
507 };
508
509 int check_string(char *s)
510 {
511   for (; *s; s++)
512     {
513       if (isupper(*s))
514         *s = tolower(*s);
515
516       if (illegalchars[(unsigned) *s])
517         return 0;
518     }
519   return 1;
520 }
This page took 0.085089 seconds and 5 git commands to generate.