/*
 * save and restore routines
 *
 * @(#)save.c	3.6 (Berkeley) 4/19/81
 */

#include <curses.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rogue.h"

typedef struct stat STAT;

extern char *sys_errlist[], version[], encstr[];
extern bool _endwin;
extern int errno;

char *sbrk();

STAT sbuf;

save_game()
{
	register FILE *savef;
	register int c;
	char buf[80];

	/*
     * get file name
     */
	mpos = 0;
	if (file_name[0] != '\0')
	{
		msg("Save file (\"%s\")? ", file_name);
		do
		{
			c = getchar();
		} while (c != 'n' && c != 'N' && c != 'y' && c != 'Y');
		mpos = 0;
		if (c == 'y' || c == 'Y')
		{
			msg("File name: %s", file_name);
			goto gotfile;
		}
	}

	do
	{
		msg("File name: ");
		mpos = 0;
		buf[0] = '\0';
		if (get_str(buf, cw) == QUIT)
		{
			msg("");
			return FALSE;
		}
		strcpy(file_name, buf);
gotfile:
		if ((savef = fopen(file_name, "w")) == NULL)
			msg(sys_errlist[errno]);	/* fake perror() */
	} while (savef == NULL);

	/*
     * write out encrpyted file (after a stat)
     * The fwrite is to force allocation of the buffer before the write
     */
	save_file(savef);
	return TRUE;
}

/*
 * automatically save a file.  This is used if a HUP signal is
 * recieved
 */
auto_save()
{
	register FILE *savef;

	if (file_name[0] != '\0' && (savef = fopen(file_name, "w")) != NULL)
		save_file(savef);
	exit(1);
}

/*
 * write the saved game on the file
 */
save_file(savef)
register FILE *savef;
{
	wmove(cw, LINES-1, 0);
	draw(cw);
	fstat(fileno(savef), &sbuf);
	fwrite("junk", 1, 5, savef);
	fseek(savef, 0L, 0);
	_endwin = TRUE;
	restfile = savef;
	encwrite(version, sbrk(0) - version, savef);
	fclose(savef);
}

restore(file, envp)
register char *file;
char **envp;
{
	register int inf;
	extern char **environ;
	char buf[80];
	STAT sbuf2;
	int chflag = cheating;

	if (strcmp(file, "-r") == 0)
		file = file_name;
	if ((inf = open(file, 0)) < 0)
	{
		perror(file);
		return FALSE;
	}

	fflush(stdout);
	encread(buf, strlen(version) + 1, inf);
	if (strcmp(buf, version) != 0)
	{
		printf("Sorry, saved game is out of date.\n");
		return FALSE;
	}

	fstat(inf, &sbuf2);
	fflush(stdout);
	brk(version + sbuf2.st_size);
	lseek(inf, 0L, 0);
	encread(version, (int) sbuf2.st_size, inf);
	if (restfile) {
		restfile->_file = -1;
		fclose(restfile);
	}
	/*
     * we do not close the file so that we will have a hold of the
     * inode for as long as possible
     */

	if (!wizard)
		if (sbuf2.st_ino != sbuf.st_ino || sbuf2.st_dev != sbuf.st_dev)
		{
			printf("Sorry, saved game is not in the same file.\n");
			return FALSE;
		}
		else if (sbuf2.st_ctime - sbuf.st_ctime > 15)
		{
			printf("Sorry, file has been touched.\n");
			return FALSE;
		}
	mpos = 0;
	mvwprintw(cw, 0, 0, "%s: %s", file, ctime(&sbuf2.st_mtime));

	/*
     * defeat multiple restarting from the same place
     */
	if (!wizard) {
		if (sbuf2.st_nlink != 1)
		{
			printf("Cannot restore from a linked file\n");
			return FALSE;
		}
		if (!cheating) {
			if (unlink(file) < 0)
			{
				printf("Cannot unlink file\n");
				return FALSE;
			}
			sbuf2.st_ino = 0;
			stat(file, &sbuf2);	/* defeat patching unlink */
			if (sbuf2.st_ino == sbuf.st_ino) {
				printf("Cheater!\n");
				return FALSE;
			}

		}
	}
	cheating |= chflag;
	environ = envp;
	if (!My_term && isatty(2))
	{
		register char	*sp;

		_tty_ch = 2;
		gettmode();
		if ((sp = getenv("TERM")) == NULL)
			sp = Def_term;
		setterm(sp);
	}
	else
		setterm(Def_term);
	strcpy(file_name, file);
	setup();
	clearok(curscr, TRUE);
	touchwin(cw);
	srand(getpid());
	playit();
	/*NOTREACHED*/
}

/*
 * perform an encrypted write
 */
encwrite(start, size, outf)
register char *start;
unsigned int size;
register FILE *outf;
{
	register char *ep;

	ep = encstr;

	while (size--)
	{
		putc(*start++ ^ *ep++, outf);
		if (*ep == '\0')
			ep = encstr;
	}
}

/*
 * perform an encrypted read
 */
encread(start, size, inf)
register char *start;
unsigned int size;
register int inf;
{
	register char *ep;
	register int read_size;

	if ((read_size = read(inf, start, size)) == -1 || read_size == 0)
		return read_size;

	ep = encstr;

	while (size--)
	{
		*start++ ^= *ep++;
		if (*ep == '\0')
			ep = encstr;
	}
	return read_size;
}
