/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred."
 *
 */
/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	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	"$Header: global.c 1.2 89/10/10 $@(#)vm.wish:src/wish/global.c	1.23"

#include	<stdio.h>
#include	<ctype.h>
#include	<time.h>	/* for glob_time() */
#include	"wish.h"
#include	"token.h"
#include	"slk.h"
#include	"actrec.h"
#include	"ctl.h"
#include	"terror.h"
#include	"moremacros.h"

#define MAX_OBJNAME	15

/*
 * Caution: MAX_ARGS is defined in other files and should ultimately reside 
 * in wish.h
 */
#define MAX_ARGS	25	

static char Objtype[MAX_OBJNAME];
char Release[] = RELEASE;

/* The global stream handler.  Handles most tokens */

int Arg_count;
char *Args[MAX_ARGS];

/* some strings that are used several times in this source file */

static char Open[] = "OPEN";
static char Menu[] = "MENU";
static char Form[] = "FORM";
static char Any[]  = "Any";
static char Extra_args[] = "Extra arguments ignored";

char *path_to_full(), *cur_path();
struct actrec *window_arg(), *wdw_to_ar();

token
global_stream(t)
token t;
{
	register int i;
	char *path, *name, *p;
	struct actrec *a;
	extern char *Filesys;
	char *tok_to_cmd();
	char	*path_to_title();
	struct actrec *path_to_ar();
	char *expand(), *path_arg();
	token gotoarg();

#ifdef _DEBUG5
	_debug5(stderr, "global_stream(%o)\n", t);
#endif
	/*
	 * no more flashing token message (yuk!)
	 *
	 * if (p = tok_to_cmd(t))
	 * {
 	 *	mess_flash(p);
  	 *	doupdate();
	 * }
	*/
	switch (t) {
	/* commands which process objects */
	case TOK_HELP:
		working(TRUE);
		if (Arg_count <= 1) {
			extern char	*Pending_op;

			if (Pending_op)
				objop("OPEN", "TEXT", "$VMSYS/OBJECTS/Text.help", Pending_op, Pending_op, NULL);
			else
				t = (token) ar_help(ar_get_current());
		}
		else 
			t = cmd_help(Args[1]);
		if (t == TOK_OPEN)
			goto openit;
		return TOK_NOP;
	case TOK_CHECKPRINT:	/* checkprint */
		working(TRUE);
		objop(Open, Menu, "$VMSYS/OBJECTS/Menu.ckpr", NULL);
		return TOK_NOP;
	case TOK_SECURITY:	/* security */
		working(TRUE);
		if (path = path_arg()) {
			objop(Open, Form, "$VMSYS/OBJECTS/Form.sec", path,
				path_to_title(path, NULL), NULL);
			return TOK_NOP;
		}
		break;
	case TOK_ORGANIZE:	/* organize */
		working(TRUE);
		if (a = window_arg(Arg_count - 1, Args + 1, 1)) {
			bool b;

			if (access(a->path,02) == FAIL) 
				mess_temp("You do not have write permission to organize this folder");
			else if (ar_ctl(a, CTISDEST, &b) == FAIL || b == FALSE) {
				mess_temp("You may only organize File folders");
			} else {
				objop(Open, Form, "$VMSYS/OBJECTS/Form.org", a->path, 
					path_to_title(a->path, NULL), NULL);
				return TOK_NOP;
			}
		} else
			mess_temp("You must open the File folder to organize");
		break;
	case TOK_FIND:		/* find */
		working(TRUE);
		if (parse_n_in_fold(&name, &path) == SUCCESS) {
			if (name == NULL)
				objop(Open, Form, "$VMSYS/OBJECTS/Form.find", path, NULL);
			else
				objop(Open, Menu, "$VMSYS/OBJECTS/Menu.find", path, name, Any, Any, Any, NULL);
			return TOK_NOP;
		}
		break;

	/* commands which are activation record functions */

	case TOK_CLEANUP:	/* cleanup */
		working(TRUE);
		(void) ar_cleanup(AR_LONGTERM);
		return TOK_NOP;
	case TOK_GOTO:		/* goto */
		if (Arg_count <= 1)
			get_string(gotoarg, "Enter a frame number or path: ", nil, 0, FALSE, "goto", "goto");
		else 
			gotoarg(NULL, t);
		return TOK_NOP;
	case TOK_TAB:		/* tab */
	case TOK_NEXT_WDW:	/* next_wdw */
		ar_cur_next();
		return TOK_NOP;
	case TOK_BTAB:		/* backtab */
	case TOK_PREV_WDW:	/* prev_wdw */
		ar_cur_prev();
		return TOK_NOP;
	case TOK_LOGOUT:	/* logout */
		working(TRUE);
		ar_cleanup(AR_IMMORTAL);
		break;
	case TOK_DEBUG:
/* les
		mdump();
*/
		return TOK_NOP;
	case TOK_REREAD:
		working(TRUE);
		if (Arg_count <= 1)
			ar_reread(ar_get_current());
		else {
			struct actrec *destar, *savear;

			savear = ar_get_current();
			if (destar = window_arg(Arg_count - 1, Args + 1, 2)) {
				if (destar == savear)
					ar_reread(savear);
				else if (ar_reread(destar) == SUCCESS) {
					/*
					 * - make the destination AR current
					 *   (to update the window immediately) 
					 * - if there is no third argument then
					 *   make the save AR current
					 */
					ar_current(destar);
					if (Arg_count != 3 || strcmp(Args[2], "true"))
						ar_current(savear);
				}
			}
		}
		return TOK_NOP;
	case TOK_CLOSE:
		{
			struct actrec *a;
			register int i;
			int close_cur, count;
			char buf[BUFSIZ];

			working(TRUE);
			if (Arg_count <= 1) {
				a = ar_get_current();
				if (!a) 
					mess_temp("Can't find any frames\n");
				else if (a->lifetime == AR_IMMORTAL)
					mess_temp("Can't close this frame\n", Args + i);
				else {
					ar_close(a);
					init_modes();
					ar_checkworld(TRUE);
				}
				return(TOK_NOP);
			}
			for (i = 1; i < Arg_count; i++) {
				a = window_arg(1, Args + i, 1);
				if (!a) {
					sprintf(buf, "Can't find frame \"%s\"\n", Args[i]);
					mess_temp(buf);
				}
				else if (a->lifetime == AR_IMMORTAL) {
					sprintf(buf, "Can't close frame \"%s\"\n", Args[i]);
					mess_temp(buf);
				}
				else {
					ar_close(a);
					init_modes();
					ar_checkworld(TRUE);
				}
			}
			return TOK_NOP;
		}
		break;
	case TOK_CHECKWORLD:	/* force the world to be checked */
		ar_checkworld(TRUE);
		return TOK_NOP;
	case TOK_UNK_CMD:	/* unknown command, if number, goto, else like open */
		if ((i = atoi(Args[0])) && wdw_to_ar(i) && strspn(Args[0], "0123456789") == strlen(Args[0])) {
			ar_current(wdw_to_ar(i));
			return(TOK_NOP);
		} else {
			if (Args[MAX_ARGS-1])
				free(Args[MAX_ARGS-1]); /* les */

			for (i = MAX_ARGS-1; i > 0; i--)
				Args[i] = Args[i-1];

			Args[0] = strsave(Open);

			Arg_count++;
			t = TOK_OPEN;
			/* fall through to open - no break!! */
		}

	/* object operations */

openit:
	case TOK_OPEN:		/* open */
	case TOK_ENTER:
	case TOK_COPY:		/* copy */
	case TOK_MOVE:		/* move */
	case TOK_REPLACE:	/* rename */
	case TOK_SCRAMBLE:	/* scramble */
	case TOK_UNSCRAMBLE:	/* unscramble */
	case TOK_PRINT:		/* print */
	case TOK_DELETE:	/* delete */
	case TOK_UNDELETE:	/* undelete */
	case TOK_OBJOP:		/* any other object operation */
		working(TRUE);
#ifdef _DEBUG
		_debug(stderr, "In global handling object operation\n");
#endif
		if (objop_args(t) != FAIL)
			objopv(tok_to_cmd(t), Objtype, &Args[1]);
		ar_checkworld(TRUE);
		return TOK_NOP;
	case TOK_SREPLACE:	/* redescribe */
		working(TRUE);
		if (objop_args(t) != FAIL) {
			if (Arg_count <= 2)
				enter_getname("redescribe", NULL, &Args[1]);
			else {
				redescribe(&Args[1]);
				ar_checkworld(TRUE);
			}
		}
		return TOK_NOP;
	case TOK_DISPLAY:	/* display */
		working(TRUE);
		if (objop_args(t) != FAIL)
			(void) glob_display(Args[1]);
		return TOK_NOP;
	case TOK_RUN:
		working(TRUE);
		if (objop_args(t) != FAIL) {
			objopv(Open, "EXECUTABLE", &Args[1]);
			ar_checkworld(TRUE);
			return(TOK_NOP);
		}
		break;
	case TOK_CREATE:	/* create */
		working(TRUE);
		return glob_create();

	/* system functions */

	case TOK_SELECT:	/* select */
		glob_select();
		return TOK_NOP;
	case TOK_CANCEL:	/* cancel out of a browse */
		mess_perm(NULL);
		glob_browse_cancel();
		return TOK_NOP;
	case TOK_REFRESH:	/* refresh the screen */
		vt_redraw();
		return TOK_NOP;
	case TOK_TIME:		/* time */
		glob_time();
		return TOK_NOP;
	case TOK_UNIX:		/* unix */
		working(TRUE);
		(void) proc_open(0, "UNIX_System", NULL, "sh", "-c", "echo \"To return, type 'exit' or control-d\nYou are in \`pwd\`\"; exec ${SHELL:-/bin/sh}", NULL);
		ar_checkworld(TRUE);	/* always check after a unix escape! */
		return TOK_NOP;
	case TOK_WDWMGMT:	/* wdw_mgmt */
		working(TRUE);
		if (Arg_count <= 1)
			mgmt_create(NULL);
		else
			mgmt_create(Args[1]);
		return TOK_NOP;
	case TOK_CMD:
		working(TRUE);
		cmd_create();
		return TOK_NOP;
	case TOK_SET:
		working(TRUE);
		if (Arg_count < 3) {
			mess_temp("Not enough arguments");
			break;
		} else {
			char buf[80];

			strcpy(buf, Args[2]);
			for (i = 3; Args[i]; i++) {
				strcat(buf, " ");
				strcat(buf, Args[i]);
			}
			chgepenv(Args[1], buf);
			mess_temp(nstrcat(Args[1], " ==> ", buf, NULL));
			return TOK_NOP;
		}
	case TOK_TOGSLK:
		slk_toggle();
		return TOK_NOP;
	case TOK_RELEASE:
		working(TRUE);
		mess_temp(Release);
		return TOK_NOP;
	case TOK_NOP:
	default:
		break;
	}
	return t;
}


