Index: lib/misc.c
===================================================================
--- lib/misc.c	(revision a51be6448b7a6aa100f27873ce40b835068a66a7)
+++ lib/misc.c	(revision dcf0f3e77ffd38ce3cc5d3c1eedfc655ff75a8f9)
@@ -39,4 +39,9 @@
 #include <glib.h>
 #include <time.h>
+
+#ifdef HAVE_RESOLV_A
+#include <arpa/nameser.h>
+#include <resolv.h>
+#endif
 
 void strip_linefeed(gchar *text)
@@ -488,2 +493,54 @@
 	return 0;
 }
+
+struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain )
+{	
+	struct ns_srv_reply *reply = NULL;
+#ifdef HAVE_RESOLV_A
+	char name[1024];
+	unsigned char querybuf[1024];
+	const unsigned char *buf;
+	ns_msg nsh;
+	ns_rr rr;
+	int i, len, size;
+	
+	g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain );
+	
+	if( ( size = res_query( name, ns_c_in, ns_t_srv, querybuf, sizeof( querybuf ) ) ) <= 0 )
+		return NULL;
+	
+	if( ns_initparse( querybuf, size, &nsh ) != 0 )
+		return NULL;
+	
+	if( ns_parserr( &nsh, ns_s_an, 0, &rr ) != 0 )
+		return NULL;
+	
+	size = ns_rr_rdlen( rr );
+	buf = ns_rr_rdata( rr );
+	
+	len = 0;
+	for( i = 6; i < size && buf[i]; i += buf[i] + 1 )
+		len += buf[i] + 1;
+	
+	if( i > size )
+		return NULL;
+	
+	reply = g_malloc( sizeof( struct ns_srv_reply ) + len );
+	memcpy( reply->name, buf + 7, len );
+	
+	for( i = buf[6]; i < len && buf[7+i]; i += buf[7+i] + 1 )
+		reply->name[i] = '.';
+	
+	if( i > len )
+	{
+		g_free( reply );
+		return NULL;
+	}
+	
+	reply->prio = ( buf[0] << 8 ) | buf[1];
+	reply->weight = ( buf[2] << 8 ) | buf[3];
+	reply->port = ( buf[4] << 8 ) | buf[5];
+#endif
+	
+	return reply;
+}
Index: lib/misc.h
===================================================================
--- lib/misc.h	(revision a51be6448b7a6aa100f27873ce40b835068a66a7)
+++ lib/misc.h	(revision dcf0f3e77ffd38ce3cc5d3c1eedfc655ff75a8f9)
@@ -30,4 +30,12 @@
 #include <time.h>
 
+struct ns_srv_reply
+{
+	int prio;
+	int weight;
+	int port;
+	char name[];
+};
+
 G_MODULE_EXPORT void strip_linefeed( gchar *text );
 G_MODULE_EXPORT char *add_cr( char *text );
@@ -54,3 +62,5 @@
 G_MODULE_EXPORT int bool2int( char *value );
 
+G_MODULE_EXPORT struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain );
+
 #endif
Index: lib/ssl_client.h
===================================================================
--- lib/ssl_client.h	(revision a51be6448b7a6aa100f27873ce40b835068a66a7)
+++ lib/ssl_client.h	(revision dcf0f3e77ffd38ce3cc5d3c1eedfc655ff75a8f9)
@@ -52,4 +52,8 @@
 G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data );
 
+/* Start an SSL session on an existing fd. Useful for STARTTLS functionality,
+   for example in Jabber. */
+G_MODULE_EXPORT void *ssl_starttls( int fd, ssl_input_function func, gpointer data );
+
 /* Obviously you need special read/write functions to read data. */
 G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len );
Index: lib/ssl_gnutls.c
===================================================================
--- lib/ssl_gnutls.c	(revision a51be6448b7a6aa100f27873ce40b835068a66a7)
+++ lib/ssl_gnutls.c	(revision dcf0f3e77ffd38ce3cc5d3c1eedfc655ff75a8f9)
@@ -49,4 +49,6 @@
 
 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
+static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond );
+static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
 
 
@@ -63,5 +65,49 @@
 	{
 		g_free( conn );
-		return( NULL );
+		return NULL;
+	}
+	
+	return conn;
+}
+
+void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
+{
+	struct scd *conn = g_new0( struct scd, 1 );
+	
+	conn->fd = fd;
+	conn->func = func;
+	conn->data = data;
+	conn->inpa = -1;
+	
+	/* This function should be called via a (short) timeout instead of
+	   directly from here, because these SSL calls are *supposed* to be
+	   *completely* asynchronous and not ready yet when this function
+	   (or *_connect, for examle) returns. Also, errors are reported via
+	   the callback function, not via this function's return value.
+	   
+	   In short, doing things like this makes the rest of the code a lot
+	   simpler. */
+	
+	b_timeout_add( 1, ssl_starttls_real, conn );
+	
+	return conn;
+}
+
+static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond )
+{
+	struct scd *conn = data;
+	
+	return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE );
+}
+
+static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
+{
+	struct scd *conn = data;
+	
+	if( source == -1 )
+	{
+		conn->func( conn->data, NULL, cond );
+		g_free( conn );
+		return FALSE;
 	}
 	
@@ -77,25 +123,4 @@
 	gnutls_set_default_priority( conn->session );
 	gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred );
