Plugins/Purple Service/ESPurpleJabberAccountViewController.m
author Zachary West <zacw@adium.im>
Tue Oct 20 11:23:25 2009 -0400 (2009-10-20)
changeset 2752 a365b03465cb
parent 2728 995a4486a368
child 3078 1b883db24823
permissions -rw-r--r--
Set the BOSH server value into the right text field. Fixes #13206.
David@0
     1
/* 
David@0
     2
 * Adium is the legal property of its developers, whose names are listed in the copyright file included
David@0
     3
 * with this source distribution.
David@0
     4
 * 
David@0
     5
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
David@0
     6
 * General Public License as published by the Free Software Foundation; either version 2 of the License,
David@0
     7
 * or (at your option) any later version.
David@0
     8
 * 
David@0
     9
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
David@0
    10
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
David@0
    11
 * Public License for more details.
David@0
    12
 * 
David@0
    13
 * You should have received a copy of the GNU General Public License along with this program; if not,
David@0
    14
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
David@0
    15
 */
David@0
    16
David@0
    17
#import "ESPurpleJabberAccountViewController.h"
David@0
    18
#import <Adium/AIAccount.h>
David@0
    19
#import <Adium/AIContactControllerProtocol.h>
David@0
    20
#import <Adium/AIService.h>
David@194
    21
#import <Adium/AIContactList.h>
catfish@2093
    22
#import <SystemConfiguration/SystemConfiguration.h>
sholt@2693
    23
#include <tgmath.h>
David@0
    24
am@2459
    25
#define SERVERFEEDRSSURL @"http://xmpp.org/services/services-full.xml"
David@0
    26
David@0
    27
@implementation ESPurpleJabberAccountViewController
David@0
    28
David@0
    29
- (NSString *)nibName{
David@0
    30
    return @"ESPurpleJabberAccountView";
David@0
    31
}
David@0
    32
David@0
    33
- (void)awakeFromNib
David@0
    34
{
David@0
    35
	[super awakeFromNib];
David@0
    36
	
David@0
    37
	[checkBox_checkMail setEnabled:NO];
David@0
    38
	
David@1109
    39
	[[NSNotificationCenter defaultCenter] addObserver:self
David@0
    40
								   selector:@selector(contactListChanged:)
David@0
    41
									   name:Contact_ListChanged
David@0
    42
									 object:nil];
David@0
    43
}
David@0
    44
David@0
    45
//Configure our controls
David@0
    46
