//*****************************************************************************
//
//	Coordinator.m  
//		
//		NXApp delegate, central control object for GateKeeper 
// 
//			by	Felipe A. Rodriguez		
//
//	This code is supplied "as is" the author makes no warranty as to its 
//	suitability for any purpose.  This code is free and may be distributed 
//	in accordance with the terms of the:
//		
//			GNU GENERAL PUBLIC LICENSE
//			Version 2, June 1991
//			copyright (C) 1989, 1991 Free Software Foundation, Inc.
// 			675 Mass Ave, Cambridge, MA 02139, USA
//
//*****************************************************************************

#import <appkit/nextstd.h>
#import <appkit/Application.h>
#import <objc/NXStringTable.h>
#import <defaults/defaults.h>
#import <bsd/c.h>
#import <sys/dir.h>  			/* POSIX applications #include <dirent.h> */
#import <mach/mach.h>
#import <kernserv/kern_loader.h>

#import "GKdefs.h"
#import "Animator.h"
#import "EParse.h"
#import "OptionsEditor.h"
#import "options.h"
#import "IconView.h"
#import "ToolBar.h"
#import "DialServer.h" 
#import "Timer.h"
#import "IdleAnimator.h"
#import "Coordinator.h"
#import "CommandScroll.h"
#import "GateDocEditor.h"
#import "InfoAnimator.h"
#import "DLDelegate.h"
#import "pppstats.h"
#import "./MiG/Library/pppd_rpc_defs.h"			// pppd RPC related defs




@interface Coordinator (Private)


		// RPC routines 
#import "pppd_rpc_types.h"
#import "pppd_rpc.h"
extern void gk_listen(void);					
extern void gk_check_out(void); 


@end
@implementation Coordinator (Private)
@end
@implementation Coordinator

//*****************************************************************************
//
//		state machine which monitors ppp daemon
//
//*****************************************************************************
 
- setPhase:(int)phase
{
	switch(phase)
		{							
		case 0: 								// pppd hangup
			[theTimer stopTimer];
			[theAnimator standBy];
											// disable the disconnect button
			[[[NXApp mainMenu] findCellWithTag:1] setEnabled:NO];
			[statusButton setEnabled:NO];
			[theOpenButton setEnabled:YES];		// enable the open doc button
			[dial setEnabled:YES];					// enable dial button
			[connectionSpeedField setStringValue:"                          "];
			[timeField setStringValue:"        "];
			[timeCell setStringValue:"      "];
			[self displayStatus:"pppdn"];
			break;

		case 2: 							// initial state after GK launch
			[theTimer stopTimer];
			[theAnimator standBy];
			[self displayStatus:"ppp is ready"];
			[statusButton setEnabled:NO];
			[connectionSpeedField setStringValue:"                      "];
			[timeField setStringValue:"        "];
			[timeCell setStringValue:"      "];
			[[[NXApp mainMenu] findCellWithTag:1] setEnabled:NO];
			[[[NXApp mainMenu] findCellWithTag:2] setEnabled:YES];
			break;

		case 8:									// Holdoff	
			[self displayStatus:"ppp daemon in holdoff"];
			break;

		case GK_CONNECT_FAIL:					// Connect script failed	
			[theAnimator standBy];
			[connectionSpeedField setStringValue:"                      "];
			[self displayStatus:"connect script failed"];
			break;

		case GK_DIALING: 						// dialing?
			if(!wasHidden)			// if sw not set chk if we are hidden
				wasHidden =	[NXApp isHidden];				// app hidden?
			if(strcmp("YES",NXGetDefaultValue([NXApp appName], DISPLAYS)) == 0)
				[[statusView window] makeKeyAndOrderFront:self];			
					// if auto unhide switch is set wait msec before hiding	
		if(strcmp(NXGetDefaultValue([NXApp appName], "autoUnhide"),"YES") == 0)	
					[NXApp perform:@selector(unhide:) with:self 
												afterDelay:2000 
												cancelPrevious:YES];				
		case MAN_DIAL: 						
			[self playSound:"Servo_2"];
			[theAnimator dialing];
			[dial setEnabled:NO];			// disable dial button
			[theOpenButton setEnabled:NO];	// disable the open doc button
			[self displayStatus:"Connecting..."];
			break;

		case 6:									// PPP link is up
			[[[NXApp mainMenu] findCellWithTag:1] setEnabled:YES];
			[[[NXApp mainMenu] findCellWithTag:2] setEnabled:NO];
			[self displayStatus:"pppup"];
			[self gotIt];
			break;

		case GK_INACTIVITY:						// Inactivity timeout					
			[self displayStatus:"ppp idle timeout is imminent"];
			idleZone = NXCreateZone(vm_page_size, vm_page_size, YES);
			[NXApp loadNibSection:"IdlePanel.nib" 
							owner:self 
							withNames:NO 
							fromZone:idleZone];
			[iTimer startAnimTimer];
			break;

		case GK_DIE:						// pppd died 	
			[theAnimator standBy];
			[[[NXApp mainMenu] findCellWithTag:1] setEnabled:NO];
			[[[NXApp mainMenu] findCellWithTag:2] setEnabled:YES];
			[statusButton setEnabled:NO];
			[self displayStatus:"ppp daemon died"];
			break;

		case GK_NO_LKS:						// pppd found no LKS support 	
			[self displayStatus:"loading BPF LKS"];
			[self loadKernelServer:"bpf_reloc"];
			[self displayStatus:"loading PPP LKS"];
			[self loadKernelServer:"ppp_reloc"];
			[self displayStatus:"launching PPP daemon"];
			[docLDelegate link];		// link, use preferences selected doc 
			break;

		default:	 		
			break;
		}
	NXPing();
		
    return self;
}
//*****************************************************************************
//
// 		return our string table (contains key->value localization pairs) 
//
//*****************************************************************************

