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