- (void)configureForAccount:(AIAccount *)inAccount
David@0
    47
{
David@0
    48
    [super configureForAccount:inAccount];
David@0
    49
	
David@0
    50
	//Connection security
David@0
    51
	[checkBox_forceOldSSL setState:[[account preferenceForKey:KEY_JABBER_FORCE_OLD_SSL group:GROUP_ACCOUNT_STATUS] boolValue]];
David@0
    52
	[checkBox_requireTLS setState:[[account preferenceForKey:KEY_JABBER_REQUIRE_TLS group:GROUP_ACCOUNT_STATUS] boolValue]];
David@0
    53
	[checkBox_checkCertificates setState:[account preferenceForKey:KEY_JABBER_VERIFY_CERTS group:GROUP_ACCOUNT_STATUS]?[[account preferenceForKey:KEY_JABBER_VERIFY_CERTS group:GROUP_ACCOUNT_STATUS] boolValue]:YES];
David@0
    54
	[checkBox_allowPlaintext setState:[[account preferenceForKey:KEY_JABBER_ALLOW_PLAINTEXT group:GROUP_ACCOUNT_STATUS] boolValue]];
David@0
    55
	
David@0
    56
	//Resource
Evan@775
    57
	NSString *resource = [account preferenceForKey:KEY_JABBER_RESOURCE group:GROUP_ACCOUNT_STATUS];
Evan@775
    58
	if (!resource)
Evan@775
    59
		resource = [(NSString*)SCDynamicStoreCopyLocalHostName(NULL) autorelease];
Evan@775
    60
	if (!resource)
Evan@775
    61
		resource = @"";	
Evan@775
    62
	[textField_resource setStringValue:resource];
David@0
    63
	
David@0
    64
	//Connect server
David@0
    65
	NSString *connectServer = [account preferenceForKey:KEY_JABBER_CONNECT_SERVER group:GROUP_ACCOUNT_STATUS];
David@0
    66
	[textField_connectServer setStringValue:(connectServer ? connectServer : @"")];
David@0
    67
	
zacw@2728
    68
	// BOSH server
zacw@2728
    69
	NSString *boshServer = [account preferenceForKey:KEY_JABBER_BOSH_SERVER group:GROUP_ACCOUNT_STATUS];
zacw@2752
    70
	[textField_BOSHserver setStringValue:(boshServer ?: @"")];	
zacw@2728
    71
	
David@0
    72
	//Priority
David@0
    73
	NSNumber *priority = [account preferenceForKey:KEY_JABBER_PRIORITY_AVAILABLE group:GROUP_ACCOUNT_STATUS];
David@0
    74
	[textField_priorityAvailable setStringValue:(priority ? [priority stringValue] : @"")];
David@0
    75
	priority = [account preferenceForKey:KEY_JABBER_PRIORITY_AWAY group:GROUP_ACCOUNT_STATUS];
David@0
    76
	[textField_priorityAway setStringValue:(priority ? [priority stringValue] : @"")];
zacw@2202
    77
	
zacw@2202
    78
	//File transfer proxies
zacw@2202
    79
	NSString *ftProxies = [account preferenceForKey:KEY_JABBER_FT_PROXIES group:GROUP_ACCOUNT_STATUS];
zacw@2205
    80
	[textField_ftProxies setStringValue:ftProxies ?: @""];
David@0
    81
		
David@0
    82
	//Subscription behavior
sholt@2693
    83
	NSInteger subbeh = [[account preferenceForKey:KEY_JABBER_SUBSCRIPTION_BEHAVIOR group:GROUP_ACCOUNT_STATUS] integerValue];
David@0
    84
	[popup_subscriptionBehavior selectItemWithTag:subbeh];
David@0
    85
	NSString *defaultGroup = [account preferenceForKey:KEY_JABBER_SUBSCRIPTION_GROUP group:GROUP_ACCOUNT_STATUS];
David@0
    86
	[comboBox_subscriptionGroup setStringValue:(defaultGroup ? defaultGroup : @"")];
David@0
    87
	
David@0
    88
	//Hide the register button if the account can't register new accounts
David@837
    89
	[button_register setHidden:![account.service canRegisterNewAccounts]];
David@0
    90
	
David@0
    91
	//Set hidden flag of the default group combobox
David@0
    92
	[self subscriptionModeDidChange:nil];
David@0
    93
}
David@0
    94
David@0
    95
//Save controls
David@0
    96
