/*	Copyright (c) 1990 UNIX System Laboratories, Inc.	*/
/*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF     	*/
/*	UNIX System Laboratories, Inc.                     	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*
 * Copyright  (c) 1985 AT&T
 *	All Rights Reserved
 */
#ident	"@(#)fmli:xx/main.c	1.46"

#include <stdio.h>
#include <signal.h>
#include <curses.h>
#include <term.h>
#include "wish.h"
#include "token.h"
#include "actrec.h"
#include "terror.h"
#include "ctl.h"
#include "vtdefs.h"
/*  #include "status.h"  empty  include file abs 9/14/88 */
#include "moremacros.h"
#include "sizes.h"


/*
 * External Globals
 */
int  Vflag = 0;		/* Set if running FACE User Interface */
pid_t Fmli_pid;		/* Process id of this FMLI.  EFT abs k16 */
char Semaphore[PATHSIZ] = "/tmp/FMLIsem.";	/* for asynch coprocs */
bool Suspend_interupt;
char *Suspend_window;
char *Aliasfile;	/* File of path aliases */
extern char	*Home;
extern char *tigetstr();	/* curses routine */
extern long strtol();		/* abs k16 */
extern pid_t  getpid();		/* EFT abs k18 */
extern void   mess_init();	/* abs k18 */

/*
 * Defines for SLK layout (4-4 or 3-2-3 layout can be specified in curses)
 */
#define FOURFOUR	"4-4"
#define LAYOUT_DESC	"slk_layout"

/*
 * Default FMLI Stream handler
 */
token physical_stream();
token virtual_stream();
token actrec_stream();
token global_stream();
token menu_stream();
token error_stream();

token (*Defstream[])() = {
	physical_stream,
	virtual_stream,
	actrec_stream,
	global_stream,
	error_stream,
	NULL
};

extern char	*Progname;

/* Status line variables */
long	Mail_check;
char	*Mail_file;
time_t	Cur_time;	/* EFT abs k16 */

/*
 * Static globals
 */
static char Interpreter[] = "fmli";	
static char Viewmaster[] = "face";	
static char Vpid[12] = "VPID=";
static char Fcolor[17] = "HAS_COLORS=";
static char Display_H[16] = "DISPLAYH=";
static char Display_W[16] = "DISPLAYW=";

static void vm_initobjects();
static void vm_setup();
static void on_suspend();
static void sig_catch();
/* static int sig_catch();   abs */

