/soc/2015/igor.gajowiak/chatlog: d78ceb0c9faf: Add incoming mess...

Igor Gajowiak <[email protected]>
Newsgroups gmane.comp.gnome.gaim.cvs
Message-ID <[email protected]>
Changeset: d78ceb0c9fafd2e84ac1256aaf5bd467272c1dec
Author:	 Igor Gajowiak <[email protected]>
Date:	 2015-06-20 00:54 +0200
Branch:	 default
URL: https://hg.pidgin.im/soc/2015/igor.gajowiak/chatlog/rev/d78ceb0c9faf

Description:

Add incoming message replacing.

diffstat:

 libpurple/conversation.c                               |  35 ++++++
 libpurple/conversation.h                               |  12 ++
 libpurple/message.c                                    |   5 +
 libpurple/protocol.c                                   |   6 +
 libpurple/protocol.h                                   |   9 +
 libpurple/protocols/jabber/jabber.c                    |   1 +
 libpurple/protocols/jabber/message.c                   |  89 ++++++++++++++++-
 libpurple/protocols/jabber/message.h                   |   1 +
 libpurple/server.c                                     |  20 +++
 libpurple/server.h                                     |   8 +
 pidgin/gtkconv.c                                       |  87 ++++++++++++++++-
 pidgin/gtkconv.h                                       |   2 +
 pidgin/gtkwebview.c                                    |  94 ++++++++++++++++++
 pidgin/themes/Contents/Resources/Outgoing/Content.html |   6 -
 pidgin/themes/Contents/Resources/main.css              |   5 +
 pidgin/themes/Template.html                            |  68 ++++++------
 16 files changed, 403 insertions(+), 45 deletions(-)

diffs (truncated from 759 to 300 lines):

