2004-01-15 Mikael Hallendal <micke@imendio.com>
authorhallski <hallski>
Thu, 15 Jan 2004 05:50:26 +0000
changeset 66 577d5059b718
parent 65 e6871fda6fc9
child 67 26c802dba268
2004-01-15 Mikael Hallendal <micke@imendio.com> * loudmouth/Makefile.am: - Added lm-proxy.[ch] * loudmouth/lm-connection.c: * loudmouth/lm-connection.h: - Commited patch from Sjoerd Simons to make async connect work better. - Cleaned out the proxy support to it's own file. - Made sure all public functions user g_return_(val)_if_fail. * loudmouth/lm-internals.h: - cleaned up a bit and added proxy function and base64 encoding * loudmouth/lm-message-handler.c: - include config.h * loudmouth/lm-proxy.c: * loudmouth/lm-proxy.h: - Added, broken out of LmConnection - Commited patch from Josh Beam * loudmouth/lm-utils.c: (_lm_utils_base64_encode): Added.
ChangeLog
loudmouth/Makefile.am
loudmouth/lm-connection.c
loudmouth/lm-connection.h
loudmouth/lm-internals.h
loudmouth/lm-message-handler.c
loudmouth/lm-proxy.c
loudmouth/lm-proxy.h
loudmouth/lm-utils.c
--- a/ChangeLog	Thu Jan 08 14:43:02 2004 +0000
+++ b/ChangeLog	Thu Jan 15 05:50:26 2004 +0000
@@ -1,3 +1,23 @@
+2004-01-15  Mikael Hallendal  <micke@imendio.com>
+
+	* loudmouth/Makefile.am:
+	- Added lm-proxy.[ch]
+	* loudmouth/lm-connection.c:
+	* loudmouth/lm-connection.h:
+	- Commited patch from Sjoerd Simons to make async connect work better.
+	- Cleaned out the proxy support to it's own file.
+	- Made sure all public functions user g_return_(val)_if_fail.
+	* loudmouth/lm-internals.h:
+	- cleaned up a bit and added proxy function and base64 encoding
+	* loudmouth/lm-message-handler.c:
+	- include config.h
+	* loudmouth/lm-proxy.c:
+	* loudmouth/lm-proxy.h:
+	- Added, broken out of LmConnection
+	- Commited patch from Josh Beam
+	* loudmouth/lm-utils.c:
+	(_lm_utils_base64_encode): Added.
+
 2004-01-08  Richard Hult  <richard@imendio.com>
 
 	* loudmouth/lm-connection.c (connection_timeout_check_open):
--- a/loudmouth/Makefile.am	Thu Jan 08 14:43:02 2004 +0000
+++ b/loudmouth/Makefile.am	Thu Jan 15 05:50:26 2004 +0000
@@ -24,6 +24,7 @@
 	lm-sha.c			\
 	lm-sha.h			\
 	lm-utils.c			\
+	lm-proxy.c                      \
 	lm-queue.c                      \
 	lm-queue.h                      \
 	$(NULL)
@@ -35,6 +36,7 @@
 	lm-message-handler.h		\
 	lm-message-node.h		\
 	lm-utils.h			\
+	lm-proxy.h                      \
 	loudmouth.h			\
 	$(NULL)
 
--- a/loudmouth/lm-connection.c	Thu Jan 08 14:43:02 2004 +0000
+++ b/loudmouth/lm-connection.c	Thu Jan 15 05:50:26 2004 +0000
@@ -55,8 +55,17 @@
 } HandlerData;
 
 typedef struct {
-	GSource source;
+	LmConnection    *connection;
 	
+	/* struct to save resolved address */
+	struct addrinfo *resolved_addrs;
+	struct addrinfo *current_addr;
+	int              fd;
+	GIOChannel           *io_channel;
+} LmConnectData;
+
+typedef struct {
+	GSource       source;
 	LmConnection *connection;
 } LmIncomingSource;
 
@@ -66,14 +75,12 @@
 	guint           port;
 	char	        fingerprint[20];
 
-	LmProxyType     proxy_type;
-	gchar          *proxy_server;
-	guint           proxy_port;
-
 #ifdef HAVE_GNUTLS
 	gnutls_session  gnutls_session;
 	gnutls_certificate_client_credentials gnutls_xcred;
 #endif
+
+	LmProxy    *proxy;
 	
 	LmParser   *parser;
 	gchar      *stream_id;
@@ -170,14 +177,15 @@
 static gboolean connection_incoming_dispatch (GSource         *source,
 					      GSourceFunc      callback,
 					      gpointer           user_data);
-static GSource * connection_create_source    (LmConnection *connection);
-static void      connection_signal_disconnect (LmConnection *connection,
-					       LmDisconnectReason reason);
+static GSource * connection_create_source       (LmConnection *connection);
+static void      connection_signal_disconnect   (LmConnection *connection,
+						 LmDisconnectReason reason);
 
-static gboolean connection_http_proxy_negotiate (gint fd, LmConnection *connection);
-static void     connection_initilize_gnutls    (LmConnection *connection);
-static gboolean connection_begin_ssl           (LmConnection *connection,
-						GError       **error);
+static void     connection_initilize_gnutls     (LmConnection *connection);
+static gboolean connection_begin_ssl            (LmConnection *connection,
+						 GError       **error);
+static void     connection_do_connect           (LmConnectData *connect_data);
+
 
 static GSourceFuncs incoming_funcs = {
 	connection_incoming_prepare,
@@ -353,72 +361,54 @@
 }
 #endif
 
-typedef struct {
-	LmConnection *connection;
-	int fd;
-} OpenTimeoutData;
-
 static gboolean
