diff libpurple/protocols/gg/lib/handlers.c @ 32072:3a90a59ddea2

Update libgadu to 0.11.0 plus local changes; thanks to Tomasz Wasilczyk. Fixes 14248
author Ethan Blanton <elb@pidgin.im>
date Sun, 05 Jun 2011 01:28:53 +0000
parents 93b08d43f684
children 9c9143e32b6c
line wrap: on
line diff
--- a/libpurple/protocols/gg/lib/handlers.c	Tue May 24 01:48:26 2011 +0000
+++ b/libpurple/protocols/gg/lib/handlers.c	Sun Jun 05 01:28:53 2011 +0000
@@ -27,11 +27,13 @@
  */
 
 #include <sys/types.h>
-
 #ifndef _WIN32
 #  include <sys/socket.h>
 #  include <netinet/in.h>
 #  include <arpa/inet.h>
+#endif
+#include <ctype.h>
+#ifndef _WIN32
 #  ifdef sun
 #    include <sys/filio.h>
 #  endif
@@ -39,12 +41,14 @@
 
 #include "compat.h"
 #include "libgadu.h"
+#include "libgadu-config.h"
 #include "resolver.h"
 #include "session.h"
 #include "protocol.h"
 #include "encoding.h"
 #include "message.h"
 #include "libgadu-internal.h"
+#include "deflate.h"
 
 #include <errno.h>
 #ifndef _WIN32
@@ -87,6 +91,8 @@
 	int ret;
 	uint8_t hash_buf[64];
 	uint32_t local_ip;
+	struct sockaddr_in sin;
+	unsigned int sin_len = sizeof(sin);
 
 	if (len < sizeof(struct gg_welcome)) {
 		ge->type = GG_EVENT_CONN_FAILED;
@@ -145,28 +151,21 @@
 	}
 #endif
 
