aboutsummaryrefslogtreecommitdiff
path: root/AppKit/GTMGetURLHandler.m
diff options
context:
space:
mode:
Diffstat (limited to 'AppKit/GTMGetURLHandler.m')
-rw-r--r--AppKit/GTMGetURLHandler.m308
1 files changed, 0 insertions, 308 deletions
diff --git a/AppKit/GTMGetURLHandler.m b/AppKit/GTMGetURLHandler.m
deleted file mode 100644
index a5f7c5d..0000000
--- a/AppKit/GTMGetURLHandler.m
+++ /dev/null
@@ -1,308 +0,0 @@
-//
-// GTMGetURLHandler.m
-//
-// Copyright 2008 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-//
-
-// Add this class to your app to have get URL handled almost automatically for
-// you. For each entry in your CFBundleURLTypes dictionaries, add a new
-// key/object pair of GTMBundleURLClass/the name of the class you want
-// to have handle the scheme(s).
-// Then have that class respond to the class method:
-// + (BOOL)gtm_openURL:(NSURL*)url
-// and voila, it will just work.
-// Note that in Debug mode we will do extensive testing to make sure that this
-// is all hooked up correctly, and will spew out to the console if we
-// find anything amiss.
-//
-// Example plist entry
-// ...
-//
-// <key>CFBundleURLTypes</key>
-// <array>
-// <dict>
-// <key>CFBundleURLName</key>
-// <string>Google Suggestion URL</string>
-// <key>GTMBundleURLClass</key>
-// <string>GoogleSuggestURLHandler</string>
-// <key>CFBundleURLSchemes</key>
-// <array>
-// <string>googlesuggest</string>
-// <string>googlesuggestextreme</string>
-// </array>
-// </dict>
-// </array>
-//
-//
-// Example implementation
-// @interface GoogleSuggestURLHandler
-// @end
-// @implementation GoogleSuggestURLHandler
-// + (BOOL)gtm_openURL:(NSURL*)url {
-// NSLog(@"%@", url);
-// }
-// @end
-
-#import <AppKit/AppKit.h>
-#import "GTMNSAppleEventDescriptor+Foundation.h"
-#import "GTMMethodCheck.h"
-
-static NSString *const kGTMBundleURLClassKey = @"GTMBundleURLClass";
-// A variety of constants Apple really should have defined somewhere to
-// allow the compiler to find your typos.
-static NSString *const kGTMCFBundleURLSchemesKey = @"CFBundleURLSchemes";
-static NSString *const kGTMCFBundleURLNameKey = @"CFBundleURLName";
-static NSString *const kGTMCFBundleTypeRoleKey = @"CFBundleTypeRole";
-static NSString *const kGTMCFBundleURLTypesKey = @"CFBundleURLTypes";
-static NSString *const kGTMCFBundleViewerRole = @"Viewer";
-static NSString *const kGTMCFBundleEditorRole = @"Editor";
-
-// Set this macro elsewhere is you want to force the
-// bundle checks on/off. They are nice for debugging
-// problems, but shouldn't be required in a release version
-// unless you are paranoid about your users messing with your
-// Info.plist
-#ifndef GTM_CHECK_BUNDLE_URL_CLASSES
-#define GTM_CHECK_BUNDLE_URL_CLASSES DEBUG
-#endif // GTM_CHECK_BUNDLE_URL_CLASSES
-
-@protocol GTMGetURLHandlerProtocol
-+ (BOOL)gtm_openURL:(NSURL*)url;
-@end
-
-@interface GTMGetURLHandler : NSObject {
- NSArray *urlTypes_;
-}
-- (id)initWithTypes:(NSArray*)urlTypes;
-- (void)getUrl:(NSAppleEventDescriptor *)event
-withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
-- (void)addError:(OSStatus)error
- withDescription:(NSString*)string
- toDescriptor:(NSAppleEventDescriptor *)desc;
-+ (id)handlerForBundle:(NSBundle *)bundle;
-+ (void)getUrl:(NSAppleEventDescriptor *)event
-withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
-@end
-
-@implementation GTMGetURLHandler
-GTM_METHOD_CHECK(NSNumber, gtm_appleEventDescriptor);
-GTM_METHOD_CHECK(NSString, gtm_appleEventDescriptor);
-
-+ (void)load {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSAppleEventManager *man = [NSAppleEventManager sharedAppleEventManager];
- [man setEventHandler:self
- andSelector:@selector(getUrl:withReplyEvent:)
- forEventClass:kInternetEventClass
- andEventID:kAEGetURL];
- [pool drain];
-}
-
-+ (void)getUrl:(NSAppleEventDescriptor *)event
-withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
- static GTMGetURLHandler *sHandler = nil;
- if (!sHandler) {
- NSBundle *bundle = [NSBundle mainBundle];
- sHandler = [GTMGetURLHandler handlerForBundle:bundle];
- if (sHandler) {
- [sHandler retain];
- }
- }
- [sHandler getUrl:event withReplyEvent:replyEvent];
-}
-
-+ (id)handlerForBundle:(NSBundle *)bundle {
- GTMGetURLHandler *handler = nil;
- NSArray *urlTypes
- = [bundle objectForInfoDictionaryKey:kGTMCFBundleURLTypesKey];
- if (urlTypes) {
- handler = [[[GTMGetURLHandler alloc] initWithTypes:urlTypes] autorelease];
- } else {
- // COV_NF_START
- // Hard to test it if we don't have it.
- _GTMDevLog(@"If you don't have CFBundleURLTypes in your plist, you may want"
- @" to remove GTMGetURLHandler.m from your project");
- // COV_NF_END
- }
- return handler;
-}
-
-- (id)initWithTypes:(NSArray*)urlTypes {
- if ((self = [super init])) {
- urlTypes_ = [urlTypes retain];
-#if GTM_CHECK_BUNDLE_URL_CLASSES
- // Some debug handling to check to make sure we can handle the
- // classes properly. We check here instead of at init in case some of the
- // handlers are being handled by plugins or other imported code that are
- // loaded after we have been initialized.
- NSDictionary *urlType;
- GTM_FOREACH_OBJECT(urlType, urlTypes_) {
- NSString *className = [urlType objectForKey:kGTMBundleURLClassKey];
- if ([className length]) {
- Class cls = NSClassFromString(className);
- if (cls) {
- if (![cls respondsToSelector:@selector(gtm_openURL:)]) {
- _GTMDevLog(@"Class %@ for URL handler %@ "
- @"(URL schemes: %@) doesn't respond to openURL:",
- className,
- [urlType objectForKey:kGTMCFBundleURLNameKey],
- [urlType objectForKey:kGTMCFBundleURLSchemesKey]);
- }
- } else {
- _GTMDevLog(@"Unable to get class %@ for URL handler %@ "
- @"(URL schemes: %@)",
- className,
- [urlType objectForKey:kGTMCFBundleURLNameKey],
- [urlType objectForKey:kGTMCFBundleURLSchemesKey]);
- }
- } else {
- NSString *role = [urlType objectForKey:kGTMCFBundleTypeRoleKey];
- if ([role caseInsensitiveCompare:kGTMCFBundleViewerRole] == NSOrderedSame ||
- [role caseInsensitiveCompare:kGTMCFBundleEditorRole] == NSOrderedSame) {
- _GTMDevLog(@"Missing %@ for URL handler %@ "
- @"(URL schemes: %@)",
- kGTMBundleURLClassKey,
- [urlType objectForKey:kGTMCFBundleURLNameKey],
- [urlType objectForKey:kGTMCFBundleURLSchemesKey]);
- }
- }
- }
-#endif // GTM_CHECK_BUNDLE_URL_CLASSES
- }
- return self;
-}
-
-// COV_NF_START
-// Singleton is never dealloc'd
-- (void)dealloc {
- [urlTypes_ release];
- [super dealloc];
-}
-// COV_NF_END
-
-
-- (NSURL*)extractURLFromEvent:(NSAppleEventDescriptor*)event
- withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
- NSAppleEventDescriptor *desc
- = [event paramDescriptorForKeyword:keyDirectObject];
- NSString *urlstring = [desc stringValue];
- NSURL *url = [NSURL URLWithString:urlstring];
- if (!url) {
- // COV_NF_START
- // Can't convince the OS to give me a bad URL
- [self addError:errAECoercionFail
- withDescription:@"Unable to extract url from key direct object."
- toDescriptor:replyEvent];
- // COV_NF_END
- }
- return url;
-}
-
-- (Class)getClassForScheme:(NSString *)scheme
- withReplyEvent:(NSAppleEventDescriptor*)replyEvent {
- NSDictionary *urlType;
- Class cls = nil;
- NSString *typeScheme = nil;
- GTM_FOREACH_OBJECT(urlType, urlTypes_) {
- NSArray *schemes = [urlType objectForKey:kGTMCFBundleURLSchemesKey];
- NSString *aScheme;
- GTM_FOREACH_OBJECT(aScheme, schemes) {
- if ([aScheme caseInsensitiveCompare:scheme] == NSOrderedSame) {
- typeScheme = aScheme;
- break;
- }
- }
- if (typeScheme) {
- break;
- }
- }
- if (typeScheme) {
- NSString *class = [urlType objectForKey:kGTMBundleURLClassKey];
- if (class) {
- cls = NSClassFromString(class);
- }
- if (!cls) {
- NSString *errorString
- = [NSString stringWithFormat:@"Unable to instantiate class for "
- @"%@:%@ for scheme:%@.",
- kGTMBundleURLClassKey, class, typeScheme];
- [self addError:errAECorruptData
- withDescription:errorString
- toDescriptor:replyEvent];
- } else {
- if (![cls respondsToSelector:@selector(gtm_openURL:)]) {
- NSString *errorString
- = [NSString stringWithFormat:@"Class %@:%@ for scheme:%@ does not"
- @"respond to gtm_openURL:",
- kGTMBundleURLClassKey, class, typeScheme];
- [self addError:errAECorruptData
- withDescription:errorString
- toDescriptor:replyEvent];
- cls = Nil;
- }
- }
- } else {
- // COV_NF_START
- // Don't know how to force an URL that we don't respond to upon ourselves.
- NSString *errorString
- = [NSString stringWithFormat:@"Unable to find handler for scheme %@.",
- scheme];
- [self addError:errAECorruptData
- withDescription:errorString
- toDescriptor:replyEvent];
- // COV_NF_END
-
- }
- return cls;
-}
-
-- (void)getUrl:(NSAppleEventDescriptor *)event
-withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
- NSURL *url = [self extractURLFromEvent:event withReplyEvent:replyEvent];
- if (!url) {
- return;
- }
- NSString *scheme = [url scheme];
- Class cls = [self getClassForScheme:scheme withReplyEvent:replyEvent];
- if (!cls) {
- return;
- }
- BOOL wasGood = [cls gtm_openURL:url];
- if (!wasGood) {
- NSString *errorString
- = [NSString stringWithFormat:@"[%@ gtm_openURL:] failed to handle %@",
- NSStringFromClass(cls), url];
- [self addError:errAEEventNotHandled
- withDescription:errorString
- toDescriptor:replyEvent];
- }
-}
-
-- (void)addError:(OSStatus)error
- withDescription:(NSString*)string
- toDescriptor:(NSAppleEventDescriptor *)desc {
- NSAppleEventDescriptor *errorDesc = nil;
- if (error != noErr) {
- NSNumber *errNum = [NSNumber numberWithLong:error];
- errorDesc = [errNum gtm_appleEventDescriptor];
- [desc setParamDescriptor:errorDesc forKeyword:keyErrorNumber];
- }
- if (string) {
- errorDesc = [string gtm_appleEventDescriptor];
- [desc setParamDescriptor:errorDesc forKeyword:keyErrorString];
- }
-}
-@end
-