William Bowling is sharing code with you
Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.
Don't show this again1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | /*
ApplescriptRunner.m
Created by Evan Schoenberg on 10/31/2004
*/
#import <Foundation/Foundation.h>
/*!
* @brief Daemon to run applescripts, optionally with a function name and arguments, and respond over NSDistributedNotificationCenter
*/
//After SECONDS_INACTIVITY_BEFORE_AUTOMATIC_QUIT seconds without any activity, the daemon will quit itself
#define SECONDS_INACTIVITY_BEFORE_AUTOMATIC_QUIT 600 /* 10 minutes */
@interface AIApplescriptRunner : NSObject {}
- (void)applescriptRunnerIsReady;
- (void)resetAutomaticQuitTimer;
@end
@implementation AIApplescriptRunner
- (id)init
{
if ((self = [super init])) {
NSDistributedNotificationCenter *distributedNotificationCenter = [NSDistributedNotificationCenter defaultCenter];
[distributedNotificationCenter addObserver:self
selector:@selector(respondIfReady:)
name:@"AdiumApplescriptRunner_RespondIfReady"
object:nil];
[distributedNotificationCenter addObserver:self
selector:@selector(executeScript:)
name:@"AdiumApplescriptRunner_ExecuteScript"
object:nil];
[distributedNotificationCenter addObserver:self
selector:@selector(quit:)
name:@"AdiumApplescriptRunner_Quit"
object:nil];
[self applescriptRunnerIsReady];
[self resetAutomaticQuitTimer];
}
return self;
}
/*!
* @brief Inform observers on the NSDistributedNotificationCenter that the applesript runner is ready
*/
- (void)applescriptRunnerIsReady
{
//Check for an existing AdiumApplescriptRunner; if there is one, it will respond with AdiumApplescriptRunnerIsReady
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"AdiumApplescriptRunner_IsReady"
object:nil
userInfo:nil
deliverImmediately:NO];
}
/*!
* @brief Observer method which responds to the @"AdiumApplescriptRunner_RespondIfReady" distributed notification
*
* This allows simple two-way communicatino from the host application to the daemon without setting up proxy or ports
*/
- (void)respondIfReady:(NSNotification *)inNotification
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self applescriptRunnerIsReady];
[pool release];
}
/*!
* @brief Execute an applescript
*
* @param inNotification An NSNotificatoin whose userInfo NSDictionary has @"funtion", @"arguments", @"path", and @"uniqueID" keys
*/
- (void)executeScript:(NSNotification *)inNotification
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *userInfo = [inNotification userInfo];
NSAppleScript *appleScript;
NSAppleEventDescriptor *thisApplication, *containerEvent;
NSString *functionName = [userInfo objectForKey:@"function"];
NSArray *scriptArgumentArray = [userInfo objectForKey:@"arguments"];
NSURL *pathURL = [NSURL fileURLWithPath:[userInfo objectForKey:@"path"]];
NSString *resultString = nil;
appleScript = [[NSAppleScript alloc] initWithContentsOfURL:pathURL
error:NULL];
if (appleScript) {
if (functionName && [functionName length]) {
/* If we have a functionName (and potentially arguments), we build
* an NSAppleEvent to execute the script. */
//Get a descriptor for ourself
int pid = [[NSProcessInfo processInfo] processIdentifier];
thisApplication = [NSAppleEventDescriptor descriptorWithDescriptorType:typeKernelProcessID
bytes:&pid
length:sizeof(pid)];
//Create the container event
//We need these constants from the Carbon OpenScripting framework, but we don't actually need Carbon.framework...
#define kASAppleScriptSuite 'ascr'
#define kASSubroutineEvent 'psbr'
#define keyASSubroutineName 'snam'
containerEvent = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite
eventID:kASSubroutineEvent
targetDescriptor:thisApplication
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
//Set the target function
[containerEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithString:functionName]
forKeyword:keyASSubroutineName];
//Pass arguments - arguments is expecting an NSArray with only NSString objects
if ([scriptArgumentArray count]) {
NSAppleEventDescriptor *arguments = [[NSAppleEventDescriptor alloc] initListDescriptor];
NSString *object;
for (object in scriptArgumentArray) {
[arguments insertDescriptor:[NSAppleEventDescriptor descriptorWithString:object]
atIndex:([arguments numberOfItems] + 1)]; //This +1 seems wrong... but it's not
}
[containerEvent setParamDescriptor:arguments forKeyword:keyDirectObject];
[arguments release];
}
//Execute the event
resultString = [[appleScript executeAppleEvent:containerEvent error:NULL] stringValue];
} else {
resultString = [[appleScript executeAndReturnError:NULL] stringValue];
}
}
//Notify of the script's completion and the result
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"AdiumApplescript_DidRun"
object:nil
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
[userInfo objectForKey:@"uniqueID"], @"uniqueID",
(resultString ? resultString : @""), @"resultString",
nil]
deliverImmediately:NO];
[appleScript release];
//Reset the automatic quit timer
[self resetAutomaticQuitTimer];
[pool release];
}
/*!
* @brief Quit, notifying via the NSDistributedNotificationCenter that we're quitting
*/
- (void)quit:(NSNotification *)inNotification
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"AdiumApplescriptRunner_DidQuit"
object:nil
userInfo:nil
deliverImmediately:YES];
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
exit(0);
}
/*!
* @brief Reset the automatic quit timer, which will exit this program after SECONDS_INACTIVITY_BEFORE_AUTOMATIC_QUIT
*/
- (void)resetAutomaticQuitTimer
{
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(quit:)
object:nil];
[self performSelector:@selector(quit:)
withObject:nil
afterDelay:SECONDS_INACTIVITY_BEFORE_AUTOMATIC_QUIT];
}
@end
int main(int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
AIApplescriptRunner *applescriptRunner;
applescriptRunner = [[AIApplescriptRunner alloc] init];
[[NSRunLoop currentRunLoop] run];
[applescriptRunner quit:nil];
[applescriptRunner release];
[pool release];
}
|