2012-07-10 17:23:33 +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 "regedit_treeview.h"
2012-07-13 08:11:55 +04:00
# include "lib/registry/registry.h"
2012-07-10 17:23:33 +04:00
2014-05-21 03:17:42 +04:00
# define HEADING_X 3
2012-07-13 08:11:55 +04:00
struct tree_node * tree_node_new ( TALLOC_CTX * ctx , struct tree_node * parent ,
const char * name , struct registry_key * key )
2012-07-10 17:23:33 +04:00
{
struct tree_node * node ;
node = talloc_zero ( ctx , struct tree_node ) ;
if ( ! node ) {
return NULL ;
}
node - > name = talloc_strdup ( node , name ) ;
if ( ! node - > name ) {
talloc_free ( node ) ;
return NULL ;
}
2012-07-13 08:11:55 +04:00
node - > key = talloc_steal ( node , key ) ;
2012-07-10 17:23:33 +04:00
if ( parent ) {
/* Check if this node is the first descendant of parent. */
if ( ! parent - > child_head ) {
parent - > child_head = node ;
}
node - > parent = parent ;
}
return node ;
}
void tree_node_append ( struct tree_node * left , struct tree_node * right )
{
if ( left - > next ) {
right - > next = left - > next ;
left - > next - > previous = right ;
}
left - > next = right ;
right - > previous = left ;
}
2012-08-10 05:14:42 +04:00
void tree_node_append_last ( struct tree_node * list , struct tree_node * node )
{
tree_node_append ( tree_node_last ( list ) , node ) ;
}
2012-07-10 17:23:33 +04:00
struct tree_node * tree_node_pop ( struct tree_node * * plist )
{
struct tree_node * node ;
node = * plist ;
if ( node = = NULL )
return NULL ;
* plist = node - > previous ;
if ( * plist = = NULL ) {
* plist = node - > next ;
}
if ( node - > previous ) {
node - > previous - > next = node - > next ;
}
if ( node - > next ) {
node - > next - > previous = node - > previous ;
}
2012-08-10 05:14:42 +04:00
if ( node - > parent & & node - > parent - > child_head = = node ) {
node - > parent - > child_head = node - > next ;
}
2012-07-10 17:23:33 +04:00
node - > next = NULL ;
node - > previous = NULL ;
return node ;
}
struct tree_node * tree_node_first ( struct tree_node * list )
{
/* Grab the first node in this list from the parent if available. */
if ( list - > parent ) {
return list - > parent - > child_head ;
}
while ( list & & list - > previous ) {
list = list - > previous ;
}
return list ;
}
2012-08-10 05:14:42 +04:00
struct tree_node * tree_node_last ( struct tree_node * list )
{
while ( list & & list - > next ) {
list = list - > next ;
}
return list ;
}
2014-06-03 08:50:01 +04:00
static uint32_t get_num_subkeys ( struct tree_node * node )
2012-07-13 08:11:55 +04:00
{
const char * classname ;
uint32_t num_subkeys ;
uint32_t num_values ;
NTTIME last_change_time ;
uint32_t max_subkeynamelen ;
uint32_t max_valnamelen ;
uint32_t max_valbufsize ;
WERROR rv ;
rv = reg_key_get_info ( node , node - > key , & classname , & num_subkeys ,
& num_values , & last_change_time ,
& max_subkeynamelen , & max_valnamelen ,
& max_valbufsize ) ;
if ( W_ERROR_IS_OK ( rv ) ) {
2014-06-03 08:50:01 +04:00
return num_subkeys ;
}
return 0 ;
}
bool tree_node_has_children ( struct tree_node * node )
{
if ( node - > child_head ) {
return true ;
2012-07-13 08:11:55 +04:00
}
2014-06-03 08:50:01 +04:00
return get_num_subkeys ( node ) > 0 ;
}
static int node_cmp ( struct tree_node * * a , struct tree_node * * b )
{
return strcmp ( ( * a ) - > name , ( * b ) - > name ) ;
}
void tree_node_insert_sorted ( struct tree_node * list , struct tree_node * node )
{
list = tree_node_first ( list ) ;
if ( node_cmp ( & list , & node ) > = 0 ) {
tree_node_append ( node , list ) ;
if ( list - > parent ) {
list - > parent - > child_head = node ;
}
return ;
}
while ( list - > next & & node_cmp ( & list - > next , & node ) < 0 ) {
list = list - > next ;
}
tree_node_append ( list , node ) ;
2012-07-13 08:11:55 +04:00
}
WERROR tree_node_load_children ( struct tree_node * node )
{
struct registry_key * key ;
const char * key_name , * klass ;
NTTIME modified ;
2014-06-03 08:50:01 +04:00
uint32_t i , nsubkeys ;
2012-07-13 08:11:55 +04:00
WERROR rv ;
2014-06-03 08:50:01 +04:00
struct tree_node * prev , * * array ;
2012-07-13 08:11:55 +04:00
/* does this node already have it's children loaded? */
if ( node - > child_head )
return WERR_OK ;
2014-06-03 08:50:01 +04:00
nsubkeys = get_num_subkeys ( node ) ;
if ( nsubkeys = = 0 )
return WERR_OK ;
array = talloc_zero_array ( node , struct tree_node * , nsubkeys ) ;
if ( array = = NULL ) {
return WERR_NOMEM ;
}
for ( i = 0 ; i < nsubkeys ; + + i ) {
2012-07-13 08:11:55 +04:00
rv = reg_key_get_subkey_by_index ( node , node - > key , i ,
& key_name , & klass ,
& modified ) ;
if ( ! W_ERROR_IS_OK ( rv ) ) {
2014-06-03 08:50:01 +04:00
goto finish ;
2012-07-13 08:11:55 +04:00
}
rv = reg_open_key ( node , node - > key , key_name , & key ) ;
if ( ! W_ERROR_IS_OK ( rv ) ) {
2014-06-03 08:50:01 +04:00
goto finish ;
2012-07-13 08:11:55 +04:00
}
2014-06-03 08:50:01 +04:00
array [ i ] = tree_node_new ( node , node , key_name , key ) ;
if ( array [ i ] = = NULL ) {
rv = WERR_NOMEM ;
goto finish ;
2012-07-13 08:11:55 +04:00
}
2014-06-03 08:50:01 +04:00
}
TYPESAFE_QSORT ( array , nsubkeys , node_cmp ) ;
for ( i = 1 , prev = array [ 0 ] ; i < nsubkeys ; + + i ) {
tree_node_append ( prev , array [ i ] ) ;
prev = array [ i ] ;
}
node - > child_head = array [ 0 ] ;
rv = WERR_OK ;
2012-07-13 08:11:55 +04:00
2014-06-03 08:50:01 +04:00
finish :
if ( ! W_ERROR_IS_OK ( rv ) ) {
for ( i = 0 ; i < nsubkeys ; + + i ) {
talloc_free ( array [ i ] ) ;
2012-07-13 08:11:55 +04:00
}
2014-06-03 08:50:01 +04:00
node - > child_head = NULL ;
2012-07-13 08:11:55 +04:00
}
2014-06-03 08:50:01 +04:00
talloc_free ( array ) ;
2012-07-13 08:11:55 +04:00
2014-06-03 08:50:01 +04:00
return rv ;
2012-07-13 08:11:55 +04:00
}
2012-07-10 17:23:33 +04:00
void tree_node_free_recursive ( struct tree_node * list )
{
struct tree_node * node ;
if ( list = = NULL ) {
return ;
}
while ( ( node = tree_node_pop ( & list ) ) ! = NULL ) {
if ( node - > child_head ) {
tree_node_free_recursive ( node - > child_head ) ;
}
node - > child_head = NULL ;
talloc_free ( node ) ;
}
}
static void tree_view_free_current_items ( ITEM * * items )
{
size_t i ;
struct tree_node * node ;
ITEM * item ;
if ( items = = NULL ) {
return ;
}
for ( i = 0 ; items [ i ] ! = NULL ; + + i ) {
item = items [ i ] ;
node = item_userptr ( item ) ;
if ( node & & node - > label ) {
talloc_free ( node - > label ) ;
node - > label = NULL ;
}
free_item ( item ) ;
}
talloc_free ( items ) ;
}
2012-08-10 05:14:42 +04:00
void tree_view_clear ( struct tree_view * view )
{
unpost_menu ( view - > menu ) ;
set_menu_items ( view - > menu , view - > empty ) ;
tree_view_free_current_items ( view - > current_items ) ;
view - > current_items = NULL ;
}
2012-07-10 17:23:33 +04:00
WERROR tree_view_update ( struct tree_view * view , struct tree_node * list )
{
ITEM * * items ;
struct tree_node * node ;
size_t i , n_items ;
if ( list = = NULL ) {
list = view - > root ;
}
for ( n_items = 0 , node = list ; node ! = NULL ; node = node - > next ) {
n_items + + ;
}
items = talloc_zero_array ( view , ITEM * , n_items + 1 ) ;
if ( items = = NULL ) {
return WERR_NOMEM ;
}
for ( i = 0 , node = list ; node ! = NULL ; + + i , node = node - > next ) {
2014-05-20 04:34:01 +04:00
char prefix = ' ' ;
2012-07-10 17:23:33 +04:00
/* Add a '+' marker to indicate that the item has
descendants . */
2012-07-13 08:11:55 +04:00
if ( tree_node_has_children ( node ) ) {
2014-05-20 04:34:01 +04:00
prefix = ' + ' ;
}
SMB_ASSERT ( node - > label = = NULL ) ;
node - > label = talloc_asprintf ( node , " %c%s " , prefix , node - > name ) ;
if ( node - > label = = NULL ) {
goto fail ;
2012-07-10 17:23:33 +04:00
}
2014-05-20 04:34:01 +04:00
items [ i ] = new_item ( node - > label , node - > name ) ;
2012-07-10 17:23:33 +04:00
set_item_userptr ( items [ i ] , node ) ;
}
unpost_menu ( view - > menu ) ;
set_menu_items ( view - > menu , items ) ;
tree_view_free_current_items ( view - > current_items ) ;
view - > current_items = items ;
return WERR_OK ;
fail :
tree_view_free_current_items ( items ) ;
return WERR_NOMEM ;
}
2014-06-03 08:50:01 +04:00
/* is this node in the current level? */
bool tree_view_is_node_visible ( struct tree_view * view , struct tree_node * node )
{
struct tree_node * first ;
first = item_userptr ( view - > current_items [ 0 ] ) ;
return first - > parent = = node - > parent ;
}
void tree_view_set_current_node ( struct tree_view * view , struct tree_node * node )
{
ITEM * * it ;
for ( it = view - > current_items ; * it ; + + it ) {
if ( item_userptr ( * it ) = = node ) {
set_current_item ( view - > menu , * it ) ;
return ;
}
}
}
struct tree_node * tree_view_get_current_node ( struct tree_view * view )
{
return item_userptr ( current_item ( view - > menu ) ) ;
}
2014-05-21 03:17:42 +04:00
void tree_view_set_selected ( struct tree_view * view , bool select )
{
attr_t attr = A_NORMAL ;
if ( select ) {
attr = A_REVERSE ;
}
mvwchgat ( view - > window , 0 , HEADING_X , 3 , attr , 0 , NULL ) ;
}
2012-07-10 17:23:33 +04:00
void tree_view_show ( struct tree_view * view )
{
post_menu ( view - > menu ) ;
}
static int tree_view_free ( struct tree_view * view )
{
if ( view - > menu ) {
unpost_menu ( view - > menu ) ;
free_menu ( view - > menu ) ;
}
2012-08-10 05:14:42 +04:00
if ( view - > empty [ 0 ] ) {
free_item ( view - > empty [ 0 ] ) ;
}
2012-08-11 07:05:20 +04:00
if ( view - > panel ) {
del_panel ( view - > panel ) ;
}
2014-05-21 03:17:42 +04:00
if ( view - > sub ) {
delwin ( view - > sub ) ;
}
2012-08-11 07:05:20 +04:00
if ( view - > window ) {
delwin ( view - > window ) ;
}
2012-07-10 17:23:33 +04:00
tree_view_free_current_items ( view - > current_items ) ;
tree_node_free_recursive ( view - > root ) ;
return 0 ;
}
struct tree_view * tree_view_new ( TALLOC_CTX * ctx , struct tree_node * root ,
2012-08-11 07:05:20 +04:00
int nlines , int ncols , int begin_y ,
int begin_x )
2012-07-10 17:23:33 +04:00
{
struct tree_view * view ;
2012-08-10 05:14:42 +04:00
static const char * dummy = " (empty) " ;
2012-07-10 17:23:33 +04:00
view = talloc_zero ( ctx , struct tree_view ) ;
if ( view = = NULL ) {
return NULL ;
}
talloc_set_destructor ( view , tree_view_free ) ;
2012-08-10 05:14:42 +04:00
view - > empty [ 0 ] = new_item ( dummy , dummy ) ;
if ( view - > empty [ 0 ] = = NULL ) {
2012-07-10 17:23:33 +04:00
goto fail ;
}
2012-08-11 07:05:20 +04:00
view - > window = newwin ( nlines , ncols , begin_y , begin_x ) ;
if ( view - > window = = NULL ) {
goto fail ;
}
2014-05-21 03:17:42 +04:00
view - > sub = subwin ( view - > window , nlines - 2 , ncols - 2 ,
begin_y + 1 , begin_x + 1 ) ;
if ( view - > sub = = NULL ) {
goto fail ;
}
box ( view - > window , 0 , 0 ) ;
mvwprintw ( view - > window , 0 , HEADING_X , " Key " ) ;
2012-08-11 07:05:20 +04:00
view - > panel = new_panel ( view - > window ) ;
if ( view - > panel = = NULL ) {
2012-08-10 05:14:42 +04:00
goto fail ;
}
2012-07-10 17:23:33 +04:00
view - > root = root ;
2012-08-10 05:14:42 +04:00
view - > menu = new_menu ( view - > empty ) ;
2012-07-10 17:23:33 +04:00
if ( view - > menu = = NULL ) {
goto fail ;
}
set_menu_format ( view - > menu , nlines , 1 ) ;
set_menu_win ( view - > menu , view - > window ) ;
2014-05-21 03:17:42 +04:00
set_menu_sub ( view - > menu , view - > sub ) ;
2012-07-10 17:23:33 +04:00
menu_opts_off ( view - > menu , O_SHOWDESC ) ;
set_menu_mark ( view - > menu , " * " ) ;
tree_view_update ( view , root ) ;
return view ;
fail :
talloc_free ( view ) ;
return NULL ;
}
2012-08-11 07:05:20 +04:00
void tree_view_resize ( struct tree_view * view , int nlines , int ncols ,
int begin_y , int begin_x )
{
2014-05-21 03:17:42 +04:00
WINDOW * nwin , * nsub ;
2012-08-11 07:05:20 +04:00
unpost_menu ( view - > menu ) ;
nwin = newwin ( nlines , ncols , begin_y , begin_x ) ;
2014-05-21 03:17:42 +04:00
nsub = subwin ( nwin , nlines - 2 , ncols - 2 , begin_y + 1 , begin_x + 1 ) ;
2012-08-11 07:05:20 +04:00
replace_panel ( view - > panel , nwin ) ;
2014-05-21 03:17:42 +04:00
delwin ( view - > sub ) ;
2012-08-11 07:05:20 +04:00
delwin ( view - > window ) ;
view - > window = nwin ;
2014-05-21 03:17:42 +04:00
view - > sub = nsub ;
box ( view - > window , 0 , 0 ) ;
mvwprintw ( view - > window , 0 , HEADING_X , " Key " ) ;
2012-08-11 07:05:20 +04:00
set_menu_format ( view - > menu , nlines , 1 ) ;
set_menu_win ( view - > menu , view - > window ) ;
2014-05-21 03:17:42 +04:00
set_menu_sub ( view - > menu , view - > sub ) ;
2012-08-11 07:05:20 +04:00
post_menu ( view - > menu ) ;
}
2012-08-19 10:44:59 +04:00
static void print_path_recursive ( WINDOW * label , struct tree_node * node ,
size_t * len )
2012-07-10 17:23:33 +04:00
{
if ( node - > parent )
2012-08-12 10:22:06 +04:00
print_path_recursive ( label , node - > parent , len ) ;
2012-07-10 17:23:33 +04:00
wprintw ( label , " %s/ " , node - > name ) ;
2012-08-12 10:22:06 +04:00
* len + = 1 + strlen ( node - > name ) ;
2012-07-10 17:23:33 +04:00
}
/* print the path of node to label */
2012-08-12 10:22:06 +04:00
size_t tree_node_print_path ( WINDOW * label , struct tree_node * node )
2012-07-10 17:23:33 +04:00
{
2012-08-12 10:22:06 +04:00
size_t len = 1 ;
2012-07-10 17:23:33 +04:00
if ( node = = NULL )
2012-08-12 10:22:06 +04:00
return 0 ;
2012-07-10 17:23:33 +04:00
2012-08-12 09:10:51 +04:00
werase ( label ) ;
2012-07-10 17:23:33 +04:00
wprintw ( label , " / " ) ;
if ( node - > parent )
2012-08-12 10:22:06 +04:00
print_path_recursive ( label , node - > parent , & len ) ;
return len ;
2012-07-10 17:23:33 +04:00
}