changeset 14089:10e8eb6a4910

[gaim-migrate @ 16712] Pretty large commit here. Basically I got sick of having to verify that gc is still valid on all the callback functions for gaim_proxy_connect(). The fix for this for gaim_proxy_connect() to return something that allows the connection attempt to be canceled. It's not quite there yet, but this is a good first step. I changed gaim_proxy_connect() to return a reference to a new GaimProxyConnectInfo (this used to be called PHB). Eventually this can be passed to a function that'll cancel the connection attempt. I also decided to add an error_cb instead of using connect_cb and passing a file descriptor of -1. And proxy.c will also pass an error message to callers which should explain the reason that the connection attempt failed. Oh, and proxy.c now never calls gaim_connection_error() committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Sat, 12 Aug 2006 10:12:43 +0000
parents 223570831b0b
children 983fbec46eb0
files src/ft.c src/protocols/irc/irc.c src/protocols/jabber/jabber.c src/protocols/jabber/si.c src/protocols/msn/directconn.c src/protocols/msn/httpconn.c src/protocols/msn/servconn.c src/protocols/oscar/oscar.c src/protocols/oscar/peer.c src/protocols/oscar/peer.h src/protocols/oscar/peer_proxy.c src/protocols/qq/qq_proxy.c src/protocols/sametime/sametime.c src/protocols/silc/silc.c src/protocols/simple/simple.c src/protocols/yahoo/yahoo.c src/protocols/yahoo/yahoo_filexfer.c src/protocols/yahoo/yahoo_picture.c src/protocols/yahoo/yahoochat.c src/protocols/yahoo/ycht.c src/proxy.c src/proxy.h src/sslconn.c src/upnp.c src/util.c
diffstat 25 files changed, 380 insertions(+), 311 deletions(-) [+]
line wrap: on
line diff
--- a/src/ft.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/ft.c	Sat Aug 12 10:12:43 2006 +0000
@@ -911,13 +911,13 @@
 }
 
 static void
-connect_cb(gpointer data, gint source, GaimInputCondition condition)
+connect_cb(gpointer data, gint source)
 {
 	GaimXfer *xfer = (GaimXfer *)data;
 
 	xfer->fd = source;
 
-	begin_transfer(xfer, condition);
+	begin_transfer(xfer, GAIM_INPUT_READ);
 }
 
 void
@@ -946,7 +946,7 @@
 
 			/* Establish a file descriptor. */
 			gaim_proxy_connect(xfer->account, xfer->remote_ip,
-							   xfer->remote_port, connect_cb, xfer);
+							   xfer->remote_port, connect_cb, NULL, xfer);
 
 			return;
 		}
--- a/src/protocols/irc/irc.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/irc/irc.c	Sat Aug 12 10:12:43 2006 +0000
@@ -46,7 +46,7 @@
 /* static GList *irc_chat_info(GaimConnection *gc); */
 static void irc_login(GaimAccount *account);
 static void irc_login_cb_ssl(gpointer data, GaimSslConnection *gsc, GaimInputCondition cond);
-static void irc_login_cb(gpointer data, gint source, GaimInputCondition cond);
+static void irc_login_cb(gpointer data, gint source);
 static void irc_ssl_connect_failure(GaimSslConnection *gsc, GaimSslErrorType error, gpointer data);
 static void irc_close(GaimConnection *gc);
 static int irc_im_send(GaimConnection *gc, const char *who, const char *what, GaimMessageFlags flags);
@@ -283,7 +283,7 @@
 	struct irc_conn *irc;
 	char **userparts;
 	const char *username = gaim_account_get_username(account);
-	int err;
+	GaimProxyConnectInfo *connect_info;
 
 	gc = gaim_account_get_connection(account);
 	gc->flags |= GAIM_CONNECTION_NO_NEWLINES;
@@ -325,11 +325,11 @@
 
 	if (!irc->gsc) {
 
-		err = gaim_proxy_connect(account, irc->server,
+		connect_info = gaim_proxy_connect(account, irc->server,
 				 gaim_account_get_int(account, "port", IRC_DEFAULT_PORT),
-				 irc_login_cb, gc);
+				 irc_login_cb, NULL, gc);
 
-		if (err || !gaim_account_get_connection(account)) {
+		if (!connect_info || !gaim_account_get_connection(account)) {
 			gaim_connection_error(gc, _("Couldn't create socket"));
 			return;
 		}
@@ -394,7 +394,7 @@
 	}
 }
 
-static void irc_login_cb(gpointer data, gint source, GaimInputCondition cond)
+static void irc_login_cb(gpointer data, gint source)
 {
 	GaimConnection *gc = data;
 	struct irc_conn *irc = gc->proto_data;
--- a/src/protocols/jabber/jabber.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/jabber/jabber.c	Sat Aug 12 10:12:43 2006 +0000
@@ -421,7 +421,7 @@
 
 
 static void
-jabber_login_callback(gpointer data, gint source, GaimInputCondition cond)
+jabber_login_callback(gpointer data, gint source)
 {
 	GaimConnection *gc = data;
 	JabberStream *js = gc->proto_data;
@@ -474,12 +474,12 @@
 
 static void jabber_login_connect(JabberStream *js, const char *server, int port)
 {
-	int rc;
+	GaimProxyConnectInfo *connect_info;
 
-	rc = gaim_proxy_connect(js->gc->account, server,
-			port, jabber_login_callback, js->gc);
+	connect_info = gaim_proxy_connect(js->gc->account, server,
+			port, jabber_login_callback, NULL, js->gc);
 
-	if (rc != 0)
+	if (connect_info == NULL)
 		gaim_connection_error(js->gc, _("Unable to create socket"));
 }
 
@@ -862,7 +862,7 @@
 	const char *connect_server = gaim_account_get_string(account,
 			"connect_server", "");
 	const char *server;
-	int rc;
+	GaimProxyConnectInfo *connect_info;
 
 	js = gc->proto_data = g_new0(JabberStream, 1);
 	js->gc = gc;
@@ -912,11 +912,11 @@
 	}
 
 	if(!js->gsc) {
-		rc = gaim_proxy_connect(account, server,
+		connect_info = gaim_proxy_connect(account, server,
 				gaim_account_get_int(account, "port", 5222),
-				jabber_login_callback, gc);
+				jabber_login_callback, NULL, gc);
 
-		if (rc != 0)
+		if (connect_info == NULL)
 			gaim_connection_error(gc, _("Unable to create socket"));
 	}
 }
--- a/src/protocols/jabber/si.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/jabber/si.c	Sat Aug 12 10:12:43 2006 +0000
@@ -88,7 +88,7 @@
 
 static void jabber_si_bytestreams_attempt_connect(GaimXfer *xfer);
 
-static void jabber_si_bytestreams_connect_cb(gpointer data, gint source, GaimInputCondition cond)
+static void jabber_si_bytestreams_connect_cb(gpointer data, gint source)
 {
 	GaimXfer *xfer = data;
 	JabberSIXfer *jsx = xfer->data;
@@ -167,7 +167,7 @@
 	for(i=0; i<20; i++, p+=2)
 		snprintf(p, 3, "%02x", hashval[i]);
 
-	gaim_proxy_connect_socks5(jsx->gpi, dstaddr, 0, jabber_si_bytestreams_connect_cb, xfer);
+	gaim_proxy_connect_socks5(jsx->gpi, dstaddr, 0, jabber_si_bytestreams_connect_cb, NULL, xfer);
 	g_free(dstaddr);
 }
 
--- a/src/protocols/msn/directconn.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/msn/directconn.c	Sat Aug 12 10:12:43 2006 +0000
@@ -368,12 +368,12 @@
 }
 
 static void
