static void fsp_directory(FSP_SESSION *ses, struct uri *uri) { struct string buf; FSP_DIR *dir; unsigned char *data = get_uri_string(uri, URI_DATA); unsigned char dircolor[8] = ""; if (!data) fsp_error(connection_state(S_OUT_OF_MEM)); decode_uri(data); if (!is_in_state(init_directory_listing(&buf, uri), S_OK)) fsp_error(connection_state(S_OUT_OF_MEM)); dir = fsp_opendir(ses, data); if (!dir) fsp_error(connection_state_for_errno(errno)); fprintf(stderr, "text/html"); fclose(stderr); puts(buf.source); if (get_opt_bool("document.browse.links.color_dirs", NULL)) { color_to_string(get_opt_color("document.colors.dirs", NULL), dircolor); } sort_and_display_entries(dir, dircolor); fsp_closedir(dir); puts("</pre><hr/></body></html>"); fsp_close_session(ses); exit(0); }
/* Select handler which is set for the socket descriptor when connect() has * indicated (via errno) that it is in progress. On completion this handler gets * called. */ static void connected(struct socket *socket) { int err = 0; struct connection_state state = connection_state(0); socklen_t len = sizeof(err); assertm(socket->connect_info != NULL, "Lost connect_info!"); if_assert_failed return; if (getsockopt(socket->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == 0) { /* Why does EMX return so large values? */ if (err >= 10000) err -= 10000; if (err != 0) state = connection_state_for_errno(err); else state = connection_state(0); } else { /* getsockopt() failed */ if (errno != 0) state = connection_state_for_errno(errno); else state = connection_state(S_STATE); } if (!is_in_state(state, 0)) { /* There are maybe still some more candidates. */ connect_socket(socket, state); return; } complete_connect_socket(socket, NULL, NULL); }
/* Returns a connection state. S_OK if all is well. */ static inline struct connection_state list_directory(struct connection *conn, unsigned char *dirpath, struct string *page) { int show_hidden_files = get_opt_bool((const unsigned char *)"protocol.file.show_hidden_files", NULL); struct directory_entry *entries; struct connection_state state; errno = 0; entries = get_directory_entries(dirpath, show_hidden_files); if (!entries) { if (errno) return connection_state_for_errno(errno); return connection_state(S_OUT_OF_MEM); } state = init_directory_listing(page, conn->uri); if (!is_in_state(state, S_OK)) return connection_state(S_OUT_OF_MEM); add_dir_entries(entries, dirpath, page); if (!add_to_string(page, (const unsigned char *)"</pre>\n<hr/>\n</body>\n</html>\n")) { done_string(page); return connection_state(S_OUT_OF_MEM); } return connection_state(S_OK); }
static void draw_file_download(struct listbox_item *item, struct listbox_context *context, int x, int y, int width) { struct file_download *file_download = item->udata; struct download *download = &file_download->download; unsigned char *stylename; struct color_pair *color; unsigned char *text; int length; int trimmedlen; int meter = DOWNLOAD_METER_WIDTH; /* We have nothing to work with */ if (width < 4) return; stylename = (item == context->box->sel) ? "menu.selected" : ((item->marked) ? "menu.marked" : "menu.normal"); color = get_bfu_color(context->term, stylename); text = get_file_download_text(item, context->term); if (!text) return; length = strlen(text); /* Show atleast the required percentage of the URI */ if (length * DOWNLOAD_URI_PERCENTAGE / 100 < width - meter - 4) { trimmedlen = int_min(length, width - meter - 4); } else { trimmedlen = int_min(length, width - 3); } draw_text(context->term, x, y, text, trimmedlen, 0, color); if (trimmedlen < length) { draw_text(context->term, x + trimmedlen, y, "...", 3, 0, color); trimmedlen += 3; } mem_free(text); if (!download->progress || download->progress->size < 0 || !is_in_state(download->state, S_TRANS) || !has_progress(download->progress)) { /* TODO: Show trimmed error message. */ return; } if (!dialog_has_refresh(context->dlg_data)) refresh_dialog(context->dlg_data, refresh_file_download, NULL); if (trimmedlen + meter >= width) return; x += width - meter; draw_progress_bar(download->progress, context->term, x, y, meter, NULL, NULL); }
/* Called when the connection changes state. Usually state starts out being * S_DMS (while looking up the host) then moves to S_CONN (while connecting), * and should hopefully become S_TRANS (while transfering). Note, state can hold * both internally defined connection states as described above and errno * values, such as ECONNREFUSED. */ static void set_bittorrent_socket_state(struct socket *socket, struct connection_state state) { struct bittorrent_peer_connection *peer = socket->conn; if (is_in_state(state, S_TRANS) && peer->bittorrent) set_connection_state(peer->bittorrent->conn, connection_state(S_TRANS)); }
struct connection_state read_nntp_response_data(struct connection *conn, struct read_buffer *rb) { struct string html; unsigned char *end; struct connection_state state = connection_state(S_TRANS); if (conn->from == 0) { switch (init_nntp_header(conn, rb).basic) { case S_OK: break; case S_OUT_OF_MEM: return connection_state(S_OUT_OF_MEM); case S_TRANS: return connection_state(S_TRANS); default: return connection_state(S_NNTP_ERROR); } } if (!init_string(&html)) return connection_state(S_OUT_OF_MEM); if (conn->from == 0) add_nntp_html_start(&html, conn); while ((end = get_nntp_line_end(rb->data, rb->length))) { unsigned char *line = check_nntp_line(rb->data, end); if (!line) { state = connection_state(S_OK); break; } add_nntp_html_line(&html, conn, line); conn->received += end - rb->data; kill_buffer_data(rb, end - rb->data); } if (!is_in_state(state, S_TRANS)) add_nntp_html_end(&html, conn); add_fragment(conn->cached, conn->from, html.source, html.length); conn->from += html.length; done_string(&html); return state; }
static void smb_directory(int dir, struct string *prefix, struct uri *uri) { struct string buf; struct directory_entry *entries; if (!is_in_state(init_directory_listing(&buf, uri), S_OK)) { smb_error(connection_state(S_OUT_OF_MEM)); } fputs("text/html", header_out); fclose(header_out); entries = get_smb_directory_entries(dir, prefix); add_smb_dir_entries(entries, NULL, &buf); add_to_string(&buf, "</pre><hr/></body></html>\n"); fputs(buf.source, data_out); done_string(&buf); exit(0); }
static void download_dialog_layouter(struct dialog_data *dlg_data) { struct file_download *file_download = dlg_data->dlg->udata; struct terminal *term = dlg_data->win->term; int w = dialog_max_width(term); int rw = w; int x, y = 0; int url_len; unsigned char *url; struct download *download = &file_download->download; struct color_pair *dialog_text_color = get_bfu_color(term, "dialog.text"); unsigned char *msg = get_download_msg(download, term, 1, 1, "\n"); int show_meter = (download_is_progressing(download) && download->progress->size >= 0); #if CONFIG_BITTORRENT int bittorrent = (file_download->uri->protocol == PROTOCOL_BITTORRENT && (show_meter || is_in_state(download->state, S_RESUME))); #endif redraw_windows(REDRAW_BEHIND_WINDOW, dlg_data->win); file_download->dlg_data = dlg_data; if (!msg) return; url = get_uri_string(file_download->uri, URI_PUBLIC); if (!url) { mem_free(msg); return; } #ifdef CONFIG_UTF8 if (term->utf8_cp) decode_uri(url); else #endif /* CONFIG_UTF8 */ decode_uri_for_display(url); url_len = strlen(url); if (show_meter) { int_lower_bound(&w, DOWN_DLG_MIN); } dlg_format_text_do(dlg_data, url, 0, &y, w, &rw, dialog_text_color, ALIGN_LEFT, 1); y++; if (show_meter) y += 2; #if CONFIG_BITTORRENT if (bittorrent) y += 2; #endif dlg_format_text_do(dlg_data, msg, 0, &y, w, &rw, dialog_text_color, ALIGN_LEFT, 1); y++; dlg_format_buttons(dlg_data, dlg_data->widgets_data, dlg_data->number_of_widgets, 0, &y, w, &rw, ALIGN_CENTER, 1); draw_dialog(dlg_data, w, y); w = rw; if (url_len > w) { /* Truncate too long urls */ url_len = w; url[url_len] = '\0'; if (url_len > 4) { url[--url_len] = '.'; url[--url_len] = '.'; url[--url_len] = '.'; } } y = dlg_data->box.y + DIALOG_TB + 1; x = dlg_data->box.x + DIALOG_LB; dlg_format_text_do(dlg_data, url, x, &y, w, NULL, dialog_text_color, ALIGN_LEFT, 0); if (show_meter) { y++; draw_progress_bar(download->progress, term, x, y, w, NULL, NULL); y++; } #if CONFIG_BITTORRENT if (bittorrent) { y++; draw_bittorrent_piece_progress(download, term, x, y, w, NULL, NULL); y++; } #endif y++; dlg_format_text_do(dlg_data, msg, x, &y, w, NULL, dialog_text_color, ALIGN_LEFT, 0); y++; dlg_format_buttons(dlg_data, dlg_data->widgets_data, dlg_data->number_of_widgets, x, &y, w, NULL, ALIGN_CENTER, 0); mem_free(url); mem_free(msg); }
/* Called when progress is made such as when the select() loop detects and * schedules reads and writes. The state variable must be ignored. */ static void set_bittorrent_socket_timeout(struct socket *socket, struct connection_state state) { assert(is_in_state(state, 0)); set_bittorrent_peer_connection_timeout(socket->conn); }
/* To reduce redundant error handling code [calls to abort_connection()] * most of the function is build around conditions that will assign the error * code to @state if anything goes wrong. The rest of the function will then just * do the necessary cleanups. If all works out we end up with @state being S_OK * resulting in a cache entry being created with the fragment data generated by * either reading the file content or listing a directory. */ void file_protocol_handler(struct connection *connection) { unsigned char *redirect_location = NULL; struct string page, name; struct connection_state state; int set_dir_content_type = 0; if (get_cmd_opt_bool((const unsigned char *)"anonymous")) { if (strcmp((const char *)connection->uri->string, "file:///dev/stdin") || isatty(STDIN_FILENO)) { abort_connection(connection, connection_state(S_FILE_ANONYMOUS)); return; } } #ifdef CONFIG_CGI if (!execute_cgi(connection)) return; #endif /* CONFIG_CGI */ /* Treat /dev/stdin in special way */ if (!strcmp((const char *)connection->uri->string, "file:///dev/stdin")) { int fd = open("/dev/stdin", O_RDONLY); if (fd == -1) { abort_connection(connection, connection_state(-errno)); return; } set_nonblocking_fd(fd); if (!init_http_connection_info(connection, 1, 0, 1)) { abort_connection(connection, connection_state(S_OUT_OF_MEM)); close(fd); return; } connection->socket->fd = fd; connection->data_socket->fd = -1; read_from_stdin(connection); return; } /* This function works on already simplified file-scheme URI pre-chewed * by transform_file_url(). By now, the function contains no hostname * part anymore, possibly relative path is converted to an absolute one * and uri->data is just the final path to file/dir we should try to * show. */ if (!init_string(&name) || !add_uri_to_string(&name, connection->uri, URI_PATH)) { done_string(&name); abort_connection(connection, connection_state(S_OUT_OF_MEM)); return; } decode_uri_string(&name); /* In Win32, file_is_dir seems to always return 0 if the name * ends with a directory separator. */ if ((name.length > 0 && dir_sep(name.source[name.length - 1])) || file_is_dir(name.source)) { /* In order for global history and directory listing to * function properly the directory url must end with a * directory separator. */ if (name.source[0] && !dir_sep(name.source[name.length - 1])) { redirect_location = (unsigned char *)STRING_DIR_SEP; state = connection_state(S_OK); } else { state = list_directory(connection, name.source, &page); set_dir_content_type = 1; } } else { state = read_encoded_file(&name, &page); /* FIXME: If state is now S_ENCODE_ERROR we should try loading * the file undecoded. --jonas */ } done_string(&name); if (is_in_state(state, S_OK)) { struct cache_entry *cached; /* Try to add fragment data to the connection cache if either * file reading or directory listing worked out ok. */ cached = connection->cached = get_cache_entry(connection->uri); if (!connection->cached) { if (!redirect_location) done_string(&page); state = connection_state(S_OUT_OF_MEM); } else if (redirect_location) { if (!redirect_cache(cached, redirect_location, 1, 0)) state = connection_state(S_OUT_OF_MEM); } else { add_fragment(cached, 0, page.source, page.length); connection->from += page.length; if (!cached->head && set_dir_content_type) { unsigned char *head; /* If the system charset somehow * changes after the directory listing * has been generated, it should be * parsed with the original charset. */ head = straconcat((const unsigned char *)"\r\nContent-Type: text/html; charset=", get_cp_mime_name(get_cp_index((const unsigned char *)"System")), "\r\n", (unsigned char *) NULL); /* Not so gracefully handle failed memory * allocation. */ if (!head) state = connection_state(S_OUT_OF_MEM); /* Setup directory listing for viewing. */ mem_free_set(&cached->head, head); } done_string(&page); } } abort_connection(connection, state); }