1 /*****************************************************************************
2  * HTICK --- FTN Ticker / Request Processor
3  *****************************************************************************
4  * Copyright (C) 1999 by
5  *
6  * Gabriel Plutzar
7  *
8  * Fido:     2:31/1
9  * Internet: gabriel@hit.priv.at
10  *
11  * Vienna, Austria, Europe
12  *
13  * This file is part of HTICK, which is based on HPT by Matthias Tichy,
14  * 2:2432/605.14 2:2433/1245, mtt@tichy.de
15  *
16  * HTICK is free software; you can redistribute it and/or modify it
17  * under the terms of the GNU General Public License as published by the
18  * Free Software Foundation; either version 2, or (at your option) any
19  * later version.
20  *
21  * HTICK is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with HTICK; see the file COPYING.  If not, write to the Free
28  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
29  *****************************************************************************
30  * $Id$
31  *****************************************************************************/
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <sys/types.h>
38 #include <signal.h>
39 #include <fcntl.h>
40 #include <sys/stat.h>
41 
42 #if (defined(__EMX__) || defined(__MINGW32__)) && defined(__NT__)
43 /* we can't include windows.h for prevent conflicts: send() & other */
44 # define CharToOem CharToOemA
45 #endif
46 
47 /*  compiler.h */
48 #include <huskylib/compiler.h>
49 
50 #ifdef HAS_UNISTD_H
51 # include <unistd.h>
52 #endif
53 
54 #ifdef HAS_IO_H
55 # include <io.h>
56 #endif
57 
58 #ifdef __OS2__
59 # define INCL_DOSPROCESS
60 # define INCL_DOSERRORS
61 # include <os2.h>
62 #endif
63 
64 /* smapi */
65 #include <smapi/msgapi.h>
66 #include <huskylib/huskylib.h>
67 
68 /* fidoconf */
69 #include <fidoconf/fidoconf.h>
70 #include <fidoconf/common.h>
71 #include <huskylib/log.h>
72 #include <huskylib/recode.h>
73 #include <huskylib/xstr.h>
74 #include <huskylib/ftnaddr.h>
75 
76 /* areafix library */
77 #include <areafix/areafix.h>
78 #include <areafix/afglobal.h>
79 
80 /* htick */
81 #include <htick.h>
82 #include <global.h>
83 #include "version.h"
84 #include <toss.h>
85 #include <scan.h>
86 #include <hatch.h>
87 #include <filelist.h>
88 #include <htickafix.h>
89 #include "report.h"
90 
processHatchParams(int i,int argc,char ** argv)91 int processHatchParams( int i, int argc, char **argv )
92 {
93 
94   char *basename, *extdelim;
95 
96   if( argc - i < 2 )
97   {
98     fprintf( stderr, "Insufficient number of arguments\n" );
99     return 0;
100   }
101 
102   cmHatch = 1;
103   hatchInfo = scalloc( sizeof( s_ticfile ), 1 );
104   basename = ( argv[i] != NULL ) ? argv[i++] : "";
105   hatchInfo->file = sstrdup( basename );
106   hatchInfo->anzdesc = 1;
107   hatchInfo->desc =
108       srealloc( hatchInfo->desc, ( hatchInfo->anzdesc ) * sizeof( &hatchInfo->desc ) );
109   hatchInfo->desc[0] = sstrdup( "-- description missing --" );
110 
111   /*  Check filename for 8.3, warn if not */
112   basename = strrchr( hatchInfo->file, PATH_DELIM );
113   if( basename == NULL )
114     basename = hatchInfo->file;
115   else
116     basename++;
117   if( ( extdelim = strchr( basename, '.' ) ) == NULL )
118     extdelim = basename + strlen( basename );
119 
120   if( extdelim - basename > 8 || strlen( extdelim ) > 4 )
121   {
122     if( !quiet )
123       fprintf( stderr, "Warning: hatching file with non-8.3 name!\n" );
124   }
125   basename = ( argv[i] != NULL ) ? argv[i++] : "";
126   hatchInfo->area = sstrdup( basename );
127 
128   if( argc - i == 0 )
129   {
130     return 1;
131   }
132   if( stricmp( argv[i], "replace" ) == 0 )
133   {
134     if( ( i < argc - 1 ) && ( stricmp( argv[i + 1], "desc" ) != 0 ) )
135     {
136       i++;
137       hatchInfo->replaces = sstrdup( argv[i] );
138     }
139     else
140     {
141       basename = strrchr( hatchInfo->file, PATH_DELIM ) ?
142           strrchr( hatchInfo->file, PATH_DELIM ) + 1 : hatchInfo->file;
143 
144       hatchInfo->replaces = sstrdup( basename );
145     }
146     if(i < argc - 1)
147     {
148         i++;
149     }
150   }
151   if( stricmp( argv[i], "desc" ) != 0 )
152     return 1;
153   else if( argc - i < 2 )
154     return 1;
155   i++;
156   nfree( hatchInfo->desc[0] );
157   hatchInfo->desc[0] = sstrdup( argv[i] );
158 #ifdef __NT__
159   CharToOem( hatchInfo->desc[0], hatchInfo->desc[0] );
160 #endif
161   i++;
162   if( argc - i != 0 )
163   {
164     hatchInfo->anzldesc = 1;
165     hatchInfo->ldesc =
166         srealloc( hatchInfo->ldesc, ( hatchInfo->anzldesc ) * sizeof( &hatchInfo->ldesc ) );
167     hatchInfo->ldesc[0] = sstrdup( argv[i] );
168 
169 #ifdef __NT__
170     CharToOem( hatchInfo->ldesc[0], hatchInfo->ldesc[0] );
171 #endif
172 
173   }
174   return 1;
175 }
176 
start_help(void)177 void start_help( void )
178 {
179   printf( "%s\n", versionStr );
180   printf( "\nUsage: htick [options] <command>\n"
181           "Options: -q              Quiet mode (display only urgent messages to console)\n"
182           "         -c <conf-file>  Specify an alternative configuration file\n"
183           "Commands:\n"
184           " toss [annfecho <file>]  Do tossing. [Announce new fileechos in text file]\n"
185           " toss -b                 Toss bad tics\n"
186           " scan                    Scan netmail area for mails to filefix and process\n"
187           "                         filefix commands contained inside the mails\n"
188           " ffix <addr> <command>   Process filefix command for address from command line\n"
189           " ffix! <addr> <command>  The same as 'ffix' and notify the link of the \n"
190           "                         processed filefix command\n"
191           " relink <pattern> <addr> Refresh subscription for fileareas matching pattern\n"
192           " relink -f [file] <addr> Refresh subscription for fileareas listed in the file\n"
193           " resubscribe <pattern> <fromaddr> <toaddr> - move subscription of areas\n"
194           "                         matching the pattern from one link to another\n"
195           " resubscribe -f [file] <fromaddr> <toaddr> - move subscription of areas\n"
196           "                         matching area patterns listed in this file with one\n"
197           "                         pattern on a line from one link to another\n"
198           " clean                   Clean passthrough dir and old files in fileechos\n"
199           " announce                Announce new files\n"
200           " send <file> <filearea> <address> Send file from filearea to address\n"
201           " hatch <file> <area> [replace [<filemask>]] [desc <desc> [<ldesc>]]\n"
202           "                         Hatch file into area using description for file,\n"
203           "                         if \"replace\" is present, add replace field to TIC;\n"
204           "                         if <filemask> is not present then put <file> in field;\n"
205           "                         if \"desc\" is present, add description(s);\n"
206           "                         a short one line <desc> and a long <ldesc>.\n"
207           "                         One may use the following as <desc>:\n"
208           "                           @@BBS to use first line from files.bbs\n"
209           "                           @@DIZ to use 1st line from the contained file_id.diz\n"
210           "                           @@<file> to use first line from <file>\n"
211           "                           @BBS to load from files.bbs\n"
212           "                           @DIZ to load from the contained file_id.diz\n"
213           "                           @<file> to load from <file>\n"
214           "                         The last three items may be used as <ldesc>.\n"
215           " filelist <file> [<dirlist>] Generate filelist which includes all files in base\n"
216           "                             <dirlist> - list of paths to files from filelist\n" );
217 }
218 
processCommandLine(int argc,char ** argv)219 e_exitCode processCommandLine( int argc, char **argv )
220 {
221   int i = 0;
222   e_exitCode rc = ex_OK;
223 
224   if( argc == 1 )
225   {
226     start_help(  );
227     return ex_Help;
228   }
229 
230   while( i < argc - 1 )
231   {
232     i++;
233     if( !strcmp( argv[i], "-h" ) )
234     {
235       start_help(  );
236       return ex_Help;
237     }
238     if( !strcmp( argv[i], "-v" ) )
239     {
240       printf( "%s", versionStr );
241       return ex_Help;
242     }
243     if( !strcmp( argv[i], "-q" ) )
244     {
245       quiet = 1;
246       continue;
247     }
248     if( !strcmp( argv[i], "-c" ) )
249     {
250       i++;
251       if( argv[i] != NULL )
252         xstrcat( &cfgFile, argv[i] );
253       else
254 	  {
255         fprintf(stderr, "Parameter missing after \"%s\"!\n", argv[i - 1]);
256 		rc = ex_Error;
257 	  }
258       continue;
259     }
260     if( stricmp( argv[i], "toss" ) == 0 )
261     {
262       cmToss = 1;
263       if( i < argc - 1 )
264       {
265         if( stricmp( argv[i + 1], "-b" ) == 0 )
266         {
267           cmToss = 2;
268           i++;
269         }
270       }
271       continue;
272     }
273     else if( stricmp( argv[i], "scan" ) == 0 )
274     {
275       cmScan = 1;
276       continue;
277     }
278     else if( stricmp( argv[i], "hatch" ) == 0 )
279     {
280       processHatchParams( i + 1, argc, argv );
281       break;
282     }
283     else if( stricmp( argv[i], "ffix" ) == 0 )
284     {
285       if( i < argc - 1 )
286       {
287         i++;
288         parseFtnAddrZS( argv[i], &afixAddr );
289         if( i < argc - 1 )
290         {
291           i++;
292           xstrcat( &afixCmd, argv[i] );
293         }
294         else
295 		{
296           fprintf(stderr, "Parameter missing after \"%s\"!\n", argv[i]);
297 		  rc = ex_Error;
298 		}
299       }
300       cmAfix = 1;
301       continue;
302     }
303     else if( stricmp( argv[i], "ffix!" ) == 0 )
304     {
305       if( i < argc - 1 )
306       {
307         i++;
308         parseFtnAddrZS( argv[i], &afixAddr );
309         if( i < argc - 1 )
310         {
311           i++;
312           xstrcat( &afixCmd, argv[i] );
313         }
314         else
315 		{
316           fprintf(stderr, "Parameter missing after \"%s\"!\n", argv[i]);
317 		  rc = ex_Error;
318 		}
319       }
320       cmNotifyLink = 1;
321       cmAfix = 1;
322       continue;
323     }
324     else if( stricmp( argv[i], "relink" ) == 0 )
325     {
326       if( i < argc - 1 )
327       {
328         i++;
329         xstrcat( &relinkPattern, argv[i] );
330         if( i < argc - 1 )
331         {
332           i++;
333           parseFtnAddrZS( argv[i], &relinkFromAddr );
334           cmRelink = modeRelink;
335         }
336         else
337 		{
338           fprintf(stderr, "Address missing after \"%s\"!\n", argv[i]);
339 		  rc = ex_Error;
340 		}
341       }
342       else
343 	  {
344         fprintf(stderr, "Pattern missing after \"%s\"!\n", argv[i]);
345 		rc = ex_Error;
346 	  }
347       continue;
348     }
349     else if( stricmp( argv[i], "resubscribe" ) == 0 )
350     {
351       if (i < argc-1)
352       {
353         i++;
354         if (stricmp(argv[i], "-f") == 0)
355         {
356           if (i < argc-1)
357           {
358             i++;
359             if (fexist(argv[i]))
360             {
361               if (fsize(argv[i]) == 0)
362 			  {
363                 fprintf(stderr, "File \"%s\" is empty\n", argv[i]);
364 				rc = ex_Error;
365               }
366               xstrcat(&resubscribePatternFile, argv[i]);
367               cmRelink = modeResubsribeWithFile;
368             }
369             else
370             {
371               fprintf(stderr, "File \"%s\" does not exist\n", argv[i]);
372 			  rc = ex_Error;
373             }
374           }
375           else
376           {
377             fprintf(stderr, "Path missing after -f\n");
378 			rc = ex_Error;
379           }
380         }
381         else
382         {
383           xstrcat(&relinkPattern, argv[i]);
384           cmRelink = modeResubsribeWithPattern;
385         }
386         if (i < argc-1)
387         {
388           i++;
389           parseFtnAddrZS(argv[i], &relinkFromAddr);
390           if (i < argc-1)
391           {
392             i++;
393             parseFtnAddrZS(argv[i], &relinkToAddr);
394           }
395           else
396           {
397             fprintf(stderr, "Address missing after \"%s\"!\n", argv[i]);
398             rc = ex_Error;
399           }
400         }
401         else
402         {
403           fprintf(stderr, "Address missing after \"%s\"!\n", argv[i]);
404           rc = ex_Error;
405         }
406       }
407       else
408       {
409         fprintf(stderr, "Pattern missing after \"%s\"!\n", argv[i]);
410         rc = ex_Error;
411       }
412     }
413     else if( stricmp( argv[i], "send" ) == 0 )
414     {
415       cmSend = 1;
416       i++;
417       strcpy( sendfile, ( argv[i] != NULL ) ? argv[i++] : "" );
418       strcpy( sendarea, ( argv[i] != NULL ) ? argv[i++] : "" );
419       strcpy( sendaddr, ( argv[i] != NULL ) ? argv[i] : "" );
420       continue;
421     }
422     else if( stricmp( argv[i], "filelist" ) == 0 )
423     {
424       cmFlist = 1;
425       if( i < argc - 1 )
426       {
427         i++;
428         flistfile = sstrdup( argv[i] );
429         if( i < argc - 1 )
430         {
431           i++;
432           dlistfile = sstrdup( argv[i] );
433         }
434       }
435       continue;
436     }
437     else if( stricmp( argv[i], "announce" ) == 0 )
438     {
439       cmAnnounce = 1;
440       continue;
441     }
442     else if( stricmp( argv[i], "annfecho" ) == 0 )
443     {
444       if( i < argc - 1 )
445       {
446         i++;
447         cmAnnNewFileecho = 1;
448         strcpy( announcenewfileecho, argv[i] );
449       }
450       else
451       {
452         fprintf(stderr, "Insufficient number of arguments\n");
453 		rc = ex_Error;
454       }
455       continue;
456     }
457     else if( stricmp( argv[i], "clean" ) == 0 )
458     {
459       cmClean = 1;
460       continue;
461     }
462     else
463     {
464       fprintf(stderr, "Unrecognized command line option %s!\n", argv[i]);
465       rc = ex_Error;
466     }
467 
468   } /* endwhile */
469   return rc;
470 }
471 
processConfig()472 void processConfig(  )
473 {
474   char *buff = NULL;
475   int exitflag = 0;
476 
477   setvar( "module", "htick" );
478   SetAppModule( M_HTICK );
479   config = readConfig( cfgFile );
480   if( NULL == config )
481   {
482     nfree( cfgFile );
483     fprintf( stderr, "Config file not found\n" );
484     exit( 1 );
485   };
486 
487 
488   /* open Logfile */
489 
490   initLog( config->logFileDir, config->logEchoToScreen, config->loglevels,
491            config->screenloglevels );
492   setLogDateFormat( config->logDateFormat );
493   htick_log = openLog( LogFileName, versionStr );       /* if failed: openLog() prints a message to stderr */
494   if( htick_log && quiet )
495     htick_log->logEcho = 0;
496 
497   if( !sstrlen( config->inbound ) && !sstrlen( config->localInbound )
498       && !sstrlen( config->protInbound ) )
499   {
500     w_log( LL_CRIT, "You must set inbound, protInbound or localInbound in fidoconfig first" );
501     exitflag = 1;
502   }
503   if( !sstrlen( config->outbound ) )
504   {
505     w_log( LL_CRIT, "You must set outbound in fidoconfig first" );
506     exitflag = 1;
507   }
508   if( config->addrCount == 0 )
509   {
510     w_log( LL_CRIT, "At least one addr must be defined" );
511     exitflag = 1;
512   }
513   if( config->linkCount == 0 )
514   {
515     w_log( LL_CRIT, "At least one link must be specified" );
516     exitflag = 1;
517   }
518   if( config->fileAreaBaseDir == NULL )
519   {
520     w_log( LL_CRIT, "You must set FileAreaBaseDir in fidoconfig first" );
521     exitflag = 1;
522   }
523   if( config->passFileAreaDir == NULL )
524   {
525     w_log( LL_CRIT, "You must set PassFileAreaDir in fidoconfig first" );
526     exitflag = 1;
527   }
528   if( cmAnnounce && config->announceSpool == NULL )
529   {
530     w_log( LL_CRIT, "You must set AnnounceSpool in fidoconfig first" );
531     exitflag = 1;
532   }
533   if( config->MaxTicLineLength && config->MaxTicLineLength < 80 )
534   {
535     w_log( LL_CRIT, "Parameter MaxTicLineLength (%d) in fidoconfig must be 0 or >80\n",
536            config->MaxTicLineLength );
537     exitflag = 1;
538   }
539 
540   if( exitflag )
541   {
542     exit_htick( "Error(s) is found in config file, please run tparser and analize it's output.",
543                 1 );
544   }
545 
546 
547   if( config->lockfile )
548   {
549     lock_fd = lockFile( config->lockfile, config->advisoryLock );
550     if( lock_fd < 0 )
551     {
552       disposeConfig( config );
553       exit( EX_CANTCREAT );
554     }
555   }
556 
557   w_log( LL_START, "Start" );
558 
559   nfree( buff );
560 
561   if( config->busyFileDir == NULL )
562   {
563     config->busyFileDir = ( char * )smalloc( strlen( config->outbound ) + 10 );
564     strcpy( config->busyFileDir, config->outbound );
565     sprintf( config->busyFileDir + strlen( config->outbound ), "busy.htk%c", PATH_DELIM );
566   }
567   if( config->ticOutbound == NULL )
568     config->ticOutbound = sstrdup( config->passFileAreaDir );
569 }
570 
main(int argc,char ** argv)571 int main( int argc, char **argv )
572 {
573   struct _minf m;
574   int rc = 0;
575   e_exitCode res;
576 
577   versionStr = GenVersionStr( "htick", VER_MAJOR, VER_MINOR, VER_PATCH, VER_BRANCH, cvs_date );
578 
579   res = processCommandLine( argc, argv );
580   if( res == ex_Error )
581     return EX_USAGE;
582   else if( res == ex_Help )
583     return EX_OK;
584   processConfig(  );
585 
586   if( !( config->netMailAreas ) )
587     w_log( LL_CRIT, "Netmailarea not defined, filefix not allowed!" );
588 
589   /* init areafix */
590   if( !init_htickafix(  ) )
591     exit_htick( "Can't init Areafix library", 1 );
592 
593   /*  init SMAPI */
594   m.req_version = 0;
595   m.def_zone = config->addr[0].zone;
596   if( MsgOpenApi( &m ) != 0 )
597   {
598     exit_htick( "MsgApiOpen Error", 1 );
599   }                             /*endif */
600 
601   /*  load recoding tables */
602   initCharsets(  );
603   getctabs( config->intab, config->outtab );
604 #ifdef __NT__
605   SetFileApisToOEM(  );
606 #endif
607 
608   checkTmpDir(  );
609 
610   if( cmScan )
611     scan(  );
612   if( cmToss )
613     toss(  );
614   if( cmHatch )
615     rc = hatch(  );
616   if( cmSend )
617     send( sendfile, sendarea, sendaddr );
618   if( cmFlist )
619     filelist(  );
620   if( cmClean )
621     Purge(  );
622   if( cmAfix && config->netMailAreas )
623     ffix( afixAddr, afixCmd );
624   if( cmAnnounce && config->announceSpool != NULL )
625     report(  );
626 
627   if (cmRelink != modeNone)
628   {
629     int ret;
630     FILE *f;
631     char *line, *fromCmd = NULL, *toCmd = NULL, *toPrint = NULL;
632     unsigned int count = 0;
633 
634     w_log(LL_START, "%s has started", cmRelink == modeRelink ? "Relinking" : "Resubscribing");
635     if (cmRelink != modeResubsribeWithFile)
636     {
637       /* modeRelink or modeResubsribeWithPattern */
638       ret = relink(cmRelink, relinkPattern, relinkFromAddr, relinkToAddr, &fromCmd, &toCmd, &count);
639       nfree(relinkPattern);
640       if (ret)
641         return 1;
642     }
643     else
644     {
645       /* modeResubsribeWithFile */
646       f = fopen(resubscribePatternFile, "r");
647       if (f == NULL)
648       {
649         fprintf(stderr, "Cannot open file \"%s\"!\n", resubscribePatternFile);
650         nfree(resubscribePatternFile);
651         return 1;
652       }
653       else
654       {
655         while ((line = readLine(f)) != NULL)
656         {
657           xstrcat(&relinkPattern, line);
658           ret = relink(cmRelink, relinkPattern, relinkFromAddr, relinkToAddr, &fromCmd, &toCmd, &count);
659           nfree(relinkPattern);
660           if (ret)
661           {
662             nfree(resubscribePatternFile);
663             return 1;
664           }
665         }
666         nfree(resubscribePatternFile);
667       }
668     }
669     if (fromCmd)
670     {
671       if (cmRelink == modeRelink)
672         sendRelinkMsg(cmRelink, relinkFromAddr, fromCmd, smodeSubscribe);
673       else
674         sendRelinkMsg(cmRelink, relinkFromAddr, fromCmd, smodeUnsubscribe);
675       nfree(fromCmd);
676     }
677     if (toCmd)
678     {
679       sendRelinkMsg(cmRelink, relinkToAddr, toCmd, smodeSubscribe);
680       nfree(toCmd);
681     }
682     xscatprintf(&toPrint, "%i ", count);
683     count == 1 ? xscatprintf(&toPrint, "%s has been ", af_robot->strA) : xscatprintf(&toPrint, "%ses have been", af_robot->strA);
684     w_log(LL_AREAFIX, "%s %s", toPrint, cmRelink == modeRelink ? "relinked" : "resubscribed");
685     nfree(toPrint);
686   }
687 
688   nfree( afixCmd );
689   nfree( flistfile );
690   nfree( dlistfile );
691   if( hatchInfo )
692   {
693     disposeTic( hatchInfo );
694     nfree( hatchInfo );
695   }
696   /*  deinit SMAPI */
697   MsgCloseApi(  );
698 
699   doneCharsets(  );
700   w_log( LL_STOP, "End" );
701   closeLog(  );
702   if( config->lockfile )
703   {
704     FreelockFile( config->lockfile, lock_fd );
705   }
706   disposeConfig( config );
707   nfree( versionStr );
708 
709   return rc;
710 }
711