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