/*----------------------------------------------------------------------------
 LIME - The definitive LInux MEnuing system
 (C)opyright 1994-1995, Scott Burkett, All Rights Reserved
 ----------------------------------------------------------------------------- 
 $Header$
 ----------------------------------------------------------------------------- 
 $Log$
 ----------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

#include <ncurses.h>

#include "lime.h"
#include "protos.h"

void Process(void)
{
	char key;
	int  _redraw=TRUE;


	ScreenSet("news", TRUE);
	ExecuteHook(HOOK_MAIN);

	currmenu=0;
	strcpy(menustack[currmenu], menuname);

	_showscreens=TRUE;

	while (TRUE) {
		
		/* Show any screensets associated with this menu */
		if(_showscreens)	
		{
			ScreenSet(menuname, TRUE);
			_showscreens=FALSE;
		}

		sprintf(buf, "%s/%s", menupath, menuname);
		if(_redraw)
		{
			if(!ShowMenu(buf))
			{
				MenuReturn();
				continue;
			}

		}

	 	sprintf(buf, "Browsing in %s", menuname);

		key = getch();
		SetAlarm();
		key = toupper(key);

		if(!Dispatch(key))
			_redraw=FALSE;
				else
					_redraw=TRUE;
		
	}
}

int Dispatch(char key) 
{
	int ndx=0;
	int redraw=FALSE;

	/* Go through the option table for the current menu */
	for(ndx=0; ndx<highoption; ndx++)
	{
		/* Check for non-blank entries and a matching keystroke */
		if( menu.options[ndx].key == key && menu.options[ndx].type != MENU_BLANK)
		{
			/* Finally, does the user have access to it? */
			if(CheckGroupAccess(menu.options[ndx].groups))
			{
				if(menu.options[ndx].password[0] != '\0') 
				{
					ColorStr(menu.pwdpromptcol);
					printf("\n\rPassword: ");

					if(!CheckPassword(menu.options[ndx].password))
					{
						ScreenSet("badpasswd", TRUE);
						redraw=TRUE;
						break;
					}
				}

				switch(menu.options[ndx].type)
				{
					case    MENU_QUIT:   	ExecuteHook(HOOK_LOGOFF);
								ScreenSet("goodbye", TRUE);
								Log("User logging off normally");
						 		Shutdown(); 
					case    MENU_JUMP:	MenuJump(ndx);
								redraw=TRUE;
								_showscreens=TRUE;
								break;
					case  MENU_RETURN:	MenuReturn(); 
								redraw=TRUE;
								break;
					case  MENU_EXTERN:	ExternalProcess(ndx);
								redraw=TRUE;
								break;
					case  MENU_SCREENSET:	ScreenSet(menu.options[ndx].secondary, TRUE);
								redraw=TRUE;
								break;
					case  MENU_SHOWFILE:	ShowFile(menu.options[ndx].secondary, TRUE, FALSE);
								redraw=TRUE;
								break;
					case  MENU_SHOWAFILE:	ShowFile(menu.options[ndx].secondary, TRUE, TRUE);
								redraw=TRUE;
								break;
					case  MENU_DISPLAY: 	Macros((char *)&menu.options[ndx].secondary);
								printf("%s\n\r", menu.options[ndx].secondary);
								redraw=TRUE;
								break;
					default:		SystemMessage("Bad menu type!", TRUE);
								redraw=TRUE;
								break;
						
				}
			}			
		}

	}

	return(redraw);
}

/* Returns TRUE is the user's effective group ID (getegid) is in the "str" 
   argument.  This argument should be a list of groups, separated by dashes,
   like so:  0-10-20-100-103 

   If an "*" is passed, then access is granted to all groups
*/

int  CheckGroupAccess(char *groups)
{
	char *ptr = groups;

	if(*ptr == '*')
		return(TRUE);

	ptr = (char *)strtok(groups, "-");

	while(ptr)
	{
		if( egid == atol(ptr))
			return(TRUE);
	
		ptr = (char *)strtok(NULL, "-");
	}

	return(FALSE);
}

/* Obtains a password.  Returns TRUE if password matches */

int CheckPassword( char *password )
{
	char *ptr;

	if((ptr = GetString(0, 1, 0, 15)) == NULL)
		return(FALSE);

	if(!strncmp(ptr, password, strlen(password)))
		return(TRUE);
	else
		return(FALSE);
}

void MenuJump(int ndx)
{
	if(currmenu == 9) 
	{
		SystemMessage("Menus nested too deep!", TRUE);
		return;
	}

	currmenu++;
	strcpy(menustack[currmenu-1], menuname);
	strcpy(menuname, menu.options[ndx].secondary);
}

void MenuReturn(void)
{
	currmenu--; 

	if(currmenu < 0)
	{
		currmenu=0;
		return;
	}

	strcpy(menuname, menustack[currmenu]);
}

void ExternalProcess(int ndx)
{
	char *start, prog[30];
	int  x, status, cntr=0;
	pid_t external_pid;

	wclear(desktop);
	wrefresh(desktop);

	sprintf(logbuf, "Option: %s", menu.options[ndx].desc);
	Log(logbuf);

	if(_debug)
	{
		sprintf(logbuf, "User executing: %s", menu.options[ndx].secondary);
		Log(logbuf);
	}

	/* TurnOffAlarm();	*/
	RemoveTraps();
	reset_shell_mode();
  	/* SetWatchDog();  */

/*	system(menu.options[ndx].secondary); */

	/* Build array of arguments for call to exec..() */
	strcpy(buf, menu.options[ndx].secondary);
	start = strtok(buf, " ");

	while ( start )
	{
		if(cntr==0)
		{
			strcpy(prog, start);
		}

		ptrs[cntr] = (char *)malloc(strlen(start)+1);
		if(ptrs[cntr] == NULL)
		{
			SystemMessage("Out of memory in ExternalProcess()!", TRUE);
			return;
		}

		strcpy(ptrs[cntr], start);

		cntr++;
		start = strtok(NULL, " ");
	}

	ptrs[cntr] = NULL;

	if(_debug)
	{
		if(_debug)
		{
			sprintf(logbuf, "PROG=%s", prog);
			Log(logbuf);
		}
	
		for(x=0; x<cntr; x++)
		{
			sprintf(logbuf, "PTRS[%d]=%s", x, ptrs[x]);
			Log(logbuf);
		}
	}

	external_pid = fork();

	if(external_pid == 0)
	{
		/* Child process */
		TurnOffAlarm();	
		execvp(prog, ptrs); 
		exit(1);
	}
	else
	{
		/* Parent waits */
		/* TurnOffAlarm(); */
		wait(&status);
		if(_debug)
		{
			sprintf(logbuf, "ERRNO: %d", errno);
			Log(logbuf);
		}

		ptrs[0] = NULL;

		for(x=1; x<cntr; x++) 
		{
			free(ptrs[x]);
			ptrs[x] = NULL;
		}
	}

	reset_prog_mode();
/* SetAlarm();
	SetTraps(); */

	printf("\n\r");
	PressEnter();
}

void ExecuteHook(int hook)
{
	char hookbuf[100];

	switch(hook)
	{
		case   HOOK_MAIN:	strcpy(hookbuf, hook_main); break;
		case HOOK_LOGOFF:	strcpy(hookbuf, hook_logoff); break;
	}

	if(hookbuf[0] == '\0') 
		return;

	system(hookbuf);

}

