//---------------------------------------------------------------------------
// LOGIN										(c) Laurence Vanhelsuwe 1994
// -----
// This program is part of a group of 3 complementary programs to log the
// usage of a stand-alone machine. (LOGIN, LOGOUT, PASSWORD)
//
// This program has been written in ANSI C to make it fully portable across
// different hardware platforms.
//
// Original development and testing was carried out on a Commodore Amiga 3000.
//
// This program and its companion LOGOUT will maintain a log file detailing
// machine usage for all authorised users.
// Authorised users are added by the PASSWORD command, which itself can only
// be used by a 'System Operator' who knows the password to activate the
// program.
//
// 2 Datafiles are maintained by the trio of programs:
//  - USERLOG.DAT
//  - PASSWOR.DAT
//
// History
// -------
// 01-JAN-94: Design and initial file creation.
// 13-JAN-94: ANSI C portability MY FOOT !!! Still struggling with porting this!
// 26-JAN-94: Finally got it: ANSI level 1 defines binary and text modes.
//			  I was using TEXT mode... which interprets EOF differently !!
// 07-FEB-94: Disabled Control-C checking for Amiga implementation
//
//---------------------------------------------------------------------------

//#define		DEBUG			1

#include	"stdio.h"
#include	"stdlib.h"
#include	"string.h"
#include	"fcntl.h"
#include	"time.h"

#define		TRUE			(1)
#define		FALSE			(0)

#define		MAX_NAME_LEN	(10)
#define		ENTRY_LEN		(65)

#ifdef	AMIGA
#define		LFILE			"DEVS:USERLOG.DAT"
#define		PFILE			"DEVS:PASSWORDS.DAT"
#define		HELP			"?"
#define		SET_FG_0		"[30;40m"
#define		SET_FG_1		"[31;40m"
#define		CREAT_MODE		(O_RDWR)
#define		OPEN_MODE		(O_RDWR)
void __regargs __chkabort(void);

#else

#include	"sys\stat.h"
#define		LFILE			"C:/DOS/USERLOG.DAT"
#define		PFILE			"C:/DOS/PASSWOR.DAT"
#define		HELP			"/?"
#define		SET_FG_0		"[30;40m"
#define		SET_FG_1		"[37;40m"
#define		CREAT_MODE		(S_IREAD | S_IWRITE)
#define		OPEN_MODE		(O_RDWR | O_BINARY)

#endif

//---------------------------------------------------------------------------
// Function Prototypes
// -------------------
//---------------------------------------------------------------------------

typedef		char	BOOL;

void get_log_entry(void);
void add_log_entry(void);
void decode_n_term(char *ptr, int offset);

BOOL valid_user(void);

//---------------------------------------------------------------------------
// Globals
// -------
//---------------------------------------------------------------------------

char entry_buffer[]="X AAAAAAAAAA DDD MMM dd hh:mm:ss YYYY - XXX XXX XX XX:XX:XX XXXX\r";

int logfile, passwfile;			// LEVEL 1 ANSI File Handles

char username[80];				// input buffers from keyboard
char userpassword[80];

long int file_size, log_pos;
int num_entries, attempt;

time_t	systime;
struct tm *tim;

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

