ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chromeos / network / shill_property_util.cc
blob2e77fb70c92716df487cec63ef5603079c51edd4
1 // Copyright 2013 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.
5 #include "chromeos/network/shill_property_util.h"
7 #include "base/i18n/icu_encoding_detection.h"
8 #include "base/i18n/icu_string_conversions.h"
9 #include "base/json/json_writer.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversion_utils.h"
14 #include "base/values.h"
15 #include "chromeos/network/network_ui_data.h"
16 #include "chromeos/network/onc/onc_utils.h"
17 #include "components/device_event_log/device_event_log.h"
18 #include "third_party/cros_system_api/dbus/service_constants.h"
20 namespace chromeos {
22 namespace shill_property_util {
24 namespace {
26 // Replace non UTF8 characters in |str| with a replacement character.
27 std::string ValidateUTF8(const std::string& str) {
28 std::string result;
29 for (int32 index = 0; index < static_cast<int32>(str.size()); ++index) {
30 uint32 code_point_out;
31 bool is_unicode_char = base::ReadUnicodeCharacter(
32 str.c_str(), str.size(), &index, &code_point_out);
33 const uint32 kFirstNonControlChar = 0x20;
34 if (is_unicode_char && (code_point_out >= kFirstNonControlChar)) {
35 base::WriteUnicodeCharacter(code_point_out, &result);
36 } else {
37 const uint32 kReplacementChar = 0xFFFD;
38 // Puts kReplacementChar if character is a control character [0,0x20)
39 // or is not readable UTF8.
40 base::WriteUnicodeCharacter(kReplacementChar, &result);
43 return result;
46 // If existent and non-empty, copies the string at |key| from |source| to
47 // |dest|. Returns true if the string was copied.
48 bool CopyStringFromDictionary(const base::DictionaryValue& source,
49 const std::string& key,
50 base::DictionaryValue* dest) {
51 std::string string_value;
52 if (!source.GetStringWithoutPathExpansion(key, &string_value) ||
53 string_value.empty()) {
54 return false;
56 dest->SetStringWithoutPathExpansion(key, string_value);
57 return true;
60 } // namespace
62 void SetSSID(const std::string ssid, base::DictionaryValue* properties) {
63 std::string hex_ssid = base::HexEncode(ssid.c_str(), ssid.size());
64 properties->SetStringWithoutPathExpansion(shill::kWifiHexSsid, hex_ssid);
67 std::string GetSSIDFromProperties(const base::DictionaryValue& properties,
68 bool verbose_logging,
69 bool* unknown_encoding) {
70 if (unknown_encoding)
71 *unknown_encoding = false;
73 // Get name for debugging.
74 std::string name;
75 properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
77 std::string hex_ssid;
78 properties.GetStringWithoutPathExpansion(shill::kWifiHexSsid, &hex_ssid);
80 if (hex_ssid.empty()) {
81 if (verbose_logging)
82 NET_LOG(DEBUG) << "GetSSIDFromProperties: No HexSSID set: " << name;
83 return std::string();
86 std::string ssid;
87 std::vector<uint8> raw_ssid_bytes;
88 if (base::HexStringToBytes(hex_ssid, &raw_ssid_bytes)) {
89 ssid = std::string(raw_ssid_bytes.begin(), raw_ssid_bytes.end());
90 VLOG(2) << "GetSSIDFromProperties: " << name << " HexSsid=" << hex_ssid
91 << " SSID=" << ssid;
92 } else {
93 NET_LOG(ERROR) << "GetSSIDFromProperties: " << name
94 << " Error processing HexSsid: " << hex_ssid;
95 return std::string();
98 if (base::IsStringUTF8(ssid))
99 return ssid;
101 // Detect encoding and convert to UTF-8.
102 std::string encoding;
103 if (!base::DetectEncoding(ssid, &encoding)) {
104 // TODO(stevenjb): This is currently experimental. If we find a case where
105 // base::DetectEncoding() fails, we need to figure out whether we can use
106 // country_code with ConvertToUtf8(). crbug.com/233267.
107 properties.GetStringWithoutPathExpansion(shill::kCountryProperty,
108 &encoding);
110 std::string utf8_ssid;
111 if (!encoding.empty() &&
112 base::ConvertToUtf8AndNormalize(ssid, encoding, &utf8_ssid)) {
113 if (utf8_ssid != ssid) {
114 if (verbose_logging) {
115 NET_LOG(DEBUG) << "GetSSIDFromProperties: " << name
116 << " Encoding=" << encoding << " SSID=" << ssid
117 << " UTF8 SSID=" << utf8_ssid;
120 return utf8_ssid;
123 if (unknown_encoding)
124 *unknown_encoding = true;
125 if (verbose_logging) {
126 NET_LOG(DEBUG) << "GetSSIDFromProperties: " << name
127 << " Unrecognized Encoding=" << encoding;
129 return ssid;
132 std::string GetNetworkIdFromProperties(
133 const base::DictionaryValue& properties) {
134 if (properties.empty())
135 return "EmptyProperties";
136 std::string result;
137 if (properties.GetStringWithoutPathExpansion(shill::kGuidProperty, &result))
138 return result;
139 if (properties.GetStringWithoutPathExpansion(shill::kSSIDProperty, &result))
140 return result;
141 if (properties.GetStringWithoutPathExpansion(shill::kNameProperty, &result))
142 return result;
143 std::string type = "UnknownType";
144 properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
145 return "Unidentified " + type;
148 std::string GetNameFromProperties(const std::string& service_path,
149 const base::DictionaryValue& properties) {
150 std::string name;
151 properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
153 std::string validated_name = ValidateUTF8(name);
154 if (validated_name != name) {
155 NET_LOG(DEBUG) << "GetNameFromProperties: " << service_path
156 << " Validated name=" << validated_name << " name=" << name;
159 std::string type;
160 properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
161 if (type.empty()) {
162 NET_LOG(ERROR) << "GetNameFromProperties: " << service_path << " No type.";
163 return validated_name;
165 if (!NetworkTypePattern::WiFi().MatchesType(type))
166 return validated_name;
168 bool unknown_ssid_encoding = false;
169 std::string ssid = GetSSIDFromProperties(
170 properties, true /* verbose_logging */, &unknown_ssid_encoding);
171 if (ssid.empty()) {
172 NET_LOG(ERROR) << "GetNameFromProperties: " << service_path
173 << " No SSID set";
176 // Use |validated_name| if |ssid| is empty.
177 // And if the encoding of the SSID is unknown, use |ssid|, which contains raw
178 // bytes in that case, only if |validated_name| is empty.
179 if (ssid.empty() || (unknown_ssid_encoding && !validated_name.empty()))
180 return validated_name;
182 if (ssid != validated_name) {
183 NET_LOG(DEBUG) << "GetNameFromProperties: " << service_path
184 << " SSID=" << ssid << " Validated name=" << validated_name;
186 return ssid;
189 scoped_ptr<NetworkUIData> GetUIDataFromValue(const base::Value& ui_data_value) {
190 std::string ui_data_str;
191 if (!ui_data_value.GetAsString(&ui_data_str))
192 return scoped_ptr<NetworkUIData>();
193 if (ui_data_str.empty())
194 return make_scoped_ptr(new NetworkUIData());
195 scoped_ptr<base::DictionaryValue> ui_data_dict(
196 chromeos::onc::ReadDictionaryFromJson(ui_data_str));
197 if (!ui_data_dict)
198 return scoped_ptr<NetworkUIData>();
199 return make_scoped_ptr(new NetworkUIData(*ui_data_dict));
202 scoped_ptr<NetworkUIData> GetUIDataFromProperties(
203 const base::DictionaryValue& shill_dictionary) {
204 const base::Value* ui_data_value = NULL;
205 shill_dictionary.GetWithoutPathExpansion(shill::kUIDataProperty,
206 &ui_data_value);
207 if (!ui_data_value) {
208 VLOG(2) << "Dictionary has no UIData entry.";
209 return scoped_ptr<NetworkUIData>();
211 scoped_ptr<NetworkUIData> ui_data = GetUIDataFromValue(*ui_data_value);
212 if (!ui_data)
213 LOG(ERROR) << "UIData is not a valid JSON dictionary.";
214 return ui_data.Pass();
217 void SetUIData(const NetworkUIData& ui_data,
218 base::DictionaryValue* shill_dictionary) {
219 base::DictionaryValue ui_data_dict;
220 ui_data.FillDictionary(&ui_data_dict);
221 std::string ui_data_blob;
222 base::JSONWriter::Write(&ui_data_dict, &ui_data_blob);
223 shill_dictionary->SetStringWithoutPathExpansion(shill::kUIDataProperty,
224 ui_data_blob);
227 bool CopyIdentifyingProperties(const base::DictionaryValue& service_properties,
228 const bool properties_read_from_shill,
229 base::DictionaryValue* dest) {
230 bool success = true;
232 // GUID is optional.
233 CopyStringFromDictionary(service_properties, shill::kGuidProperty, dest);
235 std::string type;
236 service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
237 success &= !type.empty();
238 dest->SetStringWithoutPathExpansion(shill::kTypeProperty, type);
239 if (type == shill::kTypeWifi) {
240 success &=
241 CopyStringFromDictionary(
242 service_properties, shill::kSecurityClassProperty, dest);
243 success &=
244 CopyStringFromDictionary(service_properties, shill::kWifiHexSsid, dest);
245 success &= CopyStringFromDictionary(
246 service_properties, shill::kModeProperty, dest);
247 } else if (type == shill::kTypeCellular) {
248 success &= CopyStringFromDictionary(
249 service_properties, shill::kNetworkTechnologyProperty, dest);
250 } else if (type == shill::kTypeVPN) {
251 success &= CopyStringFromDictionary(
252 service_properties, shill::kNameProperty, dest);
254 // VPN Provider values are read from the "Provider" dictionary, but written
255 // with the keys "Provider.Type" and "Provider.Host".
256 // TODO(pneubeck): Simplify this once http://crbug.com/381135 is fixed.
257 std::string vpn_provider_type;
258 std::string vpn_provider_host;
259 if (properties_read_from_shill) {
260 const base::DictionaryValue* provider_properties = NULL;
261 if (!service_properties.GetDictionaryWithoutPathExpansion(
262 shill::kProviderProperty, &provider_properties)) {
263 NET_LOG(ERROR) << "Missing VPN provider dict: "
264 << GetNetworkIdFromProperties(service_properties);
266 provider_properties->GetStringWithoutPathExpansion(shill::kTypeProperty,
267 &vpn_provider_type);
268 provider_properties->GetStringWithoutPathExpansion(shill::kHostProperty,
269 &vpn_provider_host);
270 } else {
271 service_properties.GetStringWithoutPathExpansion(
272 shill::kProviderTypeProperty, &vpn_provider_type);
273 service_properties.GetStringWithoutPathExpansion(
274 shill::kProviderHostProperty, &vpn_provider_host);
276 success &= !vpn_provider_type.empty();
277 dest->SetStringWithoutPathExpansion(shill::kProviderTypeProperty,
278 vpn_provider_type);
280 success &= !vpn_provider_host.empty();
281 dest->SetStringWithoutPathExpansion(shill::kProviderHostProperty,
282 vpn_provider_host);
283 } else if (type == shill::kTypeEthernet || type == shill::kTypeEthernetEap) {
284 // Ethernet and EthernetEAP don't have any additional identifying
285 // properties.
286 } else {
287 NOTREACHED() << "Unsupported network type " << type;
288 success = false;
290 if (!success) {
291 NET_LOG(ERROR) << "Missing required properties: "
292 << GetNetworkIdFromProperties(service_properties);
294 return success;
297 bool DoIdentifyingPropertiesMatch(const base::DictionaryValue& new_properties,
298 const base::DictionaryValue& old_properties) {
299 base::DictionaryValue new_identifying;
300 if (!CopyIdentifyingProperties(
301 new_properties,
302 false /* properties were not read from Shill */,
303 &new_identifying)) {
304 return false;
306 base::DictionaryValue old_identifying;
307 if (!CopyIdentifyingProperties(old_properties,
308 true /* properties were read from Shill */,
309 &old_identifying)) {
310 return false;
313 return new_identifying.Equals(&old_identifying);
316 bool IsPassphraseKey(const std::string& key) {
317 return key == shill::kEapPrivateKeyPasswordProperty ||
318 key == shill::kEapPasswordProperty ||
319 key == shill::kL2tpIpsecPasswordProperty ||
320 key == shill::kOpenVPNPasswordProperty ||
321 key == shill::kOpenVPNAuthUserPassProperty ||
322 key == shill::kOpenVPNTLSAuthContentsProperty ||
323 key == shill::kPassphraseProperty ||
324 key == shill::kOpenVPNOTPProperty ||
325 key == shill::kEapPrivateKeyProperty ||
326 key == shill::kEapPinProperty ||
327 key == shill::kApnPasswordProperty;
330 bool GetHomeProviderFromProperty(const base::Value& value,
331 std::string* home_provider_id) {
332 const base::DictionaryValue* dict = NULL;
333 if (!value.GetAsDictionary(&dict))
334 return false;
335 std::string home_provider_country;
336 std::string home_provider_name;
337 dict->GetStringWithoutPathExpansion(shill::kOperatorCountryKey,
338 &home_provider_country);
339 dict->GetStringWithoutPathExpansion(shill::kOperatorNameKey,
340 &home_provider_name);
341 // Set home_provider_id
342 if (!home_provider_name.empty() && !home_provider_country.empty()) {
343 *home_provider_id = base::StringPrintf(
344 "%s (%s)", home_provider_name.c_str(), home_provider_country.c_str());
345 } else {
346 if (!dict->GetStringWithoutPathExpansion(shill::kOperatorCodeKey,
347 home_provider_id)) {
348 return false;
350 LOG(WARNING)
351 << "Provider name and country not defined, using code instead: "
352 << *home_provider_id;
354 return true;
357 } // namespace shill_property_util
359 } // namespace chromeos