net rpc share allowedusers: Allow restricting shares
[garming/samba-autobuild/.git] / source3 / utils / regedit_dialog.c
1 /*
2  * Samba Unix/Linux SMB client library
3  * Registry Editor
4  * Copyright (C) Christopher Davis 2012
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
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>
29
30 static char *string_trim_n(TALLOC_CTX *ctx, const char *buf, size_t n)
31 {
32         char *str;
33
34         str = talloc_strndup(ctx, buf, n);
35
36         if (str) {
37                 trim_string(str, " ", " ");
38         }
39
40         return str;
41 }
42
43 static char *string_trim(TALLOC_CTX *ctx, const char *buf)
44 {
45         char *str;
46
47         str = talloc_strdup(ctx, buf);
48
49         if (str) {
50                 trim_string(str, " ", " ");
51         }
52
53         return str;
54 }
55
56 static int dialog_free(struct dialog *dia)
57 {
58         dialog_destroy(dia);
59
60         return 0;
61 }
62
63 static bool default_validator(struct dialog *dia, struct dialog_section *sect,
64                               void *arg)
65 {
66         return true;
67 }
68
69 struct dialog *dialog_new(TALLOC_CTX *ctx, short color, const char *title,
70                           int y, int x)
71 {
72         struct dialog *dia;
73
74         dia = talloc_zero(ctx, struct dialog);
75         if (dia == NULL) {
76                 return NULL;
77         }
78
79         talloc_set_destructor(dia, dialog_free);
80
81         dia->title = talloc_strdup(dia, title);
82         if (dia->title == NULL) {
83                 goto fail;
84         }
85         dia->x = x;
86         dia->y = y;
87         dia->color = color;
88         dia->submit = default_validator;
89
90         return dia;
91
92 fail:
93         talloc_free(dia);
94
95         return NULL;
96
97 }
98
99 void dialog_set_submit_cb(struct dialog *dia, dialog_submit_cb cb, void *arg)
100 {
101         dia->submit = cb;
102         dia->submit_arg = arg;
103 }
104
105 static void center_above_window(int *nlines, int *ncols, int *y, int *x)
106 {
107         int centery, centerx;
108
109         centery = LINES / 2;
110         centerx = COLS / 2;
111         *y = 0;
112         *x = 0;
113
114         if (*nlines > LINES) {
115                 *nlines = LINES;
116         }
117         if (*ncols > COLS) {
118                 *ncols = COLS;
119         }
120
121         if (*nlines/2 < centery) {
122                 *y = centery - *nlines / 2;
123         }
124         if (*ncols/2 < centerx) {
125                 *x = centerx - *ncols / 2;
126         }
127 }
128
129 void dialog_section_destroy(struct dialog_section *section)
130 {
131         if (section->ops->destroy) {
132                 section->ops->destroy(section);
133         }
134         if (section->window) {
135                 delwin(section->window);
136                 section->window = NULL;
137         }
138 }
139
140 void dialog_section_init(struct dialog_section *section,
141                          const struct dialog_section_ops *ops,
142                          int nlines, int ncols)
143 {
144         section->ops = ops;
145         section->nlines = nlines;
146         section->ncols = ncols;
147 }
148
149 const char *dialog_section_get_name(struct dialog_section *section)
150 {
151         return section->name;
152 }
153
154 void dialog_section_set_name(struct dialog_section *section, const char *name)
155 {
156         TALLOC_FREE(section->name);
157         section->name = talloc_strdup(section, name);
158 }
159
160 void dialog_section_set_justify(struct dialog_section *section,
161                                 enum section_justify justify)
162 {
163         section->justify = justify;
164 }
165
166 /* append a section to the dialog's circular list */
167 void dialog_append_section(struct dialog *dia,
168                            struct dialog_section *section)
169 {
170         SMB_ASSERT(section != NULL);
171
172         if (!dia->head_section) {
173                 dia->head_section = section;
174         }
175         if (dia->tail_section) {
176                 dia->tail_section->next = section;
177         }
178         section->prev = dia->tail_section;
179         section->next = dia->head_section;
180         dia->head_section->prev = section;
181         dia->tail_section = section;
182 }
183
184 struct dialog_section *dialog_find_section(struct dialog *dia, const char *name)
185 {
186         struct dialog_section *section = dia->head_section;
187
188         do {
189                 if (section->name && strequal(section->name, name)) {
190                         return section;
191                 }
192                 section = section->next;
193         } while (section != dia->head_section);
194
195         return NULL;
196 }
197
198 static void section_on_input(struct dialog *dia, int c)
199 {
200         struct dialog_section *section = dia->current_section;
201
202         if (!section->ops->on_input) {
203                 return;
204         }
205         section->ops->on_input(dia, section, c);
206 }
207
208 static bool section_on_tab(struct dialog *dia)
209 {
210         struct dialog_section *section = dia->current_section;
211
212         if (!section || !section->ops->on_tab) {
213                 return false;
214         }
215         return section->ops->on_tab(dia, section);
216 }
217
218 static bool section_on_btab(struct dialog *dia)
219 {
220         struct dialog_section *section = dia->current_section;
221
222         if (!section || !section->ops->on_btab) {
223                 return false;
224         }
225         return section->ops->on_btab(dia, section);
226 }
227
228 static bool section_on_up(struct dialog *dia)
229 {
230         struct dialog_section *section = dia->current_section;
231
232         if (!section || !section->ops->on_up) {
233                 return false;
234         }
235         return section->ops->on_up(dia, section);
236 }
237
238 static bool section_on_down(struct dialog *dia)
239 {
240         struct dialog_section *section = dia->current_section;
241
242         if (!section || !section->ops->on_down) {
243                 return false;
244         }
245         return section->ops->on_down(dia, section);
246 }
247
248 static bool section_on_left(struct dialog *dia)
249 {
250         struct dialog_section *section = dia->current_section;
251
252         if (!section || !section->ops->on_left) {
253                 return false;
254         }
255         return section->ops->on_left(dia, section);
256 }
257
258 static bool section_on_right(struct dialog *dia)
259 {
260         struct dialog_section *section = dia->current_section;
261
262         if (!section || !section->ops->on_right) {
263                 return false;
264         }
265         return section->ops->on_right(dia, section);
266 }
267
268 static enum dialog_action section_on_enter(struct dialog *dia)
269 {
270         struct dialog_section *section = dia->current_section;
271
272         if (!section || !section->ops->on_enter) {
273                 return DIALOG_OK;
274         }
275         return section->ops->on_enter(dia, section);
276 }
277
278 static bool section_on_focus(struct dialog *dia, bool forward)
279 {
280         struct dialog_section *section = dia->current_section;
281
282         if (!section->ops->on_focus) {
283                 return false;
284         }
285         return section->ops->on_focus(dia, section, forward);
286 }
287
288 static void section_on_leave_focus(struct dialog *dia)
289 {
290         struct dialog_section *section = dia->current_section;
291
292         if (section->ops->on_leave_focus) {
293                 section->ops->on_leave_focus(dia, section);
294         }
295 }
296
297 static void section_set_next_focus(struct dialog *dia)
298 {
299         section_on_leave_focus(dia);
300
301         do {
302                 dia->current_section = dia->current_section->next;
303         } while (!section_on_focus(dia, true));
304 }
305
306 static void section_set_previous_focus(struct dialog *dia)
307 {
308         section_on_leave_focus(dia);
309
310         do {
311                 dia->current_section = dia->current_section->prev;
312         } while (!section_on_focus(dia, false));
313 }
314
315 WERROR dialog_create(struct dialog *dia)
316 {
317         WERROR rv = WERR_OK;
318         int row, col;
319         int nlines, ncols;
320         struct dialog_section *section;
321
322         nlines = 0;
323         ncols = 0;
324         SMB_ASSERT(dia->head_section != NULL);
325
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);
333
334         /* fill in widths for sections that expand */
335         section = dia->head_section;
336         do {
337                 if (section->ncols < 0) {
338                         section->ncols = ncols;
339                 }
340                 section = section->next;
341         } while (section != dia->head_section);
342
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_NOT_ENOUGH_MEMORY;
349                 goto fail;
350         }
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);
355         }
356         dia->window = newwin(nlines, ncols, dia->y, dia->x);
357         if (dia->window == NULL) {
358                 rv = WERR_NOT_ENOUGH_MEMORY;
359                 goto fail;
360         }
361         dia->panel = new_panel(dia->window);
362         if (dia->panel == NULL) {
363                 rv = WERR_NOT_ENOUGH_MEMORY;
364                 goto fail;
365         }
366
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);
381
382         /* create subwindows for each section */
383         row = 2;
384         section = dia->head_section;
385         do {
386                 col = 3;
387
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;
396                 }
397
398                 section->window = subpad(dia->pad, section->nlines,
399                                          section->ncols, row, col);
400                 if (section->window == NULL) {
401                         rv = WERR_NOT_ENOUGH_MEMORY;
402                         goto fail;
403                 }
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));
409
410         dia->current_section = dia->head_section;
411         section_set_next_focus(dia);
412
413 fail:
414         return rv;
415 }
416
417 void dialog_show(struct dialog *dia)
418 {
419         int nlines, ncols;
420         int pad_y, pad_x;
421         int y, x;
422         int rv;
423
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;
430         }
431         x = 0;
432         if (pad_x > ncols) {
433                 x = (pad_x - ncols) / 2;
434         }
435         rv = copywin(dia->pad, dia->window, y, x, 0, 0,
436                      nlines - 1, ncols - 1, false);
437         SMB_ASSERT(rv == OK);
438
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);
443 }
444
445 void dialog_destroy(struct dialog *dia)
446 {
447         struct dialog_section *section;
448
449         section = dia->head_section;
450         do {
451                 dialog_section_destroy(section);
452                 section = section->next;
453         } while (section != dia->head_section);
454
455         if (dia->panel) {
456                 del_panel(dia->panel);
457                 dia->panel = NULL;
458         }
459         if (dia->window) {
460                 delwin(dia->window);
461                 dia->window = NULL;
462         }
463 }
464
465 static int dialog_getch(struct dialog *dia)
466 {
467         int c;
468
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;
474
475                 getmaxyx(dia->window, win_nlines, win_ncols);
476                 getmaxyx(dia->pad, pad_nlines, pad_ncols);
477                 getbegyx(dia->window, y, x);
478
479                 nlines = pad_nlines;
480                 ncols = pad_ncols;
481
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;
490                                 }
491                         }
492                         if (ncols + x > COLS) {
493                                 if (ncols > COLS) {
494                                         x = 0;
495                                 } else {
496                                         x = COLS - ncols;
497                                 }
498                         }
499                 }
500                 if (nlines != win_nlines || ncols != win_ncols) {
501                         wresize(dia->window, nlines, ncols);
502                         replace_panel(dia->panel, dia->window);
503                 }
504                 move_panel(dia->panel, y, x);
505         }
506
507         return c;
508 }
509
510 bool dialog_handle_input(struct dialog *dia, WERROR *err,
511                          enum dialog_action *action)
512 {
513         int c;
514
515         *err = WERR_OK;
516
517         c = dialog_getch(dia);
518
519         switch (c) {
520         case '\t':
521                 if (!section_on_tab(dia)) {
522                         section_set_next_focus(dia);
523                 }
524                 break;
525         case KEY_BTAB:
526                 if (!section_on_btab(dia)) {
527                         section_set_previous_focus(dia);
528                 }
529                 break;
530         case KEY_UP:
531                 if (!section_on_up(dia)) {
532                         section_set_previous_focus(dia);
533                 }
534                 break;
535         case KEY_DOWN:
536                 if (!section_on_down(dia)) {
537                         section_set_next_focus(dia);
538                 }
539                 break;
540         case KEY_LEFT:
541                 if (!section_on_left(dia)) {
542                         section_set_previous_focus(dia);
543                 }
544                 break;
545         case KEY_RIGHT:
546                 if (!section_on_right(dia)) {
547                         section_set_next_focus(dia);
548                 }
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);
561                 }
562                 break;
563         case 27: /* ESC */
564                 return false;
565         default:
566                 section_on_input(dia, c);
567                 break;
568         }
569
570         return true;
571 }
572
573 void dialog_modal_loop(struct dialog *dia, WERROR *err,
574                        enum dialog_action *action)
575 {
576         do {
577                 dialog_show(dia);
578                 update_panels();
579                 doupdate();
580         } while (dialog_handle_input(dia, err, action));
581 }
582
583 /* text label */
584 struct dialog_section_label {
585         struct dialog_section section;
586         char **text;
587 };
588
589 static WERROR label_create(struct dialog *dia, struct dialog_section *section)
590 {
591         int row;
592         struct dialog_section_label *label =
593                 talloc_get_type_abort(section, struct dialog_section_label);
594
595         for (row = 0; row < section->nlines; ++row) {
596                 mvwaddstr(section->window, row, 0, label->text[row]);
597         }
598
599         return WERR_OK;
600 }
601
602 struct dialog_section_ops label_ops = {
603         .create = label_create,
604 };
605
606 static int label_free(struct dialog_section_label *label)
607 {
608         dialog_section_destroy(&label->section);
609         return 0;
610 }
611
612 struct dialog_section *dialog_section_label_new_va(TALLOC_CTX *ctx,
613                                                    const char *msg, va_list ap)
614 {
615         struct dialog_section_label *label;
616         char *tmp, *ptmp, *line, *saveptr;
617         int nlines, ncols;
618
619         label = talloc_zero(ctx, struct dialog_section_label);
620         if (label == NULL) {
621                 return NULL;
622         }
623         talloc_set_destructor(label, label_free);
624         tmp = talloc_vasprintf(label, msg, ap);
625         if (tmp == NULL) {
626                 goto fail;
627         }
628
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;
637                 }
638                 ncols = MAX(ncols, strlen(line));
639                 label->text[nlines] = talloc_strdup(label->text, line);
640                 if (label->text[nlines] == NULL) {
641                         goto fail;
642                 }
643         }
644         talloc_free(tmp);
645         dialog_section_init(&label->section, &label_ops, nlines, ncols);
646
647         return &label->section;
648
649 fail:
650         talloc_free(label);
651         return NULL;
652 }
653
654 struct dialog_section *dialog_section_label_new(TALLOC_CTX *ctx,
655                                                 const char *msg, ...)
656 {
657         va_list ap;
658         struct dialog_section *rv;
659
660         va_start(ap, msg);
661         rv = dialog_section_label_new_va(ctx, msg, ap);
662         va_end(ap);
663
664         return rv;
665 }
666
667 /* horizontal separator */
668 struct dialog_section_hsep {
669         struct dialog_section section;
670         int sep;
671 };
672
673 static WERROR hsep_create(struct dialog *dia, struct dialog_section *section)
674 {
675         int y, x;
676         struct dialog_section_hsep *hsep =
677                 talloc_get_type_abort(section, struct dialog_section_hsep);
678
679         whline(section->window, hsep->sep, section->ncols);
680
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);
689         }
690
691         return WERR_OK;
692 }
693
694 struct dialog_section_ops hsep_ops = {
695         .create = hsep_create
696 };
697
698 static int hsep_free(struct dialog_section_hsep *hsep)
699 {
700         dialog_section_destroy(&hsep->section);
701         return 0;
702 }
703
704 struct dialog_section *dialog_section_hsep_new(TALLOC_CTX *ctx, int sep)
705 {
706         struct dialog_section_hsep *hsep;
707
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;
713         }
714
715         return &hsep->section;
716 }
717
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;
724         int length;
725 };
726
727 static int get_cursor_col(struct dialog_section_text_field *field)
728 {
729         int col;
730
731         col = field->form->curcol + field->form->begincol;
732
733         return col;
734 }
735
736 static WERROR text_field_create(struct dialog *dia,
737                                 struct dialog_section *section)
738 {
739         struct dialog_section_text_field *text_field =
740                 talloc_get_type_abort(section, struct dialog_section_text_field);
741
742         text_field->field[0] = new_field(section->nlines, section->ncols,
743                                          0, 0, 0, 0);
744         if (text_field->field[0] == NULL) {
745                 return WERR_NOT_ENOUGH_MEMORY;
746         }
747         set_field_back(text_field->field[0], A_REVERSE);
748         set_field_opts(text_field->field[0], text_field->opts);
749
750         text_field->form = new_form(text_field->field);
751         if (text_field->form == NULL) {
752                 return WERR_NOT_ENOUGH_MEMORY;
753         }
754
755         set_form_win(text_field->form, dia->window);
756         set_form_sub(text_field->form, section->window);
757         set_current_field(text_field->form, text_field->field[0]);
758         post_form(text_field->form);
759
760         return WERR_OK;
761 }
762
763 static void text_field_destroy(struct dialog_section *section)
764 {
765         struct dialog_section_text_field *text_field =
766                 talloc_get_type_abort(section, struct dialog_section_text_field);
767
768         if (text_field->form) {
769                 unpost_form(text_field->form);
770                 free_form(text_field->form);
771                 text_field->form = NULL;
772         }
773         if (text_field->field[0]) {
774                 free_field(text_field->field[0]);
775                 text_field->field[0] = NULL;
776         }
777 }
778
779 static void text_field_on_input(struct dialog *dia,
780                                 struct dialog_section *section,
781                                 int c)
782 {
783         struct dialog_section_text_field *text_field =
784                 talloc_get_type_abort(section, struct dialog_section_text_field);
785
786         switch (c) {
787         case KEY_BACKSPACE:
788                 if (text_field->length) {
789                         text_field->length--;
790                 }
791                 form_driver(text_field->form, REQ_DEL_PREV);
792                 break;
793         case '\x7f':
794         case KEY_DC:
795                 if (text_field->length) {
796                         text_field->length--;
797                 }
798                 form_driver(text_field->form, REQ_DEL_CHAR);
799                 break;
800         default:
801                 text_field->length++;
802                 form_driver(text_field->form, c);
803                 break;
804         }
805 }
806
807 static bool text_field_on_up(struct dialog *dia,
808                              struct dialog_section *section)
809 {
810         struct dialog_section_text_field *text_field =
811                 talloc_get_type_abort(section, struct dialog_section_text_field);
812
813         if (section->nlines > 1) {
814                 form_driver(text_field->form, REQ_UP_CHAR);
815                 return true;
816         }
817         return false;
818 }
819
820 static bool text_field_on_down(struct dialog *dia,
821                                struct dialog_section *section)
822 {
823         struct dialog_section_text_field *text_field =
824                 talloc_get_type_abort(section, struct dialog_section_text_field);
825
826         if (section->nlines > 1) {
827                 form_driver(text_field->form, REQ_DOWN_CHAR);
828                 return true;
829         }
830         return false;
831 }
832
833 static bool text_field_on_left(struct dialog *dia,
834                                struct dialog_section *section)
835 {
836         struct dialog_section_text_field *text_field =
837                 talloc_get_type_abort(section, struct dialog_section_text_field);
838
839         form_driver(text_field->form, REQ_LEFT_CHAR);
840
841         return true;
842 }
843
844 static bool text_field_on_right(struct dialog *dia,
845                                 struct dialog_section *section)
846 {
847         struct dialog_section_text_field *text_field =
848                 talloc_get_type_abort(section, struct dialog_section_text_field);
849
850         if (section->nlines > 1 ||
851             get_cursor_col(text_field) < text_field->length) {
852                 form_driver(text_field->form, REQ_RIGHT_CHAR);
853         }
854
855         return true;
856 }
857
858 static enum dialog_action text_field_on_enter(struct dialog *dia,
859                                               struct dialog_section *section)
860 {
861         struct dialog_section_text_field *text_field =
862                 talloc_get_type_abort(section, struct dialog_section_text_field);
863
864         if (section->nlines > 1) {
865                 text_field->length += text_field->form->cols;
866                 form_driver(text_field->form, REQ_NEW_LINE);
867                 return DIALOG_IGNORE;
868         }
869
870         return DIALOG_OK;
871 }
872
873 static bool text_field_on_focus(struct dialog *dia,
874                                 struct dialog_section *section, bool forward)
875 {
876         struct dialog_section_text_field *text_field =
877                 talloc_get_type_abort(section, struct dialog_section_text_field);
878
879         pos_form_cursor(text_field->form);
880
881         return true;
882 }
883
884 struct dialog_section_ops text_field_ops = {
885         .create = text_field_create,
886         .destroy = text_field_destroy,
887         .on_input = text_field_on_input,
888         .on_up = text_field_on_up,
889         .on_down = text_field_on_down,
890         .on_left = text_field_on_left,
891         .on_right = text_field_on_right,
892         .on_enter = text_field_on_enter,
893         .on_focus = text_field_on_focus
894 };
895
896 static int text_field_free(struct dialog_section_text_field *text_field)
897 {
898         dialog_section_destroy(&text_field->section);
899         return 0;
900 }
901
902 struct dialog_section *dialog_section_text_field_new(TALLOC_CTX *ctx,
903                                                      int height, int width)
904 {
905         struct dialog_section_text_field *text_field;
906
907         text_field = talloc_zero(ctx, struct dialog_section_text_field);
908         if (text_field == NULL) {
909                 return NULL;
910         }
911         talloc_set_destructor(text_field, text_field_free);
912         dialog_section_init(&text_field->section, &text_field_ops,
913                             height, width);
914         text_field->opts = O_ACTIVE | O_PUBLIC | O_EDIT | O_VISIBLE | O_NULLOK;
915
916         return &text_field->section;
917 }
918
919 const char *dialog_section_text_field_get(TALLOC_CTX *ctx,
920                                           struct dialog_section *section)
921 {
922         struct dialog_section_text_field *text_field =
923                 talloc_get_type_abort(section, struct dialog_section_text_field);
924
925         form_driver(text_field->form, REQ_VALIDATION);
926
927         return string_trim(ctx, field_buffer(text_field->field[0], 0));
928 }
929
930 void dialog_section_text_field_set(struct dialog_section *section,
931                                    const char *s)
932 {
933         struct dialog_section_text_field *text_field =
934                 talloc_get_type_abort(section, struct dialog_section_text_field);
935
936         text_field->length = strlen(s);
937         set_field_buffer(text_field->field[0], 0, s);
938 }
939
940 const char **dialog_section_text_field_get_lines(TALLOC_CTX *ctx,
941                                                  struct dialog_section *section)
942 {
943         int rows, cols, max;
944         const char **arr;
945         size_t i;
946         const char *buf;
947         struct dialog_section_text_field *text_field =
948                 talloc_get_type_abort(section, struct dialog_section_text_field);
949
950         form_driver(text_field->form, REQ_VALIDATION);
951         buf = field_buffer(text_field->field[0], 0);
952
953         dynamic_field_info(text_field->field[0], &rows, &cols, &max);
954
955         arr = talloc_zero_array(ctx, const char *, rows + 1);
956         if (arr == NULL) {
957                 return NULL;
958         }
959         for (i = 0; *buf; ++i, buf += cols) {
960                 SMB_ASSERT(i < rows);
961                 arr[i] = string_trim_n(arr, buf, cols);
962         }
963
964         return arr;
965 }
966
967 WERROR dialog_section_text_field_set_lines(TALLOC_CTX *ctx,
968                                            struct dialog_section *section,
969                                            const char **array)
970 {
971         int rows, cols, max;
972         size_t padding, length, idx;
973         const char **arrayp;
974         char *buf = NULL;
975         struct dialog_section_text_field *text_field =
976                 talloc_get_type_abort(section, struct dialog_section_text_field);
977
978         dynamic_field_info(text_field->field[0], &rows, &cols, &max);
979         /* try to fit each string on it's own line. each line
980            needs to be padded with whitespace manually, since
981            ncurses fields do not have newlines. */
982         for (idx = 0, arrayp = array; *arrayp != NULL; ++arrayp) {
983                 length = MIN(strlen(*arrayp), cols);
984                 padding = cols - length;
985                 buf = talloc_realloc(ctx, buf, char,
986                                      talloc_array_length(buf) +
987                                      length + padding + 1);
988                 if (buf == NULL) {
989                         return WERR_NOT_ENOUGH_MEMORY;
990                 }
991                 memcpy(&buf[idx], *arrayp, length);
992                 idx += length;
993                 memset(&buf[idx], ' ', padding);
994                 idx += padding;
995                 buf[idx] = '\0';
996         }
997
998         set_field_buffer(text_field->field[0], 0, buf);
999         talloc_free(buf);
1000
1001         return WERR_OK;
1002 }
1003
1004 bool dialog_section_text_field_get_int(struct dialog_section *section,
1005                                        long long *out)
1006 {
1007         bool rv;
1008         const char *buf;
1009         char *endp;
1010         struct dialog_section_text_field *text_field =
1011                 talloc_get_type_abort(section, struct dialog_section_text_field);
1012
1013         form_driver(text_field->form, REQ_VALIDATION);
1014
1015         buf = string_trim(section, field_buffer(text_field->field[0], 0));
1016         if (buf == NULL) {
1017                 return false;
1018         }
1019         *out = strtoll(buf, &endp, 0);
1020         rv = true;
1021         if (endp == buf || endp == NULL || endp[0] != '\0') {
1022                 rv = false;
1023         }
1024
1025         return rv;
1026 }
1027
1028
1029 bool dialog_section_text_field_get_uint(struct dialog_section *section,
1030                                         unsigned long long *out)
1031 {
1032         bool rv;
1033         const char *buf;
1034         char *endp;
1035         struct dialog_section_text_field *text_field =
1036                 talloc_get_type_abort(section, struct dialog_section_text_field);
1037
1038         form_driver(text_field->form, REQ_VALIDATION);
1039
1040         buf = string_trim(section, field_buffer(text_field->field[0], 0));
1041         if (buf == NULL) {
1042                 return false;
1043         }
1044         *out = strtoull(buf, &endp, 0);
1045         rv = true;
1046         if (endp == buf || endp == NULL || endp[0] != '\0') {
1047                 rv = false;
1048         }
1049
1050         return rv;
1051 }
1052
1053 /* hex editor field */
1054 struct dialog_section_hexedit {
1055         struct dialog_section section;
1056         struct hexedit *buf;
1057 };
1058
1059 #define HEXEDIT_MIN_SIZE 1
1060 static WERROR hexedit_create(struct dialog *dia,
1061                                 struct dialog_section *section)
1062 {
1063         struct dialog_section_hexedit *hexedit =
1064                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1065
1066         hexedit->buf = hexedit_new(dia, section->window, NULL,
1067                                    HEXEDIT_MIN_SIZE);
1068         if (hexedit->buf == NULL) {
1069                 return WERR_NOT_ENOUGH_MEMORY;
1070         }
1071
1072         hexedit_refresh(hexedit->buf);
1073
1074         return WERR_OK;
1075 }
1076
1077 static void hexedit_destroy(struct dialog_section *section)
1078 {
1079         struct dialog_section_hexedit *hexedit =
1080                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1081
1082         if (hexedit->buf) {
1083                 TALLOC_FREE(hexedit->buf);
1084         }
1085 }
1086
1087 static void hexedit_on_input(struct dialog *dia,
1088                                 struct dialog_section *section,
1089                                 int c)
1090 {
1091         struct dialog_section_hexedit *hexedit =
1092                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1093
1094         switch (c) {
1095         case KEY_BACKSPACE:
1096                 hexedit_driver(hexedit->buf, HE_BACKSPACE);
1097                 break;
1098         case '\x7f':
1099         case KEY_DC:
1100                 hexedit_driver(hexedit->buf, HE_DELETE);
1101                 break;
1102         default:
1103                 hexedit_driver(hexedit->buf, c);
1104                 break;
1105         }
1106 }
1107
1108 static bool hexedit_on_up(struct dialog *dia,
1109                              struct dialog_section *section)
1110 {
1111         struct dialog_section_hexedit *hexedit =
1112                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1113
1114         hexedit_driver(hexedit->buf, HE_CURSOR_UP);
1115
1116         return true;
1117 }
1118
1119 static bool hexedit_on_down(struct dialog *dia,
1120                                struct dialog_section *section)
1121 {
1122         struct dialog_section_hexedit *hexedit =
1123                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1124
1125         hexedit_driver(hexedit->buf, HE_CURSOR_DOWN);
1126
1127         return true;
1128 }
1129
1130 static bool hexedit_on_left(struct dialog *dia,
1131                                struct dialog_section *section)
1132 {
1133         struct dialog_section_hexedit *hexedit =
1134                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1135
1136         hexedit_driver(hexedit->buf, HE_CURSOR_LEFT);
1137
1138         return true;
1139 }
1140
1141 static bool hexedit_on_right(struct dialog *dia,
1142                                 struct dialog_section *section)
1143 {
1144         struct dialog_section_hexedit *hexedit =
1145                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1146
1147         hexedit_driver(hexedit->buf, HE_CURSOR_RIGHT);
1148
1149         return true;
1150 }
1151
1152 static enum dialog_action hexedit_on_enter(struct dialog *dia,
1153                                               struct dialog_section *section)
1154 {
1155         return DIALOG_IGNORE;
1156 }
1157
1158 static bool hexedit_on_focus(struct dialog *dia,
1159                                 struct dialog_section *section, bool forward)
1160 {
1161         struct dialog_section_hexedit *hexedit =
1162                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1163
1164         hexedit_set_cursor(hexedit->buf);
1165
1166         return true;
1167 }
1168
1169 struct dialog_section_ops hexedit_ops = {
1170         .create = hexedit_create,
1171         .destroy = hexedit_destroy,
1172         .on_input = hexedit_on_input,
1173         .on_up = hexedit_on_up,
1174         .on_down = hexedit_on_down,
1175         .on_left = hexedit_on_left,
1176         .on_right = hexedit_on_right,
1177         .on_enter = hexedit_on_enter,
1178         .on_focus = hexedit_on_focus
1179 };
1180
1181 static int hexedit_free(struct dialog_section_hexedit *hexedit)
1182 {
1183         dialog_section_destroy(&hexedit->section);
1184         return 0;
1185 }
1186
1187 struct dialog_section *dialog_section_hexedit_new(TALLOC_CTX *ctx, int height)
1188 {
1189         struct dialog_section_hexedit *hexedit;
1190
1191         hexedit = talloc_zero(ctx, struct dialog_section_hexedit);
1192         if (hexedit == NULL) {
1193                 return NULL;
1194         }
1195         talloc_set_destructor(hexedit, hexedit_free);
1196         dialog_section_init(&hexedit->section, &hexedit_ops,
1197                             height, LINE_WIDTH);
1198
1199         return &hexedit->section;
1200 }
1201
1202 WERROR dialog_section_hexedit_set_buf(struct dialog_section *section,
1203                                       const void *data, size_t size)
1204 {
1205         WERROR rv;
1206         struct dialog_section_hexedit *hexedit =
1207                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1208
1209         SMB_ASSERT(hexedit->buf != NULL);
1210
1211         rv = hexedit_set_buf(hexedit->buf, data, size);
1212         if (W_ERROR_IS_OK(rv)) {
1213                 hexedit_refresh(hexedit->buf);
1214                 hexedit_set_cursor(hexedit->buf);
1215         }
1216
1217         return rv;
1218 }
1219
1220 void dialog_section_hexedit_get_buf(struct dialog_section *section,
1221                                     const void **data, size_t *size)
1222 {
1223         struct dialog_section_hexedit *hexedit =
1224                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1225
1226         SMB_ASSERT(hexedit->buf != NULL);
1227         *data = hexedit_get_buf(hexedit->buf);
1228         *size = hexedit_get_buf_len(hexedit->buf);
1229 }
1230
1231 WERROR dialog_section_hexedit_resize(struct dialog_section *section,
1232                                      size_t size)
1233 {
1234         WERROR rv;
1235         struct dialog_section_hexedit *hexedit =
1236                 talloc_get_type_abort(section, struct dialog_section_hexedit);
1237
1238         SMB_ASSERT(hexedit->buf != NULL);
1239         rv = hexedit_resize_buffer(hexedit->buf, size);
1240         if (W_ERROR_IS_OK(rv)) {
1241                 hexedit_refresh(hexedit->buf);
1242         }
1243
1244         return rv;
1245 }
1246
1247
1248 /* button box */
1249 struct dialog_section_buttons {
1250         struct dialog_section section;
1251         struct button_spec *spec;
1252         int current_button;
1253 };
1254
1255 static void buttons_unhighlight(struct dialog_section_buttons *buttons)
1256 {
1257         short pair;
1258         attr_t attr;
1259
1260         /*
1261          *  Some GCC versions will complain if the macro version of
1262          *  wattr_get is used. So we should enforce the use of the
1263          *  function instead. See:
1264          *  http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1265          */
1266         (wattr_get)(buttons->section.window, &attr, &pair, NULL);
1267         mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL);
1268         wnoutrefresh(buttons->section.window);
1269 }
1270
1271 static void buttons_highlight(struct dialog_section_buttons *buttons)
1272 {
1273         struct button_spec *spec = &buttons->spec[buttons->current_button];
1274         short pair;
1275         attr_t attr;
1276
1277         /*
1278          *  Some GCC versions will complain if the macro version of
1279          *  wattr_get is used. So we should enforce the use of the
1280          *  function instead. See:
1281          *  http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1282          */
1283         (wattr_get)(buttons->section.window, &attr, &pair, NULL);
1284         mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL);
1285         mvwchgat(buttons->section.window, 0, spec->col,
1286                  strlen(spec->label), A_REVERSE, pair, NULL);
1287         wmove(buttons->section.window, 0, spec->col + 2);
1288         wcursyncup(buttons->section.window);
1289         wnoutrefresh(buttons->section.window);
1290 }
1291
1292 static bool buttons_highlight_next(struct dialog_section_buttons *buttons)
1293 {
1294         if (buttons->current_button < talloc_array_length(buttons->spec) - 1) {
1295                 buttons->current_button++;
1296                 buttons_highlight(buttons);
1297                 return true;
1298         }
1299         return false;
1300 }
1301
1302 static bool buttons_highlight_previous(struct dialog_section_buttons *buttons)
1303 {
1304         if (buttons->current_button > 0) {
1305                 buttons->current_button--;
1306                 buttons_highlight(buttons);
1307                 return true;
1308         }
1309         return false;
1310 }
1311
1312 static WERROR buttons_create(struct dialog *dia,
1313                                 struct dialog_section *section)
1314 {
1315         size_t i, nbuttons;
1316         struct dialog_section_buttons *buttons =
1317                 talloc_get_type_abort(section, struct dialog_section_buttons);
1318
1319         nbuttons = talloc_array_length(buttons->spec);
1320         for (i = 0; i < nbuttons; ++i) {
1321                 struct button_spec *spec = &buttons->spec[i];
1322                 mvwaddstr(section->window, 0, spec->col, spec->label);
1323         }
1324
1325         buttons->current_button = 0;
1326
1327         return WERR_OK;
1328 }
1329
1330 static bool buttons_on_btab(struct dialog *dia, struct dialog_section *section)
1331 {
1332         struct dialog_section_buttons *buttons =
1333                 talloc_get_type_abort(section, struct dialog_section_buttons);
1334
1335         return buttons_highlight_previous(buttons);
1336 }
1337
1338 static bool buttons_on_tab(struct dialog *dia, struct dialog_section *section)
1339 {
1340         struct dialog_section_buttons *buttons =
1341                 talloc_get_type_abort(section, struct dialog_section_buttons);
1342
1343         return buttons_highlight_next(buttons);
1344 }
1345
1346 static enum dialog_action buttons_on_enter(struct dialog *dia,
1347                                            struct dialog_section *section)
1348 {
1349         struct dialog_section_buttons *buttons =
1350                 talloc_get_type_abort(section, struct dialog_section_buttons);
1351         struct button_spec *spec = &buttons->spec[buttons->current_button];
1352
1353         if (spec->on_enter) {
1354                 return spec->on_enter(dia, section);
1355         }
1356
1357         return spec->action;
1358 }
1359
1360 static bool buttons_on_focus(struct dialog *dia,
1361                                 struct dialog_section *section,
1362                                 bool forward)
1363 {
1364         struct dialog_section_buttons *buttons =
1365                 talloc_get_type_abort(section, struct dialog_section_buttons);
1366
1367         if (forward) {
1368                 buttons->current_button = 0;
1369         } else {
1370                 buttons->current_button = talloc_array_length(buttons->spec) - 1;
1371         }
1372         buttons_highlight(buttons);
1373
1374         return true;
1375 }
1376
1377 static void buttons_on_leave_focus(struct dialog *dia,
1378                                 struct dialog_section *section)
1379 {
1380         struct dialog_section_buttons *buttons =
1381                 talloc_get_type_abort(section, struct dialog_section_buttons);
1382         buttons_unhighlight(buttons);
1383 }
1384
1385 struct dialog_section_ops buttons_ops = {
1386         .create = buttons_create,
1387         .on_tab = buttons_on_tab,
1388         .on_btab = buttons_on_btab,
1389         .on_up = buttons_on_btab,
1390         .on_down = buttons_on_tab,
1391         .on_left = buttons_on_btab,
1392         .on_right = buttons_on_tab,
1393         .on_enter = buttons_on_enter,
1394         .on_focus = buttons_on_focus,
1395         .on_leave_focus = buttons_on_leave_focus
1396 };
1397
1398 static int buttons_free(struct dialog_section_buttons *buttons)
1399 {
1400         dialog_section_destroy(&buttons->section);
1401         return 0;
1402 }
1403
1404 struct dialog_section *dialog_section_buttons_new(TALLOC_CTX *ctx,
1405                                                   const struct button_spec *spec)
1406 {
1407         struct dialog_section_buttons *buttons;
1408         size_t i, nbuttons;
1409         int width;
1410
1411         buttons = talloc_zero(ctx, struct dialog_section_buttons);
1412         if (buttons == NULL) {
1413                 return NULL;
1414         }
1415         talloc_set_destructor(buttons, buttons_free);
1416
1417         for (nbuttons = 0; spec[nbuttons].label; ++nbuttons) {
1418         }
1419         buttons->spec = talloc_zero_array(buttons, struct button_spec, nbuttons);
1420         if (buttons->spec == NULL) {
1421                 goto fail;
1422         }
1423
1424         for (width = 0, i = 0; i < nbuttons; ++i) {
1425                 buttons->spec[i] = spec[i];
1426                 buttons->spec[i].label = talloc_asprintf(buttons->spec,
1427                                                          "[ %s ]",
1428                                                          spec[i].label);
1429                 if (!buttons->spec[i].label) {
1430                         goto fail;
1431                 }
1432
1433                 buttons->spec[i].col = width;
1434                 width += strlen(buttons->spec[i].label);
1435                 if (i != nbuttons - 1) {
1436                         ++width;
1437                 }
1438         }
1439
1440         dialog_section_init(&buttons->section, &buttons_ops, 1, width);
1441
1442         return &buttons->section;
1443
1444 fail:
1445         talloc_free(buttons);
1446         return NULL;
1447 }
1448
1449 /* options */
1450 struct dialog_section_options {
1451         struct dialog_section section;
1452         struct option_spec *spec;
1453         int current_option;
1454         bool single_select;
1455 };
1456
1457 static void options_unhighlight(struct dialog_section_options *options)
1458 {
1459         short pair;
1460         attr_t attr;
1461         size_t row;
1462
1463         /*
1464          *  Some GCC versions will complain if the macro version of
1465          *  wattr_get is used. So we should enforce the use of the
1466          *  function instead. See:
1467          *  http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1468          */
1469         (wattr_get)(options->section.window, &attr, &pair, NULL);
1470         for (row = 0; row < options->section.nlines; ++row) {
1471                 mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL);
1472         }
1473         wnoutrefresh(options->section.window);
1474 }
1475
1476 static void options_highlight(struct dialog_section_options *options)
1477 {
1478         struct option_spec *spec = &options->spec[options->current_option];
1479         short pair;
1480         attr_t attr;
1481         size_t row;
1482
1483         /*
1484          *  Some GCC versions will complain if the macro version of
1485          *  wattr_get is used. So we should enforce the use of the
1486          *  function instead. See:
1487          *  http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1488          */
1489         (wattr_get)(options->section.window, &attr, &pair, NULL);
1490         for (row = 0; row < options->section.nlines; ++row) {
1491                 mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL);
1492         }
1493         mvwchgat(options->section.window, spec->row, spec->col,
1494                  strlen(spec->label), A_REVERSE, pair, NULL);
1495         wmove(options->section.window, spec->row, spec->col + 4);
1496         wcursyncup(options->section.window);
1497         wnoutrefresh(options->section.window);
1498 }
1499
1500 static void options_render_state(struct dialog_section_options *options)
1501 {
1502         size_t i, noptions;
1503
1504         noptions = talloc_array_length(options->spec);
1505         for (i = 0; i < noptions; ++i) {
1506                 struct option_spec *spec = &options->spec[i];
1507                 char c = ' ';
1508                 if (*spec->state)
1509                         c = 'x';
1510                 mvwaddch(options->section.window,
1511                          spec->row, spec->col + 1, c);
1512                 wnoutrefresh(options->section.window);
1513         }
1514 }
1515
1516 static bool options_highlight_next(struct dialog_section_options *options)
1517 {
1518         if (options->current_option < talloc_array_length(options->spec) - 1) {
1519                 options->current_option++;
1520                 options_highlight(options);
1521                 return true;
1522         }
1523         return false;
1524 }
1525
1526 static bool options_highlight_previous(struct dialog_section_options *options)
1527 {
1528         if (options->current_option > 0) {
1529                 options->current_option--;
1530                 options_highlight(options);
1531                 return true;
1532         }
1533         return false;
1534 }
1535
1536 static WERROR options_create(struct dialog *dia,
1537                              struct dialog_section *section)
1538 {
1539         size_t i, noptions;
1540         struct dialog_section_options *options =
1541                 talloc_get_type_abort(section, struct dialog_section_options);
1542
1543         noptions = talloc_array_length(options->spec);
1544         for (i = 0; i < noptions; ++i) {
1545                 struct option_spec *spec = &options->spec[i];
1546                 mvwaddstr(section->window, spec->row, spec->col,
1547                           spec->label);
1548         }
1549
1550         options->current_option = 0;
1551         options_render_state(options);
1552
1553         return WERR_OK;
1554 }
1555
1556 static bool options_on_btab(struct dialog *dia, struct dialog_section *section)
1557 {
1558         struct dialog_section_options *options =
1559                 talloc_get_type_abort(section, struct dialog_section_options);
1560
1561         return options_highlight_previous(options);
1562 }
1563
1564 static bool options_on_tab(struct dialog *dia, struct dialog_section *section)
1565 {
1566         struct dialog_section_options *options =
1567                 talloc_get_type_abort(section, struct dialog_section_options);
1568
1569         return options_highlight_next(options);
1570 }
1571
1572 static void options_on_input(struct dialog *dia, struct dialog_section *section, int c)
1573 {
1574         struct dialog_section_options *options =
1575                 talloc_get_type_abort(section, struct dialog_section_options);
1576
1577         if (c == ' ') {
1578                 struct option_spec *spec = &options->spec[options->current_option];
1579                 if (options->single_select) {
1580                         size_t i, noptions;
1581                         noptions = talloc_array_length(options->spec);
1582                         for (i = 0; i < noptions; ++i) {
1583                                 *(options->spec[i].state) = false;
1584                         }
1585                 }
1586                 *spec->state = !*spec->state;
1587                 options_unhighlight(options);
1588                 options_render_state(options);
1589                 options_highlight(options);
1590         }
1591 }
1592
1593 static enum dialog_action options_on_enter(struct dialog *dia, struct dialog_section *section)
1594 {
1595         options_on_input(dia, section, ' ');
1596         return DIALOG_OK;
1597 }
1598
1599 static bool options_on_focus(struct dialog *dia,
1600                                 struct dialog_section *section,
1601                                 bool forward)
1602 {
1603         struct dialog_section_options *options =
1604                 talloc_get_type_abort(section, struct dialog_section_options);
1605
1606         if (forward) {
1607                 options->current_option = 0;
1608         } else {
1609                 options->current_option = talloc_array_length(options->spec) - 1;
1610         }
1611         options_highlight(options);
1612
1613         return true;
1614 }
1615
1616 static void options_on_leave_focus(struct dialog *dia,
1617                                 struct dialog_section *section)
1618 {
1619         struct dialog_section_options *options =
1620                 talloc_get_type_abort(section, struct dialog_section_options);
1621         options_unhighlight(options);
1622 }
1623
1624 struct dialog_section_ops options_ops = {
1625         .create = options_create,
1626         .on_tab = options_on_tab,
1627         .on_btab = options_on_btab,
1628         .on_up = options_on_btab,
1629         .on_down = options_on_tab,
1630         .on_left = options_on_btab,
1631         .on_right = options_on_tab,
1632         .on_input = options_on_input,
1633         .on_enter = options_on_enter,
1634         .on_focus = options_on_focus,
1635         .on_leave_focus = options_on_leave_focus
1636 };
1637
1638 static int options_free(struct dialog_section_options *options)
1639 {
1640         dialog_section_destroy(&options->section);
1641         return 0;
1642 }
1643
1644 struct dialog_section *dialog_section_options_new(TALLOC_CTX *ctx,
1645                                                   const struct option_spec *spec,
1646                                                   int maxcol, bool single_select)
1647 {
1648         struct dialog_section_options *options;
1649         size_t i, noptions;
1650         int width, maxwidth, maxrows;
1651
1652         options = talloc_zero(ctx, struct dialog_section_options);
1653         if (options == NULL) {
1654                 return NULL;
1655         }
1656         talloc_set_destructor(options, options_free);
1657
1658         for (noptions = 0; spec[noptions].label; ++noptions) {
1659         }
1660         options->spec = talloc_zero_array(options, struct option_spec, noptions);
1661         if (options->spec == NULL) {
1662                 goto fail;
1663         }
1664
1665         maxrows = noptions / maxcol;
1666         if (noptions % maxcol) {
1667                 ++maxrows;
1668         }
1669
1670         for (width = 0, maxwidth = 0, i = 0; i < noptions; ++i) {
1671                 options->spec[i] = spec[i];
1672                 options->spec[i].label = talloc_asprintf(options->spec,
1673                                                          "[ ] %s",
1674                                                          spec[i].label);
1675                 if (!options->spec[i].label) {
1676                         goto fail;
1677                 }
1678
1679                 options->spec[i].col = maxwidth;
1680                 options->spec[i].row = i % maxrows;
1681                 width = MAX(strlen(options->spec[i].label), width);
1682                 if (options->spec[i].row == maxrows - 1 || i == noptions - 1) {
1683                         maxwidth += width + 1;
1684                         width = 0;
1685                 }
1686         }
1687
1688         dialog_section_init(&options->section, &options_ops, maxrows, maxwidth - 1);
1689         options->single_select = single_select;
1690
1691         return &options->section;
1692
1693 fail:
1694         talloc_free(options);
1695         return NULL;
1696 }
1697
1698
1699 enum input_type {
1700         DLG_IN_LONG,
1701         DLG_IN_ULONG,
1702         DLG_IN_STR,
1703 };
1704
1705 struct input_req {
1706         TALLOC_CTX *ctx;
1707         enum input_type type;
1708         union {
1709                 void *out;
1710                 unsigned long *out_ulong;
1711                 long *out_long;
1712                 const char **out_str;
1713         } out;
1714 };
1715
1716 static bool input_on_submit(struct dialog *dia, struct dialog_section *section,
1717                             void *arg)
1718 {
1719         struct input_req *req = arg;
1720         struct dialog_section *data;
1721         unsigned long long out_ulong;
1722         long long out_long;
1723
1724         data = dialog_find_section(dia, "input");
1725
1726         switch (req->type) {
1727         case DLG_IN_LONG:
1728                 if (!dialog_section_text_field_get_int(data, &out_long)) {
1729                         dialog_notice(dia, DIA_ALERT, "Error",
1730                                       "Input must be a number.");
1731                         return false;
1732                 }
1733                 if (out_long < LONG_MIN || out_long > LONG_MAX) {
1734                         dialog_notice(dia, DIA_ALERT, "Error",
1735                                       "Number is out of range.");
1736                         return false;
1737                 }
1738                 *req->out.out_long = out_long;
1739                 break;
1740         case DLG_IN_ULONG:
1741                 if (!dialog_section_text_field_get_uint(data, &out_ulong)) {
1742                         dialog_notice(dia, DIA_ALERT, "Error",
1743                                       "Input must be a number greater than zero.");
1744                         return false;
1745                 }
1746                 if (out_ulong > ULONG_MAX) {
1747                         dialog_notice(dia, DIA_ALERT, "Error",
1748                                       "Number is out of range.");
1749                         return false;
1750                 }
1751                 *req->out.out_ulong = out_ulong;
1752                 break;
1753         case DLG_IN_STR:
1754                 *req->out.out_str = dialog_section_text_field_get(req->ctx, data);
1755                 break;
1756         }
1757
1758         return true;
1759 }
1760
1761 static int dialog_input_internal(TALLOC_CTX *ctx, void *output,
1762                                  enum input_type type,
1763                                  const char *title,
1764                                  const char *msg, va_list ap)
1765                                  PRINTF_ATTRIBUTE(5,0);
1766
1767 static int dialog_input_internal(TALLOC_CTX *ctx, void *output,
1768                                  enum input_type type,
1769                                  const char *title,
1770                                  const char *msg, va_list ap)
1771 {
1772         WERROR err;
1773         struct input_req req;
1774         enum dialog_action action;
1775         struct dialog *dia;
1776         struct dialog_section *section;
1777         struct button_spec spec[] = {
1778                 {.label = "OK", .action = DIALOG_OK},
1779                 {.label = "Cancel", .action = DIALOG_CANCEL},
1780                 { 0 }
1781         };
1782
1783         req.ctx = ctx;
1784         req.type = type;
1785         req.out.out = output;
1786         *req.out.out_str = NULL;
1787
1788         dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1);
1789         dialog_set_submit_cb(dia, input_on_submit, &req);
1790         section = dialog_section_label_new_va(dia, msg, ap);
1791         dialog_append_section(dia, section);
1792         section = dialog_section_hsep_new(dia, ' ');
1793         dialog_append_section(dia, section);
1794         section = dialog_section_text_field_new(dia, 1, -1);
1795         dialog_section_set_name(section, "input");
1796         dialog_append_section(dia, section);
1797         section = dialog_section_hsep_new(dia, 0);
1798         dialog_append_section(dia, section);
1799         section = dialog_section_buttons_new(dia, spec);
1800         dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
1801         dialog_append_section(dia, section);
1802
1803         dialog_create(dia);
1804         dialog_show(dia);
1805         dialog_modal_loop(dia, &err, &action);
1806         talloc_free(dia);
1807
1808         return action;
1809 }
1810
1811 int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title,
1812                  const char *msg, ...)
1813 {
1814         va_list ap;
1815         int rv;
1816
1817         va_start(ap, msg);
1818         rv = dialog_input_internal(ctx, output, DLG_IN_STR, title, msg, ap);
1819         va_end(ap);
1820
1821         return rv;
1822 }
1823
1824 int dialog_input_ulong(TALLOC_CTX *ctx, unsigned long *output,
1825                        const char *title, const char *msg, ...)
1826 {
1827         va_list ap;
1828         int rv;
1829
1830         va_start(ap, msg);
1831         rv = dialog_input_internal(ctx, output, DLG_IN_ULONG, title, msg, ap);
1832         va_end(ap);
1833
1834         return rv;
1835 }
1836
1837 int dialog_input_long(TALLOC_CTX *ctx, long *output,
1838                       const char *title, const char *msg, ...)
1839 {
1840         va_list ap;
1841         int rv;
1842
1843         va_start(ap, msg);
1844         rv = dialog_input_internal(ctx, output, DLG_IN_LONG, title, msg, ap);
1845         va_end(ap);
1846
1847         return rv;
1848 }
1849
1850 int dialog_notice(TALLOC_CTX *ctx, enum dialog_type type,
1851                   const char *title, const char *msg, ...)
1852 {
1853         va_list ap;
1854         WERROR err;
1855         enum dialog_action action;
1856         struct dialog *dia;
1857         struct dialog_section *section;
1858         struct button_spec spec[3];
1859
1860         memset(&spec, '\0', sizeof(spec));
1861         spec[0].label = "OK";
1862         spec[0].action = DIALOG_OK;
1863         if (type == DIA_CONFIRM) {
1864                 spec[1].label = "Cancel";
1865                 spec[1].action = DIALOG_CANCEL;
1866         }
1867
1868         dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1);
1869         va_start(ap, msg);
1870         section = dialog_section_label_new_va(dia, msg, ap);
1871         va_end(ap);
1872         dialog_append_section(dia, section);
1873         section = dialog_section_hsep_new(dia, 0);
1874         dialog_append_section(dia, section);
1875         section = dialog_section_buttons_new(dia, spec);
1876         dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
1877         dialog_append_section(dia, section);
1878
1879         dialog_create(dia);
1880         dialog_show(dia);
1881         dialog_modal_loop(dia, &err, &action);
1882         talloc_free(dia);
1883
1884         return action;
1885 }
1886
1887
1888 struct edit_req {
1889         uint32_t type;
1890         uint32_t mode;
1891         struct registry_key *key;
1892         const struct value_item *vitem;
1893 };
1894
1895 static WERROR fill_value_buffer(struct dialog *dia, struct edit_req *edit)
1896 {
1897         char *tmp;
1898         struct dialog_section *data;
1899
1900         if (edit->vitem == NULL) {
1901                 return WERR_OK;
1902         }
1903
1904         data = dialog_find_section(dia, "data");
1905         SMB_ASSERT(data != NULL);
1906
1907         switch (edit->mode) {
1908         case REG_DWORD: {
1909                 uint32_t v = 0;
1910                 if (edit->vitem->data.length >= 4) {
1911                         v = IVAL(edit->vitem->data.data, 0);
1912                 }
1913                 tmp = talloc_asprintf(dia, "%u", (unsigned)v);
1914                 if (tmp == NULL) {
1915                         return WERR_NOT_ENOUGH_MEMORY;
1916                 }
1917                 dialog_section_text_field_set(data, tmp);
1918                 talloc_free(tmp);
1919                 break;
1920         }
1921         case REG_SZ:
1922         case REG_EXPAND_SZ: {
1923                 const char *s;
1924
1925                 if (!pull_reg_sz(dia, &edit->vitem->data, &s)) {
1926                         return WERR_NOT_ENOUGH_MEMORY;
1927                 }
1928                 dialog_section_text_field_set(data, s);
1929                 break;
1930         }
1931         case REG_MULTI_SZ: {
1932                 const char **array;
1933
1934                 if (!pull_reg_multi_sz(dia, &edit->vitem->data, &array)) {
1935                         return WERR_NOT_ENOUGH_MEMORY;
1936                 }
1937                 return dialog_section_text_field_set_lines(dia, data, array);
1938         }
1939         case REG_BINARY:
1940         default:
1941                 return dialog_section_hexedit_set_buf(data,
1942                                                       edit->vitem->data.data,
1943                                                       edit->vitem->data.length);
1944         }
1945
1946         return WERR_OK;
1947 }
1948
1949 static bool value_exists(TALLOC_CTX *ctx, const struct registry_key *key,
1950                          const char *name)
1951 {
1952         uint32_t type;
1953         DATA_BLOB blob;
1954         WERROR rv;
1955
1956         rv = reg_key_get_value_by_name(ctx, key, name, &type, &blob);
1957
1958         return W_ERROR_IS_OK(rv);
1959 }
1960
1961 static bool edit_on_submit(struct dialog *dia, struct dialog_section *section,
1962                            void *arg)
1963 {
1964         struct edit_req *edit = arg;
1965         WERROR rv;
1966         DATA_BLOB blob;
1967         const char *name;
1968         struct dialog_section *name_section, *data;
1969
1970         name_section = dialog_find_section(dia, "name");
1971         if (name_section) {
1972                 name = dialog_section_text_field_get(dia, name_section);
1973                 if (*name == '\0') {
1974                         dialog_notice(dia, DIA_ALERT, "Error",
1975                                       "Value name must not be blank.");
1976                         return false;
1977                 }
1978                 if (value_exists(dia, edit->key, name)) {
1979                         dialog_notice(dia, DIA_ALERT, "Error",
1980                                       "Value named \"%s\" already exists.",
1981                                       name);
1982                         return false;
1983                 }
1984         } else {
1985                 SMB_ASSERT(edit->vitem);
1986                 name = edit->vitem->value_name;
1987         }
1988         SMB_ASSERT(name);
1989
1990         data = dialog_find_section(dia, "data");
1991         SMB_ASSERT(data != NULL);
1992
1993         rv = WERR_OK;
1994         switch (edit->mode) {
1995         case REG_DWORD: {
1996                 unsigned long long v;
1997                 uint32_t val;
1998
1999                 if (!dialog_section_text_field_get_uint(data, &v)) {
2000                         dialog_notice(dia, DIA_ALERT, "Error",
2001                                       "REG_DWORD value must be an integer.");
2002                         return false;
2003                 }
2004                 if (v > UINT32_MAX) {
2005                         dialog_notice(dia, DIA_ALERT, "Error",
2006                                       "REG_DWORD value must less than %lu.",
2007                                       (unsigned long)UINT32_MAX);
2008                         return false;
2009                 }
2010                 val = (uint32_t)v;
2011                 blob = data_blob_talloc(dia, NULL, sizeof(val));
2012                 SIVAL(blob.data, 0, val);
2013                 break;
2014         }
2015         case REG_SZ:
2016         case REG_EXPAND_SZ: {
2017                 const char *buf;
2018
2019                 buf = dialog_section_text_field_get(dia, data);
2020                 if (!buf || !push_reg_sz(dia, &blob, buf)) {
2021                         rv = WERR_NOT_ENOUGH_MEMORY;
2022                 }
2023                 break;
2024         }
2025         case REG_MULTI_SZ: {
2026                 const char **lines;
2027
2028                 lines = dialog_section_text_field_get_lines(dia, data);
2029                 if (!lines || !push_reg_multi_sz(dia, &blob, lines)) {
2030                         rv = WERR_NOT_ENOUGH_MEMORY;
2031                 }
2032                 break;
2033         }
2034         case REG_BINARY: {
2035                 const void *buf;
2036                 size_t len;
2037
2038                 dialog_section_hexedit_get_buf(data, &buf, &len);
2039                 blob = data_blob_talloc(dia, buf, len);
2040                 break;
2041         }
2042         }
2043
2044         if (W_ERROR_IS_OK(rv)) {
2045                 rv = reg_val_set(edit->key, name, edit->type, blob);
2046         }
2047
2048         if (!W_ERROR_IS_OK(rv)) {
2049                 const char *msg = get_friendly_werror_msg(rv);
2050                 dialog_notice(dia, DIA_ALERT, "Error",
2051                               "Error saving value:\n%s", msg);
2052
2053                 return false;
2054         }
2055
2056         return true;
2057
2058 }
2059
2060 static enum dialog_action edit_on_resize(struct dialog *dia,
2061                                           struct dialog_section *section)
2062 {
2063         struct dialog_section *data;
2064         unsigned long size;
2065         int rv;
2066
2067         data = dialog_find_section(dia, "data");
2068         rv = dialog_input_ulong(dia, &size, "Resize", "Enter size of buffer");
2069         if (rv == DIALOG_OK) {
2070                 dialog_section_hexedit_resize(data, size);
2071         }
2072
2073         return DIALOG_IGNORE;
2074 }
2075
2076 int dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key,
2077                       uint32_t type, const struct value_item *vitem,
2078                       bool force_binary, WERROR *err,
2079                       const char **name)
2080 {
2081         enum dialog_action action;
2082         struct dialog *dia;
2083         struct dialog_section *section;
2084         struct edit_req edit;
2085         struct button_spec buttons[] = {
2086                 {.label = "OK", .action = DIALOG_OK},
2087                 {.label = "Cancel", .action = DIALOG_CANCEL},
2088                 { 0 }
2089         };
2090         struct button_spec buttons_hexedit[] = {
2091                 {.label = "OK", .action = DIALOG_OK},
2092                 {.label = "Resize Buffer", .on_enter = edit_on_resize},
2093                 {.label = "Cancel", .action = DIALOG_CANCEL},
2094                 { 0 }
2095         };
2096
2097
2098         edit.key = key;
2099         edit.vitem = vitem;
2100         edit.type = type;
2101         edit.mode = type;
2102         if (force_binary || (vitem && vitem->unprintable)) {
2103                 edit.mode = REG_BINARY;
2104         }
2105
2106         dia = dialog_new(ctx, PAIR_BLACK_CYAN, "Edit Value", -1, -1);
2107         dialog_set_submit_cb(dia, edit_on_submit, &edit);
2108
2109         section = dialog_section_label_new(dia, "Type");
2110         dialog_append_section(dia, section);
2111         section = dialog_section_label_new(dia, "%s",
2112                                            str_regtype(type));
2113         dialog_append_section(dia, section);
2114         section = dialog_section_hsep_new(dia, ' ');
2115         dialog_append_section(dia, section);
2116
2117         section = dialog_section_label_new(dia, "Name");
2118         dialog_append_section(dia, section);
2119         if (vitem) {
2120                 section = dialog_section_label_new(dia, "%s",
2121                                                    vitem->value_name);
2122         } else {
2123                 section = dialog_section_text_field_new(dia, 1, 50);
2124                 dialog_section_set_name(section, "name");
2125         }
2126         dialog_append_section(dia, section);
2127         section = dialog_section_hsep_new(dia, ' ');
2128         dialog_append_section(dia, section);
2129
2130         section = dialog_section_label_new(dia, "Data");
2131         dialog_append_section(dia, section);
2132
2133         switch (edit.mode) {
2134         case REG_DWORD:
2135         case REG_SZ:
2136         case REG_EXPAND_SZ:
2137                 section = dialog_section_text_field_new(dia, 1, 50);
2138                 break;
2139         case REG_MULTI_SZ:
2140                 section = dialog_section_text_field_new(dia, 10, 50);
2141                 break;
2142         case REG_BINARY:
2143         default:
2144                 section = dialog_section_hexedit_new(dia, 10);
2145                 break;
2146         }
2147
2148         dialog_section_set_name(section, "data");
2149         dialog_append_section(dia, section);
2150
2151         section = dialog_section_hsep_new(dia, 0);
2152         dialog_append_section(dia, section);
2153         if (edit.mode == REG_BINARY) {
2154                 section = dialog_section_buttons_new(dia, buttons_hexedit);
2155         } else {
2156                 section = dialog_section_buttons_new(dia, buttons);
2157         }
2158         dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2159         dialog_append_section(dia, section);
2160
2161         dialog_create(dia);
2162
2163         *err = fill_value_buffer(dia, &edit);
2164         if (!W_ERROR_IS_OK(*err)) {
2165                 return DIALOG_CANCEL;
2166         }
2167
2168         dialog_show(dia);
2169         dialog_modal_loop(dia, err, &action);
2170
2171         if (action == DIALOG_OK && name) {
2172                 if (vitem) {
2173                         *name = talloc_strdup(ctx, vitem->value_name);
2174                 } else if ((section = dialog_find_section(dia, "name"))) {
2175                         *name = dialog_section_text_field_get(ctx, section);
2176                 }
2177         }
2178
2179         talloc_free(dia);
2180
2181         return action;
2182 }
2183
2184 int dialog_select_type(TALLOC_CTX *ctx, int *type)
2185 {
2186         WERROR err;
2187         enum dialog_action action;
2188         struct dialog *dia;
2189         struct dialog_section *section;
2190         const char *reg_types[] = {
2191                 "REG_BINARY",
2192                 "REG_DWORD",
2193                 "REG_EXPAND_SZ",
2194                 "REG_MULTI_SZ",
2195                 "REG_SZ"
2196         };
2197         #define NTYPES ARRAY_SIZE(reg_types)
2198         struct button_spec spec[] = {
2199                 {.label = "OK", .action = DIALOG_OK},
2200                 {.label = "Cancel", .action = DIALOG_CANCEL},
2201                 { 0 }
2202         };
2203         bool flags[NTYPES] = { true };
2204         struct option_spec opsec[NTYPES + 1];
2205         unsigned i;
2206
2207         memset(&opsec, '\0', sizeof(opsec));
2208         for (i = 0; i < NTYPES; ++i) {
2209                 opsec[i].label = reg_types[i];
2210                 opsec[i].state = &flags[i];
2211         }
2212
2213         dia = dialog_new(ctx, PAIR_BLACK_CYAN, "New Value", -1, -1);
2214
2215         section = dialog_section_label_new(dia, "Select type for new value:");
2216         dialog_append_section(dia, section);
2217         section = dialog_section_hsep_new(dia, ' ');
2218         dialog_append_section(dia, section);
2219         section = dialog_section_options_new(dia, opsec, 2, true);
2220         dialog_append_section(dia, section);
2221         section = dialog_section_hsep_new(dia, 0);
2222         dialog_append_section(dia, section);
2223         section = dialog_section_buttons_new(dia, spec);
2224         dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2225         dialog_append_section(dia, section);
2226
2227         dialog_create(dia);
2228         dialog_show(dia);
2229
2230         dialog_modal_loop(dia, &err, &action);
2231         if (action == DIALOG_OK) {
2232                 for (i = 0; i < NTYPES; ++i) {
2233                         if (flags[i]) {
2234                                 *type = regtype_by_string(reg_types[i]);
2235                                 break;
2236                         }
2237                 }
2238         }
2239
2240         talloc_free(dia);
2241
2242         return action;
2243 }
2244
2245 struct search_req {
2246         TALLOC_CTX *ctx;
2247         struct regedit_search_opts *opts;
2248 };
2249
2250 static bool search_on_submit(struct dialog *dia, struct dialog_section *section,
2251                              void *arg)
2252 {
2253         struct search_req *search = arg;
2254         struct dialog_section *query;
2255
2256         query = dialog_find_section(dia, "query");
2257         SMB_ASSERT(query != NULL);
2258
2259         if (!search->opts->search_key && !search->opts->search_value) {
2260                 dialog_notice(dia, DIA_ALERT, "Error",
2261                               "Must search a key and/or a value");
2262                 return false;
2263         }
2264
2265         talloc_free(discard_const(search->opts->query));
2266         search->opts->query = dialog_section_text_field_get(search->ctx, query);
2267         SMB_ASSERT(search->opts->query != NULL);
2268         if (search->opts->query[0] == '\0') {
2269                 dialog_notice(dia, DIA_ALERT, "Error",
2270                               "Query must not be blank.");
2271                 return false;
2272         }
2273
2274         return true;
2275 }
2276
2277 int dialog_search_input(TALLOC_CTX *ctx, struct regedit_search_opts *opts)
2278 {
2279         WERROR err;
2280         enum dialog_action action;
2281         struct dialog *dia;
2282         struct dialog_section *section, *query;
2283         struct search_req search;
2284         struct button_spec spec[] = {
2285                 {.label = "Search", .action = DIALOG_OK},
2286                 {.label = "Cancel", .action = DIALOG_CANCEL},
2287                 { 0 }
2288         };
2289         struct option_spec search_opts[] = {
2290                 {.label = "Search Keys", .state = &opts->search_key},
2291                 {.label = "Search Values", .state = &opts->search_value},
2292                 {.label = "Recursive", .state = &opts->search_recursive},
2293                 {.label = "Case Sensitive", .state = &opts->search_case},
2294                 { 0 }
2295         };
2296
2297         if (!opts->search_key && !opts->search_value) {
2298                 opts->search_key = true;
2299         }
2300
2301         search.ctx = ctx;
2302         search.opts = opts;
2303         dia = dialog_new(ctx, PAIR_BLACK_CYAN, "Search", -1, -1);
2304         dialog_set_submit_cb(dia, search_on_submit, &search);
2305         section = dialog_section_label_new(dia, "Query");
2306         dialog_append_section(dia, section);
2307         query = dialog_section_text_field_new(dia, 1, -1);
2308         dialog_section_set_name(query, "query");
2309         dialog_append_section(dia, query);
2310         section = dialog_section_hsep_new(dia, 0);
2311         dialog_append_section(dia, section);
2312         section = dialog_section_options_new(dia, search_opts, 2, false);
2313         dialog_append_section(dia, section);
2314         section = dialog_section_hsep_new(dia, 0);
2315         dialog_append_section(dia, section);
2316         section = dialog_section_buttons_new(dia, spec);
2317         dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2318         dialog_append_section(dia, section);
2319
2320         dialog_create(dia);
2321         if (opts->query) {
2322                 dialog_section_text_field_set(query, opts->query);
2323         }
2324
2325         dialog_modal_loop(dia, &err, &action);
2326         talloc_free(dia);
2327
2328         return action;
2329 }