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