Mercurial > pidgin
changeset 28013: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 &")); + /* 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