diff options
Diffstat (limited to 'AppKit/GTMGoogleSearch.m')
-rw-r--r-- | AppKit/GTMGoogleSearch.m | 543 |
1 files changed, 0 insertions, 543 deletions
diff --git a/AppKit/GTMGoogleSearch.m b/AppKit/GTMGoogleSearch.m deleted file mode 100644 index 9384ade..0000000 --- a/AppKit/GTMGoogleSearch.m +++ /dev/null @@ -1,543 +0,0 @@ -// -// GTMGoogleSearch.m -// -// Copyright 2006-2009 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. -// - -#import "GTMGoogleSearch.h" -#import "GTMDefines.h" - -#if GTM_IPHONE_SDK -#import <UIKit/UIKit.h> -#else -#import <AppKit/AppKit.h> -#endif // GTM_IPHONE_SDK - -typedef struct { - NSString *language; - NSString *country; - // we don't include a language, we'll use what we get from the OS - NSString *defaultDomain; -} LanguageDefaultInfo; - -// -// this is a seed mapping from languages to domains for google search. -// this doesn't have to be complete, as it is just a seed. -// -// -static LanguageDefaultInfo kLanguageListDefaultMappingTable[] = { - // order is important, first match is taken - // if country is |nil|, then only language has to match - { @"en", @"US", @"com" }, // english - united states - { @"en", @"GB", @"co.uk" }, // english - united kingdom - { @"en", @"CA", @"ca" }, // english - canada - { @"en", @"AU", @"com.au" }, // english - australia - { @"en", @"NZ", @"com" }, // english - new zealand - { @"en", @"IE", @"ie" }, // english - ireland - { @"en", @"IN", @"co.in" }, // english - india - { @"en", @"PH", @"com.ph" }, // english - philippines - { @"en", @"SG", @"com.sg" }, // english - singapore - { @"en", @"ZA", @"co.za" }, // english - south africa - { @"en", @"IL", @"co.il" }, // english - israel - { @"en", nil , @"com" }, // english (catch all) - { @"fr", @"CA", @"ca" }, // french - canada - { @"fr", @"CH", @"ch" }, // french - switzerland - { @"fr", nil , @"fr" }, // france - { @"it", nil , @"it" }, // italy - { @"de", @"AT", @"at" }, // german - austria - { @"de", nil , @"de" }, // germany - { @"es", @"MX", @"com.mx" }, // spanish - mexico - { @"es", @"AR", @"com.ar" }, // spanish - argentina - { @"es", @"CL", @"cl" }, // spanish - chile - { @"es", @"CO", @"com.co" }, // spanish - colombia - { @"es", @"PE", @"com.pe" }, // spanish - peru - { @"es", @"VE", @"co.ve" }, // venezuela - { @"es", nil , @"es" }, // spain - { @"zh", @"TW", @"com.tw" }, // taiwan - { @"zh", @"HK", @"com.hk" }, // hong kong - { @"zh", nil , @"cn" }, // chinese (catch all) - { @"ja", nil , @"co.jp" }, // japan - { @"ko", nil , @"co.kr" }, // korea - { @"nl", @"BE", @"be" }, // dutch - belgium - { @"nl", nil , @"nl" }, // (dutch) netherlands - { @"ru", nil , @"ru" }, // russia - { @"pt", @"BZ", @"com.br"}, // portuguese - brazil - { @"pt", nil , @"pt" }, // portugal - { @"sv", nil , @"se" }, // sweden - { @"nn", nil , @"no" }, // norway (two variants) - { @"nb", nil , @"no" }, // norway (two variants) - { @"da", nil , @"dk" }, // denmark - { @"fi", nil , @"fi" }, // finland - { @"bg", nil , @"bg" }, // bulgaria - { @"hr", nil , @"hr" }, // croatia - { @"cx", nil , @"cz" }, // czech republic - { @"el", nil , @"gr" }, // greece - { @"hu", nil , @"co.hu" }, // hungary - { @"ro", nil , @"ro" }, // romania - { @"sk", nil , @"sk" }, // slovakia - { @"sl", nil , @"si" }, // slovenia - { @"tr", nil , @"com.tr" }, // turkey - { @"my", nil , @"com.my" }, // malaysia - { @"th", nil , @"co.th" }, // thailand - { @"uk", nil , @"com.ua" }, // ukraine - { @"vi", nil , @"com.vn" }, // vietnam - { @"af", nil , @"com.za" }, // south africa (afrikaans) - { @"hi", nil , @"co.in" }, // india (hindi) - { @"id", nil , @"co.id" }, // indonesia - { @"pl", nil , @"pl" }, // poland -}; - -// the notification we use for syncing up instances in different processes -#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS -static NSString *const kNotificationName - = @"com.google.GoogleSearchAllApps.prefsWritten"; -#endif - -// this is the bundle id we use for the pref file used for all apps -static CFStringRef const kAllAppsBuildIdentifier - = CFSTR("com.google.GoogleSearchAllApps"); - -static CFStringRef const kPreferredDomainPrefKey - = CFSTR("com.google.PreferredDomain"); -static CFStringRef const kPreferredLanguagePrefKey - = CFSTR("com.google.PreferredLanguage"); - -static NSString *const kDefaultDomain = @"com"; -static NSString *const kDefaultLanguage = @"en"; - -#define SEARCH_URL_TEMPLATE @"http://www.google.%@/%@?%@" - -@interface GTMGoogleSearch (PrivateMethods) -- (void)defaultDomain:(NSString**)preferedDomain - language:(NSString**)preferredLanguage; -- (void)reloadAllAppCachedValues:(NSNotification*)notification; -- (void)updateAllAppsDomain:(NSString*)domain language:(NSString*)language; -@end - - -@implementation GTMGoogleSearch - -+ (GTMGoogleSearch *)sharedInstance { - static GTMGoogleSearch *obj; - if (!obj) { - obj = [[self alloc] init]; - } - return obj; -} - -- (id)init { - self = [super init]; - if (self != nil) { -#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS - // register for the notification - NSDistributedNotificationCenter *distCenter = - [NSDistributedNotificationCenter defaultCenter]; - [distCenter addObserver:self - selector:@selector(reloadAllAppCachedValues:) - name:kNotificationName - object:nil]; -#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS - // load the allApps value - [self reloadAllAppCachedValues:nil]; - - // load the cur app value - CFStringRef domain - = CFPreferencesCopyValue(kPreferredDomainPrefKey, - kCFPreferencesCurrentApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - CFStringRef lang = CFPreferencesCopyValue(kPreferredLanguagePrefKey, - kCFPreferencesCurrentApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - - // make sure we got values for both and domain is not empty - if (domain && CFStringGetLength(domain) == 0) { - CFRelease(domain); - domain = nil; - if (lang) { - CFRelease(lang); - lang = nil; - } - } - - curAppCachedDomain_ = (NSString *)domain; - curAppCachedLanguage_ = (NSString *)lang; - - NSBundle *bundle = [NSBundle mainBundle]; - - NSDictionary *appArgs - = [bundle objectForInfoDictionaryKey:GTMGoogleSearchClientAppArgsKey]; - globalSearchArguments_ = [appArgs retain]; - } - return self; -} - -#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS -- (void)finalize { - [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; - [super finalize]; -} -#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS - -- (void)dealloc { -#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS - [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; -#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS - [allAppsCachedDomain_ release]; - [allAppsCachedLanguage_ release]; - [curAppCachedDomain_ release]; - [curAppCachedLanguage_ release]; - [globalSearchArguments_ release]; - [super dealloc]; -} - -- (void)preferredDomain:(NSString **)domain - language:(NSString**)language - areCurrentAppOnly:(BOOL*)currentAppOnly { - BOOL localCurrentAppOnly = YES; - NSString *localDomain = curAppCachedDomain_; - NSString *localLanguage = curAppCachedLanguage_; - - // if either one wasn't there, drop both, and use any app if we can - if (!localDomain || !localLanguage) { - localCurrentAppOnly = NO; - localDomain = allAppsCachedDomain_; - localLanguage = allAppsCachedLanguage_; - - // if we didn't get anything from the prefs, go with the defaults - if (!localDomain || !localLanguage) { - // if either one wasn't there, drop both, and use defaults - [self defaultDomain:&localDomain language:&localLanguage]; - } - } - if (!localDomain || !localLanguage) { - _GTMDevLog(@"GTMGoogleSearch: Failed to get the preferred domain/language " - @"from prefs or defaults"); - } - if (language) { - *language = [[localLanguage retain] autorelease]; - } - if (domain) { - *domain = [[localDomain retain] autorelease]; - } - if (currentAppOnly) { - *currentAppOnly = localCurrentAppOnly; - } -} - -- (void)updatePreferredDomain:(NSString*)domain - language:(NSString*)language - currentApplicationOnly:(BOOL)currentAppOnly { - // valid inputs? - if (!domain || ![domain length] || !language) { - return; - } - - if (currentAppOnly) { - // if they are the same, don't do anything - if ((domain == nil && curAppCachedDomain_ == nil && - language == nil && curAppCachedLanguage_ == nil) || - ([domain isEqualToString:curAppCachedDomain_] && - [language isEqualToString:curAppCachedLanguage_])) { - return; - } - - // save them out - CFPreferencesSetValue(kPreferredDomainPrefKey, - (CFStringRef)domain, - kCFPreferencesCurrentApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - CFPreferencesSetValue(kPreferredLanguagePrefKey, - (CFStringRef)language, - kCFPreferencesCurrentApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - CFPreferencesSynchronize(kCFPreferencesCurrentApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - // update our locals - [curAppCachedDomain_ release]; - [curAppCachedLanguage_ release]; - curAppCachedDomain_ = [domain copy]; - curAppCachedLanguage_ = [language copy]; - } else { - // Set the "any application" values - [self updateAllAppsDomain:domain language:language]; - - // Clear the current application values (if there were any) - [self clearPreferredDomainAndLanguageForCurrentApplication]; - } -} - -- (void)clearPreferredDomainAndLanguageForCurrentApplication { - // flush what's in the file - CFPreferencesSetValue(kPreferredDomainPrefKey, - NULL, - kCFPreferencesCurrentApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - CFPreferencesSetValue(kPreferredLanguagePrefKey, - NULL, - kCFPreferencesCurrentApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - CFPreferencesSynchronize(kCFPreferencesCurrentApplication, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - // clear our locals - [curAppCachedDomain_ release]; - [curAppCachedLanguage_ release]; - curAppCachedDomain_ = nil; - curAppCachedLanguage_ = nil; -} - -- (void)clearPreferredDomainAndLanguageForAllApps { - // nil/nil to clear things out, this will also update our cached values. - [self updateAllAppsDomain:nil language:nil]; -} - -- (NSDictionary *)globalSearchArguments { - return globalSearchArguments_; -} - -- (void)setGlobalSearchArguments:(NSDictionary *)args { - [globalSearchArguments_ autorelease]; - globalSearchArguments_ = [args copy]; -} - -- (NSString*)searchURLFor:(NSString*)queryText - ofType:(NSString*)type - arguments:(NSDictionary *)localArgs { - if (!type) { - return nil; - } - - NSString *language; - NSString *domain; - [self preferredDomain:&domain - language:&language - areCurrentAppOnly:NULL]; - - NSMutableDictionary *args - = [NSMutableDictionary dictionaryWithObjectsAndKeys: - @"UTF-8", @"ie", - @"UTF-8", @"oe", - language, @"hl", - nil]; - if (queryText) { - [args setObject:queryText forKey:@"q"]; - } - - NSDictionary *globalSearchArgs = [self globalSearchArguments]; - if (globalSearchArgs) { - [args addEntriesFromDictionary:globalSearchArgs]; - } - if (localArgs) { - [args addEntriesFromDictionary:localArgs]; - } - - NSMutableArray *clientArgs = [NSMutableArray array]; - NSString *key; - NSNull *nsNull = [NSNull null]; - GTM_FOREACH_KEY(key, args) { - NSString *object = [args objectForKey:key]; - if (![object isEqual:nsNull]) { -#if DEBUG - // In debug we check key and object for things that should be escaped. - // Note that percent is not in there because escaped strings will have - // percents in them - NSCharacterSet *cs = [NSCharacterSet characterSetWithCharactersInString: - @"!*'();:@&=+$,/?#[] "]; - NSRange range = [key rangeOfCharacterFromSet:cs]; - if (range.location != NSNotFound) { - _GTMDevLog(@"Unescaped string %@ in argument pair {%@, %@} in -[%@ %@]", - key, key, object, [self class], NSStringFromSelector(_cmd)); - } - range = [object rangeOfCharacterFromSet:cs]; - if (range.location != NSNotFound) { - _GTMDevLog(@"Unescaped string %@ in argument pair {%@,%@ } in -[%@ %@]", - object, key, object, [self class], - NSStringFromSelector(_cmd)); - } -#endif // DEBUG - NSString *arg = [NSString stringWithFormat:@"%@=%@", key, object]; - [clientArgs addObject:arg]; - } - } - NSString *clientArg = [clientArgs componentsJoinedByString:@"&"]; - NSString *url = [NSString stringWithFormat:SEARCH_URL_TEMPLATE, - domain, type, clientArg]; - return url; -} - -- (BOOL)performQuery:(NSString*)queryText - ofType:(NSString *)type - arguments:(NSDictionary *)localArgs { - BOOL success = NO; - NSString *urlString = [self searchURLFor:queryText - ofType:type - arguments:localArgs]; - if (urlString) { - NSURL *url = [NSURL URLWithString:urlString]; - if (url) { -#if GTM_IPHONE_SDK - success = [[UIApplication sharedApplication] openURL:url]; -#else // GTM_IPHONE_SDK - success = [[NSWorkspace sharedWorkspace] openURL:url]; -#endif // GTM_IPHONE_SDK - } - } - return success; -} - -@end - - -@implementation GTMGoogleSearch (PrivateMethods) - -- (void)defaultDomain:(NSString**)preferredDomain - language:(NSString**)preferredLanguage { - // must have both - if (!preferredDomain || !preferredLanguage) { - return; - } - - // make sure they are clear to start - *preferredDomain = nil; - *preferredLanguage = nil; - - // loop over their language list trying to find something we have in - // out default table. - - NSUserDefaults* defs = [NSUserDefaults standardUserDefaults]; - NSArray* languages = [defs objectForKey:@"AppleLanguages"]; - // the current locale is only based on what languages the running apps is - // localized to, so we stick that at the end in case we weren't able to - // find anything else as a match, we'll match that. - languages = - [languages arrayByAddingObject:[[NSLocale currentLocale] localeIdentifier]]; - - NSEnumerator *enumerator = [languages objectEnumerator]; - NSString *localeIdentifier; - while ((localeIdentifier = [enumerator nextObject])) { - NSDictionary *localeParts - = [NSLocale componentsFromLocaleIdentifier:localeIdentifier]; - NSString *localeLanguage = [localeParts objectForKey:NSLocaleLanguageCode]; - // we don't use NSLocaleScriptCode for now - NSString *localeCountry = [localeParts objectForKey:NSLocaleCountryCode]; - - LanguageDefaultInfo *scan = kLanguageListDefaultMappingTable; - LanguageDefaultInfo *end = (scan + (sizeof(kLanguageListDefaultMappingTable) - / sizeof(LanguageDefaultInfo))); - // find a match - // check language, and if country is not nil, check that - for ( ; scan < end ; ++scan) { - if ([localeLanguage isEqualToString:scan->language] && - (!(scan->country) || [localeCountry isEqualToString:scan->country])) { - *preferredDomain = scan->defaultDomain; - *preferredLanguage = localeLanguage; - return; // out of here - } - } - } - - *preferredDomain = kDefaultDomain; - *preferredLanguage = kDefaultLanguage; -} - -// -reloadAllAppCachedValues: -// -- (void)reloadAllAppCachedValues:(NSNotification*)notification { - // drop the old... - [allAppsCachedDomain_ release]; - [allAppsCachedLanguage_ release]; - allAppsCachedDomain_ = nil; - allAppsCachedLanguage_ = nil; - - // load the new - CFPreferencesSynchronize(kAllAppsBuildIdentifier, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - CFStringRef domain = CFPreferencesCopyValue(kPreferredDomainPrefKey, - kAllAppsBuildIdentifier, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - CFStringRef lang = CFPreferencesCopyValue(kPreferredLanguagePrefKey, - kAllAppsBuildIdentifier, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - - // make sure we got values for both and domain is not empty - if (domain && CFStringGetLength(domain) == 0) { - CFRelease(domain); - domain = nil; - if (lang) { - CFRelease(lang); - lang = nil; - } - } - - allAppsCachedDomain_ = (NSString *)domain; - allAppsCachedLanguage_ = (NSString *)lang; -} - -// -updateAllAppsDomain:language: -// -- (void)updateAllAppsDomain:(NSString*)domain language:(NSString*)language { - // domain and language can be nil to clear the values - - // if they are the same, don't do anything - if ((domain == nil && allAppsCachedDomain_ == nil && - language == nil && allAppsCachedLanguage_ == nil) || - ([domain isEqualToString:allAppsCachedDomain_] && - [language isEqualToString:allAppsCachedLanguage_])) { - return; - } - - // write it to the file - CFPreferencesSetValue(kPreferredDomainPrefKey, - (CFStringRef)domain, - kAllAppsBuildIdentifier, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - CFPreferencesSetValue(kPreferredLanguagePrefKey, - (CFStringRef)language, - kAllAppsBuildIdentifier, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - CFPreferencesSynchronize(kAllAppsBuildIdentifier, - kCFPreferencesCurrentUser, - kCFPreferencesAnyHost); - - // update our values - [allAppsCachedDomain_ release]; - [allAppsCachedLanguage_ release]; - allAppsCachedDomain_ = [domain copy]; - allAppsCachedLanguage_ = [language copy]; - -#if GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS - // NOTE: we'll go ahead and reload when this comes back to ourselves since - // there is a race here if two folks wrote at about the same time. - NSDistributedNotificationCenter *distCenter = - [NSDistributedNotificationCenter defaultCenter]; - [distCenter postNotificationName:kNotificationName - object:nil - userInfo:nil]; -#endif // GTM_GOOGLE_SEARCH_SUPPORTS_DISTRIBUTED_NOTIFICATIONS -} - -@end |