build: Remove unused script/mkversion.sh
[obnox/samba/samba-obnox.git] / source3 / utils / regedit_valuelist.c
1 /*
2  * Samba Unix/Linux SMB client library
3  * Registry Editor
4  * Copyright (C) Christopher Davis 2012
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "regedit_valuelist.h"
21 #include "lib/registry/registry.h"
22
23 static void value_list_free_items(ITEM **items)
24 {
25         size_t i;
26         ITEM *item;
27         struct value_item *vitem;
28
29         if (items == NULL) {
30                 return;
31         }
32
33         for (i = 0; items[i] != NULL; ++i) {
34                 item = items[i];
35                 vitem = item_userptr(item);
36                 SMB_ASSERT(vitem != NULL);
37                 free_item(item);
38         }
39
40         talloc_free(items);
41 }
42
43 static int value_list_free(struct value_list *vl)
44 {
45         if (vl->menu) {
46                 unpost_menu(vl->menu);
47                 free_menu(vl->menu);
48         }
49         if (vl->empty && vl->empty[0]) {
50                 free_item(vl->empty[0]);
51         }
52         if (vl->panel) {
53                 del_panel(vl->panel);
54         }
55         if (vl->window) {
56                 delwin(vl->window);
57         }
58         value_list_free_items(vl->items);
59
60         return 0;
61 }
62
63 struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols,
64                                   int begin_y, int begin_x)
65 {
66         static const char *empty = "(no values)";
67         static const char *empty_desc = "";
68         struct value_list *vl;
69
70         vl = talloc_zero(ctx, struct value_list);
71         if (vl == NULL) {
72                 return NULL;
73         }
74
75         talloc_set_destructor(vl, value_list_free);
76
77         vl->empty = talloc_zero_array(vl, ITEM *, 2);
78         if (vl->empty == NULL) {
79                 goto fail;
80         }
81         vl->empty[0] = new_item(empty, empty_desc);
82         if (vl->empty[0] == NULL) {
83                 goto fail;
84         }
85
86         vl->window = newwin(nlines, ncols, begin_y, begin_x);
87         if (vl->window == NULL) {
88                 goto fail;
89         }
90         vl->panel = new_panel(vl->window);
91         if (vl->panel == NULL) {
92                 goto fail;
93         }
94
95         vl->menu = new_menu(vl->empty);
96         if (vl->menu == NULL) {
97                 goto fail;
98         }
99
100         set_menu_format(vl->menu, nlines, 1);
101         set_menu_win(vl->menu, vl->window);
102
103         menu_opts_on(vl->menu, O_SHOWDESC);
104         set_menu_mark(vl->menu, "* ");
105
106         return vl;
107
108 fail:
109         talloc_free(vl);
110
111         return NULL;
112 }
113
114 void value_list_resize(struct value_list *vl, int nlines, int ncols,
115                        int begin_y, int begin_x)
116 {
117         WINDOW *nwin;
118
119         unpost_menu(vl->menu);
120         nwin = newwin(nlines, ncols, begin_y, begin_x);
121         replace_panel(vl->panel, nwin);
122         delwin(vl->window);
123         vl->window = nwin;
124         set_menu_format(vl->menu, nlines, 1);
125         set_menu_win(vl->menu, vl->window);
126         post_menu(vl->menu);
127 }
128
129 static uint32_t get_num_values(TALLOC_CTX *ctx, const struct registry_key *key)
130 {
131         const char *classname;
132         uint32_t num_subkeys;
133         uint32_t num_values;
134         NTTIME last_change_time;
135         uint32_t max_subkeynamelen;
136         uint32_t max_valnamelen;
137         uint32_t max_valbufsize;
138         WERROR rv;
139
140         rv = reg_key_get_info(ctx, key, &classname, &num_subkeys,
141                               &num_values, &last_change_time,
142                               &max_subkeynamelen, &max_valnamelen,
143                               &max_valbufsize);
144
145         if (W_ERROR_IS_OK(rv)) {
146                 return num_values;
147         }
148
149         return 0;
150 }
151
152 void value_list_show(struct value_list *vl)
153 {
154         post_menu(vl->menu);
155 }
156
157 static bool string_is_printable(const char *s)
158 {
159         const char *p;
160
161         for (p = s; *p; ++p) {
162                 if (!isprint(*p)) {
163                         return false;
164                 }
165         }
166
167         return true;
168 }
169
170 static WERROR append_data_summary(struct value_item *vitem)
171 {
172         char *tmp;
173
174 /* This is adapted from print_registry_value() in net_registry_util.c */
175
176         switch(vitem->type) {
177         case REG_DWORD: {
178                 uint32_t v = 0;
179                 if (vitem->data.length >= 4) {
180                         v = IVAL(vitem->data.data, 0);
181                 }
182                 tmp = talloc_asprintf_append(vitem->value_desc, "(0x%x)", v);
183                 break;
184         }
185         case REG_SZ:
186         case REG_EXPAND_SZ: {
187                 const char *s;
188
189                 if (!pull_reg_sz(vitem, &vitem->data, &s)) {
190                         break;
191                 }
192                 vitem->unprintable = !string_is_printable(s);
193                 if (vitem->unprintable) {
194                         tmp = talloc_asprintf_append(vitem->value_desc,
195                                                      "(unprintable)");
196                 } else {
197                         tmp = talloc_asprintf_append(vitem->value_desc,
198                                                      "(\"%s\")", s);
199                 }
200                 break;
201         }
202         case REG_MULTI_SZ: {
203                 size_t i;
204                 const char **a;
205
206                 if (!pull_reg_multi_sz(vitem, &vitem->data, &a)) {
207                         break;
208                 }
209                 tmp = vitem->value_desc;
210                 for (i = 0; a[i] != NULL; ++i) {
211                         if (!string_is_printable(a[i])) {
212                                 tmp = talloc_asprintf_append(tmp,
213                                                              "(unprintable)");
214                                 vitem->unprintable = true;
215                         } else {
216                                 tmp = talloc_asprintf_append(tmp, "\"%s\" ",
217                                                              a[i]);
218                         }
219                         if (tmp == NULL) {
220                                 return WERR_NOMEM;
221                         }
222                 }
223                 break;
224         }
225         case REG_BINARY:
226                 tmp = talloc_asprintf_append(vitem->value_desc, "(%d bytes)",
227                                              (int)vitem->data.length);
228                 break;
229         default:
230                 tmp = talloc_asprintf_append(vitem->value_desc,
231                                              "(<unprintable>)");
232                 break;
233         }
234
235         if (tmp == NULL) {
236                 return WERR_NOMEM;
237         }
238
239         vitem->value_desc = tmp;
240
241         return WERR_OK;
242 }
243
244 WERROR value_list_load(struct value_list *vl, struct registry_key *key)
245 {
246         uint32_t n_values;
247         uint32_t idx;
248         struct value_item *vitem;
249         ITEM **new_items;
250         WERROR rv;
251         static const char *empty_name = "(empty)";
252         const char *name;
253
254         unpost_menu(vl->menu);
255
256         n_values = get_num_values(vl, key);
257         if (n_values == 0) {
258                 set_menu_items(vl->menu, vl->empty);
259                 return WERR_OK;
260         }
261
262         new_items = talloc_zero_array(vl, ITEM *, n_values + 1);
263         if (new_items == NULL) {
264                 return WERR_NOMEM;
265         }
266
267         for (idx = 0; idx < n_values; ++idx) {
268                 vitem = talloc_zero(new_items, struct value_item);
269                 if (vitem == NULL) {
270                         return WERR_NOMEM;
271                 }
272
273                 rv = reg_key_get_value_by_index(vitem, key, idx,
274                                                 &vitem->value_name,
275                                                 &vitem->type,
276                                                 &vitem->data);
277
278                 if (!W_ERROR_IS_OK(rv)) {
279                         talloc_free(vitem);
280                         return rv;
281                 }
282
283                 vitem->value_desc = talloc_asprintf(vitem, "%-14s",
284                         str_regtype(vitem->type));
285                 if (vitem->value_desc == NULL) {
286                         talloc_free(vitem);
287                         return rv;
288                 }
289
290                 rv = append_data_summary(vitem);
291                 if (!W_ERROR_IS_OK(rv)) {
292                         talloc_free(vitem);
293                         return rv;
294                 }
295
296                 /* ncurses won't accept empty strings in menu items */
297                 name = vitem->value_name;
298                 if (name[0] == '\0') {
299                         name = empty_name;
300                 }
301                 new_items[idx] = new_item(name, vitem->value_desc);
302                 if (new_items[idx] == NULL) {
303                         talloc_free(vitem);
304                         return WERR_NOMEM;
305                 }
306
307                 set_item_userptr(new_items[idx], vitem);
308         }
309
310         set_menu_items(vl->menu, new_items);
311         value_list_free_items(vl->items);
312         vl->items = new_items;
313
314         return WERR_OK;
315 }