-connect_cb(gpointer data, gint source, GaimInputCondition cond)
+connect_cb(gpointer data, gint source)
 {
 	MsnDirectConn* directconn;
 	int fd;
 
-	gaim_debug_misc("msn", "directconn: connect_cb: %d, %d.\n", source, cond);
+	gaim_debug_misc("msn", "directconn: connect_cb: %d\n", source);
 
 	directconn = data;
 
@@ -423,7 +423,7 @@
 msn_directconn_connect(MsnDirectConn *directconn, const char *host, int port)
 {
 	MsnSession *session;
-	int r;
+	GaimProxyConnectInfo *connect_info;
 
 	g_return_val_if_fail(directconn != NULL, FALSE);
 	g_return_val_if_fail(host       != NULL, TRUE);
@@ -438,10 +438,10 @@
 	}
 #endif
 
-	r = gaim_proxy_connect(session->account, host, port, connect_cb,
-						   directconn);
+	connect_info = gaim_proxy_connect(session->account, host, port,
+						   connect_cb, NULL, directconn);
 
-	if (r == 0)
+	if (connect_info != NULL)
 	{
 		return TRUE;
 	}
--- a/src/protocols/msn/httpconn.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/msn/httpconn.c	Sat Aug 12 10:12:43 2006 +0000
@@ -693,7 +693,7 @@
 }
 
 static void
