#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <nit.h>
#include <ntt.h>
#include "ndwalk.h"


#define ABORT(msg) \
	fprintf(stderr,"%s at %d in %s\n",msg,__LINE__,__FILE__); \
	ExitWithUsage();
	

unsigned
	currentDrive;

BYTE
	baseDirectoryHandle,
	workDrive;
	
WORD
	serverConnID;
	
long
	sequenceNumber;

NWSALV_ENTRY
	dirEntry;

struct tm ts;

time_t
	currentTime,
	deleteTime;

double
	seconds,
	defaultTarget = 60.0 * 60.0 * 24.0 * 7.0,
	target = 0.0;

char
	directoryPathName[255],
	scratchPad[255],
	useDefaultTarget = 1,
	processSubdirectories = 0,
	reportOnly = 0,
	forceMidnight = 0,
	*rootDirectory = NULL,
	originalPathname[255],
	savePathname[255],
	tempName[13];


time_t TranslateDosDateTime(WORD dsrc,WORD tsrc,struct tm *tstruct)
{
time_t returnValue;

	tstruct->tm_year = (dsrc >> 9) + 80;
	tstruct->tm_mon  = ((dsrc >> 5) & 0x000f) - 1;
	tstruct->tm_mday = (dsrc & 0x1f);

	if (forceMidnight) {
		tstruct->tm_hour = 0;
		tstruct->tm_min = 0;
		tstruct->tm_sec = 0;
	}
	else {
		tstruct->tm_hour = (tsrc >> 11);
		tstruct->tm_min  = ((tsrc >> 5) & 0x003f);
		tstruct->tm_sec  = ((tsrc & 0x001f) * 2);
	}
	returnValue = mktime(tstruct);

	tstruct->tm_hour = (tsrc >> 11);
	tstruct->tm_min  = ((tsrc >> 5) & 0x003f);
	tstruct->tm_sec  = ((tsrc & 0x001f) * 2);
	mktime(tstruct);

	return(returnValue);	
}


PurgeFiles(BYTE directoryHandle)
{
int result;
WORD dtime, ddate;

	memset((char*)&dirEntry,0,sizeof(dirEntry));
	result = ScanSalvagableFiles(serverConnID,directoryHandle,&sequenceNumber,&dirEntry);
	if (result) return(0);

	ddate = *( ((WORD *)(&dirEntry.deletedDateAndTime))+1 );
	dtime = *( (WORD *)(&dirEntry.deletedDateAndTime) );

	deleteTime = TranslateDosDateTime(ddate,dtime,&ts);
	seconds = difftime(currentTime,deleteTime);

	if (seconds > target) {
		dirEntry.lastArchiveDateAndTime = 0;  /* kludge: create a terminator for name! */
	
			if (reportOnly) {
				printf("  advice ");
			}
			else {
				result = PurgeSalvagableFile(serverConnID,directoryHandle,sequenceNumber,
											dirEntry.name);
				if (result) {
					printf("  DENIED ");
				}
				else {
					printf("         ");
				}
			}
		printf("%2.2d/%2.2d/%4.2d %2.2d:%2.2d.%2.2d %s\n",
			ts.tm_mon+1, ts.tm_mday, ts.tm_year+1900, ts.tm_hour, ts.tm_min, ts.tm_sec,
			dirEntry.name);
	}
}


void ExitWithUsage()
{
	fprintf(stderr,"NPURGE  (Version 1.1)  Network Purge\n\n");
	fprintf(stderr,"Usage: npurge [-d <days>] [-h <hours>] [-m <minutes] [-s] [-r] [<root>]\n");
	fprintf(stderr,"          -d  Specify the age of target files in days\n");
	fprintf(stderr,"          -h  Specify the age of target files in hours\n");
	fprintf(stderr,"          -m  Specify the age of target files in minutes\n");
	fprintf(stderr,"          -f  Force file times to midnight (use with -d)\n");
	fprintf(stderr,"          -s  process subdirectories\n");
	fprintf(stderr,"          -r  report only, do not purge files\n");
	fprintf(stderr,"      <root>  specify starting directory\n");
	fprintf(stderr,"   The -d, -h, -m parameters are additive\n");
	exit(255);
}
	


#define NEXTARG \
	if (*(++(*argv)) == 0) { \
		argv++; \
		argc--; \
	}



void ParseOptions(int argc, char **argv)
{
	while(--argc > 0) {
		++argv;
		if (**argv == '-') {
			(*argv)++;
			switch (**argv) {
				case 'd':
					NEXTARG;
					target += atof(*argv) * 60 * 60 * 24;
					useDefaultTarget = 0;
					break;
				case 'h':
					NEXTARG;
					target += atof(*argv) * 60 * 60;
					useDefaultTarget = 0;
					break;
				case 'm':
					NEXTARG;
					target += atof(*argv) * 60;
					useDefaultTarget = 0;
					break;
				case 's':
					processSubdirectories = 1;
					break;
				case 'f':
					forceMidnight = 1;
					break;
				case 'r':
					reportOnly = 1;
					break;
				default:
					fprintf(stderr,"Unknown option: -%s\n",*argv);
					ExitWithUsage(); 
			}
		}
		else {
			if (rootDirectory != NULL) {
				ABORT("Root directory may only be specified once");
			}
			rootDirectory = *argv;
		}				
	}
}

void ProcessDirectory(BYTE directoryHandle)
{
BYTE newDirectoryHandle;

	GetDirectoryPath(directoryHandle,directoryPathName);
	printf("%s\n",directoryPathName);

	GetDirectoryPath(baseDirectoryHandle,savePathname);

	if (SetDirectoryHandle(baseDirectoryHandle,directoryPathName,baseDirectoryHandle)) {
		ABORT("Can't change directories");
	}
	
	sequenceNumber = -1;
	while(PurgeFiles(baseDirectoryHandle));

	if (SetDirectoryHandle(baseDirectoryHandle,savePathname,baseDirectoryHandle)) {
		ABORT("Can't change directories");
	}
}



main(int argc, char **argv)
{
BYTE newDirectoryHandle;
int result;

	if (argc == 1)  ExitWithUsage();

	time(&currentTime);

	_dos_getdrive(&currentDrive);
	currentDrive--;
	
	if (GetDriveInformation((BYTE)currentDrive,&serverConnID,&baseDirectoryHandle) & 1 != 1) {
		ABORT("Must be run from a network drive");
	}

	if (!IsV3Supported(serverConnID)) {
		ABORT("Must be Netware 386");
	}
	
	GetDirectoryPath(baseDirectoryHandle,originalPathname);
	
	ParseOptions(argc,argv);
	
	if (useDefaultTarget) target = defaultTarget;

	if (rootDirectory != NULL) {
		if (SetDirectoryHandle(baseDirectoryHandle,rootDirectory,baseDirectoryHandle)) {
			fprintf(stderr,"Possibly bad directory name: %s\n",rootDirectory);
			ABORT("Can't change directories");
		}
	}
	
	ProcessDirectory(baseDirectoryHandle);
	
	if (processSubdirectories) {
		WalkDirectory(baseDirectoryHandle,ProcessDirectory);
	}

	if (SetDirectoryHandle(baseDirectoryHandle,originalPathname,baseDirectoryHandle)) {
		ABORT("Can't change directories");
	}
}
