# HG changeset patch # User Mark Doliner # Date 1250730686 0 # Node ID b289449f3e9f084c5a37e2055e45b84442dc4884 # Parent c06114f3d58dafdfceefe97fc1d001b3a8a2ca2d 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 diff -r c06114f3d58d -r b289449f3e9f libpurple/protocols/yahoo/util.c --- 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, "'))) - 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, "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, ""); + 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, "u.size); - break; - case FATYPE_FACE: - if (!needendtag) { - needendtag = TRUE; - g_string_append(dest, "u.face); - break; - case FATYPE_JUNK: - if (!needendtag) { - needendtag = TRUE; - g_string_append(dest, "u.junk); - break; - - case FATYPE_COLOR: - if (needendtag) { - g_string_append(tmp, ""); - 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("")); - 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("")); + 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], "", 4)) { - j += 3; - break; - } - } - i = j; - break; - } + const char *start; + const char *end; + GData *attributes; + const char *attribute; + + /* + * TODO: Ideally we would replace this: + * Pidgin + * with this: + * Pidgin (http://pidgin.im/) + * + * Currently we drop the text within the tag and + * just show the URL. Doing it the fancy way is + * complicated when dealing with HTML tags within the + * 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 tag */ + end = purple_strcasestr(src + j, ""); + 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); diff -r c06114f3d58d -r b289449f3e9f libpurple/tests/test_yahoo_util.c --- 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("http://pidgin.im/")); + assert_string_equal_free("mark@example.com", + yahoo_html_to_codes("mark@example.com")); +#if 0 + assert_string_equal_free("http://pidgin.im/", + yahoo_html_to_codes("Pidgin")); +#endif + /* bold/italic/underline */ assert_string_equal_free("\x1B[1mbold\x1B[x1m", yahoo_html_to_codes("bold")); @@ -142,6 +152,12 @@ yahoo_html_to_codes("bold bolditalic italic")); assert_string_equal_free("\x1B[1mbold \x1B[2mbolditalic\x1B[x2m\x1B[x1m\x1B[2m \x1B[4mitalicunderline\x1B[x4m\x1B[x2m", yahoo_html_to_codes("bold bolditalic italicunderline")); + + /* font size */ + assert_string_equal_free("test", + yahoo_html_to_codes("test")); + assert_string_equal_free("test", + yahoo_html_to_codes("test")); } END_TEST