-connect_cb(gpointer data, gint source, GaimInputCondition cond)
+connect_cb(gpointer data, gint source)
 {
 	MsnHttpConn *httpconn = data;
 
@@ -729,7 +729,7 @@
 gboolean
 msn_httpconn_connect(MsnHttpConn *httpconn, const char *host, int port)
 {
-	int r;
+	GaimProxyConnectInfo *connect_info;
 
 	g_return_val_if_fail(httpconn != NULL, FALSE);
 	g_return_val_if_fail(host     != NULL, FALSE);
@@ -738,10 +738,10 @@
 	if (httpconn->connected)
 		msn_httpconn_disconnect(httpconn);
 
-	r = gaim_proxy_connect(httpconn->session->account,
-		"gateway.messenger.hotmail.com", 80, connect_cb, httpconn);
+	connect_info = gaim_proxy_connect(httpconn->session->account,
+		"gateway.messenger.hotmail.com", 80, connect_cb, NULL, httpconn);
 
-	if (r == 0)
+	if (connect_info != NULL)
 	{
 		httpconn->waiting_response = TRUE;
 		httpconn->connected = TRUE;
--- a/src/protocols/msn/servconn.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/msn/servconn.c	Sat Aug 12 10:12:43 2006 +0000
@@ -166,7 +166,7 @@
  **************************************************************************/
 
 static void
-connect_cb(gpointer data, gint source, GaimInputCondition cond)
+connect_cb(gpointer data, gint source)
 {
 	MsnServConn *servconn = data;
 
@@ -199,7 +199,7 @@
 msn_servconn_connect(MsnServConn *servconn, const char *host, int port)
 {
 	MsnSession *session;
-	int r;
+	GaimProxyConnectInfo *connect_info;
 
 	g_return_val_if_fail(servconn != NULL, FALSE);
 	g_return_val_if_fail(host     != NULL, FALSE);
@@ -232,10 +232,10 @@
 		return TRUE;
 	}
 
-	r = gaim_proxy_connect(session->account, host, port, connect_cb,
-		servconn);
+	connect_info = gaim_proxy_connect(session->account, host, port,
+		connect_cb, NULL, servconn);
 
-	if (r == 0)
+	if (connect_info != NULL)
 	{
 		servconn->processing = TRUE;
 		return TRUE;
--- a/src/protocols/oscar/oscar.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/oscar/oscar.c	Sat Aug 12 10:12:43 2006 +0000
@@ -943,7 +943,7 @@
  * on the type of host, we do a few different things here.
  */
 static void
-connection_established_cb(gpointer data, gint source, GaimInputCondition cond)
+connection_established_cb(gpointer data, gint source)
 {
 	NewFlapConnectionData *new_conn_data;
 	GaimConnection *gc;
@@ -1250,7 +1250,7 @@
 	if (gaim_proxy_connect(account,
 			gaim_account_get_string(account, "server", OSCAR_DEFAULT_LOGIN_SERVER),
 			gaim_account_get_int(account, "port", OSCAR_DEFAULT_LOGIN_PORT),
-			connection_established_cb, new_conn_data) < 0)
+			connection_established_cb, NULL, new_conn_data) == NULL)
 	{
 		gaim_connection_error(gc, _("Couldn't connect to host"));
 		return;
@@ -1294,7 +1294,8 @@
 	GaimConnection *gc = od->gc;
 	GaimAccount *account = gc->account;
 	char *host; int port;
-	int i, rc;
+	int i;
+	GaimProxyConnectInfo *connect_info;
 	NewFlapConnectionData *new_conn_data;
 	va_list ap;
 	struct aim_authresp_info *info;
@@ -1366,9 +1367,10 @@
 	new_conn_data->cookielen = info->cookielen;
 	new_conn_data->cookie = g_memdup(info->cookie, info->cookielen);
 	new_conn_data->data = NULL;
-	rc = gaim_proxy_connect(gc->account, host, port, connection_established_cb, new_conn_data);
+	connect_info = gaim_proxy_connect(gc->account, host, port,
+			connection_established_cb, NULL, new_conn_data);
 	g_free(host);
-	if (rc < 0) {
+	if (connect_info == NULL) {
 		gaim_connection_error(gc, _("Could Not Connect"));
 		od->killme = TRUE;
 		return 0;
@@ -1479,7 +1481,9 @@
 	g_free(pos);
 }
 
-static void straight_to_hell(gpointer data, gint source, GaimInputCondition cond) {
+static void
+straight_to_hell(gpointer data, gint source)
+{
 	struct pieceofcrap *pos = data;
 	gchar *buf;
 
@@ -1569,7 +1573,8 @@
 	pos->len = len;
 	pos->modname = g_strdup(modname);
 
-	if (gaim_proxy_connect(pos->gc->account, "gaim.sourceforge.net", 80, straight_to_hell, pos) != 0)
+	if (gaim_proxy_connect(pos->gc->account, "gaim.sourceforge.net", 80,
+			straight_to_hell, NULL, pos) == NULL)
 	{
 		char buf[256];
 		if (pos->modname)
@@ -1660,7 +1665,7 @@
 		new_conn_data->data = NULL;
 	}
 
-	if (gaim_proxy_connect(account, host, port, connection_established_cb, new_conn_data) != 0)
+	if (gaim_proxy_connect(account, host, port, connection_established_cb, NULL, new_conn_data) == NULL)
 	{
 		flap_connection_schedule_destroy(new_conn_data->conn,
 				OSCAR_DISCONNECT_COULD_NOT_CONNECT);
--- a/src/protocols/oscar/peer.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/oscar/peer.c	Sat Aug 12 10:12:43 2006 +0000
@@ -470,7 +470,7 @@
  * either connected or failed to connect.
  */
 static void
-peer_connection_established_cb(gpointer data, gint source, GaimInputCondition cond)
+peer_connection_established_cb(gpointer data, gint source)
 {
 	NewPeerConnectionData *new_conn_data;
 	GaimConnection *gc;
@@ -668,7 +668,7 @@
 		}
 
 		if (gaim_proxy_connect(account, conn->verifiedip, conn->port,
-				peer_connection_established_cb, new_conn_data) == 0)
+				peer_connection_established_cb, NULL, new_conn_data) != NULL)
 		{
 			/* Connecting... */
 			return;
@@ -699,7 +699,7 @@
 			}
 
 			if (gaim_proxy_connect(account, conn->clientip, conn->port,
-					peer_connection_established_cb, new_conn_data) == 0)
+					peer_connection_established_cb, NULL, new_conn_data) != NULL)
 			{
 				/* Connecting... */
 				return;
@@ -760,7 +760,7 @@
 		if (gaim_proxy_connect(account,
 				(conn->proxyip != NULL) ? conn->proxyip : PEER_PROXY_SERVER,
 				PEER_PROXY_PORT,
-				peer_proxy_connection_established_cb, new_conn_data) == 0)
+				peer_proxy_connection_established_cb, NULL, new_conn_data) != NULL)
 		{
 			/* Connecting... */
 			return;
--- a/src/protocols/oscar/peer.h	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/oscar/peer.h	Sat Aug 12 10:12:43 2006 +0000
@@ -254,7 +254,7 @@
 /*
  * For peer proxying
  */
-void peer_proxy_connection_established_cb(gpointer data, gint source, GaimInputCondition cond);
+void peer_proxy_connection_established_cb(gpointer data, gint source);
 
 #if 0
 int peer_oft_sendheader(OscarData *od, guint16 type, PeerConnection *peer_connection);
--- a/src/protocols/oscar/peer_proxy.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/oscar/peer_proxy.c	Sat Aug 12 10:12:43 2006 +0000
@@ -326,7 +326,7 @@
  * either connected or failed to connect.
  */
 void
-peer_proxy_connection_established_cb(gpointer data, gint source, GaimInputCondition cond)
+peer_proxy_connection_established_cb(gpointer data, gint source)
 {
 	NewPeerConnectionData *new_conn_data;
 	GaimConnection *gc;
--- a/src/protocols/qq/qq_proxy.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/qq/qq_proxy.c	Sat Aug 12 10:12:43 2006 +0000
@@ -119,7 +119,7 @@
 
 /* the callback function after socket is built
  * we setup the qq protocol related configuration here */
-static void _qq_got_login(gpointer data, gint source, GaimInputCondition cond)
+static void _qq_got_login(gpointer data, gint source)
 {
 	qq_data *qd;
 	GaimConnection *gc;
@@ -309,7 +309,7 @@
  * and qq_udp_proxy.c to add UDP proxy support (thanks henry)
  *  return the socket handle, -1 means fail */
 static gint _proxy_connect_full (GaimAccount *account, const gchar *host, guint16 port, 
-		GaimInputFunction func, gpointer data, gboolean use_tcp)
+		GaimProxyConnectFunction func, gpointer data, gboolean use_tcp)
 {
 	GaimConnection *gc;
 	qq_data *qd;
@@ -319,8 +319,12 @@
 	qd->server_ip = g_strdup(host);
 	qd->server_port = port;
 
-	return use_tcp ? gaim_proxy_connect(account, host, port, func, data) :	/* TCP mode */
-	    _qq_udp_proxy_connect(account, host, port, func, data);	/* UDP mode */
+	if (use_tcp)
+		/* TCP mode */
+		return (gaim_proxy_connect(account, host, port, func, NULL, data) == NULL);
+	else
+		/* UDP mode */
+		return _qq_udp_proxy_connect(account, host, port, func, data);
 }
 
 /* establish a generic QQ connection 
--- a/src/protocols/sametime/sametime.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/sametime/sametime.c	Sat Aug 12 10:12:43 2006 +0000
@@ -310,7 +310,7 @@
 
 /* connection functions */
 
-static void connect_cb(gpointer data, gint source, GaimInputCondition cond);
+static void connect_cb(gpointer data, gint source);
 
 
 /* ----- session ------ */
@@ -1409,7 +1409,7 @@
   port = gaim_account_get_int(account, MW_KEY_PORT, MW_PLUGIN_DEFAULT_PORT);
 
   if(gaim_account_get_bool(account, MW_KEY_FORCE, FALSE) ||
-     gaim_proxy_connect(account, host, port, connect_cb, pd)) {
+     (gaim_proxy_connect(account, host, port, connect_cb, NULL, pd) == NULL)) {
 
     mwSession_forceLogin(session);
   }
@@ -1669,8 +1669,7 @@
 
 /** Callback passed to gaim_proxy_connect when an account is logged
     in, and if the session logging in receives a redirect message */
-static void connect_cb(gpointer data, gint source,
-		       GaimInputCondition cond) {
+static void connect_cb(gpointer data, gint source) {
 
   struct mwGaimPluginData *pd = data;
   GaimConnection *gc = pd->gc;
@@ -3684,7 +3683,7 @@
 
   gaim_connection_update_progress(gc, _("Connecting"), 1, MW_CONNECT_STEPS);
 
-  if(gaim_proxy_connect(account, host, port, connect_cb, pd)) {
+  if(gaim_proxy_connect(account, host, port, connect_cb, NULL, pd) == NULL) {
     gaim_connection_error(gc, _("Unable to connect to host"));
   }
 }
--- a/src/protocols/silc/silc.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/silc/silc.c	Sat Aug 12 10:12:43 2006 +0000
@@ -141,7 +141,7 @@
 }
 
 static void
-silcgaim_login_connected(gpointer data, gint source, GaimInputCondition cond)
+silcgaim_login_connected(gpointer data, gint source)
 {
 	GaimConnection *gc = data;
 	SilcGaim sg;
@@ -367,7 +367,8 @@
 			       gaim_account_get_string(account, "server",
 						       "silc.silcnet.org"),
 			       gaim_account_get_int(account, "port", 706),
-			       silcgaim_login_connected, gc)) {
+			       silcgaim_login_connected, NULL, gc) == NULL)
+	{
 		gaim_connection_error(gc, _("Unable to create connection"));
 		return;
 	}
--- a/src/protocols/simple/simple.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/simple/simple.c	Sat Aug 12 10:12:43 2006 +0000
@@ -421,7 +421,7 @@
 
 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond);
 
-static void send_later_cb(gpointer data, gint source, GaimInputCondition cond) {
+static void send_later_cb(gpointer data, gint source) {
 	GaimConnection *gc = data;
 	struct simple_account_data *sip = gc->proto_data;
 	struct sip_connection *conn;
@@ -448,11 +448,12 @@
 
 static void sendlater(GaimConnection *gc, const char *buf) {
 	struct simple_account_data *sip = gc->proto_data;
-	int error = 0;
+	GaimProxyConnectInfo *connect_info;
+
 	if(!sip->connecting) {
 		gaim_debug_info("simple", "connecting to %s port %d\n", sip->realhostname ? sip->realhostname : "{NULL}", sip->realport);
-		error = gaim_proxy_connect(sip->account, sip->realhostname, sip->realport, send_later_cb, gc);
-		if(error) {
+		connect_info = gaim_proxy_connect(sip->account, sip->realhostname, sip->realport, send_later_cb, NULL, gc);
+		if(connect_info == NULL) {
 			gaim_connection_error(gc, _("Couldn't create socket"));
 		}
 		sip->connecting = TRUE;
@@ -1452,7 +1453,7 @@
 	conn->inputhandler = gaim_input_add(newfd, GAIM_INPUT_READ, simple_input_cb, gc);
 }
 
-static void login_cb(gpointer data, gint source, GaimInputCondition cond) {
+static void login_cb(gpointer data, gint source) {
 	GaimConnection *gc = data;
 	struct simple_account_data *sip = gc->proto_data;
 	struct sip_connection *conn;
@@ -1536,7 +1537,7 @@
 static void
 simple_tcp_connect_listen_cb(int listenfd, gpointer data) {
 	struct simple_account_data *sip = (struct simple_account_data*) data;
-	int error = 0;
+	GaimProxyConnectInfo *connect_info;
 
 	sip->listenfd = listenfd;
 	if(sip->listenfd == -1) {
@@ -1551,9 +1552,9 @@
 	gaim_debug_info("simple", "connecting to %s port %d\n",
 			sip->realhostname, sip->realport);
 	/* open tcp connection to the server */
-	error = gaim_proxy_connect(sip->account, sip->realhostname,
-			sip->realport, login_cb, sip->gc);
-	if(error) {
+	connect_info = gaim_proxy_connect(sip->account, sip->realhostname,
+			sip->realport, login_cb, NULL, sip->gc);
+	if(connect_info == NULL) {
 		gaim_connection_error(sip->gc, _("Couldn't create socket"));
 	}
 }
--- a/src/protocols/yahoo/yahoo.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/yahoo/yahoo.c	Sat Aug 12 10:12:43 2006 +0000
@@ -2239,7 +2239,7 @@
 	}
 }
 
-static void yahoo_got_connected(gpointer data, gint source, GaimInputCondition cond)
+static void yahoo_got_connected(gpointer data, gint source)
 {
 	GaimConnection *gc = data;
 	struct yahoo_data *yd;
@@ -2266,7 +2266,7 @@
 	gc->inpa = gaim_input_add(yd->fd, GAIM_INPUT_READ, yahoo_pending, gc);
 }
 
-static void yahoo_got_web_connected(gpointer data, gint source, GaimInputCondition cond)
+static void yahoo_got_web_connected(gpointer data, gint source)
 {
 	GaimConnection *gc = data;
 	struct yahoo_data *yd;
@@ -2348,7 +2348,7 @@
 	/* Now we have our cookies to login with.  I'll go get the milk. */
 	if (gaim_proxy_connect(account, "wcs2.msg.dcn.yahoo.com",
 			       gaim_account_get_int(account, "port", YAHOO_PAGER_PORT),
-			       yahoo_got_web_connected, gc) != 0) {
+			       yahoo_got_web_connected, NULL, gc) == NULL) {
 		gaim_connection_error(gc, _("Connection problem"));
 		return;
 	}
@@ -2390,7 +2390,7 @@
 	gc->inpa = gaim_input_add(source, GAIM_INPUT_READ, yahoo_web_pending, gc);
 }
 
-static void yahoo_got_cookies(gpointer data, gint source, GaimInputCondition cond)
+static void yahoo_got_cookies(gpointer data, gint source)
 {
 	GaimConnection *gc = data;
 
@@ -2516,7 +2516,7 @@
 			      "Host: login.yahoo.com\r\n\r\n");
 	g_hash_table_destroy(hash);
 	yd->auth = g_string_free(url, FALSE);
-	if (gaim_proxy_connect(account, "login.yahoo.com", 80, yahoo_got_cookies, gc) != 0) {
+	if (gaim_proxy_connect(account, "login.yahoo.com", 80, yahoo_got_cookies, NULL, gc) == NULL) {
 		gaim_connection_error(gc, _("Connection problem"));
 		return;
 	}
@@ -2618,7 +2618,7 @@
 		if (gaim_proxy_connect(account,
 		                       gaim_account_get_string(account, "serverjp",  YAHOOJP_PAGER_HOST),
 		                       gaim_account_get_int(account, "port", YAHOO_PAGER_PORT),
-		                       yahoo_got_connected, gc) != 0)
+		                       yahoo_got_connected, NULL, gc) == NULL)
 		{
 			gaim_connection_error(gc, _("Connection problem"));
 			return;
@@ -2628,7 +2628,7 @@
 		if (gaim_proxy_connect(account,
 		                       gaim_account_get_string(account, "server",  YAHOO_PAGER_HOST),
 		                       gaim_account_get_int(account, "port", YAHOO_PAGER_PORT),
-		                       yahoo_got_connected, gc) != 0)
+		                       yahoo_got_connected, NULL, gc) == NULL)
 		{
 			gaim_connection_error(gc, _("Connection problem"));
 			return;
--- a/src/protocols/yahoo/yahoo_filexfer.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/yahoo/yahoo_filexfer.c	Sat Aug 12 10:12:43 2006 +0000
@@ -92,7 +92,7 @@
 
 }
 
-static void yahoo_receivefile_connected(gpointer data, gint source, GaimInputCondition condition)
+static void yahoo_receivefile_connected(gpointer data, gint source)
 {
 	GaimXfer *xfer;
 	struct yahoo_xfer_data *xd;
@@ -162,7 +162,7 @@
 	gaim_xfer_start(xfer, source, NULL, 0);
 }
 
-static void yahoo_sendfile_connected(gpointer data, gint source, GaimInputCondition condition)
+static void yahoo_sendfile_connected(gpointer data, gint source)
 {
 	GaimXfer *xfer;
 	struct yahoo_xfer_data *xd;
@@ -263,7 +263,7 @@
 		if (yd->jp) {
 			if (gaim_proxy_connect(account, gaim_account_get_string(account, "xferjp_host",  YAHOOJP_XFER_HOST),
 			                       gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT),
-			                       yahoo_sendfile_connected, xfer) == -1)
+			                       yahoo_sendfile_connected, NULL, xfer) == NULL)
 			{
 				gaim_notify_error(gc, NULL, _("File Transfer Failed"),
 				                _("Unable to establish file descriptor."));
@@ -272,7 +272,7 @@
 		} else {
 			if (gaim_proxy_connect(account, gaim_account_get_string(account, "xfer_host",  YAHOO_XFER_HOST),
 			                       gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT),
-			                       yahoo_sendfile_connected, xfer) == -1)
+			                       yahoo_sendfile_connected, NULL, xfer) == NULL)
 			{
 				gaim_notify_error(gc, NULL, _("File Transfer Failed"),
 				                _("Unable to establish file descriptor."));
@@ -280,8 +280,12 @@
 			}
 		}
 	} else {
-		xfer->fd = gaim_proxy_connect(account, xfer_data->host, xfer_data->port,
-		                              yahoo_receivefile_connected, xfer);
+		/* TODO: Using xfer->fd like this is probably a bad thing... */
+		if (gaim_proxy_connect(account, xfer_data->host, xfer_data->port,
+		                              yahoo_receivefile_connected, NULL, xfer) == NULL)
+			xfer->fd = -1;
+		else
+			xfer->fd = 0;
 		if (xfer->fd == -1) {
 			gaim_notify_error(gc, NULL, _("File Transfer Failed"),
 			             _("Unable to establish file descriptor."));
--- a/src/protocols/yahoo/yahoo_picture.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/yahoo/yahoo_picture.c	Sat Aug 12 10:12:43 2006 +0000
@@ -406,7 +406,7 @@
 	}
 }
 
-static void yahoo_buddy_icon_upload_connected(gpointer data, gint source, GaimInputCondition condition)
+static void yahoo_buddy_icon_upload_connected(gpointer data, gint source)
 {
 	struct yahoo_buddy_icon_upload_data *d = data;
 	struct yahoo_packet *pkt;
@@ -484,7 +484,7 @@
 	if (yd->jp) {
 		if (gaim_proxy_connect(account, gaim_account_get_string(account, "xferjp_host",  YAHOOJP_XFER_HOST),
 		                       gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT),
-		                       yahoo_buddy_icon_upload_connected, d) == -1)
+		                       yahoo_buddy_icon_upload_connected, NULL, d) == NULL)
 		{
 			gaim_debug_error("yahoo", "Uploading our buddy icon failed to connect.\n");
 			yahoo_buddy_icon_upload_data_free(d);
@@ -492,7 +492,7 @@
 	} else {
 		if (gaim_proxy_connect(account, gaim_account_get_string(account, "xfer_host",  YAHOO_XFER_HOST),
 		                       gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT),
-		                       yahoo_buddy_icon_upload_connected, d) == -1)
+		                       yahoo_buddy_icon_upload_connected, NULL, d) == NULL)
 		{
 			gaim_debug_error("yahoo", "Uploading our buddy icon failed to connect.\n");
 			yahoo_buddy_icon_upload_data_free(d);
--- a/src/protocols/yahoo/yahoochat.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/yahoo/yahoochat.c	Sat Aug 12 10:12:43 2006 +0000
@@ -1373,7 +1373,7 @@
 
 }
 
