1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-07 17:18:11 +03:00
samba-mirror/source3/utils/regedit_valuelist.c
Chris Davis 55662513e1 regedit: handle awkward window sizes better
This fixes some assertion failures and an infinte loop that occurs
when the terminal window is shrunk down far enough to the point
regedit can't fit everything on screen.

Signed-off-by: Chris Davis <cd.rattan@gmail.com>
Reviewed-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
2014-10-01 14:32:08 +02:00

399 lines
8.0 KiB
C

/*
* 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_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 select)
{
attr_t attr = A_NORMAL;
if (select) {
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_NOMEM;
}
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_NOMEM;
}
}
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_NOMEM;
}
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);
}
WERROR value_list_load(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_NOMEM;
}
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;
}
rv = append_data_summary(new_items, vitem);
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;
rv = multilist_set_data(vl->list, vl);
if (W_ERROR_IS_OK(rv)) {
multilist_refresh(vl->list);
}
return rv;
}
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_driver(struct value_list *vl, int c)
{
multilist_driver(vl->list, c);
}