changeset 14195:902c3aa4950a

[gaim-migrate @ 16867] Revamped the QQ proxy code. Fixed an infinite loop that was occurring if we hit qq_input_pending() with an unexpected value of cond. Rewrote part of qq_proxy.c so that we use Gaim's non-blocking dns lookups. Quieted some warnings created by new code in proxy.c and passed appropriate error messages to _qq_got_login(). Added some extra error handling to qq_proxy_write(). I was beginning to do major clean-up on this this code when I realized that once that clean-up is done, I will have duplicated a very large amount of code from proxy.c. Therefore, I am submitting this working code now and will later submit a patch to gaim-devel that will add support for UDP proxying in proxy.c, thus eliminating the need for such code in the individual prpls. committer: Tailor Script <tailor@pidgin.im>
author Mark Huetsch <markhuetsch>
date Sat, 19 Aug 2006 02:32:55 +0000
parents ebe83aee29d2
children ec2cd563da47
files libgaim/protocols/qq/qq.c libgaim/protocols/qq/qq.h libgaim/protocols/qq/qq_proxy.c libgaim/protocols/qq/qq_proxy.h libgaim/protocols/qq/recv_core.c libgaim/protocols/qq/send_core.c libgaim/protocols/qq/udp_proxy_s5.c
diffstat 7 files changed, 214 insertions(+), 99 deletions(-) [+]
line wrap: on
line diff
--- a/libgaim/protocols/qq/qq.c	Sat Aug 19 02:26:57 2006 +0000
+++ b/libgaim/protocols/qq/qq.c	Sat Aug 19 02:32:55 2006 +0000
@@ -64,25 +64,26 @@
 #define QQ_UDP_PORT             "8000"
 
 const gchar *udp_server_list[] = {
-	"sz.tencent.com",	/* 61.144.238.145 */
-	"sz2.tencent.com",	/* 61.144.238.146 */
-	"sz3.tencent.com",	/* 202.104.129.251 */
-	"sz4.tencent.com",	/* 202.104.129.254 */
-	"sz5.tencent.com",	/* 61.141.194.203 */
-	"sz6.tencent.com",	/* 202.104.129.252 */
-	"sz7.tencent.com",	/* 202.104.129.253 */
-	"202.96.170.64",
-	"64.144.238.155",
-	"202.104.129.254"
+	"sz.tencent.com",
+	"sz2.tencent.com",
+	"sz3.tencent.com",
+	"sz4.tencent.com",
+	"sz5.tencent.com",
+	"sz6.tencent.com",
+	"sz7.tencent.com",
+	"sz8.tencent.com",
+	"sz9.tencent.com"
 };
 const gint udp_server_amount = (sizeof(udp_server_list) / sizeof(udp_server_list[0]));
 
 
 const gchar *tcp_server_list[] = {
-	"tcpconn.tencent.com",	/* 218.17.209.23 */
-	"tcpconn2.tencent.com",	/* 218.18.95.153 */
-	"tcpconn3.tencent.com",	/* 218.17.209.23 */
-	"tcpconn4.tencent.com"	/* 218.18.95.153 */
+	"tcpconn.tencent.com",
+	"tcpconn2.tencent.com",
+	"tcpconn3.tencent.com",
+	"tcpconn4.tencent.com",
+	"tcpconn5.tencent.com",
+	"tcpconn6.tencent.com"
 };
 const gint tcp_server_amount = (sizeof(tcp_server_list) / sizeof(tcp_server_list[0]));
 
@@ -102,6 +103,7 @@
 	gc->flags |= GAIM_CONNECTION_HTML | GAIM_CONNECTION_NO_BGCOLOR | GAIM_CONNECTION_AUTO_RESP;
 
 	qd = g_new0(qq_data, 1);
+	qd->gc = gc;
 	gc->proto_data = qd;
 
 	qq_server = gaim_account_get_string(account, "server", NULL);
@@ -122,13 +124,14 @@
 
 	if (qq_server == NULL || strlen(qq_server) == 0)
 		qq_server = use_tcp ?
