src/proxy.c

changeset 5681
514fbc5374dc
parent 5580
a5a3e6dfb409
child 5872
754c63f29b77
--- a/src/proxy.c	Mon Jun 02 22:30:25 2003 +0000
+++ b/src/proxy.c	Tue Jun 03 02:00:33 2003 +0000
@@ -1,7 +1,11 @@
-/*
+/**
+ * @file proxy.c Proxy API
+ * @ingroup core
+ *
  * gaim
  *
  * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
+ * Copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -47,6 +51,7 @@
 #include <errno.h>
 #include "gaim.h"
 #include "proxy.h"
+#include "prefs.h"
 
 #ifdef _WIN32
 #include "win32dep.h"
@@ -55,7 +60,8 @@
 #define GAIM_READ_COND  (G_IO_IN | G_IO_HUP | G_IO_ERR)
 #define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
 
-struct gaim_proxy_info global_proxy_info;
+static GaimProxyInfo *global_proxy_info = NULL;
+static gboolean global_proxy_info_from_prefs = FALSE;
 
 struct PHB {
 	GaimInputFunction func;
@@ -63,7 +69,7 @@
 	char *host;
 	int port;
 	gint inpa;
-	struct gaim_proxy_info *gpi;
+	GaimProxyInfo *gpi;
 	GaimAccount *account;
 };
 
@@ -71,8 +77,143 @@
 	GaimInputFunction function;
 	guint result;
 	gpointer data;
+
 } GaimIOClosure;
 
+/**************************************************************************
+ * Proxy structure API
+ **************************************************************************/
+GaimProxyInfo *
+gaim_proxy_info_new(void)
+{
+	return g_new0(GaimProxyInfo, 1);
+}
+
+void
+gaim_proxy_info_destroy(GaimProxyInfo *info)
+{
+	g_return_if_fail(info != NULL);
+
+	if (info->host     != NULL) g_free(info->host);
+	if (info->username != NULL) g_free(info->username);
+	if (info->password != NULL) g_free(info->password);
+
+	g_free(info);
+}
+
+void
+gaim_proxy_info_set_type(GaimProxyInfo *info, GaimProxyType type)
+{
+	g_return_if_fail(info != NULL);
+
+	info->type = type;
+}
+
+void
+gaim_proxy_info_set_host(GaimProxyInfo *info, const char *host)
+{
+	g_return_if_fail(info != NULL);
+
+	if (info->host != NULL)
+		g_free(info->host);
+
+	info->host = (host == NULL ? NULL : g_strdup(host));
+}
+
+void
+gaim_proxy_info_set_port(GaimProxyInfo *info, int port)
+{
+	g_return_if_fail(info != NULL);
+
+	info->port = port;
+}
+
+void
+gaim_proxy_info_set_username(GaimProxyInfo *info, const char *username)
+{
+	g_return_if_fail(info != NULL);
+
+	if (info->username != NULL)
+		g_free(info->username);
+
+	info->username = (username == NULL ? NULL : g_strdup(username));
+}
+
+void
+gaim_proxy_info_set_password(GaimProxyInfo *info, const char *password)
+{
+	g_return_if_fail(info != NULL);
+
+	if (info->password != NULL)
+		g_free(info->password);
+
+	info->password = (password == NULL ? NULL : g_strdup(password));
+}
+
+GaimProxyType
+gaim_proxy_info_get_type(const GaimProxyInfo *info)
+{
+	g_return_val_if_fail(info != NULL, GAIM_PROXY_NONE);
+
+	return info->type;
+}
+
+const char *
+gaim_proxy_info_get_host(const GaimProxyInfo *info)
+{
+	g_return_val_if_fail(info != NULL, NULL);
+
+	return info->host;
+}
+
+int
+gaim_proxy_info_get_port(const GaimProxyInfo *info)
+{
+	g_return_val_if_fail(info != NULL, 0);
+
+	return info->port;
+}
+
+const char *
+gaim_proxy_info_get_username(const GaimProxyInfo *info)
+{
+	g_return_val_if_fail(info != NULL, NULL);
+
+	return info->username;
+}
+
+const char *
+gaim_proxy_info_get_password(const GaimProxyInfo *info)
+{
+	g_return_val_if_fail(info != NULL, NULL);
+
+	return info->password;
+}
+
+/**************************************************************************
+ * Global Proxy API
+ **************************************************************************/
+void
+gaim_global_proxy_set_from_prefs(gboolean from_prefs)
+{
+	global_proxy_info_from_prefs = from_prefs;
+}
+
+GaimProxyInfo *
+gaim_global_proxy_get_info(void)
+{
+	return global_proxy_info;
+}
+
+gboolean
+gaim_global_proxy_is_from_prefs(void)
+{
+	return global_proxy_info_from_prefs;
+}
+ 
+/**************************************************************************
+ * Proxy API
+ **************************************************************************/
 static void gaim_io_destroy(gpointer data)
 {
 	g_free(data);
@@ -579,7 +720,9 @@
 	return FALSE;
 }
 
