changeset 17695:13bba54b429d

Support sending some formatted text in instant messages. Currently supported is: * bold * italic * underline * font face Bold/italic/underline cannot be nested yet.
author Jeffrey Connelly <jaconnel@calpoly.edu>
date Thu, 05 Jul 2007 06:16:25 +0000
parents 231b87b76da4
children 65cf1785e5bf
files libpurple/protocols/myspace/CHANGES libpurple/protocols/myspace/myspace.c libpurple/protocols/myspace/myspace.h
diffstat 3 files changed, 129 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/myspace/CHANGES	Thu Jul 05 06:10:30 2007 +0000
+++ b/libpurple/protocols/myspace/CHANGES	Thu Jul 05 06:16:25 2007 +0000
@@ -5,6 +5,7 @@
 * Time out if no data from server within a certain amount of time (keep alives).
 * Remove "Sign on as hidden" option, and always set status to current status
   when signing on.
+* Some support for sending formatted text.
 
 2007-07-03 Jeff Connelly <jeff2@soc.pidgin.im> - 0.10
 * On incoming instant messages, add support for:
--- a/libpurple/protocols/myspace/myspace.c	Thu Jul 05 06:10:30 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Thu Jul 05 06:16:25 2007 +0000
@@ -282,6 +282,7 @@
 
     gc = purple_account_get_connection(acct);
     gc->proto_data = msim_session_new(acct);
+    gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_NO_URLDESC;
 
     /* Passwords are limited in length. */
 	if (strlen(acct->password) > MSIM_MAX_PASSWORD_LENGTH)
