| File: | Plugins/Purple Service/ESPurpleJabberAccountViewController.m |
| Location: | line 209, column 4 |
| Description: | Memory Leak |
| Code is compiled without garbage collection. |
| 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 | #include <SystemConfiguration/SystemConfiguration.h> |
| 22 | |
| 23 | #define SERVERFEEDRSSURL @"https://www.xmpp.net/servers/feed/rss" |
| 24 | |
| 25 | @implementation ESPurpleJabberAccountViewController |
| 26 | |
| 27 | - (NSString *)nibName{ |
| 28 | return @"ESPurpleJabberAccountView"; |
| 29 | } |
| 30 | |
| 31 | - (void)awakeFromNib |
| 32 | { |
| 33 | [super awakeFromNib]; |
| 34 | |
| 35 | [checkBox_checkMail setEnabled:NO( BOOL ) 0]; |
| 36 | |
| 37 | [[adium notificationCenter] addObserver:self |
| 38 | selector:@selector(contactListChanged:) |
| 39 | name:Contact_ListChanged@ "Contact_ListChanged" |
| 40 | object:nil0]; |
| 41 | } |
| 42 | |
| 43 | //Configure our controls |
| 44 | - (void)configureForAccount:(AIAccount *)inAccount |
| 45 | { |
| 46 | [super configureForAccount:inAccount]; |
| 47 | |
| 48 | //Connection security |
| 49 | [checkBox_forceOldSSL setState:[[account preferenceForKey:KEY_JABBER_FORCE_OLD_SSL@ "Jabber:Force Old SSL" group:GROUP_ACCOUNT_STATUS@ "Account Status"] boolValue]]; |
| 50 | [checkBox_requireTLS setState:[[account preferenceForKey:KEY_JABBER_REQUIRE_TLS@ "Jabber:Require TLS" group:GROUP_ACCOUNT_STATUS@ "Account Status"] boolValue]]; |
| 51 | [checkBox_checkCertificates setState:[account preferenceForKey:KEY_JABBER_VERIFY_CERTS@ "Jabber:Verify Certificates" group:GROUP_ACCOUNT_STATUS@ "Account Status"]?[[account preferenceForKey:KEY_JABBER_VERIFY_CERTS@ "Jabber:Verify Certificates" group:GROUP_ACCOUNT_STATUS@ "Account Status"] boolValue]:YES( BOOL ) 1]; |
| 52 | [checkBox_allowPlaintext setState:[[account preferenceForKey:KEY_JABBER_ALLOW_PLAINTEXT@ "Jabber:Allow Plaintext Authentication" group:GROUP_ACCOUNT_STATUS@ "Account Status"] boolValue]]; |
| 53 | |
| 54 | //Resource |
| 55 | if([account preferenceForKey:KEY_JABBER_RESOURCE@ "Jabber:Resource" group:GROUP_ACCOUNT_STATUS@ "Account Status"]) |
| 56 | [textField_resource setStringValue:[account preferenceForKey:KEY_JABBER_RESOURCE@ "Jabber:Resource" group:GROUP_ACCOUNT_STATUS@ "Account Status"]]; |
| 57 | else |
| 58 | [textField_resource setStringValue:[(NSString*)SCDynamicStoreCopyLocalHostName(NULL( ( void * ) 0 )) autorelease]]; |
| 59 | |
| 60 | //Connect server |
| 61 | NSString *connectServer = [account preferenceForKey:KEY_JABBER_CONNECT_SERVER@ "Jabber:Connect Server" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 62 | [textField_connectServer setStringValue:(connectServer ? connectServer : @"")]; |
| 63 | |
| 64 | //Priority |
| 65 | NSNumber *priority = [account preferenceForKey:KEY_JABBER_PRIORITY_AVAILABLE@ "Jabber:Priority when Available" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 66 | [textField_priorityAvailable setStringValue:(priority ? [priority stringValue] : @"")]; |
| 67 | priority = [account preferenceForKey:KEY_JABBER_PRIORITY_AWAY@ "Jabber:Priority when Away" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 68 | [textField_priorityAway setStringValue:(priority ? [priority stringValue] : @"")]; |
| 69 | |
| 70 | //Subscription behavior |
| 71 | int subbeh = [[account preferenceForKey:KEY_JABBER_SUBSCRIPTION_BEHAVIOR@ "Jabber:Subscription Behavior" group:GROUP_ACCOUNT_STATUS@ "Account Status"] intValue]; |
| 72 | [popup_subscriptionBehavior selectItemWithTag:subbeh]; |
| 73 | NSString *defaultGroup = [account preferenceForKey:KEY_JABBER_SUBSCRIPTION_GROUP@ "Jabber:Default Subscription Group" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 74 | [comboBox_subscriptionGroup setStringValue:(defaultGroup ? defaultGroup : @"")]; |
| 75 | |
| 76 | //Hide the register button if the account can't register new accounts |
| 77 | [button_register setHidden:![[account service] canRegisterNewAccounts]]; |
| 78 | |
| 79 | //Set hidden flag of the default group combobox |
| 80 | [self subscriptionModeDidChange:nil0]; |
| 81 | } |
| 82 | |
| 83 | //Save controls |
| 84 | - (void)saveConfiguration |
| 85 | { |
| 86 | [super saveConfiguration]; |
| 87 | |
| 88 | //Connection security |
| 89 | [account setPreference:[NSNumber numberWithBool:[checkBox_forceOldSSL state]] |
| 90 | forKey:KEY_JABBER_FORCE_OLD_SSL@ "Jabber:Force Old SSL" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 91 | [account setPreference:[NSNumber numberWithBool:[checkBox_requireTLS state]] |
| 92 | forKey:KEY_JABBER_REQUIRE_TLS@ "Jabber:Require TLS" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 93 | [account setPreference:[NSNumber numberWithBool:[checkBox_checkCertificates state]] |
| 94 | forKey:KEY_JABBER_VERIFY_CERTS@ "Jabber:Verify Certificates" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 95 | [account setPreference:[NSNumber numberWithBool:[checkBox_allowPlaintext state]] |
| 96 | forKey:KEY_JABBER_ALLOW_PLAINTEXT@ "Jabber:Allow Plaintext Authentication" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 97 | |
| 98 | //Resource |
| 99 | [account setPreference:([[textField_resource stringValue] length] ? [textField_resource stringValue] : nil0) |
| 100 | forKey:KEY_JABBER_RESOURCE@ "Jabber:Resource" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 101 | |
| 102 | //Connect server |
| 103 | [account setPreference:([[textField_connectServer stringValue] length] ? [textField_connectServer stringValue] : nil0) |
| 104 | forKey:KEY_JABBER_CONNECT_SERVER@ "Jabber:Connect Server" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 105 | |
| 106 | //Priority |
| 107 | [account setPreference:([textField_priorityAvailable intValue] ? [NSNumber numberWithInt:[textField_priorityAvailable intValue]] : nil0) |
| 108 | forKey:KEY_JABBER_PRIORITY_AVAILABLE@ "Jabber:Priority when Available" |
| 109 | group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 110 | [account setPreference:([textField_priorityAway intValue] ? [NSNumber numberWithInt:[textField_priorityAway intValue]] : nil0) |
| 111 | forKey:KEY_JABBER_PRIORITY_AWAY@ "Jabber:Priority when Away" |
| 112 | group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 113 | |
| 114 | //Subscription Behavior |
| 115 | [account setPreference:([[popup_subscriptionBehavior selectedItem] tag] ? [NSNumber numberWithInt:[[popup_subscriptionBehavior selectedItem] tag]] : nil0) |
| 116 | forKey:KEY_JABBER_SUBSCRIPTION_BEHAVIOR@ "Jabber:Subscription Behavior" |
| 117 | group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 118 | [account setPreference:([[comboBox_subscriptionGroup stringValue] length] ? [comboBox_subscriptionGroup stringValue] : nil0) |
| 119 | forKey:KEY_JABBER_SUBSCRIPTION_GROUP@ "Jabber:Default Subscription Group" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 120 | } |
| 121 | |
| 122 | - (IBActionvoid)subscriptionModeDidChange:(id)sender { |
| 123 | // only show these two when "accept and add to contact list" is selected |
| 124 | int tag = [[popup_subscriptionBehavior selectedItem] tag]; |
| 125 | [textField_subscriptionModeLabel setHidden:tag != 2]; |
| 126 | [comboBox_subscriptionGroup setHidden:tag != 2]; |
| 127 | } |
| 128 | |
| 129 | - (void)dealloc { |
| 130 | [[adium notificationCenter] removeObserver:self]; |
| 131 | [window_registerServer release]; |
| 132 | [servers release]; |
| 133 | |
| 134 | [super dealloc]; |
| 135 | } |
| 136 | |
| 137 | #pragma mark group combobox datasource |
| 138 | |
| 139 | - (void)contactListChanged:(NSNotification*)n { |
| 140 | [comboBox_subscriptionGroup reloadData]; |
| 141 | } |
| 142 | |
| 143 | - (int)numberOfItemsInComboBox:(NSComboBox *)aComboBox { |
| 144 | AIListGroup *list = [[adium contactController] contactList]; |
| 145 | return [list containedObjectsCount]; |
| 146 | } |
| 147 | |
| 148 | - (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)index { |
| 149 | AIListGroup *list = [[adium contactController] contactList]; |
| 150 | return [[list objectAtIndex:index] formattedUID]; |
| 151 | } |
| 152 | |
| 153 | - (unsigned int)comboBox:(NSComboBox *)aComboBox indexOfItemWithStringValue:(NSString *)string { |
| 154 | AIListGroup *list = [[adium contactController] contactList]; |
| 155 | NSArray *groups = [list containedObjects]; |
| 156 | unsigned i; |
| 157 | for(i=0;i < [groups count];++i) { |
| 158 | AIListGroup *group = [groups objectAtIndex:i]; |
| 159 | if([[group formattedUID] isEqualToString:string]) |
| 160 | return i; |
| 161 | } |
| 162 | return NSNotFound; |
| 163 | } |
| 164 | |
| 165 | - (NSString *)comboBox:(NSComboBox *)aComboBox completedString:(NSString *)string { |
| 166 | AIListGroup *list = [[adium contactController] contactList]; |
| 167 | NSArray *groups = [list containedObjects]; |
| 168 | unsigned i; |
| 169 | for(i=0;i < [groups count];++i) { |
| 170 | AIListGroup *group = [groups objectAtIndex:i]; |
| 171 | if([[group formattedUID] hasPrefix:string]) |
| 172 | return [group formattedUID]; |
| 173 | } |
| 174 | return string; |
| 175 | } |
| 176 | |
| 177 | #pragma mark account creation |
| 178 | |
| 179 | static int compareByDistance(id one, id two, void*context) { |
| 180 | NSNumber *dist1obj = [one objectForKey:@"distance"]; |
| 181 | NSNumber *dist2obj = [two objectForKey:@"distance"]; |
| 182 | |
| 183 | if((id)dist2obj == [NSNull null]) { |
| 184 | if((id)dist1obj == [NSNull null]) |
| 185 | return NSOrderedSame; |
| 186 | return NSOrderedAscending; |
| 187 | } |
| 188 | if((id)dist1obj == [NSNull null]) |
| 189 | return NSOrderedDescending; |
| 190 | |
| 191 | float dist1 = [dist1obj floatValue]; |
| 192 | float dist2 = [dist2obj floatValue]; |
| 193 | |
| 194 | if(fabs(dist1 - dist2) < 0.000001) |
| 195 | return NSOrderedSame; |
| 196 | |
| 197 | if(dist1 > dist2) |
| 198 | return NSOrderedDescending; |
| 199 | return NSOrderedAscending; |
| 200 | } |
| 201 | |
| 202 | - (IBActionvoid)registerNewAccount:(id)sender { |
[1] Taking true branch. | |
| 203 | if(!servers) { |
| 204 | NSError *err = NULL( ( void * ) 0 ); |
[2] Method returns an object with a +1 retain count (owning reference). | |
| 205 | NSXMLDocument *serverfeed = [[NSXMLDocument alloc] initWithContentsOfURL:[NSURL URLWithString:SERVERFEEDRSSURL@ "https://www.xmpp.net/servers/feed/rss"] |
| 206 | options:0 |
| 207 | error:&err]; |
[3] Taking true branch. | |
| 208 | if(err) { |
[4] Object allocated on line 205 and stored into 'serverfeed' is no longer referenced after this point and has a retain count of +1 (object leaked). | |
| 209 | [[NSAlert alertWithError:err] runModal]; |
| 210 | } else { |
| 211 | NSXMLElement *root = [serverfeed rootElement]; |
| 212 | NSArray *channels = [root elementsForName:@"channel"]; |
| 213 | |
| 214 | if(!root || !channels || ![[root name] isEqualToString:@"rss"] || [channels count] != 1) { |
| 215 | [serverfeed release]; |
| 216 | |
| 217 | [[NSAlert alertWithMessageText:AILocalizedString[ [ NSBundle bundleForClass : [ self class ] ] localizedStringForKey : ( @ "Parse Error." ) value : @ "" table : ( 0 ) ](@"Parse Error.",nil) |
| 218 | defaultButton:AILocalizedString[ [ NSBundle bundleForClass : [ self class ] ] localizedStringForKey : ( @ "OK" ) value : @ "" table : ( 0 ) ](@"OK",nil) |
| 219 | alternateButton:nil0 |
| 220 | otherButton:nil0 |
| 221 | informativeTextWithFormat:[NSString stringWithFormat: |
| 222 | AILocalizedString[ [ NSBundle bundleForClass : [ self class ] ] localizedStringForKey : ( @ "Unable to parse the server list at %@. Please try again later." ) value : @ "" table : ( 0 ) ](@"Unable to parse the server list at %@. Please try again later.",nil), SERVERFEEDRSSURL@ "https://www.xmpp.net/servers/feed/rss"]] runModal]; |
| 223 | } else { |
| 224 | float longitude, latitude; |
| 225 | |
| 226 | MachineLocation loc; |
| 227 | ReadLocation(&loc); |
| 228 | |
| 229 | latitude = FractToFloat( ( float ) ( loc . latitude ) / ( ( Fract ) 0x40000000L ) )(loc.latitude)*(M_PI3.14159265358979323846264338327950288/2.0f); |
| 230 | longitude = FractToFloat( ( float ) ( loc . longitude ) / ( ( Fract ) 0x40000000L ) )(loc.longitude)*(M_PI3.14159265358979323846264338327950288/2.0f); |
| 231 | |
| 232 | servers = [[NSMutableArray alloc] init]; |
| 233 | NSEnumerator *enumer = [[[channels lastObject] elementsForName:@"item"] objectEnumerator]; |
| 234 | NSXMLElement *item; |
| 235 | |
| 236 | while((item = [enumer nextObject])) { |
| 237 | NSXMLElement *title = [[item elementsForName:@"title"] lastObject]; |
| 238 | if(!title) |
| 239 | continue; |
| 240 | NSXMLElement *description = [[item elementsForName:@"description"] lastObject]; |
| 241 | NSXMLElement *latitudeNode = [[item elementsForLocalName:@"latitude" URI:@"http://geourl.org/rss/module/"] lastObject]; |
| 242 | NSXMLElement *longitudeNode = [[item elementsForLocalName:@"longitude" URI:@"http://geourl.org/rss/module/"] lastObject]; |
| 243 | |
| 244 | id distance = [NSNull null]; |
| 245 | if (latitudeNode && longitudeNode) { |
| 246 | /* Calculate the distance between the computer and the xmpp server in km |
| 247 | * Note that this assumes that the earth is a perfect sphere |
| 248 | * If it turns out to be flat or doughnut-shaped, this will not work! |
| 249 | */ |
| 250 | |
| 251 | float latitude2 = [[latitudeNode stringValue] floatValue] * (M_PI3.14159265358979323846264338327950288/180.0f); |
| 252 | float longitude2 = [[longitudeNode stringValue] floatValue] * (M_PI3.14159265358979323846264338327950288/180.0f); |
| 253 | |
| 254 | float d_lat = sinf((latitude2 - latitude)/2.0); |
| 255 | float d_long = sinf((longitude2 - longitude)/2.0); |
| 256 | float a = d_lat*d_lat + cosf(latitude)*cosf(latitude2)*d_long*d_long; |
| 257 | float c = 2*atan2f(sqrtf(a),sqrtf(1.0-a)); |
| 258 | float d = 6372.797*c; // mean earth radius |
| 259 | |
| 260 | distance = [NSNumber numberWithFloat:d]; |
| 261 | } |
| 262 | |
| 263 | [(NSMutableArray*)servers addObject:[NSDictionary dictionaryWithObjectsAndKeys: |
| 264 | [title stringValue], @"servername", |
| 265 | (description ? (id)[description stringValue] : (id)[NSNull null]), @"description", |
| 266 | distance, @"distance", |
| 267 | nil0]]; |
| 268 | } |
| 269 | |
| 270 | [serverfeed release]; |
| 271 | |
| 272 | [(NSMutableArray*)servers sortUsingFunction:compareByDistance context:nil0]; |
| 273 | |
| 274 | [tableview_servers reloadData]; |
| 275 | } |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | [NSApp beginSheet:window_registerServer |
| 280 | modalForWindow:[sender window] |
| 281 | modalDelegate:self |
| 282 | didEndSelector:@selector(registrationSheetDidEnd:returnCode:contextInfo:) |
| 283 | contextInfo:NULL( ( void * ) 0 )]; |
| 284 | } |
| 285 | |
| 286 | - (void)registrationSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo |
| 287 | { |
| 288 | |
| 289 | } |
| 290 | |
| 291 | - (int)numberOfRowsInTableView:(NSTableView *)tableView { |
| 292 | return [servers count]; |
| 293 | } |
| 294 | |
| 295 | - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row { |
| 296 | id objectValue = [[servers objectAtIndex:row] objectForKey:[tableColumn identifier]]; |
| 297 | return ((objectValue && ![objectValue isKindOfClass:[NSNull class]]) ? objectValue : @""); |
| 298 | } |
| 299 | |
| 300 | - (void)tableViewSelectionDidChange:(NSNotification *)notification { |
| 301 | NSString *servername = [self tableView:[notification object] objectValueForTableColumn:[[notification object] tableColumnWithIdentifier:@"servername"] row:[[notification object] selectedRow]]; |
| 302 | [textField_registerServerName setStringValue:servername]; |
| 303 | [textField_registerServerPort setStringValue:@""]; |
| 304 | } |
| 305 | |
| 306 | - (IBActionvoid)registerCancel:(id)sender { |
| 307 | [window_registerServer orderOut:nil0]; |
| 308 | [NSApp endSheet:window_registerServer]; |
| 309 | } |
| 310 | |
| 311 | - (IBActionvoid)registerRequestAccount:(id)sender { |
| 312 | [[sender window] makeFirstResponder:nil0]; // apply all changes |
| 313 | if([[textField_registerServerName stringValue] length] == 0) { |
| 314 | NSBeep(); |
| 315 | return; |
| 316 | } |
| 317 | // [account setUID:[NSString stringWithFormat:@"unknown@%@", [textField_registerServerName stringValue]]]; |
| 318 | [account setPreference:[textField_registerServerName stringValue] |
| 319 | forKey:KEY_JABBER_CONNECT_SERVER@ "Jabber:Connect Server" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 320 | [account setPreference:[NSNumber numberWithInt:[textField_registerServerPort intValue]] |
| 321 | forKey:KEY_CONNECT_PORT@ "Connect Port" group:GROUP_ACCOUNT_STATUS@ "Account Status"]; |
| 322 | |
| 323 | NSString *newUID; |
| 324 | if ([[textField_accountUID stringValue] length]) { |
| 325 | NSRange atLocation = [[textField_accountUID stringValue] rangeOfString:@"@" options:NSLiteralSearch]; |
| 326 | if (atLocation.location == NSNotFound) |
| 327 | newUID = [NSString stringWithFormat:@"%@@%@",[textField_accountUID stringValue], [textField_registerServerName stringValue]]; |
| 328 | else |
| 329 | newUID = [NSString stringWithFormat:@"%@@%@",[[textField_accountUID stringValue] substringToIndex:atLocation.location], [textField_registerServerName stringValue]]; |
| 330 | } else { |
| 331 | newUID = [NSString stringWithFormat:@"nobody@%@",[textField_registerServerName stringValue]]; |
| 332 | } |
| 333 | |
| 334 | [account filterAndSetUID:newUID]; |
| 335 | |
| 336 | [window_registerServer orderOut:nil0]; |
| 337 | [NSApp endSheet:window_registerServer]; |
| 338 | |
| 339 | [account performRegisterWithPassword:[textField_password stringValue]]; |
| 340 | [self didBeginRegistration]; |
| 341 | } |
| 342 | |
| 343 | @end |