1 /*:ts=8*/
2 /*****************************************************************************
3 * FIDOGATE --- Gateway UNIX Mail/News <-> FIDO NetMail/EchoMail
4 *
5 * $Id: areas.c,v 4.18 2004/08/22 20:19:11 n0ll Exp $
6 *
7 * Area <-> newsgroups conversion
8 *
9 *****************************************************************************
10 * Copyright (C) 1990-2004
11 * _____ _____
12 * | |___ | Martin Junius <mj.at.n0ll.dot.net>
13 * | | | | | | Radiumstr. 18
14 * |_|_|_|@home| D-51069 Koeln, Germany
15 *
16 * This file is part of FIDOGATE.
17 *
18 * FIDOGATE is free software; you can redistribute it and/or modify it
19 * under the terms of the GNU General Public License as published by the
20 * Free Software Foundation; either version 2, or (at your option) any
21 * later version.
22 *
23 * FIDOGATE is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with FIDOGATE; see the file COPYING. If not, write to the Free
30 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31 *****************************************************************************/
32
33 #include "fidogate.h"
34
35
36
37 /*
38 * Prototypes
39 */
40 static Area *area_build (Area *, char *, char *);
41 static void areas_init_xlate (void);
42 static Area *areas_parse_line (char *);
43 static int areas_do_file (char *);
44
45
46 /* Areas linked list */
47 static Area *area_list = NULL;
48 static Area *area_last = NULL;
49
50 /* Area <-> newsgroup char translation table */
51 static char areas_x_a[256]; /* Area -> newsgroup */
52 static char areas_x_g[256]; /* Newsgroup -> area */
53
54
55
56 /*
57 * Initialize translation tables from config option "AreasXlate"
58 */
areas_init_xlate(void)59 static void areas_init_xlate(void)
60 {
61 char *cf, *x_a, *x_g;
62 unsigned char *p, *q;
63
64 if((cf = cf_get_string("AreasXlate", TRUE)))
65 {
66 debug(8, "config: AreasXlate %s", cf);
67
68 /* Chars in area name */
69 x_a = xstrtok(cf , " \t");
70 /* Chars in newsgroup name */
71 x_g = xstrtok(NULL, " \t");
72 if(!x_a || !x_g)
73 return;
74
75 /* Fill table */
76 p = x_a;
77 q = x_g;
78 while(*p || *q)
79 {
80 if(*p)
81 areas_x_a[*p] = *q;
82 if(*q)
83 areas_x_g[*q] = *p;
84 if(*p)
85 p++;
86 if(*q)
87 q++;
88 }
89 }
90 }
91
92
93
94 /*
95 * Default max/limit msg size
96 */
97 static long areas_def_maxsize = MAXMSGSIZE; /* config.h */
98 static long areas_def_limitsize = 0; /* default unlimited */
99
100
areas_maxmsgsize(long int sz)101 void areas_maxmsgsize(long int sz)
102 {
103 areas_def_maxsize = sz;
104 }
105
areas_get_maxmsgsize(void)106 long areas_get_maxmsgsize(void)
107 {
108 return areas_def_maxsize;
109 }
110
areas_limitmsgsize(long int sz)111 void areas_limitmsgsize(long int sz)
112 {
113 areas_def_limitsize = sz;
114 }
115
areas_get_limitmsgsize(void)116 long areas_get_limitmsgsize(void)
117 {
118 return areas_def_limitsize;
119 }
120
121
122
123 /*
124 * Read list of areas from LIBDIR/AREAS file.
125 *
126 * Format:
127 * AREA NEWSGROUP [-options]
128 *
129 * Options:
130 * -a Z:N/F.P use alternate address for this area
131 * -z ZONE use AKA for zone Z for this area
132 * -o ORIGIN use alternate origin line for this area
133 * -d DISTRIBUTION use Distribution: DISTRIBUTION for this newsgroup
134 * -l only local xpostings allowed
135 * -x no xpostings allowed
136 * -g no messages from other gates FTN->Usenet
137 * -8 use ISO 8-bit umlauts
138 * -H AREA/NEWSGROUP match entire hierarchy, names are
139 * translated automatically
140 * -R LVL ^ARFC header level
141 * -m MAXSIZE set MaxMsgSize for this area (0 = infinity)
142 * -L LIMITSIZE set LimitMsgSize for this area (0 = infinity)
143 * -X "Xtra: xyz" add extra RFC header (multiple -X are allowed)
144 * -8 convert to 8bit iso-8859-1 characters
145 * -Q convert to quoted-printable iso-8859-1 characters
146 * -C def:in:out charset mapping setting
147 */
areas_parse_line(char * buf)148 static Area *areas_parse_line(char *buf)
149 {
150 Area *p;
151 char *a, *g, *o;
152
153 a = xstrtok(buf, " \t"); /* FTN area */
154 g = xstrtok(NULL, " \t"); /* Newsgroup */
155 if(a==NULL || g==NULL)
156 return NULL;
157
158 /* Check for include command */
159 if(strieq(a, "include"))
160 {
161 areas_do_file(g);
162 return NULL;
163 }
164
165 /* Create new areas entry */
166 p = (Area *)xmalloc(sizeof(Area));
167 p->next = NULL;
168 p->area = strsave(a);
169 p->group = strsave(g);
170 p->zone = cf_defzone();
171 node_invalid(&p->addr);
172 p->origin = NULL;
173 p->distribution = NULL;
174 p->flags = 0;
175 p->rfc_lvl = -1;
176 p->maxsize = -1;
177 p->limitsize = -1;
178 tl_init(&p->x_hdr);
179 p->charset = NULL;
180
181 /* Options */
182 for(o=xstrtok(NULL, " \t");
183 o;
184 o=xstrtok(NULL, " \t") )
185 {
186 if(!strcmp(o, "-a"))
187 /* -a Z:N/F.P */
188 if((o = xstrtok(NULL, " \t")))
189 asc_to_node(o, &p->addr, FALSE);
190 if(!strcmp(o, "-z"))
191 /* -z ZONE */
192 if((o = xstrtok(NULL, " \t")))
193 p->zone = atoi(o);
194 if(!strcmp(o, "-o"))
195 /* -o ORIGIN */
196 if((o = xstrtok(NULL, " \t")))
197 p->origin = strsave(o);
198 if(!strcmp(o, "-d"))
199 /* -d DISTRIBUTION */
200 if((o = xstrtok(NULL, " \t")))
201 p->distribution = strsave(o);
202 if(!strcmp(o, "-l"))
203 p->flags |= AREA_LOCALXPOST;
204 if(!strcmp(o, "-x"))
205 p->flags |= AREA_NOXPOST;
206 if(!strcmp(o, "-g"))
207 p->flags |= AREA_NOGATE;
208 if(!strcmp(o, "-H"))
209 p->flags |= AREA_HIERARCHY;
210 if(!strcmp(o, "-!"))
211 p->flags |= AREA_NO;
212 if(!strcmp(o, "-R"))
213 /* -R lvl */
214 if((o = xstrtok(NULL, " \t")))
215 p->rfc_lvl = atoi(o);
216 if(!strcmp(o, "-m"))
217 /* -m MAXMSGSIZE */
218 if((o = xstrtok(NULL, " \t")))
219 p->maxsize = atol(o);
220 if(!strcmp(o, "-L"))
221 /* -L LIMITMSGSIZE */
222 if((o = xstrtok(NULL, " \t")))
223 p->limitsize = atol(o);
224 if(!strcmp(o, "-X"))
225 /* -X "Xtra: xyz" */
226 if((o = xstrtok(NULL, " \t")))
227 tl_append(&p->x_hdr, o);
228 if(!strcmp(o, "-8"))
229 p->flags |= AREA_8BIT;
230 if(!strcmp(o, "-Q"))
231 p->flags |= AREA_QP;
232 if(!strcmp(o, "-C"))
233 /* -C DEF:IN:OUT */
234 if((o = xstrtok(NULL, " \t")))
235 p->charset = strsave(o);
236 }
237 /* Value not set or error */
238 if(p->maxsize < 0)
239 p->maxsize = areas_def_maxsize;
240 if(p->limitsize < 0)
241 p->limitsize = areas_def_limitsize;
242
243 debug(15, "areas: %s %s Z=%d A=%s R=%d S=%ld",
244 p->area, p->group, p->zone,
245 p->addr.zone!=-1 ? znfp1(&p->addr) : "",
246 p->rfc_lvl, p->maxsize );
247
248 return p;
249 }
250
251
areas_do_file(char * name)252 static int areas_do_file(char *name)
253 {
254 FILE *fp;
255 Area *p;
256
257 debug(14, "Reading areas file %s", name);
258
259 fp = xfopen(name, R_MODE_T);
260
261 while(cf_getline(buffer, BUFFERSIZE, fp))
262 {
263 p = areas_parse_line(buffer);
264 if(!p)
265 continue;
266
267 /*
268 * Put into linked list
269 */
270 if(area_list)
271 area_last->next = p;
272 else
273 area_list = p;
274 area_last = p;
275 }
276
277 fclose(fp);
278
279 return OK;
280 }
281
282
areas_init(void)283 void areas_init(void)
284 {
285 areas_init_xlate();
286 areas_do_file( cf_p_areas() );
287 }
288
289
290
291 /*
292 * Lookup area/newsgroup in area_list
293 *
294 * Parameters:
295 * area, NULL --- lookup by area
296 * NULL, group --- lookup by group
297 */
areas_lookup(char * area,char * group)298 Area *areas_lookup(char *area, char *group)
299 {
300 Area *p;
301
302 /*
303 * Inefficient search, but order is important!
304 */
305 for(p=area_list; p; p=p->next)
306 {
307 if(area && area[0]==p->area[0])
308 {
309 if(p->flags & AREA_HIERARCHY)
310 {
311 if(!strncmp(area, p->area, strlen(p->area)))
312 return p->flags & AREA_NO ? NULL
313 : area_build(p, area, group);
314 }
315 else
316 {
317 if(!strcmp(area, p->area ))
318 return p->flags & AREA_NO ? NULL : p;
319 }
320 }
321
322 if(group && group[0]==p->group[0])
323 {
324 if(p->flags & AREA_HIERARCHY)
325 {
326 if(!strncmp(group, p->group, strlen(p->group)))
327 return p->flags & AREA_NO ? NULL
328 : area_build(p, area, group);
329 }
330 else
331 {
332 if(!strcmp(group, p->group))
333 return p->flags & AREA_NO ? NULL : p;
334 }
335 }
336 }
337
338 return NULL;
339 }
340
341
342
343 /*
344 * Build area/newsgroup name from hierarchy matching pattern
345 */
area_build(Area * pa,char * area,char * group)346 static Area *area_build(Area *pa, char *area, char *group)
347 {
348 static char bufa[MAXPATH], bufg[MAXPATH];
349 static Area ret;
350 char *p, *q, *end;
351
352 *bufa = *bufg = 0;
353
354 ret = *pa;
355 ret.next = NULL;
356 ret.area = bufa;
357 ret.group = bufg;
358
359 /* AREA -> Newsgroup */
360 if(area) /* Was searching for area */
361 {
362 BUF_COPY(bufa, area);
363 BUF_COPY(bufg, pa->group);
364 p = bufg + strlen(bufg);
365 end = bufg + sizeof(bufg) - 1;
366 q = area + strlen(pa->area);
367
368 for(; *q && p<end; q++, p++)
369 if(areas_x_a[(unsigned char)*q])
370 *p = areas_x_a[(unsigned char)*q];
371 else
372 *p = tolower(*q);
373 *p = 0;
374 }
375
376 /* Newsgroup -> AREA */
377 if(group) /* Was searching for newsgroup */
378 {
379 BUF_COPY(bufa, pa->area);
380 BUF_COPY(bufg, group);
381 p = bufa + strlen(bufa);
382 end = bufa + sizeof(bufa) - 1;
383 q = group + strlen(pa->group);
384
385 for(; *q && p<end; q++, p++)
386 if(areas_x_g[(unsigned char)*q])
387 *p = areas_x_g[(unsigned char)*q];
388 else
389 *p = toupper(*q);
390 *p = 0;
391 }
392
393 return &ret;
394 }
395