session.c (91226B)
1 /* session.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 struct list_head downloads = { &downloads, &downloads }; 11 12 /* prototypes */ 13 static void abort_and_delete_download(void *); 14 static void undisplay_download(void *); 15 static void increase_download_file(unsigned char **f); 16 static void copy_additional_files(struct additional_files **a); 17 static struct location *new_location(void); 18 static void destroy_location(struct location *loc); 19 20 int 21 are_there_downloads(void) 22 { 23 struct download *down = NULL; 24 struct list_head *ldown; 25 foreach (struct download, down, ldown, downloads) 26 if (!down->prog) 27 return 1; 28 return 0; 29 } 30 31 struct list_head sessions = { &sessions, &sessions }; 32 unsigned char 33 get_session_attribute(struct session *ses, int reverse) 34 { 35 if (!ses->term->spec->col) { 36 if (!reverse) 37 return COLOR_TITLE; 38 else 39 return COLOR_STATUS; 40 } else { 41 if (!reverse) 42 return get_attribute(ses->ds.t_text_color, 43 ses->ds.t_background_color); 44 else 45 return get_attribute(ses->ds.t_background_color, 46 ses->ds.t_text_color); 47 } 48 } 49 50 struct s_msg_dsc { 51 int n; 52 unsigned char *msg; 53 }; 54 55 static const struct s_msg_dsc msg_dsc[] = { 56 {S_WAIT, TEXT_(T_WAITING_IN_QUEUE) }, 57 { S_DNS, TEXT_(T_LOOKING_UP_HOST) }, 58 { S_CONN, TEXT_(T_MAKING_CONNECTION) }, 59 { S_CONN_ANOTHER, TEXT_(T_MAKING_CONNECTION_TO_ANOTHER_ADDRESS)}, 60 { S_SOCKS_NEG, TEXT_(T_SOCKS_NEGOTIATION) }, 61 { S_SSL_NEG, TEXT_(T_SSL_NEGOTIATION) }, 62 { S_SENT, TEXT_(T_REQUEST_SENT) }, 63 { S_LOGIN, TEXT_(T_LOGGING_IN) }, 64 { S_GETH, TEXT_(T_GETTING_HEADERS) }, 65 { S_PROC, TEXT_(T_SERVER_IS_PROCESSING_REQUEST) }, 66 { S_TRANS, TEXT_(T_TRANSFERRING) }, 67 68 { S__OK, TEXT_(T_OK) }, 69 { S_INTERRUPTED, TEXT_(T_INTERRUPTED) }, 70 { S_INTERNAL, TEXT_(T_INTERNAL_ERROR) }, 71 { S_OUT_OF_MEM, TEXT_(T_OUT_OF_MEMORY) }, 72 { S_NO_DNS, TEXT_(T_HOST_NOT_FOUND) }, 73 { S_NO_PROXY_DNS, TEXT_(T_PROXY_NOT_FOUND) }, 74 { S_CANT_WRITE, TEXT_(T_ERROR_WRITING_TO_SOCKET) }, 75 { S_CANT_READ, TEXT_(T_ERROR_READING_FROM_SOCKET) }, 76 { S_MODIFIED, TEXT_(T_DATA_MODIFIED) }, 77 { S_BAD_URL, TEXT_(T_BAD_URL_SYNTAX) }, 78 { S_BAD_PROXY, TEXT_(T_BAD_PROXY_SYNTAX) }, 79 { S_TIMEOUT, TEXT_(T_RECEIVE_TIMEOUT) }, 80 { S_RESTART, TEXT_(T_REQUEST_MUST_BE_RESTARTED) }, 81 { S_STATE, TEXT_(T_CANT_GET_SOCKET_STATE) }, 82 { S_CYCLIC_REDIRECT, TEXT_(T_CYCLIC_REDIRECT) }, 83 { S_LARGE_FILE, TEXT_(T_TOO_LARGE_FILE) }, 84 85 { S_HTTP_ERROR, TEXT_(T_BAD_HTTP_RESPONSE) }, 86 { S_HTTP_204, TEXT_(T_NO_CONTENT) }, 87 { S_HTTPS_FWD_ERROR, TEXT_(T_HTTPS_FWD_ERROR) }, 88 { S_INVALID_CERTIFICATE, TEXT_(T_INVALID_CERTIFICATE) }, 89 { S_DOWNGRADED_METHOD, TEXT_(T_DOWNGRADED_METHOD) }, 90 { S_INSECURE_CIPHER, TEXT_(T_INSECURE_CIPHER) }, 91 92 { S_FILE_TYPE, TEXT_(T_UNKNOWN_FILE_TYPE) }, 93 { S_FILE_ERROR, TEXT_(T_ERROR_OPENING_FILE) }, 94 95 { S_SSL_ERROR, TEXT_(T_SSL_ERROR) }, 96 { S_NO_SSL, TEXT_(T_NO_SSL) }, 97 { S_BAD_SOCKS_VERSION, TEXT_(T_BAD_SOCKS_VERSION) }, 98 { S_SOCKS_REJECTED, TEXT_(T_SOCKS_REJECTED_OR_FAILED) }, 99 { S_SOCKS_NO_IDENTD, TEXT_(T_SOCKS_NO_IDENTD) }, 100 { S_SOCKS_BAD_USERID, TEXT_(T_SOCKS_BAD_USERID) }, 101 { S_SOCKS_UNKNOWN_ERROR, TEXT_(T_SOCKS_UNKNOWN_ERROR) }, 102 103 { S_NO_PROXY, TEXT_(T_NO_PROXY) }, 104 { S_SMB_NOT_ALLOWED, TEXT_(T_SMB_NOT_ALLOWED) }, 105 { S_FILE_NOT_ALLOWED, TEXT_(T_FILE_NOT_ALLOWED) }, 106 107 { S_WAIT_REDIR, TEXT_(T_WAITING_FOR_REDIRECT_CONFIRMATION) }, 108 { 0, NULL } 109 }; 110 111 struct strerror_val { 112 list_entry_1st; 113 #ifdef REORDER_LIST_ENTRIES 114 unsigned char pad; 115 #endif 116 unsigned char msg[1]; 117 }; 118 119 static struct list_head strerror_buf = { &strerror_buf, &strerror_buf }; 120 121 void 122 free_strerror_buf(void) 123 { 124 free_list(struct strerror_val, strerror_buf); 125 } 126 127 int 128 get_error_from_errno(int errn) 129 { 130 if (errn > 0 && (errn < -S__OK || errn > -S_MAX)) 131 return -errn; 132 return S_UNKNOWN_ERROR; 133 } 134 135 unsigned char * 136 get_err_msg(int state) 137 { 138 unsigned char *e; 139 size_t sl; 140 struct strerror_val *s = NULL; 141 struct list_head *ls; 142 if ((state >= S_MAX && state <= S__OK) || state >= S_WAIT) { 143 int i; 144 for (i = 0; msg_dsc[i].msg; i++) 145 if (msg_dsc[i].n == state) 146 return msg_dsc[i].msg; 147 unk: 148 return TEXT_(T_UNKNOWN_ERROR); 149 } 150 if ((e = cast_uchar strerror(-state)) && *e) 151 goto have_error; 152 goto unk; 153 have_error: 154 foreach (struct strerror_val, s, ls, strerror_buf) 155 if (!strcmp(cast_const_char s->msg, cast_const_char e)) { 156 return s->msg; 157 } 158 sl = strlen(cast_const_char e); 159 if (sl > INT_MAX - sizeof(struct strerror_val)) 160 overalloc(); 161 s = xmalloc(sizeof(struct strerror_val) + sl); 162 strcpy(cast_char s->msg, cast_const_char e); 163 add_to_list(strerror_buf, s); 164 return s->msg; 165 } 166 167 static size_t 168 add_xnum_to_str(unsigned char **s, size_t l, off_t n) 169 { 170 unsigned char suff = 0; 171 int d = -1; 172 if (n >= 1000000000) { 173 suff = 'G'; 174 d = (int)((n / 100000000) % 10); 175 n /= 1000000000; 176 } else if (n >= 1000000) { 177 suff = 'M'; 178 d = (int)((n / 100000) % 10); 179 n /= 1000000; 180 } else if (n >= 1000) { 181 suff = 'k'; 182 d = (int)((n / 100) % 10); 183 n /= 1000; 184 } 185 l = add_num_to_str(s, l, n); 186 if (n < 10 && d != -1) { 187 l = add_chr_to_str(s, l, '.'); 188 add_num_to_str(s, l, d); 189 } 190 l = add_chr_to_str(s, l, ' '); 191 if (suff) 192 l = add_chr_to_str(s, l, suff); 193 return add_chr_to_str(s, l, 'B'); 194 } 195 196 static size_t 197 add_time_to_str(unsigned char **s, size_t l, uttime t) 198 { 199 unsigned char q[64]; 200 if (t >= 86400) { 201 sprintf(cast_char q, "%lud ", (unsigned long)(t / 86400)); 202 l = add_to_str(s, l, q); 203 } 204 if (t >= 3600) { 205 t %= 86400; 206 sprintf(cast_char q, "%d:%02d", (int)(t / 3600), 207 (int)(t / 60 % 60)); 208 l = add_to_str(s, l, q); 209 } else { 210 sprintf(cast_char q, "%d", (int)(t / 60)); 211 l = add_to_str(s, l, q); 212 } 213 sprintf(cast_char q, ":%02d", (int)(t % 60)); 214 return add_to_str(s, l, q); 215 } 216 217 static unsigned char * 218 get_stat_msg(struct status *stat, struct terminal *term) 219 { 220 if (stat->state == S_TRANS && stat->prg->elapsed / 100) { 221 unsigned char *m = NULL; 222 size_t l; 223 l = add_to_str(&m, 0, 224 get_text_translation(TEXT_(T_RECEIVED), term)); 225 l = add_chr_to_str(&m, l, ' '); 226 l = add_xnum_to_str(&m, l, stat->prg->pos); 227 if (stat->prg->size >= 0) { 228 l = add_chr_to_str(&m, l, ' '); 229 l = add_to_str(&m, l, 230 get_text_translation(TEXT_(T_OF), term)); 231 l = add_chr_to_str(&m, l, ' '); 232 l = add_xnum_to_str(&m, l, stat->prg->size); 233 } 234 l = add_to_str(&m, l, cast_uchar ", "); 235 if (stat->prg->elapsed >= CURRENT_SPD_AFTER * SPD_DISP_TIME) { 236 l = add_to_str( 237 &m, l, get_text_translation(TEXT_(T_AVG), term)); 238 l = add_chr_to_str(&m, l, ' '); 239 } 240 l = add_xnum_to_str( 241 &m, l, stat->prg->loaded * 10 / (stat->prg->elapsed / 100)); 242 l = add_to_str(&m, l, cast_uchar "/s"); 243 if (stat->prg->elapsed >= CURRENT_SPD_AFTER * SPD_DISP_TIME) { 244 l = add_to_str(&m, l, cast_uchar ", "); 245 l = add_to_str( 246 &m, l, get_text_translation(TEXT_(T_CUR), term)); 247 l = add_chr_to_str(&m, l, ' '); 248 l = add_xnum_to_str( 249 &m, l, 250 stat->prg->cur_loaded 251 / (CURRENT_SPD_SEC * SPD_DISP_TIME / 1000)); 252 l = add_to_str(&m, l, cast_uchar "/s"); 253 } 254 return m; 255 } 256 return stracpy(get_text_translation(get_err_msg(stat->state), term)); 257 } 258 259 void 260 change_screen_status(struct session *ses) 261 { 262 struct status *stat = NULL; 263 if (ses->rq) { 264 stat = &ses->rq->stat; 265 } else { 266 struct f_data_c *fd = current_frame(ses); 267 if (fd->rq) 268 stat = &fd->rq->stat; 269 if (stat && stat->state == S__OK && fd->af) { 270 unsigned count = 0; 271 struct additional_file *af = NULL; 272 struct list_head *laf; 273 foreachback (struct additional_file, af, laf, 274 fd->af->af) { 275 if (af->rq && af->rq->stat.state >= 0) { 276 if (af->rq->stat.state > stat->state 277 || (af->rq->stat.state == S_TRANS 278 && stat->state == S_TRANS 279 && af->rq->stat.prg->pos 280 > stat->prg->pos)) 281 stat = &af->rq->stat; 282 } 283 count++; 284 /* avoid too high cpu consumption */ 285 if (count >= 100 && stat->state >= 0 286 && stat->state != S_WAIT) 287 break; 288 } 289 } 290 } 291 free(ses->st); 292 293 /* default status se ukazuje, kdyz 294 * a) by se jinak ukazovalo prazdno 295 * b) neni NULL a ukazovalo by se OK 296 */ 297 ses->st = NULL; 298 if (stat) { 299 if (stat->state == S__OK) 300 ses->st = print_current_link(ses); 301 if (!ses->st) 302 ses->st = ses->default_status 303 ? stracpy(ses->default_status) 304 : get_stat_msg(stat, ses->term); 305 } else { 306 ses->st = stracpy(ses->default_status); 307 } 308 } 309 310 static void 311 x_print_screen_status(struct terminal *term, void *ses_) 312 { 313 struct session *ses = (struct session *)ses_; 314 unsigned char color = get_session_attribute(ses, proxies.only_proxies); 315 fill_area(term, 0, term->y - 1, term->x, 1, ' ', color); 316 if (ses->st) 317 print_text(term, 0, term->y - 1, 318 (int)strlen(cast_const_char ses->st), ses->st, 319 COLOR_STATUS); 320 } 321 322 static void 323 x_print_screen_title(struct terminal *term, void *ses_) 324 { 325 struct session *ses = (struct session *)ses_; 326 unsigned char *m; 327 unsigned char color = get_session_attribute(ses, proxies.only_proxies); 328 if (!term->spec->col) 329 color = COLOR_TITLE; 330 fill_area(term, 0, 0, term->x, 1, ' ', color); 331 if ((m = print_current_title(ses))) { 332 int p = term->x - 1 - strlen((char *)m); 333 if (p < 0) 334 p = 0; 335 print_text(term, p, 0, strlen((char *)m), m, color); 336 free(m); 337 } 338 } 339 340 static void 341 print_only_screen_status(struct session *ses) 342 { 343 draw_to_window(ses->win, x_print_screen_status, ses); 344 } 345 346 void 347 print_screen_status(struct session *ses) 348 { 349 unsigned char *m; 350 351 print_only_screen_status(ses); 352 draw_to_window(ses->win, x_print_screen_title, ses); 353 354 m = stracpy(cast_uchar "Links"); 355 if (ses->screen && ses->screen->f_data && ses->screen->f_data->title 356 && ses->screen->f_data->title[0]) { 357 add_to_strn(&m, cast_uchar " - "); 358 add_to_strn(&m, ses->screen->f_data->title); 359 } 360 set_terminal_title(ses->term, m); 361 362 if (ses->brl_cursor_mode) { 363 if (ses->brl_cursor_mode == 1) 364 set_cursor(ses->term, 0, 0, 0, 0); 365 if (ses->brl_cursor_mode == 2) 366 set_cursor(ses->term, 0, ses->term->y - 1, 0, 367 ses->term->y - 1); 368 } 369 } 370 371 void 372 print_progress(struct session *ses, unsigned char *msg) 373 { 374 free(ses->st); 375 ses->st = stracpy(get_text_translation(msg, ses->term)); 376 print_only_screen_status(ses); 377 flush_terminal(ses->term); 378 } 379 380 void 381 print_error_dialog(struct session *ses, struct status *stat, unsigned char *url) 382 { 383 unsigned char *t = get_err_msg(stat->state); 384 unsigned char *u = display_url(ses->term, url, 1); 385 msg_box(ses->term, getml(u, NULL), TEXT_(T_ERROR), AL_CENTER, 386 TEXT_(T_ERROR_LOADING), cast_uchar " ", u, cast_uchar ":\n\n", 387 t, MSG_BOX_END, 388 (void *)ses, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC /*, get_text_translation("Retry"), NULL, 0 !!! FIXME: retry */); 389 } 390 391 static inline unsigned char 392 hx(int a) 393 { 394 return a >= 10 ? a + 'A' - 10 : a + '0'; 395 } 396 397 static inline int 398 unhx(unsigned char a) 399 { 400 if (a >= '0' && a <= '9') 401 return a - '0'; 402 if (a >= 'A' && a <= 'F') 403 return a - 'A' + 10; 404 if (a >= 'a' && a <= 'f') 405 return a - 'a' + 10; 406 return -1; 407 } 408 409 unsigned char * 410 encode_url(unsigned char *url) 411 { 412 unsigned char *u = NULL; 413 size_t l; 414 l = add_to_str(&u, 0, cast_uchar "+++"); 415 for (; *url; url++) { 416 if (is_safe_in_shell(*url) && *url != '+') 417 l = add_chr_to_str(&u, l, *url); 418 else { 419 l = add_chr_to_str(&u, l, '+'); 420 l = add_chr_to_str(&u, l, hx(*url >> 4)); 421 l = add_chr_to_str(&u, l, hx(*url & 0xf)); 422 } 423 } 424 return u; 425 } 426 427 unsigned char * 428 decode_url(unsigned char *url) 429 { 430 unsigned char *u; 431 int l; 432 if (casecmp(url, cast_uchar "+++", 3)) 433 return stracpy(url); 434 url += 3; 435 u = NULL; 436 l = 0; 437 for (; *url; url++) { 438 if (*url != '+' || unhx(url[1]) == -1 || unhx(url[2]) == -1) 439 l = add_chr_to_str(&u, l, *url); 440 else { 441 l = add_chr_to_str(&u, l, 442 (unhx(url[1]) << 4) + unhx(url[2])); 443 url += 2; 444 } 445 } 446 return u; 447 } 448 449 struct session * 450 get_download_ses(struct download *down) 451 { 452 struct session *ses = NULL; 453 struct list_head *lses; 454 if (down) 455 foreach (struct session, ses, lses, sessions) 456 if (ses == down->ses) 457 return ses; 458 if (!list_empty(sessions)) 459 return list_struct(sessions.next, struct session); 460 return NULL; 461 } 462 463 static int 464 close_download_file(struct download *down) 465 { 466 int rs; 467 if (down->handle != -1) { 468 EINTRLOOP(rs, ftruncate(down->handle, 469 down->last_pos - down->file_shift)); 470 EINTRLOOP(rs, close(down->handle)); 471 down->handle = -1; 472 if (rs) 473 return -1; 474 } 475 return 0; 476 } 477 478 static void 479 delete_download_file(struct download *down) 480 { 481 int rs; 482 unsigned char *file = stracpy(down->orig_file); 483 unsigned char *wd = get_cwd(); 484 set_cwd(down->cwd); 485 while (1) { 486 unsigned char *f = translate_download_file(file); 487 EINTRLOOP(rs, unlink(cast_const_char f)); 488 free(f); 489 if (!strcmp(cast_const_char file, cast_const_char down->file)) 490 break; 491 increase_download_file(&file); 492 } 493 free(file); 494 if (wd) { 495 set_cwd(wd); 496 free(wd); 497 } 498 } 499 500 static void 501 abort_download(void *down_) 502 { 503 struct download *down = (struct download *)down_; 504 unregister_bottom_half(abort_download, down); 505 unregister_bottom_half(abort_and_delete_download, down); 506 unregister_bottom_half(undisplay_download, down); 507 508 if (down->win) 509 delete_window(down->win); 510 if (down->ask) 511 delete_window(down->ask); 512 if (down->stat.state >= 0) 513 change_connection(&down->stat, NULL, PRI_CANCEL); 514 free(down->url); 515 close_download_file(down); 516 if (down->prog) { 517 delete_download_file(down); 518 free(down->prog); 519 } 520 free(down->cwd); 521 free(down->orig_file); 522 free(down->file); 523 del_from_list(down); 524 free(down); 525 } 526 527 static void 528 abort_and_delete_download(void *down_) 529 { 530 struct download *down = (struct download *)down_; 531 abort_download(down); 532 } 533 534 int 535 test_abort_downloads_to_file(unsigned char *file, unsigned char *cwd, 536 int abort_downloads) 537 { 538 int ret = 0; 539 struct download *down = NULL; 540 struct list_head *ldown; 541 foreach (struct download, down, ldown, downloads) { 542 if (strcmp(cast_const_char down->cwd, cast_const_char cwd)) { 543 if (file[0] == '/') 544 goto abs; 545 continue; 546 } 547 abs: 548 if (!strcmp(cast_const_char down->file, cast_const_char file) 549 || !strcmp(cast_const_char down->orig_file, 550 cast_const_char file)) { 551 ret = 1; 552 if (!abort_downloads) 553 break; 554 ldown = ldown->prev; 555 abort_download(down); 556 } 557 } 558 return ret; 559 } 560 561 static void 562 undisplay_download(void *down_) 563 { 564 struct download *down = (struct download *)down_; 565 if (down->win) 566 delete_window(down->win); 567 } 568 569 static int 570 dlg_abort_download(struct dialog_data *dlg, struct dialog_item_data *di) 571 { 572 register_bottom_half(abort_download, dlg->dlg->udata); 573 return 0; 574 } 575 576 static int 577 dlg_abort_and_delete_download(struct dialog_data *dlg, 578 struct dialog_item_data *di) 579 { 580 register_bottom_half(abort_and_delete_download, dlg->dlg->udata); 581 return 0; 582 } 583 584 static int 585 dlg_undisplay_download(struct dialog_data *dlg, struct dialog_item_data *di) 586 { 587 register_bottom_half(undisplay_download, dlg->dlg->udata); 588 return 0; 589 } 590 591 static void 592 download_abort_function(struct dialog_data *dlg) 593 { 594 struct download *down = dlg->dlg->udata; 595 down->win = NULL; 596 } 597 598 static int 599 test_percentage(struct status *stat) 600 { 601 return stat->prg->size > 0; 602 } 603 604 static int 605 download_meter(int size, struct status *stat) 606 { 607 int m; 608 if (!stat->prg->size) 609 return 0; 610 m = (int)((double)size * (double)stat->prg->pos 611 / (double)stat->prg->size); 612 if (m < 0) 613 m = 0; 614 if (m > size) 615 m = size; 616 return m; 617 } 618 619 unsigned char * 620 download_percentage(struct download *down, int pad) 621 { 622 unsigned char *s; 623 size_t l; 624 int perc; 625 struct status *stat = &down->stat; 626 if (stat->state != S_TRANS || !test_percentage(stat)) 627 return stracpy(cast_uchar ""); 628 s = NULL; 629 l = 0; 630 perc = download_meter(100, stat); 631 if (pad) { 632 if (perc < 10) 633 l = add_chr_to_str(&s, l, ' '); 634 if (perc < 100) 635 l = add_chr_to_str(&s, l, ' '); 636 } 637 l = add_num_to_str(&s, l, perc); 638 l = add_chr_to_str(&s, l, '%'); 639 return s; 640 } 641 642 void 643 download_window_function(struct dialog_data *dlg) 644 { 645 struct download *down = dlg->dlg->udata; 646 struct terminal *term = dlg->win->term; 647 int max = 0, min = 0; 648 int w, x, y; 649 int t = 0; 650 int show_percentage = 0; 651 unsigned char *m, *u; 652 struct status *stat = &down->stat; 653 redraw_below_window(dlg->win); 654 down->win = dlg->win; 655 if (stat->state == S_TRANS && stat->prg->elapsed / 100) { 656 size_t l; 657 m = NULL; 658 t = 1; 659 l = add_to_str(&m, 0, 660 get_text_translation(TEXT_(T_RECEIVED), term)); 661 l = add_chr_to_str(&m, l, ' '); 662 l = add_xnum_to_str(&m, l, stat->prg->pos); 663 if (stat->prg->size >= 0) { 664 l = add_chr_to_str(&m, l, ' '); 665 l = add_to_str(&m, l, 666 get_text_translation(TEXT_(T_OF), term)); 667 l = add_chr_to_str(&m, l, ' '); 668 l = add_xnum_to_str(&m, l, stat->prg->size); 669 l = add_chr_to_str(&m, l, ' '); 670 } 671 l = add_chr_to_str(&m, l, '\n'); 672 if (stat->prg->elapsed >= CURRENT_SPD_AFTER * SPD_DISP_TIME) 673 l = add_to_str( 674 &m, l, 675 get_text_translation(TEXT_(T_AVERAGE_SPEED), term)); 676 else 677 l = add_to_str( 678 &m, l, get_text_translation(TEXT_(T_SPEED), term)); 679 l = add_chr_to_str(&m, l, ' '); 680 l = add_xnum_to_str(&m, l, 681 (long long)stat->prg->loaded * 10 682 / (stat->prg->elapsed / 100)); 683 l = add_to_str(&m, l, cast_uchar "/s"); 684 if (stat->prg->elapsed >= CURRENT_SPD_AFTER * SPD_DISP_TIME) { 685 l = add_to_str(&m, l, cast_uchar ", "); 686 l = add_to_str( 687 &m, l, 688 get_text_translation(TEXT_(T_CURRENT_SPEED), term)); 689 l = add_chr_to_str(&m, l, ' '); 690 l = add_xnum_to_str( 691 &m, l, 692 stat->prg->cur_loaded 693 / (CURRENT_SPD_SEC * SPD_DISP_TIME / 1000)); 694 l = add_to_str(&m, l, cast_uchar "/s"); 695 } 696 l = add_chr_to_str(&m, l, '\n'); 697 l = add_to_str( 698 &m, l, get_text_translation(TEXT_(T_ELAPSED_TIME), term)); 699 l = add_chr_to_str(&m, l, ' '); 700 l = add_time_to_str(&m, l, stat->prg->elapsed / 1000); 701 if (stat->prg->size >= 0 && stat->prg->loaded > 0) { 702 l = add_to_str(&m, l, cast_uchar ", "); 703 l = add_to_str(&m, l, 704 get_text_translation( 705 TEXT_(T_ESTIMATED_TIME), term)); 706 l = add_chr_to_str(&m, l, ' '); 707 /*add_time_to_str(&m, &l, stat->prg->elapsed / 1000 * 708 * stat->prg->size / stat->prg->loaded * 1000 - 709 * stat->prg->elapsed);*/ 710 /*add_time_to_str(&m, &l, (stat->prg->size - 711 * stat->prg->pos) / ((longlong)stat->prg->loaded * 10 / 712 * (stat->prg->elapsed / 100)));*/ 713 l = add_time_to_str( 714 &m, l, 715 (uttime)((stat->prg->size - stat->prg->pos) 716 / ((double)stat->prg->loaded * 1000 717 / stat->prg->elapsed))); 718 } 719 } else 720 m = stracpy( 721 get_text_translation(get_err_msg(stat->state), term)); 722 show_percentage = t && test_percentage(stat); 723 u = display_url(term, down->url, 1); 724 max_text_width(term, u, &max, AL_LEFT); 725 min_text_width(term, u, &min, AL_LEFT); 726 max_text_width(term, m, &max, AL_LEFT); 727 min_text_width(term, m, &min, AL_LEFT); 728 max_buttons_width(term, dlg->items, dlg->n, &max); 729 min_buttons_width(term, dlg->items, dlg->n, &min); 730 w = dlg->win->term->x * 9 / 10 - 2 * DIALOG_LB; 731 if (w < min) 732 w = min; 733 if (w > dlg->win->term->x - 2 * DIALOG_LB) 734 w = dlg->win->term->x - 2 * DIALOG_LB; 735 if (show_percentage) { 736 if (w < DOWN_DLG_MIN) 737 w = DOWN_DLG_MIN; 738 } else { 739 if (w > max) 740 w = max; 741 } 742 if (w < 1) 743 w = 1; 744 y = 0; 745 dlg_format_text(dlg, NULL, u, 0, &y, w, NULL, COLOR_DIALOG_TEXT, 746 AL_LEFT); 747 y++; 748 if (show_percentage) 749 y += 2; 750 dlg_format_text(dlg, NULL, m, 0, &y, w, NULL, COLOR_DIALOG_TEXT, 751 AL_LEFT); 752 y++; 753 dlg_format_buttons(dlg, NULL, dlg->items, dlg->n, 0, &y, w, NULL, 754 AL_CENTER); 755 dlg->xw = w + 2 * DIALOG_LB; 756 dlg->yw = y + 2 * DIALOG_TB; 757 center_dlg(dlg); 758 draw_dlg(dlg); 759 y = dlg->y + DIALOG_TB + 1; 760 x = dlg->x + DIALOG_LB; 761 dlg_format_text(dlg, term, u, x, &y, w, NULL, COLOR_DIALOG_TEXT, 762 AL_LEFT); 763 if (show_percentage) { 764 unsigned char *q; 765 int p = w - 6; 766 y++; 767 set_only_char(term, x, y, '[', 0); 768 set_only_char(term, x + p + 1, y, ']', 0); 769 fill_area(term, x + 1, y, download_meter(p, stat), 1, 770 CHAR_DIALOG_METER, COLOR_DIALOG_METER); 771 q = download_percentage(down, 1); 772 print_text(term, x + p + 2, y, (int)strlen(cast_const_char q), 773 q, COLOR_DIALOG_TEXT); 774 free(q); 775 y++; 776 } 777 y++; 778 dlg_format_text(dlg, term, m, x, &y, w, NULL, COLOR_DIALOG_TEXT, 779 AL_LEFT); 780 y++; 781 dlg_format_buttons(dlg, term, dlg->items, dlg->n, x, &y, w, NULL, 782 AL_CENTER); 783 free(u); 784 free(m); 785 } 786 787 void 788 display_download(struct terminal *term, void *down_, void *ses_) 789 { 790 struct download *down = (struct download *)down_; 791 struct session *ses = (struct session *)ses_; 792 struct dialog *dlg; 793 struct download *dd = NULL; 794 struct list_head *ldd; 795 foreach (struct download, dd, ldd, downloads) 796 if (dd == down) 797 goto found; 798 return; 799 found: 800 dlg = 801 mem_calloc(sizeof(struct dialog) + 4 * sizeof(struct dialog_item)); 802 undisplay_download(down); 803 down->ses = ses; 804 dlg->title = TEXT_(T_DOWNLOAD); 805 dlg->fn = download_window_function; 806 dlg->abort = download_abort_function; 807 dlg->udata = down; 808 dlg->align = AL_CENTER; 809 dlg->items[0].type = D_BUTTON; 810 dlg->items[0].gid = B_ENTER | B_ESC; 811 dlg->items[0].fn = dlg_undisplay_download; 812 dlg->items[0].text = TEXT_(T_BACKGROUND); 813 dlg->items[1].type = D_BUTTON; 814 dlg->items[1].gid = 0; 815 dlg->items[1].fn = dlg_abort_download; 816 dlg->items[1].text = TEXT_(T_ABORT); 817 if (!down->prog) { 818 dlg->items[2].type = D_BUTTON; 819 dlg->items[2].gid = 0; 820 dlg->items[2].fn = dlg_abort_and_delete_download; 821 dlg->items[2].text = TEXT_(T_ABORT_AND_DELETE_FILE); 822 dlg->items[3].type = D_END; 823 } else { 824 dlg->items[2].type = D_END; 825 } 826 do_dialog(term, dlg, getml(dlg, NULL)); 827 } 828 829 time_t 830 parse_http_date(unsigned char *date) /* this functions is bad !!! */ 831 { 832 static unsigned char *months[12] = { 833 cast_uchar "Jan", cast_uchar "Feb", cast_uchar "Mar", 834 cast_uchar "Apr", cast_uchar "May", cast_uchar "Jun", 835 cast_uchar "Jul", cast_uchar "Aug", cast_uchar "Sep", 836 cast_uchar "Oct", cast_uchar "Nov", cast_uchar "Dec" 837 }; 838 839 time_t t = 0; 840 /* Mon, 03 Jan 2000 21:29:33 GMT */ 841 int y; 842 struct tm tm; 843 memset(&tm, 0, sizeof(struct tm)); 844 845 date = cast_uchar strchr(cast_const_char date, ' '); 846 if (!date) 847 return 0; 848 date++; 849 if (*date >= '0' && *date <= '9') { 850 /* Sun, 06 Nov 1994 08:49:37 GMT */ 851 /* Sunday, 06-Nov-94 08:49:37 GMT */ 852 y = 0; 853 if (date[0] < '0' || date[0] > '9') 854 return 0; 855 if (date[1] < '0' || date[1] > '9') 856 return 0; 857 tm.tm_mday = (date[0] - '0') * 10 + date[1] - '0'; 858 date += 2; 859 if (*date != ' ' && *date != '-') 860 return 0; 861 date += 1; 862 for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++) 863 if (!casecmp(date, months[tm.tm_mon], 3)) 864 goto f1; 865 return 0; 866 f1: 867 date += 3; 868 if (*date == ' ') { 869 /* Sun, 06 Nov 1994 08:49:37 GMT */ 870 date++; 871 if (date[0] < '0' || date[0] > '9') 872 return 0; 873 if (date[1] < '0' || date[1] > '9') 874 return 0; 875 if (date[2] < '0' || date[2] > '9') 876 return 0; 877 if (date[3] < '0' || date[3] > '9') 878 return 0; 879 tm.tm_year = 880 (date[0] - '0') * 1000 + (date[1] - '0') * 100 881 + (date[2] - '0') * 10 + date[3] - '0' - 1900; 882 date += 4; 883 } else if (*date == '-') { 884 /* Sunday, 06-Nov-94 08:49:37 GMT */ 885 date++; 886 if (date[0] < '0' || date[0] > '9') 887 return 0; 888 if (date[1] < '0' || date[1] > '9') 889 return 0; 890 tm.tm_year = (date[0] >= '7' ? 1900 : 2000) 891 + (date[0] - '0') * 10 + date[1] - '0' 892 - 1900; 893 date += 2; 894 } else 895 return 0; 896 if (*date != ' ') 897 return 0; 898 date++; 899 } else { 900 /* Sun Nov 6 08:49:37 1994 */ 901 y = 1; 902 for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++) 903 if (!casecmp(date, months[tm.tm_mon], 3)) 904 goto f2; 905 return 0; 906 f2: 907 date += 3; 908 while (*date == ' ') 909 date++; 910 if (date[0] < '0' || date[0] > '9') 911 return 0; 912 tm.tm_mday = date[0] - '0'; 913 date++; 914 if (*date != ' ') { 915 if (date[0] < '0' || date[0] > '9') 916 return 0; 917 tm.tm_mday = tm.tm_mday * 10 + date[0] - '0'; 918 date++; 919 } 920 if (*date != ' ') 921 return 0; 922 date++; 923 } 924 925 if (date[0] < '0' || date[0] > '9') 926 return 0; 927 if (date[1] < '0' || date[1] > '9') 928 return 0; 929 tm.tm_hour = (date[0] - '0') * 10 + date[1] - '0'; 930 date += 2; 931 if (*date != ':') 932 return 0; 933 date++; 934 if (date[0] < '0' || date[0] > '9') 935 return 0; 936 if (date[1] < '0' || date[1] > '9') 937 return 0; 938 tm.tm_min = (date[0] - '0') * 10 + date[1] - '0'; 939 date += 2; 940 if (*date != ':') 941 return 0; 942 date++; 943 if (date[0] < '0' || date[0] > '9') 944 return 0; 945 if (date[1] < '0' || date[1] > '9') 946 return 0; 947 tm.tm_sec = (date[0] - '0') * 10 + date[1] - '0'; 948 date += 2; 949 if (y) { 950 if (*date != ' ') 951 return 0; 952 date++; 953 if (date[0] < '0' || date[0] > '9') 954 return 0; 955 if (date[1] < '0' || date[1] > '9') 956 return 0; 957 if (date[2] < '0' || date[2] > '9') 958 return 0; 959 if (date[3] < '0' || date[3] > '9') 960 return 0; 961 tm.tm_year = (date[0] - '0') * 1000 + (date[1] - '0') * 100 962 + (date[2] - '0') * 10 + date[3] - '0' - 1900; 963 date += 4; 964 } 965 if (*date != ' ' && *date) 966 return 0; 967 968 t = mktime(&tm); 969 if (t == (time_t)-1) 970 return 0; 971 return t; 972 } 973 974 static void 975 download_file_error(struct download *down, int err) 976 { 977 struct session *ses = get_download_ses(down); 978 if (ses) { 979 unsigned char *emsg = stracpy(err ? cast_uchar strerror(err) 980 : cast_uchar "Zero returned"); 981 unsigned char *msg = stracpy(down->file); 982 msg_box(ses->term, getml(msg, emsg, NULL), 983 TEXT_(T_DOWNLOAD_ERROR), AL_CENTER, 984 TEXT_(T_COULD_NOT_WRITE_TO_FILE), cast_uchar " ", msg, 985 cast_uchar ": ", emsg, MSG_BOX_END, NULL, 1, 986 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 987 } 988 } 989 990 static int 991 download_write(struct download *down, void *ptr, off_t to_write) 992 { 993 int w; 994 int err; 995 if (to_write != (int)to_write || (int)to_write < 0) 996 to_write = INT_MAX; 997 try_write_again: 998 w = hard_write(down->handle, ptr, (int)to_write); 999 if (w >= 0) 1000 err = 0; 1001 else 1002 err = errno; 1003 if (w <= -!to_write) { 1004 #ifdef EFBIG 1005 if (err == EFBIG && !down->prog) { 1006 if (to_write > 1) { 1007 to_write >>= 1; 1008 goto try_write_again; 1009 } 1010 if (down->last_pos == down->file_shift) 1011 goto no_e2big; 1012 if (close_download_file(down)) { 1013 download_file_error(down, errno); 1014 return -1; 1015 } 1016 increase_download_file(&down->file); 1017 if ((down->handle = create_download_file( 1018 get_download_ses(down), down->cwd, down->file, 1019 0, down->last_pos - down->file_shift)) 1020 < 0) 1021 return -1; 1022 down->file_shift = down->last_pos; 1023 goto try_write_again; 1024 no_e2big:; 1025 } 1026 #endif 1027 download_file_error(down, err); 1028 return -1; 1029 } 1030 down->last_pos += w; 1031 down->downloaded_something = 1; 1032 return 0; 1033 } 1034 1035 static void 1036 download_data(struct status *stat, void *down_) 1037 { 1038 struct download *down = (struct download *)down_; 1039 struct cache_entry *ce; 1040 struct fragment *frag = NULL; 1041 struct list_head *lfrag; 1042 int rs; 1043 if (!(ce = stat->ce)) 1044 goto end_store; 1045 if (stat->state >= S_WAIT && stat->state < S_TRANS) 1046 goto end_store; 1047 if (!down->remotetime && ce->last_modified) 1048 down->remotetime = parse_http_date(ce->last_modified); 1049 if (!down->downloaded_something) { 1050 unsigned char *enc; 1051 if (ce->redirect) { 1052 if (down->redirect_cnt++ < MAX_REDIRECTS) { 1053 unsigned char *u; 1054 unsigned char *prev_down_url; 1055 int cache, allow_flags; 1056 if (stat->state >= 0) 1057 change_connection(&down->stat, NULL, 1058 PRI_CANCEL); 1059 u = join_urls(down->url, ce->redirect); 1060 extract_position(u); 1061 prev_down_url = down->url; 1062 down->url = u; 1063 down->stat.state = S_WAIT_REDIR; 1064 if (down->win) { 1065 struct links_event ev = { EV_REDRAW, 0, 1066 0, 0 }; 1067 ev.x = down->win->term->x; 1068 ev.y = down->win->term->y; 1069 down->win->handler(down->win, &ev, 0); 1070 } 1071 cache = NC_CACHE; 1072 if (!strcmp(cast_const_char down->url, 1073 cast_const_char prev_down_url) 1074 || down->redirect_cnt 1075 >= MAX_CACHED_REDIRECTS) 1076 cache = NC_RELOAD; 1077 allow_flags = get_allow_flags(prev_down_url); 1078 free(prev_down_url); 1079 load_url(down->url, NULL, &down->stat, 1080 PRI_DOWNLOAD, cache, 1, allow_flags, 1081 down->last_pos); 1082 return; 1083 } else { 1084 if (stat->state >= 0) 1085 change_connection(&down->stat, NULL, 1086 PRI_CANCEL); 1087 stat->state = S_CYCLIC_REDIRECT; 1088 goto end_store; 1089 } 1090 } 1091 enc = get_content_encoding(ce->head, ce->url, !down->prog); 1092 if (enc) { 1093 down->decompress = 1; 1094 free(enc); 1095 enc = get_content_encoding(ce->head, ce->url, 1); 1096 if (enc) { 1097 free(enc); 1098 detach_connection(stat, down->last_pos, 1, 0); 1099 } 1100 } else { 1101 down->decompress = 0; 1102 } 1103 } 1104 if (!down->decompress) { 1105 foreachback (struct fragment, frag, lfrag, ce->frag) 1106 if (frag->offset <= down->last_pos) 1107 goto have_frag; 1108 foreach (struct fragment, frag, lfrag, ce->frag) { 1109 have_frag: 1110 while (frag->offset <= down->last_pos 1111 && frag->offset + frag->length 1112 > down->last_pos) { 1113 if (download_write( 1114 down, 1115 frag->data 1116 + (down->last_pos - frag->offset), 1117 frag->length 1118 - (down->last_pos 1119 - frag->offset))) { 1120 det_abt: 1121 detach_connection(stat, down->last_pos, 1122 0, 0); 1123 abort_download(down); 1124 return; 1125 } 1126 } 1127 } 1128 } 1129 if (!down->decompress) 1130 detach_connection(stat, down->last_pos, 0, 0); 1131 end_store: 1132 if (stat->state < 0) { 1133 if (down->decompress) { 1134 struct session *ses = get_download_ses(down); 1135 unsigned char *start; 1136 size_t len; 1137 int err; 1138 get_file_by_term(ses ? ses->term : NULL, ce, &start, 1139 &len, &err); 1140 if (err) 1141 goto det_abt; 1142 while (down->last_pos < len) { 1143 if (download_write(down, start + down->last_pos, 1144 len - down->last_pos)) 1145 goto det_abt; 1146 } 1147 } 1148 if (stat->state != S__OK) { 1149 unsigned char *t = get_err_msg(stat->state); 1150 unsigned char *tt = display_url( 1151 get_download_ses(down)->term, down->url, 1); 1152 msg_box( 1153 get_download_ses(down)->term, getml(tt, NULL), 1154 TEXT_(T_DOWNLOAD_ERROR), AL_CENTER, 1155 TEXT_(T_ERROR_DOWNLOADING), cast_uchar " ", tt, 1156 cast_uchar ":\n\n", t, MSG_BOX_END, 1157 (void *)get_download_ses(down), 1158 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC /*, TEXT_(T_RETRY), NULL, 0 !!! FIXME: retry */); 1159 } else { 1160 if (close_download_file(down)) { 1161 download_file_error(down, errno); 1162 } else if (down->prog) { 1163 exec_on_terminal(get_download_ses(down)->term, 1164 down->prog, down->orig_file, 1165 !!down->prog_flag_block); 1166 free(down->prog); 1167 down->prog = NULL; 1168 } else if (down->remotetime && download_utime) { 1169 struct timeval utv[2]; 1170 unsigned char *file = stracpy(down->orig_file); 1171 unsigned char *wd = get_cwd(); 1172 set_cwd(down->cwd); 1173 utv[0].tv_usec = utv[1].tv_usec = 0; 1174 utv[0].tv_sec = utv[1].tv_sec = 1175 down->remotetime; 1176 while (1) { 1177 unsigned char *f = 1178 translate_download_file(file); 1179 EINTRLOOP(rs, utimes(cast_char f, utv)); 1180 free(f); 1181 if (!strcmp(cast_const_char file, 1182 cast_const_char down->file)) 1183 break; 1184 increase_download_file(&file); 1185 } 1186 free(file); 1187 if (wd) { 1188 set_cwd(wd); 1189 free(wd); 1190 } 1191 } 1192 } 1193 abort_download(down); 1194 return; 1195 } 1196 if (down->win) { 1197 struct links_event ev = { EV_REDRAW, 0, 0, 0 }; 1198 ev.x = down->win->term->x; 1199 ev.y = down->win->term->y; 1200 down->win->handler(down->win, &ev, 0); 1201 } 1202 } 1203 1204 unsigned char * 1205 translate_download_file(unsigned char *fi) 1206 { 1207 unsigned char *file = stracpy(cast_uchar ""); 1208 unsigned char *h; 1209 if (fi[0] == '~' && dir_sep(fi[1]) && (h = cast_uchar getenv("HOME"))) { 1210 add_to_strn(&file, h); 1211 fi++; 1212 } 1213 add_to_strn(&file, fi); 1214 return file; 1215 } 1216 1217 int 1218 create_download_file(struct session *ses, unsigned char *cwd, unsigned char *fi, 1219 int mode, off_t siz) 1220 { 1221 unsigned char *wd; 1222 unsigned char *file; 1223 int h; 1224 #ifdef NO_FILE_SECURITY 1225 int perm = 0666; 1226 #else 1227 int perm = mode & CDF_RESTRICT_PERMISSION ? 0600 : 0666; 1228 #endif 1229 wd = get_cwd(); 1230 set_cwd(cwd); 1231 file = translate_download_file(fi); 1232 h = c_open3(file, 1233 O_CREAT | O_NOCTTY | O_WRONLY 1234 | (mode & CDF_NOTRUNC ? 0 : O_TRUNC) 1235 | (mode & CDF_EXCL ? O_EXCL : 0), 1236 perm); 1237 if (h == -1) { 1238 unsigned char *msg, *msge; 1239 int errn = errno; 1240 if (errn == EEXIST && mode & CDF_NO_POPUP_ON_EEXIST) { 1241 h = -2; 1242 goto x; 1243 } 1244 if (!ses) 1245 goto x; 1246 msg = stracpy(file); 1247 msge = stracpy(cast_uchar strerror(errn)); 1248 msg_box(ses->term, getml(msg, msge, NULL), 1249 TEXT_(T_DOWNLOAD_ERROR), AL_CENTER, 1250 TEXT_(T_COULD_NOT_CREATE_FILE), cast_uchar " ", msg, 1251 cast_uchar ": ", msge, MSG_BOX_END, NULL, 1, 1252 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1253 goto x; 1254 } 1255 x: 1256 free(file); 1257 if (wd) { 1258 set_cwd(wd); 1259 free(wd); 1260 } 1261 return h; 1262 } 1263 1264 static int 1265 create_or_append_download_file(struct session *ses, unsigned char *cwd, 1266 unsigned char *fi, int mode, int *hp, 1267 unsigned char **xl_file, off_t *last_pos, 1268 off_t *file_shift) 1269 { 1270 int rs; 1271 int down_flags = mode == DOWNLOAD_CONTINUE ? CDF_NOTRUNC 1272 : mode == DOWNLOAD_OVERWRITE ? 0 1273 : CDF_EXCL; 1274 1275 *xl_file = stracpy(fi); 1276 *last_pos = 0; 1277 *file_shift = 0; 1278 1279 retry_next_file: 1280 test_abort_downloads_to_file(*xl_file, ses->term->cwd, 1); 1281 1282 if ((*hp = create_download_file(ses, ses->term->cwd, *xl_file, 1283 down_flags, 0)) 1284 < 0) 1285 goto err_free; 1286 1287 if (mode == DOWNLOAD_CONTINUE) { 1288 off_t ls; 1289 unsigned char *f; 1290 struct stat st; 1291 1292 EINTRLOOP(rs, fstat(*hp, &st)); 1293 if (rs || !S_ISREG(st.st_mode)) 1294 goto ret_0; 1295 1296 EINTRLOOP(ls, lseek(*hp, 0, SEEK_END)); 1297 if (ls == (off_t)-1) { 1298 unsigned char *emsg = 1299 stracpy(cast_uchar strerror(errno)); 1300 unsigned char *msg = stracpy(*xl_file); 1301 msg_box(ses->term, getml(msg, emsg, NULL), 1302 TEXT_(T_DOWNLOAD_ERROR), AL_CENTER, 1303 TEXT_(T_ERROR_CALLING_LSEEK_ON_FILE), 1304 cast_uchar " ", msg, cast_uchar ": ", emsg, 1305 MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), 1306 msg_box_null, B_ENTER | B_ESC); 1307 goto err_close; 1308 } 1309 if ((off_t)(0UL + *last_pos + ls) < 0 1310 || (off_t)(0UL + *last_pos + ls) < *last_pos) { 1311 unsigned char *msg1 = stracpy(fi); 1312 unsigned char *msg2 = stracpy(*xl_file); 1313 msg_box(ses->term, getml(msg1, msg2, NULL), 1314 TEXT_(T_DOWNLOAD_ERROR), AL_CENTER, 1315 TEXT_(T_TOO_LARGE_FILE_SEQUENCE), 1316 cast_uchar " ", msg1, cast_uchar " - ", msg2, 1317 MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), 1318 msg_box_null, B_ENTER | B_ESC); 1319 goto err_close; 1320 } 1321 *last_pos += ls; 1322 1323 f = stracpy(*xl_file); 1324 increase_download_file(&f); 1325 EINTRLOOP(rs, stat(cast_const_char f, &st)); 1326 if (rs || !S_ISREG(st.st_mode)) { 1327 free(f); 1328 goto ret_0; 1329 } 1330 EINTRLOOP(rs, close(*hp)); 1331 free(*xl_file); 1332 *xl_file = f; 1333 *file_shift = *last_pos; 1334 goto retry_next_file; 1335 } 1336 1337 ret_0: 1338 return 0; 1339 1340 err_close: 1341 EINTRLOOP(rs, close(*hp)); 1342 err_free: 1343 free(*xl_file); 1344 return -1; 1345 } 1346 1347 static void 1348 increase_download_file(unsigned char **f) 1349 { 1350 unsigned char *p = NULL, *pp = *f; 1351 unsigned char *q; 1352 while ((pp = cast_uchar strstr(cast_const_char pp, ".part-"))) 1353 p = pp += 6; 1354 if (!p || !*p) { 1355 no_suffix: 1356 add_to_strn(f, cast_uchar ".part-2"); 1357 return; 1358 } 1359 for (q = p; *q; q++) 1360 if (*q < '0' || *q > '9') 1361 goto no_suffix; 1362 for (q--; q >= p; q--) { 1363 if (*q < '9') { 1364 (*q)++; 1365 return; 1366 } 1367 *q = '0'; 1368 } 1369 *p = '1'; 1370 add_to_strn(f, cast_uchar "0"); 1371 } 1372 1373 static unsigned char * 1374 get_temp_name(unsigned char *url, unsigned char *head) 1375 { 1376 size_t nl; 1377 unsigned char *name, *fn, *fnx; 1378 unsigned char *nm; 1379 unsigned char *directory = NULL; 1380 nm = cast_uchar tempnam(cast_const_char directory, "links"); 1381 if (!nm) 1382 return NULL; 1383 name = NULL; 1384 nl = add_to_str(&name, 0, nm); 1385 free(nm); 1386 fn = get_filename_from_url(url, head, 1); 1387 fnx = cast_uchar strchr(cast_const_char fn, '.'); 1388 if (fnx) { 1389 unsigned char *s; 1390 s = stracpy(fnx); 1391 check_shell_security(&s); 1392 nl = add_to_str(&name, nl, s); 1393 free(s); 1394 } 1395 free(fn); 1396 return name; 1397 } 1398 1399 unsigned char * 1400 subst_file(unsigned char *prog, unsigned char *file, int cyg_subst) 1401 { 1402 unsigned char *orig_prog = prog; 1403 unsigned char *nn; 1404 unsigned char *n = NULL; 1405 size_t l = 0; 1406 while (*prog) { 1407 int p; 1408 for (p = 0; prog[p] && prog[p] != '%'; p++) 1409 ; 1410 l = add_bytes_to_str(&n, l, prog, p); 1411 prog += p; 1412 if (*prog == '%') { 1413 if (cyg_subst) { 1414 unsigned char *conv = 1415 os_conv_to_external_path(file, orig_prog); 1416 l = add_to_str(&n, l, conv); 1417 free(conv); 1418 } else 1419 l = add_to_str(&n, l, file); 1420 prog++; 1421 } 1422 } 1423 nn = os_fixup_external_program(n); 1424 free(n); 1425 return nn; 1426 } 1427 1428 void 1429 start_download(struct session *ses, unsigned char *file, int mode) 1430 { 1431 struct download *down; 1432 int h; 1433 unsigned char *url = ses->dn_url; 1434 unsigned char *xl_file; 1435 off_t last_pos = 0, file_shift = 0; 1436 1437 if (!url) 1438 return; 1439 extract_position(url); 1440 1441 if (create_or_append_download_file(ses, ses->term->cwd, file, mode, &h, 1442 &xl_file, &last_pos, &file_shift) 1443 < 0) 1444 return; 1445 1446 down = mem_calloc(sizeof(struct download)); 1447 down->url = stracpy(url); 1448 down->stat.end = download_data; 1449 down->stat.data = down; 1450 down->decompress = 0; 1451 down->last_pos = last_pos; 1452 down->file_shift = file_shift; 1453 down->cwd = stracpy(ses->term->cwd); 1454 down->orig_file = stracpy(file); 1455 down->file = xl_file; 1456 down->handle = h; 1457 down->ses = ses; 1458 down->remotetime = 0; 1459 add_to_list(downloads, down); 1460 load_url(url, NULL, &down->stat, PRI_DOWNLOAD, NC_CACHE, 1, 1461 ses->dn_allow_flags, down->last_pos); 1462 display_download(ses->term, down, ses); 1463 } 1464 1465 void 1466 abort_all_downloads(void) 1467 { 1468 while (!list_empty(downloads)) { 1469 struct download *down = 1470 list_struct(downloads.next, struct download); 1471 abort_download(down); 1472 } 1473 } 1474 1475 int 1476 f_is_finished(struct f_data *f) 1477 { 1478 struct additional_file *af = NULL; 1479 struct list_head *laf; 1480 if (!f || f->rq->state >= 0) 1481 return 0; 1482 if (f->fd && f->fd->rq && f->fd->rq->state >= 0) 1483 return 0; 1484 if (f->af) 1485 foreach (struct additional_file, af, laf, f->af->af) 1486 if (!af->rq || af->rq->state >= 0) 1487 return 0; 1488 return 1; 1489 } 1490 1491 static int 1492 f_is_cacheable(struct f_data *f) 1493 { 1494 if (!f || f->rq->state >= 0) 1495 return 0; 1496 if (f->fd && f->fd->rq && f->fd->rq->state >= 0) 1497 return 0; 1498 return 1; 1499 } 1500 1501 static int 1502 f_need_reparse(struct f_data *f) 1503 { 1504 struct additional_file *af = NULL; 1505 struct list_head *laf; 1506 if (!f || f->rq->state >= 0) 1507 return 1; 1508 if (f->af) 1509 foreach (struct additional_file, af, laf, f->af->af) 1510 if (af->need_reparse > 0) 1511 return 1; 1512 return 0; 1513 } 1514 1515 static struct f_data * 1516 format_html(struct f_data_c *fd, struct object_request *rq, unsigned char *url, 1517 struct document_options *opt, int *cch) 1518 { 1519 struct f_data *f; 1520 pr(if (cch) *cch = 0; 1521 if (!rq->ce || !(f = init_formatted(opt))) goto nul; f->fd = fd; 1522 f->ses = fd->ses; f->time_to_get = -get_time(); 1523 clone_object(rq, &f->rq); if (f->rq->ce) { 1524 unsigned char *start; 1525 size_t len; 1526 int stl = -1; 1527 struct additional_file *af = NULL; 1528 struct list_head *laf; 1529 1530 if (fd->af) 1531 foreach (struct additional_file, af, laf, fd->af->af) 1532 if (af->need_reparse > 0) 1533 af->need_reparse = 0; 1534 1535 get_file(rq, &start, &len); 1536 if (len > INT_MAX) 1537 len = INT_MAX; 1538 f->uncacheable = 1; 1539 if (opt->plain == 2) { 1540 start = NULL; 1541 stl = 1542 add_to_str(&start, 0, cast_uchar "<img src=\""); 1543 stl = add_to_str(&start, stl, f->rq->ce->url); 1544 stl = add_to_str(&start, stl, cast_uchar "\">"); 1545 len = stl; 1546 } 1547 really_format_html(f->rq->ce, start, start + len, f, 1548 fd->ses ? fd != fd->ses->screen : 0); 1549 if (stl != -1) 1550 free(start); 1551 f->use_tag = f->rq->ce->count; 1552 if (f->af) 1553 foreach (struct additional_file, af, laf, 1554 f->af->af) { 1555 if (af->rq && af->rq->ce) { 1556 af->use_tag = af->rq->ce->count; 1557 af->use_tag2 = af->rq->ce->count2; 1558 } else { 1559 af->use_tag = 0; 1560 af->use_tag2 = 0; 1561 } 1562 } 1563 } else f->use_tag = 0; 1564 f->time_to_get += get_time();) nul : return NULL; 1565 return f; 1566 } 1567 1568 static void 1569 count_frames(struct f_data_c *fd, unsigned long *i) 1570 { 1571 struct f_data_c *sub = NULL; 1572 struct list_head *lsub; 1573 if (!fd) 1574 return; 1575 if (fd->f_data) 1576 (*i)++; 1577 foreach (struct f_data_c, sub, lsub, fd->subframes) 1578 count_frames(sub, i); 1579 } 1580 1581 unsigned long 1582 formatted_info(int type) 1583 { 1584 unsigned long i = 0; 1585 struct session *ses = NULL; 1586 struct list_head *lses; 1587 switch (type) { 1588 case CI_FILES: 1589 foreach (struct session, ses, lses, sessions) 1590 i += list_size(&ses->format_cache); 1591 /*-fallthrough*/ 1592 case CI_LOCKED: 1593 foreach (struct session, ses, lses, sessions) 1594 count_frames(ses->screen, &i); 1595 return i; 1596 default: 1597 internal("formatted_info: bad request"); 1598 } 1599 return 0; 1600 } 1601 1602 static void 1603 f_data_attach(struct f_data_c *fd, struct f_data *f) 1604 { 1605 struct additional_file *af = NULL; 1606 struct list_head *laf; 1607 f->rq->upcall = fd_loaded; 1608 f->rq->data = fd; 1609 free_additional_files(&fd->af); 1610 fd->af = f->af; 1611 if (f->af) { 1612 f->af->refcount++; 1613 foreachback (struct additional_file, af, laf, f->af->af) { 1614 if (af->rq) { 1615 af->rq->upcall = fd_loaded; 1616 af->rq->data = fd; 1617 } else { 1618 request_object( 1619 fd->ses->term, af->url, f->rq->url, PRI_IMG, 1620 NC_CACHE, get_allow_flags(f->rq->url), 1621 f->rq->upcall, f->rq->data, &af->rq); 1622 } 1623 } 1624 } 1625 } 1626 1627 static inline int 1628 is_format_cache_entry_uptodate(struct f_data *f) 1629 { 1630 struct cache_entry *ce = f->rq->ce; 1631 struct additional_file *af = NULL; 1632 struct list_head *laf; 1633 if (!ce || ce->count != f->use_tag) 1634 return 0; 1635 if (f->af) 1636 foreach (struct additional_file, af, laf, f->af->af) { 1637 struct cache_entry *ce = af->rq ? af->rq->ce : NULL; 1638 tcount tag = ce ? ce->count : 0; 1639 tcount tag2 = ce ? ce->count2 : 0; 1640 if (af->need_reparse > 0) 1641 if (tag != af->use_tag) 1642 return 0; 1643 if (af->unknown_image_size) 1644 if (tag2 != af->use_tag2) 1645 return 0; 1646 } 1647 return 1; 1648 } 1649 1650 static void 1651 detach_f_data(struct f_data **ff) 1652 { 1653 struct f_data *f = *ff; 1654 struct f_data_c *fd; 1655 if (!f) 1656 return; 1657 fd = f->fd; 1658 *ff = NULL; 1659 1660 f->fd = NULL; 1661 if (f->frame_desc_link || f->uncacheable || !f_is_cacheable(f) 1662 || !is_format_cache_entry_uptodate(f) || !f->ses) { 1663 destroy_formatted(f); 1664 } else { 1665 add_to_list(f->ses->format_cache, f); 1666 copy_additional_files(&fd->af); /* break structure sharing */ 1667 } 1668 } 1669 1670 int 1671 shrink_format_cache(int u) 1672 { 1673 static int sc = 0; 1674 int scc; 1675 int r = 0; 1676 int c = 0; 1677 struct session *ses = NULL; 1678 struct list_head *lses; 1679 foreach (struct session, ses, lses, sessions) { 1680 struct f_data *f = NULL; 1681 struct list_head *lf; 1682 foreach (struct f_data, f, lf, ses->format_cache) { 1683 if (u == SH_FREE_ALL 1684 || !is_format_cache_entry_uptodate(f)) { 1685 lf = lf->prev; 1686 del_from_list(f); 1687 destroy_formatted(f); 1688 r |= ST_SOMETHING_FREED; 1689 } else 1690 c++; 1691 } 1692 } 1693 if (c > max_format_cache_entries || (c && u == SH_FREE_SOMETHING)) { 1694 int sc_cycle = 0; 1695 unsigned char freed_in_cycle = 0; 1696 a: 1697 scc = sc++; 1698 foreach (struct session, ses, lses, sessions) 1699 if (!scc--) { 1700 if (!list_empty(ses->format_cache)) { 1701 struct f_data *ff = 1702 list_struct(ses->format_cache.prev, 1703 struct f_data); 1704 del_from_list(ff); 1705 destroy_formatted(ff); 1706 r |= ST_SOMETHING_FREED; 1707 if (--c <= max_format_cache_entries 1708 || u == SH_FREE_SOMETHING) 1709 goto ret; 1710 freed_in_cycle = 1; 1711 } 1712 goto a; 1713 } 1714 sc = 0; 1715 sc_cycle++; 1716 if (sc_cycle >= 2 && !freed_in_cycle) 1717 goto ret; 1718 freed_in_cycle = 0; 1719 goto a; 1720 } 1721 ret: 1722 return r | (!c ? ST_CACHE_EMPTY : 0); 1723 } 1724 1725 void 1726 init_fcache(void) 1727 { 1728 register_cache_upcall(shrink_format_cache, MF_GPI, cast_uchar "format"); 1729 } 1730 1731 static void 1732 calculate_scrollbars(struct f_data_c *fd, struct f_data *f) 1733 { 1734 fd->hsb = 0; 1735 fd->vsb = 0; 1736 fd->hsbsize = 0; 1737 fd->vsbsize = 0; 1738 if (!f) 1739 return; 1740 if (f->opt.scrolling == SCROLLING_YES) { 1741 fd->hsb = 1; 1742 fd->vsb = 1; 1743 } else if (f->opt.scrolling == SCROLLING_AUTO) { 1744 x: 1745 if (!fd->hsb && f->x > fd->xw - fd->vsb * G_SCROLL_BAR_WIDTH) { 1746 fd->hsb = 1; 1747 goto x; 1748 } 1749 if (!fd->vsb && f->y > fd->yw - fd->hsb * G_SCROLL_BAR_WIDTH) { 1750 fd->vsb = 1; 1751 goto x; 1752 } 1753 } 1754 if (fd->hsb) 1755 fd->hsbsize = fd->xw - fd->vsb * G_SCROLL_BAR_WIDTH; 1756 if (fd->vsb) 1757 fd->vsbsize = fd->yw - fd->hsb * G_SCROLL_BAR_WIDTH; 1758 if (fd->hsbsize < 0) 1759 fd->hsb = 0; 1760 if (fd->vsbsize < 0) 1761 fd->vsb = 0; 1762 } 1763 1764 struct f_data * 1765 cached_format_html(struct f_data_c *fd, struct object_request *rq, 1766 unsigned char *url, struct document_options *opt, int *cch, 1767 int report_status) 1768 { 1769 struct session *ses = fd->ses; 1770 struct f_data *f = NULL; 1771 struct list_head *lf; 1772 if (fd->marginwidth != -1) { 1773 int marg = 1774 (fd->marginwidth + G_HTML_MARGIN - 1) / G_HTML_MARGIN; 1775 if (marg >= 0 && marg < 9) 1776 opt->margin = marg; 1777 } 1778 if (opt->plain == 2) { 1779 opt->margin = 0; 1780 opt->display_images = 1; 1781 } 1782 pr(if (ses) { 1783 if (fd->f_data 1784 && !strcmp(cast_const_char fd->f_data->rq->url, 1785 cast_const_char url) 1786 && !compare_opt(&fd->f_data->opt, opt) 1787 && is_format_cache_entry_uptodate(fd->f_data)) { 1788 f = fd->f_data; 1789 goto ret_f; 1790 } 1791 foreach (struct f_data, f, lf, ses->format_cache) { 1792 if (!strcmp(cast_const_char f->rq->url, 1793 cast_const_char url) 1794 && !compare_opt(&f->opt, opt)) { 1795 if (!is_format_cache_entry_uptodate(f)) { 1796 lf = lf->prev; 1797 del_from_list(f); 1798 destroy_formatted(f); 1799 continue; 1800 } 1801 detach_f_data(&fd->f_data); 1802 del_from_list(f); 1803 f->fd = fd; 1804 if (cch) 1805 *cch = 1; 1806 f_data_attach(fd, f); 1807 goto ret_f; 1808 } 1809 } 1810 }){}; 1811 if (ses) { 1812 if (report_status || !fd->f_data 1813 || fd->f_data->time_to_get >= DISPLAY_FORMATTING_STATUS 1814 || (rq->ce && rq->ce->length >= 1000000)) 1815 print_progress(ses, TEXT_(T_FORMATTING_DOCUMENT)); 1816 } 1817 detach_f_data(&fd->f_data); 1818 f = format_html(fd, rq, url, opt, cch); 1819 if (f) 1820 f->fd = fd; 1821 shrink_memory(SH_CHECK_QUOTA); 1822 ret_f: 1823 calculate_scrollbars(fd, f); 1824 return f; 1825 } 1826 1827 static void 1828 create_new_frames(struct f_data_c *fd, struct frameset_desc *fs, 1829 struct document_options *o) 1830 { 1831 struct list_head *lloc; 1832 struct frame_desc *frm; 1833 int c_loc; 1834 int x, y; 1835 int xp, yp; 1836 1837 if (list_size(&fd->loc->subframes) != (unsigned long)fs->n) { 1838 while (!list_empty(fd->loc->subframes)) 1839 destroy_location(list_struct(fd->loc->subframes.next, 1840 struct location)); 1841 c_loc = 1; 1842 lloc = NULL; /* against warning */ 1843 } else { 1844 c_loc = 0; 1845 lloc = fd->loc->subframes.next; 1846 } 1847 1848 yp = fd->yp; 1849 frm = &fs->f[0]; 1850 for (y = 0; y < fs->y; y++) { 1851 xp = fd->xp; 1852 for (x = 0; x < fs->x; x++) { 1853 struct f_data_c *nfdc; 1854 struct location *loc; 1855 nfdc = create_f_data_c(fd->ses, fd); 1856 if (c_loc) { 1857 loc = new_location(); 1858 add_to_list_end(fd->loc->subframes, loc); 1859 loc->parent = fd->loc; 1860 loc->name = stracpy(frm->name); 1861 if ((loc->url = stracpy(frm->url))) 1862 nfdc->goto_position = 1863 extract_position(loc->url); 1864 } else { 1865 loc = list_struct(lloc, struct location); 1866 } 1867 nfdc->xp = xp; 1868 nfdc->yp = yp; 1869 nfdc->xw = frm->xw; 1870 nfdc->yw = frm->yw; 1871 nfdc->scrolling = frm->scrolling; 1872 nfdc->loc = loc; 1873 nfdc->vs = loc->vs; 1874 if (frm->marginwidth != -1) 1875 nfdc->marginwidth = frm->marginwidth; 1876 else 1877 nfdc->marginwidth = fd->marginwidth; 1878 if (frm->marginheight != -1) 1879 nfdc->marginheight = frm->marginheight; 1880 else 1881 nfdc->marginheight = fd->marginheight; 1882 add_to_list_end(fd->subframes, nfdc); 1883 if (frm->subframe) { 1884 create_new_frames(nfdc, frm->subframe, o); 1885 /*nfdc->f_data = 1886 * init_formatted(&fd->f_data->opt);*/ 1887 nfdc->f_data = init_formatted(o); 1888 nfdc->f_data->frame_desc = 1889 copy_frameset_desc(frm->subframe); 1890 nfdc->f_data->frame_desc_link = 1; 1891 } else { 1892 if (fd->depth < HTML_MAX_FRAME_DEPTH && loc->url 1893 && *loc->url) { 1894 struct f_data_c *rel = fd; 1895 while (rel->parent && !rel->rq) 1896 rel = rel->parent; 1897 request_object( 1898 fd->ses->term, loc->url, 1899 rel->rq ? rel->rq->url : NULL, 1900 PRI_FRAME, NC_CACHE, 1901 rel->rq 1902 ? get_allow_flags(rel->rq->url) 1903 : 0, 1904 fd_loaded, nfdc, &nfdc->rq); 1905 } 1906 } 1907 xp += frm->xw + 1; 1908 frm++; 1909 if (!c_loc) 1910 lloc = lloc->next; 1911 } 1912 yp += (frm - 1)->yw + 1; 1913 } 1914 } 1915 1916 static void 1917 html_interpret(struct f_data_c *fd, int report_status) 1918 { 1919 int i; 1920 int oxw; 1921 int oyw; 1922 int oxp; 1923 int oyp; 1924 struct f_data_c *sf = NULL; 1925 struct list_head *lsf; 1926 int cch; 1927 struct document_options o; 1928 if (!fd->loc) 1929 goto d; 1930 if (fd->f_data) { 1931 oxw = fd->f_data->opt.xw; 1932 oyw = fd->f_data->opt.yw; 1933 oxp = fd->f_data->opt.xp; 1934 oyp = fd->f_data->opt.yp; 1935 } else { 1936 oxw = oyw = oxp = oyp = -1; 1937 } 1938 memset(&o, 0, sizeof(struct document_options)); 1939 ds2do(&fd->ses->ds, &o, fd->ses->term->spec->col); 1940 if (!casecmp(fd->loc->url, cast_uchar "file://", 7) && !o.hard_assume) 1941 o.assume_cp = 0; 1942 if (fd->parent && fd->parent->f_data && !o.hard_assume) 1943 o.assume_cp = fd->parent->f_data->cp; 1944 o.gamma_stamp = 0; 1945 o.plain = fd->vs->plain; 1946 if (o.plain == 1 && !o.break_long_lines) { 1947 o.xp = 0; 1948 o.yp = 0; 1949 o.xw = INT_MAX; 1950 o.yw = INT_MAX; 1951 } else { 1952 o.xp = fd->xp; 1953 o.yp = fd->yp; 1954 o.xw = fd->xw; 1955 o.yw = fd->yw; 1956 } 1957 o.scrolling = fd->scrolling; 1958 if (fd->ses->term->spec) { 1959 if (!fd->ses->ds.t_ignore_document_color) 1960 o.col = fd->ses->term->spec->col; 1961 else 1962 o.col = 0; 1963 o.cp = 0; 1964 } else { 1965 o.col = 3; 1966 o.cp = 0; 1967 } 1968 if (!(o.framename = fd->loc->name)) 1969 o.framename = NULL; 1970 if (!(fd->f_data = cached_format_html(fd, fd->rq, fd->rq->url, &o, &cch, 1971 report_status))) { 1972 goto d; 1973 } 1974 1975 /* erase frames if changed */ 1976 i = (int)list_size(&fd->subframes); 1977 if (i != (fd->f_data->frame_desc ? fd->f_data->frame_desc->n : 0) 1978 && (f_is_finished(fd->f_data) || !f_need_reparse(fd->f_data))) { 1979 rd: 1980 foreach (struct f_data_c, sf, lsf, fd->subframes) 1981 reinit_f_data_c(sf); 1982 free_list(struct f_data_c, fd->subframes); 1983 1984 /* create new frames */ 1985 if (fd->f_data->frame_desc) 1986 create_new_frames(fd, fd->f_data->frame_desc, 1987 &fd->f_data->opt); 1988 } else { 1989 if (fd->f_data->frame_desc && fd->f_data->rq->state < 0) { 1990 if (fd->f_data->opt.xw != oxw 1991 || fd->f_data->opt.yw != oyw 1992 || fd->f_data->opt.xp != oxp 1993 || fd->f_data->opt.yp != oyp) 1994 goto rd; 1995 } 1996 } 1997 1998 d:; 1999 } 2000 2001 void 2002 html_interpret_recursive(struct f_data_c *f) 2003 { 2004 struct f_data_c *fd = NULL; 2005 struct list_head *lfd; 2006 if (f->rq) 2007 html_interpret(f, 1); 2008 foreach (struct f_data_c, fd, lfd, f->subframes) 2009 html_interpret_recursive(fd); 2010 } 2011 2012 /* You get a struct_additionl_file. never mem_free it. When you stop 2013 * using it, just forget the pointer. 2014 */ 2015 struct additional_file * 2016 request_additional_file(struct f_data *f, unsigned char *url_) 2017 { 2018 size_t sl; 2019 struct additional_file *af = NULL; 2020 struct list_head *laf; 2021 unsigned char *url; 2022 url = stracpy(url_); 2023 extract_position(url); 2024 if (!f->af) { 2025 if (!(f->af = f->fd->af)) { 2026 f->af = f->fd->af = 2027 xmalloc(sizeof(struct additional_files)); 2028 f->af->refcount = 1; 2029 init_list(f->af->af); 2030 } 2031 f->af->refcount++; 2032 } 2033 foreach (struct additional_file, af, laf, f->af->af) 2034 if (!strcmp(cast_const_char af->url, cast_const_char url)) { 2035 free(url); 2036 return af; 2037 } 2038 sl = strlen(cast_const_char url); 2039 if (sl > INT_MAX - sizeof(struct additional_file)) 2040 overalloc(); 2041 af = xmalloc(sizeof(struct additional_file) + sl); 2042 af->use_tag = 0; 2043 af->use_tag2 = 0; 2044 strcpy(cast_char af->url, cast_const_char url); 2045 if (!strcmp(cast_const_char url, cast_const_char f->rq->url)) 2046 clone_object(f->rq, &af->rq); 2047 else 2048 request_object(f->ses->term, url, f->rq->url, PRI_IMG, NC_CACHE, 2049 get_allow_flags(f->rq->url), f->rq->upcall, 2050 f->rq->data, &af->rq); 2051 af->need_reparse = 0; 2052 af->unknown_image_size = 0; 2053 add_to_list(f->af->af, af); 2054 free(url); 2055 return af; 2056 } 2057 2058 static void 2059 copy_additional_files(struct additional_files **a) 2060 { 2061 struct additional_files *afs; 2062 struct additional_file *af = NULL; 2063 struct list_head *laf; 2064 if (!*a || (*a)->refcount == 1) 2065 return; 2066 (*a)->refcount--; 2067 afs = xmalloc(sizeof(struct additional_files)); 2068 afs->refcount = 1; 2069 init_list(afs->af); 2070 foreachback (struct additional_file, af, laf, (*a)->af) { 2071 struct additional_file *afc; 2072 size_t sl = strlen(cast_const_char af->url); 2073 if (sl > INT_MAX - sizeof(struct additional_file)) 2074 overalloc(); 2075 afc = xmalloc(sizeof(struct additional_file) + sl); 2076 memcpy(afc, af, sizeof(struct additional_file) + sl); 2077 if (af->rq) 2078 clone_object(af->rq, &afc->rq); 2079 add_to_list(afs->af, afc); 2080 } 2081 *a = afs; 2082 } 2083 2084 void 2085 reinit_f_data_c(struct f_data_c *fd) 2086 { 2087 struct additional_file *af = NULL; 2088 struct list_head *laf; 2089 struct f_data_c *fd1 = NULL; 2090 struct list_head *lfd1; 2091 2092 foreach (struct f_data_c, fd1, lfd1, fd->subframes) { 2093 if (fd->ses->wtd_target_base == fd1) 2094 fd->ses->wtd_target_base = NULL; 2095 reinit_f_data_c(fd1); 2096 if (fd->ses->wtd_target_base == fd1) 2097 fd->ses->wtd_target_base = fd; 2098 } 2099 free_list(struct f_data_c, fd->subframes); 2100 fd->loc = NULL; 2101 if (fd->f_data && fd->f_data->rq) 2102 fd->f_data->rq->upcall = NULL; 2103 if (fd->f_data && fd->f_data->af) 2104 foreach (struct additional_file, af, laf, fd->f_data->af->af) 2105 if (af->rq) { 2106 af->rq->upcall = NULL; 2107 if (af->rq->state != O_OK) 2108 release_object(&af->rq); 2109 } 2110 if (fd->af) 2111 foreach (struct additional_file, af, laf, fd->af->af) 2112 if (af->rq) 2113 af->rq->upcall = NULL; 2114 free_additional_files(&fd->af); 2115 detach_f_data(&fd->f_data); 2116 release_object(&fd->rq); 2117 free(fd->link_bg); 2118 fd->link_bg = NULL; 2119 fd->link_bg_n = 0; 2120 free(fd->goto_position); 2121 fd->goto_position = NULL; 2122 free(fd->went_to_position); 2123 fd->went_to_position = NULL; 2124 fd->last_update = get_time(); 2125 fd->next_update_interval = 0; 2126 fd->done = 0; 2127 fd->parsed_done = 0; 2128 if (fd->image_timer != NULL) { 2129 kill_timer(fd->image_timer); 2130 fd->image_timer = NULL; 2131 } 2132 if (fd->refresh_timer != NULL) { 2133 kill_timer(fd->refresh_timer); 2134 fd->refresh_timer = NULL; 2135 } 2136 } 2137 2138 struct f_data_c * 2139 create_f_data_c(struct session *ses, struct f_data_c *parent) 2140 { 2141 struct f_data_c *fd; 2142 fd = mem_calloc(sizeof(struct f_data_c)); 2143 fd->parent = parent; 2144 fd->ses = ses; 2145 fd->depth = parent ? parent->depth + 1 : 1; 2146 init_list(fd->subframes); 2147 fd->last_update = get_time(); 2148 fd->next_update_interval = 0; 2149 fd->done = 0; 2150 fd->parsed_done = 0; 2151 fd->script_t = 0; 2152 fd->marginwidth = fd->marginheight = -1; 2153 fd->image_timer = NULL; 2154 fd->refresh_timer = NULL; 2155 fd->scrolling = SCROLLING_AUTO; 2156 return fd; 2157 } 2158 2159 int 2160 f_data_c_allow_flags(struct f_data_c *fd) 2161 { 2162 if (fd->rq) 2163 return get_allow_flags(fd->rq->url); 2164 return 0; 2165 } 2166 2167 static int 2168 is_forced_download(struct object_request *rq) 2169 { 2170 struct cache_entry *ce; 2171 unsigned char *cd; 2172 char *s; 2173 int ret = 0; 2174 2175 if (!rq || !(ce = rq->ce)) 2176 return ret; 2177 if ((cd = parse_http_header(ce->head, cast_uchar "Content-Disposition", 2178 NULL))) { 2179 if ((s = strchr(cast_const_char cd, ';'))) 2180 *s = 0; 2181 ret = !casestrcmp(cd, cast_uchar "attachment"); 2182 free(cd); 2183 } 2184 return ret; 2185 } 2186 2187 static int 2188 plain_type(struct object_request *rq, unsigned char **p) 2189 { 2190 struct cache_entry *ce; 2191 unsigned char *ct; 2192 int r = 0; 2193 if (p) 2194 *p = NULL; 2195 if (!rq || !(ce = rq->ce)) { 2196 r = 1; 2197 goto f; 2198 } 2199 if (!(ct = get_content_type(ce->head, ce->url))) 2200 goto f; 2201 if (is_html_type(ct)) 2202 goto ff; 2203 r = 1; 2204 if (!casestrcmp(ct, cast_uchar "text/plain") 2205 || !casestrcmp(ct, cast_uchar "file/txt")) 2206 goto ff; 2207 r = -1; 2208 2209 ff: 2210 if (!p) 2211 free(ct); 2212 else 2213 *p = ct; 2214 f: 2215 return r; 2216 } 2217 2218 static void 2219 refresh_timer(void *fd_) 2220 { 2221 struct f_data_c *fd = (struct f_data_c *)fd_; 2222 if (fd->ses->rq) { 2223 fd->refresh_timer = install_timer(500, refresh_timer, fd); 2224 return; 2225 } 2226 fd->refresh_timer = NULL; 2227 if (fd->f_data && fd->f_data->refresh) { 2228 fd->refresh_timer = install_timer( 2229 fd->f_data->refresh_seconds * 1000, refresh_timer, fd); 2230 goto_url_f(fd->ses, NULL, fd->f_data->refresh, 2231 cast_uchar "_self", fd, -1, 0, 0, 1); 2232 } 2233 } 2234 2235 void 2236 fd_loaded(struct object_request *rq, void *fd_) 2237 { 2238 struct f_data_c *fd = (struct f_data_c *)fd_; 2239 int first = !fd->f_data; 2240 if (fd->done) { 2241 if (f_is_finished(fd->f_data)) 2242 goto priint; 2243 else { 2244 fd->done = 0; 2245 fd->parsed_done = 1; 2246 } 2247 } 2248 if (fd->parsed_done && f_need_reparse(fd->f_data)) 2249 fd->parsed_done = 0; 2250 if (fd->vs->plain == -1 && rq->state != O_WAITING) { 2251 fd->vs->plain = plain_type(fd->rq, NULL); 2252 } 2253 if (fd->rq->state < 0 && (f_is_finished(fd->f_data) || !fd->f_data)) { 2254 if (!fd->parsed_done) { 2255 html_interpret(fd, 1); 2256 if (fd->went_to_position) { 2257 if (!fd->goto_position) { 2258 fd->goto_position = 2259 fd->went_to_position; 2260 fd->went_to_position = NULL; 2261 } else { 2262 free(fd->went_to_position); 2263 fd->went_to_position = NULL; 2264 } 2265 } 2266 } 2267 draw_fd(fd); 2268 /* it may happen that html_interpret requests load of additional 2269 * file */ 2270 if (!f_is_finished(fd->f_data)) 2271 goto more_data; 2272 fn: 2273 fd->done = 1; 2274 fd->parsed_done = 0; 2275 if (fd->f_data->refresh) { 2276 if (fd->refresh_timer != NULL) 2277 kill_timer(fd->refresh_timer); 2278 fd->refresh_timer = 2279 install_timer(fd->f_data->refresh_seconds * 1000, 2280 refresh_timer, fd); 2281 } 2282 } else if (get_time() - fd->last_update >= fd->next_update_interval 2283 || (rq == fd->rq && rq->state < 0)) { 2284 uttime t; 2285 if (!fd->parsed_done) { 2286 html_interpret(fd, rq == fd->rq && rq->state < 0); 2287 if (fd->rq->state < 0 && !f_need_reparse(fd->f_data)) { 2288 if (fd->went_to_position) { 2289 if (!fd->goto_position) { 2290 fd->goto_position = 2291 fd->went_to_position; 2292 fd->went_to_position = NULL; 2293 } else { 2294 free(fd->went_to_position); 2295 fd->went_to_position = NULL; 2296 } 2297 } 2298 fd->parsed_done = 1; 2299 } 2300 } 2301 draw_fd(fd); 2302 if (fd->rq->state < 0 && f_is_finished(fd->f_data)) 2303 goto fn; 2304 more_data: 2305 t = fd->f_data ? ((fd->parsed_done 2306 ? 0 2307 : fd->f_data->time_to_get * DISPLAY_TIME) 2308 + fd->f_data->time_to_draw * IMG_DISPLAY_TIME) 2309 : 0; 2310 if (t < DISPLAY_TIME_MIN) 2311 t = DISPLAY_TIME_MIN; 2312 if (first && t > DISPLAY_TIME_MAX_FIRST) 2313 t = DISPLAY_TIME_MAX_FIRST; 2314 fd->last_update = get_time(); 2315 fd->next_update_interval = t; 2316 } else { 2317 change_screen_status(fd->ses); 2318 print_screen_status(fd->ses); 2319 } 2320 priint: 2321 /* process onload handler of a frameset */ 2322 if (rq && (rq->state == O_FAILED || rq->state == O_INCOMPLETE) 2323 && (fd->rq == rq || fd->ses->rq == rq) && !rq->dont_print_error) 2324 print_error_dialog(fd->ses, &rq->stat, rq->url); 2325 } 2326 2327 static unsigned location_id = 0; 2328 2329 static struct location * 2330 new_location(void) 2331 { 2332 struct location *loc; 2333 loc = mem_calloc(sizeof(struct location)); 2334 loc->location_id = ++location_id; 2335 init_list(loc->subframes); 2336 loc->vs = create_vs(); 2337 return loc; 2338 } 2339 2340 static struct location * 2341 alloc_ses_location(struct session *ses) 2342 { 2343 struct location *loc; 2344 loc = new_location(); 2345 add_to_list(ses->history, loc); 2346 return loc; 2347 } 2348 2349 static void 2350 subst_location(struct f_data_c *fd, struct location *old, struct location *neww) 2351 { 2352 struct f_data_c *f = NULL; 2353 struct list_head *lf; 2354 foreach (struct f_data_c, f, lf, fd->subframes) 2355 subst_location(f, old, neww); 2356 if (fd->loc == old) 2357 fd->loc = neww; 2358 } 2359 2360 static struct location * 2361 copy_sublocations(struct session *ses, struct location *d, struct location *s, 2362 struct location *x) 2363 { 2364 struct location *sl = NULL, *y; 2365 struct list_head *lsl; 2366 d->name = stracpy(s->name); 2367 if (s == x) 2368 return d; 2369 d->url = stracpy(s->url); 2370 d->prev_url = stracpy(s->prev_url); 2371 destroy_vs(d->vs); 2372 d->vs = s->vs; 2373 s->vs->refcount++; 2374 subst_location(ses->screen, s, d); 2375 y = NULL; 2376 foreach (struct location, sl, lsl, s->subframes) { 2377 struct location *dl, *z; 2378 2379 dl = new_location(); 2380 add_to_list_end(d->subframes, dl); 2381 dl->parent = d; 2382 z = copy_sublocations(ses, dl, sl, x); 2383 if (z && y) 2384 internal("copy_sublocations: crossed references"); 2385 if (z) 2386 y = z; 2387 } 2388 return y; 2389 } 2390 2391 static struct location * 2392 copy_location(struct session *ses, struct location *loc) 2393 { 2394 struct location *l2, *l1, *nl; 2395 l1 = cur_loc(ses); 2396 l2 = alloc_ses_location(ses); 2397 if (!(nl = copy_sublocations(ses, l2, l1, loc))) 2398 internal("copy_location: sublocation not found"); 2399 return nl; 2400 } 2401 2402 static struct f_data_c * 2403 new_main_location(struct session *ses) 2404 { 2405 struct location *loc; 2406 loc = alloc_ses_location(ses); 2407 reinit_f_data_c(ses->screen); 2408 ses->screen->loc = loc; 2409 ses->screen->vs = loc->vs; 2410 if (ses->wanted_framename) { 2411 loc->name = ses->wanted_framename; 2412 ses->wanted_framename = NULL; 2413 } 2414 return ses->screen; 2415 } 2416 2417 static struct f_data_c * 2418 copy_location_and_replace_frame(struct session *ses, struct f_data_c *fd) 2419 { 2420 struct location *loc; 2421 loc = copy_location(ses, fd->loc); 2422 reinit_f_data_c(fd); 2423 fd->loc = loc; 2424 fd->vs = loc->vs; 2425 return fd; 2426 } 2427 2428 /* vrati frame prislusici danemu targetu 2429 pokud takovy frame nenajde, vraci NULL 2430 */ 2431 struct f_data_c * 2432 find_frame(struct session *ses, unsigned char *target, struct f_data_c *base) 2433 { 2434 struct f_data_c *f, *ff = NULL; 2435 struct list_head *lff; 2436 if (!base) 2437 base = ses->screen; 2438 if (!target || !*target) 2439 return base; 2440 if (!casestrcmp(target, cast_uchar "_blank")) 2441 return NULL; /* open in new window */ 2442 if (!casestrcmp(target, cast_uchar "_top")) 2443 return ses->screen; 2444 if (!casestrcmp(target, cast_uchar "_self")) 2445 return base; 2446 if (!casestrcmp(target, cast_uchar "_parent")) { 2447 for (ff = base->parent; ff && !ff->rq; ff = ff->parent) 2448 ; 2449 return ff ? ff : ses->screen; 2450 } 2451 f = ses->screen; 2452 if (f->loc && f->loc->name && !casestrcmp(f->loc->name, target)) 2453 return f; 2454 d: 2455 foreach (struct f_data_c, ff, lff, f->subframes) 2456 if (ff->loc && ff->loc->name 2457 && !casestrcmp(ff->loc->name, target)) 2458 return ff; 2459 if (!list_empty(f->subframes)) { 2460 f = list_struct(f->subframes.next, struct f_data_c); 2461 goto d; 2462 } 2463 u: 2464 if (!f->parent) 2465 return NULL; 2466 if (f->list_entry.next == &f->parent->subframes) { 2467 f = f->parent; 2468 goto u; 2469 } 2470 f = list_struct(f->list_entry.next, struct f_data_c); 2471 goto d; 2472 } 2473 2474 static void 2475 destroy_location(struct location *loc) 2476 { 2477 while (!list_empty(loc->subframes)) 2478 destroy_location( 2479 list_struct(loc->subframes.next, struct location)); 2480 del_from_list(loc); 2481 free(loc->name); 2482 free(loc->url); 2483 free(loc->prev_url); 2484 destroy_vs(loc->vs); 2485 free(loc); 2486 } 2487 2488 static void 2489 clear_forward_history(struct session *ses) 2490 { 2491 while (!list_empty(ses->forward_history)) 2492 destroy_location( 2493 list_struct(ses->forward_history.next, struct location)); 2494 } 2495 2496 static void 2497 ses_go_forward(struct session *ses, int plain, int refresh) 2498 { 2499 struct location *cl; 2500 struct f_data_c *fd; 2501 clear_forward_history(ses); 2502 free(ses->search_word); 2503 ses->search_word = NULL; 2504 free(ses->default_status); 2505 ses->default_status = NULL; /* smazeme default status, aby neopruzoval 2506 na jinych strankach */ 2507 if ((fd = find_frame(ses, ses->wtd_target, ses->wtd_target_base)) 2508 && fd != ses->screen) { 2509 cl = NULL; 2510 if (refresh && fd->loc 2511 && !strcmp(cast_const_char fd->loc->url, 2512 cast_const_char ses->rq->url)) 2513 cl = cur_loc(ses); 2514 fd = copy_location_and_replace_frame(ses, fd); 2515 if (cl) 2516 destroy_location(cl); 2517 } else 2518 fd = new_main_location(ses); 2519 fd->vs->plain = plain; 2520 ses->wtd = NULL; 2521 fd->rq = ses->rq; 2522 ses->rq = NULL; 2523 fd->goto_position = ses->goto_position; 2524 ses->goto_position = NULL; 2525 fd->loc->url = stracpy(fd->rq->url); 2526 fd->loc->prev_url = stracpy(fd->rq->prev_url); 2527 fd->rq->upcall = fd_loaded; 2528 fd->rq->data = fd; 2529 fd->rq->upcall(fd->rq, fd); 2530 if (!list_empty(ses->screen->subframes)) 2531 draw_formatted(ses); 2532 } 2533 2534 static void 2535 ses_go_backward(struct session *ses) 2536 { 2537 int n; 2538 struct location *loc; 2539 struct list_head *lloc; 2540 free(ses->search_word); 2541 ses->search_word = NULL; 2542 free(ses->default_status); 2543 ses->default_status = NULL; /* smazeme default status, aby neopruzoval 2544 na jinych strankach */ 2545 reinit_f_data_c(ses->screen); 2546 if (!ses->wtd_num_steps) 2547 internal("ses_go_backward: wtd_num_steps is zero"); 2548 if (ses->wtd_num_steps > 0) { 2549 n = ses->wtd_num_steps; 2550 foreach (struct location, loc, lloc, ses->history) { 2551 if (!n--) 2552 goto have_back_loc; 2553 } 2554 internal("ses_go_backward: session history disappeared"); 2555 return; 2556 have_back_loc: 2557 for (n = 0; n < ses->wtd_num_steps; n++) { 2558 loc = cur_loc(ses); 2559 del_from_list(loc); 2560 add_to_list(ses->forward_history, loc); 2561 } 2562 } else { 2563 n = ses->wtd_num_steps; 2564 foreach (struct location, loc, lloc, ses->forward_history) { 2565 if (!++n) 2566 goto have_fwd_loc; 2567 } 2568 internal( 2569 "ses_go_backward: session forward history disappeared"); 2570 return; 2571 have_fwd_loc: 2572 for (n = 0; n < -ses->wtd_num_steps; n++) { 2573 loc = list_struct(ses->forward_history.next, 2574 struct location); 2575 del_from_list(loc); 2576 add_to_list(ses->history, loc); 2577 } 2578 } 2579 ses->screen->loc = cur_loc(ses); 2580 ses->screen->vs = ses->screen->loc->vs; 2581 ses->wtd = NULL; 2582 ses->screen->rq = ses->rq; 2583 ses->rq = NULL; 2584 ses->screen->rq->upcall = fd_loaded; 2585 ses->screen->rq->data = ses->screen; 2586 ses->screen->rq->upcall(ses->screen->rq, ses->screen); 2587 } 2588 2589 static void 2590 tp_cancel(void *ses_) 2591 { 2592 struct session *ses = (struct session *)ses_; 2593 release_object(&ses->tq); 2594 } 2595 2596 static void 2597 continue_download(struct session *ses, unsigned char *file, int mode) 2598 { 2599 struct download *down; 2600 int h; 2601 int namecount = 0; 2602 unsigned char *url = ses->tq->url; 2603 unsigned char *xl_file; 2604 off_t last_pos = 0, file_shift = 0; 2605 2606 if (ses->tq_prog) { 2607 if (ses->tq_prog_flag_direct && ses->tq->state != O_OK 2608 && !strchr(cast_const_char url, POST_CHAR) 2609 && !check_shell_url(url)) { 2610 unsigned char *prog = subst_file(ses->tq_prog, url, 0); 2611 exec_on_terminal(ses->term, prog, cast_uchar "", 2612 !!ses->tq_prog_flag_block); 2613 free(prog); 2614 tp_cancel(ses); 2615 abort_background_connections(); 2616 return; 2617 } 2618 new_name: 2619 if (!(file = get_temp_name(url, ses->tq->ce ? ses->tq->ce->head 2620 : NULL))) { 2621 tp_cancel(ses); 2622 return; 2623 } 2624 if ((h = create_download_file(ses, ses->term->cwd, file, 2625 CDF_RESTRICT_PERMISSION | CDF_EXCL 2626 | CDF_NO_POPUP_ON_EEXIST, 2627 0)) 2628 < 0) { 2629 if (h == -2 && ses->tq_prog) { 2630 if (++namecount < DOWNLOAD_NAME_TRIES) { 2631 free(file); 2632 goto new_name; 2633 } 2634 msg_box( 2635 ses->term, NULL, TEXT_(T_DOWNLOAD_ERROR), 2636 AL_CENTER, 2637 TEXT_(T_COULD_NOT_CREATE_TEMPORARY_FILE), 2638 MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), 2639 msg_box_null, B_ENTER | B_ESC); 2640 } 2641 free(file); 2642 tp_cancel(ses); 2643 return; 2644 } 2645 xl_file = stracpy(file); 2646 } else { 2647 if (create_or_append_download_file(ses, ses->term->cwd, file, 2648 mode, &h, &xl_file, 2649 &last_pos, &file_shift)) { 2650 tp_cancel(ses); 2651 return; 2652 } 2653 } 2654 down = mem_calloc(sizeof(struct download)); 2655 down->url = stracpy(url); 2656 down->stat.end = download_data; 2657 down->stat.data = down; 2658 down->decompress = 0; 2659 down->last_pos = last_pos; 2660 down->file_shift = file_shift; 2661 down->cwd = stracpy(ses->term->cwd); 2662 down->orig_file = stracpy(file); 2663 down->file = xl_file; 2664 down->handle = h; 2665 down->ses = ses; 2666 down->remotetime = 0; 2667 if (ses->tq_prog) { 2668 down->prog = subst_file(ses->tq_prog, file, 1); 2669 free(file); 2670 free(ses->tq_prog); 2671 ses->tq_prog = NULL; 2672 } 2673 down->prog_flag_block = ses->tq_prog_flag_block; 2674 add_to_list(downloads, down); 2675 release_object_get_stat(&ses->tq, &down->stat, PRI_DOWNLOAD); 2676 display_download(ses->term, down, ses); 2677 } 2678 2679 static void 2680 tp_save(void *ses_) 2681 { 2682 struct session *ses = (struct session *)ses_; 2683 free(ses->tq_prog); 2684 ses->tq_prog = NULL; 2685 query_file(ses, ses->tq->url, ses->tq->ce ? ses->tq->ce->head : NULL, 2686 &continue_download, tp_cancel, DOWNLOAD_CONTINUE); 2687 } 2688 2689 static void 2690 tp_open(void *ses_) 2691 { 2692 struct session *ses = (struct session *)ses_; 2693 continue_download(ses, cast_uchar "", DOWNLOAD_DEFAULT); 2694 } 2695 2696 static int 2697 ses_abort_1st_state_loading(struct session *ses) 2698 { 2699 int r = !!ses->rq; 2700 release_object(&ses->rq); 2701 ses->wtd = NULL; 2702 free(ses->wtd_target); 2703 ses->wtd_target = NULL; 2704 ses->wtd_target_base = NULL; 2705 free(ses->goto_position); 2706 ses->goto_position = NULL; 2707 change_screen_status(ses); 2708 print_screen_status(ses); 2709 return r; 2710 } 2711 2712 static void 2713 tp_display(void *ses_) 2714 { 2715 int plain = 1; 2716 struct session *ses = (struct session *)ses_; 2717 if (plain_type(ses->tq, NULL) == 2) 2718 plain = 2; 2719 ses_abort_1st_state_loading(ses); 2720 ses->rq = ses->tq; 2721 ses->tq = NULL; 2722 ses_go_forward(ses, plain, 0); 2723 } 2724 2725 static int 2726 direct_download_possible(struct object_request *rq, struct assoc *a) 2727 { 2728 unsigned char *proto = get_protocol_name(rq->url); 2729 int ret = 0; 2730 if (!proto) 2731 return 0; 2732 if (a->accept_http && !casestrcmp(proto, cast_uchar "http")) 2733 ret = 1; 2734 if (a->accept_ftp && !casestrcmp(proto, cast_uchar "ftp")) 2735 ret = 1; 2736 free(proto); 2737 if (proxies.only_proxies) 2738 ret = 0; 2739 return ret; 2740 } 2741 2742 static int 2743 prog_sel_save(struct dialog_data *dlg, struct dialog_item_data *idata) 2744 { 2745 struct session *ses = (struct session *)dlg->dlg->udata2; 2746 2747 tp_save(ses); 2748 2749 cancel_dialog(dlg, idata); 2750 return 0; 2751 } 2752 2753 static int 2754 prog_sel_display(struct dialog_data *dlg, struct dialog_item_data *idata) 2755 { 2756 struct session *ses = (struct session *)dlg->dlg->udata2; 2757 2758 tp_display(ses); 2759 2760 cancel_dialog(dlg, idata); 2761 return 0; 2762 } 2763 2764 static int 2765 prog_sel_cancel(struct dialog_data *dlg, struct dialog_item_data *idata) 2766 { 2767 struct session *ses = (struct session *)dlg->dlg->udata2; 2768 2769 tp_cancel(ses); 2770 2771 cancel_dialog(dlg, idata); 2772 return 0; 2773 } 2774 2775 static int 2776 prog_sel_open(struct dialog_data *dlg, struct dialog_item_data *idata) 2777 { 2778 struct assoc *a = (struct assoc *)idata->item->udata; 2779 struct session *ses = (struct session *)dlg->dlg->udata2; 2780 2781 if (!a) 2782 internal("This should not happen.\n"); 2783 ses->tq_prog = stracpy(a->prog); 2784 ses->tq_prog_flag_block = a->block; 2785 ses->tq_prog_flag_direct = direct_download_possible(ses->tq, a); 2786 tp_open(ses); 2787 cancel_dialog(dlg, idata); 2788 return 0; 2789 } 2790 2791 static void 2792 type_query_multiple_programs(struct session *ses, unsigned char *ct, 2793 struct assoc *a, int n) 2794 { 2795 int i; 2796 struct dialog *d; 2797 struct memory_list *ml; 2798 unsigned char **text_array; 2799 2800 text_array = xmalloc(6 * sizeof(unsigned char *)); 2801 text_array[0] = TEXT_(T_CONTENT_TYPE_IS); 2802 text_array[1] = cast_uchar " "; 2803 text_array[2] = ct; 2804 text_array[3] = cast_uchar ".\n"; 2805 text_array[4] = 2806 !anonymous ? TEXT_(T_DO_YOU_WANT_TO_OPEN_SAVE_OR_DISPLAY_THIS_FILE) 2807 : TEXT_(T_DO_YOU_WANT_TO_OPEN_OR_DISPLAY_THIS_FILE); 2808 text_array[5] = NULL; 2809 2810 if ((unsigned)n 2811 > (INT_MAX - sizeof(struct dialog)) / sizeof(struct dialog_item) 2812 - 4) 2813 overalloc(); 2814 d = mem_calloc(sizeof(struct dialog) 2815 + (n + 2 + (!anonymous)) * sizeof(struct dialog_item)); 2816 d->title = TEXT_(T_WHAT_TO_DO); 2817 d->fn = msg_box_fn; 2818 d->udata = text_array; 2819 d->udata2 = ses; 2820 d->align = AL_CENTER; 2821 ml = getml(d, a, ct, text_array, NULL); 2822 2823 for (i = 0; i < n; i++) { 2824 unsigned char *bla = stracpy( 2825 get_text_translation(TEXT_(T_OPEN_WITH), ses->term)); 2826 add_to_strn(&bla, cast_uchar " "); 2827 add_to_strn(&bla, a[i].label); 2828 2829 d->items[i].type = D_BUTTON; 2830 d->items[i].fn = prog_sel_open; 2831 d->items[i].udata = a + i; 2832 d->items[i].text = bla; 2833 a[i].prog = stracpy(a[i].prog); 2834 add_to_ml(&ml, bla, a[i].prog, NULL); 2835 } 2836 if (!anonymous) { 2837 d->items[i].type = D_BUTTON; 2838 d->items[i].fn = prog_sel_save; 2839 d->items[i].text = TEXT_(T_SAVE); 2840 i++; 2841 } 2842 d->items[i].type = D_BUTTON; 2843 d->items[i].fn = prog_sel_display; 2844 d->items[i].text = TEXT_(T_DISPLAY); 2845 i++; 2846 d->items[i].type = D_BUTTON; 2847 d->items[i].fn = prog_sel_cancel; 2848 d->items[i].gid = B_ESC; 2849 d->items[i].text = TEXT_(T_CANCEL); 2850 i++; 2851 d->items[i].type = D_END; 2852 do_dialog(ses->term, d, ml); 2853 } 2854 2855 /* deallocates a */ 2856 static void 2857 type_query(struct session *ses, unsigned char *ct, struct assoc *a, int n) 2858 { 2859 unsigned char *m1; 2860 unsigned char *m2; 2861 if (!ct) 2862 ct = stracpy(cast_uchar "unknown"); 2863 free(ses->tq_prog); 2864 ses->tq_prog = NULL; 2865 2866 if (n > 1) { 2867 type_query_multiple_programs(ses, ct, a, n); 2868 return; 2869 } 2870 2871 if (a) { 2872 ses->tq_prog = stracpy(a[0].prog); 2873 ses->tq_prog_flag_block = a[0].block; 2874 ses->tq_prog_flag_direct = direct_download_possible(ses->tq, a); 2875 } 2876 if (a && !a[0].ask) { 2877 tp_open(ses); 2878 if (n) 2879 free(a); 2880 free(ct); 2881 return; 2882 } 2883 m1 = stracpy(ct); 2884 if (!a) { 2885 if (!anonymous) 2886 msg_box( 2887 ses->term, getml(m1, NULL), TEXT_(T_UNKNOWN_TYPE), 2888 AL_CENTER, TEXT_(T_CONTENT_TYPE_IS), cast_uchar " ", 2889 m1, cast_uchar ".\n", 2890 TEXT_(T_DO_YOU_WANT_TO_SAVE_OR_DISLPAY_THIS_FILE), 2891 MSG_BOX_END, (void *)ses, 3, TEXT_(T_SAVE), tp_save, 2892 B_ENTER, TEXT_(T_DISPLAY), tp_display, 0, 2893 TEXT_(T_CANCEL), tp_cancel, B_ESC); 2894 else 2895 msg_box( 2896 ses->term, getml(m1, NULL), TEXT_(T_UNKNOWN_TYPE), 2897 AL_CENTER, TEXT_(T_CONTENT_TYPE_IS), cast_uchar " ", 2898 m1, cast_uchar ".\n", 2899 TEXT_(T_DO_YOU_WANT_TO_SAVE_OR_DISLPAY_THIS_FILE), 2900 MSG_BOX_END, (void *)ses, 2, TEXT_(T_DISPLAY), 2901 tp_display, B_ENTER, TEXT_(T_CANCEL), tp_cancel, 2902 B_ESC); 2903 } else { 2904 m2 = stracpy(a[0].label ? a[0].label : (unsigned char *)""); 2905 if (!anonymous) 2906 msg_box( 2907 ses->term, getml(m1, m2, NULL), TEXT_(T_WHAT_TO_DO), 2908 AL_CENTER, TEXT_(T_CONTENT_TYPE_IS), cast_uchar " ", 2909 m1, cast_uchar ".\n", 2910 TEXT_(T_DO_YOU_WANT_TO_OPEN_FILE_WITH), 2911 cast_uchar " ", m2, cast_uchar ", ", 2912 TEXT_(T_SAVE_IT_OR_DISPLAY_IT), MSG_BOX_END, 2913 (void *)ses, 4, TEXT_(T_OPEN), tp_open, B_ENTER, 2914 TEXT_(T_SAVE), tp_save, 0, TEXT_(T_DISPLAY), 2915 tp_display, 0, TEXT_(T_CANCEL), tp_cancel, B_ESC); 2916 else 2917 msg_box(ses->term, getml(m1, m2, NULL), 2918 TEXT_(T_WHAT_TO_DO), AL_CENTER, 2919 TEXT_(T_CONTENT_TYPE_IS), cast_uchar " ", m1, 2920 cast_uchar ".\n", 2921 TEXT_(T_DO_YOU_WANT_TO_OPEN_FILE_WITH), 2922 cast_uchar " ", m2, cast_uchar ", ", 2923 TEXT_(T_SAVE_IT_OR_DISPLAY_IT), MSG_BOX_END, 2924 (void *)ses, 3, TEXT_(T_OPEN), tp_open, B_ENTER, 2925 TEXT_(T_DISPLAY), tp_display, 0, 2926 TEXT_(T_CANCEL), tp_cancel, B_ESC); 2927 } 2928 if (n) 2929 free(a); 2930 free(ct); 2931 } 2932 2933 static void 2934 ses_go_to_2nd_state(struct session *ses) 2935 { 2936 struct assoc *a; 2937 int n; 2938 unsigned char *ct = NULL; 2939 int r = plain_type(ses->rq, &ct); 2940 int force_download = is_forced_download(ses->rq); 2941 if (!force_download && (r == 0 || r == 1 || r == 2)) 2942 goto go; 2943 if (!(a = get_type_assoc(ses->term, ct, &n)) 2944 && strlen(cast_const_char ct) >= 4 2945 && !casecmp(ct, cast_uchar "text", 4) && !force_download) { 2946 r = 1; 2947 goto go; 2948 } 2949 if (ses->tq) { 2950 ses_abort_1st_state_loading(ses); 2951 free(a); 2952 free(ct); 2953 return; 2954 } 2955 (ses->tq = ses->rq)->upcall = NULL; 2956 ses->rq = NULL; 2957 ses_abort_1st_state_loading(ses); 2958 if (!a && ses->tq->ce && ses->tq->ce->head) { 2959 unsigned char *file = 2960 get_filename_from_header(ses->tq->ce->head); 2961 if (file) { 2962 unsigned char *new_ct = 2963 get_content_type_by_extension(file); 2964 free(file); 2965 if (new_ct) { 2966 a = get_type_assoc(ses->term, new_ct, &n); 2967 free(new_ct); 2968 } 2969 } 2970 } 2971 type_query(ses, ct, a, n); 2972 return; 2973 go: 2974 ses_go_forward(ses, r, ses->wtd_refresh); 2975 free(ct); 2976 } 2977 2978 static void 2979 ses_go_back_to_2nd_state(struct session *ses) 2980 { 2981 ses_go_backward(ses); 2982 } 2983 2984 static void 2985 ses_finished_1st_state(struct object_request *rq, void *ses_) 2986 { 2987 struct session *ses = (struct session *)ses_; 2988 if (rq->state != O_WAITING) { 2989 if (ses->wtd_refresh && ses->wtd_target_base 2990 && ses->wtd_target_base->refresh_timer != NULL) { 2991 kill_timer(ses->wtd_target_base->refresh_timer); 2992 ses->wtd_target_base->refresh_timer = NULL; 2993 } 2994 } 2995 switch (rq->state) { 2996 case O_WAITING: 2997 change_screen_status(ses); 2998 print_screen_status(ses); 2999 break; 3000 case O_FAILED: 3001 if (!rq->dont_print_error) 3002 print_error_dialog(ses, &rq->stat, rq->url); 3003 ses_abort_1st_state_loading(ses); 3004 break; 3005 case O_LOADING: 3006 case O_INCOMPLETE: 3007 case O_OK: 3008 if (!ses->goto_position && rq->goto_position) 3009 ses->goto_position = stracpy(rq->goto_position); 3010 ses->wtd(ses); 3011 break; 3012 } 3013 } 3014 3015 /* if from_goto_dialog is 1, set prev_url to NULL */ 3016 void 3017 goto_url_f(struct session *ses, void (*state2)(struct session *), 3018 unsigned char *url, unsigned char *target, struct f_data_c *df, 3019 int data, int defer, int from_goto_dialog, int refresh) 3020 { 3021 unsigned char *u, *pos; 3022 unsigned char *prev_url; 3023 void (*fn)(struct session *, unsigned char *); 3024 int reloadlevel, allow_flags; 3025 if (!state2) 3026 state2 = ses_go_to_2nd_state; 3027 if ((fn = get_external_protocol_function(url))) { 3028 if (proxies.only_proxies && url_bypasses_socks(url)) { 3029 msg_box(ses->term, NULL, TEXT_(T_ERROR), AL_CENTER, 3030 TEXT_(T_NO_PROXY), MSG_BOX_END, NULL, 1, 3031 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 3032 return; 3033 } 3034 fn(ses, url); 3035 return; 3036 } 3037 ses->reloadlevel = NC_CACHE; 3038 if (!(u = translate_url(url, ses->term->cwd))) { 3039 struct status stat = { init_list_1st(NULL) NULL, 3040 NULL, 3041 S_BAD_URL, 3042 PRI_CANCEL, 3043 0, 3044 NULL, 3045 NULL, 3046 NULL }; 3047 print_error_dialog(ses, &stat, url); 3048 return; 3049 } 3050 pos = extract_position(u); 3051 if (ses->wtd == state2 3052 && !strcmp(cast_const_char ses->rq->orig_url, cast_const_char u) 3053 && !xstrcmp(ses->wtd_target, target) 3054 && ses->wtd_target_base == df) { 3055 free(u); 3056 free(ses->goto_position); 3057 ses->goto_position = pos; 3058 return; 3059 } 3060 ses_abort_1st_state_loading(ses); 3061 ses->wtd = state2; 3062 ses->wtd_target = stracpy(target); 3063 ses->wtd_target_base = df; 3064 ses->wtd_refresh = refresh; 3065 free(ses->goto_position); 3066 ses->goto_position = pos; 3067 if (!from_goto_dialog && df && df->rq) 3068 prev_url = df->rq->url; 3069 else 3070 prev_url = NULL; /* previous page is empty - this probably never 3071 happens, but for sure */ 3072 if (refresh && ses->wtd == ses_go_to_2nd_state) { 3073 struct f_data_c *fr = 3074 find_frame(ses, ses->wtd_target, ses->wtd_target_base); 3075 if (fr && fr->loc) 3076 if (!strcmp(cast_const_char fr->loc->url, 3077 cast_const_char u)) 3078 ses->reloadlevel = NC_RELOAD; 3079 } 3080 reloadlevel = ses->reloadlevel; 3081 if (ses->wtd == ses_go_to_2nd_state && !from_goto_dialog && !refresh) { 3082 struct f_data_c *fd; 3083 fd = find_frame(ses, ses->wtd_target, ses->wtd_target_base); 3084 if (!fd) 3085 fd = ses->screen; 3086 if (fd && fd->rq 3087 && !strcmp(cast_const_char fd->rq->url, cast_const_char u)) 3088 reloadlevel = NC_ALWAYS_CACHE; 3089 } 3090 3091 if (from_goto_dialog) 3092 allow_flags = ALLOW_ALL; 3093 else if (df && df->rq) 3094 allow_flags = get_allow_flags(df->rq->url); 3095 else 3096 allow_flags = 0; 3097 3098 request_object(ses->term, u, prev_url, PRI_MAIN, reloadlevel, 3099 allow_flags, ses_finished_1st_state, ses, &ses->rq); 3100 free(u); 3101 } 3102 3103 /* this doesn't send referer */ 3104 void 3105 goto_url(void *ses_, unsigned char *url) 3106 { 3107 struct session *ses = (struct session *)ses_; 3108 unsigned char *u = stracpy(url); 3109 goto_url_utf8(ses, u); 3110 free(u); 3111 } 3112 3113 void 3114 goto_url_utf8(struct session *ses, unsigned char *url) 3115 { 3116 goto_url_f(ses, NULL, url, NULL, NULL, -1, 0, 1, 0); 3117 } 3118 3119 /* this one sends referer */ 3120 void 3121 goto_url_not_from_dialog(struct session *ses, unsigned char *url, 3122 struct f_data_c *df) 3123 { 3124 goto_url_f(ses, NULL, url, cast_uchar "_top", df, -1, 0, 0, 0); 3125 } 3126 3127 static void 3128 freeml_void(void *ml_) 3129 { 3130 freeml((struct memory_list *)ml_); 3131 } 3132 3133 static void 3134 ses_imgmap(struct session *ses) 3135 { 3136 unsigned char *start; 3137 size_t len; 3138 struct memory_list *ml; 3139 struct menu_item *menu; 3140 struct f_data_c *fd; 3141 if (ses->rq->state != O_OK && ses->rq->state != O_INCOMPLETE) 3142 return; 3143 if (!(fd = current_frame(ses)) || !fd->f_data) 3144 return; 3145 if (get_file(ses->rq, &start, &len)) 3146 return; 3147 if (len > INT_MAX) 3148 len = INT_MAX; 3149 d_opt = &fd->f_data->opt; 3150 if (get_image_map(ses->rq->ce->head, start, start + len, 3151 ses->goto_position, &menu, &ml, ses->imgmap_href_base, 3152 ses->imgmap_target_base, 0, ses->ds.assume_cp, 3153 ses->ds.hard_assume, 0)) { 3154 ses_abort_1st_state_loading(ses); 3155 return; 3156 } 3157 /*add_empty_window(ses->term, freeml_void, ml);*/ 3158 do_menu_selected(ses->term, menu, ses, 0, freeml_void, ml); 3159 ses_abort_1st_state_loading(ses); 3160 } 3161 3162 void 3163 goto_imgmap(struct session *ses, struct f_data_c *fd, unsigned char *url, 3164 unsigned char *href, unsigned char *target) 3165 { 3166 free(ses->imgmap_href_base); 3167 ses->imgmap_href_base = href; 3168 free(ses->imgmap_target_base); 3169 ses->imgmap_target_base = target; 3170 goto_url_f(ses, ses_imgmap, url, NULL, fd, -1, 0, 0, 0); 3171 } 3172 3173 void 3174 map_selected(struct terminal *term, void *ld_, void *ses_) 3175 { 3176 struct link_def *ld = (struct link_def *)ld_; 3177 struct session *ses = (struct session *)ses_; 3178 int x = 0; 3179 if (ld->onclick) { 3180 current_frame(ses); 3181 x = 1; 3182 } 3183 if (ld->link) 3184 goto_url_f(ses, NULL, ld->link, ld->target, current_frame(ses), 3185 -1, x, 0, 0); 3186 } 3187 3188 void 3189 go_back(struct session *ses, int num_steps) 3190 { 3191 struct location *loc = NULL; 3192 struct list_head *lloc; 3193 int n; 3194 if (!num_steps) 3195 return; 3196 ses->reloadlevel = NC_CACHE; 3197 if (ses_abort_1st_state_loading(ses)) { 3198 change_screen_status(ses); 3199 print_screen_status(ses); 3200 return; 3201 } 3202 n = num_steps; 3203 if (num_steps > 0) { 3204 foreach (struct location, loc, lloc, ses->history) { 3205 if (!n--) 3206 goto have_loc; 3207 } 3208 return; 3209 } else { 3210 foreach (struct location, loc, lloc, ses->forward_history) { 3211 if (!++n) 3212 goto have_loc; 3213 } 3214 return; 3215 } 3216 have_loc: 3217 ses->wtd = ses_go_back_to_2nd_state; 3218 ses->wtd_num_steps = num_steps; 3219 request_object(ses->term, loc->url, loc->prev_url, PRI_MAIN, 3220 NC_ALWAYS_CACHE, ALLOW_ALL, ses_finished_1st_state, ses, 3221 &ses->rq); 3222 } 3223 3224 static void 3225 reload_frame(struct f_data_c *fd, int no_cache) 3226 { 3227 unsigned char *u; 3228 if (!list_empty(fd->subframes)) { 3229 struct f_data_c *fdd = NULL; 3230 struct list_head *lfdd; 3231 foreach (struct f_data_c, fdd, lfdd, fd->subframes) { 3232 reload_frame(fdd, no_cache); 3233 } 3234 return; 3235 } 3236 if (!fd->rq) 3237 return; 3238 if (fd->f_data && !f_is_finished(fd->f_data)) 3239 return; 3240 u = stracpy(fd->rq->url); 3241 release_object(&fd->rq); 3242 if (fd->f_data) 3243 release_object(&fd->f_data->rq); 3244 request_object(fd->ses->term, u, NULL, PRI_MAIN, no_cache, ALLOW_ALL, 3245 fd_loaded, fd, &fd->rq); 3246 if (fd->f_data) 3247 clone_object(fd->rq, &fd->f_data->rq); 3248 fd->last_update = get_time(); 3249 fd->next_update_interval = 0; 3250 fd->done = 0; 3251 fd->parsed_done = 0; 3252 free(u); 3253 } 3254 3255 void 3256 reload(struct session *ses, int no_cache) 3257 { 3258 if (no_cache == -1) 3259 no_cache = ++ses->reloadlevel; 3260 else 3261 ses->reloadlevel = no_cache; 3262 reload_frame(ses->screen, no_cache); 3263 } 3264 3265 static void 3266 set_doc_view(struct session *ses) 3267 { 3268 ses->screen->xp = 0; 3269 ses->screen->yp = 1; 3270 ses->screen->xw = ses->term->x; 3271 if (ses->term->y < 2) 3272 ses->screen->yw = 0; 3273 else 3274 ses->screen->yw = ses->term->y - 2; 3275 } 3276 3277 static struct session * 3278 create_session(struct window *win) 3279 { 3280 static int session_id = 1; 3281 struct terminal *term = win->term; 3282 struct session *ses; 3283 ses = mem_calloc(sizeof(struct session)); 3284 init_list(ses->history); 3285 init_list(ses->forward_history); 3286 ses->term = term; 3287 ses->win = win; 3288 ses->id = session_id++; 3289 ses->screen = create_f_data_c(ses, NULL); 3290 ses->screen->xp = 0; 3291 ses->screen->xw = term->x; 3292 ses->screen->yp = 1; 3293 ses->screen->yw = term->y - 2; 3294 memcpy(&ses->ds, &dds, sizeof(struct document_setup)); 3295 init_list(ses->format_cache); 3296 add_to_list(sessions, ses); 3297 if (first_use) { 3298 first_use = 0; 3299 msg_box(term, NULL, TEXT_(T_WELCOME), AL_CENTER, 3300 TEXT_(T_WELCOME_TO_LINKS), cast_uchar "\n\n", 3301 TEXT_(T_BASIC_HELP), MSG_BOX_END, NULL, 1, TEXT_(T_OK), 3302 msg_box_null, B_ENTER | B_ESC); 3303 } 3304 return ses; 3305 } 3306 3307 /*vyrobi retezec znaku, ktery se posilaj skrz unix domain socket hlavni instanci 3308 prohlizece 3309 cp=cislo session odkud se ma kopirovat (kdyz se klikne na "open new window") 3310 url=url kam se ma jit (v pripade kliknuti na "open link in new window" nebo 3311 pusteni linksu z prikazove radky s url) framename=jmeno ramu, ktery se 3312 vytvori 3313 3314 vraci sekvenci bytu a delku 3315 */ 3316 void * 3317 create_session_info(int cp, unsigned char *url, unsigned char *framename, 3318 int *ll) 3319 { 3320 size_t sl = strlen(cast_const_char url); 3321 size_t sl1 = framename ? strlen(cast_const_char framename) : 0; 3322 int l = (int)sl; 3323 int l1 = (int)sl1; 3324 unsigned char *i; 3325 if (sl > INT_MAX || sl1 > INT_MAX) 3326 overalloc(); 3327 if (framename && !strcmp(cast_const_char framename, "_blank")) 3328 l1 = 0; 3329 3330 i = NULL; 3331 *ll = add_bytes_to_str(&i, 0, (unsigned char *)&cp, sizeof(int)); 3332 *ll = add_bytes_to_str(&i, *ll, (unsigned char *)&l, sizeof(int)); 3333 *ll = add_bytes_to_str(&i, *ll, (unsigned char *)&l1, sizeof(int)); 3334 *ll = add_bytes_to_str(&i, *ll, url, l); 3335 *ll = add_bytes_to_str(&i, *ll, framename, l1); 3336 return i; 3337 } 3338 3339 /* dostane data z create_session_info a nainicializuje podle nich session 3340 vraci -1 pokud jsou data vadna 3341 */ 3342 /* FIXME: this is a disaster */ 3343 static int 3344 read_session_info(struct session *ses, void *data, size_t len) 3345 { 3346 int cpfrom, sz, sz1; 3347 struct session *s = NULL; 3348 struct list_head *ls; 3349 if (len < 3 * sizeof(int)) 3350 return -1; 3351 cpfrom = *(int *)data; 3352 sz = *((int *)data + 1); 3353 sz1 = *((int *)data + 2); 3354 foreach (struct session, s, ls, sessions) 3355 if (s->id == cpfrom) { 3356 memcpy(&ses->ds, &s->ds, sizeof(struct document_setup)); 3357 if (!sz) { 3358 if (!list_empty(s->history)) { 3359 struct location *loc = list_struct( 3360 s->history.next, struct location); 3361 if (loc->url) 3362 goto_url_utf8(ses, loc->url); 3363 } 3364 return 0; 3365 } else 3366 break; 3367 } 3368 if (sz1) { 3369 unsigned char *tgt; 3370 if (len < 3 * sizeof(int) + sz + sz1) 3371 goto bla; 3372 if ((unsigned)sz1 >= INT_MAX) 3373 overalloc(); 3374 tgt = xmalloc(sz1 + 1); 3375 memcpy(tgt, (unsigned char *)((int *)data + 3) + sz, sz1); 3376 tgt[sz1] = 0; 3377 free(ses->wanted_framename); 3378 ses->wanted_framename = NULL; 3379 ses->wanted_framename = tgt; 3380 } 3381 bla: 3382 if (sz) { 3383 unsigned char *u, *uu; 3384 if (len < 3 * sizeof(int) + sz) 3385 return -1; 3386 if ((unsigned)sz >= INT_MAX) 3387 overalloc(); 3388 u = xmalloc(sz + 1); 3389 memcpy(u, (int *)data + 3, sz); 3390 u[sz] = 0; 3391 uu = decode_url(u); 3392 goto_url(ses, uu); 3393 free(u); 3394 free(uu); 3395 } 3396 return 0; 3397 } 3398 3399 void 3400 cleanup_session(struct session *ses) 3401 { 3402 struct download *d = NULL; 3403 struct list_head *ld; 3404 foreach (struct download, d, ld, downloads) 3405 if (d->ses == ses && d->prog) { 3406 ld = ld->prev; 3407 abort_download(d); 3408 } 3409 ses_abort_1st_state_loading(ses); 3410 reinit_f_data_c(ses->screen); 3411 ses->screen->vs = NULL; 3412 while (!list_empty(ses->format_cache)) { 3413 struct f_data *f = 3414 list_struct(ses->format_cache.next, struct f_data); 3415 del_from_list(f); 3416 destroy_formatted(f); 3417 } 3418 while (!list_empty(ses->history)) 3419 destroy_location( 3420 list_struct(ses->history.next, struct location)); 3421 clear_forward_history(ses); 3422 free(ses->default_status); 3423 free(ses->search_word); 3424 ses->default_status = NULL; 3425 ses->search_word = NULL; 3426 } 3427 3428 void 3429 destroy_session(struct session *ses) 3430 { 3431 cleanup_session(ses); 3432 free(ses->screen); 3433 free(ses->st); 3434 free(ses->st_old); 3435 ses->st = NULL; 3436 ses->st_old = NULL; 3437 free(ses->dn_url); 3438 free(ses->last_search_word); 3439 free(ses->imgmap_href_base); 3440 free(ses->imgmap_target_base); 3441 free(ses->wanted_framename); 3442 3443 release_object(&ses->tq); 3444 free(ses->tq_prog); 3445 3446 del_from_list(ses); 3447 } 3448 3449 static void 3450 move_session_to_front(struct session *ses) 3451 { 3452 if (sessions.next == &ses->list_entry) 3453 return; 3454 del_from_list(ses); 3455 add_to_list(sessions, ses); 3456 } 3457 3458 void 3459 win_func(struct window *win, struct links_event *ev, int fw) 3460 { 3461 struct session *ses = win->data; 3462 switch ((int)ev->ev) { 3463 case EV_ABORT: 3464 if (ses) 3465 destroy_session(ses); 3466 break; 3467 case EV_INIT: 3468 ses = win->data = create_session(win); 3469 if (read_session_info(ses, (char *)(ev->b + sizeof(int)), 3470 ev->b)) { 3471 register_bottom_half(destroy_terminal, win->term); 3472 return; 3473 } 3474 /*-fallthrough*/ 3475 case EV_RESIZE: 3476 move_session_to_front(ses); 3477 free(ses->st_old); 3478 ses->st_old = NULL; 3479 set_doc_view(ses); 3480 html_interpret_recursive(ses->screen); 3481 draw_fd(ses->screen); 3482 break; 3483 case EV_REDRAW: 3484 free(ses->st_old); 3485 ses->st_old = NULL; 3486 draw_formatted(ses); 3487 break; 3488 case EV_MOUSE: 3489 /*FALLTHROUGH*/ 3490 case EV_KBD: 3491 if (ev->ev == EV_KBD || (ev->b & BM_ACT) != B_MOVE 3492 || BM_IS_WHEEL(ev->b)) 3493 move_session_to_front(ses); 3494 send_event(ses, ev); 3495 break; 3496 case EV_EXTRA: 3497 if (ev->x == EV_EXTRA_OPEN_URL) 3498 goto_url(ses, (unsigned char *)ev->b); 3499 break; 3500 default: 3501 die("session.c win_func(): unknown event\n"); 3502 } 3503 } 3504 3505 /* 3506 Gets the url being viewed by this session. Writes it into str. 3507 A maximum of str_size bytes (including null) will be written. 3508 */ 3509 unsigned char * 3510 get_current_url(struct session *ses, unsigned char *str, size_t str_size) 3511 { 3512 unsigned char *here; 3513 size_t url_len = 0; 3514 3515 /* Not looking at anything */ 3516 if (list_empty(ses->history)) 3517 return NULL; 3518 3519 here = display_url(ses->term, cur_loc(ses)->url, 0); 3520 url_len = strlen(cast_const_char here); 3521 3522 /* Ensure that the url size is not greater than str_size */ 3523 if (url_len >= str_size) 3524 url_len = str_size - 1; 3525 3526 safe_strncpy(str, here, url_len + 1); 3527 3528 free(here); 3529 3530 return str; 3531 } 3532 3533 /* 3534 Gets the title of the page being viewed by this session. Writes it into str. 3535 A maximum of str_size bytes (including null) will be written. 3536 */ 3537 unsigned char * 3538 get_current_title(struct f_data_c *fd, unsigned char *str, size_t str_size) 3539 { 3540 /* Ensure that the title is defined */ 3541 if (!fd || !fd->f_data) 3542 return NULL; 3543 3544 safe_strncpy(str, fd->f_data->title, str_size); 3545 3546 return str; 3547 }