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 // The implementation of TranslateONCObjectToShill is structured in two parts:
6 // - The recursion through the existing ONC hierarchy
7 // see TranslateONCHierarchy
8 // - The local translation of an object depending on the associated signature
9 // see LocalTranslator::TranslateFields
11 #include "chromeos/network/onc/onc_translator.h"
15 #include "base/json/json_reader.h"
16 #include "base/json/json_writer.h"
17 #include "base/logging.h"
18 #include "base/values.h"
19 #include "chromeos/network/onc/onc_constants.h"
20 #include "chromeos/network/onc/onc_signature.h"
21 #include "chromeos/network/onc/onc_translation_tables.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
29 scoped_ptr
<base::StringValue
> ConvertValueToString(const base::Value
& value
) {
31 if (!value
.GetAsString(&str
))
32 base::JSONWriter::Write(&value
, &str
);
33 return make_scoped_ptr(base::Value::CreateStringValue(str
));
36 // This class is responsible to translate the local fields of the given
37 // |onc_object| according to |onc_signature| into |shill_dictionary|. This
38 // translation should consider (if possible) only fields of this ONC object and
39 // not nested objects because recursion is handled by the calling function
40 // TranslateONCHierarchy.
41 class LocalTranslator
{
43 LocalTranslator(const OncValueSignature
& onc_signature
,
44 const base::DictionaryValue
& onc_object
,
45 base::DictionaryValue
* shill_dictionary
)
46 : onc_signature_(&onc_signature
),
47 onc_object_(&onc_object
),
48 shill_dictionary_(shill_dictionary
) {
51 void TranslateFields();
54 void TranslateOpenVPN();
56 void TranslateNetworkConfiguration();
58 // Copies all entries from |onc_object_| to |shill_dictionary_| for which a
59 // translation (shill_property_name) is defined by |onc_signature_|.
60 void CopyFieldsAccordingToSignature();
62 // Adds |value| to |shill_dictionary| at the field shill_property_name given
63 // by the associated signature. Takes ownership of |value|. Does nothing if
64 // |value| is NULL or the property name cannot be read from the signature.
65 void AddValueAccordingToSignature(const std::string
& onc_field_name
,
66 scoped_ptr
<base::Value
> value
);
68 // If existent, translates the entry at |onc_field_name| in |onc_object_|
69 // using |table|. It is an error if no matching table entry is found. Writes
70 // the result as entry at |shill_property_name| in |shill_dictionary_|.
71 void TranslateWithTableAndSet(const std::string
& onc_field_name
,
72 const StringTranslationEntry table
[],
73 const std::string
& shill_property_name
);
75 const OncValueSignature
* onc_signature_
;
76 const base::DictionaryValue
* onc_object_
;
77 base::DictionaryValue
* shill_dictionary_
;
79 DISALLOW_COPY_AND_ASSIGN(LocalTranslator
);
82 void LocalTranslator::TranslateFields() {
83 if (onc_signature_
== &kNetworkConfigurationSignature
)
84 TranslateNetworkConfiguration();
85 else if (onc_signature_
== &kVPNSignature
)
87 else if (onc_signature_
== &kOpenVPNSignature
)
90 CopyFieldsAccordingToSignature();
93 void LocalTranslator::TranslateOpenVPN() {
94 // Shill supports only one RemoteCertKU but ONC a list.
95 // Copy only the first entry if existing.
96 const base::ListValue
* certKUs
;
98 if (onc_object_
->GetListWithoutPathExpansion(vpn::kRemoteCertKU
, &certKUs
) &&
99 certKUs
->GetString(0, &certKU
)) {
100 shill_dictionary_
->SetStringWithoutPathExpansion(
101 flimflam::kOpenVPNRemoteCertKUProperty
, certKU
);
104 for (base::DictionaryValue::Iterator
it(*onc_object_
); it
.HasNext();
106 scoped_ptr
<base::Value
> translated
;
107 if (it
.key() == vpn::kSaveCredentials
|| it
.key() == vpn::kRemoteCertKU
) {
108 translated
.reset(it
.value().DeepCopy());
110 // Shill wants all Provider/VPN fields to be strings.
111 translated
= ConvertValueToString(it
.value());
113 AddValueAccordingToSignature(it
.key(), translated
.Pass());
117 void LocalTranslator::TranslateVPN() {
118 TranslateWithTableAndSet(kType
, kVPNTypeTable
,
119 flimflam::kProviderTypeProperty
);
120 CopyFieldsAccordingToSignature();
123 void LocalTranslator::TranslateNetworkConfiguration() {
124 TranslateWithTableAndSet(kType
, kNetworkTypeTable
, flimflam::kTypeProperty
);
125 CopyFieldsAccordingToSignature();
128 void LocalTranslator::CopyFieldsAccordingToSignature() {
129 for (base::DictionaryValue::Iterator
it(*onc_object_
); it
.HasNext();
131 AddValueAccordingToSignature(it
.key(),
132 make_scoped_ptr(it
.value().DeepCopy()));
136 void LocalTranslator::AddValueAccordingToSignature(
137 const std::string
& onc_name
,
138 scoped_ptr
<base::Value
> value
) {
139 if (value
.get() == NULL
)
141 const OncFieldSignature
* field_signature
=
142 GetFieldSignature(*onc_signature_
, onc_name
);
143 DCHECK(field_signature
!= NULL
);
144 if (field_signature
== NULL
|| field_signature
->shill_property_name
== NULL
)
147 shill_dictionary_
->SetWithoutPathExpansion(
148 field_signature
->shill_property_name
, value
.release());
151 void LocalTranslator::TranslateWithTableAndSet(
152 const std::string
& onc_field_name
,
153 const StringTranslationEntry table
[],
154 const std::string
& shill_property_name
) {
155 std::string onc_value
;
156 if (!onc_object_
->GetStringWithoutPathExpansion(onc_field_name
, &onc_value
))
159 for (int i
= 0; table
[i
].onc_value
!= NULL
; ++i
) {
160 if (onc_value
!= table
[i
].onc_value
)
162 shill_dictionary_
->SetStringWithoutPathExpansion(shill_property_name
,
163 table
[i
].shill_value
);
166 // As we previously validate ONC, this case should never occur. If it still
167 // occurs, we should check here. Otherwise the failure will only show up much
169 LOG(ERROR
) << "Value '" << onc_value
<< "' for field '"
170 << onc_field_name
<< "' cannot be translated to Shill";
173 // Iterates recursively over |onc_object| and its |signature|. At each object
174 // applies the local translation using LocalTranslator::TranslateFields. The
175 // results are written to |shill_dictionary|.
176 void TranslateONCHierarchy(const OncValueSignature
& signature
,
177 const base::DictionaryValue
& onc_object
,
178 base::DictionaryValue
* shill_dictionary
) {
179 // Translates fields of |onc_object| and writes them to |shill_dictionary_|.
180 LocalTranslator
translator(signature
, onc_object
, shill_dictionary
);
181 translator
.TranslateFields();
183 // Recurse into nested objects.
184 for (base::DictionaryValue::Iterator
it(onc_object
); it
.HasNext();
186 const base::DictionaryValue
* inner_object
;
187 if (!it
.value().GetAsDictionary(&inner_object
))
190 const OncFieldSignature
* field_signature
=
191 GetFieldSignature(signature
, it
.key());
193 TranslateONCHierarchy(*field_signature
->value_signature
, *inner_object
,
200 scoped_ptr
<base::DictionaryValue
> TranslateONCObjectToShill(
201 const OncValueSignature
* onc_signature
,
202 const base::DictionaryValue
& onc_object
) {
203 CHECK(onc_signature
!= NULL
);
204 scoped_ptr
<base::DictionaryValue
> shill_dictionary(new base::DictionaryValue
);
205 TranslateONCHierarchy(*onc_signature
, onc_object
, shill_dictionary
.get());
206 return shill_dictionary
.Pass();
210 } // namespace chromeos