main(argc, argv)
int argc;
char *argv[];
{
	register int	i, r, c;
	static	char mail_template[256] = "/usr/mail/";
	token	t;
	extern	char *optarg;
	extern	int optind;
	char	*initfile, *commfile, *aliasfile, *p, *pidstr;
	int	labfmt, errflg;
	vt_id	vid, copyright();
	char	*itoa(), *estrtok(), *path_to_full();
	char	*filename(), *getenv(), *strnsave();
	void	susp_res(), vinterupt(), screen_clean();
	time_t  time();	/* EFT abs k16 */
	extern int vt_redraw();
	extern  void exit();	/* abs 9/12/88, also removed decl below */
/*	int	exit();
*/
	struct	actrec *firstar, *wdw_to_ar();

/* LES: optimize malloc(3X) */

	if ((p = getenv("VMFMLI")) && strcmp(p, "true") == 0) {
		Vflag++;
		putenv("VMFMLI=false");
	}
	errflg = 0;
	Progname = filename(argv[0]);
	Aliasfile = initfile = commfile = (char *) NULL;
	while ((c = getopt(argc, argv, "i:c:a:")) != EOF) {
		switch(c) {
		case 'i':
			initfile = optarg;
			break; 
		case 'c':
			commfile = optarg;
			break; 
		case 'a':
			Aliasfile = strsave(optarg);
			break;
		case '?':
			errflg++;
			break;
		}
	}

	/*
	 * Check arguments
	 */
	if (errflg) {
		fprintf(stderr, "usage: %s [-i initfile] [-c commandfile] [-a aliasfile] object ...\n", argv[0]);
		exit(-1);    /* this is fmli's exit not the C library call */
	}
	if (optind == argc) {
		fprintf(stderr, "Initial object must be specified\n");
		exit(-1);   /* this is fmli's exit not the C library call */
	}

	/* 
	 * check that all objects exist AND that they are readable
	 */
	if (initfile && access(initfile, 4) < 0) {
		errflg++;
		fprintf(stderr, "Can't open initialization file \"%s\"\n", initfile); 
	}
	if (commfile && access(commfile, 4) < 0) {
		errflg++;
		fprintf(stderr, "Can't open commands file \"%s\"\n", commfile); 
	}
	if (Aliasfile && access(Aliasfile, 4) < 0) {
		errflg++;
		fprintf(stderr, "Can't open alias file \"%s\"\n", Aliasfile); 
	}
	for (i = optind; i < argc; i++) {
		if (access(argv[i], 4) < 0) {
			errflg++;
			fprintf(stderr, "Can't open object \"%s\"\n", argv[i]);
		}
	}
	if (errflg)
		exit(-1);   /* this is fmli's exit not the C library call */
		
	/*
	 * handle signals
	 */
	if (p = getenv("DEBUG"))
		_Debug = (int) strtol(p, 0, 0);
	/* changed signal()'s to sigset()'s..   abs */
	if (sigset(SIGINT, SIG_IGN) != SIG_IGN)
		sigset(SIGINT, exit); /* fmli's exit not the C library call */
	if (sigset(SIGHUP, SIG_IGN) != SIG_IGN)
		sigset(SIGHUP, exit); /* fmli's exit not the C library call */
	if (sigset(SIGTERM, SIG_IGN) != SIG_IGN)
		sigset(SIGTERM, exit); /* fmli's exit not the C library call */
	(void) sigset(SIGALRM, sig_catch);
	/* for job control: want to reset tty before suspending and.. */
#ifdef SIGTSTP			                 /* .. cleanup after. */
	(void) signal(SIGTSTP, on_suspend); /* must be signal not sigset */
	(void) signal(SIGTTIN, on_suspend); /* must be signal not sigset */
	(void) signal(SIGTTOU, on_suspend); /* must be signal not sigset */
#endif

	/*
	 * initialize terminal/screen
	 */
	labfmt = 0;
	if (initfile) {
		/*
		 * Set up SLK layout as 4-4 or 3-2-3 ... This needs
		 * to be determined BEFORE curses is initialized
		 * in vt_init.
		 */
		char *slk_layout, *get_desc_val();

		slk_layout = get_desc_val(initfile, LAYOUT_DESC); 
		if (strcmp(slk_layout, FOURFOUR) == 0)
			labfmt = 1;

	}
	vt_init(labfmt);
	onexit(screen_clean);

	/*
	 * indicate in the environment if the terminal we just
	 * initialized has color capability or not         --dmd
	 * ..also indicate the size of the display area.   --abs
	 */
	if ( has_colors() )
		strcat(Fcolor, "true");
	else
		strcat(Fcolor, "false");
	putenv(Fcolor);
	strcat(Display_W, itoa((long)COLS, 10)); /* abs k16 */
	strcat(Display_H, itoa((long)LINES - RESERVED_LINES, 10)); /* abs k16 */
	putenv(Display_W);
	putenv(Display_H);

	/*
	 * Read defaults from initialization file
	 */
	setup_slk_array();
	if (initfile)
	    read_inits(initfile);

	/*
	 * set up default banner and working indicator strings ...
 	 * and set color attributes if terminal supports color
	 */
        /* Changed the order of next two calls.
         * First set colors and after it the baner line.    mek k17
         */
	set_def_colors();
	set_def_status();

        /*
         * Define screen function keys for terminals that do not have
         * them defined like att630.  mek k17
	 * Must be After sigset(SIGALRM...).  abs k18
         */
        init_sfk(TRUE);

	/*
	 * Put up an Introductory Object and the working indicator
	 */
	vid = copyright();
	working(TRUE);
	if (vid)
		vt_close(vid);

/* remove this ifdef and sigset when i386 sleep(2C) is fixed to reset the
 * SIGALRM signal handler.  abs k18
 */
#ifdef i386
	(void) sigset(SIGALRM, sig_catch); /* copied from above. abs k18 */
#endif
	/*
	 * Initialize command table...
	 * Read commands from commands file
	 */
	cmd_table_init();
	if (commfile)
		read_cmds(commfile);

	/*
	 * Set up FACE globals
	 */
	if (Vflag)
		vm_setup();
	else
	    Home = NULL;

	/*
	 * Set mailcheck (use mail_file variable as temp
	 * variable for MAILCHECK)
	 */
	Mail_check = 0L;
	if (Mail_file = getenv("MAILCHECK"))
		Mail_check = (long) atoi(Mail_file);
	if (Mail_check == 0L)
		Mail_check = 300L;
	else
		Mail_check = max(Mail_check, 120L);
	if ((Mail_file = getenv("MAIL")) == NULL) {
		Mail_file = mail_template;
		strcat(Mail_file, getenv("LOGNAME"));
	}
	Cur_time = time((time_t)0L); /* EFT abs k16 */

	/*
	 * Initialize object architecture (SORTMODE)
	 */
	oh_init();

	/*
	 * set VPID env variable to pid for suspend/resume (SIGUSR1)
	 * and asynchronous activity (SIGUSR2)
	 */
	Fmli_pid = getpid();
	pidstr = itoa((long)Fmli_pid, 10);
	strcat(Vpid, pidstr);
	putenv(Vpid);
	strcat(Semaphore, pidstr);	/* for enhanced asynch coprocs */
	/* changed from signal()... abs */
	sigset(SIGUSR1, susp_res);	/* set sigs for suspend/resume */
	sigset(SIGUSR2, vinterupt);	/* set sigs for interactive windows */

	/*
	 * Setup windows to be opened upon login
	 */
	for (i = optind; i < argc; i++) {
		objop("OPEN", NULL, p = path_to_full(argv[i]), NULL);
		free(p);
		ar_ctl(ar_get_current(), CTSETLIFE, AR_INITIAL);
	}

	/*
	 * make the first window current
	 */

	if ((argc - optind) >= 1) {
		if (firstar = wdw_to_ar(1))
		{
		   /*
		    * clean-up messages left over by opening initial objects
		    */
	 
		    mess_init();		/* abs k18 */
		    ar_current(firstar, FALSE); /* abs k15 */
		}
		else
		{
		        mess_flush(FALSE);
			vt_flush();
			sleep(3);
			exit(-1);  /* fmli's exit not the C library call */
		}
	}

	/*
	 * Check wastebasket 
	 */
	if (Vflag) {
		vm_initobjects();
		showmail(TRUE);
	}

	while ((t = stream(TOK_NOP, Defstream)) != TOK_LOGOUT)
		;
	exit(0);  /* fmli's exit not the C library call */
}