- (void)saveConfiguration
David@0
    97
{
David@0
    98
    [super saveConfiguration];
David@0
    99
	
David@0
   100
	//Connection security
David@0
   101
	[account setPreference:[NSNumber numberWithBool:[checkBox_forceOldSSL state]]
David@0
   102
					forKey:KEY_JABBER_FORCE_OLD_SSL group:GROUP_ACCOUNT_STATUS];
David@0
   103
	[account setPreference:[NSNumber numberWithBool:[checkBox_requireTLS state]]
David@0
   104
								   forKey:KEY_JABBER_REQUIRE_TLS group:GROUP_ACCOUNT_STATUS];
David@0
   105
	[account setPreference:[NSNumber numberWithBool:[checkBox_checkCertificates state]]
David@0
   106
					forKey:KEY_JABBER_VERIFY_CERTS group:GROUP_ACCOUNT_STATUS];
David@0
   107
	[account setPreference:[NSNumber numberWithBool:[checkBox_allowPlaintext state]]
David@0
   108
					forKey:KEY_JABBER_ALLOW_PLAINTEXT group:GROUP_ACCOUNT_STATUS];
David@0
   109
David@0
   110
	//Resource
David@0
   111
	[account setPreference:([[textField_resource stringValue] length] ? [textField_resource stringValue] : nil)
David@0
   112
					forKey:KEY_JABBER_RESOURCE group:GROUP_ACCOUNT_STATUS];
David@0
   113
	
David@0
   114
	//Connect server
David@0
   115
	[account setPreference:([[textField_connectServer stringValue] length] ? [textField_connectServer stringValue] : nil)
David@0
   116
					forKey:KEY_JABBER_CONNECT_SERVER group:GROUP_ACCOUNT_STATUS];
zacw@2202
   117
	
zacw@2728
   118
	//BOSH server
zacw@2728
   119
	[account setPreference:([[textField_BOSHserver stringValue] length] ? [textField_BOSHserver stringValue] : nil)
zacw@2728
   120
					forKey:KEY_JABBER_BOSH_SERVER group:GROUP_ACCOUNT_STATUS];	
zacw@2728
   121
	
zacw@2202
   122
	//FT proxies
zacw@2232
   123
	[account setPreference:[textField_ftProxies stringValue]
zacw@2202
   124
					forKey:KEY_JABBER_FT_PROXIES group:GROUP_ACCOUNT_STATUS];
zacw@2202
   125
	
David@0
   126
	//Priority
sholt@2693
   127
	[account setPreference:([textField_priorityAvailable integerValue] ? [NSNumber numberWithInteger:[textField_priorityAvailable integerValue]] : nil)
David@0
   128
					forKey:KEY_JABBER_PRIORITY_AVAILABLE
David@0
   129
					 group:GROUP_ACCOUNT_STATUS];
sholt@2693
   130
	[account setPreference:([textField_priorityAway integerValue] ? [NSNumber numberWithInteger:[textField_priorityAway integerValue]] : nil)
David@0
   131
					forKey:KEY_JABBER_PRIORITY_AWAY
David@0
   132
					 group:GROUP_ACCOUNT_STATUS];
David@0
   133
David@0
   134
	//Subscription Behavior
sholt@2693
   135
	[account setPreference:([[popup_subscriptionBehavior selectedItem] tag] ? [NSNumber numberWithInteger:[[popup_subscriptionBehavior selectedItem] tag]] : nil)
David@0
   136
					forKey:KEY_JABBER_SUBSCRIPTION_BEHAVIOR
David@0
   137
					 group:GROUP_ACCOUNT_STATUS];
David@0
   138
	[account setPreference:([[comboBox_subscriptionGroup stringValue] length] ? [comboBox_subscriptionGroup stringValue] : nil)
David@0
   139
					forKey:KEY_JABBER_SUBSCRIPTION_GROUP group:GROUP_ACCOUNT_STATUS];
David@0
   140
}
David@0
   141
David@0
   142
- (IBAction)subscriptionModeDidChange:(id)sender {
David@0
   143
	// only show these two when "accept and add to contact list" is selected
sholt@2693
   144
	NSInteger tag = [[popup_subscriptionBehavior selectedItem] tag];
David@0
   145
	[textField_subscriptionModeLabel setHidden:tag != 2];
David@0
   146
	[comboBox_subscriptionGroup setHidden:tag != 2];
David@0
   147
}
David@0
   148
David@0
   149
- (void)dealloc {
David@1109
   150
	[[NSNotificationCenter defaultCenter] removeObserver:self];
David@0
   151
	[window_registerServer release];
David@0
   152
	[servers release];
David@0
   153
David@0
   154
	[super dealloc];
David@0
   155
}
David@0
   156
David@0
   157
#pragma mark group combobox datasource
David@0
   158
David@0
   159
- (void)contactListChanged:(NSNotification*)n {
David@0
   160
	[comboBox_subscriptionGroup reloadData];
David@0
   161
}
David@0
   162
sholt@2634
   163