-int gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data)
+int
+gaim_gethostbyname_async(const char *hostname, int port,
+						 dns_callback_t callback, gpointer data)
 {
 	struct sockaddr_in sin;
 	pending_dns_request_t *req;
@@ -610,7 +753,8 @@
 
 #endif
 
-static void no_one_calls(gpointer data, gint source, GaimInputCondition cond)
+static void
+no_one_calls(gpointer data, gint source, GaimInputCondition cond)
 {
 	struct PHB *phb = data;
 	unsigned int len;
@@ -626,8 +770,13 @@
 		if(ret==0) errno = error;
 		close(source);
 		gaim_input_remove(phb->inpa);
-		if(!phb->account || phb->account->gc)
+
+		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);
 
@@ -635,10 +784,16 @@
 			   "getsockopt SO_ERROR check: %s\n", strerror(errno));
 		return;
 	}
+
 	fcntl(source, F_SETFL, 0);
 	gaim_input_remove(phb->inpa);
-	if(!phb->account || phb->account->gc)
+
+	if (phb->account == NULL ||
+		gaim_account_get_connection(phb->account) != NULL) {
+
 		phb->func(phb->data, source, GAIM_INPUT_READ);
+	}
+
 	g_free(phb->host);
 	g_free(phb);
 }
@@ -647,8 +802,12 @@
 {
 	struct PHB *phb = data;
 
-	if(!phb->account || phb->account->gc)
+	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);
 
@@ -656,7 +815,8 @@
 }
 
 
-static int proxy_connect_none(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
+static int
+proxy_connect_none(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
 {
 	int fd = -1;
 
@@ -675,13 +835,15 @@
 			gaim_debug(GAIM_DEBUG_WARNING, "proxy",
 					   "Connect would have blocked.\n");
 			phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, no_one_calls, phb);
-		} else {
+		}
+		else {
 			gaim_debug(GAIM_DEBUG_ERROR, "proxy",
 					   "Connect failed (errno %d)\n", errno);
 			close(fd);
 			return -1;
 		}
-	} else {
+	}
+	else {
 		unsigned int len;
 		int error = ETIMEDOUT;
 		gaim_debug(GAIM_DEBUG_MISC, "proxy", "Connect didn't block.\n");
@@ -704,7 +866,8 @@
 #define HTTP_GOODSTRING "HTTP/1.0 200"
 #define HTTP_GOODSTRING2 "HTTP/1.1 200"
 
-static void http_canread(gpointer data, gint source, GaimInputCondition cond)
+static void
+http_canread(gpointer data, gint source, GaimInputCondition cond)
 {
 	int nlc = 0;
 	int pos = 0;
@@ -721,7 +884,7 @@
 			nlc = 0;
 	}
 	inputline[pos] = '\0';
-	
+
 	error = strncmp(inputline, "HTTP/", 5) != 0;
 	if(!error) {
 		p = inputline + 5;
@@ -744,7 +907,8 @@
 				   "Unable to parse proxy's response: %s\n", inputline);
 		close(source);
 		source=-1;
-	} else if(status!=200) {
+	}
+	else if(status!=200) {
 		gaim_debug(GAIM_DEBUG_ERROR, "proxy",
 				   "Proxy server replied: (%s)\n", p);
 		close(source);
@@ -758,7 +922,8 @@
 	return;
 }
 
