]> andersk Git - moira.git/blob - gen/mailhub.pc
Don't generate hesiod pobox entries for users with a potype of "NONE".
[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 struct hash *users, *machines, *strings, *lists;
38 struct user {
39   char *login;
40   char *pobox;
41 };
42 struct member {
43   struct member *next;
44   char *name;
45   int list_id;
46 };
47 struct list {
48   char *name;
49   char maillist;
50   char *description;
51   char acl_t;
52   int acl_id;
53   char mailman;
54   char *mailman_server;
55   struct member *m;
56 };
57
58 void get_info(void);
59 int check_string(char *s);
60 void output_login(int dummy, void *names, void *out);
61 void output_mlist(int id, void *list, void *out);
62 void output_membership(struct list *l, FILE *out);
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   FILE *out = stdout;
73
74   srand(tm);
75   EXEC SQL CONNECT :db;
76
77   if (argc == 2)
78     {
79       targetfile = argv[1];
80       sprintf(filename, "%s~", targetfile);
81       if (!(out = fopen(filename, "w")))
82         {
83           fprintf(stderr, "unable to open %s for output\n", filename);
84           exit(MR_OCONFIG);
85         }
86     }
87   else if (argc != 1)
88     {
89       fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
90       exit(MR_ARGS);
91     }
92
93   fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
94   fprintf(out, "# This file is automatically generated, "
95           "do not edit it directly.\n%s\n\n", divide);
96
97   get_info();
98
99   EXEC SQL COMMIT;
100
101   incount = 0;
102   fprintf(out, "\n%s\n# Mailing lists\n%s\n\n", divide, divide);
103   hash_step(lists, output_mlist, out);
104   fprintf(stderr, "Output %d lists\n", incount);
105
106   incount = 0;
107   fprintf(out, "\n%s\n# People\n%s\n\n", divide, divide);
108   hash_step(users, output_login, out);
109   fprintf(stderr, "Output %d users\n", incount);
110
111   fprintf(out, "\n%s\n# End of aliases file\n", divide);
112
113   if (fclose(out))
114     {
115       perror("close failed");
116       exit(MR_CCONFIG);
117     }
118
119   if (argc == 2)
120     fix_file(targetfile);
121   exit(MR_SUCCESS);
122 }
123
124 void get_info(void)
125 {
126   EXEC SQL BEGIN DECLARE SECTION;
127   int id, pid, iid, bid, cnt, maillistp, acl, mid, mailman;
128   char mname[MACHINE_NAME_SIZE], str[STRINGS_STRING_SIZE];
129   char login[USERS_LOGIN_SIZE], potype[USERS_POTYPE_SIZE];
130   char lname[LIST_NAME_SIZE], desc[LIST_DESCRIPTION_SIZE];
131   char type[LIST_ACL_TYPE_SIZE], mailman_server[MACHINE_NAME_SIZE];
132   EXEC SQL END DECLARE SECTION;
133   char *s;
134   struct user *u;
135   struct list *l, *memberlist;
136   struct member *m;
137
138   /* The following is declarative, not executed,
139    * and so is dependent on where it is in the file,
140    * not in the order of execution of statements.
141    */
142   EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
143
144   cnt = 0;
145   machines = create_hash(100);
146
147   EXEC SQL DECLARE m_cursor CURSOR FOR
148     SELECT mach_id, name
149     FROM machine
150     WHERE status = 1
151     AND ( mach_id IN ( SELECT UNIQUE pop_id FROM users ) OR
152           mach_id IN ( SELECT UNIQUE mach_id FROM filesys
153                        WHERE type = 'IMAP' ) )
154     ORDER BY mach_id;
155   EXEC SQL OPEN m_cursor;
156   while (1)
157     {
158       EXEC SQL FETCH m_cursor INTO :id, :mname;
159       if (sqlca.sqlcode)
160         break;
161       if ((s = strchr(mname, '.')))
162         *s = '\0';
163       else
164         strtrim(mname);
165 #ifdef ATHENA
166       strcat(mname, ".LOCAL");
167 #endif
168       if (hash_store(machines, id, strdup(mname)) < 0)
169         {
170           fprintf(stderr, "Out of memory!\n");
171           exit(MR_NO_MEM);
172         }
173       cnt++;
174     }
175   EXEC SQL CLOSE m_cursor;
176
177   fprintf(stderr, "Loaded %d machines\n", cnt);
178
179   cnt = 0;
180   strings = create_hash(11001);
181
182   EXEC SQL DECLARE s_cursor CURSOR FOR
183     SELECT string_id, string
184     FROM strings
185     ORDER BY string_id;
186   EXEC SQL OPEN s_cursor;
187   while (1)
188     {
189       EXEC SQL FETCH s_cursor INTO :id, :str;
190       if (sqlca.sqlcode)
191         break;
192       if (hash_store(strings, id, strdup(strtrim(str))) < 0)
193         {
194           fprintf(stderr, "Out of memory!\n");
195           exit(MR_NO_MEM);
196         }
197       cnt++;
198     }
199   EXEC SQL CLOSE s_cursor;
200
201   fprintf(stderr, "Loaded %d strings\n", cnt);
202
203   cnt = 0;
204   users = create_hash(13001);
205
206   EXEC SQL DECLARE u_cursor CURSOR FOR
207     SELECT users_id, login, potype, pop_id, imap_id, box_id
208     FROM users
209     WHERE status != 3
210     ORDER BY users_id;
211   EXEC SQL OPEN u_cursor;
212   while (1)
213     {
214       char *saddr = NULL, *paddr = NULL;
215
216       EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :iid, :bid;
217       if (sqlca.sqlcode)
218         break;
219       u = malloc(sizeof(struct user));
220       u->login = strdup(strtrim(login));
221
222       if (!strcmp(strtrim(potype), "NONE"))
223         u->pobox = NULL;
224       else
225         {
226           /* If SMTP or SPLIT, get SMTP address. */
227           if (potype[0] == 'S')
228             {
229               saddr = hash_lookup(strings, bid);
230
231               /* If SMTP, clear pid and iid. */
232               if (potype[1] == 'M')
233                 pid = iid = 0;
234             }
235
236           /* If IMAP, or SPLIT with IMAP, set pid to mach_id. */
237           if (potype[0] == 'I' || (potype[0] == 'S' && iid))
238             {
239               EXEC SQL SELECT mach_id INTO :pid FROM filesys
240                 WHERE filsys_id = :iid;
241             }
242
243           if (pid && (s = hash_lookup(machines, pid)))
244             {
245               paddr = malloc(strlen(u->login) + strlen(s) + 2);
246               sprintf(paddr, "%s@%s", u->login, s);
247             }
248
249           if (paddr && saddr)
250             {
251               u->pobox = malloc(strlen(paddr) + strlen(saddr) + 3);
252               sprintf(u->pobox, "%s, %s", paddr, saddr);
253               free(paddr);
254             }
255           else if (paddr)
256             u->pobox = paddr;
257           else
258             u->pobox = saddr;
259         }
260
261       check_string(u->login);
262       if (hash_store(users, id, u) < 0)
263         {
264           fprintf(stderr, "Out of memory!\n");
265           exit(MR_NO_MEM);
266         }
267       cnt++;
268     }
269   EXEC SQL CLOSE u_cursor;
270   fprintf(stderr, "Loaded %d users\n", cnt);
271
272   cnt = 0;
273   lists = create_hash(15000);
274
275   EXEC SQL DECLARE l_cursor CURSOR FOR
276     SELECT l.list_id, l.name, l.maillist, l.description, l.acl_type, l.acl_id,
277     l.mailman, m.name
278     FROM list l, machine m
279     WHERE active != 0 AND l.mailman_id = m.mach_id
280     ORDER BY list_id;
281   EXEC SQL OPEN l_cursor;
282   while (1)
283     {
284       EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl,
285         :mailman, :mailman_server;
286       if (sqlca.sqlcode)
287         break;
288       l = malloc(sizeof(struct list));
289       l->name = strdup(strtrim(lname));
290       l->maillist = maillistp;
291       l->description = strdup(strtrim(desc));
292       l->acl_t = type[0];
293       l->acl_id = acl;
294       l->mailman = mailman;
295       l->mailman_server = strdup(strtrim(mailman_server));
296       l->m = NULL;
297       if (hash_store(lists, id, l) < 0)
298         {
299           fprintf(stderr, "Out of memory!\n");
300           exit(MR_NO_MEM);
301         }
302       cnt++;
303     }
304   EXEC SQL CLOSE l_cursor;
305   fprintf(stderr, "Loaded %d lists\n", cnt);
306
307   cnt = 0;
308
309   EXEC SQL DECLARE m_cursor2 CURSOR FOR
310     SELECT list_id, member_type, member_id
311     FROM imembers
312     WHERE direct = 1
313     ORDER BY list_id;
314   EXEC SQL OPEN m_cursor2;
315   while (1)
316     {
317       EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
318       if (sqlca.sqlcode)
319         break;
320       cnt++;
321       if ((l = hash_lookup(lists, id)))
322         {
323           m = malloc(sizeof(struct member));
324           if (type[0] == 'U' && (u = hash_lookup(users, mid)))
325             {
326               m->list_id = 0;
327               m->name = u->login;
328               m->next = l->m;
329               l->m = m;
330             }
331           else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
332             {
333               m->list_id = mid;
334               m->name = memberlist->name;
335               m->next = l->m;
336               l->m = m;
337             }
338           else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
339             {
340               m->list_id = 0;
341               m->next = l->m;
342               l->m = m;
343               m->name = s;
344             }
345         }
346     }
347   EXEC SQL CLOSE m_cursor2;
348   fprintf(stderr, "Loaded %d members\n", cnt);
349
350   EXEC SQL COMMIT;
351   return;
352 sqlerr:
353   db_error(sqlca.sqlcode);
354   exit(MR_DBMS_ERR);
355 }
356
357
358 void output_login(int dummy, void *user, void *out)
359 {
360   struct user *u = user;
361
362   incount++;
363   if (u->pobox && check_string(u->login) && u->login[0] != '#')
364     fprintf(out, "%s: %s\n", u->login, u->pobox);
365 }
366
367 int line_width, alias_width;
368 static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
369                                           "-bounces", "-confirm", "-join",
370                                           "-leave", "-subscribe",
371                                           "-unsubscribe", NULL };
372
373 void output_mlist(int id, void *list, void *out)
374 {
375   struct list *l = list, *l1;
376   struct user *u;
377   int len = strlen(l->name), i;
378
379   if (!l->maillist || !check_string(l->name))
380     return;
381
382   /* If standard user group appears on a list, substitute in the user. */
383   if (l->m && l->m->next == NULL && !strcasecmp(l->name, l->m->name))
384     return;
385
386   put_fill(out, l->description);
387
388   if (l->mailman && strcmp(l->mailman_server, "[NONE]"))
389     {
390       for (i = 0; mailman_suffixes[i]; i++)
391         fprintf(out, "%s%s: %s%s@%s\n", l->name, mailman_suffixes[i], l->name,
392                 mailman_suffixes[i], l->mailman_server);
393       fprintf(out, "owner-%s: %s-owner@%s\n", l->name, l->name,
394               l->mailman_server);
395     }
396   else if (l->acl_t ==  'L' && (l1 = hash_lookup(lists, l->acl_id)))
397     {
398       fprintf(out, "owner-%s: ", l->name);
399       if ((l1->maillist) && (strcmp(l->name, l1->name)))
400         fprintf(out, "%s\n", l1->name);
401       else
402         {
403           alias_width = line_width = len + 8;
404           output_membership(l1, out);
405           fprintf(out, "\n");
406         }
407     }
408   else if (l->acl_t ==  'U' && (u = hash_lookup(users, l->acl_id)))
409     fprintf(out, "owner-%s: %s\n", l->name, u->login);
410
411   fprintf(out, "%s: ", l->name);
412   alias_width = line_width = len + 2;
413   output_membership(l, out);
414   fprintf(out, "\n\n");
415   incount++;
416 }
417
418 void output_membership(struct list *l, FILE *out)
419 {
420   struct member *m;
421   struct list *l1;
422   int word_width, linestart = 1;
423   static int cont = 1;
424   char str[8];
425
426   for (m = l->m; m; m = m->next)
427     {
428       word_width = strlen(m->name);
429
430       if (!linestart && alias_width + word_width + 2 > MAX_ALIAS_WIDTH)
431         {
432           /* Make a continuation. */
433           sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
434                   rand() % 26 + 97, rand() % 26 + 97,
435                   rand() % 26 + 97, rand() % 26 + 97);
436           fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
437           cont++;
438           alias_width = line_width = 17 + word_width;
439         }
440       else if (linestart)
441         {
442           /* First word on line, so we can't wrap. */
443           line_width += word_width;
444           alias_width = line_width;
445           linestart = 0;
446         }
447       else if (line_width + word_width + 2 > MAX_LINE_WIDTH)
448         {
449           /* Wrap. */
450           fputs(",\n\t", out);
451           alias_width += line_width + word_width + 2;
452           line_width = word_width + 8;
453         }
454       else
455         {
456           /* Continue line. */
457           line_width += word_width + 2;
458           fputs(", ", out);
459         }
460
461       if (m->list_id && (l1 = hash_lookup(lists, m->list_id)) && !l1->maillist)
462         output_membership(l1, out);
463       else
464         fputs(m->name, out);
465     }
466   if (!l->m)
467     fprintf(out, "/dev/null");
468 }
469
470 /* Write a word-wrapped list description to the aliases file as a
471  * comment. */
472 void put_fill(FILE *aliases, char *string)
473 {
474   char *c;
475   int line_width;
476   int word_width;
477
478   if (!string || !*string)
479     return;
480   fputs("#  ", aliases);
481   line_width = 3;
482
483   while (1)
484     {
485       while (*string == ' ')
486         string++;
487       c = strchr(string, ' ');
488       if (!c)
489         word_width = strlen(string);
490       else
491         {
492           word_width = c - string;
493           *c = '\0';
494         }
495
496       if (line_width + word_width > MAX_LINE_WIDTH)
497         {
498           fputs("\n#  ", aliases);
499           line_width = 3;
500           fputs(string, aliases);
501         }
502       else
503         fputs(string, aliases);
504
505       if (!c)
506         break;
507       /* add a space after the word */
508       fputc(' ', aliases);
509       word_width++;
510       line_width += word_width;
511       string += word_width;
512       /* add another if after a period */
513       if (*--c == '.')
514         {
515           fputc(' ', aliases);
516           line_width++;
517         }
518     }
519
520   fputc('\n', aliases);
521 }
522
523
524 /* Illegal chars: this no longer corresponds to the array 
525  * in setup_alis.  '+' is a valid character in a string on 
526  * a list, but is not a valid character in a listname.
527  */
528
529 static int illegalchars[] = {
530   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
531   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
532   1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
533   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
534   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
535   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
536   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
537   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
538   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
539   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
540   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
541   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
542   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
543   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
544   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
545   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
546 };
547
548 int check_string(char *s)
549 {
550   for (; *s; s++)
551     {
552       if (isupper(*s))
553         *s = tolower(*s);
554
555       if (illegalchars[(unsigned) *s])
556         return 0;
557     }
558   return 1;
559 }
This page took 2.135185 seconds and 5 git commands to generate.