2012-07-06 14:08:17 +04:00
/*
* Samba Unix / Linux SMB client library
* Registry Editor
* Copyright ( C ) Christopher Davis 2012
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "popt_common.h"
# include "lib/util/data_blob.h"
# include "lib/registry/registry.h"
# include "regedit.h"
2012-07-13 08:11:55 +04:00
# include "regedit_treeview.h"
2012-07-18 13:31:41 +04:00
# include "regedit_valuelist.h"
2012-07-27 14:37:22 +04:00
# include "regedit_dialog.h"
2012-07-10 17:16:35 +04:00
# include <ncurses.h>
# include <menu.h>
2012-07-27 14:37:22 +04:00
# include <panel.h>
2012-08-11 07:05:20 +04:00
# define KEY_START_X 0
# define KEY_START_Y 3
# define KEY_WIDTH (COLS / 4)
2012-08-16 08:05:01 +04:00
# define KEY_HEIGHT (LINES - KEY_START_Y - 2)
2012-08-11 07:05:20 +04:00
# define VAL_START_X KEY_WIDTH
# define VAL_START_Y 3
# define VAL_WIDTH (COLS - KEY_WIDTH)
2012-08-16 08:05:01 +04:00
# define VAL_HEIGHT (LINES - VAL_START_Y - 2)
2012-08-12 09:10:51 +04:00
# define HEADING_START_Y (KEY_START_Y - 1)
2012-08-16 08:05:01 +04:00
# define HELP1_START_Y (LINES - 2)
# define HELP1_START_X 0
# define HELP1_WIDTH (LINES)
# define HELP2_START_Y (LINES - 1)
# define HELP2_START_X 0
# define HELP2_WIDTH (LINES)
2012-08-12 09:10:51 +04:00
# define PATH_START_Y 0
# define PATH_START_X 6
2012-08-12 10:22:06 +04:00
# define PATH_MAX_Y (COLS - 1)
# define PATH_WIDTH (COLS - 6)
2012-08-12 09:10:51 +04:00
# define PATH_WIDTH_MAX 1024
2012-08-11 07:05:20 +04:00
2012-07-27 14:37:22 +04:00
struct regedit {
WINDOW * main_window ;
WINDOW * path_label ;
2012-08-12 10:22:06 +04:00
size_t path_len ;
2012-07-27 14:37:22 +04:00
struct value_list * vl ;
struct tree_view * keys ;
bool tree_input ;
} ;
2012-07-06 14:08:17 +04:00
2012-08-11 08:56:58 +04:00
static struct regedit * regedit_main = NULL ;
2012-08-12 09:10:51 +04:00
static void show_path ( struct regedit * regedit )
{
2012-08-12 10:22:06 +04:00
int start_pad = 0 ;
int start_win = PATH_START_X ;
if ( PATH_START_X + regedit - > path_len > COLS ) {
start_pad = 3 + PATH_START_X + regedit - > path_len - COLS ;
mvprintw ( PATH_START_Y , start_win , " ... " ) ;
start_win + = 3 ;
}
2012-08-12 10:29:13 +04:00
copywin ( regedit - > path_label , regedit - > main_window , 0 , start_pad ,
PATH_START_Y , start_win , PATH_START_Y , PATH_MAX_Y , false ) ;
2012-08-12 09:10:51 +04:00
}
static void print_path ( struct regedit * regedit , struct tree_node * node )
{
2012-08-12 10:22:06 +04:00
regedit - > path_len = tree_node_print_path ( regedit - > path_label , node ) ;
2012-08-12 10:29:13 +04:00
show_path ( regedit ) ;
2012-08-12 09:10:51 +04:00
}
2012-07-14 04:07:44 +04:00
/* load all available hives */
static struct tree_node * load_hives ( TALLOC_CTX * mem_ctx ,
struct registry_context * ctx )
{
const char * hives [ ] = {
" HKEY_CLASSES_ROOT " ,
" HKEY_CURRENT_USER " ,
" HKEY_LOCAL_MACHINE " ,
" HKEY_PERFORMANCE_DATA " ,
" HKEY_USERS " ,
" HKEY_CURRENT_CONFIG " ,
" HKEY_DYN_DATA " ,
" HKEY_PERFORMANCE_TEXT " ,
" HKEY_PERFORMANCE_NLSTEXT " ,
NULL
} ;
struct tree_node * root , * prev , * node ;
struct registry_key * key ;
WERROR rv ;
size_t i ;
root = NULL ;
prev = NULL ;
for ( i = 0 ; hives [ i ] ! = NULL ; + + i ) {
rv = reg_get_predefined_key_by_name ( ctx , hives [ i ] , & key ) ;
if ( ! W_ERROR_IS_OK ( rv ) ) {
2012-07-18 13:31:41 +04:00
continue ;
2012-07-14 04:07:44 +04:00
}
node = tree_node_new ( mem_ctx , NULL , hives [ i ] , key ) ;
if ( node = = NULL ) {
return NULL ;
}
if ( root = = NULL ) {
root = node ;
}
if ( prev ) {
tree_node_append ( prev , node ) ;
}
prev = node ;
}
return root ;
}
2012-08-13 09:38:06 +04:00
static void print_help ( struct regedit * regedit )
{
const char * khelp = " [n] New Key [s] New Subkey [d] Del Key "
" [LEFT] Ascend [RIGHT] Descend " ;
const char * vhelp = " [n] New Value [d] Del Value [ENTER] Edit " ;
const char * msg = " KEYS " ;
const char * help = khelp ;
2012-08-16 08:05:01 +04:00
const char * genhelp = " [TAB] Switch sections [q] Quit regedit "
" [UP] List up [DOWN] List down " ;
2012-08-13 09:38:06 +04:00
int i , pad ;
if ( ! regedit - > tree_input ) {
msg = " VALUES " ;
help = vhelp ;
}
2012-08-16 08:05:01 +04:00
move ( HELP1_START_Y , HELP1_START_X ) ;
2012-08-13 09:38:06 +04:00
clrtoeol ( ) ;
2012-08-16 07:50:00 +04:00
attron ( A_REVERSE ) ;
2012-08-16 08:05:01 +04:00
mvaddstr ( HELP1_START_Y , HELP1_START_X , help ) ;
2012-08-13 09:38:06 +04:00
pad = COLS - strlen ( msg ) - strlen ( help ) ;
for ( i = 0 ; i < pad ; + + i ) {
addch ( ' ' ) ;
}
2012-08-16 07:50:00 +04:00
attron ( A_BOLD ) ;
addstr ( msg ) ;
attroff ( A_REVERSE | A_BOLD ) ;
2012-08-16 08:05:01 +04:00
move ( HELP2_START_Y , HELP2_START_X ) ;
clrtoeol ( ) ;
mvaddstr ( HELP2_START_Y , HELP2_START_X , genhelp ) ;
2012-08-13 09:38:06 +04:00
}
2012-08-11 07:05:20 +04:00
static void print_heading ( struct regedit * regedit )
2012-07-27 14:37:22 +04:00
{
2012-08-11 07:05:20 +04:00
move ( HEADING_START_Y , 0 ) ;
clrtoeol ( ) ;
if ( regedit - > tree_input ) {
attron ( A_REVERSE ) ;
} else {
attroff ( A_REVERSE ) ;
}
mvprintw ( HEADING_START_Y , KEY_START_X , " Key " ) ;
attroff ( A_REVERSE ) ;
if ( ! regedit - > tree_input ) {
attron ( A_REVERSE ) ;
2012-07-27 14:37:22 +04:00
} else {
2012-08-11 07:05:20 +04:00
attroff ( A_REVERSE ) ;
2012-07-27 14:37:22 +04:00
}
2012-08-11 07:05:20 +04:00
mvprintw ( HEADING_START_Y , VAL_START_X , " Value " ) ;
attroff ( A_REVERSE ) ;
2012-08-13 09:38:06 +04:00
print_help ( regedit ) ;
2012-07-27 14:37:22 +04:00
}
2012-08-20 05:29:06 +04:00
static void load_values ( struct regedit * regedit )
{
struct tree_node * node ;
node = item_userptr ( current_item ( regedit - > keys - > menu ) ) ;
value_list_load ( regedit - > vl , node - > key ) ;
}
2012-08-11 00:16:20 +04:00
static void add_reg_key ( struct regedit * regedit , struct tree_node * node ,
bool subkey )
{
char * name ;
const char * msg ;
if ( ! subkey & & ! node - > parent ) {
return ;
}
msg = " Enter name of new key " ;
if ( subkey ) {
msg = " Enter name of new subkey " ;
}
2012-08-11 08:56:58 +04:00
dialog_input ( regedit , & name , " New Key " , msg ) ;
2012-08-11 00:16:20 +04:00
if ( name ) {
WERROR rv ;
struct registry_key * new_key ;
struct tree_node * new_node ;
struct tree_node * list ;
struct tree_node * parent ;
if ( subkey ) {
parent = node ;
list = node - > child_head ;
} else {
parent = node - > parent ;
list = tree_node_first ( node ) ;
SMB_ASSERT ( list ! = NULL ) ;
}
rv = reg_key_add_name ( regedit , parent - > key , name ,
NULL , NULL , & new_key ) ;
if ( W_ERROR_IS_OK ( rv ) ) {
/* The list of subkeys may not be present in
cache yet , so if not , don ' t bother allocating
a new node for the key . */
if ( list ) {
new_node = tree_node_new ( parent , parent ,
name , new_key ) ;
SMB_ASSERT ( new_node ) ;
tree_node_append_last ( list , new_node ) ;
}
list = tree_node_first ( node ) ;
tree_view_clear ( regedit - > keys ) ;
tree_view_update ( regedit - > keys , list ) ;
} else {
dialog_notice ( regedit , DIA_ALERT , " New Key " ,
" Failed to create key. " ) ;
}
talloc_free ( name ) ;
}
}
2012-07-27 14:37:22 +04:00
static void handle_tree_input ( struct regedit * regedit , int c )
2012-07-24 15:12:56 +04:00
{
struct tree_node * node ;
switch ( c ) {
case KEY_DOWN :
2012-07-27 14:37:22 +04:00
menu_driver ( regedit - > keys - > menu , REQ_DOWN_ITEM ) ;
2012-08-20 05:29:06 +04:00
load_values ( regedit ) ;
2012-07-24 15:12:56 +04:00
break ;
case KEY_UP :
2012-07-27 14:37:22 +04:00
menu_driver ( regedit - > keys - > menu , REQ_UP_ITEM ) ;
2012-08-20 05:29:06 +04:00
load_values ( regedit ) ;
2012-07-24 15:12:56 +04:00
break ;
2012-07-26 12:56:31 +04:00
case ' \n ' :
2012-07-24 15:12:56 +04:00
case KEY_ENTER :
case KEY_RIGHT :
2012-07-27 14:37:22 +04:00
node = item_userptr ( current_item ( regedit - > keys - > menu ) ) ;
2012-07-24 15:12:56 +04:00
if ( node & & tree_node_has_children ( node ) ) {
tree_node_load_children ( node ) ;
2012-08-12 09:10:51 +04:00
print_path ( regedit , node - > child_head ) ;
2012-07-27 14:37:22 +04:00
tree_view_update ( regedit - > keys , node - > child_head ) ;
value_list_load ( regedit - > vl , node - > child_head - > key ) ;
2012-07-24 15:12:56 +04:00
}
break ;
case KEY_LEFT :
2012-07-27 14:37:22 +04:00
node = item_userptr ( current_item ( regedit - > keys - > menu ) ) ;
2012-07-24 15:12:56 +04:00
if ( node & & node - > parent ) {
2012-08-12 09:10:51 +04:00
print_path ( regedit , node - > parent ) ;
2012-07-24 15:12:56 +04:00
node = tree_node_first ( node - > parent ) ;
2012-07-27 14:37:22 +04:00
tree_view_update ( regedit - > keys , node ) ;
value_list_load ( regedit - > vl , node - > key ) ;
2012-07-24 15:12:56 +04:00
}
break ;
2012-08-10 05:14:42 +04:00
case ' n ' :
2012-08-11 00:16:20 +04:00
case ' N ' :
2012-08-10 05:14:42 +04:00
node = item_userptr ( current_item ( regedit - > keys - > menu ) ) ;
2012-08-11 00:16:20 +04:00
add_reg_key ( regedit , node , false ) ;
break ;
case ' s ' :
case ' S ' :
node = item_userptr ( current_item ( regedit - > keys - > menu ) ) ;
add_reg_key ( regedit , node , true ) ;
2012-08-10 05:14:42 +04:00
break ;
2012-07-27 14:37:22 +04:00
case ' d ' :
2012-08-07 06:11:13 +04:00
case ' D ' : {
int sel ;
2012-07-27 14:37:22 +04:00
node = item_userptr ( current_item ( regedit - > keys - > menu ) ) ;
2012-08-10 05:14:42 +04:00
if ( ! node - > parent ) {
break ;
}
2012-08-09 02:36:01 +04:00
sel = dialog_notice ( regedit , DIA_CONFIRM ,
" Delete Key " ,
" Really delete key \" %s \" ? " ,
node - > name ) ;
2012-08-10 05:14:42 +04:00
if ( sel = = DIALOG_OK ) {
WERROR rv ;
struct tree_node * pop ;
struct tree_node * parent = node - > parent ;
rv = reg_key_del ( node , parent - > key , node - > name ) ;
if ( W_ERROR_IS_OK ( rv ) ) {
tree_view_clear ( regedit - > keys ) ;
pop = tree_node_pop ( & node ) ;
tree_node_free_recursive ( pop ) ;
node = parent - > child_head ;
if ( node = = NULL ) {
node = tree_node_first ( parent ) ;
2012-08-12 09:10:51 +04:00
print_path ( regedit , node ) ;
2012-08-10 05:14:42 +04:00
}
tree_view_update ( regedit - > keys , node ) ;
value_list_load ( regedit - > vl , node - > key ) ;
} else {
dialog_notice ( regedit , DIA_ALERT , " Delete Key " ,
" Failed to delete key. " ) ;
}
}
2012-07-27 14:37:22 +04:00
break ;
2012-07-24 15:12:56 +04:00
}
2012-08-07 06:11:13 +04:00
}
2012-07-27 14:37:22 +04:00
tree_view_show ( regedit - > keys ) ;
value_list_show ( regedit - > vl ) ;
2012-07-24 15:12:56 +04:00
}
2012-07-27 14:37:22 +04:00
static void handle_value_input ( struct regedit * regedit , int c )
2012-07-24 15:12:56 +04:00
{
2012-07-27 14:37:22 +04:00
struct value_item * vitem ;
2012-07-24 15:12:56 +04:00
switch ( c ) {
case KEY_DOWN :
2012-07-27 14:37:22 +04:00
menu_driver ( regedit - > vl - > menu , REQ_DOWN_ITEM ) ;
2012-07-24 15:12:56 +04:00
break ;
case KEY_UP :
2012-07-27 14:37:22 +04:00
menu_driver ( regedit - > vl - > menu , REQ_UP_ITEM ) ;
break ;
2012-08-07 06:11:13 +04:00
case ' \n ' :
2012-07-27 14:37:22 +04:00
case KEY_ENTER :
2012-08-07 06:11:13 +04:00
vitem = item_userptr ( current_item ( regedit - > vl - > menu ) ) ;
if ( vitem ) {
struct tree_node * node ;
node = item_userptr ( current_item ( regedit - > keys - > menu ) ) ;
2012-08-08 10:41:50 +04:00
dialog_edit_value ( regedit , node - > key , vitem - > type ,
2012-08-11 08:56:58 +04:00
vitem ) ;
2012-08-08 10:41:50 +04:00
value_list_load ( regedit - > vl , node - > key ) ;
2012-08-07 06:11:13 +04:00
}
2012-07-24 15:12:56 +04:00
break ;
2012-08-08 23:09:03 +04:00
case ' n ' :
case ' N ' : {
int new_type ;
2012-08-09 01:16:41 +04:00
int sel ;
2012-08-08 23:09:03 +04:00
2012-08-11 08:56:58 +04:00
sel = dialog_select_type ( regedit , & new_type ) ;
2012-08-09 01:16:41 +04:00
if ( sel = = DIALOG_OK ) {
struct tree_node * node ;
node = item_userptr ( current_item ( regedit - > keys - > menu ) ) ;
2012-08-11 08:56:58 +04:00
dialog_edit_value ( regedit , node - > key , new_type , NULL ) ;
2012-08-09 01:16:41 +04:00
value_list_load ( regedit - > vl , node - > key ) ;
2012-08-08 23:09:03 +04:00
}
break ;
}
2012-07-27 14:37:22 +04:00
case ' d ' :
case ' D ' :
vitem = item_userptr ( current_item ( regedit - > vl - > menu ) ) ;
if ( vitem ) {
2012-08-07 06:11:13 +04:00
int sel ;
2012-08-09 02:36:01 +04:00
sel = dialog_notice ( regedit , DIA_CONFIRM ,
" Delete Value " ,
" Really delete value \" %s \" ? " ,
vitem - > value_name ) ;
2012-08-09 01:16:41 +04:00
if ( sel = = DIALOG_OK ) {
ITEM * it = current_item ( regedit - > keys - > menu ) ;
struct tree_node * node = item_userptr ( it ) ;
reg_del_value ( regedit , node - > key ,
vitem - > value_name ) ;
value_list_load ( regedit - > vl , node - > key ) ;
}
2012-07-27 14:37:22 +04:00
}
break ;
}
value_list_show ( regedit - > vl ) ;
}
static void handle_main_input ( struct regedit * regedit , int c )
2012-07-24 15:12:56 +04:00
{
2012-07-27 14:37:22 +04:00
switch ( c ) {
case ' \t ' :
regedit - > tree_input = ! regedit - > tree_input ;
2012-08-11 07:05:20 +04:00
print_heading ( regedit ) ;
2012-07-27 14:37:22 +04:00
break ;
default :
if ( regedit - > tree_input ) {
handle_tree_input ( regedit , c ) ;
} else {
handle_value_input ( regedit , c ) ;
}
2012-07-24 15:12:56 +04:00
}
}
2012-08-11 08:56:58 +04:00
int regedit_getch ( void )
{
int c ;
SMB_ASSERT ( regedit_main ) ;
c = getch ( ) ;
if ( c = = KEY_RESIZE ) {
tree_view_resize ( regedit_main - > keys , KEY_HEIGHT , KEY_WIDTH ,
KEY_START_Y , KEY_START_X ) ;
value_list_resize ( regedit_main - > vl , VAL_HEIGHT , VAL_WIDTH ,
VAL_START_Y , VAL_START_X ) ;
print_heading ( regedit_main ) ;
2012-08-12 10:29:13 +04:00
show_path ( regedit_main ) ;
2012-08-11 08:56:58 +04:00
}
return c ;
}
static void display_window ( TALLOC_CTX * mem_ctx , struct registry_context * ctx )
2012-07-13 08:11:55 +04:00
{
2012-07-27 14:37:22 +04:00
struct regedit * regedit ;
2012-07-24 15:12:56 +04:00
struct tree_node * root ;
2012-07-13 08:11:55 +04:00
int c ;
initscr ( ) ;
start_color ( ) ;
cbreak ( ) ;
noecho ( ) ;
2012-07-27 14:37:22 +04:00
regedit = talloc_zero ( mem_ctx , struct regedit ) ;
SMB_ASSERT ( regedit ! = NULL ) ;
2012-08-11 08:56:58 +04:00
regedit_main = regedit ;
2012-07-27 14:37:22 +04:00
2012-08-11 07:05:20 +04:00
regedit - > main_window = stdscr ;
2012-07-27 14:37:22 +04:00
keypad ( regedit - > main_window , TRUE ) ;
2012-07-13 08:11:55 +04:00
2012-07-27 14:37:22 +04:00
mvwprintw ( regedit - > main_window , 0 , 0 , " Path: " ) ;
2012-08-12 09:10:51 +04:00
regedit - > path_label = newpad ( 1 , PATH_WIDTH_MAX ) ;
SMB_ASSERT ( regedit - > path_label ) ;
2012-07-27 14:37:22 +04:00
wprintw ( regedit - > path_label , " / " ) ;
2012-08-12 10:29:13 +04:00
show_path ( regedit_main ) ;
2012-07-14 04:16:51 +04:00
2012-07-27 14:37:22 +04:00
root = load_hives ( regedit , ctx ) ;
2012-07-13 08:11:55 +04:00
SMB_ASSERT ( root ! = NULL ) ;
2012-08-11 07:05:20 +04:00
regedit - > keys = tree_view_new ( regedit , root , KEY_HEIGHT , KEY_WIDTH ,
KEY_START_Y , KEY_START_X ) ;
2012-07-27 14:37:22 +04:00
SMB_ASSERT ( regedit - > keys ! = NULL ) ;
2012-08-11 07:05:20 +04:00
regedit - > vl = value_list_new ( regedit , VAL_HEIGHT , VAL_WIDTH ,
VAL_START_Y , VAL_START_X ) ;
2012-07-27 14:37:22 +04:00
SMB_ASSERT ( regedit - > vl ! = NULL ) ;
regedit - > tree_input = true ;
2012-08-11 07:05:20 +04:00
print_heading ( regedit ) ;
2012-07-27 14:37:22 +04:00
tree_view_show ( regedit - > keys ) ;
2012-08-20 05:29:06 +04:00
menu_driver ( regedit - > keys - > menu , REQ_FIRST_ITEM ) ;
load_values ( regedit ) ;
2012-07-27 14:37:22 +04:00
value_list_show ( regedit - > vl ) ;
update_panels ( ) ;
doupdate ( ) ;
2012-08-11 08:56:58 +04:00
while ( 1 ) {
c = regedit_getch ( ) ;
if ( c = = ' q ' | | c = = ' Q ' ) {
break ;
2012-08-11 07:05:20 +04:00
}
2012-08-07 06:11:13 +04:00
handle_main_input ( regedit , c ) ;
2012-07-27 14:37:22 +04:00
update_panels ( ) ;
doupdate ( ) ;
2012-07-13 08:11:55 +04:00
}
endwin ( ) ;
}
2012-07-06 14:08:17 +04:00
int main ( int argc , char * * argv )
{
struct poptOption long_options [ ] = {
POPT_AUTOHELP
/* ... */
POPT_COMMON_SAMBA
POPT_COMMON_CONNECTION
POPT_COMMON_CREDENTIALS
POPT_TABLEEND
} ;
int opt ;
poptContext pc ;
struct user_auth_info * auth_info ;
TALLOC_CTX * frame ;
struct registry_context * ctx ;
WERROR rv ;
2012-07-13 08:11:55 +04:00
talloc_enable_leak_report_full ( ) ;
2012-07-10 17:16:35 +04:00
2012-07-06 14:08:17 +04:00
frame = talloc_stackframe ( ) ;
setup_logging ( " regedit " , DEBUG_DEFAULT_STDERR ) ;
lp_set_cmdline ( " log level " , " 0 " ) ;
/* process options */
auth_info = user_auth_info_init ( frame ) ;
if ( auth_info = = NULL ) {
exit ( 1 ) ;
}
popt_common_set_auth_info ( auth_info ) ;
pc = poptGetContext ( " regedit " , argc , ( const char * * ) argv , long_options , 0 ) ;
while ( ( opt = poptGetNextOpt ( pc ) ) ! = - 1 ) {
/* TODO */
}
2012-07-13 12:57:02 +04:00
if ( ! lp_load_global ( get_dyn_CONFIGFILE ( ) ) ) {
DEBUG ( 0 , ( " ERROR loading config file... \n " ) ) ;
exit ( 1 ) ;
}
2012-07-06 14:08:17 +04:00
/* some simple tests */
rv = reg_open_samba3 ( frame , & ctx ) ;
2012-08-02 14:41:49 +04:00
if ( ! W_ERROR_IS_OK ( rv ) ) {
TALLOC_FREE ( frame ) ;
return 1 ;
}
2012-07-06 14:08:17 +04:00
2012-08-11 08:56:58 +04:00
display_window ( frame , ctx ) ;
2012-07-06 14:08:17 +04:00
2012-07-13 08:11:55 +04:00
//talloc_report_full(frame, stdout);
2012-07-06 14:08:17 +04:00
TALLOC_FREE ( frame ) ;
return 0 ;
}