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