/*
 * This function looks at its arglist, and parses its argument into an
 * activation record.  The argument could be either a window number or a path
 */
struct actrec *
window_arg(argc, argv, maxargs)
int	argc;
char	*argv[];
int	maxargs;
{
	char	*p;
	int n;
	struct actrec	*ret;
	struct actrec	*path_to_ar();
	struct actrec	*wdw_to_ar();

	if (argc <= 0) {
		ret = ar_get_current();
		return(ret);
	}
	else {
		if (argc > maxargs)
			mess_temp(Extra_args);
		if ((n = atoi(argv[0])) && (strspn(argv[0], "0123456789") == strlen(argv[0])) && (ret = wdw_to_ar(n)))
			return(ret);
		else {
			p = path_to_full(argv[0]);
			ret = path_to_ar(p);
			free(p);
			return ret;
		}
	}
}

/*
 * this is used for those functions that require an argument that is
 * a path inside a window by default, or a full path.
 */
static char *
path_arg()
{
	char	*p;
	extern char	*Filecabinet;

	if (Arg_count > 2)
		mess_temp(Extra_args);
	if (Arg_count >= 2)
		return path_to_full(Args[1]);
	else if (ar_ctl(ar_get_current(), CTGETARG, &p) != FAIL && p && *p)
		return path_to_full(p);
	return Filecabinet;
}

