1 /*****************************************************************************
2  * HTICK --- FTN Ticker / Request Processor
3  *****************************************************************************
4  * Hatch file to fileecho implementation
5  *
6  * This file is part of HTICK, part of the Husky fidosoft project
7  * http://husky.sourceforge.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 <errno.h>
32 
33 /*  compiler.h */
34 #include <huskylib/compiler.h>
35 
36 #ifdef HAS_UNISTD_H
37 # include <unistd.h>
38 #endif
39 
40 /* smapi */
41 #include <huskylib/huskylib.h>
42 
43 /* fidoconf */
44 #include <fidoconf/fidoconf.h>
45 #include <fidoconf/common.h>
46 #include <huskylib/dirlayer.h>
47 #include <huskylib/xstr.h>
48 #include <fidoconf/afixcmd.h>
49 #include <huskylib/recode.h>
50 #include <huskylib/crc.h>
51 
52 #include <areafix/areafix.h>
53 
54 /*  htick  */
55 #include <filecase.h>
56 #include <seenby.h>
57 #include <add_desc.h>
58 #include <hatch.h>
59 #include <global.h>
60 #include <fcommon.h>
61 #include <toss.h>
62 
63 char *versionStr;
64 
65 typedef enum _descrMacro
66 { DESCRERROR = 0, BBSONELINE =
67       1, BBSMLTLINE, DIZONELINE, DIZMLTLINE, FILONELINE, FILMLTLINE } descrMacro;
68 
getDescOptions(char * desc,char ** filename)69 static descrMacro getDescOptions( char *desc, char **filename )
70 {
71   byte descOPT = 0;
72 
73   if( !desc || !filename )
74   {
75     w_log( LL_CRIT,
76            __FILE__
77            ":: Parameter is NULL: getDescOptions(%s,%s). This is serious error in program, please report to developers.",
78            desc ? "desc" : "NULL", filename ? "filename" : "NULL" );
79     return DESCRERROR;
80   }
81 
82   if( stricmp( desc, "@@BBS" ) == 0 )
83     descOPT = BBSONELINE;
84   else if( stricmp( desc, "@@DIZ" ) == 0 )
85     descOPT = DIZONELINE;
86   else if( stricmp( desc, "@BBS" ) == 0 )
87     descOPT = BBSMLTLINE;
88   else if( stricmp( desc, "@DIZ" ) == 0 )
89     descOPT = DIZMLTLINE;
90   else if( desc[0] == '@' )
91   {
92     char *basename = desc;
93 
94     basename++;
95     if( *basename == '@' )
96       basename++;
97     if( fexist( basename ) )
98     {
99       descOPT = ( basename - desc == 1 ) ? FILMLTLINE : FILONELINE;
100       *filename = sstrdup( basename );
101     }
102   }
103   return descOPT;
104 }
105 
expandDescMacros(s_ticfile * tic,char * hatchedFile)106 static void expandDescMacros( s_ticfile * tic, char *hatchedFile )
107 {
108   char *descr_file_name = NULL;
109   char *basename = NULL;
110   char *ldFileName = NULL;
111   char *sdFileName = NULL;
112   char ctmp;
113   int SdescOPT = 0;
114   int LdescOPT = 0;
115   s_ticfile tmptic;
116   char **tmpArray = NULL;
117   UINT i;
118 
119   if( !tic || !hatchedFile )
120   {
121     w_log( LL_CRIT,
122            __FILE__
123            ":: Parameter is NULL: expandDescMacros(%s,%s). This is serious error in program, please report to developers.",
124            tic ? "tic" : "NULL", hatchedFile ? "hatchedFile" : "NULL" );
125     return;
126   }
127 
128   memset( &tmptic, 0, sizeof( s_ticfile ) );
129   if( tic->anzdesc > 0 )
130   {
131     SdescOPT = getDescOptions( tic->desc[0], &sdFileName );
132     if( SdescOPT > 0 )
133     {
134       nfree( tic->desc[0] );
135       tic->desc[0] = sstrdup( "-- description missing --" );
136     }
137   }
138   if( tic->anzldesc > 0 )
139   {
140     LdescOPT = getDescOptions( tic->ldesc[0], &ldFileName );
141     if( LdescOPT > 0 )
142     {
143       nfree( tic->ldesc[0] );
144       nfree( tic->ldesc );
145       tic->anzldesc = 0;
146     }
147   }
148 
149   if( !SdescOPT && !LdescOPT )
150     goto recode;
151 
152   if( SdescOPT == BBSONELINE || LdescOPT == BBSONELINE || SdescOPT == BBSMLTLINE
153       || LdescOPT == BBSMLTLINE )
154   {
155     if( strrchr( tic->file, PATH_DELIM ) )
156     {
157       basename = strrchr( tic->file, PATH_DELIM );
158       ctmp = *basename;
159       *basename = '\0';
160       xscatprintf( &descr_file_name, "%s%c%s", tic->file, PATH_DELIM, config->fileDescription );
161       *basename = ctmp;
162     }
163     else
164     {
165       xstrcat( &descr_file_name, config->fileDescription );
166     }
167     adaptcase( descr_file_name );
168     if( GetDescFormBbsFile( descr_file_name, tic->file, &tmptic ) == 0 )
169     {
170 
171       if( LdescOPT == BBSONELINE )
172       {
173         tic->anzldesc = 1;
174         tic->ldesc = scalloc( sizeof( *tic->ldesc ), tic->anzldesc );
175         tic->ldesc[0] = sstrdup( tmptic.desc[0] );
176         LdescOPT = 0;
177       }
178       else if( LdescOPT == BBSMLTLINE )
179       {
180         tic->anzldesc = tmptic.anzdesc;
181         tic->ldesc = scalloc( sizeof( *tic->ldesc ), tic->anzldesc );
182         for( i = 0; i < tic->anzldesc; i++ )
183         {
184           tic->ldesc[i] = sstrdup( tmptic.desc[i] );
185         }
186         LdescOPT = 0;
187       }
188       if( SdescOPT == BBSONELINE )
189       {
190         tic->anzdesc = 1;
191         tic->desc = scalloc( sizeof( *tic->desc ), tic->anzdesc );
192         tic->desc[0] = sstrdup( tmptic.desc[0] );
193         SdescOPT = 0;
194       }
195       else if( SdescOPT == BBSMLTLINE )
196       {
197 
198         tic->anzdesc = tmptic.anzdesc;
199         tic->desc = scalloc( sizeof( *tic->desc ), tic->anzdesc );
200         for( i = 0; i < tic->anzdesc; i++ )
201         {
202           tic->desc[i] = sstrdup( tmptic.desc[i] );
203         }
204         SdescOPT = 0;
205       }
206       disposeTic( &tmptic );
207       memset( &tmptic, 0, sizeof( s_ticfile ) );
208     }
209   }
210   if( SdescOPT == DIZONELINE || LdescOPT == DIZONELINE || SdescOPT == DIZMLTLINE
211       || LdescOPT == DIZMLTLINE )
212   {
213     if( GetDescFormDizFile( hatchedFile, &tmptic ) == 1 )
214     {
215       if( SdescOPT == DIZMLTLINE || LdescOPT == DIZMLTLINE )
216       {
217         tmpArray = scalloc( sizeof( char * ), tmptic.anzldesc );
218         for( i = 0; i < tmptic.anzldesc; i++ )
219         {
220           tmpArray[i] = sstrdup( tmptic.ldesc[i] );
221         }
222       }
223       if( LdescOPT == DIZONELINE )
224       {
225         tic->anzldesc = 1;
226         tic->ldesc = scalloc( sizeof( *tic->ldesc ), tic->anzldesc );
227         tic->ldesc[0] = sstrdup( tmptic.ldesc[0] );
228       }
229       else if( LdescOPT == DIZMLTLINE )
230       {
231         tic->anzldesc = tmptic.anzldesc;
232         tic->ldesc = tmpArray;
233       }
234       if( SdescOPT == DIZONELINE )
235       {
236         nfree( tic->desc[0] );
237         tic->desc[0] = sstrdup( tmptic.ldesc[0] );
238       }
239       else if( SdescOPT == DIZMLTLINE )
240       {
241         tic->anzdesc = tmptic.anzldesc;
242         tic->desc = tmpArray;
243       }
244       disposeTic( &tmptic );
245       memset( &tmptic, 0, sizeof( s_ticfile ) );
246     }
247   }
248 
249   if( SdescOPT == FILONELINE || SdescOPT == FILMLTLINE )
250   {
251     if( GetDescFormFile( sdFileName, &tmptic ) == 1 )
252     {
253       if( SdescOPT == FILMLTLINE || LdescOPT == FILMLTLINE )
254       {
255         tmpArray = scalloc( sizeof( char * ), tmptic.anzldesc );
256         for( i = 0; i < tmptic.anzldesc; i++ )
257         {
258           tmpArray[i] = sstrdup( tmptic.ldesc[i] );
259         }
260       }
261       if( SdescOPT == FILONELINE )
262       {
263         nfree( tic->desc[0] );
264         tic->desc[0] = sstrdup( tmptic.ldesc[0] );
265       }
266       else if( SdescOPT == FILMLTLINE )
267       {
268         tic->anzdesc = tmptic.anzldesc;
269         tic->desc = tmpArray;
270       }
271     }
272   }
273   if( LdescOPT == FILONELINE || LdescOPT == FILMLTLINE )
274   {
275     if( sdFileName && ldFileName && stricmp( sdFileName, ldFileName ) == 0 )
276     {
277       if( LdescOPT == FILONELINE )
278       {
279         tic->anzldesc = 1;
280         tic->ldesc = scalloc( sizeof( *tic->ldesc ), tic->anzldesc );
281         tic->ldesc[0] = sstrdup( tmptic.ldesc[0] );
282       }
283       else if( LdescOPT == FILMLTLINE )
284       {
285         tic->anzldesc = tmptic.anzldesc;
286         tic->ldesc = tmpArray;
287       }
288     }
289     else
290     {
291       disposeTic( &tmptic );
292       memset( &tmptic, 0, sizeof( s_ticfile ) );
293       if( GetDescFormFile( ldFileName, &tmptic ) == 1 )
294       {
295         if( LdescOPT == FILMLTLINE )
296         {
297           tic->anzldesc = tmptic.anzldesc;
298           tic->ldesc = scalloc( sizeof( char * ), tmptic.anzldesc );
299           for( i = 0; i < tmptic.anzldesc; i++ )
300           {
301             tic->ldesc[i] = sstrdup( tmptic.ldesc[i] );
302           }
303         }
304         else if( LdescOPT == FILONELINE )
305         {
306           tic->anzldesc = 1;
307           tic->ldesc = scalloc( sizeof( *tic->ldesc ), tic->anzldesc );
308           tic->ldesc[0] = sstrdup( tmptic.ldesc[0] );
309         }
310       }
311     }
312   }
313 
314 recode:
315   if( config->outtab != NULL )
316   {
317     for( i = 0; i < tic->anzdesc; i++ )
318     {
319       recodeToTransportCharset( tic->desc[i] );
320     }
321     for( i = 0; i < tic->anzldesc; i++ )
322     {
323       recodeToTransportCharset( tic->ldesc[i] );
324     }
325   }
326 
327   disposeTic( &tmptic );
328 }
329 
hatch()330 HATCH_HATCH_RETURN_CODES hatch(  )
331 {
332   s_area *filearea;
333   struct stat stbuf;
334   char *hatchedFile = NULL;
335   char buffer[256] = "";
336 
337   w_log( LL_INFO, "Start file hatch..." );
338 
339   hatchedFile = sstrdup( hatchInfo->file );
340 
341   /*  Exist file? */
342   adaptcase( hatchedFile );
343   {
344     FILE *f = fopen( hatchedFile, "rb" );
345 
346     if( f )
347       fclose( f );
348     else
349     {
350       w_log( LL_ALERT, "File %s: %s", hatchedFile, strerror( errno ) );
351       return HATCH_ERROR_FILE;
352     }
353   }
354 
355   xstrcpy( &hatchInfo->file, GetFilenameFromPathname( hatchedFile ) );
356 
357   if( stricmp( hatchedFile, hatchInfo->file ) == 0 )    /* hatch from current dir */
358   {
359     int len = 0;
360 
361     getcwd( buffer, 256 );
362     len = strlen( buffer );
363     if( buffer[len - 1] == PATH_DELIM )
364     {
365       Strip_Trailing( buffer, PATH_DELIM );
366     }
367     nfree( hatchedFile );
368     xscatprintf( &hatchedFile, "%s%c%s", buffer, ( char )PATH_DELIM, hatchInfo->file );
369   }
370 
371   MakeProperCase( hatchInfo->file );
372 
373   filearea = getFileArea( hatchInfo->area );
374 
375   if( filearea == NULL )
376   {
377     w_log( '9', "Cannot open or create File Area %s", hatchInfo->area );
378     return HATCH_NOT_FILEAREA;
379   }
380 
381   expandDescMacros( hatchInfo, hatchedFile );
382 
383   stat( hatchedFile, &stbuf );
384   hatchInfo->size = stbuf.st_size;
385 
386   hatchInfo->origin = hatchInfo->from = *filearea->useAka;
387 
388   seenbyAdd( &hatchInfo->seenby, &hatchInfo->anzseenby, filearea->useAka );
389 
390   if( filearea->description )
391     hatchInfo->areadesc = sstrdup( filearea->description );
392   /*  Adding crc */
393   hatchInfo->crc = filecrc32( hatchedFile );
394 
395   if( sendToLinks( 0, filearea, hatchInfo, hatchedFile ) == 0 )
396   {
397     doSaveTic( NULL, hatchInfo, filearea );
398   }
399 
400   nfree( hatchedFile );
401   return HATCH_OK;
402 }
403 
send(char * filename,char * area,char * addr)404 HATCH_SEND_RETURN_CODES send( char *filename, char *area, char *addr )
405 /* 0 - OK */
406 /* 1 - Passthrough filearea */
407 /* 2 - filearea not found */
408 /* 3 - file not found */
409 /* 4 - link not found */
410 /* 5 - put on link error */
411 /* -1 - invalid parameter */
412 {
413   s_ticfile tic;
414   s_link *link = NULL;
415   s_area *filearea;
416   char *sendfile = NULL, *descr_file_name = NULL, *tmpfile = NULL;
417   char timestr[40];
418   struct stat stbuf;
419   time_t acttime;
420   HATCH_SEND_RETURN_CODES rc;
421 
422   if( !filename || !area || !addr )
423   {
424     w_log( LL_CRIT,
425            __FILE__
426            ":: Parameter is NULL: send(%s,%s,%s). This is serious error in program, please report to developers.",
427            filename ? "filename" : "NULL", area ? "area" : "NULL", addr ? "addr" : "NULL" );
428     return HATCH_SEND_E_INVALID;
429   }
430 
431   w_log( LL_INFO, "Start file send (%s in %s to %s)", filename, area, addr );
432 
433   filearea = getFileArea( area );
434   if( filearea == NULL )
435   {
436     if( !quiet )
437       fprintf( stderr, "Error: Filearea not found\n" );
438     return HATCH_SEND_E_FILEAREANOTFOUND;
439   }
440 
441   link = getLink( config, addr );
442   if( link == NULL )
443   {
444     if( !quiet )
445       fprintf( stderr, "Error: Link not found\n" );
446     return HATCH_SEND_E_LINKNOTFOUND;
447   }
448 
449   memset( &tic, 0, sizeof( tic ) );
450 
451   if( filearea->msgbType == MSGTYPE_PASSTHROUGH )
452     sendfile = sstrdup( config->passFileAreaDir );
453   else
454     sendfile = sstrdup( filearea->fileName );
455 
456   strLower( sendfile );
457   _createDirectoryTree( sendfile );
458   xstrcat( &sendfile, filename );
459 
460   /*  Exist file? */
461   adaptcase( sendfile );
462   if( !fexist( sendfile ) )
463   {
464     if( !quiet )
465       fprintf( stderr, "Error: File not found\n" );
466     w_log( '6', "File %s, not found", sendfile );
467     nfree( sendfile );
468     disposeTic( &tic );
469     return HATCH_SEND_E_FILENOTFOUND;
470   }
471 
472   tic.file = sstrdup( filename );
473 
474   if( filearea->sendorig )
475   {
476     xstrscat( &tmpfile, config->passFileAreaDir, tic.file, NULL );
477     adaptcase( tmpfile );
478 
479     if( copy_file( sendfile, tmpfile, 1 ) != 0 )
480     {                           /* overwrite existing file if not same */
481       adaptcase( sendfile );
482       if( copy_file( sendfile, tmpfile, 1 ) == 0 )
483       {                         /* overwrite existing file if not same */
484         w_log( '6', "Copied %s to %s", sendfile, tmpfile );
485       }
486       else
487       {
488         w_log( '9', "File %s not found or not copyable", sendfile );
489         disposeTic( &tic );
490         nfree( sendfile );
491         nfree( tmpfile );
492         return HATCH_SEND_E_FILEAREANOTFOUND;
493       }
494     }
495     else
496     {
497       w_log( '6', "Copied %s to %s", sendfile, tmpfile );
498       strcpy( sendfile, tmpfile );
499     }
500   }
501 
502   tic.area = sstrdup( area );
503 
504   stat( sendfile, &stbuf );
505   tic.size = stbuf.st_size;
506 
507   tic.origin = tic.from = *filearea->useAka;
508 
509   /*  Adding crc */
510   tic.crc = filecrc32( sendfile );
511 
512   xstrscat( &descr_file_name, filearea->fileName, config->fileDescription, NULL );
513   adaptcase( descr_file_name );
514 
515   GetDescFormBbsFile( descr_file_name, tic.file, &tic );
516 
517   /*  Adding path */
518   time( &acttime );
519   strcpy( timestr, asctime( gmtime( &acttime ) ) );
520   timestr[strlen( timestr ) - 1] = 0;
521   if( timestr[8] == ' ' )
522     timestr[8] = '0';
523   tic.path = srealloc( tic.path, ( tic.anzpath + 1 ) * sizeof( *tic.path ) );
524   tic.path[tic.anzpath] = NULL;
525   xscatprintf( &tic.path[tic.anzpath], "%s %lu %s UTC %s",
526                aka2str( *filearea->useAka ), ( unsigned long )time( NULL ), timestr, versionStr );
527   tic.anzpath++;
528 
529   /*  Adding Downlink to Seen-By */
530   seenbyAdd( &tic.seenby, &tic.anzseenby, &link->hisAka );
531   /*  Forward file to */
532   if( PutFileOnLink( sendfile, &tic, link ) )
533     rc = HATCH_SEND_OK;
534   else
535     rc = HATCH_SEND_E_PUT_ON_LINK;
536 
537   disposeTic( &tic );
538   nfree( sendfile );
539   nfree( tmpfile );
540   nfree( descr_file_name );
541   return rc;
542 }
543 
544 /* Return values:
545  * 1 if success
546  * 0 if error
547  */
PutFileOnLink(char * newticedfile,s_ticfile * tic,s_link * downlink)548 int PutFileOnLink( char *newticedfile, s_ticfile * tic, s_link * downlink )
549 {
550   int busy = 0;
551   char *linkfilepath = NULL;
552   char *newticfile = NULL;
553   FILE *flohandle = NULL;
554   hs_addr *aka;
555   char *str_hisAka, *str_Aka;
556 
557   if( !newticedfile || !tic || !downlink )
558   {
559     w_log( LL_CRIT,
560            __FILE__
561            ":: Parameter is NULL: PutFileOnLink(%s,%s,%s). This is serious error in program, please report to developers.",
562            newticedfile ? "newticedfile" : "NULL", tic ? "tic" : "NULL",
563            downlink ? "downlink" : "NULL" );
564     return 0;
565   }
566 
567   aka = SelectPackAka( downlink );
568   memcpy( &tic->from, downlink->ourAka, sizeof( hs_addr ) );
569   memcpy( &tic->to, &downlink->hisAka, sizeof( hs_addr ) );
570 
571   nfree( tic->password );
572   if( downlink->ticPwd != NULL )
573     tic->password = sstrdup( downlink->ticPwd );
574 
575   if( createOutboundFileNameAka( downlink, downlink->fileEchoFlavour, FLOFILE, aka ) == 1 )
576     busy = 1;
577 
578   if( busy )
579   {
580     xstrcat( &linkfilepath, config->busyFileDir );
581   }
582   else
583   {
584     if( config->separateBundles )
585     {
586       char *point = strrchr( downlink->floFile, '.' );
587 
588       *point = '\0';
589       xscatprintf( &linkfilepath, "%s.sep%c", downlink->floFile, PATH_DELIM );
590       *point = '.';
591     }
592     else
593     {
594       xstrcat( &linkfilepath, config->ticOutbound );
595     }
596   }
597 
598   /*  fileBoxes support */
599   if( needUseFileBoxForLinkAka( config, downlink, aka ) )
600   {
601     nfree( linkfilepath );
602     if( !downlink->fileBox )
603       downlink->fileBox = makeFileBoxNameAka( config, downlink, aka );
604     xstrcat( &linkfilepath, downlink->fileBox );
605   }
606 
607   _createDirectoryTree( linkfilepath );
608   /* Don't create TICs for everybody */
609   if( !downlink->noTIC )
610   {
611     newticfile = makeUniqueDosFileName( linkfilepath, "tic", config );
612     if( !writeTic( newticfile, tic ) )
613     {
614       /* try to toss into config->busyFileDir */
615       w_log( LL_CRIT, "Can't write into: %s", linkfilepath );
616       nfree( newticfile );
617       nfree( linkfilepath );
618       xstrcat( &linkfilepath, config->busyFileDir );
619       newticfile = makeUniqueDosFileName( linkfilepath, "tic", config );
620       if( !writeTic( newticfile, tic ) )
621       {
622         w_log( LL_CRIT, "Can't write into: %s", linkfilepath );
623         nfree( newticfile );
624         return 0;
625       }
626       busy = 1;                 /* do not touch floFile if it's BSO */
627     }
628   }
629   else
630     newticfile = NULL;
631 
632   if( needUseFileBoxForLinkAka( config, downlink, aka ) )
633   {
634     /* do not copy file into busyFileDir */
635     if( strcasecmp( linkfilepath, config->busyFileDir ) )
636     {
637       xstrcat( &linkfilepath, tic->file );
638       if( link_file( newticedfile, linkfilepath ) == 0 )
639       {
640         if( copy_file( newticedfile, linkfilepath, 1 ) == 0 )
641         {                       /* overwrite existing file if not same */
642           w_log( LL_FILESENT, "Copied: %s", newticedfile );
643           w_log( LL_FILESENT, "    to: %s", linkfilepath );
644         }
645         else
646         {
647           w_log( '9', "File %s not found or not copyable", newticedfile );
648           if( !busy && downlink->bsyFile )
649             remove( downlink->bsyFile );
650           nfree( downlink->bsyFile );
651           nfree( downlink->floFile );
652           nfree( linkfilepath );
653         }
654       }
655       else
656       {
657         w_log( LL_FILESENT, "Linked: %s", newticedfile );
658         w_log( LL_FILESENT, "    to: %s", linkfilepath );
659       }
660     }
661   }
662   else if( !busy )
663   {
664     flohandle = fopen( downlink->floFile, "a" );
665     fprintf( flohandle, "%s\n", newticedfile );
666     if( newticfile != NULL )
667       fprintf( flohandle, "^%s\n", newticfile );
668     fclose( flohandle );
669   }
670   if( !busy || needUseFileBoxForLinkAka( config, downlink, aka ) )
671   {
672 
673     str_hisAka = aka2str5d( downlink->hisAka );
674     str_Aka = aka2str5d( *aka );
675 
676     if( newticfile != NULL )
677       w_log( LL_LINK, "Forwarding %s with tic %s for %s via %s", tic->file,
678              GetFilenameFromPathname( newticfile ), str_hisAka, str_Aka );
679     else
680       w_log( LL_LINK, "Forwarding %s for %s via %s", tic->file, str_hisAka, str_Aka );
681 
682     nfree( str_hisAka );
683     nfree( str_Aka );
684 
685     if( !busy && downlink->bsyFile )
686       remove( downlink->bsyFile );
687   }
688   nfree( downlink->bsyFile );
689   nfree( downlink->floFile );
690   nfree( linkfilepath );
691   nfree( newticfile );
692   return 1;
693 }
694