-	if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) {
-		struct sockaddr_in sin;
-		unsigned int sin_len = sizeof(sin);
-
-		gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() detecting address\n");
-
-		if (!getsockname(gs->fd, (struct sockaddr*) &sin, &sin_len)) {
-			gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr));
-			local_ip = sin.sin_addr.s_addr;
-		} else {
-			gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
-			local_ip = 0;
-		}
-	} else
-		local_ip = gg_dcc_ip;
-
-	gs->client_addr = local_ip;
+	if (!getsockname(gs->fd, (struct sockaddr*) &sin, &sin_len)) {
+		gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr));
+		local_ip = sin.sin_addr.s_addr;
+	} else {
+		gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n");
+		local_ip = 0;
+	}
 
 	if (GG_SESSION_IS_PROTOCOL_8_0(gs)) {
 		struct gg_login80 l80;
-		const char *version, *descr;
-		uint32_t version_len, descr_len;
+		const char *client_name, *version, *descr;
+		uint32_t client_name_len, version_len, descr_len;
+
+		if (gs->external_addr == 0)
+			gs->external_addr = local_ip;
 
 		memset(&l80, 0, sizeof(l80));
 		gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd() sending GG_LOGIN80 packet\n");
@@ -180,8 +179,16 @@
 		l80.image_size = gs->image_size;
 		l80.dunno2 = 0x64;
 
+		if (gs->client_version != NULL && !isdigit(gs->client_version[0])) {
+			client_name = "";
+			client_name_len = 0;
+		} else {
+			client_name = GG8_VERSION;
+			client_name_len = strlen(GG8_VERSION);
+		}
+
 		version = (gs->client_version != NULL) ? gs->client_version : GG_DEFAULT_CLIENT_VERSION;
-		version_len = gg_fix32(strlen(GG8_VERSION) + strlen(version));
+		version_len = gg_fix32(client_name_len + strlen(version));
 
 		descr = (gs->initial_descr != NULL) ? gs->initial_descr : "";
 		descr_len = (gs->initial_descr != NULL) ? gg_fix32(strlen(gs->initial_descr)) : 0;
@@ -190,7 +197,7 @@
 				GG_LOGIN80,
 				&l80, sizeof(l80),
 				&version_len, sizeof(version_len),
-				GG8_VERSION, strlen(GG8_VERSION),
+				client_name, client_name_len,
 				version, strlen(version),
 				&descr_len, sizeof(descr_len),
 				descr, strlen(descr),
@@ -198,6 +205,11 @@
 	} else {
 		struct gg_login70 l70;
 
+		if (gg_dcc_ip != (unsigned long) inet_addr("255.255.255.255"))
+			local_ip = gg_dcc_ip;
+
+		gs->client_addr = local_ip;
+
 		memset(&l70, 0, sizeof(l70));
 		l70.uin = gg_fix32(gs->uin);
 		l70.hash_type = gs->hash_type;
@@ -460,7 +472,7 @@
 
 /**
  * \internal Obsługuje pakiet GG_DCC7_NEW.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_dcc7_new(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -472,7 +484,7 @@
 
 /**
  * \internal Obsługuje pakiet GG_DCC7_REJECT.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_dcc7_reject(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -484,7 +496,7 @@
 
 /**
  * \internal Obsługuje pakiet GG_DCC7_INFO.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_dcc7_info(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -574,7 +586,7 @@
 
 /**
  * \internal Analizuje informacje rozszerzone wiadomości.
- *
+ * 
  * \param sess Struktura sesji.
  * \param e Struktura zdarzenia.
  * \param sender Numer nadawcy.
@@ -756,10 +768,11 @@
  * \internal Wysyła potwierdzenie odebrania wiadomości.
  *
  * \param gs Struktura sesji
+ * \param seq Numer sekwencyjny odebranej wiadomości
  *
  * \return 0 jeśli się powiodło, -1 jeśli wystąpił błąd
  */
-static int gg_session_send_msg_ack(struct gg_session *gs)
+static int gg_session_send_msg_ack(struct gg_session *gs, uint32_t seq)
 {
 	struct gg_recv_msg_ack pkt;
 
@@ -768,15 +781,18 @@
 	if ((gs->protocol_features & GG_FEATURE_MSG_ACK) == 0)
 		return 0;
 
+	/* Kiedyś zdawało nam się, że mamy wysyłać liczbę odebranych
+	 * wiadomości, ale okazało się, że numer sekwencyjny. */
 	gs->recv_msg_count++;
-	pkt.count = gg_fix32(gs->recv_msg_count);
+
+	pkt.seq = gg_fix32(seq);
 
 	return gg_send_packet(gs, GG_RECV_MSG_ACK, &pkt, sizeof(pkt), NULL);
 }
 
 /**
  * \internal Obsługuje pakiet GG_RECV_MSG.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_recv_msg(struct gg_session *sess, uint32_t type, const char *packet, size_t length, struct gg_event *e)
@@ -799,19 +815,19 @@
 		length = 1;
 	} else {
 		const char *options;
-
+		
 		options = memchr(payload, 0, (size_t) (payload_end - payload));
 
 		if (options == NULL) {
 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() malformed packet, message out of bounds (0)\n");
 			goto malformed;
 		}
-
+		
 		length = (size_t) (options - payload);
 
 		switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), options + 1, payload_end)) {
 			case -1:	// handled
-				gg_session_send_msg_ack(sess);
+				gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 				return 0;
 
 			case -2:	// failed
@@ -833,7 +849,7 @@
 		goto fail;
 	e->event.msg.message = (unsigned char*) tmp;
 
-	gg_session_send_msg_ack(sess);
+	gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 	return 0;
 
 fail:
@@ -848,13 +864,13 @@
 	free(e->event.msg.xhtml_message);
 	free(e->event.msg.recipients);
 	free(e->event.msg.formats);
-	gg_session_send_msg_ack(sess);
+	gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 	return 0;
 }
 
 /**
  * \internal Obsługuje pakiet GG_RECV_MSG80.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_recv_msg_80(struct gg_session *sess, uint32_t type, const char *packet, size_t length, struct gg_event *e)
@@ -906,7 +922,7 @@
 	if (offset_attr != 0) {
 		switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), packet + offset_attr, packet + length)) {
 			case -1:	// handled
-				gg_session_send_msg_ack(sess);
+				gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 				return 0;
 
 			case -2:	// failed
@@ -940,7 +956,7 @@
 	else
 		e->event.msg.xhtml_message = NULL;
 
-	gg_session_send_msg_ack(sess);
+	gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 	return 0;
 
 fail:
@@ -956,13 +972,13 @@
 	free(e->event.msg.xhtml_message);
 	free(e->event.msg.recipients);
 	free(e->event.msg.formats);
-	gg_session_send_msg_ack(sess);
+	gg_session_send_msg_ack(sess, gg_fix32(r->seq));
 	return 0;
 }
 
 /**
  * \internal Obsługuje pakiet GG_STATUS.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_status(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -990,7 +1006,7 @@
 
 /**
  * \internal Obsługuje pakiety GG_STATUS60, GG_STATUS77 i GG_STATUS80BETA.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_status_60_77_80beta(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1057,7 +1073,7 @@
 
 /**
  * \internal Obsługuje pakiet GG_NOTIFY_REPLY.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_notify_reply(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1121,7 +1137,7 @@
 
 /**
  * \internal Obsługuje pakiet GG_STATUS80.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_status_80(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1159,7 +1175,7 @@
 
 /**
  * \internal Obsługuje pakiet GG_NOTIFY_REPLY80.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_notify_reply_80(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1235,7 +1251,7 @@
 
 /**
  * \internal Obsługuje pakiety GG_NOTIFY_REPLY77 i GG_NOTIFY_REPLY80BETA.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_notify_reply_77_80beta(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1287,7 +1303,7 @@
 				}
 
 				/* XXX czas */
-
+					
 				length -= sizeof(struct gg_notify_reply77) + descr_len + 1;
 				n = (void*) ((char*) n + sizeof(struct gg_notify_reply77) + descr_len + 1);
 			} else {
@@ -1314,7 +1330,7 @@
 
 /**
  * \internal Obsługuje pakiet GG_NOTIFY_REPLY60.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_notify_reply_60(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1368,7 +1384,7 @@
 				ge->event.notify60[i].descr = descr;
 
 				/* XXX czas */
-
+					
 				length -= sizeof(struct gg_notify_reply60) + descr_len + 1;
 				n = (void*) ((char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1);
 			} else {
@@ -1395,7 +1411,7 @@
 
 /**
  * \internal Obsługuje pakiet GG_USER_DATA.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_user_data(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1441,7 +1457,7 @@
 	ge->event.user_data.type = d.type;
 	ge->event.user_data.user_count = d.user_count;
 	ge->event.user_data.users = users;
-
+	
 	gg_debug_session(gs, GG_DEBUG_DUMP, "type=%d, count=%d\n", d.type, d.user_count);
 
 	for (i = 0; i < d.user_count; i++) {
@@ -1577,7 +1593,7 @@
 
 /**
  * \internal Obsługuje pakiet GG_TYPING_NOTIFICATION.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_typing_notification(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1598,7 +1614,7 @@
 
 /**
  * \internal Obsługuje pakiet GG_MULTILOGON_INFO.
- *
+ * 
  * Patrz gg_packet_handler_t
  */
 static int gg_session_handle_multilogon_info(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
@@ -1626,7 +1642,7 @@
 		gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_multilogon_info() out of memory (%d*%d)\n", count, sizeof(struct gg_multilogon_session));
 		return -1;
 	}
-
+	
 	ge->type = GG_EVENT_MULTILOGON_INFO;
 	ge->event.multilogon_info.count = count;
 	ge->event.multilogon_info.sessions = sessions;
@@ -1687,6 +1703,53 @@
 }
 
 /**
+ * \internal Obsługuje pakiet GG_USERLIST100_VERSION.
+ *
+ * Patrz gg_packet_handler_t
+ */
+static int gg_session_handle_userlist_100_version(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
+{
+	struct gg_userlist100_version *version = (struct gg_userlist100_version*) ptr;
+
+	gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist 100 version\n");
+
+	ge->type = GG_EVENT_USERLIST100_VERSION;
+	ge->event.userlist100_version.version = gg_fix32(version->version);
+
+	return 0;
+}
+
+/**
+ * \internal Obsługuje pakiet GG_USERLIST100_REPLY.
+ *
+ * Patrz gg_packet_handler_t
+ */
+static int gg_session_handle_userlist_100_reply(struct gg_session *gs, uint32_t type, const char *ptr, size_t len, struct gg_event *ge)
+{
+	struct gg_userlist100_reply *reply = (struct gg_userlist100_reply*) ptr;
+	char *data = NULL;
+
+	gg_debug_session(gs, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist 100 reply\n");
+
+	if (len > sizeof(*reply)) {
+		data = gg_inflate((const unsigned char*) ptr + sizeof(*reply), len - sizeof(*reply));
+		
+		if (data == NULL) {
+			gg_debug_session(gs, GG_DEBUG_MISC, "// gg_handle_userlist_100_reply() gg_inflate() failed\n");
+			return -1;
+		}
+	}
+
+	ge->type = GG_EVENT_USERLIST100_REPLY;
+	ge->event.userlist100_reply.type = reply->type;
+	ge->event.userlist100_reply.version = gg_fix32(reply->version);
+	ge->event.userlist100_reply.format_type = reply->format_type;
+	ge->event.userlist100_reply.reply = data;
+
+	return 0;
+}
+
+/**
  * \internal Tablica obsługiwanych pakietów
  */
 static const gg_packet_handler_t handlers[] =
@@ -1726,6 +1789,8 @@
 	{ GG_MULTILOGON_INFO, GG_STATE_CONNECTED, sizeof(struct gg_multilogon_info), gg_session_handle_multilogon_info },
 	{ GG_XML_ACTION, GG_STATE_CONNECTED, 0, gg_session_handle_xml_event },
 	{ GG_RECV_OWN_MSG, GG_STATE_CONNECTED, sizeof(struct gg_recv_msg80), gg_session_handle_recv_msg_80 },
+	{ GG_USERLIST100_VERSION, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_version), gg_session_handle_userlist_100_version },
+	{ GG_USERLIST100_REPLY, GG_STATE_CONNECTED, sizeof(struct gg_userlist100_reply), gg_session_handle_userlist_100_reply },
 };
 
 /**