| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "remoting/host/me2me_preference_pane.h" | 5 #import "remoting/host/me2me_preference_pane.h" |
| 6 | 6 |
| 7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
| 8 #include <CommonCrypto/CommonHMAC.h> | 8 #include <CommonCrypto/CommonHMAC.h> |
| 9 #include <launch.h> | 9 #include <launch.h> |
| 10 #import <PreferencePanes/PreferencePanes.h> | 10 #import <PreferencePanes/PreferencePanes.h> |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 object:nil]; | 172 object:nil]; |
| 173 | 173 |
| 174 service_status_timer_ = | 174 service_status_timer_ = |
| 175 [[NSTimer scheduledTimerWithTimeInterval:2.0 | 175 [[NSTimer scheduledTimerWithTimeInterval:2.0 |
| 176 target:self | 176 target:self |
| 177 selector:@selector(refreshServiceStatus:) | 177 selector:@selector(refreshServiceStatus:) |
| 178 userInfo:nil | 178 userInfo:nil |
| 179 repeats:YES] retain]; | 179 repeats:YES] retain]; |
| 180 [self updateServiceStatus]; | 180 [self updateServiceStatus]; |
| 181 [self updateAuthorizationStatus]; | 181 [self updateAuthorizationStatus]; |
| 182 [self readNewConfig]; | 182 |
| 183 [self checkInstalledVersion]; |
| 184 if (!restart_pending_or_canceled_) |
| 185 [self readNewConfig]; |
| 186 |
| 183 [self updateUI]; | 187 [self updateUI]; |
| 184 } | 188 } |
| 185 | 189 |
| 190 - (void)didSelect { |
| 191 [self checkInstalledVersion]; |
| 192 } |
| 193 |
| 186 - (void)willUnselect { | 194 - (void)willUnselect { |
| 187 NSDistributedNotificationCenter* center = | 195 NSDistributedNotificationCenter* center = |
| 188 [NSDistributedNotificationCenter defaultCenter]; | 196 [NSDistributedNotificationCenter defaultCenter]; |
| 189 [center removeObserver:self]; | 197 [center removeObserver:self]; |
| 190 | 198 |
| 191 [service_status_timer_ invalidate]; | 199 [service_status_timer_ invalidate]; |
| 192 [service_status_timer_ release]; | 200 [service_status_timer_ release]; |
| 193 service_status_timer_ = nil; | 201 service_status_timer_ = nil; |
| 194 if (have_new_config_) { | 202 if (have_new_config_) |
| 195 [self notifyPlugin:kUpdateFailedNotificationName]; | 203 [self notifyPlugin:kUpdateFailedNotificationName]; |
| 196 } | |
| 197 } | 204 } |
| 198 | 205 |
| 199 - (void)applyConfiguration:(id)sender | 206 - (void)applyConfiguration:(id)sender |
| 200 pin:(NSString*)pin { | 207 pin:(NSString*)pin { |
| 201 if (!have_new_config_) { | 208 if (!have_new_config_) { |
| 202 // It shouldn't be possible to hit the button if there is no config to | 209 // It shouldn't be possible to hit the button if there is no config to |
| 203 // apply, but check anyway just in case it happens somehow. | 210 // apply, but check anyway just in case it happens somehow. |
| 204 return; | 211 return; |
| 205 } | 212 } |
| 206 | 213 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 return; | 245 return; |
| 239 } | 246 } |
| 240 | 247 |
| 241 // Stop the launchd job. This cannot easily be done by the helper tool, | 248 // Stop the launchd job. This cannot easily be done by the helper tool, |
| 242 // since the launchd job runs in the current user's context. | 249 // since the launchd job runs in the current user's context. |
| 243 [self sendJobControlMessage:LAUNCH_KEY_STOPJOB]; | 250 [self sendJobControlMessage:LAUNCH_KEY_STOPJOB]; |
| 244 awaiting_service_stop_ = YES; | 251 awaiting_service_stop_ = YES; |
| 245 } | 252 } |
| 246 | 253 |
| 247 - (void)onNewConfigFile:(NSNotification*)notification { | 254 - (void)onNewConfigFile:(NSNotification*)notification { |
| 248 [self readNewConfig]; | 255 [self checkInstalledVersion]; |
| 256 if (!restart_pending_or_canceled_) |
| 257 [self readNewConfig]; |
| 258 |
| 249 [self updateUI]; | 259 [self updateUI]; |
| 250 } | 260 } |
| 251 | 261 |
| 252 - (void)refreshServiceStatus:(NSTimer*)timer { | 262 - (void)refreshServiceStatus:(NSTimer*)timer { |
| 253 BOOL was_running = is_service_running_; | 263 BOOL was_running = is_service_running_; |
| 254 [self updateServiceStatus]; | 264 [self updateServiceStatus]; |
| 255 if (awaiting_service_stop_ && !is_service_running_) { | 265 if (awaiting_service_stop_ && !is_service_running_) { |
| 256 awaiting_service_stop_ = NO; | 266 awaiting_service_stop_ = NO; |
| 257 [self notifyPlugin:kUpdateSucceededNotificationName]; | 267 [self notifyPlugin:kUpdateSucceededNotificationName]; |
| 258 } | 268 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 274 - (void)updateServiceStatus { | 284 - (void)updateServiceStatus { |
| 275 pid_t job_pid = base::mac::PIDForJob(kServiceName); | 285 pid_t job_pid = base::mac::PIDForJob(kServiceName); |
| 276 is_service_running_ = (job_pid > 0); | 286 is_service_running_ = (job_pid > 0); |
| 277 } | 287 } |
| 278 | 288 |
| 279 - (void)updateAuthorizationStatus { | 289 - (void)updateAuthorizationStatus { |
| 280 is_pane_unlocked_ = [authorization_view_ updateStatus:authorization_view_]; | 290 is_pane_unlocked_ = [authorization_view_ updateStatus:authorization_view_]; |
| 281 } | 291 } |
| 282 | 292 |
| 283 - (void)readNewConfig { | 293 - (void)readNewConfig { |
| 284 if ([self restartPanelIfDifferentVersionInstalled]) { | |
| 285 // Don't read any new config if the version is mismatched. Return control | |
| 286 // to the main run-loop instead, so the application can be terminated. | |
| 287 return; | |
| 288 } | |
| 289 | |
| 290 std::string file; | 294 std::string file; |
| 291 if (!GetTemporaryConfigFilePath(&file)) { | 295 if (!GetTemporaryConfigFilePath(&file)) { |
| 292 LOG(ERROR) << "Failed to get path of configuration data."; | 296 LOG(ERROR) << "Failed to get path of configuration data."; |
| 293 [self showError]; | 297 [self showError]; |
| 294 return; | 298 return; |
| 295 } | 299 } |
| 296 if (access(file.c_str(), F_OK) != 0) | 300 if (access(file.c_str(), F_OK) != 0) |
| 297 return; | 301 return; |
| 298 | 302 |
| 299 scoped_ptr<remoting::JsonHostConfig> new_config_( | 303 scoped_ptr<remoting::JsonHostConfig> new_config_( |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 344 [status_message_ setStringValue:message]; | 348 [status_message_ setStringValue:message]; |
| 345 | 349 |
| 346 std::string email; | 350 std::string email; |
| 347 if (config_.get()) { | 351 if (config_.get()) { |
| 348 bool result = config_->GetString(remoting::kXmppLoginConfigPath, &email); | 352 bool result = config_->GetString(remoting::kXmppLoginConfigPath, &email); |
| 349 | 353 |
| 350 // The config has already been checked by |IsConfigValid|. | 354 // The config has already been checked by |IsConfigValid|. |
| 351 DCHECK(result); | 355 DCHECK(result); |
| 352 } | 356 } |
| 353 | 357 |
| 354 [disable_view_ setEnabled:(is_pane_unlocked_ && is_service_running_)]; | 358 [disable_view_ setEnabled:(is_pane_unlocked_ && is_service_running_ && |
| 355 [confirm_pin_view_ setEnabled:is_pane_unlocked_]; | 359 !restart_pending_or_canceled_)]; |
| 360 [confirm_pin_view_ setEnabled:(is_pane_unlocked_ && |
| 361 !restart_pending_or_canceled_)]; |
| 356 [confirm_pin_view_ setEmail:base::SysUTF8ToNSString(email)]; | 362 [confirm_pin_view_ setEmail:base::SysUTF8ToNSString(email)]; |
| 357 NSString* applyButtonText = is_service_running_ ? @"Confirm" : @"Enable"; | 363 NSString* applyButtonText = is_service_running_ ? @"Confirm" : @"Enable"; |
| 358 [confirm_pin_view_ setButtonText:applyButtonText]; | 364 [confirm_pin_view_ setButtonText:applyButtonText]; |
| 365 |
| 366 if (restart_pending_or_canceled_) |
| 367 [authorization_view_ setEnabled:NO]; |
| 359 } | 368 } |
| 360 | 369 |
| 361 - (void)showError { | 370 - (void)showError { |
| 362 NSAlert* alert = [[NSAlert alloc] init]; | 371 NSAlert* alert = [[NSAlert alloc] init]; |
| 363 [alert setMessageText:@"An unexpected error occurred."]; | 372 [alert setMessageText:@"An unexpected error occurred."]; |
| 364 [alert setInformativeText:@"Check the system log for more information."]; | 373 [alert setInformativeText:@"Check the system log for more information."]; |
| 365 [alert setAlertStyle:NSWarningAlertStyle]; | 374 [alert setAlertStyle:NSWarningAlertStyle]; |
| 366 [alert beginSheetModalForWindow:[[self mainView] window] | 375 [alert beginSheetModalForWindow:[[self mainView] window] |
| 367 modalDelegate:nil | 376 modalDelegate:nil |
| 368 didEndSelector:nil | 377 didEndSelector:nil |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 | 531 |
| 523 - (void)notifyPlugin:(const char*)message { | 532 - (void)notifyPlugin:(const char*)message { |
| 524 NSDistributedNotificationCenter* center = | 533 NSDistributedNotificationCenter* center = |
| 525 [NSDistributedNotificationCenter defaultCenter]; | 534 [NSDistributedNotificationCenter defaultCenter]; |
| 526 NSString* name = [NSString stringWithUTF8String:message]; | 535 NSString* name = [NSString stringWithUTF8String:message]; |
| 527 [center postNotificationName:name | 536 [center postNotificationName:name |
| 528 object:nil | 537 object:nil |
| 529 userInfo:nil]; | 538 userInfo:nil]; |
| 530 } | 539 } |
| 531 | 540 |
| 532 - (BOOL)restartPanelIfDifferentVersionInstalled { | 541 - (void)checkInstalledVersion { |
| 533 NSBundle* this_bundle = [NSBundle bundleForClass:[self class]]; | 542 // There's no point repeating the check if the pane has already been disabled |
| 534 NSDictionary* this_plist = [this_bundle infoDictionary]; | 543 // from a previous call to this method. The pane only gets disabled when a |
| 535 NSString* this_version = [this_plist objectForKey:@"CFBundleVersion"]; | 544 // version-mismatch has been detected here, so skip the check, but continue to |
| 545 // handle the version-mismatch case. |
| 546 if (!restart_pending_or_canceled_) { |
| 547 NSBundle* this_bundle = [NSBundle bundleForClass:[self class]]; |
| 548 NSDictionary* this_plist = [this_bundle infoDictionary]; |
| 549 NSString* this_version = [this_plist objectForKey:@"CFBundleVersion"]; |
| 536 | 550 |
| 537 NSString* bundle_path = [this_bundle bundlePath]; | 551 NSString* bundle_path = [this_bundle bundlePath]; |
| 538 NSString* plist_path = | 552 NSString* plist_path = |
| 539 [bundle_path stringByAppendingString:@"/Contents/Info.plist"]; | 553 [bundle_path stringByAppendingString:@"/Contents/Info.plist"]; |
| 540 NSDictionary* disk_plist = | 554 NSDictionary* disk_plist = |
| 541 [NSDictionary dictionaryWithContentsOfFile:plist_path]; | 555 [NSDictionary dictionaryWithContentsOfFile:plist_path]; |
| 542 NSString* disk_version = [disk_plist objectForKey:@"CFBundleVersion"]; | 556 NSString* disk_version = [disk_plist objectForKey:@"CFBundleVersion"]; |
| 543 | 557 |
| 544 if (disk_version == nil) { | 558 if (disk_version == nil) { |
| 545 LOG(ERROR) << "Failed to get installed version information"; | 559 LOG(ERROR) << "Failed to get installed version information"; |
| 546 [self showError]; | 560 [self showError]; |
| 547 return NO; | 561 return; |
| 562 } |
| 563 |
| 564 if ([this_version isEqualToString:disk_version]) |
| 565 return; |
| 566 |
| 567 restart_pending_or_canceled_ = YES; |
| 568 [self updateUI]; |
| 548 } | 569 } |
| 549 | 570 |
| 550 if ([this_version isEqualToString:disk_version]) { | 571 NSWindow* window = [[self mainView] window]; |
| 551 return NO; | 572 if (window == nil) { |
| 573 // Defer the alert until |didSelect| is called, which happens just after |
| 574 // the window is created. |
| 575 return; |
| 576 } |
| 577 |
| 578 // This alert appears as a sheet over the top of the Chromoting pref-pane, |
| 579 // underneath the title, so it's OK to refer to "this preference pane" rather |
| 580 // than repeat the title "Chromoting" here. |
| 581 NSAlert* alert = [[NSAlert alloc] init]; |
| 582 [alert setMessageText:@"System update detected"]; |
| 583 [alert setInformativeText:@"To use this preference pane, System Preferences " |
| 584 "needs to be restarted"]; |
| 585 [alert addButtonWithTitle:@"OK"]; |
| 586 NSButton* cancel_button = [alert addButtonWithTitle:@"Cancel"]; |
| 587 [cancel_button setKeyEquivalent:@"\e"]; |
| 588 [alert setAlertStyle:NSWarningAlertStyle]; |
| 589 [alert beginSheetModalForWindow:window |
| 590 modalDelegate:self |
| 591 didEndSelector:@selector( |
| 592 mismatchAlertDidEnd:returnCode:contextInfo:) |
| 593 contextInfo:nil]; |
| 594 [alert release]; |
| 595 } |
| 596 |
| 597 - (void)mismatchAlertDidEnd:(NSAlert*)alert |
| 598 returnCode:(NSInteger)returnCode |
| 599 contextInfo:(void*)contextInfo { |
| 600 if (returnCode == NSAlertFirstButtonReturn) { |
| 601 // OK was pressed. |
| 602 |
| 603 // Dismiss the alert window here, so that the application will respond to |
| 604 // the NSApp terminate: message. |
| 605 [[alert window] orderOut:nil]; |
| 606 [self restartSystemPreferences]; |
| 552 } else { | 607 } else { |
| 553 // Terminate and relaunch System Preferences. | 608 // Cancel was pressed. |
| 554 | 609 |
| 555 // TODO(lambroslambrou): Improve this when System Preferences supports | 610 // If there is a new config file, delete it and notify the web-app of |
| 556 // dynamic reloading of pref-panes. | 611 // failure to apply the config. Otherwise, the web-app will remain in a |
| 557 NSTask* task = [[NSTask alloc] init]; | 612 // spinning state until System Preferences eventually gets restarted and |
| 558 NSArray* arguments = [NSArray arrayWithObjects:@"--relaunch-prefpane", nil]; | 613 // the user visits this pane again. |
| 559 [task setLaunchPath:[NSString stringWithUTF8String:kHelperTool]]; | 614 std::string file; |
| 560 [task setArguments:arguments]; | 615 if (!GetTemporaryConfigFilePath(&file)) { |
| 561 [task setStandardInput:[NSPipe pipe]]; | 616 // There's no point in alerting the user here. The same error would |
| 562 [task launch]; | 617 // happen when the pane is eventually restarted, so the user would be |
| 563 [task release]; | 618 // alerted at that time. |
| 564 [NSApp terminate:nil]; | 619 LOG(ERROR) << "Failed to get path of configuration data."; |
| 565 return YES; | 620 return; |
| 621 } |
| 622 if (access(file.c_str(), F_OK) != 0) |
| 623 return; |
| 624 |
| 625 remove(file.c_str()); |
| 626 [self notifyPlugin:kUpdateFailedNotificationName]; |
| 566 } | 627 } |
| 567 } | 628 } |
| 568 | 629 |
| 630 - (void)restartSystemPreferences { |
| 631 NSTask* task = [[NSTask alloc] init]; |
| 632 NSArray* arguments = [NSArray arrayWithObjects:@"--relaunch-prefpane", nil]; |
| 633 [task setLaunchPath:[NSString stringWithUTF8String:kHelperTool]]; |
| 634 [task setArguments:arguments]; |
| 635 [task setStandardInput:[NSPipe pipe]]; |
| 636 [task launch]; |
| 637 [task release]; |
| 638 [NSApp terminate:nil]; |
| 639 } |
| 640 |
| 569 @end | 641 @end |
| OLD | NEW |