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.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", 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
) {
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
);
513 vitem
= value_list_get_current_item(regedit
->vl
);
515 struct tree_node
*node
;
516 const char *name
= NULL
;
517 node
= tree_view_get_current_node(regedit
->keys
);
518 sel
= dialog_edit_value(regedit
, node
->key
, vitem
->type
,
519 vitem
, binmode
, &err
, &name
);
520 if (!W_ERROR_IS_OK(err
)) {
521 const char *msg
= get_friendly_werror_msg(err
);
522 dialog_notice(regedit
, DIA_ALERT
, "Error",
523 "Error editing value:\n%s", msg
);
524 } else if (sel
== DIALOG_OK
) {
525 tree_node_reopen_key(regedit
->registry_context
,
527 value_list_load(regedit
->vl
, node
->key
);
528 value_list_set_current_item_by_name(regedit
->vl
,
530 talloc_free(discard_const(name
));
538 sel
= dialog_select_type(regedit
, &new_type
);
539 if (sel
== DIALOG_OK
) {
540 struct tree_node
*node
;
541 const char *name
= NULL
;
542 node
= tree_view_get_current_node(regedit
->keys
);
543 sel
= dialog_edit_value(regedit
, node
->key
, new_type
,
544 NULL
, false, &err
, &name
);
545 if (!W_ERROR_IS_OK(err
)) {
546 const char *msg
= get_friendly_werror_msg(err
);
547 dialog_notice(regedit
, DIA_ALERT
, "Error",
548 "Error creating value:\n%s", msg
);
549 } else if (sel
== DIALOG_OK
) {
550 tree_node_reopen_key(regedit
->registry_context
,
552 value_list_load(regedit
->vl
, node
->key
);
553 value_list_set_current_item_by_name(regedit
->vl
,
555 talloc_free(discard_const(name
));
562 vitem
= value_list_get_current_item(regedit
->vl
);
564 sel
= dialog_notice(regedit
, DIA_CONFIRM
,
566 "Really delete value \"%s\"?",
568 if (sel
== DIALOG_OK
) {
569 struct tree_node
*node
;
570 node
= tree_view_get_current_node(regedit
->keys
);
571 reg_del_value(regedit
, node
->key
,
573 tree_node_reopen_key(regedit
->registry_context
,
575 value_list_load(regedit
->vl
, node
->key
);
581 value_list_show(regedit
->vl
);
584 static bool find_substring(const char *haystack
, const char *needle
)
586 return strstr(haystack
, needle
) != NULL
;
589 static bool find_substring_nocase(const char *haystack
, const char *needle
)
591 return strcasestr(haystack
, needle
) != NULL
;
594 static void handle_main_input(struct regedit
*regedit
, int c
)
597 case 18: { /* CTRL-R */
598 struct tree_node
*root
, *node
;
601 node
= tree_view_get_current_node(regedit
->keys
);
602 path
= tree_node_get_path(regedit
, node
);
603 SMB_ASSERT(path
!= NULL
);
605 root
= tree_node_new_root(regedit
, regedit
->registry_context
);
606 SMB_ASSERT(root
!= NULL
);
608 tree_view_set_root(regedit
->keys
, root
);
609 tree_view_set_path(regedit
->keys
, path
);
610 node
= tree_view_get_current_node(regedit
->keys
);
611 value_list_load(regedit
->vl
, node
->key
);
612 tree_view_show(regedit
->keys
);
613 value_list_show(regedit
->vl
);
614 print_path(regedit
, node
);
615 talloc_free(discard_const(path
));
622 struct regedit_search_opts
*opts
;
623 struct tree_node
*node
;
625 opts
= ®edit
->active_search
;
626 rv
= dialog_search_input(regedit
, opts
);
627 if (rv
== DIALOG_OK
) {
628 SMB_ASSERT(opts
->query
!= NULL
);
629 opts
->match
= find_substring_nocase
;
630 node
= regedit
->keys
->root
->child_head
;
631 if (opts
->search_case
) {
632 opts
->match
= find_substring
;
634 if (!opts
->search_recursive
) {
635 node
= tree_view_get_current_node(regedit
->keys
);
636 node
= tree_node_first(node
);
638 regedit_search(regedit
, node
, NULL
, SEARCH_NEXT
);
643 regedit_search_repeat(regedit
, SEARCH_NEXT
);
646 regedit_search_repeat(regedit
, SEARCH_PREV
);
649 regedit
->tree_input
= !regedit
->tree_input
;
650 print_heading(regedit
);
653 if (regedit
->tree_input
) {
654 handle_tree_input(regedit
, c
);
656 handle_value_input(regedit
, c
);
661 int regedit_getch(void)
665 SMB_ASSERT(regedit_main
);
668 if (c
== KEY_RESIZE
) {
669 tree_view_resize(regedit_main
->keys
, KEY_HEIGHT
, KEY_WIDTH
,
670 KEY_START_Y
, KEY_START_X
);
671 value_list_resize(regedit_main
->vl
, VAL_HEIGHT
, VAL_WIDTH
,
672 VAL_START_Y
, VAL_START_X
);
673 print_heading(regedit_main
);
674 show_path(regedit_main
);
680 static void regedit_panic_handler(const char *msg
)
686 static void display_window(TALLOC_CTX
*mem_ctx
, struct registry_context
*ctx
)
688 struct regedit
*regedit
;
689 struct tree_node
*root
;
698 fault_configure(regedit_panic_handler
);
700 colors
= has_colors();
703 use_default_colors();
704 assume_default_colors(COLOR_WHITE
, COLOR_BLUE
);
705 init_pair(PAIR_YELLOW_CYAN
, COLOR_YELLOW
, COLOR_CYAN
);
706 init_pair(PAIR_BLACK_CYAN
, COLOR_BLACK
, COLOR_CYAN
);
707 init_pair(PAIR_YELLOW_BLUE
, COLOR_YELLOW
, COLOR_BLUE
);
710 regedit
= talloc_zero(mem_ctx
, struct regedit
);
711 SMB_ASSERT(regedit
!= NULL
);
712 regedit_main
= regedit
;
714 regedit
->registry_context
= ctx
;
715 regedit
->main_window
= stdscr
;
716 keypad(regedit
->main_window
, TRUE
);
718 mvwprintw(regedit
->main_window
, 0, 0, "Path: ");
719 regedit
->path_label
= newpad(1, PATH_WIDTH_MAX
);
720 SMB_ASSERT(regedit
->path_label
);
721 wprintw(regedit
->path_label
, "/");
722 show_path(regedit_main
);
724 root
= tree_node_new_root(regedit
, ctx
);
725 SMB_ASSERT(root
!= NULL
);
727 regedit
->keys
= tree_view_new(regedit
, root
, KEY_HEIGHT
, KEY_WIDTH
,
728 KEY_START_Y
, KEY_START_X
);
729 SMB_ASSERT(regedit
->keys
!= NULL
);
731 regedit
->vl
= value_list_new(regedit
, VAL_HEIGHT
, VAL_WIDTH
,
732 VAL_START_Y
, VAL_START_X
);
733 SMB_ASSERT(regedit
->vl
!= NULL
);
735 regedit
->tree_input
= true;
736 print_heading(regedit
);
738 tree_view_show(regedit
->keys
);
739 load_values(regedit
);
740 value_list_show(regedit
->vl
);
746 key
= regedit_getch();
748 handle_main_input(regedit
, key
);
751 } while (key
!= 'q' || key
== 'Q');
756 int main(int argc
, const char **argv
)
758 struct poptOption long_options
[] = {
762 POPT_COMMON_CONNECTION
763 POPT_COMMON_CREDENTIALS
768 struct user_auth_info
*auth_info
;
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 auth_info
= user_auth_info_init(frame
);
780 if (auth_info
== NULL
) {
783 popt_common_set_auth_info(auth_info
);
784 pc
= poptGetContext("regedit", argc
, argv
, long_options
, 0);
786 while ((opt
= poptGetNextOpt(pc
)) != -1) {
790 if (!lp_load_global(get_dyn_CONFIGFILE())) {
791 DEBUG(0, ("ERROR loading config file...\n"));
795 rv
= reg_open_samba3(frame
, &ctx
);
796 if (!W_ERROR_IS_OK(rv
)) {
797 fprintf(stderr
, "Unable to open registry: %s\n",
804 display_window(frame
, ctx
);