diff libpurple/protocols/gg/lib/events.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 ef01f180114b
line wrap: on
line diff
--- a/libpurple/protocols/gg/lib/events.c	Tue May 24 01:48:26 2011 +0000
+++ b/libpurple/protocols/gg/lib/events.c	Sun Jun 05 01:28:53 2011 +0000
@@ -1,4 +1,4 @@
-/* $Id: events.c 1062 2011-03-13 18:10:24Z wojtekka $ */
+/* $Id: events.c 1105 2011-05-25 21:34:50Z wojtekka $ */
 
 /*
  *  (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl>
@@ -27,22 +27,22 @@
  * \brief Obsługa zdarzeń
  */
 
-#include "libgadu.h"
-#include "libgadu-internal.h"
-#include "libgadu-debug.h"
-
 #include <sys/types.h>
-
 #ifndef _WIN32
 #  include <sys/ioctl.h>
 #  include <sys/socket.h>
 #  include <netinet/in.h>
 #  include <arpa/inet.h>
 #endif
+#include <ctype.h>
 
 #include "compat.h"
+#include "libgadu.h"
+#include "libgadu-config.h"
 #include "protocol.h"
+#include "libgadu-internal.h"
 #include "encoding.h"
+#include "libgadu-debug.h"
 #include "session.h"
 
 #include <errno.h>
@@ -156,7 +156,7 @@
 
 			break;
 		}
-
+	
 		case GG_EVENT_MULTILOGON_INFO:
 		{
 			int i;
@@ -168,6 +168,10 @@
 
 			break;
 		}
+
+		case GG_EVENT_USERLIST100_REPLY:
+			free(e->event.userlist100_reply.reply);
+			break;
 	}
 
 	free(e);
@@ -258,9 +262,9 @@
 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() write() failed (errno=%d, %s)\n", errno, strerror(errno));
 
 			if (sess->state == GG_STATE_READING_REPLY)
-				goto fail_connecting;
-			else
-				goto done;
+				e->event.failure = GG_FAILURE_CONNECTING;
+
+			goto fail;
 		}
 
 		if (res == sess->send_left) {
@@ -299,7 +303,7 @@
 
 			if (failed) {
 				errno = errno2;
-				goto fail_resolving;
+				goto fail_proxy_hub;
 			}
 
 			/* jeśli jesteśmy w resolverze i mamy ustawiony port
@@ -326,7 +330,7 @@
 				/* jeśli w trybie asynchronicznym gg_connect()
 				 * zwróci błąd, nie ma sensu próbować dalej. */
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), critical\n", errno, strerror(errno));
-				goto fail_connecting;
+				goto fail_proxy_hub;
 			}
 
 			/* jeśli podano serwer i łączmy się przez proxy,
@@ -357,19 +361,20 @@
 			/* jeśli asynchroniczne, sprawdzamy, czy nie wystąpił
 			 * przypadkiem jakiś błąd. */
 			if (sess->async && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) {
-				if (sess->proxy_addr && sess->proxy_port)
-					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res));
-				else
-					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to hub failed (errno=%d, %s)\n", res, strerror(res));
-
-				goto fail_connecting;
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to %s failed (errno=%d, %s)\n", (sess->proxy_addr && sess->proxy_port) ? "proxy" : "hub", res, strerror(res));
+				goto fail_proxy_hub;
 			}
 
 			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connected to hub, sending query\n");
 
-			if (!(client = gg_urlencode((sess->client_version) ? sess->client_version : GG_DEFAULT_CLIENT_VERSION))) {
+			if (sess->client_version != NULL && isdigit(sess->client_version[0]))
+				client = gg_urlencode(sess->client_version);
+			else
+				client = gg_urlencode(GG_DEFAULT_CLIENT_VERSION);
+
+			if (client == NULL) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory for client version\n");
-				goto fail_connecting;
+				goto fail;
 			}
 
 			if (!gg_proxy_http_only && sess->proxy_addr && sess->proxy_port)
@@ -407,13 +412,7 @@
 			 * stało się coś złego. */
 			if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n");
