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_merger.h"
10 #include "base/basictypes.h"
11 #include "base/logging.h"
12 #include "base/values.h"
13 #include "chromeos/network/onc/onc_constants.h"
19 typedef scoped_ptr
<base::DictionaryValue
> DictionaryPtr
;
21 // Inserts |true| at every field name in |result| that is recommended in policy.
22 void MarkRecommendedFieldnames(const base::DictionaryValue
& policy
,
23 base::DictionaryValue
* result
) {
24 const ListValue
* recommended_value
= NULL
;
25 if (!policy
.GetListWithoutPathExpansion(kRecommended
, &recommended_value
))
27 for (ListValue::const_iterator it
= recommended_value
->begin();
28 it
!= recommended_value
->end(); ++it
) {
30 if ((*it
)->GetAsString(&entry
))
31 result
->SetBooleanWithoutPathExpansion(entry
, true);
35 // Split the given |policy| into its recommended and mandatory settings. The
36 // dictionary |result_editable| contains a |true| value at each path that is
37 // editable by the user.
38 void SplitPolicy(const base::DictionaryValue
& policy
,
39 DictionaryPtr
* result_recommended
,
40 DictionaryPtr
* result_editable
,
41 DictionaryPtr
* result_mandatory
) {
42 result_recommended
->reset(new base::DictionaryValue
);
43 result_editable
->reset(new base::DictionaryValue
);
44 result_mandatory
->reset(new base::DictionaryValue
);
46 MarkRecommendedFieldnames(policy
, result_editable
->get());
48 // Distribute policy's entries into |result_recommended| and |result_editable|
49 // according to |result_editable| and recurse into nested dictionaries.
50 for (base::DictionaryValue::Iterator
it(policy
); it
.HasNext(); it
.Advance()) {
51 if (it
.key() == kRecommended
)
54 const base::DictionaryValue
* child_policy
= NULL
;
55 if (it
.value().GetAsDictionary(&child_policy
)) {
56 DictionaryPtr child_recommended
, child_editable
, child_mandatory
;
57 SplitPolicy(*child_policy
, &child_recommended
, &child_editable
,
60 (*result_recommended
)->SetWithoutPathExpansion(
61 it
.key(), child_recommended
.release());
62 (*result_editable
)->SetWithoutPathExpansion(
63 it
.key(), child_editable
.release());
64 (*result_mandatory
)->SetWithoutPathExpansion(
65 it
.key(), child_mandatory
.release());
67 bool is_recommended
= false;
68 (*result_editable
)->GetBooleanWithoutPathExpansion(it
.key(),
71 (*result_recommended
)->SetWithoutPathExpansion(
72 it
.key(), it
.value().DeepCopy());
74 (*result_mandatory
)->SetWithoutPathExpansion(
75 it
.key(), it
.value().DeepCopy());
81 // Copy values from |user| at paths that are assigned true in |editable|. The
82 // values are copied to a new dictionary which is returned.
83 DictionaryPtr
DeepCopyIf(
84 const base::DictionaryValue
& user
,
85 const base::DictionaryValue
& editable
) {
86 DictionaryPtr
result(new base::DictionaryValue
);
88 for (base::DictionaryValue::Iterator
it(user
); it
.HasNext(); it
.Advance()) {
89 const base::DictionaryValue
* user_child
= NULL
;
90 if (it
.value().GetAsDictionary(&user_child
)) {
91 const base::DictionaryValue
* editable_child
= NULL
;
92 if (editable
.GetDictionaryWithoutPathExpansion(it
.key(),
94 result
->SetWithoutPathExpansion(
95 it
.key(), DeepCopyIf(*user_child
, *editable_child
).release());
99 if (editable
.GetBooleanWithoutPathExpansion(it
.key(), &editable_flag
) &&
101 result
->SetWithoutPathExpansion(it
.key(), it
.value().DeepCopy());
106 return result
.Pass();
109 void MergeDictionaryIfNotNULL(const base::DictionaryValue
* update
,
110 base::DictionaryValue
* result
) {
112 result
->MergeDictionary(update
);
117 DictionaryPtr
MergeSettingsWithPolicies(
118 const base::DictionaryValue
* user_policy
,
119 const base::DictionaryValue
* device_policy
,
120 const base::DictionaryValue
* user_onc
,
121 const base::DictionaryValue
* shared_onc
) {
122 DictionaryPtr user_mandatory
;
123 DictionaryPtr user_editable
;
124 DictionaryPtr user_recommended
;
125 if (user_policy
!= NULL
) {
126 SplitPolicy(*user_policy
, &user_recommended
, &user_editable
,
129 user_mandatory
.reset(new base::DictionaryValue
);
130 user_recommended
.reset(new base::DictionaryValue
);
131 // 'user_editable == NULL' means everything is editable
134 DictionaryPtr device_mandatory
;
135 DictionaryPtr device_editable
;
136 DictionaryPtr device_recommended
;
137 if (device_policy
!= NULL
) {
138 SplitPolicy(*device_policy
, &device_recommended
, &device_editable
,
141 device_mandatory
.reset(new base::DictionaryValue
);
142 device_recommended
.reset(new base::DictionaryValue
);
143 // 'device_editable == NULL' means everything is editable
146 DictionaryPtr
reduced_user_onc(
147 user_onc
!= NULL
? user_onc
->DeepCopy() : new base::DictionaryValue
);
148 if (user_editable
.get() != NULL
)
149 reduced_user_onc
= DeepCopyIf(*reduced_user_onc
, *user_editable
);
150 if (device_editable
.get() != NULL
)
151 reduced_user_onc
= DeepCopyIf(*reduced_user_onc
, *device_editable
);
153 DictionaryPtr
reduced_shared_onc(
154 shared_onc
!= NULL
? shared_onc
->DeepCopy() : new base::DictionaryValue
);
155 if (user_editable
.get() != NULL
)
156 reduced_shared_onc
= DeepCopyIf(*reduced_shared_onc
, *user_editable
);
157 if (device_editable
.get() != NULL
)
158 reduced_shared_onc
= DeepCopyIf(*reduced_shared_onc
, *device_editable
);
160 // Merge the settings layers according to their priority: From lowest to
162 DictionaryPtr
result(new base::DictionaryValue
);
163 MergeDictionaryIfNotNULL(device_recommended
.get(), result
.get());
164 MergeDictionaryIfNotNULL(user_recommended
.get(), result
.get());
165 MergeDictionaryIfNotNULL(reduced_shared_onc
.get(), result
.get());
166 MergeDictionaryIfNotNULL(reduced_user_onc
.get(), result
.get());
167 MergeDictionaryIfNotNULL(device_mandatory
.get(), result
.get());
168 MergeDictionaryIfNotNULL(user_mandatory
.get(), result
.get());
170 return result
.Pass();
174 } // namespace chromeos