3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 #include "smiley-parser.h"
24 #include "smiley-custom.h"
25 #include "smiley-theme.h"
27 #define DISPLAY_OUR_CUSTOM_SMILEYS_FOR_INCOMING_MESSAGES 1
33 PurpleConversation
*conv
;
34 PurpleSmileyParseCb cb
;
38 GHashTable
*found_smileys
;
43 } PurpleSmileyParseData
;
45 static PurpleTrie
*html_sentry
;
48 purple_smiley_parse_check_html(const gchar
*word
,
49 PurpleSmileyParseData
*parse_data
)
51 if (G_LIKELY(word
[0] == '<'))
52 parse_data
->in_html_tag
= TRUE
;
53 else if (G_LIKELY(word
[0] == '>'))
54 parse_data
->in_html_tag
= FALSE
;
56 g_return_if_reached();
57 g_warn_if_fail(word
[1] == '\0');
61 purple_smiley_parse_cb(GString
*out
, const gchar
*word
, gpointer _smiley
,
64 PurpleSmileyParseData
*parse_data
= _parse_data
;
65 PurpleSmiley
*smiley
= _smiley
;
67 /* a special-case for html_sentry */
69 purple_smiley_parse_check_html(word
, parse_data
);
73 if (parse_data
->in_html_tag
)
76 return parse_data
->job
.replace
.cb(out
, smiley
,
77 parse_data
->job
.replace
.conv
, parse_data
->job
.replace
.ui_data
);
80 /* XXX: this shouldn't be a conv for incoming messages - see
81 * PurpleConversationPrivate.remote_smileys.
82 * For outgoing messages, we could pass conv in ui_data (or something).
83 * Or maybe we should use two distinct functions?
84 * To be reconsidered when we had PurpleDude-like objects.
87 purple_smiley_parser_smileify(PurpleConversation
*conv
, const gchar
*html_message
,
88 gboolean use_remote_smileys
, PurpleSmileyParseCb cb
, gpointer ui_data
)
90 PurpleSmileyTheme
*theme
;
91 PurpleSmileyList
*theme_smileys
= NULL
, *remote_smileys
= NULL
;
92 PurpleTrie
*theme_trie
= NULL
, *custom_trie
= NULL
, *remote_trie
= NULL
;
94 GSList tries_sentry
, tries_theme
, tries_custom
, tries_remote
;
95 PurpleSmileyParseData parse_data
;
97 if (html_message
== NULL
|| html_message
[0] == '\0')
98 return g_strdup(html_message
);
100 /* get remote smileys */
101 if (use_remote_smileys
)
102 remote_smileys
= purple_conversation_get_remote_smileys(conv
);
104 remote_trie
= purple_smiley_list_get_trie(remote_smileys
);
105 if (remote_trie
&& purple_trie_get_size(remote_trie
) == 0)
108 /* get custom smileys */
109 if (purple_conversation_get_features(conv
) &
110 PURPLE_CONNECTION_FLAG_ALLOW_CUSTOM_SMILEY
)
112 custom_trie
= purple_smiley_list_get_trie(
113 purple_smiley_custom_get_list());
114 #if !DISPLAY_OUR_CUSTOM_SMILEYS_FOR_INCOMING_MESSAGES
115 if (use_remote_smileys
)
119 if (custom_trie
&& purple_trie_get_size(custom_trie
) == 0)
122 /* get theme smileys */
123 theme
= purple_smiley_theme_get_current();
125 theme_smileys
= purple_smiley_theme_get_smileys(theme
, ui_data
);
126 if (theme_smileys
!= NULL
)
127 theme_trie
= purple_smiley_list_get_trie(theme_smileys
);
129 /* we have absolutely no smileys */
130 if (theme_trie
== NULL
&& custom_trie
== NULL
&& remote_trie
== NULL
)
131 return g_strdup(html_message
);
133 /* Create a tries list on the stack. */
134 tries_sentry
.data
= html_sentry
;
135 tries_theme
.data
= theme_trie
;
136 tries_custom
.data
= custom_trie
;
137 tries_remote
.data
= remote_trie
;
138 tries_sentry
.next
= NULL
;
139 tries_theme
.next
= tries_custom
.next
= tries_remote
.next
= NULL
;
140 tries
= &tries_sentry
;
141 if (remote_trie
!= NULL
)
142 g_slist_last(tries
)->next
= &tries_remote
;
143 if (custom_trie
!= NULL
)
144 g_slist_last(tries
)->next
= &tries_custom
;
145 if (theme_trie
!= NULL
)
146 g_slist_last(tries
)->next
= &tries_theme
;
148 parse_data
.job
.replace
.conv
= conv
;
149 parse_data
.job
.replace
.cb
= cb
;
150 parse_data
.job
.replace
.ui_data
= ui_data
;
151 parse_data
.in_html_tag
= FALSE
;
153 /* TODO: parse greedily (as much as possible) when PurpleTrie
154 * provides support for it. */
155 return purple_trie_multi_replace(tries
, html_message
,
156 purple_smiley_parse_cb
, &parse_data
);
160 purple_smiley_parser_replace(PurpleSmileyList
*smileys
,
161 const gchar
*html_message
, PurpleSmileyParseCb cb
, gpointer ui_data
)
163 PurpleTrie
*smileys_trie
= NULL
;
164 GSList trie_1
, trie_2
;
165 PurpleSmileyParseData parse_data
;
167 if (html_message
== NULL
|| html_message
[0] == '\0')
168 return g_strdup(html_message
);
170 if (smileys
== NULL
|| purple_smiley_list_is_empty(smileys
))
171 return g_strdup(html_message
);
173 smileys_trie
= purple_smiley_list_get_trie(smileys
);
174 g_return_val_if_fail(smileys_trie
!= NULL
, NULL
);
176 trie_1
.data
= html_sentry
;
177 trie_2
.data
= smileys_trie
;
178 trie_1
.next
= &trie_2
;
181 parse_data
.job
.replace
.conv
= NULL
;
182 parse_data
.job
.replace
.cb
= cb
;
183 parse_data
.job
.replace
.ui_data
= ui_data
;
184 parse_data
.in_html_tag
= FALSE
;
186 return purple_trie_multi_replace(&trie_1
, html_message
,
187 purple_smiley_parse_cb
, &parse_data
);
191 smiley_find_cb(const gchar
*word
, gpointer _smiley
, gpointer _parse_data
)
193 PurpleSmiley
*smiley
= _smiley
;
194 PurpleSmileyParseData
*parse_data
= _parse_data
;
196 /* a special-case for html_sentry */
197 if (smiley
== NULL
) {
198 purple_smiley_parse_check_html(word
, parse_data
);
202 if (parse_data
->in_html_tag
)
205 g_hash_table_insert(parse_data
->job
.find
.found_smileys
, smiley
, smiley
);
211 purple_smiley_parser_find(PurpleSmileyList
*smileys
, const gchar
*message
,
214 PurpleTrie
*smileys_trie
;
216 gchar
*escaped_message
= NULL
;
217 PurpleSmileyParseData parse_data
;
218 GSList trie_1
, trie_2
;
220 if (message
== NULL
|| message
[0] == '\0')
223 if (smileys
== NULL
|| purple_smiley_list_is_empty(smileys
))
226 smileys_trie
= purple_smiley_list_get_trie(smileys
);
227 g_return_val_if_fail(smileys_trie
!= NULL
, NULL
);
230 message
= escaped_message
= g_markup_escape_text(message
, -1);
232 parse_data
.job
.find
.found_smileys
=
233 g_hash_table_new(g_direct_hash
, g_direct_equal
);
234 parse_data
.in_html_tag
= FALSE
;
236 trie_1
.data
= html_sentry
;
237 trie_2
.data
= smileys_trie
;
238 trie_1
.next
= &trie_2
;
240 purple_trie_multi_find(&trie_1
, message
, smiley_find_cb
, &parse_data
);
242 g_free(escaped_message
);
244 found_list
= g_hash_table_get_values(parse_data
.job
.find
.found_smileys
);
245 g_hash_table_destroy(parse_data
.job
.find
.found_smileys
);
251 _purple_smiley_parser_init(void)
253 html_sentry
= purple_trie_new();
254 purple_trie_add(html_sentry
, "<", NULL
);
255 purple_trie_add(html_sentry
, ">", NULL
);
259 _purple_smiley_parser_uninit(void)
261 g_object_unref(html_sentry
);