@@ -516,6 +517,8 @@
 		PurpleMessageFlags flags)
 {
     MsimSession *session;
+    gchar *message_msim;
+    int rc;
     
     g_return_val_if_fail(gc != NULL, -1);
     g_return_val_if_fail(who != NULL, -1);
@@ -527,7 +530,9 @@
 
     g_return_val_if_fail(MSIM_SESSION_VALID(session), -1);
 
-	if (msim_send_bm(session, who, message, MSIM_BM_INSTANT))
+    message_msim = html_to_msim_markup(message);
+
+	if (msim_send_bm(session, who, message_msim, MSIM_BM_INSTANT))
 	{
 		/* Return 1 to have Purple show this IM as being sent, 0 to not. I always
 		 * return 1 even if the message could not be sent, since I don't know if
@@ -537,10 +542,13 @@
         /* TODO: maybe if message is delayed, don't echo to conv window,
          * but do echo it to conv window manually once it is actually
          * sent? Would be complicated. */
-		return 1;
+		rc = 1;
 	} else {
-		return -1;
+		rc = -1;
 	}
+
+    g_free(message_msim);
+
     /*
      * In MySpace, you login with your email address, but don't talk to other
      * users using their email address. So there is currently an asymmetry in the 
@@ -553,6 +561,8 @@
      * TODO: Make the sent IM's appear as from the user's username, instead of
      * their email address. Purple uses the login (in MSIM, the email)--change this.
      */
+
+    return rc;
 }
 
 /** Send a buddy message of a given type.
@@ -678,7 +688,7 @@
 		g_string_prepend(gs_end, "</b>");
 	}
 
-	if (decor & MSIM_TEXT_ITALICS)
+	if (decor & MSIM_TEXT_ITALIC)
 	{
 		g_string_append(gs_begin, "<i>");
 		g_string_append(gs_end, "</i>");	
@@ -811,12 +821,84 @@
 	*end = g_strdup("</p>");
 }
 
-
-/** Convert an xmlnode of msim markup to an HTML string.
+/** Convert an individual msim markup tag to HTML. */
+void msim_markup_tag_to_html(xmlnode *root, gchar **begin, gchar **end)
+{
+	if (!strcmp(root->name, "f"))
+	{
+		msim_markup_f_to_html(root, begin, end);
+	} else if (!strcmp(root->name, "p")) {
+		msim_markup_p_to_html(root, begin, end);
+	} else if (!strcmp(root->name, "c")) {
+		msim_markup_c_to_html(root, begin, end);
+	} else if (!strcmp(root->name, "b")) {
+		msim_markup_b_to_html(root, begin, end);
+	} else if (!strcmp(root->name, "i")) {
+		msim_markup_i_to_html(root, begin, end);
+	} else {
+		purple_debug_info("msim", "msim_markup_tag_to_html: "
+				"unknown tag name=%s, ignoring", root->name);
+		*begin = g_strdup("");
+		*end = g_strdup("");
+	}
+}
+
+/** Convert an individual HTML tag to msim markup. */
+void html_tag_to_msim_markup(xmlnode *root, gchar **begin, gchar **end)
+{
+    /* TODO: TODO XXX */
+    /*
+    *begin = g_strdup_printf("[begin-%s]", root->name);
+    *end = g_strdup_printf("[end-%s]", root->name);
+    */
+
+    /* TODO: Coalesce nested tags into one <f> tag!
+     * Currently, the 's' value will be overwritten when b/i/u is nested
+     * within another one, and only the inner-most formatting will be 
+     * applied to the text. */
+    if (!strcmp(root->name, "b"))
+    {
+        *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_BOLD);
+        *end = g_strdup("</f>");
+    } else if (!strcmp(root->name, "i")) {
+        *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_ITALIC);
+        *end = g_strdup("</f>");
+    } else if (!strcmp(root->name, "u")) {
+        *begin = g_strdup_printf("<f s='%d'>", MSIM_TEXT_UNDERLINE);
+        *end = g_strdup("</f>");
+    } else if (!strcmp(root->name, "font")) {
+        const gchar *size;
+        const gchar *face;
+
+        size = xmlnode_get_attrib(root, "size");
+        face = xmlnode_get_attrib(root, "face");
+
+        if (face && size)
+            *begin = g_strdup_printf("<f f='%s' h='%s'>", face, size);
+        else if (face)
+            *begin = g_strdup_printf("<f f='%s'>", face);
+        else if (size)
+            *begin = g_strdup_printf("<f h='%s'>", face);
+        else
+            *begin = g_strdup("<f>");
+
+        *end = g_strdup("</f>");
+
+        /* TODO: color (bg uses <body>), emoticons */
+    } else {
+        *begin = g_strdup_printf("[%s]", root->name);
+        *end = g_strdup_printf("[/%s]", root->name);
+    }
+}
+
+/** Convert an xmlnode of msim markup or HTML to an HTML string or msim markup.
+ *
+ * @param f Function to convert tags.
+ *
  * @return An HTML string. Caller frees.
  */
 static gchar *
-msim_markup_xmlnode_to_html(xmlnode *root)
+msim_convert_xmlnode(xmlnode *root, MSIM_XMLNODE_CONVERT f)
 {
 	xmlnode *node;
 	gchar *begin, *inner, *end;
@@ -825,28 +907,12 @@
 	if (!root || !root->name)
 		return g_strdup("");
 
-	purple_debug_info("msim", "msim_markup_xmlnode_to_html: got root=%s\n",
+	purple_debug_info("msim", "msim_convert_xmlnode: got root=%s\n",
 			root->name);
 
 	begin = inner = end = NULL;
 
-	if (!strcmp(root->name, "f"))
-	{
-		msim_markup_f_to_html(root, &begin, &end);
-	} else if (!strcmp(root->name, "p")) {
-		msim_markup_p_to_html(root, &begin, &end);
-	} else if (!strcmp(root->name, "c")) {
-		msim_markup_c_to_html(root, &begin, &end);
-	} else if (!strcmp(root->name, "b")) {
-		msim_markup_b_to_html(root, &begin, &end);
-	} else if (!strcmp(root->name, "i")) {
-		msim_markup_i_to_html(root, &begin, &end);
-	} else {
-		purple_debug_info("msim", "msim_markup_xmlnode_to_html: "
-				"unknown tag name=%s, ignoring", root->name);
-		begin = g_strdup("");
-		end = g_strdup("");
-	}
+    f(root, &begin, &end);
 
 	/* Loop over all child nodes. */
  	for (node = root->child; node != NULL; node = node->next)
@@ -859,7 +925,7 @@
 
 		case XMLNODE_TYPE_TAG:
 			/* A tag or tag with attributes. Recursively descend. */
-			inner = msim_markup_xmlnode_to_html(node);
+			inner = msim_convert_xmlnode(node, f);
             g_return_val_if_fail(inner != NULL, NULL);
 
 			purple_debug_info("msim", " ** node name=%s\n", node->name);
@@ -876,7 +942,7 @@
 			
 		default:
 			purple_debug_info("msim",
-					"msim_markup_xmlnode_to_html: strange node\n");
+					"msim_convert_xmlnode: strange node\n");
 			inner = g_strdup("");
 		}
 	}