-		    tcp_server_list[random() % tcp_server_amount] : udp_server_list[random() % udp_server_amount];
+		    tcp_server_list[random() % tcp_server_amount] : 
+		    udp_server_list[random() % udp_server_amount];
 
 	if (qq_port == NULL || strtol(qq_port, NULL, 10) == 0)
 		qq_port = use_tcp ? QQ_TCP_QUERY_PORT : QQ_UDP_PORT;
 
 	gaim_connection_update_progress(gc, _("Connecting"), 0, QQ_CONNECT_STEPS);
-
+ 
 	if (qq_connect(account, qq_server, strtol(qq_port, NULL, 10), use_tcp, FALSE) < 0)
 		gaim_connection_error(gc, _("Unable to connect."));
 }
--- a/libgaim/protocols/qq/qq.h	Sat Aug 19 02:26:57 2006 +0000
+++ b/libgaim/protocols/qq/qq.h	Sat Aug 19 02:32:55 2006 +0000
@@ -67,7 +67,9 @@
 	gboolean logged_in;		/* used by qq-add_buddy */
 	gboolean use_tcp;		/* network in tcp or udp */
 
-	GaimProxyType proxy_type;	/* proxy type */
+	GaimProxyType proxy_type;
+	GaimConnection *gc;
+
 	GaimXfer *xfer;			/* file transfer handler */
 	struct sockaddr_in dest_sin;
 
--- a/libgaim/protocols/qq/qq_proxy.c	Sat Aug 19 02:26:57 2006 +0000
+++ b/libgaim/protocols/qq/qq_proxy.c	Sat Aug 19 02:32:55 2006 +0000
@@ -43,11 +43,11 @@
 #include "udp_proxy_s5.h"
 #include "utils.h"
 
-/* These functions are used only in development phase
- *
+/* These functions are used only in development phase */
+/*
 static void _qq_show_socket(gchar *desc, gint fd) {
 	struct sockaddr_in sin;
-	gint len = sizeof(sin);
+	socklen_t len = sizeof(sin);
 	getsockname(fd, (struct sockaddr *)&sin, &len);
 	gaim_debug(GAIM_DEBUG_INFO, desc, "%s:%d\n",
             inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
@@ -88,22 +88,24 @@
 	return g_memdup(pwkey_tmp, QQ_KEY_LENGTH);
 }
 
-gint _qq_fill_host(struct sockaddr_in *addr, const gchar *host, guint16 port)
+static gboolean _qq_fill_host(GSList *hosts, struct sockaddr_in *addr, gint *addr_size)
 {
-	if (!inet_aton(host, &(addr->sin_addr))) {
-		struct hostent *hp;
-		if (!(hp = gethostbyname(host))) {
-			return -1;
-		}
-		memset(addr, 0, sizeof(struct sockaddr_in));
-		memcpy(&(addr->sin_addr.s_addr), hp->h_addr, hp->h_length);
-		addr->sin_family = hp->h_addrtype;
-	} else {
-		addr->sin_family = AF_INET;
+	if (!hosts || !hosts->data)
+		return FALSE;
+
+	*addr_size = GPOINTER_TO_INT(hosts->data);
+
+	hosts = g_slist_remove(hosts, hosts->data);
+	memcpy(addr, hosts->data, *addr_size);
+	g_free(hosts->data);
+	hosts = g_slist_remove(hosts, hosts->data);
+	while(hosts) {
+		hosts = g_slist_remove(hosts, hosts->data);
+		g_free(hosts->data);
+		hosts = g_slist_remove(hosts, hosts->data);
 	}
 
-	addr->sin_port = htons(port);
-	return 0;
+	return TRUE;
 }
 
 /* set up any finalizing start-up stuff */
@@ -136,12 +138,16 @@
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
 
 	if (source < 0) {	/* socket returns -1 */
-		gaim_connection_error(gc, _("Unable to connect."));
+		gaim_connection_error(gc, error_message);
 		return;
 	}
 
 	qd = (qq_data *) gc->proto_data;
 
+	/*
+	_qq_show_socket("Got login socket", source);
+	*/
+
 	/* QQ use random seq, to minimize duplicated packets */
 	srandom(time(NULL));
 	qd->send_seq = random() & 0x0000ffff;
@@ -201,6 +207,54 @@
 	qq_buddies_list_free(gc->account, qd);
 }
 
