links

lynx-like text mode web browser
git clone anongit@rnpnr.xyz:links.git
Log | Files | Refs | Feed | README | LICENSE

bfu.c (61168B)


      1 /* bfu.c
      2  * (c) 2002 Mikulas Patocka
      3  * This file is a part of the Links program, released under GPL.
      4  */
      5 
      6 #include <limits.h>
      7 
      8 #include "links.h"
      9 
     10 unsigned char m_bar = 0;
     11 
     12 static void menu_func(struct window *, struct links_event *, int);
     13 static void mainmenu_func(struct window *, struct links_event *, int);
     14 
     15 struct memory_list *
     16 getml(void *p, ...)
     17 {
     18 	struct memory_list *ml;
     19 	va_list ap;
     20 	int n = 0;
     21 	void *q = p;
     22 	va_start(ap, p);
     23 	while (q) {
     24 		if (n == INT_MAX)
     25 			overalloc();
     26 		n++;
     27 		q = va_arg(ap, void *);
     28 	}
     29 	if ((unsigned)n
     30 	    > (INT_MAX - sizeof(struct memory_list)) / sizeof(void *))
     31 		overalloc();
     32 	ml = xmalloc(sizeof(struct memory_list) + n * sizeof(void *));
     33 	ml->n = n;
     34 	n = 0;
     35 	q = p;
     36 	va_end(ap);
     37 	va_start(ap, p);
     38 	while (q) {
     39 		ml->p[n++] = q;
     40 		q = va_arg(ap, void *);
     41 	}
     42 	va_end(ap);
     43 	return ml;
     44 }
     45 
     46 void
     47 add_to_ml(struct memory_list **ml, ...)
     48 {
     49 	struct memory_list *nml;
     50 	va_list ap;
     51 	int n = 0;
     52 	void *q;
     53 	if (!*ml) {
     54 		*ml = xmalloc(sizeof(struct memory_list));
     55 		(*ml)->n = 0;
     56 	}
     57 	va_start(ap, ml);
     58 	while (va_arg(ap, void *)) {
     59 		if (n == INT_MAX)
     60 			overalloc();
     61 		n++;
     62 	}
     63 	if ((unsigned)n + (unsigned)((*ml)->n)
     64 	    > (INT_MAX - sizeof(struct memory_list)) / sizeof(void *))
     65 		overalloc();
     66 	nml = xrealloc(*ml, sizeof(struct memory_list)
     67 	                        + (n + (*ml)->n) * sizeof(void *));
     68 	va_end(ap);
     69 	va_start(ap, ml);
     70 	while ((q = va_arg(ap, void *)))
     71 		nml->p[nml->n++] = q;
     72 	*ml = nml;
     73 	va_end(ap);
     74 }
     75 
     76 void
     77 freeml(struct memory_list *ml)
     78 {
     79 	int i;
     80 	if (!ml)
     81 		return;
     82 	for (i = 0; i < ml->n; i++)
     83 		free(ml->p[i]);
     84 	free(ml);
     85 }
     86 
     87 static inline int
     88 txtlen(unsigned char *s)
     89 {
     90 	return strlen((char *)s);
     91 }
     92 
     93 static unsigned
     94 select_hotkey(struct terminal *term, unsigned char *text, unsigned char *hotkey,
     95               unsigned *hotkeys, int n)
     96 {
     97 	unsigned c;
     98 	if (hotkey == M_BAR)
     99 		return 0;
    100 	if (text) {
    101 		text = stracpy(get_text_translation(text, term));
    102 		charset_upcase_string(&text, 0);
    103 	}
    104 	hotkey = get_text_translation(hotkey, term);
    105 	while (1) {
    106 		int i;
    107 		c = GET_TERM_CHAR(term, &hotkey);
    108 		if (!c)
    109 			break;
    110 		c = charset_upcase(c, 0);
    111 		for (i = 0; i < n; i++)
    112 			if (hotkeys[i] == c)
    113 				continue;
    114 		if (!text || strchr((char *)text, c))
    115 			break;
    116 	}
    117 	free(text);
    118 	return c;
    119 }
    120 
    121 void
    122 do_menu_selected(struct terminal *term, struct menu_item *items, void *data,
    123                  int selected, void (*free_function)(void *), void *free_data)
    124 {
    125 	int i;
    126 	struct menu *menu;
    127 	for (i = 0; items[i].text; i++)
    128 		if (i == (INT_MAX - sizeof(struct menu)) / sizeof(unsigned))
    129 			overalloc();
    130 	menu =
    131 	    xmalloc(sizeof(struct menu) + (!i ? 0 : i - 1) * sizeof(unsigned));
    132 	menu->selected = selected;
    133 	menu->view = 0;
    134 	menu->ni = i;
    135 	menu->items = items;
    136 	menu->data = data;
    137 	menu->free_function = free_function;
    138 	menu->free_data = free_data;
    139 	for (i = 0; i < menu->ni; i++)
    140 		menu->hotkeys[i] = select_hotkey(
    141 		    term, items[i].text, items[i].hotkey, menu->hotkeys, i);
    142 	add_window(term, menu_func, menu);
    143 }
    144 
    145 void
    146 do_menu(struct terminal *term, struct menu_item *items, void *data)
    147 {
    148 	do_menu_selected(term, items, data, 0, NULL, NULL);
    149 }
    150 
    151 static void
    152 select_menu(struct terminal *term, struct menu *menu)
    153 {
    154 	struct menu_item *it;
    155 	void (*func)(struct terminal *, void *, void *);
    156 	void *data1;
    157 	void *data2;
    158 	if (menu->selected < 0 || menu->selected >= menu->ni)
    159 		return;
    160 	it = &menu->items[menu->selected];
    161 	func = it->func;
    162 	data1 = it->data;
    163 	data2 = menu->data;
    164 	if (it->hotkey == M_BAR)
    165 		return;
    166 	flush_terminal(term);
    167 	if (!it->in_m) {
    168 		struct window *win = NULL;
    169 		struct list_head *lwin;
    170 		foreach (struct window, win, lwin, term->windows) {
    171 			if (win->handler != menu_func
    172 			    && win->handler != mainmenu_func)
    173 				break;
    174 			lwin = lwin->prev;
    175 			delete_window(win);
    176 		}
    177 	}
    178 	func(term, data1, data2);
    179 }
    180 
    181 static unsigned char *
    182 get_rtext(unsigned char *rtext)
    183 {
    184 	if (!strcmp(cast_const_char rtext, ">"))
    185 		return MENU_SUBMENU;
    186 	return rtext;
    187 }
    188 
    189 static void
    190 count_menu_size(struct terminal *term, struct menu *menu)
    191 {
    192 	int sx = term->x;
    193 	int sy = term->y;
    194 	int mx = 4;
    195 	int my;
    196 	for (my = 0; my < menu->ni; my++) {
    197 		int s;
    198 		s = txtlen(get_text_translation(menu->items[my].text, term))
    199 		    + txtlen(get_text_translation(
    200 			get_rtext(menu->items[my].rtext), term))
    201 		    + MENU_HOTKEY_SPACE
    202 		          * (get_text_translation(
    203 				 get_rtext(menu->items[my].rtext), term)[0]
    204 		             != 0);
    205 		s += 4;
    206 		if (s > mx)
    207 			mx = s;
    208 	}
    209 	my += 2;
    210 	if (mx > sx)
    211 		mx = sx;
    212 	if (my > sy)
    213 		my = sy;
    214 	menu->nview = my - 2;
    215 	menu->xw = mx;
    216 	menu->yw = my;
    217 	if ((menu->x = menu->xp) < 0)
    218 		menu->x = 0;
    219 	if ((menu->y = menu->yp) < 0)
    220 		menu->y = 0;
    221 	if (menu->x + mx > sx)
    222 		menu->x = sx - mx;
    223 	if (menu->y + my > sy)
    224 		menu->y = sy - my;
    225 }
    226 
    227 static void
    228 scroll_menu(struct menu *menu, int d)
    229 {
    230 	int c = 0;
    231 	int w = menu->nview;
    232 	int scr_i = SCROLL_ITEMS > (w - 1) / 2 ? (w - 1) / 2 : SCROLL_ITEMS;
    233 	if (scr_i < 0)
    234 		scr_i = 0;
    235 	if (w < 0)
    236 		w = 0;
    237 	menu->selected += d;
    238 	while (1) {
    239 		if (c++ > menu->ni) {
    240 			menu->selected = -1;
    241 			menu->view = 0;
    242 			return;
    243 		}
    244 		if (menu->selected < 0)
    245 			menu->selected = 0;
    246 		if (menu->selected >= menu->ni)
    247 			menu->selected = menu->ni - 1;
    248 		if (menu->ni && menu->items[menu->selected].hotkey != M_BAR)
    249 			break;
    250 		menu->selected += d;
    251 	}
    252 	if (menu->selected < menu->view + scr_i)
    253 		menu->view = menu->selected - scr_i;
    254 	if (menu->selected >= menu->view + w - scr_i - 1)
    255 		menu->view = menu->selected - w + scr_i + 1;
    256 	if (menu->view > menu->ni - w)
    257 		menu->view = menu->ni - w;
    258 	if (menu->view < 0)
    259 		menu->view = 0;
    260 }
    261 
    262 static void
    263 display_menu_txt(struct terminal *term, void *menu_)
    264 {
    265 	struct menu *menu = (struct menu *)menu_;
    266 	int p, s;
    267 	fill_area(term, menu->x + 1, menu->y + 1, menu->xw - 2, menu->yw - 2,
    268 	          ' ', COLOR_MENU_TEXT);
    269 	draw_frame(term, menu->x, menu->y, menu->xw, menu->yw, COLOR_MENU_FRAME,
    270 	           1);
    271 	set_window_ptr(menu->win, menu->x, menu->y);
    272 	for (p = menu->view, s = menu->y + 1;
    273 	     p < menu->ni && p < menu->view + menu->yw - 2; p++, s++) {
    274 		int x;
    275 		int h = 0;
    276 		unsigned c;
    277 		unsigned char *tmptext =
    278 		    get_text_translation(menu->items[p].text, term);
    279 		unsigned char co;
    280 		if (p == menu->selected) {
    281 			h = 1;
    282 			co = COLOR_MENU_SELECTED;
    283 		} else
    284 			co = COLOR_MENU_TEXT;
    285 		if (h) {
    286 			set_cursor(term, menu->x + 1, s, term->x - 1,
    287 			           term->y - 1);
    288 			/*set_window_ptr(menu->win, menu->x+3, s+1);*/
    289 			set_window_ptr(menu->win, menu->x + menu->xw, s);
    290 			fill_area(term, menu->x + 1, s, menu->xw - 2, 1, ' ',
    291 			          co);
    292 		}
    293 		if (menu->items[p].hotkey != M_BAR || (tmptext[0])) {
    294 			unsigned char *rt = get_text_translation(
    295 			    get_rtext(menu->items[p].rtext), term);
    296 			int l = strlen((char *)rt);
    297 			for (x = 0;; x++) {
    298 				c = GET_TERM_CHAR(term, &rt);
    299 				if (!c)
    300 					break;
    301 				if (menu->xw - 4 >= l - x)
    302 					set_char(term,
    303 					         menu->x + menu->xw - 2 - l + x,
    304 					         s, c, co);
    305 			}
    306 			for (x = 0; x < menu->xw - 4; x++) {
    307 				c = GET_TERM_CHAR(term, &tmptext);
    308 				if (!c)
    309 					break;
    310 				if (!h
    311 				    && charset_upcase(c, 0)
    312 				           == menu->hotkeys[p]) {
    313 					h = 1;
    314 					set_char(term, menu->x + x + 2, s, c,
    315 					         COLOR_MENU_HOTKEY);
    316 				} else
    317 					set_char(term, menu->x + x + 2, s, c,
    318 					         co);
    319 			}
    320 		} else {
    321 			set_char(term, menu->x, s, 0xc3,
    322 			         COLOR_MENU_FRAME | ATTR_FRAME);
    323 			fill_area(term, menu->x + 1, s, menu->xw - 2, 1, 0xc4,
    324 			          COLOR_MENU_FRAME | ATTR_FRAME);
    325 			set_char(term, menu->x + menu->xw - 1, s, 0xb4,
    326 			         COLOR_MENU_FRAME | ATTR_FRAME);
    327 		}
    328 	}
    329 }
    330 
    331 static void
    332 menu_func(struct window *win, struct links_event *ev, int fwd)
    333 {
    334 	int s = 0;
    335 	int xp, yp;
    336 	struct menu *menu = win->data;
    337 	menu->win = win;
    338 	switch ((int)ev->ev) {
    339 	case EV_INIT:
    340 	case EV_RESIZE:
    341 		get_parent_ptr(win, &menu->xp, &menu->yp);
    342 		count_menu_size(win->term, menu);
    343 		goto xxx;
    344 	case EV_REDRAW:
    345 		get_parent_ptr(win, &xp, &yp);
    346 		if (xp != menu->xp || yp != menu->yp) {
    347 			menu->xp = xp;
    348 			menu->yp = yp;
    349 			count_menu_size(win->term, menu);
    350 		}
    351 xxx:
    352 		menu->selected--;
    353 		scroll_menu(menu, 1);
    354 		draw_to_window(win, display_menu_txt, menu);
    355 		break;
    356 	case EV_MOUSE:
    357 		if ((ev->b & BM_ACT) == B_MOVE)
    358 			break;
    359 		if ((ev->b & BM_BUTT) == B_FOURTH
    360 		    || (ev->b & BM_BUTT) == B_FIFTH) {
    361 			if ((ev->b & BM_ACT) == B_DOWN)
    362 				goto go_lr;
    363 			break;
    364 		}
    365 		if ((ev->b & BM_BUTT) == B_SIXTH)
    366 			break;
    367 
    368 		if (ev->x < menu->x || ev->x >= menu->x + menu->xw
    369 		    || ev->y < menu->y || ev->y >= menu->y + menu->yw) {
    370 			struct window *w1 = NULL;
    371 			struct list_head *w1l;
    372 			foreachfrom (struct window, w1, w1l, win->term->windows,
    373 			             &win->list_entry) {
    374 				struct menu *m1;
    375 				if (w1->handler == mainmenu_func) {
    376 					if (ev->y < 1)
    377 						goto del;
    378 					break;
    379 				}
    380 				if (w1->handler != menu_func)
    381 					break;
    382 				m1 = w1->data;
    383 				if (ev->x > m1->x && ev->x < m1->x + m1->xw - 1
    384 				    && ev->y > m1->y
    385 				    && ev->y < m1->y + m1->yw - 1)
    386 					goto del;
    387 			}
    388 			if ((ev->b & BM_ACT) == B_DOWN)
    389 				goto del;
    390 			if (0)
    391 del:
    392 				delete_window_ev(win, ev);
    393 		} else {
    394 			if (!(ev->x < menu->x || ev->x >= menu->x + menu->xw
    395 			      || ev->y < menu->y + 1
    396 			      || ev->y >= menu->y + menu->yw - 1)) {
    397 				int s = ev->y - menu->y - 1 + menu->view;
    398 				if (s >= 0 && s < menu->ni
    399 				    && menu->items[s].hotkey != M_BAR) {
    400 					menu->selected = s;
    401 					scroll_menu(menu, 0);
    402 					draw_to_window(win, display_menu_txt,
    403 					               menu);
    404 					if ((ev->b & BM_ACT) == B_UP)
    405 						select_menu(win->term, menu);
    406 				}
    407 			}
    408 		}
    409 		break;
    410 	case EV_KBD:
    411 		if (ev->y & KBD_PASTING)
    412 			break;
    413 		if (ev->x == KBD_LEFT || ev->x == KBD_RIGHT) {
    414 go_lr:
    415 			if (win->list_entry.next == &win->term->windows)
    416 				goto mm;
    417 			if (list_struct(win->list_entry.next, struct window)
    418 			        ->handler
    419 			    == mainmenu_func)
    420 				goto mm;
    421 			if (ev->ev == EV_MOUSE && (ev->b & BM_BUTT) == B_FIFTH)
    422 				goto mm;
    423 			if (ev->ev == EV_KBD && ev->x == KBD_RIGHT)
    424 				goto enter;
    425 			delete_window(win);
    426 			break;
    427 		}
    428 		if (ev->x == KBD_ESC) {
    429 			if (win->list_entry.next == &win->term->windows)
    430 				ev = NULL;
    431 			else if (list_struct(win->list_entry.next,
    432 			                     struct window)
    433 			             ->handler
    434 			         != mainmenu_func)
    435 				ev = NULL;
    436 			delete_window_ev(win, ev);
    437 			break;
    438 		}
    439 		if (KBD_ESCAPE_MENU(ev->x) || ev->y & KBD_ALT) {
    440 mm:
    441 			delete_window_ev(win, ev);
    442 			break;
    443 		}
    444 		if (ev->x == KBD_UP)
    445 			scroll_menu(menu, -1);
    446 		else if (ev->x == KBD_DOWN)
    447 			scroll_menu(menu, 1);
    448 		else if (ev->x == KBD_HOME
    449 		         || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) {
    450 			menu->selected = -1;
    451 			scroll_menu(menu, 1);
    452 		} else if (ev->x == KBD_END
    453 		           || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) {
    454 			menu->selected = menu->ni;
    455 			scroll_menu(menu, -1);
    456 		} else if (ev->x == KBD_PAGE_UP
    457 		           || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) {
    458 			if ((menu->selected -= menu->yw - 3) < -1)
    459 				menu->selected = -1;
    460 			if ((menu->view -= menu->yw - 2) < 0)
    461 				menu->view = 0;
    462 			scroll_menu(menu, -1);
    463 		} else if (ev->x == KBD_PAGE_DOWN
    464 		           || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL)) {
    465 			if ((menu->selected += menu->yw - 3) > menu->ni)
    466 				menu->selected = menu->ni;
    467 			if ((menu->view += menu->yw - 2)
    468 			    >= menu->ni - menu->yw + 2)
    469 				menu->view = menu->ni - menu->yw + 2;
    470 			scroll_menu(menu, 1);
    471 		} else if (ev->x > ' ') {
    472 			int i;
    473 			for (i = 0; i < menu->ni; i++) {
    474 				if (charset_upcase(ev->x, 0)
    475 				    == menu->hotkeys[i]) {
    476 					menu->selected = i;
    477 					scroll_menu(menu, 0);
    478 					s = 1;
    479 				}
    480 			}
    481 		}
    482 		draw_to_window(win, display_menu_txt, menu);
    483 		if (s || ev->x == KBD_ENTER || ev->x == ' ')
    484 enter:
    485 			select_menu(win->term, menu);
    486 		break;
    487 	case EV_ABORT:
    488 		if (menu->items->free_i) {
    489 			int i;
    490 			for (i = 0; i < menu->ni; i++) {
    491 				if (menu->items[i].free_i & MENU_FREE_TEXT)
    492 					free(menu->items[i].text);
    493 				if (menu->items[i].free_i & MENU_FREE_RTEXT)
    494 					free(menu->items[i].rtext);
    495 				if (menu->items[i].free_i & MENU_FREE_HOTKEY)
    496 					free(menu->items[i].hotkey);
    497 			}
    498 			if (menu->items->free_i & MENU_FREE_ITEMS)
    499 				free(menu->items);
    500 		}
    501 		if (menu->free_function)
    502 			register_bottom_half(menu->free_function,
    503 			                     menu->free_data);
    504 		break;
    505 	}
    506 }
    507 
    508 void
    509 do_mainmenu(struct terminal *term, struct menu_item *items, void *data, int sel)
    510 {
    511 	int i;
    512 	struct mainmenu *menu;
    513 	for (i = 0; items[i].text; i++)
    514 		if (i == (INT_MAX - sizeof(struct mainmenu)) / sizeof(unsigned))
    515 			overalloc();
    516 	menu = xmalloc(sizeof(struct mainmenu)
    517 	               + (!i ? 0 : i - 1) * sizeof(unsigned));
    518 	menu->selected = sel == -1 ? 0 : sel;
    519 	menu->ni = i;
    520 	menu->items = items;
    521 	menu->data = data;
    522 	for (i = 0; i < menu->ni; i++)
    523 		menu->hotkeys[i] = select_hotkey(term, NULL, items[i].hotkey,
    524 		                                 menu->hotkeys, i);
    525 	add_window(term, mainmenu_func, menu);
    526 	if (sel != -1) {
    527 		struct links_event ev = { EV_KBD, KBD_ENTER, 0, 0 };
    528 		struct window *win =
    529 		    list_struct(term->windows.next, struct window);
    530 		win->handler(win, (struct links_event *)&ev, 0);
    531 	}
    532 }
    533 
    534 static void
    535 display_mainmenu(struct terminal *term, void *menu_)
    536 {
    537 	struct mainmenu *menu = (struct mainmenu *)menu_;
    538 	int i;
    539 	int p = 2;
    540 	fill_area(term, 0, 0, term->x, 1, ' ', COLOR_MAINMENU);
    541 	for (i = 0; i < menu->ni; i++) {
    542 		int s = 0;
    543 		unsigned c;
    544 		unsigned char *tmptext =
    545 		    get_text_translation(menu->items[i].text, term);
    546 		unsigned char co;
    547 		if (i == menu->selected) {
    548 			s = 1;
    549 			co = COLOR_MAINMENU_SELECTED;
    550 		} else {
    551 			co = COLOR_MAINMENU;
    552 		}
    553 		if (i == menu->selected) {
    554 			fill_area(term, p, 0, 2, 1, ' ', co);
    555 			menu->sp = p;
    556 			set_cursor(term, p, 0, term->x - 1, term->y - 1);
    557 			set_window_ptr(menu->win, p, 1);
    558 		}
    559 		p += 2;
    560 		for (;; p++) {
    561 			c = GET_TERM_CHAR(term, &tmptext);
    562 			if (!c)
    563 				break;
    564 			if (!s && charset_upcase(c, 0) == menu->hotkeys[i]) {
    565 				s = 1;
    566 				set_char(term, p, 0, c, COLOR_MAINMENU_HOTKEY);
    567 			} else {
    568 				set_char(term, p, 0, c, co);
    569 			}
    570 		}
    571 		if (i == menu->selected)
    572 			fill_area(term, p, 0, 2, 1, ' ', co);
    573 		p += 2;
    574 	}
    575 }
    576 
    577 static void
    578 select_mainmenu(struct terminal *term, struct mainmenu *menu)
    579 {
    580 	struct menu_item *it;
    581 	if (menu->selected < 0 || menu->selected >= menu->ni)
    582 		return;
    583 	it = &menu->items[menu->selected];
    584 	if (it->hotkey == M_BAR)
    585 		return;
    586 	if (!it->in_m) {
    587 		struct window *win = NULL;
    588 		struct list_head *lwin;
    589 		foreach (struct window, win, lwin, term->windows) {
    590 			if (win->handler != menu_func
    591 			    && win->handler != mainmenu_func)
    592 				break;
    593 			lwin = lwin->prev;
    594 			delete_window(win);
    595 		}
    596 	}
    597 	it->func(term, it->data, menu->data);
    598 }
    599 
    600 static void
    601 mainmenu_func(struct window *win, struct links_event *ev, int fwd)
    602 {
    603 	int s = 0;
    604 	int in_menu;
    605 	struct mainmenu *menu = win->data;
    606 	menu->win = win;
    607 	switch ((int)ev->ev) {
    608 	case EV_INIT:
    609 	case EV_RESIZE:
    610 		/* FALLTHROUGH */
    611 	case EV_REDRAW:
    612 		draw_to_window(win, display_mainmenu, menu);
    613 		break;
    614 	case EV_MOUSE:
    615 		in_menu = ev->x >= 0 && ev->x < win->term->x && ev->y >= 0
    616 		          && ev->y < 1;
    617 		if ((ev->b & BM_ACT) == B_MOVE)
    618 			break;
    619 		if ((ev->b & BM_BUTT) == B_FOURTH) {
    620 			if ((ev->b & BM_ACT) == B_DOWN)
    621 				goto go_left;
    622 			break;
    623 		}
    624 		if ((ev->b & BM_BUTT) == B_FIFTH) {
    625 			if ((ev->b & BM_ACT) == B_DOWN)
    626 				goto go_right;
    627 			break;
    628 		}
    629 		if ((ev->b & BM_BUTT) == B_SIXTH) {
    630 			break;
    631 		}
    632 		if ((ev->b & BM_ACT) == B_DOWN && !in_menu)
    633 			delete_window_ev(win, ev);
    634 		else if (in_menu) {
    635 			int i;
    636 			int p = 2;
    637 			for (i = 0; i < menu->ni; i++) {
    638 				int o = p;
    639 				unsigned char *tmptext = get_text_translation(
    640 				    menu->items[i].text, win->term);
    641 				p += txtlen(tmptext) + 4;
    642 				if (ev->x >= o && ev->x < p) {
    643 					menu->selected = i;
    644 					draw_to_window(win, display_mainmenu,
    645 					               menu);
    646 					if ((ev->b & BM_ACT) == B_UP
    647 					    || menu->items[s].in_m)
    648 						select_mainmenu(win->term,
    649 						                menu);
    650 					break;
    651 				}
    652 			}
    653 		}
    654 		break;
    655 	case EV_KBD:
    656 		if (ev->y & KBD_PASTING)
    657 			break;
    658 		if (ev->x == ' ' || ev->x == KBD_ENTER || ev->x == KBD_DOWN
    659 		    || ev->x == KBD_UP || ev->x == KBD_PAGE_DOWN
    660 		    || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL)
    661 		    || ev->x == KBD_PAGE_UP
    662 		    || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) {
    663 			select_mainmenu(win->term, menu);
    664 			break;
    665 		} else if (ev->x == KBD_LEFT) {
    666 go_left:
    667 			if (!menu->selected--)
    668 				menu->selected = menu->ni - 1;
    669 			s = 1;
    670 			if (fwd)
    671 				s = 2;
    672 		} else if (ev->x == KBD_RIGHT) {
    673 go_right:
    674 			if (++menu->selected >= menu->ni)
    675 				menu->selected = 0;
    676 			s = 1;
    677 			if (fwd)
    678 				s = 2;
    679 		} else if (ev->x == KBD_HOME
    680 		           || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) {
    681 			menu->selected = 0;
    682 			s = 1;
    683 		} else if (ev->x == KBD_END
    684 		           || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) {
    685 			menu->selected = menu->ni - 1;
    686 			s = 1;
    687 		} else if (ev->x > ' ') {
    688 			int i;
    689 			s = 1;
    690 			for (i = 0; i < menu->ni; i++) {
    691 				if (charset_upcase(ev->x, 0)
    692 				    == menu->hotkeys[i]) {
    693 					menu->selected = i;
    694 					s = 2;
    695 				}
    696 			}
    697 		}
    698 		if (!s) {
    699 			delete_window_ev(win, KBD_ESCAPE_MENU(ev->x)
    700 			                              || ev->y & KBD_ALT
    701 			                          ? ev
    702 			                          : NULL);
    703 			break;
    704 		}
    705 		draw_to_window(win, display_mainmenu, menu);
    706 		if (s == 2)
    707 			select_mainmenu(win->term, menu);
    708 		break;
    709 	case EV_ABORT:
    710 		break;
    711 	}
    712 }
    713 
    714 struct menu_item *
    715 new_menu(int free_i)
    716 {
    717 	struct menu_item *mi;
    718 	mi = mem_calloc(sizeof(struct menu_item));
    719 	mi->free_i = free_i;
    720 	return mi;
    721 }
    722 
    723 void
    724 add_to_menu(struct menu_item **mi, unsigned char *text, unsigned char *rtext,
    725             unsigned char *hotkey,
    726             void (*func)(struct terminal *, void *, void *), void *data,
    727             int in_m, int pos)
    728 {
    729 	struct menu_item *mii;
    730 	int n;
    731 	if (pos != -1) {
    732 		n = pos;
    733 		if ((*mi)[n].text)
    734 			internal("invalid menu position %d", n);
    735 	} else
    736 		for (n = 0; (*mi)[n].text; n++)
    737 			if (n == INT_MAX)
    738 				overalloc();
    739 	if (((unsigned)n + 2) > INT_MAX / sizeof(struct menu_item))
    740 		overalloc();
    741 	mii = xrealloc(*mi, (n + 2) * sizeof(struct menu_item));
    742 	*mi = mii;
    743 	memcpy(mii + n + 1, mii + n, sizeof(struct menu_item));
    744 	mii[n].text = text;
    745 	mii[n].rtext = rtext;
    746 	mii[n].hotkey = hotkey;
    747 	mii[n].func = func;
    748 	mii[n].data = data;
    749 	mii[n].in_m = in_m;
    750 }
    751 
    752 void
    753 do_dialog(struct terminal *term, struct dialog *dlg, struct memory_list *ml)
    754 {
    755 	struct dialog_data *dd;
    756 	struct dialog_item *d;
    757 	int n = 0;
    758 	for (d = dlg->items; d->type != D_END; d++) {
    759 		if (n == INT_MAX)
    760 			overalloc();
    761 		n++;
    762 	}
    763 	if ((unsigned)n > (INT_MAX - sizeof(struct dialog_data))
    764 	                      / sizeof(struct dialog_item_data))
    765 		overalloc();
    766 	dd = mem_calloc(sizeof(struct dialog_data)
    767 	                + sizeof(struct dialog_item_data) * n);
    768 	dd->dlg = dlg;
    769 	dd->n = n;
    770 	dd->ml = ml;
    771 	add_window(term, dialog_func, dd);
    772 }
    773 
    774 void
    775 display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, int sel)
    776 {
    777 	struct terminal *term = dlg->win->term;
    778 	unsigned char co;
    779 	unsigned char *text, *t;
    780 	int vposlen, cposlen;
    781 
    782 	switch (di->item->type) {
    783 	case D_CHECKBOX:
    784 		/* radio or checkbox */
    785 		if (di->checked)
    786 			print_text(term, di->x, di->y, 3, cast_uchar "[X]",
    787 			           COLOR_DIALOG_CHECKBOX);
    788 		else
    789 			print_text(term, di->x, di->y, 3, cast_uchar "[ ]",
    790 			           COLOR_DIALOG_CHECKBOX);
    791 		if (sel) {
    792 			set_cursor(term, di->x + 1, di->y, di->x + 1, di->y);
    793 			set_window_ptr(dlg->win, di->x, di->y);
    794 		}
    795 		break;
    796 	case D_FIELD:
    797 	case D_FIELD_PASS:
    798 		fill_area(term, di->x, di->y, di->l, 1, ' ',
    799 		          COLOR_DIALOG_FIELD);
    800 		if (di->vpos > di->cpos)
    801 			di->vpos = di->cpos;
    802 		vposlen = strlen((char *)(di->cdata + di->vpos));
    803 		cposlen = strlen((char *)(di->cdata + di->cpos));
    804 		if (!di->l) {
    805 			di->vpos = di->cpos;
    806 			vposlen = cposlen;
    807 		} else {
    808 			while (vposlen - cposlen > di->l - 1) {
    809 				t = di->cdata + di->vpos;
    810 				GET_TERM_CHAR(term, &t);
    811 				di->vpos = (int)(t - di->cdata);
    812 				vposlen--;
    813 			}
    814 		}
    815 		if (di->item->type == D_FIELD_PASS) {
    816 			t = xmalloc(vposlen + 1);
    817 			memset(t, '*', vposlen);
    818 			t[vposlen] = 0;
    819 		} else {
    820 			t = di->cdata + di->vpos;
    821 		}
    822 		print_text(term, di->x, di->y, di->l, t,
    823 		           COLOR_DIALOG_FIELD_TEXT);
    824 		if (di->item->type == D_FIELD_PASS)
    825 			free(t);
    826 		if (sel) {
    827 			set_cursor(term, di->x + vposlen - cposlen, di->y,
    828 			           di->x + vposlen - cposlen, di->y);
    829 			set_window_ptr(dlg->win, di->x, di->y);
    830 		}
    831 		break;
    832 	case D_BUTTON:
    833 		co = sel ? COLOR_DIALOG_BUTTON_SELECTED : COLOR_DIALOG_BUTTON;
    834 		text = get_text_translation(di->item->text, term);
    835 		print_text(term, di->x, di->y, 2, cast_uchar "[ ", co);
    836 		print_text(term, di->x + 2, di->y, strlen((char *)text), text,
    837 		           co);
    838 		print_text(term, di->x + 2 + strlen((char *)text), di->y, 2,
    839 		           cast_uchar " ]", co);
    840 		if (sel) {
    841 			set_cursor(term, di->x + 2, di->y, di->x + 2, di->y);
    842 			set_window_ptr(dlg->win, di->x, di->y);
    843 		}
    844 		break;
    845 	default:
    846 		internal("display_dlg_item: unknown item: %d", di->item->type);
    847 	}
    848 }
    849 
    850 struct dspd {
    851 	struct dialog_data *dlg;
    852 	struct dialog_item_data *di;
    853 	int sel;
    854 };
    855 
    856 static void
    857 u_display_dlg_item(struct terminal *term, void *p)
    858 {
    859 	struct dspd *d = p;
    860 	display_dlg_item(d->dlg, d->di, d->sel);
    861 }
    862 
    863 static void
    864 x_display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di,
    865                    int sel)
    866 {
    867 	struct dspd dspd;
    868 	dspd.dlg = dlg;
    869 	dspd.di = di;
    870 	dspd.sel = sel;
    871 	draw_to_window(dlg->win, u_display_dlg_item, &dspd);
    872 }
    873 
    874 static void
    875 dlg_select_item(struct dialog_data *dlg, struct dialog_item_data *di)
    876 {
    877 	if (di->item->type == D_CHECKBOX) {
    878 		if (!di->item->gid)
    879 			di->checked = *(int *)di->cdata = !*(int *)di->cdata;
    880 		else {
    881 			int i;
    882 			for (i = 0; i < dlg->n; i++) {
    883 				if (dlg->items[i].item->type == D_CHECKBOX
    884 				    && dlg->items[i].item->gid
    885 				           == di->item->gid) {
    886 					*(int *)dlg->items[i].cdata =
    887 					    di->item->gnum;
    888 					dlg->items[i].checked = 0;
    889 					x_display_dlg_item(dlg, &dlg->items[i],
    890 					                   0);
    891 				}
    892 			}
    893 			di->checked = 1;
    894 		}
    895 		x_display_dlg_item(dlg, di, 1);
    896 	} else if (di->item->type == D_BUTTON)
    897 		di->item->fn(dlg, di);
    898 }
    899 
    900 static unsigned char *
    901 dlg_get_history_string(struct terminal *term, struct history_item *hi, int l)
    902 {
    903 	unsigned char *s;
    904 	int ch = 0;
    905 	s = stracpy(hi->str);
    906 	if (strlen(cast_const_char s) >= (size_t)l)
    907 		s[l - 1] = 0;
    908 	if (!ch) {
    909 		int r = (int)strlen(cast_const_char s);
    910 		unsigned char *p = s;
    911 		while (r) {
    912 			int chl = utf8chrlen(*p);
    913 			if (chl > r) {
    914 				*p = 0;
    915 				break;
    916 			}
    917 			p += chl;
    918 			r -= chl;
    919 		}
    920 	}
    921 	return s;
    922 }
    923 
    924 static void
    925 dlg_set_history(struct terminal *term, struct dialog_item_data *di)
    926 {
    927 	unsigned char *s;
    928 	if (di->cur_hist == &di->history)
    929 		s = stracpy(cast_uchar "");
    930 	else
    931 		s = dlg_get_history_string(
    932 		    term, list_struct(di->cur_hist, struct history_item),
    933 		    di->item->dlen);
    934 	strcpy(cast_char di->cdata, cast_const_char s);
    935 	di->cpos = (int)strlen(cast_const_char s);
    936 	di->vpos = 0;
    937 	free(s);
    938 }
    939 
    940 static int
    941 dlg_mouse(struct dialog_data *dlg, struct dialog_item_data *di,
    942           struct links_event *ev)
    943 {
    944 	switch (di->item->type) {
    945 	case D_BUTTON:
    946 		if (ev->y != di->y || ev->x < di->x
    947 		    || ev->x >= di->x
    948 		                    + strlen((char *)get_text_translation(
    949 					di->item->text, dlg->win->term))
    950 		                    + 4)
    951 			return 0;
    952 		if (dlg->selected != di - dlg->items) {
    953 			x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
    954 			dlg->selected = (int)(di - dlg->items);
    955 			x_display_dlg_item(dlg, di, 1);
    956 		}
    957 		if ((ev->b & BM_ACT) == B_UP)
    958 			dlg_select_item(dlg, di);
    959 		return 1;
    960 	case D_FIELD:
    961 	case D_FIELD_PASS:
    962 		if (ev->y != di->y || ev->x < di->x || ev->x >= di->x + di->l)
    963 			return 0;
    964 		int p, u;
    965 		unsigned char *t = di->cdata;
    966 		p = di->x - di->vpos;
    967 		while (1) {
    968 			di->cpos = (int)(t - di->cdata);
    969 			if (!*t)
    970 				break;
    971 			GET_UTF_8(t, u);
    972 			if (!u)
    973 				continue;
    974 			p++;
    975 			if (p > ev->x)
    976 				break;
    977 		}
    978 		if (dlg->selected != di - dlg->items) {
    979 			x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
    980 			dlg->selected = (int)(di - dlg->items);
    981 			x_display_dlg_item(dlg, di, 1);
    982 		} else
    983 			x_display_dlg_item(dlg, di, 1);
    984 		return 1;
    985 	case D_CHECKBOX:
    986 		if (ev->y != di->y || ev->x < di->x || ev->x >= di->x + 3)
    987 			return 0;
    988 		if (dlg->selected != di - dlg->items) {
    989 			x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
    990 			dlg->selected = (int)(di - dlg->items);
    991 			x_display_dlg_item(dlg, di, 1);
    992 		}
    993 		if ((ev->b & BM_ACT) == B_UP)
    994 			dlg_select_item(dlg, di);
    995 		return 1;
    996 	}
    997 	return 0;
    998 }
    999 
   1000 static void
   1001 redraw_dialog_items(struct terminal *term, void *dlg_)
   1002 {
   1003 	struct dialog_data *dlg = (struct dialog_data *)dlg_;
   1004 	int i;
   1005 	for (i = 0; i < dlg->n; i++)
   1006 		display_dlg_item(dlg, &dlg->items[i], i == dlg->selected);
   1007 }
   1008 
   1009 static void
   1010 redraw_dialog(struct terminal *term, void *dlg_)
   1011 {
   1012 	struct dialog_data *dlg = (struct dialog_data *)dlg_;
   1013 	dlg->dlg->fn(dlg);
   1014 	redraw_dialog_items(term, dlg);
   1015 }
   1016 
   1017 static void
   1018 tab_compl(struct terminal *term, void *hi_, void *win_)
   1019 {
   1020 	struct history_item *hi = (struct history_item *)hi_;
   1021 	struct window *win = (struct window *)win_;
   1022 	struct links_event ev = { EV_REDRAW, 0, 0, 0 };
   1023 	struct dialog_item_data *di =
   1024 	    &((struct dialog_data *)win->data)
   1025 		 ->items[((struct dialog_data *)win->data)->selected];
   1026 	unsigned char *s = dlg_get_history_string(term, hi, di->item->dlen);
   1027 	strcpy(cast_char di->cdata, cast_const_char s);
   1028 	di->cpos = (int)strlen(cast_const_char s);
   1029 	di->vpos = 0;
   1030 	free(s);
   1031 	ev.x = term->x;
   1032 	ev.y = term->y;
   1033 	dialog_func(win, &ev, 0);
   1034 }
   1035 
   1036 static void
   1037 do_tab_compl(struct terminal *term, struct list_head *history,
   1038              struct window *win)
   1039 {
   1040 	unsigned char *cdata =
   1041 	    ((struct dialog_data *)win->data)
   1042 		->items[((struct dialog_data *)win->data)->selected]
   1043 		.cdata;
   1044 	int l = (int)strlen(cast_const_char cdata), n = 0;
   1045 	struct history_item *hi = NULL;
   1046 	struct list_head *lhi;
   1047 	struct menu_item *items = NULL;
   1048 	foreach (struct history_item, hi, lhi, *history) {
   1049 		unsigned char *s = dlg_get_history_string(term, hi, INT_MAX);
   1050 		if (!strncmp(cast_const_char cdata, cast_const_char s, l)) {
   1051 			if (!(n & (ALLOC_GR - 1))) {
   1052 				if ((unsigned)n
   1053 				    > INT_MAX / sizeof(struct menu_item)
   1054 				          - ALLOC_GR - 1)
   1055 					overalloc();
   1056 				items = xrealloc(
   1057 				    items, (n + ALLOC_GR + 1)
   1058 					       * sizeof(struct menu_item));
   1059 			}
   1060 			items[n].text = s;
   1061 			items[n].rtext = cast_uchar "";
   1062 			items[n].hotkey = cast_uchar "";
   1063 			items[n].func = tab_compl;
   1064 			items[n].rtext = cast_uchar "";
   1065 			items[n].data = hi;
   1066 			items[n].in_m = 0;
   1067 			items[n].free_i = MENU_FREE_ITEMS | MENU_FREE_TEXT;
   1068 			if (n == INT_MAX)
   1069 				overalloc();
   1070 			n++;
   1071 		} else
   1072 			free(s);
   1073 	}
   1074 	if (n == 1) {
   1075 		tab_compl(term, items->data, win);
   1076 		free(items->text);
   1077 		free(items);
   1078 		return;
   1079 	}
   1080 	if (n) {
   1081 		memset(&items[n], 0, sizeof(struct menu_item));
   1082 		do_menu_selected(term, items, win, n - 1, NULL, NULL);
   1083 	}
   1084 }
   1085 
   1086 void
   1087 dialog_func(struct window *win, struct links_event *ev, int fwd)
   1088 {
   1089 	int i;
   1090 	struct terminal *term = win->term;
   1091 	struct dialog_data *dlg = win->data;
   1092 	struct dialog_item_data *di;
   1093 
   1094 	dlg->win = win;
   1095 
   1096 	/* Use nonstandard event handlers */
   1097 	if (dlg->dlg->handle_event
   1098 	    && dlg->dlg->handle_event(dlg, ev) == EVENT_PROCESSED) {
   1099 		return;
   1100 	}
   1101 
   1102 	switch ((int)ev->ev) {
   1103 	case EV_INIT:
   1104 		for (i = 0; i < dlg->n; i++) {
   1105 			struct dialog_item_data *di = &dlg->items[i];
   1106 			memset(di, 0, sizeof(struct dialog_item_data));
   1107 			di->item = &dlg->dlg->items[i];
   1108 			di->cdata = xmalloc(di->item->dlen);
   1109 			if (di->item->dlen)
   1110 				memcpy(di->cdata, di->item->data,
   1111 				       di->item->dlen);
   1112 			if (di->item->type == D_CHECKBOX) {
   1113 				if (di->item->gid) {
   1114 					if (*(int *)di->cdata == di->item->gnum)
   1115 						di->checked = 1;
   1116 				} else if (*(int *)di->cdata)
   1117 					di->checked = 1;
   1118 			}
   1119 			init_list(di->history);
   1120 			di->cur_hist = &di->history;
   1121 			if (di->item->type == D_FIELD
   1122 			    || di->item->type == D_FIELD_PASS) {
   1123 				if (di->item->history) {
   1124 					struct history_item *j = NULL;
   1125 					struct list_head *lj;
   1126 					foreach (struct history_item, j, lj,
   1127 					         di->item->history->items) {
   1128 						struct history_item *hi;
   1129 						size_t sl = strlen(
   1130 						    cast_const_char j->str);
   1131 						if (sl > INT_MAX
   1132 						             - sizeof(
   1133 								 struct
   1134 								 history_item))
   1135 							overalloc();
   1136 						hi = xmalloc(
   1137 						    sizeof(struct history_item)
   1138 						    + sl);
   1139 						strcpy(cast_char hi->str,
   1140 						       cast_const_char j->str);
   1141 						add_to_list(di->history, hi);
   1142 					}
   1143 				}
   1144 				di->cpos =
   1145 				    (int)strlen(cast_const_char di->cdata);
   1146 			}
   1147 		}
   1148 		dlg->selected = 0;
   1149 		/*-fallthrough*/
   1150 	case EV_RESIZE:
   1151 		/* this must be really called twice !!! */
   1152 		draw_to_window(dlg->win, redraw_dialog, dlg);
   1153 		/*-fallthrough*/
   1154 	case EV_REDRAW:
   1155 		draw_to_window(dlg->win, redraw_dialog, dlg);
   1156 		break;
   1157 	case EV_MOUSE:
   1158 		if ((ev->b & BM_ACT) == B_MOVE)
   1159 			break;
   1160 		if ((ev->b & BM_BUTT) == B_FOURTH) {
   1161 			if ((ev->b & BM_ACT) == B_DOWN)
   1162 				goto go_prev;
   1163 			break;
   1164 		}
   1165 		if ((ev->b & BM_BUTT) == B_FIFTH) {
   1166 			if ((ev->b & BM_ACT) == B_DOWN)
   1167 				goto go_next;
   1168 			break;
   1169 		}
   1170 		if ((ev->b & BM_BUTT) == B_SIXTH) {
   1171 			if ((ev->b & BM_ACT) == B_DOWN)
   1172 				goto go_enter;
   1173 			break;
   1174 		}
   1175 		for (i = 0; i < dlg->n; i++)
   1176 			if (dlg_mouse(dlg, &dlg->items[i], ev))
   1177 				break;
   1178 		if ((ev->b & BM_ACT) == B_DOWN
   1179 		    && (ev->b & BM_BUTT) == B_MIDDLE) {
   1180 			/* don't delete this!!! it's here because of jump from
   1181 			 * mouse event */
   1182 			di = &dlg->items[dlg->selected];
   1183 			if (di->item->type == D_FIELD
   1184 			    || di->item->type == D_FIELD_PASS)
   1185 				goto clipbd_paste;
   1186 		}
   1187 		break;
   1188 	case EV_KBD:
   1189 		di = &dlg->items[dlg->selected];
   1190 		if (ev->y & KBD_PASTING) {
   1191 			if (!((di->item->type == D_FIELD
   1192 			       || di->item->type == D_FIELD_PASS)
   1193 			      && (ev->x >= ' '
   1194 			          && !(ev->y & (KBD_CTRL | KBD_ALT)))))
   1195 				break;
   1196 		}
   1197 		if (di->item->type == D_FIELD
   1198 		    || di->item->type == D_FIELD_PASS) {
   1199 			if (ev->x == KBD_UP
   1200 			    && di->cur_hist->prev != &di->history) {
   1201 				di->cur_hist = di->cur_hist->prev;
   1202 				dlg_set_history(term, di);
   1203 				goto dsp_f;
   1204 			}
   1205 			if (ev->x == KBD_DOWN && di->cur_hist != &di->history) {
   1206 				di->cur_hist = di->cur_hist->next;
   1207 				dlg_set_history(term, di);
   1208 				goto dsp_f;
   1209 			}
   1210 			if (ev->x == KBD_RIGHT) {
   1211 				if ((size_t)di->cpos
   1212 				    < strlen(cast_const_char di->cdata)) {
   1213 					int u;
   1214 					unsigned char *p = di->cdata + di->cpos;
   1215 					GET_UTF_8(p, u);
   1216 					di->cpos = (int)(p - di->cdata);
   1217 				}
   1218 				goto dsp_f;
   1219 			}
   1220 			if (ev->x == KBD_LEFT) {
   1221 				if (di->cpos > 0) {
   1222 					unsigned char *p = di->cdata + di->cpos;
   1223 					BACK_UTF_8(p, di->cdata);
   1224 					di->cpos = (int)(p - di->cdata);
   1225 				}
   1226 				goto dsp_f;
   1227 			}
   1228 			if (ev->x == KBD_HOME
   1229 			    || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) {
   1230 				di->cpos = 0;
   1231 				goto dsp_f;
   1232 			}
   1233 			if (ev->x == KBD_END
   1234 			    || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) {
   1235 				di->cpos =
   1236 				    (int)strlen(cast_const_char di->cdata);
   1237 				goto dsp_f;
   1238 			}
   1239 			if (ev->x >= ' ' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
   1240 				unsigned char *u;
   1241 				u = encode_utf_8(ev->x);
   1242 				if (strlen(cast_const_char di->cdata)
   1243 				        + strlen(cast_const_char u)
   1244 				    < (size_t)di->item->dlen) {
   1245 					memmove(
   1246 					    di->cdata + di->cpos
   1247 						+ strlen(cast_const_char u),
   1248 					    di->cdata + di->cpos,
   1249 					    strlen(cast_const_char di->cdata)
   1250 						- di->cpos + 1);
   1251 					memcpy(&di->cdata[di->cpos], u,
   1252 					       strlen(cast_const_char u));
   1253 					di->cpos +=
   1254 					    (int)strlen(cast_const_char u);
   1255 				}
   1256 				goto dsp_f;
   1257 			}
   1258 			if (ev->x == KBD_BS) {
   1259 				if (di->cpos) {
   1260 					int s = 1;
   1261 					unsigned u;
   1262 					unsigned char *p, *pp;
   1263 					p = di->cdata;
   1264 a:
   1265 					pp = p;
   1266 					GET_UTF_8(p, u);
   1267 					if (p < di->cdata + di->cpos)
   1268 						goto a;
   1269 					s = (int)(p - pp);
   1270 					memmove(
   1271 					    di->cdata + di->cpos - s,
   1272 					    di->cdata + di->cpos,
   1273 					    strlen(cast_const_char di->cdata)
   1274 						- di->cpos + s);
   1275 					di->cpos -= s;
   1276 				}
   1277 				goto dsp_f;
   1278 			}
   1279 			if (ev->x == KBD_DEL
   1280 			    || (upcase(ev->x) == 'D' && ev->y & KBD_CTRL)) {
   1281 				if ((size_t)di->cpos
   1282 				    < strlen(cast_const_char di->cdata)) {
   1283 					int s = 1;
   1284 					unsigned u;
   1285 					unsigned char *p = di->cdata + di->cpos;
   1286 					GET_UTF_8(p, u);
   1287 					s = (int)(p - (di->cdata + di->cpos));
   1288 					memmove(
   1289 					    di->cdata + di->cpos,
   1290 					    di->cdata + di->cpos + s,
   1291 					    strlen(cast_const_char di->cdata)
   1292 						- di->cpos + s);
   1293 				}
   1294 				goto dsp_f;
   1295 			}
   1296 			if (upcase(ev->x) == 'U' && ev->y & KBD_CTRL) {
   1297 				unsigned char *a = memacpy(di->cdata, di->cpos);
   1298 				if (a) {
   1299 					set_clipboard_text(term, a);
   1300 					free(a);
   1301 				}
   1302 				memmove(
   1303 				    di->cdata, di->cdata + di->cpos,
   1304 				    strlen(cast_const_char di->cdata + di->cpos)
   1305 					+ 1);
   1306 				di->cpos = 0;
   1307 				goto dsp_f;
   1308 			}
   1309 			if (upcase(ev->x) == 'K' && ev->y & KBD_CTRL) {
   1310 				set_clipboard_text(term, di->cdata + di->cpos);
   1311 				di->cdata[di->cpos] = 0;
   1312 				goto dsp_f;
   1313 			}
   1314 			/* Copy to clipboard */
   1315 			if ((ev->x == KBD_INS && ev->y & KBD_CTRL)
   1316 			    || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)
   1317 			    || ev->x == KBD_COPY) {
   1318 				set_clipboard_text(term, di->cdata);
   1319 				break; /* We don't need to redraw */
   1320 			}
   1321 			/* FIXME -- why keyboard shortcuts with shift don't
   1322 			 * works??? */
   1323 			/* Cut to clipboard */
   1324 			if ((ev->x == KBD_DEL && ev->y & KBD_SHIFT)
   1325 			    || (upcase(ev->x) == 'X' && ev->y & KBD_CTRL)
   1326 			    || ev->x == KBD_CUT) {
   1327 				set_clipboard_text(term, di->cdata);
   1328 				di->cdata[0] = 0;
   1329 				di->cpos = 0;
   1330 				goto dsp_f;
   1331 			}
   1332 			/* Paste from clipboard */
   1333 			if ((ev->x == KBD_INS && ev->y & KBD_SHIFT)
   1334 			    || (upcase(ev->x) == 'V' && ev->y & KBD_CTRL)
   1335 			    || ev->x == KBD_PASTE) {
   1336 				unsigned char *clipboard;
   1337 clipbd_paste:
   1338 				clipboard = get_clipboard_text(term);
   1339 				if (clipboard) {
   1340 					unsigned char *nl = clipboard;
   1341 					while ((nl = cast_uchar strchr(
   1342 						    cast_const_char nl, '\n')))
   1343 						*nl = ' ';
   1344 					if (strlen(cast_const_char di->cdata)
   1345 					            + strlen(cast_const_char
   1346 					                         clipboard)
   1347 					        < (size_t)di->item->dlen
   1348 					    || strlen(cast_const_char di->cdata)
   1349 					               + strlen(cast_const_char
   1350 					                            clipboard)
   1351 					           < strlen(cast_const_char di
   1352 					                        ->cdata)) {
   1353 
   1354 						memmove(
   1355 						    di->cdata + di->cpos
   1356 							+ strlen(cast_const_char
   1357 						                     clipboard),
   1358 						    di->cdata + di->cpos,
   1359 						    strlen(cast_const_char di
   1360 						               ->cdata)
   1361 							- di->cpos + 1);
   1362 						memcpy(&di->cdata[di->cpos],
   1363 						       clipboard,
   1364 						       strlen(cast_const_char
   1365 						                  clipboard));
   1366 						di->cpos += (int)strlen(
   1367 						    cast_const_char clipboard);
   1368 					}
   1369 					free(clipboard);
   1370 				}
   1371 				goto dsp_f;
   1372 			}
   1373 			if ((upcase(ev->x) == 'W' && ev->y & KBD_CTRL)
   1374 			    || ev->x == KBD_FIND) {
   1375 				do_tab_compl(term, &di->history, win);
   1376 				goto dsp_f;
   1377 			}
   1378 			goto gh;
   1379 dsp_f:
   1380 			x_display_dlg_item(dlg, di, 1);
   1381 			break;
   1382 		}
   1383 		if ((ev->x == KBD_ENTER && di->item->type == D_BUTTON)
   1384 		    || ev->x == ' ') {
   1385 			dlg_select_item(dlg, di);
   1386 			break;
   1387 		}
   1388 gh:
   1389 		if (ev->x > ' ')
   1390 			for (i = 0; i < dlg->n; i++) {
   1391 				unsigned char *tx = get_text_translation(
   1392 				    dlg->dlg->items[i].text, term);
   1393 				if (dlg->dlg->items[i].type == D_BUTTON
   1394 				    && charset_upcase(GET_TERM_CHAR(term, &tx),
   1395 				                      0)
   1396 				           == charset_upcase(ev->x, 0))
   1397 					goto sel;
   1398 			}
   1399 		if (ev->x == KBD_ENTER) {
   1400 go_enter:
   1401 			for (i = 0; i < dlg->n; i++)
   1402 				if (dlg->dlg->items[i].type == D_BUTTON
   1403 				    && dlg->dlg->items[i].gid & B_ENTER)
   1404 					goto sel;
   1405 			break;
   1406 		}
   1407 		if (ev->x == KBD_ESC) {
   1408 			for (i = 0; i < dlg->n; i++)
   1409 				if (dlg->dlg->items[i].type == D_BUTTON
   1410 				    && dlg->dlg->items[i].gid & B_ESC)
   1411 					goto sel;
   1412 			break;
   1413 		}
   1414 		if (0) {
   1415 sel:
   1416 			if (dlg->selected != i) {
   1417 				x_display_dlg_item(
   1418 				    dlg, &dlg->items[dlg->selected], 0);
   1419 				x_display_dlg_item(dlg, &dlg->items[i], 1);
   1420 				dlg->selected = i;
   1421 			}
   1422 			dlg_select_item(dlg, &dlg->items[i]);
   1423 			break;
   1424 		}
   1425 		if (((ev->x == KBD_TAB && !ev->y) || ev->x == KBD_DOWN
   1426 		     || ev->x == KBD_RIGHT)
   1427 		    && dlg->n > 1) {
   1428 go_next:
   1429 			x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
   1430 			if ((++dlg->selected) >= dlg->n)
   1431 				dlg->selected = 0;
   1432 			x_display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
   1433 			break;
   1434 		}
   1435 		if (((ev->x == KBD_TAB && ev->y) || ev->x == KBD_UP
   1436 		     || ev->x == KBD_LEFT)
   1437 		    && dlg->n > 1) {
   1438 go_prev:
   1439 			x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
   1440 			if ((--dlg->selected) < 0)
   1441 				dlg->selected = dlg->n - 1;
   1442 			x_display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
   1443 			break;
   1444 		}
   1445 		break;
   1446 	case EV_ABORT:
   1447 		/* Moved this line up so that the dlg would have access to its
   1448 		   member vars before they get freed. */
   1449 		if (dlg->dlg->abort)
   1450 			dlg->dlg->abort(dlg);
   1451 		for (i = 0; i < dlg->n; i++) {
   1452 			struct dialog_item_data *di = &dlg->items[i];
   1453 			free(di->cdata);
   1454 			free_list(struct history_item, di->history);
   1455 		}
   1456 		freeml(dlg->ml);
   1457 	}
   1458 }
   1459 
   1460 /* gid and gnum are 100 times greater than boundaries (e.g. if gid==1 boundary
   1461  * is 0.01) */
   1462 int
   1463 check_float(struct dialog_data *dlg, struct dialog_item_data *di)
   1464 {
   1465 	char *end;
   1466 	double d = strtod(cast_const_char di->cdata, &end);
   1467 	if (!*di->cdata || *end
   1468 	    || di->cdata[strspn(cast_const_char di->cdata, "0123456789.")]
   1469 	    || *di->cdata == (unsigned char)'.') {
   1470 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER,
   1471 		        TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1,
   1472 		        TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
   1473 		return 1;
   1474 	}
   1475 	if (d < 0 || d > di->item->gnum || 100 * d < di->item->gid
   1476 	    || 100 * d > di->item->gnum) {
   1477 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER,
   1478 		        TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1,
   1479 		        TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
   1480 		return 1;
   1481 	}
   1482 	return 0;
   1483 }
   1484 
   1485 int
   1486 check_number(struct dialog_data *dlg, struct dialog_item_data *di)
   1487 {
   1488 	char *end;
   1489 	long l = strtol(cast_const_char di->cdata, &end, 10);
   1490 	if (!*di->cdata || *end) {
   1491 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER,
   1492 		        TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1,
   1493 		        TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
   1494 		return 1;
   1495 	}
   1496 	if (l < di->item->gid || l > di->item->gnum) {
   1497 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER,
   1498 		        TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1,
   1499 		        TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
   1500 		return 1;
   1501 	}
   1502 	return 0;
   1503 }
   1504 
   1505 int
   1506 check_hex_number(struct dialog_data *dlg, struct dialog_item_data *di)
   1507 {
   1508 	char *end;
   1509 	long l = strtol(cast_const_char di->cdata, &end, 16);
   1510 	if (!*di->cdata || *end) {
   1511 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER,
   1512 		        TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1,
   1513 		        TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
   1514 		return 1;
   1515 	}
   1516 	if (l < di->item->gid || l > di->item->gnum) {
   1517 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER,
   1518 		        TEXT_(T_NUMBER_OUT_OF_RANGE), MSG_BOX_END, NULL, 1,
   1519 		        TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
   1520 		return 1;
   1521 	}
   1522 	return 0;
   1523 }
   1524 
   1525 int
   1526 check_nonempty(struct dialog_data *dlg, struct dialog_item_data *di)
   1527 {
   1528 	unsigned char *p;
   1529 	for (p = di->cdata; *p; p++)
   1530 		if (*p > ' ')
   1531 			return 0;
   1532 	msg_box(dlg->win->term, NULL, TEXT_(T_BAD_STRING), AL_CENTER,
   1533 	        TEXT_(T_EMPTY_STRING_NOT_ALLOWED), MSG_BOX_END, NULL, 1,
   1534 	        TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
   1535 	return 1;
   1536 }
   1537 
   1538 static int
   1539 check_local_ip_address_internal(struct dialog_data *dlg,
   1540                                 struct dialog_item_data *di, int pf)
   1541 {
   1542 	int s;
   1543 	int rs;
   1544 	unsigned char *p = di->cdata;
   1545 	if (!*p) {
   1546 		return 0;
   1547 	}
   1548 	if (pf == PF_INET6)
   1549 		rs = numeric_ipv6_address((char *)p, NULL, NULL);
   1550 	else
   1551 		rs = numeric_ip_address((char *)p, NULL);
   1552 	if (rs) {
   1553 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_IP_ADDRESS),
   1554 		        AL_CENTER, TEXT_(T_INVALID_IP_ADDRESS_SYNTAX),
   1555 		        MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null,
   1556 		        B_ENTER | B_ESC);
   1557 		return 1;
   1558 	}
   1559 	s = socket_and_bind(pf, p);
   1560 	if (s != -1)
   1561 		EINTRLOOP(rs, close(s));
   1562 	else {
   1563 		if (1
   1564 #ifdef ENFILE
   1565 		    && errno != ENFILE
   1566 #endif
   1567 #ifdef EMFILE
   1568 		    && errno != EMFILE
   1569 #endif
   1570 #ifdef ENOBUFS
   1571 		    && errno != ENOBUFS
   1572 #endif
   1573 #ifdef ENOMEM
   1574 		    && errno != ENOMEM
   1575 #endif
   1576 		) {
   1577 			unsigned char *er = stracpy(cast_uchar strerror(errno));
   1578 			unsigned char *ad = stracpy(p);
   1579 			msg_box(dlg->win->term, getml(er, ad, NULL),
   1580 			        TEXT_(T_BAD_IP_ADDRESS), AL_CENTER,
   1581 			        TEXT_(T_UNABLE_TO_USE_LOCAL_IP_ADDRESS),
   1582 			        cast_uchar " ", ad, cast_uchar ": ", er,
   1583 			        MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL),
   1584 			        msg_box_null, B_ENTER | B_ESC);
   1585 			return 1;
   1586 		}
   1587 	}
   1588 	return 0;
   1589 }
   1590 
   1591 int
   1592 check_local_ip_address(struct dialog_data *dlg, struct dialog_item_data *di)
   1593 {
   1594 	return check_local_ip_address_internal(dlg, di, PF_INET);
   1595 }
   1596 
   1597 int
   1598 check_local_ipv6_address(struct dialog_data *dlg, struct dialog_item_data *di)
   1599 {
   1600 	return check_local_ip_address_internal(dlg, di, PF_INET6);
   1601 }
   1602 
   1603 int
   1604 cancel_dialog(struct dialog_data *dlg, struct dialog_item_data *di)
   1605 {
   1606 	delete_window(dlg->win);
   1607 	return 0;
   1608 }
   1609 
   1610 int
   1611 check_dialog(struct dialog_data *dlg)
   1612 {
   1613 	int i;
   1614 	for (i = 0; i < dlg->n; i++)
   1615 		if (dlg->dlg->items[i].type == D_CHECKBOX
   1616 		    || dlg->dlg->items[i].type == D_FIELD
   1617 		    || dlg->dlg->items[i].type == D_FIELD_PASS)
   1618 			if (dlg->dlg->items[i].fn
   1619 			    && dlg->dlg->items[i].fn(dlg, &dlg->items[i])) {
   1620 				dlg->selected = i;
   1621 				draw_to_window(dlg->win, redraw_dialog_items,
   1622 				               dlg);
   1623 				return 1;
   1624 			}
   1625 	return 0;
   1626 }
   1627 
   1628 void
   1629 get_dialog_data(struct dialog_data *dlg)
   1630 {
   1631 	int i;
   1632 	for (i = 0; i < dlg->n; i++) {
   1633 		void *p1 = dlg->dlg->items[i].data;
   1634 		void *p2 = dlg->items[i].cdata;
   1635 		int l = dlg->dlg->items[i].dlen;
   1636 		if (l)
   1637 			memcpy(p1, p2, l);
   1638 	}
   1639 }
   1640 
   1641 int
   1642 ok_dialog(struct dialog_data *dlg, struct dialog_item_data *di)
   1643 {
   1644 	void (*fn)(void *) = dlg->dlg->refresh;
   1645 	void *data = dlg->dlg->refresh_data;
   1646 	if (check_dialog(dlg))
   1647 		return 1;
   1648 	get_dialog_data(dlg);
   1649 	if (fn)
   1650 		fn(data);
   1651 	return cancel_dialog(dlg, di);
   1652 }
   1653 
   1654 void
   1655 center_dlg(struct dialog_data *dlg)
   1656 {
   1657 	dlg->x = (dlg->win->term->x - dlg->xw) / 2;
   1658 	dlg->y = (dlg->win->term->y - dlg->yw) / 2;
   1659 }
   1660 
   1661 void
   1662 draw_dlg(struct dialog_data *dlg)
   1663 {
   1664 	int i, tpos;
   1665 	struct terminal *term = dlg->win->term;
   1666 
   1667 	fill_area(term, dlg->x, dlg->y, dlg->xw, dlg->yw, ' ', COLOR_DIALOG);
   1668 	draw_frame(term, dlg->x + DIALOG_LEFT_BORDER,
   1669 	           dlg->y + DIALOG_TOP_BORDER, dlg->xw - 2 * DIALOG_LEFT_BORDER,
   1670 	           dlg->yw - 2 * DIALOG_TOP_BORDER, COLOR_DIALOG_FRAME,
   1671 	           DIALOG_FRAME);
   1672 	i = strlen((char *)get_text_translation(dlg->dlg->title, term));
   1673 	tpos = (dlg->xw - i) / 2;
   1674 	print_text(term, tpos + dlg->x - 1, dlg->y + DIALOG_TOP_BORDER, 1,
   1675 	           cast_uchar " ", COLOR_DIALOG_TITLE);
   1676 	print_text(term, tpos + dlg->x, dlg->y + DIALOG_TOP_BORDER, i,
   1677 	           get_text_translation(dlg->dlg->title, term),
   1678 	           COLOR_DIALOG_TITLE);
   1679 	print_text(term, tpos + dlg->x + i, dlg->y + DIALOG_TOP_BORDER, 1,
   1680 	           cast_uchar " ", COLOR_DIALOG_TITLE);
   1681 }
   1682 
   1683 void
   1684 max_text_width(struct terminal *term, unsigned char *text, int *width,
   1685                int align)
   1686 {
   1687 	text = get_text_translation(text, term);
   1688 	do {
   1689 		int c = 0;
   1690 		while (*text && *text != '\n') {
   1691 			int u;
   1692 			GET_UTF_8(text, u);
   1693 			c++;
   1694 		}
   1695 		if (c > *width)
   1696 			*width = c;
   1697 	} while (*(text++));
   1698 }
   1699 
   1700 void
   1701 min_text_width(struct terminal *term, unsigned char *text, int *width,
   1702                int align)
   1703 {
   1704 	text = get_text_translation(text, term);
   1705 	do {
   1706 		int c = 0;
   1707 		while (*text && *text != '\n' && *text != ' ') {
   1708 			int u;
   1709 			GET_UTF_8(text, u);
   1710 			c++;
   1711 		}
   1712 		if (c > *width)
   1713 			*width = c;
   1714 	} while (*(text++));
   1715 }
   1716 
   1717 int
   1718 dlg_format_text(struct dialog_data *dlg, struct terminal *term,
   1719                 unsigned char *text, int x, int *y, int w, int *rw,
   1720                 unsigned char co, int align)
   1721 {
   1722 	int xx = x;
   1723 	text = get_text_translation(text, dlg->win->term);
   1724 	for (;;) {
   1725 		unsigned char *t1;
   1726 		unsigned ch;
   1727 		int cx, lbr;
   1728 
   1729 		t1 = text;
   1730 		cx = 0;
   1731 		lbr = 0;
   1732 next_chr:
   1733 		ch = GET_TERM_CHAR(dlg->win->term, &t1);
   1734 		if (ch == ' ') {
   1735 			lbr = cx;
   1736 		}
   1737 		if (ch && ch != '\n') {
   1738 			if (cx == w) {
   1739 				if (!lbr)
   1740 					lbr = cx;
   1741 				goto print_line;
   1742 			}
   1743 			cx++;
   1744 			goto next_chr;
   1745 		}
   1746 		if (!ch && !cx)
   1747 			break;
   1748 		lbr = cx;
   1749 print_line:
   1750 		if (rw && lbr > *rw)
   1751 			*rw = lbr;
   1752 		xx = x;
   1753 		if ((align & AL_MASK) == AL_CENTER) {
   1754 			xx += (w - lbr) / 2;
   1755 		}
   1756 		for (; lbr--; xx++) {
   1757 			ch = GET_TERM_CHAR(dlg->win->term, &text);
   1758 			if (term)
   1759 				set_char(term, xx, *y, ch, co);
   1760 		}
   1761 		xx++;
   1762 		if (*text == ' ' || *text == '\n')
   1763 			text++;
   1764 		(*y)++;
   1765 	}
   1766 	return xx - x;
   1767 }
   1768 
   1769 void
   1770 max_buttons_width(struct terminal *term, struct dialog_item_data *butt, int n,
   1771                   int *width)
   1772 {
   1773 	int w = -2;
   1774 	int i;
   1775 	for (i = 0; i < n; i++)
   1776 		w += txtlen(get_text_translation((butt++)->item->text, term))
   1777 		     + 6;
   1778 	if (w > *width)
   1779 		*width = w;
   1780 }
   1781 
   1782 void
   1783 min_buttons_width(struct terminal *term, struct dialog_item_data *butt, int n,
   1784                   int *width)
   1785 {
   1786 	int i;
   1787 	for (i = 0; i < n; i++) {
   1788 		int w = txtlen(get_text_translation((butt++)->item->text, term))
   1789 		        + 4;
   1790 		if (w > *width)
   1791 			*width = w;
   1792 	}
   1793 }
   1794 
   1795 void
   1796 dlg_format_buttons(struct dialog_data *dlg, struct terminal *term,
   1797                    struct dialog_item_data *butt, int n, int x, int *y, int w,
   1798                    int *rw, int align)
   1799 {
   1800 	int i1 = 0;
   1801 	while (i1 < n) {
   1802 		int i2 = i1 + 1;
   1803 		int mw;
   1804 		while (i2 < n) {
   1805 			mw = 0;
   1806 			max_buttons_width(dlg->win->term, butt + i1,
   1807 			                  i2 - i1 + 1, &mw);
   1808 			if (mw <= w)
   1809 				i2++;
   1810 			else
   1811 				break;
   1812 		}
   1813 		mw = 0;
   1814 		max_buttons_width(dlg->win->term, butt + i1, i2 - i1, &mw);
   1815 		if (rw && mw > *rw)
   1816 			if ((*rw = mw) > w)
   1817 				*rw = w;
   1818 		if (term) {
   1819 			int i;
   1820 			int p = x
   1821 			        + ((align & AL_MASK) == AL_CENTER ? (w - mw) / 2
   1822 			                                          : 0);
   1823 			for (i = i1; i < i2; i++) {
   1824 				butt[i].x = p;
   1825 				butt[i].y = *y;
   1826 				p += (butt[i].l = txtlen(get_text_translation(
   1827 						      butt[i].item->text,
   1828 						      dlg->win->term))
   1829 				                  + 4)
   1830 				     + 2;
   1831 			}
   1832 		}
   1833 		*y += 2;
   1834 		i1 = i2;
   1835 	}
   1836 }
   1837 
   1838 void
   1839 dlg_format_checkbox(struct dialog_data *dlg, struct terminal *term,
   1840                     struct dialog_item_data *chkb, int x, int *y, int w,
   1841                     int *rw, unsigned char *text)
   1842 {
   1843 	int k = 4;
   1844 	if (term) {
   1845 		chkb->x = x;
   1846 		chkb->y = *y;
   1847 	}
   1848 	if (rw)
   1849 		*rw -= k;
   1850 	dlg_format_text(dlg, term, text, x + k, y, w - k, rw,
   1851 	                COLOR_DIALOG_CHECKBOX_TEXT, AL_LEFT | AL_NOBRLEXP);
   1852 	if (rw)
   1853 		*rw += k;
   1854 }
   1855 
   1856 void
   1857 dlg_format_checkboxes(struct dialog_data *dlg, struct terminal *term,
   1858                       struct dialog_item_data *chkb, int n, int x, int *y,
   1859                       int w, int *rw, unsigned char *const *texts)
   1860 {
   1861 	while (n) {
   1862 		dlg_format_checkbox(dlg, term, chkb, x, y, w, rw, texts[0]);
   1863 		texts++;
   1864 		chkb++;
   1865 		n--;
   1866 	}
   1867 }
   1868 
   1869 void
   1870 checkboxes_width(struct terminal *term, unsigned char *const *texts, int n,
   1871                  int *w,
   1872                  void (*fn)(struct terminal *, unsigned char *, int *, int))
   1873 {
   1874 	int k = 4;
   1875 	while (n--) {
   1876 		*w -= k;
   1877 		fn(term, get_text_translation(texts[0], term), w, 0);
   1878 		*w += k;
   1879 		texts++;
   1880 	}
   1881 }
   1882 
   1883 void
   1884 dlg_format_field(struct dialog_data *dlg, struct terminal *term,
   1885                  struct dialog_item_data *item, int x, int *y, int w, int *rw,
   1886                  int align)
   1887 {
   1888 	if (term) {
   1889 		item->x = x;
   1890 		item->y = *y;
   1891 		item->l = w;
   1892 		if (rw && item->l > *rw)
   1893 			if ((*rw = item->l) > w)
   1894 				*rw = w;
   1895 	}
   1896 	(*y)++;
   1897 }
   1898 
   1899 void
   1900 dlg_format_text_and_field(struct dialog_data *dlg, struct terminal *term,
   1901                           unsigned char *text, struct dialog_item_data *item,
   1902                           int x, int *y, int w, int *rw, unsigned char co,
   1903                           int align)
   1904 {
   1905 	dlg_format_text(dlg, term, text, x, y, w, rw, co, align);
   1906 	dlg_format_field(dlg, term, item, x, y, w, rw, align);
   1907 }
   1908 
   1909 #if 0
   1910 /* Layout for generic boxes */
   1911 void dlg_format_box(struct terminal *term, struct terminal *t2, struct dialog_item_data *item, int x, int *y, int w, int *rw, int align) {
   1912 	item->x = x;
   1913 	item->y = *y;
   1914 	item->l = w;
   1915 	if (rw && item->l > *rw) if ((*rw = item->l) > w) *rw = w;
   1916 	(*y) += item->item->gid;
   1917 }
   1918 #endif
   1919 
   1920 void
   1921 max_group_width(struct terminal *term, unsigned char *const *texts,
   1922                 struct dialog_item_data *item, int n, int *w)
   1923 {
   1924 	int ww = 0;
   1925 	while (n--) {
   1926 		int wx =
   1927 		    item->item->type == D_CHECKBOX ? 4
   1928 		    : item->item->type == D_BUTTON
   1929 			? txtlen(get_text_translation(item->item->text, term))
   1930 			      + 4
   1931 			: item->item->dlen;
   1932 		wx += txtlen(get_text_translation(texts[0], term)) + 1;
   1933 		if (n)
   1934 			wx++;
   1935 		ww += wx;
   1936 		texts++;
   1937 		item++;
   1938 	}
   1939 	if (ww > *w)
   1940 		*w = ww;
   1941 }
   1942 
   1943 void
   1944 min_group_width(struct terminal *term, unsigned char *const *texts,
   1945                 struct dialog_item_data *item, int n, int *w)
   1946 {
   1947 	while (n--) {
   1948 		int wx =
   1949 		    item->item->type == D_CHECKBOX ? 4
   1950 		    : item->item->type == D_BUTTON
   1951 			? txtlen(get_text_translation(item->item->text, term))
   1952 			      + 4
   1953 			: item->item->dlen + 1;
   1954 		wx += txtlen(get_text_translation(texts[0], term));
   1955 		if (wx > *w)
   1956 			*w = wx;
   1957 		texts++;
   1958 		item++;
   1959 	}
   1960 }
   1961 
   1962 void
   1963 dlg_format_group(struct dialog_data *dlg, struct terminal *term,
   1964                  unsigned char *const *texts, struct dialog_item_data *item,
   1965                  int n, int x, int *y, int w, int *rw)
   1966 {
   1967 	int nx = 0;
   1968 	while (n--) {
   1969 		int wx = item->item->type == D_CHECKBOX ? 3
   1970 		         : item->item->type == D_BUTTON
   1971 		             ? txtlen(get_text_translation(item->item->text,
   1972 		                                           dlg->win->term))
   1973 		                   + 4
   1974 		             : item->item->dlen;
   1975 		int sl;
   1976 		if (get_text_translation(texts[0], dlg->win->term)[0])
   1977 			sl = txtlen(
   1978 				 get_text_translation(texts[0], dlg->win->term))
   1979 			     + 1;
   1980 		else
   1981 			sl = 0;
   1982 		wx += sl;
   1983 		if (nx && nx + wx > w) {
   1984 			nx = 0;
   1985 			(*y) += 2;
   1986 		}
   1987 		if (term) {
   1988 			print_text(
   1989 			    term, x + nx + 4 * (item->item->type == D_CHECKBOX),
   1990 			    *y,
   1991 			    strlen((char *)get_text_translation(
   1992 				texts[0], dlg->win->term)),
   1993 			    get_text_translation(texts[0], dlg->win->term),
   1994 			    COLOR_DIALOG_TEXT);
   1995 			item->x =
   1996 			    x + nx + sl * (item->item->type != D_CHECKBOX);
   1997 			item->y = *y;
   1998 			if (item->item->type == D_FIELD
   1999 			    || item->item->type == D_FIELD_PASS)
   2000 				item->l = item->item->dlen;
   2001 		}
   2002 		if (rw && nx + wx > *rw)
   2003 			if ((*rw = nx + wx) > w)
   2004 				*rw = w;
   2005 		nx += wx + 1;
   2006 		texts++;
   2007 		item++;
   2008 	}
   2009 	(*y)++;
   2010 }
   2011 
   2012 void
   2013 checkbox_list_fn(struct dialog_data *dlg)
   2014 {
   2015 	struct terminal *term = dlg->win->term;
   2016 	int n_checkboxes;
   2017 	int max = 0, min = 0;
   2018 	int w, rw;
   2019 	int y = 0;
   2020 	for (n_checkboxes = 0;
   2021 	     ((unsigned char **)dlg->dlg->udata)[n_checkboxes]; n_checkboxes++)
   2022 		;
   2023 	checkboxes_width(term, dlg->dlg->udata, n_checkboxes, &max,
   2024 	                 max_text_width);
   2025 	checkboxes_width(term, dlg->dlg->udata, n_checkboxes, &min,
   2026 	                 min_text_width);
   2027 	max_buttons_width(term, dlg->items + n_checkboxes,
   2028 	                  dlg->n - n_checkboxes, &max);
   2029 	min_buttons_width(term, dlg->items + n_checkboxes,
   2030 	                  dlg->n - n_checkboxes, &min);
   2031 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
   2032 	if (w > max)
   2033 		w = max;
   2034 	if (w < min)
   2035 		w = min;
   2036 	if (w > term->x - 2 * DIALOG_LB)
   2037 		w = term->x - 2 * DIALOG_LB;
   2038 	if (w < 5)
   2039 		w = 5;
   2040 	rw = 0;
   2041 	dlg_format_checkboxes(dlg, NULL, dlg->items, n_checkboxes, 0, &y, w,
   2042 	                      &rw, dlg->dlg->udata);
   2043 	y++;
   2044 	dlg_format_buttons(dlg, NULL, dlg->items + n_checkboxes,
   2045 	                   dlg->n - n_checkboxes, 0, &y, w, &rw, AL_CENTER);
   2046 	w = rw;
   2047 	dlg->xw = rw + 2 * DIALOG_LB;
   2048 	dlg->yw = y + 2 * DIALOG_TB;
   2049 	center_dlg(dlg);
   2050 	draw_dlg(dlg);
   2051 	y = dlg->y + DIALOG_TB + 1;
   2052 	dlg_format_checkboxes(dlg, term, dlg->items, n_checkboxes,
   2053 	                      dlg->x + DIALOG_LB, &y, w, NULL, dlg->dlg->udata);
   2054 	y++;
   2055 	dlg_format_buttons(dlg, term, dlg->items + n_checkboxes,
   2056 	                   dlg->n - n_checkboxes, dlg->x + DIALOG_LB, &y, w,
   2057 	                   &rw, AL_CENTER);
   2058 }
   2059 
   2060 void
   2061 group_fn(struct dialog_data *dlg)
   2062 {
   2063 	struct terminal *term = dlg->win->term;
   2064 	int max = 0, min = 0;
   2065 	int w, rw;
   2066 	int y = 0;
   2067 	max_group_width(term, dlg->dlg->udata, dlg->items, dlg->n - 2, &max);
   2068 	min_group_width(term, dlg->dlg->udata, dlg->items, dlg->n - 2, &min);
   2069 	max_buttons_width(term, dlg->items + dlg->n - 2, 2, &max);
   2070 	min_buttons_width(term, dlg->items + dlg->n - 2, 2, &min);
   2071 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
   2072 	if (w > max)
   2073 		w = max;
   2074 	if (w < min)
   2075 		w = min;
   2076 	if (w > term->x - 2 * DIALOG_LB)
   2077 		w = term->x - 2 * DIALOG_LB;
   2078 	if (w < 1)
   2079 		w = 1;
   2080 	rw = 0;
   2081 	dlg_format_group(dlg, NULL, dlg->dlg->udata, dlg->items, dlg->n - 2, 0,
   2082 	                 &y, w, &rw);
   2083 	y++;
   2084 	dlg_format_buttons(dlg, NULL, dlg->items + dlg->n - 2, 2, 0, &y, w, &rw,
   2085 	                   AL_CENTER);
   2086 	w = rw;
   2087 	dlg->xw = rw + 2 * DIALOG_LB;
   2088 	dlg->yw = y + 2 * DIALOG_TB;
   2089 	center_dlg(dlg);
   2090 	draw_dlg(dlg);
   2091 	y = dlg->y + DIALOG_TB + 1;
   2092 	dlg_format_group(dlg, term, dlg->dlg->udata, dlg->items, dlg->n - 2,
   2093 	                 dlg->x + DIALOG_LB, &y, w, NULL);
   2094 	y++;
   2095 	dlg_format_buttons(dlg, term, dlg->items + dlg->n - 2, 2,
   2096 	                   dlg->x + DIALOG_LB, &y, w, &rw, AL_CENTER);
   2097 }
   2098 
   2099 void
   2100 msg_box_fn(struct dialog_data *dlg)
   2101 {
   2102 	struct terminal *term = dlg->win->term;
   2103 	int max = 0, min = 0;
   2104 	int w, rw;
   2105 	int y = 0;
   2106 	unsigned char **ptr;
   2107 	unsigned char *text = NULL;
   2108 	size_t textl = 0;
   2109 
   2110 	for (ptr = dlg->dlg->udata; *ptr; ptr++)
   2111 		textl =
   2112 		    add_to_str(&text, textl, get_text_translation(*ptr, term));
   2113 	max_text_width(term, text, &max, dlg->dlg->align);
   2114 	min_text_width(term, text, &min, dlg->dlg->align);
   2115 	max_buttons_width(term, dlg->items, dlg->n, &max);
   2116 	min_buttons_width(term, dlg->items, dlg->n, &min);
   2117 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
   2118 	if (w > max)
   2119 		w = max;
   2120 	if (w < min)
   2121 		w = min;
   2122 	if (w > term->x - 2 * DIALOG_LB)
   2123 		w = term->x - 2 * DIALOG_LB;
   2124 	if (w < 1)
   2125 		w = 1;
   2126 	rw = 0;
   2127 	dlg_format_text(dlg, NULL, text, 0, &y, w, &rw, COLOR_DIALOG_TEXT,
   2128 	                dlg->dlg->align);
   2129 	y++;
   2130 	dlg_format_buttons(dlg, NULL, dlg->items, dlg->n, 0, &y, w, &rw,
   2131 	                   AL_CENTER);
   2132 	w = rw;
   2133 	dlg->xw = rw + 2 * DIALOG_LB;
   2134 	dlg->yw = y + 2 * DIALOG_TB;
   2135 	center_dlg(dlg);
   2136 	draw_dlg(dlg);
   2137 	y = dlg->y + DIALOG_TB + 1;
   2138 	dlg_format_text(dlg, term, text, dlg->x + DIALOG_LB, &y, w, NULL,
   2139 	                COLOR_DIALOG_TEXT, dlg->dlg->align);
   2140 	y++;
   2141 	dlg_format_buttons(dlg, term, dlg->items, dlg->n, dlg->x + DIALOG_LB,
   2142 	                   &y, w, NULL, AL_CENTER);
   2143 	free(text);
   2144 }
   2145 
   2146 static int
   2147 msg_box_button(struct dialog_data *dlg, struct dialog_item_data *di)
   2148 {
   2149 	msg_button_fn msg_fn = di->item->u.msg_fn;
   2150 	void *data = dlg->dlg->udata2;
   2151 	msg_fn(data);
   2152 	cancel_dialog(dlg, di);
   2153 	return 0;
   2154 }
   2155 
   2156 void
   2157 msg_box_null(void *data)
   2158 {
   2159 }
   2160 
   2161 /* coverity[+free : arg-1] */
   2162 void
   2163 msg_box(struct terminal *term, struct memory_list *ml, unsigned char *title,
   2164         int align, /*unsigned char *text, ..., void *data, int n,*/...)
   2165 {
   2166 	struct dialog *dlg;
   2167 	int i;
   2168 	int n;
   2169 	unsigned char *text;
   2170 	unsigned char **udata;
   2171 	void *udata2;
   2172 	int udatan;
   2173 	va_list ap;
   2174 	va_start(ap, align);
   2175 	udata = NULL;
   2176 	udatan = 0;
   2177 	do {
   2178 		text = va_arg(ap, unsigned char *);
   2179 		udatan++;
   2180 		if ((unsigned)udatan > INT_MAX / sizeof(unsigned char *))
   2181 			overalloc();
   2182 		udata = xrealloc(udata, udatan * sizeof(unsigned char *));
   2183 		udata[udatan - 1] = text;
   2184 	} while (text);
   2185 	udata2 = va_arg(ap, void *);
   2186 	n = va_arg(ap, int);
   2187 	if ((unsigned)n
   2188 	    > (INT_MAX - sizeof(struct dialog)) / sizeof(struct dialog_item)
   2189 	          - 1)
   2190 		overalloc();
   2191 	dlg = mem_calloc(sizeof(struct dialog)
   2192 	                 + (n + 1) * sizeof(struct dialog_item));
   2193 	dlg->title = title;
   2194 	dlg->fn = msg_box_fn;
   2195 	dlg->udata = udata;
   2196 	dlg->udata2 = udata2;
   2197 	dlg->align = align;
   2198 	for (i = 0; i < n; i++) {
   2199 		unsigned char *m;
   2200 		msg_button_fn msg_fn;
   2201 		int flags;
   2202 		m = va_arg(ap, unsigned char *);
   2203 		msg_fn = va_arg(ap, msg_button_fn);
   2204 		flags = va_arg(ap, int);
   2205 		if (!m) {
   2206 			i--;
   2207 			n--;
   2208 			continue;
   2209 		}
   2210 		dlg->items[i].type = D_BUTTON;
   2211 		dlg->items[i].gid = flags;
   2212 		dlg->items[i].fn = msg_box_button;
   2213 		dlg->items[i].dlen = 0;
   2214 		dlg->items[i].text = m;
   2215 		dlg->items[i].u.msg_fn = msg_fn;
   2216 	}
   2217 	va_end(ap);
   2218 	dlg->items[i].type = D_END;
   2219 	add_to_ml(&ml, dlg, udata, NULL);
   2220 	do_dialog(term, dlg, ml);
   2221 }
   2222 
   2223 void
   2224 add_to_history(struct terminal *term, struct history *h, unsigned char *t)
   2225 {
   2226 	struct history_item *hi, *hs = NULL;
   2227 	struct list_head *lhs;
   2228 	size_t l;
   2229 	if (!h || !t || !*t)
   2230 		return;
   2231 	l = strlen(cast_const_char t);
   2232 	if (l > INT_MAX - sizeof(struct history_item))
   2233 		overalloc();
   2234 	hi = xmalloc(sizeof(struct history_item) + l);
   2235 	memcpy(hi->str, t, l + 1);
   2236 	if (term)
   2237 		foreach (struct history_item, hs, lhs, h->items)
   2238 			if (!strcmp(cast_const_char hs->str,
   2239 			            cast_const_char hi->str)) {
   2240 				lhs = lhs->prev;
   2241 				del_from_list(hs);
   2242 				free(hs);
   2243 				h->n--;
   2244 			}
   2245 	add_to_list(h->items, hi);
   2246 	h->n++;
   2247 	while (h->n > MAX_HISTORY_ITEMS) {
   2248 		struct history_item *hd;
   2249 		if (list_empty(h->items)) {
   2250 			internal("history is empty");
   2251 			h->n = 0;
   2252 			return;
   2253 		}
   2254 		hd = list_struct(h->items.prev, struct history_item);
   2255 		del_from_list(hd);
   2256 		free(hd);
   2257 		h->n--;
   2258 	}
   2259 }
   2260 
   2261 static int
   2262 input_field_cancel(struct dialog_data *dlg, struct dialog_item_data *di)
   2263 {
   2264 	input_field_button_fn fn = di->item->u.input_fn;
   2265 	void *data = dlg->dlg->udata2;
   2266 	unsigned char *text = dlg->items->cdata;
   2267 	fn(data, text);
   2268 	cancel_dialog(dlg, di);
   2269 	return 0;
   2270 }
   2271 
   2272 static int
   2273 input_field_ok(struct dialog_data *dlg, struct dialog_item_data *di)
   2274 {
   2275 	input_field_button_fn fn = di->item->u.input_fn;
   2276 	void *data = dlg->dlg->udata2;
   2277 	unsigned char *text = dlg->items->cdata;
   2278 	if (check_dialog(dlg))
   2279 		return 1;
   2280 	add_to_history(dlg->win->term, dlg->dlg->items->history, text);
   2281 	fn(data, text);
   2282 	ok_dialog(dlg, di);
   2283 	return 0;
   2284 }
   2285 
   2286 static void
   2287 input_field_fn(struct dialog_data *dlg)
   2288 {
   2289 	struct terminal *term = dlg->win->term;
   2290 	int max = 0, min = 0;
   2291 	int w, rw;
   2292 	int y = -1;
   2293 	max_text_width(term, dlg->dlg->udata, &max, AL_LEFT);
   2294 	min_text_width(term, dlg->dlg->udata, &min, AL_LEFT);
   2295 	max_buttons_width(term, dlg->items + 1, dlg->n - 1, &max);
   2296 	min_buttons_width(term, dlg->items + 1, dlg->n - 1, &min);
   2297 	if (max < dlg->dlg->items->dlen)
   2298 		max = dlg->dlg->items->dlen;
   2299 	w = term->x * 9 / 10 - 2 * DIALOG_LB;
   2300 	if (w > max)
   2301 		w = max;
   2302 	if (w < min)
   2303 		w = min;
   2304 	rw = w;
   2305 	dlg_format_text_and_field(dlg, NULL, dlg->dlg->udata, dlg->items, 0, &y,
   2306 	                          w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
   2307 	y++;
   2308 	dlg_format_buttons(dlg, NULL, dlg->items + 1, dlg->n - 1, 0, &y, w, &rw,
   2309 	                   AL_CENTER);
   2310 	w = rw;
   2311 	dlg->xw = rw + 2 * DIALOG_LB;
   2312 	dlg->yw = y + 2 * DIALOG_TB;
   2313 	center_dlg(dlg);
   2314 	draw_dlg(dlg);
   2315 	y = dlg->y + DIALOG_TB;
   2316 	dlg_format_text_and_field(dlg, term, dlg->dlg->udata, dlg->items,
   2317 	                          dlg->x + DIALOG_LB, &y, w, NULL,
   2318 	                          COLOR_DIALOG_TEXT, AL_LEFT);
   2319 	y++;
   2320 	dlg_format_buttons(dlg, term, dlg->items + 1, dlg->n - 1,
   2321 	                   dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
   2322 }
   2323 
   2324 void
   2325 input_field_null(void)
   2326 {
   2327 }
   2328 
   2329 /* coverity[+free : arg-1] */
   2330 void
   2331 input_field(struct terminal *term, struct memory_list *ml, unsigned char *title,
   2332             unsigned char *text, void *data, struct history *history, int l,
   2333             unsigned char *def, int min, int max,
   2334             int (*check)(struct dialog_data *, struct dialog_item_data *),
   2335             int n, ...)
   2336 {
   2337 	struct dialog *dlg;
   2338 	unsigned char *field;
   2339 	va_list va;
   2340 	int i;
   2341 	if ((unsigned)n > INT_MAX / sizeof(struct dialog_item) - 2)
   2342 		overalloc();
   2343 	if ((unsigned)l > INT_MAX - sizeof(struct dialog)
   2344 	                      - (2 + n) * sizeof(struct dialog_item))
   2345 		overalloc();
   2346 	dlg = mem_calloc(sizeof(struct dialog)
   2347 	                 + (2 + n) * sizeof(struct dialog_item) + l);
   2348 	*(field = (unsigned char *)dlg + sizeof(struct dialog)
   2349 	          + (2 + n) * sizeof(struct dialog_item)) = 0;
   2350 	if (def) {
   2351 		if (strlen(cast_const_char def) + 1 > (size_t)l)
   2352 			memcpy(field, def, l - 1);
   2353 		else
   2354 			strcpy(cast_char field, cast_const_char def);
   2355 	}
   2356 	dlg->title = title;
   2357 	dlg->fn = input_field_fn;
   2358 	dlg->udata = text;
   2359 	dlg->udata2 = data;
   2360 	dlg->items[0].type = D_FIELD;
   2361 	dlg->items[0].gid = min;
   2362 	dlg->items[0].gnum = max;
   2363 	dlg->items[0].fn = check;
   2364 	dlg->items[0].history = history;
   2365 	dlg->items[0].dlen = l;
   2366 	dlg->items[0].data = field;
   2367 	va_start(va, n);
   2368 	for (i = 1; i <= n; i++) {
   2369 		dlg->items[i].type = D_BUTTON;
   2370 		dlg->items[i].gid = i == 1 ? B_ENTER : i == n ? B_ESC : 0;
   2371 		dlg->items[i].fn =
   2372 		    i != n || n == 1 ? input_field_ok : input_field_cancel;
   2373 		dlg->items[i].dlen = 0;
   2374 		dlg->items[i].text = va_arg(va, unsigned char *);
   2375 		dlg->items[i].u.input_fn = va_arg(va, input_field_button_fn);
   2376 	}
   2377 	va_end(va);
   2378 
   2379 	dlg->items[i].type = D_END;
   2380 	add_to_ml(&ml, dlg, NULL);
   2381 	do_dialog(term, dlg, ml);
   2382 }
   2383 
   2384 int
   2385 find_msg_box(struct terminal *term, unsigned char *title,
   2386              int (*sel)(void *, void *), void *data)
   2387 {
   2388 	struct window *win = NULL;
   2389 	struct list_head *lwin;
   2390 	foreach (struct window, win, lwin, term->windows)
   2391 		if (win->handler == dialog_func) {
   2392 			struct dialog_data *dd = win->data;
   2393 			struct dialog *d = dd->dlg;
   2394 			if (d->fn != msg_box_fn)
   2395 				continue;
   2396 			if (d->title == title) {
   2397 				if (sel && !sel(data, d->udata2))
   2398 					continue;
   2399 				return 1;
   2400 			}
   2401 		}
   2402 	return 0;
   2403 }