static bool Suspend_allowed = TRUE;

bool
suspset(b)
bool b;
{
	bool old = Suspend_allowed;

	Suspend_allowed = b;
	return(old);
}

long Interupt_pending = 0;

static void
vinterupt(sig)
int sig;
{
	(void) sigset(sig, vinterupt); /* changed from signal() abs */
	Interupt_pending++;
	return;
}
 
static void
susp_res(sig)
int sig;
{
	char *p;	/* temp for some operations */
	char buf[BUFSIZ];
	pid_t  respid;		/* EFT abs k16 */

	FILE *fp;

	char *getepenv();

	(void) sigset(sig, susp_res);  /* changed from signal  abs */

	sprintf(buf, "/tmp/suspend%ld", getpid());
	if ((fp = fopen(buf, "r")) == NULL) {		/* resume failed */
		_debug(stderr, "Unable to open resume file\n");
		return;
	}

	(void) unlink(buf);
	if (fgets(buf, BUFSIZ, fp) == NULL) {
		_debug(stderr, "could not read resume file");
	} else {
		respid = strtol(buf, (char **)NULL, 0);	/* EFT abs k16 */
		if (!Suspend_allowed) {
			fflush(stdout);
			fflush(stderr);
			printf("\r\n\nYou are not allowed to suspend at this time.\r\n");
			printf("You are in the process of logging out of FACE.\r\n");
			printf("Please take steps to end the application program you are\n\r");
			printf("currently using.\n\r");
			fflush(stdout);
			sleep(4);
			if (kill(respid, SIGUSR1) == FAIL)
				Suspend_interupt = TRUE;
			fclose(fp);
			return;
		}

		if (fgets(buf, BUFSIZ, fp) != NULL) {
			buf[strlen(buf) - 1] = '\0';
			if (buf[0])
				Suspend_window = strsave(buf);
			else
				Suspend_window = NULL;
		} else
			Suspend_window = NULL;
		_debug(stderr, "Resume pid is %d\n", respid);
		ar_ctl(ar_get_current(), CTSETPID, respid);
	}
	fclose(fp);

	Suspend_interupt = TRUE;	/* let wait loop in proc_current know */
	return;
}
	
