/pidgin/main: afa6d777bc7c: Smileys: avoid breaking (x)html by n...

Tomasz Wasilczyk twasilczyk at pidgin.im
Mon Apr 7 09:52:29 EDT 2014


Changeset: afa6d777bc7cb8f20ff121acc3fd9343a7d6d1e7
Author:	 Tomasz Wasilczyk <twasilczyk at pidgin.im>
Date:	 2014-04-07 15:52 +0200
Branch:	 default
URL: https://hg.pidgin.im/pidgin/main/rev/afa6d777bc7c

Description:

Smileys: avoid breaking (x)html by not replacing smileys inside tags

diffstat:

 libpurple/protocols/jabber/message.c |  83 ++++++++++++-----------------------
 libpurple/smiley-parser.c            |  38 ++++++++++++++-
 libpurple/smiley-parser.h            |  23 +++++++++-
 pidgin/gtkconv.c                     |   4 +-
 4 files changed, 87 insertions(+), 61 deletions(-)

diffs (230 lines):

diff --git a/libpurple/protocols/jabber/message.c b/libpurple/protocols/jabber/message.c
--- a/libpurple/protocols/jabber/message.c
+++ b/libpurple/protocols/jabber/message.c
@@ -849,57 +849,6 @@ jabber_message_get_mimetype_from_ext(con
 	}
 }
 
-static gchar *
-jabber_message_get_smileyfied_xhtml(const gchar *xhtml, const GList *smileys)
-{
-	/* create XML element for all smileys (img tags) */
-	GString *result = g_string_new(NULL);
-	int pos = 0;
-	int length = strlen(xhtml);
-
-	while (pos < length) {
-		const GList *iterator;
-		gboolean found_smiley = FALSE;
-
-		for (iterator = smileys ; iterator ;
-			iterator = g_list_next(iterator)) {
-			const PurpleSmiley *smiley = (PurpleSmiley *) iterator->data;
-			const gchar *shortcut = purple_smiley_get_shortcut(smiley);
-			const gssize len = strlen(shortcut);
-			gchar *escaped = g_markup_escape_text(shortcut, len);
-
-			/* TODO: it doesn't take care of text inside a tag.
-			 * Use purple_smiley_parse. */
-			if (g_str_has_prefix(&(xhtml[pos]), escaped)) {
-				/* we found the current smiley at this position */
-				const JabberData *data =
-					jabber_data_find_local_by_alt(shortcut);
-				PurpleXmlNode *img = jabber_data_get_xhtml_im(data, shortcut);
-				int len;
-				gchar *img_text = purple_xmlnode_to_str(img, &len);
-
-				found_smiley = TRUE;
-				result = g_string_append(result, img_text);
-				g_free(img_text);
-				pos += strlen(escaped);
-				g_free(escaped);
-				purple_xmlnode_free(img);
-				break;
-			} else {
-				/* cleanup from the before the next round... */
-				g_free(escaped);
-			}
-		}
-		if (!found_smiley) {
-			/* there was no smiley here, just copy one byte */
-			result = g_string_append_c(result, xhtml[pos]);
-			pos++;
-		}
-	}
-
-	return g_string_free(result, FALSE);
-}
-
 static gboolean
 jabber_conv_support_custom_smileys(JabberStream *js,
 								   PurpleConversation *conv,
@@ -931,6 +880,32 @@ jabber_conv_support_custom_smileys(Jabbe
 	}
 }
 
+static gboolean
+jabber_message_smileyify_cb(GString *out, PurpleSmiley *smiley,
+	PurpleConversation *_empty, gpointer _unused)
+{
+	const gchar *shortcut;
+	const JabberData *data;
+	PurpleXmlNode *smiley_node;
+	gchar *node_xml;
+
+	shortcut = purple_smiley_get_shortcut(smiley);
+	data = jabber_data_find_local_by_alt(shortcut);
+
+	if (!data)
+		return FALSE;
+
+	smiley_node = jabber_data_get_xhtml_im(data, shortcut);
+	node_xml = purple_xmlnode_to_str(smiley_node, NULL);
+
+	g_string_append(out, node_xml);
+
+	purple_xmlnode_free(smiley_node);
+	g_free(node_xml);
+
+	return TRUE;
+}
+
 static char *
 jabber_message_smileyfy_xhtml(JabberMessage *jm, const char *xhtml)
 {
@@ -1013,10 +988,10 @@ jabber_message_smileyfy_xhtml(JabberMess
 		jabber_data_associate_local(jdata, shortcut);
 	}
 
-	smileyfied_xhtml = jabber_message_get_smileyfied_xhtml(xhtml,
-		found_smileys);
+	g_list_free(found_smileys);
 
-	g_list_free(found_smileys);
+	smileyfied_xhtml = purple_smiley_parse_custom(xhtml,
+		jabber_message_smileyify_cb, NULL);
 
 	return smileyfied_xhtml;
 }
