forked from stweil/OSXvnc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
JaguarExtensions.m
286 lines (231 loc) · 9.56 KB
/
JaguarExtensions.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
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
//
// JaguarExtensions.m
// OSXvnc
//
// Created by Jonathan Gillaspie on Fri Jul 11 2003.
// Copyright (c) 2003 RedstoneSoftware, Inc. All rights reserved.
#import "JaguarExtensions.h"
#import <ApplicationServices/ApplicationServices.h>
#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>
#include "keysymdef.h"
#include "kbdptr.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include "rfb.h"
#import "rfbserver.h"
#import "VNCServer.h"
#import "../RFBBundleProtocol.h"
@implementation JaguarExtensions
static NSNetService *rfbService;
static NSNetService *vncService;
static BOOL keyboardLoading = FALSE;
static KeyboardLayoutRef loadedKeyboardRef;
static BOOL useIP6 = TRUE;
static BOOL listenerFinished = FALSE;
rfbserver *theServer;
+ (void) loadGUI {
// ProcessSerialNumber psn = { 0, kCurrentProcess };
// OSStatus returnCode = TransformProcessType(& psn, kProcessTransformToForegroundApplication);
// returnCode = SetFrontProcess(& psn );
// if( returnCode != 0) {
// NSLog(@"Could not bring the application to front. Error %d", returnCode);
// }
//[[NSApplication sharedApplication] activateIgnoringOtherApps: YES];
}
+ (void) rfbStartup: (rfbserver *) aServer {
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
@"NO", @"keyboardLoading", // allows OSXvnc to look at the users selected keyboard and map keystrokes using it
@"YES", @"pressModsForKeys", // If OSXvnc finds the key you want it will temporarily toggle the modifier keys to produce it
[NSArray arrayWithObjects:[NSNumber numberWithInt:kUCKeyActionDisplay], [NSNumber numberWithInt:kUCKeyActionAutoKey], nil], @"KeyStates", // Key States to review to find KeyCodes
//[NSNumber numberWithInt:kUCKeyActionDisplay], [NSNumber numberWithInt:kUCKeyActionDown], nil],
nil]];
theServer = aServer;
keyboardLoading = [[NSUserDefaults standardUserDefaults] boolForKey:@"keyboardLoading"];
if (keyboardLoading) {
OSErr result;
NSLog(@"Keyboard Loading - Enabled");
*(theServer->pressModsForKeys) = [[NSUserDefaults standardUserDefaults] boolForKey:@"pressModsForKeys"];
if (*(theServer->pressModsForKeys))
NSLog(@"Press Modifiers For Keys - Enabled");
else
NSLog(@"Press Modifiers For Keys - Disabled");
result = KLGetCurrentKeyboardLayout(&loadedKeyboardRef);
if (result == noErr)
[self loadKeyboard:loadedKeyboardRef forServer: theServer];
else
NSLog(@"Error (%u) unabled to load current keyboard layout", result);
}
if ([[[NSProcessInfo processInfo] arguments] indexOfObject:@"-ipv4"] != NSNotFound) {
useIP6 = FALSE;
}
}
+ (void) rfbUsage {
fprintf(stderr,
"\nJAGUAR BUNDLE OPTIONS (10.2+):\n"
"-keyboardLoading flag This feature allows OSXvnc to look at the users selected keyboard and map keystrokes using it.\n"
" Disabling this returns OSXvnc to standard (U.S. Keyboard) which will work better with Dead Keys.\n"
" (default: no), 10.2+ ONLY\n"
"-pressModsForKeys flag If OSXvnc finds the key you want it will temporarily toggle the modifier keys to produce it.\n"
" This flag works well if you have different keyboards on the local and remote machines.\n"
" Only works if -keyboardLoading is on\n"
" (default: yes), 10.2+ ONLY\n"
"-bonjour flag Allow OSXvnc to advertise VNC server using Bonjour discovery services.\n"
" 'VNC' will enable the service named VNC (For Eggplant & Chicken 2.02b)\n"
" 'Both' or '2' will enable the services named RFB and VNC\n"
" (default: RFB:YES VNC:NO), 10.2+ ONLY\n"
"-ipv4 Listen For Connections on IPv4 ONLY (Default: Off). 10.2+ ONLY\n"
"-ipv6 Listen For Connections on IPv6 ONLY (Default: Off). 10.2+ ONLY\n"
);
}
+ (void) rfbRunning {
[JaguarExtensions registerRendezvous];
if (useIP6) {
[NSThread detachNewThreadSelector:@selector(setupIPv6:) toTarget:self withObject:nil];
// Wait for the IP6 to bind, if it binds later it confuses the IPv4 binding into allowing others on the port
while (!listenerFinished)
usleep(1000);
}
}
+ (void) setupIPv6: argument {
int listen_fd6=0, client_fd=0;
int value=1; // Need to pass a ptr to this
struct sockaddr_in6 sin6, peer6;
unsigned int len6=sizeof(sin6);
bzero(&sin6, sizeof(sin6));
sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(theServer->rfbPort);
if (theServer->rfbLocalhostOnly)
sin6.sin6_addr = in6addr_loopback;
else
sin6.sin6_addr = in6addr_any;
if ((listen_fd6 = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
NSLog(@"IPv6: Unable to open socket");
}
/*
else if (fcntl(listen_fd6, F_SETFL, O_NONBLOCK) < 0) {
NSLog(@"IPv6: fcntl O_NONBLOCK failed");
}
*/
else if (setsockopt(listen_fd6, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)) < 0) {
NSLog(@"IPv6: setsockopt SO_REUSEADDR failed");
}
else if (bind(listen_fd6, (struct sockaddr *) &sin6, len6) < 0) {
NSLog(@"IPv6: Failed to bind socket: port %d may be in use by another VNC", theServer->rfbPort);
}
else if (listen(listen_fd6, 5) < 0) {
NSLog(@"IPv6: Listen failed");
}
else {
NSLog(@"Started listener thread on IPv6 port %d", theServer->rfbPort);
listenerFinished = TRUE;
while ((client_fd = accept(listen_fd6, (struct sockaddr *) &peer6, &len6)) !=-1) {
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
[[NSNotificationCenter defaultCenter] postNotification:
[NSNotification notificationWithName:@"NewRFBClient" object:[NSNumber numberWithInt:client_fd]]];
// We have to trigger a signal so the event loop will pickup (if no clients are connected)
pthread_cond_signal(&(theServer->listenerGotNewClient));
[pool release];
}
NSLog(@"IPv6: Accept failed %d", errno);
}
listenerFinished = TRUE;
return;
}
+ (void) registerRendezvous {
BOOL loadRendezvousVNC = NO;
BOOL loadRendezvousRFB = YES;
int argumentIndex = [[[NSProcessInfo processInfo] arguments] indexOfObject:@"-rendezvous"];
RendezvousDelegate *rendezvousDelegate = [[RendezvousDelegate alloc] init];
if (argumentIndex == NSNotFound) {
argumentIndex = [[[NSProcessInfo processInfo] arguments] indexOfObject:@"-bonjour"];
}
if (argumentIndex != NSNotFound) {
NSString *value = nil;
if ([[[NSProcessInfo processInfo] arguments] count] > argumentIndex + 1)
value = [[[NSProcessInfo processInfo] arguments] objectAtIndex:argumentIndex+1];
if ([value hasPrefix:@"n"] || [value hasPrefix:@"N"] || [value hasPrefix:@"0"]) {
loadRendezvousVNC = NO; loadRendezvousRFB = NO;
}
else if ([value hasPrefix:@"y"] || [value hasPrefix:@"Y"] || [value hasPrefix:@"1"] || [value hasPrefix:@"rfb"]) {
loadRendezvousVNC = NO; loadRendezvousRFB = YES;
}
else if ([value hasPrefix:@"b"] || [value hasPrefix:@"B"] || [value hasPrefix:@"2"]) {
loadRendezvousVNC = YES; loadRendezvousRFB = YES;
}
else if ([value hasPrefix:@"vnc"]) {
loadRendezvousVNC = YES; loadRendezvousRFB = NO;
}
}
// Register For Rendezvous
if (loadRendezvousRFB) {
rfbService = [[NSNetService alloc] initWithDomain:@""
type:@"_rfb._tcp."
name:[NSString stringWithCString:theServer->desktopName]
port:(int) theServer->rfbPort];
[rfbService setDelegate:rendezvousDelegate];
[rfbService publish];
}
// else
// NSLog(@"Bonjour (_rfb._tcp) - Disabled");
if (loadRendezvousVNC) {
vncService = [[NSNetService alloc] initWithDomain:@""
type:@"_vnc._tcp."
name:[NSString stringWithCString:theServer->desktopName]
port:(int) theServer->rfbPort];
[vncService setDelegate:rendezvousDelegate];
[vncService publish];
}
// else
// NSLog(@"Bonjour (_vnc._tcp) - Disabled");
}
+ (void) rfbPoll {
// Check if keyboardLayoutRef has changed
if (keyboardLoading) {
KeyboardLayoutRef currentKeyboardLayoutRef;
if (KLGetCurrentKeyboardLayout(¤tKeyboardLayoutRef) == noErr) {
if (currentKeyboardLayoutRef != loadedKeyboardRef) {
loadedKeyboardRef = currentKeyboardLayoutRef;
[self loadKeyboard: loadedKeyboardRef forServer:theServer];
}
}
}
}
+ (void) rfbReceivedClientMessage {
return;
}
+ (void) rfbShutdown {
NSLog(@"Unloading Jaguar Extensions");
[rfbService stop];
[vncService stop];
}
@end
@implementation RendezvousDelegate
// Sent when the service is about to publish
- (void)netServiceWillPublish:(NSNetService *)netService {
NSLog(@"Registering Bonjour Service(%@) - %@", [netService type], [netService name]);
}
// Sent if publication fails
- (void)netService:(NSNetService *)netService didNotPublish:(NSDictionary *)errorDict {
NSLog(@"An error occurred with service %@.%@.%@, error code = %@",
[netService name], [netService type], [netService domain], [errorDict objectForKey:NSNetServicesErrorCode]);
}
// Sent when the service stops
- (void)netServiceDidStop:(NSNetService *)netService {
NSLog(@"Disabling Bonjour Service - %@", [netService name]);
// You may want to do something here, such as updating a user interfac
}
@end
#include <netdb.h>
@implementation NSProcessInfo (VNCExtension)
- (CGDirectDisplayID) CGMainDisplayID {
return CGMainDisplayID();
}
@end