changeset 28363:b289449f3e9f

Make outgoing yahoo messages with links, font color, font face or font size formatting work somewhat correctly. Not heavily tested, but it's definitely an improvement
author Mark Doliner <mark@kingant.net>
date Thu, 20 Aug 2009 01:11:26 +0000
parents c06114f3d58d
children 2aabf39b5581
files libpurple/protocols/yahoo/util.c libpurple/tests/test_yahoo_util.c
diffstat 2 files changed, 130 insertions(+), 175 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/yahoo/util.c	Wed Aug 19 22:01:10 2009 +0000
+++ b/libpurple/protocols/yahoo/util.c	Thu Aug 20 01:11:26 2009 +0000
@@ -660,7 +660,7 @@
 	xmlstr2 = g_strndup(xmlstr1 + 6, strlen(xmlstr1) - 13);
 	g_free(xmlstr1);
 
-	purple_debug_misc("yahoo", "yahoo_codes_to_html:  Returning string: '%s'.\n", xmlstr2);
+	purple_debug_misc("yahoo", "yahoo_codes_to_html(%s)=%s\n", x, xmlstr2);
 	return xmlstr2;
 }
 
@@ -673,8 +673,7 @@
 {
 	FATYPE_SIZE,
 	FATYPE_COLOR,
-	FATYPE_FACE,
-	FATYPE_JUNK
+	FATYPE_FACE
 };
 
 typedef struct
@@ -684,7 +683,6 @@
 		int size;
 		char *color;
 		char *face;
-		char *junk;
 	} u;
 } fontattr;
 
@@ -716,164 +714,100 @@
 	}
 }
 
