/*
 * passphrase.c
 *		 Copyright (C) 1995 Kazuhiko Yamamoto
 *	      Kazuhiko Yamamoto <kazu@is.aist-nara.ac.jp>
 *		 Copyright (C) 2016 Peter Pentchev <roam@ringlet.net>
 */


#include "config.h"
#include "donkey.h"

static FILE *fp, *outfp;

static void turnecho(const bool on)
{
#ifdef HAVE_TERMIOS_H
  static struct termios orig, noecho, *tp;
#else
#  ifdef HAVE_TERMIO_H
     static struct termio orig, noecho, *tp;
#  else
     static struct sgttyb orig, noecho, *tp;
#  endif
#endif

	const int fd = fileno(fp);
	if (!isatty(fd))
		return; /* return void */

	static int state = 0;
	if (state == 0) {
#ifdef HAVE_TERMIOS_H
		if (tcgetattr(fd, &orig) < 0)
			perror("tcgetattr");
		noecho = orig;
		noecho.c_lflag &= ~ECHO;
#else
#  ifdef HAVE_TERMIO_H
		if (ioctl(fd, TCGETA, &orig) < 0)
			perror("ioctl");
		noecho = orig;
		noecho.c_lflag &= ~ECHO;
#  else
		if (ioctl(fd, TIOCGETP, &orig) < 0)
			perror("ioctl");
		noecho = orig;
		noecho.sg_flags &= ~ECHO;
#  endif
#endif
		state = 1;
	}
	tp = NULL;
	if (on && state == 2) {
		/* Turn echo back on. */
		tp = &orig;
		state = 1;
	} else if (!on && state == 1) {
		/* Turn echo off. */
		tp = &noecho;
		state = 2;
	}
	if (tp != NULL) {
#ifdef HAVE_TERMIOS_H
		if (tcsetattr(fd, TCSANOW, tp) < 0)
			perror("tcsetattr");
#else
#  ifdef HAVE_TERMIO_H
		if (ioctl(fd, TCSETA, tp) < 0)
			perror("ioctl");
#  else
		if (ioctl(fd, TIOCSETP, tp) < 0)
			perror("ioctl");
#  endif
#endif	/* !HAVE_TERMIOS_H */
	}
}

static RETSIGTYPE get_sigint(const int sig __unused)
{
	(void) rewind(outfp);

	turnecho(true);
	
	(void) fputc('\n', outfp);

	if (fp != stdin)
		(void)fclose(fp);
	exit(0);
}

/*
 * read size-free passphrase without echo
 */

int passphrase(const char * const prompt, char * const phrase,
		const size_t size, const bool reject_short)
{
	/*
	 * read and write to /dev/tty if possible; else read from
	 * stdin and write to stderr.
	 */
  	if ((outfp = fp = fopen("/dev/tty", "r+")) == NULL) {
  		outfp = stderr;
  		fp = stdin;
  	}

	/* 
	 * We don't want to return with echoing off.
	 */
	const sigtype oldintr = signal(SIGINT, get_sigint);

	/*
	 * Ignore suspend.
	 */
#ifdef SIGTSTP
	const sigtype oldtstp = signal(SIGTSTP, SIG_IGN);
#endif

	turnecho(false);
	(void) fputs(prompt, outfp);
	(void) fflush(outfp);
	(void) rewind(outfp);
	phrase[0] = '\0';
	if (fgets(phrase, size, fp) != NULL)
		phrase[strlen(phrase) - 1] = '\0';
	(void) fflush(fp);

	if (reject_short)
		while (strlen(phrase) < PASS_PHRASE_MIN_LEN) {
			(void) rewind(outfp);
			
			(void) fputs("\nYour passphrase is too short. Enter longer passphrase.\n", outfp);
			(void) fputs(prompt, outfp);
			(void) fflush(outfp);
			(void) rewind(outfp);
			
			phrase[0] = '\0';		
			if (fgets(phrase, size, fp) != NULL)
				phrase[strlen(phrase) - 1] = '\0';
			(void) fflush(fp);
		}
	
	(void) rewind(outfp);

	turnecho(true);
	
	(void) fputc('\n', outfp);

	(void) signal(SIGINT, oldintr);
#ifdef SIGTSTP
	(void) signal(SIGTSTP, oldtstp);
#endif

	if (fp != stdin)
		(void)fclose(fp);
	return(RET_SUCCESS);
}

/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Copyright (c) 1995 Mike Gleason, NCEMRSoft.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted provided
 * that: (1) source distributions retain this entire copyright notice and
 * comment, and (2) distributions may not be sold for profit on physical
 * media such as disks, tapes, and CD-ROMS, without expressed written
 * permission.
 */