diff --git a/libpurple/conversation.c b/libpurple/conversation.c
--- a/libpurple/conversation.c
+++ b/libpurple/conversation.c
@@ -772,6 +772,7 @@ purple_conversation_replace_message(Purp
 	PurpleConversationClass *klass = NULL;
 
 	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
+	g_return_if_fail(replaced_msg_id != PURPLE_MESSAGE_ID_NONE);
 	g_return_if_fail(msg != NULL);
 
 	klass = PURPLE_CONVERSATION_GET_CLASS(conv);
@@ -803,6 +804,40 @@ purple_conversation_send_with_flags(Purp
 	common_send(conv, message, flags);
 }
 
+void
+purple_conversation_send_replace_message_with_flags(
+	PurpleConversation *conv, guint replaced_msg_id,
+	const char *new_message, PurpleMessageFlags flags)
+{
+	g_return_if_fail(PURPLE_IS_CONVERSATION(conv));
+	g_return_if_fail(replaced_msg_id != PURPLE_MESSAGE_ID_NONE);
+	g_return_if_fail(new_message != NULL);
+
+	PurpleAccount *account;
+	PurpleConnection *gc;
+	PurpleMessage *msg;
+
+	account = purple_conversation_get_account(conv);
+	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
+
+	gc = purple_account_get_connection(account);
+	g_return_if_fail(PURPLE_IS_CONNECTION(gc));
+
+	flags |= PURPLE_MESSAGE_SEND;
+
+	if (PURPLE_IS_IM_CONVERSATION(conv)) {
+		msg = purple_message_new_outgoing(
+			purple_conversation_get_name(conv), new_message, flags);
+
+		// Replace message in conversation if sending succeeded
+		if (purple_serv_send_replace_im(gc, replaced_msg_id, msg))
+			purple_conversation_replace_message(conv, replaced_msg_id, msg);
+	}
+	else if (PURPLE_IS_CHAT_CONVERSATION(conv)) {
+		// TODO: Do we need to implement this?
+	}
+}
+
 gboolean
 purple_conversation_has_focus(PurpleConversation *conv)
 {
diff --git a/libpurple/conversation.h b/libpurple/conversation.h
--- a/libpurple/conversation.h
+++ b/libpurple/conversation.h
@@ -525,6 +525,18 @@ void purple_conversation_send_with_flags
 		PurpleMessageFlags flags);
 
 /**
+ * purple_conversation_send_replace_message_with_flags:
+ * @conv:            The conversation.
+ * @replaced_msg_id: The id of the PurpleMessage to replace.
+ * @new_message:     The new message data.
+ * @flags:           The PurpleMessageFlags flags to use in addition to
+ *                   PURPLE_MESSAGE_SEND.
+ */
+void purple_conversation_send_replace_message_with_flags(
+	PurpleConversation *conv, guint replaced_msg_id,
+	const char *new_message, PurpleMessageFlags flags);
+
+/**
  * purple_conversation_set_features:
  * @conv:      The conversation
  * @features:  Bitset defining supported features
diff --git a/libpurple/message.c b/libpurple/message.c
--- a/libpurple/message.c
+++ b/libpurple/message.c
@@ -251,6 +251,9 @@ purple_message_init(GTypeInstance *insta
 	PurpleMessagePrivate *priv = PURPLE_MESSAGE_GET_PRIVATE(msg);
 	PURPLE_DBUS_REGISTER_POINTER(msg, PurpleMessage);
 
+	purple_signal_register(msg, "purple-message-edit",
+		purple_marshal_VOID__POINTER, G_TYPE_NONE, 1, PURPLE_TYPE_MESSAGE);
+
 	priv->id = generate_next_id();
 	g_hash_table_insert(messages, GINT_TO_POINTER(priv->id), msg);
 }
@@ -261,6 +264,8 @@ purple_message_finalize(GObject *obj)
 	PurpleMessage *message = PURPLE_MESSAGE(obj);
 	PurpleMessagePrivate *priv = PURPLE_MESSAGE_GET_PRIVATE(message);
 
+	purple_signal_unregister(message, "purple-message-edit");
+
 	g_free(priv->author);
 	g_free(priv->author_alias);
 	g_free(priv->recipient);
diff --git a/libpurple/protocol.c b/libpurple/protocol.c
--- a/libpurple/protocol.c
+++ b/libpurple/protocol.c
@@ -611,6 +611,12 @@ purple_protocol_im_iface_send(PurpleProt
 	DEFINE_PROTOCOL_FUNC_WITH_RETURN(protocol, 0, send, gc, msg);
 }
 
+int purple_protocol_im_iface_replace(PurpleProtocol *protocol, PurpleConnection *gc,
+	guint replaced_msg_id, PurpleMessage *msg)
+{
+	DEFINE_PROTOCOL_FUNC_WITH_RETURN(protocol, 0, replace, gc, replaced_msg_id, msg);
+}
+
 unsigned int
 purple_protocol_im_iface_send_typing(PurpleProtocol *protocol,
 		PurpleConnection *gc, const char *name, PurpleIMTypingState state)
diff --git a/libpurple/protocol.h b/libpurple/protocol.h
--- a/libpurple/protocol.h
+++ b/libpurple/protocol.h
@@ -394,6 +394,10 @@ typedef struct _PurpleProtocolIMIface Pu
  *               negative value. You can use one of the valid #errno values, or
  *               just big something. If the message should not be echoed to the
  *               conversation window, return 0.
+ * @replace      This function should behave exactly the same as @send except
+ *               the fact that it should replace a message instead of sending a new one.
+ *               It is a protocol's responsibility to map PurpleMessage ids to internal
+ *               protocol's message ids and vice versa.
  * @send_typing: If this protocol requires the #PURPLE_IM_TYPING message to be
  *               sent repeatedly to signify that the user is still typing, then
  *               the protocol should return the number of seconds to wait before
@@ -412,6 +416,8 @@ struct _PurpleProtocolIMIface
 	/*< public >*/
 	int  (*send)(PurpleConnection *, PurpleMessage *msg);
 
+	int (*replace)(PurpleConnection *, guint replaced_msg_id, PurpleMessage *msg);
+
 	unsigned int (*send_typing)(PurpleConnection *, const char *name,
 							PurpleIMTypingState state);
 };