+static void no_one_calls(gpointer data, gint source, GaimInputCondition cond)
+{
+        struct PHB *phb = data;
+	socklen_t len;
+	int error=0, ret;
+
+	gaim_debug_info("proxy", "Connected.\n");
+
+	len = sizeof(error);
+
+	/*
+	* getsockopt after a non-blocking connect returns -1 if something is
+	* really messed up (bad descriptor, usually). Otherwise, it returns 0 and
+	* error holds what connect would have returned if it blocked until now.
+	* Thus, error == 0 is success, error == EINPROGRESS means "try again",
+	* and anything else is a real error.
+	*
+	* (error == EINPROGRESS can happen after a select because the kernel can
+	* be overly optimistic sometimes. select is just a hint that you might be
+	* able to do something.)
+	*/
+	ret = getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len);
+	if (ret == 0 && error == EINPROGRESS)
+		return; /* we'll be called again later */
+	if (ret < 0 || error != 0) {
+		if(ret!=0) 
+			error = errno;
+		close(source);
+		gaim_input_remove(phb->inpa);
+
+		gaim_debug_error("proxy", "getsockopt SO_ERROR check: %s\n", strerror(error));
+
+		phb->func(phb->data, -1, _("Unable to connect"));
+		return;
+	}
+
+	gaim_input_remove(phb->inpa);
+
+	if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
+
+		phb->func(phb->data, source, NULL);
+	}
+
+	g_free(phb->host);
+	g_free(phb);
+}
+
+/* returns -1 if fails, otherwise returns the file handle */
 static gint _qq_proxy_none(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
 {
 	gint fd = -1;
@@ -209,7 +263,8 @@
 	fd = socket(PF_INET, SOCK_DGRAM, 0);
 
 	if (fd < 0) {
-		gaim_debug(GAIM_DEBUG_ERROR, "QQ Redirect", "Unable to create socket: %s\n", strerror(errno));
+		gaim_debug(GAIM_DEBUG_ERROR, "QQ Redirect", 
+			"Unable to create socket: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -238,8 +293,9 @@
 		 */
 		if ((errno == EINPROGRESS) || (errno == EINTR)) {
 			gaim_debug(GAIM_DEBUG_WARNING, "QQ", "Connect in asynchronous mode.\n");
+			phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, no_one_calls, phb);
 		} else {
-			gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Faiil connection: %d\n", strerror(errno));
+			gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Connection failed: %d\n", strerror(errno));
 			close(fd);
 			return -1;
 		}		/* if errno */
@@ -252,20 +308,80 @@
 	return fd;
 }
 
-/* returns the socket handler, or -1 if there is any error */
+static void _qq_proxy_resolved(GSList *hosts, gpointer data, const char *error_message)
+{
+	struct PHB *phb = (struct PHB *) data;
+	struct sockaddr_in addr;
+	gint addr_size, ret = -1;
+
+	if(_qq_fill_host(hosts, &addr, &addr_size))
+		ret = qq_proxy_socks5(phb, (struct sockaddr *) &addr, addr_size);
+
+	if (ret < 0) {
+		phb->func(phb->data, -1, _("Unable to connect"));
+		g_free(phb->host);
+		g_free(phb);
+	}
+}
+
+static void _qq_server_resolved(GSList *hosts, gpointer data, const char *error_message)
+{
+	struct PHB *phb = (struct PHB *) data;
+	GaimConnection *gc = (GaimConnection *) phb->data;
+	qq_data *qd = (qq_data *) gc->proto_data;
+	struct sockaddr_in addr;
+	gint addr_size, ret = -1;
+
+	if(_qq_fill_host(hosts, &addr, &addr_size)) {
+		switch (gaim_proxy_info_get_type(phb->gpi)) {
+			case GAIM_PROXY_NONE:
+				ret = _qq_proxy_none(phb, (struct sockaddr *) &addr, addr_size);
+				break;
+			case GAIM_PROXY_SOCKS5:
+				ret = 0;
+				if (gaim_proxy_info_get_host(phb->gpi) == NULL || 
+						gaim_proxy_info_get_port(phb->gpi) == 0) {
+					gaim_debug(GAIM_DEBUG_ERROR, "QQ", 
+							"Use of socks5 proxy selected but host or port info doesn't exist.\n");
+					ret = -1;
+				} else {
+					/* as the destination is always QQ server during the session, 
+				 	* we can set dest_sin here, instead of _qq_s5_canread_again */
+					memcpy(&qd->dest_sin, &addr, addr_size);
+					if (gaim_dnsquery_a(gaim_proxy_info_get_host(phb->gpi),
+							gaim_proxy_info_get_port(phb->gpi),
+							_qq_proxy_resolved, phb) == NULL)
+						ret = -1;
+				}
+				break;
+			default:
+				gaim_debug(GAIM_DEBUG_WARNING, "QQ", 
+						"Proxy type %i is unsupported, not using a proxy.\n",
+						gaim_proxy_info_get_type(phb->gpi));
+				ret = _qq_proxy_none(phb, (struct sockaddr *) &addr, addr_size);
+		}
+	}
+
+	if (ret < 0) {
+		phb->func(gc, -1, _("Unable to connect"));
+		g_free(phb->host);
+		g_free(phb);
+	}
+}
+
+/* returns -1 if dns lookup fails, otherwise returns 0 */
 static gint _qq_udp_proxy_connect(GaimAccount *account,
-			   const gchar *server,
-			   guint16 port, void callback(gpointer, gint, const gchar *error_message), GaimConnection *gc)
+			   const gchar *server, guint16 port, 
+			   void callback(gpointer, gint, const gchar *error_message), 
+			   GaimConnection *gc)
 {
-	struct sockaddr_in sin;
+	GaimProxyInfo *info;
 	struct PHB *phb;
-	GaimProxyInfo *info;
-	qq_data *qd;
+	qq_data *qd = (qq_data *) gc->proto_data;
 
-	g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1);
-	qd = (qq_data *) gc->proto_data;
+	g_return_val_if_fail(gc != NULL && qd != NULL, -1);
 
-	info = gaim_account_get_proxy_info(account);
+	info = gaim_proxy_get_setup(account);
 
 	phb = g_new0(struct PHB, 1);
 	phb->host = g_strdup(server);
@@ -274,41 +390,24 @@
 	phb->gpi = info;
 	phb->func = callback;
 	phb->data = gc;
-
-	if (_qq_fill_host(&sin, server, port) < 0) {
-		gaim_debug(GAIM_DEBUG_ERROR, "QQ",
-			   "gethostbyname(\"%s\", %d) failed: %s\n", server, port, hstrerror(h_errno));
-		return -1;
-	}
+	qd->proxy_type = gaim_proxy_info_get_type(phb->gpi);
 
-	if (info == NULL) {
-		qd->proxy_type = GAIM_PROXY_NONE;
-		return _qq_proxy_none(phb, (struct sockaddr *) &sin, sizeof(sin));
-	}
-
-	qd->proxy_type = info->type;
-	gaim_debug(GAIM_DEBUG_INFO, "QQ", "Choosing proxy type %d\n", info->type);
+	gaim_debug(GAIM_DEBUG_INFO, "QQ", "Choosing proxy type %d\n", 
+			gaim_proxy_info_get_type(phb->gpi));
 
-	switch (info->type) {
-	case GAIM_PROXY_NONE:
-		return _qq_proxy_none(phb, (struct sockaddr *) &sin, sizeof(sin));
-	case GAIM_PROXY_SOCKS5:
-		/* as the destination is always QQ server during the session, 
-		 * we can set dest_sin here, instead of _qq_s5_canread_again */
-		_qq_fill_host(&qd->dest_sin, phb->host, phb->port);
-		_qq_fill_host(&sin, phb->gpi->host, phb->gpi->port);
-		return qq_proxy_socks5(phb, (struct sockaddr *) &sin, sizeof(sin));
-	default:
-		return _qq_proxy_none(phb, (struct sockaddr *) &sin, sizeof(sin));
+	if (gaim_dnsquery_a(server, port, _qq_server_resolved, phb) == NULL) {
+		phb->func(gc, -1, _("Unable to connect"));
+		g_free(phb->host);
+		g_free(phb);
+		return -1;
+	} else {
+		return 0;
 	}
-
-	return -1;
 }
 
 /* QQ connection via UDP/TCP. 
- * I use GAIM proxy function to provide TCP proxy support,
- * and qq_udp_proxy.c to add UDP proxy support (thanks henry)
- *  return the socket handle, -1 means fail */
+ * I use Gaim proxy function to provide TCP proxy support,
+ * and qq_udp_proxy.c to add UDP proxy support (thanks henry) */
 static gint _proxy_connect_full (GaimAccount *account, const gchar *host, guint16 port, 
 		GaimProxyConnectFunction func, gpointer data, gboolean use_tcp)
 {
@@ -320,18 +419,16 @@
 	qd->server_ip = g_strdup(host);
 	qd->server_port = port;
 
-	if (use_tcp)
-		/* TCP mode */
+	if(use_tcp)
 		return (gaim_proxy_connect(account, host, port, func, data) == NULL);
 	else
-		/* UDP mode */
 		return _qq_udp_proxy_connect(account, host, port, func, data);
 }
 
 /* establish a generic QQ connection 
- * TCP/UDP, and direct/redirected
- * return the socket handler, or -1 if there is any error */
-gint qq_connect(GaimAccount *account, const gchar *host, guint16 port, gboolean use_tcp, gboolean is_redirect)
+ * TCP/UDP, and direct/redirected */
+gint qq_connect(GaimAccount *account, const gchar *host, guint16 port, 
+		gboolean use_tcp, gboolean is_redirect)
 {
 	GaimConnection *gc;
 
@@ -385,10 +482,19 @@
 		g_memmove(buf + 4, &(qd->dest_sin.sin_addr.s_addr), 4);
 		g_memmove(buf + 8, &(qd->dest_sin.sin_port), 2);
 		g_memmove(buf + 10, data, len);
+		errno = 0;
 		ret = send(qd->fd, buf, len + 10, 0);
 	} else {
+		errno = 0;
 		ret = send(qd->fd, data, len, 0);
 	}
+	if (ret == -1) {
+		gaim_connection_error(qd->gc, _("Socket send error"));
+		return ret;
+	} else if (errno == ECONNREFUSED) {
+		gaim_connection_error(qd->gc, _("Connection refused"));
+		return ret;
+	}
 
 	return ret;
 }
