This is ExecMonitor.m in view mode; [Download] [Up]
// -------------------------------------------------------------------------------------
// ExecMonitor
// -------------------------------------------------------------------------------------
// Permission is granted to freely redistribute this source code, and to use fragments
// of this code in your own applications if you find them to be useful. This class,
// along with the source code, come with no warranty of any kind, and the user assumes
// all responsibility for its use.
// -------------------------------------------------------------------------------------
#import <appkit/appkit.h>
#import <libc.h>
#import <stdlib.h>
#import <c.h>
#import <errno.h>
#import <ctype.h>
#import <math.h>
#import <sys/param.h>
#import <sys/types.h>
#import <sys/time.h>
#import <sys/wait.h>
#import <sys/resource.h>
#import "RemoteCommand.h"
#import "userInfo.h"
#import "ExecServer.h"
#import "ExecScrollText.h"
#import "ExecMonitor.h"
// -------------------------------------------------------------------------------------
// misc defines
#define REMOTE_SERVER_CMD "RemoteRunServer"
// -------------------------------------------------------------------------------------
// misc defines
#define X origin.x
#define Y origin.y
#define W size.width
#define H size.height
#define freeString(X) { if (X) { free((char*)X); X = 0; } }
#define freeCopy(T,F) { freeString(T); if (F) T = NXCopyStringBuffer(F); }
#define cpnil (char*)nil
#define exeBtnTITLE "Execute\nCommand"
// -------------------------------------------------------------------------------------
// ExecMonitor list of instances
static id instanceList = (id)nil;
// -------------------------------------------------------------------------------------
// list of cached user passwords
typedef struct userPassword_s {
char *user; // user name
char *password; // password
void *next; // pointer to next user
} userPassword_t;
static userPassword_t *userList = (userPassword_t*)nil;
// -------------------------------------------------------------------------------------
@implementation ExecMonitor
// -------------------------------------------------------------------------------------
// user password
// -------------------------------------------------------------------------------------
/* find user password */
+ (userPassword_t*)_findUserRcd:(const char*)user
{
userPassword_t *u;
for (u = userList; u && strcmp(user, u->user); u = (userPassword_t*)u->next);
return u;
}
/* update user password */
+ (userPassword_t*)_addUser:(const char*)userName password:(const char*)password
{
userPassword_t *u;
if (!XUserVerifyPassword(userName, password)) return (userPassword_t*)nil;
u = (userPassword_t*)malloc(sizeof(userPassword_t));
u->user = NXCopyStringBuffer(userName);
u->password = NXCopyStringBuffer(password?password:"");
u->next = (void*)userList;
userList = u;
return u;
}
/* find user password */
+ (const char*)findUserPassword:(const char*)user
{
userPassword_t *u = [self _findUserRcd:user];
return u? u->password : (char*)nil;
}
/* update user password */
+ updateUser:(const char*)user password:(const char*)password
{
userPassword_t *u = [self _findUserRcd:user];
if (u) { if (strcmp(u->password, password)) freeCopy(u->password, password); }
else [self _addUser:user password:password];
return self;
}
/* update user password */
+ removeUserPassword:(const char*)user
{
userPassword_t *u = userList, *l = (userPassword_t*)nil;
for (;u && strcmp(user,u->user); l = u, u = (userPassword_t*)u->next);
if (u) {
(l? l->next : userList) = u->next;
freeString(u->user);
freeString(u->password);
free(u);
}
return self;
}
// -------------------------------------------------------------------------------------
// object initialization
// -------------------------------------------------------------------------------------
/* new exec monitor */
+ newExecHost:(const char*)host server:(const char*)server
{
self = [[self alloc] init];
if (![self setRemoteHost:host server:server]) {
[self free];
return (id)nil;
}
[self showPanel:self];
return self;
}
/* init */
- init
{
NXRect wFrame;
/* instanceList initialization */
if (!instanceList) instanceList = [[[List alloc] initCount:1] empty];
[instanceList addObject:self];
/* init super */
[super init];
exeUser = (id)nil;
exePassword = (id)nil;
exeWindow = (id)nil;
exeCommandScroll = (id)nil;
/* load nib */
if (![NXApp loadNibSection:"ExecMonitor.nib" owner:self]) {
NXLogError("[ExecMonitor] Could not load nib file 'ExecMonitor.nib'");
[NXApp delayedFree:self];
return self;
}
/* spot-check nib loading */
if (!exeWindow || !exeCommandScroll) {
NXLogError("[ExecMonitor] 'ExecMonitor.nib' did not load properly");
[NXApp delayedFree:self];
return self;
}
/* init vars */
saveFileName = (char*)nil;
useRunServer = YES;
cmdInProcess = NO;
shutDown = NO;
exeRunServer = (id)nil;
/* set user values if specified */
if (exeUser) [exeUser setStringValue:""];
if (exePassword) [exePassword setStringValue:""];
/* init panel */
[exeExecute setTitle:exeBtnTITLE];
[exeCommandScroll clearScrollText];
[exeControlBox setBorderType:NX_NOBORDER];
[exeWindow setDelegate:self];
[exeWindow setFreeWhenClosed:NO];
[exeWindow getFrame:&wFrame];
minWinSize = wFrame.size;
return self;
}
/* free */
- _free:sender { return [self free]; }
- free
{
shutDown = YES;
if (cmdInProcess) { // loop until command has completed
[self exeExecute:(id)nil];
[self perform:@selector(_free:) with:self afterDelay:500 cancelPrevious:YES];
return (id)nil;
}
[exeWindow free];
[instanceList removeObject:self]; // make sure 'self' is removed
return [super free];
}
// -------------------------------------------------------------------------------------
// run arguments
/* set remote host (start server if necessary) */
- setRemoteHost:(const char*)host server:(const char*)server
{
char cmd[MAXPATHLEN + 1], title[256];
/* check for already set */
if (exeRunServer) {
NXLogError("[ExecMonitor] ExecServer is already running");
return (id)nil;
}
/* instantiate ExecServer object */
exeRunServer = (host && *host)? [[ExecServer alloc] init] : (id)nil;
if (!exeRunServer) {
NXLogError("[ExecMonitor] Could not create ExecServer (no host specified)");
return (id)nil;
}
/* set attributes */
[exeRunServer setMainAppPath:XAppPath()];
[exeRunServer setMainAppServerName:[NXApp appServerName] host:[NXApp appServerHost]];
[exeRunServer setRemoteHost:host];
if (server && *server) [exeRunServer setRemoteServerName:server];
sprintf(cmd, "%s/%s", XAppPath(), REMOTE_SERVER_CMD);
if (![exeRunServer setServerCommandName:cmd]) {
NXLogError("[ExecMonitor] Unable to set ExecServer command to %s", cmd);
exeRunServer = (id)nil;
return (id)nil;
}
/* start server */
if (![exeRunServer startServer]) {
NXLogError("[ExecMonitor] Could not connect to RemoteRunServer");
exeRunServer = (id)nil;
return (id)nil;
}
/* set window title */
sprintf(title, "ExecMonitor: %s (%s)",
[exeRunServer remoteHost], [exeRunServer remoteServerName]);
[exeWindow setTitle:title];
return self;
}
/* show ExecMonitor panel */
- showPanel:sender
{
return [exeWindow makeKeyAndOrderFront:(id)nil];
}
// -------------------------------------------------------------------------------------
// command execution
// -------------------------------------------------------------------------------------
/* print messages */
- _printCompletion:(BOOL)isError:(char*)fmt, ...
{
char *h = isError?">>>>>>>>>>":"----------", *t = isError?"<<<<<<<<<<":"----------";
va_list args;
/* message color and header */
if (isError) [exeShellScroll setTextAttributeColor:NX_COLORRED];
else [exeShellScroll setTextAttributeGray:NX_DKGRAY];
[exeShellScroll textPrintf:"\n%s ", h];
/* message */
va_start(args, fmt);
[exeShellScroll textPrintf:fmt args:args];
va_end(args);
/* message trailer and reset gray */
[exeShellScroll textPrintf:" %s\n\n", t];
[exeShellScroll setTextAttributeGray:textGray];
/* return error condition */
return isError? (id)nil : self;
}
/* execute Server command */
- exeExecute:sender
{
int commandLen;
char *cmdStr, *user, *pass;
/* check for no run server */
if (!exeRunServer) { NXBeep(); return (id)nil; }
/* check for "STOP" */
if (cmdInProcess) {
if (!strcmp([exeExecute icon], "Stop")) {
if (useRunServer) [exeRunServer terminateCommand:execId];
else [exeShellScroll terminateCommand];
[exeExecute setIcon:"Kill"];
} else {
if (useRunServer) [exeRunServer killCommand:execId];
else [exeShellScroll killCommand];
}
return self;
}
if (!sender) return (id)nil;
/* exit if shutdown in progress */
if (shutDown) return (id)nil;
/* get user */
user = exeUser? (char*)[exeUser stringValue] : (char*)nil;
if (!user || !*user) user = (char*)[NXApp appUserName];
/* get password (if needed) */
if (!XIsCurrentUser(user)) {
pass = exePassword? (char*)[exePassword stringValue] : "";
if ([exeRunServer needUserPassword:user] && !XUserVerifyPassword(user, pass)) {
[[self class] removeUserPassword:user];
return [self _printCompletion:1:"User password not valid"];
}
[[self class] updateUser:user password:pass];
}
/* setup command */
commandLen = [[exeCommandScroll docView] textLength] + 1;
cmdStr = (char*)malloc(commandLen + 1);
[[exeCommandScroll docView] getSubstring:cmdStr start:0 length:commandLen];
strcat(cmdStr, "\n");
/* print command info */
[exeShellScroll setTextAttributeGray:NX_DKGRAY];
[exeShellScroll textPrintf:"\n---------- Executing Command ----------\n"];
[exeShellScroll textPrintf:"%s", cmdStr];
[exeShellScroll textPrintf: "---------------------------------------\n\n"];
[exeShellScroll setTextAttributeGray:textGray];
/* run command */
if (useRunServer) {
execId = [exeRunServer runCommand:cmdStr
withUser:user:[[self class] findUserPassword:user]
forClient:exeShellScroll
killOnError:YES];
} else {
execId = (execHandle_t)[exeShellScroll runCommand:cmdStr];
}
/* free command */
free(cmdStr);
/* check to see if command actually started running */
if (!execId) return [self _printCompletion:1:"Command failed to start"];
/* change button */
cmdInProcess = YES;
[exeExecute setIconPosition:NX_ICONONLY];
[exeExecute setIcon:"Stop"];
return self;
}
/* call-back from shell command (main thread) */
- commandDidComplete:shellId withError:(int)theError
{
/* check for completion status */
if (!theError) { // successful
[self _printCompletion:0:"completed normally"];
} else {
char *desc = [ExecServer errorDesc:theError];
if (desc) [self _printCompletion:1:"%s",desc];
else [self _printCompletion:1:"Terminated with exit(%d)",theError];
}
/* remove user if password is bad */
if ((theError == RSRV_BADPASSWD) && exeUser) {
[ExecMonitor removeUserPassword:[exeUser stringValue]];
}
/* reset execution button */
[exeExecute setEnabled:YES];
[exeExecute setIconPosition:NX_TITLEONLY];
[exeExecute setTitle:exeBtnTITLE];
cmdInProcess = NO;
execId = (execHandle_t)nil;
return self;
}
// -------------------------------------------------------------------------------------
// Terminal invoke
// -------------------------------------------------------------------------------------
/* invoke command in Terminal window */
+ terminalCommand:(const char*)cmd title:(const char*)title
{
Speaker *speaker;
port_t terminalPort;
/* can't find Terminal */
if (!(terminalPort = NXPortFromName("Terminal", NULL))) return (id)nil;
/* launch Terminal */
[NXApp deactivateSelf];
creat("/tmp/.reallyignorethis.term", 0444);
[[Application workspace] openFile:"/tmp/.reallyignorethis.term"
fromImage:(id)nil at:(NXPoint*)nil inView:(id)nil];
/* run command */
speaker = [NXApp appSpeaker];
[speaker setSendPort: terminalPort];
[speaker selectorRPC:"runCommand:usingShell:inFolder:windowTitle:closeOnExit:"
paramTypes: "cccci", cmd, "", "", title, NO];
return self;
}
// -------------------------------------------------------------------------------------
// outlets
// -------------------------------------------------------------------------------------
- setExeShellScroll:anObject
{
exeShellScroll = [[ExecScrollText newExecScrollText:anObject] clearScrollText];
[exeShellScroll setDelegate:self];
textFont = [[exeShellScroll docView] font];
textGray = [[exeShellScroll docView] textGray];
[exeShellScroll setTab:[textFont getWidthOf:" "] count:10];
[exeShellScroll textPrintf:"\n"]; // this forces the scroll view to initialize
[exeShellScroll clearScrollText];
return self;
}
- setExeCommandScroll:anObject
{
exeCommandScroll = [[ExecScrollText newExecScrollText:anObject] clearScrollText];
return self;
}
// -------------------------------------------------------------------------------------
// first responder methods
// -------------------------------------------------------------------------------------
/* save error handler */
- (BOOL)attemptOverwrite:(const char*)fileName
{
NXLogError("[ExecMonitor] Unable to save %s", fileName);
return NO;
}
/* save contents of text view */
- saveAs:sender
{
char *temp;
id savePanel = [SavePanel new];
/* set up save panel */
[savePanel setTitle:"Save Command Output"];
[savePanel setPrompt:"File:"];
[savePanel setRequiredFileType:""];
[savePanel setDirectory:(saveFileName?saveFileName:[NXApp appUserHome])];
/* get file name to save */
if (![savePanel runModalForDirectory:[NXApp appUserHome] file:""]) return self;
if (!(temp = (char*)[savePanel filename])) return self;
freeString(saveFileName);
saveFileName = NXCopyStringBuffer(temp);
return [self save:sender];
}
/* save contents of text view */
- save:sender
{
if (!saveFileName) return [self saveAs:sender];
[[exeShellScroll docView] saveRTFDTo:saveFileName removeBackup:NO errorHandler:self];
return self;
}
// -------------------------------------------------------------------------------------
// window close
// -------------------------------------------------------------------------------------
/* close all windows */
+ closeAllWindows
{
if (instanceList) [instanceList makeObjectsPerform:@selector(closeWindow:) with:self];
return self;
}
/* shut down */
- closeWindow:sender
{
return [exeWindow performClose:self];
}
// -------------------------------------------------------------------------------------
// window delegate methods
// -------------------------------------------------------------------------------------
- windowWillClose:windowId
{
if (cmdInProcess) return (id)nil;
[instanceList removeObject:self];
return [NXApp delayedFree:self];
}
- windowWillResize:windowId toSize:(NXSize*)newSize
{
if (newSize->width < minWinSize.width ) newSize->width = minWinSize.width;
if (newSize->height < minWinSize.height) newSize->height = minWinSize.height;
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.