/*
 * These should really go in separate source files when they are 
 * finally finished.
 */
static
glob_time()
{
	char	buf[12];
	long	t;
	register struct tm	*tp;
	long	time();
	struct tm	*localtime();

	t = time(0L);
	tp = localtime(&t);
	sprintf(buf, "%d:%02.2d:%02.2d %cM", tp->tm_hour % 12 ? tp->tm_hour % 12 : 12, tp->tm_min, tp->tm_sec, tp->tm_hour >= 12 ? 'P' : 'A');
	mess_temp(buf);
}

/* prepare the argument array for an impending object operation */

static int
objop_args(t)
token t;
{
	char *p;
	register int i;

	strcpy(Objtype, "OBJECT");
	if (Arg_count <= 1) {	/* current object is the arg */
		if (ar_ctl(ar_get_current(), CTGETARG, &Args[1]) == FAIL) {
			glob_mess_nosrc(t);
			return(FAIL);
		}

		Args[1] = strsave(Args[1]);
		if ( Args[2] )
			free( Args[ 2 ] ); /* les */
		Args[2] = NULL;
		Arg_count = 2;
		return(SUCCESS);
	}
	if (Arg_count > 2 && 
		(is_objtype(Args[1]) || strCcmp("OBJECT", Args[1]) == 0)) {
		strncpy(Objtype, Args[1], MAX_OBJNAME);
		for (p = &Objtype[0]; *p; p++)
			if (islower(*p))
				*p = toupper(*p);
		free(Args[1]);
		for (i = 1; Args[i] = Args[i+1]; i++)
			;
		Arg_count--;
	}
	if (Arg_count >= 3 && strCcmp(Args[1], "to") == 0) {
		free(Args[1]);
		if (ar_ctl(ar_get_current(), CTGETARG, &Args[1]) == FAIL) {
			glob_mess_nosrc(t);
			return(FAIL);
		}
	}

	p = Args[1];
	Args[1] = path_to_full(Args[1]);
	if (p)
		free(p);
	return SUCCESS;
}