- stringTable;
{
    return stringTable;
}
//*****************************************************************************
//
// 	localize error messages using stringTable as appropriate, displays
// 	the message in an alert panel
//
//*****************************************************************************

- showAlert:(const char *)errorString
{
	NXRunAlertPanel(0, [self localString:errorString], 
							[stringTable valueForStringKey:"OK"], NULL, NULL);

    return self;
}
//*****************************************************************************
//
// 	localize string messages using stringTable as appropriate
//
//*****************************************************************************

- (const char *)localString:(const char *)aString
{
const char *returnedString;
    
    if (returnedString = [stringTable valueForStringKey:aString])
    	return returnedString;

    return aString;
}
//*****************************************************************************
//
// 		display status messages in status panel and on console
//
//*****************************************************************************

- displayStatus:(const char *)status
{
const char *statusString = [self localString:status];

	[statusView setStringValue:statusString];
	[commandView appendString:statusString];
	[commandView appendString:"\n"];

    return self;
}
//*****************************************************************************
//
// 		Called when link is established
//
//*****************************************************************************
 
- gotIt
{
	[theAnimator pppup];
	[self playSound:"majestic"];					// play ppp up snd

	[theTimer Fire:self];							// session timer start cnt
	[self pppstats:commandView];

	if(!onImage)									// display ppp up app icon
		onImage = [NXImage findImageNamed:"g4"];	
	[theIconView setImage:onImage];	
				
	[statusButton setEnabled:YES];

						// if auto hide switch is set wait 5 sec before hiding	
	if((strcmp(NXGetDefaultValue([NXApp appName],"autoHide"),"YES") == 0) &&
																	 wasHidden)	
		[NXApp perform:@selector(hide:) with:self 
								  afterDelay:3000 
							  cancelPrevious:YES];				
	wasHidden =	NO;												// reset sw

    return self;
}
//*****************************************************************************
//
// 		registers connection speed 
//
//*****************************************************************************

- connectedAt:(const char *)speed  
{
	strncpy(Path, [stringTable valueForStringKey:"connectAt"], MAXPATHLEN);
	strncat(Path, speed, MAXPATHLEN - strlen(Path));
	[connectionSpeedField setStringValue:Path];
	[commandView appendString:Path];
	[commandView appendString:"\n"];

    return self;
}
//*********************** Application Object Delegation ***********************
//*****************************************************************************
//
// 			setup defaults data base cache before app is init'd
//
//*****************************************************************************

