1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/system/chromeos/network/network_connect.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ash/session/session_state_delegate.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/shell.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/system/chromeos/network/network_state_notifier.h"
10424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/system/system_notifier.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/system/tray/system_tray_delegate.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/system/tray/system_tray_notifier.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/bind.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/strings/string_util.h"
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/strings/utf_string_conversions.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/values.h"
18ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chromeos/login/login_state.h"
19ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chromeos/network/device_state.h"
20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chromeos/network/network_activation_handler.h"
21ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chromeos/network/network_configuration_handler.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chromeos/network/network_connection_handler.h"
23ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chromeos/network/network_event_log.h"
24ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chromeos/network/network_handler_callbacks.h"
25ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chromeos/network/network_profile.h"
26ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chromeos/network/network_profile_handler.h"
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chromeos/network/network_state.h"
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chromeos/network/network_state_handler.h"
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "grit/ash_resources.h"
307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "grit/ash_strings.h"
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "third_party/cros_system_api/dbus/service_constants.h"
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "ui/base/l10n/l10n_util.h"
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/message_center/message_center.h"
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/message_center/notification.h"
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
37ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochusing chromeos::DeviceState;
38ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochusing chromeos::NetworkConfigurationHandler;
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using chromeos::NetworkConnectionHandler;
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using chromeos::NetworkHandler;
41ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochusing chromeos::NetworkProfile;
42ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochusing chromeos::NetworkProfileHandler;
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using chromeos::NetworkState;
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)using chromeos::NetworkStateHandler;
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using chromeos::NetworkTypePattern;
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace ash {
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace {
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
51ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// TODO(stevenjb): This should be in service_constants.h
52ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochconst char kErrorInProgress[] = "org.chromium.flimflam.Error.InProgress";
53ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
54ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// Returns true for carriers that can be activated through Shill instead of
55ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// through a WebUI dialog.
56ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochbool IsDirectActivatedCarrier(const std::string& carrier) {
57ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (carrier == shill::kCarrierSprint)
58ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return true;
59ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  return false;
60ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
61ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ShowErrorNotification(const std::string& error_name,
63ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                           const std::string& service_path) {
64ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  Shell::GetInstance()->system_tray_notifier()->network_state_notifier()->
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ShowNetworkConnectError(error_name, service_path);
66ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
67ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HandleUnconfiguredNetwork(const std::string& service_path) {
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      GetNetworkState(service_path);
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!network) {
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    NET_LOG_ERROR("Configuring unknown network", service_path);
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (network->type() == shill::kTypeWifi) {
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Only show the config view for secure networks, otherwise do nothing.
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (network->security() != shill::kSecurityNone) {
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ash::Shell::GetInstance()->system_tray_delegate()->
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          ShowNetworkConfigure(service_path);
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (network->type() == shill::kTypeWimax ||
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      network->type() == shill::kTypeVPN) {
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ash::Shell::GetInstance()->system_tray_delegate()->
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ShowNetworkConfigure(service_path);
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (network->type() == shill::kTypeCellular) {
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (network->RequiresActivation()) {
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ash::network_connect::ActivateCellular(service_path);
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return;
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (network->cellular_out_of_credits()) {
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ash::network_connect::ShowMobileSetup(service_path);
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return;
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // No special configure or setup for |network|, show the settings UI.
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (chromeos::LoginState::Get()->IsUserLoggedIn()) {
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ash::Shell::GetInstance()->system_tray_delegate()->
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          ShowNetworkSettings(service_path);
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  NOTREACHED();
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// If |shared| is true, sets |profile_path| to the shared profile path.
112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Otherwise sets |profile_path| to the user profile path if authenticated and
113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// available. Returns 'false' if unable to set |profile_path|.
114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool GetNetworkProfilePath(bool shared, std::string* profile_path) {
115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (shared) {
116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    *profile_path = NetworkProfileHandler::GetSharedProfilePath();
117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return true;
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
120a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!chromeos::LoginState::Get()->UserHasNetworkProfile()) {
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    NET_LOG_ERROR("User profile specified before login", "");
122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return false;
123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const NetworkProfile* profile  =
126effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      NetworkHandler::Get()->network_profile_handler()->
127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      GetDefaultUserProfile();
128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!profile) {
129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    NET_LOG_ERROR("No user profile for unshared network configuration", "");
130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return false;
131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  *profile_path = profile->path;
134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return true;
135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void OnConnectFailed(const std::string& service_path,
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                     const std::string& error_name,
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                     scoped_ptr<base::DictionaryValue> error_data) {
140ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_ERROR("Connect Failed: " + error_name, service_path);
141ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ash::Shell::HasInstance())
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
145ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // If a new connect attempt canceled this connect, no need to notify the user.
146ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (error_name == NetworkConnectionHandler::kErrorConnectCanceled)
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
148ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
14968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error_name == shill::kErrorBadPassphrase ||
15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      error_name == NetworkConnectionHandler::kErrorPassphraseRequired ||
151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      error_name == NetworkConnectionHandler::kErrorConfigurationRequired ||
152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      error_name == NetworkConnectionHandler::kErrorAuthenticationRequired) {
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    HandleUnconfiguredNetwork(service_path);
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
156ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
157ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (error_name == NetworkConnectionHandler::kErrorCertificateRequired) {
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (!ash::Shell::GetInstance()->system_tray_delegate()->EnrollNetwork(
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            service_path)) {
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      HandleUnconfiguredNetwork(service_path);
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
162ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
163ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
164ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
165ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (error_name == NetworkConnectionHandler::kErrorActivationRequired) {
166ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    network_connect::ActivateCellular(service_path);
167ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
168ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
169ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (error_name == NetworkConnectionHandler::kErrorConnected ||
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      error_name == NetworkConnectionHandler::kErrorConnecting) {
1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    network_connect::ShowNetworkSettings(service_path);
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
175ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
176ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // ConnectFailed or unknown error; show a notification.
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ShowErrorNotification(error_name, service_path);
178ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Only show a configure dialog if there was a ConnectFailed error and the
180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // screen is not locked.
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (error_name != shill::kErrorConnectFailed ||
182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      Shell::GetInstance()->session_state_delegate()->IsScreenLocked())
183ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
184ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
185ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // If Shill reports an InProgress error, don't try to configure the network.
186ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  std::string dbus_error_name;
187ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  error_data.get()->GetString(
188ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      chromeos::network_handler::kDbusErrorName, &dbus_error_name);
189ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (dbus_error_name == kErrorInProgress)
190ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
191ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  HandleUnconfiguredNetwork(service_path);
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void OnConnectSucceeded(const std::string& service_path) {
196ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_USER("Connect Succeeded", service_path);
1973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ash::Shell::HasInstance())
1983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
1993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  message_center::MessageCenter::Get()->RemoveNotification(
2003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      network_connect::kNetworkConnectNotificationId, false /* not by user */);
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
203ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// If |check_error_state| is true, error state for the network is checked,
204ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch// otherwise any current error state is ignored (e.g. for recently configured
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// networks or repeat connect attempts).
206ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid CallConnectToNetwork(const std::string& service_path,
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          bool check_error_state) {
2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ash::Shell::HasInstance())
2093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
2103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  message_center::MessageCenter::Get()->RemoveNotification(
2113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      network_connect::kNetworkConnectNotificationId, false /* not by user */);
212ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
213ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
214ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      service_path,
215ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&OnConnectSucceeded, service_path),
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&OnConnectFailed, service_path),
217ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      check_error_state);
218ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
219ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
220ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid OnActivateFailed(const std::string& service_path,
22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                      const std::string& error_name,
222ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                      scoped_ptr<base::DictionaryValue> error_data) {
223ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_ERROR("Unable to activate network", service_path);
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ShowErrorNotification(network_connect::kErrorActivateFailed, service_path);
225ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
226ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
227ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid OnActivateSucceeded(const std::string& service_path) {
228ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_USER("Activation Succeeded", service_path);
229ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
230ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
231ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid OnConfigureFailed(const std::string& error_name,
232ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                       scoped_ptr<base::DictionaryValue> error_data) {
233ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_ERROR("Unable to configure network", "");
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ShowErrorNotification(NetworkConnectionHandler::kErrorConfigureFailed, "");
235ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
236ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid OnConfigureSucceeded(bool connect_on_configure,
238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                          const std::string& service_path) {
239ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_USER("Configure Succeeded", service_path);
240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!connect_on_configure)
241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
242ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // After configuring a network, ignore any (possibly stale) error state.
243ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const bool check_error_state = false;
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CallConnectToNetwork(service_path, check_error_state);
245ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
246ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid CallCreateConfiguration(base::DictionaryValue* properties,
248effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                             bool shared,
249effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                             bool connect_on_configure) {
250effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string profile_path;
251effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!GetNetworkProfilePath(shared, &profile_path)) {
252effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ShowErrorNotification(NetworkConnectionHandler::kErrorConfigureFailed, "");
253effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
254effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
255effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  properties->SetStringWithoutPathExpansion(
256effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      shill::kProfileProperty, profile_path);
257effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  NetworkHandler::Get()->network_configuration_handler()->CreateConfiguration(
258effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      *properties,
259effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&OnConfigureSucceeded, connect_on_configure),
260effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      base::Bind(&OnConfigureFailed));
261effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
262effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
263ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid SetPropertiesFailed(const std::string& desc,
264ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                         const std::string& service_path,
265ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                         const std::string& config_error_name,
266ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                         scoped_ptr<base::DictionaryValue> error_data) {
267ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_ERROR(desc + ": Failed: " + config_error_name, service_path);
268ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  ShowErrorNotification(
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      NetworkConnectionHandler::kErrorConfigureFailed, service_path);
270ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
271ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
272ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid SetPropertiesToClear(base::DictionaryValue* properties_to_set,
273ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                          std::vector<std::string>* properties_to_clear) {
274ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Move empty string properties to properties_to_clear.
275ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (base::DictionaryValue::Iterator iter(*properties_to_set);
276ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch       !iter.IsAtEnd(); iter.Advance()) {
277ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    std::string value_str;
278ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (iter.value().GetAsString(&value_str) && value_str.empty())
279ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      properties_to_clear->push_back(iter.key());
280ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
281ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // Remove cleared properties from properties_to_set.
282ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (std::vector<std::string>::iterator iter = properties_to_clear->begin();
283ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch       iter != properties_to_clear->end(); ++iter) {
284ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    properties_to_set->RemoveWithoutPathExpansion(*iter, NULL);
285ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
286ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
287ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
288ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ClearPropertiesAndConnect(
289ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& service_path,
290ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::vector<std::string>& properties_to_clear) {
291ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_USER("ClearPropertiesAndConnect", service_path);
292ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  // After configuring a network, ignore any (possibly stale) error state.
293ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const bool check_error_state = false;
294ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NetworkHandler::Get()->network_configuration_handler()->ClearProperties(
295ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      service_path,
296ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      properties_to_clear,
297ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&CallConnectToNetwork,
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 service_path, check_error_state),
299ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&SetPropertiesFailed, "ClearProperties", service_path));
300ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
301ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
302ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ConfigureSetProfileSucceeded(
303ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& service_path,
304ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    scoped_ptr<base::DictionaryValue> properties_to_set) {
305ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  std::vector<std::string> properties_to_clear;
306ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  SetPropertiesToClear(properties_to_set.get(), &properties_to_clear);
307ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NetworkHandler::Get()->network_configuration_handler()->SetProperties(
308ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      service_path,
309ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      *properties_to_set,
310ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&ClearPropertiesAndConnect,
311ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                 service_path,
312ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                 properties_to_clear),
313ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&SetPropertiesFailed, "SetProperties", service_path));
314ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
315ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
3164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const NetworkState* GetNetworkState(const std::string& service_path) {
3174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return NetworkHandler::Get()->network_state_handler()->
3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      GetNetworkState(service_path);
3194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace
322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace network_connect {
324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const char kNetworkConnectNotificationId[] =
3263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    "chrome://settings/internet/connect";
3273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const char kNetworkActivateNotificationId[] =
3283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    "chrome://settings/internet/activate";
3293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
33058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const char kErrorActivateFailed[] = "activate-failed";
33158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ConnectToNetwork(const std::string& service_path) {
3333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NET_LOG_USER("ConnectToNetwork", service_path);
3344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const NetworkState* network = GetNetworkState(service_path);
3356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (network) {
3366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (!network->error().empty() && !network->security().empty()) {
3376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      NET_LOG_USER("Configure: " + network->error(), service_path);
3386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // If the network is in an error state, show the configuration UI directly
3396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      // to avoid a spurious notification.
3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      HandleUnconfiguredNetwork(service_path);
3416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return;
3426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    } else if (network->RequiresActivation()) {
3436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ActivateCellular(service_path);
3446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return;
3456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
3463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
347ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const bool check_error_state = true;
3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CallConnectToNetwork(service_path, check_error_state);
349ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
350ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
35158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void SetTechnologyEnabled(const NetworkTypePattern& technology,
35258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                          bool enabled_state) {
3533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string log_string =
3543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::StringPrintf("technology %s, target state: %s",
35558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                         technology.ToDebugString().c_str(),
3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                         (enabled_state ? "ENABLED" : "DISABLED"));
3573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NET_LOG_USER("SetTechnologyEnabled", log_string);
3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
3593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool enabled = handler->IsTechnologyEnabled(technology);
3603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (enabled_state == enabled) {
3613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NET_LOG_USER("Technology already in target state.", log_string);
3623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
3633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (enabled) {
3653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // User requested to disable the technology.
3663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    handler->SetTechnologyEnabled(
3673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        technology, false, chromeos::network_handler::ErrorCallback());
3683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
3693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If we're dealing with a mobile network, then handle SIM lock here.
3713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // SIM locking only applies to cellular, so the code below won't execute
3723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // if |technology| has been explicitly set to WiMAX.
37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (technology.MatchesPattern(NetworkTypePattern::Mobile())) {
3743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const DeviceState* mobile = handler->GetDeviceStateByType(technology);
3753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!mobile) {
3763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      NET_LOG_ERROR("SetTechnologyEnabled with no device", log_string);
3773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return;
3783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
3793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // The following only applies to cellular.
38068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (mobile->type() == shill::kTypeCellular) {
3813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (mobile->IsSimAbsent()) {
3823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // If this is true, then we have a cellular device with no SIM inserted.
3833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // TODO(armansito): Chrome should display a notification here, prompting
3843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // the user to insert a SIM card and restart the device to enable
3853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // cellular. See crbug.com/125171.
3863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        NET_LOG_USER("Cannot enable cellular device without SIM.", log_string);
3873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return;
3883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
3893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (!mobile->sim_lock_type().empty()) {
3903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // A SIM has been inserted, but it is locked. Let the user unlock it
3913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // via the dialog.
3923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ash::Shell::GetInstance()->system_tray_delegate()->
3933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            ShowMobileSimDialog();
3943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return;
3953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
3963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
3973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  handler->SetTechnologyEnabled(
3993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    technology, true, chromeos::network_handler::ErrorCallback());
4003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
402ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ActivateCellular(const std::string& service_path) {
403ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_USER("ActivateCellular", service_path);
4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const NetworkState* cellular = GetNetworkState(service_path);
40568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!cellular || cellular->type() != shill::kTypeCellular) {
4063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NET_LOG_ERROR("ActivateCellular with no Service", service_path);
4073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
4083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
409ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const DeviceState* cellular_device =
410ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      NetworkHandler::Get()->network_state_handler()->
4113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      GetDeviceState(cellular->device_path());
412ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!cellular_device) {
413ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    NET_LOG_ERROR("ActivateCellular with no Device", service_path);
414ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
415ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
416ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!IsDirectActivatedCarrier(cellular_device->carrier())) {
417ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    // For non direct activation, show the mobile setup dialog which can be
41858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // used to activate the network.
41958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ShowMobileSetup(service_path);
420868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
421ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
42268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (cellular->activation_state() == shill::kActivationStateActivated) {
423ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    NET_LOG_ERROR("ActivateCellular for activated service", service_path);
424ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
425ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
426ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
427424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  NetworkHandler::Get()->network_activation_handler()->Activate(
428868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      service_path,
429ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "",  // carrier
430ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&OnActivateSucceeded, service_path),
431ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&OnActivateFailed, service_path));
432ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
433ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
4343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ShowMobileSetup(const std::string& service_path) {
4353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
4363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const NetworkState* cellular = handler->GetNetworkState(service_path);
43768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!cellular || cellular->type() != shill::kTypeCellular) {
4383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NET_LOG_ERROR("ShowMobileSetup without Cellular network", service_path);
4393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
4403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
44168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (cellular->activation_state() != shill::kActivationStateActivated &&
4426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      cellular->activation_type() == shill::kActivationTypeNonCellular &&
4433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      !handler->DefaultNetwork()) {
4443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    message_center::MessageCenter::Get()->AddNotification(
4453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        message_center::Notification::CreateSystemNotification(
4463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            kNetworkActivateNotificationId,
4473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            l10n_util::GetStringUTF16(IDS_NETWORK_ACTIVATION_ERROR_TITLE),
4483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            l10n_util::GetStringFUTF16(IDS_NETWORK_ACTIVATION_NEEDS_CONNECTION,
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                       base::UTF8ToUTF16(cellular->name())),
4503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            ui::ResourceBundle::GetSharedInstance().GetImageNamed(
4513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                IDR_AURA_UBER_TRAY_CELLULAR_NETWORK_FAILED),
452a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            ash::system_notifier::kNotifierNetworkError,
4533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            base::Bind(&ash::network_connect::ShowNetworkSettings,
4543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                       service_path)));
4553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
4563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ash::Shell::GetInstance()->system_tray_delegate()->ShowMobileSetupDialog(
4583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      service_path);
4593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
461ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ConfigureNetworkAndConnect(const std::string& service_path,
462ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                const base::DictionaryValue& properties,
463ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                bool shared) {
464ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_USER("ConfigureNetworkAndConnect", service_path);
465ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
466ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  scoped_ptr<base::DictionaryValue> properties_to_set(properties.DeepCopy());
467ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
468ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  std::string profile_path;
469ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!GetNetworkProfilePath(shared, &profile_path)) {
470ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    ShowErrorNotification(
471a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        NetworkConnectionHandler::kErrorConfigureFailed, service_path);
472ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
473ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
474ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NetworkHandler::Get()->network_configuration_handler()->SetNetworkProfile(
475ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      service_path, profile_path,
476ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&ConfigureSetProfileSucceeded,
477ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                 service_path, base::Passed(&properties_to_set)),
478ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&SetPropertiesFailed,
479ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                 "SetProfile: " + profile_path, service_path));
480ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
481ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
482ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid CreateConfigurationAndConnect(base::DictionaryValue* properties,
483ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                   bool shared) {
484ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  NET_LOG_USER("CreateConfigurationAndConnect", "");
485effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CallCreateConfiguration(properties, shared, true /* connect_on_configure */);
486effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
487effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
488effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid CreateConfiguration(base::DictionaryValue* properties, bool shared) {
489effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  NET_LOG_USER("CreateConfiguration", "");
490effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  CallCreateConfiguration(properties, shared, false /* connect_on_configure */);
491868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
492868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ErrorString(const std::string& error,
4944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     const std::string& service_path) {
4957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (error.empty())
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return base::string16();
49768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorOutOfRange)
4987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_OUT_OF_RANGE);
49968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorPinMissing)
5007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_PIN_MISSING);
50168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorDhcpFailed)
5027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_DHCP_FAILED);
50368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorConnectFailed)
5047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED);
50568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorBadPassphrase)
5067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_BAD_PASSPHRASE);
50768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorBadWEPKey)
5087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_BAD_WEPKEY);
50968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorActivationFailed) {
5107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(
5117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED);
5127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
51368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorNeedEvdo)
5147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_NEED_EVDO);
51568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorNeedHomeNetwork) {
5167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(
5177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        IDS_CHROMEOS_NETWORK_ERROR_NEED_HOME_NETWORK);
5187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
51968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorOtaspFailed)
5207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_OTASP_FAILED);
52168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorAaaFailed)
5227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_AAA_FAILED);
52368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorInternal)
5247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_INTERNAL);
52568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorDNSLookupFailed) {
5267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(
5277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        IDS_CHROMEOS_NETWORK_ERROR_DNS_LOOKUP_FAILED);
5287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
52968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorHTTPGetFailed) {
5307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(
5317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        IDS_CHROMEOS_NETWORK_ERROR_HTTP_GET_FAILED);
5327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
53368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorIpsecPskAuthFailed) {
5347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(
5357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        IDS_CHROMEOS_NETWORK_ERROR_IPSEC_PSK_AUTH_FAILED);
5367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
5374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (error == shill::kErrorIpsecCertAuthFailed) {
5387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(
5397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        IDS_CHROMEOS_NETWORK_ERROR_CERT_AUTH_FAILED);
5407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
5414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (error == shill::kErrorEapAuthenticationFailed) {
5424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const NetworkState* network = GetNetworkState(service_path);
5434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // TLS always requires a client certificate, so show a cert auth
5444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // failed message for TLS. Other EAP methods do not generally require
5454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // a client certicate.
5464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (network && network->eap_method() == shill::kEapMethodTLS) {
5474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return l10n_util::GetStringUTF16(
5484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          IDS_CHROMEOS_NETWORK_ERROR_CERT_AUTH_FAILED);
5494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    } else {
5504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return l10n_util::GetStringUTF16(
5514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          IDS_CHROMEOS_NETWORK_ERROR_EAP_AUTH_FAILED);
5524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
5534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
5547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (error == shill::kErrorEapLocalTlsFailed) {
5557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(
5567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        IDS_CHROMEOS_NETWORK_ERROR_EAP_LOCAL_TLS_FAILED);
5577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
5587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (error == shill::kErrorEapRemoteTlsFailed) {
5597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(
5607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        IDS_CHROMEOS_NETWORK_ERROR_EAP_REMOTE_TLS_FAILED);
5617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
56268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (error == shill::kErrorPppAuthFailed) {
5637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(
5647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        IDS_CHROMEOS_NETWORK_ERROR_PPP_AUTH_FAILED);
5657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
5667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (base::StringToLowerASCII(error) ==
5686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      base::StringToLowerASCII(std::string(shill::kUnknownString))) {
5697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN);
5707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
5717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return l10n_util::GetStringFUTF16(IDS_NETWORK_UNRECOGNIZED_ERROR,
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::UTF8ToUTF16(error));
5737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
5747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ShowNetworkSettings(const std::string& service_path) {
5763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ash::Shell::HasInstance())
5773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
5783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ash::Shell::GetInstance()->system_tray_delegate()->ShowNetworkSettings(
5793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      service_path);
5803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
582868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // network_connect
583868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // ash
584