OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "chromeos/network/shill_property_util.h" | |
6 | |
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_event_log.h" | |
16 #include "chromeos/network/network_ui_data.h" | |
17 #include "chromeos/network/onc/onc_utils.h" | |
18 #include "third_party/cros_system_api/dbus/service_constants.h" | |
19 | |
20 namespace chromeos { | |
21 | |
22 namespace shill_property_util { | |
23 | |
24 namespace { | |
25 | |
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); | |
41 } | |
42 } | |
43 return result; | |
44 } | |
45 | |
46 void CopyStringFromDictionary(const base::DictionaryValue& source, | |
47 const std::string& key, | |
48 base::DictionaryValue* dest) { | |
49 std::string string_value; | |
50 if (source.GetStringWithoutPathExpansion(key, &string_value)) | |
51 dest->SetStringWithoutPathExpansion(key, string_value); | |
52 } | |
53 | |
54 } // namespace | |
55 | |
56 std::string GetNameFromProperties(const std::string& service_path, | |
57 const base::DictionaryValue& properties) { | |
58 std::string name, hex_ssid; | |
59 properties.GetStringWithoutPathExpansion(flimflam::kNameProperty, &name); | |
60 properties.GetStringWithoutPathExpansion(flimflam::kWifiHexSsid, &hex_ssid); | |
61 | |
62 if (hex_ssid.empty()) { | |
63 if (name.empty()) | |
64 return name; | |
65 // Validate name for UTF8. | |
66 std::string valid_ssid = ValidateUTF8(name); | |
67 if (valid_ssid != name) { | |
68 NET_LOG_DEBUG( | |
69 "GetNameFromProperties", | |
70 base::StringPrintf( | |
71 "%s: UTF8: %s", service_path.c_str(), valid_ssid.c_str())); | |
72 } | |
73 return valid_ssid; | |
74 } | |
75 | |
76 std::string ssid; | |
77 std::vector<uint8> raw_ssid_bytes; | |
78 if (base::HexStringToBytes(hex_ssid, &raw_ssid_bytes)) { | |
79 ssid = std::string(raw_ssid_bytes.begin(), raw_ssid_bytes.end()); | |
80 NET_LOG_DEBUG("GetNameFromProperties", | |
81 base::StringPrintf("%s: %s, SSID: %s", | |
82 service_path.c_str(), | |
83 hex_ssid.c_str(), | |
84 ssid.c_str())); | |
85 } else { | |
86 NET_LOG_ERROR("GetNameFromProperties", | |
87 base::StringPrintf("%s: Error processing: %s", | |
88 service_path.c_str(), | |
89 hex_ssid.c_str())); | |
90 return name; | |
91 } | |
92 | |
93 if (IsStringUTF8(ssid)) { | |
94 if (ssid != name) { | |
95 NET_LOG_DEBUG("GetNameFromProperties", | |
96 base::StringPrintf( | |
97 "%s: UTF8: %s", service_path.c_str(), ssid.c_str())); | |
98 } | |
99 return ssid; | |
100 } | |
101 | |
102 // Detect encoding and convert to UTF-8. | |
103 std::string country_code; | |
104 properties.GetStringWithoutPathExpansion(flimflam::kCountryProperty, | |
105 &country_code); | |
106 std::string encoding; | |
107 if (!base::DetectEncoding(ssid, &encoding)) { | |
108 // TODO(stevenjb): This is currently experimental. If we find a case where | |
109 // base::DetectEncoding() fails, we need to figure out whether we can use | |
110 // country_code with ConvertToUtf8(). crbug.com/233267. | |
111 encoding = country_code; | |
112 } | |
113 if (!encoding.empty()) { | |
114 std::string utf8_ssid; | |
115 if (base::ConvertToUtf8AndNormalize(ssid, encoding, &utf8_ssid)) { | |
116 if (utf8_ssid != name) { | |
117 NET_LOG_DEBUG("GetNameFromProperties", | |
118 base::StringPrintf("%s: Encoding=%s: %s", | |
119 service_path.c_str(), | |
120 encoding.c_str(), | |
121 utf8_ssid.c_str())); | |
122 } | |
123 return utf8_ssid; | |
124 } | |
125 } | |
126 | |
127 // Unrecognized encoding. Only use raw bytes if name_ is empty. | |
128 NET_LOG_DEBUG("GetNameFromProperties", | |
129 base::StringPrintf("%s: Unrecognized Encoding=%s: %s", | |
130 service_path.c_str(), | |
131 encoding.c_str(), | |
132 ssid.c_str())); | |
133 if (name.empty() && !ssid.empty()) | |
134 return ssid; | |
135 return name; | |
136 } | |
137 | |
138 bool GetUIDataFromValue(const base::Value& ui_data_value, NetworkUIData* out) { | |
139 std::string ui_data_str; | |
140 if (!ui_data_value.GetAsString(&ui_data_str)) | |
141 return false; | |
142 if (ui_data_str.empty()) { | |
143 *out = NetworkUIData(); | |
144 return true; | |
145 } | |
146 scoped_ptr<base::DictionaryValue> ui_data_dict( | |
147 chromeos::onc::ReadDictionaryFromJson(ui_data_str)); | |
148 if (!ui_data_dict) | |
149 return false; | |
150 *out = NetworkUIData(*ui_data_dict); | |
151 return true; | |
152 } | |
153 | |
154 scoped_ptr<NetworkUIData> GetUIData( | |
155 const base::DictionaryValue& shill_dictionary) { | |
156 const base::Value* ui_data_value = NULL; | |
157 shill_dictionary.GetWithoutPathExpansion(flimflam::kUIDataProperty, | |
158 &ui_data_value); | |
159 if (ui_data_value) { | |
160 scoped_ptr<NetworkUIData> ui_data(new NetworkUIData); | |
161 if (GetUIDataFromValue(*ui_data_value, ui_data.get())) | |
162 return ui_data.Pass(); | |
163 else | |
stevenjb
2013/08/28 15:33:54
no else
pneubeck (no reviews)
2013/09/02 13:39:54
Done.
| |
164 LOG(ERROR) << "UIData is not a valid JSON dictionary."; | |
165 } else { | |
166 VLOG(2) << "Dictionary has no UIData entry."; | |
167 } | |
168 return scoped_ptr<NetworkUIData>(); | |
169 } | |
170 | |
171 void SetUIData(const NetworkUIData& ui_data, | |
172 base::DictionaryValue* shill_dictionary) { | |
173 base::DictionaryValue ui_data_dict; | |
174 ui_data.FillDictionary(&ui_data_dict); | |
175 std::string ui_data_blob; | |
176 base::JSONWriter::Write(&ui_data_dict, &ui_data_blob); | |
177 shill_dictionary->SetStringWithoutPathExpansion(flimflam::kUIDataProperty, | |
178 ui_data_blob); | |
179 } | |
180 | |
181 bool CopyIdentifyingProperties(const base::DictionaryValue& service_properties, | |
182 base::DictionaryValue* dest) { | |
183 CopyStringFromDictionary(service_properties, flimflam::kGuidProperty, dest); | |
184 | |
185 std::string type; | |
186 service_properties.GetStringWithoutPathExpansion(flimflam::kTypeProperty, | |
187 &type); | |
188 dest->SetStringWithoutPathExpansion(flimflam::kTypeProperty, type); | |
189 if (type == flimflam::kTypeWifi) { | |
190 CopyStringFromDictionary( | |
191 service_properties, flimflam::kSecurityProperty, dest); | |
192 CopyStringFromDictionary(service_properties, flimflam::kSSIDProperty, dest); | |
193 CopyStringFromDictionary(service_properties, flimflam::kModeManaged, dest); | |
194 } else if (type == flimflam::kTypeVPN) { | |
195 CopyStringFromDictionary(service_properties, flimflam::kNameProperty, dest); | |
196 // VPN Provider values are read from the "Provider" dictionary, but written | |
197 // with the keys "Provider.Type" and "Provider.Host". | |
198 const base::DictionaryValue* provider_properties; | |
199 if (!service_properties.GetDictionaryWithoutPathExpansion( | |
200 flimflam::kProviderProperty, &provider_properties)) { | |
201 LOG(ERROR) << "Incomplete Shill dictionary missing VPN provider dict."; | |
202 return false; | |
203 } | |
204 std::string vpn_provider_type; | |
205 provider_properties->GetStringWithoutPathExpansion(flimflam::kTypeProperty, | |
206 &vpn_provider_type); | |
207 dest->SetStringWithoutPathExpansion(flimflam::kProviderTypeProperty, | |
208 vpn_provider_type); | |
209 | |
210 std::string vpn_provider_host; | |
211 provider_properties->GetStringWithoutPathExpansion(flimflam::kHostProperty, | |
212 &vpn_provider_host); | |
213 dest->SetStringWithoutPathExpansion(flimflam::kProviderHostProperty, | |
214 vpn_provider_host); | |
215 } else if (type == flimflam::kTypeEthernet || | |
216 type == shill::kTypeEthernetEap) { | |
stevenjb
2013/08/28 15:33:54
I think we should add something like shill_propert
| |
217 // Ethernet and EthernetEAP don't have any additional identifying | |
218 // properties. | |
219 } else { | |
220 NOTREACHED() << "Unsupported network type " << type; | |
221 } | |
222 return true; | |
223 } | |
224 | |
225 } // namespace shill_property_util | |
226 | |
227 } // namespace chromeos | |
OLD | NEW |