コード例 #1
0
ファイル: magnet.c プロジェクト: MrJoe/gtk-gnutella
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)));
}
コード例 #2
0
ファイル: header.c プロジェクト: Haxe/gtk-gnutella
/**
 * 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);
}
コード例 #3
0
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);
}
コード例 #4
0
ファイル: header.c プロジェクト: Haxe/gtk-gnutella
/**
 * 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);
}
コード例 #5
0
ファイル: nodes.c プロジェクト: Longdengyu/gtk-gnutella
/**
 * 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);
    }
}
コード例 #6
0
ファイル: compat_misc.c プロジェクト: Haxe/gtk-gnutella
/**
 * 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);
}
コード例 #7
0
ファイル: bh_upload.c プロジェクト: Haxe/gtk-gnutella
/**
 * 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>&nbsp;[",
                                                          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>"
                                                          "&nbsp;[",
                                                          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);
}
コード例 #8
0
/**
 * 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;
}
コード例 #9
0
ファイル: html.c プロジェクト: Eppo791906066/gtk-gnutella
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;
}
コード例 #10
0
ファイル: html.c プロジェクト: Eppo791906066/gtk-gnutella
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);
	}
}
コード例 #11
0
ファイル: filename.c プロジェクト: Eppo791906066/gtk-gnutella
/**
 * 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);
}
コード例 #12
0
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);
	}
}
コード例 #13
0
ファイル: upload_stats.c プロジェクト: Haxe/gtk-gnutella
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;
}