/*
Class MPAuthority
Project Pallet
Copyright (C) 2006 MacPorts.
This code is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
For a copy of the GNU General Public License, visit or
write to the Free Software Foundation, Inc., 59 Temple Place--Suite 330,
Boston, MA 02111-1307, USA.
More information is available at http://www.macports.org or macports-users@lists.macosforge.org
History:
Created by Randall Wood rhwood@macports.org on 6 October 2006
*/
#import "PortAuthority.h"
#include
@implementation PortAuthority
enum portCommands {
portInstall,
portList,
portListAll,
portSync,
portSelfupdate,
portListInstalled,
portListOutdated
};
#pragma mark STARTUP
- (void)awakeFromNib
{
// Get a MacPorts Interpeter
interpeter = [[MPInterp alloc] init];
if (![interpeter loadPackage:MPPackageName version:MPPackageVersion usingCommand:MPPackageInit]) {
NSLog(@"Failed to load interpeter");
exit(1);
}
if (![interpeter redirectCommand:MPUIPuts toObject:self]) {
NSLog(@"Failed to redirect interpeter input");
exit(1);
}
NSLog(@"Printing system_options");
NSLog([[interpeter getVariable:[MPObject objectWithString:@"system_options"]] stringValue]);
NSLog(@"system_options printed");
// Load/set preferences/defaults
if (![[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey:@"portInstallationPath"]) {
[[[NSUserDefaultsController sharedUserDefaultsController] values] setValue:@"/opt/local" forKey:@"portInstallationPath"];
NSString *userDefaultsValuesPath;
NSDictionary *userDefaultsValuesDict;
userDefaultsValuesPath = [[NSBundle mainBundle] pathForResource:@"UserDefaults"
ofType:@"plist"];
userDefaultsValuesDict = [NSDictionary dictionaryWithContentsOfFile:userDefaultsValuesPath];
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
[[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:userDefaultsValuesDict];
}
// Hide duplicate items in Windows menu
[portsWindow setExcludedFromWindowsMenu:YES];
[portLogWindow setExcludedFromWindowsMenu:YES];
// Locate port
macPortsPath = [[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey:@"portInstallationPath"];
macPortsPort = [[NSString alloc] initWithString:[macPortsPath stringByAppendingPathComponent:@"bin/port"]];
// Initialize the port settings cache
portSettings = [[NSMutableDictionary alloc] init];
// Clean the main window
[status setStringValue:@""];
// Setup the port task
portIsRunning = NO;
launcher = [[NSBundle mainBundle] pathForResource:@"Launcher" ofType:nil];
agentTask = [[AuthorizedExecutable alloc] initWithExecutable:launcher];
authPortTask = [[AuthorizedExecutable alloc] initWithExecutable:launcher];
killTask = [[AuthorizedExecutable alloc] initWithExecutable:launcher];
[agentTask setDelegate:self];
[authPortTask setDelegate:self];
[killTask setDelegate:self];
// Setup the value transformers used in bindings
NSValueTransformer *transformer = [[PAStatusTransformer alloc] init];
[NSValueTransformer setValueTransformer:transformer forName:@"PAStatusTransformer"];
// UI Tweaks
[[portsList headerView] setMenu:portsListHeaderMenu];
[[portsList cornerView] setMenu:portsListHeaderMenu];
// TESTING TESTING TESTING
NSLog(@"Ports Database path: %@", [self configurationSetting:@"portdbpath"]);
}
/*
TODO: rewrite to run sync/selfupdate, and port list methods in thread so as not to block UI.
*/
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// configure and register the connection to the PalletHelper
connection = [NSConnection defaultConnection];
[connection setRootObject: self];
[connection enableMultipleThreads];
if ([connection registerName:MPAppMessagePort] == NO) {
NSRunAlertPanel(@"Pallet", @"Could not register Pallet connection on this host.", nil, @"Quit", nil);
[NSApp terminate: self];
}
// sync or selfupdate as required
if ([[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey:@"updateMacPortsOnStartup"] boolValue] == YES) {
[self updateMacPorts:nil];
} else if ([[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey:@"synchronizePortsListOnStartup"] boolValue] == YES) {
[self syncPortsList:nil];
}
// List ports
[self getPortIndexes];
[self populatePortIndex];
}
#pragma mark PORT INDEX
- (NSDictionary *)tPorts
{
if (!_ports) {
NSPropertyListFormat format;
NSString *error;
NSData *portsData = [[self agent] portsData];
_ports= [[NSPropertyListSerialization propertyListFromData:portsData
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&error]
retain];
}
NSLog(_ports);
return _ports;
}
- (void)getPortIndexes
{
NSArray *conf;
NSString *path;
NSString *file;
NSMutableDictionary *sources;
NSEnumerator *enumerator;
id line;
NSMutableString *source;
source = [[NSMutableString alloc] init];
sources = [[NSMutableDictionary alloc] init];
path = [macPortsPath stringByAppendingPathComponent:@"etc/macports/sources.conf"];
file = [[NSString alloc] initWithContentsOfFile:path];
conf = [[NSArray alloc] initWithArray:[file componentsSeparatedByString:@"\n"]];
if ([conf count] == 1) {
[conf release];
conf = [[NSArray alloc] initWithArray:[file componentsSeparatedByString:@"\r"]];
}
enumerator = [conf objectEnumerator];
while (line = [enumerator nextObject]) {
@try {
if ([line characterAtIndex:0] != '#') {
[sources setValue:[self pathToPortIndexWithSource:line] forKey:line];
}
}
@catch (NSException *exception) {
// Exceptions will be thrown where line is nil or 0 length
// Ignore the exception since it means only that the line was empty
}
}
if (portIndexes != nil) {
[portIndexes release];
}
portIndexes = [[NSDictionary alloc] initWithDictionary:sources copyItems:YES];
}
- (NSString *)pathToPortIndexWithSource:(NSString *)source
{
NSMutableString *path;
NSRange range;
path = [[NSMutableString alloc] init];
range = [source rangeOfString:@"://"];
[path setString:[source substringFromIndex:(range.location + range.length)]];
// if the source URL is not a file:// type URL, prepend it with ${prefix}/var/macports/sources
if (![[source substringToIndex:4] isEqualToString:@"file"]) {
[path setString:[[macPortsPath stringByAppendingPathComponent:@"var/macports/sources"] stringByAppendingPathComponent:path]];
}
return [path stringByAppendingPathComponent:@"PortIndex"];
}
- (void)parsePortIndex:(NSString *)index intoIndexObject:(id)indexObject
{
NSString *file;
NSArray *lines;
NSMutableArray *arrays;
NSMutableDictionary *port;
NSArray *array;
NSEnumerator *indexEnumerator;
int counter;
int tclCount;
int tclResult;
const char **tclElements;
NSStringEncoding encoding;
NSString *key;
id value;
NSMutableArray *values;
NSEnumerator *valuesEnumerator;
int valuesCount;
int valuesCounter;
const char **valuesElements;
id line;
arrays = [[NSMutableArray alloc] init];
file = [[NSString alloc] initWithContentsOfFile:index];
lines = [file componentsSeparatedByString:@"\n"];
indexEnumerator = [lines objectEnumerator];
// throw away the lines that contain only two words (the portname and a number)
while (line = [indexEnumerator nextObject]) {
array = [line componentsSeparatedByString:@" "];
if ([array count] > 2) {
[arrays addObject:line];
}
}
indexEnumerator = [arrays objectEnumerator];
encoding = [NSString defaultCStringEncoding];
while (line = [indexEnumerator nextObject]) {
port = [[NSMutableDictionary alloc] init];
tclResult = Tcl_SplitList(NULL, [line cString], &tclCount, &tclElements);
if (tclResult == TCL_OK && !(tclCount % 2)) {
for (counter = 0; counter < tclCount; counter+=2) {
key = [[NSString alloc] initWithCString:tclElements[counter] encoding:encoding];
if ([key isEqualToString:@"maintainers"] ||
[key isEqualToString:@"depends_lib"] ||
[key isEqualToString:@"categories"] ||
[key isEqualToString:@"depends_build"]) {
tclResult = Tcl_SplitList(NULL, tclElements[counter + 1], &valuesCount, &valuesElements);
if (tclResult == TCL_OK) {
values = [[NSMutableArray alloc] initWithCapacity:valuesCount];
for (valuesCounter = 0; valuesCounter < valuesCount; valuesCounter++) {
[values addObject:[[NSString alloc] initWithCString:valuesElements[valuesCounter] encoding:encoding]];
}
} else {
values = [[NSArray alloc] init];
}
value = [[NSArray alloc] initWithArray:values];
// create a string containing all the tokens so that it can be rapidly and easily searched
[port setValue:[[NSString alloc] initWithCString:tclElements[counter + 1] encoding:encoding] forKey:[key stringByAppendingString:@"_as_string"]];
} else {
value = [[NSString alloc] initWithCString:tclElements[counter + 1] encoding:encoding];
}
[port setValue:value forKey:key];
//NSLog(@"%@: %@\n", key, value);
}
if ([port valueForKey:@"depends_lib"]) {
values = [[NSMutableArray alloc] initWithArray:[port valueForKey:@"depends_lib"]];
valuesCount = [values count];
for (valuesCounter = 0; valuesCounter < valuesCount; valuesCounter++) {
value = [[[values objectAtIndex:valuesCounter] componentsSeparatedByString:@":"] lastObject];
[values replaceObjectAtIndex:valuesCounter withObject:value];
}
[port setValue:[[NSArray alloc] initWithArray:values] forKey:@"depends_lib"];
}
if ([port valueForKey:@"depends_build"]) {
values = [[NSMutableArray alloc] initWithArray:[port valueForKey:@"depends_build"]];
valuesCount = [values count];
for (valuesCounter = 0; valuesCounter < valuesCount; valuesCounter++) {
value = [[[values objectAtIndex:valuesCounter] componentsSeparatedByString:@":"] lastObject];
[values replaceObjectAtIndex:valuesCounter withObject:value];
}
[port setValue:[[NSArray alloc] initWithArray:values] forKey:@"depends_build"];
}
@try {
if ([[port valueForKey:@"long_description"] characterAtIndex:0] == '{') {
[port setValue:[port valueForKey:@"description"] forKey:@"long_description"];
}
}
@catch (NSException *e) {
[port setValue:[NSString stringWithFormat:
NSLocalizedStringWithDefaultValue(@"parsePortIndexDescreiptionError",
@"Localizable",
[NSBundle mainBundle],
@"Port has an invalid desciption or long_description key.",
@"Error statement for exception raised when testing long_description.")]
forKey:@"long_description"];
}
// generate a composite version string: version_revision
[port setValue:[[[port valueForKey:@"version"] stringByAppendingString:@"_"] stringByAppendingString:[port valueForKey:@"revision"]] forKey:@"compositeVersion"];
// set the status flag to unknown
[port setValue:[NSNumber numberWithInt:portStatusUnknown] forKey:@"status"];
[indexObject addObject:port];
} else {
NSLog(@"Line \"%@\" from index %@ is bad.\n", line, index);
}
}
//NSLog(@"Parsed %d ports from index %@\n", [ports count], index);
Tcl_Free((char *)tclElements);
}
- (void)populatePortIndex
{
NSEnumerator *indexEnumerator;
id index;
if (portIndex = nil) {
portIndex = [[NSMutableArray alloc] init];
}
indexEnumerator = [portIndexes keyEnumerator];
while (index = [indexEnumerator nextObject]) {
[progressIndicator startAnimation:nil];
[status setStringValue:@"Listing ports in all indexes..."];
[status setStringValue:[NSString stringWithFormat:
NSLocalizedStringWithDefaultValue(@"statusPopulatePortIndex",
@"Localizable",
[NSBundle mainBundle],
@"Listing ports in index %@",
@"Status for [MPAuthority populatePortIndex] method"),
index]];
[self parsePortIndex:[portIndexes valueForKey:index] intoIndexObject:portIndexController];
}
[status setStringValue:@""];
[progressIndicator stopAnimation:nil];
}
- (void)indexPortsInThread
{
}
#pragma mark PORT CONFIGURATION
- (NSString *)configurationSetting:(NSString *)setting
/*
For some reason, the below script can not find {$prefix}/etc/ports/ports.conf
So what we need to do is execute a tclsh resource script to get conf settings out of port
Better yet, create a RFE for port to dump its configuration settings so we can read all port conf files
without knowing where the setting came from (default, ports.conf, .portrc, wherever)...
*/
{
if ([portSettings valueForKey:setting] == nil) {
int tclResult;
Tcl_Interp *tcl;
NSString *script = [[NSString alloc] initWithFormat:@"source %@/etc/macports/macports.conf\nproc %@ x {puts [list %2$@ $x]}", macPortsPath, setting, nil];
NSLog(script);
tcl = Tcl_CreateInterp();
tclResult = Tcl_EvalEx(tcl, [script cString], -1, TCL_EVAL_GLOBAL);
if (tclResult == TCL_OK) {
NSLog(@"%s", Tcl_GetStringResult(tcl));
[portSettings setValue:[NSString stringWithCString:Tcl_GetStringResult(tcl)] forKey:setting];
} else {
NSLog(@"%s", Tcl_ErrnoMsg(Tcl_ErrnoId()));
}
Tcl_DeleteInterp(tcl);
}
return [portSettings valueForKey:setting];
}
#pragma mark PORT COMMANDS
- (void)defaultAction:(id)items
/*
rewrite to use other methods in this class to avoid duplication
*/
{
id item;
switch ([[item valueForKey:@"status"] intValue]) {
case portStatusActive:
[self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
@"uninstall",
@"-dv",
[item valueForKey:@"name"]]];
break;
case portStatusInstalled:
[self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
@"activate",
@"-dv",
[item valueForKey:@"name"]]];
break;
case portStatusOutdated:
[self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
@"upgrade",
@"-dv",
[item valueForKey:@"name"]]];
break;
case portStatusUnknown:
[self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
@"install",
@"-dv",
[item valueForKey:@"name"]]];
break;
default:
break;
}
}
- (IBAction)installPort:(id)sender
{
portCommand = portInstall;
NSArray *selection = [portIndexController selectedObjects];
NSEnumerator *selectionEnumerator = [selection objectEnumerator];
id port;
while (port = [selectionEnumerator nextObject]) {
[self installSinglePort:[port objectForKey:@"name"]];
}
}
- (void)installSinglePort:(NSString *)port
{
[status setStringValue:[NSString localizedStringWithFormat:NSLocalizedStringWithDefaultValue(@"statusInstallPort",
@"Localizable",
[NSBundle mainBundle],
@"Preparing to install %@",
@"Status for [MPAuthority installPort] method"),
port]];
NSLog([status stringValue]);
[self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
@"-dv",
@"install",
port,
nil]];
}
- (IBAction)reinstallPort:(id)sender
{
}
- (IBAction)removePort:(id)sender
{
}
- (IBAction)syncPortsList:(id)sender
{
portCommand = portSync;
[status setStringValue:NSLocalizedStringWithDefaultValue(@"statusSyncPortsList",
@"Localizable",
[NSBundle mainBundle],
@"Syncing ports list with MacPorts",
@"Status for [MPAuthority syncPortsList] method")];
[self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
@"sync",
@"-dv",
nil]];
}
- (IBAction)updateMacPorts:(id)sender
{
portCommand = portSelfupdate;
[status setStringValue:NSLocalizedStringWithDefaultValue(@"statusUpdateMacPorts",
@"Localizable",
[NSBundle mainBundle],
@"Updating MacPorts Installation",
@"Status for [MPAuthority updateMacPorts] method")];
[self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
@"selfupdate",
nil]];
}
- (IBAction)upgradeOutdated:(id)sender
{
NSLog(@"Upgrade Outdated\n");
portCommand = portSelfupdate;
[status setStringValue:NSLocalizedStringWithDefaultValue(@"statusUpgradeOutdated",
@"Localizable",
[NSBundle mainBundle],
@"Preparing to upgrade all outdated ports...",
@"Status for [MPAuthority upgradeOutdated] method")];
[self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
@"-dv",
@"upgrade",
@"outdated",
nil]];
}
- (IBAction)upgradePort:(id)sender
{
}
- (IBAction)haltPortCommand:(id)sender
{
}
- (void)runPortCommand:(NSString *)action port:(NSString *)port
{
}
- (void)runPortCommandInThread:(id)parameters
{
}
#pragma mark TABLES
- (void)updateAvailablePorts:(id)output
{
NSMutableArray *fields;
NSMutableDictionary *columns;
columns = [[NSMutableDictionary alloc] initWithCapacity:4];
fields = [[NSMutableArray alloc] initWithArray:[output componentsSeparatedByString:@" "]];
[fields removeObjectIdenticalTo:[NSString string]];
[columns setValue:[NSNumber numberWithInt:portStatusUnknown] forKey:@"status"];
[columns setValue:[fields objectAtIndex:0] forKey:@"name"];
[columns setValue:[fields objectAtIndex:1] forKey:@"version"];
[columns setValue:[fields objectAtIndex:2] forKey:@"categories"];
[portIndex addObject:columns];
[portsList reloadData];
}
#pragma mark TABLE DATASOURCES
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
NSLog(@"request for row %@ column %@\n", [NSNumber numberWithInt:rowIndex], [aTableColumn identifier]);
NSParameterAssert(rowIndex >= 0 && rowIndex < [portIndex count]);
if ([[[aTableColumn identifier] stringValue] isEqualToString:@"status"]) {
switch ([[[portIndex objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]] intValue]) {
case portStatusInstalled:
return nil;
break;
case portStatusActive:
return nil;
break;
case portStatusOutdated:
return nil;
break;
default:
return nil;
}
}
return [[portIndex objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]];
}
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [portIndex count];
}
#pragma mark MENU ITEMS
- (IBAction)about:(id)sender
{
NSMutableDictionary *options;
NSMutableAttributedString *credits;
NSMutableString *version;
version = [NSMutableString stringWithContentsOfFile:[macPortsPath stringByAppendingPathComponent:@"etc/ports/dp_version"]];
[version deleteCharactersInRange:NSMakeRange([version length] - 1, 1)];
credits = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:
NSLocalizedStringFromTable(@"MacPorts Version: %@",
@"Localizable",
@"MacPorts Version"),
version]];
[credits setAlignment:NSCenterTextAlignment range:NSMakeRange(0, [credits length])];
[credits addAttribute:@"NSFontAttributeName" value:[NSFont labelFontOfSize:[NSFont labelFontSize]] range:NSMakeRange(0, [credits length])];
options = [[NSMutableDictionary alloc] init];
[options setObject:credits forKey:@"Credits"];
[NSApp orderFrontStandardAboutPanelWithOptions:options];
}
- (IBAction)macPortsSite:(id)sender
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.macports.org"]];
}
- (IBAction)portAuthoritySite:(id)sender
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.macports.org"]];
}
#pragma mark UTILITIES
- (void)launchExecutableWithArguments:(NSMutableArray *)args
{
if (!portIsRunning) {
portIsRunning = YES;
[NSApp setApplicationIconImage:[NSImage imageNamed:@"ApplicationIconBusy"]];
if (portTask != nil) {
[portTask release];
}
portTask = [[TaskWrapper alloc] initWithController:self arguments:args];
[portTask startProcess];
}
}
- (void)launchAuthorizedExecutableWithArguments:(NSMutableArray *)args
{
NSLog(@"Launching command %@", args);
if (!portIsRunning) {
portIsRunning = YES;
[NSApp setApplicationIconImage:[NSImage imageNamed:@"ApplicationIconBusy"]];
[authPortTask setArguments:args];
[authPortTask authorizeWithQuery];
[progressIndicator startAnimation:nil];
[authPortTask start];
} else {
[taskQueue addObject:args];
}
}
#pragma mark TOOLBAR
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
{
return YES;
}
#pragma mark MACPORTS INTERPETER
- (NSDictionary *)listPorts:(NSString *)query
{
Tcl_Obj **objv;
int count = 0, i=0;
MPObject *result;
NSString *error;
NSMutableDictionary *portsData;
// [_ports removeAllObjects];
result = [interpeter evaluateCommand:[MPObject objectWithString:MPSearchCommand]
withObject:[MPObject objectWithString:query]];
Tcl_ListObjGetElements(NULL, [result tclObj], &count, &objv);
while (++i < count) {
NSMutableDictionary *portDict = [NSMutableDictionary dictionary];
Tcl_Obj **innerobjs;
int innercount = 0, j = 0;
Tcl_ListObjGetElements(NULL, objv[i++], &innercount, &innerobjs);
while (j < innercount)
{
MPObject *keyObject = [MPObject objectWithTclObj: innerobjs[j++]];
MPObject *valueObject = [MPObject objectWithTclObj: innerobjs[j++]];
NSString *key = [keyObject stringValue];
id value;
if ([key isEqualToString: MPCategoriesKey] || [key isEqualToString: MPMaintainersKey]) {
NSEnumerator *enm = [[[valueObject stringValue] componentsSeparatedByString: @" "] objectEnumerator];
NSString *component;
value = [NSMutableArray array];
while (component = [enm nextObject]) {
if (![value containsObject: component]) {
[value addObject: component];
}
}
} else if ([key rangeOfString: MPDependsKey].location != NSNotFound) {
NSEnumerator *dependencyEnm = [[[valueObject stringValue] componentsSeparatedByString: @" "] objectEnumerator];
NSString *component;
value = [NSMutableArray array];
while (component = [dependencyEnm nextObject]) {
NSString *dependencyName = [[component componentsSeparatedByString: @":"] objectAtIndex: 2];
if (![value containsObject: dependencyName]) {
[value addObject: dependencyName];
}
}
key = MPDependsKey;
} else {
value = [valueObject stringValue];
}
[portDict setObject:value forKey:key];
}
[portsData setObject:portDict forKey:[portDict objectForKey:MPNameKey]];
}
return [NSDictionary dictionaryWithDictionary:portsData];
}
- (MPObject *) ui_puts: (NSArray *)array
{
NSDictionary *message = [[array objectAtIndex: 1] dictionaryValue];
if (message == nil)
return [MPObject objectWithString: MPNoResult];
NSString *data = [message objectForKey: @"data"];
NSString *priority = [message objectForKey: @"priority"];
if (data == nil || priority == nil)
return [MPObject objectWithString: MPNoResult];
id delegate = [[[NSThread currentThread] threadDictionary] objectForKey: @"delegate"];
//[delegate displayMessage: message forPortName: [_currentOp objectForKey: @"portName"]];
return [MPObject objectWithString: MPYesResult];
}
#pragma mark MACPORTS AGENT
- (id )agent {
if (agentIsBusy) {
return nil;
}
agentIsBusy = YES;
if (!agent) {
NSString *agentPath = [[NSBundle mainBundle] pathForResource:@"PalletHelper" ofType:@""];
int i;
// [self launchAuthorizedExecutableWithArguments:];
[agentTask setArguments:[NSArray arrayWithObjects:agentPath, nil]];
[agentTask authorizeWithQuery];
[agentTask start];
for (i = 0; i < 10; i++) {
connection = [[NSConnection connectionWithRegisteredName:MPAgentMessagePort host:nil] retain];
if (connection) {
break;
}
sleep(1);
}
if (!connection) {
NSRunAlertPanel(@"Pallet", @"Could not connect to PalletHelper.", nil, nil, nil);
// exit(0); don't exit as I want to see the bloody console window
}
agent = [[connection rootProxy] retain];
[(NSDistantObject *)agent setProtocolForProxy:@protocol(MPAgentProtocol)];
[connection setRootObject:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectionDidDie:) name:NSConnectionDidDieNotification object:connectionInvalid];
}
agentIsBusy = NO;
return agent;
}
- (void)connectionDidDie:(id)server
{
NSRunAlertPanel(@"Pallet", @"Connection to PalletHelper died!", nil, nil, nil);
agent = nil;
// resetting agent to nil will cause a new instance of the agent to
// be spawned by [PortAuthority agent] next time someone tries to access it
}
- (oneway void)displayMessage:(in bycopy NSDictionary *)message forPortName:(in bycopy NSString *)portName {
[self appendOutput:[message objectForKey:@"data"]];
}
- (void)executeTarget:(NSString *)target forPortName:(NSString *)portName {
NSDictionary *operation = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
portName, @"portName",
target, "@target",
nil];
if (!operations) {
operations = [[NSMutableArray alloc] init];
}
[operations addObject:operation];
[[self agent] executeTarget:target forPortName:portName];
}
- (BOOL)shouldPerformTarget:(in bycopy NSString *)target forPortName:(in bycopy NSString *)portName {
return YES;
}
- (oneway void)willPerformTarget:(in bycopy NSString *)target forPortName:(in bycopy NSString *)portName {
[progressIndicator startAnimation:nil];
[NSApp setApplicationIconImage:[NSImage imageNamed:@"ApplicationIconBusy"]];
}
- (oneway void)didPerformTarget:(in bycopy NSString *)target forPortName:(in bycopy NSString *)portName withResult:(in bycopy NSString *)result {
[progressIndicator stopAnimation:nil];
[NSApp setApplicationIconImage:[NSImage imageNamed:@"ApplicationIcon"]];
[status setStringValue:@""];
}
#pragma mark AUTHORIZED EXECUTABLE DELEGATES / TASK WRAPPER CONTROLLER
// This callback is implemented as part of conforming to the ProcessController protocol.
// It will be called whenever there is output from the TaskWrapper.
- (void)appendOutput:(NSString *)output
{
// add the string (a chunk of the results from locate) to the NSTextView's
// backing store, in the form of an attributed string
[[portLog textStorage] appendAttributedString: [[[NSAttributedString alloc]
initWithString: output] autorelease]];
// setup a selector to be called the next time through the event loop to scroll
// the view to the just pasted text. We don't want to scroll right now,
// because of a bug in Mac OS X version 10.1 that causes scrolling in the context
// of a text storage update to starve the app of events
[self performSelector:@selector(scrollToVisible:) withObject:nil afterDelay:0.0];
switch (portCommand) {
}
}
// This routine is called after adding new results to the text view's backing store.
// We now need to scroll the NSScrollView in which the NSTextView sits to the part
// that we just added at the end
- (void)scrollToVisible:(id)ignore {
[portLog scrollRangeToVisible:NSMakeRange([[portLog string] length], 0)];
}
// A callback that gets called when a TaskWrapper is launched, allowing us to do any setup
// that is needed from the app side. This method is implemented as a part of conforming
// to the ProcessController protocol.
- (void)processStarted
{
portIsRunning = YES;
[portLog setString:@""];
[progressIndicator startAnimation:nil];
}
// A callback that gets called when a TaskWrapper is completed, allowing us to do any cleanup
// that is needed from the app side. This method is implemented as a part of conforming
// to the ProcessController protocol.
- (void)processFinished
{
portIsRunning = NO;
[status setStringValue:@""];
[progressIndicator stopAnimation:nil];
if ([taskQueue count]) {
[self launchAuthorizedExecutableWithArguments:[taskQueue objectAtIndex:0]];
[taskQueue removeObjectAtIndex:0];
}
}
- (void)captureOutput:(NSString*)str forExecutable:(AuthorizedExecutable*)exe
{
NSRange marker, eol;
[[portLog textStorage] appendAttributedString: [[[NSAttributedString alloc]
initWithString: str] autorelease]];
@try {
marker = [str rangeOfString:@"--->"];
eol = [str rangeOfString:@"\n" options:NSLiteralSearch range:NSMakeRange(marker.location + 4, [str length] - marker.location)];
NSLog([str substringWithRange:NSMakeRange(marker.location + 4, eol.location - (marker.location + 4))]);
}
@catch (NSException *exception) {
// Exceptions will be thrown where "--->" is not in str
// Ignore the exceptions since we want to change the status line only if such a line exists
}
[self performSelector:@selector(scrollToVisible:) withObject:nil afterDelay:0.0];
}
- (void)executableFinished:(AuthorizedExecutable *)exe withStatus:(int)exeStatus
{
NSLog(@"Launcher finished with status %u", exeStatus);
portIsRunning = NO;
[status setStringValue:@""];
[progressIndicator stopAnimation:nil];
if ([taskQueue count]) {
[self launchAuthorizedExecutableWithArguments:[taskQueue objectAtIndex:0]];
[taskQueue removeObjectAtIndex:0];
}
}
#pragma mark APPLICATION DELEGATES
-(void)applicationWillTerminate:(NSNotification*)anotification
{
[NSApp setApplicationIconImage:[NSImage imageNamed:@"ApplicationIcon"]];
[authPortTask unAuthorize];
[killTask unAuthorize];
}
@end