- appWillInit:sender
{
    static NXDefaultsVector myDefaults = {		// setup defaults database
		{VERSION, "0"},							// version string
        {DISPLAYD, "YES"},						// display diagnostics window
		{DISPLAYS, "YES"},						// display status window
		{"autoHide", "YES"},					// auto hide upon link		
		{"autoUnhide", "YES"},					// auto appear while linking		
		{"DispPPP", "YES"},						// display pppstats
		{DISPLAYT, "YES"},						// display toolbar
		{SOUND, "YES"},							// play sound 
		{AITIMER, "YES"},						// icon displayed online time
		{"iTimeout", "Off"},					// inactivity unlink's us
		{"iTimeThreshold", "0"},				// inactivity threshold 
		{SELCELL, "0"},							// cell selected in hotList
		{DOD, "YES"},							// dial on demand
		{"options", "/etc/ppp/options"},			
		{"ip-down", "/etc/ppp/ip-down"},			
		{"ip-up", "/etc/ppp/ip-up"},			
		{"resolv", "/etc/resolv.conf"},			
		{"messages", "/usr/adm/messages"},			
		{"remote", "/etc/remote"},			
		{LIBPATH, "/Library/GateKeeper"},		// path for .Gate documents
		{"BaudStr", "CARRIER"},								// pref form end
		{DIALINIT, "ATZ&D0L3"},			// modem init str for manual Dial
		{"dialPrefix", "ATD"},			// modem AT command prefix for dialing
		{MODEMPORT, "cufa"},			// modem port, used in releasing locks
		{EDOC, "/"},							// path for .Gate documents
		{CDOC, " "},							// current .Gate document
		{"lastNumDialed", "8675309"},				// default man dial number
		{"savedTime", "000000000000"},			// save time used this mo
		{"monthTime", "000000000000"},			// save mo,yr of this ses'n
		{"preMonthTime", "000000000000"},		// save previous mo,yr 
        {NULL}};									// make local cache of ddb
    NXRegisterDefaults([NXApp appName], myDefaults);	
		
    return self;
}
//*****************************************************************************
//
// 			standard init
//
//*****************************************************************************

- appDidInit:sender
{												
kern_return_t 	ret;							// MiG return value variable
port_t			server;							// port id
static int c;
static char buf[256];

	theAnimator = [[Animator alloc] init];		// get appIcon window
	theIconView = [theAnimator iconView];
	timeCell = [theIconView getTextCell]; 		// ret the iconView's textCell

				// load console window and have it remember its size and loc
	[NXApp loadNibSection:"Console.nib" owner:self withNames:NO];
	[[commandView window] setFrameUsingName:[[commandView window] title]];	
	[[commandView window] setFrameAutosaveName:[[commandView window] title]];
	if(strcmp(NXGetDefaultValue([NXApp appName], DISPLAYD),"YES") == 0)
		[[commandView window] makeKeyAndOrderFront:self];	// show console win
	
	if(strcmp("YES", NXGetDefaultValue([NXApp appName], DISPLAYS)) == 0)
		[[statusView window] makeKeyAndOrderFront:self];  // show status panel

    if(strcmp(NXGetDefaultValue([NXApp appName], VERSION), CURRVERSION) != 0) 
		{							// if first time this version was launched
		if(!NXWriteDefault([NXApp appName], VERSION, CURRVERSION))
			NXRunAlertPanel(0,
					[stringTable valueForStringKey:"ddbWriteError"],
                	[stringTable valueForStringKey:"OK"],
                	NULL,
                	NULL);
		[self showInfo:self];	
		}
							// primary thread should listen for DO messages  
							// since appkit is not thread-safe
	GKAppDelegate = [NXConnection registerRoot:self withName:"GKAppDelegate"]; 
	[GKAppDelegate runFromAppKit];		// listen for DO messages from appKit
	gk_listen();						// create RPC listener thread

	if(strcmp("YES", NXGetDefaultValue([NXApp appName], AITIMER)) == 0)	
		appIconTime = YES;					// show online time in app icon

	theTimer = [[Timer allocFromZone:[self zone]] init];

											// if dock autolaunched at startup
	if(strcmp("YES", NXGetDefaultValue([NXApp appName], "NXAutoLaunch")) == 0)	
		{
					// if auto hide switch is set wait x sec before hiding	
		if((strcmp(NXGetDefaultValue([NXApp appName],"autoHide"),"YES")==0))	
			[NXApp perform:@selector(hide:) with:self 
									afterDelay:100 
									cancelPrevious:YES];	
		}

	[docLDelegate awake];					// initialize the doc delegate 

	if(strcmp("YES", NXGetDefaultValue([NXApp appName], DISPLAYT)) == 0)	
		[self toolBar:self];							// show toolbar if set

	usleep(200);
	server = pppd_rpc_server_look_up();					// find pppd
	if (server != PORT_NULL)							// pppd is active
		{
		if ((ret = pppd_status(server, &c)) != KERN_SUCCESS) 			 
			[self showAlert:"Error getting ppp daemon status."];
		else
			{
			sprintf(buf,"pppd returned status:  %d \n",(int) c);
			[commandView appendString:buf];
			[self setPhase:c];
			}
		}
	else								// if pppd did not respond launch it
		{	 	
			// if not opeining a doc we were launched by double clicking 
			// on the application icon instead of a document. 
		if(!NXGetDefaultValue([NXApp appName], "NXOpen") &&
			!NXGetDefaultValue([NXApp appName], "NXOpenTemp") &&
				!NXGetDefaultValue([NXApp appName], "NXServiceLaunch"))
			{								// set dial on demand if enabled
			if(strcmp("YES", NXGetDefaultValue([NXApp appName], DOD)) == 0)
				[self startDaemon:self];	// start the daemon
			else
				{				// allow user to start daemon from tools menu
				[cDaemonButton setAction:@selector(startDaemon:)];
				[cDaemonButton setTitle:[self localString:"Start pppd"]];
				}
			}
		}
					 
    return self;
}
//*****************************************************************************
//
// 		This method is performed whenever a user double-clicks on an icon in
// 		the Workspace Manager representing a Gate program document.  
// 		
// 		Brings up the gate doc editor which can edit or link using the doc
//
//*****************************************************************************

