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    Tool to check the CRC value in a Fidonet Nodelist
7    References: FTS-0005, FTS-5000
8 */
9 
10 #include <stdio.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15 
16 #include <huskylib/huskylib.h>
17 
18 #include "crc16.h"
19 #include "version.h"
20 
21 enum
22 { SCANCOLON, SCANDIGIT, CRCVAL, AFTERCRCVAL, FINISH };
23 enum
24 { ok = 0, unknown_option = 1, illegal_parameter = 2, nodelist_without_crc = 4, error_nodelist =
25     8, error_CRC = 16 } exit_codes;
26 
27 #define PROGRAM "nlcrc"
28 char *versionStr = "";
29 
analyze_first_line(FILE * f)30 unsigned short analyze_first_line( FILE * f )
31 {
32   char c = 0;
33   int state = SCANCOLON;
34   unsigned short crc = 0;
35 
36   while( state != FINISH )
37   {
38     fread( &c, 1, 1, f );
39     if( c == '\n' )
40     {
41       if( state < CRCVAL )
42       {
43         fprintf( stderr, "Warning: File does not contain checksum.\n" );
44         exit( nodelist_without_crc );
45       }
46       else
47       {
48         state = FINISH;
49       }
50     }
51     else if( isdigit( c ) )
52     {
53       switch ( state )
54       {
55       case SCANDIGIT:
56         crc = c - '0';
57         state = CRCVAL;
58         break;
59       case CRCVAL:
60         crc = crc * 10U + ( c - '0' );
61         break;
62       default:;
63       }
64     }
65     else if( c == ':' )
66     {
67       switch ( state )
68       {
69       case SCANCOLON:
70         state = SCANDIGIT;
71         break;
72       default:;
73       }
74     }
75     else
76     {
77       switch ( state )
78       {
79       case CRCVAL:
80         state = AFTERCRCVAL;
81         break;
82       default:;
83       }
84     }
85   }
86   return crc;
87 }
88 
89 #define BUFSZ 32768
90 
analyze_rest(FILE * f)91 unsigned short analyze_rest( FILE * f )
92 {
93   static unsigned char buffer[BUFSZ + 1];
94   size_t l;
95   unsigned short crc;
96   unsigned char *p = NULL;
97 
98   crc16_init( &crc );
99 
100   errno = 0;
101   while( ( ( l = fread( buffer, 1, BUFSZ, f ) ) > 0 ) && p == NULL )
102   {
103     buffer[l] = '\0';
104     p = ( unsigned char * ) strchr( ( char * ) buffer, 0x1A );
105 
106     if( p != NULL )
107     {
108       l = p - buffer;
109     }
110 
111     crc16_process( &crc, buffer, l );
112   }
113 
114   crc16_finalize( &crc );
115 
116   return crc;
117 }
118 
usage()119 void usage(  )
120 {
121   printf( "\nUsage: " PROGRAM " <FILENAME>\n\n"
122           "\tIf nothing is printed ans exit code is zero, the CRC was OK. If the CRC is not\n"
123           "\tOK, an error message and a exit code 8 is given.\n" );
124 }
125 
main(int argc,char ** argv)126 int main( int argc, char **argv )
127 {
128   FILE *f;
129   unsigned short should, is;
130   int flag_quiet;
131   char *nlname = NULL;
132 
133   versionStr = GenVersionStr( PROGRAM, VER_MAJOR, VER_MINOR, VER_PATCH, VER_BRANCH, cvs_date );
134 
135   {
136     int i;
137     for( i = 1; i < argc; i++ )
138     {
139       int j, plen;
140       if( argv[i][0] == '-' )
141       {
142         int plen = sstrlen( argv[i] );
143         for( j = 1; j < plen; j++ )
144           switch ( argv[i][j] )
145           {
146           case 'h':
147             usage(  );
148             return ok;
149           case 'v':
150             printversion(  );
151             return ok;
152           case 'q':
153             flag_quiet = 1;
154             break;
155           default:
156             printf( "Illegal option '%c'!\n\n", argv[i][j] );
157             usage(  );
158             return unknown_option;
159           }
160       }
161       else if( !nlname )
162         nlname = argv[i];
163       else
164       {
165         printf( "Illegal call: supports only one nodelist file name!\n"
166                 "Detected filename: \"%s\"\n" "Extra parameter is \"%s\"\nExit.", nlname, argv[i] );
167         return illegal_parameter;
168       }
169     }
170     if( !nlname )
171       printf( "Illegal call: nodelist filename is needed!\n" );
172     return illegal_parameter;
173   }
174 
175   if( !flag_quiet )
176     printversion(  );
177 
178   if( ( f = fopen( nlname, "rb" ) ) == NULL )
179   {
180     fprintf( stderr, "Cannot open %s.\n", argv[1] );
181     return error_nodelist;
182   }
183 
184   should = analyze_first_line( f );
185   is = analyze_rest( f );
186 
187   fclose( f );
188 
189   if( should != is )
190   {
191     fprintf( stderr, "Nodelist %s fails CRC check (%u != %u)\n",
192              argv[1], ( unsigned ) should, ( unsigned ) is );
193     return error_CRC;
194   }
195 
196   return ok;
197 }
198