-static void _parse_font_tag(const char *src, GString *dest, int *i, int *j,
-				int len, GSList **colors, GSList **tags, GQueue *ftattr)
+static void parse_font_tag(const char *src, GString *dest, const char *tag_name, const char *tag,
+				int src_len, GSList **colors, GSList **tags, GQueue *ftattr)
 {
-	int m, n, vstart;
-	gboolean quote = FALSE, done = FALSE;
-
-	m = *j;
+	const char *start;
+	const char *end;
+	GData *attributes;
+	const char *attribute;
+	gboolean needendtag;
+	fontattr *f;
+	GString *tmp;
 
-	while (1) {
-		m++;
+	purple_markup_find_tag(tag_name, tag, &start, &end, &attributes);
 
-		if (m >= len) {
-			g_string_append(dest, &src[*i]);
-			*i = len;
-			break;
-		}
+	attribute = g_datalist_get_data(&attributes, "color");
+	if (attribute != NULL) {
+		f = g_new(fontattr, 1);
+		f->type = FATYPE_COLOR;
+		f->u.color = g_strdup(attribute);
+		if (!ftattr)
+			ftattr = g_queue_new();
+		g_queue_push_head(ftattr, f);
+	}
 
-		if (src[m] == '=') {
-			n = vstart = m;
-			while (1) {
-				n++;
+	attribute = g_datalist_get_data(&attributes, "face");
+	if (attribute != NULL) {
+		f = g_new(fontattr, 1);
+		f->type = FATYPE_FACE;
+		f->u.face = g_strdup(attribute);
+		if (!ftattr)
+			ftattr = g_queue_new();
+		g_queue_push_tail(ftattr, f);
+	}
 
-				if (n >= len) {
-					m = n;
-					break;
-				}
+	attribute = g_datalist_get_data(&attributes, "size");
+	if (attribute != NULL) {
+		f = g_new(fontattr, 1);
+		f->type = FATYPE_SIZE;
+		f->u.size = POINT_SIZE(strtol(attribute, NULL, 10));
+		if (!ftattr)
+			ftattr = g_queue_new();
+		g_queue_push_tail(ftattr, f);
+	}
 
-				if (src[n] == '"') {
-					if (!quote) {
-						quote = TRUE;
-						vstart = n;
-						continue;
-					} else {
-						done = 1;
-					}
+	g_datalist_clear(&attributes);
+
+	needendtag = FALSE;
+	tmp = g_string_new(NULL);
+
+	if (ftattr != NULL && !g_queue_is_empty(ftattr)) {
+		while ((f = g_queue_pop_tail(ftattr))) {
+			switch (f->type) {
+			case FATYPE_SIZE:
+				if (!needendtag) {
+					needendtag = TRUE;
+					g_string_append(dest, "<font ");
 				}
 
-				if (!quote && ((src[n] == ' ') || (src[n] == '>')))
-					done = TRUE;
-
-				if (done) {
-					if (!g_ascii_strncasecmp(&src[*j+1], "FACE", m - *j - 1)) {
-						fontattr *f;
+				g_string_append_printf(dest, "size=\"%d\" ", f->u.size);
+				break;
+			case FATYPE_FACE:
+				if (!needendtag) {
+					needendtag = TRUE;
+					g_string_append(dest, "<font ");
+				}
 
-						f = g_new(fontattr, 1);
-						f->type = FATYPE_FACE;
-						f->u.face = g_strndup(&src[vstart+1], n-vstart-1);
-						if (!ftattr)
-							ftattr = g_queue_new();
-						g_queue_push_tail(ftattr, f);
-						m = n;
-						break;
-					} else if (!g_ascii_strncasecmp(&src[*j+1], "SIZE", m - *j - 1)) {
-						fontattr *f;
+				g_string_append_printf(dest, "face=\"%s\" ", f->u.face);
+				break;
 
-						f = g_new(fontattr, 1);
-						f->type = FATYPE_SIZE;
-						f->u.size = POINT_SIZE(strtol(&src[vstart+1], NULL, 10));
-						if (!ftattr)
-							ftattr = g_queue_new();
-						g_queue_push_tail(ftattr, f);
-						m = n;
-						break;
-					} else if (!g_ascii_strncasecmp(&src[*j+1], "COLOR", m - *j - 1)) {
-						fontattr *f;
+			case FATYPE_COLOR:
+				if (needendtag) {
+					g_string_append(tmp, "</font>");
+					dest->str[dest->len-1] = '>';
+					needendtag = TRUE;
+				}
 
-						f = g_new(fontattr, 1);
-						f->type = FATYPE_COLOR;
-						f->u.color = g_strndup(&src[vstart+1], n-vstart-1);
-						if (!ftattr)
-							ftattr = g_queue_new();
-						g_queue_push_head(ftattr, f);
-						m = n;
-						break;
-					} else {
-						fontattr *f;
-
-						f = g_new(fontattr, 1);
-						f->type = FATYPE_JUNK;
-						f->u.junk = g_strndup(&src[*j+1], n-*j);
-						if (!ftattr)
-							ftattr = g_queue_new();
-						g_queue_push_tail(ftattr, f);
-						m = n;
-						break;
-					}
-
-				}
+				g_string_append(tmp, *colors ? (*colors)->data : "\033[#000000m");
+				g_string_append_printf(dest, "\033[%sm", f->u.color);
+				*colors = g_slist_prepend(*colors,
+						g_strdup_printf("\033[%sm", f->u.color));
+				break;
 			}
+			fontattr_free(f);
 		}
 
-		if (src[m] == ' ')
-			*j = m;
-
-		if (src[m] == '>') {
-			gboolean needendtag = FALSE;
-			fontattr *f;
-			GString *tmp = g_string_new(NULL);
-
-			if (!g_queue_is_empty(ftattr)) {
-				while ((f = g_queue_pop_tail(ftattr))) {
-					switch (f->type) {
-					case FATYPE_SIZE:
-						if (!needendtag) {
-							needendtag = TRUE;
-							g_string_append(dest, "<font ");
-						}
-
-						g_string_append_printf(dest, "size=\"%d\" ", f->u.size);
-						break;
-					case FATYPE_FACE:
-						if (!needendtag) {
-							needendtag = TRUE;
-							g_string_append(dest, "<font ");
-						}
-
-						g_string_append_printf(dest, "face=\"%s\" ", f->u.face);
-						break;
-					case FATYPE_JUNK:
-						if (!needendtag) {
-							needendtag = TRUE;
-							g_string_append(dest, "<font ");
-						}
+		g_queue_free(ftattr);
+		ftattr = NULL;
 
-						g_string_append(dest, f->u.junk);
-						break;
-
-					case FATYPE_COLOR:
-						if (needendtag) {
-							g_string_append(tmp, "</font>");
-							dest->str[dest->len-1] = '>';
-							needendtag = TRUE;
-						}
-
-						g_string_append(tmp, *colors ? (*colors)->data : "\033[#000000m");
-						g_string_append_printf(dest, "\033[%sm", f->u.color);
-						*colors = g_slist_prepend(*colors,
-								g_strdup_printf("\033[%sm", f->u.color));
-						break;
-					}
-					fontattr_free(f);
-				}
-
-				g_queue_free(ftattr);
-				ftattr = NULL;
-
-				if (needendtag) {
-					dest->str[dest->len-1] = '>';
-					*tags = g_slist_prepend(*tags, g_strdup("</font>"));
-					g_string_free(tmp, TRUE);
-				} else {
-					*tags = g_slist_prepend(*tags, tmp->str);
-					g_string_free(tmp, FALSE);
-				}
-			}
-
-			*i = *j = m;
-			break;
+		if (needendtag) {
+			dest->str[dest->len-1] = '>';
+			*tags = g_slist_prepend(*tags, g_strdup("</font>"));
+			g_string_free(tmp, TRUE);
+		} else {
+			*tags = g_slist_prepend(*tags, tmp->str);
+			g_string_free(tmp, FALSE);
 		}
 	}
 }
@@ -929,35 +863,40 @@
 				tag_name = yahoo_markup_get_tag_name(tag, &is_closing_tag);
 
 				if (g_str_equal(tag_name, "a")) {
-					j += 7;
-					g_string_append(dest, "\033[lm");
-					if (purple_str_has_prefix(src + j, "mailto:"))
-						j += sizeof("mailto:") - 1;
-					while (1) {
-						g_string_append_c(dest, src[j]);
-						if (++j >= src_len) {
-							i = src_len;
-							break;
-						}
-						if (src[j] == '"') {
-							g_string_append(dest, "\033[xlm");
-							while (1) {
-								if (++j >= src_len) {
-									i = src_len;
-									break;
-								}
-								if (!g_ascii_strncasecmp(&src[j], "</A>", 4)) {
-									j += 3;
-									break;
-								}
-							}
-							i = j;
-							break;
-						}
+					const char *start;
+					const char *end;
+					GData *attributes;
+					const char *attribute;
+
+					/*
+					 * TODO: Ideally we would replace this:
+					 * <a href="http://pidgin.im/">Pidgin</a>
+					 * with this:
+					 * Pidgin (http://pidgin.im/)
+					 *
+					 * Currently we drop the text within the <a> tag and
+					 * just show the URL.  Doing it the fancy way is
+					 * complicated when dealing with HTML tags within the
+					 * <a> tag.
+					 */
+
+					/* Append the URL */
+					purple_markup_find_tag(tag_name, tag, &start, &end, &attributes);
+					attribute = g_datalist_get_data(&attributes, "href");
+					if (attribute != NULL) {
+						if (purple_str_has_prefix(attribute, "mailto:"))
+							attribute += 7;
+						g_string_append(dest, attribute);
 					}
+					g_datalist_clear(&attributes);
+
+					/* Skip past the closing </a> tag */
+					end = purple_strcasestr(src + j, "</a>");
+					if (end != NULL)
+						j = end - src + 3;
 
 				} else if (g_str_equal(tag_name, "font")) {
-					_parse_font_tag(src, dest, &i, &j, src_len, &colors, &tags, ftattr);
+					parse_font_tag(src, dest, tag_name, tag, src_len, &colors, &tags, ftattr);
 				} else if (g_str_equal(tag_name, "b")) {
 					g_string_append(dest, "\033[1m");
 					current_state.bold = TRUE;
@@ -983,7 +922,7 @@
 						current_state.underline = FALSE;
 					}
 				} else if (g_str_equal(tag_name, "/a")) {
-					g_string_append(dest, "\033[xlm");
+					/* Do nothing */
 				} else if (g_str_equal(tag_name, "br")) {
 					g_string_append_c(dest, '\n');
 				} else if (g_str_equal(tag_name, "/font")) {
@@ -1023,7 +962,7 @@
 	}
 
 	esc = g_strescape(dest->str, NULL);
-	purple_debug_misc("yahoo", "yahoo_html_to_codes:  Returning string: '%s'.\n", esc);
+	purple_debug_misc("yahoo", "yahoo_html_to_codes(%s)=%s\n", src, esc);
 	g_free(esc);
 
 	yahoo_htc_list_cleanup(colors);
--- a/libpurple/tests/test_yahoo_util.c	Wed Aug 19 22:01:10 2009 +0000
+++ b/libpurple/tests/test_yahoo_util.c	Thu Aug 20 01:11:26 2009 +0000
@@ -127,6 +127,16 @@
 	assert_string_equal_free("plain &",
 			yahoo_html_to_codes("plain &amp;"));
 
+	/* link */
+	assert_string_equal_free("http://pidgin.im/",
+			yahoo_html_to_codes("<A HREF=\"http://pidgin.im/\">http://pidgin.im/</A>"));
+	assert_string_equal_free("mark@example.com",
+			yahoo_html_to_codes("<A HREF=\"mailto:mark@example.com\">mark@example.com</A>"));
+#if 0
+	assert_string_equal_free("http://pidgin.im/",
+			yahoo_html_to_codes("<A HREF=\"http://pidgin.im/\">Pidgin</A>"));
+#endif
+
 	/* bold/italic/underline */
 	assert_string_equal_free("\x1B[1mbold\x1B[x1m",
 			yahoo_html_to_codes("<b>bold</b>"));
@@ -142,6 +152,12 @@
 			yahoo_html_to_codes("<b>bold <i>bolditalic</i></b><i> italic</i>"));
 	assert_string_equal_free("\x1B[1mbold \x1B[2mbolditalic\x1B[x2m\x1B[x1m\x1B[2m \x1B[4mitalicunderline\x1B[x4m\x1B[x2m",
 			yahoo_html_to_codes("<b>bold <i>bolditalic</i></b><i> <u>italicunderline</u></i>"));
+
+	/* font size */
+	assert_string_equal_free("<font size=\"10\">test</font>",
+			yahoo_html_to_codes("<font size=\"2\">test</font>"));
+	assert_string_equal_free("<font size=\"30\">test</font>",
+			yahoo_html_to_codes("<font size=\"6\">test</font>"));
 }
 END_TEST