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