diff options
author | lambroslambrou@chromium.org <lambroslambrou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-08 22:47:55 +0000 |
---|---|---|
committer | lambroslambrou@chromium.org <lambroslambrou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-08 22:47:55 +0000 |
commit | b1636bb28518e391520a90bccc1eb3febf18c3be (patch) | |
tree | 89a0ecd7ad0256aba98610fec984383dbde090c5 /remoting | |
parent | 1f7f8fe0eb8908ea4aee0896a6f93d62fcb440ff (diff) | |
download | chromium_src-b1636bb28518e391520a90bccc1eb3febf18c3be.zip chromium_src-b1636bb28518e391520a90bccc1eb3febf18c3be.tar.gz chromium_src-b1636bb28518e391520a90bccc1eb3febf18c3be.tar.bz2 |
Preference Pane for chromoting on Mac
This adds a new System Preference pane, which is shown when a user configures
the Chromoting Host via the web-app.
This is basically functional, but is not yet properly integrated with the
flow of the web-app. I will prepare a separate CL that implements
notifications from the pref-pane back to the web-app.
BUG=120903,121749
TEST=Manual
Review URL: https://chromiumcodereview.appspot.com/10171020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@135934 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/host/installer/mac/ChromotingHostService.packproj | 19 | ||||
-rw-r--r-- | remoting/host/me2me_preference_pane-Info.plist | 36 | ||||
-rw-r--r-- | remoting/host/me2me_preference_pane.h | 84 | ||||
-rw-r--r-- | remoting/host/me2me_preference_pane.mm | 403 | ||||
-rw-r--r-- | remoting/host/me2me_preference_pane.xib | 1047 | ||||
-rw-r--r-- | remoting/host/plugin/daemon_controller_mac.cc | 190 | ||||
-rw-r--r-- | remoting/remoting.gyp | 59 |
7 files changed, 1709 insertions, 129 deletions
diff --git a/remoting/host/installer/mac/ChromotingHostService.packproj b/remoting/host/installer/mac/ChromotingHostService.packproj index 9ad76ae..15e9f0c 100644 --- a/remoting/host/installer/mac/ChromotingHostService.packproj +++ b/remoting/host/installer/mac/ChromotingHostService.packproj @@ -217,7 +217,24 @@ </dict> <dict> <key>Children</key> - <array/> + <array> + <dict> + <key>Children</key> + <array/> + <key>GID</key> + <integer>80</integer> + <key>Path</key> + <string>PreferencePanes/org.chromium.chromoting.prefPane</string> + <key>Path Type</key> + <integer>2</integer> + <key>Privileges</key> + <integer>493</integer> + <key>Type</key> + <integer>3</integer> + <key>UID</key> + <integer>0</integer> + </dict> + </array> <key>GID</key> <integer>80</integer> <key>Path</key> diff --git a/remoting/host/me2me_preference_pane-Info.plist b/remoting/host/me2me_preference_pane-Info.plist new file mode 100644 index 0000000..983c206 --- /dev/null +++ b/remoting/host/me2me_preference_pane-Info.plist @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>${EXECUTABLE_NAME}</string> + <key>CFBundleIconFile</key> + <string></string> + <key>CFBundleIdentifier</key> + <string>BUNDLE_ID</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>BUNDLE_NAME</string> + <key>CFBundlePackageType</key> + <string>BNDL</string> + <key>CFBundleShortVersionString</key> + <string>VERSION_SHORT</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>VERSION_FULL</string> + <key>NSHumanReadableCopyright</key> + <string>Copyright © 2012 COPYRIGHT_BY All rights reserved.</string> + <key>NSMainNibFile</key> + <string>me2me_preference_pane</string> + <key>NSPrefPaneIconFile</key> + <string>chromoting128.png</string> + <key>NSPrefPaneIconLabel</key> + <string>Me2Me</string> + <key>NSPrincipalClass</key> + <string>Me2MePreferencePane</string> +</dict> +</plist> diff --git a/remoting/host/me2me_preference_pane.h b/remoting/host/me2me_preference_pane.h new file mode 100644 index 0000000..2ed986e --- /dev/null +++ b/remoting/host/me2me_preference_pane.h @@ -0,0 +1,84 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Cocoa/Cocoa.h> +#import <PreferencePanes/PreferencePanes.h> +#import <SecurityInterface/SFAuthorizationView.h> + +#include <string> + +#include "base/memory/scoped_ptr.h" + +namespace remoting { +class JsonHostConfig; +} + +@interface Me2MePreferencePane : NSPreferencePane { + IBOutlet NSTextField* status_message_; + IBOutlet NSButton* disable_button_; + IBOutlet NSTextField* pin_instruction_message_; + IBOutlet NSTextField* email_; + IBOutlet NSTextField* pin_; + IBOutlet NSButton* apply_button_; + IBOutlet SFAuthorizationView* authorization_view_; + + // Holds the new proposed configuration if a temporary config file is + // present. + scoped_ptr<remoting::JsonHostConfig> config_; + + NSTimer* service_status_timer_; + + // These flags determine the UI state. These are computed in the + // update...Status methods. + BOOL is_service_running_; + BOOL is_pane_unlocked_; + + // True if a new proposed config file has been loaded into memory. + BOOL have_new_config_; +} + +- (void)mainViewDidLoad; +- (void)willSelect; +- (void)willUnselect; +- (IBAction)onDisable:(id)sender; +- (IBAction)onApply:(id)sender; +- (void)onNewConfigFile:(NSNotification*)notification; +- (void)refreshServiceStatus:(NSTimer*)timer; +- (void)authorizationViewDidAuthorize:(SFAuthorizationView*)view; +- (void)authorizationViewDidDeauthorize:(SFAuthorizationView*)view; +- (void)updateServiceStatus; +- (void)updateAuthorizationStatus; + +// Read any new config file if present. If a config file is successfully read, +// this deletes the file and keeps the config data loaded in memory. If this +// method is called a second time (when the file has been deleted), the current +// config is remembered, so this method acts as a latch: it can change +// |have_new_config_| from NO to YES, but never from YES to NO. +// +// This scheme means that this method can delete the file immediately (to avoid +// leaving a stale file around in case of a crash), but this method can safely +// be called multiple times without forgetting the loaded config. To explicitly +// forget the current config, set |have_new_config_| to NO. +- (void)readNewConfig; + +// Update all UI controls according to any stored flags and loaded config. +// This should be called after any sequence of operations that might change the +// UI state. +- (void)updateUI; + +// Alert the user to a generic error condition. +- (void)showError; + +// Alert the user that the typed PIN is incorrect. +- (void)showIncorrectPinMessage; + +// Save the new config to the system, and either start the service or inform +// the currently-running service of the new config. +- (void)applyNewServiceConfig; + +- (BOOL)runHelperAsRootWithCommand:(const char*)command + inputData:(const std::string&)input_data; +- (BOOL)sendJobControlMessage:(const char*)launch_key; + +@end diff --git a/remoting/host/me2me_preference_pane.mm b/remoting/host/me2me_preference_pane.mm new file mode 100644 index 0000000..d092983 --- /dev/null +++ b/remoting/host/me2me_preference_pane.mm @@ -0,0 +1,403 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "remoting/host/me2me_preference_pane.h" + +#import <Cocoa/Cocoa.h> +#include <launch.h> +#import <PreferencePanes/PreferencePanes.h> +#import <SecurityInterface/SFAuthorizationView.h> + +#include "base/eintr_wrapper.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/mac/authorization_util.h" +#include "base/mac/foundation_util.h" +#include "base/mac/launchd.h" +#include "base/mac/mac_logging.h" +#include "base/mac/scoped_launch_data.h" +#include "base/memory/scoped_ptr.h" +#include "base/stringprintf.h" +#include "base/sys_string_conversions.h" +#include "remoting/host/host_config.h" +#include "remoting/host/json_host_config.h" +#include "remoting/protocol/me2me_host_authenticator_factory.h" + +namespace { +// The name of the Remoting Host service that is registered with launchd. +#define kServiceName "org.chromium.chromoting" +#define kConfigDir "/Library/PrivilegedHelperTools/" + +// This helper script is executed as root. It is passed a command-line option +// (--enable or --disable), which causes it to create or remove a file that +// informs the host's launch script of whether the host is enabled or disabled. +const char kHelperTool[] = kConfigDir kServiceName ".me2me.sh"; + +bool GetTemporaryConfigFilePath(FilePath* path) { + if (!file_util::GetTempDir(path)) + return false; + *path = path->Append(kServiceName ".json"); + return true; +} + +bool IsConfigValid(const remoting::JsonHostConfig* config) { + std::string value; + return (config->GetString(remoting::kHostIdConfigPath, &value) && + config->GetString(remoting::kHostSecretHashConfigPath, &value) && + config->GetString(remoting::kXmppLoginConfigPath, &value)); +} + +bool IsPinValid(const std::string& pin, const std::string& host_id, + const std::string& host_secret_hash) { + remoting::protocol::SharedSecretHash hash; + if (!hash.Parse(host_secret_hash)) { + LOG(ERROR) << "Invalid host_secret_hash."; + return false; + } + std::string result = + remoting::protocol::AuthenticationMethod::ApplyHashFunction( + hash.hash_function, host_id, pin); + return result == hash.value; +} + +} // namespace + + +@implementation Me2MePreferencePane + +- (void)mainViewDidLoad { + [authorization_view_ setDelegate:self]; + [authorization_view_ setString:kAuthorizationRightExecute]; + [authorization_view_ setAutoupdate:YES]; +} + +- (void)willSelect { + have_new_config_ = NO; + + NSDistributedNotificationCenter* center = + [NSDistributedNotificationCenter defaultCenter]; + [center addObserver:self + selector:@selector(onNewConfigFile:) + name:@kServiceName + object:nil]; + + service_status_timer_ = + [[NSTimer scheduledTimerWithTimeInterval:2.0 + target:self + selector:@selector(refreshServiceStatus:) + userInfo:nil + repeats:YES] retain]; + [self updateServiceStatus]; + [self updateAuthorizationStatus]; + [self readNewConfig]; + [self updateUI]; +} + +- (void)willUnselect { + NSDistributedNotificationCenter* center = + [NSDistributedNotificationCenter defaultCenter]; + [center removeObserver:self]; + + [service_status_timer_ invalidate]; + [service_status_timer_ release]; + service_status_timer_ = nil; +} + +- (void)onApply:(id)sender { + if (!have_new_config_) { + // It shouldn't be possible to hit the button if there is no config to + // apply, but check anyway just in case it happens somehow. + return; + } + + // Ensure the authorization token is up-to-date before using it. + [self updateAuthorizationStatus]; + [self updateUI]; + + std::string pin = base::SysNSStringToUTF8([pin_ stringValue]); + std::string host_id, host_secret_hash; + bool result = (config_->GetString(remoting::kHostIdConfigPath, &host_id) && + config_->GetString(remoting::kHostSecretHashConfigPath, + &host_secret_hash)); + DCHECK(result); + if (!IsPinValid(pin, host_id, host_secret_hash)) { + [self showIncorrectPinMessage]; + return; + } + + [self applyNewServiceConfig]; + [self updateUI]; +} + +- (void)onDisable:(id)sender { + // Ensure the authorization token is up-to-date before using it. + [self updateAuthorizationStatus]; + [self updateUI]; + if (!is_pane_unlocked_) + return; + + if (![self runHelperAsRootWithCommand:"--disable" + inputData:""]) { + LOG(ERROR) << "Failed to run the helper tool"; + [self showError]; + return; + } + + // Stop the launchd job. This cannot easily be done by the helper tool, + // since the launchd job runs in the current user's context. + [self sendJobControlMessage:LAUNCH_KEY_STOPJOB]; +} + +- (void)onNewConfigFile:(NSNotification*)notification { + [self readNewConfig]; + [self updateUI]; +} + +- (void)refreshServiceStatus:(NSTimer*)timer { + BOOL was_running = is_service_running_; + [self updateServiceStatus]; + if (was_running != is_service_running_) + [self updateUI]; +} + +- (void)authorizationViewDidAuthorize:(SFAuthorizationView*)view { + [self updateAuthorizationStatus]; + [self updateUI]; +} + +- (void)authorizationViewDidDeauthorize:(SFAuthorizationView*)view { + [self updateAuthorizationStatus]; + [self updateUI]; +} + +- (void)updateServiceStatus { + pid_t job_pid = base::mac::PIDForJob(kServiceName); + is_service_running_ = (job_pid > 0); +} + +- (void)updateAuthorizationStatus { + is_pane_unlocked_ = [authorization_view_ updateStatus:authorization_view_]; +} + +- (void)readNewConfig { + FilePath file; + if (!GetTemporaryConfigFilePath(&file)) { + LOG(ERROR) << "Failed to get path of configuration data."; + [self showError]; + return; + } + if (!file_util::PathExists(file)) + return; + + scoped_ptr<remoting::JsonHostConfig> new_config_( + new remoting::JsonHostConfig(file)); + if (!new_config_->Read()) { + // Report the error, because the file exists but couldn't be read. The + // case of non-existence is normal and expected. + LOG(ERROR) << "Error reading configuration data from " << file.value(); + [self showError]; + return; + } + file_util::Delete(file, false); + if (!IsConfigValid(new_config_.get())) { + LOG(ERROR) << "Invalid configuration data read."; + [self showError]; + return; + } + + config_.swap(new_config_); + have_new_config_ = YES; +} + +- (void)updateUI { + // TODO(lambroslambrou): These strings should be localized. +#ifdef OFFICIAL_BUILD + NSString* name = @"Chrome Remote Desktop"; +#else + NSString* name = @"Chromoting"; +#endif + NSString* message; + if (is_service_running_) { + message = [NSString stringWithFormat:@"%@ is enabled", name]; + } else { + message = [NSString stringWithFormat:@"%@ is disabled", name]; + } + [status_message_ setStringValue:message]; + + std::string email; + if (config_.get()) { + bool result = config_->GetString(remoting::kXmppLoginConfigPath, &email); + + // The config has already been checked by |IsConfigValid|. + DCHECK(result); + } + [email_ setStringValue:base::SysUTF8ToNSString(email)]; + + [disable_button_ setEnabled:(is_pane_unlocked_ && is_service_running_)]; + [pin_instruction_message_ setEnabled:have_new_config_]; + [email_ setEnabled:have_new_config_]; + [pin_ setEnabled:have_new_config_]; + [apply_button_ setEnabled:(is_pane_unlocked_ && have_new_config_)]; +} + +- (void)showError { + NSAlert* alert = [[NSAlert alloc] init]; + [alert setMessageText:@"An unexpected error occurred."]; + [alert setInformativeText:@"Check the system log for more information."]; + [alert setAlertStyle:NSWarningAlertStyle]; + [alert beginSheetModalForWindow:[[self mainView] window] + modalDelegate:nil + didEndSelector:nil + contextInfo:nil]; + [alert release]; +} + +- (void)showIncorrectPinMessage { + NSAlert* alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Incorrect PIN entered."]; + [alert setAlertStyle:NSWarningAlertStyle]; + [alert beginSheetModalForWindow:[[self mainView] window] + modalDelegate:nil + didEndSelector:nil + contextInfo:nil]; + [alert release]; +} + +- (void)applyNewServiceConfig { + [self updateServiceStatus]; + std::string serialized_config = config_->GetSerializedData(); + const char* command = is_service_running_ ? "--save-config" : "--enable"; + if (![self runHelperAsRootWithCommand:command + inputData:serialized_config]) { + LOG(ERROR) << "Failed to run the helper tool"; + [self showError]; + return; + } + + have_new_config_ = NO; + + // If the service is running, send a signal to cause it to reload its + // configuration, otherwise start the service. + if (is_service_running_) { + pid_t job_pid = base::mac::PIDForJob(kServiceName); + if (job_pid > 0) { + kill(job_pid, SIGHUP); + } else { + LOG(ERROR) << "Failed to obtain PID of service " << kServiceName; + [self showError]; + } + } else { + [self sendJobControlMessage:LAUNCH_KEY_STARTJOB]; + } +} + +- (BOOL)runHelperAsRootWithCommand:(const char*)command + inputData:(const std::string&)input_data { + AuthorizationRef authorization = + [[authorization_view_ authorization] authorizationRef]; + if (!authorization) { + LOG(ERROR) << "Failed to obtain authorizationRef"; + return NO; + } + + // TODO(lambroslambrou): Replace the deprecated ExecuteWithPrivileges + // call with a launchd-based helper tool, which is more secure. + // http://crbug.com/120903 + const char* arguments[] = { command, NULL }; + FILE* pipe = NULL; + pid_t pid; + OSStatus status = base::mac::ExecuteWithPrivilegesAndGetPID( + authorization, + kHelperTool, + kAuthorizationFlagDefaults, + arguments, + &pipe, + &pid); + if (status != errAuthorizationSuccess) { + OSSTATUS_LOG(ERROR, status) << "AuthorizationExecuteWithPrivileges"; + return NO; + } + if (pid == -1) { + LOG(ERROR) << "Failed to get child PID"; + if (pipe) + fclose(pipe); + + return NO; + } + if (!pipe) { + LOG(ERROR) << "Unexpected NULL pipe"; + return NO; + } + + // Some cleanup is needed (closing the pipe and waiting for the child + // process), so flag any errors before returning. + BOOL error = NO; + + if (!input_data.empty()) { + size_t bytes_written = fwrite(input_data.data(), sizeof(char), + input_data.size(), pipe); + // According to the fwrite manpage, a partial count is returned only if a + // write error has occurred. + if (bytes_written != input_data.size()) { + LOG(ERROR) << "Failed to write data to child process"; + error = YES; + } + } + + // In all cases, fclose() should be called with the returned FILE*. In the + // case of sending data to the child, this needs to be done before calling + // waitpid(), since the child reads until EOF on its stdin, so calling + // waitpid() first would result in deadlock. + if (fclose(pipe) != 0) { + PLOG(ERROR) << "fclose"; + error = YES; + } + + int exit_status; + pid_t wait_result = HANDLE_EINTR(waitpid(pid, &exit_status, 0)); + if (wait_result != pid) { + PLOG(ERROR) << "waitpid"; + error = YES; + } + + // No more cleanup needed. + if (error) + return NO; + + if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 0) { + return YES; + } else { + LOG(ERROR) << kHelperTool << " failed with exit status " << exit_status; + return NO; + } +} + +- (BOOL)sendJobControlMessage:(const char*)launch_key { + base::mac::ScopedLaunchData response( + base::mac::MessageForJob(kServiceName, launch_key)); + if (!response) { + LOG(ERROR) << "Failed to send message to launchd"; + [self showError]; + return NO; + } + + // Expect a response of type LAUNCH_DATA_ERRNO. + launch_data_type_t type = launch_data_get_type(response.get()); + if (type != LAUNCH_DATA_ERRNO) { + LOG(ERROR) << "launchd returned unexpected type: " << type; + [self showError]; + return NO; + } + + int error = launch_data_get_errno(response.get()); + if (error) { + LOG(ERROR) << "launchd returned error: " << error; + [self showError]; + return NO; + } + return YES; +} + +@end diff --git a/remoting/host/me2me_preference_pane.xib b/remoting/host/me2me_preference_pane.xib new file mode 100644 index 0000000..f433f2d --- /dev/null +++ b/remoting/host/me2me_preference_pane.xib @@ -0,0 +1,1047 @@ +<?xml version="1.0" encoding="UTF-8"?> +<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00"> + <data> + <int key="IBDocument.SystemTarget">1050</int> + <string key="IBDocument.SystemVersion">10K549</string> + <string key="IBDocument.InterfaceBuilderVersion">851</string> + <string key="IBDocument.AppKitVersion">1038.36</string> + <string key="IBDocument.HIToolboxVersion">461.00</string> + <object class="NSMutableDictionary" key="IBDocument.PluginVersions"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="NS.object.0">851</string> + </object> + <array class="NSMutableArray" key="IBDocument.EditedObjectIDs"/> + <array key="IBDocument.PluginDependencies"> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + </array> + <object class="NSMutableDictionary" key="IBDocument.Metadata"> + <string key="NS.key.0">PluginDependencyRecalculationVersion</string> + <integer value="1" key="NS.object.0"/> + </object> + <array class="NSMutableArray" key="IBDocument.RootObjects" id="409411428"> + <object class="NSCustomObject" id="294453543"> + <string key="NSClassName">Me2MePreferencePane</string> + </object> + <object class="NSCustomObject" id="308860122"> + <string key="NSClassName">FirstResponder</string> + </object> + <object class="NSCustomObject" id="278121016"> + <string key="NSClassName">NSApplication</string> + </object> + <object class="NSWindowTemplate" id="660800786"> + <int key="NSWindowStyleMask">7</int> + <int key="NSWindowBacking">2</int> + <string key="NSWindowRect">{{176, 715}, {667, 292}}</string> + <int key="NSWTFlags">1081606144</int> + <string key="NSWindowTitle"><< do not localize >></string> + <string key="NSWindowClass">NSWindow</string> + <object class="NSMutableString" key="NSViewClass"> + <characters key="NS.bytes">View</characters> + </object> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> + <string key="NSWindowContentMinSize">{224.664, 10}</string> + <object class="NSView" key="NSWindowView" id="1037298196"> + <nil key="NSNextResponder"/> + <int key="NSvFlags">256</int> + <array class="NSMutableArray" key="NSSubviews"> + <object class="NSButton" id="1007314448"> + <reference key="NSNextResponder" ref="1037298196"/> + <int key="NSvFlags">298</int> + <string key="NSFrame">{{293, 88}, {82, 32}}</string> + <reference key="NSSuperview" ref="1037298196"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="987594175"> + <int key="NSCellFlags">604110336</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Apply</string> + <object class="NSFont" key="NSSupport" id="819947481"> + <string key="NSName">LucidaGrande</string> + <double key="NSSize">13</double> + <int key="NSfFlags">1044</int> + </object> + <reference key="NSControlView" ref="1007314448"/> + <int key="NSButtonFlags">-2038284033</int> + <int key="NSButtonFlags2">129</int> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent"/> + <int key="NSPeriodicDelay">200</int> + <int key="NSPeriodicInterval">25</int> + </object> + </object> + <object class="NSTextField" id="963034143"> + <reference key="NSNextResponder" ref="1037298196"/> + <int key="NSvFlags">298</int> + <string key="NSFrame">{{87, 154}, {494, 17}}</string> + <reference key="NSSuperview" ref="1037298196"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="165875597"> + <int key="NSCellFlags">68288064</int> + <int key="NSCellFlags2">138413056</int> + <string key="NSContents">email</string> + <reference key="NSSupport" ref="819947481"/> + <reference key="NSControlView" ref="963034143"/> + <object class="NSColor" key="NSBackgroundColor" id="436039819"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">controlColor</string> + <object class="NSColor" key="NSColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes> + </object> + </object> + <object class="NSColor" key="NSTextColor" id="666068957"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">controlTextColor</string> + <object class="NSColor" key="NSColor" id="311176931"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MAA</bytes> + </object> + </object> + </object> + </object> + <object class="NSTextField" id="85957345"> + <reference key="NSNextResponder" ref="1037298196"/> + <int key="NSvFlags">298</int> + <string key="NSFrame">{{240, 124}, {187, 22}}</string> + <reference key="NSSuperview" ref="1037298196"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="785807768"> + <int key="NSCellFlags">-1804468671</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents"/> + <reference key="NSSupport" ref="819947481"/> + <reference key="NSControlView" ref="85957345"/> + <bool key="NSDrawsBackground">YES</bool> + <object class="NSColor" key="NSBackgroundColor"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">textBackgroundColor</string> + <object class="NSColor" key="NSColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MQA</bytes> + </object> + </object> + <object class="NSColor" key="NSTextColor"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">textColor</string> + <reference key="NSColor" ref="311176931"/> + </object> + </object> + </object> + <object class="NSCustomView" id="737813299"> + <reference key="NSNextResponder" ref="1037298196"/> + <int key="NSvFlags">303</int> + <string key="NSFrame">{{20, 20}, {627, 47}}</string> + <reference key="NSSuperview" ref="1037298196"/> + <string key="NSClassName">SFAuthorizationView</string> + </object> + <object class="NSTextField" id="345845398"> + <reference key="NSNextResponder" ref="1037298196"/> + <int key="NSvFlags">298</int> + <string key="NSFrame">{{86, 255}, {494, 17}}</string> + <reference key="NSSuperview" ref="1037298196"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="101917910"> + <int key="NSCellFlags">68288064</int> + <int key="NSCellFlags2">138413056</int> + <string key="NSContents">Status text</string> + <reference key="NSSupport" ref="819947481"/> + <reference key="NSControlView" ref="345845398"/> + <reference key="NSBackgroundColor" ref="436039819"/> + <reference key="NSTextColor" ref="666068957"/> + </object> + </object> + <object class="NSTextField" id="441586301"> + <reference key="NSNextResponder" ref="1037298196"/> + <int key="NSvFlags">298</int> + <string key="NSFrame">{{86, 179}, {494, 17}}</string> + <reference key="NSSuperview" ref="1037298196"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="146146078"> + <int key="NSCellFlags">68288064</int> + <int key="NSCellFlags2">138413056</int> + <string key="NSContents">Please confirm PIN for user:</string> + <reference key="NSSupport" ref="819947481"/> + <reference key="NSControlView" ref="441586301"/> + <reference key="NSBackgroundColor" ref="436039819"/> + <reference key="NSTextColor" ref="666068957"/> + </object> + </object> + <object class="NSButton" id="331564268"> + <reference key="NSNextResponder" ref="1037298196"/> + <int key="NSvFlags">268</int> + <string key="NSFrame">{{240, 219}, {186, 32}}</string> + <reference key="NSSuperview" ref="1037298196"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="448132067"> + <int key="NSCellFlags">604110336</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Disable Remote Access</string> + <reference key="NSSupport" ref="819947481"/> + <reference key="NSControlView" ref="331564268"/> + <int key="NSButtonFlags">-2038284033</int> + <int key="NSButtonFlags2">129</int> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent"/> + <int key="NSPeriodicDelay">200</int> + <int key="NSPeriodicInterval">25</int> + </object> + </object> + </array> + <string key="NSFrameSize">{667, 292}</string> + </object> + <string key="NSScreenRect">{{0, 0}, {2560, 1578}}</string> + <string key="NSMinSize">{224.664, 32}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> + </object> + </array> + <object class="IBObjectContainer" key="IBDocument.Objects"> + <array class="NSMutableArray" key="connectionRecords"> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">_window</string> + <reference key="source" ref="294453543"/> + <reference key="destination" ref="660800786"/> + </object> + <int key="connectionID">26</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">authorization_view_</string> + <reference key="source" ref="294453543"/> + <reference key="destination" ref="737813299"/> + </object> + <int key="connectionID">108</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">status_message_</string> + <reference key="source" ref="294453543"/> + <reference key="destination" ref="345845398"/> + </object> + <int key="connectionID">111</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">email_</string> + <reference key="source" ref="294453543"/> + <reference key="destination" ref="963034143"/> + </object> + <int key="connectionID">114</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">apply_button_</string> + <reference key="source" ref="294453543"/> + <reference key="destination" ref="1007314448"/> + </object> + <int key="connectionID">115</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">onApply:</string> + <reference key="source" ref="294453543"/> + <reference key="destination" ref="1007314448"/> + </object> + <int key="connectionID">116</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">pin_</string> + <reference key="source" ref="294453543"/> + <reference key="destination" ref="85957345"/> + </object> + <int key="connectionID">117</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">disable_button_</string> + <reference key="source" ref="294453543"/> + <reference key="destination" ref="331564268"/> + </object> + <int key="connectionID">120</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">pin_instruction_message_</string> + <reference key="source" ref="294453543"/> + <reference key="destination" ref="441586301"/> + </object> + <int key="connectionID">121</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">onDisable:</string> + <reference key="source" ref="294453543"/> + <reference key="destination" ref="331564268"/> + </object> + <int key="connectionID">122</int> + </object> + </array> + <object class="IBMutableOrderedSet" key="objectRecords"> + <array key="orderedObjects"> + <object class="IBObjectRecord"> + <int key="objectID">0</int> + <array key="object" id="0"/> + <reference key="children" ref="409411428"/> + <nil key="parent"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-2</int> + <reference key="object" ref="294453543"/> + <reference key="parent" ref="0"/> + <string key="objectName">File's Owner</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-1</int> + <reference key="object" ref="308860122"/> + <reference key="parent" ref="0"/> + <string key="objectName">First Responder</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">12</int> + <reference key="object" ref="660800786"/> + <array class="NSMutableArray" key="children"> + <reference ref="1037298196"/> + </array> + <reference key="parent" ref="0"/> + <string key="objectName">PrefPane</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">6</int> + <reference key="object" ref="1037298196"/> + <array class="NSMutableArray" key="children"> + <reference ref="345845398"/> + <reference ref="737813299"/> + <reference ref="1007314448"/> + <reference ref="963034143"/> + <reference ref="331564268"/> + <reference ref="85957345"/> + <reference ref="441586301"/> + </array> + <reference key="parent" ref="660800786"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-3</int> + <reference key="object" ref="278121016"/> + <reference key="parent" ref="0"/> + <string key="objectName">Application</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">99</int> + <reference key="object" ref="1007314448"/> + <array class="NSMutableArray" key="children"> + <reference ref="987594175"/> + </array> + <reference key="parent" ref="1037298196"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">100</int> + <reference key="object" ref="987594175"/> + <reference key="parent" ref="1007314448"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">101</int> + <reference key="object" ref="963034143"/> + <array class="NSMutableArray" key="children"> + <reference ref="165875597"/> + </array> + <reference key="parent" ref="1037298196"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">102</int> + <reference key="object" ref="165875597"/> + <reference key="parent" ref="963034143"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">103</int> + <reference key="object" ref="85957345"/> + <array class="NSMutableArray" key="children"> + <reference ref="785807768"/> + </array> + <reference key="parent" ref="1037298196"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">104</int> + <reference key="object" ref="785807768"/> + <reference key="parent" ref="85957345"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">105</int> + <reference key="object" ref="737813299"/> + <reference key="parent" ref="1037298196"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">109</int> + <reference key="object" ref="345845398"/> + <array class="NSMutableArray" key="children"> + <reference ref="101917910"/> + </array> + <reference key="parent" ref="1037298196"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">110</int> + <reference key="object" ref="101917910"/> + <reference key="parent" ref="345845398"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">112</int> + <reference key="object" ref="441586301"/> + <array class="NSMutableArray" key="children"> + <reference ref="146146078"/> + </array> + <reference key="parent" ref="1037298196"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">113</int> + <reference key="object" ref="146146078"/> + <reference key="parent" ref="441586301"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">118</int> + <reference key="object" ref="331564268"/> + <array class="NSMutableArray" key="children"> + <reference ref="448132067"/> + </array> + <reference key="parent" ref="1037298196"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">119</int> + <reference key="object" ref="448132067"/> + <reference key="parent" ref="331564268"/> + </object> + </array> + </object> + <dictionary class="NSMutableDictionary" key="flattenedProperties"> + <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="100.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="101.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="102.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="103.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="104.CustomClassName">NSSecureTextFieldCell</string> + <string key="104.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="105.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="109.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="110.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="112.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="113.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="118.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="119.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="12.IBEditorWindowLastContentRect">{{0, 1253}, {668, 292}}</string> + <string key="12.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="12.IBWindowTemplateEditedContentRect">{{0, 1253}, {668, 292}}</string> + <boolean value="YES" key="12.windowTemplate.hasMinSize"/> + <string key="12.windowTemplate.minSize">{224.664, 10}</string> + <string key="6.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="99.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + </dictionary> + <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/> + <nil key="activeLocalization"/> + <dictionary class="NSMutableDictionary" key="localizations"/> + <nil key="sourceID"/> + <int key="maxID">122</int> + </object> + <object class="IBClassDescriber" key="IBDocument.Classes"> + <array class="NSMutableArray" key="referencedPartialClassDescriptions"> + <object class="IBPartialClassDescription"> + <string key="className">Me2MePreferencePane</string> + <string key="superclassName">NSPreferencePane</string> + <dictionary class="NSMutableDictionary" key="actions"> + <string key="onApply:">id</string> + <string key="onDisable:">id</string> + </dictionary> + <dictionary class="NSMutableDictionary" key="actionInfosByName"> + <object class="IBActionInfo" key="onApply:"> + <string key="name">onApply:</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBActionInfo" key="onDisable:"> + <string key="name">onDisable:</string> + <string key="candidateClassName">id</string> + </object> + </dictionary> + <dictionary class="NSMutableDictionary" key="outlets"> + <string key="apply_button_">NSButton</string> + <string key="authorization_view_">SFAuthorizationView</string> + <string key="disable_button_">NSButton</string> + <string key="email_">NSTextField</string> + <string key="pin_">NSTextField</string> + <string key="pin_instruction_message_">NSTextField</string> + <string key="status_message_">NSTextField</string> + </dictionary> + <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName"> + <object class="IBToOneOutletInfo" key="apply_button_"> + <string key="name">apply_button_</string> + <string key="candidateClassName">NSButton</string> + </object> + <object class="IBToOneOutletInfo" key="authorization_view_"> + <string key="name">authorization_view_</string> + <string key="candidateClassName">SFAuthorizationView</string> + </object> + <object class="IBToOneOutletInfo" key="disable_button_"> + <string key="name">disable_button_</string> + <string key="candidateClassName">NSButton</string> + </object> + <object class="IBToOneOutletInfo" key="email_"> + <string key="name">email_</string> + <string key="candidateClassName">NSTextField</string> + </object> + <object class="IBToOneOutletInfo" key="pin_"> + <string key="name">pin_</string> + <string key="candidateClassName">NSTextField</string> + </object> + <object class="IBToOneOutletInfo" key="pin_instruction_message_"> + <string key="name">pin_instruction_message_</string> + <string key="candidateClassName">NSTextField</string> + </object> + <object class="IBToOneOutletInfo" key="status_message_"> + <string key="name">status_message_</string> + <string key="candidateClassName">NSTextField</string> + </object> + </dictionary> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">host/me2me_preference_pane.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">../third_party/GTM/AppKit/GTMCarbonEvent.h</string> + </object> + </object> + </array> + <array class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+"> + <object class="IBPartialClassDescription"> + <string key="className">NSActionCell</string> + <string key="superclassName">NSCell</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSActionCell.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSApplication</string> + <string key="superclassName">NSResponder</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier" id="741398341"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSApplication.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSApplication</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier" id="537953501"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSApplicationScripting.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSApplication</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier" id="813691524"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSColorPanel.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSApplication</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSHelpManager.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSApplication</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSPageLayout.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSApplication</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSUserInterfaceItemSearching.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSButton</string> + <string key="superclassName">NSControl</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSButton.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSButtonCell</string> + <string key="superclassName">NSActionCell</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSButtonCell.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSCell</string> + <string key="superclassName">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSCell.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSControl</string> + <string key="superclassName">NSView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier" id="161226876"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSControl.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSFormatter</string> + <string key="superclassName">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSMenu</string> + <string key="superclassName">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier" id="924316341"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSMenu.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSAccessibility.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <reference key="sourceIdentifier" ref="741398341"/> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <reference key="sourceIdentifier" ref="537953501"/> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <reference key="sourceIdentifier" ref="813691524"/> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <reference key="sourceIdentifier" ref="161226876"/> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSDictionaryController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSDragging.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSFontPanel.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSKeyValueBinding.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <reference key="sourceIdentifier" ref="924316341"/> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSNibLoading.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSPasteboard.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSSavePanel.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSTableView.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSToolbarItem.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier" id="464411912"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSView.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSArchiver.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSClassDescription.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSError.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSObject.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSObjectScripting.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSPortCoder.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSScriptClassDescription.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSScriptKeyValueCoding.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSScriptObjectSpecifiers.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSScriptWhoseTests.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSThread.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSURL.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSURLDownload.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">QTKit.framework/Headers/QTCaptureDecompressedAudioOutput.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">QTKit.framework/Headers/QTCaptureDecompressedVideoOutput.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">QTKit.framework/Headers/QTCaptureFileOutput.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">QTKit.framework/Headers/QTCaptureVideoPreviewOutput.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">QTKit.framework/Headers/QTCaptureView.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">QTKit.framework/Headers/QTMovie.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">QTKit.framework/Headers/QTMovieView.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSPreferencePane</string> + <string key="superclassName">NSObject</string> + <dictionary class="NSMutableDictionary" key="outlets"> + <string key="_firstKeyView">NSView</string> + <string key="_initialKeyView">NSView</string> + <string key="_lastKeyView">NSView</string> + <string key="_window">NSWindow</string> + </dictionary> + <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName"> + <object class="IBToOneOutletInfo" key="_firstKeyView"> + <string key="name">_firstKeyView</string> + <string key="candidateClassName">NSView</string> + </object> + <object class="IBToOneOutletInfo" key="_initialKeyView"> + <string key="name">_initialKeyView</string> + <string key="candidateClassName">NSView</string> + </object> + <object class="IBToOneOutletInfo" key="_lastKeyView"> + <string key="name">_lastKeyView</string> + <string key="candidateClassName">NSView</string> + </object> + <object class="IBToOneOutletInfo" key="_window"> + <string key="name">_window</string> + <string key="candidateClassName">NSWindow</string> + </object> + </dictionary> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">PreferencePanes.framework/Headers/NSPreferencePane.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSResponder</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSInterfaceStyle.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSResponder</string> + <string key="superclassName">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSResponder.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSSecureTextFieldCell</string> + <string key="superclassName">NSTextFieldCell</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSSecureTextField.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSTextField</string> + <string key="superclassName">NSControl</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSTextField.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSTextFieldCell</string> + <string key="superclassName">NSActionCell</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSTextFieldCell.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSClipView.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSRulerView.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSView</string> + <string key="superclassName">NSResponder</string> + <reference key="sourceIdentifier" ref="464411912"/> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSWindow</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSDrawer.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSWindow</string> + <string key="superclassName">NSResponder</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSWindow.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSWindow</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string> + </object> + </object> + </array> + </object> + <int key="IBDocument.localizationMode">0</int> + <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string> + <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string> + <real value="1050" key="NS.object.0"/> + </object> + <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string> + <integer value="1060" key="NS.object.0"/> + </object> + <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> + <string key="IBDocument.LastKnownRelativeProjectPath">../remoting.xcodeproj</string> + <int key="IBDocument.defaultPropertyAccessControl">3</int> + </data> +</archive> diff --git a/remoting/host/plugin/daemon_controller_mac.cc b/remoting/host/plugin/daemon_controller_mac.cc index a75d613..a59c164 100644 --- a/remoting/host/plugin/daemon_controller_mac.cc +++ b/remoting/host/plugin/daemon_controller_mac.cc @@ -10,15 +10,14 @@ #include "base/basictypes.h" #include "base/bind.h" #include "base/compiler_specific.h" -#include "base/eintr_wrapper.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/json/json_writer.h" #include "base/logging.h" -#include "base/mac/authorization_util.h" +#include "base/mac/foundation_util.h" #include "base/mac/launchd.h" #include "base/mac/mac_logging.h" -#include "base/mac/scoped_authorizationref.h" +#include "base/mac/mac_util.h" #include "base/mac/scoped_launch_data.h" #include "base/threading/thread.h" #include "base/time.h" @@ -29,6 +28,12 @@ namespace remoting { namespace { +// The NSSystemDirectories.h header has a conflicting definition of +// NSSearchPathDirectory with the one in base/mac/foundation_util.h. +// Foundation.h would work, but it can only be included from Objective-C files. +// Therefore, we define the needed constants here. +const int NSLibraryDirectory = 5; + // The name of the Remoting Host service that is registered with launchd. #define kServiceName "org.chromium.chromoting" #define kConfigDir "/Library/PrivilegedHelperTools/" @@ -72,13 +77,8 @@ class DaemonControllerMac : public remoting::DaemonController { void NotifyWhenStopped(const CompletionCallback& done_callback, int tries_remaining, const base::TimeDelta& sleep); + bool ShowPreferencePane(const std::string& config_data); - bool RunToolScriptAsRoot(const char* command, const std::string& input_data); - bool SendJobControlMessage(const char* launchKey); - - // The API for gaining root privileges is blocking (it prompts the user for - // a password). Since Start() and Stop() must not block the main thread, they - // need to post their tasks to a separate thread. base::Thread auth_thread_; DISALLOW_COPY_AND_ASSIGN(DaemonControllerMac); @@ -90,12 +90,6 @@ DaemonControllerMac::DaemonControllerMac() } DaemonControllerMac::~DaemonControllerMac() { - // This will block if the thread is waiting on a root password prompt. There - // doesn't seem to be an easy solution for this, other than to spawn a - // separate process to do the root elevation. - - // TODO(lambroslambrou): Improve this, either by finding a way to terminate - // the thread, or by moving to a separate process. auth_thread_.Stop(); } @@ -167,13 +161,11 @@ void DaemonControllerMac::DoGetConfig(const GetConfigCallback& callback) { void DaemonControllerMac::DoSetConfigAndStart( scoped_ptr<base::DictionaryValue> config, const CompletionCallback& done_callback) { - std::string file_content; - base::JSONWriter::Write(config.get(), &file_content); - if (!RunToolScriptAsRoot("--enable", file_content)) { - done_callback.Run(RESULT_FAILED); - return; - } - bool result = SendJobControlMessage(LAUNCH_KEY_STARTJOB); + std::string config_data; + base::JSONWriter::Write(config.get(), &config_data); + + bool result = ShowPreferencePane(config_data); + done_callback.Run(result ? RESULT_OK : RESULT_FAILED); } @@ -197,36 +189,65 @@ void DaemonControllerMac::DoUpdateConfig( config_file.SetString(*key, value); } - std::string file_content = config_file.GetSerializedData(); - if (!RunToolScriptAsRoot("--save-config", file_content)) { - done_callback.Run(RESULT_FAILED); - return; + std::string config_data = config_file.GetSerializedData(); + bool success = ShowPreferencePane(config_data); + + done_callback.Run(success ? RESULT_OK : RESULT_FAILED); +} + +bool DaemonControllerMac::ShowPreferencePane(const std::string& config_data) { + if (!config_data.empty()) { + FilePath config_path; + if (!file_util::GetTempDir(&config_path)) { + LOG(ERROR) << "Failed to get filename for saving configuration data."; + return false; + } + config_path = config_path.Append(kServiceName ".json"); + + int written = file_util::WriteFile(config_path, config_data.data(), + config_data.size()); + if (written != static_cast<int>(config_data.size())) { + LOG(ERROR) << "Failed to save configuration data to: " + << config_path.value(); + return false; + } } - done_callback.Run(RESULT_OK); - pid_t job_pid = base::mac::PIDForJob(kServiceName); - if (job_pid > 0) { - kill(job_pid, SIGHUP); + FilePath pane_path; + // TODO(lambroslambrou): Use NSPreferencePanesDirectory once we start + // building against SDK 10.6. + if (!base::mac::GetLocalDirectory(NSLibraryDirectory, &pane_path)) { + LOG(ERROR) << "Failed to get directory for local preference panes."; + return false; } -} + pane_path = pane_path.Append("PreferencePanes") + .Append(kServiceName ".prefPane"); -void DaemonControllerMac::DoStop(const CompletionCallback& done_callback) { - if (!RunToolScriptAsRoot("--disable", "")) { - done_callback.Run(RESULT_FAILED); - return; + FSRef pane_path_ref; + if (!base::mac::FSRefFromPath(pane_path.value(), &pane_path_ref)) { + LOG(ERROR) << "Failed to create FSRef"; + return false; + } + OSStatus status = LSOpenFSRef(&pane_path_ref, NULL); + if (status != noErr) { + OSSTATUS_LOG(ERROR, status) << "LSOpenFSRef failed for path: " + << pane_path.value(); + return false; } - // Deleting the trigger file does not cause launchd to stop the service. - // Since the service is running for the local user's desktop (not as root), - // it has to be stopped for that user. This cannot easily be done in the - // shell-script running as root, so it is done here instead. - if (!SendJobControlMessage(LAUNCH_KEY_STOPJOB)) { + CFNotificationCenterRef center = + CFNotificationCenterGetDistributedCenter(); + CFNotificationCenterPostNotification(center, CFSTR(kServiceName), NULL, NULL, + TRUE); + return true; +} + +void DaemonControllerMac::DoStop(const CompletionCallback& done_callback) { + if (!ShowPreferencePane("")) { done_callback.Run(RESULT_FAILED); return; } - // SendJobControlMessage does not wait for the stop to take effect, so we - // can't return immediately. Instead, we wait up to 10s. NotifyWhenStopped(done_callback, kStopWaitRetryLimit, base::TimeDelta::FromMilliseconds(kStopWaitTimeout)); @@ -252,91 +273,6 @@ void DaemonControllerMac::NotifyWhenStopped( } } -bool DaemonControllerMac::RunToolScriptAsRoot(const char* command, - const std::string& input_data) { - // TODO(lambroslambrou): Supply a localized prompt string here. - base::mac::ScopedAuthorizationRef authorization( - base::mac::AuthorizationCreateToRunAsRoot(CFSTR(""))); - if (!authorization) { - LOG(ERROR) << "Failed to get root privileges."; - return false; - } - - if (!file_util::VerifyPathControlledByAdmin(FilePath(kStartStopTool))) { - LOG(ERROR) << "Security check failed for: " << kStartStopTool; - return false; - } - - // TODO(lambroslambrou): Use sandbox-exec to minimize exposure - - // http://crbug.com/120903 - const char* arguments[] = { command, NULL }; - FILE* pipe = NULL; - pid_t pid; - OSStatus status = base::mac::ExecuteWithPrivilegesAndGetPID( - authorization.get(), - kStartStopTool, - kAuthorizationFlagDefaults, - arguments, - &pipe, - &pid); - if (status != errAuthorizationSuccess) { - OSSTATUS_LOG(ERROR, status) << "AuthorizationExecuteWithPrivileges"; - return false; - } - if (pid == -1) { - LOG(ERROR) << "Failed to get child PID"; - return false; - } - - DCHECK(pipe); - if (!input_data.empty()) { - size_t bytes_written = fwrite(input_data.data(), sizeof(char), - input_data.size(), pipe); - // According to the fwrite manpage, a partial count is returned only if a - // write error has occurred. - if (bytes_written != input_data.size()) { - LOG(ERROR) << "Failed to write data to child process"; - } - // Need to close, since the child waits for EOF on its stdin. - if (fclose(pipe) != 0) { - PLOG(ERROR) << "fclose"; - } - } - - int exit_status; - pid_t wait_result = HANDLE_EINTR(waitpid(pid, &exit_status, 0)); - if (wait_result != pid) { - PLOG(ERROR) << "waitpid"; - return false; - } - if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 0) { - return true; - } else { - LOG(ERROR) << kStartStopTool << " failed with exit status " << exit_status; - return false; - } -} - -bool DaemonControllerMac::SendJobControlMessage(const char* launchKey) { - base::mac::ScopedLaunchData response( - base::mac::MessageForJob(kServiceName, launchKey)); - if (!response) { - LOG(ERROR) << "Failed to send message to launchd"; - return false; - } - - // Got a response, so check if launchd sent a non-zero error code, otherwise - // assume the command was successful. - if (launch_data_get_type(response.get()) == LAUNCH_DATA_ERRNO) { - int error = launch_data_get_errno(response.get()); - if (error) { - LOG(ERROR) << "launchd returned error " << error; - return false; - } - } - return true; -} - } // namespace scoped_ptr<DaemonController> remoting::DaemonController::Create() { diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index e357c7dd..e1258ef 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -286,8 +286,9 @@ 'target_name': 'remoting_me2me_host_archive', 'type': 'none', 'dependencies': [ - 'remoting_me2me_host', + 'remoting_host_prefpane', 'remoting_host_uninstaller', + 'remoting_me2me_host', ], 'sources': [ 'host/installer/build-installer-archive.py', @@ -318,10 +319,12 @@ 'temp_dir': '<(SHARED_INTERMEDIATE_DIR)/remoting/remoting-me2me-host', 'zip_path': '<(PRODUCT_DIR)/remoting-me2me-host-<(OS).zip', 'generated_files': [ + '<(PRODUCT_DIR)/remoting_host_prefpane.prefPane', '<(PRODUCT_DIR)/remoting_me2me_host', '<(PRODUCT_DIR)/remoting_host_uninstaller.app', ], 'generated_files_dst': [ + 'PreferencePanes/org.chromium.chromoting.prefPane', 'PrivilegedHelperTools/org.chromium.chromoting.me2me_host', 'Applications/<(host_uninstaller_name).app', ], @@ -372,6 +375,60 @@ }, ], # actions }, # end of target 'remoting_me2me_host_archive' + + { + 'target_name': 'remoting_host_prefpane', + 'type': 'loadable_module', + 'mac_bundle': 1, + 'product_extension': 'prefPane', + 'dependencies': [ + 'remoting_base', + 'remoting_host', + ], + 'sources': [ + 'host/me2me_preference_pane.h', + 'host/me2me_preference_pane.mm', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/PreferencePanes.framework', + ], + }, + 'xcode_settings': { + 'INFOPLIST_FILE': 'host/me2me_preference_pane-Info.plist', + 'INFOPLIST_PREPROCESS': 'YES', + 'INFOPLIST_PREPROCESSOR_DEFINITIONS': 'VERSION_FULL="<(version_full)" VERSION_SHORT="<(version_short)" BUNDLE_NAME="<(bundle_name)" BUNDLE_ID="<(bundle_id)" COPYRIGHT_BY="<(copyright_by)"', + }, + 'mac_bundle_resources': [ + 'host/me2me_preference_pane.xib', + 'host/me2me_preference_pane-Info.plist', + 'resources/chromoting128.png', + ], + 'mac_bundle_resources!': [ + 'host/me2me_preference_pane-Info.plist', + ], + 'conditions': [ + ['mac_breakpad==1', { + 'variables': { + # A real .dSYM is needed for dump_syms to operate on. + 'mac_real_dsym': 1, + }, + }], + ['branding == "Chrome"', { + 'variables': { + 'copyright_by': 'Google Inc.', + 'bundle_id': 'com.google.chromeremotedesktop.preferences', + 'bundle_name': 'Chrome Remote Desktop Host Preferences', + }, + }, { # else branding!="Chrome" + 'variables': { + 'copyright_by': 'The Chromium Authors.', + 'bundle_id': 'org.chromium.remoting.preferences', + 'bundle_name': 'Chromoting Host Preferences', + }, + }], + ], # conditions + }, # end of target 'remoting_host_prefpane' ], # end of 'targets' }], # 'OS=="mac"' |