- (int)app:sender openFile:(const char *)path type:(const char *)type 
{
	[theGateDocEditor editGateDoc:path];
				
	return 1;
}
//*****************************************************************************
//
// 		invoked immediately after app is hidden and unhidden respectively
//
//			the following two methods are implemented to produce
//			normal main window/menu app behavior when toolBar is open
//
//******************************************************************************
- appDidHide:sender
{
	[[NXApp mainMenu] close];		// close the main menu  
									
    return self;
}

- appDidUnhide:sender
{
	[[NXApp mainMenu] makeKeyAndOrderFront:self];		 

    return self;
}
//*****************************************************************************
//
// 		Instantantiates the subprocess object which exec's pppd
//
//*****************************************************************************

- linkWithFile:(const char *)path  
{
static char commandLine[MAXPATHLEN + 1], buf[8]; 
int timeout;
id image;

	if([self runScript:"preLink"])				// exec pre link script
		{ 
												// build command line
		strncpy(commandLine, [[NXBundle mainBundle] directory], MAXPATHLEN);	 
		strncat(commandLine, "/pppd", MAXPATHLEN - strlen(commandLine));
												// idle timeout is set
		if(strcmp("Off", NXGetDefaultValue([NXApp appName], "iTimeout")) != 0)
			{	
			strncat(commandLine, " idle ", MAXPATHLEN - strlen(commandLine));
			timeout = atoi(NXGetDefaultValue([NXApp appName],"iTimeout")) * 60;
			sprintf(buf,"%d",(int)timeout);
			strncat(commandLine, buf, MAXPATHLEN - strlen(commandLine));
			}

		if(path == NULL)
			{				
			lastCall[0] = '\0';	
			if([docLDelegate selGateDocOptionsPath] == NULL)
				commandLine[0] = '\0';
			else								// if hotlist points to valid
				{
				strncat(commandLine, " ipcp-accept-local ipcp-accept-remote", 
											MAXPATHLEN - strlen(commandLine));
				strncat(commandLine," file ",MAXPATHLEN - strlen(commandLine));
				strncat(commandLine, [docLDelegate selGateDocOptionsPath], 
											MAXPATHLEN - strlen(commandLine));
				strncpy(BPath,[docLDelegate selGateDocOptionsPath],MAXPATHLEN);			
				[providerField setStringValue:[self localString:"manDial"]];
				}
			}
		else
			{								// set dial on demand if enabled
			if(strcmp("YES", NXGetDefaultValue([NXApp appName], DOD)) == 0)
				{
				strncat(commandLine, 
				  " demand :192.42.172.4 ipcp-accept-local ipcp-accept-remote", 
					MAXPATHLEN - strlen(commandLine));
				manDial = NO;				// daemon should persist
				}
			else
				manDial = YES;				// kill pppd upon session term

			strcpy(lastCall, path);			// stores path of last invocation
											// setup status panel
			[statusView setStringValue:[self localString:"connecting"]];
			[providerField setStringValue:[docLDelegate extractName:path]];	
			strncpy(Path, path, MAXPATHLEN);
			strncat(Path, "/Icon.tiff", MAXPATHLEN - strlen(Path));
			if(!(image = [[NXImage alloc] initFromFile:Path]))		// if image
				image = [NXImage findImageNamed: ".dir"];	// else use blank
			[statusImageView setImage:image];

			if((strlen([[NXBundle mainBundle] directory]) + 45 + 
					(2 * strlen(path)) + strlen(commandLine)) < MAXPATHLEN)	
				{								// if we won't overrun buffer
				strcat(commandLine, " file ");
				strcat(commandLine, path);
				strcat(commandLine, OPTION);	// options file name wrapper
				strcat(commandLine, " connect \"");				
				strcat(commandLine, [[NXBundle mainBundle] directory]);
				strcat(commandLine, "/chat -v -f ");
				strcat(commandLine, path);
				strcat(commandLine, PPPUP);	// pppup file name wrapper
				strcat(commandLine, "\"");
				}
			else
				perror("command line is longer than MAXPATHLEN");
			strncpy(BPath, path , MAXPATHLEN);	
			strncat(BPath, OPTION, MAXPATHLEN - strlen(BPath));	// options 
			}
		if(commandLine[0] != '\0')				// if we have a valid commline 
			{
			if([self debugFlag:BPath])
				{				// if debug sw set in options disg commandline
				[commandView appendString:commandLine];
				[commandView appendString:"\n\r"];
				}
			system(commandLine);
			}
		else
			[self showAlert:"GateKeeper error building ppp command line."];
		}
		
	return self;
}
//*****************************************************************************
//
// 		Use terminal to do a manual link 
//
//*****************************************************************************

