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 "lib/cmdline/cmdline.h"
22 #include "lib/param/param.h"
23 #include "lib/util/data_blob.h"
24 #include "lib/registry/registry.h"
26 #include "regedit_treeview.h"
27 #include "regedit_valuelist.h"
28 #include "regedit_dialog.h"
29 #include "regedit_list.h"
36 #define KEY_WIDTH (COLS / 4)
37 #define KEY_HEIGHT (LINES - KEY_START_Y - 2)
38 #define VAL_START_X KEY_WIDTH
40 #define VAL_WIDTH (COLS - KEY_WIDTH)
41 #define VAL_HEIGHT (LINES - VAL_START_Y - 2)
43 #define HELP1_START_Y (LINES - 2)
44 #define HELP1_START_X 0
45 #define HELP1_WIDTH (LINES)
46 #define HELP2_START_Y (LINES - 1)
47 #define HELP2_START_X 0
48 #define HELP2_WIDTH (LINES)
49 #define PATH_START_Y 0
50 #define PATH_START_X 6
51 #define PATH_MAX_Y (COLS - 1)
52 #define PATH_WIDTH (COLS - 6)
53 #define PATH_WIDTH_MAX 1024
56 struct registry_context
*registry_context
;
60 struct value_list
*vl
;
61 struct tree_view
*keys
;
63 struct regedit_search_opts active_search
;
66 static struct regedit
*regedit_main
= NULL
;
68 static void show_path(struct regedit
*regedit
)
71 int start_win
= PATH_START_X
;
73 if (PATH_START_X
+ regedit
->path_len
> COLS
) {
74 start_pad
= 3 + PATH_START_X
+ regedit
->path_len
- COLS
;
75 mvprintw(PATH_START_Y
, start_win
, "...");
78 copywin(regedit
->path_label
, regedit
->main_window
, 0, start_pad
,
79 PATH_START_Y
, start_win
, PATH_START_Y
, PATH_MAX_Y
, false);
81 mvchgat(0, 0, COLS
, A_BOLD
, PAIR_YELLOW_CYAN
, NULL
);
84 static void print_path(struct regedit
*regedit
, struct tree_node
*node
)
86 regedit
->path_len
= tree_node_print_path(regedit
->path_label
, node
);
90 static void print_help(struct regedit
*regedit
)
92 const char *khelp
= "[n] New Key [s] New Subkey [d] Del Key "
93 "[LEFT] Ascend [RIGHT] Descend";
94 const char *vhelp
= "[n] New Value [d] Del Value [ENTER] Edit "
96 const char *msg
= "KEYS";
97 const char *help
= khelp
;
98 const char *genhelp
= "[TAB] Switch sections [q] Quit "
99 "[UP] List up [DOWN] List down "
100 "[/] Search [x] Next";
103 if (!regedit
->tree_input
) {
108 move(HELP1_START_Y
, HELP1_START_X
);
110 attron(COLOR_PAIR(PAIR_BLACK_CYAN
));
111 mvaddstr(HELP1_START_Y
, HELP1_START_X
, help
);
112 pad
= COLS
- strlen(msg
) - strlen(help
);
113 for (i
= 0; i
< pad
; ++i
) {
116 attroff(COLOR_PAIR(PAIR_BLACK_CYAN
));
117 attron(COLOR_PAIR(PAIR_YELLOW_CYAN
) | A_BOLD
);
119 attroff(COLOR_PAIR(PAIR_YELLOW_CYAN
) | A_BOLD
);
121 move(HELP2_START_Y
, HELP2_START_X
);
123 mvaddstr(HELP2_START_Y
, HELP2_START_X
, genhelp
);
126 static void print_heading(struct regedit
*regedit
)
128 if (regedit
->tree_input
) {
129 tree_view_set_selected(regedit
->keys
, true);
130 value_list_set_selected(regedit
->vl
, false);
132 tree_view_set_selected(regedit
->keys
, false);
133 value_list_set_selected(regedit
->vl
, true);
139 static void load_values(struct regedit
*regedit
)
141 struct tree_node
*node
;
143 node
= tree_view_get_current_node(regedit
->keys
);
144 value_list_load(regedit
->vl
, node
->key
);
147 static void add_reg_key(struct regedit
*regedit
, struct tree_node
*node
,
153 if (!subkey
&& tree_node_is_top_level(node
)) {
157 msg
= "Enter name of new key";
159 msg
= "Enter name of new subkey";
161 dialog_input(regedit
, &name
, "New Key", "%s", msg
);
164 struct registry_key
*new_key
;
165 struct tree_node
*new_node
= NULL
;
166 struct tree_node
*list
;
167 struct tree_node
*parent
;
171 list
= node
->child_head
;
173 parent
= node
->parent
;
174 list
= tree_node_first(node
);
175 SMB_ASSERT(list
!= NULL
);
177 rv
= reg_key_add_name(regedit
, parent
->key
, name
,
178 NULL
, NULL
, &new_key
);
179 if (W_ERROR_IS_OK(rv
)) {
180 /* The list of subkeys may not be present in
181 cache yet, so if not, don't bother allocating
182 a new node for the key. */
184 new_node
= tree_node_new(parent
, parent
,
186 SMB_ASSERT(new_node
);
187 tree_node_insert_sorted(list
, new_node
);
189 /* Reopen the parent key to make sure the
190 new subkey will be noticed. */
191 tree_node_reopen_key(regedit
->registry_context
,
195 list
= tree_node_first(node
);
196 tree_view_clear(regedit
->keys
);
197 tree_view_update(regedit
->keys
, list
);
201 tree_view_set_current_node(regedit
->keys
, node
);
202 load_values(regedit
);
204 msg
= get_friendly_werror_msg(rv
);
205 dialog_notice(regedit
, DIA_ALERT
, "New Key",
206 "Failed to create key: %s", msg
);
208 talloc_free(discard_const(name
));
213 SEARCH_NEXT
= (1<<0),
214 SEARCH_PREV
= (1<<1),
215 SEARCH_REPEAT
= (1<<2)
217 static WERROR
regedit_search(struct regedit
*regedit
, struct tree_node
*node
,
218 struct value_item
*vitem
, unsigned flags
)
220 struct regedit_search_opts
*opts
;
221 struct tree_node
*found
;
222 struct value_item
*found_value
;
223 bool search_key
, need_sync
;
224 char *save_value_name
;
226 bool (*iterate
)(struct tree_node
**, bool, WERROR
*);
227 struct value_item
*(*find_item
)(struct value_list
*,
230 regedit_search_match_fn_t
);
232 opts
= ®edit
->active_search
;
234 if (!opts
->query
|| !opts
->match
) {
238 SMB_ASSERT(opts
->search_key
|| opts
->search_value
);
243 save_value_name
= NULL
;
244 search_key
= opts
->search_key
;
246 iterate
= tree_node_next
;
247 find_item
= value_list_find_next_item
;
249 if (flags
& SEARCH_PREV
) {
250 iterate
= tree_node_prev
;
251 find_item
= value_list_find_prev_item
;
254 if (opts
->search_value
) {
255 struct value_item
*it
;
257 it
= value_list_get_current_item(regedit
->vl
);
259 save_value_name
= talloc_strdup(regedit
,
261 if (save_value_name
== NULL
) {
262 return WERR_NOT_ENOUGH_MEMORY
;
271 if (!vitem
&& (flags
& SEARCH_REPEAT
)) {
272 if (opts
->search_value
) {
274 } else if (!iterate(&node
, opts
->search_recursive
, &rv
)) {
282 SMB_ASSERT(opts
->search_key
== true);
283 if (opts
->match(node
->name
, opts
->query
)) {
285 } else if (opts
->search_value
) {
290 SMB_ASSERT(opts
->search_value
== true);
292 rv
= value_list_load_quick(regedit
->vl
,
294 if (!W_ERROR_IS_OK(rv
)) {
299 found_value
= find_item(regedit
->vl
, vitem
, opts
->query
,
305 search_key
= opts
->search_key
;
308 } while (!found
&& iterate(&node
, opts
->search_recursive
, &rv
));
310 if (!W_ERROR_IS_OK(rv
)) {
315 /* Put the cursor on the node that was found */
316 if (!tree_view_is_node_visible(regedit
->keys
, found
)) {
317 tree_view_update(regedit
->keys
,
318 tree_node_first(found
));
319 print_path(regedit
, found
);
321 tree_view_set_current_node(regedit
->keys
, found
);
324 value_list_sync(regedit
->vl
);
326 value_list_set_current_item(regedit
->vl
, found_value
);
327 regedit
->tree_input
= false;
329 load_values(regedit
);
330 regedit
->tree_input
= true;
332 tree_view_show(regedit
->keys
);
333 value_list_show(regedit
->vl
);
334 print_heading(regedit
);
337 load_values(regedit
);
338 value_list_set_current_item_by_name(regedit
->vl
,
345 talloc_free(save_value_name
);
350 static void regedit_search_repeat(struct regedit
*regedit
, unsigned flags
)
352 struct tree_node
*node
;
353 struct value_item
*vitem
;
354 struct regedit_search_opts
*opts
;
356 opts
= ®edit
->active_search
;
357 if (opts
->query
== NULL
) {
361 node
= tree_view_get_current_node(regedit
->keys
);
363 if (opts
->search_value
&& !regedit
->tree_input
) {
364 vitem
= value_list_get_current_item(regedit
->vl
);
366 regedit_search(regedit
, node
, vitem
, flags
| SEARCH_REPEAT
);
369 static void handle_tree_input(struct regedit
*regedit
, int c
)
371 struct tree_node
*node
;
375 tree_view_driver(regedit
->keys
, ML_CURSOR_DOWN
);
376 load_values(regedit
);
379 tree_view_driver(regedit
->keys
, ML_CURSOR_UP
);
380 load_values(regedit
);
383 tree_view_driver(regedit
->keys
, ML_CURSOR_PGDN
);
384 load_values(regedit
);
387 tree_view_driver(regedit
->keys
, ML_CURSOR_PGUP
);
388 load_values(regedit
);
391 tree_view_driver(regedit
->keys
, ML_CURSOR_HOME
);
392 load_values(regedit
);
395 tree_view_driver(regedit
->keys
, ML_CURSOR_END
);
396 load_values(regedit
);
401 node
= tree_view_get_current_node(regedit
->keys
);
402 if (node
&& tree_node_has_children(node
)) {
405 rv
= tree_node_load_children(node
);
406 if (W_ERROR_IS_OK(rv
)) {
407 print_path(regedit
, node
->child_head
);
408 tree_view_update(regedit
->keys
, node
->child_head
);
409 value_list_load(regedit
->vl
, node
->child_head
->key
);
411 const char *msg
= get_friendly_werror_msg(rv
);
412 dialog_notice(regedit
, DIA_ALERT
, "Loading Subkeys",
413 "Failed to load subkeys: %s", msg
);
418 node
= tree_view_get_current_node(regedit
->keys
);
419 if (node
&& !tree_node_is_top_level(node
)) {
420 print_path(regedit
, node
->parent
);
422 tree_view_update(regedit
->keys
, tree_node_first(node
));
423 tree_view_set_current_node(regedit
->keys
, node
);
424 value_list_load(regedit
->vl
, node
->key
);
429 node
= tree_view_get_current_node(regedit
->keys
);
430 add_reg_key(regedit
, node
, false);
434 node
= tree_view_get_current_node(regedit
->keys
);
435 add_reg_key(regedit
, node
, true);
441 node
= tree_view_get_current_node(regedit
->keys
);
442 if (tree_node_is_top_level(node
)) {
445 sel
= dialog_notice(regedit
, DIA_CONFIRM
,
447 "Really delete key \"%s\"?",
449 if (sel
== DIALOG_OK
) {
451 struct tree_node
*pop
;
452 struct tree_node
*parent
= node
->parent
;
454 rv
= reg_key_del(node
, parent
->key
, node
->name
);
455 if (W_ERROR_IS_OK(rv
)) {
456 tree_node_reopen_key(regedit
->registry_context
,
458 tree_view_clear(regedit
->keys
);
459 pop
= tree_node_pop(&node
);
461 node
= parent
->child_head
;
463 node
= tree_node_first(parent
);
464 print_path(regedit
, node
);
466 tree_view_update(regedit
->keys
, node
);
467 value_list_load(regedit
->vl
, node
->key
);
469 const char *msg
= get_friendly_werror_msg(rv
);
470 dialog_notice(regedit
, DIA_ALERT
, "Delete Key",
471 "Failed to delete key: %s", msg
);
478 tree_view_show(regedit
->keys
);
479 value_list_show(regedit
->vl
);
482 static void handle_value_input(struct regedit
*regedit
, int c
)
484 struct value_item
*vitem
;
485 bool binmode
= false;
491 value_list_driver(regedit
->vl
, ML_CURSOR_DOWN
);
494 value_list_driver(regedit
->vl
, ML_CURSOR_UP
);
497 value_list_driver(regedit
->vl
, ML_CURSOR_PGDN
);
500 value_list_driver(regedit
->vl
, ML_CURSOR_PGUP
);
503 value_list_driver(regedit
->vl
, ML_CURSOR_HOME
);
506 value_list_driver(regedit
->vl
, ML_CURSOR_END
);
515 vitem
= value_list_get_current_item(regedit
->vl
);
517 struct tree_node
*node
;
518 const char *name
= NULL
;
519 node
= tree_view_get_current_node(regedit
->keys
);
520 sel
= dialog_edit_value(regedit
, node
->key
, vitem
->type
,
521 vitem
, binmode
, &err
, &name
);
522 if (!W_ERROR_IS_OK(err
)) {
523 const char *msg
= get_friendly_werror_msg(err
);
524 dialog_notice(regedit
, DIA_ALERT
, "Error",
525 "Error editing value:\n%s", msg
);
526 } else if (sel
== DIALOG_OK
) {
527 tree_node_reopen_key(regedit
->registry_context
,
529 value_list_load(regedit
->vl
, node
->key
);
530 value_list_set_current_item_by_name(regedit
->vl
,
532 talloc_free(discard_const(name
));
540 sel
= dialog_select_type(regedit
, &new_type
);
541 if (sel
== DIALOG_OK
) {
542 struct tree_node
*node
;
543 const char *name
= NULL
;
544 node
= tree_view_get_current_node(regedit
->keys
);
545 sel
= dialog_edit_value(regedit
, node
->key
, new_type
,
546 NULL
, false, &err
, &name
);
547 if (!W_ERROR_IS_OK(err
)) {
548 const char *msg
= get_friendly_werror_msg(err
);
549 dialog_notice(regedit
, DIA_ALERT
, "Error",
550 "Error creating value:\n%s", msg
);
551 } else if (sel
== DIALOG_OK
) {
552 tree_node_reopen_key(regedit
->registry_context
,
554 value_list_load(regedit
->vl
, node
->key
);
555 value_list_set_current_item_by_name(regedit
->vl
,
557 talloc_free(discard_const(name
));
564 vitem
= value_list_get_current_item(regedit
->vl
);
566 sel
= dialog_notice(regedit
, DIA_CONFIRM
,
568 "Really delete value \"%s\"?",
570 if (sel
== DIALOG_OK
) {
571 struct tree_node
*node
;
572 node
= tree_view_get_current_node(regedit
->keys
);
573 reg_del_value(regedit
, node
->key
,
575 tree_node_reopen_key(regedit
->registry_context
,
577 value_list_load(regedit
->vl
, node
->key
);
583 value_list_show(regedit
->vl
);
586 static bool find_substring(const char *haystack
, const char *needle
)
588 return strstr(haystack
, needle
) != NULL
;
591 static bool find_substring_nocase(const char *haystack
, const char *needle
)
593 return strcasestr(haystack
, needle
) != NULL
;
596 static void handle_main_input(struct regedit
*regedit
, int c
)
599 case 18: { /* CTRL-R */
600 struct tree_node
*root
, *node
;
603 node
= tree_view_get_current_node(regedit
->keys
);
604 path
= tree_node_get_path(regedit
, node
);
605 SMB_ASSERT(path
!= NULL
);
607 root
= tree_node_new_root(regedit
, regedit
->registry_context
);
608 SMB_ASSERT(root
!= NULL
);
610 tree_view_set_root(regedit
->keys
, root
);
611 tree_view_set_path(regedit
->keys
, path
);
612 node
= tree_view_get_current_node(regedit
->keys
);
613 value_list_load(regedit
->vl
, node
->key
);
614 tree_view_show(regedit
->keys
);
615 value_list_show(regedit
->vl
);
616 print_path(regedit
, node
);
617 talloc_free(discard_const(path
));
624 struct regedit_search_opts
*opts
;
625 struct tree_node
*node
;
627 opts
= ®edit
->active_search
;
628 rv
= dialog_search_input(regedit
, opts
);
629 if (rv
== DIALOG_OK
) {
630 SMB_ASSERT(opts
->query
!= NULL
);
631 opts
->match
= find_substring_nocase
;
632 node
= regedit
->keys
->root
->child_head
;
633 if (opts
->search_case
) {
634 opts
->match
= find_substring
;
636 if (!opts
->search_recursive
) {
637 node
= tree_view_get_current_node(regedit
->keys
);
638 node
= tree_node_first(node
);
640 regedit_search(regedit
, node
, NULL
, SEARCH_NEXT
);
645 regedit_search_repeat(regedit
, SEARCH_NEXT
);
648 regedit_search_repeat(regedit
, SEARCH_PREV
);
651 regedit
->tree_input
= !regedit
->tree_input
;
652 print_heading(regedit
);
655 if (regedit
->tree_input
) {
656 handle_tree_input(regedit
, c
);
658 handle_value_input(regedit
, c
);
663 int regedit_getch(void)
667 SMB_ASSERT(regedit_main
);
670 if (c
== KEY_RESIZE
) {
671 tree_view_resize(regedit_main
->keys
, KEY_HEIGHT
, KEY_WIDTH
,
672 KEY_START_Y
, KEY_START_X
);
673 value_list_resize(regedit_main
->vl
, VAL_HEIGHT
, VAL_WIDTH
,
674 VAL_START_Y
, VAL_START_X
);
675 print_heading(regedit_main
);
676 show_path(regedit_main
);
682 static void regedit_panic_handler(const char *msg
)
689 static void display_window(TALLOC_CTX
*mem_ctx
, struct registry_context
*ctx
)
691 struct regedit
*regedit
;
692 struct tree_node
*root
;
701 fault_configure(regedit_panic_handler
);
703 colors
= has_colors();
706 use_default_colors();
707 assume_default_colors(COLOR_WHITE
, COLOR_BLUE
);
708 init_pair(PAIR_YELLOW_CYAN
, COLOR_YELLOW
, COLOR_CYAN
);
709 init_pair(PAIR_BLACK_CYAN
, COLOR_BLACK
, COLOR_CYAN
);
710 init_pair(PAIR_YELLOW_BLUE
, COLOR_YELLOW
, COLOR_BLUE
);
713 regedit
= talloc_zero(mem_ctx
, struct regedit
);
714 SMB_ASSERT(regedit
!= NULL
);
715 regedit_main
= regedit
;
717 regedit
->registry_context
= ctx
;
718 regedit
->main_window
= stdscr
;
719 keypad(regedit
->main_window
, TRUE
);
721 mvwprintw(regedit
->main_window
, 0, 0, "Path: ");
722 regedit
->path_label
= newpad(1, PATH_WIDTH_MAX
);
723 SMB_ASSERT(regedit
->path_label
);
724 wprintw(regedit
->path_label
, "/");
725 show_path(regedit_main
);
727 root
= tree_node_new_root(regedit
, ctx
);
728 SMB_ASSERT(root
!= NULL
);
730 regedit
->keys
= tree_view_new(regedit
, root
, KEY_HEIGHT
, KEY_WIDTH
,
731 KEY_START_Y
, KEY_START_X
);
732 SMB_ASSERT(regedit
->keys
!= NULL
);
734 regedit
->vl
= value_list_new(regedit
, VAL_HEIGHT
, VAL_WIDTH
,
735 VAL_START_Y
, VAL_START_X
);
736 SMB_ASSERT(regedit
->vl
!= NULL
);
738 regedit
->tree_input
= true;
739 print_heading(regedit
);
741 tree_view_show(regedit
->keys
);
742 load_values(regedit
);
743 value_list_show(regedit
->vl
);
749 key
= regedit_getch();
751 handle_main_input(regedit
, key
);
754 } while (key
!= 'q' && key
!= 'Q');
759 int main(int argc
, char **argv
)
761 const char **argv_const
= discard_const_p(const char *, argv
);
762 struct poptOption long_options
[] = {
766 POPT_COMMON_CONNECTION
767 POPT_COMMON_CREDENTIALS
774 struct registry_context
*ctx
;
777 struct loadparm_context
*lp_ctx
= NULL
;
779 frame
= talloc_stackframe();
783 ok
= samba_cmdline_init(frame
,
784 SAMBA_CMDLINE_CONFIG_CLIENT
,
785 false /* require_smbconf */);
787 DBG_ERR("Failed to init cmdline parser!\n");
791 lp_ctx
= samba_cmdline_get_lp_ctx();
792 lpcfg_set_cmdline(lp_ctx
, "log level", "0");
794 /* process options */
795 pc
= samba_popt_get_context(getprogname(),
801 DBG_ERR("Failed to setup popt context!\n");
806 while ((opt
= poptGetNextOpt(pc
)) != -1) {
808 case POPT_ERROR_BADOPT
:
809 fprintf(stderr
, "\nInvalid option %s: %s\n\n",
810 poptBadOption(pc
, 0), poptStrerror(opt
));
811 poptPrintUsage(pc
, stderr
, 0);
817 samba_cmdline_burn(argc
, argv
);
819 rv
= reg_open_samba3(frame
, &ctx
);
820 if (!W_ERROR_IS_OK(rv
)) {
821 fprintf(stderr
, "Unable to open registry: %s\n",
828 display_window(frame
, ctx
);