static token
gotoarg(s, t)
char *s;
token t;
{
	struct actrec *a;

	if (t == TOK_CANCEL)
		return t;
	if (s) {
		if (Args[1] && Arg_count > 1)
			free(Args[1]);
		Args[1] = strsave(s);
		if (Arg_count < 2)
			Arg_count = 2;
	}
	if ((a = window_arg(Arg_count - 1, Args + 1, 1)) == NULL) {
		mess_temp("Unable to find a frame with that name");
		return t;
	}
	else
		ar_current(a);
	return TOK_NOP;
}

/* parse for arguments of the form: command [name] [in folder] */

int
parse_n_in_fold(name, folder)
char **name, **folder;
{
	struct actrec *a;

	switch (Arg_count) {
	case 0:
	case 1:
		*name = NULL;
		*folder = cur_path();
		break;
	case 2:
		*name = Args[1];
		*folder = cur_path();
		break;
	default:
		mess_temp(Extra_args);
		sleep(2);
	case 4:
		if (strCcmp(Args[2], "in") != 0) {
			mess_temp(Extra_args);
			return(FAIL);
		}
		*folder = path_to_full(Args[3]);
		*name = Args[1];
		break;
	case 3:
		*folder = path_to_full(Args[2]);
		if (strCcmp(Args[1], "in") == 0)
			*name = NULL;
		else
			*name = Args[1];
		break;
	}
	return SUCCESS;
}

static char *
cur_path()
{
	bool arg;
	char *path;
	extern char *Filecabinet;

	if (ar_ctl(ar_get_current(), CTISDEST, &arg) == FAIL || arg == FALSE)
		path = Filecabinet;
	else
		path = ar_get_current()->path;
	return(path);
}