- Dial:sender  
{								
	if([self runScript:"preLink"])
		{ 
		manDial = YES;
		[self stopDaemon:self];				// kill the daemon
		usleep(800);
		[self setPhase:MAN_DIAL];

		if(!theGateServer)					// create distributed Obj server
			theGateServer = [[DialServer alloc] init];  		
		GateConnection = [NXConnection registerRoot: theGateServer
						withName:"GateKeeperDialServer"];// DO name of server
		[GateConnection runFromAppKit];	// listen for DO messages from appKit
						
										// ask workspace to launch MODEM tool
		if(![[NXBundle mainBundle]getPath:Path forResource:"MODEM"ofType:NULL])
			[self showAlert:"Error getting path for MODEM file"];
		[[Application workspace] openFile:Path withApplication:"Terminal"];	
		}

    return self;
}
//*****************************************************************************
//
// 		Called when menu item Unlink is pressed.  
//
//*****************************************************************************

- disconnect:sender  
{
kern_return_t 	ret;							// MiG return value variable
port_t			server;							// port id

	if([self runScript:"preUnLink"])
		{ 
		[self displayStatus:"terminating ppp session"];
		server = pppd_rpc_server_look_up();			// find pppd
		if (server == PORT_NULL)
			[self showAlert:"unable to find pppd server"];
		else
			{
			ret = set_pppd(server, GK_TERMINATE);	// set pppd state
			if (ret != KERN_SUCCESS) 
				[self showAlert:"Call to pppd server failed."];
			}
		if(manDial)
			[self stopDaemon:self];	
		manDial = NO;
		}

    return self;
}
//*****************************************************************************
//
// 		run the preLink or preUnLink scripts, proceed if exit status true 
//
//*****************************************************************************

- runScript:(const char *)type  
{
id exitStatus = self;
int fd;

	strncpy(Path, [[NXBundle mainBundle] directory], MAXPATHLEN);
	strncat(Path, "/", MAXPATHLEN - strlen(Path));
	strncat(Path, type, MAXPATHLEN - strlen(Path));
	if(fd = open(Path, O_RDONLY) != -1)			//	if script exists
		{
		close(fd);
		if(system(Path) != 0)					// exec script, test exit
			exitStatus = nil;
		strcpy(Path, type);
		if(!exitStatus)
			strcat(Path," script exit status prevents requested action\n");
		else
			strcat(Path, " script executed sucessfully\n");
		[commandView appendStringUseFixedFont:Path];
		}

    return exitStatus;
}
//*****************************************************************************
//
// 		we can always edit another gate doc
//
//*****************************************************************************

- (BOOL)appAcceptsAnotherFile:sender 
{
    return YES;
}
//*****************************************************************************
//
//		termination is imminent 
//
//*****************************************************************************

- appWillTerminate:sender
{
int ret;

	if((ret = NXRunAlertPanel(0, [self localString:"Terminate ppp daemon?"],
							[stringTable valueForStringKey:"Yes"],
							[stringTable valueForStringKey:"No"], 
							"Cancel")) == NX_OKTAG)
		{
		[self killDaemon];
		[self runScript:"postPPP"];			// to do after daemon is killed
		}

	gk_check_out();					// remove our name from net name server

	[theAnimator removeTimedEntry];
	if(theGateServer)					
		[theGateServer appWillTerminate];
	if(docLDelegate)					
		[docLDelegate appWillTerminate];
	
    return (ret != NX_ALERTOTHER ? self : nil);		
}
//*****************************************************************************
//
// 		kill pppd
//
//*****************************************************************************

- killDaemon
{
port_t server;									// port id
FILE *ff; 
int pid;

	server = pppd_rpc_server_look_up();			// find pppd
	if (server == PORT_NULL)
		fprintf(stderr,"lookup of pppd server failed in (killDaemon).\n");
	else
		die_pppd(server, GK_KILL);				// async RPC call to pppd

	usleep(900);
									// if the lock file is still around kill 
									// the daemon with extreme prejudice
    if((ff = fopen( "/etc/ppp/ppp0.pid", "r")) != NULL)
		{			 
		fprintf(stderr,"Killing ppp daemon with extreme prejudice.\n");
    	if( fscanf( ff, "%d", &pid) < 1) 
        	perror("Unable to read pid from ppp0.pid\n");
		else
			{
    		fclose( ff);
    		if( kill( pid, SIGKILL) == -1) 
				fprintf(stderr,"Error killing ppp daemon in (killDaemon).\n");
			}
    	}
	
    return self;
}
//*****************************************************************************
//
//		start and stop the ppp daemon 
//
//*****************************************************************************

