1 /* view.c
2  * (c) 2002 Mikulas Patocka
3  * This file is a part of the Links program, released under GPL.
4  */
5 
6 #include "links.h"
7 
8 static void init_ctrl(struct form_control *, struct form_state *);
9 
10 static int c_in_view(struct f_data_c *);
11 
12 static void set_pos_x(struct f_data_c *, struct link *);
13 static void set_pos_y(struct f_data_c *, struct link *);
14 static void find_link(struct f_data_c *, int, int);
15 static void update_braille_link(struct f_data_c *f);
16 
17 static int is_active_frame(struct session *ses, struct f_data_c *f);
18 
19 static void send_open_in_new_xterm(struct terminal *term, void *open_window_, void *ses_);
20 static void (* const send_open_in_new_xterm_ptr)(struct terminal *, void *fn_, void *ses_) = send_open_in_new_xterm;
21 
free_format_text_cache_entry(struct form_state * fs)22 void free_format_text_cache_entry(struct form_state *fs)
23 {
24 	struct format_text_cache_entry *ftce = fs->ftce;
25 	if (!ftce)
26 		return;
27 	fs->ftce = NULL;
28 	mem_free(ftce);
29 }
30 
create_vs(void)31 struct view_state *create_vs(void)
32 {
33 	struct view_state *vs;
34 	vs = mem_calloc(sizeof(struct view_state));
35 	vs->refcount = 1;
36 	vs->current_link = -1;
37 	vs->orig_link = -1;
38 	vs->frame_pos = -1;
39 	vs->plain = -1;
40 	vs->form_info = DUMMY;
41 	vs->form_info_len = 0;
42 	return vs;
43 }
44 
free_form_state(struct form_state * fs)45 static void free_form_state(struct form_state *fs)
46 {
47 	free_format_text_cache_entry(fs);
48 	if (fs->string)
49 		mem_free(fs->string);
50 }
51 
destroy_vs(struct view_state * vs)52 void destroy_vs(struct view_state *vs)
53 {
54 	int i;
55 	if (--vs->refcount) {
56 		if (vs->refcount < 0) internal_error("destroy_vs: view_state refcount underflow");
57 		return;
58 	}
59 	for (i = 0; i < vs->form_info_len; i++) {
60 		free_form_state(&vs->form_info[i]);
61 	}
62 	mem_free(vs->form_info);
63 	mem_free(vs);
64 }
65 
66 #ifdef JS
create_js_event_spec(struct js_event_spec ** j)67 void create_js_event_spec(struct js_event_spec **j)
68 {
69 	if (*j) return;
70 	*j = mem_calloc(sizeof(struct js_event_spec));
71 }
72 
free_js_event_spec(struct js_event_spec * j)73 void free_js_event_spec(struct js_event_spec *j)
74 {
75 	if (!j) return;
76 	if (j->move_code) mem_free(j->move_code);
77 	if (j->over_code) mem_free(j->over_code);
78 	if (j->out_code) mem_free(j->out_code);
79 	if (j->down_code) mem_free(j->down_code);
80 	if (j->up_code) mem_free(j->up_code);
81 	if (j->click_code) mem_free(j->click_code);
82 	if (j->dbl_code) mem_free(j->dbl_code);
83 	if (j->blur_code) mem_free(j->blur_code);
84 	if (j->focus_code) mem_free(j->focus_code);
85 	if (j->change_code) mem_free(j->change_code);
86 	if (j->keypress_code) mem_free(j->keypress_code);
87 	if (j->keyup_code) mem_free(j->keyup_code);
88 	if (j->keydown_code) mem_free(j->keydown_code);
89 	mem_free(j);
90 }
91 
compare_js_event_spec(struct js_event_spec * j1,struct js_event_spec * j2)92 int compare_js_event_spec(struct js_event_spec *j1, struct js_event_spec *j2)
93 {
94 	if (!j1 && !j2) return 0;
95 	if (!j1 || !j2) return 1;
96 	return
97 		xstrcmp(j1->move_code, j2->move_code) ||
98 		xstrcmp(j1->over_code, j2->over_code) ||
99 		xstrcmp(j1->out_code, j2->out_code) ||
100 		xstrcmp(j1->down_code, j2->down_code) ||
101 		xstrcmp(j1->up_code, j2->up_code) ||
102 		xstrcmp(j1->click_code, j2->click_code) ||
103 		xstrcmp(j1->dbl_code, j2->dbl_code) ||
104 		xstrcmp(j1->blur_code, j2->blur_code) ||
105 		xstrcmp(j1->focus_code, j2->focus_code) ||
106 		xstrcmp(j1->change_code, j2->change_code) ||
107 		xstrcmp(j1->keypress_code, j2->keypress_code) ||
108 		xstrcmp(j1->keydown_code, j2->keydown_code) ||
109 		xstrcmp(j1->keyup_code, j2->keyup_code);
110 }
111 
copy_js_event_spec(struct js_event_spec ** target,struct js_event_spec * source)112 void copy_js_event_spec(struct js_event_spec **target, struct js_event_spec *source)
113 {
114 	struct js_event_spec *t;
115 	*target = NULL;
116 	if (!source) return;
117 	create_js_event_spec(target);
118 	t = *target;
119 	t->move_code = stracpy(source->move_code);
120 	t->over_code = stracpy(source->over_code);
121 	t->out_code = stracpy(source->out_code);
122 	t->down_code = stracpy(source->down_code);
123 	t->up_code = stracpy(source->up_code);
124 	t->click_code = stracpy(source->click_code);
125 	t->dbl_code = stracpy(source->dbl_code);
126 	t->blur_code = stracpy(source->blur_code);
127 	t->focus_code = stracpy(source->focus_code);
128 	t->change_code = stracpy(source->change_code);
129 	t->keypress_code = stracpy(source->keypress_code);
130 	t->keyup_code = stracpy(source->keyup_code);
131 	t->keydown_code = stracpy(source->keydown_code);
132 }
133 
copy_string(unsigned char ** dest,unsigned char * src)134 static inline int copy_string(unsigned char **dest, unsigned char *src)
135 {
136 	if (!src) return 0;
137 	if (*dest) {
138 		if (!strcmp(cast_const_char src, cast_const_char *dest)) return 0;
139 		mem_free(*dest);
140 	}
141 	*dest = stracpy(src);
142 	return 1;
143 }
144 
join_js_event_spec(struct js_event_spec ** target,struct js_event_spec * source)145 int join_js_event_spec(struct js_event_spec **target, struct js_event_spec *source)
146 {
147 	if (!source) return 0;
148 	create_js_event_spec(target);
149 	return
150 	copy_string(&(*target)->move_code, source->move_code) |
151 	copy_string(&(*target)->over_code, source->over_code) |
152 	copy_string(&(*target)->out_code, source->out_code) |
153 	copy_string(&(*target)->down_code, source->down_code) |
154 	copy_string(&(*target)->up_code, source->up_code) |
155 	copy_string(&(*target)->click_code, source->click_code) |
156 	copy_string(&(*target)->dbl_code, source->dbl_code) |
157 	copy_string(&(*target)->blur_code, source->blur_code) |
158 	copy_string(&(*target)->focus_code, source->focus_code) |
159 	copy_string(&(*target)->change_code, source->change_code) |
160 	copy_string(&(*target)->keypress_code, source->keypress_code) |
161 	copy_string(&(*target)->keyup_code, source->keyup_code) |
162 	copy_string(&(*target)->keydown_code, source->keydown_code);
163 }
164 
add_event_desc(unsigned char ** str,int * l,unsigned char * fn,unsigned char * desc)165 static void add_event_desc(unsigned char **str, int *l, unsigned char *fn, unsigned char *desc)
166 {
167 	if (!fn) return;
168 	if (*l) add_to_str(str, l, cast_uchar ", ");
169 	add_to_str(str, l, desc);
170 	add_chr_to_str(str, l, ':');
171 	add_to_str(str, l, fn);
172 }
173 
print_js_event_spec(struct js_event_spec * j)174 unsigned char *print_js_event_spec(struct js_event_spec *j)
175 {
176 	unsigned char *str = init_str();
177 	int l = 0;
178 	if (!j) return str;
179 	add_event_desc(&str, &l, j->click_code, cast_uchar "onclick");
180 	add_event_desc(&str, &l, j->dbl_code, cast_uchar "ondblclick");
181 	add_event_desc(&str, &l, j->down_code, cast_uchar "onmousedown");
182 	add_event_desc(&str, &l, j->up_code, cast_uchar "onmouseup");
183 	add_event_desc(&str, &l, j->over_code, cast_uchar "onmouseover");
184 	add_event_desc(&str, &l, j->out_code, cast_uchar "onmouseout");
185 	add_event_desc(&str, &l, j->move_code, cast_uchar "onmousemove");
186 	add_event_desc(&str, &l, j->focus_code, cast_uchar "onfocus");
187 	add_event_desc(&str, &l, j->blur_code, cast_uchar "onblur");
188 	add_event_desc(&str, &l, j->change_code, cast_uchar "onchange");
189 	add_event_desc(&str, &l, j->keypress_code, cast_uchar "onkeypress");
190 	add_event_desc(&str, &l, j->keyup_code, cast_uchar "onkeyup");
191 	add_event_desc(&str, &l, j->keydown_code, cast_uchar "onkeydown");
192 	return str;
193 }
194 
195 #else
196 
free_js_event_spec(struct js_event_spec * j)197 void free_js_event_spec(struct js_event_spec *j)
198 {
199 }
200 
compare_js_event_spec(struct js_event_spec * j1,struct js_event_spec * j2)201 int compare_js_event_spec(struct js_event_spec *j1, struct js_event_spec *j2)
202 {
203 	return 0;
204 }
205 
copy_js_event_spec(struct js_event_spec ** target,struct js_event_spec * source)206 void copy_js_event_spec(struct js_event_spec **target, struct js_event_spec *source)
207 {
208 }
209 
join_js_event_spec(struct js_event_spec ** target,struct js_event_spec * source)210 int join_js_event_spec(struct js_event_spec **target, struct js_event_spec *source)
211 {
212 	return 0;
213 }
214 
print_js_event_spec(struct js_event_spec * j)215 unsigned char *print_js_event_spec(struct js_event_spec *j)
216 {
217 	return stracpy(cast_uchar "");
218 }
219 
220 #endif
221 
check_vs(struct f_data_c * f)222 void check_vs(struct f_data_c *f)
223 {
224 	struct view_state *vs = f->vs;
225 	int ovx, ovy, ol, obx, oby;
226 	if (f->f_data->frame_desc) {
227 		int n = (int)list_size(&f->subframes);
228 		if (vs->frame_pos < 0) vs->frame_pos = 0;
229 		if (vs->frame_pos >= n) vs->frame_pos = n - 1;
230 		return;
231 	}
232 	ovx = f->vs->orig_view_posx;
233 	ovy = f->vs->orig_view_pos;
234 	ol = f->vs->orig_link;
235 	obx = f->vs->orig_brl_x;
236 	oby = f->vs->orig_brl_y;
237 	if (vs->current_link >= f->f_data->nlinks) vs->current_link = f->f_data->nlinks - 1;
238 	if (!F) {
239 		if (vs->current_link != -1 && !c_in_view(f)) {
240 			set_pos_x(f, &f->f_data->links[f->vs->current_link]);
241 			set_pos_y(f, &f->f_data->links[f->vs->current_link]);
242 		}
243 		if (vs->current_link == -1) find_link(f, 1, 0);
244 		if (f->ses->term->spec->braille) {
245 			if (vs->brl_x >= f->f_data->x) vs->brl_x = f->f_data->x - 1;
246 			if (vs->brl_x >= vs->view_posx + f->xw) vs->brl_x = vs->view_posx + f->xw - 1;
247 			if (vs->brl_x < vs->view_posx) vs->brl_x = vs->view_posx;
248 			if (vs->brl_y >= f->f_data->y) vs->brl_y = f->f_data->y - 1;
249 			if (vs->brl_y >= vs->view_pos + f->yw) vs->brl_y = vs->view_pos + f->yw - 1;
250 			if (vs->brl_y < vs->view_pos) vs->brl_y = vs->view_pos;
251 			update_braille_link(f);
252 		}
253 #ifdef G
254 	} else {
255 		/*if (vs->current_link >= 0 && !is_link_in_view(f, vs->current_link)) vs->current_link = -1;*/
256 #endif
257 	}
258 	f->vs->orig_view_posx = ovx;
259 	f->vs->orig_view_pos = ovy;
260 	if (!f->ses->term->spec->braille) f->vs->orig_link = ol;
261 	f->vs->orig_brl_x = obx;
262 	f->vs->orig_brl_y = oby;
263 }
264 
set_link(struct f_data_c * f)265 static void set_link(struct f_data_c *f)
266 {
267 	if (c_in_view(f)) return;
268 	find_link(f, 1, 0);
269 }
270 
find_tag(struct f_data * f,unsigned char * name)271 static int find_tag(struct f_data *f, unsigned char *name)
272 {
273 	struct tag *tag;
274 	struct list_head *ltag;
275 	unsigned char *tt;
276 	int ll;
277 	tt = init_str();
278 	ll = 0;
279 	add_conv_str(&tt, &ll, name, (int)strlen(cast_const_char name), -2);
280 	foreachback(struct tag, tag, ltag, f->tags) if (!casestrcmp(tag->name, tt) || (tag->name[0] == '#' && !casestrcmp(tag->name + 1, tt))) {
281 		mem_free(tt);
282 		return tag->y;
283 	}
284 	mem_free(tt);
285 	return -1;
286 }
287 
comp_links(const void * l1_,const void * l2_)288 LIBC_CALLBACK static int comp_links(const void *l1_, const void *l2_)
289 {
290 	const struct link *l1 = (const struct link *)l1_;
291 	const struct link *l2 = (const struct link *)l2_;
292 	return l1->num - l2->num;
293 }
294 
sort_links(struct f_data * f)295 void sort_links(struct f_data *f)
296 {
297 	int i;
298 	if (F) return;
299 	if (f->nlinks) qsort(f->links, f->nlinks, sizeof(struct link), (int (*)(const void *, const void *))comp_links);
300 	if ((unsigned)f->y > MAXINT / sizeof(struct link *)) overalloc();
301 	f->lines1 = mem_calloc(f->y * sizeof(struct link *));
302 	f->lines2 = mem_calloc(f->y * sizeof(struct link *));
303 	for (i = 0; i < f->nlinks; i++) {
304 		int p, q, j;
305 		struct link *link = &f->links[i];
306 		if (!link->n) {
307 			if (d_opt->num_links) continue;
308 			if (link->where) mem_free(link->where);
309 			if (link->target) mem_free(link->target);
310 			if (link->where_img) mem_free(link->where_img);
311 			if (link->img_alt) mem_free(link->img_alt);
312 			if (link->pos) mem_free(link->pos);
313 			free_js_event_spec(link->js_event);
314 			memmove(link, link + 1, (f->nlinks - i - 1) * sizeof(struct link));
315 			f->nlinks--;
316 			i--;
317 			continue;
318 		}
319 		p = f->y - 1;
320 		q = 0;
321 		for (j = 0; j < link->n; j++) {
322 			if (link->pos[j].y < p) p = link->pos[j].y;
323 			if (link->pos[j].y > q) q = link->pos[j].y;
324 		}
325 		if (p > q) j = p, p = q, q = j;
326 		for (j = p; j <= q; j++) {
327 			if (j >= f->y) {
328 				internal_error("link out of screen");
329 				continue;
330 			}
331 			f->lines2[j] = &f->links[i];
332 			if (!f->lines1[j]) f->lines1[j] = &f->links[i];
333 		}
334 	}
335 }
336 
textptr_add(unsigned char * t,int i,int cp)337 unsigned char *textptr_add(unsigned char *t, int i, int cp)
338 {
339 	if (cp != utf8_table) {
340 		if (i) t += strnlen(cast_const_char t, i);
341 		return t;
342 	} else {
343 		while (i-- && *t) FWD_UTF_8(t);
344 		return t;
345 	}
346 }
347 
textptr_diff(unsigned char * t2,unsigned char * t1,int cp)348 int textptr_diff(unsigned char *t2, unsigned char *t1, int cp)
349 {
350 	if (cp != utf8_table) return (int)(t2 - t1);
351 	else {
352 		int i = 0;
353 		while (t2 > t1) {
354 			FWD_UTF_8(t1);
355 			i++;
356 		}
357 		return i;
358 	}
359 }
360 
format_text_uncached(unsigned char * text,int width,int wrap,int cp)361 static struct format_text_cache_entry *format_text_uncached(unsigned char *text, int width, int wrap, int cp)
362 {
363 	unsigned char *text_start = text;
364 	struct format_text_cache_entry *ftce;
365 	int lnn_allocated = ALLOC_GR;
366 	int lnn = 0;
367 	unsigned char *b;
368 	int sk, ps = 0;
369 	int xpos;
370 	unsigned char *last_space;
371 	int last_space_xpos;
372 
373 	ftce = mem_alloc(sizeof(struct format_text_cache_entry) - sizeof(struct line_info) + lnn_allocated * sizeof(struct line_info));
374 
375 	ftce->width = width;
376 	ftce->wrap = wrap;
377 	ftce->cp = cp;
378 	ftce->last_state = -1;
379 
380 	b = text;
381 	xpos = 0;
382 	last_space = NULL;
383 	last_space_xpos = 0;
384 
385 	while (*text) {
386 		if (*text == '\n') {
387 			sk = 1;
388 			put:
389 			if (lnn == lnn_allocated) {
390 				if ((unsigned)lnn_allocated > (MAXINT - (sizeof(struct format_text_cache_entry) - sizeof(struct line_info))) / sizeof(struct line_info) / 2) overalloc();
391 				lnn_allocated *= 2;
392 				ftce = mem_realloc(ftce, sizeof(struct format_text_cache_entry) - sizeof(struct line_info) + lnn_allocated * sizeof(struct line_info));
393 			}
394 			ftce->ln[lnn].st_offs = (int)(b - text_start);
395 			ftce->ln[lnn].en_offs = (int)(text - text_start);
396 			ftce->ln[lnn++].chars = xpos;
397 			b = text += sk;
398 			xpos = 0;
399 			last_space = NULL;
400 			continue;
401 		}
402 		if (*text == ' ') {
403 			last_space = text;
404 			last_space_xpos = xpos;
405 		}
406 		if (!wrap || xpos < width) {
407 			if (cp != utf8_table) text++;
408 			else FWD_UTF_8(text);
409 			xpos++;
410 			continue;
411 		}
412 		if (last_space) {
413 			text = last_space;
414 			xpos = last_space_xpos;
415 			if (wrap == 2) {
416 				unsigned char *s = last_space;
417 				*s = '\n';
418 				for (s++; *s; s++) if (*s == '\n') {
419 					if (s[1] != '\n') *s = ' ';
420 					break;
421 				}
422 			}
423 			sk = 1;
424 			goto put;
425 		}
426 		sk = 0;
427 		goto put;
428 	}
429 	if (ps < 1) {
430 		ps++;
431 		sk = 0;
432 		goto put;
433 	}
434 	ftce->n_lines = lnn;
435 	return ftce;
436 }
437 
format_text(struct f_data_c * fd,struct form_control * fc,struct form_state * fs)438 struct format_text_cache_entry *format_text(struct f_data_c *fd, struct form_control *fc, struct form_state *fs)
439 {
440 	int width = fc->cols;
441 	int wrap = fc->wrap;
442 	int cp = fd->f_data->opt.cp;
443 	struct format_text_cache_entry *ftce = fs->ftce;
444 
445 	if (ftce && ftce->width == width && ftce->wrap == wrap && ftce->cp == cp)
446 		return fs->ftce;
447 
448 	free_format_text_cache_entry(fs);
449 
450 	ftce = format_text_uncached(fs->string, width, wrap, cp);
451 	fs->ftce = ftce;
452 	return ftce;
453 }
454 
find_cursor_line(struct format_text_cache_entry * ftce,int state)455 static int find_cursor_line(struct format_text_cache_entry *ftce, int state)
456 {
457 	int res;
458 #define LINE_EQ(x, key)		(key >= ftce->ln[x].st_offs && (x >= ftce->n_lines - 1 || key < ftce->ln[x + 1].st_offs))
459 #define LINE_ABOVE(x, key)	(key < ftce->ln[x].st_offs)
460 	BIN_SEARCH(ftce->n_lines, LINE_EQ, LINE_ABOVE, state, res);
461 #undef LINE_EQ
462 #undef LINE_ABOVE
463 	return res;
464 }
465 
area_cursor(struct f_data_c * f,struct form_control * fc,struct form_state * fs)466 int area_cursor(struct f_data_c *f, struct form_control *fc, struct form_state *fs)
467 {
468 	struct format_text_cache_entry *ftce;
469 	int q = 0;
470 	int x, y;
471 	ftce = format_text(f, fc, fs);
472 	if (ftce->last_state == fs->state && ftce->last_vpos == fs->vpos && ftce->last_vypos == fs->vypos)
473 		return fs->ftce->last_cursor;
474 	y = find_cursor_line(ftce, fs->state);
475 	if (y >= 0) {
476 		x = textptr_diff(fs->string + fs->state, fs->string + ftce->ln[y].st_offs, f->f_data->opt.cp);
477 		if (fc->wrap && x == fc->cols) x--;
478 
479 		if (x >= fc->cols + fs->vpos) fs->vpos = x - fc->cols + 1;
480 		if (x < fs->vpos) fs->vpos = x;
481 
482 		if (fs->vypos > ftce->n_lines - fc->rows) {
483 			fs->vypos = ftce->n_lines - fc->rows;
484 			if (fs->vypos < 0) fs->vypos = 0;
485 		}
486 
487 		if (y >= fc->rows + fs->vypos) fs->vypos = y - fc->rows + 1;
488 		if (y < fs->vypos) fs->vypos = y;
489 		x -= fs->vpos;
490 		y -= fs->vypos;
491 		q = y * fc->cols + x;
492 	}
493 	ftce->last_state = fs->state;
494 	ftce->last_vpos = fs->vpos;
495 	ftce->last_vypos = fs->vypos;
496 	ftce->last_cursor = q;
497 	return q;
498 }
499 
draw_link(struct terminal * t,struct f_data_c * scr,int l)500 static void draw_link(struct terminal *t, struct f_data_c *scr, int l)
501 {
502 	struct link *link = &scr->f_data->links[l];
503 	int xp = scr->xp;
504 	int yp = scr->yp;
505 	int xw = scr->xw;
506 	int yw = scr->yw;
507 	int vx, vy;
508 	struct view_state *vs = scr->vs;
509 	int f = 0;
510 	vx = vs->view_posx;
511 	vy = vs->view_pos;
512 	if (scr->link_bg) {
513 		internal_error("link background not empty");
514 		mem_free(scr->link_bg);
515 	}
516 	if (l == -1) return;
517 	switch (link->type) {
518 		int i;
519 		int q;
520 		case L_LINK:
521 		case L_CHECKBOX:
522 		case L_BUTTON:
523 		case L_SELECT:
524 		case L_FIELD:
525 		case L_AREA:
526 			q = 0;
527 			if (link->type == L_FIELD) {
528 				struct form_state *fs = find_form_state(scr, link->form);
529 				q = textptr_diff(fs->string + fs->state, fs->string + fs->vpos, scr->f_data->opt.cp);
530 			} else if (link->type == L_AREA) {
531 				struct form_state *fs = find_form_state(scr, link->form);
532 				q = area_cursor(scr, link->form, fs);
533 			}
534 			if ((unsigned)link->n > MAXINT / sizeof(struct link_bg)) overalloc();
535 			scr->link_bg = mem_alloc(link->n * sizeof(struct link_bg));
536 			scr->link_bg_n = link->n;
537 			for (i = 0; i < link->n; i++) {
538 				int x = link->pos[i].x + xp - vx;
539 				int y = link->pos[i].y + yp - vy;
540 				if (x >= xp && y >= yp && x < xp+xw && y < yp+yw) {
541 					const chr *co;
542 					co = get_char(t, x, y);
543 					scr->link_bg[i].x = x;
544 					scr->link_bg[i].y = y;
545 					scr->link_bg[i].c = co->at;
546 					if (t->spec->braille && !vs->brl_in_field) goto skip_link;
547 					if (!f || (link->type == L_CHECKBOX && i == 1) || (link->type == L_BUTTON && i == 2) || ((link->type == L_FIELD || link->type == L_AREA) && i == q)) {
548 						int xx = x, yy = y;
549 						if (link->type != L_FIELD && link->type != L_AREA) {
550 							if ((unsigned)(co->at & 0x38) != (link->sel_color & 0x38)) xx = xp + xw - 1, yy = yp + yw - 1;
551 						}
552 						set_cursor(t, x, y, xx, yy);
553 						set_window_ptr(scr->ses->win, x, y);
554 						f = 1;
555 					}
556 					skip_link:
557 					set_color(t, x, y, link->sel_color);
558 				} else {
559 					scr->link_bg[i].x = scr->link_bg[i].y = -1;
560 					scr->link_bg[i].c = 0;
561 				}
562 			}
563 			break;
564 		default: internal_error("bad link type");
565 	}
566 }
567 
free_link(struct f_data_c * scr)568 static void free_link(struct f_data_c *scr)
569 {
570 	if (scr->link_bg) {
571 		mem_free(scr->link_bg);
572 		scr->link_bg = NULL;
573 	}
574 	scr->link_bg_n = 0;
575 }
576 
clear_link(struct terminal * t,struct f_data_c * scr)577 static void clear_link(struct terminal *t, struct f_data_c *scr)
578 {
579 	if (scr->link_bg) {
580 		int i;
581 		for (i = scr->link_bg_n - 1; i >= 0; i--)
582 			set_color(t, scr->link_bg[i].x, scr->link_bg[i].y, scr->link_bg[i].c);
583 		free_link(scr);
584 	}
585 }
586 
search_lookup(struct f_data * f,int idx)587 static struct search *search_lookup(struct f_data *f, int idx)
588 {
589 	static struct search sr;
590 	int result;
591 #define S_EQUAL(i, id) (f->search_pos[i].idx <= id && f->search_pos[i].idx + f->search_pos[i].co > id)
592 #define S_ABOVE(i, id) (f->search_pos[i].idx > id)
593 	BIN_SEARCH(f->nsearch_pos, S_EQUAL, S_ABOVE, idx, result)
594 	if (result == -1)
595 		internal_error("search_lookup: invalid index: %d, %d", idx, f->nsearch_chr);
596 	if (idx == f->search_pos[result].idx)
597 		return &f->search_pos[result];
598 	memcpy(&sr, &f->search_pos[result], sizeof(struct search));
599 	sr.x += idx - f->search_pos[result].idx;
600 	return &sr;
601 }
602 
get_range(struct f_data * f,int y,int yw,int l,int * s1,int * s2)603 static int get_range(struct f_data *f, int y, int yw, int l, int *s1, int *s2)
604 {
605 	int i;
606 	*s1 = *s2 = -1;
607 	for (i = y < 0 ? 0 : y; i < y + yw && i < f->y; i++) {
608 		if (f->slines1[i] >= 0 && (*s1 < 0 || f->slines1[i] < *s1)) *s1 = f->slines1[i];
609 		if (f->slines2[i] >= 0 && (*s2 < 0 || f->slines2[i] > *s2)) *s2 = f->slines2[i];
610 	}
611 
612 	if (l > f->nsearch_chr) *s1 = *s2 = -1;
613 	if (*s1 < 0 || *s2 < 0) return -1;
614 
615 	if (*s1 < l) *s1 = 0;
616 	else *s1 -= l;
617 
618 	if (f->nsearch_chr - *s2 < l) *s2 = f->nsearch_chr - l;
619 
620 	if (*s1 > *s2) *s1 = *s2 = -1;
621 	if (*s1 < 0 || *s2 < 0) return -1;
622 
623 	return 0;
624 }
625 
is_in_range(struct f_data * f,int y,int yw,unsigned char * txt,int * min,int * max)626 static int is_in_range(struct f_data *f, int y, int yw, unsigned char *txt, int *min, int *max)
627 {
628 #ifdef ENABLE_UTF8
629 	int utf8 = f->opt.cp == utf8_table;
630 #else
631 	const int utf8 = 0;
632 #endif
633 	int found = 0;
634 	int l;
635 	int s1, s2;
636 	*min = MAXINT, *max = 0;
637 
638 	if (!utf8) {
639 		l = (int)strlen(cast_const_char txt);
640 	} else {
641 		l = strlen_utf8(txt);
642 	}
643 
644 	if (get_range(f, y, yw, l, &s1, &s2)) return 0;
645 	for (; s1 <= s2; s1++) {
646 		int i;
647 		if (!utf8) {
648 			if (f->search_chr[s1] != txt[0]) goto cont;
649 			for (i = 1; i < l; i++) if (f->search_chr[s1 + i] != txt[i]) goto cont;
650 		} else {
651 			unsigned char *tt = txt;
652 			for (i = 0; i < l; i++) {
653 				unsigned cc;
654 				GET_UTF_8(tt, cc);
655 				if (f->search_chr[s1 + i] != cc) goto cont;
656 			}
657 		}
658 		for (i = 0; i < l; i++) {
659 			struct search *sr = search_lookup(f, s1 + i);
660 			if (sr->y >= y && sr->y < y + yw && sr->n) goto in_view;
661 		}
662 		continue;
663 		in_view:
664 		found = 1;
665 		for (i = 0; i < l; i++) {
666 			struct search *sr = search_lookup(f, s1 + i);
667 			if (sr->n) {
668 				if (sr->x < *min) *min = sr->x;
669 				if (sr->x + sr->n > *max) *max = sr->x + sr->n;
670 			}
671 		}
672 		cont:;
673 	}
674 	return found;
675 }
676 
get_searched(struct f_data_c * scr,struct point ** pt,int * pl)677 static int get_searched(struct f_data_c *scr, struct point **pt, int *pl)
678 {
679 #ifdef ENABLE_UTF8
680 	int utf8 = term_charset(scr->ses->term) == utf8_table;
681 #else
682 	const int utf8 = 0;
683 #endif
684 	struct f_data *f = scr->f_data;
685 	int xp = scr->xp;
686 	int yp = scr->yp;
687 	int xw = scr->xw;
688 	int yw = scr->yw;
689 	int vx = scr->vs->view_posx;
690 	int vy = scr->vs->view_pos;
691 	int s1, s2;
692 	int l;
693 	unsigned c;
694 	struct point *points = DUMMY;
695 	int len = 0;
696 	unsigned char *ww;
697 	unsigned char *w = scr->ses->search_word;
698 	if (!w || !*w) return -1;
699 	if (get_search_data(f) < 0) {
700 		mem_free(scr->ses->search_word);
701 		scr->ses->search_word = NULL;
702 		return -1;
703 	}
704 	if (!utf8) {
705 		l = (int)strlen(cast_const_char w);
706 		c = w[0];
707 	} else {
708 		l = strlen_utf8(w);
709 		ww = w;
710 		GET_UTF_8(ww, c);
711 	}
712 	if (get_range(f, scr->vs->view_pos, scr->yw, l, &s1, &s2)) goto ret;
713 	for (; s1 <= s2; s1++) {
714 		int i, j;
715 		if (f->search_chr[s1] != c) {
716 			c:continue;
717 		}
718 		if (!utf8) {
719 			for (i = 1; i < l; i++) if (f->search_chr[s1 + i] != w[i]) goto c;
720 		} else {
721 			ww = w;
722 			for (i = 0; i < l; i++) {
723 				unsigned cc;
724 				GET_UTF_8(ww, cc);
725 				if (f->search_chr[s1 + i] != cc) goto c;
726 			}
727 		}
728 		for (i = 0; i < l && (!scr->ses->term->spec->braille || i < 1); i++) {
729 			struct search *sr = search_lookup(f, s1 + i);
730 			for (j = 0; j < sr->n; j++) {
731 				int x = sr->x + j + xp - vx;
732 				int y = sr->y + yp - vy;
733 				if (x >= xp && y >= yp && x < xp + xw && y < yp + yw) {
734 					if (!(len & (ALLOC_GR - 1))) {
735 						struct point *points2;
736 						if ((unsigned)len > MAXINT / sizeof(struct point) - ALLOC_GR) goto ret;
737 						points2 = mem_realloc_mayfail(points, sizeof(struct point) * (len + ALLOC_GR));
738 						if (!points2) goto ret;
739 						points = points2;
740 					}
741 					points[len].x = sr->x + j;
742 					points[len++].y = sr->y;
743 				}
744 			}
745 		}
746 	}
747 	ret:
748 	*pt = points;
749 	*pl = len;
750 	return 0;
751 }
752 
draw_searched(struct terminal * t,struct f_data_c * scr)753 static void draw_searched(struct terminal *t, struct f_data_c *scr)
754 {
755 	int xp = scr->xp;
756 	int yp = scr->yp;
757 	int vx = scr->vs->view_posx;
758 	int vy = scr->vs->view_pos;
759 	struct point *pt;
760 	int len, i;
761 	if (get_searched(scr, &pt, &len) < 0) return;
762 	for (i = 0; i < len; i++) {
763 		int x = pt[i].x + xp - vx, y = pt[i].y + yp - vy;
764 		const chr *co;
765 		unsigned char nco;
766 		co = get_char(t, x, y);
767 		nco = ((co->at >> 3) & 0x07) | ((co->at << 3) & 0x38);
768 		set_color(t, x, y, nco);
769 	}
770 	mem_free(pt);
771 }
772 
draw_current_link(struct terminal * t,struct f_data_c * scr)773 static void draw_current_link(struct terminal *t, struct f_data_c *scr)
774 {
775 	draw_link(t, scr, scr->vs->current_link);
776 	draw_searched(t, scr);
777 }
778 
get_first_link(struct f_data_c * f)779 static struct link *get_first_link(struct f_data_c *f)
780 {
781 	int i;
782 	struct link *l = f->f_data->links + f->f_data->nlinks;
783 	for (i = f->vs->view_pos; i < f->vs->view_pos + f->yw; i++)
784 		if (i >= 0 && i < f->f_data->y && f->f_data->lines1[i] && f->f_data->lines1[i] < l)
785 			l = f->f_data->lines1[i];
786 	if (l == f->f_data->links + f->f_data->nlinks) l = NULL;
787 	return l;
788 }
789 
get_last_link(struct f_data_c * f)790 static struct link *get_last_link(struct f_data_c *f)
791 {
792 	int i;
793 	struct link *l = NULL;
794 	for (i = f->vs->view_pos; i < f->vs->view_pos + f->yw; i++)
795 		if (i >= 0 && i < f->f_data->y && f->f_data->lines2[i] && (!l || f->f_data->lines2[i] > l))
796 			l = f->f_data->lines2[i];
797 	return l;
798 }
799 
fixup_select_state(struct form_control * fc,struct form_state * fs)800 void fixup_select_state(struct form_control *fc, struct form_state *fs)
801 {
802 	int inited = 0;
803 	int i;
804 	retry:
805 	if (fs->state >= 0 && fs->state < fc->nvalues && !strcmp(cast_const_char fc->values[fs->state], cast_const_char fs->string)) return;
806 	for (i = 0; i < fc->nvalues; i++) {
807 		if (!strcmp(cast_const_char fc->values[i], cast_const_char fs->string)) {
808 			fs->state = i;
809 			return;
810 		}
811 	}
812 	if (!inited) {
813 		init_ctrl(fc, fs);
814 		inited = 1;
815 		goto retry;
816 	}
817 	free_format_text_cache_entry(fs);
818 	fs->state = 0;
819 	if (fs->string) mem_free(fs->string);
820 	if (fc->nvalues) fs->string = stracpy(fc->values[0]);
821 	else fs->string = stracpy(cast_uchar "");
822 }
823 
init_ctrl(struct form_control * form,struct form_state * fs)824 static void init_ctrl(struct form_control *form, struct form_state *fs)
825 {
826 	free_format_text_cache_entry(fs);
827 	if (fs->string) mem_free(fs->string), fs->string = NULL;
828 	switch (form->type) {
829 		case FC_TEXT:
830 		case FC_PASSWORD:
831 		case FC_TEXTAREA:
832 			fs->string = stracpy(form->default_value);
833 			fs->state = (int)strlen(cast_const_char form->default_value);
834 			fs->vpos = 0;
835 			break;
836 		case FC_FILE_UPLOAD:
837 			fs->string = stracpy(cast_uchar "");
838 			fs->state = 0;
839 			fs->vpos = 0;
840 			break;
841 		case FC_CHECKBOX:
842 		case FC_RADIO:
843 			fs->state = form->default_state;
844 			break;
845 		case FC_SELECT:
846 			fs->string = stracpy(form->default_value);
847 			fs->state = form->default_state;
848 			fixup_select_state(form, fs);
849 			break;
850 	}
851 }
852 
find_form_state(struct f_data_c * f,struct form_control * form)853 struct form_state *find_form_state(struct f_data_c *f, struct form_control *form)
854 {
855 	struct view_state *vs = f->vs;
856 	struct form_state *fs;
857 	int n = form->g_ctrl_num;
858 	if (n < vs->form_info_len) fs = &vs->form_info[n];
859 	else {
860 		if ((unsigned)n > MAXINT / sizeof(struct form_state) - 1) overalloc();
861 		fs = mem_realloc(vs->form_info, (n + 1) * sizeof(struct form_state));
862 		vs->form_info = fs;
863 		memset(fs + vs->form_info_len, 0, (n + 1 - vs->form_info_len) * sizeof(struct form_state));
864 		vs->form_info_len = n + 1;
865 		fs = &vs->form_info[n];
866 	}
867 	if (fs->form_num == form->form_num && fs->ctrl_num == form->ctrl_num && fs->g_ctrl_num == form->g_ctrl_num && /*fs->position == form->position &&*/ fs->type == form->type) return fs;
868 	free_form_state(fs);
869 	memset(fs, 0, sizeof(struct form_state));
870 	fs->form_num = form->form_num;
871 	fs->ctrl_num = form->ctrl_num;
872 	fs->g_ctrl_num = form->g_ctrl_num;
873 	fs->position = form->position;
874 	fs->type = form->type;
875 	init_ctrl(form, fs);
876 	return fs;
877 }
878 
draw_form_entry(struct terminal * t,struct f_data_c * f,struct link * l)879 static void draw_form_entry(struct terminal *t, struct f_data_c *f, struct link *l)
880 {
881 	int xp = f->xp;
882 	int yp = f->yp;
883 	int xw = f->xw;
884 	int yw = f->yw;
885 	struct view_state *vs = f->vs;
886 	int vx = vs->view_posx;
887 	int vy = vs->view_pos;
888 	struct form_state *fs;
889 	struct form_control *form = l->form;
890 	int i, x, y;
891 	if (!form) {
892 		internal_error("link %d has no form", (int)(l - f->f_data->links));
893 		return;
894 	}
895 	fs = find_form_state(f, form);
896 	switch (form->type) {
897 		unsigned char *s;
898 		struct format_text_cache_entry *ftce;
899 		int lid;
900 		int sl, td;
901 
902 		case FC_TEXT:
903 		case FC_PASSWORD:
904 		case FC_FILE_UPLOAD:
905 			if ((size_t)fs->vpos > strlen(cast_const_char fs->string)) fs->vpos = (int)strlen(cast_const_char fs->string);
906 			sl = (int)strlen(cast_const_char fs->string);
907 			td = textptr_diff(fs->string + fs->state, fs->string + fs->vpos, f->f_data->opt.cp);
908 			while (fs->vpos < sl && td >= form->size) {
909 				unsigned char *p = fs->string + fs->vpos;
910 				FWD_UTF_8(p);
911 				fs->vpos = (int)(p - fs->string);
912 				td--;
913 			}
914 			while (fs->vpos > fs->state) {
915 				unsigned char *p = fs->string + fs->vpos;
916 				BACK_UTF_8(p, fs->string);
917 				fs->vpos = (int)(p - fs->string);
918 			}
919 			if (!l->n) break;
920 			x = l->pos[0].x + xp - vx; y = l->pos[0].y + yp - vy;
921 			s = fs->string + fs->vpos;
922 			for (i = 0; i < form->size; i++, x++) {
923 				unsigned ch;
924 				if (!*s) {
925 					ch = '_';
926 				} else {
927 					if (f->f_data->opt.cp != utf8_table) {
928 						ch = *s++;
929 					} else {
930 						GET_UTF_8(s, ch);
931 					}
932 					if (form->type == FC_PASSWORD) {
933 						ch = '*';
934 					}
935 				}
936 				if (x >= xp && y >= yp && x < xp+xw && y < yp+yw) {
937 					set_only_char(t, x, y, ch, 0);
938 				}
939 			}
940 			break;
941 		case FC_TEXTAREA:
942 			if (!l->n) break;
943 			x = l->pos[0].x + xp - vx; y = l->pos[0].y + yp - vy;
944 			area_cursor(f, form, fs);	/* scroll the viewport */
945 			ftce = format_text(f, form, fs);
946 			lid = fs->vypos;
947 			for (; lid < ftce->n_lines && y < l->pos[0].y + yp - vy + form->rows; lid++, y++) {
948 				s = textptr_add(fs->string + ftce->ln[lid].st_offs, fs->vpos, f->f_data->opt.cp);
949 				for (i = 0; i < form->cols; i++) {
950 					unsigned ch;
951 					if (s >= fs->string + ftce->ln[lid].en_offs) {
952 						ch = '_';
953 					} else {
954 						if (f->f_data->opt.cp != utf8_table) {
955 							ch = *s++;
956 						} else {
957 							GET_UTF_8(s, ch);
958 						}
959 					}
960 					if (x+i >= xp && y >= yp && x+i < xp+xw && y < yp+yw) {
961 						set_only_char(t, x+i, y, ch, 0);
962 					}
963 				}
964 			}
965 			for (; y < l->pos[0].y + yp - vy + form->rows; y++) {
966 				for (i = 0; i < form->cols; i++) {
967 					if (x+i >= xp && y >= yp && x+i < xp+xw && y < yp+yw)
968 						set_only_char(t, x+i, y, '_', 0);
969 				}
970 			}
971 
972 			break;
973 		case FC_CHECKBOX:
974 			if (l->n < 2) break;
975 			x = l->pos[1].x + xp - vx;
976 			y = l->pos[1].y + yp - vy;
977 			if (x >= xp && y >= yp && x < xp+xw && y < yp+yw)
978 				set_only_char(t, x, y, fs->state ? 'X' : ' ', 0);
979 			break;
980 		case FC_RADIO:
981 			if (l->n < 2) break;
982 			x = l->pos[1].x + xp - vx;
983 			y = l->pos[1].y + yp - vy;
984 			if (x >= xp && y >= yp && x < xp+xw && y < yp+yw)
985 				set_only_char(t, x, y, fs->state ? 'X' : ' ', 0);
986 			break;
987 		case FC_SELECT:
988 			fixup_select_state(form, fs);
989 			s = fs->state < form->nvalues ? form->labels[fs->state] : NULL;
990 			if (!s) s = cast_uchar "";
991 			for (i = 0; i < l->n; i++) {
992 				unsigned chr;
993 				if (!*s) {
994 					chr = '_';
995 				} else {
996 #ifdef ENABLE_UTF8
997 					if (term_charset(t) == utf8_table) {
998 						GET_UTF_8(s, chr);
999 					} else
1000 #endif
1001 					chr = *s++;
1002 				}
1003 				x = l->pos[i].x + xp - vx;
1004 				y = l->pos[i].y + yp - vy;
1005 				if (x >= xp && y >= yp && x < xp+xw && y < yp+yw)
1006 					set_only_char(t, x, y, chr, 0);
1007 			}
1008 			break;
1009 		case FC_SUBMIT:
1010 		case FC_IMAGE:
1011 		case FC_RESET:
1012 		case FC_HIDDEN:
1013 		case FC_BUTTON:
1014 			break;
1015 	}
1016 }
1017 
1018 struct xdfe {
1019 	struct f_data_c *f;
1020 	struct link *l;
1021 };
1022 
y_draw_form_entry(struct terminal * t,void * x_)1023 static void y_draw_form_entry(struct terminal *t, void *x_)
1024 {
1025 	struct xdfe *x = (struct xdfe *)x_;
1026 	draw_form_entry(t, x->f, x->l);
1027 }
1028 
x_draw_form_entry(struct session * ses,struct f_data_c * f,struct link * l)1029 static void x_draw_form_entry(struct session *ses, struct f_data_c *f, struct link *l)
1030 {
1031 	struct xdfe x;
1032 	x.f = f, x.l = l;
1033 	draw_to_window(ses->win, y_draw_form_entry, &x);
1034 }
1035 
draw_forms(struct terminal * t,struct f_data_c * f)1036 static void draw_forms(struct terminal *t, struct f_data_c *f)
1037 {
1038 	struct link *l1 = get_first_link(f);
1039 	struct link *l2 = get_last_link(f);
1040 	if (!l1 || !l2) {
1041 		if (l1 || l2) internal_error("get_first_link == %p, get_last_link == %p", (void *)l1, (void *)l2);
1042 		return;
1043 	}
1044 	do {
1045 		if (l1->type != L_LINK) draw_form_entry(t, f, l1);
1046 	} while (l1++ < l2);
1047 }
1048 
1049 /* 0 -> 1 <- 2 v 3 ^ */
1050 
1051 static unsigned char fr_trans[2][4] = {{0xb3, 0xc3, 0xb4, 0xc5}, {0xc4, 0xc2, 0xc1, 0xc5}};
1052 
set_xchar(struct terminal * t,int x,int y,unsigned dir)1053 static void set_xchar(struct terminal *t, int x, int y, unsigned dir)
1054 {
1055 	const chr *co;
1056 	if (x < 0 || x >= t->x || y < 0 || y >= t->y) return;
1057 	co = get_char(t, x, y);
1058 	if (!(co->at & ATTR_FRAME)) return;
1059 	if (co->ch == fr_trans[dir / 2][0]) set_only_char(t, x, y, fr_trans[dir / 2][1 + (dir & 1)], ATTR_FRAME);
1060 	else if (co->ch == fr_trans[dir / 2][2 - (dir & 1)]) set_only_char(t, x, y, fr_trans[dir / 2][3], ATTR_FRAME);
1061 }
1062 
draw_frame_lines(struct session * ses,struct frameset_desc * fsd,int xp,int yp)1063 static void draw_frame_lines(struct session *ses, struct frameset_desc *fsd, int xp, int yp)
1064 {
1065 	struct terminal *t = ses->term;
1066 	int i, j;
1067 	int x, y;
1068 	if (!fsd) return;
1069 	y = yp - 1;
1070 	for (j = 0; j < fsd->y; j++) {
1071 		int wwy = fsd->f[j * fsd->x].yw;
1072 		x = xp - 1;
1073 		for (i = 0; i < fsd->x; i++) {
1074 			int wwx = fsd->f[i].xw;
1075 			if (i) {
1076 				fill_area(t, x, y + 1, 1, wwy, 179, ATTR_FRAME | get_session_attribute(ses, 0));
1077 				if (j == fsd->y - 1) set_xchar(t, x, y + wwy + 1, 3);
1078 			} else if (j) set_xchar(t, x, y, 0);
1079 			if (j) {
1080 				fill_area(t, x + 1, y, wwx, 1, 196, ATTR_FRAME | get_session_attribute(ses, 0));
1081 				if (i == fsd->x - 1) set_xchar(t, x + wwx + 1, y, 1);
1082 			} else if (i) set_xchar(t, x, y, 2);
1083 			if (i && j) set_char(t, x, y, 197, ATTR_FRAME | get_session_attribute(ses, 0));
1084 			/*if (fsd->f[j * fsd->x + i].subframe) {
1085 				draw_frame_lines(ses, fsd->f[j * fsd->x + i].subframe, x + 1, y + 1);
1086 			}*/
1087 			x += wwx + 1;
1088 		}
1089 		y += wwy + 1;
1090 	}
1091 }
1092 
set_brl_cursor(struct terminal * t,struct f_data_c * scr)1093 static void set_brl_cursor(struct terminal *t, struct f_data_c *scr)
1094 {
1095 	set_cursor(t, scr->xp + scr->vs->brl_x - scr->vs->view_posx, scr->yp + scr->vs->brl_y - scr->vs->view_pos, scr->xp + scr->vs->brl_x - scr->vs->view_posx, scr->yp + scr->vs->brl_y - scr->vs->view_pos);
1096 	set_window_ptr(scr->ses->win, scr->xp + scr->vs->brl_x - scr->vs->view_posx, scr->yp + scr->vs->brl_y - scr->vs->view_pos);
1097 }
1098 
draw_doc(struct terminal * t,void * scr_)1099 void draw_doc(struct terminal *t, void *scr_)
1100 {
1101 	struct f_data_c *scr = (struct f_data_c *)scr_;
1102 	struct session *ses = scr->ses;
1103 	int active = scr->active;
1104 	int y;
1105 	int xp = scr->xp;
1106 	int yp = scr->yp;
1107 	int xw = scr->xw;
1108 	int yw = scr->yw;
1109 	struct view_state *vs;
1110 	int vx, vy;
1111 	if (!scr->vs || !scr->f_data) {
1112 		if (!F) {
1113 			if (active) {
1114 				if (!scr->parent) set_cursor(t, 0, 0, 0, 0);
1115 				else set_cursor(t, xp, yp, xp, yp);
1116 			}
1117 			fill_area(t, xp, yp, xw, yw, ' ', get_session_attribute(ses, 0));
1118 #ifdef G
1119 		} else {
1120 			long color = dip_get_color_sRGB(ses->ds.g_background_color /* 0x808080 */);
1121 			drv->fill_area(t->dev, xp, yp, xp + xw, yp + yw, color);
1122 #endif
1123 		}
1124 		if (active) set_window_ptr(ses->win, xp, yp);
1125 		return;
1126 	}
1127 	if (active) {
1128 		if (!F) {
1129 			if (!t->spec->braille) {
1130 				set_cursor(t, xp + xw - 1, yp + yw - 1, xp + xw - 1, yp + yw - 1);
1131 				set_window_ptr(ses->win, xp, yp);
1132 			} else {
1133 				set_brl_cursor(t, scr);
1134 			}
1135 		}
1136 	}
1137 	check_vs(scr);
1138 	if (scr->f_data->frame_desc) {
1139 		struct f_data_c *f;
1140 		struct list_head *lf;
1141 		int n;
1142 		if (!F) {
1143 			fill_area(t, xp, yp, xw, yw, ' ', scr->f_data->y ? scr->f_data->bg : 0);
1144 			draw_frame_lines(ses, scr->f_data->frame_desc, xp, yp);
1145 		}
1146 		n = 0;
1147 		foreach(struct f_data_c, f, lf, scr->subframes) {
1148 			f->active = active && n++ == scr->vs->frame_pos;
1149 			draw_doc(t, f);
1150 		}
1151 		return;
1152 	}
1153 	vs = scr->vs;
1154 	if (scr->goto_position && (vy = find_tag(scr->f_data, scr->goto_position)) != -1) {
1155 		if (vy > scr->f_data->y) vy = scr->f_data->y - 1;
1156 		if (vy < 0) vy = 0;
1157 		vs->view_pos = vy;
1158 		vs->orig_view_pos = vy;
1159 		vs->view_posx = 0;
1160 		vs->orig_view_posx = 0;
1161 		if (t->spec->braille) {
1162 			vs->brl_y = vy;
1163 			vs->brl_x = 0;
1164 			vs->orig_brl_y = vy;
1165 			vs->orig_brl_x = 0;
1166 		}
1167 		if (!F) set_link(scr);
1168 		if (scr->went_to_position) mem_free(scr->went_to_position);
1169 		scr->went_to_position = scr->goto_position;
1170 		scr->goto_position = NULL;
1171 		if (t->spec->braille) set_brl_cursor(t, scr);
1172 	}
1173 	if (vs->view_pos != vs->orig_view_pos || vs->view_posx != vs->orig_view_posx || vs->current_link != vs->orig_link || (t->spec->braille && (vs->brl_x != vs->orig_brl_x || vs->brl_y != vs->orig_brl_y))) {
1174 		int ol;
1175 		vs->view_pos = vs->orig_view_pos;
1176 		vs->view_posx = vs->orig_view_posx;
1177 		vs->brl_x = vs->orig_brl_x;
1178 		vs->brl_y = vs->orig_brl_y;
1179 		ol = vs->orig_link;
1180 		if (ol < scr->f_data->nlinks) vs->current_link = ol;
1181 		if (!F) {
1182 			while (vs->view_pos >= scr->f_data->y) vs->view_pos -= yw ? yw : 1;
1183 			if (vs->view_pos < 0) vs->view_pos = 0;
1184 		}
1185 		if (!F && !t->spec->braille) set_link(scr);
1186 		check_vs(scr);
1187 		if (!t->spec->braille) {
1188 			vs->orig_link = ol;
1189 		} else {
1190 			vs->orig_link = vs->current_link;
1191 			set_brl_cursor(t, scr);
1192 		}
1193 	}
1194 	if (!F) {
1195 		vx = vs->view_posx;
1196 		vy = vs->view_pos;
1197 		if (scr->xl == vx && scr->yl == vy && scr->xl != -1 && !ses->search_word) {
1198 			clear_link(t, scr);
1199 			draw_forms(t, scr);
1200 			if (active) draw_current_link(t, scr);
1201 			return;
1202 		}
1203 		free_link(scr);
1204 		scr->xl = vx;
1205 		scr->yl = vy;
1206 		fill_area(t, xp, yp, xw, yw, ' ', scr->f_data->y ? scr->f_data->bg : get_session_attribute(ses, 0));
1207 		if (!scr->f_data->y) return;
1208 		while (vs->view_pos >= scr->f_data->y) vs->view_pos -= yw ? yw : 1;
1209 		if (vs->view_pos < 0) vs->view_pos = 0;
1210 		if (vy != vs->view_pos) vy = vs->view_pos, check_vs(scr);
1211 		for (y = vy <= 0 ? 0 : vy; y < (-vy + scr->f_data->y <= yw ? scr->f_data->y : yw + vy); y++) {
1212 			struct line *ln = &scr->f_data->data[y];
1213 			int st = vx <= 0 ? 0 : vx;
1214 			int en = -vx + ln->l <= xw ? ln->l : xw + vx;
1215 			int xoff = xp + st - vx;
1216 			int yoff = yp + y - vy;
1217 			if (ln->allocated >= 0) {
1218 				set_line(t, xoff, yoff, en - st, &ln->u.du[st]);
1219 			} else {
1220 				int i;
1221 				for (i = 0; i < en - st; i++) {
1222 					set_char(t, xoff + i, yoff, ln->u.dc[st + i], ln->allocated & 0xff);
1223 				}
1224 			}
1225 		}
1226 		draw_forms(t, scr);
1227 		if (active) draw_current_link(t, scr);
1228 		if (ses->search_word) scr->xl = scr->yl = -1;
1229 #ifdef G
1230 	} else {
1231 		draw_graphical_doc(t, scr, active);
1232 #endif
1233 	}
1234 }
1235 
clr_xl(struct f_data_c * fd)1236 static void clr_xl(struct f_data_c *fd)
1237 {
1238 	struct f_data_c *fdd;
1239 	struct list_head *lfdd;
1240 	fd->xl = fd->yl = -1;
1241 	foreach(struct f_data_c, fdd, lfdd, fd->subframes) clr_xl(fdd);
1242 }
1243 
draw_doc_c(struct terminal * t,void * scr_)1244 static void draw_doc_c(struct terminal *t, void *scr_)
1245 {
1246 	struct f_data_c *scr = (struct f_data_c *)scr_;
1247 	clr_xl(scr);
1248 #ifdef G
1249 	if (F) if (scr == scr->ses->screen) draw_title(scr);
1250 #endif
1251 	draw_doc(t, scr);
1252 }
1253 
draw_formatted(struct session * ses)1254 void draw_formatted(struct session *ses)
1255 {
1256 	/*clr_xl(ses->screen);*/
1257 	ses->screen->active = 1;
1258 	draw_to_window(ses->win, draw_doc_c, ses->screen);
1259 	change_screen_status(ses);
1260 	print_screen_status(ses);
1261 }
1262 
draw_fd(struct f_data_c * f)1263 void draw_fd(struct f_data_c *f)
1264 {
1265 	if (f->f_data) f->f_data->time_to_draw = -get_time();
1266 	f->active = is_active_frame(f->ses, f);
1267 	draw_to_window(f->ses->win, draw_doc_c, f);
1268 	change_screen_status(f->ses);
1269 	print_screen_status(f->ses);
1270 	if (f->f_data) f->f_data->time_to_draw += get_time();
1271 }
1272 
draw_fd_nrd(struct f_data_c * f)1273 static void draw_fd_nrd(struct f_data_c *f)
1274 {
1275 	f->active = is_active_frame(f->ses, f);
1276 	draw_to_window(f->ses->win, draw_doc, f);
1277 	change_screen_status(f->ses);
1278 	print_screen_status(f->ses);
1279 }
1280 
1281 #define D_BUF	65536
1282 
dump_to_file(struct f_data * fd,int h)1283 int dump_to_file(struct f_data *fd, int h)
1284 {
1285 	int x, y;
1286 	unsigned char *buf;
1287 	int bptr = 0;
1288 	int retval;
1289 	buf = mem_alloc(D_BUF);
1290 	for (y = 0; y < fd->y; y++) for (x = 0; x <= fd->data[y].l; x++) {
1291 		unsigned c;
1292 		if (x == fd->data[y].l) c = '\n';
1293 		else {
1294 			unsigned char at;
1295 			get_char_attr(fd, x, y, &c, &at);
1296 			if (c == 1) c = ' ';
1297 			if (at & ATTR_FRAME && c >= 176 && c < 224) c = frame_dumb[c - 176];
1298 		}
1299 #ifdef ENABLE_UTF8
1300 		if (fd->opt.cp == utf8_table && c >= 0x80) {
1301 			unsigned char *enc = encode_utf_8(c);
1302 			strcpy(cast_char(buf + bptr), cast_const_char enc);
1303 			bptr += (int)strlen(cast_const_char enc);
1304 		} else
1305 #endif
1306 		{
1307 			buf[bptr++] = (unsigned char)c;
1308 		}
1309 		if (bptr >= D_BUF - 7) {
1310 			if ((retval = hard_write(h, buf, bptr)) != bptr) {
1311 				mem_free(buf);
1312 				goto fail;
1313 			}
1314 			bptr = 0;
1315 		}
1316 	}
1317 	if ((retval = hard_write(h, buf, bptr)) != bptr) {
1318 		mem_free(buf);
1319 		goto fail;
1320 	}
1321 	mem_free(buf);
1322 	if (fd->opt.num_links && fd->nlinks) {
1323 		static const unsigned char head[] = "\nLinks:\n";
1324 		int i;
1325 		if ((retval = hard_write(h, head, (int)strlen(cast_const_char head))) != (int)strlen(cast_const_char head))
1326 			goto fail;
1327 		for (i = 0; i < fd->nlinks; i++) {
1328 			struct link *lnk = &fd->links[i];
1329 			unsigned char *s = init_str();
1330 			int l = 0;
1331 			add_num_to_str(&s, &l, i + 1);
1332 			add_to_str(&s, &l, cast_uchar ". ");
1333 			if (lnk->where) {
1334 				add_to_str(&s, &l, lnk->where);
1335 			} else if (lnk->where_img) {
1336 				add_to_str(&s, &l, cast_uchar "Image: ");
1337 				add_to_str(&s, &l, lnk->where_img);
1338 			} else if (lnk->type == L_BUTTON) {
1339 				struct form_control *fc = lnk->form;
1340 				if (fc->type == FC_RESET) add_to_str(&s, &l, cast_uchar "Reset form");
1341 				else if (fc->type == FC_BUTTON || !fc->action) add_to_str(&s, &l, cast_uchar "Button");
1342 				else {
1343 					if (fc->method == FM_GET) add_to_str(&s, &l, cast_uchar "Submit form: ");
1344 					else add_to_str(&s, &l, cast_uchar "Post form: ");
1345 					add_to_str(&s, &l, fc->action);
1346 				}
1347 			} else if (lnk->type == L_CHECKBOX || lnk->type == L_SELECT || lnk->type == L_FIELD || lnk->type == L_AREA) {
1348 				struct form_control *fc = lnk->form;
1349 				if (fc->type == FC_RADIO) add_to_str(&s, &l, cast_uchar "Radio button");
1350 				else if (fc->type == FC_CHECKBOX) add_to_str(&s, &l, cast_uchar "Checkbox");
1351 				else if (fc->type == FC_SELECT) add_to_str(&s, &l, cast_uchar "Select field");
1352 				else if (fc->type == FC_TEXT) add_to_str(&s, &l, cast_uchar "Text field");
1353 				else if (fc->type == FC_TEXTAREA) add_to_str(&s, &l, cast_uchar "Text area");
1354 				else if (fc->type == FC_FILE_UPLOAD) add_to_str(&s, &l, cast_uchar "File upload");
1355 				else if (fc->type == FC_PASSWORD) add_to_str(&s, &l, cast_uchar "Password field");
1356 				else goto unknown;
1357 				if (fc->name && fc->name[0]) add_to_str(&s, &l, cast_uchar ", Name "), add_to_str(&s, &l, fc->name);
1358 				if ((fc->type == FC_CHECKBOX || fc->type == FC_RADIO) && fc->default_value && fc->default_value[0]) add_to_str(&s, &l, cast_uchar ", Value "), add_to_str(&s, &l, fc->default_value);
1359 			}
1360 			unknown:
1361 			add_to_str(&s, &l, cast_uchar "\n");
1362 			if ((retval = hard_write(h, s, l)) != l) {
1363 				mem_free(s);
1364 				goto fail;
1365 			}
1366 			mem_free(s);
1367 		}
1368 	}
1369 	return 0;
1370 
1371 fail:
1372 	if (retval < 0)
1373 		return get_error_from_errno(errno);
1374 	else
1375 		return S_CANT_WRITE;
1376 }
1377 
in_viewx(struct f_data_c * f,struct link * l)1378 static int in_viewx(struct f_data_c *f, struct link *l)
1379 {
1380 	int i;
1381 	for (i = 0; i < l->n; i++) {
1382 		if (l->pos[i].x >= f->vs->view_posx && l->pos[i].x < f->vs->view_posx + f->xw)
1383 			return 1;
1384 	}
1385 	return 0;
1386 }
1387 
in_viewy(struct f_data_c * f,struct link * l)1388 static int in_viewy(struct f_data_c *f, struct link *l)
1389 {
1390 	int i;
1391 	for (i = 0; i < l->n; i++) {
1392 		if (l->pos[i].y >= f->vs->view_pos && l->pos[i].y < f->vs->view_pos + f->yw)
1393 			return 1;
1394 	}
1395 	return 0;
1396 }
1397 
in_view(struct f_data_c * f,struct link * l)1398 static int in_view(struct f_data_c *f, struct link *l)
1399 {
1400 	return in_viewy(f, l) && in_viewx(f, l);
1401 }
1402 
c_in_view(struct f_data_c * f)1403 static int c_in_view(struct f_data_c *f)
1404 {
1405 	return f->vs->current_link != -1 && in_view(f, &f->f_data->links[f->vs->current_link]);
1406 }
1407 
next_in_view(struct f_data_c * f,int p,int d,int (* fn)(struct f_data_c *,struct link *),void (* cntr)(struct f_data_c *,struct link *))1408 static int next_in_view(struct f_data_c *f, int p, int d, int (*fn)(struct f_data_c *, struct link *), void (*cntr)(struct f_data_c *, struct link *))
1409 {
1410 	int p1 = f->f_data->nlinks - 1;
1411 	int p2 = 0;
1412 	int y;
1413 	int yl = f->vs->view_pos + f->yw;
1414 	if (yl > f->f_data->y) yl = f->f_data->y;
1415 	for (y = f->vs->view_pos < 0 ? 0 : f->vs->view_pos; y < yl; y++) {
1416 		if (f->f_data->lines1[y] && f->f_data->lines1[y] - f->f_data->links < p1) p1 = (int)(f->f_data->lines1[y] - f->f_data->links);
1417 		if (f->f_data->lines2[y] && f->f_data->lines2[y] - f->f_data->links > p2) p2 = (int)(f->f_data->lines2[y] - f->f_data->links);
1418 	}
1419 	/*while (p >= 0 && p < f->f_data->nlinks) {*/
1420 	while (p >= p1 && p <= p2) {
1421 		if (fn(f, &f->f_data->links[p])) {
1422 			f->vs->current_link = p;
1423 			f->vs->orig_link = f->vs->current_link;
1424 			if (cntr) cntr(f, &f->f_data->links[p]);
1425 			return 1;
1426 		}
1427 		p += d;
1428 	}
1429 	f->vs->current_link = -1;
1430 	f->vs->orig_link = f->vs->current_link;
1431 	return 0;
1432 }
1433 
set_pos_x(struct f_data_c * f,struct link * l)1434 static void set_pos_x(struct f_data_c *f, struct link *l)
1435 {
1436 	int i;
1437 	int xm = 0;
1438 	int xl = MAXINT;
1439 	for (i = 0; i < l->n; i++) {
1440 		if (l->pos[i].y >= f->vs->view_pos && l->pos[i].y < f->vs->view_pos + f->yw) {
1441 			if (l->pos[i].x >= xm) xm = l->pos[i].x + 1;
1442 			if (l->pos[i].x < xl) xl = l->pos[i].x;
1443 		}
1444 	}
1445 	if (xl == MAXINT) return;
1446 	/*if ((f->vs->view_posx = xm - f->xw) > xl) f->vs->view_posx = xl;*/
1447 	if (f->vs->view_posx + f->xw < xm) f->vs->view_posx = xm - f->xw;
1448 	if (f->vs->view_posx > xl) f->vs->view_posx = xl;
1449 	f->vs->orig_view_posx = f->vs->view_posx;
1450 }
1451 
set_pos_y(struct f_data_c * f,struct link * l)1452 static void set_pos_y(struct f_data_c *f, struct link *l)
1453 {
1454 	int i;
1455 	int ym = 0;
1456 	int yl = f->f_data->y;
1457 	for (i = 0; i < l->n; i++) {
1458 		if (l->pos[i].y >= ym) ym = l->pos[i].y + 1;
1459 		if (l->pos[i].y < yl) yl = l->pos[i].y;
1460 	}
1461 	if ((f->vs->view_pos = (ym + yl) / 2 - f->yw / 2) > f->f_data->y - f->yw) f->vs->view_pos = f->f_data->y - f->yw;
1462 	if (f->vs->view_pos < 0) f->vs->view_pos = 0;
1463 	f->vs->orig_view_pos = f->vs->view_pos;
1464 }
1465 
update_braille_link(struct f_data_c * f)1466 static void update_braille_link(struct f_data_c *f)
1467 {
1468 	int i;
1469 	struct link *l1, *l2;
1470 	struct view_state *vs = f->vs;
1471 	struct f_data *f_data = f->f_data;
1472 	if (vs->brl_x >= f->f_data->x && f->f_data->x) vs->brl_x = f->f_data->x - 1;
1473 	if (vs->brl_x >= vs->view_posx + f->xw) vs->view_posx = vs->brl_x - f->xw + 1;
1474 	if (vs->brl_x < vs->view_posx) vs->view_posx = vs->brl_x;
1475 	if (vs->brl_y >= f_data->y && f_data->y) vs->brl_y = f->f_data->y - 1;
1476 	if (vs->brl_y >= vs->view_pos + f->yw) vs->view_pos = vs->brl_y - f->yw + 1;
1477 	if (vs->brl_y < vs->view_pos) vs->view_pos = vs->brl_y;
1478 	vs->orig_brl_x = vs->brl_x;
1479 	vs->orig_brl_y = vs->brl_y;
1480 	vs->orig_view_pos = vs->view_pos;
1481 	vs->orig_view_posx = vs->view_posx;
1482 	if (vs->brl_y >= f_data->y) goto no_link;
1483 	l1 = f_data->lines1[vs->brl_y];
1484 	l2 = f_data->lines2[vs->brl_y];
1485 	if (!l1 || !l2) goto no_link;
1486 	for (; l1 <= l2; l1++) {
1487 		for (i = 0; i < l1->n; i++) if (l1->pos[i].x == vs->brl_x && l1->pos[i].y == vs->brl_y) {
1488 			if (l1 - f_data->links != vs->current_link) vs->brl_in_field = 0;
1489 			vs->current_link = (int)(l1 - f_data->links);
1490 			vs->orig_link = vs->current_link;
1491 			return;
1492 		}
1493 	}
1494 	no_link:
1495 	vs->brl_in_field = 0;
1496 	vs->current_link = -1;
1497 	vs->orig_link = vs->current_link;
1498 }
1499 
find_link(struct f_data_c * f,int p,int s)1500 static void find_link(struct f_data_c *f, int p, int s)
1501 { /* p=1 - top, p=-1 - bottom, s=0 - pgdn, s=1 - down */
1502 	int y;
1503 	int l;
1504 	struct link *link;
1505 	struct link **line;
1506 	if (f->ses->term->spec->braille) {
1507 		update_braille_link(f);
1508 		return;
1509 	}
1510 	line = p == -1 ? f->f_data->lines2 : f->f_data->lines1;
1511 	if (p == -1) {
1512 		y = f->vs->view_pos + f->yw - 1;
1513 		if (y >= f->f_data->y) y = f->f_data->y - 1;
1514 	} else {
1515 		y = f->vs->view_pos;
1516 		if (y < 0) y = 0;
1517 	}
1518 	if (y < 0 || y >= f->f_data->y) goto nolink;
1519 	link = NULL;
1520 	do {
1521 		if (line[y] && (!link || (p > 0 ? line[y] < link : line[y] > link))) link = line[y];
1522 		y += p;
1523 	} while (!(y < 0 || y < f->vs->view_pos || y >= f->vs->view_pos + f->yw || y >= f->f_data->y));
1524 	if (!link) goto nolink;
1525 	l = (int)(link - f->f_data->links);
1526 	if (s == 0) {
1527 		next_in_view(f, l, p, in_view, NULL);
1528 		return;
1529 	}
1530 	f->vs->current_link = l;
1531 	f->vs->orig_link = f->vs->current_link;
1532 	set_pos_x(f, link);
1533 	return;
1534 	nolink:
1535 	f->vs->current_link = -1;
1536 	f->vs->orig_link = f->vs->current_link;
1537 }
1538 
page_down(struct session * ses,struct f_data_c * f,int a)1539 static void page_down(struct session *ses, struct f_data_c *f, int a)
1540 {
1541 	if (f->vs->view_pos + f->yw < f->f_data->y) {
1542 		f->vs->view_pos += f->yw;
1543 		f->vs->orig_view_pos = f->vs->view_pos;
1544 		if (!ses->term->spec->braille) find_link(f, 1, a);
1545 	} else {
1546 		if (!ses->term->spec->braille) find_link(f, -1, a);
1547 		else if (f->f_data->y) f->vs->brl_y = f->f_data->y - 1;
1548 	}
1549 	if (ses->term->spec->braille) {
1550 		if (f->vs->view_pos > f->vs->brl_y) f->vs->brl_y = f->vs->view_pos;
1551 		f->vs->orig_brl_y = f->vs->brl_y;
1552 		update_braille_link(f);
1553 	}
1554 }
1555 
page_up(struct session * ses,struct f_data_c * f,int a)1556 static void page_up(struct session *ses, struct f_data_c *f, int a)
1557 {
1558 	f->vs->view_pos -= f->yw;
1559 	if (ses->term->spec->braille) {
1560 		if (f->vs->view_pos + f->yw <= f->vs->brl_y) f->vs->brl_y = f->vs->view_pos + f->yw - 1;
1561 	} else find_link(f, -1, a);
1562 	if (f->vs->view_pos < 0) {
1563 		f->vs->view_pos = 0;
1564 	}
1565 	f->vs->orig_view_pos = f->vs->view_pos;
1566 	if (ses->term->spec->braille) {
1567 		if (f->vs->brl_y < 0) f->vs->brl_y = 0;
1568 		f->vs->orig_brl_y = f->vs->brl_y;
1569 		update_braille_link(f);
1570 	}
1571 }
1572 
down(struct session * ses,struct f_data_c * f,int a)1573 static void down(struct session *ses, struct f_data_c *f, int a)
1574 {
1575 	int l;
1576 	if (ses->term->spec->braille) {
1577 		if (f->vs->brl_y < f->f_data->y - 1) f->vs->brl_y++;
1578 		else if (f->f_data->y) f->vs->brl_y = f->f_data->y - 1;
1579 		else f->vs->brl_y = 0;
1580 		f->vs->orig_brl_y = f->vs->brl_y;
1581 		if (f->vs->brl_y >= f->vs->view_pos + f->yw) {
1582 			page_down(ses, f, 1);
1583 			return;
1584 		}
1585 		update_braille_link(f);
1586 		return;
1587 	}
1588 	l = f->vs->current_link;
1589 	/*if (f->vs->current_link >= f->nlinks - 1) return;*/
1590 	if (f->vs->current_link == -1 || !next_in_view(f, f->vs->current_link+1, 1, in_viewy, set_pos_x)) page_down(ses, f, 1);
1591 	if (l != f->vs->current_link) set_textarea(ses, f, -1);
1592 }
1593 
up(struct session * ses,struct f_data_c * f,int a)1594 static void up(struct session *ses, struct f_data_c *f, int a)
1595 {
1596 	int l;
1597 	if (ses->term->spec->braille) {
1598 		if (f->vs->brl_y > 0) f->vs->brl_y--;
1599 		else f->vs->brl_y = 0;
1600 		f->vs->orig_brl_y = f->vs->brl_y;
1601 		if (f->vs->brl_y < f->vs->view_pos) {
1602 			page_up(ses, f, 0);
1603 			return;
1604 		}
1605 		update_braille_link(f);
1606 		return;
1607 	}
1608 	l = f->vs->current_link;
1609 	if (f->vs->current_link == -1 || !next_in_view(f, f->vs->current_link-1, -1, in_viewy, set_pos_x)) page_up(ses, f, 1);
1610 	if (l != f->vs->current_link) set_textarea(ses, f, 1);
1611 }
1612 
scroll(struct session * ses,struct f_data_c * f,int a)1613 static void scroll(struct session *ses, struct f_data_c *f, int a)
1614 {
1615 	if (f->vs->view_pos + f->yw >= f->f_data->y && a > 0) return;
1616 	f->vs->view_pos += a;
1617 	if (f->vs->view_pos > f->f_data->y - f->yw && a > 0) f->vs->view_pos = f->f_data->y - f->yw;
1618 	if (f->vs->view_pos < 0) f->vs->view_pos = 0;
1619 	f->vs->orig_view_pos = f->vs->view_pos;
1620 	if (ses->term->spec->braille) {
1621 		if (f->vs->view_pos + f->yw <= f->vs->brl_y) f->vs->brl_y = f->vs->view_pos + f->yw - 1;
1622 		if (f->vs->view_pos > f->vs->brl_y) f->vs->brl_y = f->vs->view_pos;
1623 		f->vs->orig_brl_y = f->vs->brl_y;
1624 		update_braille_link(f);
1625 		return;
1626 	}
1627 	if (c_in_view(f)) return;
1628 	find_link(f, a < 0 ? -1 : 1, 0);
1629 }
1630 
hscroll(struct session * ses,struct f_data_c * f,int a)1631 static void hscroll(struct session *ses, struct f_data_c *f, int a)
1632 {
1633 	f->vs->view_posx += a;
1634 	if (f->vs->view_posx >= f->f_data->x) f->vs->view_posx = f->f_data->x - 1;
1635 	if (f->vs->view_posx < 0) f->vs->view_posx = 0;
1636 	f->vs->orig_view_posx = f->vs->view_posx;
1637 	if (ses->term->spec->braille) {
1638 		if (f->vs->view_posx + f->xw <= f->vs->brl_x) f->vs->brl_x = f->vs->view_posx + f->xw - 1;
1639 		if (f->vs->view_posx > f->vs->brl_x) f->vs->brl_x = f->vs->view_posx;
1640 		f->vs->orig_brl_x = f->vs->brl_x;
1641 		update_braille_link(f);
1642 		return;
1643 	}
1644 	if (c_in_view(f)) return;
1645 	find_link(f, 1, 0);
1646 	/* !!! FIXME: check right margin */
1647 }
1648 
right(struct session * ses,struct f_data_c * f,int a)1649 static void right(struct session *ses, struct f_data_c *f, int a)
1650 {
1651 	if (ses->term->spec->braille) {
1652 		if (f->vs->brl_x < f->f_data->x - 1) f->vs->brl_x++;
1653 		else if (f->f_data->x) f->vs->brl_x = f->f_data->x - 1;
1654 		else f->vs->brl_x = 0;
1655 		f->vs->orig_brl_x = f->vs->brl_x;
1656 		if (f->vs->brl_x >= f->vs->view_posx + f->xw) {
1657 			hscroll(ses, f, 1);
1658 			return;
1659 		}
1660 		update_braille_link(f);
1661 		return;
1662 	}
1663 }
1664 
left(struct session * ses,struct f_data_c * f,int a)1665 static void left(struct session *ses, struct f_data_c *f, int a)
1666 {
1667 	if (ses->term->spec->braille) {
1668 		if (f->vs->brl_x > 0) f->vs->brl_x--;
1669 		else f->vs->brl_x = 0;
1670 		f->vs->orig_brl_x = f->vs->brl_x;
1671 		if (f->vs->brl_x < f->vs->view_posx) {
1672 			hscroll(ses, f, -1);
1673 			return;
1674 		}
1675 		update_braille_link(f);
1676 		return;
1677 	}
1678 }
1679 
get_at_pos(struct f_data * f,int x,int y)1680 static int get_at_pos(struct f_data *f, int x, int y)
1681 {
1682 	unsigned c;
1683 	unsigned char at;
1684 	struct line *ln;
1685 	if (y < 0 || y >= f->y) return -1;
1686 	ln = &f->data[y];
1687 	if (x < 0 || x >= ln->l) return 0;
1688 	get_char_attr(f, x, y, &c, &at);
1689 	if (at & ATTR_FRAME) return 0;
1690 	return c != 0 && c != 1 && c != ' ' && c != '~';
1691 }
1692 
cursor_word(struct session * ses,struct f_data_c * f,int a)1693 static void cursor_word(struct session *ses, struct f_data_c *f, int a)
1694 {
1695 	if (ses->term->spec->braille) {
1696 		int p = 1;
1697 		int q;
1698 		int x = f->vs->brl_x, y = f->vs->brl_y;
1699 		while (1) {
1700 			q = get_at_pos(f->f_data, x, y);
1701 			if (q == -1) return;
1702 			if (!p && q) {
1703 				f->vs->brl_x = x;
1704 				f->vs->brl_y = y;
1705 				f->vs->orig_brl_x = f->vs->brl_x;
1706 				f->vs->orig_brl_y = f->vs->brl_y;
1707 				update_braille_link(f);
1708 				return;
1709 			}
1710 			x++;
1711 			if (x >= f->f_data->x) x = 0, y++;
1712 			p = q;
1713 		}
1714 	}
1715 }
1716 
cursor_word_back(struct session * ses,struct f_data_c * f,int a)1717 static void cursor_word_back(struct session *ses, struct f_data_c *f, int a)
1718 {
1719 	if (ses->term->spec->braille) {
1720 		int p = 0;
1721 		int q;
1722 		int x = f->vs->brl_x, y = f->vs->brl_y;
1723 		int px, py;
1724 		while (1) {
1725 			px = x, py = y;
1726 			x--;
1727 			if (x < 0) x = f->f_data->x - 1, y--;
1728 			if (x < 0) x = 0;
1729 			q = get_at_pos(f->f_data, x, y);
1730 			if (q == -1) return;
1731 			if (p && !q) {
1732 				f->vs->brl_x = px;
1733 				f->vs->brl_y = py;
1734 				f->vs->orig_brl_x = f->vs->brl_x;
1735 				f->vs->orig_brl_y = f->vs->brl_y;
1736 				update_braille_link(f);
1737 				return;
1738 			}
1739 			p = q;
1740 		}
1741 	}
1742 }
1743 
cursor_home(struct session * ses,struct f_data_c * f,int a)1744 static void cursor_home(struct session *ses, struct f_data_c *f, int a)
1745 {
1746 	if (ses->term->spec->braille) {
1747 		f->vs->brl_x = 0;
1748 		f->vs->orig_brl_x = f->vs->brl_x;
1749 		update_braille_link(f);
1750 		return;
1751 	}
1752 }
1753 
cursor_end(struct session * ses,struct f_data_c * f,int a)1754 static void cursor_end(struct session *ses, struct f_data_c *f, int a)
1755 {
1756 	if (ses->term->spec->braille) {
1757 		if (f->f_data->x) f->vs->brl_x = f->f_data->x - 1;
1758 		else f->vs->brl_x = 0;
1759 		f->vs->orig_brl_x = f->vs->brl_x;
1760 		update_braille_link(f);
1761 		return;
1762 	}
1763 }
1764 
1765 
br_next_link(struct session * ses,struct f_data_c * f,int a)1766 static void br_next_link(struct session *ses, struct f_data_c *f, int a)
1767 {
1768 	if (ses->term->spec->braille) {
1769 		int y;
1770 		struct link *l, *ol, *cl;
1771 		struct view_state *vs = f->vs;
1772 		struct f_data *f_data = f->f_data;
1773 		if (vs->brl_y >= f_data->y) return;
1774 		for (y = vs->brl_y; y < f_data->y; y++) if (f_data->lines1[y]) goto o;
1775 		return;
1776 		o:
1777 		cl = NULL, ol = NULL;
1778 		for (l = f_data->lines1[y]; l && l < f_data->links + f_data->nlinks && (!cl || l <= cl); l++) {
1779 			if (!l->n) continue;
1780 			if (a && !l->form) continue;
1781 			if (l->pos[0].y > vs->brl_y || (l->pos[0].y == vs->brl_y && l->pos[0].x > vs->brl_x)) if (vs->current_link == -1 || l != f_data->links + vs->current_link) {
1782 				if (!ol || l->pos[0].y < ol->pos[0].y || (l->pos[0].y == ol->pos[0].y && l->pos[0].x < ol->pos[0].x)) {
1783 					ol = l;
1784 					cl = f_data->lines2[ol->pos[0].y];
1785 				}
1786 			}
1787 		}
1788 		if (!ol) return;
1789 		vs->brl_x = ol->pos[0].x;
1790 		vs->brl_y = ol->pos[0].y;
1791 		while (vs->brl_y >= vs->view_pos + f->yw) {
1792 			vs->view_pos += f->yw ? f->yw : 1;
1793 			if (vs->view_pos >= f_data->y) vs->view_pos = f_data->y - !!f_data->y;
1794 			vs->orig_view_pos = vs->view_pos;
1795 		}
1796 		vs->orig_brl_x = vs->brl_x;
1797 		vs->orig_brl_y = vs->brl_y;
1798 		set_pos_x(f, ol);
1799 		update_braille_link(f);
1800 	}
1801 }
1802 
br_prev_link(struct session * ses,struct f_data_c * f,int a)1803 static void br_prev_link(struct session *ses, struct f_data_c *f, int a)
1804 {
1805 	if (ses->term->spec->braille) {
1806 		int y;
1807 		struct link *l, *ol, *cl;
1808 		struct view_state *vs = f->vs;
1809 		struct f_data *f_data = f->f_data;
1810 		if (vs->brl_y >= f_data->y) return;
1811 		for (y = vs->brl_y; y >= 0; y--) if (f_data->lines2[y]) goto o;
1812 		return;
1813 		o:
1814 		cl = NULL, ol = NULL;
1815 		for (l = f_data->lines2[y]; l && l >= f_data->links && (!cl || l >= cl); l--) {
1816 			if (!l->n) goto cont;
1817 			if (l->pos[0].y < vs->brl_y || (l->pos[0].y == vs->brl_y && l->pos[0].x < vs->brl_x)) if (vs->current_link == -1 || l != f_data->links + vs->current_link) {
1818 				if (!ol || l->pos[0].y > ol->pos[0].y || (l->pos[0].y == ol->pos[0].y && l->pos[0].x > ol->pos[0].x)) {
1819 					ol = l;
1820 					cl = f_data->lines1[ol->pos[0].y];
1821 				}
1822 			}
1823 			cont:
1824 			if (l == f_data->links) break;
1825 		}
1826 		if (!ol) return;
1827 		vs->brl_x = ol->pos[0].x;
1828 		vs->brl_y = ol->pos[0].y;
1829 		while (vs->brl_y < vs->view_pos) {
1830 			vs->view_pos -= f->yw ? f->yw : 1;
1831 			if (vs->view_pos < 0) vs->view_pos = 0;
1832 			vs->orig_view_pos = vs->view_pos;
1833 		}
1834 		vs->orig_brl_x = vs->brl_x;
1835 		vs->orig_brl_y = vs->brl_y;
1836 		set_pos_x(f, ol);
1837 		update_braille_link(f);
1838 	}
1839 }
1840 
home(struct session * ses,struct f_data_c * f,int a)1841 static void home(struct session *ses, struct f_data_c *f, int a)
1842 {
1843 	f->vs->view_pos = f->vs->view_posx = 0;
1844 	f->vs->orig_view_pos = f->vs->view_pos;
1845 	f->vs->orig_view_posx = f->vs->view_posx;
1846 	if (ses->term->spec->braille) {
1847 		f->vs->brl_x = f->vs->brl_y = 0;
1848 		f->vs->orig_brl_x = f->vs->brl_x;
1849 		f->vs->orig_brl_y = f->vs->brl_y;
1850 		update_braille_link(f);
1851 		return;
1852 	}
1853 	find_link(f, 1, 0);
1854 }
1855 
x_end(struct session * ses,struct f_data_c * f,int a)1856 static void x_end(struct session *ses, struct f_data_c *f, int a)
1857 {
1858 	f->vs->view_posx = 0;
1859 	if (f->vs->view_pos < f->f_data->y - f->yw) f->vs->view_pos = f->f_data->y - f->yw;
1860 	if (f->vs->view_pos < 0) f->vs->view_pos = 0;
1861 	f->vs->orig_view_pos = f->vs->view_pos;
1862 	f->vs->orig_view_posx = f->vs->view_posx;
1863 	if (ses->term->spec->braille) {
1864 		if (f->f_data->y) f->vs->brl_y = f->f_data->y - 1;
1865 		else f->vs->brl_y = 0;
1866 		f->vs->brl_x = 0;
1867 		f->vs->orig_brl_x = f->vs->brl_x;
1868 		f->vs->orig_brl_y = f->vs->brl_y;
1869 		update_braille_link(f);
1870 		return;
1871 	}
1872 	find_link(f, -1, 0);
1873 }
1874 
has_form_submit(struct f_data * f,struct form_control * form)1875 static int has_form_submit(struct f_data *f, struct form_control *form)
1876 {
1877 	struct form_control *i;
1878 	struct list_head *li;
1879 	int q = 0;
1880 	foreach (struct form_control, i, li, f->forms) if (i->form_num == form->form_num) {
1881 		if ((i->type == FC_SUBMIT || i->type == FC_IMAGE)) return 1;
1882 		q = 1;
1883 	}
1884 	if (!q) internal_error("form is not on list");
1885 	return 0;
1886 }
1887 
1888 struct submitted_value {
1889 	list_entry_1st
1890 	int type;
1891 	unsigned char *name;
1892 	unsigned char *value;
1893 	void *file_content;
1894 	int fc_len;
1895 	int position;
1896 	list_entry_last
1897 };
1898 
free_succesful_controls(struct list_head * submit)1899 static void free_succesful_controls(struct list_head *submit)
1900 {
1901 	struct submitted_value *v;
1902 	struct list_head *lv;
1903 	foreach(struct submitted_value, v, lv, *submit) {
1904 		if (v->name) mem_free(v->name);
1905 		if (v->value) mem_free(v->value);
1906 		if (v->file_content) mem_free(v->file_content);
1907 	}
1908 	free_list(struct submitted_value, *submit);
1909 }
1910 
encode_textarea(unsigned char * t)1911 static unsigned char *encode_textarea(unsigned char *t)
1912 {
1913 	int len = 0;
1914 	unsigned char *o = init_str();
1915 	for (; *t; t++) {
1916 		if (*t != '\n') add_chr_to_str(&o, &len, *t);
1917 		else add_to_str(&o, &len, cast_uchar "\r\n");
1918 	}
1919 	return o;
1920 }
1921 
compare_submitted(struct submitted_value * sub1,struct submitted_value * sub2)1922 static int compare_submitted(struct submitted_value *sub1, struct submitted_value *sub2)
1923 {
1924 	/*int c = (sub1->type == FC_IMAGE) - (sub2->type == FC_IMAGE);
1925 	if (c) return c;*/
1926 	return sub1->position - sub2->position;
1927 }
1928 
get_succesful_controls(struct f_data_c * f,struct form_control * fc,struct list_head * subm)1929 static void get_succesful_controls(struct f_data_c *f, struct form_control *fc, struct list_head *subm)
1930 {
1931 	int ch;
1932 	struct form_control *form;
1933 	struct list_head *lform;
1934 	init_list(*subm);
1935 	foreach(struct form_control, form, lform, f->f_data->forms) {
1936 		if (form->form_num == fc->form_num && ((form->type != FC_SUBMIT && form->type != FC_IMAGE && form->type != FC_RESET && form->type != FC_BUTTON) || form == fc) && form->name && form->name[0] && form->ro != 2) {
1937 			struct submitted_value *sub;
1938 			struct form_state *fs;
1939 			int fi = form->type == FC_IMAGE && form->default_value && *form->default_value ? -1 : 0;
1940 			int svl;
1941 			fs = find_form_state(f, form);
1942 			if ((form->type == FC_CHECKBOX || form->type == FC_RADIO) && !fs->state) continue;
1943 			if (form->type == FC_BUTTON) continue;
1944 			if (form->type == FC_SELECT && !form->nvalues) continue;
1945 			fi_rep:
1946 			sub = mem_calloc(sizeof(struct submitted_value));
1947 			sub->type = form->type;
1948 			sub->name = stracpy(form->name);
1949 			switch (form->type) {
1950 				case FC_TEXT:
1951 				case FC_PASSWORD:
1952 				case FC_FILE_UPLOAD:
1953 					sub->value = stracpy(fs->string);
1954 					break;
1955 				case FC_TEXTAREA:
1956 					sub->value = encode_textarea(fs->string);
1957 					break;
1958 				case FC_CHECKBOX:
1959 				case FC_RADIO:
1960 				case FC_SUBMIT:
1961 				case FC_HIDDEN:
1962 					sub->value = encode_textarea(form->default_value);
1963 					break;
1964 				case FC_SELECT:
1965 					fixup_select_state(form, fs);
1966 					sub->value = encode_textarea(fs->string);
1967 					break;
1968 				case FC_IMAGE:
1969 					if (fi == -1) {
1970 						sub->value = encode_textarea(form->default_value);
1971 						break;
1972 					}
1973 					add_to_strn(&sub->name, fi ? cast_uchar ".x" : cast_uchar ".y");
1974 					/*sub->value = stracpy("0");*/
1975 					sub->value = init_str();
1976 					svl = 0;
1977 					add_num_to_str(&sub->value, &svl, fi ? ismap_x : ismap_y);
1978 					break;
1979 				default:
1980 					internal_error("bad form control type");
1981 					mem_free(sub);
1982 					continue;
1983 			}
1984 			sub->position = form->form_num + form->ctrl_num;
1985 			add_to_list(*subm, sub);
1986 			if (form->type == FC_IMAGE && fi < 1) {
1987 				fi++;
1988 				goto fi_rep;
1989 			}
1990 		}
1991 	}
1992 	do {
1993 		struct submitted_value *sub, *nx;
1994 		struct list_head *lsub;
1995 		ch = 0;
1996 		foreach(struct submitted_value, sub, lsub, *subm) if (sub->list_entry.next != subm) {
1997 			nx = list_struct(sub->list_entry.next, struct submitted_value);
1998 			if (compare_submitted(nx, sub) < 0) {
1999 				del_from_list(sub);
2000 				add_after_pos(nx, sub);
2001 				lsub = &nx->list_entry;
2002 				ch = 1;
2003 			}
2004 		}
2005 		foreachback(struct submitted_value, sub, lsub, *subm) if (sub->list_entry.next != subm) {
2006 			nx = list_struct(sub->list_entry.next, struct submitted_value);
2007 			if (compare_submitted(nx, sub) < 0) {
2008 				del_from_list(sub);
2009 				add_after_pos(nx, sub);
2010 				sub = nx;
2011 				lsub = &nx->list_entry;
2012 				ch = 1;
2013 			}
2014 		}
2015 	} while (ch);
2016 }
2017 
strip_file_name(unsigned char * f)2018 static unsigned char *strip_file_name(unsigned char *f)
2019 {
2020 	unsigned char *n;
2021 	unsigned char *l = f - 1;
2022 	for (n = f; *n; n++) if (dir_sep(*n)) l = n;
2023 	return l + 1;
2024 }
2025 
safe_char(unsigned char c)2026 static inline int safe_char(unsigned char c)
2027 {
2028 	return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c== '.' || c == '-' || c == '_';
2029 }
2030 
encode_string(unsigned char * name,unsigned char ** data,int * len)2031 static void encode_string(unsigned char *name, unsigned char **data, int *len)
2032 {
2033 	for (; *name; name++) {
2034 		if (*name == ' ') add_chr_to_str(data, len, '+');
2035 		else if (safe_char(*name)) add_chr_to_str(data, len, *name);
2036 		else {
2037 			unsigned char n[4];
2038 			sprintf(cast_char n, "%%%02X", *name);
2039 			add_to_str(data, len, n);
2040 		}
2041 	}
2042 }
2043 
encode_controls(struct list_head * l,unsigned char ** data,int * len,int cp_from,int cp_to)2044 static void encode_controls(struct list_head *l, unsigned char **data, int *len,
2045 		     int cp_from, int cp_to)
2046 {
2047 	struct submitted_value *sv;
2048 	struct list_head *lsv;
2049 	int lst = 0;
2050 	unsigned char *p2;
2051 	*len = 0;
2052 	*data = init_str();
2053 	foreach(struct submitted_value, sv, lsv, *l) {
2054 		unsigned char *p = sv->value;
2055 		if (lst) add_chr_to_str(data, len, '&'); else lst = 1;
2056 		encode_string(sv->name, data, len);
2057 		add_chr_to_str(data, len, '=');
2058 		if (sv->type == FC_TEXT || sv->type == FC_PASSWORD || sv->type == FC_TEXTAREA)
2059 			p2 = convert(cp_from, cp_to, p, NULL);
2060 		else p2 = stracpy(p);
2061 		encode_string(p2, data, len);
2062 		mem_free(p2);
2063 	}
2064 }
2065 
2066 #define BL	56
2067 #define BL1	27
2068 
encode_multipart(struct session * ses,struct list_head * l,unsigned char ** data,int * len,unsigned char * bound,int cp_from,int cp_to)2069 static void encode_multipart(struct session *ses, struct list_head *l, unsigned char **data, int *len,
2070 		      unsigned char *bound, int cp_from, int cp_to)
2071 {
2072 	int errn;
2073 	int *bound_ptrs = DUMMY;
2074 	int nbound_ptrs = 0;
2075 	unsigned char *m1, *m2;
2076 	struct submitted_value *sv = NULL;	/* against warning */
2077 	struct list_head *lsv;
2078 	int i, j;
2079 	int flg = 0;
2080 	unsigned char *p;
2081 	int rs;
2082 	memset(bound, 'x', BL);
2083 	*len = 0;
2084 	*data = init_str();
2085 	foreach(struct submitted_value, sv, lsv, *l) {
2086 		unsigned char *ct;
2087 		bnd:
2088 		add_to_str(data, len, cast_uchar "--");
2089 		if (!(nbound_ptrs & (ALLOC_GR-1))) {
2090 			if ((unsigned)nbound_ptrs > MAXINT / sizeof(int) - ALLOC_GR) overalloc();
2091 			bound_ptrs = mem_realloc(bound_ptrs, (nbound_ptrs + ALLOC_GR) * sizeof(int));
2092 		}
2093 		bound_ptrs[nbound_ptrs++] = *len;
2094 		add_bytes_to_str(data, len, bound, BL);
2095 		if (flg) break;
2096 		add_to_str(data, len, cast_uchar "\r\nContent-Disposition: form-data; name=\"");
2097 		add_to_str(data, len, sv->name);
2098 		add_to_str(data, len, cast_uchar "\"");
2099 		if (sv->type == FC_FILE_UPLOAD) {
2100 			add_to_str(data, len, cast_uchar "; filename=\"");
2101 			add_to_str(data, len, strip_file_name(sv->value));
2102 				/* It sends bad data if the file name contains ", but
2103 				   Netscape does the same */
2104 			add_to_str(data, len, cast_uchar "\"");
2105 			if (*sv->value) if ((ct = get_content_type(NULL, sv->value))) {
2106 				add_to_str(data, len, cast_uchar "\r\nContent-Type: ");
2107 				add_to_str(data, len, ct);
2108 				if (strlen(cast_const_char ct) >= 4 && !casecmp(ct, cast_uchar "text", 4)) {
2109 					add_to_str(data, len, cast_uchar "; charset=");
2110 					if (!F) add_to_str(data, len, get_cp_mime_name(term_charset(ses->term)));
2111 #ifdef G
2112 					else add_to_str(data, len, get_cp_mime_name(ses->ds.assume_cp));
2113 #endif
2114 				}
2115 				mem_free(ct);
2116 			}
2117 		}
2118 		add_to_str(data, len, cast_uchar "\r\n\r\n");
2119 		if (sv->type != FC_FILE_UPLOAD) {
2120 			if (sv->type == FC_TEXT || sv->type == FC_PASSWORD || sv->type == FC_TEXTAREA)
2121 				p = convert(cp_from, cp_to, sv->value, NULL);
2122 			else p = stracpy(sv->value);
2123 			add_to_str(data, len, p);
2124 			mem_free(p);
2125 		} else {
2126 			int fh, rd;
2127 #define F_BUFLEN 1024
2128 			unsigned char buffer[F_BUFLEN];
2129 			if (*sv->value) {
2130 				unsigned char *wd;
2131 				if (anonymous) {
2132 					goto not_allowed;
2133 				}
2134 				wd = get_cwd();
2135 				set_cwd(ses->term->cwd);
2136 				fh = c_open(sv->value, O_RDONLY | O_NOCTTY);
2137 				if (fh == -1) {
2138 					errn = errno;
2139 					if (wd) set_cwd(wd), mem_free(wd);
2140 					goto error;
2141 				}
2142 				if (wd) set_cwd(wd), mem_free(wd);
2143 				do {
2144 					if ((rd = hard_read(fh, buffer, F_BUFLEN)) == -1) {
2145 						errn = errno;
2146 						EINTRLOOP(rs, close(fh));
2147 						goto error;
2148 					}
2149 					if (rd) add_bytes_to_str(data, len, buffer, rd);
2150 				} while (rd);
2151 				EINTRLOOP(rs, close(fh));
2152 			}
2153 		}
2154 		add_to_str(data, len, cast_uchar "\r\n");
2155 	}
2156 	if (!flg) {
2157 		flg = 1;
2158 		goto bnd;
2159 	}
2160 	add_to_str(data, len, cast_uchar "--\r\n");
2161 	memset(bound, '-', BL1);
2162 	memset(bound + BL1, '0', BL - BL1);
2163 	again:
2164 	for (i = 0; i <= *len - BL; i++) {
2165 		for (j = 0; j < BL; j++) if ((*data)[i + j] != bound[j]) goto nb;
2166 		for (j = BL - 1; j >= 0; j--) {
2167 			if (bound[j] < '0') bound[j] = '0' - 1;
2168 			if (bound[j]++ >= '9') bound[j] = '0';
2169 			else goto again;
2170 		}
2171 		internal_error("Could not assign boundary");
2172 		nb:;
2173 	}
2174 	for (i = 0; i < nbound_ptrs; i++) memcpy(*data + bound_ptrs[i], bound, BL);
2175 	mem_free(bound_ptrs);
2176 	return;
2177 
2178 	error:
2179 	mem_free(bound_ptrs);
2180 	mem_free(*data);
2181 	*data = NULL;
2182 	m1 = stracpy(sv->value);
2183 	m2 = strerror_alloc(errn, ses->term);
2184 	msg_box(ses->term, getml(m1, m2, NULL), TEXT_(T_ERROR_WHILE_POSTING_FORM), AL_CENTER, TEXT_(T_COULD_NOT_GET_FILE), cast_uchar " ", m1, cast_uchar ": ", m2, MSG_BOX_END, (void *)ses, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
2185 	return;
2186 
2187 	not_allowed:
2188 	mem_free(bound_ptrs);
2189 	mem_free(*data);
2190 	*data = NULL;
2191 	msg_box(ses->term, NULL, TEXT_(T_ERROR_WHILE_POSTING_FORM), AL_CENTER, TEXT_(T_READING_FILES_IS_NOT_ALLOWED), MSG_BOX_END, (void *)ses, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
2192 }
2193 
reset_form(struct f_data_c * f,int form_num)2194 void reset_form(struct f_data_c *f, int form_num)
2195 {
2196 	struct form_control *form;
2197 	struct list_head *lform;
2198 	foreach(struct form_control, form, lform, f->f_data->forms) if (form->form_num == form_num) {
2199 		struct form_state *fs;
2200 		fs = find_form_state(f, form);
2201 		init_ctrl(form, fs);
2202 	}
2203 }
2204 
get_form_url(struct session * ses,struct f_data_c * f,struct form_control * form,int * onsubmit)2205 unsigned char *get_form_url(struct session *ses, struct f_data_c *f, struct form_control *form, int *onsubmit)
2206 {
2207 	struct list_head submit;
2208 	unsigned char *data;
2209 	unsigned char bound[BL];
2210 	int len;
2211 	unsigned char *go = NULL;
2212 	int cp_from, cp_to;
2213 	if (!form) return NULL;
2214 	if (form->type == FC_RESET) {
2215 		reset_form(f, form->form_num);
2216 #ifdef G
2217 		if (F) draw_fd(f);
2218 #endif
2219 		return NULL;
2220 	}
2221 	if (onsubmit)*onsubmit=0;
2222 #ifdef JS
2223 	if (form->onsubmit)
2224 	{
2225 		jsint_execute_code(f,form->onsubmit,strlen(cast_const_char form->onsubmit),-1,form->form_num,form->form_num, NULL);
2226 		if (onsubmit)*onsubmit=1;
2227 	}
2228 #endif
2229 	if (!form->action) return NULL;
2230 	get_succesful_controls(f, form, &submit);
2231 	cp_from = term_charset(ses->term);
2232 	cp_to = f->f_data->cp;
2233 	if (form->method == FM_GET || form->method == FM_POST)
2234 		encode_controls(&submit, &data, &len, cp_from, cp_to);
2235 	else
2236 		encode_multipart(ses, &submit, &data, &len, bound, cp_from, cp_to);
2237 	if (!data) goto ff;
2238 	if (!casecmp(form->action, cast_uchar "javascript:", 11))
2239 	{
2240 		go=stracpy(form->action);
2241 		goto x;
2242 	}
2243 	if (form->method == FM_GET) {
2244 		unsigned char *pos, *da;
2245 		size_t q;
2246 		go = stracpy(form->action);
2247 		pos = extract_position(go);
2248 		if (!(da = get_url_data(go))) da = go;
2249 		q = strlen(cast_const_char da);
2250 		if (q && (da[q - 1] == '&' || da[q - 1] == '?'))
2251 			;
2252 		else if (strchr(cast_const_char da, '?')) add_to_strn(&go, cast_uchar "&");
2253 		else add_to_strn(&go, cast_uchar "?");
2254 		add_to_strn(&go, data);
2255 		if (pos) {
2256 			add_to_strn(&go, pos);
2257 			mem_free(pos);
2258 		}
2259 	} else {
2260 		int l = 0;
2261 		int i;
2262 		go = init_str();
2263 		add_to_str(&go, &l, form->action);
2264 		add_chr_to_str(&go, &l, POST_CHAR);
2265 		if (form->method == FM_POST) add_to_str(&go, &l, cast_uchar "application/x-www-form-urlencoded\n");
2266 		else {
2267 			add_to_str(&go, &l, cast_uchar "multipart/form-data; boundary=");
2268 			add_bytes_to_str(&go, &l, bound, BL);
2269 			add_to_str(&go, &l, cast_uchar "\n");
2270 		}
2271 		for (i = 0; i < len; i++) {
2272 			unsigned char p[3];
2273 			sprintf(cast_char p, "%02x", (int)data[i]);
2274 			add_to_str(&go, &l, p);
2275 		}
2276 	}
2277 	x:
2278 	mem_free(data);
2279 	ff:
2280 	free_succesful_controls(&submit);
2281 	return go;
2282 }
2283 
2284 int ismap_link = 0, ismap_x = 1, ismap_y = 1;
2285 
2286 /* if onsubmit is not NULL it will contain 1 if link is submit and the form has an onsubmit handler */
get_link_url(struct session * ses,struct f_data_c * f,struct link * l,int * onsubmit)2287 static unsigned char *get_link_url(struct session *ses, struct f_data_c *f, struct link *l, int *onsubmit)
2288 {
2289 	if (l->type == L_LINK) {
2290 		if (!l->where) {
2291 			if (l->where_img && (!F || (!f->f_data->opt.display_images && f->f_data->opt.plain != 2))) return stracpy(l->where_img);
2292 			return NULL;
2293 		}
2294 		if (ismap_link && strlen(cast_const_char l->where) >= 4 && !strcmp(cast_const_char(l->where + strlen(cast_const_char l->where) - 4), "?0,0")) {
2295 			unsigned char *nu = init_str();
2296 			int ll = 0;
2297 			add_bytes_to_str(&nu, &ll, l->where, strlen(cast_const_char l->where) - 3);
2298 			add_num_to_str(&nu, &ll, ismap_x);
2299 			add_chr_to_str(&nu, &ll, ',');
2300 			add_num_to_str(&nu, &ll, ismap_y);
2301 			return nu;
2302 		}
2303 		return stracpy(l->where);
2304 	}
2305 	if (l->type != L_BUTTON && l->type != L_FIELD) return NULL;
2306 	return get_form_url(ses, f, l->form, onsubmit);
2307 }
2308 
clone_select_menu(struct menu_item * m)2309 static struct menu_item *clone_select_menu(struct menu_item *m)
2310 {
2311 	struct menu_item *n = DUMMY;
2312 	int i = 0;
2313 	do {
2314 		if ((unsigned)i > MAXINT / sizeof(struct menu_item) - 1) overalloc();
2315 		n = mem_realloc(n, (i + 1) * sizeof(struct menu_item));
2316 		n[i].text = stracpy(m->text);
2317 		n[i].rtext = stracpy(m->rtext);
2318 		n[i].hotkey = stracpy(m->hotkey);
2319 		n[i].in_m = m->in_m;
2320 		n[i].free_i = 0;
2321 		if ((n[i].func = m->func) != do_select_submenu) {
2322 			n[i].data = m->data;
2323 		} else n[i].data = clone_select_menu(m->data);
2324 		i++;
2325 	} while (m++->text);
2326 	return n;
2327 }
2328 
free_select_menu(void * m_)2329 static void free_select_menu(void *m_)
2330 {
2331 	struct menu_item *m = (struct menu_item *)m_;
2332 	struct menu_item *om = m;
2333 	do {
2334 		if (m->text) mem_free(m->text);
2335 		if (m->rtext) mem_free(m->rtext);
2336 		if (m->hotkey) mem_free(m->hotkey);
2337 		if (m->func == do_select_submenu) free_select_menu(m->data);
2338 	} while (m++->text);
2339 	mem_free(om);
2340 }
2341 
set_frame(struct session * ses,struct f_data_c * f,int a)2342 void set_frame(struct session *ses, struct f_data_c *f, int a)
2343 {
2344 	if (f == ses->screen) return;
2345 	if (!f->loc->url) return;
2346 	goto_url_not_from_dialog(ses, f->loc->url, ses->screen);
2347 }
2348 
get_current_link(struct f_data_c * f)2349 static struct link *get_current_link(struct f_data_c *f)
2350 {
2351 	if (!f || !f->f_data || !f->vs) return NULL;
2352 	if (f->vs->current_link >= 0 && f->vs->current_link < f->f_data->nlinks)
2353 		return &f->f_data->links[f->vs->current_link];
2354 	if (F && f->f_data->opt.plain == 2 && f->f_data->nlinks == 1)
2355 		return &f->f_data->links[0];
2356 	return NULL;
2357 }
2358 
2359 /* pokud je a==1, tak se nebude submitovat formular, kdyz kliknu na input field a formular nema submit */
enter(struct session * ses,struct f_data_c * f,int a)2360 int enter(struct session *ses, struct f_data_c *f, int a)
2361 {
2362 	struct link *link;
2363 	unsigned char *u;
2364 	link = get_current_link(f);
2365 	if (!link) return 1;
2366 #ifdef JS
2367 	if (link->js_event&&link->js_event->click_code)
2368 		jsint_execute_code(f,link->js_event->click_code,strlen(cast_const_char link->js_event->click_code),-1,(link->type==L_BUTTON&&link->form&&link->form->type==FC_SUBMIT)?link->form->form_num:-1,-1, NULL);
2369 #endif
2370 	if (link->type == L_LINK || link->type == L_BUTTON) {
2371 		int has_onsubmit;
2372 		if (link->type==L_BUTTON&&link->form->type==FC_BUTTON)return 1;
2373 		submit:
2374 		if ((u = get_link_url(ses, f, link, &has_onsubmit))) {
2375 #ifdef JS
2376 			struct js_event_spec *s=link->js_event;
2377 #endif
2378 			if (strlen(cast_const_char u) >= 4 && !casecmp(u, cast_uchar "MAP@", 4)) {
2379 				goto_imgmap(ses, f, u + 4, stracpy(u + 4), stracpy(link->target));
2380 			} else if (ses->ds.target_in_new_window && link->target && *link->target && !find_frame(ses, link->target, f) && can_open_in_new(ses->term)) {	/* open in new window */
2381 				if (ses->wtd_target) mem_free(ses->wtd_target);
2382 				ses->wtd_target = stracpy(link->target);
2383 				open_in_new_window(ses->term, (void *)&send_open_in_new_xterm_ptr, ses);
2384 				mem_free(ses->wtd_target), ses->wtd_target=NULL;
2385 			} else {
2386 				goto_url_f(
2387 				ses,
2388 				NULL,
2389 				u,
2390 				link->target,
2391 				f,
2392 				(link->type==L_BUTTON&&link->form&&link->form->type==FC_SUBMIT)?link->form->form_num:-1,
2393 #ifdef JS
2394 				(s&&(/*s->keyup_code||s->keydown_code||s->keypress_code||s->change_code||s->blur_code||s->focus_code||s->move_code||s->over_code||s->out_code||*/s->down_code||s->up_code||s->click_code||s->dbl_code))||has_onsubmit
2395 #else
2396 				0
2397 #endif
2398 				,0,0
2399 				);
2400 			}
2401 			mem_free(u);
2402 			return 2;
2403 		}
2404 		return 1;
2405 	}
2406 	if (link->type == L_CHECKBOX) {
2407 		struct form_state *fs = find_form_state(f, link->form);
2408 		if (link->form->ro) return 1;
2409 		if (link->form->type == FC_CHECKBOX) fs->state = !fs->state;
2410 		else {
2411 			struct form_control *fc;
2412 			struct list_head *lfc;
2413 #ifdef G
2414 			int re = 0;
2415 #endif
2416 			foreach(struct form_control, fc, lfc, f->f_data->forms)
2417 				if (fc->form_num == link->form->form_num && fc->type == FC_RADIO && !xstrcmp(fc->name, link->form->name)) {
2418 					struct form_state *fffs = find_form_state(f, fc);
2419 					fffs->state = 0;
2420 #ifdef G
2421 					re = 1;
2422 #endif
2423 				}
2424 			fs = find_form_state(f, link->form);
2425 			fs->state = 1;
2426 #ifdef G
2427 			if (F && re) draw_fd(f);
2428 #endif
2429 		}
2430 		return 1;
2431 	}
2432 	if (link->type == L_SELECT) {
2433 		struct menu_item *m;
2434 		if (link->form->ro) return 1;
2435 		m = clone_select_menu(link->form->menu);
2436 		if (!m) return 1;
2437 		/* execute onfocus code of the select object */
2438 #ifdef JS
2439 		if (link->js_event&&link->js_event->focus_code)
2440 		{
2441 			jsint_execute_code(f,link->js_event->focus_code,strlen(cast_const_char link->js_event->focus_code),-1,-1,-1, NULL);
2442 		}
2443 #endif
2444 		add_empty_window(ses->term, free_select_menu, m);
2445 		do_select_submenu(ses->term, m, ses);
2446 		return 1;
2447 	}
2448 	if (link->type == L_FIELD || link->type == L_AREA) {
2449 		/* pri enteru v textovem policku se bude posilat vzdycky       -- Brain */
2450 		if (!has_form_submit(f->f_data, link->form) && (!a || !F)) goto submit;
2451 #ifdef JS
2452 		/* process onfocus handler */
2453 		if (
2454 #ifdef G
2455 		    !ses->locked_link&&
2456 #endif
2457 		    f->vs&&f->f_data&&f->vs->current_link>=0&&f->vs->current_link<f->f_data->nlinks)
2458 		{
2459 			struct link *lnk=&(f->f_data->links[f->vs->current_link]);
2460 			if (lnk->js_event&&lnk->js_event->focus_code)
2461 				jsint_execute_code(f,lnk->js_event->focus_code,strlen(cast_const_char lnk->js_event->focus_code),-1,-1,-1, NULL);
2462 		}
2463 #endif
2464 #ifdef G
2465 		if (F && a) {
2466 			ses->locked_link = 1;
2467 			return 2;
2468 		}
2469 #endif
2470 		if (!F) {
2471 			if (!ses->term->spec->braille) {
2472 				down(ses, f, 0);
2473 			} else {
2474 				if (f->vs->current_link < f->f_data->nlinks - 1) {
2475 					f->vs->current_link++;
2476 					if (f->f_data->links[f->vs->current_link].n) {
2477 						f->vs->brl_x = f->f_data->links[f->vs->current_link].pos[0].x;
2478 						f->vs->brl_y = f->f_data->links[f->vs->current_link].pos[0].y;
2479 						f->vs->orig_brl_x = f->vs->brl_x;
2480 						f->vs->orig_brl_y = f->vs->brl_y;
2481 					}
2482 				}
2483 			}
2484 		}
2485 #ifdef G
2486 		else g_next_link(f, 1, 1);
2487 #endif
2488 		return 1;
2489 	}
2490 	internal_error("bad link type %d", link->type);
2491 	return 1;
2492 }
2493 
toggle(struct session * ses,struct f_data_c * f,int a)2494 void toggle(struct session *ses, struct f_data_c *f, int a)
2495 {
2496 	if (!f || !f->vs) {
2497 		msg_box(ses->term, NULL, TEXT_(T_TOGGLE_HTML_PLAIN), AL_LEFT, TEXT_(T_YOU_ARE_NOWHERE), MSG_BOX_END, NULL, 1, TEXT_(T_OK), msg_box_null, B_ENTER | B_ESC);
2498 		return;
2499 	}
2500 	if (f->vs->plain == -1) f->vs->plain = 1;
2501 	else f->vs->plain = f->vs->plain ^ 1;
2502 	html_interpret_recursive(f);
2503 	draw_formatted(ses);
2504 }
2505 
selected_item(struct terminal * term,void * pitem,void * ses_)2506 void selected_item(struct terminal *term, void *pitem, void *ses_)
2507 {
2508 	struct session *ses = (struct session *)ses_;
2509 	int item = (int)(my_intptr_t)pitem;
2510 #ifdef JS
2511 	int old_item=item;
2512 #endif
2513 	struct f_data_c *f = current_frame(ses);
2514 	struct link *l;
2515 	struct form_state *fs;
2516 	struct form_control *form;
2517 	l = get_current_link(f);
2518 	if (!l) return;
2519 	if (l->type != L_SELECT) return;
2520 	form = l->form;
2521 	fs = find_form_state(f, form);
2522 	if (item >= 0 && item < form->nvalues) {
2523 #ifdef JS
2524 		old_item = fs->state;
2525 #endif
2526 		free_format_text_cache_entry(fs);
2527 		fs->state = item;
2528 		if (fs->string) mem_free(fs->string);
2529 		fs->string = stracpy(form->values[item]);
2530 	}
2531 	fixup_select_state(form, fs);
2532 	f->active = 1;
2533 #ifdef G
2534 	if (F) {
2535 		f->xl = -1;
2536 		f->yl = -1;
2537 	}
2538 #endif
2539 	/* execute onchange handler */
2540 #ifdef JS
2541 	if (old_item!=item&&l->js_event&&l->js_event->change_code)
2542 		jsint_execute_code(f,l->js_event->change_code,strlen(cast_const_char l->js_event->change_code),-1,-1,-1, NULL);
2543 #endif
2544 	/* execute onblur handler */
2545 #ifdef JS
2546 	if (l->js_event&&l->js_event->blur_code)
2547 		jsint_execute_code(f,l->js_event->blur_code,strlen(cast_const_char l->js_event->blur_code),-1,-1,-1, NULL);
2548 #endif
2549 	draw_to_window(ses->win, draw_doc, f);
2550 	change_screen_status(ses);
2551 	print_screen_status(ses);
2552 	/*if (!has_form_submit(f->f_data, l->form)) {
2553 		goto_form(ses, f, l->form, l->target);
2554 	}*/
2555 }
2556 
get_current_state(struct session * ses)2557 int get_current_state(struct session *ses)
2558 {
2559 	struct f_data_c *f = current_frame(ses);
2560 	struct link *l;
2561 	struct form_state *fs;
2562 	l = get_current_link(f);
2563 	if (!l) return -1;
2564 	if (l->type != L_SELECT) return -1;
2565 	fs = find_form_state(f, l->form);
2566 	return fs->state;
2567 }
2568 
2569 static int find_pos_in_link(struct f_data_c *fd,struct link *l,struct links_event *ev,int *xx,int *yy);
2570 
set_form_position(struct f_data_c * fd,struct link * l,struct links_event * ev)2571 static void set_form_position(struct f_data_c *fd, struct link *l, struct links_event *ev)
2572 {
2573 	/* if links is a field, set cursor position */
2574 	if (l->form && (l->type == L_AREA || l->type == L_FIELD)) {
2575 		struct form_state *fs = find_form_state(fd,l->form);
2576 		int xx = 0, yy = 0; /* against uninitialized warning */
2577 
2578 		if (l->type == L_AREA) {
2579 			struct format_text_cache_entry *ftce;
2580 
2581 			if (!find_pos_in_link(fd, l, ev, &xx, &yy)) {
2582 				xx += fs->vpos;
2583 				yy += fs->vypos;
2584 				ftce = format_text(fd, l->form, fs);
2585 				if (yy >= ftce->n_lines)
2586 					yy = ftce->n_lines - 1;
2587 				if (yy >= 0) {
2588 					unsigned char *ptr;
2589 					fs->state = ftce->ln[yy].st_offs;
2590 					ptr = textptr_add(fs->string + fs->state, xx, fd->f_data->opt.cp);
2591 					if (ptr > fs->string + ftce->ln[yy].en_offs)
2592 						ptr = fs->string + ftce->ln[yy].en_offs;
2593 					fs->state = (int)(ptr - fs->string);
2594 					goto br;
2595 				}
2596 				fs->state = (int)strlen(cast_const_char fs->string);
2597 				br:;
2598 			}
2599 		} else if (l->type == L_FIELD) {
2600 			if (!find_pos_in_link(fd, l, ev, &xx, &yy)) {
2601 				unsigned char *ptr;
2602 				ptr = textptr_add(fs->string + fs->vpos, xx, fd->f_data->opt.cp);
2603 				fs->state = (int)(ptr - fs->string);
2604 			}
2605 		}
2606 
2607 		fd->last_captured = 1;
2608 	}
2609 }
2610 
textarea_adjust_viewport(struct f_data_c * fd,struct link * l)2611 static int textarea_adjust_viewport(struct f_data_c *fd, struct link *l)
2612 {
2613 	struct form_control *fc = l->form;
2614 	struct view_state *vs = fd->vs;
2615 	int r = 0;
2616 	if (l->pos[0].x + fc->cols > fd->xw + vs->view_posx)
2617 		vs->view_posx = l->pos[0].x + fc->cols - fd->xw, r = 1;
2618 	if (l->pos[0].x < vs->view_posx)
2619 		vs->view_posx = l->pos[0].x, r = 1;
2620 	if (l->pos[0].y + fc->rows > fd->yw + vs->view_pos)
2621 		vs->view_pos = l->pos[0].y + fc->rows - fd->yw, r = 1;
2622 	if (l->pos[0].y < vs->view_pos)
2623 		vs->view_pos = l->pos[0].y, r = 1;
2624 	vs->orig_view_pos = vs->view_pos;
2625 	vs->orig_view_posx = vs->view_posx;
2626 	return r;
2627 }
2628 
set_br_pos(struct f_data_c * fd,struct link * l)2629 static void set_br_pos(struct f_data_c *fd, struct link *l)
2630 {
2631 	struct links_event ev;
2632 	if (!fd->ses->term->spec->braille || fd->vs->brl_in_field) return;
2633 	ev.ev = EV_MOUSE;
2634 	ev.x = fd->ses->term->cx - fd->xp;
2635 	ev.y = fd->ses->term->cy - fd->yp;
2636 	ev.b = 0;
2637 	set_form_position(fd, l, &ev);
2638 }
2639 
2640 #ifdef JS
2641 /* executes onkey-press/up/down handler */
field_op_changed(struct f_data_c * f,struct link * lnk)2642 static void field_op_changed(struct f_data_c *f, struct link *lnk)
2643 {
2644 	/*
2645 	if (lnk->js_event&&lnk->js_event->keydown_code)
2646 		jsint_execute_code(f,lnk->js_event->keydown_code,strlen(cast_const_char lnk->js_event->keydown_code),-1,-1,-1, NULL);
2647 	if (lnk->js_event&&lnk->js_event->keypress_code)
2648 		jsint_execute_code(f,lnk->js_event->keypress_code,strlen(cast_const_char lnk->js_event->keypress_code),-1,-1,-1, NULL);
2649 	if (lnk->js_event&&lnk->js_event->keyup_code)
2650 		jsint_execute_code(f,lnk->js_event->keyup_code,strlen(cast_const_char lnk->js_event->keyup_code),-1,-1,-1, NULL);
2651 	*/
2652 }
2653 #endif
2654 
2655 
field_op(struct session * ses,struct f_data_c * f,struct link * l,struct links_event * ev)2656 int field_op(struct session *ses, struct f_data_c *f, struct link *l, struct links_event *ev)
2657 {
2658 	struct form_control *form = l->form;
2659 	struct form_state *fs;
2660 	int r = 1;
2661 	struct format_text_cache_entry *ftce;
2662 	int y;
2663 
2664 	if (!form) {
2665 		internal_error("link has no form control");
2666 		return 0;
2667 	}
2668 	if (form->ro == 2) return 0;
2669 	fs = find_form_state(f, form);
2670 	if (!fs->string) return 0;
2671 	if (ev->ev == EV_KBD) {
2672 		if (!(ev->y & (KBD_CTRL | KBD_ALT)) && ev->x >= ' ') {
2673 			if (cp2u(ev->x, term_charset(ses->term)) == -1)
2674 				goto done;
2675 			set_br_pos(f, l);
2676 			if (!form->ro && cp_len(term_charset(ses->term), fs->string) < form->maxlength) {
2677 				unsigned char *v;
2678 				unsigned char a_[2];
2679 				unsigned char *nw;
2680 				int ll;
2681 				free_format_text_cache_entry(fs);
2682 				v = fs->string = mem_realloc(fs->string, strlen(cast_const_char fs->string) + 12);
2683 				if (f->f_data->opt.cp != utf8_table) {
2684 					nw = a_;
2685 					a_[0] = (unsigned char)ev->x;
2686 					a_[1] = 0;
2687 				} else {
2688 					nw = encode_utf_8(ev->x);
2689 				}
2690 				ll = (int)strlen(cast_const_char nw);
2691 				if (ll > 10) goto done;
2692 				memmove(v + fs->state + ll, v + fs->state, strlen(cast_const_char(v + fs->state)) + 1);
2693 				memcpy(&v[fs->state], nw, ll);
2694 				fs->state += ll;
2695 #ifdef JS
2696 				fs->changed = 1;
2697 				field_op_changed(f, l);
2698 #endif
2699 			}
2700 			goto done;
2701 		} else if (!(ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT)) && ev->x == KBD_ENTER && form->type == FC_TEXTAREA && (!ses->term->spec->braille || f->vs->brl_in_field)) {
2702 			if (!form->ro && strlen(cast_const_char fs->string) < (size_t)form->maxlength) {
2703 				unsigned char *v;
2704 				free_format_text_cache_entry(fs);
2705 				v = mem_realloc(fs->string, strlen(cast_const_char fs->string) + 2);
2706 				fs->string = v;
2707 				memmove(v + fs->state + 1, v + fs->state, strlen(cast_const_char(v + fs->state)) + 1);
2708 				v[fs->state++] = '\n';
2709 #ifdef JS
2710 				fs->changed = 1;
2711 				field_op_changed(f, l);
2712 #endif
2713 			}
2714 			goto done;
2715 		}
2716 		if (ev->y & KBD_PASTING) {
2717 			r = 0;
2718 			goto done;
2719 		}
2720 		if (ev->x == KBD_LEFT && (!ses->term->spec->braille || f->vs->brl_in_field)) {
2721 			if (f->f_data->opt.cp != utf8_table) fs->state = fs->state ? fs->state - 1 : 0;
2722 			else {
2723 				unsigned char *p = fs->string + fs->state;
2724 				BACK_UTF_8(p, fs->string);
2725 				fs->state = (int)(p - fs->string);
2726 			}
2727 		} else if (ev->x == KBD_RIGHT && (!ses->term->spec->braille || f->vs->brl_in_field)) {
2728 			if ((size_t)fs->state < strlen(cast_const_char fs->string)) {
2729 				if (f->f_data->opt.cp != utf8_table) fs->state = fs->state + 1;
2730 				else {
2731 					unsigned char *p = fs->string + fs->state;
2732 					FWD_UTF_8(p);
2733 					fs->state = (int)(p - fs->string);
2734 				}
2735 			} else fs->state = (int)strlen(cast_const_char fs->string);
2736 		} else if ((ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) /*&& (!ses->term->spec->braille || f->vs->brl_in_field)*/) {
2737 			set_br_pos(f, l);
2738 			if (form->type == FC_TEXTAREA) {
2739 				ftce = format_text(f, form, fs);
2740 				y = find_cursor_line(ftce, fs->state);
2741 				if (y >= 0) {
2742 					fs->state = ftce->ln[y].st_offs;
2743 					goto done;
2744 				}
2745 				fs->state = 0;
2746 			} else fs->state = 0;
2747 		} else if ((ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) /*&& (!ses->term->spec->braille || f->vs->brl_in_field)*/) {
2748 			set_br_pos(f, l);
2749 			if (form->type == FC_TEXTAREA) {
2750 				ftce = format_text(f, form, fs);
2751 				y = find_cursor_line(ftce, fs->state);
2752 				if (y >= 0) {
2753 					fs->state = ftce->ln[y].en_offs;
2754 					if (fs->state && y < ftce->n_lines - 1 && ftce->ln[y + 1].st_offs == ftce->ln[y].en_offs)
2755 						fs->state--;
2756 					goto done;
2757 				}
2758 				fs->state = (int)strlen(cast_const_char fs->string);
2759 			} else fs->state = (int)strlen(cast_const_char fs->string);
2760 		} else if (ev->x == KBD_UP && (!ses->term->spec->braille || f->vs->brl_in_field)) {
2761 			if (form->type == FC_TEXTAREA) {
2762 				ftce = format_text(f, form, fs);
2763 				y = find_cursor_line(ftce, fs->state);
2764 				if (y >= 0) {
2765 					if (!y) {
2766 						goto b;
2767 					}
2768 					fs->state = (int)(textptr_add(fs->string + ftce->ln[y - 1].st_offs, textptr_diff(fs->string + fs->state, fs->string + ftce->ln[y].st_offs, f->f_data->opt.cp), f->f_data->opt.cp) - fs->string);
2769 					if (fs->state > ftce->ln[y - 1].en_offs) fs->state = ftce->ln[y - 1].en_offs;
2770 				} else
2771 					goto b;
2772 			} else r = 0, f->vs->brl_in_field = 0;
2773 		} else if (ev->x == KBD_DOWN && (!ses->term->spec->braille || f->vs->brl_in_field)) {
2774 			if (form->type == FC_TEXTAREA) {
2775 				ftce = format_text(f, form, fs);
2776 				y = find_cursor_line(ftce, fs->state);
2777 				if (y >= 0) {
2778 					if (y >= ftce->n_lines - 1) {
2779 						goto b;
2780 					}
2781 					fs->state = (int)(textptr_add(fs->string + ftce->ln[y + 1].st_offs, textptr_diff(fs->string + fs->state, fs->string + ftce->ln[y].st_offs, f->f_data->opt.cp), f->f_data->opt.cp) - fs->string);
2782 					if (fs->state > ftce->ln[y + 1].en_offs) fs->state = ftce->ln[y + 1].en_offs;
2783 				} else {
2784 					goto b;
2785 				}
2786 			} else r = 0, f->vs->brl_in_field = 0;
2787 		} else if ((ev->x == KBD_INS && ev->y & KBD_CTRL) || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL) || ev->x == KBD_COPY) {
2788 			set_br_pos(f, l);
2789 			set_clipboard_text(ses->term, fs->string);
2790 		} else if ((ev->x == KBD_DEL && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'X' && ev->y & KBD_CTRL) || ev->x == KBD_CUT) {
2791 			set_br_pos(f, l);
2792 			set_clipboard_text(ses->term, fs->string);
2793 			if (!form->ro) {
2794 				free_format_text_cache_entry(fs);
2795 				fs->string[0] = 0;
2796 			}
2797 			fs->state = 0;
2798 #ifdef JS
2799 			fs->changed = 1;
2800 			field_op_changed(f, l);
2801 #endif
2802 		} else if ((ev->x == KBD_INS && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'V' && ev->y & KBD_CTRL) || ev->x == KBD_PASTE) {
2803 			unsigned char *clipboard;
2804 			set_br_pos(f, l);
2805 			clipboard = get_clipboard_text(ses->term);
2806 			if (!clipboard) goto done;
2807 			if (form->type != FC_TEXTAREA) {
2808 				unsigned char *nl = clipboard;
2809 				while ((nl = cast_uchar strchr(cast_const_char nl, '\n'))) *nl = ' ';
2810 			}
2811 			if (!form->ro && cp_len(term_charset(ses->term), fs->string) + cp_len(term_charset(ses->term), clipboard) <= form->maxlength) {
2812 				unsigned char *v;
2813 				free_format_text_cache_entry(fs);
2814 				v = mem_realloc(fs->string, strlen(cast_const_char fs->string) + strlen(cast_const_char clipboard) +1);
2815 				fs->string = v;
2816 				memmove(v + fs->state + strlen(cast_const_char clipboard), v + fs->state, strlen(cast_const_char v) - fs->state + 1);
2817 				memcpy(v + fs->state, clipboard, strlen(cast_const_char clipboard));
2818 				fs->state += (int)strlen(cast_const_char clipboard);
2819 			}
2820 			mem_free(clipboard);
2821 #ifdef JS
2822 			fs->changed = 1;
2823 			field_op_changed(f, l);
2824 #endif
2825 		} else if (ev->x == KBD_ENTER) {
2826 			r = 0;
2827 		} else if (ev->x == KBD_BS) {
2828 			set_br_pos(f, l);
2829 			if (!form->ro && fs->state) {
2830 				int ll = 1;
2831 				free_format_text_cache_entry(fs);
2832 				if (f->f_data->opt.cp == utf8_table) {
2833 					unsigned char *p = fs->string + fs->state;
2834 					BACK_UTF_8(p, fs->string);
2835 					ll = (int)(fs->string + fs->state - p);
2836 				}
2837 				memmove(fs->string + fs->state - ll, fs->string + fs->state, strlen(cast_const_char(fs->string + fs->state)) + 1);
2838 				fs->state -= ll;
2839 #ifdef JS
2840 				fs->changed = 1;
2841 				field_op_changed(f, l);
2842 #endif
2843 			}
2844 		} else if (ev->x == KBD_DEL || (upcase(ev->x) == 'D' && ev->y & KBD_CTRL)) {
2845 			int ll = 1;
2846 			if (!F && ev->x == KBD_DEL && !f->last_captured)
2847 				return 0;
2848 			set_br_pos(f, l);
2849 			if (f->f_data->opt.cp == utf8_table) {
2850 				unsigned char *p = fs->string + fs->state;
2851 				FWD_UTF_8(p);
2852 				ll = (int)(p - (fs->string + fs->state));
2853 			}
2854 			if (!form->ro && (size_t)fs->state < strlen(cast_const_char fs->string)) {
2855 				free_format_text_cache_entry(fs);
2856 				memmove(fs->string + fs->state, fs->string + fs->state + ll, strlen(cast_const_char(fs->string + fs->state + ll)) + 1);
2857 #ifdef JS
2858 				fs->changed = 1;
2859 				field_op_changed(f, l);
2860 #endif
2861 			}
2862 		} else if (upcase(ev->x) == 'U' && ev->y & KBD_CTRL) {
2863 			unsigned char *a;
2864 			set_br_pos(f, l);
2865 			a = memacpy(fs->string, fs->state);
2866 			set_clipboard_text(ses->term, a);
2867 			mem_free(a);
2868 			if (!form->ro) {
2869 				free_format_text_cache_entry(fs);
2870 				memmove(fs->string, fs->string + fs->state, strlen(cast_const_char(fs->string + fs->state)) + 1);
2871 			}
2872 			fs->state = 0;
2873 #ifdef JS
2874 			fs->changed = 1;
2875 			field_op_changed(f, l);
2876 #endif
2877 		} else if (upcase(ev->x) == 'K' && ev->y & KBD_CTRL) {
2878 			set_br_pos(f, l);
2879 			if (!form->ro) {
2880 				if (form->type == FC_TEXTAREA) {
2881 					ftce = format_text(f, form, fs);
2882 					y = find_cursor_line(ftce, fs->state);
2883 					if (y >= 0) {
2884 						int l = ftce->ln[y].en_offs - ftce->ln[y].st_offs;
2885 						unsigned char *start_line = fs->string + ftce->ln[y].st_offs;
2886 						unsigned char *cp = memacpy(start_line, ftce->ln[y].en_offs - ftce->ln[y].st_offs);
2887 						set_clipboard_text(ses->term, cp);
2888 						mem_free(cp);
2889 						l += y < ftce->n_lines - 1 && ftce->ln[y + 1].st_offs > ftce->ln[y].en_offs;
2890 						memmove(fs->string + ftce->ln[y].st_offs, fs->string + ftce->ln[y].st_offs + l, strlen(cast_const_char(fs->string + ftce->ln[y].st_offs + l)) + 1);
2891 						fs->state = ftce->ln[y].st_offs;
2892 					}
2893 				} else {
2894 					set_clipboard_text(ses->term, fs->state + fs->string);
2895 					fs->string[fs->state] = 0;
2896 				}
2897 				free_format_text_cache_entry(fs);
2898 			}
2899 #ifdef JS
2900 			fs->changed = 1;
2901 			field_op_changed(f, l);
2902 #endif
2903 		} else {
2904 			b:
2905 			f->vs->brl_in_field = 0;
2906 			r = 0;
2907 		}
2908 	} else if (ev->ev == EV_MOUSE && BM_IS_WHEEL(ev->b) && form->type == FC_TEXTAREA) {
2909 		int xdiff = 0, ydiff = 0;
2910 		int x;
2911 		unsigned char *ap;
2912 
2913 		ftce = format_text(f, form, fs);
2914 		y = find_cursor_line(ftce, fs->state);
2915 		if (y >= 0)
2916 			x = textptr_diff(fs->string + fs->state, fs->string + ftce->ln[y].st_offs, f->f_data->opt.cp);
2917 		else
2918 			x = 0, y = 0;
2919 
2920 		if ((ev->b & BM_BUTT) == B_WHEELUP)
2921 			ydiff = form->rows >= 5 ? -5 : -form->rows;
2922 		else if ((ev->b & BM_BUTT) == B_WHEELUP1)
2923 			ydiff = -1;
2924 		else if ((ev->b & BM_BUTT) == B_WHEELDOWN)
2925 			ydiff = form->rows >= 5 ? 5 : form->rows;
2926 		else if ((ev->b & BM_BUTT) == B_WHEELDOWN1)
2927 			ydiff = 1;
2928 		else if ((ev->b & BM_BUTT) == B_WHEELLEFT)
2929 			xdiff = form->cols >= 5 ? -5 : -form->cols;
2930 		else if ((ev->b & BM_BUTT) == B_WHEELLEFT1)
2931 			xdiff = -1;
2932 		else if ((ev->b & BM_BUTT) == B_WHEELRIGHT)
2933 			xdiff = form->cols >= 5 ? 5 : form->cols;
2934 		else if ((ev->b & BM_BUTT) == B_WHEELRIGHT1)
2935 			xdiff = 1;
2936 
2937 		if (ydiff) {
2938 			int target_y = -1;
2939 			fs->vypos += ydiff;
2940 			if (fs->vypos > ftce->n_lines - form->rows) fs->vypos = ftce->n_lines - form->rows;
2941 			if (fs->vypos < 0) fs->vypos = 0;
2942 			if (y >= form->rows + fs->vypos) {
2943 				target_y = form->rows + fs->vypos - 1;
2944 				if (target_y < 0)
2945 					target_y = 0;
2946 			}
2947 			if (y < fs->vypos) {
2948 				target_y = fs->vypos;
2949 			}
2950 
2951 			if (target_y >= 0) {
2952 				if (target_y >= ftce->n_lines)
2953 					target_y = ftce->n_lines - 1;
2954 				fs->state = ftce->ln[target_y].st_offs;
2955 				if (x > ftce->ln[target_y].chars)
2956 					x = ftce->ln[target_y].chars;
2957 				ap = textptr_add(fs->string + fs->state, x, f->f_data->opt.cp);
2958 				fs->state = (int)(ap - fs->string);
2959 			}
2960 		} else if (xdiff) {
2961 			int j;
2962 			int maxx = 0;
2963 			int longest = y;
2964 			for (j = fs->vypos; j < fs->vypos + form->rows && j < ftce->n_lines; j++) {
2965 				if (ftce->ln[j].chars > maxx) {
2966 					maxx = ftce->ln[j].chars;
2967 					longest = j;
2968 				}
2969 			}
2970 			maxx -= form->cols - 1;
2971 			if (maxx < 0) maxx = 0;
2972 			fs->vpos += xdiff;
2973 			if (fs->vpos < 0) fs->vpos = 0;
2974 			if (fs->vpos > maxx) fs->vpos = maxx;
2975 			if (x > fs->vpos + form->cols - 1) {
2976 				ap = textptr_add(fs->string + ftce->ln[y].st_offs, fs->vpos + form->cols - 1, f->f_data->opt.cp);
2977 				fs->state = (int)(ap - fs->string);
2978 			} else if (x < fs->vpos) {
2979 				ap = textptr_add(fs->string + ftce->ln[y].st_offs, fs->vpos, f->f_data->opt.cp);
2980 				if (y < ftce->n_lines - 1 && ap >= fs->string + ftce->ln[y + 1].st_offs)
2981 					ap = textptr_add(fs->string + ftce->ln[longest].st_offs, fs->vpos, f->f_data->opt.cp);
2982 				fs->state = (int)(ap - fs->string);
2983 			}
2984 		}
2985 		goto done;
2986 	} else {
2987 		r = 0;
2988 	}
2989 done:
2990 	if (!F && r) {
2991 		if (((ev->ev != EV_KBD || (ev->x != KBD_UP && ev->x != KBD_DOWN)) || ses->term->spec->braille) && form->type == FC_TEXTAREA && textarea_adjust_viewport(f, l))
2992 			;
2993 		else x_draw_form_entry(ses, f, l);
2994 	}
2995 	if (!r && ses->term->spec->braille) {
2996 		f->vs->brl_x = ses->term->cx - f->xp + f->vs->view_posx;
2997 		f->vs->brl_y = ses->term->cy - f->yp + f->vs->view_pos;
2998 		f->vs->orig_brl_x = f->vs->brl_x;
2999 		f->vs->orig_brl_y = f->vs->brl_y;
3000 	}
3001 	return r;
3002 }
3003 
set_textarea(struct session * ses,struct f_data_c * f,int dir)3004 void set_textarea(struct session *ses, struct f_data_c *f, int dir)
3005 {
3006 	struct link *l = get_current_link(f);
3007 	if (l && l->type == L_AREA && !ses->term->spec->braille) {
3008 		struct form_control *form = l->form;
3009 		struct form_state *fs;
3010 		struct format_text_cache_entry *ftce;
3011 		int y;
3012 
3013 		if (form->ro == 2) return;
3014 		fs = find_form_state(f, form);
3015 		if (!fs->string) return;
3016 
3017 		ftce = format_text(f, form, fs);
3018 		y = find_cursor_line(ftce, fs->state);
3019 		if (y >= 0) {
3020 			int ty = dir < 0 ? 0 : ftce->n_lines - 1;
3021 			if (ty < 0) return;
3022 
3023 			fs->state = (int)(textptr_add(fs->string + ftce->ln[ty].st_offs, textptr_diff(fs->string + fs->state, fs->string + ftce->ln[y].st_offs, f->f_data->opt.cp), f->f_data->opt.cp) - fs->string);
3024 			if (fs->state > ftce->ln[ty].en_offs) fs->state = ftce->ln[ty].en_offs;
3025 		}
3026 	}
3027 }
3028 
search_for_back(void * ses_,unsigned char * str)3029 void search_for_back(void *ses_, unsigned char *str)
3030 {
3031 	struct session *ses = (struct session *)ses_;
3032 	struct f_data_c *f = current_frame(ses);
3033 	if (!f || !str || !str[0]) return;
3034 	if (ses->search_word) mem_free(ses->search_word);
3035 	ses->search_word = stracpy(str);
3036 	clr_spaces(ses->search_word, 0);
3037 	charset_upcase_string(&ses->search_word, term_charset(ses->term));
3038 	if (ses->last_search_word) mem_free(ses->last_search_word);
3039 	ses->last_search_word = stracpy(ses->search_word);
3040 	ses->search_direction = -1;
3041 	find_next(ses, f, 1);
3042 }
3043 
search_for(void * ses_,unsigned char * str)3044 void search_for(void *ses_, unsigned char *str)
3045 {
3046 	struct session *ses = (struct session *)ses_;
3047 	struct f_data_c *f = current_frame(ses);
3048 	if (!f || !f->vs || !f->f_data || !str || !str[0]) return;
3049 	if (ses->search_word) mem_free(ses->search_word);
3050 	ses->search_word = stracpy(str);
3051 	clr_spaces(ses->search_word, 0);
3052 	charset_upcase_string(&ses->search_word, term_charset(ses->term));
3053 	if (ses->last_search_word) mem_free(ses->last_search_word);
3054 	ses->last_search_word = stracpy(ses->search_word);
3055 	ses->search_direction = 1;
3056 	find_next(ses, f, 1);
3057 }
3058 
3059 #define HASH_SIZE	4096
3060 
3061 #define HASH(p) (((p.y << 6) + p.x) & (HASH_SIZE - 1))
3062 
point_intersect(struct point * p1,int l1,struct point * p2,int l2)3063 static int point_intersect(struct point *p1, int l1, struct point *p2, int l2)
3064 {
3065 	int i, j;
3066 	static unsigned char hash[HASH_SIZE];
3067 	static unsigned char init = 0;
3068 	if (!init) memset(hash, 0, HASH_SIZE), init = 1;
3069 	for (i = 0; i < l1; i++) hash[HASH(p1[i])] = 1;
3070 	for (j = 0; j < l2; j++) if (hash[HASH(p2[j])]) {
3071 		for (i = 0; i < l1; i++) if (p1[i].x == p2[j].x && p1[i].y == p2[j].y) {
3072 			for (i = 0; i < l1; i++) hash[HASH(p1[i])] = 0;
3073 			return 1;
3074 		}
3075 	}
3076 	for (i = 0; i < l1; i++) hash[HASH(p1[i])] = 0;
3077 	return 0;
3078 }
3079 
find_next_link_in_search(struct f_data_c * f,int d)3080 static int find_next_link_in_search(struct f_data_c *f, int d)
3081 {
3082 	struct point *pt;
3083 	int len;
3084 	struct link *link;
3085 	if (f->ses->term->spec->braille) {
3086 		int i, opt;
3087 		if (get_searched(f, &pt, &len))
3088 			return 1;
3089 		if (!len) {
3090 			mem_free(pt);
3091 			return 1;
3092 		}
3093 		opt = -1;
3094 		for (i = 0; i < len; i++) {
3095 			if (d > 0) {
3096 				if ((d == 2 || pt[i].y > f->vs->brl_y || (pt[i].y == f->vs->brl_y && pt[i].x > f->vs->brl_x)) && (opt == -1 || pt[i].y < pt[opt].y || (pt[i].y == pt[opt].y && pt[i].x < pt[opt].x))) opt = i;
3097 			}
3098 			if (d < 0) {
3099 				if ((d == -2 || pt[i].y < f->vs->brl_y || (pt[i].y == f->vs->brl_y && pt[i].x < f->vs->brl_x)) && (opt == -1 || pt[i].y > pt[opt].y || (pt[i].y == pt[opt].y && pt[i].x > pt[opt].x))) opt = i;
3100 			}
3101 		}
3102 		if (opt == -1) {
3103 			mem_free(pt);
3104 			return 1;
3105 		}
3106 		f->vs->brl_x = pt[opt].x;
3107 		f->vs->brl_y = pt[opt].y;
3108 		f->vs->orig_brl_x = f->vs->brl_x;
3109 		f->vs->orig_brl_y = f->vs->brl_y;
3110 		update_braille_link(f);
3111 		mem_free(pt);
3112 		return 0;
3113 	}
3114 	if (d == -2 || d == 2) {
3115 		d /= 2;
3116 		find_link(f, d, 0);
3117 		if (f->vs->current_link == -1) return 1;
3118 	} else nx:if (f->vs->current_link == -1 || !(next_in_view(f, f->vs->current_link + d, d, in_view, NULL))) {
3119 		find_link(f, d, 0);
3120 		return 1;
3121 	}
3122 	link = &f->f_data->links[f->vs->current_link];
3123 	if (get_searched(f, &pt, &len) < 0)
3124 		return 1;
3125 	if (point_intersect(pt, len, link->pos, link->n)) {
3126 		mem_free(pt);
3127 		return 0;
3128 	}
3129 	mem_free(pt);
3130 	goto nx;
3131 }
3132 
find_next(struct session * ses,struct f_data_c * f,int a)3133 void find_next(struct session *ses, struct f_data_c *f, int a)
3134 {
3135 	int min, max;
3136 	int c = 0;
3137 	int p;
3138 	if (!f->f_data || !f->vs) {
3139 		msg_box(ses->term, NULL, TEXT_(T_SEARCH), AL_CENTER, TEXT_(T_YOU_ARE_NOWHERE), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
3140 		return;
3141 	}
3142 	p = f->vs->view_pos;
3143 	if (!F && !a && ses->search_word) {
3144 		if (!(find_next_link_in_search(f, ses->search_direction))) return;
3145 		p += ses->search_direction * f->yw;
3146 	}
3147 	if (!ses->search_word) {
3148 		if (!ses->last_search_word) {
3149 			msg_box(ses->term, NULL, TEXT_(T_SEARCH), AL_CENTER, TEXT_(T_NO_PREVIOUS_SEARCH), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
3150 			return;
3151 		}
3152 		ses->search_word = stracpy(ses->last_search_word);
3153 	}
3154 	print_progress(ses, TEXT_(T_SEARCHING));
3155 #ifdef G
3156 	if (F) {
3157 		g_find_next(f, a);
3158 		return;
3159 	}
3160 #endif
3161 	if (get_search_data(f->f_data) < 0) {
3162 		mem_free(ses->search_word);
3163 		ses->search_word = NULL;
3164 		msg_box(ses->term, NULL, TEXT_(T_SEARCH), AL_CENTER, TEXT_(T_OUT_OF_MEMORY), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
3165 		return;
3166 	}
3167 	do {
3168 		if (is_in_range(f->f_data, p, f->yw, ses->search_word, &min, &max)) {
3169 			f->vs->view_pos = p;
3170 			if (max >= min) {
3171 				if (max > f->vs->view_posx + f->xw) f->vs->view_posx = max - f->xw;
3172 				if (min < f->vs->view_posx) f->vs->view_posx = min;
3173 			}
3174 			f->vs->orig_view_pos = f->vs->view_pos;
3175 			f->vs->orig_view_posx = f->vs->view_posx;
3176 			if (!ses->term->spec->braille) set_link(f);
3177 			find_next_link_in_search(f, ses->search_direction * 2);
3178 			return;
3179 		}
3180 		if ((p += ses->search_direction * f->yw) > f->f_data->y) p = 0;
3181 		if (p < 0) {
3182 			p = 0;
3183 			while (p < f->f_data->y) p += f->yw ? f->yw : 1;
3184 			p -= f->yw;
3185 		}
3186 	} while ((c += f->yw ? f->yw : 1) < f->f_data->y + f->yw);
3187 	msg_box(ses->term, NULL, TEXT_(T_SEARCH), AL_CENTER, TEXT_(T_SEARCH_STRING_NOT_FOUND), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
3188 }
3189 
find_next_back(struct session * ses,struct f_data_c * f,int a)3190 void find_next_back(struct session *ses, struct f_data_c *f, int a)
3191 {
3192 	ses->search_direction = - ses->search_direction;
3193 	find_next(ses, f, a);
3194 	ses->search_direction = - ses->search_direction;
3195 }
3196 
rep_ev(struct session * ses,struct f_data_c * fd,void (* f)(struct session *,struct f_data_c *,int),int a)3197 static void rep_ev(struct session *ses, struct f_data_c *fd, void (*f)(struct session *, struct f_data_c *, int), int a)
3198 {
3199 	int i = ses->kbdprefix.rep ? ses->kbdprefix.rep_num : 1;
3200 	while (i--) f(ses, fd, a);
3201 }
3202 
choose_mouse_link(struct f_data_c * f,struct links_event * ev)3203 static struct link *choose_mouse_link(struct f_data_c *f, struct links_event *ev)
3204 {
3205 	return get_link_at_location(f->f_data, ev->x + f->vs->view_posx, ev->y + f->vs->view_pos);
3206 }
3207 
goto_link_number(void * ses_,unsigned char * num)3208 static void goto_link_number(void *ses_, unsigned char *num)
3209 {
3210 	struct session *ses = (struct session *)ses_;
3211 	int n = atoi(cast_const_char num);
3212 	struct f_data_c *f = current_frame(ses);
3213 	struct link *link;
3214 	if (!f || !f->vs) return;
3215 	if (n < 0 || n > f->f_data->nlinks) return;
3216 	f->vs->current_link = n - 1;
3217 	f->vs->orig_link = f->vs->current_link;
3218 	link = &f->f_data->links[f->vs->current_link];
3219 	if (ses->term->spec->braille) {
3220 		if (link->n) {
3221 			f->vs->brl_x = link->pos[0].x;
3222 			f->vs->brl_y = link->pos[0].y;
3223 			f->vs->orig_brl_x = f->vs->brl_x;
3224 			f->vs->orig_brl_y = f->vs->brl_y;
3225 		}
3226 	}
3227 	check_vs(f);
3228 	f->vs->orig_view_pos = f->vs->view_pos;
3229 	f->vs->orig_view_posx = f->vs->view_posx;
3230 	if (link->type != L_AREA && link->type != L_FIELD) enter(ses, f, 0);
3231 }
3232 
3233 /* l must be a valid link, ev must be a mouse event */
find_pos_in_link(struct f_data_c * fd,struct link * l,struct links_event * ev,int * xx,int * yy)3234 static int find_pos_in_link(struct f_data_c *fd, struct link *l, struct links_event *ev, int *xx, int *yy)
3235 {
3236 	int a;
3237 	int minx, miny;
3238 	int found = 0;
3239 
3240 	if (!l->n) return 1;
3241 	minx = l->pos[0].x;
3242 	miny = l->pos[0].y;
3243 	for (a = 0; a < l->n; a++) {
3244 		if (l->pos[a].x < minx) minx = l->pos[a].x;
3245 		if (l->pos[a].y < miny) miny = l->pos[a].y;
3246 		if (l->pos[a].x - fd->vs->view_posx == ev->x && l->pos[a].y - fd->vs->view_pos == ev->y) (*xx = l->pos[a].x), (*yy = l->pos[a].y), found = 1;
3247 	}
3248 	if (!found) return 1;
3249 	*xx -= minx;
3250 	*yy -= miny;
3251 	return 0;
3252 }
3253 
frame_ev(struct session * ses,struct f_data_c * fd,struct links_event * ev)3254 static int frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev)
3255 {
3256 	int x = 1;
3257 
3258 	if (!fd || !fd->vs || !fd->f_data) return 0;
3259 	if (fd->vs->current_link >= 0 && (fd->f_data->links[fd->vs->current_link].type == L_FIELD || fd->f_data->links[fd->vs->current_link].type == L_AREA)) {
3260 		if (field_op(ses, fd, &fd->f_data->links[fd->vs->current_link], ev)) {
3261 			fd->last_captured = 1;
3262 			fd->vs->brl_in_field = 1;
3263 			return 1;
3264 		}
3265 	}
3266 	fd->last_captured = 0;
3267 	if (ev->ev == EV_KBD && !(ev->y & KBD_PASTING)) {
3268 		if (ev->x >= '0'+!ses->kbdprefix.rep && ev->x <= '9' && (!fd->f_data->opt.num_links || (ev->y & (KBD_CTRL | KBD_ALT)))) {
3269 			if (!ses->kbdprefix.rep) ses->kbdprefix.rep_num = 0;
3270 			if ((ses->kbdprefix.rep_num = ses->kbdprefix.rep_num * 10 + ev->x - '0') > 65536) ses->kbdprefix.rep_num = 65536;
3271 			ses->kbdprefix.rep = 1;
3272 			return 1;
3273 		}
3274 		if (ev->x == KBD_PAGE_DOWN || (ev->x == ' ' && (!(ev->y & KBD_ALT))) || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL)) rep_ev(ses, fd, page_down, 0);
3275 		else if (ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && (!(ev->y & KBD_ALT)))) rep_ev(ses, fd, page_up, 0);
3276 		else if (ev->x == KBD_DOWN) rep_ev(ses, fd, down, 0);
3277 		else if (ev->x == KBD_UP) rep_ev(ses, fd, up, 0);
3278 		else if (ev->x == KBD_LEFT && ses->term->spec->braille) rep_ev(ses, fd, left, 0);
3279 		else if (ev->x == KBD_RIGHT && ses->term->spec->braille) rep_ev(ses, fd, right, 0);
3280 		else if (ev->x == '{' && ses->term->spec->braille) rep_ev(ses, fd, cursor_home, 0);
3281 		else if (ev->x == '}' && ses->term->spec->braille) rep_ev(ses, fd, cursor_end, 0);
3282 		else if (upcase(ev->x) == 'Y' && !(ev->y & (KBD_CTRL | KBD_ALT)) && ses->term->spec->braille) rep_ev(ses, fd, cursor_word, 0);
3283 		else if (upcase(ev->x) == 'T' && !(ev->y & (KBD_CTRL | KBD_ALT)) && ses->term->spec->braille) rep_ev(ses, fd, cursor_word_back, 0);
3284 		else if (((ev->x == KBD_TAB && !ev->y && fd == ses->screen) || (upcase(ev->x) == 'Y' && ev->y & KBD_CTRL)) && ses->term->spec->braille) rep_ev(ses, fd, br_next_link, 0);
3285 		else if (((ev->x == KBD_TAB && ev->y && fd == ses->screen) || (upcase(ev->x) == 'T' && ev->y & KBD_CTRL)) && ses->term->spec->braille) rep_ev(ses, fd, br_prev_link, 0);
3286 		else if (upcase(ev->x) == 'O' && ev->y & KBD_CTRL && ses->term->spec->braille) rep_ev(ses, fd, br_next_link, 1);
3287 		/* Copy current link to clipboard */
3288 		else if ((ev->x == KBD_INS && ev->y & KBD_CTRL) || (upcase(ev->x) == 'C' && ev->y & KBD_CTRL)) {
3289 			unsigned char *current_link = print_current_link(ses);
3290 			if (current_link) {
3291 				set_clipboard_text(ses->term, current_link);
3292 				mem_free(current_link);
3293 			}
3294 		}
3295 		else if (ev->x == KBD_INS || (upcase(ev->x) == 'P' && ev->y & KBD_CTRL) || (ev->x == 'p' && !(ev->y & (KBD_CTRL | KBD_ALT)))) rep_ev(ses, fd, scroll, -1 - !ses->kbdprefix.rep);
3296 		else if (ev->x == KBD_DEL || (upcase(ev->x) == 'N' && ev->y & KBD_CTRL) || (ev->x == 'l' && !(ev->y & (KBD_CTRL | KBD_ALT)))) rep_ev(ses, fd, scroll, 1 + !ses->kbdprefix.rep);
3297 		else if (ev->x == '[') rep_ev(ses, fd, hscroll, -1 - 7 * !ses->kbdprefix.rep);
3298 		else if (ev->x == ']') rep_ev(ses, fd, hscroll, 1 + 7 * !ses->kbdprefix.rep);
3299 		else if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) rep_ev(ses, fd, home, 0);
3300 		else if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) rep_ev(ses, fd, x_end, 0);
3301 		else if ((ev->x == KBD_RIGHT && !ses->term->spec->braille) || ev->x == KBD_ENTER) {
3302 			x = enter(ses, fd, 0);
3303 		} else if (ev->x == '*') {
3304 			ses->ds.images ^= 1;
3305 			html_interpret_recursive(ses->screen);
3306 			draw_formatted(ses);
3307 		} else if (ev->x == 'i' && !(ev->y & KBD_ALT)) {
3308 			if (!F || fd->f_data->opt.plain != 2) frm_view_image(ses, fd);
3309 		} else if (ev->x == 'I' && !(ev->y & KBD_ALT)) {
3310 			if (!anonymous) frm_download_image(ses, fd);
3311 		} else if (upcase(ev->x) == 'D' && !(ev->y & KBD_ALT)) {
3312 			if (!anonymous) frm_download(ses, fd);
3313 		} else if (ev->x == '/' || (ev->x == KBD_FIND && !(ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT)))) search_dlg(ses, fd, 0);
3314 		else if (ev->x == '?' || (ev->x == KBD_FIND && ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT))) search_back_dlg(ses, fd, 0);
3315 		else if ((ev->x == 'n' && !(ev->y & KBD_ALT)) || ev->x == KBD_REDO) find_next(ses, fd, 0);
3316 		else if ((ev->x == 'N' && !(ev->y & KBD_ALT)) || ev->x == KBD_UNDO) find_next_back(ses, fd, 0);
3317 		else if ((upcase(ev->x) == 'F' && !(ev->y & (KBD_ALT | KBD_CTRL))) || ev->x == KBD_FRONT) set_frame(ses, fd, 0);
3318 		else if (ev->x == 'H' && !(ev->y & (KBD_CTRL | KBD_ALT))) find_link(fd, 1, 1);
3319 		else if (ev->x == 'L' && !(ev->y & (KBD_CTRL | KBD_ALT))) find_link(fd, -1, 1);
3320 		else if (ev->x >= '1' && ev->x <= '9' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
3321 			struct f_data *f_data = fd->f_data;
3322 			int nl, lnl;
3323 			unsigned char d[2];
3324 			d[0] = (unsigned char)ev->x;
3325 			d[1] = 0;
3326 			nl = f_data->nlinks, lnl = 1;
3327 			while (nl) nl /= 10, lnl++;
3328 			if (lnl > 1) input_field(ses->term, NULL, TEXT_(T_GO_TO_LINK), TEXT_(T_ENTER_LINK_NUMBER), ses, NULL, lnl, d, 1, f_data->nlinks, check_number, 2, TEXT_(T_OK), goto_link_number, TEXT_(T_CANCEL), input_field_null);
3329 		}
3330 		else x = 0;
3331 	} else if (ev->ev == EV_MOUSE && (ev->b & BM_BUTT) == B_WHEELUP) rep_ev(ses, fd, scroll, -1 - 5 * !ses->kbdprefix.rep);
3332 	else if (ev->ev == EV_MOUSE && (ev->b & BM_BUTT) == B_WHEELDOWN) rep_ev(ses, fd, scroll, 1 + 5 * !ses->kbdprefix.rep);
3333 	else if (ev->ev == EV_MOUSE && (ev->b & BM_BUTT) == B_WHEELLEFT) rep_ev(ses, fd, hscroll, -1 - 3 * !ses->kbdprefix.rep);
3334 	else if (ev->ev == EV_MOUSE && (ev->b & BM_BUTT) == B_WHEELRIGHT) rep_ev(ses, fd, hscroll, 1 + 3 * !ses->kbdprefix.rep);
3335 	else if (ev->ev == EV_MOUSE && (ev->b & BM_BUTT) <= B_RIGHT) {
3336 		struct link *l = choose_mouse_link(fd, ev);
3337 		if (l) {
3338 			x = 1;
3339 			fd->vs->current_link = (int)(l - fd->f_data->links);
3340 			fd->vs->orig_link = fd->vs->current_link;
3341 			if (l->type == L_LINK || l->type == L_BUTTON || l->type == L_CHECKBOX || l->type == L_SELECT) if ((ev->b & BM_ACT) == B_UP) {
3342 				fd->active = 1;
3343 				draw_to_window(ses->win, draw_doc_c, fd);
3344 				change_screen_status(ses);
3345 				print_screen_status(ses);
3346 				if ((ev->b & BM_BUTT) == B_LEFT) x = enter(ses, fd, 0);
3347 				else link_menu(ses->term, NULL, ses);
3348 			}
3349 
3350 			set_form_position(fd, l, ev);
3351 		}
3352 	} else x = 0;
3353 	ses->kbdprefix.rep = 0;
3354 	return x;
3355 }
3356 
current_frame(struct session * ses)3357 struct f_data_c *current_frame(struct session *ses)
3358 {
3359 	struct f_data_c *fd, *fdd;
3360 	struct list_head *lfdd;
3361 	fd = ses->screen;
3362 	while (!list_empty(fd->subframes)) {
3363 		int n = fd->vs->frame_pos;
3364 		if (n == -1) break;
3365 		foreach(struct f_data_c, fdd, lfdd, fd->subframes) if (!n--) {
3366 			fd = fdd;
3367 			goto r;
3368 		}
3369 		fd = list_struct(fd->subframes.next, struct f_data_c);
3370 		r:;
3371 	}
3372 	return fd;
3373 }
3374 
is_active_frame(struct session * ses,struct f_data_c * f)3375 static int is_active_frame(struct session *ses, struct f_data_c *f)
3376 {
3377 	struct f_data_c *fd, *fdd;
3378 	struct list_head *lfdd;
3379 	fd = ses->screen;
3380 	if (f == fd) return 1;
3381 	while (!list_empty(fd->subframes)) {
3382 		int n = fd->vs->frame_pos;
3383 		if (n == -1) break;
3384 		foreach(struct f_data_c, fdd, lfdd, fd->subframes) if (!n--) {
3385 			fd = fdd;
3386 			goto r;
3387 		}
3388 		fd = list_struct(fd->subframes.next, struct f_data_c);
3389 		r:
3390 		if (f == fd) return 1;
3391 	}
3392 	return 0;
3393 }
3394 
3395 #ifdef JS
event_catchable(struct links_event * ev)3396 static int event_catchable(struct links_event *ev)
3397 {
3398 	if (ev->ev != EV_KBD) return 0;
3399 	if (ev->x == KBD_TAB || ev->x == KBD_ESC || ev->x == KBD_CTRL_C || ev->x == KBD_CLOSE) return 0;
3400 	return 1;
3401 }
3402 
call_keyboard_event(struct f_data_c * fd,unsigned char * code,struct links_event * ev)3403 static int call_keyboard_event(struct f_data_c *fd, unsigned char *code, struct links_event *ev)
3404 {
3405 	int keycode;
3406 	unsigned char *shiftkey, *ctrlkey, *altkey;
3407 	unsigned char *nc;
3408 	int nl;
3409 	shiftkey = ev->y & KBD_SHIFT ? "true" : "false";
3410 	ctrlkey = ev->y & KBD_CTRL ? "true" : "false";
3411 	altkey = ev->y & KBD_ALT ? "true" : "false";
3412 	if (ev->x >= 0) {
3413 		if (ev->x < 0x80 || term_charset(fd->ses->term) == utf8_table) keycode = ev->x;
3414 		else keycode = cp2u(ev->x, term_charset(fd->ses->term));
3415 	}
3416 	else if (ev->x == KBD_ENTER) keycode = 13;
3417 	else if (ev->x == KBD_BS) keycode = 8;
3418 	else if (ev->x == KBD_TAB) keycode = 9;
3419 	else if (ev->x == KBD_ESC) keycode = 27;
3420 	else if (ev->x == KBD_INS) keycode = 45;
3421 	else if (ev->x == KBD_DEL) keycode = 46;
3422 	else if (ev->x == KBD_PAGE_UP) keycode = 33;
3423 	else if (ev->x == KBD_PAGE_DOWN) keycode = 34;
3424 	else if (ev->x == KBD_END) keycode = 35;
3425 	else if (ev->x == KBD_HOME) keycode = 36;
3426 	else if (ev->x == KBD_LEFT) keycode = 37;
3427 	else if (ev->x == KBD_UP) keycode = 38;
3428 	else if (ev->x == KBD_RIGHT) keycode = 39;
3429 	else if (ev->x == KBD_DOWN) keycode = 40;
3430 	else if (ev->x == KBD_F1) keycode = 112;
3431 	else if (ev->x == KBD_F2) keycode = 113;
3432 	else if (ev->x == KBD_F3) keycode = 114;
3433 	else if (ev->x == KBD_F4) keycode = 115;
3434 	else if (ev->x == KBD_F5) keycode = 116;
3435 	else if (ev->x == KBD_F6) keycode = 117;
3436 	else if (ev->x == KBD_F7) keycode = 118;
3437 	else if (ev->x == KBD_F8) keycode = 119;
3438 	else if (ev->x == KBD_F9) keycode = 120;
3439 	else if (ev->x == KBD_F10) keycode = 121;
3440 	else if (ev->x == KBD_F11) keycode = 122;
3441 	else if (ev->x == KBD_F12) keycode = 123;
3442 	else return -1;
3443 	nc = init_str();
3444 	nl = 0;
3445 	add_to_str(&nc, &nl, cast_uchar "event = new Object(); event.keyCode = ");
3446 	add_num_to_str(&nc, &nl, keycode);
3447 	add_to_str(&nc, &nl, cast_uchar "; event.shiftKey = ");
3448 	add_to_str(&nc, &nl, shiftkey);
3449 	add_to_str(&nc, &nl, cast_uchar "; event.ctrlKey = ");
3450 	add_to_str(&nc, &nl, ctrlkey);
3451 	add_to_str(&nc, &nl, cast_uchar "; event.altKey = ");
3452 	add_to_str(&nc, &nl, altkey);
3453 	add_to_str(&nc, &nl, cast_uchar "; ");
3454 	add_to_str(&nc, &nl, code);
3455 	jsint_execute_code(fd, nc, nl, -1, -1, -1, ev);
3456 	mem_free(nc);
3457 	return 0;
3458 }
3459 #endif
3460 
send_to_frame(struct session * ses,struct links_event * ev)3461 static int send_to_frame(struct session *ses, struct links_event *ev)
3462 {
3463 	int r;
3464 	struct f_data_c *fd;
3465 #ifdef JS
3466 	int previous_link;
3467 #endif
3468 	fd = current_frame(ses);
3469 	if (!fd) {
3470 		/*internal_error("document not formatted");*/
3471 		return 0;
3472 	}
3473 
3474 #ifdef JS
3475 	previous_link=fd->vs ? fd->vs->current_link : -1;
3476 	if (!event_catchable(ev) || !fd->f_data || !fd->vs) goto dont_catch;
3477 	if (fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks) {
3478 		struct link *l = &fd->f_data->links[fd->vs->current_link];
3479 		if (ev->b < EVH_LINK_KEYDOWN_PROCESSED && l->js_event && l->js_event->keydown_code) {
3480 			ev->b = EVH_LINK_KEYDOWN_PROCESSED;
3481 			if (!(call_keyboard_event(fd, l->js_event->keydown_code, ev))) return 1;
3482 		}
3483 		if (ev->b < EVH_LINK_KEYPRESS_PROCESSED && l->js_event && l->js_event->keypress_code) {
3484 			ev->b = EVH_LINK_KEYPRESS_PROCESSED;
3485 			if (!(call_keyboard_event(fd, l->js_event->keypress_code, ev))) return 1;
3486 		}
3487 	}
3488 	if (ev->b < EVH_DOCUMENT_KEYDOWN_PROCESSED && fd->f_data->js_event && fd->f_data->js_event->keydown_code) {
3489 		ev->b = EVH_DOCUMENT_KEYDOWN_PROCESSED;
3490 		if (!(call_keyboard_event(fd, fd->f_data->js_event->keydown_code, ev))) return 1;
3491 	}
3492 	if (ev->b < EVH_DOCUMENT_KEYPRESS_PROCESSED && fd->f_data->js_event && fd->f_data->js_event->keypress_code) {
3493 		ev->b = EVH_DOCUMENT_KEYPRESS_PROCESSED;
3494 		if (!(call_keyboard_event(fd, fd->f_data->js_event->keypress_code, ev))) return 1;
3495 	}
3496 	dont_catch:
3497 #endif
3498 
3499 	if (!F) r = frame_ev(ses, fd, ev);
3500 #ifdef G
3501 	else r = g_frame_ev(ses, fd, ev);
3502 #endif
3503 	if (r == 1) {
3504 		fd->active = 1;
3505 		draw_to_window(ses->win, draw_doc_c, fd);
3506 		change_screen_status(ses);
3507 		print_screen_status(ses);
3508 	}
3509 	if (r == 3) draw_fd_nrd(fd);
3510 	if (!F && fd->vs) {
3511 #ifdef JS
3512 		if (previous_link!=fd->vs->current_link&&fd->f_data&&previous_link>=0&&previous_link<fd->f_data->nlinks) /* link has changed */
3513 		{
3514 			struct link *l=&(fd->f_data->links[previous_link]);
3515 
3516 			/* process onchange code, if previous link was a textarea or a textfield and has changed */
3517 			if (l->type==L_FIELD||l->type==L_AREA) {
3518 				struct form_state *fs = find_form_state(fd,l->form);
3519 				if (fs->changed && l->js_event && l->js_event->change_code)
3520 					fs->changed=0, jsint_execute_code(fd, l->js_event->change_code, strlen(cast_const_char l->js_event->change_code), -1, -1, -1, NULL);
3521 			}
3522 
3523 			/* process blur and mouse-out handlers */
3524 			if (l->js_event&&l->js_event->blur_code)
3525 				jsint_execute_code(fd,l->js_event->blur_code,strlen(cast_const_char l->js_event->blur_code),-1,-1,-1, NULL);
3526 			if (l->js_event&&l->js_event->out_code)
3527 				jsint_execute_code(fd,l->js_event->out_code,strlen(cast_const_char l->js_event->out_code),-1,-1,-1, NULL);
3528 		}
3529 		if (previous_link!=fd->vs->current_link&&fd->f_data&&fd->vs->current_link>=0&&fd->vs->current_link<fd->f_data->nlinks)
3530 		{
3531 			struct link *l=&(fd->f_data->links[fd->vs->current_link]);
3532 
3533 			/* process focus and mouse-over handlers */
3534 			if (l->js_event&&l->js_event->focus_code)
3535 				jsint_execute_code(fd,l->js_event->focus_code,strlen(cast_const_char l->js_event->focus_code),-1,-1,-1, NULL);
3536 			if (l->js_event&&l->js_event->over_code)
3537 				jsint_execute_code(fd,l->js_event->over_code,strlen(cast_const_char l->js_event->over_code),-1,-1,-1, NULL);
3538 		}
3539 #endif
3540 	}
3541 	return r;
3542 }
3543 
next_frame(struct session * ses,int p)3544 void next_frame(struct session *ses, int p)
3545 {
3546 	int n;
3547 	struct view_state *vs;
3548 	struct f_data_c *fd, *fdd;
3549 	struct list_head *lfdd;
3550 
3551 	if (!(fd = current_frame(ses))) return;
3552 #ifdef G
3553 	ses->locked_link = 0;
3554 #endif
3555 	while ((fd = fd->parent)) {
3556 		n = (int)list_size(&fd->subframes);
3557 		vs = fd->vs;
3558 		vs->frame_pos += p;
3559 		if (vs->frame_pos < -!fd->f_data->frame_desc) { vs->frame_pos = n - 1; continue; }
3560 		if (vs->frame_pos >= n) { vs->frame_pos = -!fd->f_data->frame_desc; continue; }
3561 		break;
3562 	}
3563 	if (!fd) fd = ses->screen;
3564 	vs = fd->vs;
3565 	n = 0;
3566 	foreach(struct f_data_c, fdd, lfdd, fd->subframes) if (n++ == vs->frame_pos) {
3567 		fd = fdd;
3568 		next_sub:
3569 		if (list_empty(fd->subframes)) break;
3570 		fd = list_struct(p < 0 ? fd->subframes.prev : fd->subframes.next, struct f_data_c);
3571 		vs = fd->vs;
3572 		vs->frame_pos = -1;
3573 		if (!fd->f_data || (!fd->f_data->frame_desc && p > 0)) break;
3574 		if (p < 0) vs->frame_pos += (int)list_size(&fd->subframes);
3575 		else vs->frame_pos = 0;
3576 		goto next_sub;
3577 	}
3578 #ifdef G
3579 	if (F && (fd = current_frame(ses)) && fd->vs && fd->f_data) {
3580 		if (fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks) {
3581 			/*fd->vs->g_display_link = 1;*/
3582 			if (fd->vs->g_display_link && (fd->f_data->links[fd->vs->current_link].type == L_FIELD || fd->f_data->links[fd->vs->current_link].type == L_AREA)) {
3583 				if ((fd->f_data->locked_on = fd->f_data->links[fd->vs->current_link].obj)) fd->ses->locked_link = 1;
3584 			}
3585 		}
3586 	}
3587 #endif
3588 }
3589 
do_for_frame(struct session * ses,void (* f)(struct session *,struct f_data_c *,int),int a)3590 void do_for_frame(struct session *ses, void (*f)(struct session *, struct f_data_c *, int), int a)
3591 {
3592 	struct f_data_c *fd = current_frame(ses);
3593 	if (!fd) {
3594 		/*internal_error("document not formatted");*/
3595 		return;
3596 	}
3597 	f(ses, fd, a);
3598 	if (!F) {
3599 		fd->active = 1;
3600 		draw_to_window(ses->win, draw_doc_c, fd);
3601 		change_screen_status(ses);
3602 		print_screen_status(ses);
3603 	}
3604 }
3605 
do_mouse_event(struct session * ses,struct links_event * ev)3606 static void do_mouse_event(struct session *ses, struct links_event *ev)
3607 {
3608 	struct links_event evv;
3609 	struct f_data_c *fdd, *fd = current_frame(ses);
3610 	if (!fd) return;
3611 	if (ev->x >= fd->xp && ev->x < fd->xp + fd->xw &&
3612 	    ev->y >= fd->yp && ev->y < fd->yp + fd->yw) goto ok;
3613 #ifdef G
3614 	if (ses->scrolling) goto ok;
3615 #endif
3616 	r:
3617 	next_frame(ses, 1);
3618 	fdd = current_frame(ses);
3619 	/*o = &fdd->f_data->opt;*/
3620 	if (ev->x >= fdd->xp && ev->x < fdd->xp + fdd->xw &&
3621 	    ev->y >= fdd->yp && ev->y < fdd->yp + fdd->yw) {
3622 		draw_formatted(ses);
3623 		fd = fdd;
3624 		goto ok;
3625 	}
3626 	if (fdd != fd) goto r;
3627 	return;
3628 	ok:
3629 	memcpy(&evv, ev, sizeof(struct links_event));
3630 	evv.x -= fd->xp;
3631 	evv.y -= fd->yp;
3632 	send_to_frame(ses, &evv);
3633 }
3634 
send_event(struct session * ses,struct links_event * ev)3635 void send_event(struct session *ses, struct links_event *ev)
3636 {
3637 	if (ses->brl_cursor_mode) {
3638 		ses->brl_cursor_mode = 0;
3639 		print_screen_status(ses);
3640 	}
3641 	if (ev->ev == EV_KBD) {
3642 		if (send_to_frame(ses, ev)) return;
3643 		if (ev->y & KBD_PASTING) goto x;
3644 		if (ev->y & KBD_ALT && ev->x != KBD_TAB && !KBD_ESCAPE_MENU(ev->x)) {
3645 			struct window *m;
3646 			ev->y &= ~KBD_ALT;
3647 			activate_bfu_technology(ses, -1);
3648 			m = list_struct(ses->term->windows.next, struct window);
3649 			m->handler(m, ev, 0);
3650 			if (ses->term->windows.next == &m->list_entry) {
3651 				delete_window(m);
3652 			} else goto x;
3653 			ev->y |= KBD_ALT;
3654 		}
3655 		if (ev->x == KBD_F1 || ev->x == KBD_HELP) {
3656 			activate_keys(ses);
3657 			goto x;
3658 		}
3659 		if (ev->x == KBD_ESC || ev->x == KBD_F9) {
3660 			activate_bfu_technology(ses, -1);
3661 			goto x;
3662 		}
3663 		if (ev->x == KBD_F10) {
3664 			activate_bfu_technology(ses, 0);
3665 			goto x;
3666 		}
3667 		if (ev->x == KBD_TAB) {
3668 			next_frame(ses, ev->y ? -1 : 1);
3669 			draw_formatted(ses);
3670 		}
3671 		if (ev->x == KBD_LEFT && !ses->term->spec->braille) {
3672 			go_back(ses, 1);
3673 			goto x;
3674 		}
3675 		if ((upcase(ev->x) == 'Z' && !(ev->y & (KBD_CTRL | KBD_ALT))) || ev->x == KBD_BS || ev->x == KBD_BACK) {
3676 			go_back(ses, 1);
3677 			goto x;
3678 		}
3679 		if ((upcase(ev->x) == 'X' && !(ev->y & (KBD_CTRL | KBD_ALT))) || ev->x == '\'' || ev->x == KBD_FORWARD) {
3680 			go_back(ses, -1);
3681 			goto x;
3682 		}
3683 		if (upcase(ev->x) == 'A' && ses->term->spec->braille) {
3684 			ses->brl_cursor_mode = 2;
3685 			print_screen_status(ses);
3686 			goto x;
3687 		}
3688 		if (upcase(ev->x) == 'W' && ses->term->spec->braille) {
3689 			ses->brl_cursor_mode = 1;
3690 			print_screen_status(ses);
3691 			goto x;
3692 		}
3693 		if ((upcase(ev->x) == 'R' && ev->y & KBD_CTRL) || ev->x == KBD_RELOAD) {
3694 			reload(ses, -1);
3695 			goto x;
3696 		}
3697 		if ((ev->x == 'g' && !(ev->y & (KBD_CTRL | KBD_ALT))) || (ev->x == KBD_OPEN && !(ev->y & (KBD_SHIFT | KBD_CTRL)))) {
3698 			quak:
3699 			dialog_goto_url(ses, cast_uchar "");
3700 			goto x;
3701 		}
3702 		if ((ev->x == 'G' && !(ev->y & (KBD_CTRL | KBD_ALT))) || (ev->x == KBD_OPEN && ev->y & KBD_SHIFT)) {
3703 			unsigned char *s;
3704 			if (list_empty(ses->history) || !ses->screen->rq->url) goto quak;
3705 			s = display_url(ses->term, ses->screen->rq->url, 0);
3706 			dialog_goto_url(ses, s);
3707 			mem_free(s);
3708 			goto x;
3709 		}
3710 		if ((upcase(ev->x) == 'G' && ev->y & KBD_CTRL) || (ev->x == KBD_OPEN && ev->y & KBD_CTRL)) {
3711 			struct f_data_c *fd = current_frame(ses);
3712 			unsigned char *s;
3713 			if (!fd->vs || !fd->f_data || fd->vs->current_link < 0 || fd->vs->current_link >= fd->f_data->nlinks) goto quak;
3714 			s = display_url(ses->term, fd->f_data->links[fd->vs->current_link].where, 0);
3715 			dialog_goto_url(ses, s);
3716 			mem_free(s);
3717 			goto x;
3718 		}
3719 		if (ev->x == KBD_PROPS) {
3720 			dialog_html_options(ses);
3721 			goto x;
3722 		}
3723 		/*
3724 		if (upcase(ev->x) == 'A' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
3725 			if (!anonymous) menu_bookmark_manager(ses->term, NULL, ses);
3726 			goto x;
3727 		}
3728 		*/
3729 		if ((upcase(ev->x) == 'S' && !(ev->y & (KBD_CTRL | KBD_ALT))) || ev->x == KBD_BOOKMARKS) {
3730 			if (!anonymous) menu_bookmark_manager(ses->term, NULL, ses);
3731 			goto x;
3732 		}
3733 		if ((upcase(ev->x) == 'Q' && !(ev->y & (KBD_CTRL | KBD_ALT))) || ev->x == KBD_CTRL_C) {
3734 			exit_prog(ses->term, (void *)(my_intptr_t)(ev->x == KBD_CTRL_C || ev->x == 'Q'), ses);
3735 			goto x;
3736 		}
3737 		if (ev->x == KBD_CLOSE) {
3738 			really_exit_prog(ses);
3739 			goto x;
3740 		}
3741 		if (ev->x == '=') {
3742 			state_msg(ses);
3743 			goto x;
3744 		}
3745 		if (ev->x == '|') {
3746 			head_msg(ses);
3747 			goto x;
3748 		}
3749 		if (ev->x == '\\') {
3750 			toggle(ses, ses->screen, 0);
3751 			goto x;
3752 		}
3753 	}
3754 	if (ev->ev == EV_MOUSE) {
3755 		if (ev->b == (B_DOWN | B_FOURTH)) {
3756 			go_back(ses, 1);
3757 			goto x;
3758 		}
3759 		if (ev->b == (B_DOWN | B_FIFTH)) {
3760 			go_back(ses, -1);
3761 			goto x;
3762 		}
3763 #ifdef G
3764 		if (ses->locked_link) {
3765 			if (BM_IS_WHEEL(ev->b)) {
3766 				send_to_frame(ses, ev);
3767 				return;
3768 			} else if ((ev->b & BM_ACT) != B_MOVE) {
3769 				ses->locked_link = 0;
3770 #ifdef JS
3771 				/* process onblur handler of current link */
3772 				if (ses->screen&&ses->screen->vs&&ses->screen->f_data&&ses->screen->vs->current_link>=0&&ses->screen->vs->current_link<ses->screen->f_data->nlinks)
3773 				{
3774 					struct link *lnk=&(ses->screen->f_data->links[ses->screen->vs->current_link]);
3775 					/* select se dela jinde */
3776 					if (lnk->type!=L_SELECT&&lnk->js_event&&lnk->js_event->blur_code)
3777 						jsint_execute_code(current_frame(ses),lnk->js_event->blur_code,strlen(cast_const_char lnk->js_event->blur_code),-1,-1,-1, NULL);
3778 
3779 					/* execute onchange handler of text field/area */
3780 					if ((lnk->type==L_AREA||lnk->type==L_FIELD)) {
3781 						struct form_state *fs = find_form_state(ses->screen,lnk->form);
3782 						if (fs->changed && lnk->js_event && lnk->js_event->change_code)
3783 							fs->changed = 0, jsint_execute_code(current_frame(ses), lnk->js_event->change_code, strlen(cast_const_char lnk->js_event->change_code), -1, -1, -1, NULL);
3784 					}
3785 				}
3786 #endif
3787 				clr_xl(ses->screen);
3788 				draw_formatted(ses);
3789 			} else return;
3790 		}
3791 #endif
3792 		if (ev->y >= 0 && ev->y < gf_val(1, G_BFU_FONT_SIZE) && ev->x >=0 && ev->x < ses->term->x && (ev->b & BM_ACT) == B_DOWN) {
3793 #ifdef G
3794 			if (F && ev->x < ses->back_size) {
3795 				go_back(ses, 1);
3796 				goto x;
3797 			} else
3798 #endif
3799 			{
3800 				struct window *m;
3801 				activate_bfu_technology(ses, -1);
3802 				m = list_struct(ses->term->windows.next, struct window);
3803 				m->handler(m, ev, 0);
3804 				goto x;
3805 			}
3806 		}
3807 		do_mouse_event(ses, ev);
3808 	}
3809 	return;
3810 	x:
3811 	ses->kbdprefix.rep = 0;
3812 }
3813 
send_enter(struct terminal * term,void * xxx,void * ses_)3814 static void send_enter(struct terminal *term, void *xxx, void *ses_)
3815 {
3816 	struct session *ses = (struct session *)ses_;
3817 	struct links_event ev = { EV_KBD, KBD_ENTER, 0, 0 };
3818 	send_event(ses, &ev);
3819 }
3820 
frm_download(struct session * ses,struct f_data_c * fd)3821 void frm_download(struct session *ses, struct f_data_c *fd)
3822 {
3823 	struct link *link = get_current_link(fd);
3824 	if (!link) return;
3825 	if (ses->dn_url) mem_free(ses->dn_url), ses->dn_url = NULL;
3826 	if (link->type != L_LINK && link->type != L_BUTTON) return;
3827 	if ((ses->dn_url = get_link_url(ses, fd, link, NULL))) {
3828 		ses->dn_allow_flags = f_data_c_allow_flags(fd);
3829 		if (!casecmp(ses->dn_url, cast_uchar "MAP@", 4)) {
3830 			mem_free(ses->dn_url);
3831 			ses->dn_url = NULL;
3832 			return;
3833 		}
3834 		query_file(ses, ses->dn_url, NULL, start_download, NULL, DOWNLOAD_CONTINUE);
3835 	}
3836 }
3837 
frm_view_image(struct session * ses,struct f_data_c * fd)3838 void frm_view_image(struct session *ses, struct f_data_c *fd)
3839 {
3840 	struct link *link = get_current_link(fd);
3841 	if (!link) return;
3842 	if (link->type != L_LINK && link->type != L_BUTTON) return;
3843 	if (!link->where_img) return;
3844 	goto_url_not_from_dialog(ses, link->where_img, fd);
3845 }
3846 
frm_download_image(struct session * ses,struct f_data_c * fd)3847 void frm_download_image(struct session *ses, struct f_data_c *fd)
3848 {
3849 	struct link *link = get_current_link(fd);
3850 	if (!link) return;
3851 	if (ses->dn_url) mem_free(ses->dn_url), ses->dn_url = NULL;
3852 	if (link->type != L_LINK && link->type != L_BUTTON) return;
3853 	if (!link->where_img) return;
3854 	if ((ses->dn_url = stracpy(link->where_img))) {
3855 		ses->dn_allow_flags = f_data_c_allow_flags(fd);
3856 		if (!casecmp(ses->dn_url, cast_uchar "MAP@", 4)) {
3857 			mem_free(ses->dn_url);
3858 			ses->dn_url = NULL;
3859 			return;
3860 		}
3861 		query_file(ses, ses->dn_url, NULL, start_download, NULL, DOWNLOAD_CONTINUE);
3862 	}
3863 }
3864 
send_download_image(struct terminal * term,void * xxx,void * ses_)3865 static void send_download_image(struct terminal *term, void *xxx, void *ses_)
3866 {
3867 	struct session *ses = (struct session *)ses_;
3868 	struct f_data_c *fd = current_frame(ses);
3869 	struct link *link = get_current_link(fd);
3870 	if (!link) return;
3871 	if (ses->dn_url) mem_free(ses->dn_url);
3872 	if ((ses->dn_url = stracpy(link->where_img))) {
3873 		ses->dn_allow_flags = f_data_c_allow_flags(fd);
3874 		query_file(ses, ses->dn_url, NULL, start_download, NULL, DOWNLOAD_CONTINUE);
3875 	}
3876 }
3877 
3878 #ifdef G
send_block_image(struct terminal * term,void * xxx,void * ses_)3879 static void send_block_image(struct terminal *term, void *xxx, void *ses_)
3880 {
3881 	struct session *ses = (struct session *)ses_;
3882 	struct f_data_c *fd = current_frame(ses);
3883 	struct link *link = get_current_link(fd);
3884 	if (!link) return;
3885 	if (!link->where_img) return;
3886 	block_url_query(ses, link->where_img);
3887 }
3888 #endif
3889 
send_download(struct terminal * term,void * xxx,void * ses_)3890 static void send_download(struct terminal *term, void *xxx, void *ses_)
3891 {
3892 	struct session *ses = (struct session *)ses_;
3893 	struct f_data_c *fd = current_frame(ses);
3894 	struct link *link = get_current_link(fd);
3895 	if (!link) return;
3896 	if (ses->dn_url) mem_free(ses->dn_url);
3897 	if ((ses->dn_url = get_link_url(ses, fd, link, NULL))) {
3898 		ses->dn_allow_flags = f_data_c_allow_flags(fd);
3899 		query_file(ses, ses->dn_url, NULL, start_download, NULL, DOWNLOAD_CONTINUE);
3900 	}
3901 }
3902 
send_submit(struct terminal * term,void * xxx,void * ses_)3903 static void send_submit(struct terminal *term, void *xxx, void *ses_)
3904 {
3905 	struct session *ses = (struct session *)ses_;
3906 	int has_onsubmit;
3907 	struct form_control *form;
3908 	struct f_data_c *fd = current_frame(ses);
3909 	struct link *link = get_current_link(fd);
3910 	unsigned char *u;
3911 
3912 	if (!link) return;
3913 	if (!(form = link->form)) return;
3914 	u = get_form_url(ses, fd, form, &has_onsubmit);
3915 	if (u) {
3916 		goto_url_f(fd->ses, NULL, u, NULL, fd, form->form_num, has_onsubmit, 0, 0);
3917 		mem_free(u);
3918 	}
3919 	draw_fd(fd);
3920 }
3921 
send_reset(struct terminal * term,void * xxx,void * ses_)3922 static void send_reset(struct terminal *term, void *xxx, void *ses_)
3923 {
3924 	struct session *ses = (struct session *)ses_;
3925 	struct form_control *form;
3926 	struct f_data_c *fd = current_frame(ses);
3927 	struct link *link = get_current_link(fd);
3928 
3929 	if (!link) return;
3930 	if (!(form = link->form)) return;
3931 	reset_form(fd, form->form_num);
3932 	draw_fd(fd);
3933 }
3934 
copy_link_location(struct terminal * term,void * xxx,void * ses_)3935 static void copy_link_location(struct terminal *term, void *xxx, void *ses_)
3936 {
3937 	struct session *ses = (struct session *)ses_;
3938 	unsigned char *current_link = print_current_link(ses);
3939 
3940 	if (current_link) {
3941 		set_clipboard_text(term, current_link);
3942 		mem_free(current_link);
3943 	}
3944 
3945 }
3946 
copy_url_location(struct terminal * term,void * xxx,void * ses_)3947 void copy_url_location(struct terminal *term, void *xxx, void *ses_)
3948 {
3949 	struct session *ses = (struct session *)ses_;
3950 	struct location *current_location;
3951 	unsigned char *url;
3952 
3953 	if (list_empty(ses->history)) return;
3954 
3955 	current_location = cur_loc(ses);
3956 
3957 	url = display_url(term, current_location->url, 0);
3958 	set_clipboard_text(term, url);
3959 	mem_free(url);
3960 }
3961 
cant_open_new_window(struct terminal * term)3962 static void cant_open_new_window(struct terminal *term)
3963 {
3964 	msg_box(term, NULL, TEXT_(T_NEW_WINDOW), AL_CENTER, TEXT_(T_UNABLE_TO_OPEN_NEW_WINDOW), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
3965 }
3966 
3967 /* open a link in a new xterm, pass target frame name */
send_open_in_new_xterm(struct terminal * term,void * open_window_,void * ses_)3968 static void send_open_in_new_xterm(struct terminal *term, void *open_window_, void *ses_)
3969 {
3970 	int (*open_window)(struct terminal *, unsigned char *, unsigned char *) = *(int (* const *)(struct terminal *, unsigned char *, unsigned char *))open_window_;
3971 	struct session *ses = (struct session *)ses_;
3972 	struct f_data_c *fd = current_frame(ses);
3973 	struct link *l;
3974 	l = get_current_link(fd);
3975 	if (!l) return;
3976 	if (ses->dn_url) mem_free(ses->dn_url);
3977 	if ((ses->dn_url = get_link_url(ses, fd, l, NULL))) {
3978 		unsigned char *p;
3979 		int pl;
3980 		unsigned char *enc_url;
3981 		unsigned char *path;
3982 
3983 		ses->dn_allow_flags = f_data_c_allow_flags(fd);
3984 		if (disallow_url(ses->dn_url, ses->dn_allow_flags)) {
3985 			mem_free(ses->dn_url);
3986 			ses->dn_url = NULL;
3987 			return;
3988 		}
3989 
3990 		p = init_str();
3991 		pl = 0;
3992 
3993 		add_to_str(&p, &pl, cast_uchar "-base-session ");
3994 		add_num_to_str(&p, &pl, ses->id);
3995 		add_chr_to_str(&p, &pl, ' ');
3996 
3997 		if (ses->wtd_target && *ses->wtd_target) {
3998 			unsigned char *tgt = stracpy(ses->wtd_target);
3999 
4000 			check_shell_security(&tgt);
4001 			add_to_str(&p, &pl, cast_uchar "-target ");
4002 			add_to_str(&p, &pl, tgt);
4003 			add_chr_to_str(&p, &pl, ' ');
4004 			mem_free(tgt);
4005 		}
4006 		enc_url = encode_url(ses->dn_url);
4007 		add_to_str(&p, &pl, enc_url);
4008 		mem_free(enc_url);
4009 		path = escape_path(path_to_exe);
4010 		if (open_window(term, path, p))
4011 			cant_open_new_window(term);
4012 		mem_free(p);
4013 		mem_free(path);
4014 	}
4015 }
4016 
send_open_new_xterm(struct terminal * term,void * open_window_,void * ses_)4017 static void send_open_new_xterm(struct terminal *term, void *open_window_, void *ses_)
4018 {
4019 	int (*open_window)(struct terminal *, unsigned char *, unsigned char *) = *(int (* const *)(struct terminal *, unsigned char *, unsigned char *))open_window_;
4020 	struct session *ses = (struct session *)ses_;
4021 	unsigned char *p = init_str();
4022 	int pl = 0;
4023 	unsigned char *path;
4024 	add_to_str(&p, &pl, cast_uchar "-base-session ");
4025 	add_num_to_str(&p, &pl, ses->id);
4026 	path = escape_path(path_to_exe);
4027 	if (open_window(term, path, p))
4028 		cant_open_new_window(term);
4029 	mem_free(path);
4030 	mem_free(p);
4031 }
4032 
4033 void (* const send_open_new_xterm_ptr)(struct terminal *, void *fn_, void *ses_) = send_open_new_xterm;
4034 
open_in_new_window(struct terminal * term,void * fn_,void * ses_)4035 void open_in_new_window(struct terminal *term, void *fn_, void *ses_)
4036 {
4037 	struct session *ses = (struct session *)ses_;
4038 	void (*fn)(struct terminal *, void *, void *) = *(void (* const *)(struct terminal *, void *, void *))fn_;
4039 	struct menu_item *mi;
4040 	struct open_in_new *oin, *oi;
4041 	if (!(oin = get_open_in_new(term->environment))) return;
4042 	if (!oin[1].text) {
4043 		fn(term, (void *)oin[0].open_window_fn, ses);
4044 		mem_free(oin);
4045 		return;
4046 	}
4047 	mi = new_menu(MENU_FREE_ITEMS);
4048 	for (oi = oin; oi->text; oi++) add_to_menu(&mi, oi->text, cast_uchar "", oi->hk, fn, (void *)oi->open_window_fn, 0, -1);
4049 	mem_free(oin);
4050 	do_menu(term, mi, ses);
4051 }
4052 
can_open_in_new(struct terminal * term)4053 int can_open_in_new(struct terminal *term)
4054 {
4055 	struct open_in_new *oin = get_open_in_new(term->environment);
4056 	if (!oin) return 0;
4057 	if (!oin[1].text) {
4058 		mem_free(oin);
4059 		return 1;
4060 	}
4061 	mem_free(oin);
4062 	return 2;
4063 }
4064 
save_url(void * ses_,unsigned char * url)4065 void save_url(void *ses_, unsigned char *url)
4066 {
4067 	struct session *ses = (struct session *)ses_;
4068 	unsigned char *u1, *u2;
4069 	u1 = convert(term_charset(ses->term), utf8_table, url, NULL);
4070 	u2 = translate_url(u1, ses->term->cwd);
4071 	mem_free(u1);
4072 	if (!u2) {
4073 		struct status stat = { init_list_1st(NULL) NULL, NULL, S_BAD_URL, PRI_CANCEL, 0, NULL, NULL, NULL, init_list_last(NULL) };
4074 		print_error_dialog(ses, &stat, url);
4075 		return;
4076 	}
4077 	if (ses->dn_url) mem_free(ses->dn_url);
4078 	ses->dn_url = u2;
4079 	ses->dn_allow_flags = ALLOW_ALL;
4080 	query_file(ses, ses->dn_url, NULL, start_download, NULL, DOWNLOAD_CONTINUE);
4081 }
4082 
send_image(struct terminal * term,void * xxx,void * ses_)4083 static void send_image(struct terminal *term, void *xxx, void *ses_)
4084 {
4085 	struct session *ses = (struct session *)ses_;
4086 	unsigned char *u;
4087 	struct f_data_c *fd = current_frame(ses);
4088 	struct link *l;
4089 	l = get_current_link(fd);
4090 	if (!l) return;
4091 	if (!(u = l->where_img)) return;
4092 	goto_url_not_from_dialog(ses, u, fd);
4093 }
4094 
4095 #ifdef G
4096 
send_scale(struct terminal * term,void * xxx,void * ses_)4097 static void send_scale(struct terminal *term, void *xxx, void *ses_)
4098 {
4099 	struct session *ses = (struct session *)ses_;
4100 	ses->ds.porn_enable ^= 1;
4101 	html_interpret_recursive(ses->screen);
4102 	draw_formatted(ses);
4103 }
4104 
4105 #endif
4106 
save_as(struct terminal * term,void * xxx,void * ses_)4107 void save_as(struct terminal *term, void *xxx, void *ses_)
4108 {
4109 	struct session *ses = (struct session *)ses_;
4110 	unsigned char *head;
4111 	if (list_empty(ses->history)) return;
4112 	if (ses->dn_url) mem_free(ses->dn_url);
4113 	ses->dn_url = stracpy(ses->screen->rq->url);
4114 	ses->dn_allow_flags = ALLOW_ALL;
4115 	if (!ses->dn_url) return;
4116 	head = stracpy(ses->screen->rq->ce ? ses->screen->rq->ce->head : NULL);
4117 	if (head) {
4118 		unsigned char *p, *q;
4119 		/* remove Content-Encoding from the header */
4120 		q = parse_http_header(head, cast_uchar "Content-Encoding", &p);
4121 		if (q) {
4122 			mem_free(q);
4123 			if (p > head && p < (unsigned char *)strchr(cast_const_char head, 0)) {
4124 				for (q = p - 1; q > head && *q != 10; q--)
4125 					;
4126 				q[1] = 'X';
4127 			}
4128 		}
4129 	}
4130 	query_file(ses, ses->dn_url, head, start_download, NULL, DOWNLOAD_CONTINUE);
4131 	if (head)
4132 		mem_free(head);
4133 }
4134 
save_formatted(struct session * ses,unsigned char * file,int mode)4135 static void save_formatted(struct session *ses, unsigned char *file, int mode)
4136 {
4137 	int h, rs, err;
4138 	struct f_data_c *f;
4139 	int download_mode = mode == DOWNLOAD_DEFAULT ? CDF_EXCL : 0;
4140 	if (!(f = current_frame(ses)) || !f->f_data) return;
4141 	if ((h = create_download_file(ses, ses->term->cwd, file, download_mode, 0)) < 0) return;
4142 	if ((err = dump_to_file(f->f_data, h))) {
4143 		msg_box(ses->term, NULL, TEXT_(T_SAVE_ERROR), AL_CENTER, TEXT_(T_ERROR_WRITING_TO_FILE), cast_uchar ": ", get_err_msg(err, ses->term), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
4144 	}
4145 	EINTRLOOP(rs, close(h));
4146 }
4147 
menu_save_formatted(struct terminal * term,void * xxx,void * ses_)4148 void menu_save_formatted(struct terminal *term, void *xxx, void *ses_)
4149 {
4150 	struct session *ses = (struct session *)ses_;
4151 	struct f_data_c *f;
4152 	if (!(f = current_frame(ses)) || !f->f_data) return;
4153 	query_file(ses, f->rq->url, NULL, save_formatted, NULL, DOWNLOAD_OVERWRITE);
4154 }
4155 
link_menu(struct terminal * term,void * xxx,void * ses_)4156 void link_menu(struct terminal *term, void *xxx, void *ses_)
4157 {
4158 	struct session *ses = (struct session *)ses_;
4159 	struct f_data_c *f = current_frame(ses);
4160 	struct link *link;
4161 	struct menu_item *mi;
4162 	if (ses->wtd_target) mem_free(ses->wtd_target), ses->wtd_target = NULL;
4163 	mi = new_menu(MENU_FREE_ITEMS);
4164 	link = get_current_link(f);
4165 	if (!link) goto no_l;
4166 	if (link->type == L_LINK && link->where) {
4167 		if (strlen(cast_const_char link->where) >= 4 && !casecmp(link->where, cast_uchar "MAP@", 4)) {
4168 			if (!F) {
4169 				add_to_menu(&mi, TEXT_(T_DISPLAY_USEMAP), cast_uchar ">", TEXT_(T_HK_DISPLAY_USEMAP), send_enter, NULL, 1, -1);
4170 			}
4171 		} else {
4172 			int c = can_open_in_new(term);
4173 			add_to_menu(&mi, TEXT_(T_FOLLOW_LINK), cast_uchar "Enter", TEXT_(T_HK_FOLLOW_LINK), send_enter, NULL, 0, -1);
4174 			if (c) add_to_menu(&mi, TEXT_(T_OPEN_IN_NEW_WINDOW), c - 1 ? cast_uchar ">" : cast_uchar "", TEXT_(T_HK_OPEN_IN_NEW_WINDOW), open_in_new_window, (void *)&send_open_in_new_xterm_ptr, c - 1, -1);
4175 			if (!anonymous) add_to_menu(&mi, TEXT_(T_DOWNLOAD_LINK), cast_uchar "d", TEXT_(T_HK_DOWNLOAD_LINK), send_download, NULL, 0, -1);
4176 			if (clipboard_support(term))
4177 				add_to_menu(&mi, TEXT_(T_COPY_LINK_LOCATION), cast_uchar "", TEXT_(T_HK_COPY_LINK_LOCATION), copy_link_location, NULL, 0, -1);
4178 			/*add_to_menu(&mi, TEXT_(T_ADD_BOOKMARK), cast_uchar "A", TEXT_(T_HK_ADD_BOOKMARK), menu_bookmark_manager, NULL, 0);*/
4179 
4180 		}
4181 	}
4182 	if ((link->type == L_CHECKBOX || link->type == L_SELECT || link->type == L_FIELD || link->type == L_AREA) && link->form) {
4183 		int c = can_open_in_new(term);
4184 		add_to_menu(&mi, TEXT_(T_SUBMIT_FORM), cast_uchar "", TEXT_(T_HK_SUBMIT_FORM), send_submit, NULL, 0, -1);
4185 		if (c && link->form->method == FM_GET) add_to_menu(&mi, TEXT_(T_SUBMIT_FORM_AND_OPEN_IN_NEW_WINDOW), c - 1 ? cast_uchar ">" : cast_uchar "", TEXT_(T_HK_SUBMIT_FORM_AND_OPEN_IN_NEW_WINDOW), open_in_new_window, (void *)&send_open_in_new_xterm_ptr, c - 1, -1);
4186 		/*if (!anonymous) add_to_menu(&mi, TEXT_(T_SUBMIT_FORM_AND_DOWNLOAD), cast_uchar "d", TEXT_(T_HK_SUBMIT_FORM_AND_DOWNLOAD), send_download, NULL, 0, -1);*/
4187 		add_to_menu(&mi, TEXT_(T_RESET_FORM), cast_uchar "", TEXT_(T_HK_RESET_FORM), send_reset, NULL, 0, -1);
4188 	}
4189 	if (link->type == L_BUTTON && link->form) {
4190 		if (link->form->type == FC_RESET) add_to_menu(&mi, TEXT_(T_RESET_FORM), cast_uchar "", TEXT_(T_HK_RESET_FORM), send_enter, NULL, 0, -1);
4191 		else if (link->form->type==FC_BUTTON)
4192 			;
4193 		else if (link->form->type == FC_SUBMIT || link->form->type == FC_IMAGE) {
4194 			int c = can_open_in_new(term);
4195 			add_to_menu(&mi, TEXT_(T_SUBMIT_FORM), cast_uchar "", TEXT_(T_HK_SUBMIT_FORM), send_enter, NULL, 0, -1);
4196 			if (c && link->form->method == FM_GET) add_to_menu(&mi, TEXT_(T_SUBMIT_FORM_AND_OPEN_IN_NEW_WINDOW), c - 1 ? cast_uchar ">" : cast_uchar "", TEXT_(T_HK_SUBMIT_FORM_AND_OPEN_IN_NEW_WINDOW), open_in_new_window, (void *)&send_open_in_new_xterm_ptr, c - 1, -1);
4197 			if (!anonymous) add_to_menu(&mi, TEXT_(T_SUBMIT_FORM_AND_DOWNLOAD), cast_uchar "d", TEXT_(T_HK_SUBMIT_FORM_AND_DOWNLOAD), send_download, NULL, 0, -1);
4198 		}
4199 	}
4200 	if (link->where_img) {
4201 		if (!F || f->f_data->opt.plain != 2) add_to_menu(&mi, TEXT_(T_VIEW_IMAGE), cast_uchar "i", TEXT_(T_HK_VIEW_IMAGE), send_image, NULL, 0, -1);
4202 #ifdef G
4203 		else add_to_menu(&mi, TEXT_(T_SCALE_IMAGE_TO_FULL_SCREEN), cast_uchar "Enter", TEXT_(T_HK_SCALE_IMAGE_TO_FULL_SCREEN), send_scale, NULL, 0, -1);
4204 #endif
4205 		if (!anonymous) add_to_menu(&mi, TEXT_(T_DOWNLOAD_IMAGE), cast_uchar "I", TEXT_(T_HK_DOWNLOAD_IMAGE), send_download_image, NULL, 0, -1);
4206 #ifdef G
4207 		if (F && !anonymous) add_to_menu(&mi, TEXT_(T_BLOCK_URL), cast_uchar "", TEXT_(T_HK_BLOCK_URL), send_block_image, NULL, 0, -1);
4208 #endif
4209 	}
4210 	no_l:
4211 	if (!mi->text) add_to_menu(&mi, TEXT_(T_NO_LINK_SELECTED), cast_uchar "", M_BAR, NULL, NULL, 0, -1);
4212 	do_menu(term, mi, ses);
4213 }
4214 
print_current_titlex(struct f_data_c * fd,int w)4215 static unsigned char *print_current_titlex(struct f_data_c *fd, int w)
4216 {
4217 	int mul, pul;
4218 	int ml = 0, pl = 0;
4219 	unsigned char *m, *p;
4220 	if (!fd || !fd->vs || !fd->f_data) return NULL;
4221 	w -= 1;
4222 	p = init_str();
4223 	if (fd->yw < fd->f_data->y) {
4224 		int pp, pe;
4225 		if (fd->yw) {
4226 			pp = (fd->vs->view_pos + fd->yw / 2) / fd->yw + 1;
4227 			pe = (fd->f_data->y + fd->yw - 1) / fd->yw;
4228 		} else pp = pe = 1;
4229 		if (pp > pe) pp = pe;
4230 		if (fd->vs->view_pos + fd->yw >= fd->f_data->y) pp = pe;
4231 		if (fd->f_data->title && !fd->ses->term->spec->braille) add_chr_to_str(&p, &pl, ' ');
4232 		add_to_str(&p, &pl, get_text_translation(TEXT_(T_PAGE_P), fd->ses->term));
4233 		add_num_to_str(&p, &pl, pp);
4234 		add_to_str(&p, &pl, get_text_translation(TEXT_(T_PAGE_OF), fd->ses->term));
4235 		add_num_to_str(&p, &pl, pe);
4236 		add_to_str(&p, &pl, get_text_translation(TEXT_(T_PAGE_CL), fd->ses->term));
4237 		if (fd->f_data->title && fd->ses->term->spec->braille) add_chr_to_str(&p, &pl, ' ');
4238 	}
4239 	if (!fd->f_data->title) return p;
4240 	if (fd->ses->term->spec->braille) {
4241 		add_to_str(&p, &pl, fd->f_data->title);
4242 		return p;
4243 	}
4244 	m = init_str();
4245 	add_to_str(&m, &ml, fd->f_data->title);
4246 	mul = cp_len(term_charset(fd->ses->term), m);
4247 	pul = cp_len(term_charset(fd->ses->term), p);
4248 	if (mul + pul > w) {
4249 		unsigned char *mm;
4250 		if ((mul = w - pul) < 0) mul = 0;
4251 		for (mm = m; mul--; GET_TERM_CHAR(fd->ses->term, &mm))
4252 			;
4253 		ml = (int)(mm - m);
4254 	}
4255 	add_to_str(&m, &ml, p);
4256 	mem_free(p);
4257 	return m;
4258 }
4259 
print_current_linkx(struct f_data_c * fd,struct terminal * term)4260 static unsigned char *print_current_linkx(struct f_data_c *fd, struct terminal *term)
4261 {
4262 	int ll = 0;
4263 	struct link *l;
4264 	unsigned char *d;
4265 	unsigned char *m = NULL /* shut up warning */;
4266 	if (!fd || !fd->vs || !fd->f_data) return NULL;
4267 	if (fd->vs->current_link == -1 || fd->vs->current_link >= fd->f_data->nlinks || fd->f_data->frame_desc) return NULL;
4268 	l = &fd->f_data->links[fd->vs->current_link];
4269 	if (l->type == L_LINK) {
4270 		if (!l->where && l->where_img) {
4271 			m = init_str();
4272 			ll = 0;
4273 			if (l->img_alt)
4274 			{
4275 				unsigned char *txt;
4276 
4277 				txt = convert(fd->f_data->cp, fd->f_data->opt.cp, l->img_alt, &fd->f_data->opt);
4278 				add_to_str(&m, &ll, txt);
4279 				mem_free(txt);
4280 			}
4281 			else
4282 			{
4283 				add_to_str(&m, &ll, get_text_translation(TEXT_(T_IMAGE), term));
4284 				add_chr_to_str(&m, &ll, ' ');
4285 				d = display_url(term, l->where_img, 1);
4286 				add_to_str(&m, &ll, d);
4287 				mem_free(d);
4288 			}
4289 			goto p;
4290 		}
4291 		if (l->where && strlen(cast_const_char l->where) >= 4 && !casecmp(l->where, cast_uchar "MAP@", 4)) {
4292 			m = init_str();
4293 			ll = 0;
4294 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_USEMAP), term));
4295 			add_chr_to_str(&m, &ll, ' ');
4296 			d = display_url(term, l->where + 4, 1);
4297 			add_to_str(&m, &ll, d);
4298 			mem_free(d);
4299 			goto p;
4300 		}
4301 		if (l->where) {
4302 			m = display_url(term, l->where, 1);
4303 			goto p;
4304 		}
4305 		m = print_js_event_spec(l->js_event);
4306 		goto p;
4307 	}
4308 	if (!l->form) return NULL;
4309 	if (l->type == L_BUTTON) {
4310 		if (l->form->type == FC_BUTTON) {
4311 			unsigned char *n;
4312 			unsigned char *txt;
4313 			m = init_str();
4314 			ll = 0;
4315 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_BUTTON), term));
4316 			if (!l->js_event) goto p;
4317 			add_chr_to_str(&m, &ll, ' ');
4318 			n=print_js_event_spec(l->js_event);
4319 			if (fd->f_data)
4320 			{
4321 				txt=convert(fd->f_data->cp,fd->f_data->opt.cp, n, NULL);
4322 				mem_free(n);
4323 			}
4324 			else
4325 				txt=n;
4326 			add_to_str(&m, &ll, txt);
4327 			mem_free(txt);
4328 			goto p;
4329 		}
4330 		if (l->form->type == FC_RESET) {
4331 			m = stracpy(get_text_translation(TEXT_(T_RESET_FORM), term));
4332 			goto p;
4333 		}
4334 		if (!l->form->action) return NULL;
4335 		m = init_str();
4336 		ll = 0;
4337 		if (l->form->method == FM_GET) add_to_str(&m, &ll, get_text_translation(TEXT_(T_SUBMIT_FORM_TO), term));
4338 		else add_to_str(&m, &ll, get_text_translation(TEXT_(T_POST_FORM_TO), term));
4339 		add_chr_to_str(&m, &ll, ' ');
4340 		add_to_str(&m, &ll, l->form->action);
4341 		goto p;
4342 	}
4343 	if (l->type == L_CHECKBOX || l->type == L_SELECT || l->type == L_FIELD || l->type == L_AREA) {
4344 		m = init_str();
4345 		ll = 0;
4346 		if (l->form->type == FC_RADIO) add_to_str(&m, &ll, get_text_translation(TEXT_(T_RADIO_BUTTON), term));
4347 		else if (l->form->type == FC_CHECKBOX) add_to_str(&m, &ll, get_text_translation(TEXT_(T_CHECKBOX), term));
4348 		else if (l->form->type == FC_SELECT) add_to_str(&m, &ll, get_text_translation(TEXT_(T_SELECT_FIELD), term));
4349 		else if (l->form->type == FC_TEXT) add_to_str(&m, &ll, get_text_translation(TEXT_(T_TEXT_FIELD), term));
4350 		else if (l->form->type == FC_TEXTAREA) add_to_str(&m, &ll, get_text_translation(TEXT_(T_TEXT_AREA), term));
4351 		else if (l->form->type == FC_FILE_UPLOAD) add_to_str(&m, &ll, get_text_translation(TEXT_(T_FILE_UPLOAD), term));
4352 		else if (l->form->type == FC_PASSWORD) add_to_str(&m, &ll, get_text_translation(TEXT_(T_PASSWORD_FIELD), term));
4353 		else {
4354 			mem_free(m);
4355 			return NULL;
4356 		}
4357 		if (l->form->name && l->form->name[0]) {
4358 			add_to_str(&m, &ll, cast_uchar ", ");
4359 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_NAME), term));
4360 			add_chr_to_str(&m, &ll, ' ');
4361 			add_to_str(&m, &ll, l->form->name);
4362 		}
4363 		if ((l->form->type == FC_CHECKBOX || l->form->type == FC_RADIO) && l->form->default_value && l->form->default_value[0]) {
4364 			add_to_str(&m, &ll, cast_uchar ", ");
4365 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_VALUE), term));
4366 			add_chr_to_str(&m, &ll, ' ');
4367 			add_to_str(&m, &ll, l->form->default_value);
4368 		}
4369 				       /* pri enteru se bude posilat vzdycky   -- Brain */
4370 		if (l->type == L_FIELD && !has_form_submit(fd->f_data, l->form)  && l->form->action) {
4371 			add_to_str(&m, &ll, cast_uchar ", ");
4372 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_HIT_ENTER_TO), term));
4373 			add_chr_to_str(&m, &ll, ' ');
4374 			if (l->form->method == FM_GET) add_to_str(&m, &ll, get_text_translation(TEXT_(T_SUBMIT_TO), term));
4375 			else add_to_str(&m, &ll, get_text_translation(TEXT_(T_POST_TO), term));
4376 			add_chr_to_str(&m, &ll, ' ');
4377 			add_to_str(&m, &ll, l->form->action);
4378 		}
4379 		goto p;
4380 	}
4381 	p:
4382 	return m;
4383 }
4384 
4385 /* jako print_current_linkx, ale vypisuje vice informaci o obrazku
4386    pouziva se v informacich o dokumentu
4387 
4388    Ach jo, to Brain kopiroval kod, snad to nedela i v ty firme,
4389    kde ted pracuje... -- mikulas
4390  */
print_current_linkx_plus(struct f_data_c * fd,struct terminal * term)4391 static unsigned char *print_current_linkx_plus(struct f_data_c *fd, struct terminal *term)
4392 {
4393 	int ll = 0;
4394 	struct link *l;
4395 	unsigned char *d;
4396 	unsigned char *m = NULL /* shut up warning */;
4397 	if (!fd || !fd->vs || !fd->f_data) return NULL;
4398 	if (fd->vs->current_link == -1 || fd->vs->current_link >= fd->f_data->nlinks || fd->f_data->frame_desc) return NULL;
4399 	l = &fd->f_data->links[fd->vs->current_link];
4400 	if (l->type == L_LINK) {
4401 		unsigned char *spc;
4402 		m = init_str();
4403 		ll = 0;
4404 		if (l->where && strlen(cast_const_char l->where) >= 4 && !casecmp(l->where, cast_uchar "MAP@", 4)) {
4405 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_USEMAP), term));
4406 			add_chr_to_str(&m, &ll, ' ');
4407 			d = display_url(term, l->where + 4, 1);
4408 			add_to_str(&m, &ll, d);
4409 			mem_free(d);
4410 		}
4411 		else if (l->where) {
4412 			d = display_url(term, l->where, 1);
4413 			add_to_str(&m, &ll, d);
4414 			mem_free(d);
4415 		}
4416 		spc = print_js_event_spec(l->js_event);
4417 		if (spc&&*spc)
4418 		{
4419 			add_to_str(&m, &ll, cast_uchar "\n");
4420 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_JAVASCRIPT), term));
4421 			add_to_str(&m, &ll, cast_uchar ": ");
4422 			add_to_str(&m, &ll, spc);
4423 		}
4424 		if (spc) mem_free(spc);
4425 		if (l->where_img) {
4426 			add_to_str(&m, &ll, cast_uchar "\n");
4427 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_IMAGE), term));
4428 			add_to_str(&m, &ll, cast_uchar ": src='");
4429 			d = display_url(term, l->where_img, 1);
4430 			add_to_str(&m, &ll, d);
4431 			mem_free(d);
4432 			add_chr_to_str(&m, &ll, '\'');
4433 
4434 			if (l->img_alt)
4435 			{
4436 				unsigned char *txt;
4437 
4438 				add_to_str(&m, &ll, cast_uchar " alt='");
4439 				txt = convert(fd->f_data->cp, fd->f_data->opt.cp, l->img_alt, &fd->f_data->opt);
4440 				add_to_str(&m, &ll, txt);
4441 				add_chr_to_str(&m, &ll, '\'');
4442 				mem_free(txt);
4443 			}
4444 #ifdef G
4445 			if (F&&l->obj)
4446 			{
4447 				add_to_str(&m, &ll, cast_uchar " size='");
4448 				add_num_to_str(&m, &ll, l->obj->xw);
4449 				add_chr_to_str(&m, &ll, 'x');
4450 				add_num_to_str(&m, &ll, l->obj->yw);
4451 				add_chr_to_str(&m, &ll, '\'');
4452 			}
4453 #endif
4454 			goto p;
4455 		}
4456 		goto p;
4457 	}
4458 	if (!l->form) return NULL;
4459 	if (l->type == L_BUTTON) {
4460 		if (l->form->type == FC_BUTTON) {
4461 			unsigned char *n;
4462 			unsigned char *txt;
4463 			m = init_str();
4464 			ll = 0;
4465 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_BUTTON), term));
4466 			if (!l->js_event) goto p;
4467 			add_chr_to_str(&m, &ll, ' ');
4468 			n=print_js_event_spec(l->js_event);
4469 			if (fd->f_data)
4470 			{
4471 				txt=convert(fd->f_data->cp, fd->f_data->opt.cp, n, NULL);
4472 				mem_free(n);
4473 			}
4474 			else
4475 				txt=n;
4476 			add_to_str(&m, &ll, txt);
4477 			mem_free(txt);
4478 			goto p;
4479 		}
4480 		if (l->form->type == FC_RESET) {
4481 			m = stracpy(get_text_translation(TEXT_(T_RESET_FORM), term));
4482 			goto p;
4483 		}
4484 		if (!l->form->action) return NULL;
4485 		m = init_str();
4486 		ll = 0;
4487 		if (l->form->method == FM_GET) add_to_str(&m, &ll, get_text_translation(TEXT_(T_SUBMIT_FORM_TO), term));
4488 		else add_to_str(&m, &ll, get_text_translation(TEXT_(T_POST_FORM_TO), term));
4489 		add_chr_to_str(&m, &ll, ' ');
4490 		add_to_str(&m, &ll, l->form->action);
4491 		goto p;
4492 	}
4493 	if (l->type == L_CHECKBOX || l->type == L_SELECT || l->type == L_FIELD || l->type == L_AREA) {
4494 		m = init_str();
4495 		ll = 0;
4496 		if (l->form->type == FC_RADIO) add_to_str(&m, &ll, get_text_translation(TEXT_(T_RADIO_BUTTON), term));
4497 		else if (l->form->type == FC_CHECKBOX) add_to_str(&m, &ll, get_text_translation(TEXT_(T_CHECKBOX), term));
4498 		else if (l->form->type == FC_SELECT) add_to_str(&m, &ll, get_text_translation(TEXT_(T_SELECT_FIELD), term));
4499 		else if (l->form->type == FC_TEXT) add_to_str(&m, &ll, get_text_translation(TEXT_(T_TEXT_FIELD), term));
4500 		else if (l->form->type == FC_TEXTAREA) add_to_str(&m, &ll, get_text_translation(TEXT_(T_TEXT_AREA), term));
4501 		else if (l->form->type == FC_FILE_UPLOAD) add_to_str(&m, &ll, get_text_translation(TEXT_(T_FILE_UPLOAD), term));
4502 		else if (l->form->type == FC_PASSWORD) add_to_str(&m, &ll, get_text_translation(TEXT_(T_PASSWORD_FIELD), term));
4503 		else {
4504 			mem_free(m);
4505 			return NULL;
4506 		}
4507 		if (l->form->name && l->form->name[0]) {
4508 			add_to_str(&m, &ll, cast_uchar ", ");
4509 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_NAME), term));
4510 			add_chr_to_str(&m, &ll, ' ');
4511 			add_to_str(&m, &ll, l->form->name);
4512 		}
4513 		if ((l->form->type == FC_CHECKBOX || l->form->type == FC_RADIO) && l->form->default_value && l->form->default_value[0]) {
4514 			add_to_str(&m, &ll, cast_uchar ", ");
4515 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_VALUE), term));
4516 			add_chr_to_str(&m, &ll, ' ');
4517 			add_to_str(&m, &ll, l->form->default_value);
4518 		}
4519 				       /* pri enteru se bude posilat vzdycky   -- Brain */
4520 		if (l->type == L_FIELD && !has_form_submit(fd->f_data, l->form)  && l->form->action) {
4521 			add_to_str(&m, &ll, cast_uchar ", ");
4522 			add_to_str(&m, &ll, get_text_translation(TEXT_(T_HIT_ENTER_TO), term));
4523 			add_chr_to_str(&m, &ll, ' ');
4524 			if (l->form->method == FM_GET) add_to_str(&m, &ll, get_text_translation(TEXT_(T_SUBMIT_TO), term));
4525 			else add_to_str(&m, &ll, get_text_translation(TEXT_(T_POST_TO), term));
4526 			add_chr_to_str(&m, &ll, ' ');
4527 			add_to_str(&m, &ll, l->form->action);
4528 		}
4529 		goto p;
4530 	}
4531 	p:
4532 	return m;
4533 }
4534 
print_current_link(struct session * ses)4535 unsigned char *print_current_link(struct session *ses)
4536 {
4537 	return print_current_linkx(current_frame(ses), ses->term);
4538 }
4539 
print_current_title(struct session * ses)4540 unsigned char *print_current_title(struct session *ses)
4541 {
4542 	return print_current_titlex(current_frame(ses), ses->term->x);
4543 }
4544 
loc_msg(struct terminal * term,struct location * lo,struct f_data_c * frame)4545 void loc_msg(struct terminal *term, struct location *lo, struct f_data_c *frame)
4546 {
4547 	struct cache_entry *ce;
4548 	unsigned char *s;
4549 	int l = 0;
4550 	unsigned char *a;
4551 	if (!lo || !frame || !frame->vs || !frame->f_data) {
4552 		msg_box(term, NULL, TEXT_(T_INFO), AL_LEFT, TEXT_(T_YOU_ARE_NOWHERE), MSG_BOX_END, NULL, 1, TEXT_(T_OK), msg_box_null, B_ENTER | B_ESC);
4553 		return;
4554 	}
4555 	s = init_str();
4556 	add_to_str(&s, &l, get_text_translation(TEXT_(T_URL), term));
4557 	add_to_str(&s, &l, cast_uchar ": ");
4558 	a = display_url(term, lo->url, 1);
4559 	add_to_str(&s, &l, a);
4560 	mem_free(a);
4561 	if (!find_in_cache(lo->url, &ce)) {
4562 		unsigned char *start;
4563 		size_t len;
4564 		if (ce->ip_address) {
4565 			add_to_str(&s, &l, cast_uchar "\n");
4566 			if (!strchr(cast_const_char ce->ip_address, ' '))
4567 				add_to_str(&s, &l, get_text_translation(TEXT_(T_IP_ADDRESS), term));
4568 			else
4569 				add_to_str(&s, &l, get_text_translation(TEXT_(T_IP_ADDRESSES), term));
4570 			add_to_str(&s, &l, cast_uchar ": ");
4571 			add_to_str(&s, &l, ce->ip_address);
4572 		}
4573 		add_to_str(&s, &l, cast_uchar "\n");
4574 		add_to_str(&s, &l, get_text_translation(TEXT_(T_SIZE), term));
4575 		add_to_str(&s, &l, cast_uchar ": ");
4576 		get_file_by_term(NULL, ce, &start, &len, NULL);
4577 		if (ce->decompressed) {
4578 			unsigned char *enc;
4579 			add_unsigned_long_num_to_str(&s, &l, len);
4580 			enc = get_content_encoding(ce->head, ce->url, 0);
4581 			if (enc) {
4582 				add_to_str(&s, &l, cast_uchar " (");
4583 				add_num_to_str(&s, &l, ce->length);
4584 				add_chr_to_str(&s, &l, ' ');
4585 				add_to_str(&s, &l, get_text_translation(TEXT_(T_COMPRESSED_WITH), term));
4586 				add_chr_to_str(&s, &l, ' ');
4587 				add_to_str(&s, &l, enc);
4588 				add_chr_to_str(&s, &l, ')');
4589 				mem_free(enc);
4590 			}
4591 		} else {
4592 			add_num_to_str(&s, &l, ce->length);
4593 		}
4594 		if (ce->incomplete) {
4595 			add_to_str(&s, &l, cast_uchar " (");
4596 			add_to_str(&s, &l, get_text_translation(TEXT_(T_INCOMPLETE), term));
4597 			add_chr_to_str(&s, &l, ')');
4598 		}
4599 		if (frame->f_data->ass >= 0) {
4600 			add_to_str(&s, &l, cast_uchar "\n");
4601 			add_to_str(&s, &l, get_text_translation(TEXT_(T_CODEPAGE), term));
4602 			add_to_str(&s, &l, cast_uchar ": ");
4603 			add_to_str(&s, &l, get_cp_name(frame->f_data->cp));
4604 			if (frame->f_data->ass == 1) {
4605 				add_to_str(&s, &l, cast_uchar " (");
4606 				add_to_str(&s, &l, get_text_translation(TEXT_(T_ASSUMED), term));
4607 				add_chr_to_str(&s, &l, ')');
4608 			}
4609 			if (frame->f_data->ass == 2) {
4610 				add_to_str(&s, &l, cast_uchar " (");
4611 				add_to_str(&s, &l, get_text_translation(TEXT_(T_IGNORING_SERVER_SETTING), term));
4612 				add_chr_to_str(&s, &l, ')');
4613 			}
4614 		}
4615 		if (ce->head && ce->head[0] != '\n' && ce->head[0] != '\r' && (a = parse_http_header(ce->head, cast_uchar "Content-Type", NULL))) {
4616 			add_to_str(&s, &l, cast_uchar "\n");
4617 			add_to_str(&s, &l, get_text_translation(TEXT_(T_CONTENT_TYPE), term));
4618 			add_to_str(&s, &l, cast_uchar ": ");
4619 			add_to_str(&s, &l, a);
4620 			mem_free(a);
4621 		}
4622 		if ((a = parse_http_header(ce->head, cast_uchar "Server", NULL))) {
4623 			add_to_str(&s, &l, cast_uchar "\n");
4624 			add_to_str(&s, &l, get_text_translation(TEXT_(T_SERVER), term));
4625 			add_to_str(&s, &l, cast_uchar ": ");
4626 			add_to_str(&s, &l, a);
4627 			mem_free(a);
4628 		}
4629 		if ((a = parse_http_header(ce->head, cast_uchar "Date", NULL))) {
4630 			add_to_str(&s, &l, cast_uchar "\n");
4631 			add_to_str(&s, &l, get_text_translation(TEXT_(T_DATE), term));
4632 			add_to_str(&s, &l, cast_uchar ": ");
4633 			add_to_str(&s, &l, a);
4634 			mem_free(a);
4635 		}
4636 		if ((a = parse_http_header(ce->head, cast_uchar "Last-Modified", NULL))) {
4637 			add_to_str(&s, &l, cast_uchar "\n");
4638 			add_to_str(&s, &l, get_text_translation(TEXT_(T_LAST_MODIFIED), term));
4639 			add_to_str(&s, &l, cast_uchar ": ");
4640 			add_to_str(&s, &l, a);
4641 			mem_free(a);
4642 		}
4643 #ifdef HAVE_SSL
4644 		if (ce->ssl_info) {
4645 			add_to_str(&s, &l, cast_uchar "\n");
4646 			add_to_str(&s, &l, get_text_translation(TEXT_(T_SSL_CIPHER), term));
4647 			add_to_str(&s, &l, cast_uchar ": ");
4648 			add_to_str(&s, &l, ce->ssl_info);
4649 		}
4650 		if (ce->ssl_authority) {
4651 			add_to_str(&s, &l, cast_uchar "\n");
4652 			if (strstr(cast_const_char ce->ssl_authority, cast_const_char CERT_RIGHT_ARROW))
4653 				add_to_str(&s, &l, get_text_translation(TEXT_(T_CERTIFICATE_AUTHORITIES), term));
4654 			else
4655 				add_to_str(&s, &l, get_text_translation(TEXT_(T_CERTIFICATE_AUTHORITY), term));
4656 			add_to_str(&s, &l, cast_uchar ": ");
4657 			add_to_str(&s, &l, ce->ssl_authority);
4658 		}
4659 #endif
4660 		ce->refcount--;
4661 	}
4662 	if ((a = print_current_linkx_plus(frame, term))) {
4663 		add_to_str(&s, &l, cast_uchar "\n\n");
4664 		if (*a != '\n') {
4665 			add_to_str(&s, &l, get_text_translation(TEXT_(T_LINK), term));
4666 			add_to_str(&s, &l, cast_uchar ": ");
4667 			add_to_str(&s, &l, a);
4668 		} else {
4669 			add_to_str(&s, &l, a + 1);
4670 		}
4671 		mem_free(a);
4672 	}
4673 	msg_box(term, getml(s, NULL), TEXT_(T_INFO), AL_LEFT, s, MSG_BOX_END, NULL, 1, TEXT_(T_OK), msg_box_null, B_ENTER | B_ESC);
4674 }
4675 
state_msg(struct session * ses)4676 void state_msg(struct session *ses)
4677 {
4678 	if (list_empty(ses->history)) loc_msg(ses->term, NULL, NULL);
4679 	else loc_msg(ses->term, cur_loc(ses), current_frame(ses));
4680 }
4681 
head_msg(struct session * ses)4682 void head_msg(struct session *ses)
4683 {
4684 	struct cache_entry *ce;
4685 	unsigned char *s, *ss;
4686 	int len;
4687 	if (list_empty(ses->history)) {
4688 		msg_box(ses->term, NULL, TEXT_(T_HEADER_INFO), AL_LEFT, TEXT_(T_YOU_ARE_NOWHERE), MSG_BOX_END, NULL, 1, TEXT_(T_OK), msg_box_null, B_ENTER | B_ESC);
4689 		return;
4690 	}
4691 	if (!find_in_cache(cur_loc(ses)->url, &ce)) {
4692 		if (ce->head) s = stracpy(ce->head);
4693 		else s = stracpy(cast_uchar "");
4694 		len = (int)strlen(cast_const_char s) - 1;
4695 		if (len > 0) {
4696 			while ((ss = cast_uchar strstr(cast_const_char s, "\r\n"))) memmove(ss, ss + 1, strlen(cast_const_char ss));
4697 			while (*s && s[strlen(cast_const_char s) - 1] == '\n') s[strlen(cast_const_char s) - 1] = 0;
4698 		}
4699 		if (*s && *s != '\n') {
4700 			msg_box(ses->term, getml(s, NULL), TEXT_(T_HEADER_INFO), AL_LEFT, s, MSG_BOX_END, NULL, 1, TEXT_(T_OK), msg_box_null, B_ENTER | B_ESC);
4701 		} else {
4702 			msg_box(ses->term, getml(s, NULL), TEXT_(T_HEADER_INFO), AL_CENTER, TEXT_(T_NO_HEADER), MSG_BOX_END, NULL, 1, TEXT_(T_OK), msg_box_null, B_ENTER | B_ESC);
4703 		}
4704 		ce->refcount--;
4705 	}
4706 }
4707