-static void yahoo_roomlist_got_connected(gpointer data, gint source, GaimInputCondition cond)
+static void yahoo_roomlist_got_connected(gpointer data, gint source)
 {
 	struct yahoo_roomlist *yrl = data;
 	GaimRoomlist *list = yrl->list;
@@ -1449,8 +1449,8 @@
 
 	gaim_roomlist_set_fields(rl, fields);
 
-	if (gaim_proxy_connect(gaim_connection_get_account(gc),
-	                       yrl->host, 80, yahoo_roomlist_got_connected, yrl) != 0)
+	if (gaim_proxy_connect(gaim_connection_get_account(gc), yrl->host, 80,
+	                       yahoo_roomlist_got_connected, NULL, yrl) == NULL)
 	{
 		gaim_notify_error(gc, NULL, _("Connection problem"), _("Unable to fetch room list."));
 		yahoo_roomlist_cleanup(rl, yrl);
@@ -1518,8 +1518,8 @@
 	yrl->ucat = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_CATEGORY, _("User Rooms"), yrl->cat);
 	gaim_roomlist_room_add(list, yrl->ucat);
 
-	if (gaim_proxy_connect(list->account,
-	                       yrl->host, 80, yahoo_roomlist_got_connected, yrl) != 0)
+	if (gaim_proxy_connect(list->account, yrl->host, 80,
+	                       yahoo_roomlist_got_connected, NULL, yrl) == NULL)
 	{
 		gaim_notify_error(gaim_account_get_connection(list->account),
 		                  NULL, _("Connection problem"), _("Unable to fetch room list."));
--- a/src/protocols/yahoo/ycht.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/protocols/yahoo/ycht.c	Sat Aug 12 10:12:43 2006 +0000
@@ -528,7 +528,7 @@
 	}
 }
 
