regedit: Add new value type selection dialog.
[gd/samba-autobuild/.git] / source3 / utils / regedit.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 "includes.h"
21 #include "popt_common.h"
22 #include "lib/util/data_blob.h"
23 #include "lib/registry/registry.h"
24 #include "regedit.h"
25 #include "regedit_treeview.h"
26 #include "regedit_valuelist.h"
27 #include "regedit_dialog.h"
28 #include <ncurses.h>
29 #include <menu.h>
30 #include <panel.h>
31
32 struct regedit {
33         WINDOW *main_window;
34         PANEL *main_panel;
35         WINDOW *path_label;
36         WINDOW *key_label;
37         WINDOW *value_label;
38         struct value_list *vl;
39         struct tree_view *keys;
40         bool tree_input;
41 };
42
43 /* load all available hives */
44 static struct tree_node *load_hives(TALLOC_CTX *mem_ctx,
45                                     struct registry_context *ctx)
46 {
47         const char *hives[] = {
48                 "HKEY_CLASSES_ROOT",
49                 "HKEY_CURRENT_USER",
50                 "HKEY_LOCAL_MACHINE",
51                 "HKEY_PERFORMANCE_DATA",
52                 "HKEY_USERS",
53                 "HKEY_CURRENT_CONFIG",
54                 "HKEY_DYN_DATA",
55                 "HKEY_PERFORMANCE_TEXT",
56                 "HKEY_PERFORMANCE_NLSTEXT",
57                 NULL
58         };
59         struct tree_node *root, *prev, *node;
60         struct registry_key *key;
61         WERROR rv;
62         size_t i;
63
64         root = NULL;
65         prev = NULL;
66
67         for (i = 0; hives[i] != NULL; ++i) {
68                 rv = reg_get_predefined_key_by_name(ctx, hives[i], &key);
69                 if (!W_ERROR_IS_OK(rv)) {
70                         continue;
71                 }
72
73                 node = tree_node_new(mem_ctx, NULL, hives[i], key);
74                 if (node == NULL) {
75                         return NULL;
76                 }
77
78                 if (root == NULL) {
79                         root = node;
80                 }
81                 if (prev) {
82                         tree_node_append(prev, node);
83                 }
84                 prev = node;
85         }
86
87         return root;
88 }
89
90 static void print_heading(WINDOW *win, bool selected, const char *str)
91 {
92         if (selected) {
93                 wattron(win, A_REVERSE);
94         } else {
95                 wattroff(win, A_REVERSE);
96         }
97         wmove(win, 0, 0);
98         wclrtoeol(win);
99         waddstr(win, str);
100         wnoutrefresh(win);
101         wrefresh(win);
102 }
103
104 static void handle_tree_input(struct regedit *regedit, int c)
105 {
106         struct tree_node *node;
107
108         switch (c) {
109         case KEY_DOWN:
110                 menu_driver(regedit->keys->menu, REQ_DOWN_ITEM);
111                 node = item_userptr(current_item(regedit->keys->menu));
112                 value_list_load(regedit->vl, node->key);
113                 break;
114         case KEY_UP:
115                 menu_driver(regedit->keys->menu, REQ_UP_ITEM);
116                 node = item_userptr(current_item(regedit->keys->menu));
117                 value_list_load(regedit->vl, node->key);
118                 break;
119         case '\n':
120         case KEY_ENTER:
121         case KEY_RIGHT:
122                 node = item_userptr(current_item(regedit->keys->menu));
123                 if (node && tree_node_has_children(node)) {
124                         tree_node_load_children(node);
125                         tree_node_print_path(regedit->path_label,
126                                              node->child_head);
127                         tree_view_update(regedit->keys, node->child_head);
128                         value_list_load(regedit->vl, node->child_head->key);
129                 }
130                 break;
131         case KEY_LEFT:
132                 node = item_userptr(current_item(regedit->keys->menu));
133                 if (node && node->parent) {
134                         tree_node_print_path(regedit->path_label, node->parent);
135                         node = tree_node_first(node->parent);
136                         tree_view_update(regedit->keys, node);
137                         value_list_load(regedit->vl, node->key);
138                 }
139                 break;
140         case 'd':
141         case 'D': {
142                 struct dialog *dia;
143                 int sel;
144
145                 node = item_userptr(current_item(regedit->keys->menu));
146                 dia = dialog_confirm_new(regedit, "Delete Key",
147                                          regedit->main_window,
148                                          "Really delete key \"%s\"?",
149                                          node->name);
150                 sel = dialog_modal_loop(dia);
151                 mvwprintw(regedit->main_window, 1, 0, "Sel: %d", sel);
152                 /* TODO */
153                 break;
154         }
155         }
156
157         tree_view_show(regedit->keys);
158         value_list_show(regedit->vl);
159 }
160
161 static void handle_value_input(struct regedit *regedit, int c)
162 {
163         struct value_item *vitem;
164
165         switch (c) {
166         case KEY_DOWN:
167                 menu_driver(regedit->vl->menu, REQ_DOWN_ITEM);
168                 break;
169         case KEY_UP:
170                 menu_driver(regedit->vl->menu, REQ_UP_ITEM);
171                 break;
172         case '\n':
173         case KEY_ENTER:
174                 vitem = item_userptr(current_item(regedit->vl->menu));
175                 if (vitem) {
176                         struct tree_node *node;
177                         node = item_userptr(current_item(regedit->keys->menu));
178                         dialog_edit_value(regedit, node->key, vitem->type,
179                                           vitem, regedit->main_window);
180                         value_list_load(regedit->vl, node->key);
181                 }
182                 break;
183         case 'n':
184         case 'N': {
185                 int new_type;
186
187                 if (dialog_select_type(regedit, &new_type, regedit->main_window) == DIALOG_OK) {
188                         mvwprintw(regedit->main_window, 1, 0, "Item: %s (%d)", str_regtype(new_type), new_type);
189                 }
190                 break;
191         }
192         case 'd':
193         case 'D':
194                 vitem = item_userptr(current_item(regedit->vl->menu));
195                 if (vitem) {
196                         struct dialog *dia;
197                         int sel;
198
199                         dia = dialog_confirm_new(regedit, "Delete Value",
200                                                  regedit->main_window,
201                                                  "Really delete value \"%s\"?",
202                                                  vitem->value_name);
203                         sel = dialog_modal_loop(dia);
204                         mvwprintw(regedit->main_window, 1, 0, "Sel: %d", sel);
205                 }
206                 break;
207         }
208
209         value_list_show(regedit->vl);
210 }
211
212 static void handle_main_input(struct regedit *regedit, int c)
213 {
214         switch (c) {
215         case '\t':
216                 regedit->tree_input = !regedit->tree_input;
217                 print_heading(regedit->key_label, regedit->tree_input == true,
218                               "Keys");
219                 print_heading(regedit->value_label, regedit->tree_input == false,
220                               "Values");
221                 break;
222         default:
223                 if (regedit->tree_input) {
224                         handle_tree_input(regedit, c);
225                 } else {
226                         handle_value_input(regedit, c);
227                 }
228         }
229 }
230
231 /* test navigating available hives */
232 static void display_test_window(TALLOC_CTX *mem_ctx,
233                                 struct registry_context *ctx)
234 {
235         struct regedit *regedit;
236         struct tree_node *root;
237         int c;
238
239         initscr();
240         start_color();
241         cbreak();
242         noecho();
243         keypad(stdscr, TRUE);
244
245         regedit = talloc_zero(mem_ctx, struct regedit);
246         SMB_ASSERT(regedit != NULL);
247
248         regedit->main_window = newwin(25, 80, 0, 0);
249         SMB_ASSERT(regedit->main_window != NULL);
250
251         keypad(regedit->main_window, TRUE);
252
253         mvwprintw(regedit->main_window, 0, 0, "Path: ");
254         regedit->path_label = derwin(regedit->main_window, 1, 65, 0, 6);
255         wprintw(regedit->path_label, "/");
256
257         root = load_hives(regedit, ctx);
258         SMB_ASSERT(root != NULL);
259
260         regedit->key_label = derwin(regedit->main_window, 1, 10, 2, 0);
261         regedit->value_label = derwin(regedit->main_window, 1, 10, 2, 25);
262
263         print_heading(regedit->key_label, true, "Keys");
264         regedit->keys = tree_view_new(regedit, root, regedit->main_window,
265                                       15, 24, 3, 0);
266         SMB_ASSERT(regedit->keys != NULL);
267
268         print_heading(regedit->value_label, false, "Values");
269         regedit->vl = value_list_new(regedit, regedit->main_window,
270                                      15, 40, 3, 25);
271         SMB_ASSERT(regedit->vl != NULL);
272
273         regedit->tree_input = true;
274
275         tree_view_show(regedit->keys);
276         value_list_show(regedit->vl);
277
278         regedit->main_panel = new_panel(regedit->main_window);
279         SMB_ASSERT(regedit->main_panel != NULL);
280
281         update_panels();
282         doupdate();
283         while ((c = wgetch(regedit->main_window)) != 'q') {
284                 handle_main_input(regedit, c);
285                 update_panels();
286                 doupdate();
287         }
288
289         endwin();
290 }
291
292 int main(int argc, char **argv)
293 {
294         struct poptOption long_options[] = {
295                 POPT_AUTOHELP
296                 /* ... */
297                 POPT_COMMON_SAMBA
298                 POPT_COMMON_CONNECTION
299                 POPT_COMMON_CREDENTIALS
300                 POPT_TABLEEND
301         };
302         int opt;
303         poptContext pc;
304         struct user_auth_info *auth_info;
305         TALLOC_CTX *frame;
306         struct registry_context *ctx;
307         WERROR rv;
308
309         talloc_enable_leak_report_full();
310
311         frame = talloc_stackframe();
312
313         setup_logging("regedit", DEBUG_DEFAULT_STDERR);
314         lp_set_cmdline("log level", "0");
315
316         /* process options */
317         auth_info = user_auth_info_init(frame);
318         if (auth_info == NULL) {
319                 exit(1);
320         }
321         popt_common_set_auth_info(auth_info);
322         pc = poptGetContext("regedit", argc, (const char **)argv, long_options, 0);
323
324         while ((opt = poptGetNextOpt(pc)) != -1) {
325                 /* TODO */
326         }
327
328         if (!lp_load_global(get_dyn_CONFIGFILE())) {
329                 DEBUG(0, ("ERROR loading config file...\n"));
330                 exit(1);
331         }
332
333         /* some simple tests */
334
335         rv = reg_open_samba3(frame, &ctx);
336         if (!W_ERROR_IS_OK(rv)) {
337                 TALLOC_FREE(frame);
338
339                 return 1;
340         }
341
342         display_test_window(frame, ctx);
343
344         //talloc_report_full(frame, stdout);
345
346         TALLOC_FREE(frame);
347
348         return 0;
349 }