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