2 * Samba Unix/Linux SMB client library
4 * Copyright (C) Christopher Davis 2012
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "regedit_dialog.h"
22 #include "regedit_valuelist.h"
24 #include "lib/registry/registry.h"
28 static int dialog_free(struct dialog *dia)
33 if (dia->sub_window) {
34 delwin(dia->sub_window);
37 del_panel(dia->panel);
40 unpost_menu(dia->choices);
41 free_menu(dia->choices);
43 if (dia->choice_items) {
45 for (it = dia->choice_items; *it != NULL; ++it) {
53 struct dialog *dialog_new(TALLOC_CTX *ctx, const char *title, int nlines,
54 int ncols, int y, int x)
58 dia = talloc_zero(ctx, struct dialog);
63 talloc_set_destructor(dia, dialog_free);
65 dia->window = newwin(nlines, ncols, y, x);
66 if (dia->window == NULL) {
70 box(dia->window, 0, 0);
71 mvwaddstr(dia->window, 0, 1, title);
73 /* body of the dialog within the box outline */
74 dia->sub_window = derwin(dia->window, nlines - 2, ncols - 2, 1, 1);
75 if (dia->sub_window == NULL) {
79 dia->panel = new_panel(dia->window);
80 if (dia->panel == NULL) {
93 static void center_dialog_above_window(WINDOW *below, int *nlines, int *ncols,
99 getmaxyx(below, maxy, maxx);
106 if (*nlines > maxy) {
113 if (*nlines < centery) {
114 *y = centery - *nlines;
116 if (*ncols < centerx) {
117 *x = centerx - *ncols;
121 struct dialog *dialog_center_new(TALLOC_CTX *ctx, const char *title, int nlines,
122 int ncols, WINDOW *below)
126 center_dialog_above_window(below, &nlines, &ncols, &y, &x);
128 return dialog_new(ctx, title, nlines, ncols, y, x);
131 struct dialog *dialog_choice_new(TALLOC_CTX *ctx, const char *title,
132 const char **choices, int nlines,
133 int ncols, int y, int x)
138 dia = dialog_new(ctx, title, nlines, ncols, y, x);
143 dia->menu_window = derwin(dia->sub_window, 1, ncols - 3,
145 if (dia->menu_window == NULL) {
149 for (nchoices = 0; choices[nchoices] != NULL; ++nchoices)
151 dia->choice_items = talloc_zero_array(dia, ITEM *, nchoices + 1);
152 if (dia->choice_items == NULL) {
155 for (i = 0; i < nchoices; ++i) {
156 char *desc = talloc_strdup(dia, choices[i]);
160 dia->choice_items[i] = new_item(desc, desc);
161 if (dia->choice_items[i] == NULL) {
164 /* store choice index */
165 set_item_userptr(dia->choice_items[i], (void*)(uintptr_t)i);
168 dia->choices = new_menu(dia->choice_items);
169 if (dia->choices == NULL) {
173 set_menu_format(dia->choices, 1, ncols);
174 set_menu_win(dia->choices, dia->sub_window);
175 set_menu_sub(dia->choices, dia->menu_window);
176 menu_opts_off(dia->choices, O_SHOWDESC);
177 set_menu_mark(dia->choices, "* ");
178 post_menu(dia->choices);
179 wmove(dia->sub_window, 0, 0);
189 struct dialog *dialog_choice_center_new(TALLOC_CTX *ctx, const char *title,
190 const char **choices, int nlines,
191 int ncols, WINDOW *below)
195 center_dialog_above_window(below, &nlines, &ncols, &y, &x);
197 return dialog_choice_new(ctx, title, choices, nlines, ncols, y, x);
200 struct dialog *dialog_confirm_new(TALLOC_CTX *ctx, const char *title,
201 WINDOW *below, const char *msg, ...)
206 const char *choices[] = {
214 str = talloc_vasprintf(ctx, msg, ap);
220 width = strlen(str) + 2;
222 dia = dialog_choice_center_new(ctx, title, choices, 5, width, below);
227 waddstr(dia->sub_window, str);
233 static int handle_menu_input(MENU *menu, int c)
239 menu_driver(menu, REQ_LEFT_ITEM);
242 menu_driver(menu, REQ_RIGHT_ITEM);
246 item = current_item(menu);
247 return (int)(uintptr_t)item_userptr(item);
253 int dialog_modal_loop(struct dialog *dia)
258 keypad(dia->window, true);
262 while (selection == -1) {
263 c = wgetch(dia->window);
264 selection = handle_menu_input(dia->choices, c);
274 static void handle_form_input(FORM *frm, int c)
278 form_driver(frm, REQ_NEW_LINE);
281 form_driver(frm, REQ_UP_CHAR);
284 form_driver(frm, REQ_DOWN_CHAR);
288 form_driver(frm, REQ_DEL_PREV);
291 form_driver(frm, REQ_LEFT_CHAR);
294 form_driver(frm, REQ_RIGHT_CHAR);
314 FIELD *field[MAX_FIELDS];
315 enum input_section section;
318 static int edit_dialog_free(struct edit_dialog *edit)
321 unpost_form(edit->input);
323 if (edit->field[0]) {
324 free_field(edit->field[0]);
326 if (edit->field[1]) {
327 free_field(edit->field[1]);
329 delwin(edit->input_win);
334 static WERROR fill_value_buffer(struct edit_dialog *edit,
335 const struct value_item *vitem)
339 switch (vitem->type) {
342 if (vitem->data.length >= 4) {
343 v = IVAL(vitem->data.data, 0);
345 tmp = talloc_asprintf(edit, "0x%x", v);
349 set_field_buffer(edit->field[1], 0, tmp);
351 set_field_type(edit->field[1], TYPE_REGEXP,
352 "^ *([0-9]+|0[xX][0-9a-fA-F]+) *$");
356 case REG_EXPAND_SZ: {
359 if (!pull_reg_sz(edit, &vitem->data, &s)) {
362 set_field_buffer(edit->field[1], 0, s);
369 if (!pull_reg_multi_sz(edit, &vitem->data, &a)) {
372 for (p = a; *p != NULL; ++p) {
374 buf = talloc_asprintf(edit, "%s\n", *p);
376 buf = talloc_asprintf_append(buf, "%s\n", *p);
382 set_field_buffer(edit->field[1], 0, buf);
391 static char *string_trim_n(TALLOC_CTX *ctx, const char *buf, size_t n)
395 str = talloc_strndup(ctx, buf, n);
398 trim_string(str, " ", " ");
404 static char *string_trim(TALLOC_CTX *ctx, const char *buf)
408 str = talloc_strdup(ctx, buf);
411 trim_string(str, " ", " ");
417 static WERROR set_value(struct edit_dialog *edit, struct registry_key *key,
422 const char *buf = field_buffer(edit->field[1], 0);
423 char *name = string_trim(edit, field_buffer(edit->field[0], 0));
428 if (!field_status(edit->field[1])) {
437 if (buf[0] == '0' && tolower(buf[1]) == 'x') {
441 val = strtoul(buf, NULL, base);
442 blob = data_blob_talloc(edit, NULL, sizeof(val));
443 SIVAL(blob.data, 0, val);
448 case REG_EXPAND_SZ: {
449 char *str = string_trim(edit, buf);
450 if (!str || !push_reg_sz(edit, &blob, str)) {
460 dynamic_field_info(edit->field[1], &rows, &cols, &max);
462 arr = talloc_zero_array(edit, const char *, rows + 1);
466 for (i = 0; *buf; ++i, buf += cols) {
467 SMB_ASSERT(i < rows);
468 arr[i] = string_trim_n(edit, buf, cols);
470 if (!push_reg_multi_sz(edit, &blob, arr)) {
477 rv = reg_val_set(key, name, type, blob);
482 static void section_down(struct edit_dialog *edit)
484 switch (edit->section) {
486 if (form_driver(edit->input, REQ_VALIDATION) == E_OK) {
487 edit->section = IN_DATA;
488 set_current_field(edit->input, edit->field[1]);
492 if (form_driver(edit->input, REQ_VALIDATION) == E_OK) {
493 edit->section = IN_MENU;
494 menu_driver(edit->dia->choices, REQ_FIRST_ITEM);
498 edit->section = IN_NAME;
499 set_current_field(edit->input, edit->field[0]);
504 static void section_up(struct edit_dialog *edit)
506 switch (edit->section) {
508 if (form_driver(edit->input, REQ_VALIDATION) == E_OK) {
509 edit->section = IN_MENU;
510 menu_driver(edit->dia->choices, REQ_FIRST_ITEM);
514 if (form_driver(edit->input, REQ_VALIDATION) == E_OK) {
515 edit->section = IN_NAME;
516 set_current_field(edit->input, edit->field[0]);
520 edit->section = IN_DATA;
521 set_current_field(edit->input, edit->field[1]);
526 WERROR dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key, uint32_t type,
527 const struct value_item *vitem, WINDOW *below)
529 struct edit_dialog *edit;
530 const char *choices[] = {
536 int nlines, ncols, val_rows;
537 WERROR rv = WERR_NOMEM;
540 edit = talloc_zero(ctx, struct edit_dialog);
544 talloc_set_destructor(edit, edit_dialog_free);
546 title = talloc_asprintf(edit, "Edit %s value", str_regtype(vitem->type));
552 if (vitem->type == REG_MULTI_SZ) {
556 edit->dia = dialog_choice_center_new(edit, title, choices, nlines,
559 if (edit->dia == NULL) {
564 edit->field[0] = new_field(1, ncols - 4, 1, 1, 0, 0);
565 if (edit->field[0] == NULL) {
571 if (vitem->type == REG_MULTI_SZ) {
574 edit->field[1] = new_field(val_rows, ncols - 4, 4, 1, 0, 0);
575 if (edit->field[1] == NULL) {
578 set_field_back(edit->field[0], A_REVERSE);
579 set_field_back(edit->field[1], A_REVERSE);
580 field_opts_off(edit->field[0], O_BLANK | O_AUTOSKIP | O_STATIC);
581 field_opts_off(edit->field[1], O_BLANK | O_AUTOSKIP | O_STATIC | O_WRAP);
584 set_field_buffer(edit->field[0], 0, vitem->value_name);
585 field_opts_off(edit->field[0], O_EDIT);
586 fill_value_buffer(edit, vitem);
589 edit->input = new_form(edit->field);
590 if (edit->input == NULL) {
593 form_opts_off(edit->input, O_NL_OVERLOAD | O_BS_OVERLOAD);
595 edit->input_win = derwin(edit->dia->sub_window, nlines - 3, ncols - 3, 0, 0);
596 if (edit->input_win == NULL) {
600 set_form_win(edit->input, edit->dia->sub_window);
601 set_form_sub(edit->input, edit->input_win);
602 post_form(edit->input);
603 mvwprintw(edit->dia->sub_window, 0, 0, "Name");
604 mvwprintw(edit->dia->sub_window, 3, 0, "Data");
606 keypad(edit->dia->window, true);
610 edit->section = IN_NAME;
613 int c = wgetch(edit->dia->window);
617 } else if (c == KEY_BTAB) {
622 if (edit->section == IN_NAME || edit->section == IN_DATA) {
623 handle_form_input(edit->input, c);
625 selection = handle_menu_input(edit->dia->choices, c);
626 if (selection != -1) {
636 if (selection == DIALOG_OK) {
637 rv = set_value(edit, key, type);
645 int dialog_select_type(TALLOC_CTX *ctx, int *type, WINDOW *below)
648 const char *choices[] = {
653 const char *reg_types[] = {
659 #define NTYPES (sizeof(reg_types) / sizeof(const char*))
666 dia = dialog_choice_center_new(ctx, "New Value", choices, 10, 20,
672 mvwprintw(dia->sub_window, 0, 0, "Choose type:");
673 type_win = derwin(dia->sub_window, 6, 18, 1, 0);
674 if (type_win == NULL) {
678 item = talloc_zero_array(dia, ITEM *, NTYPES + 1);
683 for (i = 0; i < NTYPES; ++i) {
684 int t = regtype_by_string(reg_types[i]);
686 item[i] = new_item(reg_types[i], reg_types[i]);
687 if (item[i] == NULL) {
690 set_item_userptr(item[i], (void*)(uintptr_t)t);
693 list = new_menu(item);
698 set_menu_format(list, 7, 1);
699 set_menu_win(list, dia->sub_window);
700 set_menu_sub(list, type_win);
701 menu_opts_off(list, O_SHOWDESC);
702 set_menu_mark(list, "* ");
705 keypad(dia->window, true);
711 int c = wgetch(dia->window);
715 menu_driver(list, REQ_UP_ITEM);
718 menu_driver(list, REQ_DOWN_ITEM);
721 menu_driver(dia->choices, REQ_LEFT_ITEM);
724 menu_driver(dia->choices, REQ_RIGHT_ITEM);
728 it = current_item(list);
729 *type = (int)(uintptr_t)item_userptr(it);
730 it = current_item(dia->choices);
731 sel = (int)(uintptr_t)item_userptr(it);
743 for (it = item; *it; ++it) {