OLD | NEW |
| (Empty) |
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 "chrome/browser/chromeos/network_settings/onc_merger.h" | |
6 | |
7 #include <set> | |
8 #include <string> | |
9 | |
10 #include "base/basictypes.h" | |
11 #include "base/logging.h" | |
12 #include "base/values.h" | |
13 #include "chrome/browser/chromeos/cros/onc_constants.h" | |
14 | |
15 namespace chromeos { | |
16 namespace onc { | |
17 namespace { | |
18 | |
19 typedef scoped_ptr<base::DictionaryValue> DictionaryPtr; | |
20 | |
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)) | |
26 return; | |
27 for (ListValue::const_iterator it = recommended_value->begin(); | |
28 it != recommended_value->end(); ++it) { | |
29 std::string entry; | |
30 if ((*it)->GetAsString(&entry)) | |
31 result->SetBooleanWithoutPathExpansion(entry, true); | |
32 } | |
33 } | |
34 | |
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); | |
45 | |
46 MarkRecommendedFieldnames(policy, result_editable->get()); | |
47 | |
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) | |
52 continue; | |
53 | |
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, | |
58 &child_mandatory); | |
59 | |
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()); | |
66 } else { | |
67 bool is_recommended = false; | |
68 (*result_editable)->GetBooleanWithoutPathExpansion(it.key(), | |
69 &is_recommended); | |
70 if (is_recommended) { | |
71 (*result_recommended)->SetWithoutPathExpansion( | |
72 it.key(), it.value().DeepCopy()); | |
73 } else { | |
74 (*result_mandatory)->SetWithoutPathExpansion( | |
75 it.key(), it.value().DeepCopy()); | |
76 } | |
77 } | |
78 } | |
79 } | |
80 | |
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); | |
87 | |
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(), | |
93 &editable_child)) { | |
94 result->SetWithoutPathExpansion( | |
95 it.key(), DeepCopyIf(*user_child, *editable_child).release()); | |
96 } | |
97 } else { | |
98 bool editable_flag; | |
99 if (editable.GetBooleanWithoutPathExpansion(it.key(), &editable_flag) && | |
100 editable_flag) { | |
101 result->SetWithoutPathExpansion(it.key(), it.value().DeepCopy()); | |
102 } | |
103 } | |
104 } | |
105 | |
106 return result.Pass(); | |
107 } | |
108 | |
109 void MergeDictionaryIfNotNULL(const base::DictionaryValue* update, | |
110 base::DictionaryValue* result) { | |
111 if (update != NULL) | |
112 result->MergeDictionary(update); | |
113 } | |
114 | |
115 } // namespace | |
116 | |
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, | |
127 &user_mandatory); | |
128 } else { | |
129 user_mandatory.reset(new base::DictionaryValue); | |
130 user_recommended.reset(new base::DictionaryValue); | |
131 // 'user_editable == NULL' means everything is editable | |
132 } | |
133 | |
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, | |
139 &device_mandatory); | |
140 } else { | |
141 device_mandatory.reset(new base::DictionaryValue); | |
142 device_recommended.reset(new base::DictionaryValue); | |
143 // 'device_editable == NULL' means everything is editable | |
144 } | |
145 | |
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); | |
152 | |
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); | |
159 | |
160 // Merge the settings layers according to their priority: From lowest to | |
161 // highest priority. | |
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()); | |
169 | |
170 return result.Pass(); | |
171 } | |
172 | |
173 } // namespace onc | |
174 } // namespace chromeos | |
OLD | NEW |