This is Coordinator.m in view mode; [Download] [Up]
//*****************************************************************************
//
// Coordinator.m
//
// NXApp delegate, central control object for GateKeeper
//
// by Felipe A. Rodriguez
//
// The base for this file was:
//
// Coordinator.m
// by Joe Freeman, David LaVallee
// Subprocess Example, Release 2.0
// NeXT Computer, Inc.
//
// 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 "GKdefs.h"
#import "Animator.h"
#import "Parse.h"
#import "OptionsEditor.h"
#import "options.h"
#import "IconView.h"
#import "ToolBar.h"
#import "DOserver.h"
#import "Timer.h"
#import "InactivityTimer.h"
#import "Coordinator.h"
#import "CommandScroll.h"
#import "Subprocess.h"
#import "GateDocEditor.h"
#import "HLRecord.h"
#import "HLDelegate.h"
#import <appkit/nextstd.h>
#import <appkit/Application.h>
#import <dpsclient/dpsNeXT.h>
#import <objc/NXStringTable.h>
#import <defaults/defaults.h>
#import <bsd/c.h>
#import <sys/dir.h> /* POSIX applications #include <dirent.h> */
@interface Coordinator(Private)
// preferences controls
extern char *cList[];
extern char *rfList[];
extern char *rsList[];
// private functions
- miscPrep2;
// dial on demand server
#import <mach/mach_error.h>
#import <servers/netname.h>
#import "nsRPC_types.h"
any_t server_loop(any_t port);
// defined by MiG:
boolean_t nsRPC_server(msg_header_t *in, msg_header_t *out);
// from Request types in nsRPCUser.c
struct message
{
msg_header_t head; /* standard header field */
msg_type_t arg1_type; /* first arg type */
int arg1; /* first arg */
msg_type_t arg2_type; /* second arg type */
int arg2; /* second arg */
};
@end
@implementation Coordinator(Private)
//*****************************************************************************
//
// misc to do before coordinator starts a subprocess
//
//*****************************************************************************
- miscPrep2
{
int i = 0;
[[theAnimator startAnimTimer] setStandbyGate:NO];
[linkMenuButton setEnabled:NO]; // disable link button
[dial setEnabled:NO]; // disable dial button
[theOpenButton setEnabled:NO]; // disable the open doc button
while(i < 3)
{ // erase captured str's array
if(capturedStr[i])
free(capturedStr[i]);
capturedStr[i++] = NULL; // blank, for next invocation
}
linkStg = 0; // prevent stages in link process from getting called twice
// setup and load our keyword's hashtable
if(strHashTable)
free(strHashTable);
strHashTable = [[HashTable alloc] initKeyDesc:"*" valueDesc:"i"];
for(i = 0; i < 2; i++)
{
numEntries[i] = i;
[strHashTable insertKey:NXGetDefaultValue([NXApp appName], cList[i+1])
value:&numEntries[i]];
}
for(i = 0; i < 4; i++)
{
numEntries[i + 2] = i + 2;
[strHashTable insertKey:NXGetDefaultValue([NXApp appName], rfList[i])
value:&numEntries[i + 2]];
}
numEntries[6] = 6;
[strHashTable insertKey:"address" value:&numEntries[6]];
numEntries[7] = 7;
[strHashTable insertKey:"remote" value:&numEntries[7]];
return self;
}
@end
@implementation Coordinator
//************************ Subprocess Delegation ****************************** //*****************************************************************************
//
// recieves output from subprocess
// canonicalizes output stream into lines
//
//*****************************************************************************
- subprocessOutput:(char *)buffer
{
static char strbuf[132];
static int strpos = 0;
while(*buffer)
{ // cr/lf delimit lines and we do not exceed strbuf size
if((*buffer != '\n' && *buffer != '\r') && strpos < 128)
{
strbuf[strpos++] = *buffer++;
strbuf[strpos] = '\0';
}
else
{
while((*buffer == '\n' || *buffer == '\r') && (strpos < 130))
strbuf[strpos++] = *buffer++;
strbuf[strpos] = '\0';
[self analyzeBuffer:strbuf];
strpos = 0;
}
}
return self;
}
//*****************************************************************************
//
// - captures certain keywords as status and info markers
// - calls gotIt, displayLinkStatus methods when link is established
// - sends data stream to diagnostics window and comments to status
//
//*****************************************************************************
- analyzeBuffer:(char *)buffer
{
char *str, delim[] = {" \n\r^/"}, delim2[] = {"\n\r^"}, *argString = NULL;
int *cntr;
if(argString != NULL)
free(argString);
argString = NXCopyStringBuffer(buffer);
[commandView appendString:buffer]; // send buffer to diag win
str = strtok(argString, delim); // Parse string and test it
while(str != NULL)
{
if(*str == '#') // comments will be displayed in status panel
{
if(str = strtok(NULL, delim2))
{
if(strlen(str) > 3)
[statusView setStringValue:[self localString:str]];
}
}
else
{
if ([strHashTable isKey:str] == YES) // if str is in hash table
{ // we have caught a keyword
cntr = [strHashTable valueForKey:str];
switch(*cntr)
{
case 2: // redial?
case 3: // Persistent connect
case 4: // Fail connect
case 5: // LCP terminate
if((strcmp(NXGetDefaultValue([NXApp appName],
rsList[*cntr - 2]),"YES") == 0) // sw "ON"?
&& (lastCall[0] != '\0'))
[self perform:@selector(redial:) with:self
afterDelay:backOffDelay cancelPrevious:YES];
else
[self UnLink:nil]; // if redial off, unlink
break;
case 0: // baud str caught
if((str = strtok(NULL, delim)) &&
(capturedStr[0] == NULL))
[self connectedAt:str];
break;
case 1: // the link is up
if(linkStg < 4) // if ivar is >, ppp
{
[self gotIt]; // may be sending
linkStg = 4; // keyword twice
}
break;
case 6: // local address str caught
if((str = strtok(NULL, delim)) && (linkStg < 5))
{
capturedStr[1] = NXCopyStringBuffer(str);
linkStg = 5;
}
break;
case 7: // display addresses
if(linkStg < 6)
{
if((str = strtok(NULL, delim)) != NULL)
{
if((str = strtok(NULL, delim)) != NULL)
{
if((str = strtok(NULL, delim)) != NULL)
{
capturedStr[2] =
NXCopyStringBuffer(str);
[self displayLinkStatus];
}
}
}
}
break;
default:
break;
}
}
}
str = strtok(NULL, delim);
}
return self;
}
//************************************************************************
//
// Called when subprocess has terminated
//
//************************************************************************
- subprocessDone
{
[theTimer stopTimer];
if(theGateServer)
[theGateServer free];
theGateServer = nil;
[theSubprocess free];
theSubprocess = nil;
if(userWantsTermination) // end only if user chose too (not subP fail)
[NXApp terminate:self];
else // if not exiting
[theAnimator startAnimTimer]; // cycle thru animation
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;
}
//*****************************************************************************
//
// Called when link is established
//
//*****************************************************************************
- gotIt
{
[theAnimator removeTimedEntry];
// ppp is up, play snd for me
if(strcmp(NXGetDefaultValue([NXApp appName],"sound"), "YES") == 0)
[[[Sound findSoundFor: "majestic"] play: nil] free];
[theTimer Fire:self];
if(!onImage)
onImage = [NXImage findImageNamed:"g4"];
[theIconView setImage:onImage];
[statusView setStringValue:[self localString:"pppup"]];
// if auto hide switch is set wait 5 sec before hiding
if(strcmp(NXGetDefaultValue([NXApp appName], "autoHide"),"YES") == 0)
[NXApp perform:@selector(hide:) with:self afterDelay:5000
cancelPrevious:NO];
return self;
}
//*****************************************************************************
//
// registers connection speed
//
//*****************************************************************************
- connectedAt:(const char *)speed
{
strncpy(Path, [stringTable valueForStringKey:"connectAt"], MAXPATHLEN);
strncat(Path, speed, MAXPATHLEN - strlen(Path));
capturedStr[0] = NXCopyStringBuffer(Path);
[connectionSpeedField setStringValue:capturedStr[0]];
return self;
}
//*****************************************************************************
//
// displays captured info regarding current ppp session
//
//*****************************************************************************
- displayLinkStatus
{
if(capturedStr[0] != NULL) // in case we man dialed
{ // we will not know connect speed
[commandView appendString:"\n#################################\n"];
[commandView appendString:"####\n"];
[commandView appendString:"#### "];
[commandView appendString:capturedStr[0]];
}
else
[commandView appendString:"\n#################################"];
[commandView appendString:"\n####\n"];
[commandView appendString:[stringTable valueForStringKey:"localIP"]];
[commandView appendString:capturedStr[1]];
[localIPField setStringValue:capturedStr[1]];
[commandView appendString:"\n####\n"];
[commandView appendString:[stringTable valueForStringKey:"remoteIP"]];
[commandView appendString:capturedStr[2]];
[commandView appendString:"\n####"];
[remoteIPField setStringValue:capturedStr[2]];
[commandView appendString:"\n#################################\n"];
linkStg = 6; // ppp link is up, set ivar
[iTimer pppstats:commandView]; // run pppstats w/view
return self;
}
//*********************** Application Object Delegation ***********************
//*****************************************************************************
//
// setup defaults data base cache before app is init'd
//
//*****************************************************************************
- appWillInit:sender
{
static NXDefaultsVector myDefaults = { // setup defaults database
{DISPLAYD, "YES"}, // display diagnostics window
{DISPLAYS, "YES"}, // display status window
{"autoLaunch", "NO"},
{"autoHide", "YES"}, // auto hide upon link
{"autoRedial", "YES"},
{"PersistCon", "YES"},
{"FailRedial", "YES"}, // redial if a Fail occurs
{"LCPterminate", "YES"}, // redial if lcp termination occurs
{"Fail", "Exit."},
{"reDial", "Failed"},
{"Persist", "down"}, // persistent connect trigger
{"LCPterm", "terminated."}, // lcp termination trigger
{"DispPPP", "YES"}, // display pppstats
{DISPLAYT, "YES"}, // display toolbar
{"DoD", "NO"}, // dial on demand
{USEFIFO, "YES"}, // use a FIFO for IPC w/pppd?
{"sound", "YES"}, // play sound
{AITIMER, "YES"}, // icon displayed online time
{REDBOFF, "YES"}, // backoff on failed redials?
{"iTimeout", "Off"}, // inactivity unlink's us
{"preTimeout", "YES"}, // inactivity unlink's us
{"iTimeThreshold", "0"}, // inactivity threshold
{SELCELL, "0"}, // cell selected in hotList
{BROWSERHT, "999.0"}, // ht of browser in hotList
{ADDRESSHT, "999.0"}, // ht of address in hotList
{FIRSTTIME, "YES"}, // first time thru?
{"options", "/etc/ppp/options"},
{"ip-down", "/etc/ppp/ip-down"},
{"ip-up", "/etc/ppp/ip-up"},
{"resolv", "/etc/resolv.conf"},
{"syslog", "/etc/syslog.conf"},
{"messages", "/usr/adm/messages"},
{"rc", "/etc/rc.local"},
{"remote", "/etc/remote"},
{"locFIFO", "/usr/adm/GateKeeper.fifo"}, // pref form start
{"comLine", "/usr/local/bin/pppd -detach"},
{HLLIST, "/"},
{"BaudStr", "CARRIER"}, // pref form end
{"LinkUp", "local"}, // Link is up trigger
{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
{"path", "/"}, // path for .Gate documents
{"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
{
time_t waitTime; // time to delay
time(<ime); // Get time and place in time_t
if(strcmp(NXGetDefaultValue([NXApp appName], USEFIFO), "YES") == 0)
[self syslogdReset]; // reset the syslogd daemon
// setup appIcon for animation
theAnimator = [[Animator alloc] init]; // get appIcon window
theIconView = [theAnimator iconView];
timeCell = [theIconView getTextCell]; // return the iconView's textCell
if(strcmp(NXGetDefaultValue([NXApp appName], FIRSTTIME),"YES") == 0)
{ // if first time this version was launched
[self showInfo:self];
if(!NXWriteDefault([NXApp appName], FIRSTTIME, "NO"))
NXRunAlertPanel(0,
[stringTable valueForStringKey:"ddbWriteError"],
[stringTable valueForStringKey:"OK"],
NULL,
NULL);
}
[NXApp loadNibSection:"StatusWindow.nib" owner:self withNames:NO];
if(strcmp("YES", NXGetDefaultValue([NXApp appName], DISPLAYS)) == 0)
[statusWin makeKeyAndOrderFront:self]; // show status panel
[NXApp loadNibSection:"DiagWindow.nib" owner:self withNames:NO];
[diagWin setFrameUsingName:[diagWin title]]; // remem sz,loc
[diagWin setFrameAutosaveName:[diagWin title]];
if(strcmp("YES", NXGetDefaultValue([NXApp appName], DISPLAYT)) == 0)
[self toolBar:self]; // show toolbar if set
if(strcmp("YES", NXGetDefaultValue([NXApp appName], AITIMER)) == 0)
appIconTime = YES; // show online time in app icon
if(strcmp("YES", NXGetDefaultValue([NXApp appName], REDBOFF)) == 0)
backOffDefault = backOffDelay = BDEF; // redial delay backoff on
// setup Inactivity timeout and pppstats controller
iTimer = [[InactivityTimer allocFromZone:[self zone]] init];
if(strcmp(NXGetDefaultValue([NXApp appName],"NXAutoLaunch"),"YES") == 0)
{ // if app was dock autoLaunched
waitTime = ltime + 2; // delay for X sec so that syslogd can sync
while(ltime < waitTime) // ltime ivar is set in syslogReset method
{time(<ime);}
}
theTimer = [[Timer allocFromZone:[self zone]] init];
// If we weren't asked to open any documents at launch time, then
// we were launched by double clicking on the application instead
// of a document. If so check whether we should auto-launch w/def's
if(!NXGetDefaultValue([NXApp appName], "NXOpen") &&
!NXGetDefaultValue([NXApp appName], "NXOpenTemp") &&
!NXGetDefaultValue([NXApp appName], "NXServiceLaunch"))
{
if(strcmp(NXGetDefaultValue([NXApp appName], "autoLaunch"),"YES") == 0)
[self Link:self];
}
[self DialOnDemand]; // prepare for dial on demand if set
return self;
}
//*****************************************************************************
//
// redial
//
//*****************************************************************************
- redial:sender
{ // only allow a redial if user has not stopped linking
if((strcmp([[[NXApp mainMenu] findCellWithTag:2] title],
[[NXApp delegate] localString:"Disconnect"]) == 0) &&
[[[NXApp mainMenu] findCellWithTag:2] isEnabled] && (sender))
{
[self UnLink:nil];
if([self runScript:"preLink"])
{ // back off in multiples of 2
backOffDelay *= 2;
[self perform:@selector(resetDelay:) with:self
afterDelay:(backOffDelay + 1000) cancelPrevious:YES];
[self linkWithFile:lastCall];
}
}
return self;
}
//*****************************************************************************
//
// reset the backoff delay
//
//*****************************************************************************
- resetDelay:sender
{ // eliminate any pending redials
[self perform:@selector(redial:) with:nil afterDelay:0 cancelPrevious:YES];
if ([sender isKindOf:[Matrix class]])
{
if((BOOL)[[sender selectedCell] intValue])
backOffDefault = BDEF; // redial delay backoff on
else
backOffDefault = 0;
}
backOffDelay = backOffDefault;
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
{
char commandLine[MAXPATHLEN + 1];
[self miscPrep2]; // misc initialization's
if(strcmp(NXGetDefaultValue([NXApp appName], DISPLAYD),"YES") == 0)
[diagWin makeKeyAndOrderFront:self]; // show diagnostics win
strncpy(commandLine, NXGetDefaultValue([NXApp appName], "comLine"),
MAXPATHLEN);
commandLine[MAXPATHLEN-1] = 0;
if(path == NULL)
{
lastCall[0] = '\0';
if([hotListDelegate selGateDocOptionsPath] == NULL)
commandLine[0] = '\0';
else // if hotlist points to valid
{
strncat(commandLine, " file ", MAXPATHLEN - strlen(commandLine));
strncat(commandLine, [hotListDelegate selGateDocOptionsPath],
MAXPATHLEN - strlen(commandLine));
strncpy(BPath,[hotListDelegate selGateDocOptionsPath], MAXPATHLEN);
[providerField setStringValue:[self localString:"manDial"]];
}
}
else
{
strcpy(lastCall, path); // stores path of last invocation
if(strstr(path, "GateKeeper.app") == NULL)
[providerField setStringValue:[self extractName:path]];
else
[providerField setStringValue:[self localString:"gkDefault"]];
[statusView setStringValue:[self localString:"connecting"]];
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
{
[linkMenuButton setEnabled:YES]; // enable unlink button
[linkMenuButton setTitle:[self localString:"Disconnect"]];
[linkMenuButton setAction:@selector(UnLink:)];
[statusButton setTitle:[self localString:"Disconnect"]];
[statusButton setAction:@selector(UnLink:)];
if([iTimer posNonInter])
[commandView appendString:
"Dial on demand triggered ppp session\n"];
if([self debugFlag:BPath])
{ // if debug sw set in options disg commandline
[commandView appendString:commandLine];
[commandView appendString:"\n\r"];
}
theSubprocess = [[Subprocess alloc] init:commandLine withDelegate:self
andStdErr:YES];
}
return self;
}
//*****************************************************************************
//
// Use terminal to do a manual link
//
//*****************************************************************************
- Dial:sender
{
if((strcmp([linkMenuButton title], [self localString:"Connect"]) == 0) &&
[linkMenuButton isEnabled] && [self runScript:"preLink"])
{
[self miscPrep2]; // misc initialization's
[iTimer setPosNonInter:NO]; // user interactive session
if(!theGateServer) // create distributed Obj server
theGateServer = [[DOserver alloc] init];
[theGateServer setDelegate:self];
GateConnection = [NXConnection registerRoot: theGateServer
withName:"GateKeeperServer"]; // DO name of server
[GateConnection runFromAppKit]; // listen for DO messages from appKit
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 link is pressed, when DNS triggers us.
// Calls app:sender
//
//*****************************************************************************
- Link:sender
{
if((strcmp([linkMenuButton title], [self localString:"Connect"]) == 0) &&
[linkMenuButton isEnabled] && [self runScript:"preLink"])
{
if(!sender) // DNS triggered session,
[iTimer setPosNonInter:YES]; // possibly non-interactive
else
[iTimer setPosNonInter:NO]; // user interactive session
[hotListDelegate playLink]; // selected in the HotList to launch pppd
}
return self;
}
//*****************************************************************************
//
// Called when menu item Unlink is pressed.
//
//*****************************************************************************
- UnLink:sender
{
if([self runScript:"preUnLink"])
{
if(theSubprocess && [theSubprocess respondsTo:@selector(terminate:)])
[theSubprocess terminate:sender];
[[theAnimator setOpenGate:YES] setStandbyGate:YES];
[iTimer pppstatsReset]; // disable pppstats
[timeCell setStringValue:" "];
[linkMenuButton setEnabled:YES]; // enable unlink button
[linkMenuButton setTitle:[self localString:"Connect"]];
[linkMenuButton setAction:@selector(Link:)];
[statusButton setTitle:[self localString:"Connect"]];
[statusButton setAction:@selector(Link:)];
[theOpenButton setEnabled:YES]; // enable the open doc button
[dial setEnabled:YES]; // enable dial button
[statusView setStringValue:[self localString:"pppdn"]];
[connectionSpeedField setStringValue:" "];
[timeField setStringValue:" "];
[providerField setStringValue:" "];
[localIPField setStringValue:" "];
[remoteIPField setStringValue:" "];
[self namedDod]; // kill/restart named to dump cache
}
if(sender)
[self resetDelay:self];
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 allowed only if the user has selected it, subprocess
// failure should not cause GateKeeper to terminate
//
//****************************************************************************
- terminate:sender
{
userWantsTermination = YES;
return self;
}
//****************************************************************************
//
// termination is imminent
//
//****************************************************************************
- appWillTerminate:sender
{
[theSubprocess terminate:sender];
[theAnimator removeTimedEntry];
[self namedReset:"/usr/etc/named"]; // replace our named with system's
[hotListDelegate appWillTerminate];
return self;
}
//*****************************************************************************
//
// show the info panel
//
//*****************************************************************************
- showInfo:sender
{
if(!infoPanel)
[NXApp loadNibSection:"InfoPanel.nib" owner:self withNames:NO];
[infoPanel center];
[infoPanel makeKeyAndOrderFront:self];
return self;
}
//****************************************************************************
//
// show preferences panel
//
//****************************************************************************
- preferences:sender
{
if(!prefPanel)
[NXApp loadNibSection:"Preferences.nib" owner:self withNames:NO];
[prefPanel 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 [statusWin makeKeyAndOrderFront:self];
}
//*****************************************************************************
//
// display the Diagnostics window
//
//*****************************************************************************
- showDiagWin:sender
{
if(!NXWriteDefault([NXApp appName], DISPLAYD, "YES"))
[self showAlert:"ddbWriteError"];
return [diagWin 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];
[iTimer inactivityTimeout];
return self;
}
//*****************************************************************************
//
// set inactivity timer's timeout Ivar and write its value to ddb
//
//*****************************************************************************
- setTimeout:(int)minTillTimeout
{
[iTimer setTimeout:minTillTimeout];
return self;
}
//*****************************************************************************
//
// enable/disable display of online time in app icon
//
//*****************************************************************************
- setAppIconTimer:(BOOL)onOff
{
appIconTime = onOff;
return self;
}
//*****************************************************************************
//
// return a pointer to the hotlist window's delegate
//
//*****************************************************************************
- hotListDelegate
{
return hotListDelegate;
}
//*****************************************************************************
//
// tell browser to update its data from its delegate
//
//*****************************************************************************
- updateBrowser:sender
{
return [hotListDelegate loadBrowser];
}
//************************************************************************
//
// extracts the Gate doc name from its path
//
//************************************************************************
- (const char *)extractName:(const char *)aPath
{
char *ptr;
strcpy(Path, aPath);
ptr = Path + strlen(Path) - 1;
while(*ptr != '.' && *ptr)
ptr--;
*ptr-- = '\0';
while(*ptr != '/' && *ptr)
ptr--;
++ptr;
return ptr;
}
//************************************************************************
//
// 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; // enable link button
}
//************************************************************************
//
// called by DO server when remote manual Dial Tool's ports are
// invalidated
//
//************************************************************************
- DOFinished
{
return [self UnLink:self]; // enable link button
}
//************************************************************************
//
// 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];
}
//*****************************************************************************
//
// Attempt to reset syslogd daemon. Failing that, try starting it.
//
//*****************************************************************************
- syslogdReset
{
FILE *ff;
int pid, fd;
if((ff = fopen( "/etc/syslog.pid", "r")) != NULL)
{
if( fscanf( ff, "%d", &pid) < 1)
perror("Unable to read pid from etc/syslog.pid\n");
else
{
if( kill( pid, SIGHUP) != -1) // tell syslogd to reconfigure
{
fclose( ff);
// open FIFO so that syslogd is not blocked
if((fd=open(NXGetDefaultValue([NXApp appName], "locFIFO"),O_RDONLY))<0)
{
perror("Error opening FIFO\n");
return self;
}
sleep(1);
close(fd);
return self; // report success
}
else // if app was not dock autoLaunched
if(strcmp(NXGetDefaultValue(
[NXApp appName],"NXAutoLaunch"),"NO") == 0)
perror("error reconfiguring syslogd");
}
}
else
perror("Unable to open /etc/syslog.pid\n");
return [self syslogdRun]; // failed to reconfig so restart syslogd
}
//*****************************************************************************
//
// Terminante and then run the syslogd daemon
//
//*****************************************************************************
- syslogdRun
{
FILE *ff;
int pid, fd;
if((ff = fopen( "/etc/syslog.pid", "r")) != NULL)
{
if( fscanf( ff, "%d", &pid) < 1)
perror("Unable to read pid from etc/syslog.pid\n");
else
if( kill( pid, SIGTERM) == -1)
{
if(strcmp(NXGetDefaultValue(
[NXApp appName],"NXAutoLaunch"),"NO") == 0)
perror("error killing syslogd");
}
}
switch (pid = vfork()) // create new process
{
case -1: // error
perror("Error during vfork syslogdReset.");
return self;
case 0: // child -- Vfork returns 0 in the child's context
execl("/usr/etc/syslogd", "syslogd", 0);
perror("vfork error restarting syslogd");
exit(1);
default: // parent -- vfork returns pid of the child
break;
}
// open FIFO so that syslogd is not blocked
if((fd=open(NXGetDefaultValue([NXApp appName], "locFIFO"),O_RDONLY))<0)
{
perror("Error opening FIFO\n");
return self;
}
sleep(1);
close(fd);
return self;
}
//*****************************************************************************
//
// prepare ourself to be triggered by named when dial on demand is
// necessary
//
//*****************************************************************************
- DialOnDemand
{
port_t server_port;
kern_return_t r;
// if dial on demand is "ON"
if(strcmp("YES", NXGetDefaultValue([NXApp appName], "DoD")) == 0)
{
// allocate a port for this task, ret in arg 2
r = port_allocate(task_self(), &server_port);
if (r != KERN_SUCCESS)
{
mach_error("port_allocate failed", r);
exit(1);
} // Register with the Network Name Server.
r = netname_check_in(name_server_port, GK_DNS_SERVER, PORT_NULL,
server_port);
if (r != KERN_SUCCESS)
{
mach_error("netname_check_in failed", r);
exit(1);
}
// create dial on demand server thread and detach it
cthread_detach(cthread_fork((cthread_fn_t)server_loop,
(any_t)server_port));
[self namedDod]; // replace named with dial on demand trigger named
}
return self;
}
//*****************************************************************************
//
// Attempt to kill and restart named daemon. Resets RR's cache.
//
//*****************************************************************************
- namedReset:(const char *)buffer
{
FILE *ff;
int pid;
// if dial on demand is "ON"
if(strcmp("YES", NXGetDefaultValue([NXApp appName], "DoD")) == 0)
{
if((ff = fopen( "/etc/named.pid", "r")) != NULL)
{
if( fscanf( ff, "%d", &pid) < 1)
perror("Unable to read pid from etc/named.pid\n");
else
{
if( kill( pid, SIGTERM) == -1) // kill named
perror("error killing named");
}
}
else
perror("Unable to open /etc/named.pid\n");
fclose( ff);
system(buffer); // start GateKeeper named
}
return self;
}
//*****************************************************************************
//
// replace the system named with our own which will inform us when a
// dial on demand is necessary
//
//*****************************************************************************
- namedDod
{
if(!strcpy(Path, [[NXBundle mainBundle] directory])) // app's home dir
[self showAlert:"Error getting mainbundle path"];
else
{
strcat(Path,"/named");
[self namedReset:Path]; // kill named and replace with our own
}
return self;
}
//*****************************************************************************
//
// search /etc/syslog.conf to find the location of the named pipe used
// in recieving the output from pppd/syslog
//
//*****************************************************************************
- fifo
{
static char del1[] = {". =:|\t\r\n"}, del2[] = {" \t\r\n"};
char *fifoName = NULL;
if(!Parser)
Parser = [[Parse alloc] init]; // create parser to find port
[[Parser setKey1:"local2"] setKey2:"debug"]; // set search pattern
[[Parser setDelim1:del1] setDelim2:del2]; // and delimiters
if(fifoName = [Parser parseFile:"/etc/syslog.conf"])
{
if(!NXWriteDefault([NXApp appName], "locFIFO", fifoName))
NXRunAlertPanel(0,
[stringTable valueForStringKey:"ddbWriteError"],
[stringTable valueForStringKey:"OK"],
NULL,
NULL);
free(fifoName);
}
else
[self showAlert:"FIFO Path Error"];
return self;
}
//*****************************************************************************
//
// 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;
}
//************** Diagnostics Window delegate methods **************************
//*****************************************************************************
//
// called whenever the user minituriazes our Diagnostics window.
//
//*****************************************************************************
- windowWillMiniaturize:sender toMiniwindow:miniwindow
{
return [sender setMiniwindowIcon:"miniWinIcon"];
}
//*****************************************************************************
//
// called whenever the user closes our Diagnostics window.
//
//*****************************************************************************
- 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
//*****************************************************************************
//
// c thread loop which listens for RPC telling us to link
//
//*****************************************************************************
any_t server_loop(any_t port)
{
struct message msg, reply;
kern_return_t ret;
while (TRUE)
{
/* Receive a request from a client. */
msg.head.msg_local_port = (port_t)port;
msg.head.msg_size = sizeof(struct message);
ret = msg_receive(&msg.head, MSG_OPTION_NONE, 0);
if (ret != RCV_SUCCESS) /* ignore errors */
continue;
/* Feed the request into the server. */
(void)nsRPC_server((msg_header_t *)&msg, (msg_header_t *)&reply);
/* Send a reply to the client. */
reply.head.msg_local_port = (port_t)port;
ret = msg_send(&reply.head, MSG_OPTION_NONE, 0);
if (ret != SEND_SUCCESS) /* ignore errors */
continue;
}
return 0;
}
//*****************************************************************************
//
// This function is called by nsRPC_server, which was created by MiG.
// It is NOT directly called by any client process.
//
//*****************************************************************************
kern_return_t pppUp(port_t server)
{
[[NXApp delegate] Link:nil];
return KERN_SUCCESS;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.