/* static int    changed to void abs 9/12/88  */
static void
sig_catch(n)
int	n;
{
/*	signal(n, sig_catch);
abs */
        sigset(n, sig_catch);
}


static void
pull()		/* force various library routines to get pulled in */
{
	menu_stream();
	actrec_stream();
	error_stream();
	virtual_stream();
	stubs();
	indicator();
}

char 		Opwd[PATHSIZ+5];
extern char	*Filecabinet;
extern char	*Wastebasket;
extern char	*Filesys;
extern char	*Oasys;

static void
vm_setup()
{
	static	char filecabinet[] = "";
	static	char wastebasket[] = "/WASTEBASKET";
	char *p, *getenv(), *getepenv();

	/*
	 * get/set globals
	 */
	if ((Home = getenv("HOME")) == NULL)
		fatal(MUNGED, "HOME!");
	if ((Filesys = getenv("VMSYS")) == NULL)
		fatal(MUNGED, "VMSYS");
	if ((Oasys = getenv("OASYS")) == NULL)
		fatal(MUNGED, "OASYS");
	Filecabinet = strnsave(Home, strlen(Home) + sizeof(filecabinet) - 1);
	strcat(Filecabinet, filecabinet);
	Wastebasket = strnsave(Home, strlen(Home) + sizeof(wastebasket) - 1);
	strcat(Wastebasket, wastebasket);

	sprintf(Opwd, "OPWD=%s", Filecabinet);
	putenv(Opwd);
	if (p = getepenv("UMASK"))		/* set file masking */
		umask((mode_t) strtol(p, NULL, 8)); /* EFT abs k16 */
}

#define MAX_WCUST (9)
static char	Loginwins[] = "LOGINWIN ";	/* leave space for a digit */

static void
vm_initobjects()
{
    char	*p;
    register int i;
    char *path_to_full(), *getepenv();
    struct actrec *prev, *firstobj;

    prev = NULL;
    firstobj = ar_get_current();
    for (i = 1; i <= MAX_WCUST; i++) {
	Loginwins[sizeof(Loginwins) - 2] = '0' + i;

	if ((p = getepenv(Loginwins)) != NULL && *p) {
	    p = path_to_full(p);
	    if (prev)		/* aids ordering */
		ar_current(prev, FALSE); /* abs k15 */
	    objop("OPEN", NULL, p, NULL);
	    if (firstobj != (prev = ar_get_current()))
		ar_ctl(prev, CTSETLIFE, AR_PERMANENT);
	    free(p);
	    ar_current(firstobj, FALSE); /* aids ordering *//*abs k15*/
	}
    }

    /* clean out WASTEBASKET, if needed */
    if (p = getepenv("WASTEPROMPT")) {
	objop("OPEN", "MENU", strCcmp(p, "yes") ?
	      "$VMSYS/OBJECTS/Menu.remove" :
	      "$VMSYS/OBJECTS/Menu.waste", NULL);
	free(p);
    }
    else
	objop("OPEN", "MENU", "$VMSYS/OBJECTS/Menu.remove", NULL);
}


/* Signal handler for SIGTSTP, the user job control suspend signal.
 * Signal handler for SIGTTIN and SIGTTOU, the terminal input and
 * terminal output signals.
 * Clear the screen and then do the default action for the signal.
 * On return, redraw the screen.
 */
#ifdef SIGTSTP
static void 
on_suspend(signum)
int signum;
{
    endwin();		  /* reset tty to normal */
    kill(getpid(), signum);

    /* start back here when resumed after job control suspend */

    signal(signum, on_suspend); /* reset the signal */

    (void)putchar('\0');  /* output something innocent so we will.. */
                          /* ..suspend on o/p if running in background*/
    vt_redraw();	  /* refresh the screen */
}
#endif
