// // AppleScriptManager.m // Pennyworth // // Created by Chris Karr on 4/28/08. // Copyright 2008 Chris Karr. All rights reserved. // #import "AppleScriptManager.h" #import #define SCRIPT_URL @"http://pennyworth.aetherial.net/scripts/scripts.xml" #define NAME @"name" #define TYPE @"type" #define STATUS @"status" #define VERSION @"version" #define DESCRIPTION @"description" #define INSTALL @"installed" #define PATH @"path" @implementation AppleScriptManager - (NSString *) callFunction:(NSString *) function onScript:(NSString *) scriptPath { NSDictionary * errors = [NSDictionary dictionary]; NSURL * scriptUrl = [NSURL fileURLWithPath:scriptPath]; NSAppleScript * scpt = [[NSAppleScript alloc] initWithContentsOfURL:scriptUrl error:nil]; if (scpt != nil) { ProcessSerialNumber psn = { 0, kCurrentProcess }; NSAppleEventDescriptor * target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&psn length:sizeof(ProcessSerialNumber)]; NSAppleEventDescriptor * handler = [NSAppleEventDescriptor descriptorWithString:function]; NSAppleEventDescriptor * event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite eventID:kASSubroutineEvent targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID]; [event setParamDescriptor:handler forKeyword:keyASSubroutineName]; NSAppleEventDescriptor * results = [scpt executeAppleEvent:event error:&errors]; [scpt release]; if (results != nil) return [results stringValue]; } return nil; } - (IBAction) refresh:(id) sender { [appleScripts setFilterPredicate:nil]; [appleScripts removeObjects:[appleScripts arrangedObjects]]; NSFileManager * manager = [NSFileManager defaultManager]; NSArray * directories = NSSearchPathForDirectoriesInDomains (NSApplicationSupportDirectory, NSUserDomainMask, YES); NSString * folder = [NSString stringWithFormat:@"%@/Pennyworth/AppleScript", [directories lastObject]]; for (NSString * file in [manager directoryContentsAtPath:folder]) { if ([file hasSuffix:@".scpt"]) { NSString * fullPath = [NSString stringWithFormat:@"%@/%@", folder, file]; NSMutableDictionary * action = [NSMutableDictionary dictionary]; [action setValue:[file stringByDeletingPathExtension] forKey:NAME]; [action setValue:@"Action" forKey:TYPE]; [action setValue:@"Installed" forKey:STATUS]; [action setValue:[NSNumber numberWithBool:YES] forKey:INSTALL]; [action setValue:[self callFunction:@"script_version" onScript:fullPath] forKey:VERSION]; [action setValue:[self callFunction:@"script_description" onScript:fullPath] forKey:DESCRIPTION]; [action setValue:fullPath forKey:PATH]; [appleScripts addObject:action]; } } folder = [NSString stringWithFormat:@"%@/Pennyworth/AppleScript/Sensors", [directories lastObject]]; for (NSString * file in [manager directoryContentsAtPath:folder]) { if ([file hasSuffix:@".scpt"]) { NSString * fullPath = [NSString stringWithFormat:@"%@/%@", folder, file]; NSMutableDictionary * sensor = [NSMutableDictionary dictionary]; [sensor setValue:[file stringByDeletingPathExtension] forKey:NAME]; [sensor setValue:@"Sensor" forKey:TYPE]; [sensor setValue:@"Installed" forKey:STATUS]; [sensor setValue:[NSNumber numberWithBool:YES] forKey:INSTALL]; [sensor setValue:[self callFunction:@"script_version" onScript:fullPath] forKey:VERSION]; [sensor setValue:[self callFunction:@"script_description" onScript:fullPath] forKey:DESCRIPTION]; [sensor setValue:fullPath forKey:PATH]; [appleScripts addObject:sensor]; } } if ([[NSUserDefaults standardUserDefaults] boolForKey:@"Online_AppleScripts"]) { NSURL * url = [NSURL URLWithString:SCRIPT_URL]; NSURLRequest * request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10]; NSURLResponse * response; NSData * data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil]; if (data == nil) return; NSError * error = nil; NSXMLDocument * scriptXML = [[NSXMLDocument alloc] initWithData:data options:NSXMLNodeOptionsNone error:nil]; // [[NSXMLDocument alloc] initWithContentsOfURL:[NSURL URLWithString:SCRIPT_URL] // options:NSXMLDocumentTidyXML // error:&error]; if (scriptXML != nil) { NSXMLElement * root = [scriptXML rootElement]; for (NSXMLElement * scriptElement in [root elementsForName:@"script"]) { NSMutableDictionary * script = [NSMutableDictionary dictionary]; [script setValue:[[scriptElement attributeForName:NAME] stringValue] forKey:NAME]; [script setValue:[[scriptElement attributeForName:TYPE] stringValue] forKey:TYPE]; [script setValue:@"Not installed" forKey:STATUS]; [script setValue:[NSNumber numberWithBool:NO] forKey:INSTALL]; [script setValue:[[scriptElement attributeForName:VERSION] stringValue] forKey:VERSION]; [script setValue:[scriptElement stringValue] forKey:DESCRIPTION]; [script setValue:[[scriptElement attributeForName:@"url"] stringValue] forKey:PATH]; BOOL install = YES; for (NSDictionary * entry in [appleScripts arrangedObjects]) { if ([[script valueForKey:@"name"] isEqualToString:[entry valueForKey:@"name"]] && [[script valueForKey:TYPE] isEqualToString:[entry valueForKey:TYPE]] && [[script valueForKey:VERSION] isEqualToString:[entry valueForKey:VERSION]]) install = NO; } if (install) [appleScripts addObject:script]; } } else NSRunAlertPanel ([error localizedFailureReason], [error localizedDescription], @"OK", nil, nil); } } - (IBAction) open:(id) sender { NSDictionary * selected = [[appleScripts selectedObjects] lastObject]; if ([[selected valueForKey:STATUS] isEqualToString:@"Installed"]) [[NSWorkspace sharedWorkspace] openFile:[selected valueForKey:PATH]]; else [self install:sender]; } - (void) awakeFromNib { [tableView setTarget:self]; [tableView setDoubleAction:@selector(open:)]; [self refresh:self]; } - (IBAction) install:(id) sender { NSDictionary * selected = [[appleScripts selectedObjects] lastObject]; if (NSOKButton == NSRunInformationalAlertPanel (@"Install Script?", [NSString stringWithFormat:@"Would you like to install the '%@' script?", [selected valueForKey:@"name"]], @"Yes", @"No", nil)) { NSArray * directories = NSSearchPathForDirectoriesInDomains (NSApplicationSupportDirectory, NSUserDomainMask, YES); NSString * path = [selected valueForKey:PATH]; NSData * data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:path]]; NSMutableString * prefix = [NSMutableString stringWithFormat:@"%@/Pennyworth/AppleScript", [directories lastObject]]; if ([[selected valueForKey:TYPE] isEqualToString:@"Sensor"]) [prefix appendString:@"/Sensors"]; NSString * file = [path lastPathComponent]; NSString * finalPath = [[NSString stringWithFormat:@"%@/%@", prefix, file] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSFileManager * manager = [NSFileManager defaultManager]; if ([manager fileExistsAtPath:finalPath]) [manager movePath:finalPath toPath:[finalPath stringByReplacingOccurrencesOfString:@".scpt" withString:@".scpt-old"] handler:nil]; [data writeToFile:finalPath atomically:YES]; [data release]; [self refresh:sender]; } } - (IBAction) invoke:(id) sender { [panel makeKeyAndOrderFront:sender]; } @end