1 /*****************************************************************************
2  * HTICK --- FTN Ticker / Request Processor
3  *****************************************************************************
4  * Filelist generator routines.
5  *
6  * This file is part of HTICK, part of the Husky fidosoft project
7  * http://husky.sf.net
8  *
9  * HTICK 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  * HTICK 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 HTICK; see the file COPYING.  If not, write to the Free
21  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22  *****************************************************************************
23  * $Id$
24  *****************************************************************************/
25 
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 
33 
34 #include <huskylib/huskylib.h>
35 
36 #include <huskylib/log.h>
37 #include <huskylib/dirlayer.h>
38 #include <huskylib/xstr.h>
39 
40 #include <fidoconf/common.h>
41 #include <fidoconf/afixcmd.h>
42 
43 #include <areafix/areafix.h>
44 
45 #include "add_desc.h"
46 #include "global.h"
47 #include "fcommon.h"
48 #include "filelist.h"
49 #include "toss.h"
50 
51 typedef struct _FileDescEntry
52 {
53   char *filename;
54   char **desc;                  /*  Short Description of file */
55   UINT anzdesc;                 /*  Number of Desc Lines */
56 } FileDescEntry;
57 
58 
59 static BigSize totalfilessize;
60 unsigned int totalfilesnumber = 0;
61 static tree *DescTree = NULL;
62 static FileDescEntry fdesccmp;
63 char *DescNA = "Description not avaliable";
64 
DescTreeDeleteEntry(char * entry)65 int DescTreeDeleteEntry( char *entry )
66 {
67   if( entry )
68   {
69     FileDescEntry *entxt;
70     UINT i;
71 
72     entxt = ( FileDescEntry * ) entry;
73     nfree( entxt->filename );
74     for( i = 0; i < entxt->anzdesc; i++ )
75       nfree( entxt->desc[i] );
76     nfree( entxt->desc );
77     nfree( entxt );
78   }
79   return 1;
80 }
81 
DescTreeCompareEntries(char * p_e1,char * p_e2)82 int DescTreeCompareEntries( char *p_e1, char *p_e2 )
83 {
84   FileDescEntry *e1 = ( FileDescEntry * ) p_e1;
85   FileDescEntry *e2 = ( FileDescEntry * ) p_e2;
86 
87   if( !p_e1 || !p_e2 )
88   {
89     w_log( LL_CRIT,
90            __FILE__
91            ":: Parameter is NULL: DescTreeCompareEntries(%s,%s). This is serious error in program, please report to developers.",
92            p_e1 ? "p_e1" : "NULL", p_e2 ? "p_e2" : "NULL" );
93     return -1;
94   }
95 
96   return strcmp( e1->filename, e2->filename );
97 }
98 
99 
ParseBBSFile(const char * fbbsname)100 int ParseBBSFile( const char *fbbsname )
101 {
102   FILE *filehandle;
103   char *line = NULL, *tmp = NULL, *token = NULL, *p = NULL;
104   int flag = 0, rc = 1;
105   FileDescEntry *fdesc = NULL;
106 
107   if( !fbbsname )
108   {
109     w_log( LL_CRIT,
110            __FILE__
111            ":: Parameter is NULL: ParseBBSFile(%s). This is serious error in program, please report to developers.",
112            fbbsname ? "fbbsname" : "NULL" );
113     return -1;
114   }
115 
116   if( DescTree )
117   {
118     tree_mung( &DescTree, DescTreeDeleteEntry );
119   }
120   tree_init( &DescTree, 1 );
121 
122 
123   filehandle = fopen( fbbsname, "r+b" );
124   if( filehandle == NULL )
125     return 1;
126 
127   while( ( line = readLine( filehandle ) ) != NULL )
128   {
129 
130     if( flag && ( *line == '\t' || *line == ' ' || *line == '>' ) )
131     {
132       token = stripLeadingChars( line, " >" );
133       if( *token == '>' )
134         token++;
135       fdesc->desc = srealloc( fdesc->desc, ( fdesc->anzdesc + 1 ) * sizeof( *fdesc->desc ) );
136       fdesc->desc[fdesc->anzdesc] = sstrdup( token );
137       fdesc->anzdesc++;
138       nfree( line );
139       continue;
140     }
141     else
142     {
143       flag = 0;
144       if( rc == 0 )
145       {
146         tree_add( &DescTree, DescTreeCompareEntries, ( char * )fdesc, DescTreeDeleteEntry );
147       }
148     }
149     tmp = sstrdup( line );
150     token = tmp;
151     p = token;
152     while( p && *p != '\0' && !isspace( *p ) )
153       p++;
154     if( p && *p != '\0' )
155     {
156       *p = '\0';
157     }
158     else
159     {
160       p = NULL;
161     }
162 
163     fdesc = scalloc( 1, sizeof( FileDescEntry ) );
164     fdesc->filename = sstrdup( token );
165 
166     if( p == NULL )
167     {
168       token = "";
169     }
170     else
171     {
172       p++;
173       while( p && *p != '\0' && isspace( *p ) )
174         p++;
175       if( p && *p != '\0' )
176         token = p;
177       else
178         token = "";
179     }
180     if( config->addDLC && config->DLCDigits > 0 && config->DLCDigits < 10 && token[0] == '[' )
181     {
182       while( ']' != *p )
183         p++;
184       p++;
185       while( p && !isspace( *p ) )
186         p++;
187       token = p;
188     }
189     fdesc->anzdesc = 0;
190     fdesc->desc = srealloc( fdesc->desc, ( fdesc->anzdesc + 1 ) * sizeof( *fdesc->desc ) );
191     fdesc->desc[fdesc->anzdesc] = sstrdup( token );
192     fdesc->anzdesc++;
193     flag = 1;
194     rc = 0;
195     nfree( line );
196     nfree( tmp );
197   }
198   if( rc == 0 )
199   {
200     tree_add( &DescTree, DescTreeCompareEntries, ( char * )fdesc, DescTreeDeleteEntry );
201   }
202   fclose( filehandle );
203   return rc;
204 }
205 
putFileInFilelist(FILE * f,char * filename,off_t size,int day,int month,int year,int countdesc,char ** desc)206 void putFileInFilelist( FILE * f, char *filename, off_t size, int day, int month, int year,
207                         int countdesc, char **desc )
208 {
209   int i;
210   static BigSize bs;
211 
212   if( !f || !filename || !desc )
213   {
214     w_log( LL_CRIT,
215            __FILE__
216            ":: Parameter is NULL: putFileInFilelist(%s,%s,size,day,month,year,countdesc,%s). This is serious error in program, please report to developers.",
217            f ? "f" : "NULL", filename ? "filename" : "NULL", desc ? "desc" : "NULL" );
218     return;
219   }
220 
221   memset( &bs, 0, sizeof( BigSize ) );
222   IncBigSize( &bs, ( ULONG ) size );
223   fprintf( f, "%-12s", filename );
224   fprintf( f, "%8s ", PrintBigSize( &bs ) );
225   fprintf( f, "%02u-", day );
226 
227   switch ( month )
228   {
229   case 0:
230     fprintf( f, "Jan" );
231     break;
232   case 1:
233     fprintf( f, "Feb" );
234     break;
235   case 2:
236     fprintf( f, "Mar" );
237     break;
238   case 3:
239     fprintf( f, "Apr" );
240     break;
241   case 4:
242     fprintf( f, "May" );
243     break;
244   case 5:
245     fprintf( f, "Jun" );
246     break;
247   case 6:
248     fprintf( f, "Jul" );
249     break;
250   case 7:
251     fprintf( f, "Aug" );
252     break;
253   case 8:
254     fprintf( f, "Sep" );
255     break;
256   case 9:
257     fprintf( f, "Oct" );
258     break;
259   case 10:
260     fprintf( f, "Nov" );
261     break;
262   case 11:
263     fprintf( f, "Dec" );
264     break;
265   default:
266     break;
267   }
268   fprintf( f, "-%02u", year % 100 );
269   if( countdesc == 0 )
270     fprintf( f, " Description not avaliable\n" );
271   else
272   {
273     /* desc = formatDesc(desc, &countdesc); */
274     for( i = 0; i < countdesc; i++ )
275     {
276       if( desc[i] )
277       {
278         if( i == 0 )
279           fprintf( f, " %s\n", desc[i] );
280         else
281           fprintf( f, "                               %s\n", desc[i] );
282       }
283       else
284       {
285         w_log( LL_CRIT,
286                __FILE__
287                "::putFileInFilelist() Description line %i is NULL. This is serious error in program, please report to developers.",
288                i );
289         break;
290       }
291     }
292   }
293   return;
294 }
295 
printFileArea(char * area_areaName,char * area_pathName,char * area_description,FILE * f,int bbs)296 void printFileArea( char *area_areaName, char *area_pathName, char *area_description, FILE * f,
297                     int bbs )
298 {
299 
300   char *fileareapath = NULL, *fbbsname = NULL, *filename = NULL;
301   char *fbbsline;
302   husky_DIR *dir;
303   char *file;
304   struct stat stbuf;
305   FileDescEntry *fdesc;
306   time_t fileTime;
307   struct tm *locTime;
308   unsigned int totalnumber = 0;
309   char **removeFiles = NULL;
310   unsigned int removeCount = 0, i, Len;
311   FILE *fbbs;
312   char *token = "";
313   int flag = 0;
314   static BigSize bs;
315 
316   if( !area_areaName || !area_pathName || !f )
317   {
318     w_log( LL_CRIT,
319            __FILE__
320            ":: Parameter is NULL: printFileArea(%s,%s,%s,%s). This is serious error in program, please report to developers.",
321            area_areaName ? "area_areaName" : "NULL", area_pathName ? "area_pathName" : "NULL",
322            "area_description", f ? "f" : "NULL" );
323     return;
324   }
325 
326   memset( &bs, 0, sizeof( BigSize ) );
327 
328   fileareapath = sstrdup( area_pathName );
329   adaptcase( fileareapath );
330   xstrscat( &fbbsname, fileareapath, config->fileDescription, NULL );
331   adaptcase( fbbsname );
332 
333   dir = husky_opendir( fileareapath );
334   if( dir == NULL )
335     return;
336 
337   w_log( LL_INFO, "Processing: %s", area_areaName );
338 
339   ParseBBSFile( fbbsname );
340 
341   while( ( file = husky_readdir( dir ) ) != NULL )
342   {
343     if( strcmp( file, "." ) == 0 || strcmp( file, ".." ) == 0 )
344       continue;
345     nfree( filename );
346     xstrscat( &filename, fileareapath, file, NULL );
347     if( stricmp( filename, fbbsname ) == 0 )
348       continue;
349     if( direxist( filename ) )
350       continue;
351     if( !flag )
352     {
353       if( bbs )
354         fprintf( f, "BbsArea: %s", area_areaName );
355       else
356         fprintf( f, "FileArea: %s", area_areaName );
357       if( area_description != NULL )
358         fprintf( f, " (%s)\n", area_description );
359       else
360         fprintf( f, "\n" );
361       fprintf( f,
362                "-----------------------------------------------------------------------------\n" );
363       flag = 1;
364     }
365     fdesccmp.filename = file;
366     fdesc =
367         ( FileDescEntry * ) tree_srch( &DescTree, DescTreeCompareEntries, ( char * )( &fdesccmp ) );
368     if( !fdesc )
369     {
370       add_description( fbbsname, file, &DescNA, 1 );
371     }
372     stat( filename, &stbuf );
373     fileTime = stbuf.st_mtime > 0 ? stbuf.st_mtime : 0;
374     locTime = localtime( &fileTime );
375     IncBigSize( &bs, ( ULONG ) stbuf.st_size );
376     totalnumber++;
377     if( fdesc )
378     {
379       putFileInFilelist( f, file, stbuf.st_size, locTime->tm_mday, locTime->tm_mon,
380                          locTime->tm_year, fdesc->anzdesc, fdesc->desc );
381     }
382     else
383     {
384       putFileInFilelist( f, file, stbuf.st_size, locTime->tm_mday, locTime->tm_mon,
385                          locTime->tm_year, 1, &DescNA );
386     }
387   }
388   husky_closedir( dir );
389   if( flag )
390   {
391     fprintf( f, "-----------------------------------------------------------------------------\n" );
392     fprintf( f, "Total files in area: %6d, total size: %10s bytes\n\n", totalnumber,
393              PrintBigSize( &bs ) );
394   }
395 
396   /* collect information about files in files.bbs that realy do not exist */
397   if( ( fbbs = fopen( fbbsname, "r" ) ) == NULL )
398     return;
399   while( ( fbbsline = readLine( fbbs ) ) != NULL )
400   {
401     if( *fbbsline == 0 || *fbbsline == 10 || *fbbsline == 13
402         || *fbbsline == ' ' || *fbbsline == '\t' || *fbbsline == '>' )
403       continue;
404 
405     Len = strlen( fbbsline );
406     if( fbbsline[Len - 1] == '\n' )
407       fbbsline[--Len] = 0;
408 
409     if( fbbsline[Len - 1] == '\r' )
410       fbbsline[--Len] = 0;
411 
412     token = strtok( fbbsline, " \t\0" );
413 
414     if( token == NULL )
415       continue;
416     nfree( filename );
417     xstrscat( &filename, fileareapath, token, NULL );
418     adaptcase( filename );
419     if( !fexist( filename ) )
420     {
421       removeFiles = srealloc( removeFiles, sizeof( char * ) * ( removeCount + 1 ) );
422       removeFiles[removeCount] =
423           ( char * )smalloc( strlen( strrchr( filename, PATH_DELIM ) + 1 ) + 1 );
424       strcpy( removeFiles[removeCount], strrchr( filename, PATH_DELIM ) + 1 );
425       removeCount++;
426     }
427     nfree( fbbsline );
428   }
429   fclose( fbbs );
430 
431   /* remove descriptions from files.bbs on files that realy do not exist */
432   if( removeCount > 0 )
433   {
434     for( i = 0; i < removeCount; i++ )
435     {
436       removeDesc( fbbsname, removeFiles[i] );
437       nfree( removeFiles[i] );
438     }
439     nfree( removeFiles );
440   }
441   IncBigSize2( &totalfilessize, &bs );
442   totalfilesnumber += totalnumber;
443   nfree( filename );
444   return;
445 }
446 
filelist()447 void filelist(  )
448 {
449   FILE *f = NULL;
450   FILE *d = NULL;
451   unsigned int i;
452 
453   w_log( LL_INFO, "Start filelist..." );
454 
455   if( flistfile == NULL )
456   {
457     w_log( '6', "Could not find output file" );
458     return;
459   }
460 
461   if( ( f = fopen( flistfile, "w" ) ) == NULL )
462   {
463     w_log( '6', "Could not open for write file %s", flistfile );
464     return;
465   }
466 
467   if( dlistfile )
468   {
469     if( ( d = fopen( dlistfile, "w" ) ) == NULL )
470     {
471       w_log( '6', "Could not open for write file %s", dlistfile );
472     }
473   }
474   for( i = 0; i < config->fileAreaCount; i++ )
475   {
476     if( config->fileAreas[i].msgbType != MSGTYPE_PASSTHROUGH && !( config->fileAreas[i].hide ) )
477     {
478       printFileArea( config->fileAreas[i].areaName, config->fileAreas[i].fileName,
479                      config->fileAreas[i].description, f, 0 );
480       if( d )
481         fprintf( d, "%s\n", config->fileAreas[i].fileName );
482     }
483   }
484 
485   for( i = 0; i < config->bbsAreaCount; i++ )
486   {
487     printFileArea( config->bbsAreas[i].areaName, config->bbsAreas[i].pathName,
488                    config->bbsAreas[i].description, f, 1 );
489     if( d )
490       fprintf( d, "%s\n", config->bbsAreas[i].pathName );
491   }
492 
493   fprintf( f, "=============================================================================\n" );
494   fprintf( f, "Total files in filelist: %6d, total size: %10s bytes\n", totalfilesnumber,
495            PrintBigSize( &totalfilessize ) );
496   fprintf( f, "=============================================================================\n\n" );
497 
498   fclose( f );
499   if( d )
500     fclose( d );
501 }
502