-connection_timeout_check_open (OpenTimeoutData *data)
+connection_succeeded (LmConnectData *connect_data)
 {
-	LmConnection   *connection;
-	fd_set          rset, wset;
-	struct timeval  tval;
-	int             result;
-	LmMessage      *m;
-	
-	connection = data->connection;
-
+	LmConnection *connection = connect_data->connection;
+	LmMessage    *m;
+	GIOFlags      flags;
 
 	/* Need some way to report error/success */
 	if (connection->cancel_open) {
 		return FALSE;
 	}
+	
+	connection->fd = connect_data->fd;
+	connection->io_channel = connect_data->io_channel;
 
-	FD_ZERO (&rset);
-	FD_SET (data->fd, &rset);
-	wset = rset;
+	freeaddrinfo (connect_data->resolved_addrs);
 
-	tval.tv_sec = tval.tv_usec = 0;
+	/* don't need this anymore */
+	g_free(connect_data);
 
-	result = select (data->fd + 1, &rset, &wset, NULL, &tval);
-	if (result == -1) {
-		/* error */
-		connection->fd = -1;
-		return FALSE;
-	}
-	else if (result == 0) {
-		/* timeout */
-		connection->fd = -1;
-		return TRUE;
-	} 
+	flags = g_io_channel_get_flags (connection->io_channel);
+
+	/* unset the nonblock flag */
+	flags &= ~G_IO_FLAG_NONBLOCK;
 	
-	if (FD_ISSET (data->fd, &rset) && FD_ISSET (data->fd, &wset)) {
-		close (data->fd);
-		connection->fd = -1;
-		return FALSE;
-	}
-
-	connection->fd = data->fd;
-	connection->io_channel = g_io_channel_unix_new (data->fd);
+	/* unset the nonblocking stuff for some time, because GNUTLS doesn't 
+	 * like that */
+	g_io_channel_set_flags (connection->io_channel, flags, NULL);
 
 	/* FIXME: Handle error */
 	if (!connection_begin_ssl (connection, NULL)) {
 		connection->fd = -1;
+		g_io_channel_unref(connection->io_channel);
 		return FALSE;
 	}
 	
-	connection->io_channel = g_io_channel_unix_new (data->fd);
 	g_io_channel_set_close_on_unref (connection->io_channel, TRUE);
 	g_io_channel_set_encoding (connection->io_channel, NULL, NULL);
 	
 	g_io_channel_set_buffered (connection->io_channel, FALSE);
 	g_io_channel_set_flags (connection->io_channel,
-				G_IO_FLAG_NONBLOCK, NULL);
+				flags & G_IO_FLAG_NONBLOCK, NULL);
+	
 	connection->io_watch_in = g_io_add_watch (connection->io_channel,
 						  G_IO_IN,
 						  (GIOFunc) connection_in_event,
 						  connection);
+	
 	connection->io_watch_err = g_io_add_watch (connection->io_channel, 
 						   G_IO_ERR,
 						   (GIOFunc) connection_error_event,
@@ -436,12 +426,10 @@
 		return FALSE;
 	}
 
-#if 0
-	g_print ("In timeoutfunc\n");
-#endif
 	m = lm_message_new (connection->server, LM_MESSAGE_TYPE_STREAM);
 	lm_message_node_set_attributes (m->node,
-					"xmlns:stream", "http://etherx.jabber.org/streams",
+					"xmlns:stream", 
+					"http://etherx.jabber.org/streams",
 					"xmlns", "jabber:client",
 					NULL);
 	
@@ -455,29 +443,93 @@
 		
 	lm_message_unref (m);
 
-#if 0
-	g_print ("Success!!\n");
-#endif
-	
 	/* Success */
 	return FALSE;
 }
+
+static void 
+connection_failed_with_error (LmConnectData *connect_data, int error) 
+{
+	g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
+	       "Connection failed: %s (error %d)\n",
+	       strerror (error), error);
 	