--- a/libgaim/protocols/qq/qq_proxy.h	Sat Aug 19 02:26:57 2006 +0000
+++ b/libgaim/protocols/qq/qq_proxy.h	Sat Aug 19 02:32:55 2006 +0000
@@ -25,7 +25,9 @@
 #define _QQ_PROXY_H
 
 #include <glib.h>
+#include "dnsquery.h"
 #include "proxy.h"
+
 #include "qq.h"
 
 #define QQ_CONNECT_STEPS    2	/* steps in connection */
@@ -48,8 +50,6 @@
 gint qq_connect(GaimAccount *account, const gchar *host, guint16 port, gboolean use_tcp, gboolean is_redirect);
 void qq_disconnect(GaimConnection *gc);
 
-gint _qq_fill_host(struct sockaddr_in *addr, const gchar *host, guint16 port);
-
 void _qq_show_packet(const gchar *desc, const guint8 *buf, gint len);
 
 #endif
--- a/libgaim/protocols/qq/recv_core.c	Sat Aug 19 02:26:57 2006 +0000
+++ b/libgaim/protocols/qq/recv_core.c	Sat Aug 19 02:32:55 2006 +0000
@@ -296,7 +296,10 @@
 	gint len;
 
 	gc = (GaimConnection *) data;
-	g_return_if_fail(gc != NULL && gc->proto_data != NULL && cond == GAIM_INPUT_READ);
+	if(gc == NULL || gc->proto_data == NULL || cond != GAIM_INPUT_READ) {
+		gaim_connection_error(gc, _("Socket error"));
+		return;
+	}
 
 	qd = (qq_data *) gc->proto_data;
 	buf = g_newa(guint8, MAX_PACKET_SIZE);
