tests: Create symlinks using posix extensions
[Samba.git] / source3 / utils / regedit_dialog.c
blobd1cb45fd8f28d6796ebd856963512fc3bf7a7240
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 "lib/util/smb_strtox.h"
28 #include <stdarg.h>
29 #include <form.h>
31 static char *string_trim_n(TALLOC_CTX *ctx, const char *buf, size_t n)
33 char *str;
35 str = talloc_strndup(ctx, buf, n);
37 if (str) {
38 trim_string(str, " ", " ");
41 return str;
44 static char *string_trim(TALLOC_CTX *ctx, const char *buf)
46 char *str;
48 str = talloc_strdup(ctx, buf);
50 if (str) {
51 trim_string(str, " ", " ");
54 return str;
57 static int dialog_free(struct dialog *dia)
59 dialog_destroy(dia);
61 return 0;
64 static bool default_validator(struct dialog *dia, struct dialog_section *sect,
65 void *arg)
67 return true;
70 struct dialog *dialog_new(TALLOC_CTX *ctx, short color, const char *title,
71 int y, int x)
73 struct dialog *dia;
75 dia = talloc_zero(ctx, struct dialog);
76 if (dia == NULL) {
77 return NULL;
80 talloc_set_destructor(dia, dialog_free);
82 dia->title = talloc_strdup(dia, title);
83 if (dia->title == NULL) {
84 goto fail;
86 dia->x = x;
87 dia->y = y;
88 dia->color = color;
89 dia->submit = default_validator;
91 return dia;
93 fail:
94 talloc_free(dia);
96 return NULL;
100 void dialog_set_submit_cb(struct dialog *dia, dialog_submit_cb cb, void *arg)
102 dia->submit = cb;
103 dia->submit_arg = arg;
106 static void center_above_window(int *nlines, int *ncols, int *y, int *x)
108 int centery, centerx;
110 centery = LINES / 2;
111 centerx = COLS / 2;
112 *y = 0;
113 *x = 0;
115 if (*nlines > LINES) {
116 *nlines = LINES;
118 if (*ncols > COLS) {
119 *ncols = COLS;
122 if (*nlines/2 < centery) {
123 *y = centery - *nlines / 2;
125 if (*ncols/2 < centerx) {
126 *x = centerx - *ncols / 2;
130 void dialog_section_destroy(struct dialog_section *section)
132 if (section->ops->destroy) {
133 section->ops->destroy(section);
135 if (section->window) {
136 delwin(section->window);
137 section->window = NULL;
141 void dialog_section_init(struct dialog_section *section,
142 const struct dialog_section_ops *ops,
143 int nlines, int ncols)
145 section->ops = ops;
146 section->nlines = nlines;
147 section->ncols = ncols;
150 const char *dialog_section_get_name(struct dialog_section *section)
152 return section->name;
155 void dialog_section_set_name(struct dialog_section *section, const char *name)
157 TALLOC_FREE(section->name);
158 section->name = talloc_strdup(section, name);
161 void dialog_section_set_justify(struct dialog_section *section,
162 enum section_justify justify)
164 section->justify = justify;
167 /* append a section to the dialog's circular list */
168 void dialog_append_section(struct dialog *dia,
169 struct dialog_section *section)
171 SMB_ASSERT(section != NULL);
173 if (!dia->head_section) {
174 dia->head_section = section;
176 if (dia->tail_section) {
177 dia->tail_section->next = section;
179 section->prev = dia->tail_section;
180 section->next = dia->head_section;
181 dia->head_section->prev = section;
182 dia->tail_section = section;
185 struct dialog_section *dialog_find_section(struct dialog *dia, const char *name)
187 struct dialog_section *section = dia->head_section;
189 do {
190 if (section->name && strequal(section->name, name)) {
191 return section;
193 section = section->next;
194 } while (section != dia->head_section);
196 return NULL;
199 static void section_on_input(struct dialog *dia, int c)
201 struct dialog_section *section = dia->current_section;
203 if (!section->ops->on_input) {
204 return;
206 section->ops->on_input(dia, section, c);
209 static bool section_on_tab(struct dialog *dia)
211 struct dialog_section *section = dia->current_section;
213 if (!section || !section->ops->on_tab) {
214 return false;
216 return section->ops->on_tab(dia, section);
219 static bool section_on_btab(struct dialog *dia)
221 struct dialog_section *section = dia->current_section;
223 if (!section || !section->ops->on_btab) {
224 return false;
226 return section->ops->on_btab(dia, section);
229 static bool section_on_up(struct dialog *dia)
231 struct dialog_section *section = dia->current_section;
233 if (!section || !section->ops->on_up) {
234 return false;
236 return section->ops->on_up(dia, section);
239 static bool section_on_down(struct dialog *dia)
241 struct dialog_section *section = dia->current_section;
243 if (!section || !section->ops->on_down) {
244 return false;
246 return section->ops->on_down(dia, section);
249 static bool section_on_left(struct dialog *dia)
251 struct dialog_section *section = dia->current_section;
253 if (!section || !section->ops->on_left) {
254 return false;
256 return section->ops->on_left(dia, section);
259 static bool section_on_right(struct dialog *dia)
261 struct dialog_section *section = dia->current_section;
263 if (!section || !section->ops->on_right) {
264 return false;
266 return section->ops->on_right(dia, section);
269 static enum dialog_action section_on_enter(struct dialog *dia)
271 struct dialog_section *section = dia->current_section;
273 if (!section || !section->ops->on_enter) {
274 return DIALOG_OK;
276 return section->ops->on_enter(dia, section);
279 static bool section_on_focus(struct dialog *dia, bool forward)
281 struct dialog_section *section = dia->current_section;
283 if (!section->ops->on_focus) {
284 return false;
286 return section->ops->on_focus(dia, section, forward);
289 static void section_on_leave_focus(struct dialog *dia)
291 struct dialog_section *section = dia->current_section;
293 if (section->ops->on_leave_focus) {
294 section->ops->on_leave_focus(dia, section);
298 static void section_set_next_focus(struct dialog *dia)
300 section_on_leave_focus(dia);
302 do {
303 dia->current_section = dia->current_section->next;
304 } while (!section_on_focus(dia, true));
307 static void section_set_previous_focus(struct dialog *dia)
309 section_on_leave_focus(dia);
311 do {
312 dia->current_section = dia->current_section->prev;
313 } while (!section_on_focus(dia, false));
316 WERROR dialog_create(struct dialog *dia)
318 WERROR rv = WERR_OK;
319 int row, col;
320 int nlines, ncols;
321 struct dialog_section *section;
323 nlines = 0;
324 ncols = 0;
325 SMB_ASSERT(dia->head_section != NULL);
327 /* calculate total size based on sections */
328 section = dia->head_section;
329 do {
330 nlines += section->nlines;
331 ncols = MAX(ncols, section->ncols);
332 section = section->next;
333 } while (section != dia->head_section);
335 /* fill in widths for sections that expand */
336 section = dia->head_section;
337 do {
338 if (section->ncols < 0) {
339 section->ncols = ncols;
341 section = section->next;
342 } while (section != dia->head_section);
344 /* create window for dialog */
345 nlines += 4;
346 ncols += 6;
347 dia->pad = newpad(nlines, ncols);
348 if (dia->pad == NULL) {
349 rv = WERR_NOT_ENOUGH_MEMORY;
350 goto fail;
352 dia->centered = false;
353 if (dia->y < 0 || dia->x < 0) {
354 dia->centered = true;
355 center_above_window(&nlines, &ncols, &dia->y, &dia->x);
357 dia->window = newwin(nlines, ncols, dia->y, dia->x);
358 if (dia->window == NULL) {
359 rv = WERR_NOT_ENOUGH_MEMORY;
360 goto fail;
362 dia->panel = new_panel(dia->window);
363 if (dia->panel == NULL) {
364 rv = WERR_NOT_ENOUGH_MEMORY;
365 goto fail;
368 /* setup color and border */
369 getmaxyx(dia->pad, nlines, ncols);
370 wbkgdset(dia->pad, ' ' | COLOR_PAIR(dia->color));
371 wclear(dia->pad);
372 mvwhline(dia->pad, 1, 2, 0, ncols - 4);
373 mvwhline(dia->pad, nlines - 2, 2, 0, ncols - 4);
374 mvwvline(dia->pad, 2, 1, 0, nlines - 4);
375 mvwvline(dia->pad, 2, ncols - 2, 0, nlines - 4);
376 mvwaddch(dia->pad, 1, 1, ACS_ULCORNER);
377 mvwaddch(dia->pad, 1, ncols - 2, ACS_URCORNER);
378 mvwaddch(dia->pad, nlines - 2, 1, ACS_LLCORNER);
379 mvwaddch(dia->pad, nlines - 2, ncols - 2, ACS_LRCORNER);
380 col = ncols / 2 - MIN(strlen(dia->title) + 2, ncols) / 2;
381 mvwprintw(dia->pad, 1, col, " %s ", dia->title);
383 /* create subwindows for each section */
384 row = 2;
385 section = dia->head_section;
386 do {
387 col = 3;
389 switch (section->justify) {
390 case SECTION_JUSTIFY_LEFT:
391 break;
392 case SECTION_JUSTIFY_CENTER:
393 col += (ncols - 6)/ 2 - section->ncols / 2;
394 break;
395 case SECTION_JUSTIFY_RIGHT:
396 break;
399 section->window = subpad(dia->pad, section->nlines,
400 section->ncols, row, col);
401 if (section->window == NULL) {
402 rv = WERR_NOT_ENOUGH_MEMORY;
403 goto fail;
405 SMB_ASSERT(section->ops->create != NULL);
406 rv = section->ops->create(dia, section);
407 row += section->nlines;
408 section = section->next;
409 } while (section != dia->head_section && W_ERROR_IS_OK(rv));
411 dia->current_section = dia->head_section;
412 section_set_next_focus(dia);
414 fail:
415 return rv;
418 void dialog_show(struct dialog *dia)
420 int nlines, ncols;
421 int pad_y, pad_x;
422 int y, x;
423 int rv;
425 touchwin(dia->pad);
426 getmaxyx(dia->window, nlines, ncols);
427 getmaxyx(dia->pad, pad_y, pad_x);
428 y = 0;
429 if (pad_y > nlines) {
430 y = (pad_y - nlines) / 2;
432 x = 0;
433 if (pad_x > ncols) {
434 x = (pad_x - ncols) / 2;
436 rv = copywin(dia->pad, dia->window, y, x, 0, 0,
437 nlines - 1, ncols - 1, false);
438 SMB_ASSERT(rv == OK);
440 getyx(dia->pad, pad_y, pad_x);
441 wmove(dia->window, pad_y - y, pad_x - x);
442 touchwin(dia->window);
443 wnoutrefresh(dia->window);
446 void dialog_destroy(struct dialog *dia)
448 struct dialog_section *section;
450 section = dia->head_section;
451 do {
452 dialog_section_destroy(section);
453 section = section->next;
454 } while (section != dia->head_section);
456 if (dia->panel) {
457 del_panel(dia->panel);
458 dia->panel = NULL;
460 if (dia->window) {
461 delwin(dia->window);
462 dia->window = NULL;
466 static int dialog_getch(struct dialog *dia)
468 int c;
470 c = regedit_getch();
471 if (c == KEY_RESIZE) {
472 int nlines, ncols, y, x;
473 int pad_nlines, pad_ncols;
474 int win_nlines, win_ncols;
476 getmaxyx(dia->window, win_nlines, win_ncols);
477 getmaxyx(dia->pad, pad_nlines, pad_ncols);
478 getbegyx(dia->window, y, x);
480 nlines = pad_nlines;
481 ncols = pad_ncols;
483 if (dia->centered) {
484 center_above_window(&nlines, &ncols, &y, &x);
485 } else {
486 if (nlines + y > LINES) {
487 if (nlines > LINES) {
488 y = 0;
489 } else {
490 y = LINES - nlines;
493 if (ncols + x > COLS) {
494 if (ncols > COLS) {
495 x = 0;
496 } else {
497 x = COLS - ncols;
501 if (nlines != win_nlines || ncols != win_ncols) {
502 wresize(dia->window, nlines, ncols);
503 replace_panel(dia->panel, dia->window);
505 move_panel(dia->panel, y, x);
508 return c;
511 bool dialog_handle_input(struct dialog *dia, WERROR *err,
512 enum dialog_action *action)
514 int c;
516 *err = WERR_OK;
518 c = dialog_getch(dia);
520 switch (c) {
521 case '\t':
522 if (!section_on_tab(dia)) {
523 section_set_next_focus(dia);
525 break;
526 case KEY_BTAB:
527 if (!section_on_btab(dia)) {
528 section_set_previous_focus(dia);
530 break;
531 case KEY_UP:
532 if (!section_on_up(dia)) {
533 section_set_previous_focus(dia);
535 break;
536 case KEY_DOWN:
537 if (!section_on_down(dia)) {
538 section_set_next_focus(dia);
540 break;
541 case KEY_LEFT:
542 if (!section_on_left(dia)) {
543 section_set_previous_focus(dia);
545 break;
546 case KEY_RIGHT:
547 if (!section_on_right(dia)) {
548 section_set_next_focus(dia);
550 break;
551 case '\n':
552 case KEY_ENTER:
553 *action = section_on_enter(dia);
554 switch (*action) {
555 case DIALOG_IGNORE:
556 break;
557 case DIALOG_CANCEL:
558 return false;
559 case DIALOG_OK:
560 return !dia->submit(dia, dia->current_section,
561 dia->submit_arg);
563 break;
564 case 27: /* ESC */
565 return false;
566 default:
567 section_on_input(dia, c);
568 break;
571 return true;
574 void dialog_modal_loop(struct dialog *dia, WERROR *err,
575 enum dialog_action *action)
577 do {
578 dialog_show(dia);
579 update_panels();
580 doupdate();
581 } while (dialog_handle_input(dia, err, action));
584 /* text label */
585 struct dialog_section_label {
586 struct dialog_section section;
587 char **text;
590 static WERROR label_create(struct dialog *dia, struct dialog_section *section)
592 int row;
593 struct dialog_section_label *label =
594 talloc_get_type_abort(section, struct dialog_section_label);
596 for (row = 0; row < section->nlines; ++row) {
597 mvwaddstr(section->window, row, 0, label->text[row]);
600 return WERR_OK;
603 struct dialog_section_ops label_ops = {
604 .create = label_create,
607 static int label_free(struct dialog_section_label *label)
609 dialog_section_destroy(&label->section);
610 return 0;
613 struct dialog_section *dialog_section_label_new_va(TALLOC_CTX *ctx,
614 const char *msg, va_list ap)
616 struct dialog_section_label *label;
617 char *tmp, *ptmp, *line, *saveptr;
618 int nlines, ncols;
620 label = talloc_zero(ctx, struct dialog_section_label);
621 if (label == NULL) {
622 return NULL;
624 talloc_set_destructor(label, label_free);
625 tmp = talloc_vasprintf(label, msg, ap);
626 if (tmp == NULL) {
627 goto fail;
630 for (nlines = 0, ncols = 0, ptmp = tmp;
631 (line = strtok_r(ptmp, "\n", &saveptr)) != NULL;
632 ++nlines) {
633 ptmp = NULL;
634 label->text = talloc_realloc(label, label->text,
635 char *, nlines + 1);
636 if (label->text == NULL) {
637 goto fail;
639 ncols = MAX(ncols, strlen(line));
640 label->text[nlines] = talloc_strdup(label->text, line);
641 if (label->text[nlines] == NULL) {
642 goto fail;
645 talloc_free(tmp);
646 dialog_section_init(&label->section, &label_ops, nlines, ncols);
648 return &label->section;
650 fail:
651 talloc_free(label);
652 return NULL;
655 struct dialog_section *dialog_section_label_new(TALLOC_CTX *ctx,
656 const char *msg, ...)
658 va_list ap;
659 struct dialog_section *rv;
661 va_start(ap, msg);
662 rv = dialog_section_label_new_va(ctx, msg, ap);
663 va_end(ap);
665 return rv;
668 /* horizontal separator */
669 struct dialog_section_hsep {
670 struct dialog_section section;
671 int sep;
674 static WERROR hsep_create(struct dialog *dia, struct dialog_section *section)
676 int y, x;
677 struct dialog_section_hsep *hsep =
678 talloc_get_type_abort(section, struct dialog_section_hsep);
680 whline(section->window, hsep->sep, section->ncols);
682 if (hsep->sep == 0 || hsep->sep == ACS_HLINE) {
683 /* change the border characters around this section to
684 tee chars */
685 getparyx(section->window, y, x);
686 mvwaddch(dia->pad, y, x - 1, ACS_HLINE);
687 mvwaddch(dia->pad, y, x - 2, ACS_LTEE);
688 mvwaddch(dia->pad, y, x + section->ncols, ACS_HLINE);
689 mvwaddch(dia->pad, y, x + section->ncols + 1, ACS_RTEE);
692 return WERR_OK;
695 struct dialog_section_ops hsep_ops = {
696 .create = hsep_create
699 static int hsep_free(struct dialog_section_hsep *hsep)
701 dialog_section_destroy(&hsep->section);
702 return 0;
705 struct dialog_section *dialog_section_hsep_new(TALLOC_CTX *ctx, int sep)
707 struct dialog_section_hsep *hsep;
709 hsep = talloc_zero(ctx, struct dialog_section_hsep);
710 if (hsep) {
711 talloc_set_destructor(hsep, hsep_free);
712 dialog_section_init(&hsep->section, &hsep_ops, 1, -1);
713 hsep->sep = sep;
716 return &hsep->section;
719 /* text input field */
720 struct dialog_section_text_field {
721 struct dialog_section section;
722 unsigned opts;
723 FIELD *field[2];
724 FORM *form;
725 int length;
728 static int get_cursor_col(struct dialog_section_text_field *field)
730 int col;
732 col = field->form->curcol + field->form->begincol;
734 return col;
737 static WERROR text_field_create(struct dialog *dia,
738 struct dialog_section *section)
740 struct dialog_section_text_field *text_field =
741 talloc_get_type_abort(section, struct dialog_section_text_field);
743 text_field->field[0] = new_field(section->nlines, section->ncols,
744 0, 0, 0, 0);
745 if (text_field->field[0] == NULL) {
746 return WERR_NOT_ENOUGH_MEMORY;
748 set_field_back(text_field->field[0], A_REVERSE);
749 set_field_opts(text_field->field[0], text_field->opts);
751 text_field->form = new_form(text_field->field);
752 if (text_field->form == NULL) {
753 return WERR_NOT_ENOUGH_MEMORY;
756 set_form_win(text_field->form, dia->window);
757 set_form_sub(text_field->form, section->window);
758 set_current_field(text_field->form, text_field->field[0]);
759 post_form(text_field->form);
761 return WERR_OK;
764 static void text_field_destroy(struct dialog_section *section)
766 struct dialog_section_text_field *text_field =
767 talloc_get_type_abort(section, struct dialog_section_text_field);
769 if (text_field->form) {
770 unpost_form(text_field->form);
771 free_form(text_field->form);
772 text_field->form = NULL;
774 if (text_field->field[0]) {
775 free_field(text_field->field[0]);
776 text_field->field[0] = NULL;
780 static void text_field_on_input(struct dialog *dia,
781 struct dialog_section *section,
782 int c)
784 struct dialog_section_text_field *text_field =
785 talloc_get_type_abort(section, struct dialog_section_text_field);
787 switch (c) {
788 case KEY_BACKSPACE:
789 if (text_field->length) {
790 text_field->length--;
792 form_driver(text_field->form, REQ_DEL_PREV);
793 break;
794 case '\x7f':
795 case KEY_DC:
796 if (text_field->length) {
797 text_field->length--;
799 form_driver(text_field->form, REQ_DEL_CHAR);
800 break;
801 default:
802 text_field->length++;
803 form_driver(text_field->form, c);
804 break;
808 static bool text_field_on_up(struct dialog *dia,
809 struct dialog_section *section)
811 struct dialog_section_text_field *text_field =
812 talloc_get_type_abort(section, struct dialog_section_text_field);
814 if (section->nlines > 1) {
815 form_driver(text_field->form, REQ_UP_CHAR);
816 return true;
818 return false;
821 static bool text_field_on_down(struct dialog *dia,
822 struct dialog_section *section)
824 struct dialog_section_text_field *text_field =
825 talloc_get_type_abort(section, struct dialog_section_text_field);
827 if (section->nlines > 1) {
828 form_driver(text_field->form, REQ_DOWN_CHAR);
829 return true;
831 return false;
834 static bool text_field_on_left(struct dialog *dia,
835 struct dialog_section *section)
837 struct dialog_section_text_field *text_field =
838 talloc_get_type_abort(section, struct dialog_section_text_field);
840 form_driver(text_field->form, REQ_LEFT_CHAR);
842 return true;
845 static bool text_field_on_right(struct dialog *dia,
846 struct dialog_section *section)
848 struct dialog_section_text_field *text_field =
849 talloc_get_type_abort(section, struct dialog_section_text_field);
851 if (section->nlines > 1 ||
852 get_cursor_col(text_field) < text_field->length) {
853 form_driver(text_field->form, REQ_RIGHT_CHAR);
856 return true;
859 static enum dialog_action text_field_on_enter(struct dialog *dia,
860 struct dialog_section *section)
862 struct dialog_section_text_field *text_field =
863 talloc_get_type_abort(section, struct dialog_section_text_field);
865 if (section->nlines > 1) {
866 text_field->length += text_field->form->cols;
867 form_driver(text_field->form, REQ_NEW_LINE);
868 return DIALOG_IGNORE;
871 return DIALOG_OK;
874 static bool text_field_on_focus(struct dialog *dia,
875 struct dialog_section *section, bool forward)
877 struct dialog_section_text_field *text_field =
878 talloc_get_type_abort(section, struct dialog_section_text_field);
880 pos_form_cursor(text_field->form);
882 return true;
885 struct dialog_section_ops text_field_ops = {
886 .create = text_field_create,
887 .destroy = text_field_destroy,
888 .on_input = text_field_on_input,
889 .on_up = text_field_on_up,
890 .on_down = text_field_on_down,
891 .on_left = text_field_on_left,
892 .on_right = text_field_on_right,
893 .on_enter = text_field_on_enter,
894 .on_focus = text_field_on_focus
897 static int text_field_free(struct dialog_section_text_field *text_field)
899 dialog_section_destroy(&text_field->section);
900 return 0;
903 struct dialog_section *dialog_section_text_field_new(TALLOC_CTX *ctx,
904 int height, int width)
906 struct dialog_section_text_field *text_field;
908 text_field = talloc_zero(ctx, struct dialog_section_text_field);
909 if (text_field == NULL) {
910 return NULL;
912 talloc_set_destructor(text_field, text_field_free);
913 dialog_section_init(&text_field->section, &text_field_ops,
914 height, width);
915 text_field->opts = O_ACTIVE | O_PUBLIC | O_EDIT | O_VISIBLE | O_NULLOK;
917 return &text_field->section;
920 const char *dialog_section_text_field_get(TALLOC_CTX *ctx,
921 struct dialog_section *section)
923 struct dialog_section_text_field *text_field =
924 talloc_get_type_abort(section, struct dialog_section_text_field);
926 form_driver(text_field->form, REQ_VALIDATION);
928 return string_trim(ctx, field_buffer(text_field->field[0], 0));
931 void dialog_section_text_field_set(struct dialog_section *section,
932 const char *s)
934 struct dialog_section_text_field *text_field =
935 talloc_get_type_abort(section, struct dialog_section_text_field);
937 text_field->length = strlen(s);
938 set_field_buffer(text_field->field[0], 0, s);
941 const char **dialog_section_text_field_get_lines(TALLOC_CTX *ctx,
942 struct dialog_section *section)
944 int rows, cols, max;
945 const char **arr;
946 size_t i;
947 const char *buf;
948 struct dialog_section_text_field *text_field =
949 talloc_get_type_abort(section, struct dialog_section_text_field);
951 form_driver(text_field->form, REQ_VALIDATION);
952 buf = field_buffer(text_field->field[0], 0);
954 dynamic_field_info(text_field->field[0], &rows, &cols, &max);
956 arr = talloc_zero_array(ctx, const char *, rows + 1);
957 if (arr == NULL) {
958 return NULL;
960 for (i = 0; *buf; ++i, buf += cols) {
961 SMB_ASSERT(i < rows);
962 arr[i] = string_trim_n(arr, buf, cols);
965 return arr;
968 WERROR dialog_section_text_field_set_lines(TALLOC_CTX *ctx,
969 struct dialog_section *section,
970 const char **array)
972 int rows, cols, max;
973 size_t padding, length, idx;
974 const char **arrayp;
975 char *buf = NULL;
976 struct dialog_section_text_field *text_field =
977 talloc_get_type_abort(section, struct dialog_section_text_field);
979 dynamic_field_info(text_field->field[0], &rows, &cols, &max);
980 /* try to fit each string on it's own line. each line
981 needs to be padded with whitespace manually, since
982 ncurses fields do not have newlines. */
983 for (idx = 0, arrayp = array; *arrayp != NULL; ++arrayp) {
984 length = MIN(strlen(*arrayp), cols);
985 padding = cols - length;
986 buf = talloc_realloc(ctx, buf, char,
987 talloc_array_length(buf) +
988 length + padding + 1);
989 if (buf == NULL) {
990 return WERR_NOT_ENOUGH_MEMORY;
992 memcpy(&buf[idx], *arrayp, length);
993 idx += length;
994 memset(&buf[idx], ' ', padding);
995 idx += padding;
996 buf[idx] = '\0';
999 set_field_buffer(text_field->field[0], 0, buf);
1000 talloc_free(buf);
1002 return WERR_OK;
1005 bool dialog_section_text_field_get_int(struct dialog_section *section,
1006 long long *out)
1008 bool rv;
1009 const char *buf;
1010 char *endp;
1011 struct dialog_section_text_field *text_field =
1012 talloc_get_type_abort(section, struct dialog_section_text_field);
1014 form_driver(text_field->form, REQ_VALIDATION);
1016 buf = string_trim(section, field_buffer(text_field->field[0], 0));
1017 if (buf == NULL) {
1018 return false;
1020 *out = strtoll(buf, &endp, 0);
1021 rv = true;
1022 if (endp == buf || endp == NULL || endp[0] != '\0') {
1023 rv = false;
1026 return rv;
1030 bool dialog_section_text_field_get_uint(struct dialog_section *section,
1031 unsigned long long *out)
1033 const char *buf;
1034 int error = 0;
1035 struct dialog_section_text_field *text_field =
1036 talloc_get_type_abort(section, struct dialog_section_text_field);
1038 form_driver(text_field->form, REQ_VALIDATION);
1040 buf = string_trim(section, field_buffer(text_field->field[0], 0));
1041 if (buf == NULL) {
1042 return false;
1044 *out = smb_strtoull(buf, NULL, 0, &error, SMB_STR_FULL_STR_CONV);
1045 if (error != 0) {
1046 return false;
1049 return true;
1052 /* hex editor field */
1053 struct dialog_section_hexedit {
1054 struct dialog_section section;
1055 struct hexedit *buf;
1058 #define HEXEDIT_MIN_SIZE 1
1059 static WERROR hexedit_create(struct dialog *dia,
1060 struct dialog_section *section)
1062 struct dialog_section_hexedit *hexedit =
1063 talloc_get_type_abort(section, struct dialog_section_hexedit);
1065 hexedit->buf = hexedit_new(dia, section->window, NULL,
1066 HEXEDIT_MIN_SIZE);
1067 if (hexedit->buf == NULL) {
1068 return WERR_NOT_ENOUGH_MEMORY;
1071 hexedit_refresh(hexedit->buf);
1073 return WERR_OK;
1076 static void hexedit_destroy(struct dialog_section *section)
1078 struct dialog_section_hexedit *hexedit =
1079 talloc_get_type_abort(section, struct dialog_section_hexedit);
1081 if (hexedit->buf) {
1082 TALLOC_FREE(hexedit->buf);
1086 static void hexedit_on_input(struct dialog *dia,
1087 struct dialog_section *section,
1088 int c)
1090 struct dialog_section_hexedit *hexedit =
1091 talloc_get_type_abort(section, struct dialog_section_hexedit);
1093 switch (c) {
1094 case KEY_BACKSPACE:
1095 hexedit_driver(hexedit->buf, HE_BACKSPACE);
1096 break;
1097 case '\x7f':
1098 case KEY_DC:
1099 hexedit_driver(hexedit->buf, HE_DELETE);
1100 break;
1101 default:
1102 hexedit_driver(hexedit->buf, c);
1103 break;
1107 static bool hexedit_on_up(struct dialog *dia,
1108 struct dialog_section *section)
1110 struct dialog_section_hexedit *hexedit =
1111 talloc_get_type_abort(section, struct dialog_section_hexedit);
1113 hexedit_driver(hexedit->buf, HE_CURSOR_UP);
1115 return true;
1118 static bool hexedit_on_down(struct dialog *dia,
1119 struct dialog_section *section)
1121 struct dialog_section_hexedit *hexedit =
1122 talloc_get_type_abort(section, struct dialog_section_hexedit);
1124 hexedit_driver(hexedit->buf, HE_CURSOR_DOWN);
1126 return true;
1129 static bool hexedit_on_left(struct dialog *dia,
1130 struct dialog_section *section)
1132 struct dialog_section_hexedit *hexedit =
1133 talloc_get_type_abort(section, struct dialog_section_hexedit);
1135 hexedit_driver(hexedit->buf, HE_CURSOR_LEFT);
1137 return true;
1140 static bool hexedit_on_right(struct dialog *dia,
1141 struct dialog_section *section)
1143 struct dialog_section_hexedit *hexedit =
1144 talloc_get_type_abort(section, struct dialog_section_hexedit);
1146 hexedit_driver(hexedit->buf, HE_CURSOR_RIGHT);
1148 return true;
1151 static enum dialog_action hexedit_on_enter(struct dialog *dia,
1152 struct dialog_section *section)
1154 return DIALOG_IGNORE;
1157 static bool hexedit_on_focus(struct dialog *dia,
1158 struct dialog_section *section, bool forward)
1160 struct dialog_section_hexedit *hexedit =
1161 talloc_get_type_abort(section, struct dialog_section_hexedit);
1163 hexedit_set_cursor(hexedit->buf);
1165 return true;
1168 struct dialog_section_ops hexedit_ops = {
1169 .create = hexedit_create,
1170 .destroy = hexedit_destroy,
1171 .on_input = hexedit_on_input,
1172 .on_up = hexedit_on_up,
1173 .on_down = hexedit_on_down,
1174 .on_left = hexedit_on_left,
1175 .on_right = hexedit_on_right,
1176 .on_enter = hexedit_on_enter,
1177 .on_focus = hexedit_on_focus
1180 static int hexedit_free(struct dialog_section_hexedit *hexedit)
1182 dialog_section_destroy(&hexedit->section);
1183 return 0;
1186 struct dialog_section *dialog_section_hexedit_new(TALLOC_CTX *ctx, int height)
1188 struct dialog_section_hexedit *hexedit;
1190 hexedit = talloc_zero(ctx, struct dialog_section_hexedit);
1191 if (hexedit == NULL) {
1192 return NULL;
1194 talloc_set_destructor(hexedit, hexedit_free);
1195 dialog_section_init(&hexedit->section, &hexedit_ops,
1196 height, LINE_WIDTH);
1198 return &hexedit->section;
1201 WERROR dialog_section_hexedit_set_buf(struct dialog_section *section,
1202 const void *data, size_t size)
1204 WERROR rv;
1205 struct dialog_section_hexedit *hexedit =
1206 talloc_get_type_abort(section, struct dialog_section_hexedit);
1208 SMB_ASSERT(hexedit->buf != NULL);
1210 rv = hexedit_set_buf(hexedit->buf, data, size);
1211 if (W_ERROR_IS_OK(rv)) {
1212 hexedit_refresh(hexedit->buf);
1213 hexedit_set_cursor(hexedit->buf);
1216 return rv;
1219 void dialog_section_hexedit_get_buf(struct dialog_section *section,
1220 const void **data, size_t *size)
1222 struct dialog_section_hexedit *hexedit =
1223 talloc_get_type_abort(section, struct dialog_section_hexedit);
1225 SMB_ASSERT(hexedit->buf != NULL);
1226 *data = hexedit_get_buf(hexedit->buf);
1227 *size = hexedit_get_buf_len(hexedit->buf);
1230 WERROR dialog_section_hexedit_resize(struct dialog_section *section,
1231 size_t size)
1233 WERROR rv;
1234 struct dialog_section_hexedit *hexedit =
1235 talloc_get_type_abort(section, struct dialog_section_hexedit);
1237 SMB_ASSERT(hexedit->buf != NULL);
1238 rv = hexedit_resize_buffer(hexedit->buf, size);
1239 if (W_ERROR_IS_OK(rv)) {
1240 hexedit_refresh(hexedit->buf);
1243 return rv;
1247 /* button box */
1248 struct dialog_section_buttons {
1249 struct dialog_section section;
1250 struct button_spec *spec;
1251 int current_button;
1254 static void buttons_unhighlight(struct dialog_section_buttons *buttons)
1256 short pair;
1257 attr_t attr;
1260 * Some GCC versions will complain if the macro version of
1261 * wattr_get is used. So we should enforce the use of the
1262 * function instead. See:
1263 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1265 (wattr_get)(buttons->section.window, &attr, &pair, NULL);
1266 mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL);
1267 wnoutrefresh(buttons->section.window);
1270 static void buttons_highlight(struct dialog_section_buttons *buttons)
1272 struct button_spec *spec = &buttons->spec[buttons->current_button];
1273 short pair;
1274 attr_t attr;
1277 * Some GCC versions will complain if the macro version of
1278 * wattr_get is used. So we should enforce the use of the
1279 * function instead. See:
1280 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1282 (wattr_get)(buttons->section.window, &attr, &pair, NULL);
1283 mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL);
1284 mvwchgat(buttons->section.window, 0, spec->col,
1285 strlen(spec->label), A_REVERSE, pair, NULL);
1286 wmove(buttons->section.window, 0, spec->col + 2);
1287 wcursyncup(buttons->section.window);
1288 wnoutrefresh(buttons->section.window);
1291 static bool buttons_highlight_next(struct dialog_section_buttons *buttons)
1293 if (buttons->current_button < talloc_array_length(buttons->spec) - 1) {
1294 buttons->current_button++;
1295 buttons_highlight(buttons);
1296 return true;
1298 return false;
1301 static bool buttons_highlight_previous(struct dialog_section_buttons *buttons)
1303 if (buttons->current_button > 0) {
1304 buttons->current_button--;
1305 buttons_highlight(buttons);
1306 return true;
1308 return false;
1311 static WERROR buttons_create(struct dialog *dia,
1312 struct dialog_section *section)
1314 size_t i, nbuttons;
1315 struct dialog_section_buttons *buttons =
1316 talloc_get_type_abort(section, struct dialog_section_buttons);
1318 nbuttons = talloc_array_length(buttons->spec);
1319 for (i = 0; i < nbuttons; ++i) {
1320 struct button_spec *spec = &buttons->spec[i];
1321 mvwaddstr(section->window, 0, spec->col, spec->label);
1324 buttons->current_button = 0;
1326 return WERR_OK;
1329 static bool buttons_on_btab(struct dialog *dia, struct dialog_section *section)
1331 struct dialog_section_buttons *buttons =
1332 talloc_get_type_abort(section, struct dialog_section_buttons);
1334 return buttons_highlight_previous(buttons);
1337 static bool buttons_on_tab(struct dialog *dia, struct dialog_section *section)
1339 struct dialog_section_buttons *buttons =
1340 talloc_get_type_abort(section, struct dialog_section_buttons);
1342 return buttons_highlight_next(buttons);
1345 static enum dialog_action buttons_on_enter(struct dialog *dia,
1346 struct dialog_section *section)
1348 struct dialog_section_buttons *buttons =
1349 talloc_get_type_abort(section, struct dialog_section_buttons);
1350 struct button_spec *spec = &buttons->spec[buttons->current_button];
1352 if (spec->on_enter) {
1353 return spec->on_enter(dia, section);
1356 return spec->action;
1359 static bool buttons_on_focus(struct dialog *dia,
1360 struct dialog_section *section,
1361 bool forward)
1363 struct dialog_section_buttons *buttons =
1364 talloc_get_type_abort(section, struct dialog_section_buttons);
1366 if (forward) {
1367 buttons->current_button = 0;
1368 } else {
1369 buttons->current_button = talloc_array_length(buttons->spec) - 1;
1371 buttons_highlight(buttons);
1373 return true;
1376 static void buttons_on_leave_focus(struct dialog *dia,
1377 struct dialog_section *section)
1379 struct dialog_section_buttons *buttons =
1380 talloc_get_type_abort(section, struct dialog_section_buttons);
1381 buttons_unhighlight(buttons);
1384 struct dialog_section_ops buttons_ops = {
1385 .create = buttons_create,
1386 .on_tab = buttons_on_tab,
1387 .on_btab = buttons_on_btab,
1388 .on_up = buttons_on_btab,
1389 .on_down = buttons_on_tab,
1390 .on_left = buttons_on_btab,
1391 .on_right = buttons_on_tab,
1392 .on_enter = buttons_on_enter,
1393 .on_focus = buttons_on_focus,
1394 .on_leave_focus = buttons_on_leave_focus
1397 static int buttons_free(struct dialog_section_buttons *buttons)
1399 dialog_section_destroy(&buttons->section);
1400 return 0;
1403 struct dialog_section *dialog_section_buttons_new(TALLOC_CTX *ctx,
1404 const struct button_spec *spec)
1406 struct dialog_section_buttons *buttons;
1407 size_t i, nbuttons;
1408 int width;
1410 buttons = talloc_zero(ctx, struct dialog_section_buttons);
1411 if (buttons == NULL) {
1412 return NULL;
1414 talloc_set_destructor(buttons, buttons_free);
1416 for (nbuttons = 0; spec[nbuttons].label; ++nbuttons) {
1418 buttons->spec = talloc_zero_array(buttons, struct button_spec, nbuttons);
1419 if (buttons->spec == NULL) {
1420 goto fail;
1423 for (width = 0, i = 0; i < nbuttons; ++i) {
1424 buttons->spec[i] = spec[i];
1425 buttons->spec[i].label = talloc_asprintf(buttons->spec,
1426 "[ %s ]",
1427 spec[i].label);
1428 if (!buttons->spec[i].label) {
1429 goto fail;
1432 buttons->spec[i].col = width;
1433 width += strlen(buttons->spec[i].label);
1434 if (i != nbuttons - 1) {
1435 ++width;
1439 dialog_section_init(&buttons->section, &buttons_ops, 1, width);
1441 return &buttons->section;
1443 fail:
1444 talloc_free(buttons);
1445 return NULL;
1448 /* options */
1449 struct dialog_section_options {
1450 struct dialog_section section;
1451 struct option_spec *spec;
1452 int current_option;
1453 bool single_select;
1456 static void options_unhighlight(struct dialog_section_options *options)
1458 short pair;
1459 attr_t attr;
1460 size_t row;
1463 * Some GCC versions will complain if the macro version of
1464 * wattr_get is used. So we should enforce the use of the
1465 * function instead. See:
1466 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1468 (wattr_get)(options->section.window, &attr, &pair, NULL);
1469 for (row = 0; row < options->section.nlines; ++row) {
1470 mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL);
1472 wnoutrefresh(options->section.window);
1475 static void options_highlight(struct dialog_section_options *options)
1477 struct option_spec *spec = &options->spec[options->current_option];
1478 short pair;
1479 attr_t attr;
1480 size_t row;
1483 * Some GCC versions will complain if the macro version of
1484 * wattr_get is used. So we should enforce the use of the
1485 * function instead. See:
1486 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1488 (wattr_get)(options->section.window, &attr, &pair, NULL);
1489 for (row = 0; row < options->section.nlines; ++row) {
1490 mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL);
1492 mvwchgat(options->section.window, spec->row, spec->col,
1493 strlen(spec->label), A_REVERSE, pair, NULL);
1494 wmove(options->section.window, spec->row, spec->col + 4);
1495 wcursyncup(options->section.window);
1496 wnoutrefresh(options->section.window);
1499 static void options_render_state(struct dialog_section_options *options)
1501 size_t i, noptions;
1503 noptions = talloc_array_length(options->spec);
1504 for (i = 0; i < noptions; ++i) {
1505 struct option_spec *spec = &options->spec[i];
1506 char c = ' ';
1507 if (*spec->state)
1508 c = 'x';
1509 mvwaddch(options->section.window,
1510 spec->row, spec->col + 1, c);
1511 wnoutrefresh(options->section.window);
1515 static bool options_highlight_next(struct dialog_section_options *options)
1517 if (options->current_option < talloc_array_length(options->spec) - 1) {
1518 options->current_option++;
1519 options_highlight(options);
1520 return true;
1522 return false;
1525 static bool options_highlight_previous(struct dialog_section_options *options)
1527 if (options->current_option > 0) {
1528 options->current_option--;
1529 options_highlight(options);
1530 return true;
1532 return false;
1535 static WERROR options_create(struct dialog *dia,
1536 struct dialog_section *section)
1538 size_t i, noptions;
1539 struct dialog_section_options *options =
1540 talloc_get_type_abort(section, struct dialog_section_options);
1542 noptions = talloc_array_length(options->spec);
1543 for (i = 0; i < noptions; ++i) {
1544 struct option_spec *spec = &options->spec[i];
1545 mvwaddstr(section->window, spec->row, spec->col,
1546 spec->label);
1549 options->current_option = 0;
1550 options_render_state(options);
1552 return WERR_OK;
1555 static bool options_on_btab(struct dialog *dia, struct dialog_section *section)
1557 struct dialog_section_options *options =
1558 talloc_get_type_abort(section, struct dialog_section_options);
1560 return options_highlight_previous(options);
1563 static bool options_on_tab(struct dialog *dia, struct dialog_section *section)
1565 struct dialog_section_options *options =
1566 talloc_get_type_abort(section, struct dialog_section_options);
1568 return options_highlight_next(options);
1571 static void options_on_input(struct dialog *dia, struct dialog_section *section, int c)
1573 struct dialog_section_options *options =
1574 talloc_get_type_abort(section, struct dialog_section_options);
1576 if (c == ' ') {
1577 struct option_spec *spec = &options->spec[options->current_option];
1578 if (options->single_select) {
1579 size_t i, noptions;
1580 noptions = talloc_array_length(options->spec);
1581 for (i = 0; i < noptions; ++i) {
1582 *(options->spec[i].state) = false;
1585 *spec->state = !*spec->state;
1586 options_unhighlight(options);
1587 options_render_state(options);
1588 options_highlight(options);
1592 static enum dialog_action options_on_enter(struct dialog *dia, struct dialog_section *section)
1594 options_on_input(dia, section, ' ');
1595 return DIALOG_OK;
1598 static bool options_on_focus(struct dialog *dia,
1599 struct dialog_section *section,
1600 bool forward)
1602 struct dialog_section_options *options =
1603 talloc_get_type_abort(section, struct dialog_section_options);
1605 if (forward) {
1606 options->current_option = 0;
1607 } else {
1608 options->current_option = talloc_array_length(options->spec) - 1;
1610 options_highlight(options);
1612 return true;
1615 static void options_on_leave_focus(struct dialog *dia,
1616 struct dialog_section *section)
1618 struct dialog_section_options *options =
1619 talloc_get_type_abort(section, struct dialog_section_options);
1620 options_unhighlight(options);
1623 struct dialog_section_ops options_ops = {
1624 .create = options_create,
1625 .on_tab = options_on_tab,
1626 .on_btab = options_on_btab,
1627 .on_up = options_on_btab,
1628 .on_down = options_on_tab,
1629 .on_left = options_on_btab,
1630 .on_right = options_on_tab,
1631 .on_input = options_on_input,
1632 .on_enter = options_on_enter,
1633 .on_focus = options_on_focus,
1634 .on_leave_focus = options_on_leave_focus
1637 static int options_free(struct dialog_section_options *options)
1639 dialog_section_destroy(&options->section);
1640 return 0;
1643 struct dialog_section *dialog_section_options_new(TALLOC_CTX *ctx,
1644 const struct option_spec *spec,
1645 int maxcol, bool single_select)
1647 struct dialog_section_options *options;
1648 size_t i, noptions;
1649 int width, maxwidth, maxrows;
1651 options = talloc_zero(ctx, struct dialog_section_options);
1652 if (options == NULL) {
1653 return NULL;
1655 talloc_set_destructor(options, options_free);
1657 for (noptions = 0; spec[noptions].label; ++noptions) {
1659 options->spec = talloc_zero_array(options, struct option_spec, noptions);
1660 if (options->spec == NULL) {
1661 goto fail;
1664 maxrows = noptions / maxcol;
1665 if (noptions % maxcol) {
1666 ++maxrows;
1669 for (width = 0, maxwidth = 0, i = 0; i < noptions; ++i) {
1670 options->spec[i] = spec[i];
1671 options->spec[i].label = talloc_asprintf(options->spec,
1672 "[ ] %s",
1673 spec[i].label);
1674 if (!options->spec[i].label) {
1675 goto fail;
1678 options->spec[i].col = maxwidth;
1679 options->spec[i].row = i % maxrows;
1680 width = MAX(strlen(options->spec[i].label), width);
1681 if (options->spec[i].row == maxrows - 1 || i == noptions - 1) {
1682 maxwidth += width + 1;
1683 width = 0;
1687 dialog_section_init(&options->section, &options_ops, maxrows, maxwidth - 1);
1688 options->single_select = single_select;
1690 return &options->section;
1692 fail:
1693 talloc_free(options);
1694 return NULL;
1698 enum input_type {
1699 DLG_IN_LONG,
1700 DLG_IN_ULONG,
1701 DLG_IN_STR,
1704 struct input_req {
1705 TALLOC_CTX *ctx;
1706 enum input_type type;
1707 union {
1708 void *out;
1709 unsigned long *out_ulong;
1710 long *out_long;
1711 const char **out_str;
1712 } out;
1715 static bool input_on_submit(struct dialog *dia, struct dialog_section *section,
1716 void *arg)
1718 struct input_req *req = arg;
1719 struct dialog_section *data;
1720 unsigned long long out_ulong;
1721 long long out_long;
1723 data = dialog_find_section(dia, "input");
1725 switch (req->type) {
1726 case DLG_IN_LONG:
1727 if (!dialog_section_text_field_get_int(data, &out_long)) {
1728 dialog_notice(dia, DIA_ALERT, "Error",
1729 "Input must be a number.");
1730 return false;
1732 if (out_long < LONG_MIN || out_long > LONG_MAX) {
1733 dialog_notice(dia, DIA_ALERT, "Error",
1734 "Number is out of range.");
1735 return false;
1737 *req->out.out_long = out_long;
1738 break;
1739 case DLG_IN_ULONG:
1740 if (!dialog_section_text_field_get_uint(data, &out_ulong)) {
1741 dialog_notice(dia, DIA_ALERT, "Error",
1742 "Input must be a number greater than zero.");
1743 return false;
1745 if (out_ulong > ULONG_MAX) {
1746 dialog_notice(dia, DIA_ALERT, "Error",
1747 "Number is out of range.");
1748 return false;
1750 *req->out.out_ulong = out_ulong;
1751 break;
1752 case DLG_IN_STR:
1753 *req->out.out_str = dialog_section_text_field_get(req->ctx, data);
1754 break;
1757 return true;
1760 static int dialog_input_internal(TALLOC_CTX *ctx, void *output,
1761 enum input_type type,
1762 const char *title,
1763 const char *msg, va_list ap)
1764 PRINTF_ATTRIBUTE(5,0);
1766 static int dialog_input_internal(TALLOC_CTX *ctx, void *output,
1767 enum input_type type,
1768 const char *title,
1769 const char *msg, va_list ap)
1771 WERROR err;
1772 struct input_req req;
1773 enum dialog_action action;
1774 struct dialog *dia;
1775 struct dialog_section *section;
1776 struct button_spec spec[] = {
1777 {.label = "OK", .action = DIALOG_OK},
1778 {.label = "Cancel", .action = DIALOG_CANCEL},
1779 { 0 }
1782 req.ctx = ctx;
1783 req.type = type;
1784 req.out.out = output;
1785 *req.out.out_str = NULL;
1787 dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1);
1788 dialog_set_submit_cb(dia, input_on_submit, &req);
1789 section = dialog_section_label_new_va(dia, msg, ap);
1790 dialog_append_section(dia, section);
1791 section = dialog_section_hsep_new(dia, ' ');
1792 dialog_append_section(dia, section);
1793 section = dialog_section_text_field_new(dia, 1, -1);
1794 dialog_section_set_name(section, "input");
1795 dialog_append_section(dia, section);
1796 section = dialog_section_hsep_new(dia, 0);
1797 dialog_append_section(dia, section);
1798 section = dialog_section_buttons_new(dia, spec);
1799 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
1800 dialog_append_section(dia, section);
1802 dialog_create(dia);
1803 dialog_show(dia);
1804 dialog_modal_loop(dia, &err, &action);
1805 talloc_free(dia);
1807 return action;
1810 int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title,
1811 const char *msg, ...)
1813 va_list ap;
1814 int rv;
1816 va_start(ap, msg);
1817 rv = dialog_input_internal(ctx, output, DLG_IN_STR, title, msg, ap);
1818 va_end(ap);
1820 return rv;
1823 int dialog_input_ulong(TALLOC_CTX *ctx, unsigned long *output,
1824 const char *title, const char *msg, ...)
1826 va_list ap;
1827 int rv;
1829 va_start(ap, msg);
1830 rv = dialog_input_internal(ctx, output, DLG_IN_ULONG, title, msg, ap);
1831 va_end(ap);
1833 return rv;
1836 int dialog_input_long(TALLOC_CTX *ctx, long *output,
1837 const char *title, const char *msg, ...)
1839 va_list ap;
1840 int rv;
1842 va_start(ap, msg);
1843 rv = dialog_input_internal(ctx, output, DLG_IN_LONG, title, msg, ap);
1844 va_end(ap);
1846 return rv;
1849 int dialog_notice(TALLOC_CTX *ctx, enum dialog_type type,
1850 const char *title, const char *msg, ...)
1852 va_list ap;
1853 WERROR err;
1854 enum dialog_action action;
1855 struct dialog *dia;
1856 struct dialog_section *section;
1857 struct button_spec spec[3];
1859 memset(&spec, '\0', sizeof(spec));
1860 spec[0].label = "OK";
1861 spec[0].action = DIALOG_OK;
1862 if (type == DIA_CONFIRM) {
1863 spec[1].label = "Cancel";
1864 spec[1].action = DIALOG_CANCEL;
1867 dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1);
1868 va_start(ap, msg);
1869 section = dialog_section_label_new_va(dia, msg, ap);
1870 va_end(ap);
1871 dialog_append_section(dia, section);
1872 section = dialog_section_hsep_new(dia, 0);
1873 dialog_append_section(dia, section);
1874 section = dialog_section_buttons_new(dia, spec);
1875 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
1876 dialog_append_section(dia, section);
1878 dialog_create(dia);
1879 dialog_show(dia);
1880 dialog_modal_loop(dia, &err, &action);
1881 talloc_free(dia);
1883 return action;
1887 struct edit_req {
1888 uint32_t type;
1889 uint32_t mode;
1890 struct registry_key *key;
1891 const struct value_item *vitem;
1894 static WERROR fill_value_buffer(struct dialog *dia, struct edit_req *edit)
1896 char *tmp;
1897 struct dialog_section *data;
1899 if (edit->vitem == NULL) {
1900 return WERR_OK;
1903 data = dialog_find_section(dia, "data");
1904 SMB_ASSERT(data != NULL);
1906 switch (edit->mode) {
1907 case REG_DWORD: {
1908 uint32_t v = 0;
1909 if (edit->vitem->data.length >= 4) {
1910 v = IVAL(edit->vitem->data.data, 0);
1912 tmp = talloc_asprintf(dia, "%u", (unsigned)v);
1913 if (tmp == NULL) {
1914 return WERR_NOT_ENOUGH_MEMORY;
1916 dialog_section_text_field_set(data, tmp);
1917 talloc_free(tmp);
1918 break;
1920 case REG_SZ:
1921 case REG_EXPAND_SZ: {
1922 const char *s;
1924 if (!pull_reg_sz(dia, &edit->vitem->data, &s)) {
1925 return WERR_NOT_ENOUGH_MEMORY;
1927 dialog_section_text_field_set(data, s);
1928 break;
1930 case REG_MULTI_SZ: {
1931 const char **array;
1933 if (!pull_reg_multi_sz(dia, &edit->vitem->data, &array)) {
1934 return WERR_NOT_ENOUGH_MEMORY;
1936 return dialog_section_text_field_set_lines(dia, data, array);
1938 case REG_BINARY:
1939 default:
1940 return dialog_section_hexedit_set_buf(data,
1941 edit->vitem->data.data,
1942 edit->vitem->data.length);
1945 return WERR_OK;
1948 static bool value_exists(TALLOC_CTX *ctx, const struct registry_key *key,
1949 const char *name)
1951 uint32_t type;
1952 DATA_BLOB blob;
1953 WERROR rv;
1955 rv = reg_key_get_value_by_name(ctx, key, name, &type, &blob);
1957 return W_ERROR_IS_OK(rv);
1960 static bool edit_on_submit(struct dialog *dia, struct dialog_section *section,
1961 void *arg)
1963 struct edit_req *edit = arg;
1964 WERROR rv;
1965 DATA_BLOB blob;
1966 const char *name;
1967 struct dialog_section *name_section, *data;
1969 name_section = dialog_find_section(dia, "name");
1970 if (name_section) {
1971 name = dialog_section_text_field_get(dia, name_section);
1972 if (*name == '\0') {
1973 dialog_notice(dia, DIA_ALERT, "Error",
1974 "Value name must not be blank.");
1975 return false;
1977 if (value_exists(dia, edit->key, name)) {
1978 dialog_notice(dia, DIA_ALERT, "Error",
1979 "Value named \"%s\" already exists.",
1980 name);
1981 return false;
1983 } else {
1984 SMB_ASSERT(edit->vitem);
1985 name = edit->vitem->value_name;
1987 SMB_ASSERT(name);
1989 data = dialog_find_section(dia, "data");
1990 SMB_ASSERT(data != NULL);
1992 rv = WERR_OK;
1993 switch (edit->mode) {
1994 case REG_DWORD: {
1995 unsigned long long v;
1996 uint32_t val;
1998 if (!dialog_section_text_field_get_uint(data, &v)) {
1999 dialog_notice(dia, DIA_ALERT, "Error",
2000 "REG_DWORD value must be an integer.");
2001 return false;
2003 if (v > UINT32_MAX) {
2004 dialog_notice(dia, DIA_ALERT, "Error",
2005 "REG_DWORD value must less than %lu.",
2006 (unsigned long)UINT32_MAX);
2007 return false;
2009 val = (uint32_t)v;
2010 blob = data_blob_talloc(dia, NULL, sizeof(val));
2011 SIVAL(blob.data, 0, val);
2012 break;
2014 case REG_SZ:
2015 case REG_EXPAND_SZ: {
2016 const char *buf;
2018 buf = dialog_section_text_field_get(dia, data);
2019 if (!buf || !push_reg_sz(dia, &blob, buf)) {
2020 rv = WERR_NOT_ENOUGH_MEMORY;
2022 break;
2024 case REG_MULTI_SZ: {
2025 const char **lines;
2027 lines = dialog_section_text_field_get_lines(dia, data);
2028 if (!lines || !push_reg_multi_sz(dia, &blob, lines)) {
2029 rv = WERR_NOT_ENOUGH_MEMORY;
2031 break;
2033 case REG_BINARY: {
2034 const void *buf;
2035 size_t len;
2037 dialog_section_hexedit_get_buf(data, &buf, &len);
2038 blob = data_blob_talloc(dia, buf, len);
2039 break;
2043 if (W_ERROR_IS_OK(rv)) {
2044 rv = reg_val_set(edit->key, name, edit->type, blob);
2047 if (!W_ERROR_IS_OK(rv)) {
2048 const char *msg = get_friendly_werror_msg(rv);
2049 dialog_notice(dia, DIA_ALERT, "Error",
2050 "Error saving value:\n%s", msg);
2052 return false;
2055 return true;
2059 static enum dialog_action edit_on_resize(struct dialog *dia,
2060 struct dialog_section *section)
2062 struct dialog_section *data;
2063 unsigned long size;
2064 int rv;
2066 data = dialog_find_section(dia, "data");
2067 rv = dialog_input_ulong(dia, &size, "Resize", "Enter size of buffer");
2068 if (rv == DIALOG_OK) {
2069 dialog_section_hexedit_resize(data, size);
2072 return DIALOG_IGNORE;
2075 int dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key,
2076 uint32_t type, const struct value_item *vitem,
2077 bool force_binary, WERROR *err,
2078 const char **name)
2080 enum dialog_action action;
2081 struct dialog *dia;
2082 struct dialog_section *section;
2083 struct edit_req edit;
2084 struct button_spec buttons[] = {
2085 {.label = "OK", .action = DIALOG_OK},
2086 {.label = "Cancel", .action = DIALOG_CANCEL},
2087 { 0 }
2089 struct button_spec buttons_hexedit[] = {
2090 {.label = "OK", .action = DIALOG_OK},
2091 {.label = "Resize Buffer", .on_enter = edit_on_resize},
2092 {.label = "Cancel", .action = DIALOG_CANCEL},
2093 { 0 }
2097 edit.key = key;
2098 edit.vitem = vitem;
2099 edit.type = type;
2100 edit.mode = type;
2101 if (force_binary || (vitem && vitem->unprintable)) {
2102 edit.mode = REG_BINARY;
2105 dia = dialog_new(ctx, PAIR_BLACK_CYAN, "Edit Value", -1, -1);
2106 dialog_set_submit_cb(dia, edit_on_submit, &edit);
2108 section = dialog_section_label_new(dia, "Type");
2109 dialog_append_section(dia, section);
2110 section = dialog_section_label_new(dia, "%s",
2111 str_regtype(type));
2112 dialog_append_section(dia, section);
2113 section = dialog_section_hsep_new(dia, ' ');
2114 dialog_append_section(dia, section);
2116 section = dialog_section_label_new(dia, "Name");
2117 dialog_append_section(dia, section);
2118 if (vitem) {
2119 section = dialog_section_label_new(dia, "%s",
2120 vitem->value_name);
2121 } else {
2122 section = dialog_section_text_field_new(dia, 1, 50);
2123 dialog_section_set_name(section, "name");
2125 dialog_append_section(dia, section);
2126 section = dialog_section_hsep_new(dia, ' ');
2127 dialog_append_section(dia, section);
2129 section = dialog_section_label_new(dia, "Data");
2130 dialog_append_section(dia, section);
2132 switch (edit.mode) {
2133 case REG_DWORD:
2134 case REG_SZ:
2135 case REG_EXPAND_SZ:
2136 section = dialog_section_text_field_new(dia, 1, 50);
2137 break;
2138 case REG_MULTI_SZ:
2139 section = dialog_section_text_field_new(dia, 10, 50);
2140 break;
2141 case REG_BINARY:
2142 default:
2143 section = dialog_section_hexedit_new(dia, 10);
2144 break;
2147 dialog_section_set_name(section, "data");
2148 dialog_append_section(dia, section);
2150 section = dialog_section_hsep_new(dia, 0);
2151 dialog_append_section(dia, section);
2152 if (edit.mode == REG_BINARY) {
2153 section = dialog_section_buttons_new(dia, buttons_hexedit);
2154 } else {
2155 section = dialog_section_buttons_new(dia, buttons);
2157 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2158 dialog_append_section(dia, section);
2160 dialog_create(dia);
2162 *err = fill_value_buffer(dia, &edit);
2163 if (!W_ERROR_IS_OK(*err)) {
2164 return DIALOG_CANCEL;
2167 dialog_show(dia);
2168 dialog_modal_loop(dia, err, &action);
2170 if (action == DIALOG_OK && name) {
2171 if (vitem) {
2172 *name = talloc_strdup(ctx, vitem->value_name);
2173 } else if ((section = dialog_find_section(dia, "name"))) {
2174 *name = dialog_section_text_field_get(ctx, section);
2178 talloc_free(dia);
2180 return action;
2183 int dialog_select_type(TALLOC_CTX *ctx, int *type)
2185 WERROR err;
2186 enum dialog_action action;
2187 struct dialog *dia;
2188 struct dialog_section *section;
2189 const char *reg_types[] = {
2190 "REG_BINARY",
2191 "REG_DWORD",
2192 "REG_EXPAND_SZ",
2193 "REG_MULTI_SZ",
2194 "REG_SZ"
2196 #define NTYPES ARRAY_SIZE(reg_types)
2197 struct button_spec spec[] = {
2198 {.label = "OK", .action = DIALOG_OK},
2199 {.label = "Cancel", .action = DIALOG_CANCEL},
2200 { 0 }
2202 bool flags[NTYPES] = { true };
2203 struct option_spec opsec[NTYPES + 1];
2204 unsigned i;
2206 memset(&opsec, '\0', sizeof(opsec));
2207 for (i = 0; i < NTYPES; ++i) {
2208 opsec[i].label = reg_types[i];
2209 opsec[i].state = &flags[i];
2212 dia = dialog_new(ctx, PAIR_BLACK_CYAN, "New Value", -1, -1);
2214 section = dialog_section_label_new(dia, "Select type for new value:");
2215 dialog_append_section(dia, section);
2216 section = dialog_section_hsep_new(dia, ' ');
2217 dialog_append_section(dia, section);
2218 section = dialog_section_options_new(dia, opsec, 2, true);
2219 dialog_append_section(dia, section);
2220 section = dialog_section_hsep_new(dia, 0);
2221 dialog_append_section(dia, section);
2222 section = dialog_section_buttons_new(dia, spec);
2223 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2224 dialog_append_section(dia, section);
2226 dialog_create(dia);
2227 dialog_show(dia);
2229 dialog_modal_loop(dia, &err, &action);
2230 if (action == DIALOG_OK) {
2231 for (i = 0; i < NTYPES; ++i) {
2232 if (flags[i]) {
2233 *type = regtype_by_string(reg_types[i]);
2234 break;
2239 talloc_free(dia);
2241 return action;
2244 struct search_req {
2245 TALLOC_CTX *ctx;
2246 struct regedit_search_opts *opts;
2249 static bool search_on_submit(struct dialog *dia, struct dialog_section *section,
2250 void *arg)
2252 struct search_req *search = arg;
2253 struct dialog_section *query;
2255 query = dialog_find_section(dia, "query");
2256 SMB_ASSERT(query != NULL);
2258 if (!search->opts->search_key && !search->opts->search_value) {
2259 dialog_notice(dia, DIA_ALERT, "Error",
2260 "Must search a key and/or a value");
2261 return false;
2264 talloc_free(discard_const(search->opts->query));
2265 search->opts->query = dialog_section_text_field_get(search->ctx, query);
2266 SMB_ASSERT(search->opts->query != NULL);
2267 if (search->opts->query[0] == '\0') {
2268 dialog_notice(dia, DIA_ALERT, "Error",
2269 "Query must not be blank.");
2270 return false;
2273 return true;
2276 int dialog_search_input(TALLOC_CTX *ctx, struct regedit_search_opts *opts)
2278 WERROR err;
2279 enum dialog_action action;
2280 struct dialog *dia;
2281 struct dialog_section *section, *query;
2282 struct search_req search;
2283 struct button_spec spec[] = {
2284 {.label = "Search", .action = DIALOG_OK},
2285 {.label = "Cancel", .action = DIALOG_CANCEL},
2286 { 0 }
2288 struct option_spec search_opts[] = {
2289 {.label = "Search Keys", .state = &opts->search_key},
2290 {.label = "Search Values", .state = &opts->search_value},
2291 {.label = "Recursive", .state = &opts->search_recursive},
2292 {.label = "Case Sensitive", .state = &opts->search_case},
2293 { 0 }
2296 if (!opts->search_key && !opts->search_value) {
2297 opts->search_key = true;
2300 search.ctx = ctx;
2301 search.opts = opts;
2302 dia = dialog_new(ctx, PAIR_BLACK_CYAN, "Search", -1, -1);
2303 dialog_set_submit_cb(dia, search_on_submit, &search);
2304 section = dialog_section_label_new(dia, "Query");
2305 dialog_append_section(dia, section);
2306 query = dialog_section_text_field_new(dia, 1, -1);
2307 dialog_section_set_name(query, "query");
2308 dialog_append_section(dia, query);
2309 section = dialog_section_hsep_new(dia, 0);
2310 dialog_append_section(dia, section);
2311 section = dialog_section_options_new(dia, search_opts, 2, false);
2312 dialog_append_section(dia, section);
2313 section = dialog_section_hsep_new(dia, 0);
2314 dialog_append_section(dia, section);
2315 section = dialog_section_buttons_new(dia, spec);
2316 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2317 dialog_append_section(dia, section);
2319 dialog_create(dia);
2320 if (opts->query) {
2321 dialog_section_text_field_set(query, opts->query);
2324 dialog_modal_loop(dia, &err, &action);
2325 talloc_free(dia);
2327 return action;