1 /* $Id$
2    Written 1999 by Tobias Ernst and released do the Public Domain.
3    This file is part of NLTOOLS, the nodelist processor of the Husky fidonet
4    software project.
5 
6    Fido Userlist Compiler routines
7 */
8 #include <stdio.h>
9 #include <string.h>
10 #include <assert.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include "nlstring.h"
14 #include "ulc.h"
15 
16 enum
17 { T_ZONE, T_REGION, T_HOST, T_HUB, T_NODE };
18 
19 /* A node or point has been parsed in a node list. Write it in Fidouser.Lst
20    format to the output file. The output file is not yet sorted. The
21    "username" parameter should contain underscores instead of spaces. */
22 
23 #define ENTRYLENGTH 60          /* without trailing \r\n! */
24 
parsednode(FILE * fout,unsigned zone,unsigned net,unsigned node,unsigned point,char * username)25 static int parsednode( FILE * fout, unsigned zone, unsigned net, unsigned node,
26                        unsigned point, char *username )
27 {
28   char rev_username[ENTRYLENGTH + 3], *cp, *cp2;
29   char nodenr[24];
30 
31   cp = strrchr( username, '_' );
32 
33   if( cp == NULL )
34   {
35     strncpy( rev_username, username, ENTRYLENGTH );
36     rev_username[ENTRYLENGTH] = '\0';
37   }
38   else
39   {
40     strncpy( rev_username, cp + 1, ENTRYLENGTH - 2 );
41     strcat( rev_username, ", " );
42     *cp = 0;
43 
44     for( cp = username, cp2 = rev_username + strlen( rev_username );
45          *cp && cp2 - rev_username < ENTRYLENGTH; cp++, cp2++ )
46     {
47       if( *cp == '_' )
48       {
49         *cp2 = ' ';
50       }
51       else
52       {
53         *cp2 = *cp;
54       }
55     }
56     *cp2 = '\0';
57   }
58 
59   sprintf( nodenr, "%u:%u/%u.%u", zone % 65536, net % 65536, node % 65536, point % 65536 );
60 
61   if( strlen( rev_username ) > ENTRYLENGTH - strlen( nodenr ) - 1 )
62   {
63     rev_username[ENTRYLENGTH - strlen( nodenr ) - 1] = '\0';
64   }
65   else
66   {
67     for( cp = rev_username + strlen( rev_username );
68          cp - rev_username < ENTRYLENGTH - ( signed ) strlen( nodenr ) - 1; cp++ )
69     {
70       *cp = ' ';
71     }
72   }
73 
74   strcat( rev_username, " " );
75   strcat( rev_username, nodenr );
76   strcat( rev_username, "\r\n" );
77 
78   return ( fwrite( rev_username, ENTRYLENGTH + 2, 1, fout ) == 1 );
79 }
80 
81 /* Process a line from a nodelist file */
82 
parse2d(char * ptr,unsigned int * net,unsigned int * node)83 static void parse2d( char *ptr, unsigned int *net, unsigned int *node )
84 {
85   *net = 0;
86   *node = 0;
87   while( isdigit( *ptr ) )
88   {
89     *net = 10 * ( *net ) + ( *ptr ) - '0';
90     ptr++;
91   }
92   if( ( *( ptr ) ) != '/' )
93   {
94     *net = *node = 0;
95   }
96   else
97   {
98     ptr++;
99     while( isdigit( *ptr ) )
100     {
101       *node = 10 * ( *node ) + ( *ptr ) - '0';
102       ptr++;
103     }
104     if( *ptr )
105     {
106       *net = *node = 0;
107     }
108   }
109 }
110 
parse3d(char * ptr,unsigned int * zone,unsigned int * net,unsigned int * node)111 static void parse3d( char *ptr, unsigned int *zone, unsigned int *net, unsigned int *node )
112 {
113   *zone = 0;
114   while( isdigit( *ptr ) )
115   {
116     *zone = 10 * ( *zone ) + ( *ptr ) - '0';
117     ptr++;
118   }
119   if( ( *( ptr ) ) != ':' )
120   {
121     *zone = *net = *node = 0;
122   }
123   else
124   {
125     ptr++;
126     parse2d( ptr, net, node );
127   }
128 }
129 
ulc_line(FILE * fin,FILE * fout,unsigned format,unsigned * zone,unsigned * net,unsigned * node)130 static int ulc_line( FILE * fin, FILE * fout, unsigned format,
131                      unsigned *zone, unsigned *net, unsigned *node )
132 {
133   char linebuf[128], *ptr = NULL, *sptr = NULL;
134   size_t l;
135   int incomplete;
136   int k, rv = 1;
137   char *username = NULL;
138   unsigned point = 0;
139   int type = 0;
140 
141   if( fgets( linebuf, sizeof( linebuf ), fin ) != NULL )
142   {
143     l = strlen( linebuf );
144     incomplete = ( l && linebuf[l - 1] != '\n' );
145 
146     /* analyze the string */
147 
148     switch ( *linebuf )
149     {
150     case ';':
151       break;                    /* ignore the comment */
152 
153     case ',':
154       ptr = "";
155       sptr = linebuf + 1;
156       break;
157 
158     default:
159       ptr = strtok( linebuf, ",\r\n" );
160       break;
161 
162     }
163 
164     for( k = 0; ptr != NULL && k <= 4; k++ )
165     {
166 
167       switch ( format )
168       {
169 
170       case F_POINTS4D:
171         switch ( k )
172         {
173         case 0:
174           if( !casecmp( ptr, "BOSS" ) )
175           {
176             type = T_HOST;
177           }
178           else if( ( !*ptr ) || ( !casecmp( ptr, "POINT" ) ) )
179           {
180             type = T_NODE;
181           }
182           else
183           {
184             k = 4;              /* ignore this one */
185           }
186           break;
187 
188         case 1:
189           if( type == T_HOST )
190           {
191             parse3d( ptr, zone, net, node );
192           }
193           else
194           {
195             point = atoi( ptr );
196           }
197           break;
198 
199         case 2:
200           break;
201 
202         case 3:
203           break;
204 
205         case 4:
206           if( type == T_NODE )
207           {
208             username = ptr;
209             rv = parsednode( fout, *zone, *net, *node, point, username );
210           }
211           break;
212         }
213         break;
214 
215       case F_POINTS24:
216 
217         switch ( k )
218         {
219         case 0:
220           if( !strcmp( ptr, "Host" ) )
221           {
222             type = T_HOST;
223           }
224           else if( !*ptr )
225           {
226             type = T_NODE;
227           }
228           else
229           {
230             k = 4;              /* ignore this one */
231           }
232           break;
233 
234         case 1:
235           if( type == T_NODE )
236           {
237             point = atoi( ptr );
238           }
239           break;
240 
241         case 2:
242           if( type == T_HOST )
243           {
244             parse2d( ptr, net, node );
245           }
246           break;
247 
248         case 3:                /* Country */
249           break;
250 
251         case 4:                /* Sysop Name */
252           if( type == T_NODE )
253           {
254 
255             username = ptr;
256             rv = parsednode( fout, *zone, *net, *node, point, username );
257           }
258           break;
259         }
260         break;
261 
262       default:
263 
264         switch ( k )
265         {
266         case 0:
267           if( !strcmp( ptr, "Zone" ) )
268           {
269             type = T_ZONE;
270           }
271           else if( !strcmp( ptr, "Region" ) )
272           {
273             type = T_REGION;
274           }
275           else if( !strcmp( ptr, "Host" ) )
276           {
277             type = T_HOST;
278           }
279           else if( !strcmp( ptr, "Hub" ) )
280           {
281             type = T_HUB;
282           }
283           else                  /* Pvt, or empty */
284           {
285             type = T_NODE;
286           }
287           break;
288 
289         case 1:
290           switch ( type )
291           {
292           case T_ZONE:
293             *zone = *net = atoi( ptr );
294             *node = 0;
295             break;
296           case T_REGION:
297           case T_HOST:
298             *net = atoi( ptr );
299             *node = 0;
300             break;
301           case T_HUB:
302           case T_NODE:
303             *node = atoi( ptr );
304             break;
305           }
306           break;
307 
308         case 2:                /* System Name */
309           break;
310 
311         case 3:                /* Country */
312           break;
313 
314         case 4:                /* Sysop Name */
315           username = ptr;
316           rv = parsednode( fout, *zone, *net, *node, 0, username );
317           break;
318         }
319       }
320 
321 
322       ptr = strtok( sptr, ",\r\n" );
323       sptr = NULL;
324     }
325 
326 
327     /* if the string is longer than 128 characters, ignore the rest */
328 
329     while( incomplete && fgets( linebuf, sizeof( linebuf ), fin ) != NULL )
330     {
331       l = strlen( linebuf );
332       incomplete = ( l && linebuf[l - 1] != '\n' );
333     }
334 
335     return rv;
336   }
337   if( feof( fin ) )
338     return 2;                   /* EOF is a normal situation */
339 
340   return 0;                     /* everything else is an error */
341 }
342 
ul_compile(FILE * fin,FILE * fout,int type,int defzone)343 int ul_compile( FILE * fin, FILE * fout, int type, int defzone )
344 {
345   unsigned int zone, net, code, node;
346 
347   zone = net = defzone;
348   node = 0;
349 
350   while( ( code = ulc_line( fin, fout, type, &zone, &net, &node ) ) == 1 );
351 
352   return code == 2;
353 }
354