/*
 ************************************************************************
 *                          Verify files
 *   i.e. ensure the specified files to have total length and checksum
 *                              unchanged
 *
 * Call the routine
 *      verify catalog_file_name [-s]
 * where
 *      'catalog_file_name' (with default extension .VRF) specifies the text
 *      file containing information about files being verified.
 *      The fist record of the file is a comment and skipped.
 *      The other catalog entries are of form
 *              name of a file to be verified
 *              file length in blocks
 *              file check sum (modulo 2^32)
 *              date when information about this file was set
 *      verify program may work in two modes. When mode 'set' is specified
 *      by the key '-s' in the command string, the program fills in
 *      'file length' and 'file checksum' fields in each catalog entry.
 *      In 'check' mode (set on default) the program reads catalog, for
 *      each file obtains its length and checksum and compares them with
 *      the values in the catalog entry. When they are same the file is
 *      considered to be verified OK.
 *
 ************************************************************************
 */

#include <stdio.h>
#include <time.h>


/*
 *-----------------------------------------------------------------------
 *                   Calculate checksum of a file
 */
static long int checksum(file)
FILE *file;                             /* Assumed to be opened in BIN  */
{                                       /* mode                         */
  long int sum = 0;

  while( !feof(file) )
    sum += getw(file);

  return sum;
}


/*
 *========================================================================
 *                           Mainline processing
 */

char Filename [16];                     /* Name of the file to be verfd */
int Filesize;                           /* File size in blocks          */
long int Checksum;                      /* File checksum                */
char Datetime [25];                     /* Date and time in form        */
					/* THU JAN 01 00:00:00 1970\0   */

                                /* Verify the file specifd by Filename  */
                                /* and set Filesize and Checksum        */
                                /* Return 1 if OK                       */
static int file_process()
{
  FILE * fp;
  extern int $$flen;                    /* Length of the file just opend*/

  fprintf(stderr,"Processing %-14s ... ",Filename);
  if( (fp = fopen(Filename,"rn")) == 0 )
  {
    errmsg("Can't open: %s",errtxt());
    return 0;                           /* Opening error occurred       */
  }

  Filesize = $$flen;
  Checksum = checksum(fp);
  if( ferror(fp) )
  {
    errmsg("Read error: %s",errtxt());
    fclose(fp);
    return 0;                           /* Reading error occured        */
  }

  fclose(fp);
  return 1;                             /* Successful completion        */
}

                                /* Processing in SET mode               */
static set_mode_processing(catalog_file_name)
char * catalog_file_name;
{
  FILE *catif,                          /* Catalog input file           */
       *catof;                          /* Catalog output file          */

  char record [81];                     /* A catalog record             */

                                        /* Open the catalog             */
 catif = fopenexc(catalog_file_name,"r","VRF");
 catof = fopenexc(catalog_file_name,"w","VRF");
                                        /* Skip a comment record        */
 fputs(fgets(record,sizeof(record)-1,catif),catof);

 while( !feof(catif) )                  /* Main loop                    */
 {
   if( ferror(catif) )
     error("Error reading catalog: %s. Processing terminated",errtxt());

   if( fgets(record,sizeof(record)-1,catif) == 0 )/*Get a catalog record*/
     break;

   if( sscanf(record,"%16s",Filename) != 1 )
     continue;                          /* Skip a bad catalog entry     */

   if( !file_processing() )             /* Error on opening or reading  */
     continue;                          /* file, skip the corr. cat recd*/

   fprintf(catof,"%-16s %3d %8lx %s\n",Filename,Filesize,Checksum,Datetime);
   fprintf(stderr," Checksum is %8lx\n",Checksum);
 }

 fclose(catif);
 if( ferror(catof) )
 {
   errmsg("\nError writing new catalog file. The catalog remains unchanged");
   fpurge(catof);
 }
 else
 fclose(catof);
}

                                /* Processing in CHECK mode             */
static check_mode_processing(catalog_file_name)
char * catalog_file_name;
{
  FILE *catif;                          /* Catalog input file           */
  char record [81];                     /* A catalog record             */
  int  old_filesize;                    /* Filesize from a catalog entry*/
  long int old_checksum;                /* Checksum from a catalog entry*/
  int total_counter = 0;                /* for files frocessed          */
  int ok_counter = 0;                   /* for files verified ok        */

                                        /* Open the catalog             */
 catif = fopenexc(catalog_file_name,"r","VRF");
                                        
 fgets(record,sizeof(record)-1,catif);  /* Skip a comment record        */

 while( !feof(catif) )                  /* Main loop                    */
 {
   if( ferror(catif) )
     error("Error reading catalog: %s. Processing terminated",errtxt());

   if( fgets(record,sizeof(record)-1,catif) == 0 )/*Get a catalog record*/
     break;

   if( sscanf(record,"%16s %d %lx",
              Filename,&old_filesize,&old_checksum) != 3 )
     continue;                          /* Skip a bad catalog entry     */

   total_counter++;
   if( !file_processing() )             /* Error on opening or reading  */
     continue;                          /* file, skip the corr. cat recd*/

   if( Checksum == old_checksumi && Filesize == old_filesize )
   {
     fprintf(stderr,"\b\b\b OK\r");
     ok_counter++;
   }
   else
     errmsg("\n\tNew/old filesize %d/%d, new/old checksum %8lx/%8lx ***",
            Filesize,old_filesize,Checksum,old_checksum);
 }

 fclose(catif);
 fprintf(stderr,"\n\n%d files have been verified OK from the total %d\n",
         ok_counter, total_counter);
}


/*
 *========================================================================
 *			Initialization routines
 */

/*
 *-----------------------------------------------------------------------
 *		Get the current date and time and fill in
 *			  Datetime string
 */
get_date_and_time()
{
  long clock;				/* Time in UNIX standard	*/
  time(&clock);				/* Get the UNIX-like time	*/
  sprintf(Datetime,"%.24s",ctime(&clock)); /* and convert it to ASCII	*/
}


/*
 *-----------------------------------------------------------------------
 *				Root module
 *      Parse the command string, set the mode and main control
 */
main(argc,argv)
int argc;				/* No. of arguments being passed*/
char *argv[];				/* Vector of pointers to args 	*/
{
 char * catalog_file_name;
 int mode_SET = 0;                      /* 1 if mode is SET             */


 if(argc <= 1 || argc > 3)              /* One or two arguments are     */
   {                                    /* expected (except the pgm nam)*/
     puts("\nVerify files\nUsage:");
     puts("\n\tverify catalog_file_name [-s]");
     puts("\nwhere key '-s' specifies for the SET mode");
     exit();
 }

 catalog_file_name = argv[1];

 if( argc == 3 )                        /* Next argument may be a key   */
 {
     register char *p = argv[2];
     if( strcmp(p,"-s") != 0 )
       error("\nIllegal key '%s' is specified. '-s' was expected",p);
     mode_SET = 1;                      /* Set the SET mode             */
 }

 get_date_and_time();
                                        /* Double height header         */
 printf("\n\n\t\033#3* \033[1mVerify files\033[m *");
 printf(  "\n\t\033#4* \033[1mVerify files\033[m *");
 printf("\n\nCatalog %s,  mode \033[4m%s\033[m\n\n",catalog_file_name,
                          ( mode_SET ? "SET" : "CHECK" ) );

 if( mode_SET )
   set_mode_processing(catalog_file_name);
 else
   check_mode_processing(catalog_file_name);

}
