1 /*
2 * hptsqfix - rebuilding squish index and some info in sqd
3 * made by Serguei Revtov 2:5021/19.1
4 * from hptUtil by Fedor Lizunkov 2:5020/960@Fidonet
5 *
6 * This file is part of HPTSQFIX, part of The HUSKY Fidonet Software project.
7 * About HUSKY see http://husky.sourceforge.net (http://husky.sf.net)
8 *
9 * HPTSQFIX is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2, or (at your option) any
12 * later version.
13 *
14 * HPTSQFIX is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with HPTSQFIX; see the file COPYING. If not, write to the Free
21 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 * See also http://www.gnu.org
23 *****************************************************************************
24 */
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32
33 /* compiler.h */
34 #include <huskylib/compiler.h>
35
36 #if defined(HAS_IO_H)
37 # include <io.h>
38 #endif
39
40 #if defined(HAS_SHARE_H)
41 # include <share.h>
42 #endif
43
44 #if defined(HAS_UNISTD_H)
45 # include <unistd.h>
46 #endif
47
48 /* smapi */
49 #include <smapi/msgapi.h>
50
51 #include "squish.h"
52 #include "version.h"
53
54 char *versionStr;
55
56 #define fop_wpb (O_CREAT | O_TRUNC | O_RDWR | O_BINARY)
57 #define fop_rpb (O_RDWR | O_BINARY)
58
59 int tryfind = 0;
60 int unDelete = 0;
61 size_t maxMsgLen;
62
63 /*
64 typedef struct {
65 time_t msgTime;
66 dword frame_pos;
67 } sortedbase;
68
69 sortedbase *SortedBase = NULL;
70 */
71
Open_File(char * name,word mode)72 int Open_File( char *name, word mode )
73 {
74 int handle;
75
76 #ifdef __UNIX__
77 handle =
78 sopen( name, mode, SH_DENYNONE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH );
79 #else
80 handle = sopen( name, mode, SH_DENYNONE, S_IREAD | S_IWRITE );
81 #endif
82
83 if( handle < 0 )
84 fprintf( stderr, "Can't open file '%s'\n", name );
85
86 return handle;
87 }
88
usage()89 void usage( )
90 {
91 printf( "hptsqfix corrects errors in squish message bases\n");
92 printf( "Usage: hptsqfix [options] areafilename ...\n"
93 "Options: -f\t- try to find next header after broken msg\n"
94 "\t -e\t- 'areafilename' has extension, strip it\n"
95 "\t -u\t- undelete (restore deleted messages)\n" );
96 exit( -1 );
97 }
98
99 /*
100 static int cmp_msgEntry(const void *a, const void *b)
101 {
102 const sortedbase* r1 = (sortedbase*)a;
103 const sortedbase* r2 = (sortedbase*)b;
104
105 if( r1->msgTime > r2->msgTime)
106 return 1;
107 else if( r1->msgTime < r2->msgTime)
108 return -1;
109 return 0;
110 }
111 */
findhdr(int SqdHandle)112 int findhdr( int SqdHandle )
113 {
114 off_t pos;
115 dword i = 0, rc = 1, stop = 0;
116
117 unsigned char chr;
118 unsigned char sqhdrid[] = { 0x53, 0x44, 0xae, 0xaf };
119
120 fprintf( stderr, "Searching valid header ID... " );
121
122 pos = tell( SqdHandle );
123
124
125 do
126 {
127 if( read( SqdHandle, &chr, 1 ) == 1 )
128 {
129 pos++;
130 if( chr == sqhdrid[i] )
131 {
132 i++;
133 if( i == 4 )
134 {
135 fprintf( stderr, " Wow! Found at pos %lu\n", ( unsigned long ) pos - 4 );
136 lseek( SqdHandle, pos - 4, SEEK_SET );
137 rc = 0;
138 stop = 1;
139 }
140 }
141 else
142 {
143 if( chr == sqhdrid[0] )
144 i = 1;
145 else
146 i = 0;
147 }
148 }
149 else
150 {
151 fprintf( stderr, " not found\n" );
152 stop = 1;
153 rc = 1;
154 }
155
156 }
157 while( !stop );
158
159 return rc;
160 }
161
Checkhdr(int SqdHandle,SQHDR * sqhdr)162 int Checkhdr( int SqdHandle, SQHDR * sqhdr )
163 {
164 int stop = 0;
165
166 if( read_sqhdr( SqdHandle, sqhdr ) == 0 )
167 {
168 fprintf( stderr, "... end" );
169 stop++;
170 }
171
172 if( stop == 0 && sqhdr->frame_length != sqhdr->msg_length )
173 fprintf( stderr, "\nFrame Length != Msg Length %ld:%ld\n", sqhdr->frame_length,
174 sqhdr->msg_length );
175
176 if( stop == 0 && sqhdr->id != SQHDRID )
177 {
178
179 fprintf( stderr, "\nLooks like Message header is damaged\n" );
180
181 if( tryfind )
182 {
183 stop = findhdr( SqdHandle );
184 if( stop == 0 )
185 stop = -1;
186 }
187 else
188 {
189 fprintf( stderr, "\nYou may want to use -f parameter\n" );
190 stop++;
191 }
192 }
193
194 if( stop == 0 && sqhdr->msg_length <= XMSG_SIZE )
195 {
196
197 fprintf( stderr, "\nMessage body is too short: %ld\n", sqhdr->msg_length );
198
199 if( tryfind )
200 {
201 stop = findhdr( SqdHandle );
202 if( stop == 0 )
203 stop = -1;
204 }
205 else
206 {
207 fprintf( stderr, "\nYou may want to use -f parameter\n" );
208 stop++;
209 }
210 }
211
212 if( stop == 0 && sqhdr->frame_length > maxMsgLen )
213 {
214
215 fprintf( stderr,
216 "\nFrame is larger than rest of file\nLooks like Message header is damaged\n" );
217
218 if( tryfind )
219 {
220 stop = findhdr( SqdHandle );
221 if( stop == 0 )
222 stop = -1;
223 }
224 else
225 {
226 fprintf( stderr, "\nYou may want to use -f parameter\n" );
227 stop++;
228 }
229 }
230 return stop;
231 }
232
233
repair(char * areaName)234 int repair( char *areaName )
235 {
236
237 int SqdHandle;
238 int NewSqdHandle, NewSqiHandle;
239 dword i;
240 long saved = 0;
241 int stop;
242 int firstmsg = 1;
243 int sayFree = 0;
244 dword frame_length = 0;
245
246 char *sqd, *newsqd, *newsqi, *text;
247
248 SQBASE sqbase;
249 SQHDR sqhdr;
250 XMSG xmsg;
251 SQIDX sqidx;
252
253 sqd = ( char * ) malloc( strlen( areaName ) + 5 );
254
255 newsqd = ( char * ) malloc( strlen( areaName ) + 5 );
256 newsqi = ( char * ) malloc( strlen( areaName ) + 5 );
257
258 sprintf( sqd, "%s%s", areaName, EXT_SQDFILE );
259
260 SqdHandle = Open_File( sqd, fop_rpb );
261 if( SqdHandle == -1 )
262 {
263 free( sqd );
264 free( newsqd );
265 free( newsqi );
266 return 0;
267 } /* endif */
268
269 sprintf( newsqd, "%s.tmd", areaName );
270 sprintf( newsqi, "%s.tmi", areaName );
271
272 NewSqdHandle = Open_File( newsqd, fop_wpb );
273 if( NewSqdHandle == -1 )
274 {
275 free( sqd );
276 free( newsqd );
277 free( newsqi );
278 close( SqdHandle );
279 return 0;
280 } /* endif */
281 NewSqiHandle = Open_File( newsqi, fop_wpb );
282 if( NewSqiHandle == -1 )
283 {
284 free( sqd );
285 free( newsqd );
286 free( newsqi );
287 close( NewSqdHandle );
288 close( SqdHandle );
289 return 0;
290 } /* endif */
291
292 lseek( SqdHandle, 0L, SEEK_END );
293 maxMsgLen = tell( SqdHandle ) - SQBASE_SIZE - SQHDR_SIZE;
294 lseek( SqdHandle, 0L, SEEK_SET );
295
296
297 if( lock( SqdHandle, 0, 1 ) != 0 )
298 {
299 close( NewSqdHandle );
300 close( NewSqiHandle );
301 close( SqdHandle );
302 free( sqd );
303 free( newsqd );
304 free( newsqi );
305 fprintf( stderr, "\nCan't lock msg base\n" );
306 return 0;
307 }
308 read_sqbase( SqdHandle, &sqbase );
309
310 sqbase.num_msg = 0;
311 sqbase.high_msg = 0;
312 sqbase.skip_msg = 0;
313 sqbase.begin_frame = SQBASE_SIZE;
314 sqbase.last_frame = sqbase.begin_frame;
315 sqbase.free_frame = sqbase.last_free_frame = 0;
316 sqbase.end_frame = sqbase.begin_frame;
317
318 for( stop = 0, i = 1; !stop; i++ )
319 {
320
321 fprintf( stderr, "Msg %ld", i );
322
323 stop = Checkhdr( SqdHandle, &sqhdr );
324
325 if( stop == 1 )
326 break;
327 if( stop == -1 )
328 {
329 stop = 0;
330 continue;
331 }
332
333 if( sqhdr.frame_type != FRAME_normal )
334 {
335 if( unDelete != 0 && sqhdr.frame_type == FRAME_free )
336 {
337 sqhdr.frame_type = FRAME_normal;
338 fprintf( stderr, "... free, restoring\n" );
339 }
340 else
341 {
342 sayFree = 1;
343 fprintf( stderr, "... free\r" );
344 lseek( SqdHandle, sqhdr.frame_length, SEEK_CUR );
345 continue;
346 }
347 }
348
349 read_xmsg( SqdHandle, &xmsg );
350 xmsg.attr = 0;
351 xmsg.replyto = 0;
352 memset( xmsg.replies, '\000', sizeof( UMSGID ) * MAX_REPLY );
353
354 text = ( char * ) calloc( sqhdr.frame_length, sizeof( char * ) );
355 farread( SqdHandle, text, ( sqhdr.frame_length - XMSG_SIZE ) );
356 memcpy( text, text, sqhdr.msg_length );
357 frame_length = sqhdr.frame_length;
358 sqhdr.frame_length = sqhdr.msg_length;
359 if( firstmsg )
360 {
361 sqhdr.prev_frame = 0;
362 firstmsg = 0;
363 }
364 else
365 {
366 sqhdr.prev_frame = sqbase.last_frame;
367 }
368
369 sqhdr.next_frame = tell( NewSqdHandle ) + SQHDR_SIZE + sqhdr.msg_length;
370
371 sqbase.last_frame = tell( NewSqdHandle );
372 sqidx.ofs = sqbase.last_frame;
373
374 write_sqhdr( NewSqdHandle, &sqhdr );
375 write_xmsg( NewSqdHandle, &xmsg );
376 farwrite( NewSqdHandle, text, ( sqhdr.msg_length - XMSG_SIZE ) );
377
378 sqbase.end_frame = tell( NewSqdHandle );
379
380 sqidx.hash = SquishHash( xmsg.to );
381 if( xmsg.attr & MSGREAD )
382 {
383 sqidx.hash |= ( dword ) 0x80000000L;
384 }
385 sqidx.umsgid = sqbase.num_msg + 1;
386
387 write_sqidx( NewSqiHandle, &sqidx, 1 );
388 free( text );
389
390 sqbase.num_msg++;
391 sqbase.high_msg = sqbase.num_msg;
392 saved++;
393 if( sayFree )
394 {
395 fprintf( stderr, " " );
396 sayFree = 0;
397 }
398 fprintf( stderr, "\r" );
399
400 maxMsgLen -= frame_length;
401 }
402
403 fprintf( stderr, "\n%ld messages read\n", i - 2 );
404
405 lseek( NewSqiHandle, SQIDX_SIZE, SEEK_END );
406 read_sqidx( NewSqiHandle, &sqidx, 1 );
407 lseek( NewSqdHandle, sqidx.ofs, SEEK_SET );
408 read_sqhdr( NewSqdHandle, &sqhdr );
409 sqhdr.next_frame = 0;
410 lseek( NewSqdHandle, sqidx.ofs, SEEK_SET );
411 write_sqhdr( NewSqdHandle, &sqhdr );
412 lseek( NewSqdHandle, 0L, SEEK_SET );
413 write_sqbase( NewSqdHandle, &sqbase );
414
415 unlock( SqdHandle, 0, 1 );
416
417 close( NewSqdHandle );
418 close( NewSqiHandle );
419 close( SqdHandle );
420
421 free( sqd );
422 free( newsqd );
423 free( newsqi );
424
425 fprintf( stderr, "%ld messages saved\n", saved );
426
427 return 0;
428 }
429
430
main(int argc,char * argv[])431 int main( int argc, char *argv[] )
432 {
433 int i, j, extIndx;
434 int stripExt = 0;
435
436 versionStr = GenVersionStr( "hptsqfix", VER_MAJOR, VER_MINOR, VER_PATCH, VER_BRANCH, cvs_date );
437 printf( "%s\n\n", versionStr );
438
439 if( argc < 2 )
440 usage( );
441
442 for( i = 1; i < argc; i++ )
443 {
444 if( argv[i][0] == '-' )
445 {
446 if( stricmp( argv[i], "-f" ) == 0 )
447 {
448 tryfind = 1;
449 }
450 else if( stricmp( argv[i], "-e" ) == 0 )
451 {
452 stripExt = 1;
453 }
454 else if( stricmp( argv[i], "-u" ) == 0 )
455 {
456 unDelete = 1;
457 }
458 else
459 {
460 usage( );
461 }
462 }
463 }
464
465 for( i = 1; i < argc; i++ )
466 {
467 if( argv[i][0] != '-' )
468 {
469
470 if( stripExt )
471 {
472 extIndx = 0;
473 for( j = 0; argv[i][j]; j++ )
474 {
475 if( argv[i][j] == '.' )
476 extIndx = j;
477 }
478 if( extIndx > 0 )
479 {
480 argv[i][extIndx] = '\0';
481 }
482 else
483 {
484 fprintf( stderr, "Warning: loose extension in '%s'\n", argv[i] );
485 }
486 }
487
488 fprintf( stderr, "Repairing area '%s'\n", argv[i] );
489
490 repair( argv[i] );
491
492 fprintf( stderr, "Done\n\n" );
493 }
494 }
495
496 return 0;
497 }
498