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
string_trim_n(TALLOC_CTX * ctx,const char * buf,size_t n)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
string_trim(TALLOC_CTX * ctx,const char * buf)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
dialog_free(struct dialog * dia)56 static int dialog_free(struct dialog *dia)
57 {
58 dialog_destroy(dia);
59
60 return 0;
61 }
62
default_validator(struct dialog * dia,struct dialog_section * sect,void * arg)63 static bool default_validator(struct dialog *dia, struct dialog_section *sect,
64 void *arg)
65 {
66 return true;
67 }
68
dialog_new(TALLOC_CTX * ctx,short color,const char * title,int y,int x)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
dialog_set_submit_cb(struct dialog * dia,dialog_submit_cb cb,void * arg)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
center_above_window(int * nlines,int * ncols,int * y,int * x)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
dialog_section_destroy(struct dialog_section * section)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
dialog_section_init(struct dialog_section * section,const struct dialog_section_ops * ops,int nlines,int ncols)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
dialog_section_get_name(struct dialog_section * section)149 const char *dialog_section_get_name(struct dialog_section *section)
150 {
151 return section->name;
152 }
153
dialog_section_set_name(struct dialog_section * section,const char * name)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
dialog_section_set_justify(struct dialog_section * section,enum section_justify justify)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 */
dialog_append_section(struct dialog * dia,struct dialog_section * section)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
dialog_find_section(struct dialog * dia,const char * name)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
section_on_input(struct dialog * dia,int c)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
section_on_tab(struct dialog * dia)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
section_on_btab(struct dialog * dia)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
section_on_up(struct dialog * dia)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
section_on_down(struct dialog * dia)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
section_on_left(struct dialog * dia)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
section_on_right(struct dialog * dia)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
section_on_enter(struct dialog * dia)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
section_on_focus(struct dialog * dia,bool forward)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
section_on_leave_focus(struct dialog * dia)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
section_set_next_focus(struct dialog * dia)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
section_set_previous_focus(struct dialog * dia)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
dialog_create(struct dialog * dia)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
dialog_show(struct dialog * dia)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
dialog_destroy(struct dialog * dia)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
dialog_getch(struct dialog * dia)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
dialog_handle_input(struct dialog * dia,WERROR * err,enum dialog_action * action)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
dialog_modal_loop(struct dialog * dia,WERROR * err,enum dialog_action * action)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
label_create(struct dialog * dia,struct dialog_section * section)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
label_free(struct dialog_section_label * label)606 static int label_free(struct dialog_section_label *label)
607 {
608 dialog_section_destroy(&label->section);
609 return 0;
610 }
611
dialog_section_label_new_va(TALLOC_CTX * ctx,const char * msg,va_list ap)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
dialog_section_label_new(TALLOC_CTX * ctx,const char * msg,...)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
hsep_create(struct dialog * dia,struct dialog_section * section)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
hsep_free(struct dialog_section_hsep * hsep)698 static int hsep_free(struct dialog_section_hsep *hsep)
699 {
700 dialog_section_destroy(&hsep->section);
701 return 0;
702 }
703
dialog_section_hsep_new(TALLOC_CTX * ctx,int sep)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
get_cursor_col(struct dialog_section_text_field * field)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
text_field_create(struct dialog * dia,struct dialog_section * section)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
text_field_destroy(struct dialog_section * section)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
text_field_on_input(struct dialog * dia,struct dialog_section * section,int c)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
text_field_on_up(struct dialog * dia,struct dialog_section * section)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
text_field_on_down(struct dialog * dia,struct dialog_section * section)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
text_field_on_left(struct dialog * dia,struct dialog_section * section)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
text_field_on_right(struct dialog * dia,struct dialog_section * section)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
text_field_on_enter(struct dialog * dia,struct dialog_section * section)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
text_field_on_focus(struct dialog * dia,struct dialog_section * section,bool forward)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
text_field_free(struct dialog_section_text_field * text_field)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
dialog_section_text_field_new(TALLOC_CTX * ctx,int height,int width)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
dialog_section_text_field_get(TALLOC_CTX * ctx,struct dialog_section * section)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
dialog_section_text_field_set(struct dialog_section * section,const char * s)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
dialog_section_text_field_get_lines(TALLOC_CTX * ctx,struct dialog_section * section)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
dialog_section_text_field_set_lines(TALLOC_CTX * ctx,struct dialog_section * section,const char ** array)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
dialog_section_text_field_get_int(struct dialog_section * section,long long * out)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
dialog_section_text_field_get_uint(struct dialog_section * section,unsigned long long * out)1029 bool dialog_section_text_field_get_uint(struct dialog_section *section,
1030 unsigned long long *out)
1031 {
1032 const char *buf;
1033 int error = 0;
1034 struct dialog_section_text_field *text_field =
1035 talloc_get_type_abort(section, struct dialog_section_text_field);
1036
1037 form_driver(text_field->form, REQ_VALIDATION);
1038
1039 buf = string_trim(section, field_buffer(text_field->field[0], 0));
1040 if (buf == NULL) {
1041 return false;
1042 }
1043 *out = smb_strtoull(buf, NULL, 0, &error, SMB_STR_FULL_STR_CONV);
1044 if (error != 0) {
1045 return false;
1046 }
1047
1048 return true;
1049 }
1050
1051 /* hex editor field */
1052 struct dialog_section_hexedit {
1053 struct dialog_section section;
1054 struct hexedit *buf;
1055 };
1056
1057 #define HEXEDIT_MIN_SIZE 1
hexedit_create(struct dialog * dia,struct dialog_section * section)1058 static WERROR hexedit_create(struct dialog *dia,
1059 struct dialog_section *section)
1060 {
1061 struct dialog_section_hexedit *hexedit =
1062 talloc_get_type_abort(section, struct dialog_section_hexedit);
1063
1064 hexedit->buf = hexedit_new(dia, section->window, NULL,
1065 HEXEDIT_MIN_SIZE);
1066 if (hexedit->buf == NULL) {
1067 return WERR_NOT_ENOUGH_MEMORY;
1068 }
1069
1070 hexedit_refresh(hexedit->buf);
1071
1072 return WERR_OK;
1073 }
1074
hexedit_destroy(struct dialog_section * section)1075 static void hexedit_destroy(struct dialog_section *section)
1076 {
1077 struct dialog_section_hexedit *hexedit =
1078 talloc_get_type_abort(section, struct dialog_section_hexedit);
1079
1080 if (hexedit->buf) {
1081 TALLOC_FREE(hexedit->buf);
1082 }
1083 }
1084
hexedit_on_input(struct dialog * dia,struct dialog_section * section,int c)1085 static void hexedit_on_input(struct dialog *dia,
1086 struct dialog_section *section,
1087 int c)
1088 {
1089 struct dialog_section_hexedit *hexedit =
1090 talloc_get_type_abort(section, struct dialog_section_hexedit);
1091
1092 switch (c) {
1093 case KEY_BACKSPACE:
1094 hexedit_driver(hexedit->buf, HE_BACKSPACE);
1095 break;
1096 case '\x7f':
1097 case KEY_DC:
1098 hexedit_driver(hexedit->buf, HE_DELETE);
1099 break;
1100 default:
1101 hexedit_driver(hexedit->buf, c);
1102 break;
1103 }
1104 }
1105
hexedit_on_up(struct dialog * dia,struct dialog_section * section)1106 static bool hexedit_on_up(struct dialog *dia,
1107 struct dialog_section *section)
1108 {
1109 struct dialog_section_hexedit *hexedit =
1110 talloc_get_type_abort(section, struct dialog_section_hexedit);
1111
1112 hexedit_driver(hexedit->buf, HE_CURSOR_UP);
1113
1114 return true;
1115 }
1116
hexedit_on_down(struct dialog * dia,struct dialog_section * section)1117 static bool hexedit_on_down(struct dialog *dia,
1118 struct dialog_section *section)
1119 {
1120 struct dialog_section_hexedit *hexedit =
1121 talloc_get_type_abort(section, struct dialog_section_hexedit);
1122
1123 hexedit_driver(hexedit->buf, HE_CURSOR_DOWN);
1124
1125 return true;
1126 }
1127
hexedit_on_left(struct dialog * dia,struct dialog_section * section)1128 static bool hexedit_on_left(struct dialog *dia,
1129 struct dialog_section *section)
1130 {
1131 struct dialog_section_hexedit *hexedit =
1132 talloc_get_type_abort(section, struct dialog_section_hexedit);
1133
1134 hexedit_driver(hexedit->buf, HE_CURSOR_LEFT);
1135
1136 return true;
1137 }
1138
hexedit_on_right(struct dialog * dia,struct dialog_section * section)1139 static bool hexedit_on_right(struct dialog *dia,
1140 struct dialog_section *section)
1141 {
1142 struct dialog_section_hexedit *hexedit =
1143 talloc_get_type_abort(section, struct dialog_section_hexedit);
1144
1145 hexedit_driver(hexedit->buf, HE_CURSOR_RIGHT);
1146
1147 return true;
1148 }
1149
hexedit_on_enter(struct dialog * dia,struct dialog_section * section)1150 static enum dialog_action hexedit_on_enter(struct dialog *dia,
1151 struct dialog_section *section)
1152 {
1153 return DIALOG_IGNORE;
1154 }
1155
hexedit_on_focus(struct dialog * dia,struct dialog_section * section,bool forward)1156 static bool hexedit_on_focus(struct dialog *dia,
1157 struct dialog_section *section, bool forward)
1158 {
1159 struct dialog_section_hexedit *hexedit =
1160 talloc_get_type_abort(section, struct dialog_section_hexedit);
1161
1162 hexedit_set_cursor(hexedit->buf);
1163
1164 return true;
1165 }
1166
1167 struct dialog_section_ops hexedit_ops = {
1168 .create = hexedit_create,
1169 .destroy = hexedit_destroy,
1170 .on_input = hexedit_on_input,
1171 .on_up = hexedit_on_up,
1172 .on_down = hexedit_on_down,
1173 .on_left = hexedit_on_left,
1174 .on_right = hexedit_on_right,
1175 .on_enter = hexedit_on_enter,
1176 .on_focus = hexedit_on_focus
1177 };
1178
hexedit_free(struct dialog_section_hexedit * hexedit)1179 static int hexedit_free(struct dialog_section_hexedit *hexedit)
1180 {
1181 dialog_section_destroy(&hexedit->section);
1182 return 0;
1183 }
1184
dialog_section_hexedit_new(TALLOC_CTX * ctx,int height)1185 struct dialog_section *dialog_section_hexedit_new(TALLOC_CTX *ctx, int height)
1186 {
1187 struct dialog_section_hexedit *hexedit;
1188
1189 hexedit = talloc_zero(ctx, struct dialog_section_hexedit);
1190 if (hexedit == NULL) {
1191 return NULL;
1192 }
1193 talloc_set_destructor(hexedit, hexedit_free);
1194 dialog_section_init(&hexedit->section, &hexedit_ops,
1195 height, LINE_WIDTH);
1196
1197 return &hexedit->section;
1198 }
1199
dialog_section_hexedit_set_buf(struct dialog_section * section,const void * data,size_t size)1200 WERROR dialog_section_hexedit_set_buf(struct dialog_section *section,
1201 const void *data, size_t size)
1202 {
1203 WERROR rv;
1204 struct dialog_section_hexedit *hexedit =
1205 talloc_get_type_abort(section, struct dialog_section_hexedit);
1206
1207 SMB_ASSERT(hexedit->buf != NULL);
1208
1209 rv = hexedit_set_buf(hexedit->buf, data, size);
1210 if (W_ERROR_IS_OK(rv)) {
1211 hexedit_refresh(hexedit->buf);
1212 hexedit_set_cursor(hexedit->buf);
1213 }
1214
1215 return rv;
1216 }
1217
dialog_section_hexedit_get_buf(struct dialog_section * section,const void ** data,size_t * size)1218 void dialog_section_hexedit_get_buf(struct dialog_section *section,
1219 const void **data, size_t *size)
1220 {
1221 struct dialog_section_hexedit *hexedit =
1222 talloc_get_type_abort(section, struct dialog_section_hexedit);
1223
1224 SMB_ASSERT(hexedit->buf != NULL);
1225 *data = hexedit_get_buf(hexedit->buf);
1226 *size = hexedit_get_buf_len(hexedit->buf);
1227 }
1228
dialog_section_hexedit_resize(struct dialog_section * section,size_t size)1229 WERROR dialog_section_hexedit_resize(struct dialog_section *section,
1230 size_t size)
1231 {
1232 WERROR rv;
1233 struct dialog_section_hexedit *hexedit =
1234 talloc_get_type_abort(section, struct dialog_section_hexedit);
1235
1236 SMB_ASSERT(hexedit->buf != NULL);
1237 rv = hexedit_resize_buffer(hexedit->buf, size);
1238 if (W_ERROR_IS_OK(rv)) {
1239 hexedit_refresh(hexedit->buf);
1240 }
1241
1242 return rv;
1243 }
1244
1245
1246 /* button box */
1247 struct dialog_section_buttons {
1248 struct dialog_section section;
1249 struct button_spec *spec;
1250 int current_button;
1251 };
1252
buttons_unhighlight(struct dialog_section_buttons * buttons)1253 static void buttons_unhighlight(struct dialog_section_buttons *buttons)
1254 {
1255 short pair;
1256 attr_t attr;
1257
1258 /*
1259 * Some GCC versions will complain if the macro version of
1260 * wattr_get is used. So we should enforce the use of the
1261 * function instead. See:
1262 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1263 */
1264 (wattr_get)(buttons->section.window, &attr, &pair, NULL);
1265 mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL);
1266 wnoutrefresh(buttons->section.window);
1267 }
1268
buttons_highlight(struct dialog_section_buttons * buttons)1269 static void buttons_highlight(struct dialog_section_buttons *buttons)
1270 {
1271 struct button_spec *spec = &buttons->spec[buttons->current_button];
1272 short pair;
1273 attr_t attr;
1274
1275 /*
1276 * Some GCC versions will complain if the macro version of
1277 * wattr_get is used. So we should enforce the use of the
1278 * function instead. See:
1279 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1280 */
1281 (wattr_get)(buttons->section.window, &attr, &pair, NULL);
1282 mvwchgat(buttons->section.window, 0, 0, -1, A_NORMAL, pair, NULL);
1283 mvwchgat(buttons->section.window, 0, spec->col,
1284 strlen(spec->label), A_REVERSE, pair, NULL);
1285 wmove(buttons->section.window, 0, spec->col + 2);
1286 wcursyncup(buttons->section.window);
1287 wnoutrefresh(buttons->section.window);
1288 }
1289
buttons_highlight_next(struct dialog_section_buttons * buttons)1290 static bool buttons_highlight_next(struct dialog_section_buttons *buttons)
1291 {
1292 if (buttons->current_button < talloc_array_length(buttons->spec) - 1) {
1293 buttons->current_button++;
1294 buttons_highlight(buttons);
1295 return true;
1296 }
1297 return false;
1298 }
1299
buttons_highlight_previous(struct dialog_section_buttons * buttons)1300 static bool buttons_highlight_previous(struct dialog_section_buttons *buttons)
1301 {
1302 if (buttons->current_button > 0) {
1303 buttons->current_button--;
1304 buttons_highlight(buttons);
1305 return true;
1306 }
1307 return false;
1308 }
1309
buttons_create(struct dialog * dia,struct dialog_section * section)1310 static WERROR buttons_create(struct dialog *dia,
1311 struct dialog_section *section)
1312 {
1313 size_t i, nbuttons;
1314 struct dialog_section_buttons *buttons =
1315 talloc_get_type_abort(section, struct dialog_section_buttons);
1316
1317 nbuttons = talloc_array_length(buttons->spec);
1318 for (i = 0; i < nbuttons; ++i) {
1319 struct button_spec *spec = &buttons->spec[i];
1320 mvwaddstr(section->window, 0, spec->col, spec->label);
1321 }
1322
1323 buttons->current_button = 0;
1324
1325 return WERR_OK;
1326 }
1327
buttons_on_btab(struct dialog * dia,struct dialog_section * section)1328 static bool buttons_on_btab(struct dialog *dia, struct dialog_section *section)
1329 {
1330 struct dialog_section_buttons *buttons =
1331 talloc_get_type_abort(section, struct dialog_section_buttons);
1332
1333 return buttons_highlight_previous(buttons);
1334 }
1335
buttons_on_tab(struct dialog * dia,struct dialog_section * section)1336 static bool buttons_on_tab(struct dialog *dia, struct dialog_section *section)
1337 {
1338 struct dialog_section_buttons *buttons =
1339 talloc_get_type_abort(section, struct dialog_section_buttons);
1340
1341 return buttons_highlight_next(buttons);
1342 }
1343
buttons_on_enter(struct dialog * dia,struct dialog_section * section)1344 static enum dialog_action buttons_on_enter(struct dialog *dia,
1345 struct dialog_section *section)
1346 {
1347 struct dialog_section_buttons *buttons =
1348 talloc_get_type_abort(section, struct dialog_section_buttons);
1349 struct button_spec *spec = &buttons->spec[buttons->current_button];
1350
1351 if (spec->on_enter) {
1352 return spec->on_enter(dia, section);
1353 }
1354
1355 return spec->action;
1356 }
1357
buttons_on_focus(struct dialog * dia,struct dialog_section * section,bool forward)1358 static bool buttons_on_focus(struct dialog *dia,
1359 struct dialog_section *section,
1360 bool forward)
1361 {
1362 struct dialog_section_buttons *buttons =
1363 talloc_get_type_abort(section, struct dialog_section_buttons);
1364
1365 if (forward) {
1366 buttons->current_button = 0;
1367 } else {
1368 buttons->current_button = talloc_array_length(buttons->spec) - 1;
1369 }
1370 buttons_highlight(buttons);
1371
1372 return true;
1373 }
1374
buttons_on_leave_focus(struct dialog * dia,struct dialog_section * section)1375 static void buttons_on_leave_focus(struct dialog *dia,
1376 struct dialog_section *section)
1377 {
1378 struct dialog_section_buttons *buttons =
1379 talloc_get_type_abort(section, struct dialog_section_buttons);
1380 buttons_unhighlight(buttons);
1381 }
1382
1383 struct dialog_section_ops buttons_ops = {
1384 .create = buttons_create,
1385 .on_tab = buttons_on_tab,
1386 .on_btab = buttons_on_btab,
1387 .on_up = buttons_on_btab,
1388 .on_down = buttons_on_tab,
1389 .on_left = buttons_on_btab,
1390 .on_right = buttons_on_tab,
1391 .on_enter = buttons_on_enter,
1392 .on_focus = buttons_on_focus,
1393 .on_leave_focus = buttons_on_leave_focus
1394 };
1395
buttons_free(struct dialog_section_buttons * buttons)1396 static int buttons_free(struct dialog_section_buttons *buttons)
1397 {
1398 dialog_section_destroy(&buttons->section);
1399 return 0;
1400 }
1401
dialog_section_buttons_new(TALLOC_CTX * ctx,const struct button_spec * spec)1402 struct dialog_section *dialog_section_buttons_new(TALLOC_CTX *ctx,
1403 const struct button_spec *spec)
1404 {
1405 struct dialog_section_buttons *buttons;
1406 size_t i, nbuttons;
1407 int width;
1408
1409 buttons = talloc_zero(ctx, struct dialog_section_buttons);
1410 if (buttons == NULL) {
1411 return NULL;
1412 }
1413 talloc_set_destructor(buttons, buttons_free);
1414
1415 for (nbuttons = 0; spec[nbuttons].label; ++nbuttons) {
1416 }
1417 buttons->spec = talloc_zero_array(buttons, struct button_spec, nbuttons);
1418 if (buttons->spec == NULL) {
1419 goto fail;
1420 }
1421
1422 for (width = 0, i = 0; i < nbuttons; ++i) {
1423 buttons->spec[i] = spec[i];
1424 buttons->spec[i].label = talloc_asprintf(buttons->spec,
1425 "[ %s ]",
1426 spec[i].label);
1427 if (!buttons->spec[i].label) {
1428 goto fail;
1429 }
1430
1431 buttons->spec[i].col = width;
1432 width += strlen(buttons->spec[i].label);
1433 if (i != nbuttons - 1) {
1434 ++width;
1435 }
1436 }
1437
1438 dialog_section_init(&buttons->section, &buttons_ops, 1, width);
1439
1440 return &buttons->section;
1441
1442 fail:
1443 talloc_free(buttons);
1444 return NULL;
1445 }
1446
1447 /* options */
1448 struct dialog_section_options {
1449 struct dialog_section section;
1450 struct option_spec *spec;
1451 int current_option;
1452 bool single_select;
1453 };
1454
options_unhighlight(struct dialog_section_options * options)1455 static void options_unhighlight(struct dialog_section_options *options)
1456 {
1457 short pair;
1458 attr_t attr;
1459 size_t row;
1460
1461 /*
1462 * Some GCC versions will complain if the macro version of
1463 * wattr_get is used. So we should enforce the use of the
1464 * function instead. See:
1465 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1466 */
1467 (wattr_get)(options->section.window, &attr, &pair, NULL);
1468 for (row = 0; row < options->section.nlines; ++row) {
1469 mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL);
1470 }
1471 wnoutrefresh(options->section.window);
1472 }
1473
options_highlight(struct dialog_section_options * options)1474 static void options_highlight(struct dialog_section_options *options)
1475 {
1476 struct option_spec *spec = &options->spec[options->current_option];
1477 short pair;
1478 attr_t attr;
1479 size_t row;
1480
1481 /*
1482 * Some GCC versions will complain if the macro version of
1483 * wattr_get is used. So we should enforce the use of the
1484 * function instead. See:
1485 * http://lists.gnu.org/archive/html/bug-ncurses/2013-12/msg00017.html
1486 */
1487 (wattr_get)(options->section.window, &attr, &pair, NULL);
1488 for (row = 0; row < options->section.nlines; ++row) {
1489 mvwchgat(options->section.window, row, 0, -1, A_NORMAL, pair, NULL);
1490 }
1491 mvwchgat(options->section.window, spec->row, spec->col,
1492 strlen(spec->label), A_REVERSE, pair, NULL);
1493 wmove(options->section.window, spec->row, spec->col + 4);
1494 wcursyncup(options->section.window);
1495 wnoutrefresh(options->section.window);
1496 }
1497
options_render_state(struct dialog_section_options * options)1498 static void options_render_state(struct dialog_section_options *options)
1499 {
1500 size_t i, noptions;
1501
1502 noptions = talloc_array_length(options->spec);
1503 for (i = 0; i < noptions; ++i) {
1504 struct option_spec *spec = &options->spec[i];
1505 char c = ' ';
1506 if (*spec->state)
1507 c = 'x';
1508 mvwaddch(options->section.window,
1509 spec->row, spec->col + 1, c);
1510 wnoutrefresh(options->section.window);
1511 }
1512 }
1513
options_highlight_next(struct dialog_section_options * options)1514 static bool options_highlight_next(struct dialog_section_options *options)
1515 {
1516 if (options->current_option < talloc_array_length(options->spec) - 1) {
1517 options->current_option++;
1518 options_highlight(options);
1519 return true;
1520 }
1521 return false;
1522 }
1523
options_highlight_previous(struct dialog_section_options * options)1524 static bool options_highlight_previous(struct dialog_section_options *options)
1525 {
1526 if (options->current_option > 0) {
1527 options->current_option--;
1528 options_highlight(options);
1529 return true;
1530 }
1531 return false;
1532 }
1533
options_create(struct dialog * dia,struct dialog_section * section)1534 static WERROR options_create(struct dialog *dia,
1535 struct dialog_section *section)
1536 {
1537 size_t i, noptions;
1538 struct dialog_section_options *options =
1539 talloc_get_type_abort(section, struct dialog_section_options);
1540
1541 noptions = talloc_array_length(options->spec);
1542 for (i = 0; i < noptions; ++i) {
1543 struct option_spec *spec = &options->spec[i];
1544 mvwaddstr(section->window, spec->row, spec->col,
1545 spec->label);
1546 }
1547
1548 options->current_option = 0;
1549 options_render_state(options);
1550
1551 return WERR_OK;
1552 }
1553
options_on_btab(struct dialog * dia,struct dialog_section * section)1554 static bool options_on_btab(struct dialog *dia, struct dialog_section *section)
1555 {
1556 struct dialog_section_options *options =
1557 talloc_get_type_abort(section, struct dialog_section_options);
1558
1559 return options_highlight_previous(options);
1560 }
1561
options_on_tab(struct dialog * dia,struct dialog_section * section)1562 static bool options_on_tab(struct dialog *dia, struct dialog_section *section)
1563 {
1564 struct dialog_section_options *options =
1565 talloc_get_type_abort(section, struct dialog_section_options);
1566
1567 return options_highlight_next(options);
1568 }
1569
options_on_input(struct dialog * dia,struct dialog_section * section,int c)1570 static void options_on_input(struct dialog *dia, struct dialog_section *section, int c)
1571 {
1572 struct dialog_section_options *options =
1573 talloc_get_type_abort(section, struct dialog_section_options);
1574
1575 if (c == ' ') {
1576 struct option_spec *spec = &options->spec[options->current_option];
1577 if (options->single_select) {
1578 size_t i, noptions;
1579 noptions = talloc_array_length(options->spec);
1580 for (i = 0; i < noptions; ++i) {
1581 *(options->spec[i].state) = false;
1582 }
1583 }
1584 *spec->state = !*spec->state;
1585 options_unhighlight(options);
1586 options_render_state(options);
1587 options_highlight(options);
1588 }
1589 }
1590
options_on_enter(struct dialog * dia,struct dialog_section * section)1591 static enum dialog_action options_on_enter(struct dialog *dia, struct dialog_section *section)
1592 {
1593 options_on_input(dia, section, ' ');
1594 return DIALOG_OK;
1595 }
1596
options_on_focus(struct dialog * dia,struct dialog_section * section,bool forward)1597 static bool options_on_focus(struct dialog *dia,
1598 struct dialog_section *section,
1599 bool forward)
1600 {
1601 struct dialog_section_options *options =
1602 talloc_get_type_abort(section, struct dialog_section_options);
1603
1604 if (forward) {
1605 options->current_option = 0;
1606 } else {
1607 options->current_option = talloc_array_length(options->spec) - 1;
1608 }
1609 options_highlight(options);
1610
1611 return true;
1612 }
1613
options_on_leave_focus(struct dialog * dia,struct dialog_section * section)1614 static void options_on_leave_focus(struct dialog *dia,
1615 struct dialog_section *section)
1616 {
1617 struct dialog_section_options *options =
1618 talloc_get_type_abort(section, struct dialog_section_options);
1619 options_unhighlight(options);
1620 }
1621
1622 struct dialog_section_ops options_ops = {
1623 .create = options_create,
1624 .on_tab = options_on_tab,
1625 .on_btab = options_on_btab,
1626 .on_up = options_on_btab,
1627 .on_down = options_on_tab,
1628 .on_left = options_on_btab,
1629 .on_right = options_on_tab,
1630 .on_input = options_on_input,
1631 .on_enter = options_on_enter,
1632 .on_focus = options_on_focus,
1633 .on_leave_focus = options_on_leave_focus
1634 };
1635
options_free(struct dialog_section_options * options)1636 static int options_free(struct dialog_section_options *options)
1637 {
1638 dialog_section_destroy(&options->section);
1639 return 0;
1640 }
1641
dialog_section_options_new(TALLOC_CTX * ctx,const struct option_spec * spec,int maxcol,bool single_select)1642 struct dialog_section *dialog_section_options_new(TALLOC_CTX *ctx,
1643 const struct option_spec *spec,
1644 int maxcol, bool single_select)
1645 {
1646 struct dialog_section_options *options;
1647 size_t i, noptions;
1648 int width, maxwidth, maxrows;
1649
1650 options = talloc_zero(ctx, struct dialog_section_options);
1651 if (options == NULL) {
1652 return NULL;
1653 }
1654 talloc_set_destructor(options, options_free);
1655
1656 for (noptions = 0; spec[noptions].label; ++noptions) {
1657 }
1658 options->spec = talloc_zero_array(options, struct option_spec, noptions);
1659 if (options->spec == NULL) {
1660 goto fail;
1661 }
1662
1663 maxrows = noptions / maxcol;
1664 if (noptions % maxcol) {
1665 ++maxrows;
1666 }
1667
1668 for (width = 0, maxwidth = 0, i = 0; i < noptions; ++i) {
1669 options->spec[i] = spec[i];
1670 options->spec[i].label = talloc_asprintf(options->spec,
1671 "[ ] %s",
1672 spec[i].label);
1673 if (!options->spec[i].label) {
1674 goto fail;
1675 }
1676
1677 options->spec[i].col = maxwidth;
1678 options->spec[i].row = i % maxrows;
1679 width = MAX(strlen(options->spec[i].label), width);
1680 if (options->spec[i].row == maxrows - 1 || i == noptions - 1) {
1681 maxwidth += width + 1;
1682 width = 0;
1683 }
1684 }
1685
1686 dialog_section_init(&options->section, &options_ops, maxrows, maxwidth - 1);
1687 options->single_select = single_select;
1688
1689 return &options->section;
1690
1691 fail:
1692 talloc_free(options);
1693 return NULL;
1694 }
1695
1696
1697 enum input_type {
1698 DLG_IN_LONG,
1699 DLG_IN_ULONG,
1700 DLG_IN_STR,
1701 };
1702
1703 struct input_req {
1704 TALLOC_CTX *ctx;
1705 enum input_type type;
1706 union {
1707 void *out;
1708 unsigned long *out_ulong;
1709 long *out_long;
1710 const char **out_str;
1711 } out;
1712 };
1713
input_on_submit(struct dialog * dia,struct dialog_section * section,void * arg)1714 static bool input_on_submit(struct dialog *dia, struct dialog_section *section,
1715 void *arg)
1716 {
1717 struct input_req *req = arg;
1718 struct dialog_section *data;
1719 unsigned long long out_ulong;
1720 long long out_long;
1721
1722 data = dialog_find_section(dia, "input");
1723
1724 switch (req->type) {
1725 case DLG_IN_LONG:
1726 if (!dialog_section_text_field_get_int(data, &out_long)) {
1727 dialog_notice(dia, DIA_ALERT, "Error",
1728 "Input must be a number.");
1729 return false;
1730 }
1731 if (out_long < LONG_MIN || out_long > LONG_MAX) {
1732 dialog_notice(dia, DIA_ALERT, "Error",
1733 "Number is out of range.");
1734 return false;
1735 }
1736 *req->out.out_long = out_long;
1737 break;
1738 case DLG_IN_ULONG:
1739 if (!dialog_section_text_field_get_uint(data, &out_ulong)) {
1740 dialog_notice(dia, DIA_ALERT, "Error",
1741 "Input must be a number greater than zero.");
1742 return false;
1743 }
1744 if (out_ulong > ULONG_MAX) {
1745 dialog_notice(dia, DIA_ALERT, "Error",
1746 "Number is out of range.");
1747 return false;
1748 }
1749 *req->out.out_ulong = out_ulong;
1750 break;
1751 case DLG_IN_STR:
1752 *req->out.out_str = dialog_section_text_field_get(req->ctx, data);
1753 break;
1754 }
1755
1756 return true;
1757 }
1758
1759 static int dialog_input_internal(TALLOC_CTX *ctx, void *output,
1760 enum input_type type,
1761 const char *title,
1762 const char *msg, va_list ap)
1763 PRINTF_ATTRIBUTE(5,0);
1764
dialog_input_internal(TALLOC_CTX * ctx,void * output,enum input_type type,const char * title,const char * msg,va_list ap)1765 static int dialog_input_internal(TALLOC_CTX *ctx, void *output,
1766 enum input_type type,
1767 const char *title,
1768 const char *msg, va_list ap)
1769 {
1770 WERROR err;
1771 struct input_req req;
1772 enum dialog_action action;
1773 struct dialog *dia;
1774 struct dialog_section *section;
1775 struct button_spec spec[] = {
1776 {.label = "OK", .action = DIALOG_OK},
1777 {.label = "Cancel", .action = DIALOG_CANCEL},
1778 { 0 }
1779 };
1780
1781 req.ctx = ctx;
1782 req.type = type;
1783 req.out.out = output;
1784 *req.out.out_str = NULL;
1785
1786 dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1);
1787 dialog_set_submit_cb(dia, input_on_submit, &req);
1788 section = dialog_section_label_new_va(dia, msg, ap);
1789 dialog_append_section(dia, section);
1790 section = dialog_section_hsep_new(dia, ' ');
1791 dialog_append_section(dia, section);
1792 section = dialog_section_text_field_new(dia, 1, -1);
1793 dialog_section_set_name(section, "input");
1794 dialog_append_section(dia, section);
1795 section = dialog_section_hsep_new(dia, 0);
1796 dialog_append_section(dia, section);
1797 section = dialog_section_buttons_new(dia, spec);
1798 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
1799 dialog_append_section(dia, section);
1800
1801 dialog_create(dia);
1802 dialog_show(dia);
1803 dialog_modal_loop(dia, &err, &action);
1804 talloc_free(dia);
1805
1806 return action;
1807 }
1808
dialog_input(TALLOC_CTX * ctx,const char ** output,const char * title,const char * msg,...)1809 int dialog_input(TALLOC_CTX *ctx, const char **output, const char *title,
1810 const char *msg, ...)
1811 {
1812 va_list ap;
1813 int rv;
1814
1815 va_start(ap, msg);
1816 rv = dialog_input_internal(ctx, output, DLG_IN_STR, title, msg, ap);
1817 va_end(ap);
1818
1819 return rv;
1820 }
1821
dialog_input_ulong(TALLOC_CTX * ctx,unsigned long * output,const char * title,const char * msg,...)1822 int dialog_input_ulong(TALLOC_CTX *ctx, unsigned long *output,
1823 const char *title, const char *msg, ...)
1824 {
1825 va_list ap;
1826 int rv;
1827
1828 va_start(ap, msg);
1829 rv = dialog_input_internal(ctx, output, DLG_IN_ULONG, title, msg, ap);
1830 va_end(ap);
1831
1832 return rv;
1833 }
1834
dialog_input_long(TALLOC_CTX * ctx,long * output,const char * title,const char * msg,...)1835 int dialog_input_long(TALLOC_CTX *ctx, long *output,
1836 const char *title, const char *msg, ...)
1837 {
1838 va_list ap;
1839 int rv;
1840
1841 va_start(ap, msg);
1842 rv = dialog_input_internal(ctx, output, DLG_IN_LONG, title, msg, ap);
1843 va_end(ap);
1844
1845 return rv;
1846 }
1847
dialog_notice(TALLOC_CTX * ctx,enum dialog_type type,const char * title,const char * msg,...)1848 int dialog_notice(TALLOC_CTX *ctx, enum dialog_type type,
1849 const char *title, const char *msg, ...)
1850 {
1851 va_list ap;
1852 WERROR err;
1853 enum dialog_action action;
1854 struct dialog *dia;
1855 struct dialog_section *section;
1856 struct button_spec spec[3];
1857
1858 memset(&spec, '\0', sizeof(spec));
1859 spec[0].label = "OK";
1860 spec[0].action = DIALOG_OK;
1861 if (type == DIA_CONFIRM) {
1862 spec[1].label = "Cancel";
1863 spec[1].action = DIALOG_CANCEL;
1864 }
1865
1866 dia = dialog_new(ctx, PAIR_BLACK_CYAN, title, -1, -1);
1867 va_start(ap, msg);
1868 section = dialog_section_label_new_va(dia, msg, ap);
1869 va_end(ap);
1870 dialog_append_section(dia, section);
1871 section = dialog_section_hsep_new(dia, 0);
1872 dialog_append_section(dia, section);
1873 section = dialog_section_buttons_new(dia, spec);
1874 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
1875 dialog_append_section(dia, section);
1876
1877 dialog_create(dia);
1878 dialog_show(dia);
1879 dialog_modal_loop(dia, &err, &action);
1880 talloc_free(dia);
1881
1882 return action;
1883 }
1884
1885
1886 struct edit_req {
1887 uint32_t type;
1888 uint32_t mode;
1889 struct registry_key *key;
1890 const struct value_item *vitem;
1891 };
1892
fill_value_buffer(struct dialog * dia,struct edit_req * edit)1893 static WERROR fill_value_buffer(struct dialog *dia, struct edit_req *edit)
1894 {
1895 char *tmp;
1896 struct dialog_section *data;
1897
1898 if (edit->vitem == NULL) {
1899 return WERR_OK;
1900 }
1901
1902 data = dialog_find_section(dia, "data");
1903 SMB_ASSERT(data != NULL);
1904
1905 switch (edit->mode) {
1906 case REG_DWORD: {
1907 uint32_t v = 0;
1908 if (edit->vitem->data.length >= 4) {
1909 v = IVAL(edit->vitem->data.data, 0);
1910 }
1911 tmp = talloc_asprintf(dia, "%u", (unsigned)v);
1912 if (tmp == NULL) {
1913 return WERR_NOT_ENOUGH_MEMORY;
1914 }
1915 dialog_section_text_field_set(data, tmp);
1916 talloc_free(tmp);
1917 break;
1918 }
1919 case REG_SZ:
1920 case REG_EXPAND_SZ: {
1921 const char *s;
1922
1923 if (!pull_reg_sz(dia, &edit->vitem->data, &s)) {
1924 return WERR_NOT_ENOUGH_MEMORY;
1925 }
1926 dialog_section_text_field_set(data, s);
1927 break;
1928 }
1929 case REG_MULTI_SZ: {
1930 const char **array;
1931
1932 if (!pull_reg_multi_sz(dia, &edit->vitem->data, &array)) {
1933 return WERR_NOT_ENOUGH_MEMORY;
1934 }
1935 return dialog_section_text_field_set_lines(dia, data, array);
1936 }
1937 case REG_BINARY:
1938 default:
1939 return dialog_section_hexedit_set_buf(data,
1940 edit->vitem->data.data,
1941 edit->vitem->data.length);
1942 }
1943
1944 return WERR_OK;
1945 }
1946
value_exists(TALLOC_CTX * ctx,const struct registry_key * key,const char * name)1947 static bool value_exists(TALLOC_CTX *ctx, const struct registry_key *key,
1948 const char *name)
1949 {
1950 uint32_t type;
1951 DATA_BLOB blob;
1952 WERROR rv;
1953
1954 rv = reg_key_get_value_by_name(ctx, key, name, &type, &blob);
1955
1956 return W_ERROR_IS_OK(rv);
1957 }
1958
edit_on_submit(struct dialog * dia,struct dialog_section * section,void * arg)1959 static bool edit_on_submit(struct dialog *dia, struct dialog_section *section,
1960 void *arg)
1961 {
1962 struct edit_req *edit = arg;
1963 WERROR rv;
1964 DATA_BLOB blob;
1965 const char *name;
1966 struct dialog_section *name_section, *data;
1967
1968 name_section = dialog_find_section(dia, "name");
1969 if (name_section) {
1970 name = dialog_section_text_field_get(dia, name_section);
1971 if (*name == '\0') {
1972 dialog_notice(dia, DIA_ALERT, "Error",
1973 "Value name must not be blank.");
1974 return false;
1975 }
1976 if (value_exists(dia, edit->key, name)) {
1977 dialog_notice(dia, DIA_ALERT, "Error",
1978 "Value named \"%s\" already exists.",
1979 name);
1980 return false;
1981 }
1982 } else {
1983 SMB_ASSERT(edit->vitem);
1984 name = edit->vitem->value_name;
1985 }
1986 SMB_ASSERT(name);
1987
1988 data = dialog_find_section(dia, "data");
1989 SMB_ASSERT(data != NULL);
1990
1991 rv = WERR_OK;
1992 switch (edit->mode) {
1993 case REG_DWORD: {
1994 unsigned long long v;
1995 uint32_t val;
1996
1997 if (!dialog_section_text_field_get_uint(data, &v)) {
1998 dialog_notice(dia, DIA_ALERT, "Error",
1999 "REG_DWORD value must be an integer.");
2000 return false;
2001 }
2002 if (v > UINT32_MAX) {
2003 dialog_notice(dia, DIA_ALERT, "Error",
2004 "REG_DWORD value must less than %lu.",
2005 (unsigned long)UINT32_MAX);
2006 return false;
2007 }
2008 val = (uint32_t)v;
2009 blob = data_blob_talloc(dia, NULL, sizeof(val));
2010 SIVAL(blob.data, 0, val);
2011 break;
2012 }
2013 case REG_SZ:
2014 case REG_EXPAND_SZ: {
2015 const char *buf;
2016
2017 buf = dialog_section_text_field_get(dia, data);
2018 if (!buf || !push_reg_sz(dia, &blob, buf)) {
2019 rv = WERR_NOT_ENOUGH_MEMORY;
2020 }
2021 break;
2022 }
2023 case REG_MULTI_SZ: {
2024 const char **lines;
2025
2026 lines = dialog_section_text_field_get_lines(dia, data);
2027 if (!lines || !push_reg_multi_sz(dia, &blob, lines)) {
2028 rv = WERR_NOT_ENOUGH_MEMORY;
2029 }
2030 break;
2031 }
2032 case REG_BINARY: {
2033 const void *buf;
2034 size_t len;
2035
2036 dialog_section_hexedit_get_buf(data, &buf, &len);
2037 blob = data_blob_talloc(dia, buf, len);
2038 break;
2039 }
2040 }
2041
2042 if (W_ERROR_IS_OK(rv)) {
2043 rv = reg_val_set(edit->key, name, edit->type, blob);
2044 }
2045
2046 if (!W_ERROR_IS_OK(rv)) {
2047 const char *msg = get_friendly_werror_msg(rv);
2048 dialog_notice(dia, DIA_ALERT, "Error",
2049 "Error saving value:\n%s", msg);
2050
2051 return false;
2052 }
2053
2054 return true;
2055
2056 }
2057
edit_on_resize(struct dialog * dia,struct dialog_section * section)2058 static enum dialog_action edit_on_resize(struct dialog *dia,
2059 struct dialog_section *section)
2060 {
2061 struct dialog_section *data;
2062 unsigned long size;
2063 int rv;
2064
2065 data = dialog_find_section(dia, "data");
2066 rv = dialog_input_ulong(dia, &size, "Resize", "Enter size of buffer");
2067 if (rv == DIALOG_OK) {
2068 dialog_section_hexedit_resize(data, size);
2069 }
2070
2071 return DIALOG_IGNORE;
2072 }
2073
dialog_edit_value(TALLOC_CTX * ctx,struct registry_key * key,uint32_t type,const struct value_item * vitem,bool force_binary,WERROR * err,const char ** name)2074 int dialog_edit_value(TALLOC_CTX *ctx, struct registry_key *key,
2075 uint32_t type, const struct value_item *vitem,
2076 bool force_binary, WERROR *err,
2077 const char **name)
2078 {
2079 enum dialog_action action;
2080 struct dialog *dia;
2081 struct dialog_section *section;
2082 struct edit_req edit;
2083 struct button_spec buttons[] = {
2084 {.label = "OK", .action = DIALOG_OK},
2085 {.label = "Cancel", .action = DIALOG_CANCEL},
2086 { 0 }
2087 };
2088 struct button_spec buttons_hexedit[] = {
2089 {.label = "OK", .action = DIALOG_OK},
2090 {.label = "Resize Buffer", .on_enter = edit_on_resize},
2091 {.label = "Cancel", .action = DIALOG_CANCEL},
2092 { 0 }
2093 };
2094
2095
2096 edit.key = key;
2097 edit.vitem = vitem;
2098 edit.type = type;
2099 edit.mode = type;
2100 if (force_binary || (vitem && vitem->unprintable)) {
2101 edit.mode = REG_BINARY;
2102 }
2103
2104 dia = dialog_new(ctx, PAIR_BLACK_CYAN, "Edit Value", -1, -1);
2105 dialog_set_submit_cb(dia, edit_on_submit, &edit);
2106
2107 section = dialog_section_label_new(dia, "Type");
2108 dialog_append_section(dia, section);
2109 section = dialog_section_label_new(dia, "%s",
2110 str_regtype(type));
2111 dialog_append_section(dia, section);
2112 section = dialog_section_hsep_new(dia, ' ');
2113 dialog_append_section(dia, section);
2114
2115 section = dialog_section_label_new(dia, "Name");
2116 dialog_append_section(dia, section);
2117 if (vitem) {
2118 section = dialog_section_label_new(dia, "%s",
2119 vitem->value_name);
2120 } else {
2121 section = dialog_section_text_field_new(dia, 1, 50);
2122 dialog_section_set_name(section, "name");
2123 }
2124 dialog_append_section(dia, section);
2125 section = dialog_section_hsep_new(dia, ' ');
2126 dialog_append_section(dia, section);
2127
2128 section = dialog_section_label_new(dia, "Data");
2129 dialog_append_section(dia, section);
2130
2131 switch (edit.mode) {
2132 case REG_DWORD:
2133 case REG_SZ:
2134 case REG_EXPAND_SZ:
2135 section = dialog_section_text_field_new(dia, 1, 50);
2136 break;
2137 case REG_MULTI_SZ:
2138 section = dialog_section_text_field_new(dia, 10, 50);
2139 break;
2140 case REG_BINARY:
2141 default:
2142 section = dialog_section_hexedit_new(dia, 10);
2143 break;
2144 }
2145
2146 dialog_section_set_name(section, "data");
2147 dialog_append_section(dia, section);
2148
2149 section = dialog_section_hsep_new(dia, 0);
2150 dialog_append_section(dia, section);
2151 if (edit.mode == REG_BINARY) {
2152 section = dialog_section_buttons_new(dia, buttons_hexedit);
2153 } else {
2154 section = dialog_section_buttons_new(dia, buttons);
2155 }
2156 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2157 dialog_append_section(dia, section);
2158
2159 dialog_create(dia);
2160
2161 *err = fill_value_buffer(dia, &edit);
2162 if (!W_ERROR_IS_OK(*err)) {
2163 return DIALOG_CANCEL;
2164 }
2165
2166 dialog_show(dia);
2167 dialog_modal_loop(dia, err, &action);
2168
2169 if (action == DIALOG_OK && name) {
2170 if (vitem) {
2171 *name = talloc_strdup(ctx, vitem->value_name);
2172 } else if ((section = dialog_find_section(dia, "name"))) {
2173 *name = dialog_section_text_field_get(ctx, section);
2174 }
2175 }
2176
2177 talloc_free(dia);
2178
2179 return action;
2180 }
2181
dialog_select_type(TALLOC_CTX * ctx,int * type)2182 int dialog_select_type(TALLOC_CTX *ctx, int *type)
2183 {
2184 WERROR err;
2185 enum dialog_action action;
2186 struct dialog *dia;
2187 struct dialog_section *section;
2188 const char *reg_types[] = {
2189 "REG_BINARY",
2190 "REG_DWORD",
2191 "REG_EXPAND_SZ",
2192 "REG_MULTI_SZ",
2193 "REG_SZ"
2194 };
2195 #define NTYPES ARRAY_SIZE(reg_types)
2196 struct button_spec spec[] = {
2197 {.label = "OK", .action = DIALOG_OK},
2198 {.label = "Cancel", .action = DIALOG_CANCEL},
2199 { 0 }
2200 };
2201 bool flags[NTYPES] = { true };
2202 struct option_spec opsec[NTYPES + 1];
2203 unsigned i;
2204
2205 memset(&opsec, '\0', sizeof(opsec));
2206 for (i = 0; i < NTYPES; ++i) {
2207 opsec[i].label = reg_types[i];
2208 opsec[i].state = &flags[i];
2209 }
2210
2211 dia = dialog_new(ctx, PAIR_BLACK_CYAN, "New Value", -1, -1);
2212
2213 section = dialog_section_label_new(dia, "Select type for new value:");
2214 dialog_append_section(dia, section);
2215 section = dialog_section_hsep_new(dia, ' ');
2216 dialog_append_section(dia, section);
2217 section = dialog_section_options_new(dia, opsec, 2, true);
2218 dialog_append_section(dia, section);
2219 section = dialog_section_hsep_new(dia, 0);
2220 dialog_append_section(dia, section);
2221 section = dialog_section_buttons_new(dia, spec);
2222 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2223 dialog_append_section(dia, section);
2224
2225 dialog_create(dia);
2226 dialog_show(dia);
2227
2228 dialog_modal_loop(dia, &err, &action);
2229 if (action == DIALOG_OK) {
2230 for (i = 0; i < NTYPES; ++i) {
2231 if (flags[i]) {
2232 *type = regtype_by_string(reg_types[i]);
2233 break;
2234 }
2235 }
2236 }
2237
2238 talloc_free(dia);
2239
2240 return action;
2241 }
2242
2243 struct search_req {
2244 TALLOC_CTX *ctx;
2245 struct regedit_search_opts *opts;
2246 };
2247
search_on_submit(struct dialog * dia,struct dialog_section * section,void * arg)2248 static bool search_on_submit(struct dialog *dia, struct dialog_section *section,
2249 void *arg)
2250 {
2251 struct search_req *search = arg;
2252 struct dialog_section *query;
2253
2254 query = dialog_find_section(dia, "query");
2255 SMB_ASSERT(query != NULL);
2256
2257 if (!search->opts->search_key && !search->opts->search_value) {
2258 dialog_notice(dia, DIA_ALERT, "Error",
2259 "Must search a key and/or a value");
2260 return false;
2261 }
2262
2263 talloc_free(discard_const(search->opts->query));
2264 search->opts->query = dialog_section_text_field_get(search->ctx, query);
2265 SMB_ASSERT(search->opts->query != NULL);
2266 if (search->opts->query[0] == '\0') {
2267 dialog_notice(dia, DIA_ALERT, "Error",
2268 "Query must not be blank.");
2269 return false;
2270 }
2271
2272 return true;
2273 }
2274
dialog_search_input(TALLOC_CTX * ctx,struct regedit_search_opts * opts)2275 int dialog_search_input(TALLOC_CTX *ctx, struct regedit_search_opts *opts)
2276 {
2277 WERROR err;
2278 enum dialog_action action;
2279 struct dialog *dia;
2280 struct dialog_section *section, *query;
2281 struct search_req search;
2282 struct button_spec spec[] = {
2283 {.label = "Search", .action = DIALOG_OK},
2284 {.label = "Cancel", .action = DIALOG_CANCEL},
2285 { 0 }
2286 };
2287 struct option_spec search_opts[] = {
2288 {.label = "Search Keys", .state = &opts->search_key},
2289 {.label = "Search Values", .state = &opts->search_value},
2290 {.label = "Recursive", .state = &opts->search_recursive},
2291 {.label = "Case Sensitive", .state = &opts->search_case},
2292 { 0 }
2293 };
2294
2295 if (!opts->search_key && !opts->search_value) {
2296 opts->search_key = true;
2297 }
2298
2299 search.ctx = ctx;
2300 search.opts = opts;
2301 dia = dialog_new(ctx, PAIR_BLACK_CYAN, "Search", -1, -1);
2302 dialog_set_submit_cb(dia, search_on_submit, &search);
2303 section = dialog_section_label_new(dia, "Query");
2304 dialog_append_section(dia, section);
2305 query = dialog_section_text_field_new(dia, 1, -1);
2306 dialog_section_set_name(query, "query");
2307 dialog_append_section(dia, query);
2308 section = dialog_section_hsep_new(dia, 0);
2309 dialog_append_section(dia, section);
2310 section = dialog_section_options_new(dia, search_opts, 2, false);
2311 dialog_append_section(dia, section);
2312 section = dialog_section_hsep_new(dia, 0);
2313 dialog_append_section(dia, section);
2314 section = dialog_section_buttons_new(dia, spec);
2315 dialog_section_set_justify(section, SECTION_JUSTIFY_CENTER);
2316 dialog_append_section(dia, section);
2317
2318 dialog_create(dia);
2319 if (opts->query) {
2320 dialog_section_text_field_set(query, opts->query);
2321 }
2322
2323 dialog_modal_loop(dia, &err, &action);
2324 talloc_free(dia);
2325
2326 return action;
2327 }
2328