- stopDaemon:sender 
{
	[self setPhase:0];
	[commandView appendString:[self localString:"Killing ppp daemon\n"]];
	[self killDaemon];
	[cDaemonButton setAction:@selector(startDaemon:)];
	[cDaemonButton setTitle:[self localString:"Start pppd"]];

	return self;
}
//*****************************************************************************
//
//		start and stop the ppp daemon 
//
//*****************************************************************************

- startDaemon:sender 
{
	[commandView appendString:[self localString:"Starting ppp daemon\n"]];
					// preferences selected HotList doc for launching pppd
	[docLDelegate link];	
	[cDaemonButton setAction:@selector(stopDaemon:)];
	[cDaemonButton setTitle:[self localString:"Stop pppd "]];

	return self;
}
//*****************************************************************************
//
// 		view the ppp log file 
//
//*****************************************************************************

- viewLog:sender
{
const char *logFile;
														// if readable
	if([self readable:(logFile = [self logFile])])		// open with edit
		[[Application workspace] openFile:logFile withApplication:"Edit"];
	
    return self;
}
//*****************************************************************************
//
// 		show the info panel 
//
//*****************************************************************************

- showInfo:sender
{
    if(!infoPanel)
		[NXApp loadNibSection:"InfoPanel.nib" owner:self withNames:NO];
    [infoPanel startAnimTimer];
	
    return self;
}
//*****************************************************************************
//
//		show preferences panel   
//
//*****************************************************************************
 
- preferences:sender
{
	if(!preferencesPanel) 
		{
		[self loadBundlesOfType:"gkPreference" owner:NXApp nib:NO];
		preferencesPanel = [NXApp loadNibSection:"Preferences.nib" owner:NXApp 
															   withNames:YES];
		}
	[preferencesPanel makeKeyAndOrderFront:self];
		
    return self;
}
//*****************************************************************************
//
//		show NXHelpPanel 
//
//*****************************************************************************

- showHelpPanel:sender 
{
    if(!helpPanel)
		helpPanel = [NXHelpPanel new];
    [helpPanel display];
    [helpPanel makeKeyAndOrderFront:self];
	
    return self;
}
//*****************************************************************************
//
//		display the Status panel 
//
//*****************************************************************************

- showStatusPanel:sender 
{
	if(!NXWriteDefault([NXApp appName], DISPLAYS, "YES"))
		[self showAlert:"ddbWriteError"];

 	return [[statusView window] makeKeyAndOrderFront:self];
}
//*****************************************************************************
//
// 		display the Console window 
//
//*****************************************************************************

- showConsole:sender
{
	if(!NXWriteDefault([NXApp appName], DISPLAYD, "YES"))
		[self showAlert:"ddbWriteError"];

	return [[commandView window] makeKeyAndOrderFront:self];
}
//*****************************************************************************
//
//		show the timer 
//
//*****************************************************************************

- showTimerPanel:sender 
{
    return [theTimer showTimerPanel:self];
}
//*****************************************************************************
//
// 		called by timer in order to pass us appIcon time string 
//
//		also used in determining inactivity timeout (since this is called
//		once per minute during ppp sessions).
//
//*****************************************************************************

- showMenuTimer:(char *)buffer 
{
	if(appIconTime)
		[timeCell setStringValue:buffer];
	[timeField setStringValue:buffer];
	[theIconView setImage:onImage];
	[self pppstats];

	return self; 
}
//*****************************************************************************
//
// 		enable/disable display of online time in app icon 
//
//*****************************************************************************

- setAppIconTimer:(BOOL)onOff 
{
	appIconTime = onOff;

	return self; 
}
//*****************************************************************************
//
// 		return a pointer to the document list delegate 
//
//*****************************************************************************

- docLDelegate 
{
	return docLDelegate; 
}
//*****************************************************************************
//
//		returns whether a Gate doc may be opened or edited by real user
//
//*****************************************************************************

- readable:(const char *)nameOfFile
{
FILE *fp;

	if ((fp = fopen(nameOfFile, "r+")) == NULL)
		[self showAlert:"Unable to open Gate doc"];
	else
		{
		if(readable(fileno(fp)))
			{
			fclose(fp);
  			return self;				// we have permission
			}
		[self showAlert:"Access to Gate doc denied"];
		fclose(fp);
		}

   	return nil;						// we do not have permission
}
//*****************************************************************************
//
// 		returns the Gate doc options editor
//
//*****************************************************************************

