void magnet_add_search(struct magnet_resource *res, const char *search) { g_return_if_fail(res); g_return_if_fail(search); res->searches = g_slist_prepend(res->searches, deconstify_gchar(atom_str_get(search))); }
/** * Get field value, or NULL if not present. The value returned is a * pointer to the internals of the header structure, so it must not be * kept around. */ char * header_get(const header_t *o, const char *field) { str_t *v; header_check(o); if (o->headers) { v = g_hash_table_lookup(o->headers, deconstify_gchar(field)); } else { v = NULL; } return str_2c(v); }
static void search_stats_notify_routed(query_type_t unused_type, const gchar *unused_search, const host_addr_t addr, guint16 port) { const word_vec_t *p_wovec; word_vec_t wovec; (void) unused_type; (void) unused_search; wovec.word = deconstify_gchar(host_addr_port_to_string(addr, port)); wovec.len = strlen(wovec.word); wovec.amount = 1; p_wovec = &wovec; search_stats_tally(p_wovec); }
/** * Get field value, or NULL if not present. The value returned is a * pointer to the internals of the header structure, so it must not be * kept around. * * If the len_ptr pointer is not NULL, it is filled with the length * of the header string. */ char * header_get_extended(const header_t *o, const char *field, size_t *len_ptr) { str_t *v; header_check(o); if (o->headers) { v = g_hash_table_lookup(o->headers, deconstify_gchar(field)); } else { v = NULL; } if (v && len_ptr != NULL) { *len_ptr = str_len(v); } return str_2c(v); }
/** * Update the row with the given nodeinfo. If row is -1 the row number * is determined by the node_id contained in the gnet_node_info_t. */ static void nodes_gui_update_node_info(gnet_node_info_t *n, gint row) { GtkCList *clist = GTK_CLIST(gui_main_window_lookup("clist_nodes")); g_assert(n != NULL); if (row == -1) { row = gtk_clist_find_row_from_data(clist, deconstify_gpointer(n->node_id)); } if (row != -1) { gchar ver_buf[64]; gnet_node_status_t status; time_t now = tm_time(); if (guc_node_get_status(n->node_id, &status)) { gtk_clist_set_text(clist, row, c_gnet_user_agent, n->vendor ? lazy_utf8_to_locale(n->vendor) : "..."); gtk_clist_set_text(clist, row, c_gnet_loc, deconstify_gchar(iso3166_country_cc(n->country))); str_bprintf(ver_buf, sizeof ver_buf, "%d.%d", n->proto_major, n->proto_minor); gtk_clist_set_text(clist, row, c_gnet_version, ver_buf); if (status.status == GTA_NODE_CONNECTED) gtk_clist_set_text(clist, row, c_gnet_connected, short_uptime(delta_time(now, status.connect_date))); if (status.up_date) gtk_clist_set_text(clist, row, c_gnet_uptime, status.up_date ? short_uptime(delta_time(now, status.up_date)) : "..."); gtk_clist_set_text(clist, row, c_gnet_info, nodes_gui_common_status_str(&status)); } } else { g_warning("%s(): no matching row found", G_STRFUNC); } }
/** * Equivalent to strstr() for raw memory without NUL-termination. * * @param data The memory to scan. * @param data_size The length of data. * @param pattern The byte pattern to look for. * @param pattern_size The length of the pattern. * @return NULL if not found. Otherwise, the start address of the first match * is returned. */ void * compat_memmem(const void *data, size_t data_size, const void *pattern, size_t pattern_size) { const char *next, *p, *pat; pat = pattern; for (p = data; NULL != p; p = next) { if (data_size < pattern_size) { p = NULL; break; } if (0 == memcmp(p, pattern, pattern_size)) { break; } next = memchr(&p[1], pat[0], data_size - 1); data_size -= next - p; } return deconstify_gchar(p); }
/** * Writes the browse host data of the context ``ctx'' to the buffer * ``dest''. This must be called multiple times to retrieve the complete * data until zero is returned i.e., the end of file is reached. * * This routine deals with HTML data generation. * * @param ctx an initialized browse host context. * @param dest the destination buffer. * @param size the amount of bytes ``dest'' can hold. * * @return -1 on failure, zero at the end-of-file condition or if size * was zero. On success, the amount of bytes copied to ``dest'' * is returned. */ static ssize_t browse_host_read_html(struct special_upload *ctx, gpointer const dest, size_t size) { static const char header[] = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\r\n" "<html>\r\n" "<head>\r\n" "<title>Browse Host</title>\r\n" "</head>\r\n" "<body>\r\n"; static const char trailer[] = "</ul>\r\n</body>\r\n</html>\r\n"; struct browse_host_upload *bh = cast_to_browse_host_upload(ctx); char *p = dest; g_assert(NULL != bh); g_assert(NULL != dest); g_assert(size <= INT_MAX); g_assert(UNSIGNED(bh->state) < NUM_BH_STATES); g_assert(bh->b_size <= INT_MAX); g_assert(bh->b_offset <= bh->b_size); do { switch (bh->state) { case BH_STATE_HEADER: if (!bh->b_data) { bh->b_data = header; bh->b_size = CONST_STRLEN(header); } p += browse_host_read_data(bh, p, &size); if (bh->b_size == bh->b_offset) browse_host_next_state(bh, BH_STATE_LIBRARY_INFO); break; case BH_STATE_LIBRARY_INFO: if (!bh->b_data) { bh->w_buf_size = w_concat_strings(&bh->w_buf, "<h1>" GTA_PRODUCT_NAME "</h1>\r\n" "<h3>", version_get_string(), " sharing ", uint64_to_string(shared_files_scanned()), " file", shared_files_scanned() == 1 ? "" : "s", " ", short_kb_size(shared_kbytes_scanned(), GNET_PROPERTY(display_metric_units)), " total</h3>\r\n" "<ul>\r\n", (void *) 0); bh->b_data = bh->w_buf; bh->b_size = bh->w_buf_size - 1; /* minus trailing NUL */ bh->b_offset = 0; } p += browse_host_read_data(bh, p, &size); if (bh->b_size == bh->b_offset) browse_host_next_state(bh, BH_STATE_FILES); break; case BH_STATE_TRAILER: if (!bh->b_data) { bh->b_data = trailer; bh->b_size = CONST_STRLEN(trailer); } p += browse_host_read_data(bh, p, &size); if (bh->b_size == bh->b_offset) browse_host_next_state(bh, BH_STATE_EOF); break; case BH_STATE_FILES: if (bh->b_data && bh->b_size == bh->b_offset) { g_assert(bh->w_buf == bh->b_data); wfree(bh->w_buf, bh->w_buf_size); bh->w_buf = NULL; bh->w_buf_size = 0; bh->b_data = NULL; } if (!bh->b_data) { const shared_file_t *sf; bh->file_index++; sf = shared_file_sorted(bh->file_index); if (!sf) { if (bh->file_index > shared_files_scanned()) browse_host_next_state(bh, BH_STATE_TRAILER); /* Skip holes in the file_index table */ } else if (SHARE_REBUILDING == sf) { browse_host_next_state(bh, BH_STATE_REBUILDING); } else { const char * const name_nfc = shared_file_name_nfc(sf); const filesize_t file_size = shared_file_size(sf); size_t html_size; char *html_name; { const char *dir; char *name; dir = shared_file_relative_path(sf); if (dir) { name = h_strconcat(dir, "/", name_nfc, (void *) 0); } else { name = deconstify_gchar(name_nfc); } html_size = 1 + html_escape(name, NULL, 0); html_name = walloc(html_size); html_escape(name, html_name, html_size); if (name != name_nfc) { HFREE_NULL(name); } } if (sha1_hash_available(sf)) { const struct sha1 *sha1 = shared_file_sha1(sf); bh->w_buf_size = w_concat_strings(&bh->w_buf, "<li><a href=\"/uri-res/N2R?urn:sha1:", sha1_base32(sha1), "\">", html_name, "</a> [", short_html_size(file_size, GNET_PROPERTY(display_metric_units)), "]</li>\r\n", (void *) 0); } else { char *escaped; escaped = url_escape(name_nfc); bh->w_buf_size = w_concat_strings(&bh->w_buf, "<li><a href=\"/get/", uint32_to_string(shared_file_index(sf)), "/", escaped, "\">", html_name, "</a>" " [", short_html_size(file_size, GNET_PROPERTY(display_metric_units)), "]</li>\r\n", (void *) 0); if (escaped != name_nfc) { HFREE_NULL(escaped); } } wfree(html_name, html_size); bh->b_data = bh->w_buf; bh->b_size = bh->w_buf_size - 1; /* minus trailing NUL */ bh->b_offset = 0; } } if (bh->b_data) p += browse_host_read_data(bh, p, &size); break; case BH_STATE_REBUILDING: if (!bh->b_data) { static const char msg[] = "<li>" "<b>" "The library is currently being rebuild. Please, " "try again in a moment." "</b>" "</li>"; bh->b_data = msg; bh->b_size = CONST_STRLEN(msg); } p += browse_host_read_data(bh, p, &size); if (bh->b_size == bh->b_offset) browse_host_next_state(bh, BH_STATE_TRAILER); break; case BH_STATE_EOF: return p - cast_to_gchar_ptr(dest); case NUM_BH_STATES: g_assert_not_reached(); } } while (size > 0); return p - cast_to_gchar_ptr(dest); }
/** * Extract information from SOAP fault tree. * * @param fault the XML <Fault> tree * @param code where UPnP error code is written, if non-NULL * @param error where address of UPnP error string is written, if non-NULL * * @attention * The error string is pointing in the XML tree and will become invalid as * soon as the tree is freed so it needs to be duplicated if it must persist. * * @return TRUE if OK, FALSE on error. */ static gboolean upnp_ctrl_extract_fault(xnode_t *fault, int *code, const char **error) { xnode_t *fcode, *fstring, *detail, *uerror; const char *parse_error = NULL; g_assert(fault != NULL); /* * The SOAP specification for the <faultcode> element are very bad. * Indeed, the content is a string bearing the *prefix* of the SOAP * namespace, which is completely arbitrary and not accessible at this * level since all nodes are normalized with their namespace, the prefix * string being irrelevant once parsing is done. And namespace have no * meaning in element *content*. * * Sure, we know we force the "s" prefix for SOAP, and most UPnP stacks * are going to use that prefix as well, but matching the <faultcode> * content to look for "s:Client" or "s:MustUnderstand" is just plain * wrong, and a blatant encapsulation violation. * * So instead we look backwards in the string to find the first ':' and * consider the tail part of the string, totally ignoring the prefix. * That's a lousy parsing, but in practice it's going to work and should * be safe since there's little choice anyway according to the SOAP * specifications (meaning they could have just as well ignored the * prefix in this string and just mandate "Client" or "MustUnderstand"). * * Also note that <faultcode>, <faultstring> and <detail> elements are * architected without any SOAP namespace. That's surprising. */ fcode = xnode_tree_find_depth(fault, 1, node_named_as, deconstify_gchar(SOAP_FAULT_CODE)); if (NULL == fcode) { parse_error = "cannot find <faultcode>"; goto error; } else { const char *value; const char *name; value = xnode_first_text(fcode); if (NULL == value) { parse_error = "<faultcode> does not contain text"; goto error; } /* * We're only handling "Client" errors. */ name = strrchr(value, ':'); if (NULL == name) { parse_error = "no ':' in fault code name"; goto error; } name++; if (0 != strcmp(name, SOAP_CLIENT_FAULT)) { parse_error = "not a Client fault"; goto error; } } /* * Here is a sample fault tree from the UPnP 1.0 architecture: * * <s:Fault> * <faultcode>s:Client</faultcode> * <faultstring>UPnPError</faultstring> * <detail> * <UPnpError xmlns="urn:schemas-upnp-org:control-1-0"> * <errorCode>error code</errorCode> * <errorDescription>error string</errorDescription> * </UPnPError> * </detail> * <s:Fault> * * Note that the UPnP tags are in the "urn:schemas-upnp-org:control-1-0" * namespace. */ fstring = xnode_tree_find_depth(fault, 1, node_named_as, deconstify_gchar(SOAP_FAULT_STRING)); if (NULL == fstring) { parse_error = "no <faultstring> found"; goto error; } else { const char *value; value = xnode_first_text(fstring); if (NULL == value) { parse_error = "<faultstring> does not contain text"; goto error; } if (0 != strcmp(value, SOAP_UPNP_ERROR)) { parse_error = "<faultstring> is not an UPnP error"; goto error; } } detail = xnode_tree_find_depth(fault, 1, node_named_as, deconstify_gchar(SOAP_FAULT_DETAIL)); if (NULL == detail) { parse_error = "no <detail> found"; goto error; } /* * First child must be a <UPnpError> tag. */ uerror = xnode_first_child(detail); if (xnode_is_element_named(uerror, UPNP_NS_ERROR, SOAP_UPNP_ERROR)) { xnode_t *xn; if (code != NULL) { const char *value; int err; xn = xnode_tree_find_depth(uerror, 1, node_named_as, deconstify_gchar(UPNP_ERROR_CODE)); if (NULL == xn) { parse_error = "no <errorCode> found"; goto error; } value = xnode_first_text(xn); if (NULL == value) { parse_error = "<errorCode> doest not contain text"; goto error; } *code = parse_uint32(value, NULL, 10, &err); if (err) { parse_error = "cannot parse <errorCode> value"; goto error; } } if (error != NULL) { xn = xnode_tree_find_depth(uerror, 1, node_named_as, deconstify_gchar(UPNP_ERROR_DESC)); *error = (NULL == xn) ? NULL : xnode_first_text(xn); } } else { parse_error = "no <UPnPError> found"; goto error; } return TRUE; error: if (GNET_PROPERTY(upnp_debug)) g_warning("UPNP fault parsing error: %s", EMPTY_STRING(parse_error)); return FALSE; }
static int html_parse(struct html_output *output, const struct array array) { size_t i, line_num; const char *msg; uint32 c; unsigned c_len; struct array tag, text; struct html_node *nodes, *root; line_num = 1; root = html_node_alloc(); nodes = root; tag = zero_array; text = array_init(array.data, 0); for (i = 0; i < array.size; i += c_len) { const char *next_ptr; c = utf8_decode(&array.data[i], i - array.size); if ((uint32)-1 == c) { msg = "Invalid UTF-8 encoding"; goto error; } c_len = utf8_encoded_len(c); next_ptr = &array.data[i + c_len]; switch (c) { case '<': if (tag.data) { tag.size += c_len; } else { if (text.data && text.size > 0) { struct html_node *node; node = html_node_alloc(); node->type = HTML_NODE_TEXT; node->array = text; node->next = NULL; nodes->next = node; nodes = node; text = zero_array; } tag.data = deconstify_gchar(next_ptr); tag.size = 0; } break; case '>': if (!tag.data) { g_warning("'>' but no open tag"); if (text.data) text.size += c_len; } else if ( HTML_TAG_COMMENT == parse_tag(tag) && 0 != memcmp(&tag.data[tag.size - 2], "--", 2) ) { tag.size += c_len; } else { struct html_node *node; node = html_node_alloc(); node->type = HTML_NODE_TAG; node->array = tag; node->next = NULL; nodes->next = node; nodes = node; tag = zero_array; text = array_init(next_ptr, 0); } break; case '\n': line_num++; /* FALL THROUGH */ default: if (tag.data) { tag.size += c_len; } else if (text.data) { text.size += c_len; } } } { struct render_context ctx; ctx = zero_render_context; ctx.output = output; ctx.root = root; html_render(&ctx); } html_free(root); return 0; error: g_warning("line %zu: error: %s", line_num, msg); html_free(root); return -1; }
static void html_render_text(struct render_context *ctx, const struct array text) { unsigned c_len; size_t i; bool whitespace = FALSE; struct array entity, current; entity = zero_array; current = zero_array; for (i = 0; i < text.size; i += c_len) { const unsigned char c = text.data[i]; bool is_whitespace; is_whitespace = FALSE; c_len = utf8_first_byte_length_hint(c); if (!ctx->preformatted && is_ascii_space(c)) { if (whitespace) continue; is_whitespace = TRUE; whitespace = TRUE; if (0x20 == c && i > 0 && i < text.size - c_len) { const unsigned char next_c = text.data[i + c_len]; if (!is_ascii_space(next_c)) is_whitespace = FALSE; } } else { whitespace = FALSE; } if ('&' == c || ';' == c || is_whitespace) { if (current.size > 0) { html_output_print(ctx->output, current); current = zero_array; } } if (is_whitespace) { if (i > 0 || ctx->closing) html_output_print(ctx->output, array_from_string(" ")); } else if ('&' == c) { if (entity.data) { html_render_entity(ctx, entity); } entity.data = deconstify_gchar(&text.data[i + c_len]); entity.size = 0; continue; } else if (';' == c) { if (entity.data) { html_render_entity(ctx, entity); entity = zero_array; continue; } } else if (entity.data) { entity.size += c_len; } else { if (!current.data) current.data = &text.data[i]; current.size += c_len; } } if (current.size > 0) { html_output_print(ctx->output, current); } }
/** * Creates a valid and sanitized filename from the supplied string. For most * Unix-like platforms anything goes but for security reasons, shell meta * characters are replaced by harmless characters. * * @param filename the suggested filename. * @param no_spaces if TRUE, spaces are replaced with underscores. * @param no_evil if TRUE, "evil" characters are replaced with underscores. * * @returns a newly allocated string using halloc() or ``filename'' * if it was a valid filename already. */ char * filename_sanitize(const char *filename, bool no_spaces, bool no_evil) { const char *p; const char *s; char *q; g_assert(filename); /* Almost all evil characters are forbidden on Windows, anyway */ no_evil |= is_running_on_mingw(); /* Leading spaces are just confusing */ p = skip_ascii_spaces(filename); /* Make sure the filename isn't too long */ if (strlen(p) >= FILENAME_MAXBYTES) { q = halloc(FILENAME_MAXBYTES); filename_shrink(p, q, FILENAME_MAXBYTES); s = q; } else { s = p; q = NULL; } /* * Replace shell meta characters and likely problematic characters. * * Although parentheses are not evil per se, they make it a pain to * copy-n-paste filenames without going through the shell's auto- * completion (which normally does the necessary escaping). * * To keep things "readable", we replace parentheses with brackets. * Although brackets are meaningful for the shells, they are only * interpreted in the presence of "*" or "?", two characters that we * strip already. * --RAM, 2013-11-03 */ { size_t i; uchar c; for (i = 0; '\0' != (c = s[i]); i++) { if ( c < 32 || is_ascii_cntrl(c) || G_DIR_SEPARATOR == c || '/' == c || (0 == i && ('.' == c || '-' == c)) || (no_spaces && is_ascii_space(c)) || (no_evil && filename_is_evil_char(c)) ) { if (!q) q = h_strdup(s); q[i] = '_'; /* replace undesired char with underscore */ } else if ('(' == c) { if (!q) q = h_strdup(s); q[i] = '['; } else if (')' == c) { if (!q) q = h_strdup(s); q[i] = ']'; } } /** * Windows does not like filenames ending with a space or period. */ while (i-- > 0 && (is_ascii_space(s[i]) || '.' == s[i])) { if (!q) q = h_strdup(s); q[i] = '\0'; /* truncate string */ } } if (filename_is_reserved(q ? q : s)) { HFREE_NULL(q); q = h_strdup("noname"); } if (NULL == q && s != filename) q = h_strdup(s); /* Trimmed leading white space, must copy */ return q ? q : deconstify_gchar(s); }
static void html_output_tag(struct html_output *output, const struct array *tag) #if GTK_CHECK_VERSION(2,0,0) { static struct { gboolean initialized; short_string_t centre_line, nbsp, bullet, soft_hyphen, em_dash; short_string_t list_item_prefix; } special; struct html_context *ctx; const gchar *style, *text, *attr; enum html_tag id; gboolean closing; GtkTextBuffer *buffer; if (!special.initialized) { special.initialized = TRUE; special.bullet = utf8_char(0x2022); special.centre_line = utf8_char(0xFE4E); special.soft_hyphen = utf8_char(0x00AD); special.nbsp = utf8_char(0x00A0); special.em_dash = utf8_char(0x2014); concat_strings(special.list_item_prefix.str, sizeof special.list_item_prefix.str, " ", special.bullet.str, " ", (void *) 0); } style = NULL; text = NULL; attr = NULL; closing = html_tag_is_closing(tag); ctx = html_output_get_udata(output); id = html_parse_tag(tag); buffer = gtk_text_view_get_buffer(ctx->html_view->widget); switch (id) { case HTML_TAG_BODY: style = STYLE_TAG_WORD_WRAP; break; case HTML_TAG_A: if (closing) { if (ctx->start[id] && ctx->href) { GtkTextIter start, end; GtkTextTag *anchor; anchor = gtk_text_buffer_create_tag(buffer, NULL, (void *) 0); g_object_set_data(G_OBJECT(anchor), "href", deconstify_gchar(ctx->href)); gtk_text_buffer_get_iter_at_mark(buffer, &start, ctx->start[id]); gtk_text_buffer_get_end_iter(buffer, &end); gtk_text_buffer_apply_tag(buffer, anchor, &start, &end); style = get_style_for_href(ctx->href); ctx->href = NULL; } } else { struct array value; value = html_get_attribute(tag, HTML_ATTR_HREF); if (value.data && value.size > 0) { GtkTextIter iter; ctx->href = g_strndup(value.data, value.size); ctx->html_view->to_free = g_slist_prepend( ctx->html_view->to_free, deconstify_gchar(ctx->href)); gtk_text_buffer_get_end_iter(buffer, &iter); ctx->start[id] = gtk_text_buffer_create_mark(buffer, NULL, &iter, TRUE); g_object_set_data(G_OBJECT(ctx->start[id]), "href", deconstify_gchar(ctx->href)); } value = html_get_attribute(tag, HTML_ATTR_NAME); if (value.data && value.size > 0) { GtkTextTagTable *table; gchar name[256]; size_t n; n = sizeof name - 2; n = MIN(value.size, n); name[0] = '#'; memcpy(&name[1], value.data, n); name[n + 1] = '\0'; table = gtk_text_buffer_get_tag_table(buffer); if (NULL == gtk_text_tag_table_lookup(table, name)) { GtkTextIter iter; gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_create_mark(buffer, name, &iter, TRUE); } } } break; case HTML_TAG_B: case HTML_TAG_STRONG: case HTML_TAG_THEAD: style = STYLE_TAG_BOLD; break; case HTML_TAG_TH: if (closing) text = "\t"; break; case HTML_TAG_EM: style = STYLE_TAG_UNDERLINE; break; case HTML_TAG_I: case HTML_TAG_Q: style = STYLE_TAG_ITALIC; break; case HTML_TAG_IMG: if (!closing) { struct array value; static gchar alt[1024]; value = html_get_attribute(tag, HTML_ATTR_ALT); if (value.data) { gm_snprintf(alt, sizeof alt, "\n[image alt=\"%.*s\"]\n", (int)value.size, value.data); text = alt; } value = html_get_attribute(tag, HTML_ATTR_SRC); if (value.data) { GdkPixbuf *pixbuf; gchar *filename; GtkTextIter iter; filename = h_strndup(value.data, value.size); pixbuf = gdk_pixbuf_new_from_file(filename, NULL); if (pixbuf) { gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert_pixbuf(buffer, &iter, pixbuf); } else { static gchar msg[1024]; gm_snprintf(msg, sizeof msg, "\n[Image not found (\"%s\")]\n", filename); text = msg; } HFREE_NULL(filename); } if (!text) { text = "\n[image]\n"; } } attr = STYLE_TAG_BOLD; break; case HTML_TAG_TD: if (closing) text = "\t"; break; case HTML_TAG_P: case HTML_TAG_DIV: text = closing ? "\n\n" : special.soft_hyphen.str; break; case HTML_TAG_DL: case HTML_TAG_TABLE: case HTML_TAG_TR: case HTML_TAG_UL: case HTML_TAG_OL: case HTML_TAG_BR: text = "\n"; break; case HTML_TAG_DT: case HTML_TAG_LI: if (closing) { GtkTextIter start, end; GtkTextTag *margin; PangoLayout *pl; gint width; pl = pango_layout_new(gtk_widget_get_pango_context( GTK_WIDGET(ctx->html_view->widget))); pango_layout_set_text(pl, special.list_item_prefix.str, -1); pango_layout_get_pixel_size(pl, &width, NULL); g_object_unref(G_OBJECT(pl)); margin = gtk_text_buffer_create_tag(buffer, NULL, "left-margin", width * 2, "left-margin-set", TRUE, (void *) 0); gtk_text_buffer_get_iter_at_mark(buffer, &start, ctx->start[id]); gtk_text_buffer_get_end_iter(buffer, &end); gtk_text_buffer_apply_tag(buffer, margin, &start, &end); } else { GtkTextIter iter; gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, "\n", (-1)); gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, special.list_item_prefix.str, (-1), STYLE_TAG_BOLD, (void *) 0); gtk_text_buffer_get_end_iter(buffer, &iter); ctx->start[id] = gtk_text_buffer_create_mark(buffer, NULL, &iter, TRUE); } break; case HTML_TAG_CODE: case HTML_TAG_KBD: case HTML_TAG_PRE: case HTML_TAG_TT: style = STYLE_TAG_MONOSPACE; break; case HTML_TAG_H1: style = STYLE_TAG_HEADING_1; text = closing ? "\n\n" : "\n"; break; case HTML_TAG_H2: style = STYLE_TAG_HEADING_2; text = closing ? "\n\n" : "\n"; break; case HTML_TAG_H3: style = STYLE_TAG_HEADING_3; text = closing ? "\n\n" : "\n"; break; case HTML_TAG_H4: case HTML_TAG_H5: case HTML_TAG_H6: style = STYLE_TAG_HEADING_4; text = closing ? "\n\n" : "\n"; break; case HTML_TAG_TITLE: if (closing) { if (ctx->title) { GtkWidget *window; window = gtk_widget_get_toplevel( GTK_WIDGET(ctx->html_view->widget)); gtk_window_set_title(GTK_WINDOW(window), str_2c(ctx->title)); str_destroy_null(&ctx->title); } } else { ctx->title = str_new(0); } break; case HTML_TAG_HR: { GtkTextIter iter; gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, "\n \n", (-1), STYLE_TAG_CENTER, STYLE_TAG_UNDERLINE, (void *) 0); } text = "\n"; break; case HTML_TAG_COMMENT: #if 0 { GtkTextIter iter; /* Comments can be made visible this way */ ctx->start[id] = gtk_text_buffer_create_mark(buffer, NULL, &iter, TRUE); gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, tag->data, tag->size, STYLE_TAG_ITALIC, (void *) 0); } closing = TRUE; text = "\n"; #endif break; case HTML_TAG_HTML: if (closing) { if (ctx->lang && ctx->start[id]) { GtkTextIter start, end; GtkTextTag *lang; lang = gtk_text_buffer_create_tag(buffer, NULL, "language", ctx->lang, "language-set", TRUE, (void *) 0); gtk_text_buffer_get_iter_at_mark(buffer, &start, ctx->start[id]); gtk_text_buffer_get_end_iter(buffer, &end); gtk_text_buffer_apply_tag(buffer, lang, &start, &end); ctx->lang = NULL; } } else { struct array value; value = html_get_attribute(tag, HTML_ATTR_LANG); if (value.data && value.size > 0) { GtkTextIter iter; ctx->lang = g_strndup(value.data, value.size); ctx->html_view->to_free = g_slist_prepend( ctx->html_view->to_free, deconstify_gchar(ctx->lang)); gtk_text_buffer_get_end_iter(buffer, &iter); ctx->start[id] = gtk_text_buffer_create_mark(buffer, NULL, &iter, TRUE); } } case HTML_TAG_HEAD: case HTML_TAG_META: case HTML_TAG_SPAN: case HTML_TAG_COL: case HTML_TAG_DD: case HTML_TAG_TBODY: case HTML_TAG_DOCTYPE: case HTML_TAG_UNKNOWN: break; case NUM_HTML_TAG: g_assert_not_reached(); } if (style) { if (closing) { if (ctx->start[id]) { GtkTextIter start, end; gtk_text_buffer_get_iter_at_mark(buffer, &start, ctx->start[id]); gtk_text_buffer_get_end_iter(buffer, &end); gtk_text_buffer_apply_tag_by_name(buffer, style, &start, &end); ctx->start[id] = NULL; } } else { GtkTextIter iter; gtk_text_buffer_get_end_iter(buffer, &iter); ctx->start[id] = gtk_text_buffer_create_mark(buffer, NULL, &iter, TRUE); } } if (text) { GtkTextIter iter; gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, text, (-1), attr, (void *) 0); } }
G_GNUC_COLD void upload_stats_load_history(void) { FILE *upload_stats_file; file_path_t fp; char line[FILENAME_MAX + 64]; guint lineno = 0; gcu_upload_stats_gui_freeze(); file_path_set(&fp, settings_config_dir(), ul_stats_file); /* open file for reading */ upload_stats_file = file_config_open_read(ul_stats_what, &fp, 1); if (upload_stats_file == NULL) goto done; /* parse, insert names into ul_stats_clist */ while (fgets(line, sizeof(line), upload_stats_file)) { static const struct ul_stats zero_item; struct ul_stats item; struct sha1 sha1_buf; const char *p; size_t i; lineno++; if (line[0] == '#' || line[0] == '\n') continue; p = strchr(line, '\t'); if (NULL == p) goto corrupted; line[p - line] = '\0'; /* line is now the URL-escaped file name */ p++; /* URL-unescape in-place */ if (!url_unescape(line, TRUE)) goto corrupted; item = zero_item; item.pathname = line; for (i = 0; i < 8; i++) { guint64 v; int error; const char *endptr; p = skip_ascii_spaces(p); /* SVN versions up to 15322 had only 6 fields in the history */ if (5 == i && '\0' == *p) break; switch (i) { case 7: /* We have a SHA1 or '*' if none known */ if ('*' != *p) { size_t len = clamp_strlen(p, SHA1_BASE32_SIZE); error = !parse_base32_sha1(p, len, &sha1_buf); item.sha1 = error ? NULL : &sha1_buf; } else { error = FALSE; } p = skip_ascii_non_spaces(p); v = 0; break; default: v = parse_uint64(p, &endptr, 10, &error); p = deconstify_gchar(endptr); } if (error || !is_ascii_space(*endptr)) goto corrupted; switch (i) { case 0: item.size = v; break; case 1: item.attempts = v; break; case 2: item.complete = v; break; case 3: item.bytes_sent |= ((guint64) (guint32) v) << 32; break; case 4: item.bytes_sent |= (guint32) v; break; case 5: item.rtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); case 6: item.dtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); case 7: break; /* Already stored above */ default: g_assert_not_reached(); goto corrupted; } } /* * We store the filenames UTF-8 encoded but the file might have been * edited or corrupted. */ if (is_absolute_path(item.pathname)) { item.filename = lazy_filename_to_utf8_normalized( filepath_basename(item.pathname), UNI_NORM_NFC); } else { item.filename = lazy_unknown_to_utf8_normalized( filepath_basename(item.pathname), UNI_NORM_NFC, NULL); } if (upload_stats_find(NULL, item.pathname, item.size)) { g_warning("upload_stats_load_history():" " Ignoring line %u due to duplicate file.", lineno); } else if (upload_stats_find(item.sha1, item.pathname, item.size)) { g_warning("upload_stats_load_history():" " Ignoring line %u due to duplicate file.", lineno); } else { upload_stats_add(item.pathname, item.size, item.filename, item.attempts, item.complete, item.bytes_sent, item.rtime, item.dtime, item.sha1); } continue; corrupted: g_warning("upload statistics file corrupted at line %u.", lineno); } /* close file */ fclose(upload_stats_file); done: gcu_upload_stats_gui_thaw(); return; }