Mercurial > pidgin
comparison libpurple/protocols/myspace/markup.c @ 19434:1e00b684c46f
In msimprpl, move formatting functions to a markup module. It only exposes
two functions to convert between MySpaceIM markup and Purple HTML markup.
author | Jeffrey Connelly <jaconnel@calpoly.edu> |
---|---|
date | Sun, 26 Aug 2007 06:51:17 +0000 |
parents | |
children | bddc6a6fddf0 |
comparison
equal
deleted
inserted
replaced
19433:9a1b28a10c95 | 19434:1e00b684c46f |
---|---|
1 /* MySpaceIM Protocol Plugin - markup | |
2 * | |
3 * Copyright (C) 2007, Jeff Connelly <jeff2@soc.pidgin.im> | |
4 * | |
5 * This program is free software; you can redistribute it and/or modify | |
6 * it under the terms of the GNU General Public License as published by | |
7 * the Free Software Foundation; either version 2 of the License, or | |
8 * (at your option) any later version. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 * GNU General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU General Public License | |
16 * along with this program; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 #include "myspace.h" | |
21 | |
22 /* Internal functions */ | |
23 | |
24 static guint msim_point_to_purple_size(MsimSession *session, guint point); | |
25 static guint msim_purple_size_to_point(MsimSession *session, guint size); | |
26 static guint msim_height_to_point(MsimSession *session, guint height); | |
27 static guint msim_point_to_height(MsimSession *session, guint point); | |
28 | |
29 static void msim_markup_tag_to_html(MsimSession *, xmlnode *root, gchar **begin, gchar **end); | |
30 static void html_tag_to_msim_markup(MsimSession *, xmlnode *root, gchar **begin, gchar **end); | |
31 static gchar *msim_convert_xml(MsimSession *, const gchar *raw, MSIM_XMLNODE_CONVERT f); | |
32 static gchar *msim_convert_smileys_to_markup(gchar *before); | |
33 static double msim_round(double round); | |
34 | |
35 | |
36 /* Globals */ | |
37 | |
38 /* The names in in emoticon_names (for <i n=whatever>) map to corresponding | |
39 * entries in emoticon_symbols (for the ASCII representation of the emoticon). | |
40 * | |
41 * Multiple emoticon symbols in Pidgin can map to one name. List the | |
42 * canonical form, as inserted by the "Smile!" dialog, first. For example, | |
43 * :) comes before :-), because although both are recognized as 'happy', | |
44 * the first is inserted by the smiley button (first symbol in theme). | |
45 * | |
46 * Note that symbols are case-sensitive in Pidgin -- :-X is not :-x. */ | |
47 static struct MSIM_EMOTICON | |
48 { | |
49 gchar *name; | |
50 gchar *symbol; | |
51 } msim_emoticons[] = { | |
52 /* Unfortunately, this list duplicates much of the file | |
53 * pidgin/pidgin/pixmaps/emotes/default/22/default.theme.in, because | |
54 * that file is part of Pidgin, but we're part of libpurple. | |
55 */ | |
56 { "bigsmile", ":D" }, | |
57 { "bigsmile", ":-D" }, | |
58 { "devil", "}:)" }, | |
59 { "frazzled", ":Z" }, | |
60 { "geek", "B)" }, | |
61 { "googles", "%)" }, | |
62 { "growl", ":E" }, | |
63 { "laugh", ":))" }, /* Must be before ':)' */ | |
64 { "happy", ":)" }, | |
65 { "happy", ":-)" }, | |
66 { "happi", ":)" }, | |
67 { "heart", ":X" }, | |
68 { "mohawk", "-:" }, | |
69 { "mad", "X(" }, | |
70 { "messed", "X)" }, | |
71 { "nerd", "Q)" }, | |
72 { "oops", ":G" }, | |
73 { "pirate", "P)" }, | |
74 { "scared", ":O" }, | |
75 { "sidefrown", ":{" }, | |
76 { "sinister", ":B" }, | |
77 { "smirk", ":," }, | |
78 { "straight", ":|" }, | |
79 { "tongue", ":P" }, | |
80 { "tongue", ":p" }, | |
81 { "tongy", ":P" }, | |
82 { "upset", "B|" }, | |
83 { "wink", ";-)" }, | |
84 { "wink", ";)" }, | |
85 { "winc", ";)" }, | |
86 { "worried", ":[" }, | |
87 { "kiss", ":x" }, | |
88 { NULL, NULL } | |
89 }; | |
90 | |
91 | |
92 | |
93 /* Indexes of this array + 1 map HTML font size to scale of normal font size. * | |
94 * Based on _point_sizes from libpurple/gtkimhtml.c | |
95 * 1 2 3 4 5 6 7 */ | |
96 static gdouble _font_scale[] = { .85, .95, 1, 1.2, 1.44, 1.728, 2.0736 }; | |
97 | |
98 #define MAX_FONT_SIZE 7 /* Purple maximum font size */ | |
99 #define POINTS_PER_INCH 72 /* How many pt's in an inch */ | |
100 | |
101 /* round is part of C99, but sometimes is unavailable before then. | |
102 * Based on http://forums.belution.com/en/cpp/000/050/13.shtml | |
103 */ | |
104 double msim_round(double value) | |
105 { | |
106 if (value < 0) { | |
107 return -(floor(-value + 0.5)); | |
108 } else { | |
109 return floor( value + 0.5); | |
110 } | |
111 } | |
112 | |
113 | |
114 /** Convert typographical font point size to HTML font size. | |
115 * Based on libpurple/gtkimhtml.c */ | |
116 static guint | |
117 msim_point_to_purple_size(MsimSession *session, guint point) | |
118 { | |
119 guint size, this_point, base; | |
120 gdouble scale; | |
121 | |
122 base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE); | |
123 | |
124 for (size = 0; | |
125 size < sizeof(_font_scale) / sizeof(_font_scale[0]); | |
126 ++size) { | |
127 scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1]; | |
128 this_point = (guint)msim_round(scale * base); | |
129 | |
130 if (this_point >= point) { | |
131 purple_debug_info("msim", "msim_point_to_purple_size: %d pt -> size=%d\n", | |
132 point, size); | |
133 return size; | |
134 } | |
135 } | |
136 | |
137 /* No HTML font size was this big; return largest possible. */ | |
138 return this_point; | |
139 } | |
140 | |
141 /** Convert HTML font size to point size. */ | |
142 static guint | |
143 msim_purple_size_to_point(MsimSession *session, guint size) | |
144 { | |
145 gdouble scale; | |
146 guint point; | |
147 guint base; | |
148 | |
149 scale = _font_scale[CLAMP(size, 1, MAX_FONT_SIZE) - 1]; | |
150 | |
151 base = purple_account_get_int(session->account, "base_font_size", MSIM_BASE_FONT_POINT_SIZE); | |
152 | |
153 point = (guint)msim_round(scale * base); | |
154 | |
155 purple_debug_info("msim", "msim_purple_size_to_point: size=%d -> %d pt\n", | |
156 size, point); | |
157 | |
158 return point; | |
159 } | |
160 | |
161 /** Convert a msim markup font pixel height to the more usual point size, for incoming messages. */ | |
162 static guint | |
163 msim_height_to_point(MsimSession *session, guint height) | |
164 { | |
165 guint dpi; | |
166 | |
167 dpi = purple_account_get_int(session->account, "port", MSIM_DEFAULT_DPI); | |
168 | |
169 return (guint)msim_round((POINTS_PER_INCH * 1. / dpi) * height); | |
170 | |
171 /* See also: libpurple/protocols/bonjour/jabber.c | |
172 * _font_size_ichat_to_purple */ | |
173 } | |
174 | |
175 /** Convert point size to msim pixel height font size specification, for outgoing messages. */ | |
176 static guint | |
177 msim_point_to_height(MsimSession *session, guint point) | |
178 { | |
179 guint dpi; | |
180 | |
181 dpi = purple_account_get_int(session->account, "port", MSIM_DEFAULT_DPI); | |
182 | |
183 return (guint)msim_round((dpi * 1. / POINTS_PER_INCH) * point); | |
184 } | |
185 | |
186 /** Convert the msim markup <f> (font) tag into HTML. */ | |
187 static void | |
188 msim_markup_f_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) | |
189 { | |
190 const gchar *face, *height_str, *decor_str; | |
191 GString *gs_end, *gs_begin; | |
192 guint decor, height; | |
193 | |
194 face = xmlnode_get_attrib(root, "f"); | |
195 height_str = xmlnode_get_attrib(root, "h"); | |
196 decor_str = xmlnode_get_attrib(root, "s"); | |
197 | |
198 if (height_str) { | |
199 height = atol(height_str); | |
200 } else { | |
201 height = 12; | |
202 } | |
203 | |
204 if (decor_str) { | |
205 decor = atol(decor_str); | |
206 } else { | |
207 decor = 0; | |
208 } | |
209 | |
210 gs_begin = g_string_new(""); | |
211 /* TODO: get font size working */ | |
212 if (height && !face) { | |
213 g_string_printf(gs_begin, "<font size='%d'>", | |
214 msim_point_to_purple_size(session, msim_height_to_point(session, height))); | |
215 } else if (height && face) { | |
216 g_string_printf(gs_begin, "<font face='%s' size='%d'>", face, | |
217 msim_point_to_purple_size(session, msim_height_to_point(session, height))); | |
218 } else { | |
219 g_string_printf(gs_begin, "<font>"); | |
220 } | |
221 | |
222 /* No support for font-size CSS? */ | |
223 /* g_string_printf(gs_begin, "<span style='font-family: %s; font-size: %dpt'>", face, | |
224 msim_height_to_point(height)); */ | |
225 | |
226 gs_end = g_string_new("</font>"); | |
227 | |
228 if (decor & MSIM_TEXT_BOLD) { | |
229 g_string_append(gs_begin, "<b>"); | |
230 g_string_prepend(gs_end, "</b>"); | |
231 } | |
232 | |
233 if (decor & MSIM_TEXT_ITALIC) { | |
234 g_string_append(gs_begin, "<i>"); | |
235 g_string_append(gs_end, "</i>"); | |
236 } | |
237 | |
238 if (decor & MSIM_TEXT_UNDERLINE) { | |
239 g_string_append(gs_begin, "<u>"); | |
240 g_string_append(gs_end, "</u>"); | |
241 } | |
242 | |
243 | |
244 *begin = gs_begin->str; | |
245 *end = gs_end->str; | |
246 } | |
247 | |
248 /** Convert a msim markup color to a color suitable for libpurple. | |
249 * | |
250 * @param msim Either a color name, or an rgb(x,y,z) code. | |
251 * | |
252 * @return A new string, either a color name or #rrggbb code. Must g_free(). | |
253 */ | |
254 static char * | |
255 msim_color_to_purple(const char *msim) | |
256 { | |
257 guint red, green, blue; | |
258 | |
259 if (!msim) { | |
260 return g_strdup("black"); | |
261 } | |
262 | |
263 if (sscanf(msim, "rgb(%d,%d,%d)", &red, &green, &blue) != 3) { | |
264 /* Color name. */ | |
265 return g_strdup(msim); | |
266 } | |
267 /* TODO: rgba (alpha). */ | |
268 | |
269 return g_strdup_printf("#%.2x%.2x%.2x", red, green, blue); | |
270 } | |
271 | |
272 /** Convert the msim markup <a> (anchor) tag into HTML. */ | |
273 static void | |
274 msim_markup_a_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) | |
275 { | |
276 const gchar *href; | |
277 | |
278 href = xmlnode_get_attrib(root, "h"); | |
279 if (!href) { | |
280 href = ""; | |
281 } | |
282 | |
283 *begin = g_strdup_printf("<a href=\"%s\">%s", href, href); | |
284 *end = g_strdup("</a>"); | |
285 } | |
286 | |
287 /** Convert the msim markup <p> (paragraph) tag into HTML. */ | |
288 static void | |
289 msim_markup_p_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) | |
290 { | |
291 /* Just pass through unchanged. | |
292 * | |
293 * Note: attributes currently aren't passed, if there are any. */ | |
294 *begin = g_strdup("<p>"); | |
295 *end = g_strdup("</p>"); | |
296 } | |
297 | |
298 /** Convert the msim markup <c> tag (text color) into HTML. TODO: Test */ | |
299 static void | |
300 msim_markup_c_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) | |
301 { | |
302 const gchar *color; | |
303 gchar *purple_color; | |
304 | |
305 color = xmlnode_get_attrib(root, "v"); | |
306 if (!color) { | |
307 purple_debug_info("msim", "msim_markup_c_to_html: <c> tag w/o v attr"); | |
308 *begin = g_strdup(""); | |
309 *end = g_strdup(""); | |
310 /* TODO: log as unrecognized */ | |
311 return; | |
312 } | |
313 | |
314 purple_color = msim_color_to_purple(color); | |
315 | |
316 *begin = g_strdup_printf("<font color='%s'>", purple_color); | |
317 | |
318 g_free(purple_color); | |
319 | |
320 /* *begin = g_strdup_printf("<span style='color: %s'>", color); */ | |
321 *end = g_strdup("</font>"); | |
322 } | |
323 | |
324 /** Convert the msim markup <b> tag (background color) into HTML. TODO: Test */ | |
325 static void | |
326 msim_markup_b_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) | |
327 { | |
328 const gchar *color; | |
329 gchar *purple_color; | |
330 | |
331 color = xmlnode_get_attrib(root, "v"); | |
332 if (!color) { | |
333 *begin = g_strdup(""); | |
334 *end = g_strdup(""); | |
335 purple_debug_info("msim", "msim_markup_b_to_html: <b> w/o v attr"); | |
336 /* TODO: log as unrecognized. */ | |
337 return; | |
338 } | |
339 | |
340 purple_color = msim_color_to_purple(color); | |
341 | |
342 /* TODO: find out how to set background color. */ | |
343 *begin = g_strdup_printf("<span style='background-color: %s'>", | |
344 purple_color); | |
345 g_free(purple_color); | |
346 | |
347 *end = g_strdup("</p>"); | |
348 } | |
349 | |
350 /** Convert the msim markup <i> tag (emoticon image) into HTML. */ | |
351 static void | |
352 msim_markup_i_to_html(MsimSession *session, xmlnode *root, gchar **begin, gchar **end) | |
353 { | |
354 const gchar *name; | |
355 guint i; | |
356 struct MSIM_EMOTICON *emote; | |
357 | |
358 name = xmlnode_get_attrib(root, "n"); | |
359 if (!name) { | |
360 purple_debug_info("msim", "msim_markup_i_to_html: <i> w/o n"); | |
361 *begin = g_strdup(""); | |
362 *end = g_strdup(""); | |
363 /* TODO: log as unrecognized */ | |
364 return; | |
365 } | |
366 | |
367 /* Find and use canonical form of smiley symbol. */ | |
368 for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) { | |
369 if (g_str_equal(name, emote->name)) { | |
370 *begin = g_strdup(emote->symbol); | |
371 *end = g_strdup(""); | |
372 return; | |
373 } | |
374 } | |
375 | |
376 /* Couldn't find it, sorry. Try to degrade gracefully. */ | |
377 *begin = g_strdup_printf("**%s**", name); | |
378 *end = g_strdup(""); | |
379 } | |
380 | |
381 /** Convert an individual msim markup tag to HTML. */ | |
382 static void | |
383 msim_markup_tag_to_html(MsimSession *session, xmlnode *root, gchar **begin, | |
384 gchar **end) | |
385 { | |
386 if (g_str_equal(root->name, "f")) { | |
387 msim_markup_f_to_html(session, root, begin, end); | |
388 } else if (g_str_equal(root->name, "a")) { | |
389 msim_markup_a_to_html(session, root, begin, end); | |
390 } else if (g_str_equal(root->name, "p")) { | |
391 msim_markup_p_to_html(session, root, begin, end); | |
392 } else if (g_str_equal(root->name, "c")) { | |
393 msim_markup_c_to_html(session, root, begin, end); | |
394 } else if (g_str_equal(root->name, "b")) { | |
395 msim_markup_b_to_html(session, root, begin, end); | |
396 } else if (g_str_equal(root->name, "i")) { | |
397 msim_markup_i_to_html(session, root, begin, end); | |
398 } else { | |
399 purple_debug_info("msim", "msim_markup_tag_to_html: " | |
400 "unknown tag name=%s, ignoring", | |
401 (root && root->name) ? root->name : "(NULL)"); | |
402 *begin = g_strdup(""); | |
403 *end = g_strdup(""); | |
404 } | |
405 } | |
406 | |
407 /** Convert an individual HTML tag to msim markup. */ | |
408 static void | |
409 html_tag_to_msim_markup(MsimSession *session, xmlnode *root, gchar **begin, | |
410 gchar **end) | |
411 { | |
412 /* TODO: Coalesce nested tags into one <f> tag! | |
413 * Currently, the 's' value will be overwritten when b/i/u is nested | |
414 * within another one, and only the inner-most formatting will be | |
415 * applied to the text. */ | |
416 if (!purple_utf8_strcasecmp(root->name, "root")) { | |
417 *begin = g_strdup(""); | |
418 *end = g_strdup(""); | |
419 } else if (!purple_utf8_strcasecmp(root->name, "b")) { | |
420 *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD); | |
421 *end = g_strdup("</f>"); | |
422 } else if (!purple_utf8_strcasecmp(root->name, "i")) { | |
423 *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_ITALIC); | |
424 *end = g_strdup("</f>"); | |
425 } else if (!purple_utf8_strcasecmp(root->name, "u")) { | |
426 *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_UNDERLINE); | |
427 *end = g_strdup("</f>"); | |
428 } else if (!purple_utf8_strcasecmp(root->name, "a")) { | |
429 const gchar *href, *link_text; | |
430 | |
431 href = xmlnode_get_attrib(root, "href"); | |
432 | |
433 if (!href) { | |
434 href = xmlnode_get_attrib(root, "HREF"); | |
435 } | |
436 | |
437 link_text = xmlnode_get_data(root); | |
438 | |
439 if (href) { | |
440 if (g_str_equal(link_text, href)) { | |
441 /* Purple gives us: <a href="URL">URL</a> | |
442 * Translate to <a h='URL' /> | |
443 * Displayed as text of URL with link to URL | |
444 */ | |
445 *begin = g_strdup_printf("<a h='%s' />", href); | |
446 } else { | |
447 /* But if we get: <a href="URL">text</a> | |
448 * Translate to: text: <a h='URL' /> | |
449 * | |
450 * Because official client only supports self-closed <a> | |
451 * tags; you can't change the link text. | |
452 */ | |
453 *begin = g_strdup_printf("%s: <a h='%s' />", link_text, href); | |
454 } | |
455 } else { | |
456 *begin = g_strdup("<a />"); | |
457 } | |
458 | |
459 /* Sorry, kid. MySpace doesn't support you within <a> tags. */ | |
460 xmlnode_free(root->child); | |
461 root->child = NULL; | |
462 | |
463 *end = g_strdup(""); | |
464 } else if (!purple_utf8_strcasecmp(root->name, "font")) { | |
465 const gchar *size; | |
466 const gchar *face; | |
467 | |
468 size = xmlnode_get_attrib(root, "size"); | |
469 face = xmlnode_get_attrib(root, "face"); | |
470 | |
471 if (face && size) { | |
472 *begin = g_strdup_printf("<f f='%s' h='%d'>", face, | |
473 msim_point_to_height(session, | |
474 msim_purple_size_to_point(session, atoi(size)))); | |
475 } else if (face) { | |
476 *begin = g_strdup_printf("<f f='%s'>", face); | |
477 } else if (size) { | |
478 *begin = g_strdup_printf("<f h='%d'>", | |
479 msim_point_to_height(session, | |
480 msim_purple_size_to_point(session, atoi(size)))); | |
481 } else { | |
482 *begin = g_strdup("<f>"); | |
483 } | |
484 | |
485 *end = g_strdup("</f>"); | |
486 | |
487 /* TODO: color (bg uses <body>), emoticons */ | |
488 } else { | |
489 *begin = g_strdup_printf("[%s]", root->name); | |
490 *end = g_strdup_printf("[/%s]", root->name); | |
491 } | |
492 } | |
493 | |
494 /** Convert an xmlnode of msim markup or HTML to an HTML string or msim markup. | |
495 * | |
496 * @param f Function to convert tags. | |
497 * | |
498 * @return An HTML string. Caller frees. | |
499 */ | |
500 static gchar * | |
501 msim_convert_xmlnode(MsimSession *session, xmlnode *root, MSIM_XMLNODE_CONVERT f) | |
502 { | |
503 xmlnode *node; | |
504 gchar *begin, *inner, *end; | |
505 GString *final; | |
506 | |
507 if (!root || !root->name) { | |
508 return g_strdup(""); | |
509 } | |
510 | |
511 purple_debug_info("msim", "msim_convert_xmlnode: got root=%s\n", | |
512 root->name); | |
513 | |
514 begin = inner = end = NULL; | |
515 | |
516 final = g_string_new(""); | |
517 | |
518 f(session, root, &begin, &end); | |
519 | |
520 g_string_append(final, begin); | |
521 | |
522 /* Loop over all child nodes. */ | |
523 for (node = root->child; node != NULL; node = node->next) { | |
524 switch (node->type) { | |
525 case XMLNODE_TYPE_ATTRIB: | |
526 /* Attributes handled above. */ | |
527 break; | |
528 | |
529 case XMLNODE_TYPE_TAG: | |
530 /* A tag or tag with attributes. Recursively descend. */ | |
531 inner = msim_convert_xmlnode(session, node, f); | |
532 g_return_val_if_fail(inner != NULL, NULL); | |
533 | |
534 purple_debug_info("msim", " ** node name=%s\n", | |
535 (node && node->name) ? node->name : "(NULL)"); | |
536 break; | |
537 | |
538 case XMLNODE_TYPE_DATA: | |
539 /* Literal text. */ | |
540 inner = g_new0(char, node->data_sz + 1); | |
541 strncpy(inner, node->data, node->data_sz); | |
542 inner[node->data_sz] = 0; | |
543 | |
544 purple_debug_info("msim", " ** node data=%s\n", | |
545 inner ? inner : "(NULL)"); | |
546 break; | |
547 | |
548 default: | |
549 purple_debug_info("msim", | |
550 "msim_convert_xmlnode: strange node\n"); | |
551 inner = g_strdup(""); | |
552 } | |
553 | |
554 if (inner) { | |
555 g_string_append(final, inner); | |
556 } | |
557 } | |
558 | |
559 /* TODO: Note that msim counts each piece of text enclosed by <f> as | |
560 * a paragraph and will display each on its own line. You actually have | |
561 * to _nest_ <f> tags to intersperse different text in one paragraph! | |
562 * Comment out this line below to see. */ | |
563 g_string_append(final, end); | |
564 | |
565 purple_debug_info("msim", "msim_markup_xmlnode_to_gtkhtml: RETURNING %s\n", | |
566 (final && final->str) ? final->str : "(NULL)"); | |
567 | |
568 return final->str; | |
569 } | |
570 | |
571 /** Convert XML to something based on MSIM_XMLNODE_CONVERT. */ | |
572 static gchar * | |
573 msim_convert_xml(MsimSession *session, const gchar *raw, MSIM_XMLNODE_CONVERT f) | |
574 { | |
575 xmlnode *root; | |
576 gchar *str; | |
577 gchar *enclosed_raw; | |
578 | |
579 g_return_val_if_fail(raw != NULL, NULL); | |
580 | |
581 /* Enclose text in one root tag, to try to make it valid XML for parsing. */ | |
582 enclosed_raw = g_strconcat("<root>", raw, "</root>", NULL); | |
583 | |
584 root = xmlnode_from_str(enclosed_raw, -1); | |
585 | |
586 if (!root) { | |
587 purple_debug_info("msim", "msim_markup_to_html: couldn't parse " | |
588 "%s as XML, returning raw: %s\n", enclosed_raw, raw); | |
589 /* TODO: msim_unrecognized */ | |
590 g_free(enclosed_raw); | |
591 return g_strdup(raw); | |
592 } | |
593 | |
594 g_free(enclosed_raw); | |
595 | |
596 str = msim_convert_xmlnode(session, root, f); | |
597 g_return_val_if_fail(str != NULL, NULL); | |
598 purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str); | |
599 | |
600 xmlnode_free(root); | |
601 | |
602 return str; | |
603 } | |
604 | |
605 /** Convert plaintext smileys to <i> markup tags. | |
606 * | |
607 * @param before Original text with ASCII smileys. Will be freed. | |
608 * @return A new string with <i> tags, if applicable. Must be g_free()'d. | |
609 */ | |
610 static gchar * | |
611 msim_convert_smileys_to_markup(gchar *before) | |
612 { | |
613 gchar *old, *new, *replacement; | |
614 guint i; | |
615 struct MSIM_EMOTICON *emote; | |
616 | |
617 old = before; | |
618 new = NULL; | |
619 | |
620 for (i = 0; (emote = &msim_emoticons[i]) && emote->name != NULL; ++i) { | |
621 gchar *name, *symbol; | |
622 | |
623 name = emote->name; | |
624 symbol = emote->symbol; | |
625 | |
626 replacement = g_strdup_printf("<i n=\"%s\"/>", name); | |
627 | |
628 purple_debug_info("msim", "msim_convert_smileys_to_markup: %s->%s\n", | |
629 symbol ? symbol : "(NULL)", | |
630 replacement ? replacement : "(NULL)"); | |
631 new = str_replace(old, symbol, replacement); | |
632 | |
633 g_free(replacement); | |
634 g_free(old); | |
635 | |
636 old = new; | |
637 } | |
638 | |
639 return new; | |
640 } | |
641 | |
642 | |
643 /** High-level function to convert MySpaceIM markup to Purple (HTML) markup. | |
644 * | |
645 * @return Purple markup string, must be g_free()'d. */ | |
646 gchar * | |
647 msim_markup_to_html(MsimSession *session, const gchar *raw) | |
648 { | |
649 return msim_convert_xml(session, raw, | |
650 (MSIM_XMLNODE_CONVERT)(msim_markup_tag_to_html)); | |
651 } | |
652 | |
653 /** High-level function to convert Purple (HTML) to MySpaceIM markup. | |
654 * | |
655 * @return HTML markup string, must be g_free()'d. */ | |
656 gchar * | |
657 html_to_msim_markup(MsimSession *session, const gchar *raw) | |
658 { | |
659 gchar *markup; | |
660 | |
661 markup = msim_convert_xml(session, raw, | |
662 (MSIM_XMLNODE_CONVERT)(html_tag_to_msim_markup)); | |
663 | |
664 if (purple_account_get_bool(session->account, "emoticons", TRUE)) { | |
665 /* Frees markup and allocates a new one. */ | |
666 markup = msim_convert_smileys_to_markup(markup); | |
667 } | |
668 | |
669 return markup; | |
670 } | |
671 | |
672 |