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