- (NSInteger)numberOfItemsInComboBox:(NSComboBox *)aComboBox {
Peter@1061
   164
	return [adium.contactController.contactList countOfContainedObjects];
David@0
   165
}
David@0
   166
sholt@2634
   167
- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(NSInteger)index {
David@194
   168
	return [[adium.contactController.contactList.containedObjects objectAtIndex:index] formattedUID];
David@0
   169
}
David@0
   170
David@3
   171
- (NSUInteger)comboBox:(NSComboBox *)aComboBox indexOfItemWithStringValue:(NSString *)string {
David@194
   172
	NSArray *groups = adium.contactController.contactList.containedObjects;
David@3
   173
	NSUInteger i;
David@3
   174
	for(i = 0;i < [groups count];++i) {
David@0
   175
		AIListGroup *group = [groups objectAtIndex:i];
David@837
   176
		if([group.formattedUID isEqualToString:string])
David@0
   177
			return i;
David@0
   178
	}
David@0
   179
	return NSNotFound;
David@0
   180
}
David@0
   181
David@0
   182
- (NSString *)comboBox:(NSComboBox *)aComboBox completedString:(NSString *)string {
David@191
   183
	for(AIListObject *obj in adium.contactController.contactList) {
David@837
   184
		if([obj isKindOfClass:[AIListGroup class]] && [obj.formattedUID hasPrefix:string])
David@837
   185
			return obj.formattedUID;
David@0
   186
	}
David@0
   187
	return string;
David@0
   188
}
David@0
   189
David@0
   190
#pragma mark account creation
David@0
   191
David@3
   192
static NSComparisonResult compareByDistance(id one, id two, void*context) {
David@0
   193
	NSNumber *dist1obj = [one objectForKey:@"distance"];
David@0
   194
	NSNumber *dist2obj = [two objectForKey:@"distance"];
David@0
   195
	
David@0
   196
	if((id)dist2obj == [NSNull null]) {
David@0
   197
		if((id)dist1obj == [NSNull null])
David@0
   198
			return NSOrderedSame;
David@0
   199
		return NSOrderedAscending;
David@0
   200
	}
David@0
   201
	if((id)dist1obj == [NSNull null])
David@0
   202
		return NSOrderedDescending;
David@0
   203
	
sholt@2693
   204
	CGFloat dist1 = [dist1obj doubleValue];
sholt@2693
   205
	CGFloat dist2 = [dist2obj doubleValue];
David@0
   206
	
David@0
   207
	if(fabs(dist1 - dist2) < 0.000001)
David@0
   208
		return NSOrderedSame;
David@0
   209
	
David@0
   210
	if(dist1 > dist2)
David@0
   211
		return NSOrderedDescending;
David@0
   212
	return NSOrderedAscending;
David@0
   213
}
David@0
   214
David@0
   215