-
-				e->type = GG_EVENT_CONN_FAILED;
-				e->event.failure = GG_FAILURE_WRITING;
-				sess->state = GG_STATE_IDLE;
-				close(sess->fd);
-				sess->fd = -1;
-				break;
+				goto fail_proxy_hub;
 			}
 
 			sess->state = GG_STATE_READING_DATA;
@@ -439,7 +438,7 @@
 			/* sprawdzamy, czy wszystko w porządku. */
 			if (strncmp(buf, "HTTP/1.", 7) || strncmp(buf + 9, "200", 3)) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid http reply, connection failed\n");
-				goto fail_connecting;
+				goto fail_proxy_hub;
 			}
 
 			/* ignorujemy resztę nagłówka. */
@@ -447,7 +446,10 @@
 				gg_read_line(sess->fd, buf, sizeof(buf) - 1);
 
 			/* czytamy pierwszą linię danych. */
-			gg_read_line(sess->fd, buf, sizeof(buf) - 1);
+			if (gg_read_line(sess->fd, buf, sizeof(buf) - 1) == NULL) {
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() read error\n");
+				goto fail_proxy_hub;
+			}
 			gg_chomp(buf);
 
 			/* jeśli pierwsza liczba w linii nie jest równa zeru,
@@ -479,6 +481,7 @@
 			}
 
 			close(sess->fd);
+			sess->fd = -1;
 
 			gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf);
 
@@ -503,10 +506,16 @@
 				port = atoi(tmp + 1);
 			}
 
+			if (strcmp(host, "") == 0) {
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid response\n");
+				e->event.failure = GG_FAILURE_HUB;
+				goto fail;
+			}
+
 			if (!strcmp(host, "notoperating")) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() service unavailable\n", errno, strerror(errno));
-				sess->fd = -1;
-				goto fail_unavailable;
+				e->event.failure = GG_FAILURE_UNAVAILABLE;
+				goto fail;
 			}
 
 			addr.s_addr = inet_addr(host);
@@ -517,7 +526,8 @@
 				if ((sess->fd = gg_connect(&sess->proxy_addr, sess->proxy_port, sess->async)) == -1) {
 					/* nie wyszło? trudno. */
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_PROXY;
+					goto fail;
 				}
 
 				sess->state = GG_STATE_CONNECTING_GG;
@@ -533,7 +543,7 @@
 			if (sess->server_addr == INADDR_NONE) {
 				if (sess->resolver_start(&sess->fd, &sess->resolver, host) == -1) {
 					gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno));
-					goto fail_resolving;
+					goto fail;
 				}
 
 				sess->state = GG_STATE_RESOLVING_GG;
@@ -553,7 +563,8 @@
 					/* ostatnia deska ratunku zawiodła?
 					 * w takim razie zwijamy manatki. */
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_CONNECTING;
+					goto fail;
 				}
 			}
 
@@ -585,7 +596,8 @@
 
 			if (failed) {
 				errno = errno2;
-				goto fail_resolving;
+				e->event.failure = GG_FAILURE_RESOLVING;
+				goto fail;
 			}
 
 			sess->server_addr = addr.s_addr;
@@ -601,7 +613,8 @@
 					/* ostatnia deska ratunku zawiodła?
 					 * w takim razie zwijamy manatki. */
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_CONNECTING;
+					goto fail;
 				}
 			}
 
@@ -628,7 +641,8 @@
 				 * nie mamy czego próbować więcej. */
 				if (sess->proxy_addr && sess->proxy_port) {
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_PROXY;
+					goto fail;
 				}
 
 				close(sess->fd);
@@ -648,21 +662,25 @@
 
 				if (sess->ssl) {
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", res, strerror(res));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_CONNECTING;
+					goto fail;
 				}
 #endif
 
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", res, strerror(res));
 
-				if (sess->port == GG_HTTPS_PORT)
-					goto fail_connecting;
+				if (sess->port == GG_HTTPS_PORT) {
+					e->event.failure = GG_FAILURE_CONNECTING;
+					goto fail;
+				}
 
 				sess->port = GG_HTTPS_PORT;
 
 				/* próbujemy na port 443. */
 				if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) {
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno));
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_CONNECTING;
+					goto fail;
 				}
 
 				sess->state = GG_STATE_CONNECTING_GG;
