regedit: free value list subwindow
[garming/samba-autobuild/.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 #define HEADING_X 3
24
25 static void value_list_free_items(ITEM **items)
26 {
27         size_t i;
28         ITEM *item;
29         struct value_item *vitem;
30
31         if (items == NULL) {
32                 return;
33         }
34
35         for (i = 0; items[i] != NULL; ++i) {
36                 item = items[i];
37                 vitem = item_userptr(item);
38                 SMB_ASSERT(vitem != NULL);
39                 free_item(item);
40         }
41
42         talloc_free(items);
43 }
44
45 static int value_list_free(struct value_list *vl)
46 {
47         if (vl->menu) {
48                 unpost_menu(vl->menu);
49                 free_menu(vl->menu);
50         }
51         if (vl->empty && vl->empty[0]) {
52                 free_item(vl->empty[0]);
53         }
54         if (vl->panel) {
55                 del_panel(vl->panel);
56         }
57         if (vl->sub) {
58                 delwin(vl->sub);
59         }
60         if (vl->window) {
61                 delwin(vl->window);
62         }
63         value_list_free_items(vl->items);
64
65         return 0;
66 }
67
68 struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols,
69                                   int begin_y, int begin_x)
70 {
71         static const char *empty = "(no values)";
72         static const char *empty_desc = "";
73         struct value_list *vl;
74
75         vl = talloc_zero(ctx, struct value_list);
76         if (vl == NULL) {
77                 return NULL;
78         }
79
80         talloc_set_destructor(vl, value_list_free);
81
82         vl->empty = talloc_zero_array(vl, ITEM *, 2);
83         if (vl->empty == NULL) {
84                 goto fail;
85         }
86         vl->empty[0] = new_item(empty, empty_desc);
87         if (vl->empty[0] == NULL) {
88                 goto fail;
89         }
90
91         vl->window = newwin(nlines, ncols, begin_y, begin_x);
92         if (vl->window == NULL) {
93                 goto fail;
94         }
95         vl->sub = subwin(vl->window, nlines - 2, ncols - 2,
96                          begin_y + 1, begin_x + 1);
97         if (vl->sub == NULL) {
98                 goto fail;
99         }
100         box(vl->window, 0, 0);
101         mvwprintw(vl->window, 0, HEADING_X, "Value");
102
103         vl->panel = new_panel(vl->window);
104         if (vl->panel == NULL) {
105                 goto fail;
106         }
107
108         vl->menu = new_menu(vl->empty);
109         if (vl->menu == NULL) {
110                 goto fail;
111         }
112
113         set_menu_format(vl->menu, nlines, 1);
114         set_menu_win(vl->menu, vl->window);
115         set_menu_sub(vl->menu, vl->sub);
116
117         menu_opts_on(vl->menu, O_SHOWDESC);
118         set_menu_mark(vl->menu, "* ");
119
120         return vl;
121
122 fail:
123         talloc_free(vl);
124
125         return NULL;
126 }
127
128 void value_list_set_selected(struct value_list *vl, bool select)
129 {
130         attr_t attr = A_NORMAL;
131
132         if (select) {
133                 attr = A_REVERSE;
134         }
135         mvwchgat(vl->window, 0, HEADING_X, 5, attr, 0, NULL);
136 }
137
138 void value_list_resize(struct value_list *vl, int nlines, int ncols,
139                        int begin_y, int begin_x)
140 {
141         WINDOW *nwin, *nsub;
142
143         unpost_menu(vl->menu);
144         nwin = newwin(nlines, ncols, begin_y, begin_x);
145         nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1);
146         replace_panel(vl->panel, nwin);
147         delwin(vl->sub);
148         delwin(vl->window);
149         vl->window = nwin;
150         vl->sub = nsub;
151         box(vl->window, 0, 0);
152         mvwprintw(vl->window, 0, HEADING_X, "Value");
153         set_menu_format(vl->menu, nlines, 1);
154         set_menu_win(vl->menu, vl->window);
155         set_menu_sub(vl->menu, vl->sub);
156         post_menu(vl->menu);
157 }
158
159 static uint32_t get_num_values(TALLOC_CTX *ctx, const struct registry_key *key)
160 {
161         const char *classname;
162         uint32_t num_subkeys;
163         uint32_t num_values;
164         NTTIME last_change_time;
165         uint32_t max_subkeynamelen;
166         uint32_t max_valnamelen;
167         uint32_t max_valbufsize;
168         WERROR rv;
169
170         rv = reg_key_get_info(ctx, key, &classname, &num_subkeys,
171                               &num_values, &last_change_time,
172                               &max_subkeynamelen, &max_valnamelen,
173                               &max_valbufsize);
174
175         if (W_ERROR_IS_OK(rv)) {
176                 return num_values;
177         }
178
179         return 0;
180 }
181
182 void value_list_show(struct value_list *vl)
183 {
184         post_menu(vl->menu);
185 }
186
187 static bool string_is_printable(const char *s)
188 {
189         const char *p;
190
191         for (p = s; *p; ++p) {
192                 if (!isprint(*p)) {
193                         return false;
194                 }
195         }
196
197         return true;
198 }
199
200 static WERROR append_data_summary(struct value_item *vitem)
201 {
202         char *tmp = NULL;
203
204 /* This is adapted from print_registry_value() in net_registry_util.c */
205
206         switch(vitem->type) {
207         case REG_DWORD: {
208                 uint32_t v = 0;
209                 if (vitem->data.length >= 4) {
210                         v = IVAL(vitem->data.data, 0);
211                 }
212                 tmp = talloc_asprintf_append(vitem->value_desc, "(0x%x)", v);
213                 break;
214         }
215         case REG_SZ:
216         case REG_EXPAND_SZ: {
217                 const char *s;
218
219                 if (!pull_reg_sz(vitem, &vitem->data, &s)) {
220                         break;
221                 }
222                 vitem->unprintable = !string_is_printable(s);
223                 if (vitem->unprintable) {
224                         tmp = talloc_asprintf_append(vitem->value_desc,
225                                                      "(unprintable)");
226                 } else {
227                         tmp = talloc_asprintf_append(vitem->value_desc,
228                                                      "(\"%s\")", s);
229                 }
230                 break;
231         }
232         case REG_MULTI_SZ: {
233                 size_t i;
234                 const char **a;
235
236                 if (!pull_reg_multi_sz(vitem, &vitem->data, &a)) {
237                         break;
238                 }
239                 tmp = vitem->value_desc;
240                 for (i = 0; a[i] != NULL; ++i) {
241                         if (!string_is_printable(a[i])) {
242                                 tmp = talloc_asprintf_append(tmp,
243                                                              "(unprintable)");
244                                 vitem->unprintable = true;
245                         } else {
246                                 tmp = talloc_asprintf_append(tmp, "\"%s\" ",
247                                                              a[i]);
248                         }
249                         if (tmp == NULL) {
250                                 return WERR_NOMEM;
251                         }
252                 }
253                 break;
254         }
255         case REG_BINARY:
256                 tmp = talloc_asprintf_append(vitem->value_desc, "(%d bytes)",
257                                              (int)vitem->data.length);
258                 break;
259         default:
260                 tmp = talloc_asprintf_append(vitem->value_desc,
261                                              "(<unprintable>)");
262                 break;
263         }
264
265         if (tmp == NULL) {
266                 return WERR_NOMEM;
267         }
268
269         vitem->value_desc = tmp;
270
271         return WERR_OK;
272 }
273
274 WERROR value_list_load(struct value_list *vl, struct registry_key *key)
275 {
276         uint32_t n_values;
277         uint32_t idx;
278         struct value_item *vitem;
279         ITEM **new_items;
280         WERROR rv;
281         static const char *empty_name = "(empty)";
282         const char *name;
283
284         unpost_menu(vl->menu);
285
286         n_values = get_num_values(vl, key);
287         if (n_values == 0) {
288                 set_menu_items(vl->menu, vl->empty);
289                 return WERR_OK;
290         }
291
292         new_items = talloc_zero_array(vl, ITEM *, n_values + 1);
293         if (new_items == NULL) {
294                 return WERR_NOMEM;
295         }
296
297         for (idx = 0; idx < n_values; ++idx) {
298                 vitem = talloc_zero(new_items, struct value_item);
299                 if (vitem == NULL) {
300                         return WERR_NOMEM;
301                 }
302
303                 rv = reg_key_get_value_by_index(vitem, key, idx,
304                                                 &vitem->value_name,
305                                                 &vitem->type,
306                                                 &vitem->data);
307
308                 if (!W_ERROR_IS_OK(rv)) {
309                         talloc_free(vitem);
310                         return rv;
311                 }
312
313                 vitem->value_desc = talloc_asprintf(vitem, "%-14s",
314                         str_regtype(vitem->type));
315                 if (vitem->value_desc == NULL) {
316                         talloc_free(vitem);
317                         return rv;
318                 }
319
320                 rv = append_data_summary(vitem);
321                 if (!W_ERROR_IS_OK(rv)) {
322                         talloc_free(vitem);
323                         return rv;
324                 }
325
326                 /* ncurses won't accept empty strings in menu items */
327                 name = vitem->value_name;
328                 if (name[0] == '\0') {
329                         name = empty_name;
330                 }
331                 new_items[idx] = new_item(name, vitem->value_desc);
332                 if (new_items[idx] == NULL) {
333                         talloc_free(vitem);
334                         return WERR_NOMEM;
335                 }
336
337                 set_item_userptr(new_items[idx], vitem);
338         }
339
340         set_menu_items(vl->menu, new_items);
341         value_list_free_items(vl->items);
342         vl->items = new_items;
343
344         return WERR_OK;
345 }