-static void http_canwrite(gpointer data, gint source, GaimInputCondition cond)
+static void
+http_canwrite(gpointer data, gint source, GaimInputCondition cond)
 {
 	char request[8192];
 	int request_len = 0;
@@ -770,25 +935,38 @@
 
 	if (phb->inpa > 0)
 		gaim_input_remove(phb->inpa);
+
 	len = sizeof(error);
+
 	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
 	}
-	request_len = g_snprintf(request, sizeof(request), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port,
-		   phb->host, phb->port);
+	request_len = g_snprintf(request, sizeof(request),
+							 "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n",
+							 phb->host, phb->port, phb->host, phb->port);
 
-	if (phb->gpi->proxyuser) {
+	if (gaim_proxy_info_get_username(phb->gpi) != NULL) {
 		char *t1, *t2;
-		t1 = g_strdup_printf("%s:%s", phb->gpi->proxyuser, phb->gpi->proxypass);
+		t1 = g_strdup_printf("%s:%s",
+							 gaim_proxy_info_get_username(phb->gpi),
+							 gaim_proxy_info_get_password(phb->gpi));
+
 		t2 = tobase64(t1, strlen(t1));
 		g_free(t1);
 		g_return_if_fail(request_len < sizeof(request));
-		request_len += g_snprintf(request + request_len, sizeof(request) - request_len, "Proxy-Authorization: Basic %s\r\n", t2);
+		request_len += g_snprintf(request + request_len,
+								  sizeof(request) - request_len,
+								  "Proxy-Authorization: Basic %s\r\n", t2);
 		g_free(t2);
 	}
 
@@ -798,8 +976,13 @@
 
 	if (write(source, request, request_len) < 0) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
@@ -808,14 +991,16 @@
 	phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_canread, phb);
 }
 
-static int proxy_connect_http(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
+static int
+proxy_connect_http(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
 {
 	int fd = -1;
 
 	gaim_debug(GAIM_DEBUG_INFO, "http proxy",
 			   "Connecting to %s:%d via %s:%d using HTTP\n",
-			   phb->host, phb->port, phb->gpi->proxyhost,
-			   phb->gpi->proxyport);
+			   phb->host, phb->port,
+			   gaim_proxy_info_get_host(phb->gpi),
+			   gaim_proxy_info_get_port(phb->gpi));
 
 	if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) {
 		return -1;
@@ -827,12 +1012,14 @@
 		if ((errno == EINPROGRESS) || (errno == EINTR)) {
 			gaim_debug(GAIM_DEBUG_WARNING, "http proxy",
 					   "Connect would have blocked.\n");
-			phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, http_canwrite, phb);
+			phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE,
+									   http_canwrite, phb);
 		} else {
 			close(fd);
 			return -1;
 		}
-	} else {
+	}
+	else {
 		unsigned int len;
 		int error = ETIMEDOUT;
 
@@ -851,7 +1038,8 @@
 	return fd;
 }
 
-static void s4_canread(gpointer data, gint source, GaimInputCondition cond)
+static void
+s4_canread(gpointer data, gint source, GaimInputCondition cond)
 {
 	unsigned char packet[12];
 	struct PHB *phb = data;
@@ -861,21 +1049,31 @@
 	memset(packet, 0, sizeof(packet));
 
 	if (read(source, packet, 9) >= 4 && packet[1] == 90) {
-		if(!phb->account || phb->account->gc)
-			phb->func(phb->data, source, GAIM_INPUT_READ);
+		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);
 		return;
 	}
 
 	close(source);