@@ -1013,6 +1019,9 @@ GType purple_protocol_im_iface_get_type(
 int purple_protocol_im_iface_send(PurpleProtocol *, PurpleConnection *,
 		 PurpleMessage *msg);
 
+int purple_protocol_im_iface_replace(PurpleProtocol *, PurpleConnection *,
+	guint replaced_msg_id, PurpleMessage *msg);
+
 unsigned int purple_protocol_im_iface_send_typing(PurpleProtocol *,
 		PurpleConnection *, const char *name, PurpleIMTypingState state);
 
diff --git a/libpurple/protocols/jabber/jabber.c b/libpurple/protocols/jabber/jabber.c
--- a/libpurple/protocols/jabber/jabber.c
+++ b/libpurple/protocols/jabber/jabber.c
@@ -4208,6 +4208,7 @@ static void
 jabber_protocol_im_iface_init(PurpleProtocolIMIface *im_iface)
 {
 	im_iface->send        = jabber_message_send_im;
+	im_iface->replace     = jabber_message_replace_im;
 	im_iface->send_typing = jabber_send_typing;
 }
 
diff --git a/libpurple/protocols/jabber/message.c b/libpurple/protocols/jabber/message.c
--- a/libpurple/protocols/jabber/message.c
+++ b/libpurple/protocols/jabber/message.c
@@ -841,9 +841,8 @@ void jabber_message_parse(JabberStream *
 			const char *id = purple_xmlnode_get_attrib(child, "id");
 
 			// Some communicators (OneTeam for example)
-			// do not send proper xmlns here, so I skip the check for now
-			// if(id && !strcmp(xmlns, NS_MESSAGE_REPLACE))
-			if(id)
+			// do not send proper xmlns here
+			if(id && !strcmp(xmlns, NS_MESSAGE_REPLACE))
 				jm->replaced_msg_id = g_strdup(id);
 		}
 	}
@@ -1109,6 +1108,12 @@ void jabber_message_send(JabberMessage *
 		purple_xmlnode_insert_data(child, jm->body, -1);
 	}
 
