--- a/libpurple/protocols/zephyr/meson.build Sat Jan 02 19:06:28 2021 -0600
+++ b/libpurple/protocols/zephyr/meson.build Sat Jan 02 19:24:01 2021 -0600
@@ -1,4 +1,4 @@
+ZEPHYR_INTERNAL_SOURCES = [ @@ -42,26 +42,30 @@
-ZEPHYRSOURCESEXT = ['zephyr.c', 'zephyr.h']
- ZEPHYRSOURCES = ZEPHYRSOURCESEXT
+ ZEPHYR_SOURCES += ZEPHYR_INTERNAL_SOURCES - zephyr_prpl = shared_library('zephyr', ZEPHYRSOURCES,
+ zephyr_prpl = shared_library('zephyr', ZEPHYR_SOURCES, dependencies : [extdep, libpurple_dep, glib],
install : true, install_dir : PURPLE_PLUGINDIR)
--- a/libpurple/protocols/zephyr/zephyr.c Sat Jan 02 19:06:28 2021 -0600
+++ b/libpurple/protocols/zephyr/zephyr.c Sat Jan 02 19:24:01 2021 -0600
@@ -34,12 +34,9 @@
+#include "zephyr_html.h" #define ZEPHYR_FALLBACK_CHARSET "ISO-8859-1"
@@ -62,7 +59,6 @@
extern char __Zephyr_realm[];
-typedef struct _zframe zframe;
typedef struct _zephyr_triple zephyr_triple;
typedef struct _zephyr_account zephyr_account;
typedef struct _parse_tree parse_tree;
@@ -107,31 +103,6 @@
-/* struct I need for html<->zephyr */
- /* true for everything but @color, since inside the parens of that one is
- /* </i>, </font>, </b>, etc. */
- /* text including the opening html thingie. */
- /* }=1, ]=2, )=4, >=8 */
@@ -387,370 +358,6 @@
-zframe_new_with_text(const gchar *text, const gchar *closing, gboolean has_closer)
- zframe *frame = g_new(zframe, 1);
- frame->text = g_string_new(text);
- frame->closing = closing;
- frame->has_closer = has_closer;
-zframe_new(const gchar *closing, gboolean has_closer)
- return zframe_new_with_text("", closing, has_closer);
-zframe_href_has_prefix(const zframe *frame, const gchar *prefix)
- gsize prefix_len = strlen(prefix);
- return (frame->href->len == (prefix_len + frame->text->len)) &&
- !strncmp(frame->href->str, prefix, prefix_len) &&
- purple_strequal(frame->href->str + prefix_len, frame->text->str);
-html_to_zephyr_pop(GQueue *frames)
- zframe *popped = (zframe *)g_queue_pop_head(frames);
- zframe *head = (zframe *)g_queue_peek_head(frames);
- gsize result = strlen(popped->closing);
- head->href = popped->text;
- g_string_append(head->text, popped->env);
- if (popped->has_closer) {
- g_string_append_c(head->text,
- (popped->closer_mask & 1) ? '{' :
- (popped->closer_mask & 2) ? '[' :
- (popped->closer_mask & 4) ? '(' :
- g_string_append(head->text, popped->text->str);
- if (!purple_strequal(popped->href->str, popped->text->str) &&
- !zframe_href_has_prefix(popped, "http://") &&
- !zframe_href_has_prefix(popped, "mailto:")) {
- g_string_append(head->text, " <");
- g_string_append(head->text, popped->href->str);
- if (popped->closer_mask & ~8) {
- g_string_append_c(head->text, '>');
- popped->closer_mask &= ~8;
- g_string_append(head->text, "@{>}");
- g_string_free(popped->href, TRUE);
- if (popped->has_closer) {
- g_string_append_c(head->text,
- (popped->closer_mask & 1) ? '}' :
- (popped->closer_mask & 2) ? ']' :
- (popped->closer_mask & 4) ? ')' :
- if (!popped->has_closer)
- head->closer_mask = popped->closer_mask;
- g_string_free(popped->text, TRUE);
-/* This parses HTML formatting (put out by one of the gtkimhtml widgets
- And converts it to zephyr formatting.
- It currently deals properly with <b>, <br>, <i>, <font face=...>, <font color=...>,
- It ignores <font back=...>
- <font size = "1 or 2" -> @small
- <a href is dealt with by outputting "description <link>" or just "description" as appropriate
-static char *html_to_zephyr(const char *message)
- GQueue frames = G_QUEUE_INIT;
- frame = zframe_new(NULL, FALSE);
- frame->is_href = FALSE;
- frame->closer_mask = 15;
- g_queue_push_head(&frames, frame);
- purple_debug_info("zephyr","html received %s\n",message);
- frame = (zframe *)g_queue_peek_head(&frames);
- if (frame->closing && purple_str_has_caseprefix(message, frame->closing)) {
- message += html_to_zephyr_pop(&frames);
- } else if (*message == '<') {
- if (!g_ascii_strncasecmp(message + 1, "i>", 2)) {
- new_f = zframe_new("</i>", TRUE);
- new_f->is_href = FALSE;
- new_f->closer_mask = 15;
- g_queue_push_head(&frames, new_f);
- } else if (!g_ascii_strncasecmp(message + 1, "b>", 2)) {
- new_f = zframe_new("</b>", TRUE);
- new_f->is_href = FALSE;
- new_f->closer_mask = 15;
- g_queue_push_head(&frames, new_f);
- } else if (!g_ascii_strncasecmp(message + 1, "br>", 3)) {
- g_string_append_c(frame->text, '\n');
- } else if (!g_ascii_strncasecmp(message + 1, "a href=\"", 8)) {
- new_f = zframe_new("</a>", FALSE);
- new_f->is_href = FALSE;
- new_f->closer_mask = frame->closer_mask;
- g_queue_push_head(&frames, new_f);
- new_f = zframe_new("\">", FALSE);
- new_f->closer_mask = frame->closer_mask;
- g_queue_push_head(&frames, new_f);
- } else if (!g_ascii_strncasecmp(message + 1, "font", 4)) {
- new_f = zframe_new("</font>", TRUE);
- new_f->is_href = FALSE;
- new_f->closer_mask = 15;
- g_queue_push_head(&frames, new_f);
- while (*message == ' ')
- if (!g_ascii_strncasecmp(message, "color=\"", 7)) {
- new_f = zframe_new("\">", TRUE);
- new_f->is_href = FALSE;
- new_f->closer_mask = 15;
- g_queue_push_head(&frames, new_f);
- } else if (!g_ascii_strncasecmp(message, "face=\"", 6)) {
- new_f = zframe_new("\">", TRUE);
- new_f->is_href = FALSE;
- new_f->closer_mask = 15;
- g_queue_push_head(&frames, new_f);
- } else if (!g_ascii_strncasecmp(message, "size=\"", 6)) {
- if ((*message == '1') || (*message == '2')) {
- } else if ((*message == '3')
- || (*message == '4')) {
- new_f->env = "@medium";
- } else if ((*message == '5')
- || (*message == '7')) {
- new_f->has_closer = FALSE;
- new_f->closer_mask = frame->closer_mask;
- /* Drop all unrecognized/misparsed font tags */
- new_f->has_closer = FALSE;
- new_f->closer_mask = frame->closer_mask;
- while (g_ascii_strncasecmp(message, "\">", 2) != 0) {
- /* Catch all for all unrecognized/misparsed <foo> tage */
- g_string_append_c(frame->text, *message++);
- } else if (*message == '@') {
- g_string_append(frame->text, "@@");
- } else if (*message == '}') {
- if (frame->closer_mask & ~1) {
- frame->closer_mask &= ~1;
- g_string_append_c(frame->text, *message++);
- g_string_append(frame->text, "@[}]");
- } else if (*message == ']') {
- if (frame->closer_mask & ~2) {
- frame->closer_mask &= ~2;
- g_string_append_c(frame->text, *message++);
- g_string_append(frame->text, "@{]}");
- } else if (*message == ')') {
- if (frame->closer_mask & ~4) {
- frame->closer_mask &= ~4;
- g_string_append_c(frame->text, *message++);
- g_string_append(frame->text, "@{)}");
- } else if (!g_ascii_strncasecmp(message, ">", 4)) {
- if (frame->closer_mask & ~8) {
- frame->closer_mask &= ~8;
- g_string_append_c(frame->text, *message++);
- g_string_append(frame->text, "@{>}");
- g_string_append_c(frame->text, *message++);
- frame = (zframe *)g_queue_pop_head(&frames);
- ret = g_string_free(frame->text, FALSE);
- purple_debug_info("zephyr","zephyr outputted %s\n",ret);
-zephyr_to_html_pop(GQueue *frames, gboolean *last_had_closer)
- zframe *popped = (zframe *)g_queue_pop_head(frames);
- zframe *head = (zframe *)g_queue_peek_head(frames);
- g_string_append(head->text, popped->text->str);
- g_string_append(head->text, popped->closing);
- if (last_had_closer != NULL) {
- *last_had_closer = popped->has_closer;
- g_string_free(popped->text, TRUE);
-/* this parses zephyr formatting and converts it to html. For example, if
- * you pass in "@{@color(blue)@i(hello)}" you should get out
- * "<font color=blue><i>hello</i></font>". */
-static char *zephyr_to_html(const char *message)
- GQueue frames = G_QUEUE_INIT;
- frame = zframe_new("", FALSE);
- g_queue_push_head(&frames, frame);
- frame = (zframe *)g_queue_peek_head(&frames);
- if (*message == '@' && message[1] == '@') {
- g_string_append(frame->text, "@");
- } else if (*message == '@') {
- while (message[end] && (isalnum(message[end]) || message[end] == '_')) {
- (message[end] == '{' || message[end] == '[' || message[end] == '(' ||
- !g_ascii_strncasecmp(message + end, "<", 4))) {
- buf = g_new0(char, end);
- g_snprintf(buf, end, "%s", message + 1);
- closer = (*message == '{' ? "}" :
- *message == '[' ? "]" :
- *message == '(' ? ")" :
- message += (*message == '&' ? 4 : 1);
- if (!g_ascii_strcasecmp(buf, "italic") || !g_ascii_strcasecmp(buf, "i")) {
- new_f = zframe_new_with_text("<i>", "</i>", TRUE);
- } else if (!g_ascii_strcasecmp(buf, "small")) {
- new_f = zframe_new_with_text("<font size=\"1\">", "</font>", TRUE);
- } else if (!g_ascii_strcasecmp(buf, "medium")) {
- new_f = zframe_new_with_text("<font size=\"3\">", "</font>", TRUE);
- } else if (!g_ascii_strcasecmp(buf, "large")) {
- new_f = zframe_new_with_text("<font size=\"7\">", "</font>", TRUE);
- } else if (!g_ascii_strcasecmp(buf, "bold")
- || !g_ascii_strcasecmp(buf, "b")) {
- new_f = zframe_new_with_text("<b>", "</b>", TRUE);
- } else if (!g_ascii_strcasecmp(buf, "font")) {
- extra_f = zframe_new("</font>", FALSE);
- extra_f->closer = frame->closer;
- g_queue_push_head(&frames, extra_f);
- new_f = zframe_new_with_text("<font face=\"", "\">", TRUE);
- } else if (!g_ascii_strcasecmp(buf, "color")) {
- extra_f = zframe_new("</font>", FALSE);
- extra_f->closer = frame->closer;
- g_queue_push_head(&frames, extra_f);
- new_f = zframe_new_with_text("<font color=\"", "\">", TRUE);
- new_f = zframe_new("", TRUE);
- new_f->closer = closer;
- g_queue_push_head(&frames, new_f);
- /* Not a formatting tag, add the character as normal. */
- g_string_append_c(frame->text, *message++);
- } else if (frame->closer && purple_str_has_caseprefix(message, frame->closer)) {
- message += strlen(frame->closer);
- if (g_queue_get_length(&frames) > 1) {
- gboolean last_had_closer;
- zephyr_to_html_pop(&frames, &last_had_closer);
- } while (g_queue_get_length(&frames) > 1 && !last_had_closer);
- g_string_append_c(frame->text, *message);
- } else if (*message == '\n') {
- g_string_append(frame->text, "<br>");
- g_string_append_c(frame->text, *message++);
- /* go through all the stuff that they didn't close */
- while (g_queue_get_length(&frames) > 1) {
- zephyr_to_html_pop(&frames, NULL);
- frame = (zframe *)g_queue_pop_head(&frames);
- ret = g_string_free(frame->text, FALSE);
static gboolean pending_zloc(zephyr_account *zephyr, const char *who)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/zephyr/zephyr_html.c Sat Jan 02 19:24:01 2021 -0600
@@ -0,0 +1,406 @@
+ * Purple - Internet Messaging Library + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * 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, see <https://www.gnu.org/licenses/>. +#include "zephyr_html.h" +typedef struct _zframe zframe; + /* true for everything but @color, since inside the parens of that one is + /* </i>, </font>, </b>, etc. */ + /* text including the opening html thingie. */ + /* }=1, ]=2, )=4, >=8 */ +zframe_new_with_text(const gchar *text, const gchar *closing, gboolean has_closer) + zframe *frame = g_new(zframe, 1); + frame->text = g_string_new(text); + frame->closing = closing; + frame->has_closer = has_closer; +zframe_new(const gchar *closing, gboolean has_closer) + return zframe_new_with_text("", closing, has_closer); +zframe_href_has_prefix(const zframe *frame, const gchar *prefix) + gsize prefix_len = strlen(prefix); + return (frame->href->len == (prefix_len + frame->text->len)) && + !strncmp(frame->href->str, prefix, prefix_len) && + purple_strequal(frame->href->str + prefix_len, frame->text->str); +html_to_zephyr_pop(GQueue *frames) + zframe *popped = (zframe *)g_queue_pop_head(frames); + zframe *head = (zframe *)g_queue_peek_head(frames); + gsize result = strlen(popped->closing); + head->href = popped->text; + g_string_append(head->text, popped->env); + if (popped->has_closer) { + g_string_append_c(head->text, + (popped->closer_mask & 1) ? '{' : + (popped->closer_mask & 2) ? '[' : + (popped->closer_mask & 4) ? '(' : + g_string_append(head->text, popped->text->str); + if (!purple_strequal(popped->href->str, popped->text->str) && + !zframe_href_has_prefix(popped, "http://") && + !zframe_href_has_prefix(popped, "mailto:")) { + g_string_append(head->text, " <"); + g_string_append(head->text, popped->href->str); + if (popped->closer_mask & ~8) { + g_string_append_c(head->text, '>'); + popped->closer_mask &= ~8; + g_string_append(head->text, "@{>}"); + g_string_free(popped->href, TRUE); + if (popped->has_closer) { + g_string_append_c(head->text, + (popped->closer_mask & 1) ? '}' : + (popped->closer_mask & 2) ? ']' : + (popped->closer_mask & 4) ? ')' : + if (!popped->has_closer) { + head->closer_mask = popped->closer_mask; + g_string_free(popped->text, TRUE); +html_to_zephyr(const char *message) + GQueue frames = G_QUEUE_INIT; + frame = zframe_new(NULL, FALSE); + frame->is_href = FALSE; + frame->closer_mask = 15; + g_queue_push_head(&frames, frame); + purple_debug_info("zephyr", "html received %s\n", message); + frame = (zframe *)g_queue_peek_head(&frames); + if (frame->closing && purple_str_has_caseprefix(message, frame->closing)) { + message += html_to_zephyr_pop(&frames); + } else if (*message == '<') { + if (!g_ascii_strncasecmp(message + 1, "i>", 2)) { + new_f = zframe_new("</i>", TRUE); + new_f->is_href = FALSE; + new_f->closer_mask = 15; + g_queue_push_head(&frames, new_f); + } else if (!g_ascii_strncasecmp(message + 1, "b>", 2)) { + new_f = zframe_new("</b>", TRUE); + new_f->is_href = FALSE; + new_f->closer_mask = 15; + g_queue_push_head(&frames, new_f); + } else if (!g_ascii_strncasecmp(message + 1, "br>", 3)) { + g_string_append_c(frame->text, '\n'); + } else if (!g_ascii_strncasecmp(message + 1, "a href=\"", 8)) { + new_f = zframe_new("</a>", FALSE); + new_f->is_href = FALSE; + new_f->closer_mask = frame->closer_mask; + g_queue_push_head(&frames, new_f); + new_f = zframe_new("\">", FALSE); + new_f->closer_mask = frame->closer_mask; + g_queue_push_head(&frames, new_f); + } else if (!g_ascii_strncasecmp(message + 1, "font", 4)) { + new_f = zframe_new("</font>", TRUE); + new_f->is_href = FALSE; + new_f->closer_mask = 15; + g_queue_push_head(&frames, new_f); + while (*message == ' ') { + if (!g_ascii_strncasecmp(message, "color=\"", 7)) { + new_f = zframe_new("\">", TRUE); + new_f->is_href = FALSE; + new_f->closer_mask = 15; + g_queue_push_head(&frames, new_f); + } else if (!g_ascii_strncasecmp(message, "face=\"", 6)) { + new_f = zframe_new("\">", TRUE); + new_f->is_href = FALSE; + new_f->closer_mask = 15; + g_queue_push_head(&frames, new_f); + } else if (!g_ascii_strncasecmp(message, "size=\"", 6)) { + if ((*message == '1') || (*message == '2')) { + } else if ((*message == '3') || (*message == '4')) { + new_f->env = "@medium"; + } else if ((*message == '5') || (*message == '6') + || (*message == '7')) { + new_f->has_closer = FALSE; + new_f->closer_mask = frame->closer_mask; + /* Drop all unrecognized/misparsed font tags */ + new_f->has_closer = FALSE; + new_f->closer_mask = frame->closer_mask; + while (g_ascii_strncasecmp(message, "\">", 2) != 0) { + if (*message != '\0') { + /* Catch all for all unrecognized/misparsed <foo> tage */ + g_string_append_c(frame->text, *message++); + } else if (*message == '@') { + g_string_append(frame->text, "@@"); + } else if (*message == '}') { + if (frame->closer_mask & ~1) { + frame->closer_mask &= ~1; + g_string_append_c(frame->text, *message++); + g_string_append(frame->text, "@[}]"); + } else if (*message == ']') { + if (frame->closer_mask & ~2) { + frame->closer_mask &= ~2; + g_string_append_c(frame->text, *message++); + g_string_append(frame->text, "@{]}"); + } else if (*message == ')') { + if (frame->closer_mask & ~4) { + frame->closer_mask &= ~4; + g_string_append_c(frame->text, *message++); + g_string_append(frame->text, "@{)}"); + } else if (!g_ascii_strncasecmp(message, ">", 4)) { + if (frame->closer_mask & ~8) { + frame->closer_mask &= ~8; + g_string_append_c(frame->text, *message++); + g_string_append(frame->text, "@{>}"); + g_string_append_c(frame->text, *message++); + frame = (zframe *)g_queue_pop_head(&frames); + ret = g_string_free(frame->text, FALSE); + purple_debug_info("zephyr", "zephyr outputted %s\n", ret); +zephyr_to_html_pop(GQueue *frames, gboolean *last_had_closer) + zframe *popped = (zframe *)g_queue_pop_head(frames); + zframe *head = (zframe *)g_queue_peek_head(frames); + g_string_append(head->text, popped->text->str); + g_string_append(head->text, popped->closing); + if (last_had_closer != NULL) { + *last_had_closer = popped->has_closer; + g_string_free(popped->text, TRUE); +zephyr_to_html(const char *message) + GQueue frames = G_QUEUE_INIT; + frame = zframe_new("", FALSE); + g_queue_push_head(&frames, frame); + frame = (zframe *)g_queue_peek_head(&frames); + if (*message == '@' && message[1] == '@') { + g_string_append(frame->text, "@"); + } else if (*message == '@') { + while (message[end] && (isalnum(message[end]) || message[end] == '_')) { + (message[end] == '{' || message[end] == '[' || message[end] == '(' || + !g_ascii_strncasecmp(message + end, "<", 4))) { + buf = g_new0(char, end); + g_snprintf(buf, end, "%s", message + 1); + closer = (*message == '{' ? "}" : + *message == '[' ? "]" : + *message == '(' ? ")" : + message += (*message == '&' ? 4 : 1); + if (!g_ascii_strcasecmp(buf, "italic") || !g_ascii_strcasecmp(buf, "i")) { + new_f = zframe_new_with_text("<i>", "</i>", TRUE); + } else if (!g_ascii_strcasecmp(buf, "small")) { + new_f = zframe_new_with_text("<font size=\"1\">", "</font>", TRUE); + } else if (!g_ascii_strcasecmp(buf, "medium")) { + new_f = zframe_new_with_text("<font size=\"3\">", "</font>", TRUE); + } else if (!g_ascii_strcasecmp(buf, "large")) { + new_f = zframe_new_with_text("<font size=\"7\">", "</font>", TRUE); + } else if (!g_ascii_strcasecmp(buf, "bold") + || !g_ascii_strcasecmp(buf, "b")) { + new_f = zframe_new_with_text("<b>", "</b>", TRUE); + } else if (!g_ascii_strcasecmp(buf, "font")) { + extra_f = zframe_new("</font>", FALSE); + extra_f->closer = frame->closer; + g_queue_push_head(&frames, extra_f); + new_f = zframe_new_with_text("<font face=\"", "\">", TRUE); + } else if (!g_ascii_strcasecmp(buf, "color")) { + extra_f = zframe_new("</font>", FALSE); + extra_f->closer = frame->closer; + g_queue_push_head(&frames, extra_f); + new_f = zframe_new_with_text("<font color=\"", "\">", TRUE); + new_f = zframe_new("", TRUE); + new_f->closer = closer; + g_queue_push_head(&frames, new_f); + /* Not a formatting tag, add the character as normal. */ + g_string_append_c(frame->text, *message++); + } else if (frame->closer && purple_str_has_caseprefix(message, frame->closer)) { + message += strlen(frame->closer); + if (g_queue_get_length(&frames) > 1) { + gboolean last_had_closer; + zephyr_to_html_pop(&frames, &last_had_closer); + } while (g_queue_get_length(&frames) > 1 && !last_had_closer); + g_string_append_c(frame->text, *message); + } else if (*message == '\n') { + g_string_append(frame->text, "<br>"); + g_string_append_c(frame->text, *message++); + /* go through all the stuff that they didn't close */ + while (g_queue_get_length(&frames) > 1) { + zephyr_to_html_pop(&frames, NULL); + frame = (zframe *)g_queue_pop_head(&frames); + ret = g_string_free(frame->text, FALSE); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/zephyr/zephyr_html.h Sat Jan 02 19:24:01 2021 -0600
@@ -0,0 +1,43 @@
+ * Purple - Internet Messaging Library + * Copyright (C) Pidgin Developers <devel@pidgin.im> + * 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, see <https://www.gnu.org/licenses/>. +#ifndef PURPLE_ZEPHYR_ZEPHYR_HTML_H +#define PURPLE_ZEPHYR_ZEPHYR_HTML_H +/* This parses HTML formatting (put out by one of the gtkimhtml widgets + And converts it to zephyr formatting. + It currently deals properly with <b>, <br>, <i>, <font face=...>, <font color=...>, + It ignores <font back=...> + <font size = "1 or 2" -> @small + <a href is dealt with by outputting "description <link>" or just "description" as appropriate +char *html_to_zephyr(const char *message); +/* This parses zephyr formatting and converts it to html. For example, if + * you pass in "@{@color(blue)@i(hello)}" you should get out + * "<font color=blue><i>hello</i></font>". */ +char *zephyr_to_html(const char *message); +#endif /* PURPLE_ZEPHYR_ZEPHYR_HTML_H */