-static void ycht_got_connected(gpointer data, gint source, GaimInputCondition cond)
+static void ycht_got_connected(gpointer data, gint source)
 {
 	YchtConn *ycht = data;
 	GaimConnection *gc = ycht->gc;
@@ -571,7 +571,7 @@
 	if (gaim_proxy_connect(account,
 	                       gaim_account_get_string(account, "ycht-server",  YAHOO_YCHT_HOST),
 	                       gaim_account_get_int(account, "ycht-port", YAHOO_YCHT_PORT),
-	                       ycht_got_connected, ycht) != 0)
+	                       ycht_got_connected, NULL, ycht) == NULL)
 	{
 		ycht_connection_error(ycht, _("Connection problem"));
 		return;
--- a/src/proxy.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/proxy.c	Sat Aug 12 10:12:43 2006 +0000
@@ -38,16 +38,15 @@
 #include "proxy.h"
 #include "util.h"
 
-static GaimProxyInfo *global_proxy_info = NULL;
-
+/* Does anyone know what PHB stands for? */
 struct PHB {
-	GaimInputFunction func;
+	GaimProxyConnectFunction connect_cb;
+	GaimProxyErrorFunction error_cb;
 	gpointer data;
 	char *host;
 	int port;
-	gint inpa;
+	guint inpa;
 	GaimProxyInfo *gpi;
-	GaimAccount *account;
 	GSList *hosts;
 	guchar *write_buffer;
 	gsize write_buf_len;
@@ -58,8 +57,6 @@
 	gsize read_len;
 };
 
-static void try_connect(struct PHB *);
-
 static const char *socks5errors[] = {
 	"succeeded\n",
 	"general SOCKS server failure\n",
@@ -72,6 +69,11 @@
 	"Address type not supported\n"
 };
 
+static GaimProxyInfo *global_proxy_info = NULL;
+static GSList *phbs = NULL;
+
+static void try_connect(struct PHB *);
+
 /**************************************************************************
  * Proxy structure API
  **************************************************************************/
@@ -255,6 +257,63 @@
  * Proxy API
  **************************************************************************/
 
+static void
+gaim_proxy_phb_destroy(struct PHB *phb)
+{
+	phbs = g_slist_remove(phbs, phb);
+
+	if (phb->inpa > 0)
+		gaim_input_remove(phb->inpa);
+
+	while (phb->hosts != NULL)
+	{
+		/* Discard the length... */
+		phb->hosts = g_slist_remove(phb->hosts, phb->hosts->data);
+		/* Free the address... */
+		g_free(phb->hosts->data);
+		phb->hosts = g_slist_remove(phb->hosts, phb->hosts->data);
+	}
+
+	g_free(phb->host);
+	g_free(phb->write_buffer);
+	g_free(phb->read_buffer);
+	g_free(phb);
+}
+
+static void
+gaim_proxy_phb_connected(struct PHB *phb, int fd)
+{
+	phb->connect_cb(phb->data, fd);
+	gaim_proxy_phb_destroy(phb);
+}
+
+/**
+ * @param error An error message explaining why the connection
+ *        failed.  This will be passed to the callback function
+ *        specified in the call to gaim_proxy_connect().
+ */
+static void
+gaim_proxy_phb_error(struct PHB *phb, const gchar *error_message)
+{
+	if (phb->error_cb == NULL)
+	{
+		/*
+		 * TODO
+		 * While we're transitioning to the new gaim_proxy_connect()
+		 * code, not all callers supply an error_cb.  If this is the
+		 * case then they're expecting connect_cb to be called with
+		 * an fd of -1 in the case of an error.  Once all callers have
+		 * been changed this whole if statement should be removed.
+		 */
+		phb->connect_cb(phb->data, -1);
+		gaim_proxy_phb_destroy(phb);
+		return;
+	}
+
+	phb->error_cb(phb->data, error_message);
+	gaim_proxy_phb_destroy(phb);
+}
+
 #if defined(__unix__) || defined(__APPLE__)
 
 /*
@@ -264,9 +323,9 @@
 typedef struct {
 	char *host;
 	int port;
-	dns_callback_t callback;
+	GaimProxyDnsConnectFunction callback;
 	gpointer data;
-	gint inpa;
+	guint inpa;
 	int fd_in, fd_out;
 	pid_t dns_pid;
 } pending_dns_request_t;
@@ -285,7 +344,7 @@
 
 typedef struct {
 	dns_params_t params;
-	dns_callback_t callback;
+	GaimProxyDnsConnectFunction callback;
 	gpointer data;
 } queued_dns_request_t;
 
@@ -694,7 +753,7 @@
  */
 
 int
-gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data)
+gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data)
 {
 	pending_dns_request_t *req = NULL;
 	dns_params_t dns_params;
@@ -767,7 +826,7 @@
 typedef struct _dns_tdata {
 	char *hostname;
 	int port;
-	dns_callback_t callback;
+	GaimProxyDnsConnectFunction callback;
 	gpointer data;
 	GSList *hosts;
 	char *errmsg;
@@ -843,7 +902,7 @@
 
 int
 gaim_gethostbyname_async(const char *hostname, int port,
-							  dns_callback_t callback, gpointer data)
+							  GaimProxyDnsConnectFunction callback, gpointer data)
 {
 	dns_tdata *td;
 	struct sockaddr_in sin;
@@ -882,7 +941,7 @@
 	gpointer data;
 	size_t addrlen;
 	struct sockaddr *addr;
-	dns_callback_t callback;
+	GaimProxyDnsConnectFunction callback;
 } pending_dns_request_t;
 
 static gboolean host_resolved(gpointer data)
@@ -898,7 +957,7 @@
 
 int
 gaim_gethostbyname_async(const char *hostname, int port,
-						 dns_callback_t callback, gpointer data)
+						 GaimProxyDnsConnectFunction callback, gpointer data)
 {
 	struct sockaddr_in sin;
 	pending_dns_request_t *req;
@@ -955,9 +1014,11 @@
 	if (ret == 0 && error == EINPROGRESS)
 		return; /* we'll be called again later */
 	if (ret < 0 || error != 0) {
-		if(ret!=0) error = errno;
+		if (ret!=0)
+			error = errno;
 		close(source);
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
 
 		gaim_debug_error("proxy",
 			   "getsockopt SO_ERROR check: %s\n", strerror(error));
@@ -967,29 +1028,16 @@
 	}
 
 	gaim_input_remove(phb->inpa);
-
-	if (phb->account == NULL ||
-		gaim_account_get_connection(phb->account) != NULL) {
+	phb->inpa = 0;
 
-		phb->func(phb->data, source, GAIM_INPUT_READ);
-	}
-
-	g_free(phb->host);
-	g_free(phb);
+	gaim_proxy_phb_connected(phb, source);
 }
 
 static gboolean clean_connect(gpointer data)
 {
 	struct PHB *phb = data;
 
-	if (phb->account == NULL ||
-		gaim_account_get_connection(phb->account) != NULL) {
-
-		phb->func(phb->data, phb->port, GAIM_INPUT_READ);
-	}
-
-	g_free(phb->host);
-	g_free(phb);
+	gaim_proxy_phb_connected(phb, phb->port);
 
 	return FALSE;
 }
@@ -1037,8 +1085,9 @@
 			close(fd);
 			return -1;
 		}
+		/* TODO: Why is the following line so strange? */
 		phb->port = fd;	/* bleh */
-		gaim_timeout_add(50, clean_connect, phb);	/* we do this because we never
+		gaim_timeout_add(10, clean_connect, phb);	/* we do this because we never
 							   want to call our callback
 							   before we return. */
 	}