- optionsEditor
{
	if(!theOptionsEditor)
		theOptionsEditor = [[OptionsEditor alloc] init];

    return theOptionsEditor;
}
//*****************************************************************************
//
// 		returns the state of the debug flag in an options file
//
//*****************************************************************************

- (BOOL)debugFlag:(const char *)optionFile
{
  	return [[[self optionsEditor] parseOptions:optionFile] debug];
}
//*****************************************************************************
//
// 			show the Tool Bar
//
//*****************************************************************************

- toolBar:sender
{
	if(!NXWriteDefault([NXApp appName], DISPLAYT, "YES"))
		[self showAlert:"ddbWriteError"];
	if(!toolBar) 
		[NXApp loadNibSection:"ToolBar.nib" owner:self withNames:NO];
	[toolBar makeKeyAndOrderFront:self];

    return toolBar;
}
//*****************************************************************************
//
// 		return the app icons view
//
//*****************************************************************************
 
- appIconView
{
	return 	theIconView;					
}
//*****************************************************************************
//
// 		return commandview 
//
//*****************************************************************************

- commandView 
{
	return commandView; 
}
//*****************************************************************************
//
// 		called by Dial server when remote manual Dial Tool's ports are 
//		invalidated
//
//*****************************************************************************
 
- DOFinished
{
	[self setPhase:0];
	[self stopDaemon:self];			// restart the daemon
	manDial = NO;

    return self;
}
//*****************************************************************************
//
// 	free simply gets rid of everything we created
// 	This is how nice objects clean up.
//
//*****************************************************************************

- free
{
	[timeCell free];
	if(onImage)
		[onImage free];
	if(toolBar) 
		[toolBar free];
	if(iTimer) 
		[iTimer free];

    return [super free];
}
//*****************************************************************************
//
// 		search /etc/syslog.conf to find the location of the named pipe used 
//		in recieving the output from pppd/syslog 
//
//*****************************************************************************

- (const char *)logFile
{
static char del1[] = {". =:|\t\r\n"}, del2[] = {" \t\r\n"};
static char *logFile = NULL;							// ppp log file path 

	if(logFile)									
		free(logFile);
	if(!Parser)									
		Parser = [[EParse alloc] init];			// create parser to find port
	[[Parser setKey1:"local2"] setKey2:"debug"];		// set search pattern  
	[[Parser setDelim1:del1] setDelim2:del2];			// and delimiters

	if(!(logFile = [Parser parseFile:"/etc/syslog.conf"]))
		[self showAlert:"Error parsing syslog.conf for ppp log file name."];

    return logFile;
}
//*****************************************************************************
//
// 		checks the mail queue for mail awaiting delivery 
//
//*****************************************************************************

- (BOOL)mailInQueue 
{
int	eCntr = 0;
struct direct *dirp;
DIR *dp;
BOOL mail = NO;

    if ((dp = opendir("/usr/spool/mqueue")) != NULL)
		{
		while ((dirp = readdir(dp)) && eCntr < 3) 	// read dir and cnt entries
			{
			if(*dirp->d_name != '.')				// don't count if sys file
				eCntr++;
			}
		if(eCntr > 2)
			mail = YES;
		closedir(dp);
		}
	else
		[self showAlert:"Error opening Mail queue directory"];

	return mail;
}
//*****************************************************************************
//
// 		search app wrapper and load bundles of the specified type 
//
//*****************************************************************************

- loadBundlesOfType:(const char *)bundleType owner:o nib:(BOOL)loadNib
{
struct direct *dirp;
DIR *dp = NULL;
char *ptr, *p;

    if ((DIR *)(dp = opendir([[NXBundle mainBundle] directory])) != NULL)
		{										// open DIR stream
		while (dirp = readdir(dp)) 				// read dir and find all
			{									// entries with ext .bundle
			if(dirp->d_namlen > strlen(bundleType))
				{								
				ptr = dirp->d_name;
													// str end - strlen of ext
				ptr += (dirp->d_namlen - strlen(bundleType));							
				if(strcmp(ptr, bundleType) == 0)	// if extension is of type
					{
					p = ptr = NXCopyStringBuffer(dirp->d_name);
													// str end - strlen of ext
					ptr += (dirp->d_namlen - strlen(bundleType) - 1);	
					*ptr = '\0';
					[self loadBundle:p ofType:bundleType owner:o nib:loadNib];
					free(p);
					}
				}
			};
		closedir(dp);
		}
	else
		[[NXApp delegate] showAlert:"Error opening mainbundle directory."];

	return self;							
}
//*****************************************************************************
//
// 		load a bundle of the specified type  
//
//*****************************************************************************