-static int
-connection_connect_nonblocking (LmConnection    *connection, 
-				struct addrinfo *addr)
+	connect_data->current_addr =  connect_data->current_addr->ai_next;
+	
+	if (connect_data->io_channel != NULL) {
+		g_io_channel_unref (connect_data->io_channel);
+	}
+	
+	if (connect_data->current_addr == NULL) {
+		freeaddrinfo (connect_data->resolved_addrs);
+		g_free (connect_data);
+	} else {
+		/* try to connect to the next host */
+		connection_do_connect (connect_data);
+	}
+}
+
+static void 
+connection_failed (LmConnectData *connect_data)
+{
+	connection_failed_with_error (connect_data,errno);
+}
+	
+static gboolean 
+connection_connect_cb (GIOChannel   *source, 
+		       GIOCondition  condition,
+		       gpointer      data) 
 {
+	LmConnection  *connection;
+	LmConnectData *connect_data;
+	int            error;
+	int            len  = sizeof(error);
+
+	connect_data = (LmConnectData *) data;
+	connection   = connect_data->connection;
+	
+	if (condition == G_IO_ERR) {
+		/* get the real error from the socket */
+		getsockopt (connect_data->fd, SOL_SOCKET, SO_ERROR, 
+			    &error, &len);
+		connection_failed_with_error (connect_data, error);
+	} else if (condition == G_IO_OUT) {
+		if (connect_data->connection->proxy) {
+			if (!_lm_proxy_negotiate (connection->proxy, connect_data->fd, connection->server, connection->port)) {
+				connection_failed (connect_data);
+			}
+		}
+		connection_succeeded (connect_data);
+	} else {
+		g_assert_not_reached ();
+	}
+
+	return FALSE;
+}
+
+static void
+connection_do_connect (LmConnectData *connect_data) 
+{
+	LmConnection    *connection;
+	int              fd;
 	int              res;
-	int              fd;
+	int              port;
 	int              flags;
-	OpenTimeoutData *open_data;
+	char             name[NI_MAXHOST];
+	char             portname[NI_MAXSERV];
+	struct addrinfo *addr;
 	
-	if (connection->proxy_type != LM_PROXY_TYPE_NONE)
-		((struct sockaddr_in *) addr->ai_addr)->sin_port = htons (connection->proxy_port);
-	else
-		((struct sockaddr_in *) addr->ai_addr)->sin_port = htons (connection->port);
+	connection = connect_data->connection;
+	addr = connect_data->current_addr;
+ 
+	if (connection->proxy) {
+		port = htons (lm_proxy_get_port (connection->proxy));
+	} else {
+		port = htons (connection->port);
+	}
+	
+	((struct sockaddr_in *) addr->ai_addr)->sin_port = port;
 
-#if 0
 	getnameinfo (addr->ai_addr,
 		     addr->ai_addrlen,
 		     name,     sizeof (name),
@@ -486,57 +538,42 @@
 
 	g_log (LM_LOG_DOMAIN,LM_LOG_LEVEL_NET,
 	       "Trying %s port %s...\n", name, portname);
-#endif
+	
 	fd = socket (addr->ai_family, 
 		     addr->ai_socktype, 
 		     addr->ai_protocol);
+	
 	if (fd < 0) {
-		return -1;
+		connection_failed (connect_data);
 	}
 
 	flags = fcntl (fd, F_GETFL, 0);
 	fcntl (fd, F_SETFL, flags | O_NONBLOCK);
 	
 	res = connect (fd, addr->ai_addr, addr->ai_addrlen);
-	if (res == 0) {
-		if (connection->proxy_type == LM_PROXY_TYPE_HTTP) {
-			if (connection_http_proxy_negotiate(fd, connection) == TRUE) {
-				return fd;
-			}
-		} else {
-			/* connection successfull */
-			return fd;
-		}
-	} 
-
-	if (errno != EINPROGRESS) {
+	connect_data->fd = fd;
+	
+	if (res < 0 && errno != EINPROGRESS) {
 		close (fd);
-		return -1;
+		connection_failed (connect_data);
+		return;
 	}
-
-	open_data = g_new (OpenTimeoutData, 1);
-	open_data->fd = fd;
-	open_data->connection = connection;
 	
-	connection->open_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
-						  10, 
-						  (GSourceFunc) connection_timeout_check_open,
-						  open_data,
-						  g_free);
-
-	return fd;
+	connect_data->io_channel = g_io_channel_unix_new (fd);
+	g_io_add_watch (connect_data->io_channel, G_IO_OUT|G_IO_ERR,
+			(GIOFunc) connection_connect_cb, connect_data);
+	return;
 }
 
 /* Returns directly */
+/* Setups all data needed to start the connection attempts */
 static gboolean
-connection_do_open (LmConnection *connection, GError **error)
+connection_do_open (LmConnection *connection, GError **error) 
 {
 	struct addrinfo  req;
 	struct addrinfo *ans;
-	struct addrinfo *tmpaddr;
-	/* char             name[NI_MAXHOST];
-	char             portname[NI_MAXSERV]; */
-	
+	LmConnectData   *data;
+
 	if (lm_connection_is_open (connection)) {
 		g_set_error (error,
 			     LM_ERROR,
@@ -552,10 +589,11 @@
 			     "You need to set the server hostname in the call to lm_connection_new()");
 		return FALSE;
 	}
-	
+
+	/* source thingie for messages and stuff */
 	connection->incoming_source = connection_create_source (connection);
-	g_source_attach (connection->incoming_source, NULL);
-
+	g_source_attach (connection->incoming_source,NULL);
+	
 	lm_verbose ("Connecting to: %s:%d\n", 
 		    connection->server, connection->port);
 
@@ -568,12 +606,15 @@
 	connection->cancel_open = FALSE;
 	connection->state = LM_CONNECTION_STATE_CONNECTING;
 	
-	if (connection->proxy_type != LM_PROXY_TYPE_NONE) { /* connect through proxy */
+	if (connection->proxy) {
+		const gchar *proxy_server;
+
+		proxy_server = lm_proxy_get_server (connection->proxy);
+		/* connect through proxy */
 		g_log (LM_LOG_DOMAIN,LM_LOG_LEVEL_NET,
-		       "Going to connect to %s\n",connection->proxy_server);
+		       "Going to connect to %s\n", proxy_server);
 
-
-		if (getaddrinfo (connection->proxy_server, NULL, &req, &ans) != 0) {
+		if (getaddrinfo (proxy_server, NULL, &req, &ans) != 0) {
 			g_set_error (error,
 				     LM_ERROR,                 
 				     LM_ERROR_CONNECTION_OPEN,   
@@ -593,26 +634,19 @@
 		}
 	}
 
+
 	connection_initilize_gnutls (connection);
 
-	/* Do the nonblocking connection */
-	/* Get results in a timeout callback */
-	/* Return TRUE if nothing has gone wrong up until now */
-
-	for (tmpaddr = ans ; tmpaddr != NULL ; tmpaddr = tmpaddr->ai_next) {
-		if (connection->cancel_open) {
-			break;
-		}
+	/* Prepare and do the nonblocking connection */
+	data = g_new (LmConnectData, 1);
 
-		/* FIXME: Try to connect to some addr until success or end of 
-		 * addresses */
-		connection_connect_nonblocking (connection, tmpaddr);
-		/*, name, portname); */
-		break;
-	}
-	
-	freeaddrinfo (ans);
+	data->connection     = connection;
+	data->resolved_addrs = ans;
+	data->current_addr   = ans;
+	data->io_channel     = NULL;
+	data->fd             = -1;
 
+	connection_do_connect (data);
 	return TRUE;
 }
 					
@@ -1079,52 +1113,6 @@
 	}
 }
 
-static gboolean
-connection_http_proxy_negotiate (gint fd, LmConnection *connection)
-{
-	gint   i, len;
-	gchar  buf[1024];
-	gchar *str;
-
-	str = g_strdup_printf ("CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\n\r\n",
-			       connection->server, connection->port, 
-			       connection->server, connection->port);
-
-	send (fd, str, strlen (str), 0);
-
-	g_free (str);
-
-	len = read (fd, buf, 12);
-	if (len <= 0) {
-		return FALSE;
-	}
-
-	buf[len] = '\0';
-	if (strcmp (buf, "HTTP/1.1 200") != 0 && strcmp (buf, "HTTP/1.0 200") != 0) {
-		return FALSE;
-	}
-
-	/* discard any headers that we don't need */
-	for (i = 0; i < 4; i++) {
-		len = read (fd, buf + i, 1);
-		if (len <= 0) {
-			return FALSE;
-		}
-	}
-	while (strncmp (buf, "\r\n\r\n", 4) != 0) {
-		for (i = 0; i < 3; i++) {
-			buf[i] = buf[i + 1];
-		}
-		
-		len = read (fd, buf + 3, 1);
-		if (len <= 0) {
-			return FALSE;
-		}
-	}
-
-	return TRUE;
-}
-
 static void
 connection_initilize_gnutls (LmConnection *connection)
 {
@@ -1218,9 +1206,7 @@
 	connection->ssl_func          = NULL;
 	connection->expected_fingerprint = NULL;
 	connection->fingerprint[0]    = '\0';
-	connection->proxy_type        = LM_PROXY_TYPE_NONE;
-	connection->proxy_server      = NULL;
-	connection->proxy_port        = 8080;
+	connection->proxy             = NULL;
 	connection->disconnect_cb     = NULL;
 	connection->incoming_messages = lm_queue_new ();
 	connection->cancel_open       = FALSE;
@@ -1231,7 +1217,6 @@
 							 g_free, 
 							 (GDestroyNotify) lm_message_handler_unref);
 	connection->ref_count         = 1;
-	// g_source_attach (connection->incoming_source, NULL);
 	
 	for (i = 0; i < LM_MESSAGE_TYPE_UNKNOWN; ++i) {
 		connection->handlers[i] = NULL;
@@ -1525,6 +1510,8 @@
 gboolean
 lm_connection_is_open (LmConnection *connection)
 {
+	g_return_val_if_fail (connection != NULL, FALSE);
+	
 	return connection->state >= LM_CONNECTION_STATE_CONNECTED;
 }
 
@@ -1539,6 +1526,8 @@
 gboolean 
 lm_connection_is_authenticated (LmConnection *connection)
 {
+	g_return_val_if_fail (connection != NULL, FALSE);
+
 	return connection->state >= LM_CONNECTION_STATE_AUTHENTICATED;
 }
 
@@ -1553,6 +1542,8 @@
 const gchar *
 lm_connection_get_server (LmConnection *connection)
 {
+	g_return_val_if_fail (connection != NULL, NULL);
+
 	return connection->server;
 }
 
@@ -1566,6 +1557,9 @@
 void
 lm_connection_set_server (LmConnection *connection, const gchar *server)
 {
+	g_return_if_fail (connection != NULL);
+	g_return_if_fail (server != NULL);
+	
 	if (lm_connection_is_open (connection)) {
 		g_warning ("Can't change server address while connected");
 		return;
@@ -1589,6 +1583,8 @@
 guint
 lm_connection_get_port (LmConnection *connection)
 {
+	g_return_val_if_fail (connection != NULL, 0);
+
 	return connection->port;
 }
 
@@ -1602,6 +1598,8 @@
 void
 lm_connection_set_port (LmConnection *connection, guint port)
 {
+	g_return_if_fail (connection != NULL);
+	
 	if (lm_connection_is_open (connection)) {
 		g_warning ("Can't change server port while connected");
 		return;
@@ -1611,106 +1609,6 @@
 }
 
 /**
- * lm_connection_get_proxy_type:
- * @connection: an #LmConnection
- * 
- * Fetches the proxy type that @connection is using.
- * 
- * Return value: 
- **/
-LmProxyType
-lm_connection_get_proxy_type (LmConnection *connection)
-{
-	return connection->proxy_type;
-}
-
-/**
- * lm_connection_set_proxy_type:
- * @connection: an #LmConnection
- * @type: an LmProxyType
- *
- * Sets the proxy server type for @connection to @type. Notice that @connection can't be open while doing this.
- **/
-void
-lm_connection_set_proxy_type (LmConnection *connection, LmProxyType type)
-{
-	if (lm_connection_is_open (connection)) {
-		g_warning ("Can't change proxy type while connected");
-		return;
-	}
-
-	connection->proxy_type = type;
-}
-
-/**
- * lm_connection_get_proxy_server:
- * @connection: an #LmConnection
- * 
- * Fetches the proxy server address that @connection is using.
- * 
- * Return value: the proxy server address
- **/
-const gchar *
-lm_connection_get_proxy_server (LmConnection *connection)
-{
-	return connection->proxy_server;
-}
-
-/**
- * lm_connection_set_proxy_server:
- * @connection: an #LmConnection
- * @server: Address of the proxy server
- * 
- * Sets the proxy server address for @connection to @server. Notice that @connection can't be open while doing this.
- **/
-void
-lm_connection_set_proxy_server (LmConnection *connection, const gchar *server)
-{
-	if (lm_connection_is_open (connection)) {
-		g_warning ("Can't change proxy server address while connected");
-		return;
-	}
-	
-	if (connection->proxy_server) {
-		g_free (connection->proxy_server);
-	}
-	
-	connection->proxy_server = g_strdup (server);
-}
-
-/**
- * lm_connection_get_proxy_port:
- * @connection: an #LmConnection
- * 
- * Fetches the proxy port that @connection is using.
- * 
- * Return value: 
- **/
-guint
-lm_connection_get_proxy_port (LmConnection *connection)
-{
-	return connection->proxy_port;
-}
-
-/**
- * lm_connection_set_proxy_port:
- * @connection: an #LmConnection
- * @port: proxy server port
- * 
- * Sets the proxy server port that @connection will be using.
- **/
-void
-lm_connection_set_proxy_port (LmConnection *connection, guint port)
-{
-	if (lm_connection_is_open (connection)) {
-		g_warning ("Can't change proxy server port while connected");
-		return;
-	}
-	
-	connection->proxy_port = port;
-}
-
-/**
  * lm_connection_supports_ssl:
  *
  * Checks whether Loudmouth supports SSL or not.
@@ -1736,11 +1634,15 @@
 			   LmSSLFunction  ssl_function,
 			   gpointer       user_data)
 {
+	g_return_if_fail (connection != NULL);
+
 	g_free (connection->expected_fingerprint);
+	
 	if (expected_fingerprint) {
 		connection->expected_fingerprint = 
 			g_strdup (expected_fingerprint);
 	}
+
 	connection->ssl_func = ssl_function;
 	connection->ssl_func_data = user_data;
 }
@@ -1756,6 +1658,8 @@
 gboolean
 lm_connection_get_use_ssl (LmConnection *connection)
 {
+	g_return_val_if_fail (connection != NULL, FALSE);
+
 	return connection->ssl_func != NULL;
 }
 
@@ -1770,10 +1674,55 @@
 const unsigned char *
 lm_connection_get_fingerprint (LmConnection *connection)
 {
+	g_return_val_if_fail (connection != NULL, NULL);
+	
 	return (unsigned char*) connection->fingerprint;
 }
 
 /**
+ * lm_connection_get_proxy: 
+ * @connection: an #LmConnection
+ *
+ * Returns the proxy if the connection is using one.
+ * 
+ * Return value: The proxy or %NULL if no proxy is used.
+ **/
+LmProxy *
+lm_connection_get_proxy (LmConnection *connection)
+{
+	g_return_val_if_fail (connection != NULL, NULL);
+
+	return connection->proxy;
+} 
+
+/**
+ * lm_connection_set_proxy: 
+ * @connection: an #LmConnection
+ * @proxy: an #LmProxy
+ *
+ * Sets the proxy to use for this connection.
+ * 
+ * Return value: The proxy or %NULL if no proxy is used. Notice that @connection can't be open while doing this.
+ **/
+void
+lm_connection_set_proxy (LmConnection *connection, LmProxy *proxy)
+{
+	g_return_if_fail (connection != NULL);
+	g_return_if_fail (proxy != NULL);
+
+	if (lm_connection_is_open (connection)) {
+		g_warning ("Can't change server proxy while connected");
+		return;
+	}
+	
+	if (connection->proxy) {
+		lm_proxy_unref (connection->proxy);
+	}
+
+	connection->proxy = lm_proxy_ref (proxy);
+}
+
+/**
  * lm_connection_send: 
  * @connection: #LmConnection to send message over.
  * @message: #LmMessage to send.
@@ -1861,6 +1810,9 @@
 	gchar     *id;
 	LmMessage *reply = NULL;
 
+	g_return_val_if_fail (connection != NULL, NULL);
+	g_return_val_if_fail (message != NULL, NULL);
+
 	if (lm_message_node_get_attribute (message->node, "id")) {
 		id = g_strdup (lm_message_node_get_attribute (message->node, 
 							      "id"));
@@ -1991,6 +1943,8 @@
 				       gpointer              user_data,
 				       GDestroyNotify        notify)
 {
+	g_return_if_fail (connection != NULL);
+
 	if (connection->disconnect_cb) {
 		_lm_utils_free_callback (connection->disconnect_cb);
 	}
@@ -2075,45 +2029,3 @@
 	}
 }
 
-#if 0
-void
-lm_connection_register (LmConnection           *connection,
-		    const gchar        *username,
-		    const gchar        *password,
-		    const gchar        *resource,
-		    LmRegisterCallback  callback,
-		    gpointer            user_data)
-{
-	LmElement    *element;
-	LmNode       *q_node;
-	gchar        *id;
-	static gint   register_id = 0;
-	
-	g_return_if_fail (connection != NULL);
-	g_return_if_fail (lm_connection_is_open (connection));
-	
-	/* Use lm:iq:register name space */
-
-	element = lm_iq_new (LM_IQ_TYPE_SET);
-	
-	q_node = lm_node_new ("query");
-	lm_node_set_attribute (q_node, "xmlns", JABBER_IQ_REGISTER);
-	lm_node_add_child (q_node, "username", username);
-	lm_node_add_child (q_node, "password", password);
-	lm_node_add_child (q_node, "resource", resource);
-
-	lm_element_add_child_node (element, q_node);
-	
-	id = g_strdup_printf ("register_%d", ++register_id);
-	lm_element_set_id (element, id);
-	
-	lm_connection_send (connection, element, NULL);
-	connection_add_callback (connection, id, callback, user_data);
-	lm_element_unref (element);
-
-	g_free (id);
-
-	
-}
-
-#endif
--- a/loudmouth/lm-connection.h	Thu Jan 08 14:43:02 2004 +0000
+++ b/loudmouth/lm-connection.h	Thu Jan 15 05:50:26 2004 +0000
@@ -26,6 +26,7 @@
 #error "Only <loudmouth/loudmouth.h> can be included directly, this file may di\sappear or change contents."
 #endif
 
+#include <loudmouth/lm-proxy.h>
 #include <loudmouth/lm-message.h>
 
 #define LM_CONNECTION(o) (LmConnection *) o;
@@ -57,11 +58,6 @@
 } LmDisconnectReason;
 
 typedef enum {
-	LM_PROXY_TYPE_NONE = 0,
-	LM_PROXY_TYPE_HTTP
-} LmProxyType;
-
-typedef enum {
 	LM_CERT_INVALID,
 	LM_CERT_ISSUER_NOT_FOUND,
 	LM_CERT_REVOKED,
@@ -149,21 +145,13 @@
 					       gpointer            user_data);
 gboolean      lm_connection_get_use_ssl       (LmConnection       *connection);
 
-LmProxyType   lm_connection_get_proxy_type    (LmConnection       *connection);
-void          lm_connection_set_proxy_type    (LmConnection       *connection,
-                                               LmProxyType         type);
-
-const gchar * lm_connection_get_proxy_server  (LmConnection       *connection);
-void          lm_connection_set_proxy_server  (LmConnection       *connection,
-                                               const gchar        *server);
-
-guint         lm_connection_get_proxy_port    (LmConnection       *connection);
-void          lm_connection_set_proxy_port    (LmConnection       *connection,
-                                               guint               port);
-
 const unsigned char * 
 lm_connection_get_fingerprint                 (LmConnection       *connection);
 					       
+LmProxy *     lm_connection_get_proxy         (LmConnection       *connection);
+void          lm_connection_set_proxy         (LmConnection       *connection,
+					       LmProxy            *proxy);
+
 gboolean      lm_connection_send              (LmConnection       *connection,
 					       LmMessage          *message,
 					       GError            **error);
--- a/loudmouth/lm-internals.h	Thu Jan 08 14:43:02 2004 +0000
+++ b/loudmouth/lm-internals.h	Thu Jan 15 05:50:26 2004 +0000
@@ -33,22 +33,30 @@
 	GDestroyNotify notify;
 } LmCallback;
 
-LmCallback *_lm_utils_new_callback (gpointer func, 
-				    gpointer user_data,
-				    GDestroyNotify notify);
-void _lm_utils_free_callback (LmCallback *cb);
+LmCallback *     _lm_utils_new_callback             (gpointer          func, 
+						     gpointer          data,
+						     GDestroyNotify    notify);
+void             _lm_utils_free_callback            (LmCallback       *cb);
 
-gchar *            _lm_utils_generate_id             (void);
-LmHandlerResult _lm_message_handler_handle_message   (LmMessageHandler *handler,
-						      LmConnection     *connection,
-						      LmMessage        *messag);
+gchar *          _lm_utils_generate_id              (void);
+gchar *          _lm_utils_base64_encode            (const gchar      *str);
+const gchar *    _lm_message_type_to_string         (LmMessageType     type);
+const gchar *    _lm_message_sub_type_to_string     (LmMessageSubType  type);
+LmMessage *      _lm_message_new_from_node          (LmMessageNode    *node);
+void             _lm_message_node_add_child_node    (LmMessageNode    *node,
+						     LmMessageNode    *child);
+LmMessageNode *  _lm_message_node_new               (const gchar      *name);
+void             _lm_debug_init                     (void);
 
-const gchar *      _lm_message_type_to_string         (LmMessageType     type);
-const gchar *      _lm_message_sub_type_to_string     (LmMessageSubType  type);
-LmMessage *        _lm_message_new_from_node          (LmMessageNode    *node);
-void               _lm_message_node_add_child_node    (LmMessageNode    *node,
-						       LmMessageNode    *child);
-LmMessageNode *    _lm_message_node_new               (const gchar  *name);
-void               _lm_debug_init                     (void);
+gboolean         _lm_proxy_negotiate                (LmProxy          *proxy,
+						     gint              fd,
+						     const gchar      *server,
+						     guint             port);
+
+LmHandlerResult    
+_lm_message_handler_handle_message                (LmMessageHandler *handler,
+						   LmConnection     *connection,
+						   LmMessage        *messag);
+
 
 #endif /* __LM_INTERNALS_H__ */
--- a/loudmouth/lm-message-handler.c	Thu Jan 08 14:43:02 2004 +0000
+++ b/loudmouth/lm-message-handler.c	Thu Jan 15 05:50:26 2004 +0000
@@ -18,6 +18,8 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include <config.h>
+
 #include "lm-internals.h"
 #include "lm-message-handler.h"
 
@@ -115,7 +117,7 @@
  * lm_message_handler_ref:
  * @handler: an #LmMessageHandler
  * 
- * Adds a reference to @node.
+ * Adds a reference to @handler.
  * 
  * Return value: the message handler
  **/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loudmouth/lm-proxy.c	Thu Jan 15 05:50:26 2004 +0000
@@ -0,0 +1,375 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2004 Imendio HB
+ * Copyright (C) Josh Beam <josh@3ddrome.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <string.h>
+#include <unistd.h>
+#ifndef __WIN32__
+  #include <sys/socket.h>
+#else 
+  #include <winsock2.h>
+#endif
+
+#include "lm-internals.h"
+#include "lm-proxy.h"
+
+struct _LmProxy {
+	LmProxyType  type;
+	gchar       *server;
+	guint        port;
+	gchar       *username;
+	gchar       *password;
+
+        gint         ref_count;
+};
+
+static void          proxy_free              (LmProxy     *proxy);
+static gboolean      proxy_http_negotiate    (LmProxy     *proxy,
+					      gint         fd, 
+					      const gchar *server,
+					      guint        port);
+
+static void
+proxy_free (LmProxy *proxy)
+{
+	g_free (proxy->server);
+	g_free (proxy->username);
+	g_free (proxy->password);
+
+	g_free (proxy);
+}
+
+static gboolean
+proxy_http_negotiate (LmProxy *proxy, gint fd, const gchar *server, guint port)
+{
+	gint   i, len;
+	gchar  buf[1024];
+	gchar *str;
+
+	if (proxy->username && proxy->password) {
+		gchar *tmp1;
+		gchar *tmp2;
+
+		tmp1 = g_strdup_printf ("%s:%s",
+					proxy->username, 
+					proxy->password);
+		tmp2 = _lm_utils_base64_encode (tmp1);
+		g_free (tmp1);
+
+		str = g_strdup_printf ("CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\nProxy-Authorization: Basic %s\r\n\r\n",
+				       server, port,
+				       server, port,
+				       tmp2);
+		g_free (tmp2);
+	} else {
+		str = g_strdup_printf ("CONNECT %s:%u HTTP/1.1\r\nHost: %s:%u\r\n\r\n",
+				       server, port, 
+				       server, port);
+	}
+
+	send (fd, str, strlen (str), 0);
+
+	g_free (str);
+
+	len = read (fd, buf, 12);
+	if (len <= 0) {
+		return FALSE;
+	}
+
+	buf[len] = '\0';
+	if (strcmp (buf, "HTTP/1.1 200") != 0 && 
+	    strcmp (buf, "HTTP/1.0 200") != 0) {
+		return FALSE;
+	}
+
+	/* discard any headers that we don't need */
+	for (i = 0; i < 4; i++) {
+		len = read (fd, buf + i, 1);
+		if (len <= 0) {
+			return FALSE;
+		}
+	}
+	while (strncmp (buf, "\r\n\r\n", 4) != 0) {
+		for (i = 0; i < 3; i++) {
+			buf[i] = buf[i + 1];
+		}
+		
+		len = read (fd, buf + 3, 1);
+		if (len <= 0) {
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+gboolean
+_lm_proxy_negotiate (LmProxy *proxy, gint fd, const gchar *server, guint port)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+
+	switch (proxy->type) {
+	case LM_PROXY_TYPE_NONE:
+		return TRUE;
+	case LM_PROXY_TYPE_HTTP:
+		return proxy_http_negotiate (proxy, fd, server, port);
+	default:
+		g_assert_not_reached ();
+	}
+
+	return FALSE;
+}
+
+/**
+ * lm_proxy_new
+ * @type: the type of the new proxy
+ * 
+ * Creates a new Proxy. Used #lm_connection_set_proxy to make a connection 
+ * user this proxy.
+ * 
+ * Return value: a newly create proxy
+ **/
+LmProxy * 
+lm_proxy_new (LmProxyType type)
+{
+	LmProxy *proxy;
+
+	proxy = g_new0 (LmProxy, 1);
+	
+	proxy->ref_count = 1;
+	proxy->type = type;
+
+	switch (proxy->type) {
+	case LM_PROXY_TYPE_HTTP:
+		proxy->port = 8000;
+		break;
+	default:
+		proxy->port = 0;
+	}
+
+	return proxy;
+}
+
+/**
+ * lm_proxy_get_type
+ * @proxy: an #LmProxy
+ * 
+ * Fetches the proxy type
+ * 
+ * Return value: the type 
+ **/
+LmProxyType
+lm_proxy_get_type (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, LM_PROXY_TYPE_NONE);
+
+	return proxy->type;
+}
+
+/**
+ * lm_proxy_set_type
+ * @proxy: an #LmProxy
+ * @type: an LmProxyType
+ *
+ * Sets the proxy type for @proxy to @type. 
+ **/
+void
+lm_proxy_set_type (LmProxy *proxy, LmProxyType type)
+{
+	g_return_if_fail (proxy != NULL);
+
+	proxy->type = type;
+}
+
+/**
+ * lm_proxy_get_server:
+ * @proxy: an #LmProxy
+ * 
+ * Fetches the server address that @proxy is using.
+ * 
+ * Return value: the proxy server address
+ **/
+const gchar *
+lm_proxy_get_server (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, NULL);
+	
+	return proxy->server;
+}
+
+/**
+ * lm_proxy_set_server:
+ * @proxy: an #LmProxy
+ * @server: Address of the proxy server
+ * 
+ * Sets the server address for @proxy to @server. 
+ **/
+void
+lm_proxy_set_server (LmProxy *proxy, const gchar *server)
+{
+	g_return_if_fail (proxy != NULL);
+	g_return_if_fail (server != NULL);
+	
+	g_free (proxy->server);
+	proxy->server = g_strdup (server);
+}
+
+/**
+ * lm_proxy_get_port:
+ * @proxy: an #LmProxy
+ * 
+ * Fetches the port that @proxy is using.
+ * 
+ * Return value: The port 
+ **/
+guint
+lm_proxy_get_port (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, 0);
+
+	return proxy->port;
+}
+
+/**
+ * lm_proxy_set_port:
+ * @proxy: an #LmProxy
+ * @port: proxy server port
+ * 
+ * Sets the server port that @proxy will be using.
+ **/
+void
+lm_proxy_set_port (LmProxy *proxy, guint port)
+{
+	g_return_if_fail (proxy != NULL);
+	
+	proxy->port = port;
+}
+
+/**
+ * lm_proxy_get_username:
+ * @proxy: an #LmProxy
+ * 
+ * Fetches the username that @proxy is using.
+ * 
+ * Return value: the username
+ **/
+const gchar *
+lm_proxy_get_username (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, NULL);
+	
+	return proxy->username;
+}
+
+/**
+ * lm_proxy_set_username:
+ * @proxy: an #LmProxy
+ * @username: Username
+ * 
+ * Sets the username for @proxy to @username or %NULL to unset.  
+ **/
+void
+lm_proxy_set_username (LmProxy *proxy, const gchar *username)
+{
+	g_return_if_fail (proxy != NULL);
+	
+	g_free (proxy->username);
+	
+	if (username) {
+		proxy->username = g_strdup (username);
+	} else {
+		proxy->username = NULL;
+	}
+}
+/**
+ * lm_proxy_get_password:
+ * @proxy: an #LmProxy
+ * 
+ * Fetches the password that @proxy is using.
+ * 
+ * Return value: the proxy password
+ **/
+const gchar *
+lm_proxy_get_password (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, NULL);
+	
+	return proxy->password;
+}
+
+/**
+ * lm_proxy_set_password:
+ * @proxy: an #LmProxy
+ * @password: Password
+ * 
+ * Sets the password for @proxy to @password or %NULL to unset. 
+ **/
+void
+lm_proxy_set_password (LmProxy *proxy, const gchar *password)
+{
+	g_return_if_fail (proxy != NULL);
+	
+	g_free (proxy->password);
+
+	if (password) {
+		proxy->password = g_strdup (password);
+	} else {
+		proxy->password = NULL;
+	}
+}
+
+/**
+ * lm_proxy_ref:
+ * @proxy: an #LmProxy
+ * 
+ * Adds a reference to @proxy.
+ * 
+ * Return value: the proxy
+ **/
+LmProxy *
+lm_proxy_ref (LmProxy *proxy)
+{
+	g_return_val_if_fail (proxy != NULL, NULL);
+	
+	proxy->ref_count++;
+	return proxy;
+}
+
+/**
+ * lm_proxy_unref
+ * @proxy: an #LmProxy
+ * 
+ * Removes a reference from @proxy. When no more references are present
+ * @proxy is freed.
+ **/
+void
+lm_proxy_unref (LmProxy *proxy)
+{
+	g_return_if_fail (proxy != NULL);
+	
+	proxy->ref_count--;
+
+	if (proxy->ref_count == 0) {
+		proxy_free (proxy);
+        }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loudmouth/lm-proxy.h	Thu Jan 15 05:50:26 2004 +0000
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2004 Imendio HB
+ * Copyright (C) 2004 Josh Beam <josh@3ddrome.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __LM_PROXY_H__
+#define __LM_PROXY_H__
+
+#if !defined (LM_INSIDE_LOUDMOUTH_H) && !defined (LM_COMPILATION)
+#error "Only <loudmouth/loudmouth.h> can be included directly, this file may disappear or change contents."
+#endif
+
+typedef struct _LmProxy LmProxy;
+
+typedef enum {
+	LM_PROXY_TYPE_NONE = 0,
+	LM_PROXY_TYPE_HTTP
+} LmProxyType;
+
+LmProxy *     lm_proxy_new              (LmProxyType         type);
+
+LmProxyType   lm_proxy_get_type         (LmProxy            *proxy);
+void          lm_proxy_set_type         (LmProxy            *proxy,
+					 LmProxyType         type);
+
+const gchar * lm_proxy_get_server       (LmProxy            *proxy);
+void          lm_proxy_set_server       (LmProxy            *proxy,
+					 const gchar        *server);
+
+guint         lm_proxy_get_port         (LmProxy            *proxy);
+void          lm_proxy_set_port         (LmProxy            *proxy,
+					 guint               port);
+
+const gchar * lm_proxy_get_username     (LmProxy            *proxy);
+void          lm_proxy_set_username     (LmProxy            *proxy,
+					 const gchar        *username);
+
+const gchar * lm_proxy_get_password     (LmProxy            *proxy);
+void          lm_proxy_set_password     (LmProxy            *proxy,
+					 const gchar        *password);
+
+LmProxy *     lm_proxy_ref              (LmProxy            *proxy);
+void          lm_proxy_unref            (LmProxy            *proxy);
+
+#endif /* __LM_PROXY_H__ */
+
--- a/loudmouth/lm-utils.c	Thu Jan 08 14:43:02 2004 +0000
+++ b/loudmouth/lm-utils.c	Thu Jan 15 05:50:26 2004 +0000
@@ -62,6 +62,69 @@
 	return g_strdup_printf ("msg_%d", ++number);
 }
 
