pidgin/pidgin

Move zephyr<->html conversion to own module

2021-01-02, Arkadiy Illarionov
675b8605dca2
Parents f9ea6d5e8992
Children edbc992e77be
Move zephyr<->html conversion to own module

* Reorganize meson.build
* Also remove unused header

Testing Done:
Compiled.

Reviewed at https://reviews.imfreedom.org/r/302/
--- 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 @@
-ZEPHYRSOURCES = [
+ZEPHYR_INTERNAL_SOURCES = [
'ZAsyncLocate.c',
'ZCkAuth.c',
'ZCkIfNot.c',
@@ -42,26 +42,30 @@
'ZWait4Not.c',
'ZhmStat.c',
'Zinternal.c',
- 'internal.h',
'mit-copyright.h',
'mit-sipb-copyright.h',
- 'sysdep.h',
'zephyr_err.h',
- 'zephyr_internal.h',
- 'zephyr.c',
- 'zephyr.h'
+ 'zephyr_internal.h'
]
-ZEPHYRSOURCESEXT = ['zephyr.c', 'zephyr.h']
+ZEPHYR_SOURCES = [
+ 'internal.h',
+ 'sysdep.h',
+ 'zephyr.c',
+ 'zephyr.h',
+ 'zephyr_html.c',
+ 'zephyr_html.h'
+]
extdep = krb4
if EXTERNAL_LIBZEPHYR
- ZEPHYRSOURCES = ZEPHYRSOURCESEXT
extdep = ext_zephyr
+else
+ ZEPHYR_SOURCES += ZEPHYR_INTERNAL_SOURCES
endif
if DYNAMIC_ZEPHYR
- zephyr_prpl = shared_library('zephyr', ZEPHYRSOURCES,
+ zephyr_prpl = shared_library('zephyr', ZEPHYR_SOURCES,
c_args : '-Dlint',
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 <purple.h>
-#ifndef _WIN32
-# include <arpa/inet.h>
-#endif
-
#include "internal.h"
#include "zephyr.h"
+#include "zephyr_html.h"
#define ZEPHYR_FALLBACK_CHARSET "ISO-8859-1"
@@ -62,7 +59,6 @@
extern char __Zephyr_realm[];
#endif
-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 @@
int num_children;
};
-/* struct I need for html<->zephyr */
-struct _zframe {
- /* common part */
- /* true for everything but @color, since inside the parens of that one is
- * the color. */
- gboolean has_closer;
- /* </i>, </font>, </b>, etc. */
- const char *closing;
- /* text including the opening html thingie. */
- GString *text;
-
- /* html_to_zephyr */
- /* @i, @b, etc. */
- const char *env;
- /* }=1, ]=2, )=4, >=8 */
- int closer_mask;
- /* href for links */
- gboolean is_href;
- GString *href;
-
- /* zephyr_to_html */
- /* }, ], ), > */
- char *closer;
-};
-
struct _zephyr_triple {
char *class;
char *instance;
@@ -387,370 +358,6 @@
}
}
-static zframe *
-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;
-
- return frame;
-}
-
-static inline zframe *
-zframe_new(const gchar *closing, gboolean has_closer)
-{
- return zframe_new_with_text("", closing, has_closer);
-}
-
-static gboolean
-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);
-}
-
-static gsize
-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);
-
- if (popped->is_href) {
- head->href = popped->text;
- } else {
- 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 (popped->href)
- {
- 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;
- } else {
- 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);
- }
- g_free(popped);
- return result;
-}
-
-/* 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=...>
- It does
- <font size = "1 or 2" -> @small
- 3 or 4 @medium()
- 5,6, or 7 @large()
- <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;
- zframe *frame, *new_f;
- char *ret;
-
- if (*message == '\0')
- return g_strdup("");
-
- frame = zframe_new(NULL, FALSE);
- frame->href = NULL;
- frame->is_href = FALSE;
- frame->env = "";
- frame->closer_mask = 15;
-
- g_queue_push_head(&frames, frame);
-
- purple_debug_info("zephyr","html received %s\n",message);
- while (*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->href = NULL;
- new_f->is_href = FALSE;
- new_f->env = "@i";
- new_f->closer_mask = 15;
- g_queue_push_head(&frames, new_f);
- message += 3;
- } else if (!g_ascii_strncasecmp(message + 1, "b>", 2)) {
- new_f = zframe_new("</b>", TRUE);
- new_f->href = NULL;
- new_f->is_href = FALSE;
- new_f->env = "@b";
- new_f->closer_mask = 15;
- g_queue_push_head(&frames, new_f);
- message += 3;
- } else if (!g_ascii_strncasecmp(message + 1, "br>", 3)) {
- g_string_append_c(frame->text, '\n');
- message += 4;
- } else if (!g_ascii_strncasecmp(message + 1, "a href=\"", 8)) {
- message += 9;
- new_f = zframe_new("</a>", FALSE);
- new_f->href = NULL;
- new_f->is_href = FALSE;
- new_f->env = "";
- new_f->closer_mask = frame->closer_mask;
- g_queue_push_head(&frames, new_f);
- new_f = zframe_new("\">", FALSE);
- new_f->href = NULL;
- new_f->is_href = TRUE;
- 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->href = NULL;
- new_f->is_href = FALSE;
- new_f->closer_mask = 15;
- g_queue_push_head(&frames, new_f);
- message += 5;
- while (*message == ' ')
- message++;
- if (!g_ascii_strncasecmp(message, "color=\"", 7)) {
- message += 7;
- new_f->env = "@";
- new_f = zframe_new("\">", TRUE);
- new_f->env = "@color";
- new_f->href = NULL;
- 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)) {
- message += 6;
- new_f->env = "@";
- new_f = zframe_new("\">", TRUE);
- new_f->env = "@font";
- new_f->href = NULL;
- 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)) {
- message += 6;
- if ((*message == '1') || (*message == '2')) {
- new_f->env = "@small";
- } else if ((*message == '3')
- || (*message == '4')) {
- new_f->env = "@medium";
- } else if ((*message == '5')
- || (*message == '6')
- || (*message == '7')) {
- new_f->env = "@large";
- } else {
- new_f->env = "";
- new_f->has_closer = FALSE;
- new_f->closer_mask = frame->closer_mask;
- }
- message += 3;
- } else {
- /* Drop all unrecognized/misparsed font tags */
- new_f->env = "";
- new_f->has_closer = FALSE;
- new_f->closer_mask = frame->closer_mask;
- while (g_ascii_strncasecmp(message, "\">", 2) != 0) {
- message++;
- }
- if (*message != '\0')
- message += 2;
- }
- } else {
- /* Catch all for all unrecognized/misparsed <foo> tage */
- g_string_append_c(frame->text, *message++);
- }
- } else if (*message == '@') {
- g_string_append(frame->text, "@@");
- message++;
- } else if (*message == '}') {
- if (frame->closer_mask & ~1) {
- frame->closer_mask &= ~1;
- g_string_append_c(frame->text, *message++);
- } else {
- g_string_append(frame->text, "@[}]");
- message++;
- }
- } else if (*message == ']') {
- if (frame->closer_mask & ~2) {
- frame->closer_mask &= ~2;
- g_string_append_c(frame->text, *message++);
- } else {
- g_string_append(frame->text, "@{]}");
- message++;
- }
- } else if (*message == ')') {
- if (frame->closer_mask & ~4) {
- frame->closer_mask &= ~4;
- g_string_append_c(frame->text, *message++);
- } else {
- g_string_append(frame->text, "@{)}");
- message++;
- }
- } else if (!g_ascii_strncasecmp(message, "&gt;", 4)) {
- if (frame->closer_mask & ~8) {
- frame->closer_mask &= ~8;
- g_string_append_c(frame->text, *message++);
- } else {
- g_string_append(frame->text, "@{>}");
- message += 4;
- }
- } else {
- g_string_append_c(frame->text, *message++);
- }
- }
- frame = (zframe *)g_queue_pop_head(&frames);
- ret = g_string_free(frame->text, FALSE);
- g_free(frame);
- purple_debug_info("zephyr","zephyr outputted %s\n",ret);
- return ret;
-}
-
-static void
-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);
- g_free(popped);
-}
-
-/* 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;
- zframe *frame;
- char *ret;
-
- frame = zframe_new("", FALSE);
- frame->closer = NULL;
-
- g_queue_push_head(&frames, frame);
-
- while (*message) {
- frame = (zframe *)g_queue_peek_head(&frames);
- if (*message == '@' && message[1] == '@') {
- g_string_append(frame->text, "@");
- message += 2;
- } else if (*message == '@') {
- int end = 1;
- while (message[end] && (isalnum(message[end]) || message[end] == '_')) {
- end++;
- }
- if (message[end] &&
- (message[end] == '{' || message[end] == '[' || message[end] == '(' ||
- !g_ascii_strncasecmp(message + end, "&lt;", 4))) {
- zframe *new_f;
- char *buf;
- char *closer;
- buf = g_new0(char, end);
- g_snprintf(buf, end, "%s", message + 1);
- message += end;
- closer = (*message == '{' ? "}" :
- *message == '[' ? "]" :
- *message == '(' ? ")" :
- "&gt;");
- 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")) {
- zframe *extra_f;
- 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")) {
- zframe *extra_f;
- 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);
- } else {
- new_f = zframe_new("", TRUE);
- }
- new_f->closer = closer;
- g_queue_push_head(&frames, new_f);
- g_free(buf);
- } else {
- /* 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;
-
- do {
- zephyr_to_html_pop(&frames, &last_had_closer);
- } while (g_queue_get_length(&frames) > 1 && !last_had_closer);
- } else {
- g_string_append_c(frame->text, *message);
- }
- } else if (*message == '\n') {
- g_string_append(frame->text, "<br>");
- message++;
- } else {
- 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);
- g_free(frame);
- return ret;
-}
-
static gboolean pending_zloc(zephyr_account *zephyr, const char *who)
{
GList *curr;
--- /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
+ * source distribution.
+ *
+ * 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 <ctype.h>
+
+#include <purple.h>
+
+#include "zephyr_html.h"
+
+typedef struct _zframe zframe;
+
+struct _zframe {
+ /* common part */
+ /* true for everything but @color, since inside the parens of that one is
+ * the color. */
+ gboolean has_closer;
+ /* </i>, </font>, </b>, etc. */
+ const char *closing;
+ /* text including the opening html thingie. */
+ GString *text;
+
+ /* html_to_zephyr */
+ /* @i, @b, etc. */
+ const char *env;
+ /* }=1, ]=2, )=4, >=8 */
+ int closer_mask;
+ /* href for links */
+ gboolean is_href;
+ GString *href;
+
+ /* zephyr_to_html */
+ /* }, ], ), > */
+ char *closer;
+};
+
+static zframe *
+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;
+
+ return frame;
+}
+
+static inline zframe *
+zframe_new(const gchar *closing, gboolean has_closer)
+{
+ return zframe_new_with_text("", closing, has_closer);
+}
+
+static gboolean
+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);
+}
+
+static gsize
+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);
+
+ if (popped->is_href) {
+ head->href = popped->text;
+ } else {
+ 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 (popped->href) {
+ 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;
+ } else {
+ 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);
+ }
+ g_free(popped);
+ return result;
+}
+
+char *
+html_to_zephyr(const char *message)
+{
+ GQueue frames = G_QUEUE_INIT;
+ zframe *frame, *new_f;
+ char *ret;
+
+ if (*message == '\0')
+ return g_strdup("");
+
+ frame = zframe_new(NULL, FALSE);
+ frame->href = NULL;
+ frame->is_href = FALSE;
+ frame->env = "";
+ frame->closer_mask = 15;
+
+ g_queue_push_head(&frames, frame);
+
+ purple_debug_info("zephyr", "html received %s\n", message);
+ while (*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->href = NULL;
+ new_f->is_href = FALSE;
+ new_f->env = "@i";
+ new_f->closer_mask = 15;
+ g_queue_push_head(&frames, new_f);
+ message += 3;
+ } else if (!g_ascii_strncasecmp(message + 1, "b>", 2)) {
+ new_f = zframe_new("</b>", TRUE);
+ new_f->href = NULL;
+ new_f->is_href = FALSE;
+ new_f->env = "@b";
+ new_f->closer_mask = 15;
+ g_queue_push_head(&frames, new_f);
+ message += 3;
+ } else if (!g_ascii_strncasecmp(message + 1, "br>", 3)) {
+ g_string_append_c(frame->text, '\n');
+ message += 4;
+ } else if (!g_ascii_strncasecmp(message + 1, "a href=\"", 8)) {
+ message += 9;
+ new_f = zframe_new("</a>", FALSE);
+ new_f->href = NULL;
+ new_f->is_href = FALSE;
+ new_f->env = "";
+ new_f->closer_mask = frame->closer_mask;
+ g_queue_push_head(&frames, new_f);
+ new_f = zframe_new("\">", FALSE);
+ new_f->href = NULL;
+ new_f->is_href = TRUE;
+ 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->href = NULL;
+ new_f->is_href = FALSE;
+ new_f->closer_mask = 15;
+ g_queue_push_head(&frames, new_f);
+ message += 5;
+ while (*message == ' ') {
+ message++;
+ }
+ if (!g_ascii_strncasecmp(message, "color=\"", 7)) {
+ message += 7;
+ new_f->env = "@";
+ new_f = zframe_new("\">", TRUE);
+ new_f->env = "@color";
+ new_f->href = NULL;
+ 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)) {
+ message += 6;
+ new_f->env = "@";
+ new_f = zframe_new("\">", TRUE);
+ new_f->env = "@font";
+ new_f->href = NULL;
+ 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)) {
+ message += 6;
+ if ((*message == '1') || (*message == '2')) {
+ new_f->env = "@small";
+ } else if ((*message == '3') || (*message == '4')) {
+ new_f->env = "@medium";
+ } else if ((*message == '5') || (*message == '6')
+ || (*message == '7')) {
+ new_f->env = "@large";
+ } else {
+ new_f->env = "";
+ new_f->has_closer = FALSE;
+ new_f->closer_mask = frame->closer_mask;
+ }
+ message += 3;
+ } else {
+ /* Drop all unrecognized/misparsed font tags */
+ new_f->env = "";
+ new_f->has_closer = FALSE;
+ new_f->closer_mask = frame->closer_mask;
+ while (g_ascii_strncasecmp(message, "\">", 2) != 0) {
+ message++;
+ }
+ if (*message != '\0') {
+ message += 2;
+ }
+ }
+ } else {
+ /* Catch all for all unrecognized/misparsed <foo> tage */
+ g_string_append_c(frame->text, *message++);
+ }
+ } else if (*message == '@') {
+ g_string_append(frame->text, "@@");
+ message++;
+ } else if (*message == '}') {
+ if (frame->closer_mask & ~1) {
+ frame->closer_mask &= ~1;
+ g_string_append_c(frame->text, *message++);
+ } else {
+ g_string_append(frame->text, "@[}]");
+ message++;
+ }
+ } else if (*message == ']') {
+ if (frame->closer_mask & ~2) {
+ frame->closer_mask &= ~2;
+ g_string_append_c(frame->text, *message++);
+ } else {
+ g_string_append(frame->text, "@{]}");
+ message++;
+ }
+ } else if (*message == ')') {
+ if (frame->closer_mask & ~4) {
+ frame->closer_mask &= ~4;
+ g_string_append_c(frame->text, *message++);
+ } else {
+ g_string_append(frame->text, "@{)}");
+ message++;
+ }
+ } else if (!g_ascii_strncasecmp(message, "&gt;", 4)) {
+ if (frame->closer_mask & ~8) {
+ frame->closer_mask &= ~8;
+ g_string_append_c(frame->text, *message++);
+ } else {
+ g_string_append(frame->text, "@{>}");
+ message += 4;
+ }
+ } else {
+ g_string_append_c(frame->text, *message++);
+ }
+ }
+ frame = (zframe *)g_queue_pop_head(&frames);
+ ret = g_string_free(frame->text, FALSE);
+ g_free(frame);
+ purple_debug_info("zephyr", "zephyr outputted %s\n", ret);
+ return ret;
+}
+
+static void
+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);
+ g_free(popped);
+}
+
+char *
+zephyr_to_html(const char *message)
+{
+ GQueue frames = G_QUEUE_INIT;
+ zframe *frame;
+ char *ret;
+
+ frame = zframe_new("", FALSE);
+ frame->closer = NULL;
+
+ g_queue_push_head(&frames, frame);
+
+ while (*message) {
+ frame = (zframe *)g_queue_peek_head(&frames);
+ if (*message == '@' && message[1] == '@') {
+ g_string_append(frame->text, "@");
+ message += 2;
+ } else if (*message == '@') {
+ int end = 1;
+ while (message[end] && (isalnum(message[end]) || message[end] == '_')) {
+ end++;
+ }
+ if (message[end] &&
+ (message[end] == '{' || message[end] == '[' || message[end] == '(' ||
+ !g_ascii_strncasecmp(message + end, "&lt;", 4))) {
+ zframe *new_f;
+ char *buf;
+ char *closer;
+ buf = g_new0(char, end);
+ g_snprintf(buf, end, "%s", message + 1);
+ message += end;
+ closer = (*message == '{' ? "}" :
+ *message == '[' ? "]" :
+ *message == '(' ? ")" :
+ "&gt;");
+ 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")) {
+ zframe *extra_f;
+ 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")) {
+ zframe *extra_f;
+ 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);
+ } else {
+ new_f = zframe_new("", TRUE);
+ }
+ new_f->closer = closer;
+ g_queue_push_head(&frames, new_f);
+ g_free(buf);
+ } else {
+ /* 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;
+
+ do {
+ zephyr_to_html_pop(&frames, &last_had_closer);
+ } while (g_queue_get_length(&frames) > 1 && !last_had_closer);
+ } else {
+ g_string_append_c(frame->text, *message);
+ }
+ } else if (*message == '\n') {
+ g_string_append(frame->text, "<br>");
+ message++;
+ } else {
+ 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);
+ g_free(frame);
+ return ret;
+}
--- /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
+ * source distribution.
+ *
+ * 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=...>
+ It does
+ <font size = "1 or 2" -> @small
+ 3 or 4 @medium()
+ 5,6, or 7 @large()
+ <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 */