+	if (jm->replaced_msg_id) {
+		child = purple_xmlnode_new_child(message, "replace");
+		purple_xmlnode_set_attrib(child, "id", jm->replaced_msg_id);
+		purple_xmlnode_set_namespace(child, NS_MESSAGE_REPLACE);
+	}
+
 	if(jm->xhtml) {
 		if ((child = purple_xmlnode_from_str(jm->xhtml, -1))) {
 			purple_xmlnode_insert_child(message, child);
@@ -1188,6 +1193,84 @@ int jabber_message_send_im(PurpleConnect
 	jm->to = g_strdup(rcpt);
 	jm->id = jabber_get_next_id(jm->js);
 
+	g_hash_table_insert(prpl_to_jbr, purple_message_get_id(msg), g_strdup(jm->id));
+
+	if(jbr) {
+		if(jbr->thread_id)
+			jm->thread_id = jbr->thread_id;
+
+		if (jbr->chat_states == JABBER_CHAT_STATES_UNSUPPORTED)
+			jm->chat_state = JM_STATE_NONE;
+		else {
+			/* if(JABBER_CHAT_STATES_UNKNOWN == jbr->chat_states)
+			   jbr->chat_states = JABBER_CHAT_STATES_UNSUPPORTED; */
+		}
+	}
+
+	tmp = purple_utf8_strip_unprintables(purple_message_get_contents(msg));
+	purple_markup_html_to_xhtml(tmp, &xhtml, &jm->body);
+	g_free(tmp);
+
+	tmp = jabber_message_smileyfy_xhtml(jm, xhtml);
+	if (tmp) {
+		g_free(xhtml);
+		xhtml = tmp;
+	}
+
+	/*
+	 * For backward compatibility with user expectations or for those not on
+	 * the user's roster, allow sending XHTML-IM markup.
+	 */
+	if (!jbr || !jbr->caps.info ||
+			jabber_resource_has_capability(jbr, NS_XHTML_IM)) {
+		if (!jabber_xhtml_plain_equal(xhtml, jm->body))
+			/* Wrap the message in <p/> for great interoperability justice. */
+			jm->xhtml = g_strdup_printf("<html xmlns='" NS_XHTML_IM "'><body xmlns='" NS_XHTML "'><p>%s</p></body></html>", xhtml);
+	}
+
+	g_free(xhtml);
+
+	jabber_message_send(jm);
+	jabber_message_free(jm);
+	return 1;
+}
+
+// TODO: copied from jabber_message_send_im, try to refactor
+int jabber_message_replace_im(PurpleConnection *gc, guint replaced_msg_id, PurpleMessage *msg)
+{
+	JabberMessage *jm;
+	JabberBuddy *jb;
+	JabberBuddyResource *jbr;
+	char *xhtml;
+	char *tmp;
+	char *resource;
+	const gchar *rcpt = purple_message_get_recipient(msg);
+	char *msg_id;
+
+	if (!rcpt || purple_message_is_empty(msg))
+		return 0;
+
+	msg_id = (char*) g_hash_table_lookup(prpl_to_jbr, GUINT_TO_POINTER(replaced_msg_id));
+	if (msg_id == NULL)
+		return 0;
+
+	resource = jabber_get_resource(rcpt);
+
+	jb = jabber_buddy_find(purple_connection_get_protocol_data(gc), rcpt, TRUE);
+	jbr = jabber_buddy_find_resource(jb, resource);
+
+	g_free(resource);
+
+	jm = g_new0(JabberMessage, 1);
+	jm->js = purple_connection_get_protocol_data(gc);
+	jm->type = JABBER_MESSAGE_CHAT;
+	jm->chat_state = JM_STATE_ACTIVE;
+	jm->to = g_strdup(rcpt);
+	jm->id = jabber_get_next_id(jm->js);
+	jm->replaced_msg_id = g_strdup(msg_id);
+
+	g_hash_table_insert(prpl_to_jbr, purple_message_get_id(msg), g_strdup(jm->id));
+
 	if(jbr) {
 		if(jbr->thread_id)
 			jm->thread_id = jbr->thread_id;
diff --git a/libpurple/protocols/jabber/message.h b/libpurple/protocols/jabber/message.h
--- a/libpurple/protocols/jabber/message.h
+++ b/libpurple/protocols/jabber/message.h
@@ -71,6 +71,7 @@ void jabber_message_send(JabberMessage *
 
 void jabber_message_parse(JabberStream *js, PurpleXmlNode *packet);
 int jabber_message_send_im(PurpleConnection *gc, PurpleMessage *msg);
+int jabber_message_replace_im(PurpleConnection *gc, guint replaced_msg_id, PurpleMessage *msg);
 int jabber_message_send_chat(PurpleConnection *gc, int id, PurpleMessage *msg);
 
 unsigned int jabber_send_typing(PurpleConnection *gc, const char *who, PurpleIMTypingState state);
diff --git a/libpurple/server.c b/libpurple/server.c
--- a/libpurple/server.c
+++ b/libpurple/server.c
@@ -159,6 +159,26 @@ int purple_serv_send_im(PurpleConnection
 	return val;
 }
 
+int purple_serv_send_replace_im(PurpleConnection *gc, guint replaced_msg_id, PurpleMessage *msg)
+{
+	g_return_val_if_fail(gc != NULL, -EINVAL);
+	g_return_val_if_fail(replaced_msg_id != PURPLE_MESSAGE_ID_NONE, -EINVAL);
+	g_return_val_if_fail(msg != NULL, -EINVAL);
+
+	PurpleProtocol *protocol = NULL;
+	protocol = purple_connection_get_protocol(gc);
+
+	g_return_val_if_fail(protocol != NULL, -EINVAL);
+	g_return_val_if_fail(PURPLE_PROTOCOL_HAS_IM_IFACE(protocol), -EINVAL);
+
+	int res = -EINVAL;

_______________________________________________
Commits mailing list
[email protected]
https://pidgin.im/cgi-bin/mailman/listinfo/commits
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.