Plugins/Twitter Plugin/AITwitterAccountViewController.m
author Zachary West <zacw@adium.im>
Fri Oct 16 10:12:34 2009 -0400 (2009-10-16)
changeset 2612 cb1fd4d17218
parent 2487 5bc5f3809c1c
child 3095 6a3d7db6050b
permissions -rw-r--r--
Patch from brion to add an SSL option for StatusNet accounts. Fixes #13077.
     1 /* 
     2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
     3  * with this source distribution.
     4  * 
     5  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
     6  * General Public License as published by the Free Software Foundation; either version 2 of the License,
     7  * or (at your option) any later version.
     8  * 
     9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
    10  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    11  * Public License for more details.
    12  * 
    13  * You should have received a copy of the GNU General Public License along with this program; if not,
    14  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    15  */
    16 
    17 #import "AITwitterAccount.h"
    18 #import "AITwitterAccountViewController.h"
    19 #import <AIUtilities/AIMenuAdditions.h>
    20 #import <Adium/AIAccountControllerProtocol.h>
    21 
    22 #import "AITwitterAccountOAuthSetup.h"
    23 
    24 #define BUTTON_TEXT_ALLOW_ACCESS		AILocalizedString(@"Allow Adium access", nil)
    25 
    26 @interface AITwitterAccountViewController()
    27 - (void)completedOAuthSetup;
    28 - (void)setStatusText:(NSString *)text withColor:(NSColor *)color buttonEnabled:(BOOL)enabled buttonText:(NSString *)buttonText;
    29 @end
    30 
    31 @implementation AITwitterAccountViewController
    32 
    33 /*!
    34  * @brief We have no privacy settings.
    35  */
    36 - (NSView *)privacyView
    37 {
    38 	return nil;
    39 }
    40 
    41 /*!
    42  * @brief Use the Twitter account view.
    43  */
    44 - (NSString *)nibName
    45 {
    46     return @"AITwitterAccountView";
    47 }
    48 
    49 - (void)awakeFromNib
    50 {
    51 	NSMenu *intervalMenu = [[[NSMenu alloc] init] autorelease];
    52 
    53 	[intervalMenu addItemWithTitle:AILocalizedString(@"never", "Update tweets: never")
    54 							target:self
    55 							action:nil
    56 					 keyEquivalent:@""
    57 				 representedObject:[NSNumber numberWithInt:0]];
    58 	
    59 	[intervalMenu addItemWithTitle:AILocalizedString(@"every 2 minutes", "Update tweets: every 2 minutes")
    60 							target:self
    61 							action:nil
    62 					 keyEquivalent:@""
    63 				 representedObject:[NSNumber numberWithInt:2]];
    64 
    65 	[intervalMenu addItemWithTitle:AILocalizedString(@"every 5 minutes", "Update tweets: every 5 minutes")
    66 							target:self
    67 							action:nil
    68 					 keyEquivalent:@""
    69 				 representedObject:[NSNumber numberWithInt:5]];
    70 	
    71 	[intervalMenu addItemWithTitle:AILocalizedString(@"every 10 minutes", "Update tweets every: 10 minutes")
    72 							target:self
    73 							action:nil
    74 					 keyEquivalent:@""
    75 				 representedObject:[NSNumber numberWithInt:10]];
    76 	
    77 	[intervalMenu addItemWithTitle:AILocalizedString(@"every 15 minutes", "Update tweets every: 15 minutes")
    78 							target:self
    79 							action:nil
    80 					 keyEquivalent:@""
    81 				 representedObject:[NSNumber numberWithInt:15]];
    82 	
    83 	[intervalMenu addItemWithTitle:AILocalizedString(@"every half-hour", "Update tweets every: half-hour")
    84 							target:self
    85 							action:nil
    86 					 keyEquivalent:@""
    87 				 representedObject:[NSNumber numberWithInt:30]];
    88 	
    89 	[intervalMenu addItemWithTitle:AILocalizedString(@"every hour", "Update tweets every hour")
    90 							target:self
    91 							action:nil
    92 					 keyEquivalent:@""
    93 				 representedObject:[NSNumber numberWithInt:60]];
    94 	
    95 	[intervalMenu setAutoenablesItems:YES];
    96 	
    97 	[popUp_updateInterval setMenu:intervalMenu];
    98 	
    99 	[self setStatusText:@"" withColor:nil buttonEnabled:YES buttonText:BUTTON_TEXT_ALLOW_ACCESS];
   100 }
   101 
   102 - (void)dealloc
   103 {
   104 	[OAuthSetup release]; OAuthSetup = nil;
   105 	[super dealloc];
   106 }
   107 
   108 /*!
   109  * @brief A preference was changed
   110  *
   111  * Don't save here; merely update controls as necessary.
   112  */
   113 - (IBAction)changedPreference:(id)sender
   114 {
   115 	[checkBox_updateGlobalIncludeReplies setEnabled:[checkBox_updateGlobalStatus state]];
   116 	
   117 	if(sender == button_OAuthStart) {
   118 		if (OAuthSetupStep == AIOAuthStepRequestToken) {
   119 			OAuthSetup.verifier = textField_OAuthVerifier.stringValue;
   120 			textField_OAuthVerifier.stringValue = @"";
   121 			
   122 			[OAuthSetup fetchAccessToken];
   123 		} else {
   124 			[OAuthSetup release];
   125 			
   126 			OAuthSetup = [[AITwitterAccountOAuthSetup alloc] initWithDelegate:self
   127 																   forAccount:(AITwitterAccount *)account];
   128 			
   129 			[OAuthSetup beginSetup];
   130 		}
   131 	}
   132 }
   133 
   134 /*!
   135  * @brief Configure the account view
   136  */
   137 - (void)configureForAccount:(AIAccount *)inAccount
   138 {
   139 	[super configureForAccount:inAccount];
   140 	
   141 	// Setup - OAuth
   142 	
   143 	AITwitterAccount *twitterAccount = (AITwitterAccount *)account;
   144 	
   145 	if (twitterAccount.useOAuth) {
   146 		[tabView_authenticationType selectTabViewItem:tabViewItem_OAuth];
   147 		
   148 		if ([account.lastDisconnectionError isEqualToString:TWITTER_OAUTH_NOT_AUTHORIZED]) {
   149 			[self setStatusText:TWITTER_OAUTH_NOT_AUTHORIZED
   150 					  withColor:[NSColor redColor]
   151 				  buttonEnabled:YES
   152 					 buttonText:BUTTON_TEXT_ALLOW_ACCESS];
   153 		
   154 		} else if (account.UID && [[adium.accountController passwordForAccount:account] length]) {
   155 			[self setStatusText:AILocalizedString(@"Adium currently has access to your account.", nil)
   156 					  withColor:nil
   157 				  buttonEnabled:NO
   158 					 buttonText:BUTTON_TEXT_ALLOW_ACCESS];
   159 		} else {
   160 			[self setStatusText:nil
   161 					  withColor:nil
   162 				  buttonEnabled:YES
   163 					 buttonText:BUTTON_TEXT_ALLOW_ACCESS];
   164 		}
   165 	} else {
   166 		[tabView_authenticationType selectTabViewItem:tabViewItem_basicAuthentication];
   167 	}
   168 	
   169 	[textField_OAuthVerifier setHidden:YES];
   170 	
   171 	// Options
   172 	
   173 	NSNumber *updateInterval = [account preferenceForKey:TWITTER_PREFERENCE_UPDATE_INTERVAL group:TWITTER_PREFERENCE_GROUP_UPDATES];
   174 	[popUp_updateInterval selectItemAtIndex:[[popUp_updateInterval menu] indexOfItemWithRepresentedObject:updateInterval]];
   175 	
   176 	BOOL updateAfterSend = [[account preferenceForKey:TWITTER_PREFERENCE_UPDATE_AFTER_SEND group:TWITTER_PREFERENCE_GROUP_UPDATES] boolValue];
   177 	[checkBox_updateAfterSend setState:updateAfterSend];
   178 	
   179 	BOOL updateGlobal = [[account preferenceForKey:TWITTER_PREFERENCE_UPDATE_GLOBAL group:TWITTER_PREFERENCE_GROUP_UPDATES] boolValue];
   180 	[checkBox_updateGlobalStatus setState:updateGlobal];
   181 
   182 	BOOL updateGlobalIncludesReplies = [[account preferenceForKey:TWITTER_PREFERENCE_UPDATE_GLOBAL_REPLIES group:TWITTER_PREFERENCE_GROUP_UPDATES] boolValue];
   183 	[checkBox_updateGlobalIncludeReplies setState:updateGlobalIncludesReplies];
   184 	
   185 	[checkBox_updateGlobalIncludeReplies setEnabled:[checkBox_updateGlobalStatus state]];
   186 
   187 	BOOL showRetweet = [[account preferenceForKey:TWITTER_PREFERENCE_RETWEET_SPAM group:TWITTER_PREFERENCE_GROUP_UPDATES] boolValue];
   188 	[checkBox_retweet setState:showRetweet];
   189 
   190 	BOOL loadContacts = [[account preferenceForKey:TWITTER_PREFERENCE_LOAD_CONTACTS group:TWITTER_PREFERENCE_GROUP_UPDATES] boolValue];
   191 	[checkBox_loadContacts setState:loadContacts];
   192 	
   193 	// Personal
   194 
   195 	textField_name.stringValue = [account valueForProperty:@"Profile Name"] ?: @"";
   196 	textField_url.stringValue = [account valueForProperty:@"Profile URL"] ?: @"";
   197 	textField_location.stringValue = [account valueForProperty:@"Profile Location"] ?: @"";
   198 	textField_description.stringValue = [account valueForProperty:@"Profile Description"] ?: @"";
   199 	
   200 	[textField_name setEnabled:account.online];
   201 	[textField_url setEnabled:account.online];
   202 	[textField_location setEnabled:account.online];
   203 	[textField_description setEnabled:account.online];
   204 	
   205 	textField_APIpath.stringValue = @"";
   206 	
   207 	[textField_connectHost setEnabled:NO];
   208 	[textField_APIpath setEnabled:NO];
   209 	[checkBox_useSSL setEnabled:NO];
   210 }
   211 
   212 /*!
   213  * @brief The Update Interval combo box was changed.
   214  */
   215 - (void)saveConfiguration
   216 {
   217 	[super saveConfiguration];
   218 	
   219 	[OAuthSetup release]; OAuthSetup = nil;
   220 	
   221 	[account setPreference:popUp_updateInterval.selectedItem.representedObject
   222 					forKey:TWITTER_PREFERENCE_UPDATE_INTERVAL
   223 					 group:TWITTER_PREFERENCE_GROUP_UPDATES];
   224 	
   225 	[account setPreference:[NSNumber numberWithBool:[checkBox_updateAfterSend state]]
   226 					forKey:TWITTER_PREFERENCE_UPDATE_AFTER_SEND
   227 					 group:TWITTER_PREFERENCE_GROUP_UPDATES];
   228 	
   229 	[account setPreference:[NSNumber numberWithBool:[checkBox_updateGlobalStatus state]]
   230 					forKey:TWITTER_PREFERENCE_UPDATE_GLOBAL
   231 					 group:TWITTER_PREFERENCE_GROUP_UPDATES];
   232 	
   233 	[account setPreference:[NSNumber numberWithBool:[checkBox_updateGlobalIncludeReplies state]]
   234 					forKey:TWITTER_PREFERENCE_UPDATE_GLOBAL_REPLIES
   235 					 group:TWITTER_PREFERENCE_GROUP_UPDATES];
   236 	
   237 	[account setPreference:[NSNumber numberWithBool:[checkBox_retweet state]]
   238 					forKey:TWITTER_PREFERENCE_RETWEET_SPAM
   239 					 group:TWITTER_PREFERENCE_GROUP_UPDATES];
   240 
   241 	[account setPreference:[NSNumber numberWithBool:[checkBox_loadContacts state]]
   242 					forKey:TWITTER_PREFERENCE_LOAD_CONTACTS
   243 					 group:TWITTER_PREFERENCE_GROUP_UPDATES];
   244 	
   245 	if (account.online) {
   246 		[(AITwitterAccount *)account setProfileName:(textField_name.isEnabled ? textField_name.stringValue : nil)
   247 												url:(textField_url.isEnabled ? textField_url.stringValue : nil)
   248 										   location:(textField_location.isEnabled ? textField_location.stringValue : nil)
   249 										description:(textField_description.isEnabled ? textField_description.stringValue : nil)];
   250 	}
   251 }
   252 
   253 #pragma mark OAuth status text
   254 - (void)setStatusText:(NSString *)text withColor:(NSColor *)color buttonEnabled:(BOOL)enabled buttonText:(NSString *)buttonText
   255 {
   256 	textField_OAuthStatus.stringValue = text ?: @"";
   257 	textField_OAuthStatus.textColor = color ?: [NSColor controlTextColor];
   258 
   259 	[button_OAuthStart setEnabled:enabled];
   260 	
   261 	if(buttonText) {
   262 		button_OAuthStart.title = buttonText;
   263 		[button_OAuthStart sizeToFit];
   264 		[button_OAuthStart setFrameOrigin:NSMakePoint(NSMidX(button_OAuthStart.superview.frame) - NSWidth(button_OAuthStart.frame)/2.0,
   265 													  NSMinY(button_OAuthStart.frame))];
   266 	}
   267 }
   268 
   269 #pragma mark OAuth setup delegate
   270 
   271 - (void)OAuthSetup:(AITwitterAccountOAuthSetup *)setup
   272 	 changedToStep:(AIOAuthSetupStep)setupStep
   273 		 withToken:(OAToken *)token
   274 	  responseBody:(NSString *)responseBody
   275 {
   276 	AILogWithSignature(@"Step %u", setupStep);
   277 	
   278 	OAuthSetupStep = setupStep;
   279 	
   280 	switch (OAuthSetupStep) {
   281 		case AIOAuthStepStart:
   282 		case AIOAuthStepVerifyingRequest:
   283 			// Just starting or verifying a token, fetching a request token
   284 			[self setStatusText:@""
   285 					  withColor:nil
   286 				  buttonEnabled:YES
   287 					 buttonText:nil];
   288 			
   289 			[textField_OAuthVerifier setHidden:YES];
   290 			[progressIndicator setHidden:NO];
   291 			[progressIndicator startAnimation:nil];
   292 			
   293 			break;
   294 			
   295 		case AIOAuthStepRequestToken:
   296 			// We have a request token, ask user to authorize.			
   297 			[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?oauth_token=%@",
   298 																		 ((AITwitterAccount *)account).tokenAuthorizeURL,
   299 																		 token.key]]];
   300 
   301 			[self setStatusText:AILocalizedString(@"You must allow Adium access to your account in the browser window which just opened. When you have done so, enter the PIN code in the field above.", nil)
   302 					  withColor:nil
   303 				  buttonEnabled:YES
   304 					 buttonText:AILocalizedString(@"I've allowed Adium access", nil)];
   305 
   306 			[textField_OAuthVerifier setHidden:NO];
   307 			[progressIndicator setHidden:YES];
   308 			[progressIndicator stopAnimation:nil];
   309 			
   310 			break;
   311 			
   312 		case AIOAuthStepAccessToken:
   313 			// We have an access token, hoorah!
   314 			textField_password.stringValue = responseBody;
   315 			
   316 			[self setStatusText:AILocalizedString(@"Success! Adium now has access to your account. Click OK below.", nil)
   317 					  withColor:nil
   318 				  buttonEnabled:NO
   319 					 buttonText:nil];
   320 			
   321 			[textField_OAuthVerifier setHidden:YES];
   322 			[progressIndicator setHidden:YES];
   323 			[progressIndicator stopAnimation:nil];
   324 			
   325 			[account setLastDisconnectionError:nil];
   326 			[account setValue:[NSNumber numberWithBool:YES] forProperty:@"Reconnect After Edit" notify:NotifyNever];
   327 
   328 			[self completedOAuthSetup];			
   329 			
   330 			break;
   331 			
   332 		case AIOAuthStepFailure:
   333 			// Failed in some way. sad. :(
   334 
   335 			[self setStatusText:AILocalizedString(@"An error occured while trying to gain access. Please try again.", nil)
   336 					  withColor:[NSColor redColor]
   337 				  buttonEnabled:YES
   338 					 buttonText:BUTTON_TEXT_ALLOW_ACCESS];
   339 			
   340 			[textField_OAuthVerifier setHidden:YES];
   341 			[progressIndicator setHidden:YES];
   342 			[progressIndicator stopAnimation:nil];
   343 			
   344 			[self completedOAuthSetup];
   345 			
   346 			break;
   347 	}
   348 }
   349 
   350 - (void)completedOAuthSetup
   351 {
   352 	[OAuthSetup release]; OAuthSetup = nil;
   353 	OAuthSetupStep = AIOAuthStepFailure;	
   354 }
   355 
   356 @end