-	if(!phb->account || phb->account->gc)
+
+	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);
 }
 
-static void s4_canwrite(gpointer data, gint source, GaimInputCondition cond)
+static void
+s4_canwrite(gpointer data, gint source, GaimInputCondition cond)
 {
 	unsigned char packet[12];
 	struct hostent *hp;
@@ -887,11 +1085,18 @@
 
 	if (phb->inpa > 0)
 		gaim_input_remove(phb->inpa);
+
 	len = sizeof(error);
+
 	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
@@ -901,8 +1106,13 @@
 	/* XXX does socks4 not support host name lookups by the proxy? */
 	if (!(hp = gethostbyname(phb->host))) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
@@ -920,8 +1130,13 @@
 
 	if (write(source, packet, 9) != 9) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
@@ -930,26 +1145,29 @@
 	phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s4_canread, phb);
 }
 
-static int proxy_connect_socks4(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
+static int
+proxy_connect_socks4(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
 {
 	int fd = -1;
 
 	gaim_debug(GAIM_DEBUG_INFO, "socks4 proxy",
 			   "Connecting to %s:%d via %s:%d using SOCKS4\n",
-			   phb->host, phb->port, phb->gpi->proxyhost,
-			   phb->gpi->proxyport);
+			   phb->host, phb->port,
+			   gaim_proxy_info_get_host(phb->gpi),
+			   gaim_proxy_info_get_port(phb->gpi));
 
-	if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) {
+	if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0)
 		return -1;
-	}
 
 	fcntl(fd, F_SETFL, O_NONBLOCK);
+
 	if (connect(fd, addr, addrlen) < 0) {
 		if ((errno == EINPROGRESS) || (errno == EINTR)) {
 			gaim_debug(GAIM_DEBUG_WARNING, "socks4 proxy",
 					   "Connect would have blocked.\n");
 			phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, s4_canwrite, phb);
-		} else {
+		}
+		else {
 			close(fd);
 			return -1;
 		}
@@ -961,10 +1179,12 @@
 				   "Connect didn't block.\n");
 
 		len = sizeof(error);
+
 		if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
 			close(fd);
 			return -1;
 		}
+
 		fcntl(fd, F_SETFL, 0);
 		s4_canwrite(phb, fd, GAIM_INPUT_WRITE);
 	}
@@ -972,7 +1192,8 @@
 	return fd;
 }
 
-static void s5_canread_again(gpointer data, gint source, GaimInputCondition cond)
+static void
+s5_canread_again(gpointer data, gint source, GaimInputCondition cond)
 {
 	unsigned char buf[512];
 	struct PHB *phb = data;
@@ -983,8 +1204,13 @@
 	if (read(source, buf, 10) < 10) {
 		gaim_debug(GAIM_DEBUG_WARNING, "socks5 proxy", "or not...\n");
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
@@ -992,21 +1218,30 @@
 	if ((buf[0] != 0x05) || (buf[1] != 0x00)) {
 		gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Bad data.\n");
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
 	}
 
-	if(!phb->account || phb->account->gc)
+	if (phb->account == NULL ||
+		gaim_account_get_connection(phb->account) != NULL) {
+
 		phb->func(phb->data, source, GAIM_INPUT_READ);
+	}
+
 	g_free(phb->host);
 	g_free(phb);
-	return;
 }
 
-static void s5_sendconnect(gpointer data, gint source)
+static void
+s5_sendconnect(gpointer data, gint source)
 {
 	unsigned char buf[512];
 	struct PHB *phb = data;
@@ -1023,8 +1258,13 @@
 
 	if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
@@ -1033,7 +1273,8 @@
 	phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb);
 }
 
