/* --------------------------------------------------------------------
   DXZIP - This routine does for PKZIP and ZIP files what DXARC did for
           ARC files: deletes files on the main directory already in
           the ZIP file, either by name only or if size, date, and time
           matches.

   Compiler: Turbo C 1.5. Will compile under Turbo C 2.0 or under 
             MicroSoft C 5.0 or later or QuickC 2.0 or later.

   Contributions are welcome...send to:
   Edward V. Dong
   12205 Alexandria Place
   Chino, CA 91710
   Comments may be directed to E.DONG on Diamond Bar BBS at 714-861-1549
   (1200/2400/9600), "E.DONG" on GENIE, or 71641,2371 on CompuServ.
   PKZIP is copyrighted by Phil Katz.
   This routine is copyright (c) 1989 by Edward V. Dong, All Rights Reserved.
   -------------------------------------------------------------------- */
#include <stdio.h>
#include <string.h>
#include <mem.h>
#include <dos.h>
#include <dir.h>

typedef	long	signature_type;

signature_type	local_file_header_signature	= 0x04034b50;
signature_type	central_file_header_signature	= 0x02014b50;
signature_type	end_central_dir_signature	= 0x06054b50;

int	name = 0;		/* default must be complete match */
int	prompt = 0;		/* default is no prompt */
int	FilesKilled = 0;	/* initialize to zero files killed */
int	NoOfFiles = 0;		/* initialize to zero files scanned */

typedef struct xyx
{	int	version_needed_to_extract;
	int	general_purpose_bit_flag;
	int	compression_method;
	int	last_mod_file_time;
	int	last_mod_file_date;
	long	crc32;
	long	compressed_size;
	long	uncompressed_size;
	int	filename_length;
	int	extra_field_length;
} local_file_header;

typedef struct xyxx
{	int	version_made_by;
	int	version_needed_to_extract;
	int	general_purpose_bit_flag;
	int	compression_method;
	int	last_mod_file_time;
	int	last_mod_file_date;
	long	crc32;
	long	compressed_size;
	long	uncompressed_size;
	int	filename_length;
	int	extra_field_length;
	int	file_comment_length;
	int	disk_number_start;
	int	internal_file_attributes;
	long	external_file_attributes;
	long	relative_offset_local_header;
} central_directory_file_header;

typedef struct xyx2
{	int	number_this_disk;
	int	number_disk_with_start_central_directory;
	int	total_entries_central_dir_on_this_disk;
	int	total_entries_central_dir;
	long	size_central_directory;
	long	offset_start_central_directory;
	int	zipfile_comment_length;
} end_central_dir_record;

FILE*	zipfile;

int killfile(char *filename,int date,int time,long filelen)
{					/* kill main files tagged in ZIP */
struct  ffblk   ffblk;
int Kill;
	Kill = 0;			/* don't kill file */
	NoOfFiles++;			/* increment number of files scanned */
        if (!findfirst(filename,&ffblk,FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_ARCH))
	{	if (	(date==ffblk.ff_fdate) &&
			(time==ffblk.ff_ftime) &&
			(filelen==ffblk.ff_fsize))
				    Kill = 1;	/* match found */
		if (prompt)
		{	printf(" ?");
			if (toupper(getch())!='Y') return;
			Kill = 1;		/* kill file */
		}
		if (name) Kill = 1;		/* kill on name match */

		if (Kill)
		{	if (!unlink(filename))
			{	printf("\t: Killed\n");
				FilesKilled++;
			}
			else printf("\t: Can't Kill\n");
		}
	}
	else printf(": Not Found\n");
}

void process_local_file_header(void)
{
local_file_header	header;
char	filename[240], extra[240];
int	mon, day, year, hrs, min;

/* read local file header to get filename */
	fread(&header,sizeof(local_file_header),1,zipfile);
   	setmem(filename,sizeof(filename),0);
   	fread(filename,header.filename_length,1,zipfile);	/* get filename */
   	fread(extra,header.extra_field_length,1,zipfile);
   	fseek(zipfile,header.compressed_size,1);	/* skip to next one */

/* list file name, date, time, size */
	printf("%s",filename);
	killfile(filename,header.last_mod_file_date,
		header.last_mod_file_time,header.uncompressed_size);
}

void process_central_file_header(void)
{
central_directory_file_header	header;
char	filename[240], extra[240], comment[240];

/* open ZIP file & print optional comment if any */
	fread(&header,sizeof(central_directory_file_header),1,zipfile);
	fread(filename,header.filename_length,1,zipfile);
	fread(extra,header.extra_field_length,1,zipfile);
	setmem(comment,sizeof(comment),0);
	fread(comment,header.file_comment_length,1,zipfile);
	if (comment[0]) printf("%s\n",comment);
}

void process_end_central_dir(void)
{
end_central_dir_record	record;
int	count;

	fread(&record,sizeof(end_central_dir_record),1,zipfile);
	count = record.zipfile_comment_length;
	while (count)			/* bypass comments */
	{	fgetc(zipfile);
		count--;
	}
}

void process_headers(void)
{
long	sig;

	while (1)
	{	if (!fread(&sig,sizeof(long),1,zipfile))
		{	printf("\nZIP file is truncated: aborting...");
			exit(1);
		}
		if (sig == local_file_header_signature)
			process_local_file_header();
		else if (sig == central_file_header_signature)
			process_central_file_header();
		else if (sig == end_central_dir_signature)
		{	process_end_central_dir();
			printf("SUMMARY: %d (of %d) files killed\n",
				FilesKilled,NoOfFiles);
			return;
		}
		else
		{	printf("\nZIP file has errors...aborting!\n");
			exit(1);
		}
	}
}

main(int argc,char *argv[])
{
char	filename[240];
int	count;
	argc--;argv++;		/* skip zeroth argument */
	printf("DXZIP 1.0 (c) 1989 by E.Dong (on GENIE) (CIS 71641,2371)\n");
	if (argc)
	{	strcpy(filename,argv[0]);
		argc--;
		if (argc)
		{	count = strlen(strupr(argv[1]));
			if (strncmp(argv[1],"NAME",count)==0)
				name = 1;
			else if (strncmp(argv[1],"PROMPT",count)==0)
				prompt = 1;
		}
		if (strchr(filename,'.')==NULL)	/* no extension given */
			strcat(filename,".ZIP");/* add default extension */
		zipfile = fopen(filename,"rb");	/* open file if possible */
		if (zipfile == NULL)		/* error on opening file */
		{	printf("Unable to open file %s\n",filename);
			exit(1);
		}
		else process_headers();
		fclose(zipfile);
	}
	else
	{	printf("Deletes file(s) in current directory found in ZIP file\n");
		printf("Syntax: DXZIP zipfile [name|prompt]\n");
		printf("        'zipfile' is required\n");
		printf("        'name' deletes file on name match\n");
		printf("        'prompt' asks if to delete file\n");
	}
}
