2 * Samba Unix/Linux SMB client library
4 * Copyright (C) Christopher Davis 2012
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.
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.
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/>.
21 #include "popt_common_cmdline.h"
22 #include "lib/util/data_blob.h"
23 #include "lib/registry/registry.h"
25 #include "regedit_treeview.h"
26 #include "regedit_valuelist.h"
27 #include "regedit_dialog.h"
28 #include "regedit_list.h"
35 #define KEY_WIDTH (COLS / 4)
36 #define KEY_HEIGHT (LINES - KEY_START_Y - 2)
37 #define VAL_START_X KEY_WIDTH
39 #define VAL_WIDTH (COLS - KEY_WIDTH)
40 #define VAL_HEIGHT (LINES - VAL_START_Y - 2)
42 #define HELP1_START_Y (LINES - 2)
43 #define HELP1_START_X 0
44 #define HELP1_WIDTH (LINES)
45 #define HELP2_START_Y (LINES - 1)
46 #define HELP2_START_X 0
47 #define HELP2_WIDTH (LINES)
48 #define PATH_START_Y 0
49 #define PATH_START_X 6
50 #define PATH_MAX_Y (COLS - 1)
51 #define PATH_WIDTH (COLS - 6)
52 #define PATH_WIDTH_MAX 1024
55 struct registry_context
*registry_context
;
59 struct value_list
*vl
;
60 struct tree_view
*keys
;
62 struct regedit_search_opts active_search
;
65 static struct regedit
*regedit_main
= NULL
;
67 static void show_path(struct regedit
*regedit
)
70 int start_win
= PATH_START_X
;
72 if (PATH_START_X
+ regedit
->path_len
> COLS
) {
73 start_pad
= 3 + PATH_START_X
+ regedit
->path_len
- COLS
;
74 mvprintw(PATH_START_Y
, start_win
, "...");
77 copywin(regedit
->path_label
, regedit
->main_window
, 0, start_pad
,
78 PATH_START_Y
, start_win
, PATH_START_Y
, PATH_MAX_Y
, false);
80 mvchgat(0, 0, COLS
, A_BOLD
, PAIR_YELLOW_CYAN
, NULL
);
83 static void print_path(struct regedit
*regedit
, struct tree_node
*node
)
85 regedit
->path_len
= tree_node_print_path(regedit
->path_label
, node
);
89 static void print_help(struct regedit
*regedit
)
91 const char *khelp
= "[n] New Key [s] New Subkey [d] Del Key "
92 "[LEFT] Ascend [RIGHT] Descend";
93 const char *vhelp
= "[n] New Value [d] Del Value [ENTER] Edit "
95 const char *msg
= "KEYS";
96 const char *help
= khelp
;
97 const char *genhelp
= "[TAB] Switch sections [q] Quit "
98 "[UP] List up [DOWN] List down "
99 "[/] Search [x] Next";
102 if (!regedit
->tree_input
) {
107 move(HELP1_START_Y
, HELP1_START_X
);
109 attron(COLOR_PAIR(PAIR_BLACK_CYAN
));
110 mvaddstr(HELP1_START_Y
, HELP1_START_X
, help
);
111 pad
= COLS
- strlen(msg
) - strlen(help
);
112 for (i
= 0; i
< pad
; ++i
) {
115 attroff(COLOR_PAIR(PAIR_BLACK_CYAN
));
116 attron(COLOR_PAIR(PAIR_YELLOW_CYAN
) | A_BOLD
);
118 attroff(COLOR_PAIR(PAIR_YELLOW_CYAN
) | A_BOLD
);
120 move(HELP2_START_Y
, HELP2_START_X
);
122 mvaddstr(HELP2_START_Y
, HELP2_START_X
, genhelp
);
125 static void print_heading(struct regedit
*regedit
)
127 if (regedit
->tree_input
) {
128 tree_view_set_selected(regedit
->keys
, true);
129 value_list_set_selected(regedit
->vl
, false);
131 tree_view_set_selected(regedit
->keys
, false);
132 value_list_set_selected(regedit
->vl
, true);
138 static void load_values(struct regedit
*regedit
)
140 struct tree_node
*node
;
142 node
= tree_view_get_current_node(regedit
->keys
);
143 value_list_load(regedit
->vl
, node
->key
);
146 static void add_reg_key(struct regedit
*regedit
, struct tree_node
*node
,
152 if (!subkey
&& tree_node_is_top_level(node
)) {
156 msg
= "Enter name of new key";
158 msg
= "Enter name of new subkey";
160 dialog_input(regedit
, &name
, "New Key", "%s", msg
);
163 struct registry_key
*new_key
;
164 struct tree_node
*new_node
= NULL
;
165 struct tree_node
*list
;
166 struct tree_node
*parent
;
170 list
= node
->child_head
;
172 parent
= node
->parent
;
173 list
= tree_node_first(node
);
174 SMB_ASSERT(list
!= NULL
);
176 rv
= reg_key_add_name(regedit
, parent
->key
, name
,
177 NULL
, NULL
, &new_key
);
178 if (W_ERROR_IS_OK(rv
)) {
179 /* The list of subkeys may not be present in
180 cache yet, so if not, don't bother allocating
181 a new node for the key. */
183 new_node
= tree_node_new(parent
, parent
,
185 SMB_ASSERT(new_node
);
186 tree_node_insert_sorted(list
, new_node
);
188 /* Reopen the parent key to make sure the
189 new subkey will be noticed. */
190 tree_node_reopen_key(regedit
->registry_context
,
194 list
= tree_node_first(node
);
195 tree_view_clear(regedit
->keys
);
196 tree_view_update(regedit
->keys
, list
);
200 tree_view_set_current_node(regedit
->keys
, node
);
201 load_values(regedit
);
203 msg
= get_friendly_werror_msg(rv
);
204 dialog_notice(regedit
, DIA_ALERT
, "New Key",
205 "Failed to create key: %s", msg
);
207 talloc_free(discard_const(name
));
212 SEARCH_NEXT
= (1<<0),
213 SEARCH_PREV
= (1<<1),
214 SEARCH_REPEAT
= (1<<2)
216 static WERROR
regedit_search(struct regedit
*regedit
, struct tree_node
*node
,
217 struct value_item
*vitem
, unsigned flags
)
219 struct regedit_search_opts
*opts
;
220 struct tree_node
*found
;
221 struct value_item
*found_value
;
222 bool search_key
, need_sync
;
223 char *save_value_name
;
225 bool (*iterate
)(struct tree_node
**, bool, WERROR
*);
226 struct value_item
*(*find_item
)(struct value_list
*,
229 regedit_search_match_fn_t
);
231 opts
= ®edit
->active_search
;
233 if (!opts
->query
|| !opts
->match
) {
237 SMB_ASSERT(opts
->search_key
|| opts
->search_value
);
242 save_value_name
= NULL
;
243 search_key
= opts
->search_key
;
245 iterate
= tree_node_next
;
246 find_item
= value_list_find_next_item
;
248 if (flags
& SEARCH_PREV
) {
249 iterate
= tree_node_prev
;
250 find_item
= value_list_find_prev_item
;
253 if (opts
->search_value
) {
254 struct value_item
*it
;
256 it
= value_list_get_current_item(regedit
->vl
);
258 save_value_name
= talloc_strdup(regedit
,
260 if (save_value_name
== NULL
) {
261 return WERR_NOT_ENOUGH_MEMORY
;
270 if (!vitem
&& (flags
& SEARCH_REPEAT
)) {
271 if (opts
->search_value
) {
273 } else if (!iterate(&node
, opts
->search_recursive
, &rv
)) {
281 SMB_ASSERT(opts
->search_key
== true);
282 if (opts
->match(node
->name
, opts
->query
)) {
284 } else if (opts
->search_value
) {
289 SMB_ASSERT(opts
->search_value
== true);
291 rv
= value_list_load_quick(regedit
->vl
,
293 if (!W_ERROR_IS_OK(rv
)) {
298 found_value
= find_item(regedit
->vl
, vitem
, opts
->query
,
304 search_key
= opts
->search_key
;
307 } while (!found
&& iterate(&node
, opts
->search_recursive
, &rv
));
309 if (!W_ERROR_IS_OK(rv
)) {
314 /* Put the cursor on the node that was found */
315 if (!tree_view_is_node_visible(regedit
->keys
, found
)) {
316 tree_view_update(regedit
->keys
,
317 tree_node_first(found
));
318 print_path(regedit
, found
);
320 tree_view_set_current_node(regedit
->keys
, found
);
323 value_list_sync(regedit
->vl
);
325 value_list_set_current_item(regedit
->vl
, found_value
);
326 regedit
->tree_input
= false;
328 load_values(regedit
);
329 regedit
->tree_input
= true;
331 tree_view_show(regedit
->keys
);
332 value_list_show(regedit
->vl
);
333 print_heading(regedit
);
336 load_values(regedit
);
337 value_list_set_current_item_by_name(regedit
->vl
,
344 talloc_free(save_value_name
);
349 static void regedit_search_repeat(struct regedit
*regedit
, unsigned flags
)
351 struct tree_node
*node
;
352 struct value_item
*vitem
;
353 struct regedit_search_opts
*opts
;
355 opts
= ®edit
->active_search
;
356 if (opts
->query
== NULL
) {
360 node
= tree_view_get_current_node(regedit
->keys
);
362 if (opts
->search_value
&& !regedit
->tree_input
) {
363 vitem
= value_list_get_current_item(regedit
->vl
);
365 regedit_search(regedit
, node
, vitem
, flags
| SEARCH_REPEAT
);
368 static void handle_tree_input(struct regedit
*regedit
, int c
)
370 struct tree_node
*node
;
374 tree_view_driver(regedit
->keys
, ML_CURSOR_DOWN
);
375 load_values(regedit
);
378 tree_view_driver(regedit
->keys
, ML_CURSOR_UP
);
379 load_values(regedit
);
382 tree_view_driver(regedit
->keys
, ML_CURSOR_PGDN
);
383 load_values(regedit
);
386 tree_view_driver(regedit
->keys
, ML_CURSOR_PGUP
);
387 load_values(regedit
);
390 tree_view_driver(regedit
->keys
, ML_CURSOR_HOME
);
391 load_values(regedit
);
394 tree_view_driver(regedit
->keys
, ML_CURSOR_END
);
395 load_values(regedit
);
400 node
= tree_view_get_current_node(regedit
->keys
);
401 if (node
&& tree_node_has_children(node
)) {
404 rv
= tree_node_load_children(node
);
405 if (W_ERROR_IS_OK(rv
)) {
406 print_path(regedit
, node
->child_head
);
407 tree_view_update(regedit
->keys
, node
->child_head
);
408 value_list_load(regedit
->vl
, node
->child_head
->key
);
410 const char *msg
= get_friendly_werror_msg(rv
);
411 dialog_notice(regedit
, DIA_ALERT
, "Loading Subkeys",
412 "Failed to load subkeys: %s", msg
);
417 node
= tree_view_get_current_node(regedit
->keys
);
418 if (node
&& !tree_node_is_top_level(node
)) {
419 print_path(regedit
, node
->parent
);
421 tree_view_update(regedit
->keys
, tree_node_first(node
));
422 tree_view_set_current_node(regedit
->keys
, node
);
423 value_list_load(regedit
->vl
, node
->key
);
428 node
= tree_view_get_current_node(regedit
->keys
);
429 add_reg_key(regedit
, node
, false);
433 node
= tree_view_get_current_node(regedit
->keys
);
434 add_reg_key(regedit
, node
, true);
440 node
= tree_view_get_current_node(regedit
->keys
);
441 if (tree_node_is_top_level(node
)) {
444 sel
= dialog_notice(regedit
, DIA_CONFIRM
,
446 "Really delete key \"%s\"?",
448 if (sel
== DIALOG_OK
) {
450 struct tree_node
*pop
;
451 struct tree_node
*parent
= node
->parent
;
453 rv
= reg_key_del(node
, parent
->key
, node
->name
);
454 if (W_ERROR_IS_OK(rv
)) {
455 tree_node_reopen_key(regedit
->registry_context
,
457 tree_view_clear(regedit
->keys
);
458 pop
= tree_node_pop(&node
);
460 node
= parent
->child_head
;
462 node
= tree_node_first(parent
);
463 print_path(regedit
, node
);
465 tree_view_update(regedit
->keys
, node
);
466 value_list_load(regedit
->vl
, node
->key
);
468 const char *msg
= get_friendly_werror_msg(rv
);
469 dialog_notice(regedit
, DIA_ALERT
, "Delete Key",
470 "Failed to delete key: %s", msg
);
477 tree_view_show(regedit
->keys
);
478 value_list_show(regedit
->vl
);
481 static void handle_value_input(struct regedit
*regedit
, int c
)
483 struct value_item
*vitem
;
484 bool binmode
= false;
490 value_list_driver(regedit
->vl
, ML_CURSOR_DOWN
);
493 value_list_driver(regedit
->vl
, ML_CURSOR_UP
);
496 value_list_driver(regedit
->vl
, ML_CURSOR_PGDN
);
499 value_list_driver(regedit
->vl
, ML_CURSOR_PGUP
);
502 value_list_driver(regedit
->vl
, ML_CURSOR_HOME
);
505 value_list_driver(regedit
->vl
, ML_CURSOR_END
);
514 vitem
= value_list_get_current_item(regedit
->vl
);
516 struct tree_node
*node
;
517 const char *name
= NULL
;
518 node
= tree_view_get_current_node(regedit
->keys
);
519 sel
= dialog_edit_value(regedit
, node
->key
, vitem
->type
,
520 vitem
, binmode
, &err
, &name
);
521 if (!W_ERROR_IS_OK(err
)) {
522 const char *msg
= get_friendly_werror_msg(err
);
523 dialog_notice(regedit
, DIA_ALERT
, "Error",
524 "Error editing value:\n%s", msg
);
525 } else if (sel
== DIALOG_OK
) {
526 tree_node_reopen_key(regedit
->registry_context
,
528 value_list_load(regedit
->vl
, node
->key
);
529 value_list_set_current_item_by_name(regedit
->vl
,
531 talloc_free(discard_const(name
));
539 sel
= dialog_select_type(regedit
, &new_type
);
540 if (sel
== DIALOG_OK
) {
541 struct tree_node
*node
;
542 const char *name
= NULL
;
543 node
= tree_view_get_current_node(regedit
->keys
);
544 sel
= dialog_edit_value(regedit
, node
->key
, new_type
,
545 NULL
, false, &err
, &name
);
546 if (!W_ERROR_IS_OK(err
)) {
547 const char *msg
= get_friendly_werror_msg(err
);
548 dialog_notice(regedit
, DIA_ALERT
, "Error",
549 "Error creating value:\n%s", msg
);
550 } else if (sel
== DIALOG_OK
) {
551 tree_node_reopen_key(regedit
->registry_context
,
553 value_list_load(regedit
->vl
, node
->key
);
554 value_list_set_current_item_by_name(regedit
->vl
,
556 talloc_free(discard_const(name
));
563 vitem
= value_list_get_current_item(regedit
->vl
);
565 sel
= dialog_notice(regedit
, DIA_CONFIRM
,
567 "Really delete value \"%s\"?",
569 if (sel
== DIALOG_OK
) {
570 struct tree_node
*node
;
571 node
= tree_view_get_current_node(regedit
->keys
);
572 reg_del_value(regedit
, node
->key
,
574 tree_node_reopen_key(regedit
->registry_context
,
576 value_list_load(regedit
->vl
, node
->key
);
582 value_list_show(regedit
->vl
);
585 static bool find_substring(const char *haystack
, const char *needle
)
587 return strstr(haystack
, needle
) != NULL
;
590 static bool find_substring_nocase(const char *haystack
, const char *needle
)
592 return strcasestr(haystack
, needle
) != NULL
;
595 static void handle_main_input(struct regedit
*regedit
, int c
)
598 case 18: { /* CTRL-R */
599 struct tree_node
*root
, *node
;
602 node
= tree_view_get_current_node(regedit
->keys
);
603 path
= tree_node_get_path(regedit
, node
);
604 SMB_ASSERT(path
!= NULL
);
606 root
= tree_node_new_root(regedit
, regedit
->registry_context
);
607 SMB_ASSERT(root
!= NULL
);
609 tree_view_set_root(regedit
->keys
, root
);
610 tree_view_set_path(regedit
->keys
, path
);
611 node
= tree_view_get_current_node(regedit
->keys
);
612 value_list_load(regedit
->vl
, node
->key
);
613 tree_view_show(regedit
->keys
);
614 value_list_show(regedit
->vl
);
615 print_path(regedit
, node
);
616 talloc_free(discard_const(path
));
623 struct regedit_search_opts
*opts
;
624 struct tree_node
*node
;
626 opts
= ®edit
->active_search
;
627 rv
= dialog_search_input(regedit
, opts
);
628 if (rv
== DIALOG_OK
) {
629 SMB_ASSERT(opts
->query
!= NULL
);
630 opts
->match
= find_substring_nocase
;
631 node
= regedit
->keys
->root
->child_head
;
632 if (opts
->search_case
) {
633 opts
->match
= find_substring
;
635 if (!opts
->search_recursive
) {
636 node
= tree_view_get_current_node(regedit
->keys
);
637 node
= tree_node_first(node
);
639 regedit_search(regedit
, node
, NULL
, SEARCH_NEXT
);
644 regedit_search_repeat(regedit
, SEARCH_NEXT
);
647 regedit_search_repeat(regedit
, SEARCH_PREV
);
650 regedit
->tree_input
= !regedit
->tree_input
;
651 print_heading(regedit
);
654 if (regedit
->tree_input
) {
655 handle_tree_input(regedit
, c
);
657 handle_value_input(regedit
, c
);
662 int regedit_getch(void)
666 SMB_ASSERT(regedit_main
);
669 if (c
== KEY_RESIZE
) {
670 tree_view_resize(regedit_main
->keys
, KEY_HEIGHT
, KEY_WIDTH
,
671 KEY_START_Y
, KEY_START_X
);
672 value_list_resize(regedit_main
->vl
, VAL_HEIGHT
, VAL_WIDTH
,
673 VAL_START_Y
, VAL_START_X
);
674 print_heading(regedit_main
);
675 show_path(regedit_main
);
681 static void regedit_panic_handler(const char *msg
)
687 static void display_window(TALLOC_CTX
*mem_ctx
, struct registry_context
*ctx
)
689 struct regedit
*regedit
;
690 struct tree_node
*root
;
699 fault_configure(regedit_panic_handler
);
701 colors
= has_colors();
704 use_default_colors();
705 assume_default_colors(COLOR_WHITE
, COLOR_BLUE
);
706 init_pair(PAIR_YELLOW_CYAN
, COLOR_YELLOW
, COLOR_CYAN
);
707 init_pair(PAIR_BLACK_CYAN
, COLOR_BLACK
, COLOR_CYAN
);
708 init_pair(PAIR_YELLOW_BLUE
, COLOR_YELLOW
, COLOR_BLUE
);
711 regedit
= talloc_zero(mem_ctx
, struct regedit
);
712 SMB_ASSERT(regedit
!= NULL
);
713 regedit_main
= regedit
;
715 regedit
->registry_context
= ctx
;
716 regedit
->main_window
= stdscr
;
717 keypad(regedit
->main_window
, TRUE
);
719 mvwprintw(regedit
->main_window
, 0, 0, "Path: ");
720 regedit
->path_label
= newpad(1, PATH_WIDTH_MAX
);
721 SMB_ASSERT(regedit
->path_label
);
722 wprintw(regedit
->path_label
, "/");
723 show_path(regedit_main
);
725 root
= tree_node_new_root(regedit
, ctx
);
726 SMB_ASSERT(root
!= NULL
);
728 regedit
->keys
= tree_view_new(regedit
, root
, KEY_HEIGHT
, KEY_WIDTH
,
729 KEY_START_Y
, KEY_START_X
);
730 SMB_ASSERT(regedit
->keys
!= NULL
);
732 regedit
->vl
= value_list_new(regedit
, VAL_HEIGHT
, VAL_WIDTH
,
733 VAL_START_Y
, VAL_START_X
);
734 SMB_ASSERT(regedit
->vl
!= NULL
);
736 regedit
->tree_input
= true;
737 print_heading(regedit
);
739 tree_view_show(regedit
->keys
);
740 load_values(regedit
);
741 value_list_show(regedit
->vl
);
747 key
= regedit_getch();
749 handle_main_input(regedit
, key
);
752 } while (key
!= 'q' && key
!= 'Q');
757 int main(int argc
, const char **argv
)
759 struct poptOption long_options
[] = {
763 POPT_COMMON_CONNECTION
764 POPT_COMMON_CREDENTIALS
770 struct registry_context
*ctx
;
773 frame
= talloc_stackframe();
775 setup_logging("regedit", DEBUG_DEFAULT_STDERR
);
776 lp_set_cmdline("log level", "0");
778 /* process options */
779 pc
= poptGetContext("regedit", argc
, argv
, long_options
, 0);
781 while ((opt
= poptGetNextOpt(pc
)) != -1) {
785 rv
= reg_open_samba3(frame
, &ctx
);
786 if (!W_ERROR_IS_OK(rv
)) {
787 fprintf(stderr
, "Unable to open registry: %s\n",
794 display_window(frame
, ctx
);