--- a/libgaim/protocols/qq/send_core.c	Sat Aug 19 02:26:57 2006 +0000
+++ b/libgaim/protocols/qq/send_core.c	Sat Aug 19 02:32:55 2006 +0000
@@ -73,7 +73,7 @@
 /* for those need ack and resend no ack feed back from server
  * return number of bytes written to the socket,
  * return -1 if there is any error */
-gint _qq_send_packet(GaimConnection * gc, guint8 *buf, gint len, guint16 cmd)
+gint _qq_send_packet(GaimConnection *gc, guint8 *buf, gint len, guint16 cmd)
 {
 	qq_data *qd;
 	qq_sendpacket *p;
--- a/libgaim/protocols/qq/udp_proxy_s5.c	Sat Aug 19 02:26:57 2006 +0000
+++ b/libgaim/protocols/qq/udp_proxy_s5.c	Sat Aug 19 02:32:55 2006 +0000
@@ -25,15 +25,13 @@
 
 #include "udp_proxy_s5.h"
 
-extern gint			/* defined in qq_proxy.c */
- _qq_fill_host(struct sockaddr_in *addr, const gchar * host, guint16 port);
-
 static void _qq_s5_canread_again(gpointer data, gint source, GaimInputCondition cond)
 {
 	unsigned char buf[512];
 	struct PHB *phb = data;
 	struct sockaddr_in sin;
 	int len, error;
+	socklen_t errlen;
 
 	gaim_input_remove(phb->inpa);
 	gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy", "Able to read again.\n");
@@ -61,7 +59,7 @@
 
 		if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
 
-			phb->func(phb->data, -1, NULL);
+			phb->func(phb->data, -1, _("Unable to connect"));
 		}
 
 		g_free(phb->host);
@@ -84,8 +82,8 @@
 
 	error = ETIMEDOUT;
 	gaim_debug(GAIM_DEBUG_INFO, "QQ", "Connect didn't block\n");
-	len = sizeof(error);
-	if (getsockopt(phb->udpsock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+	errlen = sizeof(error);
+	if (getsockopt(phb->udpsock, SOL_SOCKET, SO_ERROR, &error, &errlen) < 0) {
 		gaim_debug(GAIM_DEBUG_ERROR, "QQ", "getsockopt failed.\n");
 		close(phb->udpsock);
 		return;
@@ -105,7 +103,8 @@
 	unsigned char buf[512];
 	struct PHB *phb = data;
 	struct sockaddr_in sin, ctlsin;
-	int port, ctllen;
+	int port; 
+	socklen_t ctllen;
 
 	gaim_debug(GAIM_DEBUG_INFO, "s5_sendconnect", "remote host is %s:%d\n", phb->host, phb->port);
 
@@ -137,7 +136,9 @@
 
 	port = ntohs(ctlsin.sin_port) + 1;
 	while (1) {
-		_qq_fill_host(&sin, "0.0.0.0", port);
+		inet_aton("0.0.0.0", &(sin.sin_addr));
+		sin.sin_family = AF_INET;
+		sin.sin_port = htons(port);
 		if (bind(phb->udpsock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
 			port++;
 			if (port > 65500) {
@@ -158,7 +159,7 @@
 		gaim_debug(GAIM_DEBUG_INFO, "s5_sendconnect", "packet too small\n");
 
 		if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
-			phb->func(phb->data, -1, NULL);
+			phb->func(phb->data, -1, _("Unable to connect"));
 		}
 
 		g_free(phb->host);
@@ -182,7 +183,7 @@
 
 		if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
 
-			phb->func(phb->data, -1, NULL);
+			phb->func(phb->data, -1, _("Unable to connect"));
 		}
 
 		g_free(phb->host);
@@ -195,7 +196,7 @@
 
 		if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
 
-			phb->func(phb->data, -1, NULL);
+			phb->func(phb->data, -1, _("Unable to connect"));
 		}
 
 		g_free(phb->host);
@@ -238,7 +239,7 @@
 
 		if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
 
-			phb->func(phb->data, -1, NULL);
+			phb->func(phb->data, -1, _("Unable to connect"));
 		}
 
 		g_free(phb->host);
@@ -263,7 +264,7 @@
 
 			if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
 
-				phb->func(phb->data, -1, NULL);
+				phb->func(phb->data, -1, _("Unable to connect"));
 			}
 
 			g_free(phb->host);
@@ -297,7 +298,7 @@
 		close(source);
 		if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
 
-			phb->func(phb->data, -1, NULL);
+			phb->func(phb->data, -1, _("Unable to connect"));
 		}
 
 		g_free(phb->host);
@@ -327,7 +328,7 @@
 
 		if (phb->account == NULL || gaim_account_get_connection(phb->account) != NULL) {
 
-			phb->func(phb->data, -1, NULL);
+			phb->func(phb->data, -1, _("Unable to connect"));
 		}
 
 		g_free(phb->host);