Licensing ITMac under the GNU Lesser General Public License version 2.1.
[ITMac.git] / ITAppleEventTools.m
1 #import "ITAppleEventTools.h"
2 #import <ITFoundation/ITCarbonSupport.h>
3
4 NSString *_ITAEDescCarbonDescription(AEDesc desc) {
5         Handle descHandle;
6         NSString *carbonDescription;
7         AEPrintDescToHandle(&desc,&descHandle);
8         carbonDescription = [NSString stringWithUTF8String:*descHandle];
9         DisposeHandle(descHandle);
10         return carbonDescription;
11 }
12
13 NSAppleEventDescriptor *ITSendAE(FourCharCode eClass, FourCharCode eID, const ProcessSerialNumber *psn) {
14         AEDesc dest;
15         int pid;
16         AppleEvent event, reply;
17         OSStatus cerr, err;
18         NSAppleEventDescriptor *cocoaReply;
19         
20         if ((GetProcessPID(psn, &pid) == noErr) && (pid == 0)) {
21                 ITDebugLog(@"ITSendAE(%@, %@, {%i, %i}): Error getting PID of application.", NSStringFromFourCharCode(eClass), NSStringFromFourCharCode(eID), psn->highLongOfPSN, psn->lowLongOfPSN);
22                 return nil;
23         }
24         
25         AECreateDesc(typeProcessSerialNumber, psn,sizeof(ProcessSerialNumber),&dest);
26         cerr = AECreateAppleEvent(eClass,eID,&dest,kAutoGenerateReturnID,kAnyTransactionID,&event);
27         
28         if (cerr) {
29                 return nil;
30         }
31         
32         err = AESend(&event, &reply, kAENoReply, kAENormalPriority, /*kAEDefaultTimeout*/60, NULL, NULL);
33         AEDisposeDesc(&dest);
34         AEDisposeDesc(&event);
35         
36         if (err) {
37                 AEDisposeDesc(&reply);
38                 return nil;
39         }
40         return [[[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&reply] autorelease];
41 }
42
43 NSAppleEventDescriptor *ITSendAEWithKey(FourCharCode reqKey, FourCharCode evClass, FourCharCode evID, const ProcessSerialNumber *psn) {
44         return ITSendAEWithString([NSString stringWithFormat:@"'----':obj { form:'prop', want:type('prop'), seld:type('%@'), from:'null'() }", NSStringFromFourCharCode(reqKey)], evClass, evID, psn);
45 }
46
47 NSAppleEventDescriptor *ITSendAEWithString(NSString *sendString, FourCharCode evClass, FourCharCode evID, const ProcessSerialNumber *psn) {
48         return ITSendAEWithStringAndTimeout(sendString, evClass, evID, psn, 60);
49 }
50
51 NSAppleEventDescriptor *ITSendAEWithStringAndTimeout(NSString *sendString, FourCharCode evClass, FourCharCode evID, const ProcessSerialNumber *psn, long timeout) {
52         pid_t pid;
53         AppleEvent sendEvent, replyEvent;
54         AEDesc resultDesc;
55         DescType resultType;
56         Size resultSize;
57         
58         AEBuildError buildError;
59         OSStatus berr,err;
60         
61         if ((GetProcessPID(psn, &pid) == noErr) && (pid == 0)) {
62                 ITDebugLog(@"ITSendAEWithString(%@, %@, %@, {%i, %i}): Error getting PID of application.", sendString, NSStringFromFourCharCode(evClass), NSStringFromFourCharCode(evID), psn->highLongOfPSN, psn->lowLongOfPSN);
63                 return nil;
64         }
65         
66         berr = AEBuildAppleEvent(evClass, evID, typeProcessSerialNumber,psn, sizeof(ProcessSerialNumber), kAutoGenerateReturnID, 0, &sendEvent, &buildError, [sendString UTF8String]);
67         
68         if (berr) {
69                 ITDebugLog(@"ITSendAEWithString(%@, %@, %@, {%i, %i}): Build Error: %d:%d at \"%@\"", sendString, NSStringFromFourCharCode(evClass), NSStringFromFourCharCode(evID), psn->highLongOfPSN, psn->lowLongOfPSN, (int)buildError.fError, buildError.fErrorPos, [sendString substringToIndex:buildError.fErrorPos]);
70                 return nil;
71         }
72         
73         err = AESend(&sendEvent, &replyEvent, kAEWaitReply, kAENormalPriority, /*kAEDefaultTimeout*/timeout, NULL, NULL);
74         AEDisposeDesc(&sendEvent);
75         
76         if (err) {
77                 ITDebugLog(@"ITSendAEWithString(%@, %@, %@, {%i, %i}): Send Error: %i", sendString, NSStringFromFourCharCode(evClass), NSStringFromFourCharCode(evID), psn->highLongOfPSN, psn->lowLongOfPSN, err);
78                 return nil;
79         }
80         
81         err = AESizeOfParam(&replyEvent, keyDirectObject, &resultType, &resultSize);
82         
83         if (resultSize == 0 || err != 0) {
84                 AEDisposeDesc(&replyEvent);
85                 return nil;
86         }
87         
88         AEGetParamDesc(&replyEvent, keyDirectObject, resultType, &resultDesc);
89         AEDisposeDesc(&replyEvent);
90         return [[[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&resultDesc] autorelease];
91 }
92
93 NSAppleEventDescriptor *ITSendAEWithStringAndObject(NSString *sendString, const AEDesc *object, FourCharCode evClass, FourCharCode evID, const ProcessSerialNumber *psn) {
94         pid_t pid;
95         AppleEvent sendEvent, replyEvent;
96         NSAppleEventDescriptor *recv;
97         AEDesc resultDesc;
98         DescType resultType;
99         Size resultSize;
100         
101         AEBuildError buildError;
102         OSStatus berr,err;
103         
104         if ((GetProcessPID(psn, &pid) == noErr) && (pid == 0)) {
105                 ITDebugLog(@"ITSendAEWithStringAndObject(%@, <%@>, %@, %@, {%i, %i}): Error getting PID of application.", sendString, _ITAEDescCarbonDescription(*object), NSStringFromFourCharCode(evClass), NSStringFromFourCharCode(evID), psn->highLongOfPSN, psn->lowLongOfPSN);
106                 return nil;
107         }
108         
109         berr = AEBuildAppleEvent(evClass, evID, typeProcessSerialNumber,psn, sizeof(ProcessSerialNumber), kAutoGenerateReturnID, 0, &sendEvent, &buildError, [sendString UTF8String]);
110         
111         if (berr) {
112                 ITDebugLog(@"ITSendAEWithStringAndObject(%@, <%@>, %@, %@, {%i, %i}): Build Error: %d:%d at \"%@\"", sendString, _ITAEDescCarbonDescription(*object), NSStringFromFourCharCode(evClass), NSStringFromFourCharCode(evID), psn->highLongOfPSN, psn->lowLongOfPSN, (int)buildError.fError, buildError.fErrorPos, [sendString substringToIndex:buildError.fErrorPos]);
113                 return nil;
114         }
115         
116         AEPutParamDesc(&sendEvent, keyDirectObject, object);
117         
118         err = AESend(&sendEvent, &replyEvent, kAEWaitReply, kAENormalPriority, /*kAEDefaultTimeout*/60, NULL, NULL);
119         AEDisposeDesc(&sendEvent);
120         
121         if (err) {
122                 ITDebugLog(@"ITSendAEWithStringAndObject(%@, <%@>, %@, %@, {%i, %i}): Send Error: %i", sendString, _ITAEDescCarbonDescription(*object), NSStringFromFourCharCode(evClass), NSStringFromFourCharCode(evID), psn->highLongOfPSN, psn->lowLongOfPSN, err);
123                 return nil;
124         }
125         
126         err = AESizeOfParam(&replyEvent, keyDirectObject, &resultType, &resultSize);
127         
128         if (resultSize == 0 || err != 0) {
129                 AEDisposeDesc(&replyEvent);
130                 return nil;
131         }
132         
133         AEGetParamDesc(&replyEvent, keyDirectObject, resultType, &resultDesc);
134         AEDisposeDesc(&replyEvent);
135         return [[[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&resultDesc] autorelease];
136 }