/* --------------------
	vmail -- init.c

	Initialisation routines - setting ttystate, finding valid folders,
	trapping signals.

	Ttystate is controlled by a mix of curses and ioctl.  For simplicity,
	initial setups are done with curses.  Curses is also used for basic
	screen manipulation.  However, for speed ioctl is used in switching
	in and out of normal terminal state.

	Copyright (C) J. Zobel, University of Melbourne, October 1987.
-------------------- */

#include "defs.h"
#include <signal.h>
#include <errno.h>

extern int errno;
extern char *strerror();

static struct sgttyb tty, t_tty;		/* for holding tty state */
static struct tchars chrs, t_chrs;
static struct ltchars lchrs, t_lchrs;

static char	termcap[1024],				/* termcap entry */
			*cur_folder;				/* initial current folder */

/* --------------------
	Start-up routine - set terminal control, signals, etc.
-------------------- */
void
init(argc, argv)
	int		argc;
	char	**argv;
{
	folder	ftmp, find_mail();
	char	*pargv[20],					/* argv from profile */
			*profile = (char *) NULL,	/* location of MH profile */
			*home = (char *) NULL,		/* home directory */
			*term = (char *) NULL;		/* terminal type */
	int		pargc = 0;					/* argc from profile */
	struct winsize	wsiz;

	get_home(&home);
	get_env(&term, &profile, home);
	tgetent(termcap, term);
	ioctl(0, TIOCGWINSZ, &wsiz);
	cols = wsiz.ws_col;
	lines = wsiz.ws_row - 2;
	ioctl(0, TIOCGETP, &tty);
	ioctl(0, TIOCGETP, &chrs);
	ioctl(0, TIOCGETP, &lchrs);

	read_profile(&pargc, pargv, profile, home);
	process_args(pargc, pargv);
	find_folders();
	mark_valid_folders(pargc, pargv);
		/* give precedence to command line args => process second */
	mark_valid_folders(argc, argv);
	for(ftmp=folders ; ftmp != (folder) NULL ;)
		if(ftmp->valid)
			ftmp = find_mail(ftmp, true);
		else
			ftmp = ftmp->next;
	if(curflr->valid == EMPTY) {
		printf("%s: folder empty.\n", curflr->name);
		exit(1);
	}
		/* find last instance of initial folder */
	LAST_OF_NAME(curflr);
	curmail = curflr->mail;

	initscr();
	crmode();
	noecho();
	nonl();

	signal(SIGTSTP, tstp);
	signal(SIGINT, tint);

	ioctl(0, TIOCGETP, &t_tty);
	ioctl(0, TIOCGETP, &t_chrs);
	ioctl(0, TIOCGETP, &t_lchrs);

	y = FIRST;
	display_page();
}


/* --------------------
	Find user name, home directory.
-------------------- */
void
get_home(home)
	char **home;
{
	struct passwd *pwent, *getpwuid();
	extern char *getenv();

  	pwent = getpwuid(getuid());
	*home = getenv("HOME");
	if (*home == NULL) {
		*home = NEWSTR(strlen(pwent->pw_dir)+1);
		strcpy(*home, pwent->pw_dir);
	}
	if(access(*home, R_OK | W_OK | X_OK)) {
		printf("%s: no permissions.\n", *home);
		exit(1);
	}
	user = getenv("USER");
	if (user == NULL)
		user = NEWSTR(strlen(pwent->pw_name)+1);
	strcpy(user, pwent->pw_name);
}


/* --------------------
	Find pager, editor, shell, terminal type, MH profile - defaults are PAGER,
	EDITOR, SHELL, none, PROFILE.  Set by PAGER, EDITOR, SHELL, TERM, MH
	environment variables.
-------------------- */
void
get_env(term, profile, home)
	char **term, **profile, *home;
{
	char	**tmp;

	for(tmp = environ ; *tmp != (char *) NULL ; tmp++)
		if(!strncmp("PAGER=", *tmp, 6)) {
			pager = NEWSTR(strlen(*tmp)-4);
			strcpy(pager, *tmp+6);
		} else if(!strncmp("EDITOR=", *tmp, 7)) {
			editor = NEWSTR(strlen(*tmp)-5);
			strcpy(editor, *tmp+7);
		} else if(!strncmp("SHELL=", *tmp, 6)) {
			shell = NEWSTR(strlen(*tmp)-4);
			strcpy(shell, *tmp+6);
		} else if(!strncmp("TERM=", *tmp, 5)) {
			*term = NEWSTR(strlen(*tmp)-3);
			strcpy(*term, *tmp+5);
		} else if(!strncmp("MH=", *tmp, 3)) {
			*profile = NEWSTR(strlen(*tmp)-1);
			strcpy(*profile, *tmp+3);
		}
	if(*term == (char *) NULL) {
		printf("Terminal type unknown\n");
		exit(1);
	}
	if(*profile == (char *) NULL) {
		*profile = NEWSTR(strlen(home)+strlen(PROFILE)+2);
		sprintf(*profile, "%s/%s", home, PROFILE);
	}
	if(pager == (char *) NULL) {
		pager = NEWSTR(strlen(PAGER)+1);
		strcpy(pager, PAGER);
	}
	if(shell == (char *) NULL) {
		shell = NEWSTR(strlen(SHELL)+1);
		strcpy(shell, SHELL);
	}
	if(editor == (char *) NULL) {
		editor = NEWSTR(strlen(EDITOR)+1);
		strcpy(editor, EDITOR);
	}
}