- loadBundle:(const char *)p ofType:(const char *)bType owner:o nib:(BOOL)lNib
{
NXBundle *myBundle = nil;

	if(![[NXBundle mainBundle] getPath:Path forResource:p ofType:bType])
		NXRunAlertPanel(0,"Error getting bundle path",0, 0, 0);
	else
		{
		if(myBundle = [[NXBundle alloc] initForDirectory:Path])
			{
			[myBundle principalClass];
			if(lNib)									// should we load a nib
				{
				if(![myBundle getPath:Path forResource:p ofType:"nib"])
					{
					NXRunAlertPanel(0,"Error getting nib path",0,0,0);
					NXRunAlertPanel(0, Path,0,0,0);
					}
				else
					[NXApp loadNibFile:Path owner:o withNames:YES 
													 fromZone:[self zone]];
				}
			}
		}

	return self;							
}
//*****************************************************************************
//
// 		enable pppstats, if aView is nil open w/o a view for stats only
//
//*****************************************************************************
 
- pppstats:aView
{
											// display pppstats?
	if(strcmp(NXGetDefaultValue([NXApp appName], "DispPPP"),"YES") == 0)
		{
		openSocket(aView);		// open IP datagram socket, pass a view
		intpr();
		pppstats = YES;
		}
	else
		pppstats = NO;	

	return self;
}
//*****************************************************************************
//
// 		poll pppstats
//
//*****************************************************************************
 
- pppstats
{
struct pppIO *pppStat;

	if(pppstats)
		pppStat = intpr();
		
	return self;
}
//*****************************************************************************
//
// 		load the specified LKS into the kernel 
//
//*****************************************************************************

- loadKernelServer:(char *)lks  
{
kern_return_t r;
port_name_t kl_port;
task_t kernel_task;

	strncpy(BPath,[[NXBundle mainBundle] directory],MAXPATHLEN -strlen(BPath));
	strncat(BPath, "/", MAXPATHLEN - strlen(BPath));
	strncat(BPath, lks, MAXPATHLEN - strlen(BPath));

    if ((r = kern_loader_look_up(&kl_port)) != KERN_SUCCESS)
        fprintf(stderr, "GateKeeper: can't find kernel loader %d\n", r);
												// Get the kernel's task port. 
	if ((r = task_by_unix_pid(task_self(), 0, &kernel_task)) != KERN_SUCCESS) 
        fprintf(stderr, "GateKeeper: get kernel_task %d\n", r);
    if ((r = kern_loader_add_server(kl_port,kernel_task,BPath))!= KERN_SUCCESS) 
		{
        fprintf(stderr, "GateKeeper: couldn't allocate kernel server %d\n", r);
        fprintf(stderr, "server: %s\n", BPath);
    	}
    if ((r = kern_loader_load_server(kl_port, lks)) != KERN_SUCCESS) 
		{
        fprintf(stderr, "GateKeeper: couldn't load kernel server %d\n", r);
        fprintf(stderr, "server: %s\n", BPath);
   		}

    return self;
}
//*****************************************************************************
//
//		plays sound
//
//*****************************************************************************

- playSound:(const char *)soundFile
{
id aSound;

	if(strcmp(NXGetDefaultValue([NXApp appName], SOUND), "YES") == 0)
		{ 
		aSound = [Sound findSoundFor:soundFile];
		if(aSound)
			[[aSound setDelegate:self] play:nil];
		}

   	return self;						
}
//*****************************************************************************
//
//	Sound delegate method
//
// 		Sent to the delegate when the Sound stops playing.
//
//*****************************************************************************

- didPlay:sender 
{
   	return self;						
}
//*****************************************************************************
//
// 		Idle Panel countdown is complete.
//
//*****************************************************************************

- idleFinished 
{
	[iTimer cleanUp];
	[NXApp delayedFree:iTimer];

   	return self;						
}
//*****************************************************************************
//
//	Diagnostics Window delegate methods
//
// 		called whenever the user minituriazes our Diagnostics window.
// 		called whenever the user closes our Diagnostics window.
//
//*****************************************************************************

- windowWillMiniaturize:sender toMiniwindow:miniwindow 
{
    return [sender setMiniwindowIcon:"miniWinIcon"];
}

- windowWillClose:sender  
{
	if(![sender isKindOf:[Panel class]])	// simple test to see if diag
		{									// win is what is being closed
		if(!NXWriteDefault([NXApp appName], DISPLAYD, "NO"))
			[self showAlert:"ddbWriteError"];
		}

    return self;
}

@end

