Some additional network settings cleanup
[chromium-blink-merge.git] / chromeos / network / onc / onc_translator_shill_to_onc.cc
blobd7bc265e0ceeb9de0d75f9f703239e96c2a6a3e9
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.
5 #include "chromeos/network/onc/onc_translator.h"
7 #include <string>
9 #include "base/basictypes.h"
10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h"
12 #include "base/logging.h"
13 #include "base/strings/string_util.h"
14 #include "base/values.h"
15 #include "chromeos/network/network_profile_handler.h"
16 #include "chromeos/network/network_state.h"
17 #include "chromeos/network/network_util.h"
18 #include "chromeos/network/onc/onc_signature.h"
19 #include "chromeos/network/onc/onc_translation_tables.h"
20 #include "chromeos/network/shill_property_util.h"
21 #include "components/onc/onc_constants.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
24 namespace chromeos {
25 namespace onc {
27 namespace {
29 // Converts |str| to a base::Value of the given |type|. If the conversion fails,
30 // returns NULL.
31 scoped_ptr<base::Value> ConvertStringToValue(const std::string& str,
32 base::Value::Type type) {
33 base::Value* value;
34 if (type == base::Value::TYPE_STRING) {
35 value = new base::StringValue(str);
36 } else {
37 value = base::JSONReader::Read(str);
40 if (value == NULL || value->GetType() != type) {
41 delete value;
42 value = NULL;
44 return make_scoped_ptr(value);
47 // This class implements the translation of properties from the given
48 // |shill_dictionary| to a new ONC object of signature |onc_signature|. Using
49 // recursive calls to CreateTranslatedONCObject of new instances, nested objects
50 // are translated.
51 class ShillToONCTranslator {
52 public:
53 ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
54 ::onc::ONCSource onc_source,
55 const OncValueSignature& onc_signature)
56 : shill_dictionary_(&shill_dictionary),
57 onc_source_(onc_source),
58 onc_signature_(&onc_signature) {
59 field_translation_table_ = GetFieldTranslationTable(onc_signature);
62 ShillToONCTranslator(const base::DictionaryValue& shill_dictionary,
63 ::onc::ONCSource onc_source,
64 const OncValueSignature& onc_signature,
65 const FieldTranslationEntry* field_translation_table)
66 : shill_dictionary_(&shill_dictionary),
67 onc_source_(onc_source),
68 onc_signature_(&onc_signature),
69 field_translation_table_(field_translation_table) {
72 // Translates the associated Shill dictionary and creates an ONC object of the
73 // given signature.
74 scoped_ptr<base::DictionaryValue> CreateTranslatedONCObject();
76 private:
77 void TranslateEthernet();
78 void TranslateOpenVPN();
79 void TranslateIPsec();
80 void TranslateVPN();
81 void TranslateWiFiWithState();
82 void TranslateCellularWithState();
83 void TranslateCellularDevice();
84 void TranslateNetworkWithState();
85 void TranslateIPConfig();
86 void TranslateSavedOrStaticIPConfig(const std::string& nameserver_property);
87 void TranslateSavedIPConfig();
88 void TranslateStaticIPConfig();
90 // Creates an ONC object from |dictionary| according to the signature
91 // associated to |onc_field_name| and adds it to |onc_object_| at
92 // |onc_field_name|.
93 void TranslateAndAddNestedObject(const std::string& onc_field_name,
94 const base::DictionaryValue& dictionary);
96 // Creates an ONC object from |shill_dictionary_| according to the signature
97 // associated to |onc_field_name| and adds it to |onc_object_| at
98 // |onc_field_name|.
99 void TranslateAndAddNestedObject(const std::string& onc_field_name);
101 // Sets |onc_field_name| in dictionary |onc_dictionary_name| in |onc_object_|
102 // to |value| if the dictionary exists.
103 void SetNestedOncValue(const std::string& onc_dictionary_name,
104 const std::string& onc_field_name,
105 const base::Value& value);
107 // Translates a list of nested objects and adds the list to |onc_object_| at
108 // |onc_field_name|. If there are errors while parsing individual objects or
109 // if the resulting list contains no entries, the result will not be added to
110 // |onc_object_|.
111 void TranslateAndAddListOfObjects(const std::string& onc_field_name,
112 const base::ListValue& list);
114 // Applies function CopyProperty to each field of |value_signature| and its
115 // base signatures.
116 void CopyPropertiesAccordingToSignature(
117 const OncValueSignature* value_signature);
119 // Applies function CopyProperty to each field of |onc_signature_| and its
120 // base signatures.
121 void CopyPropertiesAccordingToSignature();
123 // If |shill_property_name| is defined in |field_signature|, copies this
124 // entry from |shill_dictionary_| to |onc_object_| if it exists.
125 void CopyProperty(const OncFieldSignature* field_signature);
127 // If existent, translates the entry at |shill_property_name| in
128 // |shill_dictionary_| using |table|. It is an error if no matching table
129 // entry is found. Writes the result as entry at |onc_field_name| in
130 // |onc_object_|.
131 void TranslateWithTableAndSet(const std::string& shill_property_name,
132 const StringTranslationEntry table[],
133 const std::string& onc_field_name);
135 // Returns the name of the Shill service provided in |shill_dictionary_|
136 // for debugging.
137 std::string GetName();
139 const base::DictionaryValue* shill_dictionary_;
140 ::onc::ONCSource onc_source_;
141 const OncValueSignature* onc_signature_;
142 const FieldTranslationEntry* field_translation_table_;
143 scoped_ptr<base::DictionaryValue> onc_object_;
145 DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator);
148 scoped_ptr<base::DictionaryValue>
149 ShillToONCTranslator::CreateTranslatedONCObject() {
150 onc_object_.reset(new base::DictionaryValue);
151 if (onc_signature_ == &kNetworkWithStateSignature) {
152 TranslateNetworkWithState();
153 } else if (onc_signature_ == &kEthernetSignature) {
154 TranslateEthernet();
155 } else if (onc_signature_ == &kVPNSignature) {
156 TranslateVPN();
157 } else if (onc_signature_ == &kOpenVPNSignature) {
158 TranslateOpenVPN();
159 } else if (onc_signature_ == &kIPsecSignature) {
160 TranslateIPsec();
161 } else if (onc_signature_ == &kWiFiWithStateSignature) {
162 TranslateWiFiWithState();
163 } else if (onc_signature_ == &kCellularWithStateSignature) {
164 if (field_translation_table_ == kCellularDeviceTable)
165 TranslateCellularDevice();
166 else
167 TranslateCellularWithState();
168 } else if (onc_signature_ == &kIPConfigSignature) {
169 TranslateIPConfig();
170 } else if (onc_signature_ == &kSavedIPConfigSignature) {
171 TranslateSavedIPConfig();
172 } else if (onc_signature_ == &kStaticIPConfigSignature) {
173 TranslateStaticIPConfig();
174 } else {
175 CopyPropertiesAccordingToSignature();
177 return onc_object_.Pass();
180 void ShillToONCTranslator::TranslateEthernet() {
181 std::string shill_network_type;
182 shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
183 &shill_network_type);
184 const char* onc_auth = ::onc::ethernet::kAuthenticationNone;
185 if (shill_network_type == shill::kTypeEthernetEap)
186 onc_auth = ::onc::ethernet::k8021X;
187 onc_object_->SetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
188 onc_auth);
191 void ShillToONCTranslator::TranslateOpenVPN() {
192 if (shill_dictionary_->HasKey(shill::kOpenVPNVerifyX509NameProperty))
193 TranslateAndAddNestedObject(::onc::openvpn::kVerifyX509);
195 // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
196 // wraps the value into a list.
197 std::string certKU;
198 if (shill_dictionary_->GetStringWithoutPathExpansion(
199 shill::kOpenVPNRemoteCertKUProperty, &certKU)) {
200 scoped_ptr<base::ListValue> certKUs(new base::ListValue);
201 certKUs->AppendString(certKU);
202 onc_object_->SetWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
203 certKUs.release());
206 for (const OncFieldSignature* field_signature = onc_signature_->fields;
207 field_signature->onc_field_name != NULL; ++field_signature) {
208 const std::string& onc_field_name = field_signature->onc_field_name;
209 if (onc_field_name == ::onc::openvpn::kRemoteCertKU ||
210 onc_field_name == ::onc::openvpn::kServerCAPEMs) {
211 CopyProperty(field_signature);
212 continue;
215 std::string shill_property_name;
216 const base::Value* shill_value = NULL;
217 if (!field_translation_table_ ||
218 !GetShillPropertyName(field_signature->onc_field_name,
219 field_translation_table_,
220 &shill_property_name) ||
221 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
222 &shill_value)) {
223 continue;
226 scoped_ptr<base::Value> translated;
227 std::string shill_str;
228 if (shill_value->GetAsString(&shill_str)) {
229 // Shill wants all Provider/VPN fields to be strings. Translates these
230 // strings back to the correct ONC type.
231 translated = ConvertStringToValue(
232 shill_str,
233 field_signature->value_signature->onc_type);
235 if (translated.get() == NULL) {
236 LOG(ERROR) << "Shill property '" << shill_property_name
237 << "' with value " << *shill_value
238 << " couldn't be converted to base::Value::Type "
239 << field_signature->value_signature->onc_type
240 << ": " << GetName();
241 } else {
242 onc_object_->SetWithoutPathExpansion(onc_field_name,
243 translated.release());
245 } else {
246 LOG(ERROR) << "Shill property '" << shill_property_name
247 << "' has value " << *shill_value
248 << ", but expected a string: " << GetName();
253 void ShillToONCTranslator::TranslateIPsec() {
254 CopyPropertiesAccordingToSignature();
255 if (shill_dictionary_->HasKey(shill::kL2tpIpsecXauthUserProperty))
256 TranslateAndAddNestedObject(::onc::ipsec::kXAUTH);
257 std::string client_cert_id;
258 shill_dictionary_->GetStringWithoutPathExpansion(
259 shill::kL2tpIpsecClientCertIdProperty, &client_cert_id);
260 std::string authentication_type =
261 client_cert_id.empty() ? ::onc::ipsec::kPSK : ::onc::ipsec::kCert;
262 onc_object_->SetStringWithoutPathExpansion(::onc::ipsec::kAuthenticationType,
263 authentication_type);
266 void ShillToONCTranslator::TranslateVPN() {
267 CopyPropertiesAccordingToSignature();
269 // Parse Shill Provider dictionary. Note, this may not exist, e.g. if we are
270 // just translating network state in network_util::TranslateNetworkStateToONC.
271 const base::DictionaryValue* provider = NULL;
272 if (!shill_dictionary_->GetDictionaryWithoutPathExpansion(
273 shill::kProviderProperty, &provider)) {
274 return;
276 std::string shill_provider_type, onc_provider_type;
277 provider->GetStringWithoutPathExpansion(shill::kTypeProperty,
278 &shill_provider_type);
279 if (!TranslateStringToONC(
280 kVPNTypeTable, shill_provider_type, &onc_provider_type)) {
281 return;
283 onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kType,
284 onc_provider_type);
285 std::string provider_host;
286 if (provider->GetStringWithoutPathExpansion(shill::kHostProperty,
287 &provider_host)) {
288 onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kHost,
289 provider_host);
292 // Translate the nested dictionary.
293 std::string provider_type_dictionary;
294 if (onc_provider_type == ::onc::vpn::kTypeL2TP_IPsec) {
295 TranslateAndAddNestedObject(::onc::vpn::kIPsec, *provider);
296 TranslateAndAddNestedObject(::onc::vpn::kL2TP, *provider);
297 provider_type_dictionary = ::onc::vpn::kIPsec;
298 } else {
299 TranslateAndAddNestedObject(onc_provider_type, *provider);
300 provider_type_dictionary = onc_provider_type;
303 bool save_credentials;
304 if (shill_dictionary_->GetBooleanWithoutPathExpansion(
305 shill::kSaveCredentialsProperty, &save_credentials)) {
306 SetNestedOncValue(provider_type_dictionary,
307 ::onc::vpn::kSaveCredentials,
308 base::FundamentalValue(save_credentials));
312 void ShillToONCTranslator::TranslateWiFiWithState() {
313 TranslateWithTableAndSet(
314 shill::kSecurityProperty, kWiFiSecurityTable, ::onc::wifi::kSecurity);
315 std::string ssid = shill_property_util::GetSSIDFromProperties(
316 *shill_dictionary_, NULL /* ignore unknown encoding */);
317 if (!ssid.empty())
318 onc_object_->SetStringWithoutPathExpansion(::onc::wifi::kSSID, ssid);
319 CopyPropertiesAccordingToSignature();
322 void ShillToONCTranslator::TranslateCellularWithState() {
323 CopyPropertiesAccordingToSignature();
324 TranslateWithTableAndSet(shill::kActivationStateProperty,
325 kActivationStateTable,
326 ::onc::cellular::kActivationState);
327 TranslateWithTableAndSet(shill::kRoamingStateProperty,
328 kRoamingStateTable,
329 ::onc::cellular::kRoamingState);
330 const base::DictionaryValue* dictionary = NULL;
331 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
332 shill::kServingOperatorProperty, &dictionary)) {
333 TranslateAndAddNestedObject(::onc::cellular::kServingOperator, *dictionary);
335 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
336 shill::kCellularApnProperty, &dictionary)) {
337 TranslateAndAddNestedObject(::onc::cellular::kAPN, *dictionary);
339 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
340 shill::kCellularLastGoodApnProperty, &dictionary)) {
341 TranslateAndAddNestedObject(::onc::cellular::kLastGoodAPN, *dictionary);
343 // Merge the Device dictionary with this one (Cellular) using the
344 // CellularDevice signature.
345 const base::DictionaryValue* device_dictionary = NULL;
346 if (!shill_dictionary_->GetDictionaryWithoutPathExpansion(
347 shill::kDeviceProperty, &device_dictionary)) {
348 return;
350 ShillToONCTranslator nested_translator(*device_dictionary,
351 onc_source_,
352 kCellularWithStateSignature,
353 kCellularDeviceTable);
354 scoped_ptr<base::DictionaryValue> nested_object =
355 nested_translator.CreateTranslatedONCObject();
356 onc_object_->MergeDictionary(nested_object.get());
359 void ShillToONCTranslator::TranslateCellularDevice() {
360 CopyPropertiesAccordingToSignature();
361 const base::DictionaryValue* shill_sim_lock_status = NULL;
362 if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
363 shill::kSIMLockStatusProperty, &shill_sim_lock_status)) {
364 TranslateAndAddNestedObject(::onc::cellular::kSIMLockStatus,
365 *shill_sim_lock_status);
367 const base::ListValue* shill_apns = NULL;
368 if (shill_dictionary_->GetListWithoutPathExpansion(
369 shill::kCellularApnListProperty, &shill_apns)) {
370 TranslateAndAddListOfObjects(::onc::cellular::kAPNList, *shill_apns);
372 const base::ListValue* shill_found_networks = NULL;
373 if (shill_dictionary_->GetListWithoutPathExpansion(
374 shill::kFoundNetworksProperty, &shill_found_networks)) {
375 TranslateAndAddListOfObjects(::onc::cellular::kFoundNetworks,
376 *shill_found_networks);
380 void ShillToONCTranslator::TranslateNetworkWithState() {
381 CopyPropertiesAccordingToSignature();
383 std::string shill_network_type;
384 shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
385 &shill_network_type);
386 std::string onc_network_type = ::onc::network_type::kEthernet;
387 if (shill_network_type != shill::kTypeEthernet &&
388 shill_network_type != shill::kTypeEthernetEap) {
389 TranslateStringToONC(
390 kNetworkTypeTable, shill_network_type, &onc_network_type);
392 // Translate nested Cellular, WiFi, etc. properties.
393 if (!onc_network_type.empty()) {
394 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kType,
395 onc_network_type);
396 TranslateAndAddNestedObject(onc_network_type);
399 // Since Name is a read only field in Shill unless it's a VPN, it is copied
400 // here, but not when going the other direction (if it's not a VPN).
401 std::string name;
402 shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
403 onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kName,
404 name);
406 // Limit ONC state to "NotConnected", "Connected", or "Connecting".
407 std::string state;
408 if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kStateProperty,
409 &state)) {
410 std::string onc_state = ::onc::connection_state::kNotConnected;
411 if (NetworkState::StateIsConnected(state)) {
412 onc_state = ::onc::connection_state::kConnected;
413 } else if (NetworkState::StateIsConnecting(state)) {
414 onc_state = ::onc::connection_state::kConnecting;
416 onc_object_->SetStringWithoutPathExpansion(
417 ::onc::network_config::kConnectionState, onc_state);
418 // Only set 'RestrictedConnectivity' if true.
419 if (state == shill::kStatePortal) {
420 onc_object_->SetBooleanWithoutPathExpansion(
421 ::onc::network_config::kRestrictedConnectivity, true);
425 std::string profile_path;
426 if (onc_source_ != ::onc::ONC_SOURCE_UNKNOWN &&
427 shill_dictionary_->GetStringWithoutPathExpansion(shill::kProfileProperty,
428 &profile_path)) {
429 std::string source;
430 if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY)
431 source = ::onc::network_config::kSourceDevicePolicy;
432 else if (onc_source_ == ::onc::ONC_SOURCE_USER_POLICY)
433 source = ::onc::network_config::kSourceUserPolicy;
434 else if (profile_path == NetworkProfileHandler::GetSharedProfilePath())
435 source = ::onc::network_config::kSourceDevice;
436 else if (!profile_path.empty())
437 source = ::onc::network_config::kSourceUser;
438 else
439 source = ::onc::network_config::kSourceNone;
440 onc_object_->SetStringWithoutPathExpansion(
441 ::onc::network_config::kSource, source);
444 // Use a human-readable aa:bb format for any hardware MAC address. Note:
445 // this property is provided by the caller but is not part of the Shill
446 // Service properties (it is copied from the Device properties).
447 std::string address;
448 if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kAddressProperty,
449 &address)) {
450 onc_object_->SetStringWithoutPathExpansion(
451 ::onc::network_config::kMacAddress,
452 network_util::FormattedMacAddress(address));
455 // Shill's Service has an IPConfig property (note the singular), not an
456 // IPConfigs property. However, we require the caller of the translation to
457 // patch the Shill dictionary before passing it to the translator.
458 const base::ListValue* shill_ipconfigs = NULL;
459 if (shill_dictionary_->GetListWithoutPathExpansion(shill::kIPConfigsProperty,
460 &shill_ipconfigs)) {
461 TranslateAndAddListOfObjects(::onc::network_config::kIPConfigs,
462 *shill_ipconfigs);
465 TranslateAndAddNestedObject(::onc::network_config::kSavedIPConfig);
466 TranslateAndAddNestedObject(::onc::network_config::kStaticIPConfig);
469 void ShillToONCTranslator::TranslateIPConfig() {
470 CopyPropertiesAccordingToSignature();
471 std::string shill_ip_method;
472 shill_dictionary_->GetStringWithoutPathExpansion(shill::kMethodProperty,
473 &shill_ip_method);
474 std::string type;
475 if (shill_ip_method == shill::kTypeIPv4 ||
476 shill_ip_method == shill::kTypeDHCP) {
477 type = ::onc::ipconfig::kIPv4;
478 } else if (shill_ip_method == shill::kTypeIPv6 ||
479 shill_ip_method == shill::kTypeDHCP6) {
480 type = ::onc::ipconfig::kIPv6;
481 } else {
482 return; // Ignore unhandled IPConfig types, e.g. bootp, zeroconf, ppp
485 onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType, type);
488 void ShillToONCTranslator::TranslateSavedOrStaticIPConfig(
489 const std::string& nameserver_property) {
490 CopyPropertiesAccordingToSignature();
491 // Saved/Static IP config nameservers are stored as a comma separated list.
492 std::string shill_nameservers;
493 shill_dictionary_->GetStringWithoutPathExpansion(
494 nameserver_property, &shill_nameservers);
495 std::vector<std::string> onc_nameserver_vector;
496 if (Tokenize(shill_nameservers, ",", &onc_nameserver_vector) > 0) {
497 scoped_ptr<base::ListValue> onc_nameservers(new base::ListValue);
498 for (std::vector<std::string>::iterator iter =
499 onc_nameserver_vector.begin();
500 iter != onc_nameserver_vector.end(); ++iter) {
501 onc_nameservers->AppendString(*iter);
503 onc_object_->SetWithoutPathExpansion(::onc::ipconfig::kNameServers,
504 onc_nameservers.release());
506 // Static and Saved IPConfig in Shill are always of type IPv4. Set this type
507 // in ONC, but not if the object would be empty except the type.
508 if (!onc_object_->empty()) {
509 onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType,
510 ::onc::ipconfig::kIPv4);
514 void ShillToONCTranslator::TranslateSavedIPConfig() {
515 TranslateSavedOrStaticIPConfig(shill::kSavedIPNameServersProperty);
518 void ShillToONCTranslator::TranslateStaticIPConfig() {
519 TranslateSavedOrStaticIPConfig(shill::kStaticIPNameServersProperty);
522 void ShillToONCTranslator::TranslateAndAddNestedObject(
523 const std::string& onc_field_name) {
524 TranslateAndAddNestedObject(onc_field_name, *shill_dictionary_);
527 void ShillToONCTranslator::TranslateAndAddNestedObject(
528 const std::string& onc_field_name,
529 const base::DictionaryValue& dictionary) {
530 const OncFieldSignature* field_signature =
531 GetFieldSignature(*onc_signature_, onc_field_name);
532 if (!field_signature) {
533 NOTREACHED() << "Unable to find signature for field: " << onc_field_name;
534 return;
536 ShillToONCTranslator nested_translator(
537 dictionary, onc_source_, *field_signature->value_signature);
538 scoped_ptr<base::DictionaryValue> nested_object =
539 nested_translator.CreateTranslatedONCObject();
540 if (nested_object->empty())
541 return;
542 onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
545 void ShillToONCTranslator::SetNestedOncValue(
546 const std::string& onc_dictionary_name,
547 const std::string& onc_field_name,
548 const base::Value& value) {
549 base::DictionaryValue* nested;
550 if (!onc_object_->GetDictionaryWithoutPathExpansion(
551 onc_dictionary_name, &nested)) {
552 nested = new base::DictionaryValue;
553 onc_object_->SetWithoutPathExpansion(onc_dictionary_name, nested);
555 nested->SetWithoutPathExpansion(onc_field_name, value.DeepCopy());
558 void ShillToONCTranslator::TranslateAndAddListOfObjects(
559 const std::string& onc_field_name,
560 const base::ListValue& list) {
561 const OncFieldSignature* field_signature =
562 GetFieldSignature(*onc_signature_, onc_field_name);
563 if (field_signature->value_signature->onc_type != base::Value::TYPE_LIST) {
564 LOG(ERROR) << "ONC Field name: '" << onc_field_name << "' has type '"
565 << field_signature->value_signature->onc_type
566 << "', expected: base::Value::TYPE_LIST: " << GetName();
567 return;
569 DCHECK(field_signature->value_signature->onc_array_entry_signature);
570 scoped_ptr<base::ListValue> result(new base::ListValue());
571 for (base::ListValue::const_iterator it = list.begin();
572 it != list.end(); ++it) {
573 const base::DictionaryValue* shill_value = NULL;
574 if (!(*it)->GetAsDictionary(&shill_value))
575 continue;
576 ShillToONCTranslator nested_translator(
577 *shill_value,
578 onc_source_,
579 *field_signature->value_signature->onc_array_entry_signature);
580 scoped_ptr<base::DictionaryValue> nested_object =
581 nested_translator.CreateTranslatedONCObject();
582 // If the nested object couldn't be parsed, simply omit it.
583 if (nested_object->empty())
584 continue;
585 result->Append(nested_object.release());
587 // If there are no entries in the list, there is no need to expose this field.
588 if (result->empty())
589 return;
590 onc_object_->SetWithoutPathExpansion(onc_field_name, result.release());
593 void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
594 CopyPropertiesAccordingToSignature(onc_signature_);
597 void ShillToONCTranslator::CopyPropertiesAccordingToSignature(
598 const OncValueSignature* value_signature) {
599 if (value_signature->base_signature)
600 CopyPropertiesAccordingToSignature(value_signature->base_signature);
601 if (!value_signature->fields)
602 return;
603 for (const OncFieldSignature* field_signature = value_signature->fields;
604 field_signature->onc_field_name != NULL; ++field_signature) {
605 CopyProperty(field_signature);
609 void ShillToONCTranslator::CopyProperty(
610 const OncFieldSignature* field_signature) {
611 std::string shill_property_name;
612 const base::Value* shill_value = NULL;
613 if (!field_translation_table_ ||
614 !GetShillPropertyName(field_signature->onc_field_name,
615 field_translation_table_,
616 &shill_property_name) ||
617 !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
618 &shill_value)) {
619 return;
622 if (shill_value->GetType() != field_signature->value_signature->onc_type) {
623 LOG(ERROR) << "Shill property '" << shill_property_name
624 << "' with value " << *shill_value
625 << " has base::Value::Type " << shill_value->GetType()
626 << " but ONC field '" << field_signature->onc_field_name
627 << "' requires type "
628 << field_signature->value_signature->onc_type
629 << ": " << GetName();
630 return;
633 onc_object_->SetWithoutPathExpansion(field_signature->onc_field_name,
634 shill_value->DeepCopy());
637 void ShillToONCTranslator::TranslateWithTableAndSet(
638 const std::string& shill_property_name,
639 const StringTranslationEntry table[],
640 const std::string& onc_field_name) {
641 std::string shill_value;
642 if (!shill_dictionary_->GetStringWithoutPathExpansion(shill_property_name,
643 &shill_value)) {
644 return;
646 std::string onc_value;
647 if (TranslateStringToONC(table, shill_value, &onc_value)) {
648 onc_object_->SetStringWithoutPathExpansion(onc_field_name, onc_value);
649 return;
651 LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
652 << shill_value << " couldn't be translated to ONC: " << GetName();
655 std::string ShillToONCTranslator::GetName() {
656 DCHECK(shill_dictionary_);
657 std::string name;
658 shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
659 return name;
662 } // namespace
664 scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart(
665 const base::DictionaryValue& shill_dictionary,
666 ::onc::ONCSource onc_source,
667 const OncValueSignature* onc_signature) {
668 CHECK(onc_signature != NULL);
670 ShillToONCTranslator translator(shill_dictionary, onc_source, *onc_signature);
671 return translator.CreateTranslatedONCObject();
674 } // namespace onc
675 } // namespace chromeos