From d11efc8d287ca1643e9ac6a7b561cad7cd659bda Mon Sep 17 00:00:00 2001 From: Kent Sutherland Date: Tue, 28 Oct 2003 03:20:58 +0000 Subject: [PATCH] Committing more stuff. Added password encryption with SHA, partially added password checking. Added checking for servers that quit and reopen. Added more UI stuff. Added more more more more more. It's gonna be HUUUUUUGEEEE!!!! --- English.lproj/Preferences.nib/classes.nib | 2 + English.lproj/Preferences.nib/info.nib | 2 - .../Preferences.nib/keyedobjects.nib | Bin 39686 -> 38454 bytes ITMTRemote.h | 8 ++ ITMTRemote.m | 8 ++ MainController.m | 47 ++++++++- NetworkController.h | 4 + NetworkController.m | 89 +++++++++++++++++- PreferencesController.h | 2 + PreferencesController.m | 56 ++++++++--- StatusWindowController.h | 1 + StatusWindowController.m | 15 +++ libValidate.a | Bin 8032 -> 8032 bytes 13 files changed, 214 insertions(+), 20 deletions(-) diff --git a/English.lproj/Preferences.nib/classes.nib b/English.lproj/Preferences.nib/classes.nib index ccf6333..68f916a 100755 --- a/English.lproj/Preferences.nib/classes.nib +++ b/English.lproj/Preferences.nib/classes.nib @@ -24,6 +24,7 @@ hotKeysTableView = NSTableView; launchAtLoginCheckbox = NSButton; launchPlayerAtLaunchCheckbox = NSButton; + locationTextField = NSTextField; manualView = NSView; menuTableView = CustomMenuTableView; nameCheckbox = NSButton; @@ -33,6 +34,7 @@ selectPlayerBox = NSBox; selectPlayerSheet = NSPanel; selectSharedPlayerButton = NSButton; + selectedPlayerTextField = NSTextField; shareMenuTunesCheckbox = NSButton; sharingTableView = NSTableView; showOnChangeCheckbox = NSButton; diff --git a/English.lproj/Preferences.nib/info.nib b/English.lproj/Preferences.nib/info.nib index 4695b7b..d4a5e32 100755 --- a/English.lproj/Preferences.nib/info.nib +++ b/English.lproj/Preferences.nib/info.nib @@ -19,8 +19,6 @@ IBOpenObjects - 639 - 634 6 IBSystem Version diff --git a/English.lproj/Preferences.nib/keyedobjects.nib b/English.lproj/Preferences.nib/keyedobjects.nib index 9cae2d6c838d6048a5ff4634f1d543c704845a1d..88ffb88a8b3b114fc2e8a505979ec0563acd8a57 100755 GIT binary patch literal 38454 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

