]> andersk Git - moira.git/blob - gen/mailhub.pc
fix RCS IDs
[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 ML_WID  72
32 #define AL_MAX_WID 592
33
34 #define FALSE 0
35 #define TRUE (!FALSE)
36
37 FILE *out = stdout;
38
39 struct hash *users, *machines, *strings, *lists, *names;
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 struct names {
58   char *name;
59   struct names *next;
60   int keep;
61   int id;
62 };
63
64 void get_info(void);
65 void save_mlist(int id, void *list, void *force);
66 void insert_login(int id, void *user, void *hint);
67 void insert_name(char *s, int id, int nodups, int copy);
68 int hashstr(char *s);
69 void sort_info(void);
70 void output_data(int dummy, void *names, void *out);
71 void output_mlist(int id, struct list *l);
72 void do_member(FILE *out, char *s);
73 void put_fill(FILE *aliases, char *string);
74 void do_people(void);
75
76 int main(int argc, char **argv)
77 {
78   long tm = time(NULL);
79   char filename[MAXPATHLEN], *targetfile;
80   struct stat sb;
81   EXEC SQL BEGIN DECLARE SECTION;
82   int flag;
83   EXEC SQL END DECLARE SECTION;
84
85   EXEC SQL CONNECT :db;
86
87   if (argc == 2)
88     {
89       if (stat(argv[1], &sb) == 0)
90         {
91           if (ModDiff (&flag, "users", sb.st_mtime))
92             exit(MR_DATE);
93           if (flag < 0)
94             {
95               fprintf(stderr, "File %s does not need to be rebuilt.\n",
96                       argv[1]);
97               exit(MR_NO_CHANGE);
98             }
99         }
100       targetfile = argv[1];
101       sprintf(filename, "%s~", targetfile);
102       if (!(out = fopen(filename, "w")))
103         {
104           fprintf(stderr, "unable to open %s for output\n", filename);
105           exit(MR_OCONFIG);
106         }
107     }
108   else if (argc != 1)
109     {
110       fprintf(stderr, "usage: %s [outfile]\n", argv[0]);
111       exit(MR_ARGS);
112     }
113
114   fprintf(out, "%s\n# Aliases File Extract of %s", divide, ctime(&tm));
115   fprintf(out, "# This file is automatically generated, "
116           "do not edit it directly.\n%s\n\n", divide);
117
118   get_info();
119
120   EXEC SQL COMMIT;
121
122   fprintf(stderr, "Sorting Info\n");
123   sort_info();
124
125   fprintf(stderr, "Dumping information\n");
126   do_people();
127
128   fprintf(out, "\n%s\n# End of aliases file\n", divide);
129
130   if (fclose(out))
131     {
132       perror("close failed");
133       exit(MR_CCONFIG);
134     }
135
136   if (argc == 2)
137     fix_file(targetfile);
138   exit(MR_SUCCESS);
139 }
140
141 void get_info(void)
142 {
143   EXEC SQL BEGIN DECLARE SECTION;
144   int id, pid, bid, cnt, maillistp, acl, mid;
145   char mname[MACHINE_NAME_SIZE], str[STRINGS_STRING_SIZE];
146   char login[USERS_LOGIN_SIZE], potype[USERS_POTYPE_SIZE];
147   char lname[LIST_NAME_SIZE], desc[LIST_DESCRIPTION_SIZE];
148   char type[LIST_ACL_TYPE_SIZE];
149   EXEC SQL END DECLARE SECTION;
150   char *s;
151   struct user *u;
152   struct list *l, *memberlist;
153   struct member *m;
154
155   /* The following is declarative, not executed,
156    * and so is dependent on where it is in the file,
157    * not in the order of execution of statements.
158    */
159   EXEC SQL WHENEVER SQLERROR GOTO sqlerr;
160
161   cnt = 0;
162   machines = create_hash(1000);
163
164   EXEC SQL DECLARE m_cursor CURSOR FOR
165     SELECT mach_id, name
166     FROM machine
167     WHERE status = 1
168     ORDER BY mach_id;
169   EXEC SQL OPEN m_cursor;
170   while (1)
171     {
172       EXEC SQL FETCH m_cursor INTO :id, :mname;
173       if (sqlca.sqlcode)
174         break;
175       if ((s = strchr(mname, '.')))
176         *s = '\0';
177       else
178         strtrim(mname);
179 #ifdef ATHENA
180       strcat(mname, ".LOCAL");
181 #endif
182       if (hash_store(machines, id, strdup(mname)) < 0)
183         {
184           fprintf(stderr, "Out of memory!\n");
185           exit(MR_NO_MEM);
186         }
187       cnt++;
188     }
189   EXEC SQL CLOSE m_cursor;
190
191   fprintf(stderr, "Loaded %d machines\n", cnt);
192
193   cnt = 0;
194   strings = create_hash(11001);
195
196   EXEC SQL DECLARE s_cursor CURSOR FOR
197     SELECT string_id, string
198     FROM strings
199     ORDER BY string_id;
200   EXEC SQL OPEN s_cursor;
201   while (1)
202     {
203       EXEC SQL FETCH s_cursor INTO :id, :str;
204       if (sqlca.sqlcode)
205         break;
206       if (hash_store(strings, id, strdup(strtrim(str))) < 0)
207         {
208           fprintf(stderr, "Out of memory!\n");
209           exit(MR_NO_MEM);
210         }
211       cnt++;
212     }
213   EXEC SQL CLOSE s_cursor;
214
215   fprintf(stderr, "Loaded %d strings\n", cnt);
216
217   cnt = 0;
218   users = create_hash(13001);
219
220   EXEC SQL DECLARE u_cursor CURSOR FOR
221     SELECT users_id, login, potype, pop_id, box_id
222     FROM users
223     WHERE status != 3
224     ORDER BY users_id;
225   EXEC SQL OPEN u_cursor;
226   while (1)
227     {
228       EXEC SQL FETCH u_cursor INTO :id, :login, :potype, :pid, :bid;
229       if (sqlca.sqlcode)
230         break;
231       u = malloc(sizeof(struct user));
232       u->login = strdup(strtrim(login));
233
234       if (potype[0] == 'P' && (s = hash_lookup(machines, pid)))
235         {
236           char *buf = malloc(strlen(u->login) + strlen(s) + 2);
237           sprintf(buf, "%s@%s", u->login, s);
238           u->pobox = buf;
239         }
240       else if (potype[0] ==  'S')
241         u->pobox = hash_lookup(strings, bid);
242       else
243         u->pobox = NULL;
244       if (hash_store(users, id, u) < 0)
245         {
246           fprintf(stderr, "Out of memory!\n");
247           exit(MR_NO_MEM);
248         }
249       cnt++;
250     }
251   EXEC SQL CLOSE u_cursor;
252   fprintf(stderr, "Loaded %d users\n", cnt);
253
254   cnt = 0;
255   lists = create_hash(15000);
256
257   EXEC SQL DECLARE l_cursor CURSOR FOR
258     SELECT list_id, name, maillist, description, acl_type, acl_id
259     FROM list
260     WHERE active != 0
261     ORDER BY list_id;
262   EXEC SQL OPEN l_cursor;
263   while (1)
264     {
265       EXEC SQL FETCH l_cursor INTO :id, :lname, :maillistp, :desc, :type, :acl;
266       if (sqlca.sqlcode)
267         break;
268       l = malloc(sizeof(struct list));
269       l->name = strdup(strtrim(lname));
270       l->maillist = maillistp;
271       l->description = strdup(strtrim(desc));
272       l->acl_t = type[0];
273       l->acl_id = acl;
274       l->m = NULL;
275       if (hash_store(lists, id, l) < 0)
276         {
277           fprintf(stderr, "Out of memory!\n");
278           exit(MR_NO_MEM);
279         }
280       cnt++;
281     }
282   EXEC SQL CLOSE l_cursor;
283   fprintf(stderr, "Loaded %d lists\n", cnt);
284
285   cnt = 0;
286
287   EXEC SQL DECLARE m_cursor2 CURSOR FOR
288     SELECT list_id, member_type, member_id
289     FROM imembers
290     WHERE direct = 1
291     ORDER BY list_id;
292   EXEC SQL OPEN m_cursor2;
293   while (1)
294     {
295       EXEC SQL FETCH m_cursor2 INTO :id, :type, :mid;
296       if (sqlca.sqlcode)
297         break;
298       cnt++;
299       if ((l = hash_lookup(lists, id)))
300         {
301           m = malloc(sizeof(struct member));
302           if (type[0] == 'U' && (u = hash_lookup(users, mid)))
303             {
304               m->list_id = 0;
305               m->name = u->login;
306               m->next = l->m;
307               l->m = m;
308             }
309           else if (type[0] == 'L' && (memberlist = hash_lookup(lists, mid)))
310             {
311               m->list_id = mid;
312               m->name = memberlist->name;
313               m->next = l->m;
314               l->m = m;
315             }
316           else if (type[0] == 'S' && (s = hash_lookup(strings, mid)))
317             {
318               m->list_id = 0;
319               m->next = l->m;
320               l->m = m;
321               m->name = s;
322             }
323         }
324     }
325   EXEC SQL CLOSE m_cursor2;
326   fprintf(stderr, "Loaded %d members\n", cnt);
327
328   EXEC SQL COMMIT;
329   return;
330 sqlerr:
331   db_error(sqlca.sqlcode);
332   exit(MR_DBMS_ERR);
333 }
334
335
336 void save_mlist(int id, void *list, void *force)
337 {
338   struct member *m;
339   struct list *l = list, *l1;
340
341   if (l->maillist > 1 || (l->maillist == 0 && !force))
342     return;
343
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   insert_name(l->name, -1, TRUE, FALSE);
351   output_mlist(id, l);
352
353   if (l->acl_t == 'L' && (l1 = hash_lookup(lists, l->acl_id)))
354     save_mlist(0, l1, (void *)TRUE);
355
356   for (m = l->m; m; m = m->next)
357     {
358       if (m->list_id && (l1 = hash_lookup(lists, m->list_id)))
359         save_mlist(0, l1, (void *)TRUE);
360     }
361 }
362
363
364 void insert_login(int id, void *user, void *hint)
365 {
366   struct user *u = user;
367   if (u->pobox && u->login[0] != '#')
368     insert_name(u->login, id, TRUE, FALSE);
369 }
370
371 int incount = 0;
372
373 void insert_name(char *s, int id, int nodups, int copy)
374 {
375   int code;
376   struct names *ns;
377
378   incount++;
379   code = hashstr(s);
380   ns = hash_lookup(names, code);
381   if (!ns)
382     {
383       if (!(ns = malloc(sizeof(struct names))))
384         {
385           fprintf(stderr, "ran out of memory inserting name (sorting)\n");
386           exit(MR_NO_MEM);
387         }
388       if (copy)
389         ns->name = strdup(s);
390       else
391         ns->name = s;
392       ns->keep = nodups;
393       ns->id = id;
394       ns->next = NULL;
395       if (hash_store(names, code, ns) < 0)
396         {
397           fprintf(stderr, "Out of memory!\n");
398           exit(MR_NO_MEM);
399         }
400       return;
401     }
402   if (strcasecmp(ns->name, s))
403     {
404       while (ns->next)
405         {
406           ns = ns->next;
407           if (!strcasecmp(ns->name, s))
408             goto foundns;
409         }
410       if (!(ns->next = malloc(sizeof(struct names))))
411         {
412           fprintf(stderr, "ran out of memory insterting name (sorting)\n");
413           exit(MR_NO_MEM);
414         }
415       ns = ns->next;
416       if (copy)
417         ns->name = strdup(s);
418       else
419         ns->name = s;
420       ns->keep = nodups;
421       ns->id = id;
422       ns->next = NULL;
423       return;
424     }
425 foundns:
426   if (nodups || ns->keep)
427     {
428       if (nodups && ns->keep)
429         fprintf(stderr, "duplicated name: %s\n", s);
430       return;
431     }
432   ns->id = 0;
433 }
434
435
436 /* Illegal chars: ! " % ( ) , / : ; < = > @ [ \ ] ^ { | } */
437
438 static int illegalchars[] = {
439   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
440   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
441   0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, /* SPACE - / */
442   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, /* 0 - ? */
443   1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
444   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* P - _ */
445   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
446   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
447   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
448   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
449   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
450   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
451   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
452   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
453   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
454   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
455 };
456
457
458 /* While hashing the string, punt any illegal characters */
459
460 int hashstr(char *s)
461 {
462   int result;
463   int c;
464
465   for (result = 0; (c = *s); s++)
466     {
467       if (illegalchars[c])
468         {
469           char *p;
470           for (p = s; *p; p++)
471             *p = p[1];
472           continue;
473         }
474       if (isupper(c))
475         c = *s = tolower(c);
476       result = (result << 5) - result + c - '`';
477     }
478   return result < 0 ? -result : result;
479 }
480
481
482 void sort_info(void)
483 {
484   names = create_hash(20001);
485   hash_step(users, insert_login, NULL);
486   incount = 0;
487   fprintf(out, "\n%s\n# Mailing lists\n%s\n", divide, divide);
488   hash_step(lists, save_mlist, FALSE);
489   fprintf(stderr, "Output %d lists\n", incount);
490 }
491
492
493 void output_data(int dummy, void *names, void *out)
494 {
495   struct names *ns, *nms = names;
496   struct user *u;
497
498   incount++;
499   for (ns = nms; ns; ns = ns->next)
500     {
501       if (!ns->name[0] || !ns->name[1])
502         {
503           fprintf(stderr, "punting %s due to short name\n", ns->name);
504           continue;
505         }
506       if (ns->id > 0)
507         {
508           u = hash_lookup(users, ns->id);
509           if (u->pobox)
510             fprintf(out, "%s: %s\n", ns->name, u->pobox);
511         }
512     }
513 }
514
515
516 int lwid, bol, awid;
517
518 void output_mlist(int id, struct list *l)
519 {
520   struct list *l1;
521   struct member *m;
522   struct user *u;
523
524   put_fill(out, l->description);
525   if (l->acl_t ==  'L' && (l1 = hash_lookup(lists, l->acl_id)))
526     fprintf(out, "owner-%s: %s\n%s: ", l->name, l1->name, l->name);
527   else if (l->acl_t ==  'U' && (u = hash_lookup(users, l->acl_id)))
528     fprintf(out, "owner-%s: %s\n%s: ", l->name, u->login, l->name);
529   else
530     fprintf(out, "%s: ", l->name);
531
532   lwid = strlen(l->name) + 2;
533   bol = 1;
534   for (m = l->m; m; m = m->next)
535     do_member(out, m->name);
536   if (!l->m)
537     fprintf(out, "/dev/null");
538   fprintf(out, "\n\n");
539   incount++;
540 }
541
542
543 /* print out strings separated by commas, doing line breaks as appropriate */
544
545 void do_member(FILE *out, char *s)
546 {
547   int wwid;
548   static int cont = 1;
549   char str[8];
550
551   wwid = strlen(s);
552
553   if (!bol && awid + wwid + 2 > AL_MAX_WID)
554     {
555       sprintf(str, "%c%c%c%c%c%c", rand() % 26 + 97, rand() % 26 + 97,
556               rand() % 26 + 97, rand() % 26 + 97,
557               rand() % 26 + 97, rand() % 26 + 97);
558       str[6] = '\0';
559       fprintf(out, ",\n\tcont%d-%s\ncont%d-%s: ", cont, str, cont, str);
560       cont++;
561       awid = lwid = 17 + wwid;
562       fputs(s, out);
563       return;
564     }
565
566   if (bol)
567     {
568       lwid += wwid;
569       awid = lwid;
570       fputs(s, out);
571       bol = 0;
572       return;
573     }
574   if (lwid + wwid + 2 > ML_WID)
575     {
576       fprintf(out, ",\n\t%s", s);
577       awid += lwid + wwid + 2;
578       lwid = wwid + 8;
579       return;
580     }
581   lwid += wwid + 2;
582   fprintf(out, ", %s", s);
583 }
584
585
586 void put_fill(FILE *aliases, char *string)
587 {
588   char *c;
589   int lwid;
590   int wwid;
591
592   if (!string || !*string)
593     return;
594   fputs("#  ", aliases);
595   lwid = 3;
596
597   while (1)
598     {
599       while (*string == ' ')
600         string++;
601       c = strchr(string, ' ');
602       if (!c)
603         wwid = strlen(string);
604       else
605         {
606           wwid = c - string;
607           *c = '\0';
608         }
609
610       if ((lwid + wwid) > ML_WID)
611         {
612           fputs("\n#  ", aliases);
613           lwid = 3;
614           fputs(string, aliases);
615         }
616       else
617         fputs(string, aliases);
618
619       if (!c)
620         break;
621       /* add a space after the word */
622       fputc(' ', aliases);
623       wwid++;
624       lwid += wwid;
625       string += wwid;
626       /* add another if after a period */
627       if (*--c == '.')
628         {
629           fputc(' ', aliases);
630           lwid++;
631         }
632     }
633
634   fputc('\n', aliases);
635 }
636
637
638 void do_people(void)
639 {
640   incount = 0;
641   fprintf(out, "\n%s\n# People\n%s\n", divide, divide);
642   hash_step(names, output_data, out);
643   fprintf(stderr, "Output %d entries\n", incount);
644 }
This page took 0.074408 seconds and 5 git commands to generate.