More bugfixes in networking. Added password panels. Fixed bug with 0:60 time.
[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     }
37     return self;
38 }
39
40 - (void)dealloc
41 {
42     [self disconnect];
43     if (serverOn) {
44         [serverConnection release];
45     }
46     [serverPass release];
47     [clientPass release];
48     [clientProxy release];
49     [remoteServices release];
50     [browser release];
51     [service stop];
52     [service release];
53     [super dealloc];
54 }
55
56 - (void)startRemoteServerSearch
57 {
58     [browser searchForServicesOfType:@"_mttp._tcp." inDomain:@""];
59     [remoteServices release];
60     remoteServices = [[NSMutableArray alloc] init];
61 }
62
63 - (void)stopRemoteServerSearch
64 {
65     [browser stop];
66 }
67
68 - (void)setServerStatus:(BOOL)status
69 {
70     if (!serverOn && status) {
71         NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:@"sharedPlayerName"];
72         unsigned char buffer;
73         NSData *fullPass;
74         //Turn on
75         NS_DURING
76             serverPort = [[NSSocketPort alloc] initWithTCPPort:SERVER_PORT];
77             serverConnection = [[NSConnection alloc] initWithReceivePort:serverPort
78                                                      sendPort:serverPort];
79             [serverConnection setRootObject:[[NetworkObject alloc] init]];
80             [serverConnection registerName:@"ITMTPlayerHost"];
81         NS_HANDLER
82             [[serverConnection rootObject] release];
83             [serverConnection release];
84             [serverPort release];
85             ITDebugLog(@"Error starting server!");
86         NS_ENDHANDLER
87         ITDebugLog(@"Started server.");
88         if (!name) {
89             name = @"MenuTunes Shared Player";
90         }
91         service = [[NSNetService alloc] initWithDomain:@""
92                                         type:@"_mttp._tcp."
93                                         name:name
94                                         port:SERVER_PORT];
95         fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"sharedPlayerPassword"];
96         if (fullPass) {
97             [fullPass getBytes:&buffer range:NSMakeRange(6, 4)];
98             [serverPass release];
99             serverPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)];
100         } else {
101             serverPass = nil;
102         }
103         [service publish];
104         serverOn = YES;
105     } else if (serverOn && !status && [serverConnection isValid]) {
106         //Turn off
107         [service stop];
108         [serverConnection registerName:nil];
109         [[serverConnection rootObject] release];
110         [serverConnection release];
111         ITDebugLog(@"Stopped server.");
112         serverOn = NO;
113     }
114 }
115
116 - (int)connectToHost:(NSString *)host
117 {
118     NSData *fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"];
119     unsigned char buffer;
120     ITDebugLog(@"Connecting to host: %@", host);
121     [remoteHost release];
122     remoteHost = [host copy];
123     if (fullPass) {
124         [fullPass getBytes:&buffer range:NSMakeRange(6, 4)];
125         [clientPass release];
126         clientPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)];
127     } else {
128         clientPass = nil;
129     }
130     NS_DURING
131         clientPort = [[NSSocketPort alloc] initRemoteWithTCPPort:SERVER_PORT
132                                            host:host];
133         clientConnection = [[NSConnection connectionWithReceivePort:nil sendPort:clientPort] retain];
134         [clientConnection setReplyTimeout:5];
135         clientProxy = [[clientConnection rootProxy] retain];
136     NS_HANDLER
137         [clientConnection release];
138         [clientPort release];
139         ITDebugLog(@"Connection to host failed: %@", host);
140         return NO;
141     NS_ENDHANDLER
142     
143     if (!clientProxy) {
144         ITDebugLog(@"Null proxy! Couldn't connect!");
145         [self disconnect];
146         return NO;
147     }
148     
149     if ([clientProxy requiresPassword]) {
150         ITDebugLog(@"Server requires password.");
151         //Check to see if a password is set in defaults
152         if ([[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"] == nil) {
153             ITDebugLog(@"Asking for password.");
154             if (![[PreferencesController sharedPrefs] showPasswordPanel]) {
155                 ITDebugLog(@"Giving up connection attempt.");
156                 [self disconnect];
157                 return -1;
158             }
159         }
160         
161         //Send the password
162         ITDebugLog(@"Sending password.");
163         while (![clientProxy sendPassword:[[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"]]) {
164             ITDebugLog(@"Invalid password!");
165             if (![[PreferencesController sharedPrefs] showInvalidPasswordPanel]) {
166                 ITDebugLog(@"Giving up connection attempt.");
167                 [self disconnect];
168                 return -1;
169             }
170         }
171     }
172     
173     ITDebugLog(@"Connected to host: %@", host);
174     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disconnect) name:NSConnectionDidDieNotification object:clientConnection];
175     connectedToServer = YES;
176     return 1;
177 }
178
179 - (BOOL)disconnect
180 {
181     ITDebugLog(@"Disconnecting from host.");
182     connectedToServer = NO;
183     [remoteHost release];
184     remoteHost = nil;
185     [[NSNotificationCenter defaultCenter] removeObserver:self];
186     [clientProxy release];
187     [clientConnection release];
188     return YES;
189 }
190
191 - (BOOL)checkForServerAtHost:(NSString *)host
192 {
193     NSData *fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"];
194     unsigned char buffer;
195     NSConnection *testConnection;
196     NSSocketPort *testPort;
197     NetworkObject *tempProxy;
198     ITDebugLog(@"Checking for shared remote at %@.", host);
199     if (fullPass) {
200         [fullPass getBytes:&buffer range:NSMakeRange(6, 4)];
201         [clientPass release];
202         clientPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)];
203     } else {
204         clientPass = nil;
205     }
206     
207     NS_DURING
208         testPort = [[NSSocketPort alloc] initRemoteWithTCPPort:SERVER_PORT
209                                          host:host];
210         testConnection = [[NSConnection connectionWithReceivePort:nil sendPort:testPort] retain];
211         [testConnection setReplyTimeout:2];
212         tempProxy = (NetworkObject *)[testConnection rootProxy];
213         [tempProxy serverName];
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 (!clientProxy) {
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 YES;
230 }
231
232 - (BOOL)isServerOn
233 {
234     return serverOn;
235 }
236
237 - (BOOL)isClientConnected
238 {
239     return clientConnected;
240 }
241
242 - (BOOL)isConnectedToServer
243 {
244     return connectedToServer;
245 }
246
247 - (NSString *)remoteHost
248 {
249     return remoteHost;
250 }
251
252 - (NetworkObject *)networkObject
253 {
254     return clientProxy;
255 }
256
257 - (NSArray *)remoteServices
258 {
259     return remoteServices;
260 }
261
262 - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
263 {
264     ITDebugLog(@"Found service named %@.", [aNetService name]);
265     [remoteServices addObject:aNetService];
266     [aNetService setDelegate:self];
267     [aNetService resolve];
268     if (!moreComing) {
269         [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
270     }
271 }
272
273 - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService*)aNetService moreComing:(BOOL)moreComing
274 {
275     ITDebugLog(@"Removed service named %@.", [aNetService name]);
276     [remoteServices removeObject:aNetService];
277     if (!moreComing) {
278         [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
279     }
280 }
281
282 - (void)netServiceDidResolveAddress:(NSNetService *)sender
283 {
284     ITDebugLog(@"Resolved service named %@.", [sender name]);
285     NSLog(@"Resolved service named %@.", [sender name]);
286     [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil];
287     [sender stop];
288 }
289
290 - (void)netServiceWillResolve:(NSNetService *)sender
291 {
292     ITDebugLog(@"Resolving service named %@.", [sender name]);
293 }
294
295 - (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary *)errorDict
296 {
297     ITDebugLog(@"Error resolving service %@.", errorDict);
298 }
299
300 @end