1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/webui/options/chromeos/internet_options_handler.h"
6
7#include <ctype.h>
8
9#include <map>
10#include <string>
11#include <vector>
12
13#include "ash/system/chromeos/network/network_connect.h"
14#include "base/basictypes.h"
15#include "base/bind.h"
16#include "base/bind_helpers.h"
17#include "base/command_line.h"
18#include "base/strings/utf_string_conversions.h"
19#include "base/values.h"
20#include "chrome/browser/browser_process.h"
21#include "chrome/browser/chromeos/mobile_config.h"
22#include "chrome/browser/chromeos/net/onc_utils.h"
23#include "chrome/browser/chromeos/options/network_config_view.h"
24#include "chrome/browser/chromeos/options/network_property_ui_data.h"
25#include "chrome/browser/chromeos/settings/cros_settings.h"
26#include "chrome/browser/chromeos/sim_dialog_delegate.h"
27#include "chrome/browser/chromeos/ui/choose_mobile_network_dialog.h"
28#include "chrome/browser/chromeos/ui/mobile_config_ui.h"
29#include "chrome/browser/chromeos/ui_proxy_config_service.h"
30#include "chrome/browser/profiles/profile.h"
31#include "chrome/browser/ui/webui/chromeos/mobile_setup_dialog.h"
32#include "chrome/browser/ui/webui/options/chromeos/internet_options_handler_strings.h"
33#include "chromeos/chromeos_switches.h"
34#include "chromeos/login/login_state.h"
35#include "chromeos/network/device_state.h"
36#include "chromeos/network/managed_network_configuration_handler.h"
37#include "chromeos/network/network_configuration_handler.h"
38#include "chromeos/network/network_connection_handler.h"
39#include "chromeos/network/network_device_handler.h"
40#include "chromeos/network/network_event_log.h"
41#include "chromeos/network/network_ip_config.h"
42#include "chromeos/network/network_profile.h"
43#include "chromeos/network/network_profile_handler.h"
44#include "chromeos/network/network_state.h"
45#include "chromeos/network/network_state_handler.h"
46#include "chromeos/network/network_util.h"
47#include "chromeos/network/onc/onc_signature.h"
48#include "chromeos/network/onc/onc_translation_tables.h"
49#include "chromeos/network/onc/onc_translator.h"
50#include "chromeos/network/onc/onc_utils.h"
51#include "components/onc/onc_constants.h"
52#include "content/public/browser/web_contents.h"
53#include "content/public/browser/web_ui.h"
54#include "grit/ui_chromeos_resources.h"
55#include "third_party/cros_system_api/dbus/service_constants.h"
56#include "ui/base/resource/resource_bundle.h"
57#include "ui/base/webui/web_ui_util.h"
58#include "ui/chromeos/network/network_icon.h"
59#include "ui/gfx/image/image_skia.h"
60
61namespace chromeos {
62namespace options {
63
64namespace {
65
66// Keys for the network description dictionary passed to the web ui. Make sure
67// to keep the strings in sync with what the JavaScript side uses.
68const char kNetworkInfoKeyIconURL[] = "iconURL";
69const char kNetworkInfoKeyPolicyManaged[] = "policyManaged";
70
71// These are types of name server selections from the web ui.
72const char kNameServerTypeAutomatic[] = "automatic";
73const char kNameServerTypeGoogle[] = "google";
74
75// Google public name servers (DNS).
76const char kGoogleNameServers[] = "8.8.4.4,8.8.8.8";
77
78// Functions we call in JavaScript.
79const char kRefreshNetworkDataFunction[] =
80    "options.network.NetworkList.refreshNetworkData";
81const char kSetDefaultNetworkIconsFunction[] =
82    "options.network.NetworkList.setDefaultNetworkIcons";
83const char kSendNetworkDetailsFunction[] =
84    "options.internet.DetailsInternetPage.sendNetworkDetails";
85const char kShowDetailedInfoFunction[] =
86    "options.internet.DetailsInternetPage.showDetailedInfo";
87const char kUpdateConnectionDataFunction[] =
88    "options.internet.DetailsInternetPage.updateConnectionData";
89const char kUpdateCarrierFunction[] =
90    "options.internet.DetailsInternetPage.updateCarrier";
91
92// These are used to register message handlers with JavaScript.
93const char kNetworkCommandMessage[] = "networkCommand";
94const char kSetApnMessage[] = "setApn";
95const char kSetAutoConnectMessage[] = "setAutoConnect";
96const char kSetCarrierMessage[] = "setCarrier";
97const char kSetIPConfigMessage[] = "setIPConfig";
98const char kSetPreferNetworkMessage[] = "setPreferNetwork";
99const char kSetServerHostname[] = "setServerHostname";
100const char kShowMorePlanInfoMessage[] = "showMorePlanInfo";
101const char kSimOperationMessage[] = "simOperation";
102
103// TODO(stevenjb): Replace these with the matching networkingPrivate methods.
104// crbug.com/279351.
105const char kDisableNetworkTypeMessage[] = "disableNetworkType";
106const char kEnableNetworkTypeMessage[] = "enableNetworkType";
107const char kGetManagedPropertiesMessage[] = "getManagedProperties";
108const char kRequestNetworkScanMessage[] = "requestNetworkScan";
109const char kStartConnectMessage[] = "startConnect";
110const char kStartDisconnectMessage[] = "startDisconnect";
111
112// These are strings used to communicate with JavaScript.
113const char kTagActivate[] = "activate";
114const char kTagAddConnection[] = "add";
115const char kTagCarrierSelectFlag[] = "showCarrierSelect";
116const char kTagCellularAvailable[] = "cellularAvailable";
117const char kTagCellularEnabled[] = "cellularEnabled";
118const char kTagCellularSimAbsent[] = "cellularSimAbsent";
119const char kTagCellularSimLockType[] = "cellularSimLockType";
120const char kTagCellularSupportsScan[] = "cellularSupportsScan";
121const char kTagConfigure[] = "configure";
122const char kTagForget[] = "forget";
123const char kTagRememberedList[] = "rememberedList";
124const char kTagShowDetails[] = "showDetails";
125const char kTagShowViewAccountButton[] = "showViewAccountButton";
126const char kTagSimOpChangePin[] = "changePin";
127const char kTagSimOpConfigure[] = "configure";
128const char kTagSimOpSetLocked[] = "setLocked";
129const char kTagSimOpSetUnlocked[] = "setUnlocked";
130const char kTagSimOpUnlock[] = "unlock";
131const char kTagTrue[] = "true";
132const char kTagVpnList[] = "vpnList";
133const char kTagWifiAvailable[] = "wifiAvailable";
134const char kTagWifiEnabled[] = "wifiEnabled";
135const char kTagWimaxAvailable[] = "wimaxAvailable";
136const char kTagWimaxEnabled[] = "wimaxEnabled";
137const char kTagWiredList[] = "wiredList";
138const char kTagWirelessList[] = "wirelessList";
139
140// Pseudo-ONC chrome specific properties appended to the ONC dictionary.
141const char kTagErrorMessage[] = "errorMessage";
142const char kNetworkInfoKeyServicePath[] = "servicePath";
143const char kNetworkInfoKeyGUID[] = "GUID";
144
145const int kPreferredPriority = 1;
146
147void ShillError(const std::string& function,
148                const std::string& error_name,
149                scoped_ptr<base::DictionaryValue> error_data) {
150  // UpdateConnectionData may send requests for stale services; ignore
151  // these errors.
152  if (function == "UpdateConnectionData" &&
153      error_name == network_handler::kDBusFailedError)
154    return;
155  NET_LOG_ERROR("Shill Error from InternetOptionsHandler: " + error_name,
156                function);
157}
158
159const NetworkState* GetNetworkState(const std::string& service_path) {
160  return NetworkHandler::Get()->network_state_handler()->
161      GetNetworkState(service_path);
162}
163
164void SetNetworkProperty(const std::string& service_path,
165                        const std::string& property,
166                        base::Value* value) {
167  NET_LOG_EVENT("SetNetworkProperty: " + property, service_path);
168  base::DictionaryValue properties;
169  properties.SetWithoutPathExpansion(property, value);
170  NetworkHandler::Get()->network_configuration_handler()->SetProperties(
171      service_path, properties,
172      base::Bind(&base::DoNothing),
173      base::Bind(&ShillError, "SetNetworkProperty"));
174}
175
176// Builds a dictionary with network information and an icon used for the
177// NetworkList on the settings page. Ownership of the returned pointer is
178// transferred to the caller.
179base::DictionaryValue* BuildNetworkDictionary(
180    const NetworkState* network,
181    float icon_scale_factor,
182    const PrefService* profile_prefs) {
183  scoped_ptr<base::DictionaryValue> network_info =
184      network_util::TranslateNetworkStateToONC(network);
185
186  bool has_policy = onc::HasPolicyForNetwork(
187      profile_prefs, g_browser_process->local_state(), *network);
188  network_info->SetBoolean(kNetworkInfoKeyPolicyManaged, has_policy);
189
190  std::string icon_url = ui::network_icon::GetImageUrlForNetwork(
191      network, ui::network_icon::ICON_TYPE_LIST, icon_scale_factor);
192
193  network_info->SetString(kNetworkInfoKeyIconURL, icon_url);
194  network_info->SetString(kNetworkInfoKeyServicePath, network->path());
195
196  return network_info.release();
197}
198
199bool ShowViewAccountButton(const NetworkState* cellular) {
200  if (cellular->activation_state() != shill::kActivationStateActivating &&
201      cellular->activation_state() != shill::kActivationStateActivated)
202    return false;
203
204  const DeviceState* device =
205      NetworkHandler::Get()->network_state_handler()->GetDeviceState(
206          cellular->device_path());
207
208  // If no online payment URL was provided by shill, Check to see if the
209  // MobileConfig carrier indicates that "View Account" should be shown.
210  if (cellular->payment_url().empty()) {
211    if (!device || !MobileConfig::GetInstance()->IsReady())
212      return false;
213    const MobileConfig::Carrier* carrier =
214        MobileConfig::GetInstance()->GetCarrier(device->home_provider_id());
215    if (!carrier || !carrier->show_portal_button())
216      return false;
217  }
218
219  if (!cellular->IsConnectedState()) {
220    // Disconnected LTE networks should show the button if we are online and
221    // the device's MDN is set. This is to enable users to update their plan
222    // if they are out of credits.
223    if (!NetworkHandler::Get()->network_state_handler()->DefaultNetwork())
224      return false;
225    const std::string& technology = cellular->network_technology();
226    if (technology != shill::kNetworkTechnologyLte &&
227        technology != shill::kNetworkTechnologyLteAdvanced)
228      return false;
229    std::string mdn;
230    if (device) {
231      device->properties().GetStringWithoutPathExpansion(shill::kMdnProperty,
232                                                         &mdn);
233    }
234    if (mdn.empty())
235      return false;
236  }
237
238  return true;
239}
240
241scoped_ptr<base::DictionaryValue> PopulateConnectionDetails(
242    const NetworkState* network,
243    const base::DictionaryValue& onc_properties) {
244  scoped_ptr<base::DictionaryValue> dictionary(onc_properties.DeepCopy());
245
246  // Append Service Path for now.
247  dictionary->SetString(kNetworkInfoKeyServicePath, network->path());
248  // Append a Chrome specific translated error message.
249  dictionary->SetString(
250      kTagErrorMessage,
251      ash::network_connect::ErrorString(network->error(), network->path()));
252
253  return dictionary.Pass();
254}
255
256// Helper methods for SetIPConfigProperties
257bool AppendPropertyKeyIfPresent(const std::string& key,
258                                const base::DictionaryValue& old_properties,
259                                std::vector<std::string>* property_keys) {
260  if (old_properties.HasKey(key)) {
261    property_keys->push_back(key);
262    return true;
263  }
264  return false;
265}
266
267bool AddStringPropertyIfChanged(const std::string& key,
268                                const std::string& new_value,
269                                const base::DictionaryValue& old_properties,
270                                base::DictionaryValue* new_properties) {
271  std::string old_value;
272  if (!old_properties.GetStringWithoutPathExpansion(key, &old_value) ||
273      new_value != old_value) {
274    new_properties->SetStringWithoutPathExpansion(key, new_value);
275    return true;
276  }
277  return false;
278}
279
280bool AddIntegerPropertyIfChanged(const std::string& key,
281                                 int new_value,
282                                 const base::DictionaryValue& old_properties,
283                                 base::DictionaryValue* new_properties) {
284  int old_value;
285  if (!old_properties.GetIntegerWithoutPathExpansion(key, &old_value) ||
286      new_value != old_value) {
287    new_properties->SetIntegerWithoutPathExpansion(key, new_value);
288    return true;
289  }
290  return false;
291}
292
293}  // namespace
294
295InternetOptionsHandler::InternetOptionsHandler()
296    : weak_factory_(this) {
297  NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
298}
299
300InternetOptionsHandler::~InternetOptionsHandler() {
301  if (NetworkHandler::IsInitialized()) {
302    NetworkHandler::Get()->network_state_handler()->RemoveObserver(
303        this, FROM_HERE);
304  }
305}
306
307void InternetOptionsHandler::GetLocalizedValues(
308    base::DictionaryValue* localized_strings) {
309  DCHECK(localized_strings);
310  internet_options_strings::RegisterLocalizedStrings(localized_strings);
311
312  // TODO(stevenjb): Find a better way to populate initial data before
313  // InitializePage() gets called.
314  std::string owner;
315  chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
316  localized_strings->SetString("ownerUserId", base::UTF8ToUTF16(owner));
317  bool logged_in_as_owner = LoginState::Get()->GetLoggedInUserType() ==
318                            LoginState::LOGGED_IN_USER_OWNER;
319  localized_strings->SetBoolean("loggedInAsOwner", logged_in_as_owner);
320
321  base::DictionaryValue* network_dictionary = new base::DictionaryValue;
322  FillNetworkInfo(network_dictionary);
323  localized_strings->Set("networkData", network_dictionary);
324}
325
326void InternetOptionsHandler::InitializePage() {
327  base::DictionaryValue dictionary;
328  dictionary.SetString(::onc::network_type::kCellular,
329      GetIconDataUrl(IDR_AURA_UBER_TRAY_NETWORK_BARS_DARK));
330  dictionary.SetString(::onc::network_type::kWiFi,
331      GetIconDataUrl(IDR_AURA_UBER_TRAY_NETWORK_ARCS_DARK));
332  dictionary.SetString(::onc::network_type::kVPN,
333      GetIconDataUrl(IDR_AURA_UBER_TRAY_NETWORK_VPN));
334  web_ui()->CallJavascriptFunction(kSetDefaultNetworkIconsFunction,
335                                   dictionary);
336  NetworkHandler::Get()->network_state_handler()->RequestScan();
337  RefreshNetworkData();
338}
339
340void InternetOptionsHandler::RegisterMessages() {
341  // Setup handlers specific to this panel.
342  web_ui()->RegisterMessageCallback(kNetworkCommandMessage,
343      base::Bind(&InternetOptionsHandler::NetworkCommandCallback,
344                 base::Unretained(this)));
345  web_ui()->RegisterMessageCallback(kSetPreferNetworkMessage,
346      base::Bind(&InternetOptionsHandler::SetPreferNetworkCallback,
347                 base::Unretained(this)));
348  web_ui()->RegisterMessageCallback(kSetAutoConnectMessage,
349      base::Bind(&InternetOptionsHandler::SetAutoConnectCallback,
350                 base::Unretained(this)));
351  web_ui()->RegisterMessageCallback(kSetIPConfigMessage,
352      base::Bind(&InternetOptionsHandler::SetIPConfigCallback,
353                 base::Unretained(this)));
354  web_ui()->RegisterMessageCallback(kShowMorePlanInfoMessage,
355      base::Bind(&InternetOptionsHandler::ShowMorePlanInfoCallback,
356                 base::Unretained(this)));
357  web_ui()->RegisterMessageCallback(kSetApnMessage,
358      base::Bind(&InternetOptionsHandler::SetApnCallback,
359                 base::Unretained(this)));
360  web_ui()->RegisterMessageCallback(kSetCarrierMessage,
361      base::Bind(&InternetOptionsHandler::SetCarrierCallback,
362                 base::Unretained(this)));
363  web_ui()->RegisterMessageCallback(kSimOperationMessage,
364      base::Bind(&InternetOptionsHandler::SimOperationCallback,
365                 base::Unretained(this)));
366  web_ui()->RegisterMessageCallback(kSetServerHostname,
367      base::Bind(&InternetOptionsHandler::SetServerHostnameCallback,
368                 base::Unretained(this)));
369
370  // networkingPrivate methods
371  web_ui()->RegisterMessageCallback(kDisableNetworkTypeMessage,
372      base::Bind(&InternetOptionsHandler::DisableNetworkTypeCallback,
373                 base::Unretained(this)));
374  web_ui()->RegisterMessageCallback(kEnableNetworkTypeMessage,
375      base::Bind(&InternetOptionsHandler::EnableNetworkTypeCallback,
376                 base::Unretained(this)));
377  web_ui()->RegisterMessageCallback(kGetManagedPropertiesMessage,
378      base::Bind(&InternetOptionsHandler::GetManagedPropertiesCallback,
379                 base::Unretained(this)));
380  web_ui()->RegisterMessageCallback(kRequestNetworkScanMessage,
381      base::Bind(&InternetOptionsHandler::RequestNetworkScanCallback,
382                 base::Unretained(this)));
383  web_ui()->RegisterMessageCallback(kStartConnectMessage,
384      base::Bind(&InternetOptionsHandler::StartConnectCallback,
385                 base::Unretained(this)));
386  web_ui()->RegisterMessageCallback(kStartDisconnectMessage,
387      base::Bind(&InternetOptionsHandler::StartDisconnectCallback,
388                 base::Unretained(this)));
389}
390
391void InternetOptionsHandler::ShowMorePlanInfoCallback(
392    const base::ListValue* args) {
393  if (!web_ui())
394    return;
395  std::string service_path;
396  if (args->GetSize() != 1 || !args->GetString(0, &service_path)) {
397    NOTREACHED();
398    return;
399  }
400  ash::network_connect::ShowMobileSetup(service_path);
401}
402
403void InternetOptionsHandler::SetApnCallback(const base::ListValue* args) {
404  std::string service_path;
405  if (!args->GetString(0, &service_path)) {
406    NOTREACHED();
407    return;
408  }
409  NetworkHandler::Get()->network_configuration_handler()->GetProperties(
410      service_path,
411      base::Bind(&InternetOptionsHandler::SetApnProperties,
412                 weak_factory_.GetWeakPtr(), base::Owned(args->DeepCopy())),
413      base::Bind(&ShillError, "SetApnCallback"));
414}
415
416void InternetOptionsHandler::SetApnProperties(
417    const base::ListValue* args,
418    const std::string& service_path,
419    const base::DictionaryValue& shill_properties) {
420  std::string apn, username, password;
421  if (!args->GetString(1, &apn) ||
422      !args->GetString(2, &username) ||
423      !args->GetString(3, &password)) {
424    NOTREACHED();
425    return;
426  }
427  NET_LOG_EVENT("SetApnCallback", service_path);
428
429  if (apn.empty()) {
430    std::vector<std::string> properties_to_clear;
431    properties_to_clear.push_back(shill::kCellularApnProperty);
432    NetworkHandler::Get()->network_configuration_handler()->ClearProperties(
433      service_path, properties_to_clear,
434      base::Bind(&base::DoNothing),
435      base::Bind(&ShillError, "ClearCellularApnProperties"));
436    return;
437  }
438
439  const base::DictionaryValue* shill_apn_dict = NULL;
440  std::string network_id;
441  if (shill_properties.GetDictionaryWithoutPathExpansion(
442          shill::kCellularApnProperty, &shill_apn_dict)) {
443    shill_apn_dict->GetStringWithoutPathExpansion(
444        shill::kApnNetworkIdProperty, &network_id);
445  }
446  base::DictionaryValue properties;
447  base::DictionaryValue* apn_dict = new base::DictionaryValue;
448  apn_dict->SetStringWithoutPathExpansion(shill::kApnProperty, apn);
449  apn_dict->SetStringWithoutPathExpansion(shill::kApnNetworkIdProperty,
450                                          network_id);
451  apn_dict->SetStringWithoutPathExpansion(shill::kApnUsernameProperty,
452                                          username);
453  apn_dict->SetStringWithoutPathExpansion(shill::kApnPasswordProperty,
454                                          password);
455  properties.SetWithoutPathExpansion(shill::kCellularApnProperty, apn_dict);
456  NetworkHandler::Get()->network_configuration_handler()->SetProperties(
457      service_path, properties,
458      base::Bind(&base::DoNothing),
459      base::Bind(&ShillError, "SetApnProperties"));
460}
461
462void InternetOptionsHandler::CarrierStatusCallback() {
463  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
464  const DeviceState* device =
465      handler->GetDeviceStateByType(NetworkTypePattern::Cellular());
466  if (device && (device->carrier() == shill::kCarrierSprint)) {
467    const NetworkState* network =
468        handler->FirstNetworkByType(NetworkTypePattern::Cellular());
469    if (network && network->path() == details_path_) {
470      ash::network_connect::ActivateCellular(network->path());
471      UpdateConnectionData(network->path());
472    }
473  }
474  UpdateCarrier();
475}
476
477void InternetOptionsHandler::SetCarrierCallback(const base::ListValue* args) {
478  std::string service_path;
479  std::string carrier;
480  if (args->GetSize() != 2 ||
481      !args->GetString(0, &service_path) ||
482      !args->GetString(1, &carrier)) {
483    NOTREACHED();
484    return;
485  }
486  const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
487      GetDeviceStateByType(NetworkTypePattern::Cellular());
488  if (!device) {
489    LOG(WARNING) << "SetCarrierCallback with no cellular device.";
490    return;
491  }
492  NetworkHandler::Get()->network_device_handler()->SetCarrier(
493      device->path(),
494      carrier,
495      base::Bind(&InternetOptionsHandler::CarrierStatusCallback,
496                 weak_factory_.GetWeakPtr()),
497      base::Bind(&ShillError, "SetCarrierCallback"));
498}
499
500void InternetOptionsHandler::SimOperationCallback(const base::ListValue* args) {
501  std::string operation;
502  if (args->GetSize() != 1 || !args->GetString(0, &operation)) {
503    NOTREACHED();
504    return;
505  }
506  if (operation == kTagSimOpConfigure) {
507    mobile_config_ui::DisplayConfigDialog();
508    return;
509  }
510  // 1. Bring up SIM unlock dialog, pass new RequirePin setting in URL.
511  // 2. Dialog will ask for current PIN in any case.
512  // 3. If card is locked it will first call PIN unlock operation
513  // 4. Then it will call Set RequirePin, passing the same PIN.
514  // 5. The dialog may change device properties, in which case
515  //    DevicePropertiesUpdated() will get called which will update the UI.
516  SimDialogDelegate::SimDialogMode mode;
517  if (operation == kTagSimOpSetLocked) {
518    mode = SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON;
519  } else if (operation == kTagSimOpSetUnlocked) {
520    mode = SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF;
521  } else if (operation == kTagSimOpUnlock) {
522    mode = SimDialogDelegate::SIM_DIALOG_UNLOCK;
523  } else if (operation == kTagSimOpChangePin) {
524    mode = SimDialogDelegate::SIM_DIALOG_CHANGE_PIN;
525  } else {
526    NOTREACHED();
527    return;
528  }
529  SimDialogDelegate::ShowDialog(GetNativeWindow(), mode);
530}
531
532////////////////////////////////////////////////////////////////////////////////
533// networkingPrivate implementation methods. TODO(stevenjb): Use the
534// networkingPrivate API directly in the settings JS and deprecate these
535// methods. crbug.com/279351.
536
537void InternetOptionsHandler::DisableNetworkTypeCallback(
538    const base::ListValue* args) {
539  std::string type;
540  if (!args->GetString(0, &type)) {
541    NOTREACHED();
542    return;
543  }
544  NetworkHandler::Get()->network_state_handler()->SetTechnologyEnabled(
545      chromeos::onc::NetworkTypePatternFromOncType(type), false,
546      base::Bind(&ShillError, "DisableNetworkType"));
547}
548
549void InternetOptionsHandler::EnableNetworkTypeCallback(
550    const base::ListValue* args) {
551  std::string type;
552  if (!args->GetString(0, &type)) {
553    NOTREACHED();
554    return;
555  }
556  NetworkHandler::Get()->network_state_handler()->SetTechnologyEnabled(
557      chromeos::onc::NetworkTypePatternFromOncType(type), true,
558      base::Bind(&ShillError, "EnableNetworkType"));
559}
560
561void InternetOptionsHandler::GetManagedPropertiesCallback(
562    const base::ListValue* args) {
563  std::string service_path;
564  if (!args->GetString(0, &service_path)) {
565    NOTREACHED();
566    return;
567  }
568  NetworkHandler::Get()->managed_network_configuration_handler()
569      ->GetManagedProperties(
570          LoginState::Get()->primary_user_hash(),
571          service_path,
572          base::Bind(
573              &InternetOptionsHandler::PopulateDictionaryDetailsCallback,
574              weak_factory_.GetWeakPtr()),
575          base::Bind(&ShillError, "GetManagedProperties"));
576}
577
578void InternetOptionsHandler::RequestNetworkScanCallback(
579    const base::ListValue* args) {
580  NetworkHandler::Get()->network_state_handler()->RequestScan();
581}
582
583void InternetOptionsHandler::StartConnectCallback(const base::ListValue* args) {
584  std::string service_path;
585  if (!args->GetString(0, &service_path)) {
586    NOTREACHED();
587    return;
588  }
589  ash::network_connect::ConnectToNetwork(service_path);
590}
591
592void InternetOptionsHandler::StartDisconnectCallback(
593    const base::ListValue* args) {
594  std::string service_path;
595  if (!args->GetString(0, &service_path)) {
596    NOTREACHED();
597    return;
598  }
599  NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
600      service_path,
601      base::Bind(&base::DoNothing),
602      base::Bind(&ShillError, "StartDisconnectCallback"));
603}
604
605////////////////////////////////////////////////////////////////////////////////
606
607std::string InternetOptionsHandler::GetIconDataUrl(int resource_id) const {
608  gfx::ImageSkia* icon =
609      ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
610  gfx::ImageSkiaRep image_rep = icon->GetRepresentation(
611      web_ui()->GetDeviceScaleFactor());
612  return webui::GetBitmapDataUrl(image_rep.sk_bitmap());
613}
614
615void InternetOptionsHandler::RefreshNetworkData() {
616  base::DictionaryValue dictionary;
617  FillNetworkInfo(&dictionary);
618  web_ui()->CallJavascriptFunction(kRefreshNetworkDataFunction, dictionary);
619}
620
621void InternetOptionsHandler::UpdateConnectionData(
622    const std::string& service_path) {
623  NetworkHandler::Get()
624      ->managed_network_configuration_handler()
625      ->GetManagedProperties(
626          LoginState::Get()->primary_user_hash(),
627          service_path,
628          base::Bind(&InternetOptionsHandler::UpdateConnectionDataCallback,
629                     weak_factory_.GetWeakPtr()),
630          base::Bind(&ShillError, "UpdateConnectionData"));
631}
632
633void InternetOptionsHandler::UpdateConnectionDataCallback(
634    const std::string& service_path,
635    const base::DictionaryValue& onc_properties) {
636  const NetworkState* network = GetNetworkState(service_path);
637  if (!network)
638    return;
639  scoped_ptr<base::DictionaryValue> dictionary =
640      PopulateConnectionDetails(network, onc_properties);
641  web_ui()->CallJavascriptFunction(kUpdateConnectionDataFunction, *dictionary);
642}
643
644void InternetOptionsHandler::UpdateCarrier() {
645  web_ui()->CallJavascriptFunction(kUpdateCarrierFunction);
646}
647
648void InternetOptionsHandler::DeviceListChanged() {
649  if (!web_ui())
650    return;
651  RefreshNetworkData();
652}
653
654void InternetOptionsHandler::NetworkListChanged() {
655  if (!web_ui())
656    return;
657  RefreshNetworkData();
658}
659
660void InternetOptionsHandler::NetworkConnectionStateChanged(
661    const NetworkState* network) {
662  if (!web_ui())
663    return;
664  if (network->path() == details_path_)
665    UpdateConnectionData(network->path());
666}
667
668void InternetOptionsHandler::NetworkPropertiesUpdated(
669    const NetworkState* network) {
670  if (!web_ui())
671    return;
672  RefreshNetworkData();
673  if (network->path() == details_path_)
674    UpdateConnectionData(network->path());
675}
676
677void InternetOptionsHandler::DevicePropertiesUpdated(
678    const DeviceState* device) {
679  if (!web_ui())
680    return;
681  if (device->type() != shill::kTypeCellular)
682    return;
683  const NetworkState* network =
684      NetworkHandler::Get()->network_state_handler()->FirstNetworkByType(
685          NetworkTypePattern::Cellular());
686  if (network && network->path() == details_path_)
687    UpdateConnectionData(network->path());
688}
689
690void InternetOptionsHandler::SetServerHostnameCallback(
691    const base::ListValue* args) {
692  std::string service_path, server_hostname;
693  if (args->GetSize() < 2 ||
694      !args->GetString(0, &service_path) ||
695      !args->GetString(1, &server_hostname)) {
696    NOTREACHED();
697    return;
698  }
699  SetNetworkProperty(service_path,
700                     shill::kProviderHostProperty,
701                     new base::StringValue(server_hostname));
702}
703
704void InternetOptionsHandler::SetPreferNetworkCallback(
705    const base::ListValue* args) {
706  std::string service_path, prefer_network_str;
707  if (args->GetSize() < 2 ||
708      !args->GetString(0, &service_path) ||
709      !args->GetString(1, &prefer_network_str)) {
710    NOTREACHED();
711    return;
712  }
713  int priority = (prefer_network_str == kTagTrue) ? kPreferredPriority : 0;
714  SetNetworkProperty(service_path,
715                     shill::kPriorityProperty,
716                     new base::FundamentalValue(priority));
717}
718
719void InternetOptionsHandler::SetAutoConnectCallback(
720    const base::ListValue* args) {
721  std::string service_path, auto_connect_str;
722  if (args->GetSize() < 2 ||
723      !args->GetString(0, &service_path) ||
724      !args->GetString(1, &auto_connect_str)) {
725    NOTREACHED();
726    return;
727  }
728  bool auto_connect = auto_connect_str == kTagTrue;
729  SetNetworkProperty(service_path,
730                     shill::kAutoConnectProperty,
731                     new base::FundamentalValue(auto_connect));
732}
733
734void InternetOptionsHandler::SetIPConfigCallback(const base::ListValue* args) {
735  std::string service_path;
736  if (!args->GetString(0, &service_path)) {
737    NOTREACHED();
738    return;
739  }
740  NetworkHandler::Get()->network_configuration_handler()->GetProperties(
741      service_path,
742      base::Bind(&InternetOptionsHandler::SetIPConfigProperties,
743                 weak_factory_.GetWeakPtr(), base::Owned(args->DeepCopy())),
744      base::Bind(&ShillError, "SetIPConfigCallback"));
745}
746
747void InternetOptionsHandler::SetIPConfigProperties(
748    const base::ListValue* args,
749    const std::string& service_path,
750    const base::DictionaryValue& shill_properties) {
751  std::string address, netmask, gateway, name_server_type, name_servers;
752  bool dhcp_for_ip;
753  if (!args->GetBoolean(1, &dhcp_for_ip) ||
754      !args->GetString(2, &address) ||
755      !args->GetString(3, &netmask) ||
756      !args->GetString(4, &gateway) ||
757      !args->GetString(5, &name_server_type) ||
758      !args->GetString(6, &name_servers)) {
759    NOTREACHED();
760    return;
761  }
762  NET_LOG_USER("SetIPConfigProperties: " + name_server_type, service_path);
763
764  std::vector<std::string> properties_to_clear;
765  base::DictionaryValue properties_to_set;
766
767  if (dhcp_for_ip) {
768    AppendPropertyKeyIfPresent(shill::kStaticIPAddressProperty,
769                               shill_properties,
770                               &properties_to_clear);
771    AppendPropertyKeyIfPresent(shill::kStaticIPPrefixlenProperty,
772                               shill_properties,
773                               &properties_to_clear);
774    AppendPropertyKeyIfPresent(shill::kStaticIPGatewayProperty,
775                               shill_properties,
776                               &properties_to_clear);
777  } else {
778    AddStringPropertyIfChanged(shill::kStaticIPAddressProperty,
779                               address,
780                               shill_properties,
781                               &properties_to_set);
782    int prefixlen = network_util::NetmaskToPrefixLength(netmask);
783    if (prefixlen < 0) {
784      LOG(ERROR) << "Invalid prefix length for: " << service_path
785                 << " with netmask " << netmask;
786      prefixlen = 0;
787    }
788    AddIntegerPropertyIfChanged(shill::kStaticIPPrefixlenProperty,
789                                prefixlen,
790                                shill_properties,
791                                &properties_to_set);
792    AddStringPropertyIfChanged(shill::kStaticIPGatewayProperty,
793                               gateway,
794                               shill_properties,
795                               &properties_to_set);
796  }
797
798  if (name_server_type == kNameServerTypeAutomatic) {
799    AppendPropertyKeyIfPresent(shill::kStaticIPNameServersProperty,
800                               shill_properties,
801                               &properties_to_clear);
802  } else {
803    if (name_server_type == kNameServerTypeGoogle)
804      name_servers = kGoogleNameServers;
805    AddStringPropertyIfChanged(shill::kStaticIPNameServersProperty,
806                               name_servers,
807                               shill_properties,
808                               &properties_to_set);
809  }
810
811  if (!properties_to_clear.empty()) {
812    NetworkHandler::Get()->network_configuration_handler()->ClearProperties(
813        service_path,
814        properties_to_clear,
815        base::Bind(&base::DoNothing),
816        base::Bind(&ShillError, "ClearIPConfigProperties"));
817  }
818  if (!properties_to_set.empty()) {
819    NetworkHandler::Get()->network_configuration_handler()->SetProperties(
820        service_path,
821        properties_to_set,
822        base::Bind(&base::DoNothing),
823        base::Bind(&ShillError, "SetIPConfigProperties"));
824  }
825  std::string device_path;
826  shill_properties.GetStringWithoutPathExpansion(shill::kDeviceProperty,
827                                                 &device_path);
828  if (!device_path.empty()) {
829    NetworkHandler::Get()->network_device_handler()->RequestRefreshIPConfigs(
830        device_path,
831        base::Bind(&base::DoNothing),
832        base::Bind(&ShillError, "RequestRefreshIPConfigs"));
833  }
834}
835
836void InternetOptionsHandler::PopulateDictionaryDetailsCallback(
837    const std::string& service_path,
838    const base::DictionaryValue& onc_properties) {
839  const NetworkState* network = GetNetworkState(service_path);
840  if (!network) {
841    LOG(ERROR) << "Network properties not found: " << service_path;
842    return;
843  }
844  scoped_ptr<base::DictionaryValue> dictionary =
845      PopulateConnectionDetails(network, onc_properties);
846
847  // Show details dialog
848  web_ui()->CallJavascriptFunction(kSendNetworkDetailsFunction, *dictionary);
849}
850
851gfx::NativeWindow InternetOptionsHandler::GetNativeWindow() const {
852  return web_ui()->GetWebContents()->GetTopLevelNativeWindow();
853}
854
855float InternetOptionsHandler::GetScaleFactor() const {
856  return web_ui()->GetDeviceScaleFactor();
857}
858
859const PrefService* InternetOptionsHandler::GetPrefs() const {
860  return Profile::FromWebUI(web_ui())->GetPrefs();
861}
862
863void InternetOptionsHandler::NetworkCommandCallback(
864    const base::ListValue* args) {
865  std::string onc_type;
866  std::string service_path;
867  std::string command;
868  if (args->GetSize() != 3 ||
869      !args->GetString(0, &onc_type) ||
870      !args->GetString(1, &service_path) ||
871      !args->GetString(2, &command)) {
872    NOTREACHED();
873    return;
874  }
875  std::string type;  // Shill type
876  if (!onc_type.empty()) {
877    type = network_util::TranslateONCTypeToShill(onc_type);
878    if (type.empty())
879      LOG(ERROR) << "Unable to translate ONC type: " << onc_type;
880  }
881  // Process commands that do not require an existing network.
882  if (command == kTagAddConnection) {
883    AddConnection(type);
884  } else if (command == kTagForget) {
885    NetworkHandler::Get()->network_configuration_handler()->
886        RemoveConfiguration(
887            service_path,
888            base::Bind(&base::DoNothing),
889            base::Bind(&ShillError, "NetworkCommand: " + command));
890  } else if (command == kTagShowDetails) {
891    SendShowDetailedInfo(service_path);
892  } else if (command == kTagConfigure) {
893    NetworkConfigView::Show(service_path, GetNativeWindow());
894  } else if (command == kTagActivate && type == shill::kTypeCellular) {
895    ash::network_connect::ActivateCellular(service_path);
896    // Activation may update network properties (e.g. ActivationState), so
897    // request them here in case they change.
898    UpdateConnectionData(service_path);
899  } else {
900    LOG(ERROR) << "Unknown internet options command: " << command;
901    NOTREACHED();
902  }
903}
904
905void InternetOptionsHandler::AddConnection(const std::string& type) {
906  if (type == shill::kTypeWifi) {
907    NetworkConfigView::ShowForType(shill::kTypeWifi, GetNativeWindow());
908  } else if (type == shill::kTypeVPN) {
909    NetworkConfigView::ShowForType(shill::kTypeVPN, GetNativeWindow());
910  } else if (type == shill::kTypeCellular) {
911    ChooseMobileNetworkDialog::ShowDialog(GetNativeWindow());
912  } else {
913    LOG(ERROR) << "Unsupported type for AddConnection";
914  }
915}
916
917void InternetOptionsHandler::SendShowDetailedInfo(
918    const std::string& service_path) {
919  details_path_ = service_path;
920
921  scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue);
922  const NetworkState* network = GetNetworkState(service_path);
923  if (network) {
924    dictionary->SetString(kNetworkInfoKeyServicePath, service_path);
925    dictionary->SetString(kNetworkInfoKeyGUID, network->guid());
926    if (network->type() == shill::kTypeCellular) {
927      dictionary->SetBoolean(
928          kTagCarrierSelectFlag,
929          CommandLine::ForCurrentProcess()
930          ->HasSwitch(chromeos::switches::kEnableCarrierSwitching));
931      dictionary->SetBoolean(kTagShowViewAccountButton,
932                             ShowViewAccountButton(network));
933    }
934  }
935  web_ui()->CallJavascriptFunction(kShowDetailedInfoFunction, *dictionary);
936}
937
938base::ListValue* InternetOptionsHandler::GetWiredList() {
939  base::ListValue* list = new base::ListValue();
940  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
941      FirstNetworkByType(NetworkTypePattern::Ethernet());
942  if (!network)
943    return list;
944  list->Append(BuildNetworkDictionary(network, GetScaleFactor(), GetPrefs()));
945  return list;
946}
947
948base::ListValue* InternetOptionsHandler::GetWirelessList() {
949  base::ListValue* list = new base::ListValue();
950
951  NetworkStateHandler::NetworkStateList networks;
952  NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkListByType(
953      NetworkTypePattern::Wireless(), &networks);
954  for (NetworkStateHandler::NetworkStateList::const_iterator iter =
955           networks.begin(); iter != networks.end(); ++iter) {
956    list->Append(BuildNetworkDictionary(*iter, GetScaleFactor(), GetPrefs()));
957  }
958
959  return list;
960}
961
962base::ListValue* InternetOptionsHandler::GetVPNList() {
963  base::ListValue* list = new base::ListValue();
964
965  NetworkStateHandler::NetworkStateList networks;
966  NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkListByType(
967      NetworkTypePattern::VPN(), &networks);
968  for (NetworkStateHandler::NetworkStateList::const_iterator iter =
969           networks.begin(); iter != networks.end(); ++iter) {
970    list->Append(BuildNetworkDictionary(*iter, GetScaleFactor(), GetPrefs()));
971  }
972
973  return list;
974}
975
976base::ListValue* InternetOptionsHandler::GetRememberedList() {
977  base::ListValue* list = new base::ListValue();
978
979  NetworkStateHandler::NetworkStateList networks;
980  NetworkHandler::Get()->network_state_handler()->GetNetworkListByType(
981      NetworkTypePattern::Default(),
982      true /* configured_only */,
983      false /* visible_only */,
984      0 /* no limit */,
985      &networks);
986  for (NetworkStateHandler::NetworkStateList::const_iterator iter =
987           networks.begin(); iter != networks.end(); ++iter) {
988    const NetworkState* network = *iter;
989    if (network->type() != shill::kTypeWifi &&
990        network->type() != shill::kTypeVPN)
991      continue;
992    list->Append(
993        BuildNetworkDictionary(network,
994                               web_ui()->GetDeviceScaleFactor(),
995                               Profile::FromWebUI(web_ui())->GetPrefs()));
996  }
997
998  return list;
999}
1000
1001void InternetOptionsHandler::FillNetworkInfo(
1002    base::DictionaryValue* dictionary) {
1003  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
1004  dictionary->Set(kTagWiredList, GetWiredList());
1005  dictionary->Set(kTagWirelessList, GetWirelessList());
1006  dictionary->Set(kTagVpnList, GetVPNList());
1007  dictionary->Set(kTagRememberedList, GetRememberedList());
1008
1009  dictionary->SetBoolean(
1010      kTagWifiAvailable,
1011      handler->IsTechnologyAvailable(NetworkTypePattern::WiFi()));
1012  dictionary->SetBoolean(
1013      kTagWifiEnabled,
1014      handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()));
1015
1016  const DeviceState* cellular =
1017      handler->GetDeviceStateByType(NetworkTypePattern::Mobile());
1018  dictionary->SetBoolean(
1019      kTagCellularAvailable,
1020      handler->IsTechnologyAvailable(NetworkTypePattern::Mobile()));
1021  dictionary->SetBoolean(
1022      kTagCellularEnabled,
1023      handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()));
1024  dictionary->SetBoolean(kTagCellularSupportsScan,
1025                         cellular && cellular->support_network_scan());
1026  dictionary->SetBoolean(kTagCellularSimAbsent,
1027                         cellular && cellular->IsSimAbsent());
1028  dictionary->SetString(kTagCellularSimLockType,
1029                        cellular ? cellular->sim_lock_type() : "");
1030
1031  dictionary->SetBoolean(
1032      kTagWimaxAvailable,
1033      handler->IsTechnologyAvailable(NetworkTypePattern::Wimax()));
1034  dictionary->SetBoolean(
1035      kTagWimaxEnabled,
1036      handler->IsTechnologyEnabled(NetworkTypePattern::Wimax()));
1037}
1038
1039}  // namespace options
1040}  // namespace chromeos
1041