main(int argc, char **argv) {

BOOL logged_out;

	// If there's anything on the command line...

	if(argc > 1 ) {
		printf("LOGIN V1.0  (Copyright (c) Jan 1994 L. Vanhelsuwe)\n\n");
		printf("Programmed by Laurence Vanhelsuwe in C on an Amiga 3000.\n");
		printf("Ported to IBM PC environment by L. Vanhelsuwe.\n\n");
		printf("USAGE: LOGIN [%s]\n\n", HELP);
	}

	if ((passwfile = open(PFILE, OPEN_MODE)) == -1) {
		fprintf(stderr, "Passwords file does not exist ! (Use PASS to create)\n");
		exit(10);
	}

	printf("\n\n");
	printf("====================================================\n\n");
	printf("                  PLEASE LOG ON\n\n");
	printf("====================================================\n\n");


	logged_out = TRUE;
	if ((  logfile = open(LFILE, OPEN_MODE)) != -1) {

		get_log_entry();					// get last log entry in entry_buffer

		if (entry_buffer[0] == 'I') {
			logged_out = FALSE;
			decode_n_term(&entry_buffer[2], 0);		// just 0-terminate
			printf("   --WARNING--\n\n'%s' didn't log out !\n\n", &entry_buffer[2]);
		}
	} else {
		printf("Log file doesn't exist. Attempting to create it...\n");
		logfile = creat(LFILE, CREAT_MODE);
		if (logfile == -1) {
			close(passwfile);
			fprintf(stderr, "Failed to create log file... aborting !\n");
			exit(10);
		}
		printf("Log file created OK.\n");
	}

// Get users name and password and validate entries.
// A special case is if 

	for (attempt=0; attempt < 3; attempt++) {
		do {
			printf("Please enter your name:");
			scanf("%s", username);

			if (( ! logged_out) && (strcmp(username, "CONTINUE")==0)) {
				close(passwfile);
				printf("\nUser '%s': Continued Session Log-On.\n\n", &entry_buffer[2]);
				return 0;
			}

		} while (strlen(username) > MAX_NAME_LEN);
		
		do {
			printf(SET_FG_1); printf("Please enter your password:");
			printf(SET_FG_0); scanf("%s", userpassword);

		} while (strlen(userpassword) > MAX_NAME_LEN);

		printf(SET_FG_1);

		if (valid_user()) break;

		printf("\nLogin attempt refused... try again.\n\n");
	}

	close(passwfile);

	if (attempt==3) {
		printf("Number of Login attempts exceeded.\n\n");
		printf("  -- MACHINE HALTED --");
		while (attempt) ;						// LOOP forever
	}

	entry_buffer[0]  = 'I';			// set entry to correctly logged IN
	
	strncpy(&entry_buffer[2], "                              ", MAX_NAME_LEN+1);
	strncpy(&entry_buffer[2], username, strlen(username));
	
	time(&systime);						// get machine local time
	tim = localtime(&systime);			// convert to universal time format
	strncpy(&entry_buffer[40], asctime(tim), 24);
	strncpy(&entry_buffer[13], asctime(tim), 24);
	
	add_log_entry();
	printf("\nUser '%s' Logged on.\n\n", username);

	return 0;
}

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void get_log_entry(void) {
int chars;

	lseek(logfile, 0L, SEEK_END); file_size = tell(logfile);

	num_entries = file_size/ENTRY_LEN;
	log_pos = (num_entries-1)*ENTRY_LEN;

#ifdef DEBUG
	printf("File size = %ld, Num Entries = %d, LOG Position = %d\n",
			 file_size, num_entries, log_pos);
#endif

	lseek(logfile, log_pos, SEEK_SET);
	chars = read (logfile, (void*) entry_buffer, ENTRY_LEN);

#ifdef DEBUG
	printf("Entry buffer[0] = '%c'\n", entry_buffer[0]);
	printf("Entry buffer[1] = '%c'\n", entry_buffer[1]);
	printf("Entry buffer[2] = '%c'\n", entry_buffer[2]);
	printf("Entry buffer[3] = '%c'\n", entry_buffer[3]);

	if (chars != ENTRY_LEN) {
		printf("ERROR: get_log_entry() read didn't read %d chars (but %d!)\n", ENTRY_LEN, chars);
		exit(10);
	}

#endif

	entry_buffer[12] = 0;			// zero-terminate user name field
}
//---------------------------------------------------------------------------
void add_log_entry(void) {

	lseek(logfile, 0L, SEEK_END);
	write(logfile, (void*) entry_buffer, ENTRY_LEN);
	close(logfile);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
BOOL valid_user(void) {

char name[MAX_NAME_LEN+2];
char pasw[MAX_NAME_LEN+2];
char user_entry_buf[(MAX_NAME_LEN*2)+1];
int bytes_read;

	lseek(passwfile, 0L, SEEK_SET);			// rewind passwords file.

	bytes_read = read(passwfile, user_entry_buf, (MAX_NAME_LEN*2)+1);
	do {
#ifdef	DEBUG
		printf("Bytes read from passwfile = %d\n", bytes_read);

		for (i=0 ; i<21; i++) {
		printf("PASSWLINE[%d] = '%c'\n", i , user_entry_buf[i]); }
#endif

		name[MAX_NAME_LEN] = pasw[MAX_NAME_LEN] = ' ';

		strncpy(name,  user_entry_buf              , MAX_NAME_LEN);
		strncpy(pasw, &user_entry_buf[MAX_NAME_LEN], MAX_NAME_LEN);

		decode_n_term(name, -1); decode_n_term(pasw, -2);

		if ((strcmp(username,	  name))==0 &&
			(strcmp(userpassword, pasw))==0 )	return TRUE;

		bytes_read = read(passwfile, user_entry_buf, (MAX_NAME_LEN*2)+1);

	} while (bytes_read);

	return FALSE;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void decode_n_term(char *ptr, int offset) {

	while(*ptr != ' ') {
		*ptr = (*ptr) + offset;
		ptr++;
	}

	*ptr = 0;
}
//---------------------------------------------------------------------------
// Disable CTRL-C checking.
//---------------------------------------------------------------------------
#ifdef AMIGA
void __regargs __chkabort(void) {}
#endif