@@ -892,11 +958,9 @@
 	return final;
 }
 
-/** Convert MySpaceIM markup to Purple (HTML) markup. 
- *
- * @return Purple markup string, must be g_free()'d. */
+/** Convert XML to something based on MSIM_XMLNODE_CONVERT. */
 gchar *
-msim_markup_to_html(const gchar *raw)
+msim_convert_xml(const gchar *raw, MSIM_XMLNODE_CONVERT f)
 {
 	xmlnode *root;
 	gchar *str;
@@ -909,12 +973,32 @@
 		return g_strdup(raw);
 	}
 
-	str = msim_markup_xmlnode_to_html(root);
+	str = msim_convert_xmlnode(root, f);
 	purple_debug_info("msim", "msim_markup_to_html: returning %s\n", str);
 
 	xmlnode_free(root);
 
-	return g_strdup(str);
+	return str;
+}
+
+/** High-level function to convert MySpaceIM markup to Purple (HTML) markup. 
+ *
+ * @return Purple markup string, must be g_free()'d. */
+gchar *
+msim_markup_to_html(const gchar *raw)
+{
+    return msim_convert_xml(raw, 
+            (MSIM_XMLNODE_CONVERT)(msim_markup_tag_to_html));
+}
+
+/** High-level function to convert Purple (HTML) to MySpaceIM markup.
+ *
+ * @return HTML markup string, must be g_free()'d. */
+gchar *
+html_to_msim_markup(const gchar *raw)
+{
+    return msim_convert_xml(raw,
+            (MSIM_XMLNODE_CONVERT)(html_tag_to_msim_markup));
 }
 
 /**
@@ -1572,8 +1656,7 @@
     purple_prpl_got_user_status(session->account, session->username, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
 #endif
 
-
-    /* Set status to current status. */
+    /* Notify servers of our current status. */
     msim_set_status(session->account,
             purple_account_get_active_status(session->account));
 
--- a/libpurple/protocols/myspace/myspace.h	Thu Jul 05 06:10:30 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.h	Thu Jul 05 06:16:25 2007 +0000
@@ -141,7 +141,7 @@
 
 /* Text formatting bits for <f s=#> */
 #define MSIM_TEXT_BOLD                  1
-#define MSIM_TEXT_ITALICS               2   
+#define MSIM_TEXT_ITALIC                2   
 #define MSIM_TEXT_UNDERLINE             4
 
 /* Random number in every MsimSession, to ensure it is valid. */
@@ -205,7 +205,16 @@
 
 void msim_unrecognized(MsimSession *session, MsimMessage *msg, gchar *note);
 
+
+typedef void (*MSIM_XMLNODE_CONVERT)(xmlnode *, gchar **, gchar **);
+void msim_markup_tag_to_html(xmlnode *root, gchar **begin, gchar **end);
+void html_tag_to_msim_markup(xmlnode *root, gchar **begin, gchar **end);
+gchar *msim_convert_xml(const gchar *raw, MSIM_XMLNODE_CONVERT f);
+
+/* High-level msim markup <=> html conversion functions. */
 gchar *msim_markup_to_html(const gchar *raw);
+gchar *html_to_msim_markup(const gchar *raw);
+
 int msim_incoming_im(MsimSession *session, MsimMessage *msg);
 int msim_incoming_action(MsimSession *session, MsimMessage *msg);