Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chromeos / network / onc / onc_translator_shill_to_onc.cc
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 "chromeos/network/onc/onc_translator.h"
6
7 #include <string>
8
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"
23
24 namespace chromeos {
25 namespace onc {
26
27 namespace {
28
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);
38   }
39
40   if (value == NULL || value->GetType() != type) {
41     delete value;
42     value = NULL;
43   }
44   return make_scoped_ptr(value);
45 }
46
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);
60   }
61
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) {
70   }
71
72   // Translates the associated Shill dictionary and creates an ONC object of the
73   // given signature.
74   scoped_ptr<base::DictionaryValue> CreateTranslatedONCObject();
75
76  private:
77   void TranslateEthernet();
78   void TranslateOpenVPN();
79   void TranslateIPsec();
80   void TranslateVPN();
81   void TranslateWiFiWithState();
82   void TranslateWiMAXWithState();
83   void TranslateCellularWithState();
84   void TranslateCellularDevice();
85   void TranslateNetworkWithState();
86   void TranslateIPConfig();
87   void TranslateSavedOrStaticIPConfig(const std::string& nameserver_property);
88   void TranslateSavedIPConfig();
89   void TranslateStaticIPConfig();
90
91   // Creates an ONC object from |dictionary| according to the signature
92   // associated to |onc_field_name| and adds it to |onc_object_| at
93   // |onc_field_name|.
94   void TranslateAndAddNestedObject(const std::string& onc_field_name,
95                                    const base::DictionaryValue& dictionary);
96
97   // Creates an ONC object from |shill_dictionary_| according to the signature
98   // associated to |onc_field_name| and adds it to |onc_object_| at
99   // |onc_field_name|.
100   void TranslateAndAddNestedObject(const std::string& onc_field_name);
101
102   // Sets |onc_field_name| in dictionary |onc_dictionary_name| in |onc_object_|
103   // to |value| if the dictionary exists.
104   void SetNestedOncValue(const std::string& onc_dictionary_name,
105                          const std::string& onc_field_name,
106                          const base::Value& value);
107
108   // Translates a list of nested objects and adds the list to |onc_object_| at
109   // |onc_field_name|. If there are errors while parsing individual objects or
110   // if the resulting list contains no entries, the result will not be added to
111   // |onc_object_|.
112   void TranslateAndAddListOfObjects(const std::string& onc_field_name,
113                                     const base::ListValue& list);
114
115   // Applies function CopyProperty to each field of |value_signature| and its
116   // base signatures.
117   void CopyPropertiesAccordingToSignature(
118       const OncValueSignature* value_signature);
119
120   // Applies function CopyProperty to each field of |onc_signature_| and its
121   // base signatures.
122   void CopyPropertiesAccordingToSignature();
123
124   // If |shill_property_name| is defined in |field_signature|, copies this
125   // entry from |shill_dictionary_| to |onc_object_| if it exists.
126   void CopyProperty(const OncFieldSignature* field_signature);
127
128   // If existent, translates the entry at |shill_property_name| in
129   // |shill_dictionary_| using |table|. It is an error if no matching table
130   // entry is found. Writes the result as entry at |onc_field_name| in
131   // |onc_object_|.
132   void TranslateWithTableAndSet(const std::string& shill_property_name,
133                                 const StringTranslationEntry table[],
134                                 const std::string& onc_field_name);
135
136   // Returns the name of the Shill service provided in |shill_dictionary_|
137   // for debugging.
138   std::string GetName();
139
140   const base::DictionaryValue* shill_dictionary_;
141   ::onc::ONCSource onc_source_;
142   const OncValueSignature* onc_signature_;
143   const FieldTranslationEntry* field_translation_table_;
144   scoped_ptr<base::DictionaryValue> onc_object_;
145
146   DISALLOW_COPY_AND_ASSIGN(ShillToONCTranslator);
147 };
148
149 scoped_ptr<base::DictionaryValue>
150 ShillToONCTranslator::CreateTranslatedONCObject() {
151   onc_object_.reset(new base::DictionaryValue);
152   if (onc_signature_ == &kNetworkWithStateSignature) {
153     TranslateNetworkWithState();
154   } else if (onc_signature_ == &kEthernetSignature) {
155     TranslateEthernet();
156   } else if (onc_signature_ == &kVPNSignature) {
157     TranslateVPN();
158   } else if (onc_signature_ == &kOpenVPNSignature) {
159     TranslateOpenVPN();
160   } else if (onc_signature_ == &kIPsecSignature) {
161     TranslateIPsec();
162   } else if (onc_signature_ == &kWiFiWithStateSignature) {
163     TranslateWiFiWithState();
164   } else if (onc_signature_ == &kWiMAXWithStateSignature) {
165     TranslateWiMAXWithState();
166   } else if (onc_signature_ == &kCellularWithStateSignature) {
167     if (field_translation_table_ == kCellularDeviceTable)
168       TranslateCellularDevice();
169     else
170       TranslateCellularWithState();
171   } else if (onc_signature_ == &kIPConfigSignature) {
172     TranslateIPConfig();
173   } else if (onc_signature_ == &kSavedIPConfigSignature) {
174     TranslateSavedIPConfig();
175   } else if (onc_signature_ == &kStaticIPConfigSignature) {
176     TranslateStaticIPConfig();
177   } else {
178     CopyPropertiesAccordingToSignature();
179   }
180   return onc_object_.Pass();
181 }
182
183 void ShillToONCTranslator::TranslateEthernet() {
184   std::string shill_network_type;
185   shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
186                                                    &shill_network_type);
187   const char* onc_auth = ::onc::ethernet::kAuthenticationNone;
188   if (shill_network_type == shill::kTypeEthernetEap)
189     onc_auth = ::onc::ethernet::k8021X;
190   onc_object_->SetStringWithoutPathExpansion(::onc::ethernet::kAuthentication,
191                                              onc_auth);
192 }
193
194 void ShillToONCTranslator::TranslateOpenVPN() {
195   if (shill_dictionary_->HasKey(shill::kOpenVPNVerifyX509NameProperty))
196     TranslateAndAddNestedObject(::onc::openvpn::kVerifyX509);
197
198   // Shill supports only one RemoteCertKU but ONC requires a list. If existing,
199   // wraps the value into a list.
200   std::string certKU;
201   if (shill_dictionary_->GetStringWithoutPathExpansion(
202           shill::kOpenVPNRemoteCertKUProperty, &certKU)) {
203     scoped_ptr<base::ListValue> certKUs(new base::ListValue);
204     certKUs->AppendString(certKU);
205     onc_object_->SetWithoutPathExpansion(::onc::openvpn::kRemoteCertKU,
206                                          certKUs.release());
207   }
208
209   for (const OncFieldSignature* field_signature = onc_signature_->fields;
210        field_signature->onc_field_name != NULL; ++field_signature) {
211     const std::string& onc_field_name = field_signature->onc_field_name;
212     if (onc_field_name == ::onc::openvpn::kRemoteCertKU ||
213         onc_field_name == ::onc::openvpn::kServerCAPEMs) {
214       CopyProperty(field_signature);
215       continue;
216     }
217
218     std::string shill_property_name;
219     const base::Value* shill_value = NULL;
220     if (!field_translation_table_ ||
221         !GetShillPropertyName(field_signature->onc_field_name,
222                               field_translation_table_,
223                               &shill_property_name) ||
224         !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
225                                                     &shill_value)) {
226       continue;
227     }
228
229     scoped_ptr<base::Value> translated;
230     std::string shill_str;
231     if (shill_value->GetAsString(&shill_str)) {
232       // Shill wants all Provider/VPN fields to be strings. Translates these
233       // strings back to the correct ONC type.
234       translated = ConvertStringToValue(
235           shill_str,
236           field_signature->value_signature->onc_type);
237
238       if (translated.get() == NULL) {
239         LOG(ERROR) << "Shill property '" << shill_property_name
240                    << "' with value " << *shill_value
241                    << " couldn't be converted to base::Value::Type "
242                    << field_signature->value_signature->onc_type
243                    << ": " << GetName();
244       } else {
245         onc_object_->SetWithoutPathExpansion(onc_field_name,
246                                              translated.release());
247       }
248     } else {
249       LOG(ERROR) << "Shill property '" << shill_property_name
250                  << "' has value " << *shill_value
251                  << ", but expected a string: " << GetName();
252     }
253   }
254 }
255
256 void ShillToONCTranslator::TranslateIPsec() {
257   CopyPropertiesAccordingToSignature();
258   if (shill_dictionary_->HasKey(shill::kL2tpIpsecXauthUserProperty))
259     TranslateAndAddNestedObject(::onc::ipsec::kXAUTH);
260   std::string client_cert_id;
261   shill_dictionary_->GetStringWithoutPathExpansion(
262       shill::kL2tpIpsecClientCertIdProperty, &client_cert_id);
263   std::string authentication_type =
264       client_cert_id.empty() ? ::onc::ipsec::kPSK : ::onc::ipsec::kCert;
265   onc_object_->SetStringWithoutPathExpansion(::onc::ipsec::kAuthenticationType,
266                                              authentication_type);
267 }
268
269 void ShillToONCTranslator::TranslateVPN() {
270   CopyPropertiesAccordingToSignature();
271
272   // Parse Shill Provider dictionary. Note, this may not exist, e.g. if we are
273   // just translating network state in network_util::TranslateNetworkStateToONC.
274   const base::DictionaryValue* provider = NULL;
275   if (!shill_dictionary_->GetDictionaryWithoutPathExpansion(
276           shill::kProviderProperty, &provider)) {
277     return;
278   }
279   std::string shill_provider_type, onc_provider_type;
280   provider->GetStringWithoutPathExpansion(shill::kTypeProperty,
281                                           &shill_provider_type);
282   if (!TranslateStringToONC(
283           kVPNTypeTable, shill_provider_type, &onc_provider_type)) {
284     return;
285   }
286   onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kType,
287                                              onc_provider_type);
288   std::string provider_host;
289   if (provider->GetStringWithoutPathExpansion(shill::kHostProperty,
290                                               &provider_host)) {
291     onc_object_->SetStringWithoutPathExpansion(::onc::vpn::kHost,
292                                                provider_host);
293   }
294
295   // Translate the nested dictionary.
296   std::string provider_type_dictionary;
297   if (onc_provider_type == ::onc::vpn::kTypeL2TP_IPsec) {
298     TranslateAndAddNestedObject(::onc::vpn::kIPsec, *provider);
299     TranslateAndAddNestedObject(::onc::vpn::kL2TP, *provider);
300     provider_type_dictionary = ::onc::vpn::kIPsec;
301   } else {
302     TranslateAndAddNestedObject(onc_provider_type, *provider);
303     provider_type_dictionary = onc_provider_type;
304   }
305
306   bool save_credentials;
307   if (shill_dictionary_->GetBooleanWithoutPathExpansion(
308           shill::kSaveCredentialsProperty, &save_credentials)) {
309     SetNestedOncValue(provider_type_dictionary,
310                       ::onc::vpn::kSaveCredentials,
311                       base::FundamentalValue(save_credentials));
312   }
313 }
314
315 void ShillToONCTranslator::TranslateWiFiWithState() {
316   TranslateWithTableAndSet(
317       shill::kSecurityProperty, kWiFiSecurityTable, ::onc::wifi::kSecurity);
318   std::string ssid = shill_property_util::GetSSIDFromProperties(
319       *shill_dictionary_, NULL /* ignore unknown encoding */);
320   if (!ssid.empty())
321     onc_object_->SetStringWithoutPathExpansion(::onc::wifi::kSSID, ssid);
322
323   bool link_monitor_disable;
324   if (shill_dictionary_->GetBooleanWithoutPathExpansion(
325           shill::kLinkMonitorDisableProperty, &link_monitor_disable)) {
326     onc_object_->SetBooleanWithoutPathExpansion(
327         ::onc::wifi::kAllowGatewayARPPolling, !link_monitor_disable);
328   }
329
330   CopyPropertiesAccordingToSignature();
331   TranslateAndAddNestedObject(::onc::wifi::kEAP);
332 }
333
334 void ShillToONCTranslator::TranslateWiMAXWithState() {
335   CopyPropertiesAccordingToSignature();
336   TranslateAndAddNestedObject(::onc::wimax::kEAP);
337 }
338
339 void ShillToONCTranslator::TranslateCellularWithState() {
340   CopyPropertiesAccordingToSignature();
341   TranslateWithTableAndSet(shill::kActivationStateProperty,
342                            kActivationStateTable,
343                            ::onc::cellular::kActivationState);
344   TranslateWithTableAndSet(shill::kRoamingStateProperty,
345                            kRoamingStateTable,
346                            ::onc::cellular::kRoamingState);
347   const base::DictionaryValue* dictionary = NULL;
348   if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
349         shill::kServingOperatorProperty, &dictionary)) {
350     TranslateAndAddNestedObject(::onc::cellular::kServingOperator, *dictionary);
351   }
352   if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
353         shill::kCellularApnProperty, &dictionary)) {
354     TranslateAndAddNestedObject(::onc::cellular::kAPN, *dictionary);
355   }
356   if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
357         shill::kCellularLastGoodApnProperty, &dictionary)) {
358     TranslateAndAddNestedObject(::onc::cellular::kLastGoodAPN, *dictionary);
359   }
360   // Merge the Device dictionary with this one (Cellular) using the
361   // CellularDevice signature.
362   const base::DictionaryValue* device_dictionary = NULL;
363   if (!shill_dictionary_->GetDictionaryWithoutPathExpansion(
364           shill::kDeviceProperty, &device_dictionary)) {
365     return;
366   }
367   ShillToONCTranslator nested_translator(*device_dictionary,
368                                          onc_source_,
369                                          kCellularWithStateSignature,
370                                          kCellularDeviceTable);
371   scoped_ptr<base::DictionaryValue> nested_object =
372       nested_translator.CreateTranslatedONCObject();
373   onc_object_->MergeDictionary(nested_object.get());
374 }
375
376 void ShillToONCTranslator::TranslateCellularDevice() {
377   CopyPropertiesAccordingToSignature();
378   const base::DictionaryValue* shill_sim_lock_status = NULL;
379   if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
380           shill::kSIMLockStatusProperty, &shill_sim_lock_status)) {
381     TranslateAndAddNestedObject(::onc::cellular::kSIMLockStatus,
382                                 *shill_sim_lock_status);
383   }
384   const base::ListValue* shill_apns = NULL;
385   if (shill_dictionary_->GetListWithoutPathExpansion(
386           shill::kCellularApnListProperty, &shill_apns)) {
387     TranslateAndAddListOfObjects(::onc::cellular::kAPNList, *shill_apns);
388   }
389   const base::ListValue* shill_found_networks = NULL;
390   if (shill_dictionary_->GetListWithoutPathExpansion(
391           shill::kFoundNetworksProperty, &shill_found_networks)) {
392     TranslateAndAddListOfObjects(::onc::cellular::kFoundNetworks,
393                                  *shill_found_networks);
394   }
395 }
396
397 void ShillToONCTranslator::TranslateNetworkWithState() {
398   CopyPropertiesAccordingToSignature();
399
400   std::string shill_network_type;
401   shill_dictionary_->GetStringWithoutPathExpansion(shill::kTypeProperty,
402                                                    &shill_network_type);
403   std::string onc_network_type = ::onc::network_type::kEthernet;
404   if (shill_network_type != shill::kTypeEthernet &&
405       shill_network_type != shill::kTypeEthernetEap) {
406     TranslateStringToONC(
407         kNetworkTypeTable, shill_network_type, &onc_network_type);
408   }
409   // Translate nested Cellular, WiFi, etc. properties.
410   if (!onc_network_type.empty()) {
411     onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kType,
412                                                onc_network_type);
413     TranslateAndAddNestedObject(onc_network_type);
414   }
415
416   // Since Name is a read only field in Shill unless it's a VPN, it is copied
417   // here, but not when going the other direction (if it's not a VPN).
418   std::string name;
419   shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
420   onc_object_->SetStringWithoutPathExpansion(::onc::network_config::kName,
421                                              name);
422
423   // Limit ONC state to "NotConnected", "Connected", or "Connecting".
424   std::string state;
425   if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kStateProperty,
426                                                        &state)) {
427     std::string onc_state = ::onc::connection_state::kNotConnected;
428     if (NetworkState::StateIsConnected(state)) {
429       onc_state = ::onc::connection_state::kConnected;
430     } else if (NetworkState::StateIsConnecting(state)) {
431       onc_state = ::onc::connection_state::kConnecting;
432     }
433     onc_object_->SetStringWithoutPathExpansion(
434         ::onc::network_config::kConnectionState, onc_state);
435     // Only set 'RestrictedConnectivity' if true.
436     if (state == shill::kStatePortal) {
437       onc_object_->SetBooleanWithoutPathExpansion(
438           ::onc::network_config::kRestrictedConnectivity, true);
439     }
440   }
441
442   std::string profile_path;
443   if (onc_source_ != ::onc::ONC_SOURCE_UNKNOWN &&
444       shill_dictionary_->GetStringWithoutPathExpansion(shill::kProfileProperty,
445                                                        &profile_path)) {
446     std::string source;
447     if (onc_source_ == ::onc::ONC_SOURCE_DEVICE_POLICY)
448       source = ::onc::network_config::kSourceDevicePolicy;
449     else if (onc_source_ == ::onc::ONC_SOURCE_USER_POLICY)
450       source = ::onc::network_config::kSourceUserPolicy;
451     else if (profile_path == NetworkProfileHandler::GetSharedProfilePath())
452       source = ::onc::network_config::kSourceDevice;
453     else if (!profile_path.empty())
454       source = ::onc::network_config::kSourceUser;
455     else
456       source = ::onc::network_config::kSourceNone;
457     onc_object_->SetStringWithoutPathExpansion(
458         ::onc::network_config::kSource, source);
459   }
460
461   // Use a human-readable aa:bb format for any hardware MAC address. Note:
462   // this property is provided by the caller but is not part of the Shill
463   // Service properties (it is copied from the Device properties).
464   std::string address;
465   if (shill_dictionary_->GetStringWithoutPathExpansion(shill::kAddressProperty,
466                                                        &address)) {
467     onc_object_->SetStringWithoutPathExpansion(
468         ::onc::network_config::kMacAddress,
469         network_util::FormattedMacAddress(address));
470   }
471
472   // Shill's Service has an IPConfig property (note the singular), not an
473   // IPConfigs property. However, we require the caller of the translation to
474   // patch the Shill dictionary before passing it to the translator.
475   const base::ListValue* shill_ipconfigs = NULL;
476   if (shill_dictionary_->GetListWithoutPathExpansion(shill::kIPConfigsProperty,
477                                                      &shill_ipconfigs)) {
478     TranslateAndAddListOfObjects(::onc::network_config::kIPConfigs,
479                                  *shill_ipconfigs);
480   }
481
482   TranslateAndAddNestedObject(::onc::network_config::kSavedIPConfig);
483   TranslateAndAddNestedObject(::onc::network_config::kStaticIPConfig);
484 }
485
486 void ShillToONCTranslator::TranslateIPConfig() {
487   CopyPropertiesAccordingToSignature();
488   std::string shill_ip_method;
489   shill_dictionary_->GetStringWithoutPathExpansion(shill::kMethodProperty,
490                                                    &shill_ip_method);
491   std::string type;
492   if (shill_ip_method == shill::kTypeIPv4 ||
493       shill_ip_method == shill::kTypeDHCP) {
494     type = ::onc::ipconfig::kIPv4;
495   } else if (shill_ip_method == shill::kTypeIPv6 ||
496              shill_ip_method == shill::kTypeDHCP6) {
497     type = ::onc::ipconfig::kIPv6;
498   } else {
499     return;  // Ignore unhandled IPConfig types, e.g. bootp, zeroconf, ppp
500   }
501
502   onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType, type);
503 }
504
505 void ShillToONCTranslator::TranslateSavedOrStaticIPConfig(
506     const std::string& nameserver_property) {
507   CopyPropertiesAccordingToSignature();
508   // Saved/Static IP config nameservers are stored as a comma separated list.
509   std::string shill_nameservers;
510   shill_dictionary_->GetStringWithoutPathExpansion(
511       nameserver_property, &shill_nameservers);
512   std::vector<std::string> onc_nameserver_vector;
513   if (Tokenize(shill_nameservers, ",", &onc_nameserver_vector) > 0) {
514     scoped_ptr<base::ListValue> onc_nameservers(new base::ListValue);
515     for (std::vector<std::string>::iterator iter =
516              onc_nameserver_vector.begin();
517          iter != onc_nameserver_vector.end(); ++iter) {
518       onc_nameservers->AppendString(*iter);
519     }
520     onc_object_->SetWithoutPathExpansion(::onc::ipconfig::kNameServers,
521                                          onc_nameservers.release());
522   }
523   // Static and Saved IPConfig in Shill are always of type IPv4. Set this type
524   // in ONC, but not if the object would be empty except the type.
525   if (!onc_object_->empty()) {
526     onc_object_->SetStringWithoutPathExpansion(::onc::ipconfig::kType,
527                                                ::onc::ipconfig::kIPv4);
528   }
529 }
530
531 void ShillToONCTranslator::TranslateSavedIPConfig() {
532   TranslateSavedOrStaticIPConfig(shill::kSavedIPNameServersProperty);
533 }
534
535 void ShillToONCTranslator::TranslateStaticIPConfig() {
536   TranslateSavedOrStaticIPConfig(shill::kStaticIPNameServersProperty);
537 }
538
539 void ShillToONCTranslator::TranslateAndAddNestedObject(
540     const std::string& onc_field_name) {
541   TranslateAndAddNestedObject(onc_field_name, *shill_dictionary_);
542 }
543
544 void ShillToONCTranslator::TranslateAndAddNestedObject(
545     const std::string& onc_field_name,
546     const base::DictionaryValue& dictionary) {
547   const OncFieldSignature* field_signature =
548       GetFieldSignature(*onc_signature_, onc_field_name);
549   if (!field_signature) {
550     NOTREACHED() << "Unable to find signature for field: " << onc_field_name;
551     return;
552   }
553   ShillToONCTranslator nested_translator(
554       dictionary, onc_source_, *field_signature->value_signature);
555   scoped_ptr<base::DictionaryValue> nested_object =
556       nested_translator.CreateTranslatedONCObject();
557   if (nested_object->empty())
558     return;
559   onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
560 }
561
562 void ShillToONCTranslator::SetNestedOncValue(
563     const std::string& onc_dictionary_name,
564     const std::string& onc_field_name,
565     const base::Value& value) {
566   base::DictionaryValue* nested;
567   if (!onc_object_->GetDictionaryWithoutPathExpansion(
568           onc_dictionary_name, &nested)) {
569     nested = new base::DictionaryValue;
570     onc_object_->SetWithoutPathExpansion(onc_dictionary_name, nested);
571   }
572   nested->SetWithoutPathExpansion(onc_field_name, value.DeepCopy());
573 }
574
575 void ShillToONCTranslator::TranslateAndAddListOfObjects(
576     const std::string& onc_field_name,
577     const base::ListValue& list) {
578   const OncFieldSignature* field_signature =
579       GetFieldSignature(*onc_signature_, onc_field_name);
580   if (field_signature->value_signature->onc_type != base::Value::TYPE_LIST) {
581     LOG(ERROR) << "ONC Field name: '" << onc_field_name << "' has type '"
582                << field_signature->value_signature->onc_type
583                << "', expected: base::Value::TYPE_LIST: " << GetName();
584     return;
585   }
586   DCHECK(field_signature->value_signature->onc_array_entry_signature);
587   scoped_ptr<base::ListValue> result(new base::ListValue());
588   for (base::ListValue::const_iterator it = list.begin();
589        it != list.end(); ++it) {
590     const base::DictionaryValue* shill_value = NULL;
591     if (!(*it)->GetAsDictionary(&shill_value))
592       continue;
593     ShillToONCTranslator nested_translator(
594         *shill_value,
595         onc_source_,
596         *field_signature->value_signature->onc_array_entry_signature);
597     scoped_ptr<base::DictionaryValue> nested_object =
598         nested_translator.CreateTranslatedONCObject();
599     // If the nested object couldn't be parsed, simply omit it.
600     if (nested_object->empty())
601       continue;
602     result->Append(nested_object.release());
603   }
604   // If there are no entries in the list, there is no need to expose this field.
605   if (result->empty())
606     return;
607   onc_object_->SetWithoutPathExpansion(onc_field_name, result.release());
608 }
609
610 void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
611   CopyPropertiesAccordingToSignature(onc_signature_);
612 }
613
614 void ShillToONCTranslator::CopyPropertiesAccordingToSignature(
615     const OncValueSignature* value_signature) {
616   if (value_signature->base_signature)
617     CopyPropertiesAccordingToSignature(value_signature->base_signature);
618   if (!value_signature->fields)
619     return;
620   for (const OncFieldSignature* field_signature = value_signature->fields;
621        field_signature->onc_field_name != NULL; ++field_signature) {
622     CopyProperty(field_signature);
623   }
624 }
625
626 void ShillToONCTranslator::CopyProperty(
627     const OncFieldSignature* field_signature) {
628   std::string shill_property_name;
629   const base::Value* shill_value = NULL;
630   if (!field_translation_table_ ||
631       !GetShillPropertyName(field_signature->onc_field_name,
632                             field_translation_table_,
633                             &shill_property_name) ||
634       !shill_dictionary_->GetWithoutPathExpansion(shill_property_name,
635                                                   &shill_value)) {
636     return;
637   }
638
639   if (shill_value->GetType() != field_signature->value_signature->onc_type) {
640     LOG(ERROR) << "Shill property '" << shill_property_name
641                << "' with value " << *shill_value
642                << " has base::Value::Type " << shill_value->GetType()
643                << " but ONC field '" << field_signature->onc_field_name
644                << "' requires type "
645                << field_signature->value_signature->onc_type
646                << ": " << GetName();
647     return;
648   }
649
650  onc_object_->SetWithoutPathExpansion(field_signature->onc_field_name,
651                                       shill_value->DeepCopy());
652 }
653
654 void ShillToONCTranslator::TranslateWithTableAndSet(
655     const std::string& shill_property_name,
656     const StringTranslationEntry table[],
657     const std::string& onc_field_name) {
658   std::string shill_value;
659   if (!shill_dictionary_->GetStringWithoutPathExpansion(shill_property_name,
660                                                         &shill_value)) {
661     return;
662   }
663   std::string onc_value;
664   if (TranslateStringToONC(table, shill_value, &onc_value)) {
665     onc_object_->SetStringWithoutPathExpansion(onc_field_name, onc_value);
666     return;
667   }
668   LOG(ERROR) << "Shill property '" << shill_property_name << "' with value "
669              << shill_value << " couldn't be translated to ONC: " << GetName();
670 }
671
672 std::string ShillToONCTranslator::GetName() {
673   DCHECK(shill_dictionary_);
674   std::string name;
675   shill_dictionary_->GetStringWithoutPathExpansion(shill::kNameProperty, &name);
676   return name;
677 }
678
679 }  // namespace
680
681 scoped_ptr<base::DictionaryValue> TranslateShillServiceToONCPart(
682     const base::DictionaryValue& shill_dictionary,
683     ::onc::ONCSource onc_source,
684     const OncValueSignature* onc_signature) {
685   CHECK(onc_signature != NULL);
686
687   ShillToONCTranslator translator(shill_dictionary, onc_source, *onc_signature);
688   return translator.CreateTranslatedONCObject();
689 }
690
691 }  // namespace onc
692 }  // namespace chromeos