static char argkeep[LEN];			/* storage for args from profile */

/* --------------------
	Find mail directory, current-folder, context, default options.
-------------------- */
void
read_profile(pargc, pargv, profile, home)
	int *pargc;
	char **pargv, *profile, *home;
{
	FILE	*fp, *fopen();
	char	str[LEN], *ptr, iscontext[LEN], *index(), *next_token();

	if((fp = fopen(profile, "r")) == (FILE *) NULL) {
		printf("Profile: %s: cannot open.\n", profile);
		exit(1);
	}
	*iscontext = '\0';
	while(fgets(str, LEN, fp) != (char *) NULL) {
			/* get entries from profile */
		if(lstrncmp("context:", str, 8) == 0 && *(ptr=str+8) != '\0') {
			squash(str);
			strcpy(iscontext, str+8);
		} else if(lstrncmp("vmail:", str, 6) == 0 && *(ptr=str+6) != '\0') {
			for( ; *ptr == ' ' || *ptr == '\t' ; ptr++)
				;
			*index(ptr, '\n') = '\0';
			strcpy(argkeep, ptr);
			for(ptr=argkeep ; *ptr != '\0' ; ) {
				pargv[(*pargc)++] = ptr;
				ptr = next_token(ptr);
			}
		} else if(lstrncmp("path:", str, 5) == 0 && *(ptr=str+5) != '\0') {
			squash(str);
			if(*ptr == '/') {		/* full pathname */
				mail_dir = NEWSTR(strlen(ptr)+1);
				strcpy(mail_dir, ptr);
			} else {
				mail_dir = NEWSTR(strlen(home)+strlen(ptr)+1);
				sprintf(mail_dir, "%s/%s", home, ptr);
			}
		} else if(lstrncmp("folder-protect:", str, 15) == 0 &&
														*(str+15) != '\0') {
			squash(str);
			folder_protect = atoo(str+15);
		} else if(lstrncmp("current-folder:", str, 15) == 0 &&
														*(str+15) != '\0') {
			squash(str);
			cur_folder = NEWSTR(strlen(str+15)+1);
			strcpy(cur_folder, str);
		}
	}
	fclose(fp);
	if(mail_dir == (char *) NULL) {
		mail_dir = NEWSTR(strlen(home)+strlen(MAILDIR)+2);
		sprintf(mail_dir, "%s/%s", home, str+6);
	}
	if(access(mail_dir, R_OK | W_OK | X_OK)) {
		printf("%s: no permissions.\n", mail_dir);
		exit(1);
	}
	if(*iscontext == '\0')
		strcpy(iscontext, CONTEXT);
	context = NEWSTR(strlen(mail_dir)+strlen(iscontext)+2);
	sprintf(context, "%s/%s", mail_dir, iscontext);
	if(access(context, R_OK | W_OK)) {
		printf("%s: no permissions.\n", context);
		exit(1);
	}
	if(cur_folder == (char *) NULL)
		cur_folder = CURFOL;
}


/* --------------------
	Squash spaces, tabs, newlines out of given string.
-------------------- */
void
squash(str)
	char	*str;
{
	int		i, j;

	for(i=0, j=0 ; (str[j] = str[i]) != '\0' ; i++)
		if(str[j] != ' ' && str[j] != '\t' && str[j] != '\n')
			j++;
}


