/*
fortunelock - Copyright (c) 1999/2000 Rob Kaper <cap@capsi.cx>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 dated June, 1991.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program;  if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
*/

#define _GNU_SOURCE
#include <stdio.h>
#include <signal.h>
#include <curses.h>
#include <string.h>

/* VT handling disabled until behavior under X or telnet/ssh is defined.
#include <sys/ioctl.h>
#include <linux/vt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
*/

#include <sys/time.h>
#include <unistd.h>

#include "fortunelock.h"

char passwd[PASSWDMAX+1], passwd_str[PASSWDMAX+1];

int main(int argc, char *argv[])
{
	int passwd_set=0;
	/* VT handling.
	int tty;
	struct vt_mode vtm;
	*/
	struct timeval timeout;
	fd_set keypress;

	void handle_sig(int);

	/* VT handling. * /
	if ((tty = open ("/dev/tty0", O_RDWR)) == -1)
	{
		perror ("open");
		exit (-1);
	}

	if (-1 == ioctl (tty, VT_GETMODE, &vtm))
	{
		perror ("ioctl");
		exit (-1);
	}

	vtm.mode = VT_PROCESS;
	vtm.relsig = SIGUSR1;
	vtm.acqsig = SIGUSR1;

	if (-1 == ioctl (tty, VT_SETMODE, &vtm))
	{
		perror ("ioctl");
		exit (-1);
	}
 	*/

	/* Default ncurses initialization. */
	initscr(); cbreak(); noecho();
	nonl();
	intrflush(stdscr, FALSE);
	keypad(stdscr, TRUE);

	/* Print some nice stuff. */
	print_header();
/*
	print_fortune();
*/
	refresh();

	/* Fuck passwd, NIS, pam, shadow... user can set his/her own password. */
	while(!passwd_set)
		passwd_set=set_passwd();
	
	/* Ctrl-C, Ctrl-Z and Ctrl-\ must be ignored (or actually handled). */
	signal(SIGINT,handle_sig);	
	signal(SIGTSTP,handle_sig);
	signal(SIGQUIT,handle_sig);

	/* Key events need to be handled. */
	signal(SIGUSR1,handle_sig);

	/* Terminal is truly locked now. */
	print_msg("Terminal locked.");
	refresh();

	/* The main loop. */
	while(1)
	{
		timeout.tv_sec = 3;
		timeout.tv_usec = 0;

		FD_ZERO(&keypress);
		FD_SET(0, &keypress);
		select (1, &keypress, NULL, NULL, &timeout);
		if (FD_ISSET(0, &keypress))
		{
			/* Let the user unlock by entering his/her password. */
			strncpy(passwd_str, get_passwd(), PASSWDMAX);
			passwd_str[PASSWDMAX]='\0';
		
			/* Check the password, this will either exit itself or continue. */
			check_passwd();
			refresh();
		}
		else
		{
			print_fortune();
			move(4, strlen("Enter the lock password to unlock: "));
			refresh();
		}
	}
}

void handle_sig(int sig)
{
	print_msg("Sorry, this terminal is locked.");
	refresh();
	
	/* Reset the signal handler. */
	signal(sig,handle_sig);	
}

void check_passwd(void)
{
	/* Compare passwords. */
	if (!strcmp(passwd, passwd_str))
	{
		/* Match. */
		erase();
		mvprintw(0, 0, "%-80s", "Terminal unlocked.");
		refresh();

		/* Exit. */
		endwin();
		exit(0);
	}
	else
		print_msg("Password incorrect.");
}

int set_passwd(void)
{
	/* Clear password strings. */
	passwd[0]='\0';
	passwd_str[0]='\0';

	/* Enter once. */
	while(!passwd[0])
	{
		mvprintw(3, 0, "Enter password to lock this terminal with: ");
		refresh();
		strncpy(passwd, get_passwd(), PASSWDMAX);
		passwd[PASSWDMAX]='\0';
	}

	/* Enter twice. */
	while(!passwd_str[0])
	{
/*
		print_fortune();
*/
		mvprintw(4, 0, "Re-enter password to verify: ");
		refresh();
		strncpy(passwd_str, get_passwd(), PASSWDMAX);
		passwd_str[PASSWDMAX]='\0';
	}

	/* Compare. */
	if(strcmp(passwd, passwd_str))
	{
		/* No match. */
		mvprintw(5, 0, "Passwords didn't match, try again please.");
		refresh();
		
		/* Return 0 to passwd_set. */
		return 0;
	}
	else return 1;
}

char *get_passwd(void)
{
	static char input[PASSWDMAX+1];
	char tmp[PASSWDMAX+1];
	int i=0, len=0;

	/* Clear buffers. */
	input[0]='\0';
	tmp[0]='\0';

	/* Keep reading those keystrokes. */
	while(1)
	{
		/* Get keystroke. */
		i=getch();
		
		if (i==13)
		/* Enter was pressed. */
			return input;
		/* Backspace was pressed, shorten the input buffer. */
		else if (i==263)
		{
			len=strlen(input);
			if (len>0)
				input[len-1]='\0';
		}
		/* Enter the typed key into the buffer. */
		else if (i>0)
		{
			strncpy(tmp, input, PASSWDMAX);
			input[PASSWDMAX]='\0';
			snprintf(input, PASSWDMAX, "%s%c", tmp, i);
			input[PASSWDMAX]='\0';
		}
		refresh();
	}
}

void print_msg(char *msg)
{
	print_fortune();

	mvprintw(3, 0, "%-80s", msg);
	mvprintw(4, 0, "%-80s", "Enter the lock password to unlock: ");
	move(4, strlen("Enter the lock password to unlock: "));
	passwd_str[0]='\0';
}

void print_header(void)
{
	mvprintw(0, 0, "------------------------------------------------------------------------------");
	mvprintw(1, 0, "%-80s", "fortunelock " VERSION " - Copyright (c) 1999/2000 Rob Kaper <cap@capsi.cx>");
	mvprintw(2, 0, "------------------------------------------------------------------------------");
}

void print_fortune(void)
{
	FILE *f;
	char str[80];
	int line=5;

	mvprintw(line++, 0, "------------------------------------------------------------------------------");
	
	f=popen("fortune -s", "r");
	if (f)
	{
		fgets(str, sizeof(str), f);
		while(!feof(f))
		{
			mvprintw(line++, 0, "%-80s", str);
			fgets(str, sizeof(str), f);
		}
		fclose(f);
	}
	else
		mvprintw(line++, 0, "Fortune? Never heard of it.");

	mvprintw(line++, 0, "------------------------------------------------------------------------------");

	while(line<LINES)
		mvprintw(line++, 0, "                                                                              ");
}


syntax highlighted by Code2HTML, v. 0.9.1