@@ -1059,6 +1108,7 @@
 		return;
 	else if(ret < 0) {
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
 		close(source);
 		g_free(phb->write_buffer);
 		phb->write_buffer = NULL;
@@ -1080,18 +1130,6 @@
 #define HTTP_GOODSTRING "HTTP/1.0 200"
 #define HTTP_GOODSTRING2 "HTTP/1.1 200"
 
-static void
-http_complete(struct PHB *phb, gint source)
-{
-	gaim_debug_info("http proxy", "proxy connection established\n");
-	if(!phb->account || phb->account->gc) {
-		phb->func(phb->data, source, GAIM_INPUT_READ);
-	}
-	g_free(phb->host);
-	g_free(phb);
-}
-
-
 /* read the response to the CONNECT request, if we are requesting a non-port-80 tunnel */
 static void
 http_canread(gpointer data, gint source, GaimInputCondition cond)
@@ -1101,6 +1139,7 @@
 	struct PHB *phb = data;
 	guchar *p;
 	gsize max_read;
+	gchar *msg;
 
 	if(phb->read_buffer == NULL) {
 		phb->read_buf_len = 8192;
@@ -1116,12 +1155,7 @@
 		return;
 	else if(len <= 0) {
 		close(source);
-		source = -1;
-		g_free(phb->read_buffer);
-		phb->read_buffer = NULL;
-		gaim_input_remove(phb->inpa);
-		phb->inpa = 0;
-		http_complete(phb, source);
+		gaim_proxy_phb_error(phb, _("Lost connection with server for an unknown reason."));
 		return;
 	} else {
 		phb->read_len += len;
@@ -1137,7 +1171,8 @@
 		return;
 
 	error = strncmp((const char *)phb->read_buffer, "HTTP/", 5) != 0;
-	if(!error) {
+	if (!error)
+	{
 		int major;
 		p = phb->read_buffer + 5;
 		major = strtol((const char *)p, (char **)&p, 10);
@@ -1157,7 +1192,8 @@
 
 	/* Read the contents */
 	p = (guchar *)g_strrstr((const gchar *)phb->read_buffer, "Content-Length: ");
-	if(p != NULL) {
+	if (p != NULL)
+	{
 		gchar *tmp;
 		int len = 0;
 		char tmpc;
@@ -1180,25 +1216,22 @@
 		}
 	}
 
-	if(error) {
-		gaim_debug_error("proxy",
-				"Unable to parse proxy's response: %s\n",
-				phb->read_buffer);
+	if (error)
+	{
 		close(source);
-		source = -1;
-		g_free(phb->read_buffer);
-		phb->read_buffer = NULL;
-		gaim_input_remove(phb->inpa);
-		phb->inpa = 0;
-		http_complete(phb, source);
+		msg = g_strdup_printf("Unable to parse response from HTTP proxy: %s\n",
+				phb->read_buffer);
+		gaim_proxy_phb_error(phb, msg);
+		g_free(msg);
 		return;
-	} else if(status != 200) {
+	}
+	else if (status != 200)
+	{
 		gaim_debug_error("proxy",
 				"Proxy server replied with:\n%s\n",
 				phb->read_buffer);
 
 
-		/* XXX: why in the hell are we calling gaim_connection_error() here? */
 		if(status == 407 /* Proxy Auth */) {
 			gchar *ntlm;
 			if((ntlm = g_strrstr((const gchar *)phb->read_buffer, "Proxy-Authenticate: NTLM "))) { /* Check for Type-2 */
@@ -1208,19 +1241,13 @@
 				gchar *username;
 				gchar *request;
 				gchar *response;
-				if(!(username = strchr(domain, '\\'))) {
-					char *msg = g_strdup_printf(_("Proxy connection error %d"), status);
+				username = strchr(domain, '\\');
+				if (username == NULL)
+				{
 					close(source);
-					source = -1;
-					if(phb->account)
-						gaim_connection_error(phb->account->gc, msg);
-					else
-						gaim_debug_error("http proxy", "%s\n", msg);
+					msg = g_strdup_printf(_("HTTP proxy connection error %d"), status);
+					gaim_proxy_phb_error(phb, msg);
 					g_free(msg);
-					gaim_input_remove(phb->inpa);
-					g_free(phb->read_buffer);
-					g_free(phb->host);
-					g_free(phb);
 					return;
 				}
 				*username = '\0';
@@ -1264,19 +1291,13 @@
 				gchar *domain = (gchar*) gaim_proxy_info_get_username(phb->gpi);
 				gchar *username;
 				int request_len;
-				if(!(username = strchr(domain, '\\'))) {
-					char *msg = g_strdup_printf(_("Proxy connection error %d"), status);
+				username = strchr(domain, '\\');
+				if (username == NULL)
+				{
 					close(source);
-					source = -1;
-					if(phb->account)
-						gaim_connection_error(phb->account->gc, msg);
-					else
-						gaim_debug_error("http proxy", "%s\n", msg);
+					msg = g_strdup_printf(_("HTTP proxy connection error %d"), status);
+					gaim_proxy_phb_error(phb, msg);
 					g_free(msg);
-					gaim_input_remove(phb->inpa);
-					g_free(phb->read_buffer);
-					g_free(phb->host);
-					g_free(phb);
 					return;
 				}
 				*username = '\0';
@@ -1313,49 +1334,29 @@
 				proxy_do_write(phb, source, cond);
 				return;
 			} else {
-				char *msg = g_strdup_printf(_("Proxy connection error %d"), status);
 				close(source);
-				source = -1;
-				if(phb->account)
-					gaim_connection_error(phb->account->gc, msg);
-				else
-					gaim_debug_error("http proxy", "%s\n", msg);
+				msg = g_strdup_printf(_("HTTP proxy connection error %d"), status);
+				gaim_proxy_phb_error(phb, msg);
 				g_free(msg);
-				gaim_input_remove(phb->inpa);
-				g_free(phb->read_buffer);
-				g_free(phb->host);
-				g_free(phb);
 				return;
 			}
 		}
 		if(status == 403 /* Forbidden */ ) {
-			gchar *msg = g_strdup_printf(_("Access denied: proxy server forbids port %d tunnelling."), phb->port);
-			if(phb->account)
-				gaim_connection_error(phb->account->gc, msg);
-			else
-				gaim_debug_error("http proxy", "%s\n", msg);
+			msg = g_strdup_printf(_("Access denied: HTTP proxy server forbids port %d tunnelling."), phb->port);
+			gaim_proxy_phb_error(phb, msg);
 			g_free(msg);
-			gaim_input_remove(phb->inpa);
-			g_free(phb->read_buffer);
-			g_free(phb->host);
-			g_free(phb);
 		} else {
-			char *msg = g_strdup_printf(_("Proxy connection error %d"), status);
-			if(phb->account)
-				gaim_connection_error(phb->account->gc, msg);
-			else
-				gaim_debug_error("http proxy", "%s\n", msg);
+			msg = g_strdup_printf(_("HTTP proxy connection error %d"), status);
+			gaim_proxy_phb_error(phb, msg);
 			g_free(msg);
-			gaim_input_remove(phb->inpa);
-			g_free(phb->read_buffer);
-			g_free(phb->host);
-			g_free(phb);
 		}
 	} else {
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
 		g_free(phb->read_buffer);
 		phb->read_buffer = NULL;
-		http_complete(phb, source);
+		gaim_debug_info("proxy", "HTTP proxy connection established\n");
+		gaim_proxy_phb_connected(phb, source);
 		return;
 	}
 }
@@ -1374,7 +1375,10 @@
 	gaim_debug_info("http proxy", "Connected.\n");
 
 	if (phb->inpa > 0)
+	{
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
+	}
 
 	len = sizeof(error);
 
@@ -1456,7 +1460,8 @@
 				phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE,
 							   http_canwrite, phb);
 			} else {
-				http_complete(phb, fd);
+				gaim_debug_info("proxy", "HTTP proxy connection established\n");
+				gaim_proxy_phb_connected(phb, fd);
 			}
 		} else {
 			close(fd);
@@ -1507,21 +1512,13 @@
 		return;
 	else if (len + phb->read_len >= 4) {
 		if (phb->read_buffer[1] == 90) {
-			if (phb->account == NULL ||
-				gaim_account_get_connection(phb->account) != NULL) {
-
-				phb->func(phb->data, source, GAIM_INPUT_READ);
-			}
-
-			gaim_input_remove(phb->inpa);
-			g_free(phb->read_buffer);
-			g_free(phb->host);
-			g_free(phb);
+			gaim_proxy_phb_connected(phb, source);
 			return;
 		}
 	}
 
 	gaim_input_remove(phb->inpa);
+	phb->inpa = 0;
 	g_free(phb->read_buffer);
 	phb->read_buffer = NULL;
 
@@ -1542,7 +1539,10 @@
 	gaim_debug_info("socks4 proxy", "Connected.\n");
 
 	if (phb->inpa > 0)
+	{
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
+	}
 
 	len = sizeof(error);
 
@@ -1662,6 +1662,7 @@
 		gaim_debug_warning("socks5 proxy", "or not...\n");
 		close(source);
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
 		g_free(phb->read_buffer);
 		phb->read_buffer = NULL;
 		try_connect(phb);
@@ -1679,6 +1680,7 @@
 			gaim_debug_error("socks5 proxy", "Bad data.\n");
 		close(source);
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
 		g_free(phb->read_buffer);
 		phb->read_buffer = NULL;
 		try_connect(phb);
@@ -1715,20 +1717,11 @@
 	/* Skip past BND.PORT */
 	buf += 2;
 
-	if (phb->account == NULL ||
-		gaim_account_get_connection(phb->account) != NULL) {
-
-		phb->func(phb->data, source, GAIM_INPUT_READ);
-	}
-
-	gaim_input_remove(phb->inpa);
-	g_free(phb->read_buffer);
-	g_free(phb->host);
-	g_free(phb);
+	gaim_proxy_phb_connected(phb, source);
 }
 
 static void
-s5_sendconnect(gpointer data, gint source)
+s5_sendconnect(gpointer data, int source)
 {
 	struct PHB *phb = data;
 	int hlen = strlen(phb->host);
@@ -1749,7 +1742,6 @@
 
 	phb->inpa = gaim_input_add(source, GAIM_INPUT_WRITE, proxy_do_write, phb);
 	proxy_do_write(phb, source, GAIM_INPUT_WRITE);
-
 }
 
 static void
@@ -1773,6 +1765,7 @@
 	else if(len <= 0) {
 		close(source);
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
 		g_free(phb->read_buffer);
 		phb->read_buffer = NULL;
 		try_connect(phb);
@@ -1784,6 +1777,7 @@
 		return;
 
 	gaim_input_remove(phb->inpa);
+	phb->inpa = 0;
 
 	if ((phb->read_buffer[0] != 0x01) || (phb->read_buffer[1] != 0x00)) {
 		close(source);
@@ -1865,6 +1859,7 @@
 	else if(len <= 0) {
 		close(source);
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
 		g_free(phb->read_buffer);
 		phb->read_buffer = NULL;
 		try_connect(phb);
@@ -1880,6 +1875,7 @@
 	if (*cmdbuf != 0x01) {
 		close(source);
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
 		g_free(phb->read_buffer);
 		phb->read_buffer = NULL;
 		try_connect(phb);
@@ -1901,6 +1897,7 @@
 				/* Did auth work? */
 				if (buf[0] == 0x00) {
 					gaim_input_remove(phb->inpa);
+					phb->inpa = 0;
 					g_free(phb->read_buffer);
 					phb->read_buffer = NULL;
 					/* Success */
@@ -1913,6 +1910,7 @@
 						"failed.  Disconnecting...");
 					close(source);
 					gaim_input_remove(phb->inpa);
+					phb->inpa = 0;
 					g_free(phb->read_buffer);
 					phb->read_buffer = NULL;
 					try_connect(phb);
@@ -1957,6 +1955,7 @@
 						"Disconnecting...");
 					close(source);
 					gaim_input_remove(phb->inpa);
+					phb->inpa = 0;
 					g_free(phb->read_buffer);
 					phb->read_buffer = NULL;
 					try_connect(phb);
@@ -1992,6 +1991,7 @@
 	else if(len <= 0) {
 		close(source);
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
 		g_free(phb->read_buffer);
 		phb->read_buffer = NULL;
 		try_connect(phb);
@@ -2003,6 +2003,7 @@
 		return;
 
 	gaim_input_remove(phb->inpa);
+	phb->inpa = 0;
 
 	if ((phb->read_buffer[0] != 0x05) || (phb->read_buffer[1] == 0xff)) {
 		close(source);
@@ -2094,7 +2095,10 @@
 	gaim_debug_info("socks5 proxy", "Connected.\n");
 
 	if (phb->inpa > 0)
+	{
 		gaim_input_remove(phb->inpa);
+		phb->inpa = 0;
+	}
 
 	len = sizeof(error);
 	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
@@ -2225,14 +2229,7 @@
 	}
 
 	if (ret < 0) {
-		if (phb->account == NULL ||
-			gaim_account_get_connection(phb->account) != NULL) {
-
-			phb->func(phb->data, -1, GAIM_INPUT_READ);
-		}
-
-		g_free(phb->host);
-		g_free(phb);
+		gaim_proxy_phb_error(phb, _("TODO"));
 	}
 }
 
@@ -2313,31 +2310,26 @@
 	return gpi;
 }
 
-/*
- * TODO: It would be really good if this returned some sort of handle
- *       that we could use to cancel the connection.  As it is now,
- *       each callback has to check to make sure gc is still valid.
- *       And that is ugly.
- */
-int
+GaimProxyConnectInfo *
 gaim_proxy_connect(GaimAccount *account, const char *host, int port,
-				   GaimInputFunction func, gpointer data)
+				   GaimProxyConnectFunction connect_cb,
+				   GaimProxyErrorFunction error_cb, gpointer data)
 {
 	const char *connecthost = host;
 	int connectport = port;
 	struct PHB *phb;
 
-	g_return_val_if_fail(host != NULL, -1);
-	g_return_val_if_fail(port != 0 && port != -1, -1);
-	g_return_val_if_fail(func != NULL, -1);
+	g_return_val_if_fail(host       != NULL, NULL);
+	g_return_val_if_fail(port       >  0,    NULL);
+	g_return_val_if_fail(connect_cb != NULL, NULL);
+	/* g_return_val_if_fail(error_cb   != NULL, NULL); *//* TODO: Soon! */
 
 	phb = g_new0(struct PHB, 1);
-
-	phb->func = func;
+	phb->connect_cb = connect_cb;
+	phb->error_cb = error_cb;
 	phb->data = data;
 	phb->host = g_strdup(host);
 	phb->port = port;
-	phb->account = account;
 	phb->gpi = gaim_proxy_get_setup(account);
 
 	if ((gaim_proxy_info_get_type(phb->gpi) != GAIM_PROXY_NONE) &&
@@ -2345,9 +2337,8 @@
 		 gaim_proxy_info_get_port(phb->gpi) <= 0)) {
 
 		gaim_notify_error(NULL, NULL, _("Invalid proxy settings"), _("Either the host name or port number specified for your given proxy type is invalid."));
-		g_free(phb->host);
-		g_free(phb);
-		return -1;
+		gaim_proxy_phb_destroy(phb);
+		return NULL;
 	}
 
 	switch (gaim_proxy_info_get_type(phb->gpi))
@@ -2364,30 +2355,55 @@
 			break;
 
 		default:
-			g_free(phb->host);
-			g_free(phb);
-			return -1;
+			gaim_proxy_phb_destroy(phb);
+			return NULL;
+	}
+
+	if (gaim_gethostbyname_async(connecthost,
+			connectport, connection_host_resolved, phb) != 0)
+	{
+		gaim_proxy_phb_destroy(phb);
+		return NULL;
 	}
 
-	return gaim_gethostbyname_async(connecthost, connectport,
-		connection_host_resolved, phb);
+	phbs = g_slist_prepend(phbs, phb);
+
+	return phb;
 }
 
-int
+/*
+ * Combine some of this code with gaim_proxy_connect()
+ */
+GaimProxyConnectInfo *
 gaim_proxy_connect_socks5(GaimProxyInfo *gpi, const char *host, int port,
-		GaimInputFunction func, gpointer data)
+				   GaimProxyConnectFunction connect_cb,
+				   GaimProxyErrorFunction error_cb, gpointer data)
 {
 	struct PHB *phb;
 
+	g_return_val_if_fail(host       != NULL, NULL);
+	g_return_val_if_fail(port       >  0,    NULL);
+	g_return_val_if_fail(connect_cb != NULL, NULL);
+	/* g_return_val_if_fail(error_cb   != NULL, NULL); *//* TODO: Soon! */
+
 	phb = g_new0(struct PHB, 1);
-	phb->gpi = gpi;
-	phb->func = func;
+	phb->connect_cb = connect_cb;
+	phb->error_cb = error_cb;
 	phb->data = data;
 	phb->host = g_strdup(host);
 	phb->port = port;
+	phb->gpi = gpi;
 
-	return gaim_gethostbyname_async(gaim_proxy_info_get_host(gpi),
-		gaim_proxy_info_get_port(gpi), connection_host_resolved, phb);
+	if (gaim_gethostbyname_async(gaim_proxy_info_get_host(gpi),
+			gaim_proxy_info_get_port(gpi), connection_host_resolved, phb) != 0)
+	{
+		gaim_proxy_phb_destroy(phb);
+		return NULL;
+	}
+
+	phbs = g_slist_prepend(phbs, phb);
+
+	return phb;
 }
 
 
@@ -2425,6 +2441,14 @@
 		gaim_proxy_info_set_password(info, value);
 }
 
+void *
+gaim_proxy_get_handle()
+{
+	static int handle;
+
+	return &handle;
+}
+
 void
 gaim_proxy_init(void)
 {
@@ -2459,10 +2483,9 @@
 #endif
 }
 
-void *
-gaim_proxy_get_handle()
+void
+gaim_proxy_uninit(void)
 {
-	static int handle;
-
-	return &handle;
+	while (phbs != NULL)
+		gaim_proxy_phb_destroy(phbs->data);
 }
--- a/src/proxy.h	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/proxy.h	Sat Aug 12 10:12:43 2006 +0000
@@ -56,6 +56,17 @@
 
 } GaimProxyInfo;
 
