1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00
samba-mirror/source3/utils/regedit_valuelist.c

497 lines
9.8 KiB
C
Raw Normal View History

/*
* 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 "regedit.h"
#include "regedit_valuelist.h"
#include "regedit_list.h"
#include "lib/registry/registry.h"
#define HEADING_X 3
static int value_list_free(struct value_list *vl)
{
if (vl->panel) {
del_panel(vl->panel);
}
if (vl->sub) {
delwin(vl->sub);
}
if (vl->window) {
delwin(vl->window);
}
return 0;
}
static const char *vl_get_column_header(const void *data, unsigned col)
{
switch (col) {
case 0:
return "Name";
case 1:
return "Type";
case 2:
return "Data";
}
return "???";
}
static const void *vl_get_first_row(const void *data)
{
const struct value_list *vl;
if (data) {
vl = talloc_get_type_abort(data, struct value_list);
if (vl->nvalues) {
return &vl->values[0];
}
}
return NULL;
}
static const void *vl_get_next_row(const void *data, const void *row)
{
const struct value_list *vl;
const struct value_item *value = row;
SMB_ASSERT(data != NULL);
SMB_ASSERT(value != NULL);
vl = talloc_get_type_abort(data, struct value_list);
if (value == &vl->values[vl->nvalues - 1]) {
return NULL;
}
return value + 1;
}
static const void *vl_get_prev_row(const void *data, const void *row)
{
const struct value_list *vl;
const struct value_item *value = row;
SMB_ASSERT(data != NULL);
SMB_ASSERT(value != NULL);
vl = talloc_get_type_abort(data, struct value_list);
if (value == &vl->values[0]) {
return NULL;
}
return value - 1;
}
static const char *vl_get_item_label(const void *row, unsigned col)
{
const struct value_item *value = row;
SMB_ASSERT(value != NULL);
SMB_ASSERT(value->value_name != NULL);
switch (col) {
case 0:
return value->value_name;
case 1:
return str_regtype(value->type);
case 2:
if (value->value) {
return value->value;
}
return "";
}
return "???";
}
static struct multilist_accessors vl_accessors = {
.get_column_header = vl_get_column_header,
.get_first_row = vl_get_first_row,
.get_next_row = vl_get_next_row,
.get_prev_row = vl_get_prev_row,
.get_item_label = vl_get_item_label
};
struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols,
int begin_y, int begin_x)
{
struct value_list *vl;
vl = talloc_zero(ctx, struct value_list);
if (vl == NULL) {
return NULL;
}
talloc_set_destructor(vl, value_list_free);
vl->window = newwin(nlines, ncols, begin_y, begin_x);
if (vl->window == NULL) {
goto fail;
}
vl->sub = subwin(vl->window, nlines - 2, ncols - 2,
begin_y + 1, begin_x + 1);
if (vl->sub == NULL) {
goto fail;
}
box(vl->window, 0, 0);
mvwprintw(vl->window, 0, HEADING_X, "Value");
vl->panel = new_panel(vl->window);
if (vl->panel == NULL) {
goto fail;
}
vl->list = multilist_new(vl, vl->sub, &vl_accessors, 3);
if (vl->list == NULL) {
goto fail;
}
return vl;
fail:
talloc_free(vl);
return NULL;
}
void value_list_set_selected(struct value_list *vl, bool reverse)
{
attr_t attr = A_NORMAL;
if (reverse) {
attr = A_REVERSE;
}
mvwchgat(vl->window, 0, HEADING_X, 5, attr, 0, NULL);
}
void value_list_resize(struct value_list *vl, int nlines, int ncols,
int begin_y, int begin_x)
{
WINDOW *nwin, *nsub;
nwin = newwin(nlines, ncols, begin_y, begin_x);
if (nwin == NULL) {
return;
}
nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1);
if (nsub == NULL) {
delwin(nwin);
return;
}
replace_panel(vl->panel, nwin);
delwin(vl->sub);
delwin(vl->window);
vl->window = nwin;
vl->sub = nsub;
box(vl->window, 0, 0);
mvwprintw(vl->window, 0, HEADING_X, "Value");
multilist_set_window(vl->list, vl->sub);
value_list_show(vl);
}
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)
{
multilist_refresh(vl->list);
touchwin(vl->window);
wnoutrefresh(vl->window);
wnoutrefresh(vl->sub);
}
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(TALLOC_CTX *ctx, 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(ctx, "0x%08x (%u)", v, v);
break;
}
case REG_SZ:
case REG_EXPAND_SZ: {
const char *s;
if (!pull_reg_sz(ctx, &vitem->data, &s)) {
break;
}
vitem->unprintable = !string_is_printable(s);
if (vitem->unprintable) {
tmp = talloc_asprintf(ctx, "(unprintable)");
} else {
tmp = talloc_asprintf(ctx, "%s", s);
}
break;
}
case REG_MULTI_SZ: {
size_t i, len;
const char **a;
const char *val;
if (!pull_reg_multi_sz(ctx, &vitem->data, &a)) {
break;
}
for (len = 0; a[len] != NULL; ++len) {
}
tmp = talloc_asprintf(ctx, "(%u) ", (unsigned)len);
if (tmp == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
for (i = 0; i < len; ++i) {
if (!string_is_printable(a[i])) {
val = "(unprintable)";
vitem->unprintable = true;
} else {
val = a[i];
}
if (i == len - 1) {
tmp = talloc_asprintf_append(tmp,
"[%u]=\"%s\"",
(unsigned)i, val);
} else {
tmp = talloc_asprintf_append(tmp,
"[%u]=\"%s\", ",
(unsigned)i, val);
}
if (tmp == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
}
break;
}
case REG_BINARY:
tmp = talloc_asprintf(ctx, "(%d bytes)",
(int)vitem->data.length);
break;
default:
tmp = talloc_asprintf(ctx, "(unknown)");
break;
}
if (tmp == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
vitem->value = tmp;
return WERR_OK;
}
static int vitem_cmp(struct value_item *a, struct value_item *b)
{
return strcmp(a->value_name, b->value_name);
}
/* load only the value names into memory to enable searching */
WERROR value_list_load_quick(struct value_list *vl, struct registry_key *key)
{
uint32_t nvalues;
uint32_t idx;
struct value_item *vitem, *new_items;
WERROR rv;
multilist_set_data(vl->list, NULL);
vl->nvalues = 0;
TALLOC_FREE(vl->values);
nvalues = get_num_values(vl, key);
if (nvalues == 0) {
return WERR_OK;
}
new_items = talloc_zero_array(vl, struct value_item, nvalues);
if (new_items == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
for (idx = 0; idx < nvalues; ++idx) {
vitem = &new_items[idx];
rv = reg_key_get_value_by_index(new_items, key, idx,
&vitem->value_name,
&vitem->type,
&vitem->data);
if (!W_ERROR_IS_OK(rv)) {
talloc_free(new_items);
return rv;
}
}
TYPESAFE_QSORT(new_items, nvalues, vitem_cmp);
vl->nvalues = nvalues;
vl->values = new_items;
return rv;
}
/* sync up the UI with the list */
WERROR value_list_sync(struct value_list *vl)
{
uint32_t idx;
WERROR rv;
for (idx = 0; idx < vl->nvalues; ++idx) {
rv = append_data_summary(vl->values, &vl->values[idx]);
if (!W_ERROR_IS_OK(rv)) {
return rv;
}
}
rv = multilist_set_data(vl->list, vl);
if (W_ERROR_IS_OK(rv)) {
multilist_refresh(vl->list);
}
return rv;
}
WERROR value_list_load(struct value_list *vl, struct registry_key *key)
{
WERROR rv;
rv = value_list_load_quick(vl, key);
if (!W_ERROR_IS_OK(rv)) {
return rv;
}
rv = value_list_sync(vl);
return rv;
}
struct value_item *value_list_find_next_item(struct value_list *vl,
struct value_item *vitem,
const char *s,
regedit_search_match_fn_t match)
{
struct value_item *end;
if (!vl->values) {
return NULL;
}
if (vitem) {
++vitem;
} else {
vitem = &vl->values[0];
}
for (end = &vl->values[vl->nvalues]; vitem < end; ++vitem) {
if (match(vitem->value_name, s)) {
return vitem;
}
}
return NULL;
}
struct value_item *value_list_find_prev_item(struct value_list *vl,
struct value_item *vitem,
const char *s,
regedit_search_match_fn_t match)
{
struct value_item *end;
if (!vl->values) {
return NULL;
}
if (vitem) {
--vitem;
} else {
vitem = &vl->values[vl->nvalues - 1];
}
for (end = &vl->values[-1]; vitem > end; --vitem) {
if (match(vitem->value_name, s)) {
return vitem;
}
}
return NULL;
}
struct value_item *value_list_get_current_item(struct value_list *vl)
{
return discard_const_p(struct value_item,
multilist_get_current_row(vl->list));
}
void value_list_set_current_item_by_name(struct value_list *vl,
const char *name)
{
size_t i;
for (i = 0; i < vl->nvalues; ++i) {
if (strequal(vl->values[i].value_name, name)) {
multilist_set_current_row(vl->list, &vl->values[i]);
return;
}
}
}
void value_list_set_current_item(struct value_list *vl,
const struct value_item *item)
{
multilist_set_current_row(vl->list, item);
}
void value_list_driver(struct value_list *vl, int c)
{
multilist_driver(vl->list, c);
}