From 46b610a25dea1e26f1348dac4024d72514130bb3 Mon Sep 17 00:00:00 2001 From: Kent Sutherland Date: Tue, 8 Nov 2005 03:56:52 +0000 Subject: [PATCH] Added a new currentSongDuration method to the remote. Moved the keychain methods to class methods in the prefs controller. The main controller will now submit audioscrobbler tracks if needed. It still needs to be implemented better though, as there are tons of loopholes. --- AudioscrobblerController.m | 68 ++++----- ITMTRemote.h | 5 + ITMTRemote.m | 5 + MainController.h | 2 +- MainController.m | 45 ++++++ PreferencesController.h | 3 +- PreferencesController.m | 297 ++++++++++++++++++------------------- iTunesRemote.m | 9 ++ 8 files changed, 243 insertions(+), 191 deletions(-) diff --git a/AudioscrobblerController.m b/AudioscrobblerController.m index 32cb718..4addcaf 100644 --- a/AudioscrobblerController.m +++ b/AudioscrobblerController.m @@ -12,6 +12,7 @@ */ #import "AudioscrobblerController.h" +#import "PreferencesController.h" #import #import @@ -19,14 +20,14 @@ static AudioscrobblerController *_sharedController = nil; @implementation AudioscrobblerController -+ (void)load +/*+ (void)load { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [[AudioscrobblerController sharedController] submitTrack:@"Immigrant Song" artist:@"Led Zeppelin" album:@"How The West Was Won" length:221]; [[AudioscrobblerController sharedController] submitTrack:@"Comfortably Numb" artist:@"Pink Floyd" album:@"The Wall" length:384]; [[AudioscrobblerController sharedController] submitTracks]; [pool release]; -} +}*/ + (AudioscrobblerController *)sharedController { @@ -39,13 +40,13 @@ static AudioscrobblerController *_sharedController = nil; - (id)init { if ( (self = [super init]) ) { - /*_handshakeCompleted = NO; + _handshakeCompleted = NO; _md5Challenge = nil; - _postURL = nil;*/ + _postURL = nil; - _handshakeCompleted = YES; + /*_handshakeCompleted = YES; _md5Challenge = @"rawr"; - _postURL = [NSURL URLWithString:@"http://audioscrobbler.com/"]; + _postURL = [NSURL URLWithString:@"http://audioscrobbler.com/"];*/ _delayDate = nil; _responseData = nil; @@ -77,10 +78,10 @@ static AudioscrobblerController *_sharedController = nil; if (!_handshakeCompleted) { NSString *version = [[[NSBundle bundleWithPath:[[NSWorkspace sharedWorkspace] fullPathForApplication:@"iTunes.app"]] infoDictionary] objectForKey:@"CFBundleVersion"], *user = @"Tristrex"; NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://post.audioscrobbler.com/?hs=true&p=1.1&c=tst&v=%@&u=%@", version, user]]; - NSURLConnection *connection; _currentStatus = AudioscrobblerRequestingHandshakeStatus; - connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30] delegate:self]; + _responseData = [[NSMutableData alloc] init]; + [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30] delegate:self]; } } @@ -91,16 +92,12 @@ static AudioscrobblerController *_sharedController = nil; - (void)submitTrack:(NSString *)title artist:(NSString *)artist album:(NSString *)album length:(int)length { - if (!_handshakeCompleted) { - [self attemptHandshake]; - return; - } ITDebugLog(@"Audioscrobbler: Adding a new track to the submission queue."); NSDictionary *newTrack = [NSDictionary dictionaryWithObjectsAndKeys:title, @"title", artist, @"artist", - album, + (album == nil) ? @"" : album, @"album", [NSString stringWithFormat:@"%i", length], @"length", @@ -108,29 +105,31 @@ static AudioscrobblerController *_sharedController = nil; @"time", nil, nil]; [_tracks addObject:newTrack]; + [self submitTracks]; } - (void)submitTracks { + if (!_handshakeCompleted) { + [self attemptHandshake]; + return; + } + NSTimeInterval interval = [_delayDate timeIntervalSinceNow]; if (interval > 0) { - ITDebugLog(@"Audioscrobbler: Delaying track submission for %i seconds", interval); - [self performSelector:@selector(attemptHandshake) withObject:nil afterDelay:interval + 1]; + ITDebugLog(@"Audioscrobbler: Delaying track submission for %f seconds", interval); + [self performSelector:@selector(submitTracks) withObject:nil afterDelay:interval + 1]; return; } int i; NSMutableString *requestString; NSString *authString, *responseHash = @""; - char *pass = "waffles"; + NSString *user = [[NSUserDefaults standardUserDefaults] stringForKey:@"audioscrobblerUser"]; + char *pass = (char *)[[PreferencesController getKeychainItemPasswordForUser:user] UTF8String]; unsigned char *buffer; EVP_MD_CTX ctx; - if (!_handshakeCompleted) { - [self attemptHandshake]; - return; - } - ITDebugLog(@"Audioscrobbler: Submitting queued tracks"); if ([_tracks count] == 0) { @@ -161,7 +160,7 @@ static AudioscrobblerController *_sharedController = nil; } free(buffer); - authString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)[NSString stringWithFormat:@"u=%@&s=%@", @"Tristrex", responseHash], NULL, NULL, kCFStringEncodingUTF8); + authString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)[NSString stringWithFormat:@"u=%@&s=%@", user, responseHash], NULL, NULL, kCFStringEncodingUTF8); requestString = [[NSMutableString alloc] initWithString:authString]; [authString release]; @@ -180,7 +179,8 @@ static AudioscrobblerController *_sharedController = nil; [request setHTTPMethod:@"POST"]; [request setHTTPBody:[requestString dataUsingEncoding:NSUTF8StringEncoding]]; _currentStatus = AudioscrobblerSubmittingTracksStatus; - //[NSURLConnection connectionWithRequest:request delegate:self]; + _responseData = [[NSMutableData alloc] init]; + [NSURLConnection connectionWithRequest:request delegate:self]; [requestString release]; [request release]; @@ -191,11 +191,8 @@ static AudioscrobblerController *_sharedController = nil; { if ([[note name] isEqualToString:@"AudioscrobblerHandshakeComplete"]) { if ([_tracks count] > 0) { - [self submitTracks]; + [self performSelector:@selector(submitTracks) withObject:nil afterDelay:2]; } - [self submitTrack:@"Immigrant Song" artist:@"Led Zeppelin" album:@"How The West Was Won" length:221]; - [self submitTrack:@"Comfortably Numb" artist:@"Pink Floyd" album:@"The Wall" length:384]; - [self submitTracks]; } } @@ -251,15 +248,16 @@ static AudioscrobblerController *_sharedController = nil; } else if (([responseAction length] > 5) && [[responseAction substringToIndex:5] isEqualToString:@"FAILED"]) { //Failed } - NSLog(string); } //Handle the final INTERVAL response - if (([responseAction length] > 9) && [[responseAction substringToIndex:7] isEqualToString:@"INTERVAL"]) { - int seconds = [[[lines objectAtIndex:[lines count] - 1] substringFromIndex:9] intValue]; + if (([[lines objectAtIndex:[lines count] - 2] length] > 9) && [[[lines objectAtIndex:[lines count] - 2] substringToIndex:8] isEqualToString:@"INTERVAL"]) { + int seconds = [[[lines objectAtIndex:[lines count] - 2] substringFromIndex:9] intValue]; ITDebugLog(@"Audioscrobbler: INTERVAL %i", seconds); - _delayDate = [NSDate dateWithTimeIntervalSinceNow:seconds]; + [_delayDate release]; + _delayDate = [[NSDate dateWithTimeIntervalSinceNow:seconds] retain]; } else { + ITDebugLog(@"No interval response."); //We have a protocol error } @@ -267,12 +265,4 @@ static AudioscrobblerController *_sharedController = nil; [_responseData release]; } --(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse -{ - ITDebugLog(@"Audioscrobbler: Sending URL request."); - NSLog(@"Sending request."); - _responseData = [[NSMutableData alloc] init]; - return request; -} - @end diff --git a/ITMTRemote.h b/ITMTRemote.h index a99d52c..f49b559 100755 --- a/ITMTRemote.h +++ b/ITMTRemote.h @@ -299,6 +299,11 @@ er's process managment. */ - (NSString *)currentSongLength; +/*! + * @method currentSongDuratioh + */ +- (int)currentSongDuration; + /*! * @method currentSongRemaining */ diff --git a/ITMTRemote.m b/ITMTRemote.m index febdda1..e4ff611 100755 --- a/ITMTRemote.m +++ b/ITMTRemote.m @@ -179,6 +179,11 @@ return nil; } +- (int)currentSongDuration +{ + return -1; +} + - (NSString *)currentSongRemaining { return nil; diff --git a/MainController.h b/MainController.h index 2ea08ba..7348a81 100755 --- a/MainController.h +++ b/MainController.h @@ -43,7 +43,7 @@ NSUserDefaults *df; MTBlingController *bling; - NSTimer *registerTimer, *_statusWindowUpdateTimer; + NSTimer *registerTimer, *_statusWindowUpdateTimer, *_audioscrobblerTimer; BOOL timerUpdating, _checkingForServer, _popped, _open, _needsPolling; BOOL blinged; int _timeUpdateCount; //Keeps track of how many times the time has been updated in the info status window diff --git a/MainController.m b/MainController.m index 927a278..548ca25 100755 --- a/MainController.m +++ b/MainController.m @@ -9,6 +9,7 @@ #import #import "StatusWindow.h" #import "StatusWindowController.h" +#import "AudioscrobblerController.h" #import "StatusItemHack.h" @interface NSMenu (MenuImpl) @@ -88,6 +89,7 @@ static MainController *sharedController; sharedController = self; _statusWindowUpdateTimer = nil; + _audioscrobblerTimer = nil; remoteArray = [[NSMutableArray alloc] initWithCapacity:1]; [[PreferencesController sharedPrefs] setController:self]; @@ -461,6 +463,18 @@ static MainController *sharedController; [statusItem setToolTip:nil]; } } + + if ([df boolForKey:@"audioscrobblerEnabled"]) { + int length = [[self currentRemote] currentSongDuration]; + if (_audioscrobblerTimer) { + [_audioscrobblerTimer invalidate]; + } + if (length > 0) { + _audioscrobblerTimer = [NSTimer scheduledTimerWithTimeInterval:((length < 240) ? length / 2 : 120) target:self selector:@selector(submitAudioscrobblerTrack:) userInfo:nil repeats:NO]; + } + } else { + _audioscrobblerTimer = nil; + } NS_HANDLER [self networkError:localException]; NS_ENDHANDLER @@ -575,6 +589,18 @@ static MainController *sharedController; [statusItem setToolTip:nil]; } } + + if ([df boolForKey:@"audioscrobblerEnabled"]) { + int length = [[self currentRemote] currentSongDuration]; + if (_audioscrobblerTimer) { + [_audioscrobblerTimer invalidate]; + } + if (length > 0) { + _audioscrobblerTimer = [NSTimer scheduledTimerWithTimeInterval:((length < 240) ? length / 2 : 120) target:self selector:@selector(submitAudioscrobblerTrack:) userInfo:nil repeats:NO]; + } + } else { + _audioscrobblerTimer = nil; + } NS_HANDLER [self networkError:localException]; NS_ENDHANDLER @@ -586,6 +612,25 @@ static MainController *sharedController; } } +- (void)submitAudioscrobblerTrack:(NSTimer *)timer +{ + if ([df boolForKey:@"audioscrobblerEnabled"]) { + NS_DURING + NSString *title = [[self currentRemote] currentSongTitle], *artist = [[self currentRemote] currentSongArtist]; + if (title && artist) { + [[AudioscrobblerController sharedController] submitTrack:title + artist:artist + album:[[self currentRemote] currentSongAlbum] + length:[[self currentRemote] currentSongDuration]]; + } + NS_HANDLER + [self networkError:localException]; + NS_ENDHANDLER + [timer invalidate]; + _audioscrobblerTimer = nil; + } +} + // // // Menu Selectors diff --git a/PreferencesController.h b/PreferencesController.h index 32c7244..06841ef 100755 --- a/PreferencesController.h +++ b/PreferencesController.h @@ -85,6 +85,7 @@ } + (PreferencesController *)sharedPrefs; ++ (NSString *)getKeychainItemPasswordForUser:(NSString *)user; - (id)controller; - (void)setController:(id)object; @@ -97,8 +98,6 @@ - (IBAction)changeStatusWindowSetting:(id)sender; - (void)resetRemotePlayerTextFields; -- (NSString *)getKeychainItemPasswordForUser:(NSString *)user; - - (IBAction)clearHotKey:(id)sender; - (IBAction)editHotKey:(id)sender; - (IBAction)showPrefsWindow:(id)sender; diff --git a/PreferencesController.m b/PreferencesController.m index 0599859..f8245d2 100755 --- a/PreferencesController.m +++ b/PreferencesController.m @@ -42,6 +42,12 @@ /*************************************************************************/ @interface PreferencesController (Private) ++ (SecKeychainItemRef)keychainItemForUser:(NSString *)user; ++ (BOOL)keychainItemExistsForUser:(NSString *)user; ++ (BOOL)createKeychainItemForUser:(NSString *)user andPassword:(NSString *)password; ++ (BOOL)deleteKeychainItemForUser:(NSString *)user; ++ (BOOL)setKeychainItemPassword:(NSString *)password forUser:(NSString *)user; + - (void)setupWindow; - (void)setupCustomizationTables; - (void)setupMenuItems; @@ -53,12 +59,6 @@ - (void)repopulateEffectPopupsForVerticalPosition:(ITVerticalWindowPosition)vPos horizontalPosition:(ITHorizontalWindowPosition)hPos; - (BOOL)effect:(Class)effectClass supportsVerticalPosition:(ITVerticalWindowPosition)vPos withHorizontalPosition:(ITHorizontalWindowPosition)hPos; - (IBAction)changeMenus:(id)sender; - -- (SecKeychainItemRef)keychainItemForUser:(NSString *)user; -- (BOOL)keychainItemExistsForUser:(NSString *)user; -- (BOOL)createKeychainItemForUser:(NSString *)user andPassword:(NSString *)password; -- (BOOL)deleteKeychainItemForUser:(NSString *)user; -- (BOOL)setKeychainItemPassword:(NSString *)password forUser:(NSString *)user; @end @@ -72,6 +72,139 @@ static PreferencesController *prefs = nil; +/*************************************************************************/ +#pragma mark - +#pragma mark STATIC KEYCHAIN SUPPORT METHODS +/*************************************************************************/ + ++ (SecKeychainItemRef)keychainItemForUser:(NSString *)user +{ + SecKeychainSearchRef search; + SecKeychainItemRef item; + OSStatus status; + SecKeychainAttribute attributes[3]; + SecKeychainAttributeList list; + + ITDebugLog(@"Audioscrobbler: Searching for keychain item for %@.", user); + attributes[0].tag = kSecAccountItemAttr; + attributes[0].data = (char *)[user UTF8String]; + attributes[0].length = [user length]; + attributes[1].tag = kSecDescriptionItemAttr; + attributes[1].data = AUDIOSCROBBLER_KEYCHAIN_KIND; + attributes[1].length = strlen(AUDIOSCROBBLER_KEYCHAIN_KIND); + attributes[2].tag = kSecLabelItemAttr; + attributes[2].data = AUDIOSCROBBLER_KEYCHAIN_SERVICE; + attributes[2].length = strlen(AUDIOSCROBBLER_KEYCHAIN_SERVICE); + list.count = 3; + list.attr = attributes; + + status = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &list, &search); + + if (status != noErr) { + ITDebugLog(@"Audioscrobbler: Error searching for existing keychain item: %i", status); + } + + status = SecKeychainSearchCopyNext(search, &item); + + if (status != noErr) { + ITDebugLog(@"Audioscrobbler: Error searching for existing keychain item: %i", status); + item = nil; + } + + CFRelease(search); + return item; +} + ++ (BOOL)keychainItemExistsForUser:(NSString *)user +{ + SecKeychainItemRef item = [PreferencesController keychainItemForUser:user]; + BOOL exists = (item != nil); + if (item) { + CFRelease(item); + } + return exists; +} + ++ (BOOL)createKeychainItemForUser:(NSString *)user andPassword:(NSString *)password +{ + SecKeychainItemRef item; + OSStatus status; + SecKeychainAttribute attributes[3]; + SecKeychainAttributeList list; + + ITDebugLog(@"Audioscrobbler: Creating new keychain item for %@.", user); + attributes[0].tag = kSecAccountItemAttr; + attributes[0].data = (char *)[user UTF8String]; + attributes[0].length = [user length]; + attributes[1].tag = kSecDescriptionItemAttr; + attributes[1].data = AUDIOSCROBBLER_KEYCHAIN_KIND; + attributes[1].length = strlen(AUDIOSCROBBLER_KEYCHAIN_KIND); + attributes[2].tag = kSecLabelItemAttr; + attributes[2].data = AUDIOSCROBBLER_KEYCHAIN_SERVICE; + attributes[2].length = strlen(AUDIOSCROBBLER_KEYCHAIN_SERVICE); + list.count = 3; + list.attr = attributes; + + status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &list, [password length], [password UTF8String], NULL, NULL, &item); + if (status != noErr) { + ITDebugLog(@"Audioscrobbler: Error creating keychain item: %i", status); + } + return (status == noErr); +} + ++ (BOOL)deleteKeychainItemForUser:(NSString *)user +{ + OSStatus status = errSecNotAvailable; + SecKeychainItemRef item = [PreferencesController keychainItemForUser:user]; + if (item != nil) { + status = SecKeychainItemDelete(item); + if (status != noErr) { + ITDebugLog(@"Audioscrobbler: Error deleting keychain item: %i", status); + } + CFRelease(item); + } + return (status == noErr); +} + ++ (BOOL)setKeychainItemPassword:(NSString *)password forUser:(NSString *)user +{ + OSStatus status = errSecNotAvailable; + SecKeychainItemRef item = [PreferencesController keychainItemForUser:user]; + if (item != nil) { + status = SecKeychainItemModifyContent(item, NULL, [password length], [password cString]); + if (status != noErr) { + ITDebugLog(@"Audioscrobbler: Error deleting keychain item: %i", status); + } + CFRelease(item); + } + return (status == noErr); +} + ++ (NSString *)getKeychainItemPasswordForUser:(NSString *)user +{ + OSStatus status = errSecNotAvailable; + SecKeychainItemRef item = [PreferencesController keychainItemForUser:user]; + NSString *pass = nil; + if (item != nil) { + UInt32 length; + char *buffer; + status = SecKeychainItemCopyContent(item, NULL, NULL, &length, (void **)&buffer); + if (status != noErr) { + ITDebugLog(@"Audioscrobbler: Error getting keychain item password: %i", status); + } else { + if ([NSString respondsToSelector:@selector(stringWithCString:encoding:)]) { + pass = [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding]; + } else { + pass = [NSString stringWithCString:buffer]; + } + } + if (status != noErr) { + ITDebugLog(@"Audioscrobbler: Error deleting keychain item: %i", status); + } + CFRelease(item); + } + return pass; +} /*************************************************************************/ #pragma mark - @@ -292,25 +425,25 @@ static PreferencesController *prefs = nil; //Here we create a new keychain item if needed and deletes the keychain item if the field is cleared. NSString *currentAccount = [df stringForKey:@"audioscrobblerUser"], *newAccount = [sender stringValue]; if ([newAccount length] == 0) { - [self deleteKeychainItemForUser:currentAccount]; + [PreferencesController deleteKeychainItemForUser:currentAccount]; } else if (![currentAccount isEqualToString:newAccount] && [[audioscrobblerPasswordTextField stringValue] length] > 0) { [df setObject:newAccount forKey:@"audioscrobblerUser"]; - if ([self keychainItemExistsForUser:currentAccount]) { + if ([PreferencesController keychainItemExistsForUser:currentAccount]) { //Delete the current keychain item if there is one - [self deleteKeychainItemForUser:currentAccount]; + [PreferencesController deleteKeychainItemForUser:currentAccount]; } - [self createKeychainItemForUser:newAccount andPassword:[audioscrobblerPasswordTextField stringValue]]; + [PreferencesController createKeychainItemForUser:newAccount andPassword:[audioscrobblerPasswordTextField stringValue]]; } } else if ( [sender tag ] == 6030) { //Here we set the password for an existing keychain item or we create a new keychain item. if ([[audioscrobblerUserTextField stringValue] length] > 0) { NSString *account = [df stringForKey:@"audioscrobblerUser"]; - if ([self keychainItemExistsForUser:account]) { + if ([PreferencesController keychainItemExistsForUser:account]) { //Update the current keychain item - [self setKeychainItemPassword:[sender stringValue] forUser:account]; + [PreferencesController setKeychainItemPassword:[sender stringValue] forUser:account]; } else if ([[sender stringValue] length] > 0 && [[audioscrobblerUserTextField stringValue] length]) { //Create a new keychain item - [self createKeychainItemForUser:account andPassword:[sender stringValue]]; + [PreferencesController createKeychainItemForUser:account andPassword:[sender stringValue]]; } } } else if ( [sender tag] == 6045) { @@ -690,140 +823,6 @@ static PreferencesController *prefs = nil; } } -/*************************************************************************/ -#pragma mark - -#pragma mark KEYCHAIN SUPPORT METHODS -/*************************************************************************/ - -- (SecKeychainItemRef)keychainItemForUser:(NSString *)user -{ - SecKeychainSearchRef search; - SecKeychainItemRef item; - OSStatus status; - SecKeychainAttribute attributes[3]; - SecKeychainAttributeList list; - - ITDebugLog(@"Audioscrobbler: Searching for keychain item for %@.", user); - attributes[0].tag = kSecAccountItemAttr; - attributes[0].data = (char *)[user UTF8String]; - attributes[0].length = [user length]; - attributes[1].tag = kSecDescriptionItemAttr; - attributes[1].data = AUDIOSCROBBLER_KEYCHAIN_KIND; - attributes[1].length = strlen(AUDIOSCROBBLER_KEYCHAIN_KIND); - attributes[2].tag = kSecLabelItemAttr; - attributes[2].data = AUDIOSCROBBLER_KEYCHAIN_SERVICE; - attributes[2].length = strlen(AUDIOSCROBBLER_KEYCHAIN_SERVICE); - list.count = 3; - list.attr = attributes; - - status = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &list, &search); - - if (status != noErr) { - ITDebugLog(@"Audioscrobbler: Error searching for existing keychain item: %i", status); - } - - status = SecKeychainSearchCopyNext(search, &item); - - if (status != noErr) { - ITDebugLog(@"Audioscrobbler: Error searching for existing keychain item: %i", status); - item = nil; - } - - CFRelease(search); - return item; -} - -- (BOOL)keychainItemExistsForUser:(NSString *)user -{ - SecKeychainItemRef item = [self keychainItemForUser:user]; - BOOL exists = (item != nil); - if (item) { - CFRelease(item); - } - return exists; -} - -- (BOOL)createKeychainItemForUser:(NSString *)user andPassword:(NSString *)password -{ - SecKeychainItemRef item; - OSStatus status; - SecKeychainAttribute attributes[3]; - SecKeychainAttributeList list; - - ITDebugLog(@"Audioscrobbler: Creating new keychain item for %@.", user); - attributes[0].tag = kSecAccountItemAttr; - attributes[0].data = (char *)[user UTF8String]; - attributes[0].length = [user length]; - attributes[1].tag = kSecDescriptionItemAttr; - attributes[1].data = AUDIOSCROBBLER_KEYCHAIN_KIND; - attributes[1].length = strlen(AUDIOSCROBBLER_KEYCHAIN_KIND); - attributes[2].tag = kSecLabelItemAttr; - attributes[2].data = AUDIOSCROBBLER_KEYCHAIN_SERVICE; - attributes[2].length = strlen(AUDIOSCROBBLER_KEYCHAIN_SERVICE); - list.count = 3; - list.attr = attributes; - - status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &list, [password length], [password UTF8String], NULL, NULL, &item); - if (status != noErr) { - ITDebugLog(@"Audioscrobbler: Error creating keychain item: %i", status); - } - return (status == noErr); -} - -- (BOOL)deleteKeychainItemForUser:(NSString *)user -{ - OSStatus status = errSecNotAvailable; - SecKeychainItemRef item = [self keychainItemForUser:user]; - if (item != nil) { - status = SecKeychainItemDelete(item); - if (status != noErr) { - ITDebugLog(@"Audioscrobbler: Error deleting keychain item: %i", status); - } - CFRelease(item); - } - return (status == noErr); -} - -- (BOOL)setKeychainItemPassword:(NSString *)password forUser:(NSString *)user -{ - OSStatus status = errSecNotAvailable; - SecKeychainItemRef item = [self keychainItemForUser:user]; - if (item != nil) { - status = SecKeychainItemModifyContent(item, NULL, [password length], [password cString]); - if (status != noErr) { - ITDebugLog(@"Audioscrobbler: Error deleting keychain item: %i", status); - } - CFRelease(item); - } - return (status == noErr); -} - -- (NSString *)getKeychainItemPasswordForUser:(NSString *)user -{ - OSStatus status = errSecNotAvailable; - SecKeychainItemRef item = [self keychainItemForUser:user]; - NSString *pass = nil; - if (item != nil) { - UInt32 length; - char *buffer; - status = SecKeychainItemCopyContent(item, NULL, NULL, &length, (void **)&buffer); - if (status != noErr) { - ITDebugLog(@"Audioscrobbler: Error getting keychain item password: %i", status); - } else { - if ([NSString respondsToSelector:@selector(stringWithCString:encoding:)]) { - pass = [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding]; - } else { - pass = [NSString stringWithCString:buffer]; - } - } - if (status != noErr) { - ITDebugLog(@"Audioscrobbler: Error deleting keychain item: %i", status); - } - CFRelease(item); - } - return pass; -} - /*************************************************************************/ #pragma mark - #pragma mark HOTKEY SUPPORT METHODS @@ -1099,8 +1098,8 @@ static PreferencesController *prefs = nil; [audioscrobblerUseCacheCheckbox setEnabled:NO]; } NSString *audioscrobblerUser = [df stringForKey:@"audioscrobblerUser"]; - if (audioscrobblerUser != nil && [audioscrobblerUser length] > 0 && [self keychainItemExistsForUser:audioscrobblerUser]) { - NSString *password = [self getKeychainItemPasswordForUser:audioscrobblerUser]; + if (audioscrobblerUser != nil && [audioscrobblerUser length] > 0 && [PreferencesController keychainItemExistsForUser:audioscrobblerUser]) { + NSString *password = [PreferencesController getKeychainItemPasswordForUser:audioscrobblerUser]; [audioscrobblerUserTextField setStringValue:audioscrobblerUser]; if (password != nil) { [audioscrobblerPasswordTextField setStringValue:password]; diff --git a/iTunesRemote.m b/iTunesRemote.m index 8386b3c..11ba443 100755 --- a/iTunesRemote.m +++ b/iTunesRemote.m @@ -670,6 +670,15 @@ return temp2; } +- (int)currentSongDuration +{ + SInt32 temp1; + ITDebugLog(@"Getting current song duration."); + temp1 = [ITSendAEWithString(@"'----':obj { form:'prop', want:type('prop'), seld:type('pDur'), from:obj { form:'prop', want:type('prop'), seld:type('pTrk'), from:'null'() } }", 'core', 'getd', &savedPSN) int32Value]; + ITDebugLog(@"Getting current song duration done."); + return temp1; +} + - (NSString *)currentSongRemaining { SInt32 duration, current, final; -- 2.20.1