-static void s5_readauth(gpointer data, gint source, GaimInputCondition cond)
+static void
+s5_readauth(gpointer data, gint source, GaimInputCondition cond)
 {
 	unsigned char buf[512];
 	struct PHB *phb = data;
@@ -1043,8 +1284,13 @@
 
 	if (read(source, buf, 2) < 2) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
@@ -1052,8 +1298,13 @@
 
 	if ((buf[0] != 0x01) || (buf[1] != 0x00)) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
@@ -1062,7 +1313,8 @@
 	s5_sendconnect(phb, source);
 }
 
-static void s5_canread(gpointer data, gint source, GaimInputCondition cond)
+static void
+s5_canread(gpointer data, gint source, GaimInputCondition cond)
 {
 	unsigned char buf[512];
 	struct PHB *phb = data;
@@ -1072,8 +1324,13 @@
 
 	if (read(source, buf, 2) < 2) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
@@ -1081,37 +1338,53 @@
 
 	if ((buf[0] != 0x05) || (buf[1] == 0xff)) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
 	}
 
 	if (buf[1] == 0x02) {
-		unsigned int i = strlen(phb->gpi->proxyuser), j = strlen(phb->gpi->proxypass);
+		unsigned int i, j;
+		
+		i = strlen(gaim_proxy_info_get_username(phb->gpi));
+		j = strlen(gaim_proxy_info_get_password(phb->gpi));
+
 		buf[0] = 0x01;	/* version 1 */
 		buf[1] = i;
-		memcpy(buf + 2, phb->gpi->proxyuser, i);
+		memcpy(buf + 2, gaim_proxy_info_get_username(phb->gpi), i);
 		buf[2 + i] = j;
-		memcpy(buf + 2 + i + 1, phb->gpi->proxypass, j);
+		memcpy(buf + 2 + i + 1, gaim_proxy_info_get_password(phb->gpi), j);
 
 		if (write(source, buf, 3 + i + j) < 3 + i + j) {
 			close(source);
-			if(!phb->account || phb->account->gc)
+
+			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);
 			return;
 		}
 
 		phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_readauth, phb);
-	} else {
+	}
+	else {
 		s5_sendconnect(phb, source);
 	}
 }
 
-static void s5_canwrite(gpointer data, gint source, GaimInputCondition cond)
+static void
+s5_canwrite(gpointer data, gint source, GaimInputCondition cond)
 {
 	unsigned char buf[512];
 	int i;
@@ -1123,11 +1396,16 @@
 
 	if (phb->inpa > 0)
 		gaim_input_remove(phb->inpa);
+
 	len = sizeof(error);
 	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
 		close(source);
-		if(!phb->account || phb->account->gc)
+		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);
 		return;
@@ -1136,12 +1414,14 @@
 
 	i = 0;
 	buf[0] = 0x05;		/* SOCKS version 5 */
-	if (phb->gpi->proxyuser[0]) {
+
+	if (gaim_proxy_info_get_username(phb->gpi) != NULL) {
 		buf[1] = 0x02;	/* two methods */
 		buf[2] = 0x00;	/* no authentication */
 		buf[3] = 0x02;	/* username/password authentication */
 		i = 4;
-	} else {
+	}
+	else {
 		buf[1] = 0x01;
 		buf[2] = 0x00;
 		i = 3;
@@ -1150,8 +1430,13 @@
 	if (write(source, buf, i) < i) {
 		gaim_debug(GAIM_DEBUG_ERROR, "socks5 proxy", "Unable to write\n");
 		close(source);
-		if(!phb->account || phb->account->gc)
+
+		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);
 		return;
@@ -1160,40 +1445,48 @@
 	phb->inpa = gaim_input_add(source, GAIM_INPUT_READ, s5_canread, phb);
 }
 
-static int proxy_connect_socks5(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
+static int
+proxy_connect_socks5(struct PHB *phb, struct sockaddr *addr, socklen_t addrlen)
 {
 	int fd = -1;
 
 	gaim_debug(GAIM_DEBUG_INFO, "socks5 proxy",
 			   "Connecting to %s:%d via %s:%d using SOCKS5\n",
-			   phb->host, phb->port, phb->gpi->proxyhost,
-			   phb->gpi->proxyport);
+			   phb->host, phb->port,
+			   gaim_proxy_info_get_host(phb->gpi),
+			   gaim_proxy_info_get_port(phb->gpi));
 
-	if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) {
+	if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0)
 		return -1;
-	}
 
 	fcntl(fd, F_SETFL, O_NONBLOCK);
