source: trunk/third/moira/gen/mailhub.pc @ 24319

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