-
Notifications
You must be signed in to change notification settings - Fork 4
/
GPGEngineHelper.m
144 lines (122 loc) · 5.9 KB
/
GPGEngineHelper.m
1
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
//
// GPGEngineHelper.m
// MacGPGME
//
// Created by davelopper at users.sourceforge.net on Sat Apr 12 2008.
//
//
// Copyright (C) 2001-2008 Mac GPG Project.
//
// This code is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 2.1 of the License, or (at your option)
// 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 Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, visit <http://www.gnu.org/> or write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
// MA 02111-1307, USA.
//
// More info at <http://macgpg.sourceforge.net/>
//
#include "GPGEngineHelper.h"
#include "GPGInternals.h"
#define NOTHING_READ 0
#define READ_STDOUT (1 << 0)
#define READ_STDERR (1 << 1)
#define READ_ALL (READ_STDOUT | READ_STDERR)
@implementation GPGEngineHelper
- (void) dealloc
{
[stderrData release];
[stdoutData release];
[super dealloc];
}
- (void) readStderr:(NSNotification *)notification
{
[readLock lock];
stderrData = [[[notification userInfo] objectForKey:NSFileHandleNotificationDataItem] retain];
[[NSNotificationCenter defaultCenter] removeObserver:self name:[notification name] object:[notification object]];
[readLock unlockWithCondition:[readLock condition] | READ_STDERR];
}
- (void) readStdout:(NSNotification *)notification
{
[readLock lock];
stdoutData = [[[notification userInfo] objectForKey:NSFileHandleNotificationDataItem] retain];
[[NSNotificationCenter defaultCenter] removeObserver:self name:[notification name] object:[notification object]];
[readLock unlockWithCondition:[readLock condition] | READ_STDOUT];
}
- (NSString *) executeWithArguments:(NSArray *)arguments localizedOutput:(BOOL)localizedOutput error:(NSError **)errorPtr
{
NSTask *aTask = [[NSTask alloc] init];
NSPipe *stdoutPipe = [NSPipe pipe];
NSPipe *stderrPipe = (errorPtr != NULL ? [NSPipe pipe] : nil);
NSString *outputString = nil;
[aTask setLaunchPath:[engine executablePath]];
arguments = [[NSArray arrayWithObjects:@"--utf8-strings", @"--charset", @"utf8", @"--no-verbose", @"--batch", @"--no-tty", nil] arrayByAddingObjectsFromArray:arguments]; // FIXME: this is engine-dependant
[aTask setArguments:arguments];
if(!localizedOutput){
// If we don't want localized output, we set language environment to English; that allows us to parse output more easily
NSMutableDictionary *environment = [NSMutableDictionary dictionaryWithDictionary:[[NSProcessInfo processInfo] environment]]; // We MUST add current environment!!
[environment setObject:@"en_US.UTF-8" forKey:@"LANG"];
[environment setObject:@"en_US.UTF-8" forKey:@"LANGUAGE"];
[environment setObject:@"en_US.UTF-8" forKey:@"LC_ALL"];
[environment setObject:@"en_US.UTF-8" forKey:@"LC_MESSAGE"];
[aTask setEnvironment:environment];
}
[aTask setStandardOutput:stdoutPipe];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(readStdout:) name:NSFileHandleReadToEndOfFileCompletionNotification object:[stdoutPipe fileHandleForReading]];
if(errorPtr != NULL){
[aTask setStandardError:stderrPipe];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(readStderr:) name:NSFileHandleReadToEndOfFileCompletionNotification object:[stderrPipe fileHandleForReading]];
readLock = [[NSConditionLock alloc] initWithCondition:NOTHING_READ];
}
else
readLock = [[NSConditionLock alloc] initWithCondition:READ_STDERR];
NS_DURING
[aTask launch];
[[stderrPipe fileHandleForReading] readToEndOfFileInBackgroundAndNotify];
[[stdoutPipe fileHandleForReading] readToEndOfFileInBackgroundAndNotify];
while([readLock tryLockWhenCondition:READ_ALL] == NO)
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
// Rendez-vous
[readLock unlockWithCondition:NOTHING_READ];
[aTask waitUntilExit];
outputString = [GPGStringFromChars([stdoutData bytes]) retain];
if([aTask terminationStatus] != 0){
if(errorPtr != NULL){
*errorPtr = [NSError errorWithDomain:@"GPGEngineHelper" code:[aTask terminationStatus] userInfo:[NSDictionary dictionaryWithObjectsAndKeys:GPGStringFromChars([stderrData bytes]), @"stderr", outputString, @"stdout", nil]];
}
else{
NSLog(@"Unhandled error %d during execution of '%@ %@'", [aTask terminationStatus], [aTask launchPath], [[aTask arguments] componentsJoinedByString:@" "]);
}
}
else{
if(errorPtr != NULL)
*errorPtr = nil;
}
NS_HANDLER
NSLog(@"### %s: exception during execution of '%@ %@': %@ %@", __PRETTY_FUNCTION__, [aTask launchPath], [[aTask arguments] componentsJoinedByString:@" "], localException, [localException userInfo]);
[aTask release];
[readLock release];
[localException raise];
NS_ENDHANDLER
[aTask release];
[readLock release];
return [outputString autorelease];
}
+ (NSString *) executeEngine:(GPGEngine *)engine withArguments:(NSArray *)arguments localizedOutput:(BOOL)localizedOutput error:(NSError **)errorPtr
{
GPGEngineHelper *helper = [[self alloc] init];
NSString *outputString;
helper->engine = engine;
outputString = [helper executeWithArguments:arguments localizedOutput:localizedOutput error:errorPtr];
[helper release];
return outputString;
}
@end