- (IBAction)registerNewAccount:(id)sender {
David@0
   216
	if(!servers) {
David@0
   217
		NSError *err = NULL;
David@748
   218
		NSXMLDocument *serverfeed = [[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL URLWithString:SERVERFEEDRSSURL]
David@0
   219
																		 options:0
David@748
   220
																		   error:&err] autorelease];
David@0
   221
		if(err) {
David@0
   222
			[[NSAlert alertWithError:err] runModal];
David@0
   223
		} else {
David@0
   224
			NSXMLElement *root = [serverfeed rootElement];
Andreas@305
   225
			NSArray *items = [root elementsForName:@"item"];
David@0
   226
			
Andreas@305
   227
			if(!root || !items || ![[root name] isEqualToString:@"query"]) {
David@0
   228
				
David@0
   229
				[[NSAlert alertWithMessageText:AILocalizedString(@"Parse Error.",nil)
David@0
   230
								 defaultButton:AILocalizedString(@"OK",nil)
David@0
   231
							   alternateButton:nil
David@0
   232
								   otherButton:nil
David@0
   233
					 informativeTextWithFormat:[NSString stringWithFormat:
David@0
   234
												AILocalizedString(@"Unable to parse the server list at %@. Please try again later.",nil), SERVERFEEDRSSURL]] runModal];
catfish@2104
   235
			} else {				
David@0
   236
				MachineLocation loc;
David@0
   237
				ReadLocation(&loc);
David@0
   238
				
sholt@2693
   239
				CGFloat latitude = FractToFloat(loc.latitude)*(M_PI/2.0f);
sholt@2693
   240
				CGFloat longitude = FractToFloat(loc.longitude)*(M_PI/2.0f);
David@0
   241
				
David@0
   242
				servers = [[NSMutableArray alloc] init];
David@0
   243
				
catfish@2104
   244
				for (NSXMLElement *item in items) {
am@2459
   245
					NSXMLElement *title = [[item elementsForName:@"domain"] lastObject];
David@0
   246
					if(!title)
David@0
   247
						continue;
David@0
   248
					NSXMLElement *description = [[item elementsForName:@"description"] lastObject];
Andreas@305
   249
					NSXMLElement *latitudeNode  = [[item elementsForName:@"latitude"] lastObject];
Andreas@305
   250
					NSXMLElement *longitudeNode = [[item elementsForName:@"longitude"] lastObject];
Andreas@305
   251
					NSString *domain = [[item attributeForName:@"jid"] stringValue];
Andreas@305
   252
					NSString *homepageStr = [[[item elementsForName:@"homepage"] lastObject] stringValue];
Andreas@305
   253
					NSURL *homepage = homepageStr?[NSURL URLWithString:homepageStr]:nil;
David@0
   254
					
David@0
   255
					id distance = [NSNull null];
David@0
   256
					if (latitudeNode && longitudeNode) {
David@0
   257
						/* Calculate the distance between the computer and the xmpp server in km
David@0
   258
						 * Note that this assumes that the earth is a perfect sphere
David@0
   259
						 * If it turns out to be flat or doughnut-shaped, this will not work!
David@0
   260
						 */
David@0
   261
						
sholt@2693
   262
						CGFloat latitude2 = [[latitudeNode stringValue] doubleValue] * (M_PI/180.0f);
sholt@2693
   263
						CGFloat longitude2 = [[longitudeNode stringValue] doubleValue] * (M_PI/180.0f);
David@0
   264
						
sholt@2693
   265
						CGFloat d_lat = sinf((latitude2 - latitude)/2.0);
sholt@2693
   266
						CGFloat d_long = sinf((longitude2 - longitude)/2.0);
sholt@2693
   267
						CGFloat a = d_lat*d_lat + cosf(latitude)*cosf(latitude2)*d_long*d_long;
sholt@2693
   268
						CGFloat c = 2*atan2f(sqrt(a),sqrt(1.0-a));
sholt@2693
   269
						CGFloat d = 6372.797*c; // mean earth radius
David@0
   270
						
sholt@2693
   271
						distance = [NSNumber numberWithDouble:d];
David@0
   272
					}
David@0
   273
					
David@0
   274
					[(NSMutableArray*)servers addObject:[NSDictionary dictionaryWithObjectsAndKeys:
David@0
   275
						[title stringValue], @"servername",
David@0
   276
						(description ? (id)[description stringValue] : (id)[NSNull null]), @"description",
David@0
   277
						distance, @"distance",
Andreas@305
   278
						domain, @"domain",
Andreas@305
   279
						homepage, @"homepage", // might be nil
David@0
   280
						nil]];
David@0
   281
				}
David@0
   282
				
David@0
   283
				[(NSMutableArray*)servers sortUsingFunction:compareByDistance context:nil];
David@0
   284
				
David@0
   285
				[tableview_servers reloadData];
David@0
   286
			}
David@0
   287
		}
David@0
   288
	}
David@0
   289
	
David@0
   290
	[NSApp beginSheet:window_registerServer
David@0
   291
	   modalForWindow:[sender window]
David@0
   292
		modalDelegate:self
David@0
   293
	   didEndSelector:@selector(registrationSheetDidEnd:returnCode:contextInfo:)
David@0
   294
		  contextInfo:NULL];