-	
-	return( conn );
-}
-
-static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
-
-static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
-{
-	struct scd *conn = data;
-	
-	if( source == -1 )
-	{
-		conn->func( conn->data, NULL, cond );
-		
-		gnutls_deinit( conn->session );
-		gnutls_certificate_free_credentials( conn->xcred );
-		
-		g_free( conn );
-		
-		return FALSE;
-	}
 	
 	sock_make_nonblocking( conn->fd );
Index: lib/ssl_openssl.c
===================================================================
--- lib/ssl_openssl.c	(revision a51be6448b7a6aa100f27873ce40b835068a66a7)
+++ lib/ssl_openssl.c	(revision dcf0f3e77ffd38ce3cc5d3c1eedfc655ff75a8f9)
@@ -53,4 +53,6 @@
 
 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
+static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond );
+static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
 
 
@@ -58,15 +60,56 @@
 {
 	struct scd *conn = g_new0( struct scd, 1 );
-	SSL_METHOD *meth;
 	
 	conn->fd = proxy_connect( host, port, ssl_connected, conn );
 	conn->func = func;
 	conn->data = data;
+	conn->inpa = -1;
 	
 	if( conn->fd < 0 )
 	{
 		g_free( conn );
-		return( NULL );
-	}
+		return NULL;
+	}
+	
+	return conn;
+}
+
+void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
+{
+	struct scd *conn = g_new0( struct scd, 1 );
+	
+	conn->fd = fd;
+	conn->func = func;
+	conn->data = data;
+	conn->inpa = -1;
+	
+	/* This function should be called via a (short) timeout instead of
+	   directly from here, because these SSL calls are *supposed* to be
+	   *completely* asynchronous and not ready yet when this function
+	   (or *_connect, for examle) returns. Also, errors are reported via
+	   the callback function, not via this function's return value.
+	   
+	   In short, doing things like this makes the rest of the code a lot
+	   simpler. */
+	
+	b_timeout_add( 1, ssl_starttls_real, conn );
+	
+	return conn;
+}
+
+static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond )
+{
+	struct scd *conn = data;
+	
+	return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE );
+}
+
+static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
+{
+	struct scd *conn = data;
+	SSL_METHOD *meth;
+	
+	if( source == -1 )
+		goto ssl_connected_failure;
 	
 	if( !initialized )
@@ -79,27 +122,9 @@
 	conn->ssl_ctx = SSL_CTX_new( meth );
 	if( conn->ssl_ctx == NULL )
-	{
-		conn->fd = -1;
-		return( NULL );
-	}
+		goto ssl_connected_failure;
 	
 	conn->ssl = SSL_new( conn->ssl_ctx );
 	if( conn->ssl == NULL )
-	{
-		conn->fd = -1;
-		return( NULL );
-	}
-	
-	return( conn );
-}
-
-static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
-
-static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
-{
-	struct scd *conn = data;
-	
-	if( source == -1 )
-		return ssl_handshake( data, -1, cond );
+		goto ssl_connected_failure;
 	
 	/* We can do at least the handshake with non-blocking I/O */
@@ -108,4 +133,22 @@
 	
 	return ssl_handshake( data, source, cond );
+
+ssl_connected_failure:
+	conn->func( conn->data, NULL, cond );
+	
+	if( conn->ssl )
+	{
+		SSL_shutdown( conn->ssl );
+		SSL_free( conn->ssl );
+	}
+	if( conn->ssl_ctx )
+	{
+		SSL_CTX_free( conn->ssl_ctx );
+	}
+	if( source >= 0 ) closesocket( source );
+	g_free( conn );
+	
+	return FALSE;
+
 }	
 
@@ -119,5 +162,16 @@
 		conn->lasterr = SSL_get_error( conn->ssl, st );
 		if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
-			goto ssl_connected_failure;
+		{
+			conn->func( conn->data, NULL, cond );
+			
+			SSL_shutdown( conn->ssl );
+			SSL_free( conn->ssl );
+			SSL_CTX_free( conn->ssl_ctx );
+			
+			if( source >= 0 ) closesocket( source );
+			g_free( conn );
+			
+			return FALSE;
+		}
 		
 		conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data );
@@ -129,21 +183,4 @@
 	conn->func( conn->data, conn, cond );
 	return FALSE;
-	
-ssl_connected_failure:
-	conn->func( conn->data, NULL, cond );
-	
-	if( conn->ssl )
-	{
-		SSL_shutdown( conn->ssl );
-		SSL_free( conn->ssl );
-	}
-	if( conn->ssl_ctx )
-	{
-		SSL_CTX_free( conn->ssl_ctx );
-	}
-	if( source >= 0 ) closesocket( source );
-	g_free( conn );
-	
-	return FALSE;
 }
 