+gchar * 
+_lm_utils_base64_encode (const gchar *s)
+{
+	static const gchar *base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+	guint    i, j;
+	guint32  bits = 0;
+	guint    maxlen = (strlen(s) * 2) + 3;
+	gchar   *str;
+
+	str = g_malloc(maxlen);
+
+	j = 0;
+	for (i = 0; i < strlen(s); i++) {
+		bits <<= 8;
+		bits |= s[i] & 0xff;
+
+		if (!((i+1) % 3)) {
+			guint indices[4];
+
+			indices[0] = (bits >> 18) & 0x3f;
+			indices[1] = (bits >> 12) & 0x3f;
+			indices[2] = (bits >> 6) & 0x3f;
+			indices[3] = bits & 0x3f;
+			bits = 0;
+
+			str[j++] = base64chars[(indices[0])];
+			str[j++] = base64chars[(indices[1])];
+			str[j++] = base64chars[(indices[2])];
+			str[j++] = base64chars[(indices[3])];
+		}
+	}
+
+	if (j + 4 < maxlen) {
+		if ((i % 3) == 1) {
+			guint indices[2];
+
+			indices[0] = (bits >> 2) & 0x3f;
+			indices[1] = (bits << 4) & 0x3f;
+
+			str[j++] = base64chars[(indices[0])];
+			str[j++] = base64chars[(indices[1])];
+			str[j++] = '=';
+			str[j++] = '=';
+		} else if ((i % 3) == 2) {
+			guint indices[3];
+
+			indices[0] = (bits >> 10) & 0x3f;
+			indices[1] = (bits >> 4) & 0x3f;
+			indices[2] = (bits << 2) & 0x3f;
+
+			str[j++] = base64chars[(indices[0])];
+			str[j++] = base64chars[(indices[1])];
+			str[j++] = base64chars[(indices[2])];
+			str[j++] = '=';
+		}
+	}
+
+	str[j] = '\0';
+
+	return str;
+}
+
 struct tm *
 lm_utils_get_localtime (const gchar *stamp)
 {