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

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