* Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA #include "smiley-parser.h" #include "smiley-custom.h" #include "smiley-theme.h" #define DISPLAY_OUR_CUSTOM_SMILEYS_FOR_INCOMING_MESSAGES 1 PurpleConversation *conv; GHashTable *found_smileys; static PurpleTrie *html_sentry; purple_smiley_parse_check_html(const gchar *word, PurpleSmileyParseData *parse_data) if (G_LIKELY(word[0] == '<')) parse_data->in_html_tag = TRUE; else if (G_LIKELY(word[0] == '>')) parse_data->in_html_tag = FALSE; g_warn_if_fail(word[1] == '\0'); purple_smiley_parse_cb(GString *out, const gchar *word, gpointer _smiley, PurpleSmileyParseData *parse_data = _parse_data; PurpleSmiley *smiley = _smiley; /* a special-case for html_sentry */ purple_smiley_parse_check_html(word, parse_data); if (parse_data->in_html_tag) 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 * PurpleConversationPrivate.remote_smileys. * For outgoing messages, we could pass conv in ui_data (or something). * Or maybe we should use two distinct functions? * To be reconsidered when we had PurpleDude-like objects. purple_smiley_parser_smileify(PurpleConversation *conv, const gchar *html_message, gboolean use_remote_smileys, PurpleSmileyParseCb cb, gpointer ui_data) PurpleSmileyTheme *theme; PurpleSmileyList *theme_smileys = NULL, *remote_smileys = NULL; PurpleTrie *theme_trie = NULL, *custom_trie = NULL, *remote_trie = NULL; GSList tries_sentry, tries_theme, tries_custom, tries_remote; PurpleSmileyParseData parse_data; if (html_message == NULL || html_message[0] == '\0') return g_strdup(html_message); remote_smileys = purple_conversation_get_remote_smileys(conv); remote_trie = purple_smiley_list_get_trie(remote_smileys); if (remote_trie && purple_trie_get_size(remote_trie) == 0) if (purple_conversation_get_features(conv) & PURPLE_CONNECTION_FLAG_ALLOW_CUSTOM_SMILEY) custom_trie = purple_smiley_list_get_trie( purple_smiley_custom_get_list()); #if !DISPLAY_OUR_CUSTOM_SMILEYS_FOR_INCOMING_MESSAGES if (custom_trie && purple_trie_get_size(custom_trie) == 0) theme = purple_smiley_theme_get_current(); theme_smileys = purple_smiley_theme_get_smileys(theme, ui_data); if (theme_smileys != NULL) theme_trie = purple_smiley_list_get_trie(theme_smileys); /* we have absolutely no smileys */ if (theme_trie == NULL && custom_trie == NULL && remote_trie == NULL) return g_strdup(html_message); /* Create a tries list on the stack. */ tries_sentry.data = html_sentry; tries_theme.data = theme_trie; tries_custom.data = custom_trie; tries_remote.data = remote_trie; tries_sentry.next = NULL; tries_theme.next = tries_custom.next = tries_remote.next = NULL; g_slist_last(tries)->next = &tries_remote; g_slist_last(tries)->next = &tries_custom; g_slist_last(tries)->next = &tries_theme; parse_data.job.replace.conv = conv; parse_data.job.replace.cb = cb; parse_data.job.replace.ui_data = ui_data; parse_data.in_html_tag = FALSE; /* TODO: parse greedily (as much as possible) when PurpleTrie * provides support for it. */ return purple_trie_multi_replace(tries, html_message, purple_smiley_parse_cb, &parse_data); purple_smiley_parser_replace(PurpleSmileyList *smileys, const gchar *html_message, PurpleSmileyParseCb cb, gpointer ui_data) PurpleTrie *smileys_trie = NULL; PurpleSmileyParseData parse_data; if (html_message == NULL || html_message[0] == '\0') return g_strdup(html_message); if (smileys == NULL || purple_smiley_list_is_empty(smileys)) return g_strdup(html_message); smileys_trie = purple_smiley_list_get_trie(smileys); g_return_val_if_fail(smileys_trie != NULL, NULL); trie_1.data = html_sentry; trie_2.data = smileys_trie; 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(&trie_1, html_message, purple_smiley_parse_cb, &parse_data); smiley_find_cb(const gchar *word, gpointer _smiley, gpointer _parse_data) PurpleSmiley *smiley = _smiley; PurpleSmileyParseData *parse_data = _parse_data; /* a special-case for html_sentry */ purple_smiley_parse_check_html(word, parse_data); if (parse_data->in_html_tag) g_hash_table_insert(parse_data->job.find.found_smileys, smiley, smiley); purple_smiley_parser_find(PurpleSmileyList *smileys, const gchar *message, PurpleTrie *smileys_trie; gchar *escaped_message = NULL; PurpleSmileyParseData parse_data; if (message == NULL || message[0] == '\0') if (smileys == NULL || purple_smiley_list_is_empty(smileys)) smileys_trie = purple_smiley_list_get_trie(smileys); g_return_val_if_fail(smileys_trie != NULL, NULL); message = escaped_message = g_markup_escape_text(message, -1); parse_data.job.find.found_smileys = g_hash_table_new(g_direct_hash, g_direct_equal); parse_data.in_html_tag = FALSE; trie_1.data = html_sentry; trie_2.data = smileys_trie; purple_trie_multi_find(&trie_1, message, smiley_find_cb, &parse_data); found_list = g_hash_table_get_values(parse_data.job.find.found_smileys); g_hash_table_destroy(parse_data.job.find.found_smileys); _purple_smiley_parser_init(void) html_sentry = purple_trie_new(); purple_trie_add(html_sentry, "<", NULL); purple_trie_add(html_sentry, ">", NULL); _purple_smiley_parser_uninit(void) g_object_unref(html_sentry);