David@0
   295
}
David@0
   296
sholt@2693
   297
- (void)registrationSheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
David@0
   298
{
David@0
   299
	
David@0
   300
}
David@0
   301
sholt@2634
   302
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
David@0
   303
	return [servers count];
David@0
   304
}
David@0
   305
sholt@2634
   306
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
David@0
   307
	id objectValue = [[servers objectAtIndex:row] objectForKey:[tableColumn identifier]];
David@0
   308
	return ((objectValue && ![objectValue isKindOfClass:[NSNull class]]) ? objectValue : @"");
David@0
   309
}
David@0
   310
David@0
   311
- (void)tableViewSelectionDidChange:(NSNotification *)notification {
Andreas@305
   312
	NSDictionary *serverInfo = [servers objectAtIndex:[tableview_servers selectedRow]];
Andreas@305
   313
	NSString *servername = [serverInfo objectForKey:@"domain"];
David@0
   314
	[textField_registerServerName setStringValue:servername];
David@0
   315
	[textField_registerServerPort setStringValue:@""];
Andreas@305
   316
	[textView_serverDescription setString:[serverInfo objectForKey:@"description"]];
Andreas@305
   317
	
Andreas@305
   318
	[button_serverHomepage setEnabled:[serverInfo objectForKey:@"homepage"] != nil];
Andreas@305
   319
}
Andreas@305
   320
Andreas@305
   321
- (IBAction)visitServerHomepage:(id)sender {
Andreas@305
   322
	NSDictionary *serverInfo = [servers objectAtIndex:[tableview_servers selectedRow]];
Andreas@305
   323
	
Andreas@305
   324
	[[NSWorkspace sharedWorkspace] openURL:[serverInfo objectForKey:@"homepage"]];
David@0
   325
}
David@0
   326
David@0
   327
- (IBAction)registerCancel:(id)sender {
David@0
   328
	[window_registerServer orderOut:nil];
David@0
   329
	[NSApp endSheet:window_registerServer];
David@0
   330
}
David@0
   331
David@0
   332
- (IBAction)registerRequestAccount:(id)sender {
David@0
   333
	[[sender window] makeFirstResponder:nil]; // apply all changes
zacw@2466
   334
	
David@0
   335
	if([[textField_registerServerName stringValue] length] == 0) {
David@0
   336
		NSBeep();
David@0
   337
		return;
David@0
   338
	}
zacw@2466
   339
	
sholt@2693
   340
	[account setPreference:[NSNumber numberWithInteger:[textField_registerServerPort integerValue]]
David@0
   341
					forKey:KEY_CONNECT_PORT group:GROUP_ACCOUNT_STATUS];
David@0
   342
David@0
   343
	NSString *newUID;
David@0
   344
	if ([[textField_accountUID stringValue] length]) {
David@0
   345
		NSRange atLocation = [[textField_accountUID stringValue] rangeOfString:@"@" options:NSLiteralSearch];
David@0
   346
		if (atLocation.location == NSNotFound)
David@0
   347
			newUID = [NSString stringWithFormat:@"%@@%@",[textField_accountUID stringValue], [textField_registerServerName stringValue]];
David@0
   348
		else
David@0
   349
			newUID = [NSString stringWithFormat:@"%@@%@",[[textField_accountUID stringValue] substringToIndex:atLocation.location], [textField_registerServerName stringValue]];
David@0
   350
	} else {
David@0
   351
		newUID = [NSString stringWithFormat:@"nobody@%@",[textField_registerServerName stringValue]];
David@0
   352
	}
David@0
   353
David@0
   354
	[account filterAndSetUID:newUID];
David@0
   355
	
David@0
   356
	[window_registerServer orderOut:nil];
David@0
   357
	[NSApp endSheet:window_registerServer];
David@0
   358
	
David@0
   359
	[account performRegisterWithPassword:[textField_password stringValue]];
David@0
   360
	[self didBeginRegistration];
David@0
   361
}
David@0
   362
David@0
   363
@end