chiark / gitweb /
WIP input file handling
[innduct.git] / frontends / sys2nf.c
1 /*  $Id: sys2nf.c 7741 2008-04-06 09:51:47Z iulius $
2 **
3 **  Read a C news "sys" file and split it up into a set of INN
4 **  newsfeeds entries.  Also works with B news.
5 **
6 **  Once done, edit all files that have HELP or all in them.
7 **  Review all files, anyway.
8 */
9
10 #include "config.h"
11 #include "clibrary.h"
12 #include <ctype.h>
13 #include <errno.h>
14 #include <sys/stat.h>
15
16 #include "inn/innconf.h"
17 #include "libinn.h"
18 #include "nntp.h"
19
20 #define TEMPFILE        ":tmp"
21 static char             **Groups;
22
23
24 /*
25 **  Fill in the Groups array with the names of all active newsgroups.
26 */
27 static void
28 ReadActive(act)
29     char        *act;
30 {
31     FILE        *F;
32     int         i;
33     char        buff[BUFSIZ];
34     char        *p;
35
36     /* Open file, count lines. */
37     if ((F = fopen(act, "r")) == NULL) {
38         perror(act);
39         exit(1);
40     }
41     for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++)
42         continue;
43     Groups = xmalloc((i + 2) * sizeof(char *));
44
45     /* Fill in each word. */
46     rewind(F);
47     for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++) {
48         if ((p = strchr(buff, ' ')) != NULL)
49             *p = '\0';
50         Groups[i] = xstrdup(buff);
51     }
52     Groups[i] = NULL;
53     fclose(F);
54 }
55
56
57 /*
58 **  Read in the sys file and turn it into an array of strings, one
59 **  per continued line.
60 */
61 char **
62 ReadSys(sys)
63     char                *sys;
64 {
65     char        *p;
66     char        *to;
67     char        *site;
68     int i;
69     char                *data;
70     char                **strings;
71
72     /* Read in the file, get rough count. */
73     if ((data = ReadInFile(sys, (struct stat *)NULL)) == NULL) {
74         perror(sys);
75         exit(1);
76     }
77     for (p = data, i = 0; (p = strchr(p, '\n')) != NULL; p++, i++)
78         continue;
79
80     /* Scan the file, glue all multi-line entries. */
81     for (strings = xmalloc((i + 1) * sizeof(char *)), i = 0, to = p = data; *p; ) {
82         for (site = to; *p; ) {
83             if (*p == '\n') {
84                 p++;
85                 *to = '\0';
86                 break;
87             }
88             if (*p == '\\' && p[1] == '\n')
89                 while (*++p && CTYPE(isspace, *p))
90                     continue;
91             else
92                 *to++ = *p++;
93         }
94         *to++ = '\0';
95         if (*site == '\0')
96             continue;
97         strings[i++] = xstrdup(site);
98     }
99     strings[i] = NULL;
100     free(data);
101     return strings;
102 }
103
104
105 /*
106 **  Is this the name of a top-level group?  We want a simple name, "foo",
107 **  and should find a "foo." in the group list.
108 */
109 static bool
110 Toplevel(p)
111     char        *p;
112 {
113     char        **gp;
114     char        *g;
115     int         i;
116
117     if (strchr(p, '.') != NULL)
118         return false;
119     for (i = strlen(p) - 1, gp = Groups; (g = *gp++) != NULL; )
120         if (strncmp(p, g, i) == 0 && g[i + 1] == '.')
121             return true;
122     return false;
123 }
124
125
126 /*
127 **  Do we have a name that's a prefix for more then one newsgroup?
128 **  For "foo.bar", we must find more then one "foo.bar" or "foo.bar."
129 */
130 static bool
131 GroupPrefix(p)
132     char        *p;
133 {
134     char        **gp;
135     char        *g;
136     int         count;
137     int         i;
138
139     if (strchr(p, '.') == NULL)
140         return false;
141     for (i = strlen(p), count = 0, gp = Groups; (g = *gp++) != NULL; )
142         if (strcmp(p, g) == 0 || (strncmp(p, g, i) == 0 && g[i] == '.'))
143             count++;
144     return count > 1;
145 }
146
147
148 /*
149 **  Step through the old subscription list, try to update each one in
150 **  turn.
151 */
152 static void
153 DoSub(F, p)
154     FILE        *F;
155     char                *p;
156 {
157     char        *s;
158     int len, i;
159     bool matched;
160     bool        SawBang;
161     bool        SawAll;
162
163     /* Distributions, not newsgroups. */
164     static const char * const distributions[] = {
165         "world", "na", "usa", "inet", "mod", "net", "local"
166     };
167
168     /* Newsgroup hierarchies. */
169     static const char * const hierarchies[] = {
170         "comp", "misc", "news", "rec", "sci", "soc", "talk", "alt", "bionet",
171         "bit", "biz", "clari", "ddn", "gnu", "ieee", "k12", "pubnet", "trial",
172         "u3b", "vmsnet",
173
174         "ba", "ca", "dc", "ne", "ny", "tx",
175
176         "info", "mail", "opinions", "uunet"
177     }
178
179     if ((s = strtok(p, ",")) == NULL)
180         return;
181
182     fprintf(F, "!*");
183     len = 8 + 1 + 2;
184     do {
185         for (matched = false, i = 0; i < ARRAY_SIZE(distributions); i++)
186             if (strcmp(s, distributions[i]) == 0) {
187                 matched = true;
188                 break;
189             }
190         if (matched)
191             continue;
192
193         if (innconf->mergetogroups)
194             if (strcmp(s, "!to") == 0 || strncmp(s, "to.", 3) == 0)
195                 continue;
196
197         putc(',', F);
198         len++;
199
200         if (len + strlen(s) + 3 > 72) {
201             fprintf(F,"\\\n\t    ");
202             len = 12;
203         }
204
205         SawBang = *s == '!';
206         if (SawBang) {
207             putc('!', F);
208             len++;
209             s++;
210         }
211
212         SawAll = (strcmp(s, "all") == 0);
213         if (SawAll)
214             s = SawBang ? "*" : "*,!control,!control.*";
215         len += strlen(s);
216         fprintf(F, "%s", s);
217
218         if (SawAll)
219             ;
220         else {
221             for (matched = false, i = 0; i < ARRAY_SIZE(distributions); i++)
222                 if (strcmp(s, hierarchies[i]) == 0) {
223                     matched = true;
224                     break;
225                 }
226
227             if (matched) {
228                 fprintf(F, ".*");
229                 len += 2;
230             } else if (GroupPrefix(s)) {
231                 putc('*', F);
232                 len++;
233             }
234         }
235     } while ((s = strtok((char *)NULL, ",")) != NULL);
236 }
237
238
239 int
240 main(ac, av)
241     int          ac;
242     char        *av[];
243 {
244     FILE        *F;
245     FILE        *out;
246     char        **sites;
247     char        *f2;
248     char        *f3;
249     char        *f4;
250     char        *p;
251     char        *q;
252     char        *site;
253     char        buff[256];
254     char        *act;
255     char        *dir;
256     char        *sys;
257     int         i;
258
259     if (!innconf_read(NULL))
260         exit(1);
261     /* Set defaults. */
262     act = "/usr/local/lib/newslib/active";
263     sys = "sys";
264     dir = "feeds";
265     while ((i = getopt(ac, av, "a:s:d:")) != EOF)
266     switch (i) {
267     default:
268         exit(1);
269         /* NOTREACHED */
270     case 'a':   act = optarg;   break;
271     case 'd':   dir = optarg;   break;
272     case 's':   sys = optarg;   break;
273     }
274
275     sites = ReadSys(sys);
276     ReadActive(act);
277     if (mkdir(dir, 0777) < 0 && errno != EEXIST)
278         perror(dir), exit(1);
279     if (chdir(dir) < 0)
280         perror("chdir"), exit(1);
281     for ( ; ; ) {
282         /* Get next non-comment ilne. */
283         if ((p = *sites++) == NULL)
284             break;
285         for (F = fopen(TEMPFILE, "w"); p && *p == '#'; p = *sites++)
286             fprintf(F, "%s\n", p);
287         if (p == NULL) {
288             fclose(F);
289             break;
290         }
291         site = xstrdup(p);
292         if ((f2 = strchr(site, ':')) == NULL)
293             f2 = "HELP";
294         else
295             *f2++ = '\0';
296         if ((f3 = strchr(f2, ':')) == NULL)
297             f3 = "HELP";
298         else
299             *f3++ = '\0';
300         if ((f4 = strchr(f3, ':')) == NULL)
301             f4 = "HELP";
302         else
303             *f4++ = '\0';
304
305         /* Write the fields. */
306         fprintf(F, "%s\\\n", site);
307         fprintf(F, "\t:");
308         DoSub(F, f2);
309         fprintf(F, "\\\n");
310         if (strcmp(f3, "n") == 0)
311             fprintf(F, "\t:Tf,Wnm\\\n", f3);
312         else
313             fprintf(F, "\t:HELP%s\\\n", f3);
314         fprintf(F, "\t:%s\n", f4);
315         if (ferror(F) || fclose(F) == EOF)
316             perror(TEMPFILE), exit(1);
317
318         free(site);
319
320         /* Find the sitename. */
321         for (q = p; *q && *q != '/' && *q != ':'; q++)
322             continue;
323         *q = '\0';
324
325         /* Append temp file to site file. */
326         if ((F = fopen(TEMPFILE, "r")) == NULL)
327             perror(TEMPFILE), exit(1);
328         if ((out = xfopena(p)) == NULL)
329             perror(p), exit(1);
330         while ((i = fread(buff, 1, sizeof buff, F)) > 0)
331             if (fwrite(buff, 1, i, out) != i)
332                 perror(p), exit(1);
333         fclose(F);
334         if (fclose(out) == EOF)
335             perror(p), exit(1);
336
337         if (unlink(TEMPFILE) < 0)
338             perror("can't unlink temp file");
339     }
340
341     exit(0);
342     /* NOTREACHED */
343 }