/* --------------------
	Mark folders as specified by setenv, command line.  At startup, default
	is for only active folder to be cur_folder.
-------------------- */
void
mark_valid_folders(argc, argv)
	int		argc;
	char	**argv;
{
	char	*name;
	folder	f;

	name = cur_folder;
		/* find valid folders - mark all folders from argv as valid */
	for(; argc > 0 ; argc--, argv++)
		if(**argv == '+')				/* startup folder */
			name = (*argv) + 1;
		else if(**argv != '-') {		/* not a flag */
			GOTO_NAME(f, *argv);
			if(f == (folder) NULL)
				printf("Warning: no such folder as %s\n", *argv);
			else
				f->valid = true;
		}
	GOTO_NAME(f, name);
	if(f == (folder) NULL) {
		printf("%s does not exist\n", name);
		exit(1);
	}
	f->valid = true;
	curflr = f;
}


/* --------------------
	Reset terminal, clean up.
-------------------- */
void
to_normal()
{
	move(lines+FIRST-1, 0);
	refresh();
	no_control();
	printf("\n");
}


/* --------------------
	Reset terminal.
-------------------- */
void
no_control()
{
	ioctl(0, TIOCSETP, &tty);
	ioctl(0, TIOCSETP, &chrs);
	ioctl(0, TIOCSETP, &lchrs);
}


/* --------------------
	Set terminal.
-------------------- */
void
to_control()
{
	ioctl(0, TIOCSETP, &t_tty);
	ioctl(0, TIOCSETP, &t_chrs);
	ioctl(0, TIOCSETP, &t_lchrs);
}


#define	mask(s)	(1 << ((s)-1))

/* --------------------
	Trap for ^Z.
-------------------- */
void
tstp()
{
	int		x, y;

	getyx(curscr, y, x);
	to_normal();
	fix_mh();

	signal(SIGTSTP, SIG_DFL);
	sigsetmask(sigblock(0) &~ mask(SIGTSTP));
	kill(0, SIGTSTP);
	sigblock(mask(SIGTSTP));
	signal(SIGTSTP, tstp);

	if(top_level) {
		to_control();
		touchwin(curscr);
		wmove(curscr, y, x);
		wrefresh(curscr);
	}
}


/* --------------------
	Trap for ^?.
-------------------- */
void
tint()
{
	touchwin(stdscr);
	addstatus("-- interrupt --", true);
	longjmp(env, 0);	/* jump to main */
}


/* --------------------
	Convert an ascii string to octal.
-------------------- */
int
atoo(str)
	char *str;
{
	int		i;

	for(; *str < '0' && *str > '7' ; str++)
		;
	for(i=0 ; *str >= '0' && *str <= '7' ; str++)
		i = i*8 + *str - '0';
	return(i);
}


/* --------------------
	Update MH environment - context and current mail item of current folder.
-------------------- */
fix_mh()
{
	char str[LEN], buf[20];

	update(context, "Current-Folder:", curflr->name, 15);
	sprintf(str, "%s/%s/%s", mail_dir, curflr->name, SEQU);
	sprintf(buf, "%d", curmail->number);
	update(str, "cur:", buf, 4);
}


/* --------------------
	Update file, replacing line beginning with match of len by "match new".
-------------------- */
update(file, match, new, len)
	char	*file, *match, *new;
	int		len;
{
	FILE	*fp, *tmp, *fopen();
	bool	change = false;
	char	*mktemp(), *fgets();
	char	str[LEN], name[20];

	strcpy(name, "/tmp/vmail.XXXXXX");
	(void) mktemp(name);

	if((fp = fopen(file, "r")) == (FILE *) NULL) {
		if((fp = fopen(file, "w+")) == (FILE *) NULL)
			printf("Can't open %s for writing\n", file);
		else {
			fprintf(fp, "%s %s\n", match, new);
			if (fclose(fp) < 0)
				printf("%s: error in fclose(): %s\n", file, strerror(errno));
		}
	} else {
		if((tmp = fopen(name, "w+")) == (FILE *) NULL)
			printf("Can't open %s\n", file);
		else {
			while(fgets(str, LEN, fp) != (char *) NULL)
				if(lstrncmp(str, match, len) == 0) {
					change = true;
					fprintf(tmp, "%s %s\n", match, new);
				} else
					fprintf(tmp, "%s", str);
			if(! change)
				fprintf(tmp, "%s %s\n", match, new);
			if (fclose(fp) < 0)
				printf("%s: error in fclose(): %s\n", file, strerror(errno));
			fclose(tmp);
			if((fp = fopen(file, "w+")) == (FILE *) NULL)
				printf("Can't open %s for writing\n", file);
			else {
				tmp = fopen(name, "r");
				while(fgets(str, LEN, tmp) != (char *) NULL)
					fprintf(fp, "%s", str);
				fclose(tmp);
				if (fclose(fp) < 0) {
					printf("%s: error in fclose(): %s\n", file, strerror(errno));
					printf("try to recover from %s\n", name);
				}
				else
					unlink(name);
			}
		}
	}
}
