#include "links.h" struct list_head downloads = {&downloads, &downloads}; int are_there_downloads() { int d = 0; struct download *down; foreach(down, downloads) if (!down->prog) d = 1; return d; } struct list_head sessions = {&sessions, &sessions}; int session_id = 1; struct strerror_val { struct strerror_val *next; struct strerror_val *prev; unsigned char msg[1]; }; struct list_head strerror_buf = { &strerror_buf, &strerror_buf }; void free_strerror_buf() { free_list(strerror_buf); } unsigned char *get_err_msg(int state) { unsigned char *e; struct strerror_val *s; if (state <= S_OK || state >= S_WAIT) { int i; for (i = 0; msg_dsc[i].msg; i++) if (msg_dsc[i].n == state) return msg_dsc[i].msg; unk: return TEXT(T_UNKNOWN_ERROR); } if (!(e = strerror(-state)) || !*e) goto unk; foreach(s, strerror_buf) if (!strcmp(s->msg, e)) return s->msg; if (!(s = mem_alloc(sizeof(struct strerror_val) + strlen(e) + 1))) goto unk; strcpy(s->msg, e); add_to_list(strerror_buf, s); return s->msg; } void add_xnum_to_str(unsigned char **s, int *l, int n) { unsigned char suff = 0; int d = -1; if (n >= 1000000) suff = 'M', d = (n / 100000) % 10, n /= 1000000; else if (n >= 1000) suff = 'k', d = (n / 100) % 10, n /= 1000; add_num_to_str(s, l, n); if (n < 10 && d != -1) add_chr_to_str(s, l, '.'), add_num_to_str(s, l, d); add_chr_to_str(s, l, ' '); if (suff) add_chr_to_str(s, l, suff); add_chr_to_str(s, l, 'B'); } void add_time_to_str(unsigned char **s, int *l, ttime t) { unsigned char q[64]; t /= 1000; t &= 0xffffffff; if (t < 0) t = 0; if (t >= 86400) sprintf(q, "%dd ", (int)(t / 86400)), add_to_str(s, l, q); if (t >= 3600) t %= 86400, sprintf(q, "%d:%02d", (int)(t / 3600), (int)(t / 60 % 60)), add_to_str(s, l, q); else sprintf(q, "%d", (int)(t / 60)), add_to_str(s, l, q); sprintf(q, ":%02d", (int)(t % 60)), add_to_str(s, l, q); } unsigned char *get_stat_msg(struct status *stat, struct terminal *term) { if (stat->state == S_TRANS && stat->prg->elapsed / 100) { unsigned char *m = init_str(); int l = 0; add_to_str(&m, &l, _(TEXT(T_RECEIVED), term)); add_to_str(&m, &l, " "); add_xnum_to_str(&m, &l, stat->prg->pos); if (stat->prg->size >= 0) add_to_str(&m, &l, " "), add_to_str(&m, &l, _(TEXT(T_OF), term)), add_to_str(&m, &l, " "), add_xnum_to_str(&m, &l, stat->prg->size); add_to_str(&m, &l, ", "); if (stat->prg->elapsed >= CURRENT_SPD_AFTER * SPD_DISP_TIME) add_to_str(&m, &l, _(TEXT(T_AVG), term)), add_to_str(&m, &l, " "); add_xnum_to_str(&m, &l, (longlong)stat->prg->loaded * 10 / (stat->prg->elapsed / 100)); add_to_str(&m, &l, "/s"); if (stat->prg->elapsed >= CURRENT_SPD_AFTER * SPD_DISP_TIME) add_to_str(&m, &l, ", "), add_to_str(&m, &l, _(TEXT(T_CUR), term)), add_to_str(&m, &l, " "), add_xnum_to_str(&m, &l, stat->prg->cur_loaded / (CURRENT_SPD_SEC * SPD_DISP_TIME / 1000)), add_to_str(&m, &l, "/s"); return m; } return stracpy(_(get_err_msg(stat->state), term)); } void print_screen_status(struct session *ses) { struct terminal *term = ses->term; struct status *stat = NULL; unsigned char *m; fill_area(term, 0, 0, term->x, 1, COLOR_TITLE_BG); fill_area(term, 0, term->y - 1, term->x, 1, COLOR_STATUS_BG); if (ses->wtd) stat = &ses->loading; else if (!list_empty(ses->history)) stat = &cur_loc(ses)->stat; if (stat && stat->state == S_OK) { struct file_to_load *ftl; foreach(ftl, ses->more_files) { if (ftl->req_sent && ftl->stat.state >= 0) { stat = &ftl->stat; break; } } } if (stat) { if (stat->state == S_OK) if ((m = print_current_link(ses))) goto p; if ((m = get_stat_msg(stat, term))) { p: print_text(term, 0, term->y - 1, strlen(m), m, COLOR_STATUS); mem_free(m); } if ((m = print_current_title(ses))) { int p = term->x - 1 - strlen(m); if (p < 0) p = 0; print_text(term, p, 0, strlen(m), m, COLOR_TITLE); /*set_window_title(0,m);*/ /*set_terminal_title(term, m);*/ mem_free(m); } if ((m = stracpy("Links"))) { if (ses->screen && ses->screen->f_data && ses->screen->f_data->title && ses->screen->f_data->title[0]) add_to_strn(&m, " - "), add_to_strn(&m, ses->screen->f_data->title); set_terminal_title(term, m); mem_free(m); } } redraw_from_window(ses->win); } void print_error_dialog(struct session *ses, struct status *stat, unsigned char *title) { unsigned char *t = get_err_msg(stat->state); if (!t) return; msg_box(ses->term, NULL, title, AL_CENTER, t, ses, 1, TEXT(T_CANCEL), NULL, B_ENTER | B_ESC/*, _("Retry"), NULL, 0 !!! FIXME: retry */); } void free_wtd(struct session *ses) { if (!ses->wtd) { internal("no WTD"); return; } if (ses->goto_position) mem_free(ses->goto_position), ses->goto_position = NULL; mem_free(ses->loading_url); ses->loading_url = NULL; ses->wtd = WTD_NO; } void abort_files_load(struct session *ses) { struct file_to_load *ftl; int q; do { q = 0; foreach(ftl, ses->more_files) { if (ftl->stat.state >= 0 && ftl->req_sent) { q = 1; change_connection(&ftl->stat, NULL, PRI_CANCEL); } } } while (q); } void free_files(struct session *ses) { struct file_to_load *ftl; abort_files_load(ses); foreach(ftl, ses->more_files) { if (ftl->ce) ftl->ce->refcount--; mem_free(ftl->url); } free_list(ses->more_files); } void destroy_location(struct location *loc) { struct frame *frame; del_from_list(loc); foreach(frame, loc->frames) { destroy_vs(&frame->vs); mem_free(frame->name); } free_list(loc->frames); destroy_vs(&loc->vs); mem_free(loc); } void ses_forward(struct session *ses) { struct location *l; int len; free_files(ses); if (!list_empty(ses->history)) { struct frame *frm; l = cur_loc(ses); foreach(frm, l->frames) frm->vs.f = NULL; l->vs.f = NULL; } if (ses->search_word) mem_free(ses->search_word), ses->search_word = NULL; x: len = strlen(ses->loading_url); if (!list_empty(ses->history) && len < strlen(cur_loc(ses)->vs.url)) len = strlen(cur_loc(ses)->vs.url); if (!(l = mem_alloc(sizeof(struct location) + len + 1))) return; memset(l, 0, sizeof(struct location)); memcpy(&l->stat, &ses->loading, sizeof(struct status)); if (ses->wtd_target && *ses->wtd_target) { struct frame *frm; if (list_empty(ses->history)) { internal("no history"); return; } copy_location(l, cur_loc(ses)); add_to_list(ses->history, l); frm = ses_change_frame_url(ses, ses->wtd_target, ses->loading_url); if (!frm) { destroy_location(l); ses->wtd_target = NULL; goto x; } destroy_vs(&frm->vs); init_vs(&frm->vs, ses->loading_url); if (ses->goto_position) { if (frm->vs.goto_position) mem_free(frm->vs.goto_position); frm->vs.goto_position = ses->goto_position; ses->goto_position = NULL; } /*request_additional_loading_file(ses, ses->loading_url, &ses->loading, PRI_FRAME);*/ } else { init_list(l->frames); init_vs(&l->vs, ses->loading_url); add_to_list(ses->history, l); if (ses->goto_position) { l->vs.goto_position = ses->goto_position; ses->goto_position = NULL; } } } void ses_imgmap(struct session *ses) { struct cache_entry *ce; struct fragment *fr; struct memory_list *ml; struct menu_item *menu; if (find_in_cache(ses->loading_url, &ce) || !ce) { internal("can't find cache entry"); return; } defrag_entry(ce); fr = ce->frag.next; if ((void *)fr == &ce->frag) return; if (get_image_map(ce->head, fr->data, fr->data + fr->length, ses->goto_position, &menu, &ml, ses->imgmap_href_base, ses->imgmap_target_base, ses->term->spec->charset, ses->ds.assume_cp, ses->ds.hard_assume)) return; add_empty_window(ses->term, (void (*)(void *))freeml, ml); do_menu(ses->term, menu, ses); } void map_selected(struct terminal *term, struct link_def *ld, struct session *ses) { goto_url_f(ses, ld->link, ld->target); } void ses_back(struct session *ses) { struct location *loc; free_files(ses); loc = ses->history.next; if (ses->search_word) mem_free(ses->search_word), ses->search_word = NULL; if ((void *)loc == &ses->history) return; destroy_location(loc); loc = ses->history.next; if ((void *)loc == &ses->history) return; if (!strcmp(loc->vs.url, ses->loading_url)) return; destroy_location(loc); ses_forward(ses); } void end_load(struct status *, struct session *); void doc_end_load(struct status *, struct session *); void file_end_load(struct status *, struct file_to_load *); void abort_loading(struct session *); void abort_preloading(struct session *); struct session *get_download_ses(struct download *down) { struct session *ses; foreach(ses, sessions) if (ses == down->ses) return ses; if (!list_empty(sessions)) return sessions.next; return NULL; } void abort_download(struct download *down) { if (down->win) delete_window(down->win); if (down->ask) delete_window(down->ask); if (down->stat.state >= 0) change_connection(&down->stat, NULL, PRI_CANCEL); mem_free(down->url); if (down->handle != -1) prealloc_truncate(down->handle, down->last_pos), close(down->handle); if (down->prog) { unlink(down->file); mem_free(down->prog); } mem_free(down->file); del_from_list(down); mem_free(down); } void kill_downloads_to_file(unsigned char *file) { struct download *down; foreach(down, downloads) if (!strcmp(down->file, file)) down = down->prev, abort_download(down->next); } void undisplay_download(struct download *down) { if (down->win) delete_window(down->win); } int dlg_abort_download(struct dialog_data *dlg, struct dialog_item_data *di) { register_bottom_half((void (*)(void *))abort_download, dlg->dlg->udata); return 0; } int dlg_undisplay_download(struct dialog_data *dlg, struct dialog_item_data *di) { register_bottom_half((void (*)(void *))undisplay_download, dlg->dlg->udata); return 0; } void download_abort_function(struct dialog_data *dlg) { struct download *down = dlg->dlg->udata; down->win = NULL; } void download_window_function(struct dialog_data *dlg) { struct download *down = dlg->dlg->udata; struct terminal *term = dlg->win->term; int max = 0, min = 0; int w, x, y; int t = 0; unsigned char *m, *u; struct status *stat = &down->stat; redraw_below_window(dlg->win); down->win = dlg->win; if (stat->state == S_TRANS && stat->prg->elapsed / 100) { int l = 0; m = init_str(); t = 1; add_to_str(&m, &l, _(TEXT(T_RECEIVED), term)); add_to_str(&m, &l, " "); add_xnum_to_str(&m, &l, stat->prg->pos); if (stat->prg->size >= 0) add_to_str(&m, &l, " "), add_to_str(&m, &l, _(TEXT(T_OF),term)), add_to_str(&m, &l, " "), add_xnum_to_str(&m, &l, stat->prg->size), add_to_str(&m, &l, " "); add_to_str(&m, &l, "\n"); if (stat->prg->elapsed >= CURRENT_SPD_AFTER * SPD_DISP_TIME) add_to_str(&m, &l, _(TEXT(T_AVERAGE_SPEED), term)); else add_to_str(&m, &l, _(TEXT(T_SPEED), term)); add_to_str(&m, &l, " "); add_xnum_to_str(&m, &l, (longlong)stat->prg->loaded * 10 / (stat->prg->elapsed / 100)); add_to_str(&m, &l, "/s"); if (stat->prg->elapsed >= CURRENT_SPD_AFTER * SPD_DISP_TIME) add_to_str(&m, &l, ", "), add_to_str(&m, &l, _(TEXT(T_CURRENT_SPEED), term)), add_to_str(&m, &l, " "), add_xnum_to_str(&m, &l, stat->prg->cur_loaded / (CURRENT_SPD_SEC * SPD_DISP_TIME / 1000)), add_to_str(&m, &l, "/s"); add_to_str(&m, &l, "\n"); add_to_str(&m, &l, _(TEXT(T_ELAPSED_TIME), term)); add_to_str(&m, &l, " "); add_time_to_str(&m, &l, stat->prg->elapsed); if (stat->prg->size >= 0 && stat->prg->loaded > 0) { add_to_str(&m, &l, ", "); add_to_str(&m, &l, _(TEXT(T_ESTIMATED_TIME), term)); add_to_str(&m, &l, " "); /*add_time_to_str(&m, &l, stat->prg->elapsed / 1000 * stat->prg->size / stat->prg->loaded * 1000 - stat->prg->elapsed);*/ add_time_to_str(&m, &l, (stat->prg->size - stat->prg->pos) / ((longlong)stat->prg->loaded * 10 / (stat->prg->elapsed / 100)) * 1000); } } else m = stracpy(_(get_err_msg(stat->state), term)); if (!m) return; u = stracpy(down->url); if (strchr(u, POST_CHAR)) *strchr(u, POST_CHAR) = 0; max_text_width(term, u, &max); min_text_width(term, u, &min); max_text_width(term, m, &max); min_text_width(term, m, &min); max_buttons_width(term, dlg->items, dlg->n, &max); min_buttons_width(term, dlg->items, dlg->n, &min); w = dlg->win->term->x * 9 / 10 - 2 * DIALOG_LB; if (w < min) w = min; if (w > dlg->win->term->x - 2 * DIALOG_LB) w = dlg->win->term->x - 2 * DIALOG_LB; if (t && stat->prg->size >= 0) { if (w < DOWN_DLG_MIN) w = DOWN_DLG_MIN; } else { if (w > max) w = max; } if (w < 1) w = 1; y = 0; dlg_format_text(NULL, term, u, 0, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT); y++; if (t && stat->prg->size >= 0) y += 2; dlg_format_text(NULL, term, m, 0, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT); y++; dlg_format_buttons(NULL, term, dlg->items, dlg->n, 0, &y, w, NULL, AL_CENTER); dlg->xw = w + 2 * DIALOG_LB; dlg->yw = y + 2 * DIALOG_TB; center_dlg(dlg); draw_dlg(dlg); y = dlg->y + DIALOG_TB + 1; x = dlg->x + DIALOG_LB; dlg_format_text(term, term, u, x, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT); if (t && stat->prg->size >= 0) { unsigned char q[64]; int p = w - 6; y++; set_only_char(term, x, y, '['); set_only_char(term, x + w - 5, y, ']'); fill_area(term, x + 1, y, (int)((longlong)p * (longlong)stat->prg->pos / (longlong)stat->prg->size), 1, COLOR_DIALOG_METER); sprintf(q, "%3d%%", (int)((longlong)100 * (longlong)stat->prg->pos / (longlong)stat->prg->size)); print_text(term, x + w - 4, y, strlen(q), q, COLOR_DIALOG_TEXT); y++; } y++; dlg_format_text(term, term, m, x, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT); y++; dlg_format_buttons(term, term, dlg->items, dlg->n, x, &y, w, NULL, AL_CENTER); mem_free(u); mem_free(m); } void display_download(struct terminal *term, struct download *down, struct session *ses) { struct dialog *dlg; struct download *dd; foreach(dd, downloads) if (dd == down) goto found; return; found: if (!(dlg = mem_alloc(sizeof(struct dialog) + 3 * sizeof(struct dialog_item)))) return; memset(dlg, 0, sizeof(struct dialog) + 3 * sizeof(struct dialog_item)); undisplay_download(down); down->ses = ses; dlg->title = TEXT(T_DOWNLOAD); dlg->fn = download_window_function; dlg->abort = download_abort_function; dlg->udata = down; dlg->align = AL_CENTER; dlg->items[0].type = D_BUTTON; dlg->items[0].gid = B_ENTER | B_ESC; dlg->items[0].fn = dlg_undisplay_download; dlg->items[0].text = TEXT(T_BACKGROUND); dlg->items[1].type = D_BUTTON; dlg->items[1].gid = 0; dlg->items[1].fn = dlg_abort_download; dlg->items[1].text = TEXT(T_ABORT); dlg->items[2].type = D_END; do_dialog(term, dlg, getml(dlg, NULL)); } time_t parse_http_date(const char *date) /* this functions is bad !!! */ { const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; time_t t = 0; /* Mon, 03 Jan 2000 21:29:33 GMT */ struct tm tm; if (!date || strlen(date) < 28) return 0; date += 5; tm.tm_mday = (date[0] - '0') * 10 + date[1] - '0'; date += 3; for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++) if (!strncmp(date, months[tm.tm_mon], 3)) break; date += 4; tm.tm_year = (date[0] - '0') * 1000 + (date[1] - '0') * 100 + (date[2] - '0') * 10 + date[3] - '0' - 1900; date += 5; tm.tm_hour = (date[0] - '0') * 10 + date[1] - '0'; date += 3; tm.tm_min = (date[0] - '0') * 10 + date[1] - '0'; date += 3; tm.tm_sec = (date[0] - '0') * 10 + date[1] - '0'; t = mktime(&tm); if (t == (time_t) - 1) return 0; else return t; } void download_data(struct status *stat, struct download *down) { struct cache_entry *ce; struct fragment *frag; if (stat->state >= S_WAIT && stat->state < S_TRANS) goto end_store; if (!(ce = stat->ce)) goto end_store; if (ce->last_modified) down->remotetime = parse_http_date(ce->last_modified); /* fprintf(stderr,"\nFEFE date %s\n",ce->last_modified); */ if (ce->redirect && down->redirect_cnt++ < MAX_REDIRECTS) { unsigned char *u, *p; if (stat->state >= 0) change_connection(&down->stat, NULL, PRI_CANCEL); u = stracpy(ce->redirect); if (!http_bugs.bug_302_redirect) if (!ce->redirect_get && (p = strchr(down->url, POST_CHAR))) add_to_strn(&u, p); mem_free(down->url); down->url = u; down->stat.state = S_WAIT_REDIR; if (down->win) { struct event ev = { EV_REDRAW, 0, 0, 0 }; ev.x = down->win->term->x; ev.y = down->win->term->y; down->win->handler(down->win, &ev, 0); } /*if (!strchr(down->url, POST_CHAR)) {*/ load_url(down->url, &down->stat, PRI_DOWNLOAD, NC_CACHE); return; /*} else { unsigned char *msg = init_str(); int l = 0; add_bytes_to_str(&msg, &l, down->url, (unsigned char *)strchr(down->url, POST_CHAR) - down->url); msg_box(get_download_ses(down)->term, getml(msg, NULL), TEXT(T_WARNING), AL_CENTER | AL_EXTD_TEXT, TEXT(T_DO_YOU_WANT_TO_FOLLOW_REDIRECT_AND_POST_FORM_DATA_TO_URL), "", msg, "?", NULL, down, 3, TEXT(T_YES), down_post_yes, B_ENTER, TEXT(T_NO), down_post_no, 0, TEXT(T_CANCEL), down_post_cancel, B_ESC); }*/ } foreach(frag, ce->frag) if (frag->offset <= down->last_pos && frag->offset + frag->length > down->last_pos) { int w; #ifdef HAVE_OPEN_PREALLOC if (!down->last_pos && (!down->stat.prg || down->stat.prg->size > 0)) { close(down->handle); down->handle = open_prealloc(down->file, O_CREAT|O_WRONLY|O_TRUNC, 0666, down->stat.prg ? down->stat.prg->size : ce->length); if (down->handle == -1) goto error; set_bin(down->handle); } #endif w = write(down->handle, frag->data + down->last_pos - frag->offset, frag->length - (down->last_pos - frag->offset)); if (w == -1) { #ifdef HAVE_OPEN_PREALLOC error: #endif detach_connection(stat, down->last_pos); if (!list_empty(sessions)) { unsigned char *msg = stracpy(down->file); unsigned char *emsg = stracpy(strerror(errno)); msg_box(get_download_ses(down)->term, getml(msg, emsg, NULL), TEXT(T_DOWNLOAD_ERROR), AL_CENTER | AL_EXTD_TEXT, TEXT(T_COULD_NOT_WRITE_TO_FILE), " ", msg, ": ", emsg, NULL, NULL, 1, TEXT(T_CANCEL), NULL, B_ENTER | B_ESC); } abort_download(down); return; } down->last_pos += w; } detach_connection(stat, down->last_pos); end_store:; if (stat->state < 0) { if (stat->state != S_OK) { unsigned char *t = get_err_msg(stat->state); if (t) { unsigned char *tt = stracpy(down->url); if (strchr(tt, POST_CHAR)) *strchr(tt, POST_CHAR) = 0; msg_box(get_download_ses(down)->term, getml(tt, NULL), TEXT(T_DOWNLOAD_ERROR), AL_CENTER | AL_EXTD_TEXT, TEXT(T_ERROR_DOWNLOADING), " ", tt, ":\n\n", t, NULL, get_download_ses(down), 1, TEXT(T_CANCEL), NULL, B_ENTER | B_ESC/*, TEXT(T_RETRY), NULL, 0 !!! FIXME: retry */); } } else { if (down->prog) { prealloc_truncate(down->handle, down->last_pos); close(down->handle), down->handle = -1; exec_on_terminal(get_download_ses(down)->term, down->prog, down->file, !!down->prog_flags); mem_free(down->prog), down->prog = NULL; } else if (down->remotetime && download_utime) { struct utimbuf foo; foo.actime = foo.modtime = down->remotetime; utime(down->file, &foo); } } abort_download(down); return; } if (down->win) { struct event ev = { EV_REDRAW, 0, 0, 0 }; ev.x = down->win->term->x; ev.y = down->win->term->y; down->win->handler(down->win, &ev, 0); } } int create_download_file(struct terminal *term, unsigned char *fi, int safe) { unsigned char *file = fi; unsigned char *wd; int h; int i; #ifdef NO_FILE_SECURITY int sf = 0; #else int sf = safe; #endif wd = get_cwd(); set_cwd(term->cwd); if (file[0] == '~' && dir_sep(file[1])) { unsigned char *h = getenv("HOME"); if (h) { int fl = 0; if ((file = init_str())) { add_to_str(&file, &fl, h); add_to_str(&file, &fl, fi + 1); } } } h = open(file, O_CREAT|O_WRONLY|O_TRUNC|(sf?O_EXCL:0), sf ? 0600 : 0666); if (wd) set_cwd(wd), mem_free(wd); if (h == -1) { unsigned char *msg = stracpy(file); unsigned char *msge = stracpy(strerror(errno)); msg_box(term, getml(msg, msge, NULL), TEXT(T_DOWNLOAD_ERROR), AL_CENTER | AL_EXTD_TEXT, TEXT(T_COULD_NOT_CREATE_FILE), " ", msg, ": ", msge, NULL, NULL, 1, TEXT(T_CANCEL), NULL, B_ENTER | B_ESC); if (file != fi) mem_free(file); return -1; } set_bin(h); if (safe) goto x; if (strlen(file) > MAX_STR_LEN) memcpy(download_dir, file, MAX_STR_LEN - 1), download_dir[MAX_STR_LEN - 1] = 0; else strcpy(download_dir, file); for (i = strlen(download_dir) - 1; i >= 0; i--) if (dir_sep(download_dir[i])) { download_dir[i + 1] = 0; goto x; } download_dir[0] = 0; x: if (file != fi) mem_free(file); return h; } unsigned char *get_temp_name(unsigned char *url) { int l, nl; unsigned char *name, *fn, *fnn, *fnnn, *s; unsigned char *nm = tempnam(NULL, "links"); if (!nm) return NULL; name = init_str(); nl = 0; add_to_str(&name, &nl, nm); free(nm); get_filename_from_url(url, &fn, &l); fnnn = NULL; for (fnn = fn; fnn < fn + l; fnn++) if (*fnn == '.') fnnn = fnn; if (fnnn && (s = memacpy(fnnn, l - (fnnn - fn)))) { check_shell_security(&s); add_to_str(&name, &nl, s); mem_free(s); } return name; } unsigned char *subst_file(unsigned char *prog, unsigned char *file) { unsigned char *n = init_str(); int l = 0; while (*prog) { int p; for (p = 0; prog[p] && prog[p] != '%'; p++) ; add_bytes_to_str(&n, &l, prog, p); prog += p; if (*prog == '%') { #if defined(HAVE_CYGWIN_CONV_TO_FULL_WIN32_PATH) #ifdef MAX_PATH unsigned char new_path[MAX_PATH]; #else unsigned char new_path[1024]; #endif cygwin_conv_to_full_win32_path(file, new_path); add_to_str(&n, &l, new_path); #else add_to_str(&n, &l, file); #endif prog++; } } return n; } void start_download(struct session *ses, unsigned char *file) { struct download *down; int h; unsigned char *url = ses->dn_url; if (!url) return; kill_downloads_to_file(file); if ((h = create_download_file(ses->term, file, 0)) == -1) return; if (!(down = mem_alloc(sizeof(struct download)))) return; memset(down, 0, sizeof(struct download)); down->url = stracpy(url); down->stat.end = (void (*)(struct status *, void *))download_data; down->stat.data = down; down->last_pos = 0; down->file = stracpy(file); down->handle = h; down->ses = ses; down->remotetime = 0; add_to_list(downloads, down); load_url(url, &down->stat, PRI_DOWNLOAD, NC_CACHE); display_download(ses->term, down, ses); } void tp_cancel(struct session *); void tp_free(struct session *); void continue_download(struct session *ses, unsigned char *file) { struct download *down; int h; unsigned char *url = ses->tq_url; if (!url) return; if (ses->tq_prog) { if (!(file = get_temp_name(url))) { tp_cancel(ses); return; } } kill_downloads_to_file(file); if ((h = create_download_file(ses->term, file, !!ses->tq_prog)) == -1) { tp_cancel(ses); if (ses->tq_prog) mem_free(file); return; } if (!(down = mem_alloc(sizeof(struct download)))) { tp_cancel(ses); if (ses->tq_prog) mem_free(file); return; } memset(down, 0, sizeof(struct download)); down->url = stracpy(url); down->stat.end = (void (*)(struct status *, void *))download_data; down->stat.data = down; down->last_pos = 0; down->file = stracpy(file); down->handle = h; down->ses = ses; if (ses->tq_prog) { down->prog = subst_file(ses->tq_prog, file); mem_free(file); mem_free(ses->tq_prog); ses->tq_prog = NULL; } down->prog_flags = ses->tq_prog_flags; add_to_list(downloads, down); change_connection(&ses->tq, &down->stat, PRI_DOWNLOAD); tp_free(ses); display_download(ses->term, down, ses); } void tp_free(struct session *ses) { ses->tq_ce->refcount--; mem_free(ses->tq_url); ses->tq_url = NULL; if (ses->tq_goto_position) mem_free(ses->tq_goto_position), ses->tq_goto_position = NULL; ses->tq_ce = NULL; } void tp_cancel(struct session *ses) { change_connection(&ses->tq, NULL, PRI_CANCEL); tp_free(ses); } void tp_save(struct session *ses) { if (ses->tq_prog) mem_free(ses->tq_prog), ses->tq_prog = NULL; query_file(ses, ses->tq_url, continue_download, tp_cancel); } void tp_open(struct session *ses) { continue_download(ses, ""); } void display_timer(struct session *); void tp_display(struct session *ses) /* !!! FIXME: frames */ { struct location *l; if (!(l = mem_alloc(sizeof(struct location) + strlen(ses->tq_url)))) return; memset(l, 0, sizeof(struct location)); init_list(l->frames); memcpy(&l->stat, &ses->tq, sizeof(struct status)); init_vs(&l->vs, ses->tq_url); if (ses->tq_goto_position) { l->vs.goto_position = ses->tq_goto_position; ses->tq_goto_position = NULL; } add_to_list(ses->history, l); cur_loc(ses)->stat.end = (void (*)(struct status *, void *))doc_end_load; cur_loc(ses)->stat.data = ses; if (ses->tq.state >= 0) change_connection(&ses->tq, &cur_loc(ses)->stat, PRI_MAIN); else cur_loc(ses)->stat.state = ses->tq.state; cur_loc(ses)->vs.plain = 1; display_timer(ses); tp_free(ses); } void type_query(struct session *ses, struct cache_entry *ce, unsigned char *ct, struct assoc *a) { unsigned char *m1; unsigned char *m2; if (ses->tq_prog) mem_free(ses->tq_prog), ses->tq_prog = NULL; if (a) ses->tq_prog = stracpy(a->prog), ses->tq_prog_flags = a->block; if (a && !a->ask) { tp_open(ses); return; } m1 = stracpy(ct); if (!a) { if (!anonymous) msg_box(ses->term, getml(m1, NULL), TEXT(T_UNKNOWN_TYPE), AL_CENTER | AL_EXTD_TEXT, TEXT(T_CONTEN_TYPE_IS), " ", m1, ".\n", TEXT(T_DO_YOU_WANT_TO_SAVE_OR_DISLPAY_THIS_FILE), NULL, ses, 3, TEXT(T_SAVE), tp_save, B_ENTER, TEXT(T_DISPLAY), tp_display, 0, TEXT(T_CANCEL), tp_cancel, B_ESC); else msg_box(ses->term, getml(m1, NULL), TEXT(T_UNKNOWN_TYPE), AL_CENTER | AL_EXTD_TEXT, TEXT(T_CONTEN_TYPE_IS), " ", m1, ".\n", TEXT(T_DO_YOU_WANT_TO_SAVE_OR_DISLPAY_THIS_FILE), NULL, ses, 2, TEXT(T_DISPLAY), tp_display, B_ENTER, TEXT(T_CANCEL), tp_cancel, B_ESC); } else { m2 = stracpy(a->label ? a->label : (unsigned char *)""); if (!anonymous) msg_box(ses->term, getml(m1, m2, NULL), TEXT(T_WHAT_TO_DO), AL_CENTER | AL_EXTD_TEXT, TEXT(T_CONTEN_TYPE_IS), " ", m1, ".\n", TEXT(T_DO_YOU_WANT_TO_OPEN_FILE_WITH), " ", m2, ", ", TEXT(T_SAVE_IT_OR_DISPLAY_IT), NULL, ses, 4, TEXT(T_OPEN), tp_open, B_ENTER, TEXT(T_SAVE), tp_save, 0, TEXT(T_DISPLAY), tp_display, 0, TEXT(T_CANCEL), tp_cancel, B_ESC); else msg_box(ses->term, getml(m1, m2, NULL), TEXT(T_WHAT_TO_DO), AL_CENTER | AL_EXTD_TEXT, TEXT(T_CONTEN_TYPE_IS), " ", m1, ".\n", TEXT(T_DO_YOU_WANT_TO_OPEN_FILE_WITH), " ", m2, ", ", TEXT(T_SAVE_IT_OR_DISPLAY_IT), NULL, ses, 3, TEXT(T_OPEN), tp_open, B_ENTER, TEXT(T_DISPLAY), tp_display, 0, TEXT(T_CANCEL), tp_cancel, B_ESC); } } int ses_chktype(struct session *ses, struct status **stat, struct cache_entry *ce) { struct assoc *a; unsigned char *ct; int r = 0; if (!(ct = get_content_type(ce->head, ce->url))) goto f; if (!strcasecmp(ct, "text/html")) goto ff; r = 1; if (!strcasecmp(ct, "text/plain")) goto ff; if (!(a = get_type_assoc(ses->term, ct)) && strlen(ct) >= 4 && !casecmp(ct, "text", 4)) goto ff; if (ses->tq_url) internal("type query to %s already in prgress", ses->tq_url); ses->tq_url = stracpy(ses->loading_url); change_connection(&ses->loading, *stat = &ses->tq, PRI_MAIN); (ses->tq_ce = ce)->refcount++; if (ses->tq_goto_position) mem_free(ses->tq_goto_position); ses->tq_goto_position = stracpy(ses->goto_position); type_query(ses, ce, ct, a); mem_free(ct); return 1; ff: mem_free(ct); f: if (ses->wtd_target && r) *ses->wtd_target = 0; ses_forward(ses); cur_loc(ses)->vs.plain = r; return 0; } struct wtd_data { struct session *ses; unsigned char *url; int pri; int cache; int wtd; unsigned char *target; unsigned char *pos; void (*fn)(struct status *, struct session *); }; void post_yes(struct wtd_data *w) { abort_preloading(w->ses); if (w->ses->goto_position) mem_free(w->ses->goto_position); w->ses->goto_position = stracpy(w->pos); w->ses->loading.end = (void (*)(struct status *, void *))w->fn; w->ses->loading.data = w->ses; w->ses->loading_url = stracpy(w->url); w->ses->wtd = w->wtd; w->ses->wtd_target = w->target; load_url(w->ses->loading_url, &w->ses->loading, w->pri, w->cache); } void post_no(struct wtd_data *w) { *strchr(w->url, POST_CHAR) = 0; post_yes(w); } void post_cancel(struct wtd_data *w) { reload(w->ses, NC_CACHE); } void ses_goto(struct session *ses, unsigned char *url, unsigned char *target, int pri, int cache, int wtd, unsigned char *pos, void (*fn)(struct status *, struct session *), int redir) { struct wtd_data *w; unsigned char *m1, *m2; struct cache_entry *e; if (!strchr(url, POST_CHAR) || (cache == NC_ALWAYS_CACHE && !find_in_cache(url, &e) && !e->incomplete) || !(w = mem_alloc(sizeof(struct wtd_data)))) { if (ses->goto_position) mem_free(ses->goto_position); ses->goto_position = pos; ses->loading.end = (void (*)(struct status *, void *))fn; ses->loading.data = ses; ses->loading_url = url; ses->wtd = wtd; ses->wtd_target = target; load_url(url, &ses->loading, pri, cache); return; } w->ses = ses; w->url = url; w->pri = pri; w->cache = cache; w->wtd = wtd; w->target = target; w->pos = pos; w->fn = fn; if (redir) m1 = TEXT(T_DO_YOU_WANT_TO_FOLLOW_REDIRECT_AND_POST_FORM_DATA_TO_URL); else if (wtd == WTD_FORWARD) m1 = TEXT(T_DO_YOU_WANT_TO_POST_FORM_DATA_TO_URL); else m1 = TEXT(T_DO_YOU_WANT_TO_REPOST_FORM_DATA_TO_URL); m2 = memacpy(url, (unsigned char *)strchr(url, POST_CHAR) - url); msg_box(ses->term, getml(m2, w, w->url, w->pos, NULL), TEXT(T_WARNING), AL_CENTER | AL_EXTD_TEXT, m1, " ", m2, "?", NULL, w, 3, TEXT(T_YES), post_yes, B_ENTER, TEXT(T_NO), post_no, 0, TEXT(T_CANCEL), post_cancel, B_ESC); } int do_move(struct session *ses, struct status **stat) { struct cache_entry *ce = NULL; if (!ses->loading_url) { internal("no ses->loading_url"); return 0; } if (!(ce = (*stat)->ce) || (ses->wtd == WTD_IMGMAP && (*stat)->state >= 0)) { return 0; } if (ce->redirect && ses->redirect_cnt++ < MAX_REDIRECTS) { unsigned char *u, *p, *gp; int w = ses->wtd; if (ses->wtd == WTD_BACK && (void *)cur_loc(ses)->next == &ses->history) goto b; if (!(u = join_urls(ses->loading_url, ce->redirect))) goto b; if (!http_bugs.bug_302_redirect) if (!ce->redirect_get && (p = strchr(ses->loading_url, POST_CHAR))) add_to_strn(&u, p); /* ^^^^ According to RFC2068 POST must not be redirected to GET, but some BUGGY message boards rely on it :-( */ gp = stracpy(ses->goto_position); abort_loading(ses); if (!list_empty(ses->history)) *stat = &cur_loc(ses)->stat; else *stat = NULL; if (w == WTD_FORWARD || w == WTD_IMGMAP) { ses_goto(ses, u, ses->wtd_target, PRI_MAIN, NC_CACHE, w, gp, end_load, 1); return 2; } if (gp) mem_free(gp); if (w == WTD_BACK) { ses_goto(ses, u, NULL, PRI_MAIN, NC_CACHE, WTD_RELOAD, NULL, end_load, 1); return 2; } if (w == WTD_RELOAD) { ses_goto(ses, u, NULL, PRI_MAIN, ses->reloadlevel, WTD_RELOAD, NULL, end_load, 1); return 2; } } else ses->redirect_cnt = 0; b: if (ses->display_timer != -1) kill_timer(ses->display_timer), ses->display_timer = -1; if (ses->wtd == WTD_FORWARD) { if (ses_chktype(ses, stat, ce)) { free_wtd(ses); reload(ses, NC_CACHE); return 2; } } if (ses->wtd == WTD_IMGMAP) ses_imgmap(ses); if (ses->wtd == WTD_BACK) ses_back(ses); if (ses->wtd == WTD_RELOAD) ses_back(ses), ses_forward(ses); if ((*stat)->state >= 0) change_connection(&ses->loading, *stat = &cur_loc(ses)->stat, PRI_MAIN); else cur_loc(ses)->stat.state = ses->loading.state; free_wtd(ses); return 1; } void request_frameset(struct session *, struct frameset_desc *); void request_frame(struct session *ses, unsigned char *name, unsigned char *uurl) { struct location *loc = cur_loc(ses); struct frame *frm; unsigned char *url, *pos; if (list_empty(ses->history)) { internal("request_frame: no location"); return; } foreach(frm, loc->frames) if (!strcasecmp(frm->name, name)) { url = stracpy(frm->vs.url); if (frm->vs.f && frm->vs.f->f_data && frm->vs.f->f_data->frame) { /*del_from_list(frm);*/ request_frameset(ses, frm->vs.f->f_data->frame_desc); /*destroy_vs(&frm->vs); mem_free(frm->name); mem_free(frm);*/ mem_free(url); return; } goto found; } url = stracpy(uurl); pos = extract_position(url); if (!(frm = mem_alloc(sizeof(struct frame) + strlen(url) + 1))) { mem_free(url); if (pos) mem_free(pos); return; } memset(frm, 0, sizeof(struct frame)); if (!(frm->name = stracpy(name))) { mem_free(frm); mem_free(url); if (pos) mem_free(pos); return; } init_vs(&frm->vs, url); if (pos) frm->vs.goto_position = pos; add_to_list(loc->frames, frm); found: if (*url) request_additional_file(ses, url, PRI_FRAME); mem_free(url); } void request_frameset(struct session *ses, struct frameset_desc *fd) { int i; static int depth = 0; if (++depth <= HTML_MAX_FRAME_DEPTH) { for (i = 0; i < fd->n; i++) { if (fd->f[i].subframe) request_frameset(ses, fd->f[i].subframe); else if (fd->f[i].name) request_frame(ses, fd->f[i].name, fd->f[i].url); } } depth--; } void load_frames(struct session *ses, struct f_data_c *fd) { struct f_data *ff = fd->f_data; if (!ff || !ff->frame) return; request_frameset(ses, ff->frame_desc); } void display_timer(struct session *ses) { ttime t = get_time(); html_interpret(ses); draw_formatted(ses); t = (get_time() - t) * DISPLAY_TIME; if (t < DISPLAY_TIME_MIN) t = DISPLAY_TIME_MIN; ses->display_timer = install_timer(t, (void (*)(void *))display_timer, ses); load_frames(ses, ses->screen); process_file_requests(ses); } struct list_head questions_queue = {&questions_queue, &questions_queue}; struct questions_entry { struct questions_entry *next; struct questions_entry *prev; void (*callback)(struct session *); }; void check_questions_queue(struct session *ses) { struct questions_entry *q; while (!list_empty(questions_queue)) { q = questions_queue.next; q->callback(ses); del_from_list(q); mem_free(q); } } void add_questions_entry(void *callback) { struct questions_entry *q; if (!(q = mem_alloc(sizeof(struct questions_entry)))) return; q->callback = callback; add_to_list(questions_queue, q); } void end_load(struct status *stat, struct session *ses) { int d; if (!ses->wtd) { internal("end_load: !ses->wtd"); return; } d = do_move(ses, &stat); if (!stat) return; if (d == 1) { stat->end = (void (*)(struct status *, void *))doc_end_load; display_timer(ses); } if (stat->state < 0) { if (d != 2 && ses->wtd) { free_wtd(ses); } if (d == 1) doc_end_load(stat, ses); } if (stat->state < 0 && stat->state != S_OK && d != 2) { print_error_dialog(ses, stat, TEXT(T_ERROR)); } if (stat->state == S_QUESTIONS) check_questions_queue(ses); print_screen_status(ses); } void doc_end_load(struct status *stat, struct session *ses) { if (stat->state < 0) { if (ses->display_timer != -1) kill_timer(ses->display_timer), ses->display_timer = -1; html_interpret(ses); draw_formatted(ses); load_frames(ses, ses->screen); process_file_requests(ses); if (stat->state != S_OK) print_error_dialog(ses, stat, TEXT(T_ERROR)); } else if (ses->display_timer == -1) display_timer(ses); if (stat->state == S_QUESTIONS) check_questions_queue(ses); print_screen_status(ses); } void file_end_load(struct status *stat, struct file_to_load *ftl) { if (ftl->stat.ce) { if (ftl->ce) ftl->ce->refcount--; (ftl->ce = ftl->stat.ce)->refcount++; } doc_end_load(stat, ftl->ses); } struct file_to_load *request_additional_file(struct session *ses, unsigned char *url, int pri) { struct file_to_load *ftl; foreach(ftl, ses->more_files) { if (!strcmp(ftl->url, url)) { if (ftl->pri > pri) { ftl->pri = pri; change_connection(&ftl->stat, &ftl->stat, pri); } return NULL; } } if (!(ftl = mem_alloc(sizeof(struct file_to_load)))) return NULL; if (!(ftl->url = stracpy(url))) { mem_free(ftl); return NULL; } ftl->stat.end = (void (*)(struct status *, void *))file_end_load; ftl->stat.data = ftl; ftl->req_sent = 0; ftl->pri = pri; ftl->ce = NULL; ftl->ses = ses; add_to_list(ses->more_files, ftl); return ftl; } struct file_to_load *request_additional_loading_file(struct session *ses, unsigned char *url, struct status *stat, int pri) { struct file_to_load *ftl; if (!(ftl = request_additional_file(ses, url, pri))) { change_connection(stat, NULL, PRI_CANCEL); return NULL; } ftl->req_sent = 1; ftl->ce = stat->ce; change_connection(stat, &ftl->stat, pri); return ftl; } void process_file_requests(struct session *ses) { static int stop_recursion = 0; struct file_to_load *ftl; int more; if (stop_recursion) return; stop_recursion = 1; do { more = 0; foreach(ftl, ses->more_files) if (!ftl->req_sent) { ftl->req_sent = 1; load_url(ftl->url, &ftl->stat, ftl->pri, NC_CACHE); more = 1; } } while (more); stop_recursion = 0; } struct session *create_session(struct window *win) { struct terminal *term = win->term; struct session *ses; if ((ses = mem_alloc(sizeof(struct session)))) { memset(ses, 0, sizeof(struct session)); init_list(ses->history); init_list(ses->scrn_frames); init_list(ses->more_files); ses->term = term; ses->win = win; ses->id = session_id++; ses->screen = NULL; ses->wtd = WTD_NO; ses->display_timer = -1; ses->loading_url = NULL; ses->goto_position = NULL; memcpy(&ses->ds, &dds, sizeof(struct document_setup)); add_to_list(sessions, ses); } if (first_use) { first_use = 0; msg_box(term, NULL, TEXT(T_WELCOME), AL_CENTER | AL_EXTD_TEXT, TEXT(T_WELCOME_TO_LINKS), "\n\n", TEXT(T_BASIC_HELP), NULL, NULL, 1, TEXT(T_OK), NULL, B_ENTER | B_ESC); } return ses; } void copy_session(struct session *old, struct session *new) { /*struct location *l; foreachback(l, old->history) { struct location *nl; if ((nl = mem_alloc(sizeof(struct location) + strlen(l->vs.url) + 1))) { struct frame *frm; memcpy(nl, l, sizeof(struct location) + strlen(l->vs.url) + 1); init_list(nl->frames); foreachback(frm, l->frames) { struct frame *nfrm; if ((nfrm = mem_alloc(sizeof(struct frame) + strlen(frm->vs.url) + 1))) { memcpy(nfrm, frm, sizeof(struct frame) + strlen(frm->vs.url) + 1); add_to_list(nl->frames, nfrm); } } add_to_list(new->history, nl); } }*/ if (!list_empty(old->history)) { goto_url(new, cur_loc(old)->vs.url); } } void *create_session_info(int cp, unsigned char *url, int *ll) { int l = strlen(url); int *i; *ll = 2 * sizeof(int) + l; if (!(i = mem_alloc(2 * sizeof(int) + l))) return NULL; i[0] = cp; i[1] = l; memcpy(i + 2, url, l); return i; } static inline unsigned char hx(int a) { return a >= 10 ? a + 'A' - 10 : a + '0'; } static inline int unhx(unsigned char a) { if (a >= '0' && a <= '9') return a - '0'; if (a >= 'A' && a <= 'F') return a - 'A' + 10; if (a >= 'a' && a <= 'f') return a - 'a' + 10; return -1; } unsigned char *encode_url(unsigned char *url) { unsigned char *u = init_str(); int l = 0; for (; *url; url++) { if (is_safe_in_shell(*url) && *url != '+') add_chr_to_str(&u, &l, *url); else add_chr_to_str(&u, &l, '+'), add_chr_to_str(&u, &l, hx(*url >> 4)), add_chr_to_str(&u, &l, hx(*url & 0xf)); } return u; } unsigned char *decode_url(unsigned char *url) { unsigned char *u = init_str(); int l = 0; for (; *url; url++) { if (*url != '+' || unhx(url[1]) == -1 || unhx(url[2]) == -1) add_chr_to_str(&u, &l, *url); else add_chr_to_str(&u, &l, (unhx(url[1]) << 4) + unhx(url[2])), url += 2; } return u; } int read_session_info(int fd, struct session *ses, void *data, int len) { unsigned char *h; int cpfrom, sz; struct session *s; if (len < 2 * sizeof(int)) return -1; cpfrom = *(int *)data; sz = *((int *)data + 1); foreach(s, sessions) if (s->id == cpfrom) { copy_session(s, ses); break; } if (sz) { char *u, *uu; if (len < 2 * sizeof(int) + sz) return 0; if ((u = mem_alloc(sz + 1))) { memcpy(u, (int *)data + 2, sz); u[sz] = 0; uu = decode_url(u); goto_url(ses, uu); mem_free(u); mem_free(uu); } } else if ((h = getenv("WWW_HOME")) && *h) goto_url(ses, h); return 0; } void abort_preloading(struct session *ses) { if (ses->wtd) { change_connection(&ses->loading, NULL, PRI_CANCEL); free_wtd(ses); } } void abort_loading(struct session *ses) { struct location *l = cur_loc(ses); if ((void *)l != &ses->history) { if (l->stat.state >= 0) change_connection(&l->stat, NULL, PRI_CANCEL); abort_files_load(ses); } abort_preloading(ses); } void destroy_session(struct session *ses) { struct f_data_c *fdc; struct download *d; struct location *l; if (!ses) return; foreach(d, downloads) if (d->ses == ses && d->prog) { d = d->prev; abort_download(d->next); } abort_loading(ses); free_files(ses); if (ses->screen) detach_formatted(ses->screen), mem_free(ses->screen); foreach(fdc, ses->scrn_frames) detach_formatted(fdc); free_list(ses->scrn_frames); while ((void *)(l = ses->history.next) != &ses->history) { struct frame *frm; while ((void *)(frm = l->frames.next) != &l->frames) { destroy_vs(&frm->vs); mem_free(frm->name); del_from_list(frm); mem_free(frm); } destroy_vs(&l->vs); del_from_list(l); mem_free(l); } if (ses->loading_url) mem_free(ses->loading_url); if (ses->display_timer != -1) kill_timer(ses->display_timer); if (ses->goto_position) mem_free(ses->goto_position); if (ses->imgmap_href_base) mem_free(ses->imgmap_href_base); if (ses->imgmap_target_base) mem_free(ses->imgmap_target_base); if (ses->tq_ce) ses->tq_ce->refcount--; if (ses->tq_url) { change_connection(&ses->tq, NULL, PRI_CANCEL); mem_free(ses->tq_url); } if (ses->tq_goto_position) mem_free(ses->tq_goto_position); if (ses->tq_prog) mem_free(ses->tq_prog); if (ses->dn_url) mem_free(ses->dn_url); if (ses->search_word) mem_free(ses->search_word); if (ses->last_search_word) mem_free(ses->last_search_word); del_from_list(ses); /*mem_free(ses);*/ } void destroy_all_sessions() { /*while (!list_empty(sessions)) destroy_session(sessions.next);*/ } void abort_all_downloads() { while (!list_empty(downloads)) abort_download(downloads.next); } void reload(struct session *ses, int no_cache) { struct location *l; abort_loading(ses); if (no_cache == -1) no_cache = ++ses->reloadlevel; else ses->reloadlevel = no_cache; if ((void *)(l = ses->history.next) != &ses->history) { struct file_to_load *ftl; l->stat.data = ses; l->stat.end = (void *)doc_end_load; load_url(l->vs.url, &l->stat, PRI_MAIN, no_cache); foreach(ftl, ses->more_files) { if (ftl->req_sent && ftl->stat.state >= 0) continue; ftl->stat.data = ftl; ftl->stat.end = (void *)file_end_load; load_url(ftl->url, &ftl->stat, PRI_FRAME, no_cache); } } } /*void ses_load_notify(struct status *stat, struct session *ses) { if (stat->state == S_TRANS || stat->state == S_OK) { stat->end = (void (*)(struct status *, void *))end_load; ses->wtd = WTD_NO; mem_free(ses->loading_url); if (ses->wtd == WTD_FORWARD) { ses_forward(ses); } else internal("bad ses->wtd"); return; } if (stat->state >= 0) print_screen_status(ses); if (stat->state < 0) print_error_dlg(ses, stat); }*/ void go_back(struct session *ses) { unsigned char *url; ses->reloadlevel = NC_CACHE; if (ses->wtd) { if (1 || ses->wtd != WTD_BACK) { abort_loading(ses); print_screen_status(ses); reload(ses, NC_CACHE); } return; } if (ses->history.next == &ses->history || ses->history.next == ses->history.prev) return; abort_loading(ses); if (!(url = stracpy(((struct location *)ses->history.next)->next->vs.url))) return; ses_goto(ses, url, NULL, PRI_MAIN, NC_ALWAYS_CACHE, WTD_BACK, NULL, end_load, 0); } void goto_url_w(struct session *ses, unsigned char *url, unsigned char *target, int wtd) { unsigned char *u; unsigned char *pos; void (*fn)(struct session *, unsigned char *); if ((fn = get_external_protocol_function(url))) { fn(ses, url); return; } ses->reloadlevel = NC_CACHE; /*struct location *l = ses->history.next;*/ if (!(u = translate_url(url, ses->term->cwd))) { struct status stat = { NULL, NULL, NULL, NULL, S_BAD_URL, PRI_CANCEL, 0, NULL, NULL }; print_error_dialog(ses, &stat, TEXT(T_ERROR)); return; } pos = extract_position(u); if (ses->wtd == wtd) { if (!strcmp(ses->loading_url, u)) { mem_free(u); if (ses->goto_position) mem_free(ses->goto_position); ses->goto_position = pos; return; } } abort_loading(ses); ses_goto(ses, u, target, PRI_MAIN, NC_CACHE, wtd, pos, end_load, 0); /*abort_loading(ses);*/ } void goto_url_f(struct session *ses, unsigned char *url, unsigned char *target) { goto_url_w(ses, url, target, WTD_FORWARD); } void goto_url(struct session *ses, unsigned char *url) { goto_url_w(ses, url, NULL, WTD_FORWARD); } void goto_imgmap(struct session *ses, unsigned char *url, unsigned char *href, unsigned char *target) { if (ses->imgmap_href_base) mem_free(ses->imgmap_href_base); ses->imgmap_href_base = href; if (ses->imgmap_target_base) mem_free(ses->imgmap_target_base); ses->imgmap_target_base = target; goto_url_w(ses, url, target, WTD_IMGMAP); } struct frame *ses_find_frame(struct session *ses, unsigned char *name) { struct location *l = cur_loc(ses); struct frame *frm; if (list_empty(ses->history)) { internal("ses_request_frame: history empty"); return NULL; } foreachback(frm, l->frames) if (!strcasecmp(frm->name, name)) return frm; /*internal("ses_find_frame: frame not found");*/ return NULL; } struct frame *ses_change_frame_url(struct session *ses, unsigned char *name, unsigned char *url) { struct location *l = cur_loc(ses); struct frame *frm; if (list_empty(ses->history)) { internal("ses_change_frame_url: history empty"); return NULL; } foreachback(frm, l->frames) if (!strcasecmp(frm->name, name)) { if (strlen(url) > strlen(frm->vs.url)) { struct f_data_c *fd; struct frame *nf = frm; if (!(nf = mem_realloc(frm, sizeof(struct frame) + strlen(url) + 1))) return NULL; nf->prev->next = nf->next->prev = nf; foreach(fd, ses->scrn_frames) { if (fd->vs == &frm->vs) fd->vs = &nf->vs; } frm = nf; } strcpy(frm->vs.url, url); return frm; } return NULL; } void win_func(struct window *win, struct event *ev, int fw) { struct session *ses = win->data; switch (ev->ev) { case EV_ABORT: destroy_session(ses); break; case EV_INIT: if (!(ses = win->data = create_session(win)) || read_session_info(win->term->fdin, ses, (char *)ev->b + sizeof(int), *(int *)ev->b)) { destroy_terminal(win->term); return; } /*make_request(ses, 0);*/ case EV_RESIZE: html_interpret(ses); draw_formatted(ses); load_frames(ses, ses->screen); process_file_requests(ses); print_screen_status(ses); break; case EV_REDRAW: draw_formatted(ses); print_screen_status(ses); break; case EV_KBD: case EV_MOUSE: send_event(ses, ev); break; default: error("ERROR: unknown event"); } } /* Gets the url being viewed by this session. Writes it into str. A maximum of str_size bytes (including null) will be written. */ unsigned char *get_current_url(struct session *ses, unsigned char *str, size_t str_size) { unsigned char *here, *end_of_url; int l = 0; size_t url_len = 0; /* Not looking at anything */ if (list_empty(ses->history)) return NULL; here = cur_loc(ses)->vs.url; /* Find the length of the url */ if (end_of_url = strchr(here, POST_CHAR)) { url_len = (size_t)(end_of_url - (unsigned char *)here); } else { url_len = strlen(here); } /* Ensure that the url size is not greater than str_size */ if (url_len >= str_size) url_len = str_size - 1; strncpy(str, here, url_len); /* Ensure null termination */ str[url_len] = '\0'; return str; } /* Gets the title of the page being viewed by this session. Writes it into str. A maximum of str_size bytes (including null) will be written. */ unsigned char *get_current_title(struct session *ses, unsigned char *str, size_t str_size) { struct f_data_c *fd; fd = (struct f_data_c *)current_frame(ses); /* Ensure that the title is defined */ if (!fd) return NULL; return safe_strncpy(str, fd->f_data->title, str_size); } /* Gets the url of the link currently selected. Writes it into str. A maximum of str_size bytes (including null) will be written. */ unsigned char *get_current_link_url(struct session *ses, unsigned char *str, size_t str_size) { struct f_data_c *fd; struct link *l; fd = (struct f_data_c *)current_frame(ses); /* What the hell is an 'fd'? */ if (!fd) return NULL; /* Nothing selected? */ if (fd->vs->current_link == -1) return NULL; l = &fd->f_data->links[fd->vs->current_link]; /* Only write a link */ if (l->type != L_LINK) return NULL; return safe_strncpy(str, l->where ? l->where : l->where_img, str_size); }