@@ -698,7 +716,8 @@
 				if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) {
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
 					free(auth);
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_PROXY;
+					goto fail;
 				}
 
 				if (auth) {
@@ -706,7 +725,8 @@
 					if (write(sess->fd, auth, strlen(auth)) < (signed)strlen(auth)) {
 						gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
 						free(auth);
-						goto fail_connecting;
+						e->event.failure = GG_FAILURE_PROXY;
+						goto fail;
 					}
 
 					free(auth);
@@ -714,7 +734,8 @@
 
 				if (write(sess->fd, "\r\n", 2) < 2) {
 					gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n");
-					goto fail_connecting;
+					e->event.failure = GG_FAILURE_PROXY;
+					goto fail;
 				}
 			}
 
@@ -904,7 +925,14 @@
 		{
 			struct gg_header *gh;
 
-			gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n");
+			if (sess->state == GG_STATE_READING_KEY)
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_KEY\n");
+			else if (sess->state == GG_STATE_READING_REPLY)
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_REPLY\n");
+			else if (sess->state == GG_STATE_CONNECTED)
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n");
+			else if (sess->state == GG_STATE_DISCONNECTING)
+				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_DISCONNECTING\n");
 
 			/* XXX bardzo, bardzo, bardzo głupi pomysł na pozbycie
 			 * się tekstu wrzucanego przez proxy. */
@@ -936,64 +964,56 @@
 
 			if (gh == NULL) {
 				gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() gg_recv_packet failed (errno=%d, %s)\n", errno, strerror(errno));
- 				if (errno == EAGAIN) {
-					e->type = GG_EVENT_NONE;
-					res = 0;
-				} else {
-					res = -1;
+
+ 				if (errno != EAGAIN)
+					goto fail;
+			} else {
+				if (gg_session_handle_packet(sess, gh->type, (const char *) gh + sizeof(struct gg_header), gh->length, e) == -1) {
+					free(gh);
+					goto fail;
 				}
 
-				goto done;
+				free(gh);
 			}
 
-			if (gg_session_handle_packet(sess, gh->type, (const char *) gh + sizeof(struct gg_header), gh->length, e) == -1) {
-				free(gh);
-				res = -1;
-				goto done;
-			}
-
-			free(gh);
-
 			sess->check = GG_CHECK_READ;
 
 			break;
 		}
 	}
 
-done:
-	if (res == -1) {
-		free(e);
-		e = NULL;
-	} else {
-		if (sess->send_buf && (sess->state == GG_STATE_READING_REPLY || sess->state == GG_STATE_CONNECTED))
-			sess->check |= GG_CHECK_WRITE;
-	}
+	if (sess->send_buf && (sess->state == GG_STATE_READING_REPLY || sess->state == GG_STATE_CONNECTED))
+		sess->check |= GG_CHECK_WRITE;
 
 	return e;
 
-fail_connecting:
+fail_proxy_hub:
+	if (sess->proxy_port)
+		e->event.failure = GG_FAILURE_PROXY;
+	else
+		e->event.failure = GG_FAILURE_HUB;
+
+fail:
+	sess->resolver_cleanup(&sess->resolver, 1);
+
+	sess->state = GG_STATE_IDLE;
+
 	if (sess->fd != -1) {
+		int errno2;
+
 		errno2 = errno;
 		close(sess->fd);
 		errno = errno2;
 		sess->fd = -1;
 	}
-	e->type = GG_EVENT_CONN_FAILED;
-	e->event.failure = GG_FAILURE_CONNECTING;
-	sess->state = GG_STATE_IDLE;
-	goto done;
 
-fail_resolving:
-	e->type = GG_EVENT_CONN_FAILED;
-	e->event.failure = GG_FAILURE_RESOLVING;
-	sess->state = GG_STATE_IDLE;
-	goto done;
-
-fail_unavailable:
-	e->type = GG_EVENT_CONN_FAILED;
-	e->event.failure = GG_FAILURE_UNAVAILABLE;
-	sess->state = GG_STATE_IDLE;
-	goto done;
+	if (e->event.failure != 0) {
+		e->type = GG_EVENT_CONN_FAILED;
+		return e;
+	} else {
+		free(e);
+		return NULL;
+	}
 }
 
 /*