--- a/libpurple/protocols/zephyr/zephyr.c Fri Dec 18 04:26:19 2020 -0600
+++ b/libpurple/protocols/zephyr/zephyr.c Fri Dec 18 04:40:41 2020 -0600
@@ -113,25 +113,29 @@
-/* struct I need for zephyr_to_html */
+/* 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. */
- /* </i>, </font>, </b>, etc. */
- /* text including the opening html thingie. */
- struct _zframe *enclosing;
@@ -387,6 +391,24 @@
+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)
@@ -397,6 +419,56 @@
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=...>,
@@ -407,159 +479,88 @@
<a href is dealt with by outputting "description <link>" or just "description" as appropriate
static char *html_to_zephyr(const char *message)
- zframe *frames, *new_f;
+ GQueue frames = G_QUEUE_INIT; - frames = g_new(zframe, 1);
- frames->text = g_string_new("");
- frames->is_href = FALSE;
- frames->enclosing = NULL;
- frames->closing = NULL;
- frames->has_closer = FALSE;
- frames->closer_mask = 15;
+ 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);
- if (frames->closing && purple_str_has_caseprefix(message, frames->closing)) {
- message += strlen(frames->closing);
- frames = frames->enclosing;
- frames->href = popped->text;
- g_string_append(frames->text, popped->env);
- if (popped->has_closer) {
- g_string_append_c(frames->text,
- (popped->closer_mask & 1) ? '{' :
- (popped->closer_mask & 2) ? '[' :
- (popped->closer_mask & 4) ? '(' :
- g_string_append(frames->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(frames->text, " <");
- g_string_append(frames->text, popped->href->str);
- if (popped->closer_mask & ~8) {
- g_string_append_c(frames->text, '>');
- popped->closer_mask &= ~8;
- g_string_append(frames->text, "@{>}");
- g_string_free(popped->href, TRUE);
- if (popped->has_closer) {
- g_string_append_c(frames->text,
- (popped->closer_mask & 1) ? '}' :
- (popped->closer_mask & 2) ? ']' :
- (popped->closer_mask & 4) ? ')' :
- if (!popped->has_closer)
- frames->closer_mask = popped->closer_mask;
- g_string_free(popped->text, TRUE);
+ 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 = g_new(zframe, 1);
- new_f->enclosing = frames;
- new_f->text = g_string_new("");
+ new_f = zframe_new("</i>", TRUE); - new_f->closing = "</i>";
- new_f->has_closer = TRUE;
+ g_queue_push_head(&frames, new_f); } else if (!g_ascii_strncasecmp(message + 1, "b>", 2)) {
- new_f = g_new(zframe, 1);
- new_f->enclosing = frames;
- new_f->text = g_string_new("");
+ new_f = zframe_new("</b>", TRUE); - new_f->closing = "</b>";
- new_f->has_closer = TRUE;
+ g_queue_push_head(&frames, new_f); } else if (!g_ascii_strncasecmp(message + 1, "br>", 3)) {
- g_string_append_c(frames->text, '\n');
+ g_string_append_c(frame->text, '\n'); } else if (!g_ascii_strncasecmp(message + 1, "a href=\"", 8)) {
- new_f = g_new(zframe, 1);
- new_f->enclosing = frames;
- new_f->text = g_string_new("");
+ new_f = zframe_new("</a>", FALSE); - new_f->closing = "</a>";
- new_f->has_closer = FALSE;
- new_f->closer_mask = frames->closer_mask;
- new_f = g_new(zframe, 1);
- new_f->enclosing = frames;
- new_f->text = g_string_new("");
+ new_f->closer_mask = frame->closer_mask; + g_queue_push_head(&frames, new_f); + new_f = zframe_new("\">", FALSE); - new_f->closing = "\">";
- new_f->has_closer = FALSE;
- new_f->closer_mask = frames->closer_mask;
+ 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 = g_new(zframe, 1);
- new_f->enclosing = frames;
- new_f->text = g_string_new("");
+ new_f = zframe_new("</font>", TRUE); - new_f->closing = "</font>";
- new_f->has_closer = TRUE;
+ g_queue_push_head(&frames, new_f); if (!g_ascii_strncasecmp(message, "color=\"", 7)) {
- new_f = g_new(zframe, 1);
- new_f->enclosing = frames;
+ new_f = zframe_new("\">", TRUE); - new_f->text = g_string_new("");
- new_f->closing = "\">";
- new_f->has_closer = TRUE;
+ g_queue_push_head(&frames, new_f); } else if (!g_ascii_strncasecmp(message, "face=\"", 6)) {
- new_f = g_new(zframe, 1);
- new_f->enclosing = frames;
+ new_f = zframe_new("\">", TRUE); - new_f->text = g_string_new("");
- new_f->closing = "\">";
- new_f->has_closer = TRUE;
+ g_queue_push_head(&frames, new_f); } else if (!g_ascii_strncasecmp(message, "size=\"", 6)) {
if ((*message == '1') || (*message == '2')) {
@@ -574,79 +575,78 @@
new_f->has_closer = FALSE;
- new_f->closer_mask = frames->closer_mask;
+ new_f->closer_mask = frame->closer_mask; /* Drop all unrecognized/misparsed font tags */
new_f->has_closer = FALSE;
- new_f->closer_mask = frames->closer_mask;
+ 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(frames->text, *message++);
+ g_string_append_c(frame->text, *message++); } else if (*message == '@') {
- g_string_append(frames->text, "@@");
+ g_string_append(frame->text, "@@"); } else if (*message == '}') {
- if (frames->closer_mask & ~1) {
- frames->closer_mask &= ~1;
- g_string_append_c(frames->text, *message++);
+ if (frame->closer_mask & ~1) { + frame->closer_mask &= ~1; + g_string_append_c(frame->text, *message++); - g_string_append(frames->text, "@[}]");
+ g_string_append(frame->text, "@[}]"); } else if (*message == ']') {
- if (frames->closer_mask & ~2) {
- frames->closer_mask &= ~2;
- g_string_append_c(frames->text, *message++);
+ if (frame->closer_mask & ~2) { + frame->closer_mask &= ~2; + g_string_append_c(frame->text, *message++); - g_string_append(frames->text, "@{]}");
+ g_string_append(frame->text, "@{]}"); } else if (*message == ')') {
- if (frames->closer_mask & ~4) {
- frames->closer_mask &= ~4;
- g_string_append_c(frames->text, *message++);
+ if (frame->closer_mask & ~4) { + frame->closer_mask &= ~4; + g_string_append_c(frame->text, *message++); - g_string_append(frames->text, "@{)}");
+ g_string_append(frame->text, "@{)}"); } else if (!g_ascii_strncasecmp(message, ">", 4)) {
- if (frames->closer_mask & ~8) {
- frames->closer_mask &= ~8;
- g_string_append_c(frames->text, *message++);
+ if (frame->closer_mask & ~8) { + frame->closer_mask &= ~8; + g_string_append_c(frame->text, *message++); - g_string_append(frames->text, "@{>}");
+ g_string_append(frame->text, "@{>}"); - g_string_append_c(frames->text, *message++);
+ g_string_append_c(frame->text, *message++); - ret = frames->text->str;
- g_string_free(frames->text, FALSE);
+ frame = (zframe *)g_queue_pop_head(&frames); + ret = g_string_free(frame->text, FALSE); purple_debug_info("zephyr","zephyr outputted %s\n",ret);
-zframe_pop(zframe *frames, gboolean *last_had_closer)
+zephyr_to_html_pop(GQueue *frames, gboolean *last_had_closer) - zframe *popped = frames;
- frames = frames->enclosing;
- g_string_append(frames->text, popped->text->str);
- g_string_append(frames->text, popped->closing);
+ 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;
@@ -654,8 +654,6 @@
g_string_free(popped->text, TRUE);
/* this parses zephyr formatting and converts it to html. For example, if
@@ -663,112 +661,97 @@
* "<font color=blue><i>hello</i></font>". */
static char *zephyr_to_html(const char *message)
+ GQueue frames = G_QUEUE_INIT; - frames = g_new(zframe, 1);
- frames->text = g_string_new("");
- frames->enclosing = NULL;
- frames->has_closer = FALSE;
+ frame = zframe_new("", FALSE); + g_queue_push_head(&frames, frame); + frame = (zframe *)g_queue_peek_head(&frames); if (*message == '@' && message[1] == '@') {
- g_string_append(frames->text, "@");
+ g_string_append(frame->text, "@"); } else if (*message == '@') {
- for (end = 1; message[end] && (isalnum(message[end]) || message[end] == '_'); end++);
+ while (message[end] && (isalnum(message[end]) || message[end] == '_')) { (message[end] == '{' || message[end] == '[' || message[end] == '(' ||
!g_ascii_strncasecmp(message + end, "<", 4))) {
g_snprintf(buf, end, "%s", message + 1);
- new_f = g_new(zframe, 1);
- new_f->enclosing = frames;
- new_f->has_closer = TRUE;
- new_f->closer = (*message == '{' ? "}" :
- *message == '[' ? "]" :
- *message == '(' ? ")" :
+ closer = (*message == '{' ? "}" : + *message == '[' ? "]" : + *message == '(' ? ")" : message += (*message == '&' ? 4 : 1);
if (!g_ascii_strcasecmp(buf, "italic") || !g_ascii_strcasecmp(buf, "i")) {
- new_f->text = g_string_new("<i>");
- new_f->closing = "</i>";
+ new_f = zframe_new_with_text("<i>", "</i>", TRUE); } else if (!g_ascii_strcasecmp(buf, "small")) {
- new_f->text = g_string_new("<font size=\"1\">");
- new_f->closing = "</font>";
+ new_f = zframe_new_with_text("<font size=\"1\">", "</font>", TRUE); } else if (!g_ascii_strcasecmp(buf, "medium")) {
- new_f->text = g_string_new("<font size=\"3\">");
- new_f->closing = "</font>";
+ new_f = zframe_new_with_text("<font size=\"3\">", "</font>", TRUE); } else if (!g_ascii_strcasecmp(buf, "large")) {
- new_f->text = g_string_new("<font size=\"7\">");
- new_f->closing = "</font>";
+ 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->text = g_string_new("<b>");
- new_f->closing = "</b>";
+ new_f = zframe_new_with_text("<b>", "</b>", TRUE); } else if (!g_ascii_strcasecmp(buf, "font")) {
- extra_f = g_new(zframe, 1);
- extra_f->enclosing = frames;
- new_f->enclosing = extra_f;
- extra_f->text = g_string_new("");
- extra_f->has_closer = FALSE;
- extra_f->closer = frames->closer;
- extra_f->closing = "</font>";
- new_f->text = g_string_new("<font face=\"");
- new_f->closing = "\">";
+ 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 = g_new(zframe, 1);
- extra_f->enclosing = frames;
- new_f->enclosing = extra_f;
- extra_f->text = g_string_new("");
- extra_f->has_closer = FALSE;
- extra_f->closer = frames->closer;
- extra_f->closing = "</font>";
- new_f->text = g_string_new("<font color=\"");
- new_f->closing = "\">";
+ 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->text = g_string_new("");
+ 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(frames->text, *message++);
+ g_string_append_c(frame->text, *message++); - } else if (frames->closer && purple_str_has_caseprefix(message, frames->closer)) {
- gboolean last_had_closer;
- message += strlen(frames->closer);
- if (frames->enclosing) {
+ } 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; - frames = zframe_pop(frames, &last_had_closer);
- } while (frames->enclosing && !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(frames->text, *message);
+ g_string_append_c(frame->text, *message); } else if (*message == '\n') {
- g_string_append(frames->text, "<br>");
+ g_string_append(frame->text, "<br>"); - g_string_append_c(frames->text, *message++);
+ g_string_append_c(frame->text, *message++); /* go through all the stuff that they didn't close */
- while (frames->enclosing) {
- frames = zframe_pop(frames, NULL);
+ while (g_queue_get_length(&frames) > 1) { + zephyr_to_html_pop(&frames, NULL); - ret = frames->text->str;
- g_string_free(frames->text, FALSE);
+ frame = (zframe *)g_queue_pop_head(&frames); + ret = g_string_free(frame->text, FALSE);