+
 	if (connect(fd, addr, addrlen) < 0) {
 		if ((errno == EINPROGRESS) || (errno == EINTR)) {
 			gaim_debug(GAIM_DEBUG_WARNING, "socks5 proxy",
 					   "Connect would have blocked.\n");
+
 			phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, s5_canwrite, phb);
-		} else {
+		}
+		else {
 			close(fd);
 			return -1;
 		}
-	} else {
+	}
+	else {
 		unsigned int len;
 		int error = ETIMEDOUT;
 
 		gaim_debug(GAIM_DEBUG_MISC, "socks5 proxy",
 				   "Connect didn't block.\n");
+
 		len = sizeof(error);
+
 		if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
 			close(fd);
 			return -1;
 		}
+
 		fcntl(fd, F_SETFL, 0);
 		s5_canwrite(phb, fd, GAIM_INPUT_WRITE);
 	}
@@ -1201,86 +1494,154 @@
 	return fd;
 }
 
-static void connection_host_resolved(GSList *hosts, gpointer data, const char *error_message)
+static void
+connection_host_resolved(GSList *hosts, gpointer data,
+						 const char *error_message)
 {
 	struct PHB *phb = (struct PHB*)data;
 	size_t addrlen;
 	struct sockaddr *addr;
 	int ret = -1;
 
-	while(hosts) {
+	while (hosts) {
 		addrlen = GPOINTER_TO_INT(hosts->data);
 		hosts = hosts->next;
 		addr = hosts->data;
 		hosts = hosts->next;
 
-		switch(phb->gpi->proxytype)
+		switch (gaim_proxy_info_get_type(phb->gpi))
 		{
-			case PROXY_NONE:
+			case GAIM_PROXY_NONE:
 				ret = proxy_connect_none(phb, addr, addrlen);
 				break;
-			case PROXY_HTTP:
+
+			case GAIM_PROXY_HTTP:
 				ret = proxy_connect_http(phb, addr, addrlen);
 				break;
-			case PROXY_SOCKS4:
+
+			case GAIM_PROXY_SOCKS4:
 				ret = proxy_connect_socks4(phb, addr, addrlen);
 				break;
-			case PROXY_SOCKS5:
+
+			case GAIM_PROXY_SOCKS5:
 				ret = proxy_connect_socks5(phb, addr, addrlen);
 				break;
+
+			default:
+				break;
 		}
+
 		if (ret > 0)
 			break;
 	}
-	if(ret < 0) {
-		if(!phb->account || phb->account->gc)
+
+	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);
 	}
 }
 
 int
-proxy_connect(GaimAccount *account, const char *host, int port, GaimInputFunction func, gpointer data)
+gaim_proxy_connect(GaimAccount *account, const char *host, int port,
+				   GaimInputFunction func, gpointer data)
 {
 	const char *connecthost = host;
 	int connectport = port;
 	struct PHB *phb = g_new0(struct PHB, 1);
-	if(!account || !account->gpi)
-		phb->gpi = &global_proxy_info;
+
+	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);
+
+	if (account == NULL || gaim_account_get_proxy_info(account) == NULL)
+		phb->gpi = gaim_global_proxy_get_info();
 	else
-		phb->gpi = account->gpi;
+		phb->gpi = gaim_account_get_proxy_info(account);
+
 	phb->func = func;
 	phb->data = data;
 	phb->host = g_strdup(host);
 	phb->port = port;
 	phb->account = account;
 