r)*H!&@x7uuuM{xR#sG| zE2}F*%J8zqWgE+S$_|xXF1uRxciGdjZ{?ol#PWc0LAkhGUal$6F3&5UQ9iqTZux@p z#pRvl>&nlUUn>8-{CfGl@_))d7(I*>qn|Or7-&p3rW)18EMu;*#ON}%7~72Njc1JK zjaQ7G#r}$G6^|>PnFgB3CaNja6mF84 zVojN*9Fx&xHd#$orsbwprZuMZrf$<_(^k_jre94LOjk{}O@EvIHGMICHxD)YnElKF z=0J0>ImFC0^UP`H40EQr(%fclH+Pzkn2(!Jna`U4wumibERhzeMQ%}AGA%8Z$ri*i z%hF+)Z&_>UvGiH?S`JtqTb@~7T0U0#RQgr=S28PEmD0+F%BD(JB~;l~xv{dRvbS=3 z>oDs`tEZJ<4YNjA1y-fiVzpUO>lAC7wbOdUdfa;3`olKBHrO`IHqyqjrPx|* zlWm9%x3$`)+veF8+BVoW+4^kfZO?75>_hAUc7a`Nm)kY=Y<8_K?Z@mV?U(F-*zegN+P_pWt5{W`RpC|fRpu&dm7}VzYDU$%s>4;ss!mp& zsd`xTxawKe%c?ik!>h&B3DwEf#Mt~k5*r;{-gTu>VK=h zI7T@D2g@0Gvm53%oNPEVVekac#=J&dQ+<=$Iomncxxl&Dxy-rJ+38&8+~C~g+~VBk+~M5m z+~eHu{LOj9dE9x*dDeNsdD(f@`G@mQ=N;!g=R@aX=QHO^=Nsoc=SSyf=Qrnn;6QK) zI2;@W0w4+W27N$3FaQh$gTWAx3-UlAC;`WUQJ@Tr1>?aaFa=Bp)nFEw3yuf1Uo0+)g-z}4VdunXJ>_JF6SkTmxK#UBg@> zU7jwYi|nGhd|m!7riuYu;acU|;@ayv?z-Z7;`-7& zqM6YEEe$-(1mbZ*FXcn-?^%ZQkB|s`*Ou{pMHhfo{O<;|_Fl-BIooceY#a zu60jzx4P%Km%3NGd)@oom)sBBZ(4@6P+GVxF)cYQ6)iO_V9Vr|)|Oc`VBe)9fwXqXQ2zwW#}sO2lOX&2f7D6gdRiBpqJ1a=pFPC`V4)8{(}d? zL*U`?C>VfAus7@j`@sQlARG*bz+9LI3tUYcSumi4xC%{g)8J^g$NTcu+xD9THXTcr)9`qu3DZBz+-7k%H^}C}za4)ljhzn^!CL;)fBdy4EWF|5PnTISymLSWKRmd7-J<^SAMz$iqAipBJ zkiEzOly=cA)doMd%WAIl2m6gRVz6pqtPw=r(ja z+K28&_n`;T!{{;eBzgutk6uKtpx4kF=q>avdLMm+K0%+OFVQ#XJM<&^8U2R-K!0Kb zu_4%SY!v2+5iv4G#e6Y;jES)@4i<`qV|+}ANwBe46eh#um;y`0lvo<3!ZcVmmWPeU z3bA5LkCkB+m<6+8)mSaofHh$t=Ef#rFot1Mu{Nw7n}u~?^Rb245^OoP3R{D%$GWl2 z*jDTp>{o0Twii2q9m0-cC$Q7lIqV{K1-pjbz;0o8vHRFV>@oHXdx^cl-eDiGPuN%N z2j1Vn#fRY|aZj9pd*KwEhSPBd9)z>;P&^#x;X+)3kHw>K87{{acp|RE)9?&D6VJi( z@j|>9*W+cl5jW$NxE*)kb@&9l33uTw_+%Wxal93uj?cvB;Pdc>_!4|Mz6xK1ufsRs foA51oFTNW;&_BZ8AN{vv{x>{;|I7dX;^+PcfpI3X diff --git a/ITMTRemote.h b/ITMTRemote.h index 82da725..91e4413 100755 --- a/ITMTRemote.h +++ b/ITMTRemote.h @@ -139,6 +139,14 @@ typedef enum { */ - (NSImage *)remoteIcon; +/*! + * @method sharedRemoteName + * @abstract Returns the shared remote's name. + * @discussion This title is shown while the user is selecting which shared remote to use. This is for informational purposes only, should not be overridden. + * @result An NSString containing the name of the shared remote. + */ +- (NSString *)sharedRemoteName; + /*! * @method begin * @abstract Sent when the remote should begin operation. diff --git a/ITMTRemote.m b/ITMTRemote.m index 96fecda..950e3d6 100755 --- a/ITMTRemote.m +++ b/ITMTRemote.m @@ -22,6 +22,14 @@ return nil; } +- (NSString *)sharedRemoteName +{ + NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:@"sharedPlayerName"]; + if (!name) + name = @"MenuTunes Shared Player"; + return name; +} + - (BOOL)begin { return NO; diff --git a/MainController.m b/MainController.m index f47c01b..2f4f820 100755 --- a/MainController.m +++ b/MainController.m @@ -61,8 +61,10 @@ static MainController *sharedController; networkController = [[NetworkController alloc] init]; if ([df boolForKey:@"enableSharing"]) { [self setServerStatus:YES]; - } else if ([df boolForKey:@"useSharedPlayer"] && [df boolForKey:@"alwaysUseSharedPlayer"]) { - [self connectToServer]; + } else if ([df boolForKey:@"useSharedPlayer"]) { + if (![self connectToServer]) { + [NSTimer scheduledTimerWithTimeInterval:45 target:self selector:@selector(checkForRemoteServer:) userInfo:nil repeats:YES]; + } } //Setup for notification of the remote player launching or quitting @@ -942,12 +944,15 @@ static MainController *sharedController; - (BOOL)connectToServer { + ITDebugLog(@"Attempting to connect to shared remote."); //Connect if ([networkController connectToHost:[df stringForKey:@"sharedPlayerHost"]]) { currentRemote = [networkController sharedRemote]; [refreshTimer invalidate]; + ITDebugLog(@"Connection successful."); return YES; } else { + ITDebugLog(@"Connection failed."); currentRemote = [remoteArray objectAtIndex:0]; return NO; } @@ -955,6 +960,7 @@ static MainController *sharedController; - (BOOL)disconnectFromServer { + ITDebugLog(@"Disconnecting from shared remote."); //Disconnect currentRemote = [remoteArray objectAtIndex:0]; [networkController disconnect]; @@ -962,14 +968,47 @@ static MainController *sharedController; return YES; } +- (void)checkForRemoteServer:(NSTimer *)timer +{ + ITDebugLog(@"Checking for remote server."); + if ([networkController checkForServerAtHost:[df stringForKey:@"sharedPlayerHost"]]) { + ITDebugLog(@"Remote server found."); + [timer invalidate]; + [[StatusWindowController sharedController] showReconnectQueryWindow]; + } else { + ITDebugLog(@"Remote server not found."); + } +} + - (void)networkError:(NSException *)exception { ITDebugLog(@"Remote exception thrown: %@: %@", [exception name], [exception reason]); - NSRunAlertPanel(@"Remote MenuTunes Disconnected", @"The MenuTunes server you were connected to stopped responding or quit. MenuTunes will revert back to the local player.", @"OK", nil, nil); + NSLog(@"Remote exception thrown: %@: %@", [exception name], [exception reason]); + NSRunCriticalAlertPanel(@"Remote MenuTunes Disconnected", @"The MenuTunes server you were connected to stopped responding or quit. MenuTunes will revert back to the local player.", @"OK", nil, nil); if ([networkController isConnectedToServer] && [self disconnectFromServer]) { + if ([[exception name] isEqualToString:NSPortTimeoutException]) { + [NSTimer scheduledTimerWithTimeInterval:45 target:self selector:@selector(checkForRemoteServer:) userInfo:nil repeats:YES]; + } } else { - ITDebugLog(@"CRITICAL ERROR DISCONNECTING!"); + ITDebugLog(@"CRITICAL ERROR, DISCONNECTING!"); + } +} + +- (void)reconnect +{ + if (![self connectToServer]) { + [NSTimer scheduledTimerWithTimeInterval:45 target:self selector:@selector(checkForRemoteServer:) userInfo:nil repeats:YES]; } + [[StatusWindow sharedWindow] setLocked:NO]; + [[StatusWindow sharedWindow] vanish:self]; + [[StatusWindow sharedWindow] setIgnoresMouseEvents:YES]; +} + +- (void)cancelReconnect +{ + [[StatusWindow sharedWindow] setLocked:NO]; + [[StatusWindow sharedWindow] vanish:self]; + [[StatusWindow sharedWindow] setIgnoresMouseEvents:YES]; } /*************************************************************************/ diff --git a/NetworkController.h b/NetworkController.h index de3801b..9a4024b 100755 --- a/NetworkController.h +++ b/NetworkController.h @@ -25,7 +25,9 @@ NSConnection *serverConnection, *clientConnection; NSSocketPort *serverPort, *clientPort; + NSString *remoteHost; BOOL serverOn, clientConnected, connectedToServer; + NSData *serverPass, *clientPass; ITMTRemote *clientProxy; } + (NetworkController *)sharedController; @@ -35,10 +37,12 @@ - (void)setServerStatus:(BOOL)status; - (BOOL)connectToHost:(NSString *)host; +- (BOOL)checkForServerAtHost:(NSString *)host; - (BOOL)disconnect; - (BOOL)isServerOn; - (BOOL)isClientConnected; - (BOOL)isConnectedToServer; +- (NSString *)remoteHost; - (ITMTRemote *)sharedRemote; - (NSArray *)remoteServices; diff --git a/NetworkController.m b/NetworkController.m index d6bfca0..fb3976c 100755 --- a/NetworkController.m +++ b/NetworkController.m @@ -43,6 +43,8 @@ static NetworkController *sharedController; [serverConnection invalidate]; [serverConnection release]; } + [serverPass release]; + [clientPass release]; [clientProxy release]; [remoteServices release]; [browser release]; @@ -67,6 +69,8 @@ static NetworkController *sharedController; { if (!serverOn && status) { NSString *name = [[NSUserDefaults standardUserDefaults] stringForKey:@"sharedPlayerName"]; + unsigned char buffer; + NSData *fullPass; //Turn on NS_DURING serverPort = [[NSSocketPort alloc] initWithTCPPort:SERVER_PORT]; @@ -76,6 +80,8 @@ static NetworkController *sharedController; [serverConnection registerName:@"ITMTPlayerHost"]; [serverConnection setDelegate:self]; NS_HANDLER + [serverConnection release]; + [serverPort release]; ITDebugLog(@"Error starting server!"); NS_ENDHANDLER ITDebugLog(@"Started server."); @@ -86,6 +92,14 @@ static NetworkController *sharedController; type:@"_mttp._tcp." name:name port:SERVER_PORT]; + fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"sharedPlayerPassword"]; + if (fullPass) { + [fullPass getBytes:&buffer range:NSMakeRange(6, 4)]; + [serverPass release]; + serverPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)]; + } else { + serverPass = nil; + } [service publish]; serverOn = YES; } else if (serverOn && !status && [serverConnection isValid]) { @@ -102,17 +116,30 @@ static NetworkController *sharedController; - (BOOL)connectToHost:(NSString *)host { + NSData *fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"]; + unsigned char buffer; ITDebugLog(@"Connecting to host: %@", host); + remoteHost = [host copy]; + if (fullPass) { + [fullPass getBytes:&buffer range:NSMakeRange(6, 4)]; + [clientPass release]; + clientPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)]; + } else { + clientPass = nil; + } NS_DURING clientPort = [[NSSocketPort alloc] initRemoteWithTCPPort:SERVER_PORT host:host]; clientConnection = [[NSConnection connectionWithReceivePort:nil sendPort:clientPort] retain]; + [clientConnection setDelegate:self]; + [clientConnection setReplyTimeout:5]; clientProxy = [[clientConnection rootProxy] retain]; NS_HANDLER + [clientConnection release]; + [clientPort release]; ITDebugLog(@"Connection to host failed: %@", host); return NO; NS_ENDHANDLER - [clientConnection setReplyTimeout:5]; ITDebugLog(@"Connected to host: %@", host); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disconnect) name:NSConnectionDidDieNotification object:clientConnection]; connectedToServer = YES; @@ -123,6 +150,8 @@ static NetworkController *sharedController; { ITDebugLog(@"Disconnecting from host."); connectedToServer = NO; + [remoteHost release]; + remoteHost = nil; [[NSNotificationCenter defaultCenter] removeObserver:self]; [clientProxy release]; [clientConnection invalidate]; @@ -130,6 +159,43 @@ static NetworkController *sharedController; return YES; } +- (BOOL)checkForServerAtHost:(NSString *)host +{ + NSData *fullPass = [[NSUserDefaults standardUserDefaults] dataForKey:@"connectPassword"]; + unsigned char buffer; + NSConnection *testConnection; + NSSocketPort *testPort; + NSDistantObject *tempProxy; + ITDebugLog(@"Checking for shared remote at %@.", host); + if (fullPass) { + [fullPass getBytes:&buffer range:NSMakeRange(6, 4)]; + [clientPass release]; + clientPass = [[NSData alloc] initWithBytes:&buffer length:strlen(&buffer)]; + } else { + clientPass = nil; + } + + NS_DURING + testPort = [[NSSocketPort alloc] initRemoteWithTCPPort:SERVER_PORT + host:host]; + testConnection = [[NSConnection connectionWithReceivePort:nil sendPort:testPort] retain]; + [testConnection setReplyTimeout:2]; + tempProxy = [testConnection rootProxy]; + [testConnection setDelegate:self]; + [tempProxy sharedRemoteName]; + NS_HANDLER + ITDebugLog(@"Connection to host failed: %@", host); + [testConnection invalidate]; + [testConnection release]; + [testPort release]; + return NO; + NS_ENDHANDLER + [testConnection invalidate]; + [testConnection release]; + [testPort release]; + return YES; +} + - (BOOL)isServerOn { return serverOn; @@ -145,6 +211,11 @@ static NetworkController *sharedController; return connectedToServer; } +- (NSString *)remoteHost +{ + return remoteHost; +} + - (ITMTRemote *)sharedRemote { return (ITMTRemote *)clientProxy; @@ -155,6 +226,21 @@ static NetworkController *sharedController; return remoteServices; } +/*- (BOOL)authenticateComponents:(NSArray*)components withData:(NSData *)authenticationData +{ + return YES; + if (![[NSUserDefaults standardUserDefaults] boolForKey:@"enableSharingPassword"] || [authenticationData isEqualToData:serverPass]) { + return YES; + } else { + return NO; + } +} + +- (NSData *)authenticationDataForComponents:(NSArray *)components +{ + return clientPass; +}*/ + - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing { ITDebugLog(@"Found service named %@.", [aNetService name]); @@ -180,6 +266,7 @@ static NetworkController *sharedController; ITDebugLog(@"Resolved service named %@.", [sender name]); NSLog(@"Resolved service named %@.", [sender name]); [[NSNotificationCenter defaultCenter] postNotificationName:@"ITMTFoundNetService" object:nil]; + [sender stop]; } - (void)netServiceWillResolve:(NSNetService *)sender diff --git a/PreferencesController.h b/PreferencesController.h index e8dcb81..394934a 100755 --- a/PreferencesController.h +++ b/PreferencesController.h @@ -27,12 +27,14 @@ IBOutlet NSTableView *hotKeysTableView; IBOutlet NSButton *launchAtLoginCheckbox; IBOutlet NSButton *launchPlayerAtLaunchCheckbox; + IBOutlet NSTextField *locationTextField; IBOutlet NSView *manualView; IBOutlet CustomMenuTableView *menuTableView; IBOutlet NSButton *nameCheckbox; IBOutlet NSTextField *nameTextField; IBOutlet NSTextField *passwordTextField; IBOutlet NSButton *ratingCheckbox; + IBOutlet NSTextField *selectedPlayerTextField; IBOutlet NSBox *selectPlayerBox; IBOutlet NSPanel *selectPlayerSheet; IBOutlet NSButton *selectSharedPlayerButton; diff --git a/PreferencesController.m b/PreferencesController.m index 85370d9..970ba88 100755 --- a/PreferencesController.m +++ b/PreferencesController.m @@ -4,8 +4,10 @@ #import "StatusWindow.h" #import "StatusWindowController.h" #import "CustomMenuTableView.h" -#import "netinet/in.h" -#import "arpa/inet.h" + +#import +#import +#import #import #import @@ -193,7 +195,18 @@ static PreferencesController *prefs = nil; } else if ( [sender tag] == 5020 ) { [df setBool:SENDER_STATE forKey:@"enableSharingPassword"]; } else if ( [sender tag] == 5030 ) { - [df setObject:[sender stringValue] forKey:@"sharedPlayerPassword"]; + //Set the server password + const char *instring = [[sender stringValue] UTF8String]; + const char *password = "password"; + unsigned char result; + NSData *hashedPass, *passwordStringHash; + SHA1(instring, strlen(instring), &result); + hashedPass = [NSData dataWithBytes:&result length:strlen(&result)]; + SHA1(password, strlen(password), &result); + passwordStringHash = [NSData dataWithBytes:&result length:strlen(&result)]; + if (![hashedPass isEqualToData:passwordStringHash]) { + [df setObject:hashedPass forKey:@"sharedPlayerPassword"]; + } } else if ( [sender tag] == 5040 ) { BOOL state = SENDER_STATE; [df setBool:state forKey:@"useSharedPlayer"]; @@ -210,10 +223,9 @@ static PreferencesController *prefs = nil; [controller disconnectFromServer]; } } else if ( [sender tag] == 5050 ) { - if ([sender clickedRow] > -1) { - //Set sharedPlayerHost - //[df setObject:[[[[NetworkController sharedController] remoteServices] objectAtIndex:[sender clickedRow]] objectForKey:@"ip"] forKey:@"sharedPlayerHost"]; - } + //Do nothing on table view click + } else if ( [sender tag] == 5051 ) { + [df setObject:[sender stringValue] forKey:@"sharedPlayerHost"]; } else if ( [sender tag] == 5060 ) { //Show selection sheet [NSApp beginSheet:selectPlayerSheet modalForWindow:window modalDelegate:self didEndSelector:NULL contextInfo:nil]; @@ -225,13 +237,20 @@ static PreferencesController *prefs = nil; frame.size.height = 273; [selectPlayerBox setContentView:zeroConfView]; [selectPlayerSheet setFrame:frame display:YES animate:YES]; - } else if ([selectPlayerBox contentView] != manualView) { + } else if ( ([sender indexOfItem:[sender selectedItem]] == 1) && ([selectPlayerBox contentView] != manualView) ){ NSRect frame = [selectPlayerSheet frame]; frame.origin.y += 58; frame.size.height = 215; + //[window makeFirstResponder:hostTextField]; [selectPlayerBox setContentView:manualView]; [selectPlayerSheet setFrame:frame display:YES animate:YES]; + [hostTextField selectText:nil]; } + } else if ( [sender tag] == 5150 ) { + const char *instring = [[sender stringValue] UTF8String]; + unsigned char result; + SHA1(instring, strlen(instring), &result); + [df setObject:[NSData dataWithBytes:&result length:strlen(&result)] forKey:@"connectPassword"]; } else if ( [sender tag] == 5110 ) { //Cancel [NSApp endSheet:selectPlayerSheet]; @@ -253,10 +272,12 @@ static PreferencesController *prefs = nil; } } - if (![controller connectToServer]) { - NSRunAlertPanel(@"Connection error.", @"The MenuTunes server you attempted to connect to was not responding. MenuTunes will revert back to the local player.", @"OK", nil, nil); - } else { + if ([controller connectToServer]) { [useSharedMenuTunesCheckbox setState:NSOnState]; + [selectedPlayerTextField setStringValue:[[[MainController sharedController] currentRemote] sharedRemoteName]]; + [locationTextField setStringValue:[[NetworkController sharedController] remoteHost]]; + } else { + NSRunAlertPanel(@"Connection error.", @"The MenuTunes server you attempted to connect to was not responding. MenuTunes will revert back to the local player.", @"OK", nil, nil); } } [df synchronize]; @@ -627,6 +648,7 @@ static PreferencesController *prefs = nil; } else if ([df boolForKey:@"useSharedPlayer"]) { [useSharedMenuTunesCheckbox setState:NSOnState]; [shareMenuTunesCheckbox setEnabled:NO]; + [selectSharedPlayerButton setEnabled:YES]; } [[NSNotificationCenter defaultCenter] addObserver:sharingTableView selector:@selector(reloadData) name:@"ITMTFoundNetService" object:nil]; @@ -639,12 +661,20 @@ static PreferencesController *prefs = nil; [selectPlayerBox setContentView:zeroConfView]; [usePasswordCheckbox setState:([df boolForKey:@"enableSharingPassword"] ? NSOnState : NSOffState)]; - if ([df stringForKey:@"sharedPlayerPassword"]) { - [passwordTextField setStringValue:@"*************"]; + if ([df dataForKey:@"sharedPlayerPassword"]) { + [passwordTextField setStringValue:@"password"]; } if ([df stringForKey:@"sharedPlayerHost"]) { [hostTextField setStringValue:[df stringForKey:@"sharedPlayerHost"]]; } + + if ([[NetworkController sharedController] isConnectedToServer]) { + [selectedPlayerTextField setStringValue:[[[MainController sharedController] currentRemote] sharedRemoteName]]; + [locationTextField setStringValue:[[NetworkController sharedController] remoteHost]]; + } else { + [selectedPlayerTextField setStringValue:@"No shared player selected."]; + [locationTextField setStringValue:@"-"]; + } } - (IBAction)changeMenus:(id)sender diff --git a/StatusWindowController.h b/StatusWindowController.h index a6633a8..11d7fe8 100755 --- a/StatusWindowController.h +++ b/StatusWindowController.h @@ -41,6 +41,7 @@ typedef enum { - (void)showRepeatWindowWithMode:(StatusWindowRepeatMode)mode; - (void)showSetupQueryWindow; - (void)showRegistrationQueryWindow; +- (void)showReconnectQueryWindow; - (void)showSongInfoWindowWithSource:(ITMTRemotePlayerSource)source title: (NSString *)title diff --git a/StatusWindowController.m b/StatusWindowController.m index 573aac8..6c8841c 100755 --- a/StatusWindowController.m +++ b/StatusWindowController.m @@ -242,5 +242,20 @@ static StatusWindowController *sharedController; [_window setLocked:YES]; } +- (void)showReconnectQueryWindow +{ + NSString *message = @"The selected shared player is available again.\nWould you like to reconnect to it?."; + + [_window setImage:[NSImage imageNamed:@"Register"]]; + [_window buildDialogWindowWithMessage:message + defaultButton:@"Reconnect" + alternateButton:@"Ignore" + target:[MainController sharedController] + defaultAction:@selector(reconnect) + alternateAction:@selector(cancelReconnect)]; + + [_window appear:self]; + [_window setLocked:YES]; +} @end \ No newline at end of file diff --git a/libValidate.a b/libValidate.a index 83fbaf1f558d4342896a8ba64271988f9c257e11..99e5c62915d7ad39b871d2d98fd6f1e254a92740 100755 GIT binary patch delta 17 YcmaE0_rPv~44bi`fw_snMkPCW065$QP5=M^ delta 17 YcmaE0_rPv~44a{Wk&%(bMkPCW06546P5=M^ -- 2.20.1