Mercurial > pidgin
changeset 5093:89c0c811befa
[gaim-migrate @ 5455]
jabber XHTML support. since people tend to not like to write valid XHTML
all of the time, we now have html_to_xhtml() which does its best to figure
out what you meant. i'm tired, hope this works for everyone
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Thu, 10 Apr 2003 06:09:26 +0000 |
parents | a4ad609ee6b3 |
children | 6df2fde9740e |
files | ChangeLog src/gaim.h src/gtkimhtml.c src/html.c src/protocols/jabber/jabber.c src/util.c |
diffstat | 6 files changed, 194 insertions(+), 25 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Thu Apr 10 00:57:06 2003 +0000 +++ b/ChangeLog Thu Apr 10 06:09:26 2003 +0000 @@ -3,6 +3,7 @@ version 0.62 * Keyboard shortcuts in the buddy list work again (Thanks Joe Clarke). + * Support for Jabber XHTML messages version 0.61 (04/07/2003): * Split the buddy pounce core and UI, and rewrote the UI for it.
--- a/src/gaim.h Thu Apr 10 00:57:06 2003 +0000 +++ b/src/gaim.h Thu Apr 10 06:09:26 2003 +0000 @@ -371,6 +371,7 @@ extern void grab_url(char *, gboolean, void (*callback)(gpointer, char *, unsigned long), gpointer); extern gchar *strip_html(const gchar *); +extern char *html_to_xhtml(const char *); struct g_url *parse_url(char *url); /* Functions in idle.c */
--- a/src/gtkimhtml.c Thu Apr 10 00:57:06 2003 +0000 +++ b/src/gtkimhtml.c Thu Apr 10 06:09:26 2003 +0000 @@ -632,6 +632,9 @@ } else if (!g_ascii_strncasecmp (string, "®", 5)) { *replace = '®'; /* was: '®' */ *length = 5; + } else if (!g_ascii_strncasecmp (string, "'", 6)) { + *replace = '\''; + *length = 6; } else if (*(string + 1) == '#') { guint pound = 0; if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { @@ -703,7 +706,7 @@ VALID_TAG ("/HEAD"); VALID_TAG ("BINARY"); VALID_TAG ("/BINARY"); - + VALID_OPT_TAG ("HR"); VALID_OPT_TAG ("FONT"); VALID_OPT_TAG ("BODY"); @@ -711,6 +714,7 @@ VALID_OPT_TAG ("IMG"); VALID_OPT_TAG ("P"); VALID_OPT_TAG ("H3"); + VALID_OPT_TAG ("HTML"); if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { gchar *e = strstr (string + strlen("!--"), "-->"); @@ -1170,8 +1174,9 @@ } case 47: /* P (opt) */ case 48: /* H3 (opt) */ + case 49: /* HTML (opt) */ break; - case 49: /* comment */ + case 50: /* comment */ NEW_BIT (NEW_TEXT_BIT); if (imhtml->show_comments) wpos = g_snprintf (ws, len, "%s", tag);
--- a/src/html.c Thu Apr 10 00:57:06 2003 +0000 +++ b/src/html.c Thu Apr 10 06:09:26 2003 +0000 @@ -322,3 +322,138 @@ callback(data, g_strdup(_("g003: Error opening connection.\n")), 0); } } + +#define ALLOW_TAG_ALT(x, y) if(!g_ascii_strncasecmp(c, "<" x " ", strlen("<" x " "))) { \ + char *o = strchr(c+1, '<'); \ + char *p = strchr(c+1, '>'); \ + if(p && (!o || p < o)) { \ + if(*(p-1) != '/') \ + tags = g_list_prepend(tags, y); \ + xhtml = g_string_append(xhtml, "<" y); \ + c += strlen("<" x ); \ + xhtml = g_string_append_len(xhtml, c, (p - c) + 1); \ + c = p + 1; \ + } else { \ + xhtml = g_string_append(xhtml, "<"); \ + } \ + continue; \ + } \ + if(!g_ascii_strncasecmp(c, "<" x, strlen("<" x)) && \ + (*(c+strlen("<" x)) == '>' || \ + !g_ascii_strncasecmp(c+strlen("<" x), "/>", 2))) { \ + xhtml = g_string_append(xhtml, "<" y); \ + c += strlen("<" x); \ + if(*c != '/') \ + tags = g_list_prepend(tags, y); \ + continue; \ + } +#define ALLOW_TAG(x) ALLOW_TAG_ALT(x, x) + +char *html_to_xhtml(const char *html) { + GString *xhtml = g_string_new(""); + GList *tags = NULL, *tag; + const char *q = NULL, *c = html; + char *ret; + while(*c) { + if(!q && (*c == '\"' || *c == '\'')) { + q = c; + xhtml = g_string_append_c(xhtml, *c); + c++; + } else if(q) { + if(*c == *q) { + q = NULL; + } else if(*c == '\\') { + xhtml = g_string_append_c(xhtml, *c); + c++; + } + xhtml = g_string_append_c(xhtml, *c); + c++; + } else if(*c == '<') { + if(*(c+1) == '/') { /* closing tag */ + tag = tags; + while(tag) { + if(!g_ascii_strncasecmp((c+2), tag->data, strlen(tag->data)) && *(c+strlen(tag->data)+2) == '>') { + c += strlen(tag->data) + 3; + break; + } + tag = tag->next; + } + if(tag) { + while(tags) { + g_string_append_printf(xhtml, "</%s>", (char *)tags->data); + if(tags == tag) + break; + tags = g_list_remove(tags, tags->data); + } + tags = g_list_remove(tags, tag->data); + } else { + /* we tried to close a tag we never opened! escape it + * and move on */ + xhtml = g_string_append(xhtml, "<"); + c++; + } + } else { /* opening tag */ + ALLOW_TAG("a"); + ALLOW_TAG("b"); + ALLOW_TAG("blockquote"); + ALLOW_TAG("body"); + ALLOW_TAG_ALT("bold", "b"); + ALLOW_TAG("br"); + ALLOW_TAG("cite"); + ALLOW_TAG("div"); + ALLOW_TAG("em"); + ALLOW_TAG("font"); + ALLOW_TAG("h1"); + ALLOW_TAG("h2"); + ALLOW_TAG("h3"); + ALLOW_TAG("h4"); + ALLOW_TAG("h5"); + ALLOW_TAG("h6"); + ALLOW_TAG("head"); + ALLOW_TAG("hr"); + ALLOW_TAG("html"); + ALLOW_TAG("i"); + ALLOW_TAG_ALT("italic", "i"); + ALLOW_TAG("li"); + ALLOW_TAG("ol"); + ALLOW_TAG("p"); + ALLOW_TAG("pre"); + ALLOW_TAG("q"); + ALLOW_TAG_ALT("s", "strike"); + ALLOW_TAG("span"); + ALLOW_TAG("strike"); + ALLOW_TAG("strong"); + ALLOW_TAG("sub"); + ALLOW_TAG("sup"); + ALLOW_TAG("title"); + ALLOW_TAG("u"); + ALLOW_TAG_ALT("underline","u"); + ALLOW_TAG("ul"); + + if(!g_ascii_strncasecmp(c, "<!--", strlen("<!--"))) { + char *p = strstr(c + strlen("<!--"), "-->"); + if(p) { + xhtml = g_string_append(xhtml, "<!--"); + c += strlen("<!--"); + continue; + } + } + + xhtml = g_string_append(xhtml, "<"); + c++; + } + } else { + xhtml = g_string_append_c(xhtml, *c); + c++; + } + } + tag = tags; + while(tag) { + g_string_append_printf(xhtml, "</%s>", (char *)tag->data); + tag = tag->next; + } + g_list_free(tags); + ret = g_strdup(xhtml->str); + g_string_free(xhtml, TRUE); + return ret; +}
--- a/src/protocols/jabber/jabber.c Thu Apr 10 00:57:06 2003 +0000 +++ b/src/protocols/jabber/jabber.c Thu Apr 10 06:09:26 2003 +0000 @@ -192,6 +192,7 @@ char *away_msg; char *thread_id; gboolean has_composing; + gboolean has_xhtml; } *jab_res_info; /* @@ -1106,6 +1107,7 @@ jri = g_new0(struct jabber_resource_info, 1); jri->name = g_strdup(res); jri->away_msg = NULL; + jri->has_xhtml = TRUE; jbd->resources = g_slist_append(jbd->resources, jri); } jri->priority = priority; @@ -1256,6 +1258,7 @@ xmlnode y, subj; time_t time_sent = time(NULL); gboolean typing = FALSE; + gboolean has_xhtml = TRUE; char *from = NULL, *msg = NULL, *type = NULL, *topic = NULL; char *thread_id = NULL; @@ -1287,13 +1290,11 @@ if (!type || !strcasecmp(type, "normal") || !strcasecmp(type, "chat")) { from = jid_full(p->from); - /* if ((y = xmlnode_get_tag(p->x, "html"))) { + msg = xmlnode2str(y); + } else if ((y = xmlnode_get_tag(p->x, "body"))) { msg = xmlnode_get_data(y); - } else - */ - if ((y = xmlnode_get_tag(p->x, "body"))) { - msg = xmlnode_get_data(y); + has_xhtml = FALSE; } if (!from) @@ -1320,8 +1321,11 @@ else { int flags = 0; jab_res_info jri = jabber_find_resource(GJ_GC(gjc), from); - if(jri && typing) - jri->has_composing = TRUE; + if(jri) { + if(typing) + jri->has_composing = TRUE; + jri->has_xhtml = has_xhtml; + } if (xmlnode_get_tag(p->x, "gaim")) flags = IM_FLAG_GAIMUSER; jabber_track_convo_thread(gjc, from, thread_id); @@ -1365,12 +1369,9 @@ struct jabber_chat *jc; static int i = 0; - /* if ((y = xmlnode_get_tag(p->x, "html"))) { - msg = xmlnode_get_data(y); - } else - */ - if ((y = xmlnode_get_tag(p->x, "body"))) { + msg = xmlnode2str(y); + } else if ((y = xmlnode_get_tag(p->x, "body"))) { msg = xmlnode_get_data(y); } @@ -2421,11 +2422,36 @@ return JABBER_TYPING_NOTIFY_INT; } +static void insert_message(xmlnode x, const char *message, gboolean use_xhtml) { + xmlnode y; + char *buf = strip_html(message); + y = xmlnode_insert_tag(x, "body"); + xmlnode_insert_cdata(y, buf, -1); + g_free(buf); + + if(use_xhtml) { + char *buf2 = g_strdup_printf("<html xmlns='http://jabber.org/protocol/xhtml-im'><body>%s</body></html>", message); + buf = html_to_xhtml(buf2); + g_free(buf2); + + y = xmlnode_str(buf, strlen(buf)); + if(y) { + xmlnode_insert_tag_node(x, y); + xmlnode_free(y); + } else { + debug_printf("holy cow, html_to_xhtml didn't work right!\n"); + debug_printf("the invalid XML: %s\n", buf); + } + g_free(buf); + } +} + static int jabber_send_im(struct gaim_connection *gc, char *who, char *message, int len, int flags) { xmlnode x, y; char *thread_id = NULL; gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; + jab_res_info jri = jabber_find_resource(gc, who); if (!who || !message) return 0; @@ -2452,8 +2478,7 @@ xmlnode_insert_tag(y, "composing"); if (message && strlen(message)) { - y = xmlnode_insert_tag(x, "body"); - xmlnode_insert_cdata(y, message, -1); + insert_message(x, message, jri ? jri->has_xhtml : TRUE); } gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); @@ -2968,8 +2993,7 @@ g_free(subject); if (message && strlen(message)) { - y = xmlnode_insert_tag(x, "body"); - xmlnode_insert_cdata(y, message, -1); + insert_message(x, message, FALSE); } gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); @@ -3024,8 +3048,7 @@ g_snprintf(buf, sizeof(buf), "/me has changed the subject to: %s", message + strlen("/topic")); xmlnode_insert_cdata(y, buf, -1); } else if (message && strlen(message)) { - y = xmlnode_insert_tag(x, "body"); - xmlnode_insert_cdata(y, message, -1); + insert_message(x, message, FALSE); } gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); @@ -3035,7 +3058,7 @@ static void jabber_chat_whisper(struct gaim_connection *gc, int id, char *who, char *message) { - xmlnode x, y; + xmlnode x; struct jabber_chat *jc = NULL; char *chatname; @@ -3051,8 +3074,7 @@ xmlnode_put_attrib(x, "type", "normal"); if (message && strlen(message)) { - y = xmlnode_insert_tag(x, "body"); - xmlnode_insert_cdata(y, message, -1); + insert_message(x, message, FALSE); } gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
--- a/src/util.c Thu Apr 10 00:57:06 2003 +0000 +++ b/src/util.c Thu Apr 10 06:09:26 2003 +0000 @@ -139,7 +139,7 @@ gint linkify_text(char *text) { - char *c, *t; + char *c, *t, *q = NULL; char *cpy = g_malloc(strlen(text) * 3 + 1); char url_buf[BUF_LEN * 4]; int cnt = 0; @@ -149,7 +149,12 @@ cpy[strlen(text)] = 0; c = cpy; while (*c) { - if (!g_ascii_strncasecmp(c, "<A", 2)) { + if(!q && (*c == '\"' || *c == '\'')) { + q = c; + } else if(q) { + if(*c == *q) + q = NULL; + } else if (!g_ascii_strncasecmp(c, "<A", 2)) { while (1) { if (!g_ascii_strncasecmp(c, "/A>", 3)) { break;