+typedef struct PBH GaimProxyConnectInfo;
+
+typedef void (*GaimProxyConnectFunction)(gpointer data, gint source);
+typedef void (*GaimProxyErrorFunction)(gpointer dat, const gchar *error_message);
+
+/**
+ * The "hosts" parameter is a linked list containing pairs of
+ * one size_t addrlen and one struct sockaddr *addr.
+ */
+typedef void (*GaimProxyDnsConnectFunction)(GSList *hosts, gpointer data, const char *error_message);
+
 
 #include "account.h"
 
@@ -69,13 +80,6 @@
 /*@{*/
 
 /**
- * Get the handle for the proxy system.
- *
- * @return the handle to the proxy system
- */
-void *gaim_proxy_get_handle(void);
-
-/**
  * Creates a proxy information structure.
  *
  * @return The proxy information structure.
@@ -196,11 +200,23 @@
 /*@{*/
 
 /**
+ * Returns the proxy subsystem handle.
+ *
+ * @return The proxy subsystem handle.
+ */
+void *gaim_proxy_get_handle(void);
+
+/**
  * Initializes the proxy subsystem.
  */
 void gaim_proxy_init(void);
 
 /**
+ * Uninitializes the proxy subsystem.
+ */
+void gaim_proxy_uninit(void);
+
+/**
  * Returns configuration of a proxy.
  *
  * @param account The account for which the configuration is needed.
@@ -210,35 +226,50 @@
 GaimProxyInfo *gaim_proxy_get_setup(GaimAccount *account);
 
 /**
- * Makes a connection to the specified host and port.
+ * Makes a connection to the specified host and port.  Note that this
+ * function name can be misleading--although it is called "proxy
+ * connect," it is used for establishing any outgoing TCP connection,
+ * whether through a proxy or not.
  *
- * @param account The account making the connection.
- * @param host    The destination host.
- * @param port    The destination port.
- * @param func    The input handler function.
- * @param data    User-defined data.
+ * @param account    The account making the connection.
+ * @param host       The destination host.
+ * @param port       The destination port.
+ * @param connect_cb The function to call when the connection is
+ *                   established.
+ * @param error_cb   The function to call if there is an error while
+ *                   establishing the connection.
+ * @param data       User-defined data.
  *
- * @return Zero indicates the connection is pending. Any other value indicates failure.
+ * @return NULL if there was an error, or a reference to a data
+ *         structure that can be used to cancel the pending
+ *         connection, if needed.
  */
