Merge branch 'master' of git://github.com/ksuther/MenuTunes
[MenuTunes.git] / NetworkController.m
1 #import "NetworkController.h"
2 #import "MainController.h"
3 #import "NetworkObject.h"
4 #import "PreferencesController.h"
5 #import <ITFoundation/ITDebug.h>
6 #import <ITFoundation/ITFoundation.h>
7
8 static NetworkController *sharedController;
9
10 @implementation NetworkController
11
12 + (NetworkController *)sharedController
13 {
14     return sharedController;
15 }
16
17 - (id)init
18 {
19     if ( (self = [super init]) ) {
20         sharedController = self;
21         browser = [[NSNetServiceBrowser alloc] init];
22         [browser setDelegate:self];
23         rootObject = [[NetworkObject alloc] init];
24         serverPort = [[NSSocketPort alloc] initWithTCPPort:SERVER_PORT];
25     }
26     return self;
27 }
28
29 - (void)dealloc
30 {
31     [self disconnect];
32     if (serverOn) {
33         [serverConnection release];
34     }
35     [serverPass release];
36     [clientPass release];
37     [serverPort release];
38     [rootObject release];
39     [clientProxy release];
40     [remoteServices release];
41     [browser release];
42     [service stop];
43     [service release];
44     [super dealloc];
45 }
46
47 - (void)startRemoteServerSearch
48 {
49     [browser searchForServicesOfType:@"_mttp._tcp." inDomain:@""];
50     [remoteServices release];
51     remoteServices = [[NSMutableArray alloc] init];
52 }
53
54 - (void)stopRemoteServerSearch
55 {
56     [browser stop];
57 }
58
59 - (void)setServerStatus:(BOOL)status
60 {
61     if (!serverOn && status) {
62         NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:@"sharedPlayerName"];
63         unsigned char buffer;
64         NSData *fullPass;
65         //Turn on
66         NS_DURING
67             serverConnection = [[NSConnection alloc] initWithReceivePort:serverPort
68                                                      sendPort:serverPort];
69             [serverConnection setRootObject:rootObject];
70             [rootObject makeValid];
71             [serverConnection registerName:@"ITMTPlayerHost"];
72         NS_HANDLER
73             [serverConnection setRootObject:nil];
74             [serverConnection release];
75             [serverPort release];
76             ITDebugLog(@"Error starting server!");
77             return;
78         NS_ENDHANDLER
79         ITDebugLog(@"Started server.");
80         if (!name) {
81             name = @"MenuTunes Shared Player";
82         }
83         service = [[NSNetService alloc] initWithDomain:@""
84                                         type:@"_mttp._tcp."
85                                         name:name
86                                         port:SERVER_PORT];
87         fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"sharedPlayerPassword"];
88         if ([fullPass length]) {
89             [fullPass getBytes:&buffer range:NSMakeRange(6, 4)];
90             [serverPass release];
91             serverPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)];
92         } else {
93             serverPass = nil;
94         }
95         [service publish];
96         serverOn = YES;
97         ITDebugLog(@"Server service published.");
98     } else if (serverOn && !status && [serverConnection isValid]) {
99         //Turn off
100         [service stop];
101         [service release];
102         [rootObject invalidate];
103         [serverConnection registerName:nil];
104         [serverConnection invalidate];
105         //[serverConnection setRootObject:nil];
106         //[[serverConnection sendPort] autorelease];
107         [serverConnection release];
108         ITDebugLog(@"Stopped server.");
109         serverOn = NO;
110     }
111 }
112
113 - (int)connectToHost:(NSString *)host
114 {
115     NSData *fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"];
116     unsigned char buffer;
117     ITDebugLog(@"Connecting to host: %@", host);
118     [remoteHost release];
119     remoteHost = [host copy];
120     if (fullPass) {
121         [fullPass getBytes:&buffer range:NSMakeRange(6, 4)];
122         [clientPass release];
123         clientPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)];
124     } else {
125         clientPass = nil;
126     }
127     NS_DURING
128         clientPort = [[NSSocketPort alloc] initRemoteWithTCPPort:SERVER_PORT
129                                            host:host];
130         clientConnection = [[NSConnection connectionWithReceivePort:nil sendPort:clientPort] retain];
131         [clientConnection setReplyTimeout:10];
132         clientProxy = [[clientConnection rootProxy] retain];
133         connectedToServer = YES;
134     NS_HANDLER
135         [clientConnection release];
136         [clientPort release];
137         ITDebugLog(@"Connection to host failed: %@", host);
138         return 0;
139     NS_ENDHANDLER
140     
141     if (!clientProxy) {
142         ITDebugLog(@"Null proxy! Couldn't connect!");
143         [self disconnect];
144         return 0;
145     }
146     
147     if ([clientProxy requiresPassword]) {
148         ITDebugLog(@"Server requires password.");
149         //Check to see if a password is set in defaults
150         if ([[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"] == nil) {
151             ITDebugLog(@"Asking for password.");
152             if (![[PreferencesController sharedPrefs] showPasswordPanel]) {
153                 ITDebugLog(@"Giving up connection attempt.");
154                 [self disconnect];
155                 return -1;
156             }
157         }
158         
159         //Send the password
160         ITDebugLog(@"Sending password.");
161         while (![clientProxy sendPassword:[[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"]]) {
162             ITDebugLog(@"Invalid password!");
163             if (![[PreferencesController sharedPrefs] showInvalidPasswordPanel]) {
164                 ITDebugLog(@"Giving up connection attempt.");
165                 [self disconnect];
166                 return -1;
167             }
168         }
169     }
170     
171     ITDebugLog(@"Connected to host: %@", host);
172     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disconnect) name:NSConnectionDidDieNotification object:clientConnection];
173     return 1;
174 }
175
176 - (BOOL)disconnect
177 {
178     ITDebugLog(@"Disconnecting from host.");
179     connectedToServer = NO;
180     [remoteHost release];
181     remoteHost = nil;
182     [[NSNotificationCenter defaultCenter] removeObserver:self];
183     [clientProxy release];
184     [clientConnection release];
185     return YES;
186 }
187
188 - (BOOL)checkForServerAtHost:(NSString *)host
189 {
190     NSData *fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"];
191     unsigned char buffer;
192     NSConnection *testConnection = nil;
193     NSSocketPort *testPort = nil;
194     NetworkObject *tempProxy;
195     BOOL valid;
196     ITDebugLog(@"Checking for shared remote at %@.", host);
197     if (fullPass) {
198         [fullPass getBytes:&buffer range:NSMakeRange(6, 4)];
199         [clientPass release];
200         clientPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)];
201     } else {
202         clientPass = nil;
203     }
204     
205     NS_DURING
206         testPort = [[NSSocketPort alloc] initRemoteWithTCPPort:SERVER_PORT
207                                          host:host];
208         testConnection = [[NSConnection connectionWithReceivePort:nil sendPort:testPort] retain];
209         [testConnection setReplyTimeout:5];
210         [testConnection setRequestTimeout:5];
211         tempProxy = (NetworkObject *)[testConnection rootProxy];
212         [tempProxy serverName];
213         valid = [tempProxy isValid];
214     NS_HANDLER
215         ITDebugLog(@"Connection to host failed: %@", host);
216         [testConnection release];
217         [testPort release];
218         return NO;
219     NS_ENDHANDLER
220     
221     if (!tempProxy) {
222         ITDebugLog(@"Null proxy! Couldn't connect!");
223         [testConnection release];
224         [testPort release];
225         return NO;
226     }
227     [testConnection release];
228     [testPort release];
229     return valid;
230 }
231
232 - (void)resetServerName
233 {
234     if ([self isServerOn]) {
235         [service stop];
236         [service release];
237         service = [[NSNetService alloc] initWithDomain:@""
238                                         type:@"_mttp._tcp."
239                                         name:[[NSUserDefaults standardUserDefaults] stringForKey:@"sharedPlayerName"]
240                                         port:SERVER_PORT];
241     }
242 }
243
244 - (BOOL)isServerOn
245 {
246     return serverOn;
247 }
248
249 - (BOOL)isClientConnected
250 {
251     return clientConnected;
252 }
253
254 - (BOOL)isConnectedToServer
255 {
256     return connectedToServer;
257 }
258
259 - (NSString *)remoteHost
260 {
261     return remoteHost;
262 }
263
264 - (NetworkObject *)networkObject
265 {
266     return clientProxy;
267 }
268
269 - (NSArray *)remoteServices
270 {
271     return remoteServices;
272 }
273
274 - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
275 {
276     ITDebugLog(@"Found service named %@.", [aNetService name]);
277     [remoteServices addObject:aNetService];
278     [aNetService setDelegate:self];
279         //Figure out if it responds to the 10.4 method
280         if ([aNetService respondsToSelector:@selector(resolveWithTimeout:)]) {
281                 (void)[aNetService resolveWithTimeout:5.0];
282         } else {
283                 [aNetService resolve];
284         }
285     if (!moreComing) {
286         [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
287     }
288 }
289
290 - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService*)aNetService moreComing:(BOOL)moreComing
291 {
292     ITDebugLog(@"Removed service named %@.", [aNetService name]);
293     [remoteServices removeObject:aNetService];
294     if (!moreComing) {
295         [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
296     }
297 }
298
299 - (void)netServiceDidResolveAddress:(NSNetService *)sender
300 {
301     ITDebugLog(@"Resolved service named %@.", [sender name]);
302     [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
303     if ([[NSUserDefaults standardUserDefaults] boolForKey:@"useSharedPlayer"] && !connectedToServer) {
304         [[MainController sharedController] checkForRemoteServerAndConnectImmediately:NO];
305     }
306     [sender stop];
307 }
308
309 - (void)netServiceWillResolve:(NSNetService *)sender
310 {
311     ITDebugLog(@"Resolving service named %@.", [sender name]);
312 }
313
314 - (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict
315 {
316     ITDebugLog(@"Error resolving service %@.", errorDict);
317 }
318
319 @end