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