diff --git a/libpurple/smiley-parser.c b/libpurple/smiley-parser.c
--- a/libpurple/smiley-parser.c
+++ b/libpurple/smiley-parser.c
@@ -73,10 +73,8 @@ purple_smiley_parse_cb(GString *out, con
 	if (parse_data->in_html_tag)
 		return FALSE;
 
-	parse_data->job.replace.cb(out, smiley, parse_data->job.replace.conv,
-		parse_data->job.replace.ui_data);
-
-	return TRUE;
+	return parse_data->job.replace.cb(out, smiley,
+		parse_data->job.replace.conv, parse_data->job.replace.ui_data);
 }
 
 /* XXX: this shouldn't be a conv for incoming messages - see
@@ -158,6 +156,38 @@ purple_smiley_parse(PurpleConversation *
 		purple_smiley_parse_cb, &parse_data);
 }
 
+gchar *
+purple_smiley_parse_custom(const gchar *html_message, PurpleSmileyParseCb cb,
+	gpointer ui_data)
+{
+	PurpleTrie *custom_trie = NULL;
+	GSList *tries = NULL;
+	GSList tries_sentry, tries_custom;
+	PurpleSmileyParseData parse_data;
+
+	if (html_message == NULL || html_message[0] == '\0')
+		return g_strdup(html_message);
+
+	custom_trie = purple_smiley_list_get_trie(
+		purple_smiley_custom_get_list());
+	if (!custom_trie || purple_trie_get_size(custom_trie) == 0)
+		return g_strdup(html_message);
+
+	tries_sentry.data = html_sentry;
+	tries_custom.data = custom_trie;
+	tries_sentry.next = &tries_custom;
+	tries_custom.next = NULL;
+	tries = &tries_sentry;
+
+	parse_data.job.replace.conv = NULL;
+	parse_data.job.replace.cb = cb;
+	parse_data.job.replace.ui_data = ui_data;
+	parse_data.in_html_tag = FALSE;
+
+	return purple_trie_multi_replace(tries, html_message,
+		purple_smiley_parse_cb, &parse_data);
+}
+
 static gboolean
 smiley_find_cb(const gchar *word, gpointer _smiley, gpointer _found_smileys)
 {
diff --git a/libpurple/smiley-parser.h b/libpurple/smiley-parser.h
--- a/libpurple/smiley-parser.h
+++ b/libpurple/smiley-parser.h
@@ -40,14 +40,19 @@
  * PurpleSmileyParseCb:
  * @out: the message buffer.
  * @smiley: found smiley.
- * @conv: the conversation of a message.
+ * @conv: the conversation of a message (or %NULL, if not passed).
  * @ui_data: the data being passed to #purple_smiley_parse.
  *
  * A replace callback for the found @smiley. It should append a HTML tag
  * representing the @smiley to the @out string. It must not modify the
  * @out string in other way than appending to its end.
+ *
+ * If callback decides not to replace a smiley, it must not modify
+ * @out in any way.
+ *
+ * Returns: %TRUE if the smiley was inserted.
  */
-typedef void (*PurpleSmileyParseCb)(GString *out, PurpleSmiley *smiley,
+typedef gboolean (*PurpleSmileyParseCb)(GString *out, PurpleSmiley *smiley,
 	PurpleConversation *conv, gpointer ui_data);
 
 /**
@@ -72,6 +77,20 @@ purple_smiley_parse(PurpleConversation *
 	gboolean use_remote_smileys, PurpleSmileyParseCb cb, gpointer ui_data);
 
 /**
+ * purple_smiley_parse_custom:
+ * @html_message:
+ * @cb:
+ * @ui_data:
+ *
+ * TODO
+ *
+ * Returns: TODO
+ */
+gchar *
+purple_smiley_parse_custom(const gchar *html_message, PurpleSmileyParseCb cb,
+	gpointer ui_data);
+
+/**
  * purple_smiley_find:
  * @smileys: the list of smileys to find.
  * @message: the message.
diff --git a/pidgin/gtkconv.c b/pidgin/gtkconv.c
--- a/pidgin/gtkconv.c
+++ b/pidgin/gtkconv.c
@@ -6627,7 +6627,7 @@ pidgin_conv_remote_smiley_got(PurpleSmil
 	g_free(js);
 }
 
-static void
+static gboolean
 pidgin_conv_write_smiley(GString *out, PurpleSmiley *smiley,
 	PurpleConversation *conv, gpointer _proto_name)
 {
@@ -6664,6 +6664,8 @@ pidgin_conv_write_smiley(GString *out, P
 	}
 
 	g_free(escaped_shortcut);
+
+	return TRUE;
 }
 
 static void



More information about the Commits mailing list