diff options
Diffstat (limited to 'QSDeliciousPlugIn_Source.m')
| -rw-r--r-- | QSDeliciousPlugIn_Source.m | 349 |
1 files changed, 194 insertions, 155 deletions
diff --git a/QSDeliciousPlugIn_Source.m b/QSDeliciousPlugIn_Source.m index 4d841a1..49526e1 100644 --- a/QSDeliciousPlugIn_Source.m +++ b/QSDeliciousPlugIn_Source.m @@ -18,28 +18,31 @@ // This method will get called whenever we change which // active entry is selected. - (void)setSelectedEntry:(id)selectedEntry { - [super setSelectedEntry:selectedEntry]; - [self loadPasswordFromKeychain]; + [super setSelectedEntry:selectedEntry]; + [self loadPasswordFromKeychain]; } #pragma mark - Quicksilver Source Methods -- (BOOL)indexIsValidFromDate:(NSDate *)indexDate forEntry:(NSDictionary *)theEntry { +- (BOOL)indexIsValidFromDate:(NSDate *)indexDate + forEntry:(NSDictionary *)theEntry { return -[indexDate timeIntervalSinceNow] < 24 * 60 * 60; } -- (BOOL)isVisibleSource{ - return YES; +- (BOOL)isVisibleSource { + return YES; } -- (NSImage *) iconForEntry:(NSDictionary *)dict { - return [[NSBundle bundleForClass:[self class]]imageNamed:@"bookmark_icon"]; +- (NSImage *)iconForEntry:(NSDictionary *)dict { + return [[NSBundle bundleForClass:[self class]] imageNamed:@"bookmark_icon"]; } -- (NSView *)settingsView -{ +- (NSView *)settingsView { if (![super settingsView]) { - [[NSBundle bundleForClass:[self class]] loadNibNamed:NSStringFromClass([self class]) owner:self topLevelObjects:NULL]; + [[NSBundle bundleForClass:[self class]] + loadNibNamed:NSStringFromClass([self class]) + owner:self + topLevelObjects:NULL]; } return [super settingsView]; } @@ -48,7 +51,9 @@ - (SocialSite)siteIndex { NSDictionary *settings = self.selectedEntry.sourceSettings; - return [settings objectForKey:@"site"] != nil ? [[settings objectForKey:@"site"] integerValue] : SocialSiteDelicious; + return [settings objectForKey:@"site"] != nil + ? [[settings objectForKey:@"site"] integerValue] + : SocialSiteDelicious; } - (NSString *)currentUsername { @@ -64,221 +69,251 @@ } - (BOOL)includeTags { - return [[self.selectedEntry.sourceSettings objectForKey:@"includeTags"] boolValue]; + return [[self.selectedEntry.sourceSettings objectForKey:@"includeTags"] + boolValue]; } - // This method is called on action from all the NIB methods // to force the catalog to save the current values. - (IBAction)settingsChanged:(id)sender { - [[NSNotificationCenter defaultCenter] postNotificationName:QSCatalogEntryChangedNotification object:self.selectedEntry]; + [[NSNotificationCenter defaultCenter] + postNotificationName:QSCatalogEntryChangedNotification + object:self.selectedEntry]; [self willChangeValueForKey:@"isHostVisible"]; [self didChangeValueForKey:@"isHostVisible"]; } - #pragma mark - Keychain Helper Methods - (NSString *)keychainKeyForIdentifier:(NSString *)identifier { - return [NSString stringWithFormat:@"QSSocialBookmarks-%@", identifier]; + return [NSString stringWithFormat:@"QSSocialBookmarks-%@", identifier]; } - (NSString *)passwordFromKeychainForKey:(NSString *)key { - const char *service = "QSSocialBookmarks"; - const char *account = [key UTF8String]; - - UInt32 passwordLength = 0; - void *passwordData = NULL; - - OSStatus status = SecKeychainFindGenericPassword(NULL, - (UInt32)strlen(service), service, - (UInt32)strlen(account), account, - &passwordLength, &passwordData, - NULL); - - if (status == errSecSuccess && passwordData != NULL) { - NSString *password = [[NSString alloc] initWithBytes:passwordData - length:passwordLength - encoding:NSUTF8StringEncoding]; - SecKeychainItemFreeContent(NULL, passwordData); - return password; - } - - return nil; + const char *service = "QSSocialBookmarks"; + const char *account = [key UTF8String]; + + UInt32 passwordLength = 0; + void *passwordData = NULL; + + OSStatus status = SecKeychainFindGenericPassword( + NULL, (UInt32)strlen(service), service, (UInt32)strlen(account), account, + &passwordLength, &passwordData, NULL); + + if (status == errSecSuccess && passwordData != NULL) { + NSString *password = [[NSString alloc] initWithBytes:passwordData + length:passwordLength + encoding:NSUTF8StringEncoding]; + SecKeychainItemFreeContent(NULL, passwordData); + return password; + } + + return nil; } -- (OSStatus)savePasswordToKeychainForKey:(NSString *)key password:(NSString *)password { - const char *service = "QSSocialBookmarks"; - const char *account = [key UTF8String]; - const char *passwordCString = [password UTF8String]; - - // First try to find existing item - SecKeychainItemRef item = NULL; - OSStatus findStatus = SecKeychainFindGenericPassword(NULL, - (UInt32)strlen(service), service, - (UInt32)strlen(account), account, - NULL, NULL, - &item); - - OSStatus status; - if (findStatus == errSecSuccess) { - // Update existing item - status = SecKeychainItemModifyAttributesAndData(item, - NULL, - (UInt32)strlen(passwordCString), - passwordCString); - CFRelease(item); - } else { - // Create new item - status = SecKeychainAddGenericPassword(NULL, - (UInt32)strlen(service), service, - (UInt32)strlen(account), account, - (UInt32)strlen(passwordCString), passwordCString, - NULL); - } - - return status; +- (OSStatus)savePasswordToKeychainForKey:(NSString *)key + password:(NSString *)password { + const char *service = "QSSocialBookmarks"; + const char *account = [key UTF8String]; + const char *passwordCString = [password UTF8String]; + + // First try to find existing item + SecKeychainItemRef item = NULL; + OSStatus findStatus = SecKeychainFindGenericPassword( + NULL, (UInt32)strlen(service), service, (UInt32)strlen(account), account, + NULL, NULL, &item); + + OSStatus status; + if (findStatus == errSecSuccess) { + // Update existing item + status = SecKeychainItemModifyAttributesAndData( + item, NULL, (UInt32)strlen(passwordCString), passwordCString); + CFRelease(item); + } else { + // Create new item + status = SecKeychainAddGenericPassword( + NULL, (UInt32)strlen(service), service, (UInt32)strlen(account), + account, (UInt32)strlen(passwordCString), passwordCString, NULL); + } + + return status; } - (OSStatus)deletePasswordFromKeychainForKey:(NSString *)key { - const char *service = "QSSocialBookmarks"; - const char *account = [key UTF8String]; - - SecKeychainItemRef item = NULL; - OSStatus findStatus = SecKeychainFindGenericPassword(NULL, - (UInt32)strlen(service), service, - (UInt32)strlen(account), account, - NULL, NULL, - &item); - - if (findStatus == errSecSuccess) { - OSStatus deleteStatus = SecKeychainItemDelete(item); - CFRelease(item); - return deleteStatus; - } - - return findStatus; + const char *service = "QSSocialBookmarks"; + const char *account = [key UTF8String]; + + SecKeychainItemRef item = NULL; + OSStatus findStatus = SecKeychainFindGenericPassword( + NULL, (UInt32)strlen(service), service, (UInt32)strlen(account), account, + NULL, NULL, &item); + + if (findStatus == errSecSuccess) { + OSStatus deleteStatus = SecKeychainItemDelete(item); + CFRelease(item); + return deleteStatus; + } + + return findStatus; } #pragma mark - Password Keychain Methods - (void)loadPasswordFromKeychain { - if (!self.selectedEntry || !self.selectedEntry.identifier) { - self.internalPassword = nil; - return; - } - - NSString *keychainKey = [self keychainKeyForIdentifier:self.selectedEntry.identifier]; - [self setPassword: [self passwordFromKeychainForKey:keychainKey]]; + if (!self.selectedEntry || !self.selectedEntry.identifier) { + self.internalPassword = nil; + return; + } + + NSString *keychainKey = + [self keychainKeyForIdentifier:self.selectedEntry.identifier]; + [self setPassword:[self passwordFromKeychainForKey:keychainKey]]; } - (void)savePasswordToKeychain { - if (!self.selectedEntry || !self.selectedEntry.identifier || !self.internalPassword) { - return; - } - - NSString *keychainKey = [self keychainKeyForIdentifier:self.selectedEntry.identifier]; - OSStatus status = [self savePasswordToKeychainForKey:keychainKey password:self.internalPassword]; - - if (status != errSecSuccess) { - NSLog(@"Failed to save password to keychain for key: %@, status: %d", keychainKey, (int)status); - } + if (!self.selectedEntry || !self.selectedEntry.identifier || + !self.internalPassword) { + return; + } + + NSString *keychainKey = + [self keychainKeyForIdentifier:self.selectedEntry.identifier]; + OSStatus status = [self savePasswordToKeychainForKey:keychainKey + password:self.internalPassword]; + + if (status != errSecSuccess) { + NSLog(@"Failed to save password to keychain for key: %@, status: %d", + keychainKey, (int)status); + } } #pragma mark - Password Property Accessors - (NSString *)password { - return self.internalPassword; + return self.internalPassword; } - (void)setPassword:(NSString *)password { - self.internalPassword = password; - - // Save to keychain asynchronously - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [self savePasswordToKeychain]; - }); + self.internalPassword = password; + + // Save to keychain asynchronously + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), + ^{ + [self savePasswordToKeychain]; + }); } #pragma mark - Host Visibility Control -- (BOOL) isHostVisible { - return [SocialSiteHelper hasVariableHost:[self siteIndex]]; +- (BOOL)isHostVisible { + return [SocialSiteHelper hasVariableHost:[self siteIndex]]; +} +- (void)setIsHostVisible:(BOOL)isVisible { } -- (void)setIsHostVisible:(BOOL)isVisible { } #pragma mark - Objects For Entry - (NSArray *)objectsForEntry:(QSCatalogEntry *)theEntry { - - NSDictionary *settings = theEntry.sourceSettings; - - SocialSite site = [settings objectForKey:@"site"] != nil ? [[settings objectForKey:@"site"] integerValue] : SocialSiteDelicious; - NSString *username = [settings objectForKey:@"username"]; - NSString *identifier = theEntry.identifier; - NSString *keychainKey = [self keychainKeyForIdentifier:identifier]; - NSString *password = [self passwordFromKeychainForKey:keychainKey]; - NSString *host = [settings objectForKey:@"host"]; - BOOL includeTags = [settings objectForKey:@"includeTags"]; - - QSBookmarkProviderFactory *factory = [QSBookmarkProviderFactory sharedFactory]; - id<QSBookmarkProvider> provider = [factory providerForSite:site username:username password:password host:host]; - - if (!provider) { - NSLog(@"No provider available for site %ld with username %@", (long)site, username); - return @[]; - } - - return [provider fetchBookmarksForSite:site username:username password:password identifier:identifier host:host includeTags:includeTags]; -} -- (NSArray *)objectsForTag:(NSString *)tag site:(SocialSite)site username:(NSString *)username identifier:(NSString *)identifier host:(NSString *)host { - + NSDictionary *settings = theEntry.sourceSettings; + + SocialSite site = [settings objectForKey:@"site"] != nil + ? [[settings objectForKey:@"site"] integerValue] + : SocialSiteDelicious; + NSString *username = [settings objectForKey:@"username"]; + NSString *identifier = theEntry.identifier; NSString *keychainKey = [self keychainKeyForIdentifier:identifier]; NSString *password = [self passwordFromKeychainForKey:keychainKey]; + NSString *host = [settings objectForKey:@"host"]; + BOOL includeTags = [settings objectForKey:@"includeTags"]; + + QSBookmarkProviderFactory *factory = + [QSBookmarkProviderFactory sharedFactory]; + id<QSBookmarkProvider> provider = [factory providerForSite:site + username:username + password:password + host:host]; - QSBookmarkProviderFactory *factory = [QSBookmarkProviderFactory sharedFactory]; - id<QSBookmarkProvider> provider = [factory providerForSite:site username:username password:password host:host]; - if (!provider) { - NSLog(@"No provider available for site %ld with username %@", (long)site, username); + NSLog(@"No provider available for site %ld with username %@", (long)site, + username); return @[]; } - - // Check if provider supports tag-based fetching - if ([provider respondsToSelector:@selector(fetchBookmarksForTag:site:username:password:host:)]) { - return [provider fetchBookmarksForTag:tag site:site username:username password:password host:host]; - } - + + return [provider fetchBookmarksForSite:site + username:username + password:password + identifier:identifier + host:host + includeTags:includeTags]; +} + +- (NSArray *)objectsForTag:(NSString *)tag + site:(SocialSite)site + username:(NSString *)username + identifier:(NSString *)identifier + host:(NSString *)host { + + NSString *keychainKey = [self keychainKeyForIdentifier:identifier]; + NSString *password = [self passwordFromKeychainForKey:keychainKey]; + + QSBookmarkProviderFactory *factory = + [QSBookmarkProviderFactory sharedFactory]; + id<QSBookmarkProvider> provider = [factory providerForSite:site + username:username + password:password + host:host]; + + if (!provider) { + NSLog(@"No provider available for site %ld with username %@", (long)site, + username); return @[]; + } + + // Check if provider supports tag-based fetching + if ([provider respondsToSelector:@selector + (fetchBookmarksForTag:site:username:password:host:)]) { + return [provider fetchBookmarksForTag:tag + site:site + username:username + password:password + host:host]; + } + + return @[]; } #pragma mark - Object Handler Methods - (void)setQuickIconForObject:(QSObject *)object { if (@available(macOS 11.0, *)) { - NSImage *image = [NSImage imageWithSystemSymbolName:@"tag" accessibilityDescription:@"Bookmark"]; + NSImage *image = [NSImage imageWithSystemSymbolName:@"tag" + accessibilityDescription:@"Bookmark"]; [object setIcon:image]; } else { - [object setIcon:[[NSBundle bundleForClass:[self class]]imageNamed:@"bookmark_icon"]]; + [object setIcon:[[NSBundle bundleForClass:[self class]] + imageNamed:@"bookmark_icon"]]; } } -// All our objects will have children. URLs will have tags, and tags will have URLs. -- (BOOL)objectHasChildren:(QSObject *) object { return YES; } +// All our objects will have children. URLs will have tags, and tags will have +// URLs. +- (BOOL)objectHasChildren:(QSObject *)object { + return YES; +} // This will receive a tag object. Tag objects will have the // source configuration in the meta: source.username, // source.site, source.host and source.identifier. - (BOOL)loadChildrenForObject:(QSObject *)object { - + NSNumber *siteNumber = [object objectForMeta:@"source.site"]; if (!siteNumber) { NSLog(@"The tag didn't have a valid site."); return NO; } - + SocialSite site = [siteNumber integerValue]; - + NSString *username = [object objectForMeta:@"source.username"]; if (!username) { NSLog(@"The tag didn't have a valid username."); @@ -302,9 +337,13 @@ return NO; } - NSArray *children = [self objectsForTag:tag site:site username:username identifier:identifier host:host]; - [object setChildren:children]; - return YES; + NSArray *children = [self objectsForTag:tag + site:site + username:username + identifier:identifier + host:host]; + [object setChildren:children]; + return YES; } @end |