-int gaim_proxy_connect(GaimAccount *account, const char *host, int port,
-					   GaimInputFunction func, gpointer data);
+GaimProxyConnectInfo *gaim_proxy_connect(GaimAccount *account,
+			const char *host, int port,
+			GaimProxyConnectFunction connect_cb,
+			GaimProxyErrorFunction error_cb, gpointer data);
 
 /**
  * Makes a connection through a SOCKS5 proxy.
  *
- * @param gpi     The GaimProxyInfo specifying the proxy settings
- * @param host    The destination host.
- * @param port    The destination port.
- * @param func    The input handler function.
- * @param data    User-defined data.
+ * @param gpi        The GaimProxyInfo specifying the proxy settings
+ * @param host       The destination host.
+ * @param port       The destination port.
+ * @param connect_cb The function to call when the connection is
+ *                   established.
+ * @param error_cb   The function to call if there is an error while
+ *                   establishing the connection.
+ * @param data       User-defined data.
  *
- * @return Zero indicates the connection is pending. Any other value indicates failure.
+ * @return NULL if there was an error, or a reference to a data
+ *         structure that can be used to cancel the pending
+ *         connection, if needed.
  */
-int gaim_proxy_connect_socks5(GaimProxyInfo *gpi, const char *host, int port,
-					   GaimInputFunction func, gpointer data);
+GaimProxyConnectInfo *gaim_proxy_connect_socks5(GaimProxyInfo *gpi,
+			const char *host, int port,
+			GaimProxyConnectFunction connect_cb,
+			GaimProxyErrorFunction error_cb, gpointer data);
 
-typedef void (*dns_callback_t)(GSList *hosts, gpointer data,
-		const char *error_message);
 /**
  * Do an async dns query
  *
@@ -249,7 +280,7 @@
  *
  * @return Zero indicates the connection is pending. Any other value indicates failure.
  */
-int gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data);
+int gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data);
 
 /*@}*/
 
--- a/src/sslconn.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/sslconn.c	Sat Aug 12 10:12:43 2006 +0000
@@ -69,7 +69,7 @@
 {
 	GaimSslConnection *gsc;
 	GaimSslOps *ops;
-	int i;
+	GaimProxyConnectInfo *connect_info;
 
 	g_return_val_if_fail(host != NULL,            NULL);
 	g_return_val_if_fail(port != 0 && port != -1, NULL);
@@ -95,9 +95,9 @@
 	gsc->connect_cb      = func;
 	gsc->error_cb        = error_func;
 
-	i = gaim_proxy_connect(account, host, port, ops->connect_cb, gsc);
+	connect_info = gaim_proxy_connect(account, host, port, ops->connect_cb, NULL, gsc);
 
-	if (i < 0)
+	if (connect_info == NULL)
 	{
 		g_free(gsc->host);
 		g_free(gsc);
--- a/src/upnp.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/upnp.c	Sat Aug 12 10:12:43 2006 +0000
@@ -780,15 +780,15 @@
 }
 
 static void
-looked_up_internal_ip_cb(gpointer data, gint sock, GaimInputCondition cond)
+looked_up_internal_ip_cb(gpointer data, gint source)
 {
-	if (sock) {
+	if (source) {
 		strncpy(control_info.internalip,
-			gaim_network_get_local_system_ip(sock),
+			gaim_network_get_local_system_ip(source),
 			sizeof(control_info.internalip));
 		gaim_debug_info("upnp", "Local IP: %s\n",
 				control_info.internalip);
-		close(sock);
+		close(source);
 	} else
 		gaim_debug_info("upnp", "Unable to look up local IP\n");
 
@@ -811,8 +811,8 @@
 	}
 
 	if(gaim_proxy_connect(NULL, addressOfControl, port,
-			looked_up_internal_ip_cb, NULL) != 0) {
-
+			looked_up_internal_ip_cb, NULL, NULL) == NULL)
+	{
 		gaim_debug_error("upnp", "Get Local IP Connect Failed: Address: %s @@@ Port %d\n",
 			addressOfControl, port);
 	}
--- a/src/util.c	Sat Aug 12 10:06:15 2006 +0000
+++ b/src/util.c	Sat Aug 12 10:12:43 2006 +0000
@@ -3367,7 +3367,7 @@
 }
 
 static void
-url_fetch_connect_cb(gpointer url_data, gint source, GaimInputCondition cond)
+url_fetch_connect_cb(gpointer url_data, gint source)
 {
 	GaimFetchUrlData *gfud;
 
@@ -3448,7 +3448,8 @@
 				   &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
 
 	if (gaim_proxy_connect(NULL, gfud->website.address,
-		gfud->website.port, url_fetch_connect_cb, gfud) != 0) {
+		gfud->website.port, url_fetch_connect_cb, NULL, gfud) == NULL)
+	{
 		destroy_fetch_url_data(gfud);
 
 		cb(user_data, g_strdup(_("g003: Error opening connection.\n")), 0);