-	if (!host || !port || (port == -1) || !func) {
-		if(host)
-			g_free(phb->host);
-		g_free(phb);
-		return -1;
+	if ((gaim_proxy_info_get_type(phb->gpi) != GAIM_PROXY_NONE) &&
+		(gaim_proxy_info_get_host(phb->gpi) == NULL ||
+		 gaim_proxy_info_get_port(phb->gpi) == 0 ||
+		 gaim_proxy_info_get_port(phb->gpi) == -1)) {
+
+		gaim_proxy_info_set_type(phb->gpi, GAIM_PROXY_NONE);
 	}
 
-	if ((phb->gpi->proxytype!=PROXY_NONE) && (!phb->gpi->proxyhost || !phb->gpi->proxyhost[0] || !phb->gpi->proxyport || (phb->gpi->proxyport == -1)))
-		phb->gpi->proxytype=PROXY_NONE;
-
-	switch(phb->gpi->proxytype)
+	switch (gaim_proxy_info_get_type(phb->gpi))
 	{
-		case PROXY_NONE:
+		case GAIM_PROXY_NONE:
 			break;
-		case PROXY_HTTP:
-		case PROXY_SOCKS4:
-		case PROXY_SOCKS5:
-			connecthost=phb->gpi->proxyhost;
-			connectport=phb->gpi->proxyport;
+
+		case GAIM_PROXY_HTTP:
+		case GAIM_PROXY_SOCKS4:
+		case GAIM_PROXY_SOCKS5:
+			connecthost = gaim_proxy_info_get_host(phb->gpi);
+			connectport = gaim_proxy_info_get_port(phb->gpi);
 			break;
+
 		default:
 			g_free(phb->host);
 			g_free(phb);
 			return -1;
 	}
-	
-	return gaim_gethostbyname_async(connecthost, connectport, connection_host_resolved, phb);
+
+	return gaim_gethostbyname_async(connecthost, connectport,
+									connection_host_resolved, phb);
+}
+
+
+static void
+proxy_pref_cb(const char *name, GaimPrefType type, gpointer value,
+			  gpointer data)
+{
+	GaimProxyInfo *info = gaim_global_proxy_get_info();
+
+	if (!strcmp(name, "/core/proxy/type"))
+		gaim_proxy_info_set_type(info, GPOINTER_TO_INT(value));
+	else if (!strcmp(name, "/core/proxy/host"))
+		gaim_proxy_info_set_host(info, value);
+	else if (!strcmp(name, "/core/proxy/port"))
+		gaim_proxy_info_set_port(info, GPOINTER_TO_INT(value));
+	else if (!strcmp(name, "/core/proxy/username"))
+		gaim_proxy_info_set_username(info, value);
+	else if (!strcmp(name, "/core/proxy/password"))
+		gaim_proxy_info_set_password(info, value);
 }
+
+void
+gaim_proxy_init(void)
+{
+	/* Initialize a default proxy info struct. */
+	global_proxy_info = gaim_proxy_info_new();
+
+	/* Proxy */
+	gaim_prefs_add_none("/core/proxy");
+	gaim_prefs_add_string("/core/proxy/type", "none");
+	gaim_prefs_add_string("/core/proxy/host", "");
+	gaim_prefs_add_int("/core/proxy/port", 0);
+	gaim_prefs_add_string("/core/proxy/username", "");
+	gaim_prefs_add_string("/core/proxy/password", "");
+
+	/* Setup callbacks for the preferences. */
+	gaim_prefs_connect_callback("/core/proxy/type",
+								proxy_pref_cb, NULL);
+	gaim_prefs_connect_callback("/core/proxy/host",
+								proxy_pref_cb, NULL);
+	gaim_prefs_connect_callback("/core/proxy/port",
+								proxy_pref_cb, NULL);
+	gaim_prefs_connect_callback("/core/proxy/username",
+								proxy_pref_cb, NULL);
+	gaim_prefs_connect_callback("/core/proxy/password",
+								proxy_pref_cb, NULL);
+}

mercurial