changeset 31476:5095ed88829a

merge of '649c72408dd9527b22c5e15aced51c15e325d4bb' and 'c64a4a6aaa74f97f9aa696b4f7756d93a9a243b8'
author Daniel Atallah <daniel.atallah@gmail.com>
date Tue, 19 Apr 2011 00:20:36 +0000
parents 3248407d3cfe (diff) 68a1efda3654 (current diff)
children f0de3178dd87
files
diffstat 8 files changed, 176 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Apr 19 00:20:26 2011 +0000
+++ b/ChangeLog	Tue Apr 19 00:20:36 2011 +0000
@@ -13,9 +13,12 @@
 	  on the fly. (Jakub Adam) (half of #13535)
 	* Don't cancel an ongoing call when rejecting the addition of a stream to
 	  the existing call. (Jakub Adam) (#13537)
+	* Pidgin plugins can now override tab completion and detect clicks on
+	  usernames in the chat userlist. (kawaii.neko) (#12599)
 
 	libpurple:
-	* media: Allow obtaining active local and remote candidates. (#11830)
+	* media: Allow obtaining active local and remote candidates. (Jakub
+	  Adam) (#11830)
 	* media: Allow getting/setting video capabilities. (Jakub Adam) (half of
 	  #13095)
 	* Simple Silence Suppression is optional per-account. (Jakub Adam) (half
@@ -41,6 +44,13 @@
 	* Require libgadu 1.10.1 to avoid using internal libgadu.
 	* SSL connection support for GNUTLS users (not on Windows yet!).
 	  (Tomasz Wasilczyk) (#13613)
+	* Don't count received messages or statuses when determining whether
+	  to send a keepalive packet. (Jan Zachorowski) (#13699)
+	* Fix a crash when receiving images on Windows or an incorrect
+	  timestamp in the log when receiving images on Linux. (Tomasz
+	  Wasilczyk) (#10268)
+	* Support XML events, resulting in immediate update of other users'
+	  buddy icons. (Tomasz Wasilczyk) (#13739)
 
 	ICQ:
 	* Fix unsetting your mood when "None" is selected.  (Dustin Gathmann)
--- a/ChangeLog.API	Tue Apr 19 00:20:26 2011 +0000
+++ b/ChangeLog.API	Tue Apr 19 00:20:36 2011 +0000
@@ -19,6 +19,7 @@
 		* Added PurpleSrvTxtQueryUiOps which allow UIs to specify their
 		  own mechanisms to resolve SRV and/or TXT queries. It works
 		  similar to PurpleDnsQueryUiOps
+		* purple_marshal_BOOLEAN__POINTER_BOOLEAN (kawaii.neko) (#12599)
 
 		Deprecated:
 		* purple_account_add_buddy
@@ -29,6 +30,8 @@
 	Pidgin:
 		Added:
 		* pidgin_make_scrollable (Gabriel Schulhof) (#10599)
+		* chat-nick-clicked signal (kawaii.neko) (#12599)
+		* chat-nick-autocomplete signal (kawaii.neko) (#12599)
 
 version 2.7.11 (03/10/2011):
 	* libpurple:
--- a/configure.ac	Tue Apr 19 00:20:26 2011 +0000
+++ b/configure.ac	Tue Apr 19 00:20:36 2011 +0000
@@ -1058,7 +1058,7 @@
 	]])], [
 		AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <libgadu.h>]], [[
 #if GG_DEFAULT_PROTOCOL_VERSION < 0x2e
-#error "Your libgadu version is too old. libpurple requires 1.9.0-rc2 or higher."
+#error "Your libgadu version is too old. libpurple requires 1.10.1 or higher."
 #endif
 		]])], [
 			AC_MSG_RESULT(yes)
@@ -1069,7 +1069,7 @@
 			echo
 			echo
 			echo "Your supplied copy of libgadu is too old."
-			echo "Install version 1.9.0-rc2 or newer."
+			echo "Install version 1.10.1 or newer."
 			echo "Then rerun this ./configure"
 			echo
 			echo "Falling back to using our own copy of libgadu"
--- a/libpurple/protocols/gg/gg.c	Tue Apr 19 00:20:26 2011 +0000
+++ b/libpurple/protocols/gg/gg.c	Tue Apr 19 00:20:36 2011 +0000
@@ -1044,6 +1044,29 @@
 }
 
 /**
+ * Try to update avatar of the buddy.
+ *
+ * @param gc     PurpleConnection
+ * @param uin    UIN of the buddy.
+ */
+static void ggp_update_buddy_avatar(PurpleConnection *gc, uin_t uin)
+{
+	gchar *avatarurl;
+	PurpleUtilFetchUrlData *url_data;
+
+	purple_debug_info("gg", "ggp_update_buddy_avatar(gc, %u)\n", uin);
+
+	avatarurl = g_strdup_printf("http://api.gadu-gadu.pl/avatars/%u/0.xml", uin);
+
+	url_data = purple_util_fetch_url_request_len_with_account(
+			purple_connection_get_account(gc), avatarurl, TRUE,
+			"Mozilla/4.0 (compatible; MSIE 5.5)", FALSE, NULL, FALSE, -1,
+			gg_get_avatar_url_cb, gc);
+
+	g_free(avatarurl);
+}
+
+/**
  * Handle change of the status of the buddy.
  *
  * @param gc     PurpleConnection
@@ -1056,18 +1079,10 @@
 {
 	gchar *from;
 	const char *st;
-	gchar *avatarurl;
-	PurpleUtilFetchUrlData *url_data;
+
+	ggp_update_buddy_avatar(gc, uin);
 
 	from = g_strdup_printf("%u", uin);
-	avatarurl = g_strdup_printf("http://api.gadu-gadu.pl/avatars/%s/0.xml", from);
-
-	url_data = purple_util_fetch_url_request_len_with_account(
-			purple_connection_get_account(gc), avatarurl, TRUE,
-			"Mozilla/4.0 (compatible; MSIE 5.5)", FALSE, NULL, FALSE, -1,
-			gg_get_avatar_url_cb, gc);
-
-	g_free(avatarurl);
 
 	switch (status) {
 		case GG_STATUS_NOT_AVAIL:
@@ -1383,8 +1398,8 @@
 			info->pending_richtext_messages = g_list_remove(info->pending_richtext_messages, entry->data);
 			/* We don't have any more images to download */
 			if (strstr(text, "<IMG ID=\"IMGID_HANDLER") == NULL) {
-				gchar *buf = g_strdup_printf("%lu", (unsigned long int)ev->event.msg.sender);
-				serv_got_im(gc, buf, text, PURPLE_MESSAGE_IMAGES, ev->event.msg.time);
+				gchar *buf = g_strdup_printf("%lu", (unsigned long int)ev->event.image_reply.sender);
+				serv_got_im(gc, buf, text, PURPLE_MESSAGE_IMAGES, time(NULL));
 				g_free(buf);
 				purple_debug_info("gg", "ggp_recv_image_handler: richtext message: %s\n", text);
 				g_free(text);
@@ -1614,6 +1629,75 @@
     g_free(from);
 }
 
+/**
+ * Handling of XML events.
+ *
+ * @param gc PurpleConnection.
+ * @param data Raw XML contents.
+ *
+ * @see http://toxygen.net/libgadu/protocol/#ch1.13
+ */
+static void ggp_xml_event_handler(PurpleConnection *gc, char *data)
+{
+	xmlnode *xml = NULL;
+	xmlnode *xmlnode_next_event;
+
+	xml = xmlnode_from_str(data, -1);
+	if (xml == NULL)
+		goto out;
+
+	xmlnode_next_event = xmlnode_get_child(xml, "event");
+	while (xmlnode_next_event != NULL)
+	{
+		xmlnode *xmlnode_current_event = xmlnode_next_event;
+		
+		xmlnode *xmlnode_type;
+		char *event_type_raw;
+		int event_type = 0;
+		
+		xmlnode *xmlnode_sender;
+		char *event_sender_raw;
+		uin_t event_sender = 0;
+
+		xmlnode_next_event = xmlnode_get_next_twin(xmlnode_next_event);
+		
+		xmlnode_type = xmlnode_get_child(xmlnode_current_event, "type");
+		if (xmlnode_type == NULL)
+			continue;
+		event_type_raw = xmlnode_get_data(xmlnode_type);
+		if (event_type_raw != NULL)
+			event_type = atoi(event_type_raw);
+		g_free(event_type_raw);
+		
+		xmlnode_sender = xmlnode_get_child(xmlnode_current_event, "sender");
+		if (xmlnode_sender != NULL)
+		{
+			event_sender_raw = xmlnode_get_data(xmlnode_sender);
+			if (event_sender_raw != NULL)
+				event_sender = ggp_str_to_uin(event_sender_raw);
+			g_free(event_sender_raw);
+		}
+		
+		switch (event_type)
+		{
+			case 28: /* avatar update */
+				purple_debug_info("gg",
+					"ggp_xml_event_handler: avatar updated (uid: %u)\n",
+					event_sender);
+				ggp_update_buddy_avatar(gc, event_sender);
+				break;
+			default:
+				purple_debug_error("gg",
+					"ggp_xml_event_handler: unsupported event type=%d from=%u\n",
+					event_type, event_sender);
+		}
+	}
+	
+	out:
+		if (xml)
+			xmlnode_free(xml);
+}
+
 static void ggp_callback_recv(gpointer _gc, gint fd, PurpleInputCondition cond)
 {
 	PurpleConnection *gc = _gc;
@@ -1629,7 +1713,7 @@
 			_("Unable to read from socket"));
 		return;
 	}
-	gc->last_received = time(NULL);
+
 	switch (ev->type) {
 		case GG_EVENT_NONE:
 			/* Nothing happened. */
@@ -1731,6 +1815,10 @@
 			ggp_typing_notification_handler(gc, ev->event.typing_notification.uin,
 				ev->event.typing_notification.length);
 			break;
+		case GG_EVENT_XML_EVENT:
+			purple_debug_info("gg", "GG_EVENT_XML_EVENT\n");
+			ggp_xml_event_handler(gc, ev->event.xml_event.data);
+			break;
 		default:
 			purple_debug_error("gg",
 				"unsupported event type=%d\n", ev->type);
--- a/libpurple/signals.c	Tue Apr 19 00:20:26 2011 +0000
+++ b/libpurple/signals.c	Tue Apr 19 00:20:36 2011 +0000
@@ -880,6 +880,20 @@
 }
 
 void
+purple_marshal_BOOLEAN__POINTER_BOOLEAN(PurpleCallback cb, va_list args,
+									  void *data, void **return_val)
+{
+	gboolean ret_val;
+	void *arg1 = va_arg(args, void *);
+	gboolean arg2 = va_arg(args, gboolean);
+
+	ret_val = ((gboolean (*)(void *, gboolean, void *))cb)(arg1, arg2, data);
+
+	if (return_val != NULL)
+		*return_val = GINT_TO_POINTER(ret_val);
+}
+
+void
 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER(PurpleCallback cb, va_list args,
 											  void *data, void **return_val)
 {
--- a/libpurple/signals.h	Tue Apr 19 00:20:26 2011 +0000
+++ b/libpurple/signals.h	Tue Apr 19 00:20:36 2011 +0000
@@ -339,6 +339,8 @@
 		PurpleCallback cb, va_list args, void *data, void **return_val);
 void purple_marshal_BOOLEAN__POINTER_POINTER(
 		PurpleCallback cb, va_list args, void *data, void **return_val);
+void purple_marshal_BOOLEAN__POINTER_BOOLEAN(
+		PurpleCallback cb, va_list args, void *data, void **return_val);
 void purple_marshal_BOOLEAN__POINTER_POINTER_POINTER(
 		PurpleCallback cb, va_list args, void *data, void **return_val);
 void purple_marshal_BOOLEAN__POINTER_POINTER_UINT(
--- a/pidgin/gtkconv.c	Tue Apr 19 00:20:26 2011 +0000
+++ b/pidgin/gtkconv.c	Tue Apr 19 00:20:36 2011 +0000
@@ -1792,6 +1792,15 @@
 	gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path);
 	gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, CHAT_USERS_NAME_COLUMN, &who, -1);
 
+	/* emit chat-nick-clicked signal */
+	if (event->type == GDK_BUTTON_PRESS) {
+		gint plugin_return = GPOINTER_TO_INT(purple_signal_emit_return_1(
+					pidgin_conversations_get_handle(), "chat-nick-clicked",
+					conv, who, event->button));
+		if (plugin_return)
+			goto handled;
+	}
+
 	if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) {
 		chat_do_im(gtkconv, who);
 	} else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) {
@@ -1806,6 +1815,7 @@
 					   event->button, event->time);
 	}
 
+handled:
 	g_free(who);
 	gtk_tree_path_free(path);
 
@@ -2122,7 +2132,13 @@
 		case GDK_ISO_Left_Tab:
 			if (gtkconv->entry != entry)
 				break;
-			return tab_complete(conv);
+			{
+				gint plugin_return;
+				plugin_return = GPOINTER_TO_INT(purple_signal_emit_return_1(
+							pidgin_conversations_get_handle(), "chat-nick-autocomplete",
+							conv, event->state & GDK_SHIFT_MASK));
+				return plugin_return ? TRUE : tab_complete(conv);
+			}
 			break;
 
 		case GDK_Page_Up:
@@ -5586,6 +5602,15 @@
 
 		buddyname = (tag->name) + 6;
 
+		/* emit chat-nick-clicked signal */
+		if (event->type == GDK_BUTTON_PRESS) {
+			gint plugin_return = GPOINTER_TO_INT(purple_signal_emit_return_1(
+						pidgin_conversations_get_handle(), "chat-nick-clicked",
+						data, buddyname, btn_event->button));
+			if (plugin_return)
+				return TRUE;
+		}
+
 		if (btn_event->button == 1 &&
 				event->type == GDK_2BUTTON_PRESS) {
 			chat_do_im(PIDGIN_CONVERSATION(conv), buddyname);
@@ -8003,6 +8028,21 @@
 						 purple_value_new(PURPLE_TYPE_BOXED,
 										"PidginConversation *"));
 
+	purple_signal_register(handle, "chat-nick-autocomplete",
+						 purple_marshal_BOOLEAN__POINTER_BOOLEAN,
+						 purple_value_new(PURPLE_TYPE_BOOLEAN), 1,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+							 			PURPLE_SUBTYPE_CONVERSATION));
+
+	purple_signal_register(handle, "chat-nick-clicked",
+						 purple_marshal_BOOLEAN__POINTER_POINTER_UINT,
+						 purple_value_new(PURPLE_TYPE_BOOLEAN), 3,
+						 purple_value_new(PURPLE_TYPE_SUBTYPE,
+							 			PURPLE_SUBTYPE_CONVERSATION),
+						 purple_value_new(PURPLE_TYPE_STRING),
+						 purple_value_new(PURPLE_TYPE_UINT));
+
+
 	/**********************************************************************
 	 * Register commands
 	 **********************************************************************/
--- a/pidgin/gtkdialogs.c	Tue Apr 19 00:20:26 2011 +0000
+++ b/pidgin/gtkdialogs.c	Tue Apr 19 00:20:36 2011 +0000
@@ -102,8 +102,10 @@
 /* Order: Alphabetical by Last Name */
 static const struct developer patch_writers[] = {
 	{"Jakub 'haakon' Adam",            NULL,                        NULL},
+	{"Krzysztof Klinikowski",          NULL,                        NULL},
 	{"Peter 'Fmoo' Ruibal",            NULL,                        NULL},
 	{"Gabriel 'Nix' Schulhof",         NULL,                        NULL},
+	{"Tomasz Wasilczyk",               NULL,                        NULL},
 	{NULL, NULL, NULL}
 };