/*
* 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 .
*/
#include "regedit_valuelist.h"
#include "lib/registry/registry.h"
static void value_list_free_items(ITEM **items)
{
size_t i;
ITEM *item;
struct value_item *vitem;
if (items == NULL) {
return;
}
for (i = 0; items[i] != NULL; ++i) {
item = items[i];
vitem = item_userptr(item);
SMB_ASSERT(vitem != NULL);
free_item(item);
}
talloc_free(items);
}
static int value_list_free(struct value_list *vl)
{
if (vl->menu) {
unpost_menu(vl->menu);
free_menu(vl->menu);
}
if (vl->empty && vl->empty[0]) {
free_item(vl->empty[0]);
}
if (vl->panel) {
del_panel(vl->panel);
}
if (vl->window) {
delwin(vl->window);
}
value_list_free_items(vl->items);
return 0;
}
struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols,
int begin_y, int begin_x)
{
static const char *empty = "(no values)";
static const char *empty_desc = "";
struct value_list *vl;
vl = talloc_zero(ctx, struct value_list);
if (vl == NULL) {
return NULL;
}
talloc_set_destructor(vl, value_list_free);
vl->empty = talloc_zero_array(vl, ITEM *, 2);
if (vl->empty == NULL) {
goto fail;
}
vl->empty[0] = new_item(empty, empty_desc);
if (vl->empty[0] == NULL) {
goto fail;
}
vl->window = newwin(nlines, ncols, begin_y, begin_x);
if (vl->window == NULL) {
goto fail;
}
vl->panel = new_panel(vl->window);
if (vl->panel == NULL) {
goto fail;
}
vl->menu = new_menu(vl->empty);
if (vl->menu == NULL) {
goto fail;
}
set_menu_format(vl->menu, nlines, 1);
set_menu_win(vl->menu, vl->window);
menu_opts_on(vl->menu, O_SHOWDESC);
set_menu_mark(vl->menu, "* ");
return vl;
fail:
talloc_free(vl);
return NULL;
}
void value_list_resize(struct value_list *vl, int nlines, int ncols,
int begin_y, int begin_x)
{
WINDOW *nwin;
unpost_menu(vl->menu);
nwin = newwin(nlines, ncols, begin_y, begin_x);
replace_panel(vl->panel, nwin);
delwin(vl->window);
vl->window = nwin;
set_menu_format(vl->menu, nlines, 1);
set_menu_win(vl->menu, vl->window);
post_menu(vl->menu);
}
static uint32_t get_num_values(TALLOC_CTX *ctx, const struct registry_key *key)
{
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(ctx, key, &classname, &num_subkeys,
&num_values, &last_change_time,
&max_subkeynamelen, &max_valnamelen,
&max_valbufsize);
if (W_ERROR_IS_OK(rv)) {
return num_values;
}
return 0;
}
void value_list_show(struct value_list *vl)
{
post_menu(vl->menu);
}
static bool string_is_printable(const char *s)
{
const char *p;
for (p = s; *p; ++p) {
if (!isprint(*p)) {
return false;
}
}
return true;
}
static WERROR append_data_summary(struct value_item *vitem)
{
char *tmp = NULL;
/* This is adapted from print_registry_value() in net_registry_util.c */
switch(vitem->type) {
case REG_DWORD: {
uint32_t v = 0;
if (vitem->data.length >= 4) {
v = IVAL(vitem->data.data, 0);
}
tmp = talloc_asprintf_append(vitem->value_desc, "(0x%x)", v);
break;
}
case REG_SZ:
case REG_EXPAND_SZ: {
const char *s;
if (!pull_reg_sz(vitem, &vitem->data, &s)) {
break;
}
vitem->unprintable = !string_is_printable(s);
if (vitem->unprintable) {
tmp = talloc_asprintf_append(vitem->value_desc,
"(unprintable)");
} else {
tmp = talloc_asprintf_append(vitem->value_desc,
"(\"%s\")", s);
}
break;
}
case REG_MULTI_SZ: {
size_t i;
const char **a;
if (!pull_reg_multi_sz(vitem, &vitem->data, &a)) {
break;
}
tmp = vitem->value_desc;
for (i = 0; a[i] != NULL; ++i) {
if (!string_is_printable(a[i])) {
tmp = talloc_asprintf_append(tmp,
"(unprintable)");
vitem->unprintable = true;
} else {
tmp = talloc_asprintf_append(tmp, "\"%s\" ",
a[i]);
}
if (tmp == NULL) {
return WERR_NOMEM;
}
}
break;
}
case REG_BINARY:
tmp = talloc_asprintf_append(vitem->value_desc, "(%d bytes)",
(int)vitem->data.length);
break;
default:
tmp = talloc_asprintf_append(vitem->value_desc,
"()");
break;
}
if (tmp == NULL) {
return WERR_NOMEM;
}
vitem->value_desc = tmp;
return WERR_OK;
}
WERROR value_list_load(struct value_list *vl, struct registry_key *key)
{
uint32_t n_values;
uint32_t idx;
struct value_item *vitem;
ITEM **new_items;
WERROR rv;
static const char *empty_name = "(empty)";
const char *name;
unpost_menu(vl->menu);
n_values = get_num_values(vl, key);
if (n_values == 0) {
set_menu_items(vl->menu, vl->empty);
return WERR_OK;
}
new_items = talloc_zero_array(vl, ITEM *, n_values + 1);
if (new_items == NULL) {
return WERR_NOMEM;
}
for (idx = 0; idx < n_values; ++idx) {
vitem = talloc_zero(new_items, struct value_item);
if (vitem == NULL) {
return WERR_NOMEM;
}
rv = reg_key_get_value_by_index(vitem, key, idx,
&vitem->value_name,
&vitem->type,
&vitem->data);
if (!W_ERROR_IS_OK(rv)) {
talloc_free(vitem);
return rv;
}
vitem->value_desc = talloc_asprintf(vitem, "%-14s",
str_regtype(vitem->type));
if (vitem->value_desc == NULL) {
talloc_free(vitem);
return rv;
}
rv = append_data_summary(vitem);
if (!W_ERROR_IS_OK(rv)) {
talloc_free(vitem);
return rv;
}
/* ncurses won't accept empty strings in menu items */
name = vitem->value_name;
if (name[0] == '\0') {
name = empty_name;
}
new_items[idx] = new_item(name, vitem->value_desc);
if (new_items[idx] == NULL) {
talloc_free(vitem);
return WERR_NOMEM;
}
set_item_userptr(new_items[idx], vitem);
}
set_menu_items(vl->menu, new_items);
value_list_free_items(vl->items);
vl->items = new_items;
return WERR_OK;
}