regedit: handle DEL key in text fields
[Samba.git] / source3 / utils / regedit_dialog.c
blobb807c4eda691cc0ad31b54560f64389f2e9f8081
1 /*
2 * Samba Unix/Linux SMB client library
3 * Registry Editor
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/>.
20 #include "includes.h"
21 #include "regedit.h"
22 #include "regedit_dialog.h"
23 #include "regedit_valuelist.h"
24 #include "regedit_hexedit.h"
25 #include "util_reg.h"
26 #include "lib/registry/registry.h"
27 #include <stdarg.h>
28 #include <form.h>
30 static char *string_trim_n(TALLOC_CTX *ctx, const char *buf, size_t n)
32 char *str;
34 str = talloc_strndup(ctx, buf, n);
36 if (str) {
37 trim_string(str, " ", " ");
40 return str;
43 static char *string_trim(TALLOC_CTX *ctx, const char *buf)
45 char *str;
47 str = talloc_strdup(ctx, buf);
49 if (str) {
50 trim_string(str, " ", " ");
53 return str;
56 static int dialog_free(struct dialog *dia)
58 dialog_destroy(dia);
60 return 0;
63 static bool default_validator(struct dialog *dia, struct dialog_section *sect,
64 void *arg)
66 return true;
69 struct dialog *dialog_new(TALLOC_CTX *ctx, short color, const char *title,
70 int y, int x)
72 struct dialog *dia;
74 dia = talloc_zero(ctx, struct dialog);
75 if (dia == NULL) {
76 return NULL;
79 talloc_set_destructor(dia, dialog_free);
81 dia->title = talloc_strdup(dia, title);
82 if (dia->title == NULL) {
83 goto fail;
85 dia->x = x;
86 dia->y = y;
87 dia->color = color;
88 dia->submit = default_validator;
90 return dia;
92 fail:
93 talloc_free(dia);
95 return NULL;
99 void dialog_set_submit_cb(struct dialog *dia, dialog_submit_cb cb, void *arg)
101 dia->submit = cb;
102 dia->submit_arg = arg;
105 static void center_above_window(int *nlines, int *ncols, int *y, int *x)
107 int centery, centerx;
109 centery = LINES / 2;
110 centerx = COLS / 2;
111 *y = 0;
112 *x = 0;
114 if (*nlines > LINES) {
115 *nlines = LINES;
117 if (*ncols > COLS) {
118 *ncols = COLS;
121 if (*nlines/2 < centery) {
122 *y = centery - *nlines / 2;
124 if (*ncols/2 < centerx) {
125 *x = centerx - *ncols / 2;
129 void dialog_section_destroy(struct dialog_section *section)
131 if (section->ops->destroy) {
132 section->ops->destroy(section);
134 if (section->window) {
135 delwin(section->window);
136 section->window = NULL;
140 void dialog_section_init(struct dialog_section *section,
141 const struct dialog_section_ops *ops,
142 int nlines, int ncols)
144 section->ops = ops;
145 section->nlines = nlines;
146 section->ncols = ncols;
149 const char *dialog_section_get_name(struct dialog_section *section)
151 return section->name;
154 void dialog_section_set_name(struct dialog_section *section, const char *name)
156 TALLOC_FREE(section->name);
157 section->name = talloc_strdup(section, name);
160 void dialog_section_set_justify(struct dialog_section *section,
161 enum section_justify justify)
163 section->justify = justify;
166 /* append a section to the dialog's circular list */
167 void dialog_append_section(struct dialog *dia,
168 struct dialog_section *section)
170 SMB_ASSERT(section != NULL);
172 if (!dia->head_section) {
173 dia->head_section = section;
175 if (dia->tail_section) {
176 dia->tail_section->next = section;
178 section->prev = dia->tail_section;
179 section->next = dia->head_section;
180 dia->head_section->prev = section;
181 dia->tail_section = section;
184 struct dialog_section *dialog_find_section(struct dialog *dia, const char *name)
186 struct dialog_section *section = dia->head_section;
188 do {
189 if (section->name && strequal(section->name, name)) {
190 return section;
192 section = section->next;
193 } while (section != dia->head_section);
195 return NULL;
198 static void section_on_input(struct dialog *dia, int c)
200 struct dialog_section *section = dia->current_section;
202 if (!section->ops->on_input) {
203 return;
205 section->ops->on_input(dia, section, c);
208 static bool section_on_tab(struct dialog *dia)
210 struct dialog_section *section = dia->current_section;
212 if (!section || !section->ops->on_tab) {
213 return false;
215 return section->ops->on_tab(dia, section);
218 static bool section_on_btab(struct dialog *dia)
220 struct dialog_section *section = dia->current_section;
222 if (!section || !section->ops->on_btab) {
223 return false;
225 return section->ops->on_btab(dia, section);
228 static bool section_on_up(struct dialog *dia)
230 struct dialog_section *section = dia->current_section;
232 if (!section || !section->ops->on_up) {
233 return false;
235 return section->ops->on_up(dia, section);
238 static bool section_on_down(struct dialog *dia)
240 struct dialog_section *section = dia->current_section;
242 if (!section || !section->ops->on_down) {
243 return false;
245 return section->ops->on_down(dia, section);
248 static bool section_on_left(struct dialog *dia)
250 struct dialog_section *section = dia->current_section;
252 if (!section || !section->ops->on_left) {
253 return false;
255 return section->ops->on_left(dia, section);
258 static bool section_on_right(struct dialog *dia)
260 struct dialog_section *section = dia->current_section;
262 if (!section || !section->ops->on_right) {
263 return false;
265 return section->ops->on_right(dia, section);
268 static enum dialog_action section_on_enter(struct dialog *dia)
270 struct dialog_section *section = dia->current_section;
272 if (!section || !section->ops->on_enter) {
273 return DIALOG_OK;
275 return section->ops->on_enter(dia, section);
278 static bool section_on_focus(struct dialog *dia, bool forward)
280 struct dialog_section *section = dia->current_section;
282 if (!section->ops->on_focus) {
283 return false;
285 return section->ops->on_focus(dia, section, forward);
288 static void section_on_leave_focus(struct dialog *dia)
290 struct dialog_section *section = dia->current_section;
292 if (section->ops->on_leave_focus) {
293 section->ops->on_leave_focus(dia, section);
297 static void section_set_next_focus(struct dialog *dia)
299 section_on_leave_focus(dia);
301 do {
302 dia->current_section = dia->current_section->next;
303 } while (!section_on_focus(dia, true));
306 static void section_set_previous_focus(struct dialog *dia)
308 section_on_leave_focus(dia);
310 do {
311 dia->current_section = dia->current_section->prev;
312 } while (!section_on_focus(dia, false));
315 WERROR dialog_create(struct dialog *dia)
317 WERROR rv = WERR_OK;
318 int row, col;
319 int nlines, ncols;
320 struct dialog_section *section;
322 nlines = 0;
323 ncols = 0;
324 SMB_ASSERT(dia->head_section != NULL);
326 /* calculate total size based on sections */
327 section = dia->head_section;
328 do {
329 nlines += section->nlines;
330 ncols = MAX(ncols, section->ncols);
331 section = section->next;
332 } while (section != dia->head_section);
334 /* fill in widths for sections that expand */
335 section = dia->head_section;
336 do {
337 if (section->ncols < 0) {
338 section->ncols = ncols;
340 section = section->next;
341 } while (section != dia->head_section);
343 /* create window for dialog */
344 nlines += 4;
345 ncols += 6;
346 dia->pad = newpad(nlines, ncols);
347 if (dia->pad == NULL) {
348 rv = WERR_NOMEM;
349 goto fail;
351 dia->centered = false;
352 if (dia->y < 0 || dia->x < 0) {
353 dia->centered = true;
354 center_above_window(&nlines, &ncols, &dia->y, &dia->x);
356 dia->window = newwin(nlines, ncols, dia->y, dia->x);
357 if (dia->window == NULL) {
358 rv = WERR_NOMEM;
359 goto fail;
361 dia->panel = new_panel(dia->window);
362 if (dia->panel == NULL) {
363 rv = WERR_NOMEM;
364 goto fail;
367 /* setup color and border */
368 getmaxyx(dia->pad, nlines, ncols);
369 wbkgdset(dia->pad, ' ' | COLOR_PAIR(dia->color));
370 wclear(dia->pad);
371 mvwhline(dia->pad, 1, 2, 0, ncols - 4);
372 mvwhline(dia->pad, nlines - 2, 2, 0, ncols - 4);
373 mvwvline(dia->pad, 2, 1, 0, nlines - 4);
374 mvwvline(dia->pad, 2, ncols - 2, 0, nlines - 4);
375 mvwaddch(dia->pad, 1, 1, ACS_ULCORNER);
376 mvwaddch(dia->pad, 1, ncols - 2, ACS_URCORNER);
377 mvwaddch(dia->pad, nlines - 2, 1, ACS_LLCORNER);
378 mvwaddch(dia->pad, nlines - 2, ncols - 2, ACS_LRCORNER);
379 col = ncols / 2 - MIN(strlen(dia->title) + 2, ncols) / 2;
380 mvwprintw(dia->pad, 1, col, " %s ", dia->title);
382 /* create subwindows for each section */
383 row = 2;
384 section = dia->head_section;
385 do {
386 col = 3;
388 switch (section->justify) {
389 case SECTION_JUSTIFY_LEFT:
390 break;
391 case SECTION_JUSTIFY_CENTER:
392 col += (ncols - 6)/ 2 - section->ncols / 2;
393 break;
394 case SECTION_JUSTIFY_RIGHT:
395 break;
398 section->window = subpad(dia->pad, section->nlines,
399 section->ncols, row, col);
400 if (section->window == NULL) {
401 rv = WERR_NOMEM;
402 goto fail;
404 SMB_ASSERT(section->ops->create != NULL);
405 rv = section->ops->create(dia, section);
406 row += section->nlines;
407 section = section->next;
408 } while (section != dia->head_section && W_ERROR_IS_OK(rv));
410 dia->current_section = dia->head_section;
411 section_set_next_focus(dia);
413 fail:
414 return rv;
417 void dialog_show(struct dialog *dia)
419 int nlines, ncols;
420 int pad_y, pad_x;
421 int y, x;
422 int rv;
424 touchwin(dia->pad);
425 getmaxyx(dia->window, nlines, ncols);
426 getmaxyx(dia->pad, pad_y, pad_x);
427 y = 0;
428 if (pad_y > nlines) {
429 y = (pad_y - nlines) / 2;
431 x = 0;
432 if (pad_x > ncols) {
433 x = (pad_x - ncols) / 2;
435 rv = copywin(dia->pad, dia->window, y, x, 0, 0,
436 nlines - 1, ncols - 1, false);
437 SMB_ASSERT(rv == OK);
439 getyx(dia->pad, pad_y, pad_x);
440 wmove(dia->window, pad_y - y, pad_x - x);
441 touchwin(dia->window);
442 wnoutrefresh(dia->window);
445 void dialog_destroy(struct dialog *dia)
447 struct dialog_section *section;
449 section = dia->head_section;
450 do {
451 dialog_section_destroy(section);
452 section = section->next;
453 } while (section != dia->head_section);
455 if (dia->panel) {
456 del_panel(dia->panel);
457 dia->panel = NULL;
459 if (dia->window) {
460 delwin(dia->window);
461 dia->window = NULL;
465 static int dialog_getch(struct dialog *dia)
467 int c;
469 c = regedit_getch();
470 if (c == KEY_RESIZE) {
471 int nlines, ncols, y, x;
472 int pad_nlines, pad_ncols;
473 int win_nlines, win_ncols;
475 getmaxyx(dia->window, win_nlines, win_ncols);
476 getmaxyx(dia->pad, pad_nlines, pad_ncols);
477 getbegyx(dia->window, y, x);
479 nlines = pad_nlines;
480 ncols = pad_ncols;
482 if (dia->centered) {
483 center_above_window(&nlines, &ncols, &y, &x);
484 } else {
485 if (nlines + y > LINES) {
486 if (nlines > LINES) {
487 y = 0;
488 } else {
489 y = LINES - nlines;
492 if (ncols + x > COLS) {
493 if (ncols > COLS) {
494 x = 0;
495 } else {
496 x = COLS - ncols;
500 if (nlines != win_nlines || ncols != win_ncols) {
501 wresize(dia->window, nlines, ncols);
502 replace_panel(dia->panel, dia->window);
504 move_panel(dia->panel, y, x);
507 return c;
510 bool dialog_handle_input(struct dialog *dia, WERROR *err,
511 enum dialog_action *action)
513 int c;
515 *err = WERR_OK;
517 c = dialog_getch(dia);
519 switch (c) {
520 case '\t':
521 if (!section_on_tab(dia)) {
522 section_set_next_focus(dia);
524 break;
525 case KEY_BTAB:
526 if (!section_on_btab(dia)) {
527 section_set_previous_focus(dia);
529 break;
530 case KEY_UP:
531 if (!section_on_up(dia)) {
532 section_set_previous_focus(dia);
534 break;
535 case KEY_DOWN:
536 if (!section_on_down(dia)) {
537 section_set_next_focus(dia);
539 break;
540 case KEY_LEFT:
541 if (!section_on_left(dia)) {
542 section_set_previous_focus(dia);
544 break;
545 case KEY_RIGHT:
546 if (!section_on_right(dia)) {
547 section_set_next_focus(dia);
549 break;
550 case '\n':
551 case KEY_ENTER:
552 *action = section_on_enter(dia);
553 switch (*action) {
554 case DIALOG_IGNORE:
555 break;
556 case DIALOG_CANCEL:
557 return false;
558 case DIALOG_OK:
559 return !dia->submit(dia, dia->current_section,
560 dia->submit_arg);
562 break;
563 case 27: /* ESC */
564 return false;
565 default:
566 section_on_input(dia, c);
567 break;
570 return true;
573 void dialog_modal_loop(struct dialog *dia, WERROR *err,
574 enum dialog_action *action)
576 do {
577 dialog_show(dia);
578 update_panels();
579 doupdate();
580 } while (dialog_handle_input(dia, err, action));
583 /* text label */
584 struct dialog_section_label {
585 struct dialog_section section;
586 char **text;
589 static WERROR label_create(struct dialog *dia, struct dialog_section *section)
591 int row;
592 struct dialog_section_label *label =
593 talloc_get_type_abort(section, struct dialog_section_label);
595 for (row = 0; row < section->nlines; ++row) {
596 mvwaddstr(section->window, row, 0, label->text[row]);
599 return WERR_OK;
602 struct dialog_section_ops label_ops = {
603 .create = label_create,
606 static int label_free(struct dialog_section_label *label)
608 dialog_section_destroy(&label->section);
609 return 0;
612 struct dialog_section *dialog_section_label_new_va(TALLOC_CTX *ctx,
613 const char *msg, va_list ap)
615 struct dialog_section_label *label;
616 char *tmp, *ptmp, *line, *saveptr;
617 int nlines, ncols;
619 label = talloc_zero(ctx, struct dialog_section_label);
620 if (label == NULL) {
621 return NULL;
623 talloc_set_destructor(label, label_free);
624 tmp = talloc_vasprintf(label, msg, ap);
625 if (tmp == NULL) {
626 goto fail;
629 for (nlines = 0, ncols = 0, ptmp = tmp;
630 (line = strtok_r(ptmp, "\n", &saveptr)) != NULL;
631 ++nlines) {
632 ptmp = NULL;
633 label->text = talloc_realloc(label, label->text,
634 char *, nlines + 1);
635 if (label->text == NULL) {
636 goto fail;
638 ncols = MAX(ncols, strlen(line));
639 label->text[nlines] = talloc_strdup(label->text, line);
640 if (label->text[nlines] == NULL) {
641 goto fail;
644 talloc_free(tmp);
645 dialog_section_init(&label->section, &label_ops, nlines, ncols);
647 return &label->section;
649 fail:
650 talloc_free(label);
651 return NULL;
654 struct dialog_section *dialog_section_label_new(TALLOC_CTX *ctx,
655 const char *msg, ...)
657 va_list ap;
658 struct dialog_section *rv;
660 va_start(ap, msg);
661 rv = dialog_section_label_new_va(ctx, msg, ap);
662 va_end(ap);
664 return rv;
667 /* horizontal separator */
668 struct dialog_section_hsep {
669 struct dialog_section section;
670 int sep;
673 static WERROR hsep_create(struct dialog *dia, struct dialog_section *section)
675 int y, x;
676 struct dialog_section_hsep *hsep =
677 talloc_get_type_abort(section, struct dialog_section_hsep);
679 whline(section->window, hsep->sep, section->ncols);
681 if (hsep->sep == 0 || hsep->sep == ACS_HLINE) {
682 /* change the border characters around this section to
683 tee chars */
684 getparyx(section->window, y, x);
685 mvwaddch(dia->pad, y, x - 1, ACS_HLINE);
686 mvwaddch(dia->pad, y, x - 2, ACS_LTEE);
687 mvwaddch(dia->pad, y, x + section->ncols, ACS_HLINE);
688 mvwaddch(dia->pad, y, x + section->ncols + 1, ACS_RTEE);
691 return WERR_OK;
694 struct dialog_section_ops hsep_ops = {
695 .create = hsep_create
698 static int hsep_free(struct dialog_section_hsep *hsep)
700 dialog_section_destroy(&hsep->section);
701 return 0;
704 struct dialog_section *dialog_section_hsep_new(TALLOC_CTX *ctx, int sep)
706 struct dialog_section_hsep *hsep;
708 hsep = talloc_zero(ctx, struct dialog_section_hsep);
709 if (hsep) {
710 talloc_set_destructor(hsep, hsep_free);
711 dialog_section_init(&hsep->section, &hsep_ops, 1, -1);
712 hsep->sep = sep;
715 return &hsep->section;
718 /* text input field */
719 struct dialog_section_text_field {
720 struct dialog_section section;
721 unsigned opts;
722 FIELD *field[2];
723 FORM *form;
726 static WERROR text_field_create(struct dialog *dia,
727 struct dialog_section *section)
729 struct dialog_section_text_field *text_field =
730 talloc_get_type_abort(section, struct dialog_section_text_field);
732 text_field->field[0] = new_field(section->nlines, section->ncols,
733 0, 0, 0, 0);
734 if (text_field->field[0] == NULL) {
735 return WERR_NOMEM;
737 set_field_back(text_field->field[0], A_REVERSE);
738 set_field_opts(text_field->field[0], text_field->opts);
740 text_field->form = new_form(text_field->field);
741 if (text_field->form == NULL) {
742 return WERR_NOMEM;
745 set_form_win(text_field->form, dia->window);
746 set_form_sub(text_field->form, section->window);
747 set_current_field(text_field->form, text_field->field[0]);
748 post_form(text_field->form);
750 return WERR_OK;
753 static void text_field_destroy(struct dialog_section *section)
755 struct dialog_section_text_field *text_field =
756 talloc_get_type_abort(section, struct dialog_section_text_field);
758 if (text_field->form) {
759 unpost_form(text_field->form);
760 free_form(text_field->form);
761 text_field->form = NULL;
763 if (text_field->field[0]) {
764 free_field(text_field->field[0]);
765 text_field->field[0] = NULL;
769 static void text_field_on_input(struct dialog *dia,
770 struct dialog_section *section,
771 int c)
773 struct dialog_section_text_field *text_field =
774 talloc_get_type_abort(section, struct dialog_section_text_field);
776 switch (c) {
777 case KEY_BACKSPACE:
778 form_driver(text_field->form, REQ_DEL_PREV);
779 break;
780 case KEY_DC:
781 form_driver(text_field->form, REQ_DEL_CHAR);
782 break;
783 default:
784 form_driver(text_field->form, c);
785 break;
789 static bool text_field_on_up(struct dialog *dia,
790 struct dialog_section *section)
792 struct dialog_section_text_field *text_field =
793 talloc_get_type_abort(section, struct dialog_section_text_field);
795 if (section->nlines > 1) {
796 form_driver(text_field->form, REQ_UP_CHAR);
797 return true;
799 return false;
802 static bool text_field_on_down(struct dialog *dia,
803 struct dialog_section *section)
805 struct dialog_section_text_field *text_field =
806 talloc_get_type_abort(section, struct dialog_section_text_field);
808 if (section->nlines > 1) {
809 form_driver(text_field->form, REQ_DOWN_CHAR);
810 return true;
812 return false;
815 static bool text_field_on_left(struct dialog *dia,
816 struct dialog_section *section)
818 struct dialog_section_text_field *text_field =
819 talloc_get_type_abort(section, struct dialog_section_text_field);
821 form_driver(text_field->form, REQ_LEFT_CHAR);
823 return true;
826 static bool text_field_on_right(struct dialog *dia,
827 struct dialog_section *section)
829 struct dialog_section_text_field *text_field =
830 talloc_get_type_abort(section, struct dialog_section_text_field);
832 form_driver(text_field->form, REQ_RIGHT_CHAR);
834 return true;
837 static enum dialog_action text_field_on_enter(struct dialog *dia,
838 struct dialog_section *section)
840 struct dialog_section_text_field *text_field =
841 talloc_get_type_abort(section, struct dialog_section_text_field);
843 if (section->nlines > 1) {
844 form_driver(text_field->form, REQ_NEW_LINE);
845 return DIALOG_IGNORE;
848 return DIALOG_OK;
851 static bool text_field_on_focus(struct dialog *dia,
852 struct dialog_section *section, bool forward)
854 struct dialog_section_text_field *text_field =
855 talloc_get_type_abort(section, struct dialog_section_text_field);
857 pos_form_cursor(text_field->form);
859 return true;
862 struct dialog_section_ops text_field_ops = {
863 .create = text_field_create,
864 .destroy = text_field_destroy,
865 .on_input = text_field_on_input,
866 .on_up = text_field_on_up,
867 .on_down = text_field_on_down,
868 .on_left = text_field_on_left,
869 .on_right = text_field_on_right,
870 .on_enter = text_field_on_enter,
871 .on_focus = text_field_on_focus
874 static int text_field_free(struct dialog_section_text_field *text_field)
876 dialog_section_destroy(&text_field->section);
877 return 0;
880 struct dialog_section *dialog_section_text_field_new(TALLOC_CTX *ctx,
881 int height, int width)
883 struct dialog_section_text_field *text_field;
885 text_field = talloc_zero(ctx, struct dialog_section_text_field);
886 if (text_field == NULL) {
887 return NULL;
889 talloc_set_destructor(text_field, text_field_free);
890 dialog_section_init(&text_field->section, &text_field_ops,
891 height, width);
892 text_field->opts = O_ACTIVE | O_PUBLIC | O_EDIT | O_VISIBLE | O_NULLOK;
894 return &text_field->section;
897 const char *dialog_section_text_field_get(TALLOC_CTX *ctx,
898 struct dialog_section *section)
900 struct dialog_section_text_field *text_field =
901 talloc_get_type_abort(section, struct dialog_section_text_field);
903 form_driver(text_field->form, REQ_VALIDATION);
905 return string_trim(ctx, field_buffer(text_field->field[0], 0));
908 void dialog_section_text_field_set(struct dialog_section *section,
909 const char *s)
911 struct dialog_section_text_field *text_field =
912 talloc_get_type_abort(section, struct dialog_section_text_field);
914 set_field_buffer(text_field->field[0], 0, s);
917 const char **dialog_section_text_field_get_lines(TALLOC_CTX *ctx,
918 struct dialog_section *section)
920 int rows, cols, max;
921 const char **arr;
922 size_t i;
923 const char *buf;
924 struct dialog_section_text_field *text_field =
925 talloc_get_type_abort(section, struct dialog_section_text_field);
927 form_driver(text_field->form, REQ_VALIDATION);
928 buf = field_buffer(text_field->field[0], 0);
930 dynamic_field_info(text_field->field[0], &rows, &cols, &max);
932 arr = talloc_zero_array(ctx, const char *, rows + 1);
933 if (arr == NULL) {
934 return NULL;
936 for (i = 0; *buf; ++i, buf += cols) {
937 SMB_ASSERT(i < rows);
938 arr[i] = string_trim_n(arr, buf, cols);
941 return arr;
944 WERROR dialog_section_text_field_set_lines(TALLOC_CTX *ctx,
945 struct dialog_section *section,
946 const char **array)
948 int rows, cols, max;
949 size_t padding, length, index;
950 const char **arrayp;
951 char *buf = NULL;
952 struct dialog_section_text_field *text_field =
953 talloc_get_type_abort(section, struct dialog_section_text_field);
955 dynamic_field_info(text_field->field[0], &rows, &cols, &max);
956 /* try to fit each string on it's own line. each line
957 needs to be padded with whitespace manually, since
958 ncurses fields do not have newlines. */
959 for (index = 0, arrayp = array; *arrayp != NULL; ++arrayp) {
960 length = MIN(strlen(*arrayp), cols);
961 padding = cols - length;
962 buf = talloc_realloc(ctx, buf, char,
963 talloc_array_length(buf) +
964 length + padding + 1);
965 if (buf == NULL) {
966 return WERR_NOMEM;
968 memcpy(&buf[index], *arrayp, length);
969 index += length;
970 memset(&buf[index], ' ', padding);
971 index += padding;
972 buf[index] = '\0';
975 set_field_buffer(text_field->field[0], 0, buf);
976 talloc_free(buf);
978 return WERR_OK;
981 bool dialog_section_text_field_get_int(struct dialog_section *section,
982 long long *out)
984 bool rv;
985 const char *buf;
986 char *endp;
987 struct dialog_section_text_field *text_field =
988 talloc_get_type_abort(section, struct dialog_section_text_field);
990 form_driver(text_field->form, REQ_VALIDATION);
992 buf = string_trim(section, field_buffer(text_field->field[0], 0));
993 if (buf == NULL) {
994 return false;
996 *out = strtoll(buf, &endp, 0);
997 rv = true;
998 if (endp == buf || endp == NULL || endp[0] != '\0') {
999 rv = false;
1002 return rv;
1006 bool dialog_section_text_field_get_uint(struct dialog_section *section,
1007 unsigned long long *out)
1009 bool rv;
1010 const char *buf;
1011 char *endp;
1012 struct dialog_section_text_field *text_field =
1013 talloc_get_type_abort(section, struct dialog_section_text_field);
1015 form_driver(text_field->form, REQ_VALIDATION);
1017 buf = string_trim(section, field_buffer(text_field->field[0], 0));
1018 if (buf == NULL) {
1019 return false;
1021 *out = strtoull(buf, &endp, 0);
1022 rv = true;
1023 if (endp == buf || endp == NULL || endp[0] != '\0') {
1024 rv = false;
1027 return rv;
1030 /* hex editor field */
1031 struct dialog_section_hexedit {
1032 struct dialog_section section;
1033 struct hexedit *buf;
1036 #define HEXEDIT_MIN_SIZE 16
1037 static WERROR hexedit_create(struct dialog *dia,
1038 struct dialog_section *section)
1040 struct dialog_section_hexedit *hexedit =
1041 talloc_get_type_abort(section, struct dialog_section_hexedit);
1043 hexedit->buf = hexedit_new(dia, section->window, NULL,
1044 HEXEDIT_MIN_SIZE);
1045 if (hexedit->buf == NULL) {
1046 return WERR_NOMEM;
1049 hexedit_refresh(hexedit->buf);
1051 return WERR_OK;
1054 static void hexedit_destroy(struct dialog_section *section)
1056 struct dialog_section_hexedit *hexedit =
1057 talloc_get_type_abort(section, struct dialog_section_hexedit);
1059 if (hexedit->buf) {
1060 TALLOC_FREE(hexedit->buf);
1064 static void hexedit_on_input(struct dialog *dia,
1065 struct dialog_section *section,
1066 int c)
1068 struct dialog_section_hexedit *hexedit =
1069 talloc_get_type_abort(section, struct dialog_section_hexedit);
1071 switch (c) {
1072 case KEY_BACKSPACE:
1073 // FIXME hexedit_driver(hexedit->buf, c);
1074 break;
1075 default:
1076 hexedit_driver(hexedit->buf, c);
1077 break;
1081 static bool hexedit_on_up(struct dialog *dia,
1082 struct dialog_section *section)
1084 struct dialog_section_hexedit *hexedit =
1085 talloc_get_type_abort(section, struct dialog_section_hexedit);
1087 hexedit_driver(hexedit->buf, HE_CURSOR_UP);
1089 return true;
1092 static bool hexedit_on_down(struct dialog *dia,
1093 struct dialog_section *section)
1095 struct dialog_section_hexedit *hexedit =
1096 talloc_get_type_abort(section, struct dialog_section_hexedit);
1098 hexedit_driver(hexedit->buf, HE_CURSOR_DOWN);
1100 return true;
1103 static bool hexedit_on_left(struct dialog *dia,
1104 struct dialog_section *section)
1106 struct dialog_section_hexedit *hexedit =
1107 talloc_get_type_abort(section, struct dialog_section_hexedit);
1109 hexedit_driver(hexedit->buf, HE_CURSOR_LEFT);
1111 return true;
1114 static bool hexedit_on_right(struct dialog *dia,
1115 struct dialog_section *section)
1117 struct dialog_section_hexedit *hexedit =
1118 talloc_get_type_abort(section, struct dialog_section_hexedit);
1120 hexedit_driver(hexedit->buf, HE_CURSOR_RIGHT);
1122 return true;
1125 static enum dialog_action hexedit_on_enter(struct dialog *dia,
1126 struct dialog_section *section)
1128 return DIALOG_IGNORE;
1131 static bool hexedit_on_focus(struct dialog *dia,
1132 struct dialog_section *section, bool forward)
1134 struct dialog_section_hexedit *hexedit =
1135 talloc_get_type_abort(section, struct dialog_section_hexedit);
1137 hexedit_set_cursor(hexedit->buf);
1139 return true;
1142 struct dialog_section_ops hexedit_ops = {
1143 .create = hexedit_create,
1144 .destroy = hexedit_destroy,
1145 .on_input = hexedit_on_input,
1146 .on_up = hexedit_on_up,
1147 .on_down = hexedit_on_down,
1148 .on_left = hexedit_on_left,
1149 .on_right = hexedit_on_right,
1150 .on_enter = hexedit_on_enter,
1151 .on_focus = hexedit_on_focus
1154 static int hexedit_free(struct dialog_section_hexedit *hexedit)
1156 dialog_section_destroy(&hexedit->section);
1157 return 0;
1160 struct dialog_section *dialog_section_hexedit_new(TALLOC_CTX *ctx, int height)
1162 struct dialog_section_hexedit *hexedit;
1164 hexedit = talloc_zero(ctx, struct dialog_section_hexedit);
1165 if (hexedit == NULL) {
1166 return NULL;
1168 talloc_set_destructor(hexedit, hexedit_free);
1169 dialog_section_init(&hexedit->section, &hexedit_ops,
1170 height, LINE_WIDTH);
1172 return &hexedit->section;
1175 WERROR dialog_section_hexedit_set_buf(struct dialog_section *section,
1176 const void *data, size_t size)
1178 WERROR rv;
1179 struct dialog_section_hexedit *hexedit =
1180 talloc_get_type_abort(section, struct dialog_section_hexedit);
1182 SMB_ASSERT(hexedit->buf != NULL);
1184 rv = hexedit_set_buf(hexedit->buf, data, size);
1185 if (W_ERROR_IS_OK(rv)) {
1186 hexedit_refresh(hexedit->buf);
1187 hexedit_set_cursor(hexedit->buf);
1190 return rv;
1193 void dialog_section_hexedit_get_buf(struct dialog_section *section,
1194 const void **data, size_t *size)
1196 struct dialog_section_hexedit *hexedit =
1197 talloc_get_type_abort(section, struct dialog_section_hexedit);
1199 SMB_ASSERT(hexedit->buf != NULL);
1200 *data = hexedit_get_buf(hexedit->buf);
1201 *size = hexedit_get_buf_len(hexedit->buf);
1204 /* button box */
1205 struct dialog_section_buttons {
1206 struct dialog_section section;
1207 struct button_spec *spec;
1208 int current_button;
1211 static void buttons_unhighlight(struct dialog_section_buttons *buttons)
1213 short pair;
1214 attr_t attr;
1217 * Some GCC versions will complain if the macro version of
1218 * wattr_get is used. So we should enforce the use of the
1219 * function instead. See:
1220 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1222 (wattr_get)(buttons->section.window, &attr, &pair, NULL);
1223 mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL);
1224 wnoutrefresh(buttons->section.window);
1227 static void buttons_highlight(struct dialog_section_buttons *buttons)
1229 struct button_spec *spec = &buttons->spec[buttons->current_button];
1230 short pair;
1231 attr_t attr;
1234 * Some GCC versions will complain if the macro version of
1235 * wattr_get is used. So we should enforce the use of the
1236 * function instead. See:
1237 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1239 (wattr_get)(buttons->section.window, &attr, &pair, NULL);
1240 mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL);
1241 mvwchgat(buttons->section.window, 0, spec->col,
1242 strlen(spec->label), A_REVERSE, pair, NULL);
1243 wmove(buttons->section.window, 0, spec->col + 2);
1244 wcursyncup(buttons->section.window);
1245 wnoutrefresh(buttons->section.window);
1248 static bool buttons_highlight_next(struct dialog_section_buttons *buttons)
1250 if (buttons->current_button < talloc_array_length(buttons->spec) - 1) {
1251 buttons->current_button++;
1252 buttons_highlight(buttons);
1253 return true;
1255 return false;
1258 static bool buttons_highlight_previous(struct dialog_section_buttons *buttons)
1260 if (buttons->current_button > 0) {
1261 buttons->current_button--;
1262 buttons_highlight(buttons);
1263 return true;
1265 return false;
1268 static WERROR buttons_create(struct dialog *dia,
1269 struct dialog_section *section)
1271 size_t i, nbuttons;
1272 struct dialog_section_buttons *buttons =
1273 talloc_get_type_abort(section, struct dialog_section_buttons);
1275 nbuttons = talloc_array_length(buttons->spec);
1276 for (i = 0; i < nbuttons; ++i) {
1277 struct button_spec *spec = &buttons->spec[i];
1278 mvwaddstr(section->window, 0, spec->col, spec->label);
1281 buttons->current_button = 0;
1283 return WERR_OK;
1286 static bool buttons_on_btab(struct dialog *dia, struct dialog_section *section)
1288 struct dialog_section_buttons *buttons =
1289 talloc_get_type_abort(section, struct dialog_section_buttons);
1291 return buttons_highlight_previous(buttons);
1294 static bool buttons_on_tab(struct dialog *dia, struct dialog_section *section)
1296 struct dialog_section_buttons *buttons =
1297 talloc_get_type_abort(section, struct dialog_section_buttons);
1299 return buttons_highlight_next(buttons);
1302 static enum dialog_action buttons_on_enter(struct dialog *dia,
1303 struct dialog_section *section)
1305 struct dialog_section_buttons *buttons =
1306 talloc_get_type_abort(section, struct dialog_section_buttons);
1307 struct button_spec *spec = &buttons->spec[buttons->current_button];
1309 if (spec->on_enter) {
1310 return spec->on_enter(dia, section);
1313 return spec->action;
1316 static bool buttons_on_focus(struct dialog *dia,
1317 struct dialog_section *section,
1318 bool forward)
1320 struct dialog_section_buttons *buttons =
1321 talloc_get_type_abort(section, struct dialog_section_buttons);
1323 if (forward) {
1324 buttons->current_button = 0;
1325 } else {
1326 buttons->current_button = talloc_array_length(buttons->spec) - 1;
1328 buttons_highlight(buttons);
1330 return true;
1333 static void buttons_on_leave_focus(struct dialog *dia,
1334 struct dialog_section *section)
1336 struct dialog_section_buttons *buttons =
1337 talloc_get_type_abort(section, struct dialog_section_buttons);
1338 buttons_unhighlight(buttons);
1341 struct dialog_section_ops buttons_ops = {
1342 .create = buttons_create,
1343 .on_tab = buttons_on_tab,
1344 .on_btab = buttons_on_btab,
1345 .on_up = buttons_on_btab,
1346 .on_down = buttons_on_tab,
1347 .on_left = buttons_on_btab,
1348 .on_right = buttons_on_tab,
1349 .on_enter = buttons_on_enter,
1350 .on_focus = buttons_on_focus,
1351 .on_leave_focus = buttons_on_leave_focus
1354 static int buttons_free(struct dialog_section_buttons *buttons)
1356 dialog_section_destroy(&buttons->section);
1357 return 0;
1360 struct dialog_section *dialog_section_buttons_new(TALLOC_CTX *ctx,
1361 const struct button_spec *spec)
1363 struct dialog_section_buttons *buttons;
1364 size_t i, nbuttons;
1365 int width;
1367 buttons = talloc_zero(ctx, struct dialog_section_buttons);
1368 if (buttons == NULL) {
1369 return NULL;
1371 talloc_set_destructor(buttons, buttons_free);
1373 for (nbuttons = 0; spec[nbuttons].label; ++nbuttons) {
1375 buttons->spec = talloc_zero_array(buttons, struct button_spec, nbuttons);
1376 if (buttons->spec == NULL) {
1377 goto fail;
1380 for (width = 0, i = 0; i < nbuttons; ++i) {
1381 buttons->spec[i] = spec[i];
1382 buttons->spec[i].label = talloc_asprintf(buttons->spec,
1383 "[ %s ]",
1384 spec[i].label);
1385 if (!buttons->spec[i].label) {
1386 goto fail;
1389 buttons->spec[i].col = width;
1390 width += strlen(buttons->spec[i].label);
1391 if (i != nbuttons - 1) {
1392 ++width;
1396 dialog_section_init(&buttons->section, &buttons_ops, 1, width);
1398 return &buttons->section;
1400 fail:
1401 talloc_free(buttons);
1402 return NULL;
1405 /* options */
1406 struct dialog_section_options {
1407 struct dialog_section section;
1408 struct option_spec *spec;
1409 int current_option;
1410 bool single_select;
1413 static void options_unhighlight(struct dialog_section_options *options)
1415 short pair;
1416 attr_t attr;
1417 size_t row;
1420 * Some GCC versions will complain if the macro version of
1421 * wattr_get is used. So we should enforce the use of the
1422 * function instead. See:
1423 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1425 (wattr_get)(options->section.window, &attr, &pair, NULL);
1426 for (row = 0; row < options->section.nlines; ++row) {
1427 mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL);
1429 wnoutrefresh(options->section.window);
1432 static void options_highlight(struct dialog_section_options *options)
1434 struct option_spec *spec = &options->spec[options->current_option];
1435 short pair;
1436 attr_t attr;
1437 size_t row;
1440 * Some GCC versions will complain if the macro version of
1441 * wattr_get is used. So we should enforce the use of the
1442 * function instead. See:
1443 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1445 (wattr_get)(options->section.window, &attr, &pair, NULL);
1446 for (row = 0; row < options->section.nlines; ++row) {
1447 mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL);
1449 mvwchgat(options->section.window, spec->row, spec->col,
1450 strlen(spec->label), A_REVERSE, pair, NULL);
1451 wmove(options->section.window, spec->row, spec->col + 4);
1452 wcursyncup(options->section.window);
1453 wnoutrefresh(options->section.window);
1456 static void options_render_state(struct dialog_section_options *options)
1458 size_t i, noptions;
1460 noptions = talloc_array_length(options->spec);
1461 for (i = 0; i < noptions; ++i) {
1462 struct option_spec *spec = &options->spec[i];
1463 char c = ' ';
1464 if (*spec->state)
1465 c = 'x';
1466 mvwaddch(options->section.window,
1467 spec->row, spec->col + 1, c);
1468 wnoutrefresh(options->section.window);
1472 static bool options_highlight_next(struct dialog_section_options *options)
1474 if (options->current_option < talloc_array_length(options->spec) - 1) {
1475 options->current_option++;
1476 options_highlight(options);
1477 return true;
1479 return false;
1482 static bool options_highlight_previous(struct dialog_section_options *options)
1484 if (options->current_option > 0) {
1485 options->current_option--;
1486 options_highlight(options);
1487 return true;
1489 return false;
1492 static WERROR options_create(struct dialog *dia,
1493 struct dialog_section *section)
1495 size_t i, noptions;
1496 struct dialog_section_options *options =
1497 talloc_get_type_abort(section, struct dialog_section_options);
1499 noptions = talloc_array_length(options->spec);
1500 for (i = 0; i < noptions; ++i) {
1501 struct option_spec *spec = &options->spec[i];
1502 mvwaddstr(section->window, spec->row, spec->col,
1503 spec->label);
1506 options->current_option = 0;
1507 options_render_state(options);
1509 return WERR_OK;
1512 static bool options_on_btab(struct dialog *dia, struct dialog_section *section)
1514 struct dialog_section_options *options =
1515 talloc_get_type_abort(section, struct dialog_section_options);
1517 return options_highlight_previous(options);
1520 static bool options_on_tab(struct dialog *dia, struct dialog_section *section)
1522 struct dialog_section_options *options =
1523 talloc_get_type_abort(section, struct dialog_section_options);
1525 return options_highlight_next(options);
1528 static void options_on_input(struct dialog *dia, struct dialog_section *section, int c)
1530 struct dialog_section_options *options =
1531 talloc_get_type_abort(section, struct dialog_section_options);
1533 if (c == ' ') {
1534 struct option_spec *spec = &options->spec[options->current_option];
1535 if (options->single_select) {
1536 size_t i, noptions;
1537 noptions = talloc_array_length(options->spec);
1538 for (i = 0; i < noptions; ++i) {
1539 *(options->spec[i].state) = false;
1542 *spec->state = !*spec->state;
1543 options_unhighlight(options);
1544 options_render_state(options);
1545 options_highlight(options);
1549 static enum dialog_action options_on_enter(struct dialog *dia, struct dialog_section *section)
1551 options_on_input(dia, section, ' ');
1552 return DIALOG_OK;
1555 static bool options_on_focus(struct dialog *dia,
1556 struct dialog_section *section,
1557 bool forward)
1559 struct dialog_section_options *options =
1560 talloc_get_type_abort(section, struct dialog_section_options);
1562 if (forward) {
1563 options->current_option = 0;
1564 } else {
1565 options->current_option = talloc_array_length(options->spec) - 1;
1567 options_highlight(options);
1569 return true;
1572 static void options_on_leave_focus(struct dialog *dia,
1573 struct dialog_section *section)
1575 struct dialog_section_options *options =
1576 talloc_get_type_abort(section, struct dialog_section_options);
1577 options_unhighlight(options);
1580 struct dialog_section_ops options_ops = {
1581 .create = options_create,
1582 .on_tab = options_on_tab,
1583 .on_btab = options_on_btab,
1584 .on_up = options_on_btab,
1585 .on_down = options_on_tab,
1586 .on_left = options_on_btab,
1587 .on_right = options_on_tab,
1588 .on_input = options_on_input,
1589 .on_enter = options_on_enter,
1590 .on_focus = options_on_focus,
1591 .on_leave_focus = options_on_leave_focus
1594 static int options_free(struct dialog_section_options *options)
1596 dialog_section_destroy(&options->section);
1597 return 0;
1600 struct dialog_section *dialog_section_options_new(TALLOC_CTX *ctx,
1601 const struct option_spec *spec,
1602 int maxcol, bool single_select)
1604 struct dialog_section_options *options;
1605 size_t i, noptions;
1606 int width, maxwidth, maxrows;
1608 options = talloc_zero(ctx, struct dialog_section_options);
1609 if (options == NULL) {
1610 return NULL;
1612 talloc_set_destructor(options, options_free);
1614 for (noptions = 0; spec[noptions].label; ++noptions) {
1616 options->spec = talloc_zero_array(options, struct option_spec, noptions);
1617 if (options->spec == NULL) {
1618 goto fail;
1621 maxrows = noptions / maxcol;
1622 if (noptions % maxcol) {
1623 ++maxrows;
1626 for (width = 0, maxwidth = 0, i = 0; i < noptions; ++i) {
1627 options->spec[i] = spec[i];
1628 options->spec[i].label = talloc_asprintf(options->spec,
1629 "[ ] %s",
1630 spec[i].label);
1631 if (!options->spec[i].label) {
1632 goto fail;
1635 options->spec[i].col = maxwidth;
1636 options->spec[i].row = i % maxrows;
1637 width = MAX(strlen(options->spec[i].label), width);
1638 if (options->spec[i].row == maxrows - 1 || i == noptions - 1) {
1639 maxwidth += width + 1;
1640 width = 0;
1644 dialog_section_init(&options->section, &options_ops, maxrows, maxwidth - 1);
1645 options->single_select = single_select;
1647 return &options->section;
1649 fail:
1650 talloc_free(options);
1651 return NULL;
1655 int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title,
1656 const char *msg, ...)
1658 va_list ap;
1659 WERROR err;
1660 enum dialog_action action;
1661 struct dialog *dia;
1662 struct dialog_section *section;
1663 struct button_spec spec[] = {
1664 {.label = "OK", .action = DIALOG_OK},
1665 {.label = "Cancel", .action = DIALOG_CANCEL},
1666 { 0 }
1669 dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1);
1670 va_start(ap, msg);
1671 section = dialog_section_label_new_va(dia, msg, ap);
1672 va_end(ap);
1673 dialog_append_section(dia, section);
1674 section = dialog_section_hsep_new(dia, ' ');
1675 dialog_append_section(dia, section);
1676 section = dialog_section_text_field_new(dia, 1, -1);
1677 dialog_section_set_name(section, "input");
1678 dialog_append_section(dia, section);
1679 section = dialog_section_hsep_new(dia, 0);
1680 dialog_append_section(dia, section);
1681 section = dialog_section_buttons_new(dia, spec);
1682 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
1683 dialog_append_section(dia, section);
1685 dialog_create(dia);
1686 dialog_show(dia);
1687 dialog_modal_loop(dia, &err, &action);
1689 *output = NULL;
1690 if (action == DIALOG_OK) {
1691 section = dialog_find_section(dia, "input");
1692 *output = dialog_section_text_field_get(ctx, section);
1695 talloc_free(dia);
1697 return action;
1700 int dialog_notice(TALLOC_CTX *ctx, enum dialog_type type,
1701 const char *title, const char *msg, ...)
1703 va_list ap;
1704 WERROR err;
1705 enum dialog_action action;
1706 struct dialog *dia;
1707 struct dialog_section *section;
1708 struct button_spec spec[3];
1710 memset(&spec, '\0', sizeof(spec));
1711 spec[0].label = "OK";
1712 spec[0].action = DIALOG_OK;
1713 if (type == DIA_CONFIRM) {
1714 spec[1].label = "Cancel";
1715 spec[1].action = DIALOG_CANCEL;
1718 dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1);
1719 va_start(ap, msg);
1720 section = dialog_section_label_new_va(dia, msg, ap);
1721 va_end(ap);
1722 dialog_append_section(dia, section);
1723 section = dialog_section_hsep_new(dia, 0);
1724 dialog_append_section(dia, section);
1725 section = dialog_section_buttons_new(dia, spec);
1726 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
1727 dialog_append_section(dia, section);
1729 dialog_create(dia);
1730 dialog_show(dia);
1731 dialog_modal_loop(dia, &err, &action);
1732 talloc_free(dia);
1734 return action;
1738 struct edit_req {
1739 uint32_t type;
1740 uint32_t mode;
1741 struct registry_key *key;
1742 const struct value_item *vitem;
1745 static WERROR fill_value_buffer(struct dialog *dia, struct edit_req *edit)
1747 char *tmp;
1748 struct dialog_section *data;
1750 if (edit->vitem == NULL) {
1751 return WERR_OK;
1754 data = dialog_find_section(dia, "data");
1755 SMB_ASSERT(data != NULL);
1757 switch (edit->mode) {
1758 case REG_DWORD: {
1759 uint32_t v = 0;
1760 if (edit->vitem->data.length >= 4) {
1761 v = IVAL(edit->vitem->data.data, 0);
1763 tmp = talloc_asprintf(dia, "%u", (unsigned)v);
1764 if (tmp == NULL) {
1765 return WERR_NOMEM;
1767 dialog_section_text_field_set(data, tmp);
1768 talloc_free(tmp);
1769 break;
1771 case REG_SZ:
1772 case REG_EXPAND_SZ: {
1773 const char *s;
1775 if (!pull_reg_sz(dia, &edit->vitem->data, &s)) {
1776 return WERR_NOMEM;
1778 dialog_section_text_field_set(data, s);
1779 break;
1781 case REG_MULTI_SZ: {
1782 const char **array;
1784 if (!pull_reg_multi_sz(dia, &edit->vitem->data, &array)) {
1785 return WERR_NOMEM;
1787 return dialog_section_text_field_set_lines(dia, data, array);
1789 case REG_BINARY:
1790 default:
1791 return dialog_section_hexedit_set_buf(data,
1792 edit->vitem->data.data,
1793 edit->vitem->data.length);
1796 return WERR_OK;
1799 static bool value_exists(TALLOC_CTX *ctx, const struct registry_key *key,
1800 const char *name)
1802 uint32_t type;
1803 DATA_BLOB blob;
1804 WERROR rv;
1806 rv = reg_key_get_value_by_name(ctx, key, name, &type, &blob);
1808 return W_ERROR_IS_OK(rv);
1811 static bool edit_on_submit(struct dialog *dia, struct dialog_section *section,
1812 void *arg)
1814 struct edit_req *edit = arg;
1815 WERROR rv;
1816 DATA_BLOB blob;
1817 const char *name;
1818 struct dialog_section *name_section, *data;
1820 name_section = dialog_find_section(dia, "name");
1821 if (name_section) {
1822 name = dialog_section_text_field_get(dia, name_section);
1823 if (*name == '\0') {
1824 dialog_notice(dia, DIA_ALERT, "Error",
1825 "Value name must not be blank.");
1826 return false;
1828 if (value_exists(dia, edit->key, name)) {
1829 dialog_notice(dia, DIA_ALERT, "Error",
1830 "Value named \"%s\" already exists.",
1831 name);
1832 return false;
1834 } else {
1835 SMB_ASSERT(edit->vitem);
1836 name = edit->vitem->value_name;
1838 SMB_ASSERT(name);
1840 data = dialog_find_section(dia, "data");
1841 SMB_ASSERT(data != NULL);
1843 rv = WERR_OK;
1844 switch (edit->mode) {
1845 case REG_DWORD: {
1846 unsigned long long v;
1847 uint32_t val;
1849 if (!dialog_section_text_field_get_uint(data, &v)) {
1850 dialog_notice(dia, DIA_ALERT, "Error",
1851 "REG_DWORD value must be an integer.");
1852 return false;
1854 if (v > UINT32_MAX) {
1855 dialog_notice(dia, DIA_ALERT, "Error",
1856 "REG_DWORD value must less than %lu.",
1857 (unsigned long)UINT32_MAX);
1858 return false;
1860 val = (uint32_t)v;
1861 blob = data_blob_talloc(dia, NULL, sizeof(val));
1862 SIVAL(blob.data, 0, val);
1863 break;
1865 case REG_SZ:
1866 case REG_EXPAND_SZ: {
1867 const char *buf;
1869 buf = dialog_section_text_field_get(dia, data);
1870 if (!buf || !push_reg_sz(dia, &blob, buf)) {
1871 rv = WERR_NOMEM;
1873 break;
1875 case REG_MULTI_SZ: {
1876 const char **lines;
1878 lines = dialog_section_text_field_get_lines(dia, data);
1879 if (!lines || !push_reg_multi_sz(dia, &blob, lines)) {
1880 rv = WERR_NOMEM;
1882 break;
1884 case REG_BINARY: {
1885 const void *buf;
1886 size_t len;
1888 dialog_section_hexedit_get_buf(data, &buf, &len);
1889 blob = data_blob_talloc(dia, buf, len);
1890 break;
1894 if (W_ERROR_IS_OK(rv)) {
1895 rv = reg_val_set(edit->key, name, edit->type, blob);
1898 if (!W_ERROR_IS_OK(rv)) {
1899 const char *msg = get_friendly_werror_msg(rv);
1900 dialog_notice(dia, DIA_ALERT, "Error",
1901 "Error saving value:\n%s", msg);
1903 return false;
1906 return true;
1910 int dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key,
1911 uint32_t type, const struct value_item *vitem,
1912 bool force_binary, WERROR *err,
1913 const char **name)
1915 enum dialog_action action;
1916 struct dialog *dia;
1917 struct dialog_section *section;
1918 struct edit_req edit;
1919 struct button_spec spec[] = {
1920 {.label = "OK", .action = DIALOG_OK},
1921 {.label = "Cancel", .action = DIALOG_CANCEL},
1922 { 0 }
1925 edit.key = key;
1926 edit.vitem = vitem;
1927 edit.type = type;
1928 edit.mode = type;
1929 if (force_binary || (vitem && vitem->unprintable)) {
1930 edit.mode = REG_BINARY;
1933 dia = dialog_new(ctx, PAIR_BLACK_CYAN, "Edit Value", -1, -1);
1934 dialog_set_submit_cb(dia, edit_on_submit, &edit);
1936 section = dialog_section_label_new(dia, "Type");
1937 dialog_append_section(dia, section);
1938 section = dialog_section_label_new(dia, "%s",
1939 str_regtype(type));
1940 dialog_append_section(dia, section);
1941 section = dialog_section_hsep_new(dia, ' ');
1942 dialog_append_section(dia, section);
1944 section = dialog_section_label_new(dia, "Name");
1945 dialog_append_section(dia, section);
1946 if (vitem) {
1947 section = dialog_section_label_new(dia, "%s",
1948 vitem->value_name);
1949 } else {
1950 section = dialog_section_text_field_new(dia, 1, 50);
1951 dialog_section_set_name(section, "name");
1953 dialog_append_section(dia, section);
1954 section = dialog_section_hsep_new(dia, ' ');
1955 dialog_append_section(dia, section);
1957 section = dialog_section_label_new(dia, "Data");
1958 dialog_append_section(dia, section);
1960 switch (edit.mode) {
1961 case REG_DWORD:
1962 case REG_SZ:
1963 case REG_EXPAND_SZ:
1964 section = dialog_section_text_field_new(dia, 1, 50);
1965 break;
1966 case REG_MULTI_SZ:
1967 section = dialog_section_text_field_new(dia, 10, 50);
1968 break;
1969 case REG_BINARY:
1970 default:
1971 section = dialog_section_hexedit_new(dia, 10);
1972 break;
1975 dialog_section_set_name(section, "data");
1976 dialog_append_section(dia, section);
1978 section = dialog_section_hsep_new(dia, 0);
1979 dialog_append_section(dia, section);
1980 section = dialog_section_buttons_new(dia, spec);
1981 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
1982 dialog_append_section(dia, section);
1984 dialog_create(dia);
1986 *err = fill_value_buffer(dia, &edit);
1987 if (!W_ERROR_IS_OK(*err)) {
1988 return DIALOG_CANCEL;
1991 dialog_show(dia);
1992 dialog_modal_loop(dia, err, &action);
1994 if (action == DIALOG_OK && name) {
1995 if (vitem) {
1996 *name = talloc_strdup(ctx, vitem->value_name);
1997 } else if ((section = dialog_find_section(dia, "name"))) {
1998 *name = dialog_section_text_field_get(ctx, section);
2002 talloc_free(dia);
2004 return action;
2007 int dialog_select_type(TALLOC_CTX *ctx, int *type)
2009 WERROR err;
2010 enum dialog_action action;
2011 struct dialog *dia;
2012 struct dialog_section *section;
2013 const char *reg_types[] = {
2014 "REG_BINARY",
2015 "REG_DWORD",
2016 "REG_EXPAND_SZ",
2017 "REG_MULTI_SZ",
2018 "REG_SZ"
2020 #define NTYPES ARRAY_SIZE(reg_types)
2021 struct button_spec spec[] = {
2022 {.label = "OK", .action = DIALOG_OK},
2023 {.label = "Cancel", .action = DIALOG_CANCEL},
2024 { 0 }
2026 bool flags[NTYPES] = { true };
2027 struct option_spec opsec[NTYPES + 1];
2028 unsigned i;
2030 memset(&opsec, '\0', sizeof(opsec));
2031 for (i = 0; i < NTYPES; ++i) {
2032 opsec[i].label = reg_types[i];
2033 opsec[i].state = &flags[i];
2036 dia = dialog_new(ctx, PAIR_BLACK_CYAN, "New Value", -1, -1);
2038 section = dialog_section_label_new(dia, "Select type for new value:");
2039 dialog_append_section(dia, section);
2040 section = dialog_section_hsep_new(dia, ' ');
2041 dialog_append_section(dia, section);
2042 section = dialog_section_options_new(dia, opsec, 2, true);
2043 dialog_append_section(dia, section);
2044 section = dialog_section_hsep_new(dia, 0);
2045 dialog_append_section(dia, section);
2046 section = dialog_section_buttons_new(dia, spec);
2047 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2048 dialog_append_section(dia, section);
2050 dialog_create(dia);
2051 dialog_show(dia);
2053 dialog_modal_loop(dia, &err, &action);
2054 if (action == DIALOG_OK) {
2055 for (i = 0; i < NTYPES; ++i) {
2056 if (flags[i]) {
2057 *type = regtype_by_string(reg_types[i]);
2058 break;
2063 talloc_free(dia);
2065 return action;
2068 struct search_req {
2069 TALLOC_CTX *ctx;
2070 struct regedit_search_opts *opts;
2073 static bool search_on_submit(struct dialog *dia, struct dialog_section *section,
2074 void *arg)
2076 struct search_req *search = arg;
2077 struct dialog_section *query;
2079 query = dialog_find_section(dia, "query");
2080 SMB_ASSERT(query != NULL);
2082 if (!search->opts->search_key && !search->opts->search_value) {
2083 dialog_notice(dia, DIA_ALERT, "Error",
2084 "Must search a key and/or a value");
2085 return false;
2088 talloc_free(discard_const(search->opts->query));
2089 search->opts->query = dialog_section_text_field_get(search->ctx, query);
2090 SMB_ASSERT(search->opts->query != NULL);
2091 if (search->opts->query[0] == '\0') {
2092 dialog_notice(dia, DIA_ALERT, "Error",
2093 "Query must not be blank.");
2094 return false;
2097 return true;
2100 int dialog_search_input(TALLOC_CTX *ctx, struct regedit_search_opts *opts)
2102 WERROR err;
2103 enum dialog_action action;
2104 struct dialog *dia;
2105 struct dialog_section *section, *query;
2106 struct search_req search;
2107 struct button_spec spec[] = {
2108 {.label = "Search", .action = DIALOG_OK},
2109 {.label = "Cancel", .action = DIALOG_CANCEL},
2110 { 0 }
2112 struct option_spec search_opts[] = {
2113 {.label = "Search Keys", .state = &opts->search_key},
2114 {.label = "Search Values", .state = &opts->search_value},
2115 {.label = "Recursive", .state = &opts->search_recursive},
2116 {.label = "Case Sensitive", .state = &opts->search_case},
2117 { 0 }
2120 if (!opts->search_key && !opts->search_value) {
2121 opts->search_key = true;
2124 search.ctx = ctx;
2125 search.opts = opts;
2126 dia = dialog_new(ctx, PAIR_BLACK_CYAN, "Search", -1, -1);
2127 dialog_set_submit_cb(dia, search_on_submit, &search);
2128 section = dialog_section_label_new(dia, "Query");
2129 dialog_append_section(dia, section);
2130 query = dialog_section_text_field_new(dia, 1, -1);
2131 dialog_section_set_name(query, "query");
2132 dialog_append_section(dia, query);
2133 section = dialog_section_hsep_new(dia, 0);
2134 dialog_append_section(dia, section);
2135 section = dialog_section_options_new(dia, search_opts, 2, false);
2136 dialog_append_section(dia, section);
2137 section = dialog_section_hsep_new(dia, 0);
2138 dialog_append_section(dia, section);
2139 section = dialog_section_buttons_new(dia, spec);
2140 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2141 dialog_append_section(dia, section);
2143 dialog_create(dia);
2144 if (opts->query) {
2145 dialog_section_text_field_set(query, opts->query);
2148 dialog_modal_loop(dia, &err, &action);
2149 talloc_free(dia);
2151 return action;