[evolution-patches] ipv6 patch




This rather big patch addresses a major issue with network connections from camel, that is, only 1 type of address is supported (ipv6 or ipv4) for a given host at a time, and only one physical address for that host will ever be tried, even if multiple addresses of the same format exist.  The only other way to address this issue would be to have all of the service connect calls perform two lookups using an extended gethostbyname2_r interface, which is only available on GNU anyway, where we already have getaddrinfo.  It would be a messier and even less portable solution.  What we have now though is 'really wrong'.

Most of the patch is just changing the api's to suit the changes and to clean up some of the related apis too.  And to remove a lot of ipv6 vs ipv4 specific code from most of the places where it doesn't need to know about the difference (like, just about everywhere, even the stuff in stream-ssl could probably just use memcpy).

The main change is the new hostname resolution interfaces, which are async/cancellable like the old ones, and use a getaddrinfo/getnameinfo interface rather than a gethostby* interface.  So it emulates getaddrinfo when it isn't available, and forces ipv4 in that case.  Sure it could also handle some ipv6 stuff, but i just don't care.

I'm inclined to simply drop support for all systems which don't support getaddrinfo/getnameinfo anyway, because its too much pain to deal with different address formats using the old-style interfaces.  But for now the patch has a very limited emulation which mostly seems to work.

Some configure changes mean that ipv6 is simply enabled by default if your system has the necessary interfaces, and it always uses those interfaces if available even if you force it to use ipv4 (not that i can see there's actually a reason to want to do this).

I would bet my house on there being lots of portability issues with it all though.  e.g. redefining struct addrinfo on half/broken systems.

It hasn't been tested a lot, so there are probably other bugs too.

--
Michael Zucchi <notzed ximian com>
"born to die, live to work, it's all downhill from here"
Novell's Evolution and Free Software Developer
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/ChangeLog,v
retrieving revision 1.1365
diff -u -3 -r1.1365 ChangeLog
--- ChangeLog	27 Aug 2004 20:35:42 -0000	1.1365
+++ ChangeLog	13 Sep 2004 10:05:46 -0000
@@ -1,3 +1,9 @@
+2004-09-13  Not Zed  <NotZed Ximian com>
+
+	* configure.in: change the way ipv6 stuff is done.  separate ipv6
+	setting from getaddrinfo call check, and default to on if the
+	interfaces are available.
+
 2004-08-27  JP Rosevear  <jpr novell com>
 
 	* configure.in: bump version, requirements
Index: configure.in
===================================================================
RCS file: /cvs/gnome/evolution/configure.in,v
retrieving revision 1.712
diff -u -3 -r1.712 configure.in
--- configure.in	27 Aug 2004 20:35:42 -0000	1.712
+++ configure.in	13 Sep 2004 10:05:47 -0000
@@ -284,11 +284,9 @@
 AC_SUBST(A11Y_LIBS)
 
 dnl **************************************************
-dnl * IPv6 support
+dnl * IPv6 support and getaddrinfo calls
 dnl **************************************************
-AC_ARG_ENABLE(ipv6, [  --enable-ipv6=[no/yes]      Enable support for resolving IPv6 addresses.],,enable_ipv6=no)
-if test "x$enable_ipv6" = "xyes"; then
-AC_CACHE_CHECK([if system has necessary structs and functions for IPv6 support], msg_ipv6,
+AC_CACHE_CHECK([if system supports getaddrinfo and getnameinfo], have_addrinfo,
 [
 	AC_TRY_COMPILE([
 		#include "confdefs.h"
@@ -301,21 +299,29 @@
 		struct addrinfo hints, *res;
 		struct sockaddr_in6 sin6;
 		int af = AF_INET6;
-		
+		char host[NI_MAXHOST];
+		char serv[NI_MAXSERV];
+
 		getaddrinfo ("www.ximian.com", NULL, &hints, &res);
 		freeaddrinfo (res);
+		getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), host, sizeof(host), serv, sizeof(serv), 0);
 	],[
-		msg_ipv6=yes
+		have_addrinfo=yes
 	],[
-		enable_ipv6=no
-		msg_ipv6=no
+		have_addrinfo=no
 	])
 ])
-else
-	msg_ipv6=no
-fi
 
-if test "x$enable_ipv6" = "xyes"; then
+if test x"$have_addrinfo" = "xno" ; then
+   AC_DEFINE(NEED_ADDRINFO,1,[Enable getaddrinfo emulation])
+   if test x"$enable_ipv6" = "xyes" ; then
+      AC_ERROR(system doesn't support necessary interfaces for ipv6 support)
+   fi
+   msg_ipv6=no
+else
+   AC_ARG_ENABLE(ipv6, [  --enable-ipv6=[no/yes]      Enable support for resolving IPv6 addresses.],,enable_ipv6=yes)
+   if test x"$enable_ipv6" = "xyes"; then
+        msg_ipv6=yes
 	AC_DEFINE(ENABLE_IPv6,1,[Enable IPv6 support])
 	AC_TRY_COMPILE([
 		#include "confdefs.h"
@@ -331,9 +337,12 @@
 	],[
 		AC_DEFINE(HAVE_AI_ADDRCONFIG,1,[Define if the system defines the AI_ADDRCONFIG flag for getaddrinfo])
 	])
+   else
+	msg_ipv6=no
+   fi
 fi
-AM_CONDITIONAL(ENABLE_IPv6, test "x$enable_ipv6" = "xyes")
 
+AM_CONDITIONAL(ENABLE_IPv6, test "x$enable_ipv6" = "xyes")
 
 dnl **************************************************
 dnl LDAP support.
Index: camel/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/camel/ChangeLog,v
retrieving revision 1.2254
diff -u -3 -r1.2254 ChangeLog
--- camel/ChangeLog	8 Sep 2004 04:02:41 -0000	1.2254
+++ camel/ChangeLog	13 Sep 2004 10:05:50 -0000
@@ -1,3 +1,33 @@
+2004-09-13  Not Zed  <NotZed Ximian com>
+
+	* camel-service.c: removed the old hostent based hostname interfaces.
+
+	* camel-sasl-kerberos4.c (krb4_challenge): new hostname interfaces.
+
+	* camel-sasl-gssapi.c (gssapi_challenge): new hostname interfaces.
+
+	* camel-sasl-digest-md5.c (digest_md5_challenge): use new hostname
+	interfaces.
+	(generate_response): just take hostname directly, not hostent.
+
+	* camel-mime-utils.c (camel_header_msgid_generate): use new
+	hostname interfaces.
+
+	* providers/smtp/camel-smtp-transport.c (connect_to_server): fixed
+	to use new addrinfo apis.
+
+	* providers/pop3/camel-pop3-store.c (connect_to_server): fixed to
+	use new addrinfo apis.
+
+	* camel-tcp-stream-ssl.c (stream_connect): try all addresses
+	supplied.
+
+	* camel-tcp-stream.c (camel_tcp_stream_get_remote_address)
+	(camel_tcp_stream_get_local_address): return a sockaddr now, and
+	also the address length.  Fixed all implementations and callers.
+	(camel_tcp_stream_connect): use addrinfo rather than hostent for
+	host AND port info.  Fixed all implementations and callers.
+
 2004-09-03  Not Zed  <NotZed Ximian com>
 
 	* camel-tcp-stream-ssl.c (stream_connect): make ssl connection
Index: camel/camel-http-stream.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-http-stream.c,v
retrieving revision 1.16
diff -u -3 -r1.16 camel-http-stream.c
--- camel/camel-http-stream.c	23 Oct 2003 19:57:58 -0000	1.16
+++ camel/camel-http-stream.c	13 Sep 2004 10:05:50 -0000
@@ -45,7 +45,6 @@
 
 #define d(x) x
 
-
 static CamelStreamClass *parent_class = NULL;
 
 static ssize_t stream_read (CamelStream *stream, char *buffer, size_t n);
@@ -174,9 +173,12 @@
 http_connect (CamelHttpStream *http, CamelURL *url)
 {
 	CamelStream *stream = NULL;
-	struct hostent *host;
+	struct addrinfo *ai, hints = { 0 };
 	int errsave;
-	
+	char *serv;
+
+	d(printf("connecting to http stream @ '%s'\n", url->host));
+
 	if (!strcasecmp (url->protocol, "https")) {
 #ifdef HAVE_SSL
 		stream = camel_tcp_stream_ssl_new (http->session, url->host, SSL_FLAGS);
@@ -189,24 +191,30 @@
 		errno = EINVAL;
 		return NULL;
 	}
-	
-	printf("connecting to http stream @ '%s'\n", url->host);
 
-	host = camel_gethostbyname (url->host, NULL);
-	if (!host) {
-		errno = EHOSTUNREACH;
+	if (url->port) {
+		serv = g_alloca(16);
+		sprintf(serv, "%d", url->port);
+	} else {
+		serv = url->protocol;
+	}
+	hints.ai_socktype = SOCK_STREAM;
+
+	ai = camel_getaddrinfo(url->host, serv, &hints, NULL);
+	if (ai == NULL) {
+		camel_object_unref (stream);
 		return NULL;
 	}
 	
-	if (camel_tcp_stream_connect (CAMEL_TCP_STREAM (stream), host, url->port ? url->port : 80) == -1) {
+	if (camel_tcp_stream_connect (CAMEL_TCP_STREAM (stream), ai) == -1) {
 		errsave = errno;
 		camel_object_unref (stream);
-		camel_free_host (host);
+		camel_freeaddrinfo(ai);
 		errno = errsave;
 		return NULL;
 	}
 	
-	camel_free_host (host);
+	camel_freeaddrinfo(ai);
 
 	http->raw = stream;
 	http->read = camel_stream_buffer_new (stream, CAMEL_STREAM_BUFFER_READ);
Index: camel/camel-mime-utils.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-mime-utils.c,v
retrieving revision 1.214
diff -u -3 -r1.214 camel-mime-utils.c
--- camel/camel-mime-utils.c	12 Aug 2004 20:20:19 -0000	1.214
+++ camel/camel-mime-utils.c	13 Sep 2004 10:05:52 -0000
@@ -3761,25 +3761,29 @@
 #define COUNT_LOCK() pthread_mutex_lock (&count_lock)
 #define COUNT_UNLOCK() pthread_mutex_unlock (&count_lock)
 	char host[MAXHOSTNAMELEN];
-	struct hostent *h = NULL;
+	char *name;
 	static int count = 0;
 	char *msgid;
 	int retval;
-	
+	struct addrinfo *ai = NULL, hints = { 0 };
+
 	retval = gethostname (host, sizeof (host));
-	
-	if (retval == 0 && *host)
-		h = camel_gethostbyname (host, NULL);
-	else
-		host[0] = '\0';
+	if (retval == 0 && *host) {
+		hints.ai_flags = AI_CANONNAME;
+		ai = camel_getaddrinfo(host, NULL, &hints, NULL);
+		if (ai && ai->ai_canonname)
+			name = ai->ai_canonname;
+		else
+			name = host;
+	} else
+		name = "localhost.localdomain";
 	
 	COUNT_LOCK ();
-	msgid = g_strdup_printf ("%d %d %d camel %s", (int) time (NULL), getpid (), count++,
-				 h ? h->h_name : (*host ? host : "localhost.localdomain"));
+	msgid = g_strdup_printf ("%d %d %d camel %s", (int) time (NULL), getpid (), count++, name);
 	COUNT_UNLOCK ();
 	
-	if (h)
-		camel_free_host (h);
+	if (ai)
+		camel_freeaddrinfo(ai);
 	
 	return msgid;
 }
Index: camel/camel-sasl-digest-md5.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-sasl-digest-md5.c,v
retrieving revision 1.20
diff -u -3 -r1.20 camel-sasl-digest-md5.c
--- camel/camel-sasl-digest-md5.c	18 Sep 2003 18:10:57 -0000	1.20
+++ camel/camel-sasl-digest-md5.c	13 Sep 2004 10:05:53 -0000
@@ -623,7 +623,7 @@
 }
 
 static struct _DigestResponse *
-generate_response (struct _DigestChallenge *challenge, struct hostent *host,
+generate_response (struct _DigestChallenge *challenge, const char *host,
 		   const char *protocol, const char *user, const char *passwd)
 {
 	struct _DigestResponse *resp;
@@ -659,7 +659,7 @@
 	/* create the URI */
 	uri = g_new0 (struct _DigestURI, 1);
 	uri->type = g_strdup (protocol);
-	uri->host = g_strdup (host->h_name);
+	uri->host = g_strdup (host);
 	uri->name = NULL;
 	resp->uri = uri;
 	
@@ -795,10 +795,10 @@
 	struct _param *rspauth;
 	GByteArray *ret = NULL;
 	gboolean abort = FALSE;
-	struct hostent *h;
 	const char *ptr;
 	guchar out[33];
 	char *tokens;
+	struct addrinfo *ai, hints;
 	
 	/* Need to wait for the server */
 	if (!token)
@@ -829,12 +829,20 @@
 						"\"Quality of Protection\" token\n"));
 			return NULL;
 		}
-		
-		h = camel_service_gethost (sasl->service, ex);
-		priv->response = generate_response (priv->challenge, h, sasl->service_name,
+
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_flags = AI_CANONNAME;
+		ai = camel_getaddrinfo(sasl->service->url->host?sasl->service->url->host:"localhost", NULL, &hints, NULL);
+		if (ai && ai->ai_canonname)
+			ptr = ai->ai_canonname;
+		else
+			ptr = "localhost.localdomain";
+
+		priv->response = generate_response (priv->challenge, ptr, sasl->service_name,
 						    sasl->service->url->user,
 						    sasl->service->url->passwd);
-		camel_free_host(h);
+		if (ai)
+			camel_freeaddrinfo(ai);
 		ret = digest_response (priv->response);
 		
 		break;
Index: camel/camel-sasl-gssapi.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-sasl-gssapi.c,v
retrieving revision 1.10
diff -u -3 -r1.10 camel-sasl-gssapi.c
--- camel/camel-sasl-gssapi.c	13 Aug 2004 14:39:19 -0000	1.10
+++ camel/camel-sasl-gssapi.c	13 Sep 2004 10:05:53 -0000
@@ -209,18 +209,18 @@
 	gss_qop_t qop;
 	gss_OID mech;
 	char *str;
+	struct addrinfo *ai, hints;
 	
 	switch (priv->state) {
 	case GSSAPI_STATE_INIT:
-		if (!(h = camel_service_gethost (sasl->service, ex))) {
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-					      _("Failed to resolve host `%s': %s"),
-					      sasl->service->url->host, g_strerror (errno));
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_flags = AI_CANONNAME;
+		ai = camel_getaddrinfo(sasl->service->url->host?sasl->service->url->host:"localhost", NULL, &hints, ex);
+		if (ai == NULL)
 			return NULL;
-		}
 		
-		str = g_strdup_printf ("%s %s", sasl->service_name, h->h_name);
-		camel_free_host (h);
+		str = g_strdup_printf("%s %s", sasl->service_name, ai->ai_canonname);
+		camel_freeaddrinfo(ai);
 		
 		inbuf.value = str;
 		inbuf.length = strlen (str);
Index: camel/camel-sasl-kerberos4.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-sasl-kerberos4.c,v
retrieving revision 1.10
diff -u -3 -r1.10 camel-sasl-kerberos4.c
--- camel/camel-sasl-kerberos4.c	16 Oct 2003 15:33:47 -0000	1.10
+++ camel/camel-sasl-kerberos4.c	13 Sep 2004 10:05:53 -0000
@@ -129,6 +129,7 @@
 	KTEXT_ST authenticator;
 	CREDENTIALS credentials;
 	guint32 plus1;
+	struct addrinfo *ai, hints;
 
 	/* Need to wait for the server */
 	if (!token)
@@ -142,11 +143,17 @@
 		memcpy (&priv->nonce_n, token->data, 4);
 		priv->nonce_h = ntohl (priv->nonce_n);
 
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_flags = AI_CANONNAME;
+		ai = camel_getaddrinfo(sasl->service->url->host?sasl->service->url->host:"localhost", NULL, &hints, ex);
+		if (ai == NULL)
+			goto lose;
+
 		/* Our response is an authenticator including that number. */
 		h = camel_service_gethost (sasl->service, ex);
-		inst = g_strndup (h->h_name, strcspn (h->h_name, "."));
+		inst = g_strndup (ai->ai_canonname, strcspn (ai->ai_canonname, "."));
 		camel_strdown (inst);
-		realm = g_strdup (krb_realmofhost (h->h_name));
+		realm = g_strdup (krb_realmofhost (ai->ai_canonname));
 		camel_free_host(h);
 		status = krb_mk_req (&authenticator, sasl->service_name, inst, realm, priv->nonce_h);
 		if (status == KSUCCESS) {
Index: camel/camel-service.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-service.c,v
retrieving revision 1.90
diff -u -3 -r1.90 camel-service.c
--- camel/camel-service.c	21 Jun 2004 15:48:06 -0000	1.90
+++ camel/camel-service.c	13 Sep 2004 10:05:53 -0000
@@ -34,6 +34,8 @@
 #include <pthread.h>
 #include <errno.h>
 
+#include <sys/poll.h>
+
 #include "e-util/e-msgport.h"
 
 #include "e-util/e-host-utils.h"
@@ -642,188 +644,226 @@
 	return ret;
 }
 
-/* URL utility routines */
-
-/**
- * camel_service_gethost:
- * @service: a CamelService
- * @ex: a CamelException
- *
- * This is a convenience function to do a gethostbyname on the host
- * for the service's URL.
- *
- * Return value: a (statically-allocated) hostent.
- **/
-struct hostent *
-camel_service_gethost (CamelService *service, CamelException *ex)
-{
-	char *hostname;
-	
-	if (service->url->host)
-		hostname = service->url->host;
-	else
-		hostname = "localhost";
-	
-	return camel_gethostbyname (hostname, ex);
-}
-
-#ifdef offsetof
-#define STRUCT_OFFSET(type, field)        ((gint) offsetof (type, field))
-#else
-#define STRUCT_OFFSET(type, field)        ((gint) ((gchar*) &((type *) 0)->field))
-#endif
-
-struct _lookup_msg {
+/* ********************************************************************** */
+struct _addrinfo_msg {
 	EMsg msg;
 	unsigned int cancelled:1;
+
+	/* for host lookup */
 	const char *name;
-	int len;
-	int type;
+	const char *service;
 	int result;
-	int herr;
+	const struct addrinfo *hints;
+	struct addrinfo **res;
+
+	/* for host lookup emulation */
+#ifdef NEED_ADDRINFO
 	struct hostent hostbuf;
 	int hostbuflen;
 	char *hostbufmem;
+#endif
+
+	/* for name lookup */
+	const struct sockaddr *addr;
+	socklen_t addrlen;
+	char *host;
+	int hostlen;
+	char *serv;
+	int servlen;
+	int flags;
 };
 
-static void *
-get_hostbyname(void *data)
+static void
+cs_freeinfo(struct _addrinfo_msg *msg)
 {
-	struct _lookup_msg *info = data;
+	g_free(msg->host);
+	g_free(msg->serv);
+#ifdef NEED_ADDRINFO
+	g_free(msg->hostbufmem);
+#endif
+	g_free(msg);
+}
 
-	while ((info->result = e_gethostbyname_r(info->name, &info->hostbuf, info->hostbufmem, info->hostbuflen, &info->herr)) == ERANGE) {
-		d(printf("gethostbyname fialed?\n"));
-		pthread_testcancel();
-                info->hostbuflen *= 2;
-                info->hostbufmem = g_realloc(info->hostbufmem, info->hostbuflen);
-	}
+/* returns -1 if cancelled */
+static int
+cs_waitinfo(void *(worker)(void *), struct _addrinfo_msg *msg, const char *error, CamelException *ex)
+{
+	EMsgPort *reply_port;
+	pthread_t id;
+	int err, cancel_fd, cancel = 0, fd;
 
-	d(printf("gethostbyname ok?\n"));
+	cancel_fd = camel_operation_cancel_fd(NULL);
+	if (cancel_fd == -1) {
+		worker(msg);
+		return 0;
+	}
 	
-	/* If we got cancelled, dont reply, just free it */
-	if (info->cancelled) {
-		g_free(info->hostbufmem);
-		g_free(info);
+	reply_port = msg->msg.reply_port = e_msgport_new();
+	fd = e_msgport_fd(msg->msg.reply_port);
+	if ((err = pthread_create(&id, NULL, worker, msg)) == 0) {
+		struct pollfd polls[2];
+		int status;
+
+		polls[0].fd = fd;
+		polls[0].events = POLLIN;
+		polls[1].fd = cancel_fd;
+		polls[1].events = POLLIN;
+
+		d(printf("waiting for name return/cancellation in main process\n"));
+		do {
+			polls[0].revents = 0;
+			polls[1].revents = 0;
+			status = poll(polls, 2, -1);
+		} while (status == -1 && errno == EINTR);
+
+		if (status == -1 || (polls[1].revents & POLLIN)) {
+			if (status == -1)
+				camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, "%s: %s", error, g_strerror(errno));
+			else
+				camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+			
+			/* We cancel so if the thread impl is decent it causes immediate exit.
+			   We detach so we dont need to wait for it to exit if it isn't.
+			   We check the reply port incase we had a reply in the mean time, which we free later */
+			d(printf("Cancelling lookup thread and leaving it\n"));
+			msg->cancelled = 1;
+			pthread_detach(id);
+			pthread_cancel(id);
+			cancel = 1;
+		} else {
+			struct _addrinfo_msg *reply = (struct _addrinfo_msg *)e_msgport_get(reply_port);
+
+			g_assert(reply == msg);
+			d(printf("waiting for child to exit\n"));
+			pthread_join(id, NULL);
+			d(printf("child done\n"));
+		}
 	} else {
-		e_msgport_reply((EMsg *)info);
+		camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, "%s: %s: %s", _("cannot create thread"), g_strerror(err));
 	}
-	
-	return NULL;
+	e_msgport_destroy(reply_port);
+
+	return cancel;
 }
 
-struct hostent *
-camel_gethostbyname (const char *name, CamelException *exout)
+#ifdef NEED_ADDRINFO
+static void *
+cs_getaddrinfo(void *data)
 {
-	int fdmax, status, fd, cancel_fd;
-	struct _lookup_msg *msg;
-	CamelException ex;
-	
-	g_return_val_if_fail(name != NULL, NULL);
-	
-	if (camel_operation_cancel_check(NULL)) {
-		camel_exception_set (exout, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
-		return NULL;
-	}
+	struct _addrinfo_msg *msg = data;
+	int herr;
+	struct hostent h;
+	struct addrinfo *res, *last = NULL;
+	struct sockaddr_in *sin;
+	in_port_t port = 0;
+	int i;
 
-	camel_exception_init(&ex);
-	camel_operation_start_transient(NULL, _("Resolving: %s"), name);
+	/* This is a pretty simplistic emulation of getaddrinfo */
 
-	msg = g_malloc0(sizeof(*msg));
-	msg->hostbuflen = 1024;
-	msg->hostbufmem = g_malloc(msg->hostbuflen);
-	msg->name = name;
-	msg->result = -1;
-	
-	cancel_fd = camel_operation_cancel_fd(NULL);
-	if (cancel_fd == -1) {
-		get_hostbyname(msg);
-	} else {
-		EMsgPort *reply_port;
-		pthread_t id;
-		fd_set rdset;
-		int err;
-
-		reply_port = msg->msg.reply_port = e_msgport_new();
-		fd = e_msgport_fd(msg->msg.reply_port);
-		if ((err = pthread_create(&id, NULL, get_hostbyname, msg)) == 0) {
-			d(printf("waiting for name return/cancellation in main process\n"));
-			do {
-				FD_ZERO(&rdset);
-				FD_SET(cancel_fd, &rdset);
-				FD_SET(fd, &rdset);
-				fdmax = MAX(fd, cancel_fd) + 1;
-				status = select(fdmax, &rdset, NULL, 0, NULL);
-			} while (status == -1 && errno == EINTR);
-
-			if (status == -1 || FD_ISSET(cancel_fd, &rdset)) {
-				if (status == -1)
-					camel_exception_setv(&ex, CAMEL_EXCEPTION_SYSTEM, _("Failure in name lookup: %s"), g_strerror(errno));
-				else
-					camel_exception_setv(&ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
-
-				/* We cancel so if the thread impl is decent it causes immediate exit.
-				   We detach so we dont need to wait for it to exit if it isn't.
-				   We check the reply port incase we had a reply in the mean time, which we free later */
-				d(printf("Cancelling lookup thread and leaving it\n"));
-				msg->cancelled = 1;
-				pthread_detach(id);
-				pthread_cancel(id);
-				msg = (struct _lookup_msg *)e_msgport_get(reply_port);
-			} else {
-				struct _lookup_msg *reply = (struct _lookup_msg *)e_msgport_get(reply_port);
-
-				g_assert(reply == msg);
-				d(printf("waiting for child to exit\n"));
-				pthread_join(id, NULL);
-				d(printf("child done\n"));
-			}
-		} else {
-			camel_exception_setv(&ex, CAMEL_EXCEPTION_SYSTEM, _("Host lookup failed: cannot create thread: %s"), g_strerror(err));
-		}
-		e_msgport_destroy(reply_port);
+	while ((msg->result = e_gethostbyname_r(msg->name, &h, msg->hostbufmem, msg->hostbuflen, &herr)) == ERANGE) {
+		pthread_testcancel();
+                msg->hostbuflen *= 2;
+                msg->hostbufmem = g_realloc(msg->hostbufmem, msg->hostbuflen);
 	}
 	
-	camel_operation_end(NULL);
+	/* If we got cancelled, dont reply, just free it */
+	if (msg->cancelled)
+		goto cancel;
 
-	if (!camel_exception_is_set(&ex)) {
-		if (msg->result == 0)
-			return &msg->hostbuf;
+	/* FIXME: map error numbers across */
+	if (msg->result != 0)
+		goto reply;
 
-		if (msg->herr == HOST_NOT_FOUND || msg->herr == NO_DATA)
-			camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM,
-					      _("Host lookup failed: %s: host not found"), name);
-		else
-			camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM,
-					      _("Host lookup failed: %s: unknown reason"), name);
+	/* check hints matched */
+	if (msg->hints && msg->hints->ai_family && msg->hints->ai_family != h.h_addrtype) {
+		msg->result = EAI_FAMILY;
+		goto reply;
 	}
 
-	if (msg) {
-		g_free(msg->hostbufmem);
-		g_free(msg);
+	/* we only support ipv4 for this interface, even if it could supply ipv6 */
+	if (h.h_addrtype != AF_INET) {
+		msg->result = EAI_FAMILY;
+		goto reply;
+	}
+
+	/* check service mapping */
+	if (msg->service) {
+		const char *p = msg->service;
+
+		while (*p) {
+			if (*p < '0' || *p > '9')
+				break;
+			p++;
+		}
+
+		if (*p) {
+			const char *socktype = NULL;
+			struct servent *serv;
+
+			if (msg->hints && msg->hints->ai_socktype) {
+				if (msg->hints->ai_socktype == SOCK_STREAM)
+					socktype = "tcp";
+				else if (msg->hints->ai_socktype == SOCK_DGRAM)
+					socktype = "udp";
+			}
+
+			serv = getservbyname(msg->service, socktype);
+			if (serv == NULL) {
+				msg->result = EAI_NONAME;
+				goto reply;
+			}
+			port = serv->s_port;
+		} else {
+			port = htons(strtoul(msg->service, NULL, 10));
+		}
 	}
 
-	camel_exception_xfer(exout, &ex);
+	for (i=0;h.h_addr_list[i];i++) {
+		res = g_malloc0(sizeof(*res));
+		if (msg->hints) {
+			res->ai_flags = msg->hints->ai_flags;
+			if (msg->hints->ai_flags & AI_CANONNAME)
+				res->ai_canonname = g_strdup(h.h_name);
+			res->ai_socktype = msg->hints->ai_socktype;
+			res->ai_protocol = msg->hints->ai_protocol;
+		} else {
+			res->ai_flags = 0;
+			res->ai_socktype = SOCK_STREAM;	/* fudge */
+			res->ai_protocol = 0;	/* fudge */
+		}
+		res->ai_family = AF_INET;
+		res->ai_addrlen = sizeof(*sin);
+		res->ai_addr = g_malloc(sizeof(*sin));
+		sin = (struct sockaddr_in *)res->ai_addr;
+		sin->sin_family = AF_INET;
+		sin->sin_port = port;
+		memcpy(&sin->sin_addr, h.h_addr_list[i], sizeof(sin->sin_addr));
 
+		if (last == NULL) {
+			*msg->res = last = res;
+		} else {
+			last->ai_next = res;
+			last = res;
+		}
+	}
+reply:
+	e_msgport_reply((EMsg *)msg);
+	return NULL;
+cancel:
+	cs_freeinfo(msg);
 	return NULL;
 }
-
+#else
 static void *
-get_hostbyaddr (void *data)
+cs_getaddrinfo(void *data)
 {
-	struct _lookup_msg *info = data;
-	
-	while ((info->result = e_gethostbyaddr_r (info->name, info->len, info->type, &info->hostbuf,
-						  info->hostbufmem, info->hostbuflen, &info->herr)) == ERANGE) {
-		d(printf ("gethostbyaddr fialed?\n"));
-		pthread_testcancel ();
-                info->hostbuflen *= 2;
-                info->hostbufmem = g_realloc (info->hostbufmem, info->hostbuflen);
-	}
-	
-	d(printf ("gethostbyaddr ok?\n"));
+	struct _addrinfo_msg *info = data;
+
+	do {
+		info->result = getaddrinfo(info->name, info->service, info->hints, info->res);
+	} while (info->result == EAI_AGAIN);
 	
 	if (info->cancelled) {
-		g_free(info->hostbufmem);
 		g_free(info);
 	} else {
 		e_msgport_reply((EMsg *)info);
@@ -831,118 +871,175 @@
 	
 	return NULL;
 }
+#endif /* NEED_ADDRINFO */
 
-
-struct hostent *
-camel_gethostbyaddr (const char *addr, int len, int type, CamelException *exout)
+struct addrinfo *
+camel_getaddrinfo(const char *name, const char *service, const struct addrinfo *hints, CamelException *ex)
 {
-	int fdmax, status, fd, cancel_fd;
-	struct _lookup_msg *msg;
-	CamelException ex;
-
-	g_return_val_if_fail (addr != NULL, NULL);
+	struct _addrinfo_msg *msg;
+	struct addrinfo *res = NULL;
+#ifndef ENABLE_IPv6
+	struct addrinfo *myhints;
+#endif
+	g_return_val_if_fail(name != NULL, NULL);
 	
-	if (camel_operation_cancel_check (NULL)) {
-		camel_exception_set (exout, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+	if (camel_operation_cancel_check(NULL)) {
+		camel_exception_set(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
 		return NULL;
 	}
 
-	camel_exception_init(&ex);
-	camel_operation_start_transient (NULL, _("Resolving address"));
-	
-	msg = g_malloc0 (sizeof (struct _lookup_msg));
+	camel_operation_start_transient(NULL, _("Resolving: %s"), name);
+
+	/* force ipv4 addresses only */
+#ifndef ENABLE_IPv6
+	if (hints == NULL) {
+		memset(&myhints, 0, sizeof(myhints));
+		hints = &myints;
+	}
+
+	hints->ai_family = AF_INET;
+#endif
+
+	msg = g_malloc0(sizeof(*msg));
+	msg->name = name;
+	msg->service = service;
+	msg->hints = hints;
+	msg->res = &res;
+#ifdef NEED_ADDRINFO
 	msg->hostbuflen = 1024;
-	msg->hostbufmem = g_malloc (msg->hostbuflen);
-	msg->name = addr;
-	msg->len = len;
-	msg->type = type;
-	msg->result = -1;
-	
-	cancel_fd = camel_operation_cancel_fd (NULL);
-	if (cancel_fd == -1) {
-		get_hostbyaddr (msg);
-	} else {
-		EMsgPort *reply_port;
-		pthread_t id;
-		fd_set rdset;
-		int err;
-
-		reply_port = msg->msg.reply_port = e_msgport_new ();
-		fd = e_msgport_fd (msg->msg.reply_port);
-		if ((err = pthread_create (&id, NULL, get_hostbyaddr, msg)) == 0) {
-			d(printf("waiting for name return/cancellation in main process\n"));
-			do {
-				FD_ZERO(&rdset);
-				FD_SET(cancel_fd, &rdset);
-				FD_SET(fd, &rdset);
-				fdmax = MAX(fd, cancel_fd) + 1;
-				status = select (fdmax, &rdset, NULL, 0, NULL);
-			} while (status == -1 && errno == EINTR);
-			
-			if (status == -1 || FD_ISSET(cancel_fd, &rdset)) {
-				if (status == -1)
-					camel_exception_setv(&ex, CAMEL_EXCEPTION_SYSTEM, _("Failure in name lookup: %s"), g_strerror(errno));
-				else
-					camel_exception_setv(&ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
-
-				/* We cancel so if the thread impl is decent it causes immediate exit.
-				   We detach so we dont need to wait for it to exit if it isn't.
-				   We check the reply port incase we had a reply in the mean time, which we free later */
-				d(printf("Cancelling lookup thread and leaving it\n"));
-				msg->cancelled = 1;
-				pthread_detach(id);
-				pthread_cancel(id);
-				msg = (struct _lookup_msg *)e_msgport_get(reply_port);
-			} else {
-				struct _lookup_msg *reply = (struct _lookup_msg *)e_msgport_get(reply_port);
-
-				g_assert(reply == msg);
-				d(printf("waiting for child to exit\n"));
-				pthread_join(id, NULL);
-				d(printf("child done\n"));
-			}
-		} else {
-			camel_exception_setv(&ex, CAMEL_EXCEPTION_SYSTEM, _("Host lookup failed: cannot create thread: %s"), g_strerror(err));
-		}
+	msg->hostbufmem = g_malloc(msg->hostbuflen);
+#endif	
+	if (cs_waitinfo(cs_getaddrinfo, msg, _("Host lookup failed"), ex) == 0)
+		cs_freeinfo(msg);
+	else
+		res = NULL;
 
-		
-		e_msgport_destroy (reply_port);
+	camel_operation_end(NULL);
+
+	return res;
+}
+
+void
+camel_freeaddrinfo(struct addrinfo *host)
+{
+	freeaddrinfo(host);
+}
+
+#ifdef NEED_ADDRINFO
+static void *
+cs_getnameinfo(void *data)
+{
+	struct _addrinfo_msg *msg = data;
+	int herr;
+	struct hostent h;
+	struct sockaddr_in *sin = (struct sockaddr_in *)msg->addr;
+
+	/* FIXME: error code */
+	if (msg->addr->sa_family != AF_INET) {
+		msg->result = -1;
+		return NULL;
 	}
-	
-	camel_operation_end (NULL);
-	
-	if (!camel_exception_is_set(&ex)) {
-		if (msg->result == 0)
-			return &msg->hostbuf;
 
-		if (msg->herr == HOST_NOT_FOUND || msg->herr == NO_DATA)
-			camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM,
-					      _("Host lookup failed: host not found"));
-		else
-			camel_exception_setv (&ex, CAMEL_EXCEPTION_SYSTEM,
-					      _("Host lookup failed: unknown reason"));
+	/* FIXME: honour getnameinfo flags: do we care, not really */
+
+	while ((msg->result = e_gethostbyaddr_r((const char *)&sin->sin_addr, sizeof(sin->sin_addr), AF_INET, &h,
+						msg->hostbufmem, msg->hostbuflen, &herr)) == ERANGE) {
+		pthread_testcancel ();
+                msg->hostbuflen *= 2;
+                msg->hostbufmem = g_realloc(msg->hostbufmem, msg->hostbuflen);
 	}
+	
+	if (msg->cancelled)
+		goto cancel;
 
-	if (msg) {
-		g_free(msg->hostbufmem);
-		g_free(msg);
+	if (msg->host) {
+		g_free(msg->host);
+		if (msg->result == 0 && h.h_name && h.h_name[0]) {
+			msg->host = g_strdup(h.h_name);
+		} else {
+			unsigned char *in = (unsigned char *)&sin->sin_addr;
+			
+			/* sin_addr is always network order which is big-endian */
+			msg->host = g_strdup_printf("%u.%u.%u.%u", in[0], in[1], in[2], in[3]);
+		}
 	}
 
-	camel_exception_xfer(exout, &ex);
+	/* we never actually use this anyway */
+	if (msg->serv)
+		sprintf(msg->serv, "%d", sin->sin_port);
 
+	e_msgport_reply((EMsg *)msg);
+	return NULL;
+cancel:
+	cs_freeinfo(msg);
 	return NULL;
 }
+#else
+static void *
+cs_getnameinfo(void *data)
+{
+	struct _addrinfo_msg *msg = data;
+
+	/* there doens't appear to be a return code which says host or serv buffers are too short, lengthen them */
+	do {
+		msg->result = getnameinfo(msg->addr, msg->addrlen, msg->host, msg->hostlen, msg->serv, msg->servlen, msg->flags);
+	} while (msg->result == EAI_AGAIN);
+	
+	if (msg->cancelled)
+		cs_freeinfo(msg);
+	else
+		e_msgport_reply((EMsg *)msg);
 
-void camel_free_host(struct hostent *h)
+	return NULL;
+}
+#endif
+
+int
+camel_getnameinfo(const struct sockaddr *sa, socklen_t salen, char **host, char **serv, int flags, CamelException *ex)
 {
-	struct _lookup_msg *msg;
+	struct _addrinfo_msg *msg;
+	int result;
 
-	g_return_if_fail(h != NULL);
+	if (camel_operation_cancel_check(NULL)) {
+		camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+		return -1;
+	}
 
-	/* yeah this looks ugly but it is safe.  we passed out a reference to inside our structure, this maps it
-	   to the base structure, so we can free everything right without having to keep track of it separately */
-	msg = (struct _lookup_msg *)(((char *)h) - STRUCT_OFFSET(struct _lookup_msg, hostbuf));
+	camel_operation_start_transient(NULL, _("Resolving address"));
 
-	g_free(msg->hostbufmem);
+	msg = g_malloc0(sizeof(*msg));
+	msg->addr = sa;
+	msg->addrlen = salen;
+	if (host) {
+		msg->hostlen = NI_MAXHOST;
+		msg->host = g_malloc(msg->hostlen);
+		msg->host[0] = 0;
+	}
+	if (serv) {
+		msg->servlen = NI_MAXSERV;
+		msg->serv = g_malloc(msg->servlen);
+		msg->serv[0] = 0;
+	}
+	msg->flags = flags;
+#ifdef NEED_ADDRINFO
+	msg->hostbuflen = 1024;
+	msg->hostbufmem = g_malloc(msg->hostbuflen);
+#endif
+	cs_waitinfo(cs_getnameinfo, msg, _("Name lookup failed"), ex);
+
+	result = msg->result;
+
+	if (host)
+		*host = g_strdup(msg->host);
+	if (serv)
+		*serv = g_strdup(msg->serv);
+
+	g_free(msg->host);
+	g_free(msg->serv);
 	g_free(msg);
+
+	camel_operation_end(NULL);
+
+	return result;
 }
+
Index: camel/camel-service.h
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-service.h,v
retrieving revision 1.49
diff -u -3 -r1.49 camel-service.h
--- camel/camel-service.h	8 May 2002 21:58:37 -0000	1.49
+++ camel/camel-service.h	13 Sep 2004 10:05:53 -0000
@@ -135,14 +135,61 @@
 GList *             camel_service_query_auth_types   (CamelService *service,
 						      CamelException *ex);
 
-/* convenience functions */
-struct hostent *    camel_service_gethost            (CamelService *service,
-						      CamelException *ex);
-
-/* cancellable dns lookup */
-struct hostent *    camel_gethostbyname              (const char *name, CamelException *ex);
-struct hostent *    camel_gethostbyaddr              (const char *addr, int len, int type, CamelException *ex);
-void		    camel_free_host	    	     (struct hostent *h);
+#ifdef NEED_ADDRINFO
+/* Some of this is copied from GNU's netdb.h
+
+  Copyright (C) 1996-2002, 2003, 2004 Free Software Foundation, Inc.
+  This file is part of the GNU C Library.
+
+   The GNU C Library 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.1 of the License, or (at your option) any later version.
+*/
+struct addrinfo {
+	int ai_flags;
+	int ai_family;
+	int ai_socktype;
+	int ai_protocol;
+	size_t ai_addrlen;
+	struct sockaddr *ai_addr;
+	char *ai_canonname;
+	struct addrinfo *ai_next;
+};
+
+#define AI_CANONNAME	0x0002	/* Request for canonical name.  */
+#define AI_NUMERICHOST	0x0004	/* Don't use name resolution.  */
+
+/* Error values for `getaddrinfo' function.  */
+#define EAI_BADFLAGS	  -1	/* Invalid value for `ai_flags' field.  */
+#define EAI_NONAME	  -2	/* NAME or SERVICE is unknown.  */
+#define EAI_AGAIN	  -3	/* Temporary failure in name resolution.  */
+#define EAI_FAIL	  -4	/* Non-recoverable failure in name res.  */
+#define EAI_NODATA	  -5	/* No address associated with NAME.  */
+#define EAI_FAMILY	  -6	/* `ai_family' not supported.  */
+#define EAI_SOCKTYPE	  -7	/* `ai_socktype' not supported.  */
+#define EAI_SERVICE	  -8	/* SERVICE not supported for `ai_socktype'.  */
+#define EAI_ADDRFAMILY	  -9	/* Address family for NAME not supported.  */
+#define EAI_MEMORY	  -10	/* Memory allocation failure.  */
+#define EAI_SYSTEM	  -11	/* System error returned in `errno'.  */
+#define EAI_OVERFLOW	  -12	/* Argument buffer overflow.  */
+
+#define NI_MAXHOST      1025
+#define NI_MAXSERV      32
+
+#define NI_NUMERICHOST	1	/* Don't try to look up hostname.  */
+#define NI_NUMERICSERV 2	/* Don't convert port number to name.  */
+#define NI_NOFQDN	4	/* Only return nodename portion.  */
+#define NI_NAMEREQD	8	/* Don't return numeric addresses.  */
+#define NI_DGRAM	16	/* Look up UDP service rather than TCP.  */
+#endif
+
+/* new hostname interfaces */
+struct addrinfo *camel_getaddrinfo(const char *name, const char *service,
+				   const struct addrinfo *hints, CamelException *ex);
+void camel_freeaddrinfo(struct addrinfo *host);
+int camel_getnameinfo(const struct sockaddr *sa, socklen_t salen, char **host, char **serv,
+		      int flags, CamelException *ex);
 
 /* Standard Camel function */
 CamelType camel_service_get_type (void);
Index: camel/camel-tcp-stream-raw.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-tcp-stream-raw.c,v
retrieving revision 1.34
diff -u -3 -r1.34 camel-tcp-stream-raw.c
--- camel/camel-tcp-stream-raw.c	30 Apr 2004 18:24:21 -0000	1.34
+++ camel/camel-tcp-stream-raw.c	13 Sep 2004 10:05:54 -0000
@@ -20,7 +20,6 @@
  *
  */
 
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
@@ -48,11 +47,11 @@
 static int stream_flush  (CamelStream *stream);
 static int stream_close  (CamelStream *stream);
 
-static int stream_connect (CamelTcpStream *stream, struct hostent *host, int port);
+static int stream_connect (CamelTcpStream *stream, struct addrinfo *host);
 static int stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
 static int stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
-static CamelTcpAddress *stream_get_local_address (CamelTcpStream *stream);
-static CamelTcpAddress *stream_get_remote_address (CamelTcpStream *stream);
+static struct sockaddr *stream_get_local_address (CamelTcpStream *stream, socklen_t *len);
+static struct sockaddr *stream_get_remote_address (CamelTcpStream *stream, socklen_t *len);
 
 static void
 camel_tcp_stream_raw_class_init (CamelTcpStreamRawClass *camel_tcp_stream_raw_class)
@@ -267,13 +266,8 @@
 /* this is a 'cancellable' connect, cancellable from camel_operation_cancel etc */
 /* returns -1 & errno == EINTR if the connection was cancelled */
 static int
-socket_connect (struct hostent *h, int port)
+socket_connect(struct addrinfo *h)
 {
-#ifdef ENABLE_IPv6
-	struct sockaddr_in6 sin6;
-#endif
-	struct sockaddr_in sin;
-	struct sockaddr *saddr;
 	struct timeval tv;
 	socklen_t len;
 	int cancel_fd;
@@ -286,31 +280,17 @@
 		return -1;
 	}
 	
-	/* setup connect, we do it using a nonblocking socket so we can poll it */
-#ifdef ENABLE_IPv6
-	if (h->h_addrtype == AF_INET6) {
-		sin6.sin6_port = htons (port);
-		sin6.sin6_family = h->h_addrtype;
-		memcpy (&sin6.sin6_addr, h->h_addr, sizeof (sin6.sin6_addr));
-		saddr = (struct sockaddr *) &sin6;
-		len = sizeof (sin6);
-	} else {
-#endif
-		sin.sin_port = htons (port);
-		sin.sin_family = h->h_addrtype;
-		memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr));
-		saddr = (struct sockaddr *) &sin;
-		len = sizeof (sin);
-#ifdef ENABLE_IPv6
+	if (h->ai_socktype != SOCK_STREAM) {
+		errno = EINVAL;
+		return -1;
 	}
-#endif
-	
-	if ((fd = socket (h->h_addrtype, SOCK_STREAM, 0)) == -1)
+
+	if ((fd = socket (h->ai_family, SOCK_STREAM, 0)) == -1)
 		return -1;
 	
 	cancel_fd = camel_operation_cancel_fd (NULL);
 	if (cancel_fd == -1) {
-		if (connect (fd, saddr, len) == -1) {
+		if (connect (fd, h->ai_addr, h->ai_addrlen) == -1) {
 			errnosav = errno;
 			close (fd);
 			errno = errnosav;
@@ -325,7 +305,7 @@
 		flags = fcntl (fd, F_GETFL);
 		fcntl (fd, F_SETFL, flags | O_NONBLOCK);
 		
-		if (connect (fd, saddr, len) == 0) {
+		if (connect (fd, h->ai_addr, h->ai_addrlen) == 0) {
 			fcntl (fd, F_SETFL, flags);
 			return fd;
 		}
@@ -383,21 +363,22 @@
 }
 
 static int
-stream_connect (CamelTcpStream *stream, struct hostent *host, int port)
+stream_connect (CamelTcpStream *stream, struct addrinfo *host)
 {
 	CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
-	int fd;
 	
 	g_return_val_if_fail (host != NULL, -1);
-	
-	if ((fd = socket_connect (host, port)) == -1)
-		return -1;
-	
-	raw->sockfd = fd;
-	
-	return 0;
-}
 
+	while (host) {
+		raw->sockfd = socket_connect(host);
+		if (raw->sockfd != -1)
+			return 0;
+
+		host = host->ai_next;
+	}
+
+	return -1;
+}
 
 static int
 get_sockopt_level (const CamelSockOptData *data)
@@ -496,72 +477,42 @@
 			   sizeof (data->value));
 }
 
+static struct sockaddr *
+stream_get_local_address (CamelTcpStream *stream, socklen_t *len)
+{
 #ifdef ENABLE_IPv6
-#define MIN_SOCKADDR_BUFLEN  (sizeof (struct sockaddr_in6))
+	struct sockaddr_in6 sin;
 #else
-#define MIN_SOCKADDR_BUFLEN  (sizeof (struct sockaddr_in))
+	struct sockaddr_in sin;
 #endif
+	struct sockaddr *saddr = (struct sockaddr *)&sin;
 
-static CamelTcpAddress *
-stream_get_local_address (CamelTcpStream *stream)
-{
-	unsigned char buf[MIN_SOCKADDR_BUFLEN];
-#ifdef ENABLE_IPv6
-	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) buf;
-#endif
-	struct sockaddr_in *sin = (struct sockaddr_in *) buf;
-	struct sockaddr *saddr = (struct sockaddr *) buf;
-	gpointer address;
-	socklen_t len;
-	int family;
-	
-	len = MIN_SOCKADDR_BUFLEN;
-	
-	if (getsockname (CAMEL_TCP_STREAM_RAW (stream)->sockfd, saddr, &len) == -1)
+	*len = sizeof(sin);
+	if (getsockname (CAMEL_TCP_STREAM_RAW (stream)->sockfd, saddr, len) == -1)
 		return NULL;
-	
-	if (saddr->sa_family == AF_INET) {
-		family = CAMEL_TCP_ADDRESS_IPv4;
-		address = &sin->sin_addr;
-#ifdef ENABLE_IPv6
-	} else if (saddr->sa_family == AF_INET6) {
-		family = CAMEL_TCP_ADDRESS_IPv6;
-		address = &sin6->sin6_addr;
-#endif
-	} else
-		return NULL;
-	
-	return camel_tcp_address_new (family, sin->sin_port, len, address);
+
+	saddr = g_malloc(*len);
+	memcpy(saddr, &sin, *len);
+
+	return saddr;
 }
 
-static CamelTcpAddress *
-stream_get_remote_address (CamelTcpStream *stream)
+static struct sockaddr *
+stream_get_remote_address (CamelTcpStream *stream, socklen_t *len)
 {
-	unsigned char buf[MIN_SOCKADDR_BUFLEN];
 #ifdef ENABLE_IPv6
-	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) buf;
-#endif
-	struct sockaddr_in *sin = (struct sockaddr_in *) buf;
-	struct sockaddr *saddr = (struct sockaddr *) buf;
-	gpointer address;
-	socklen_t len;
-	int family;
-	
-	len = MIN_SOCKADDR_BUFLEN;
-	
-	if (getpeername (CAMEL_TCP_STREAM_RAW (stream)->sockfd, saddr, &len) == -1)
-		return NULL;
-	
-	if (saddr->sa_family == AF_INET) {
-		family = CAMEL_TCP_ADDRESS_IPv4;
-		address = &sin->sin_addr;
-#ifdef ENABLE_IPv6
-	} else if (saddr->sa_family == AF_INET6) {
-		family = CAMEL_TCP_ADDRESS_IPv6;
-		address = &sin6->sin6_addr;
+	struct sockaddr_in6 sin;
+#else
+	struct sockaddr_in sin;
 #endif
-	} else
+	struct sockaddr *saddr = (struct sockaddr *)&sin;
+
+	*len = sizeof(sin);
+	if (getpeername (CAMEL_TCP_STREAM_RAW (stream)->sockfd, saddr, len) == -1)
 		return NULL;
-	
-	return camel_tcp_address_new (family, sin->sin_port, len, address);
+
+	saddr = g_malloc(*len);
+	memcpy(saddr, &sin, *len);
+
+	return saddr;
 }
Index: camel/camel-tcp-stream-ssl.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-tcp-stream-ssl.c,v
retrieving revision 1.63
diff -u -3 -r1.63 camel-tcp-stream-ssl.c
--- camel/camel-tcp-stream-ssl.c	8 Sep 2004 04:02:41 -0000	1.63
+++ camel/camel-tcp-stream-ssl.c	13 Sep 2004 10:05:54 -0000
@@ -80,11 +80,11 @@
 
 static PRFileDesc *enable_ssl (CamelTcpStreamSSL *ssl, PRFileDesc *fd);
 
-static int stream_connect    (CamelTcpStream *stream, struct hostent *host, int port);
+static int stream_connect    (CamelTcpStream *stream, struct addrinfo *host);
 static int stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
 static int stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
-static CamelTcpAddress *stream_get_local_address (CamelTcpStream *stream);
-static CamelTcpAddress *stream_get_remote_address (CamelTcpStream *stream);
+static struct sockaddr *stream_get_local_address (CamelTcpStream *stream, socklen_t *len);
+static struct sockaddr *stream_get_remote_address (CamelTcpStream *stream, socklen_t *len);
 
 struct _CamelTcpStreamSSLPrivate {
 	PRFileDesc *sockfd;
@@ -1024,30 +1024,58 @@
 }
 
 static int
-stream_connect (CamelTcpStream *stream, struct hostent *host, int port)
+sockaddr_to_praddr(struct sockaddr *s, int len, PRNetAddr *addr)
+{
+	/* We assume the ip addresses are the same size - they have to be anyway.
+	   We could probably just use memcpy *shrug* */
+
+	memset(addr, 0, sizeof(*addr));
+
+	if (s->sa_family == AF_INET) {
+		struct sockaddr_in *sin = (struct sockaddr_in *)s;
+
+		if (len < sizeof(*sin))
+			return -1;
+
+		addr->inet.family = PR_AF_INET;
+		addr->inet.port = sin->sin_port;
+		memcpy(&addr->inet.ip, &sin->sin_addr, sizeof(addr->inet.ip));
+
+		return 0;
+	}
+#ifdef ENABLE_IPv6
+	else if (s->sa_family == PR_AF_INET6) {
+		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)s;
+
+		if (len < sizeof(*sin))
+			return -1;
+
+		addr->ipv6.family = PR_AF_INET6;
+		addr->ipv6.port = sin->sin6_port;
+		addr->ipv6.flowinfo = sin->sin6_flowinfo;
+		memcpy(&addr->ipv6.ip, &sin->sin6_addr, sizeof(addr->ipv6.ip));
+		addr->ipv6.scope_id = sin->sin6_scope_id;
+
+		return 0;
+	}
+#endif
+
+	return -1;
+}
+
+static int
+socket_connect(CamelTcpStream *stream, struct addrinfo *host)
 {
 	CamelTcpStreamSSL *ssl = CAMEL_TCP_STREAM_SSL (stream);
 	PRNetAddr netaddr;
 	PRFileDesc *fd, *cancel_fd;
-	
-	g_return_val_if_fail (host != NULL, -1);
-	
-	memset ((void *) &netaddr, 0, sizeof (PRNetAddr));
-#ifdef ENABLE_IPv6
-	if (host->h_addrtype == AF_INET6)
-		memcpy (&netaddr.ipv6.ip, host->h_addr, sizeof (netaddr.ipv6.ip));
-	else
-		memcpy (&netaddr.inet.ip, host->h_addr, sizeof (netaddr.inet.ip));
-#else
-	memcpy (&netaddr.inet.ip, host->h_addr, sizeof (netaddr.inet.ip));
-#endif
-	
-	if (PR_InitializeNetAddr (PR_IpAddrNull, port, &netaddr) == PR_FAILURE) {
-		set_errno (PR_GetError ());
+
+	if (sockaddr_to_praddr(host->ai_addr, host->ai_addrlen, &netaddr) != 0) {
+		errno = EINVAL;
 		return -1;
 	}
 	
-	fd = PR_OpenTCPSocket (host->h_addrtype);
+	fd = PR_OpenTCPSocket(netaddr.raw.family);
 	if (fd == NULL) {
 		set_errno (PR_GetError ());
 		return -1;
@@ -1126,6 +1154,17 @@
 	return 0;
 }
 
+static int
+stream_connect(CamelTcpStream *stream, struct addrinfo *host)
+{
+	while (host) {
+		if (socket_connect(stream, host) == 0)
+			return 0;
+		host = host->ai_next;
+	}
+
+	return -1;
+}
 
 static int
 stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data)
@@ -1157,56 +1196,61 @@
 	return 0;
 }
 
-static CamelTcpAddress *
-stream_get_local_address (CamelTcpStream *stream)
+static struct sockaddr *
+sockaddr_from_praddr(PRNetAddr *addr, socklen_t *len)
+{
+	/* We assume the ip addresses are the same size - they have to be anyway */
+
+	if (addr->raw.family == PR_AF_INET) {
+		struct sockaddr_in *sin = g_malloc0(sizeof(*sin));
+
+		sin->sin_family = AF_INET;
+		sin->sin_port = addr->inet.port;
+		memcpy(&sin->sin_addr, &addr->inet.ip, sizeof(sin->sin_addr));
+		*len = sizeof(*sin);
+
+		return (struct sockaddr *)sin;
+	}
+#ifdef ENABLE_IPv6
+	else if (addr->raw.family == PR_AF_INET6) {
+		struct sockaddr_in6 *sin = g_malloc0(sizeof(*sin));
+
+		sin->sin6_family = AF_INET6;
+		sin->sin6_port = addr->ipv6.port;
+		sin->sin6_flowinfo = addr->ipv6.flowinfo;
+		memcpy(&sin->sin6_addr, &addr->ipv6.ip, sizeof(sin->sin6_addr));
+		sin->sin6_scope_id = addr->ipv6.scope_id;
+		*len = sizeof(*sin);
+
+		return (struct sockaddr *)sin;		
+	}
+#endif
+
+	return NULL;
+}
+
+static struct sockaddr *
+stream_get_local_address(CamelTcpStream *stream, socklen_t *len)
 {
 	PRFileDesc *sockfd = CAMEL_TCP_STREAM_SSL (stream)->priv->sockfd;
-	int family, length;
-	gpointer address;
 	PRNetAddr addr;
 	
-	PR_GetSockName (sockfd, &addr);
-	
-	if (addr.inet.family == PR_AF_INET) {
-		family = CAMEL_TCP_ADDRESS_IPv4;
-		address = &addr.inet.ip;
-		length = 4;
-#ifdef ENABLE_IPv6
-	} else if (addr.inet.family == PR_AF_INET6) {
-		family = CAMEL_TCP_ADDRESS_IPv6;
-		address = &addr.ipv6.ip;
-		length = 16;
-#endif
-	} else
+	if (PR_GetSockName(sockfd, &addr) != PR_SUCCESS)
 		return NULL;
-	
-	return camel_tcp_address_new (family, addr.inet.port, length, address);
+
+	return sockaddr_from_praddr(&addr, len);
 }
 
-static CamelTcpAddress *
-stream_get_remote_address (CamelTcpStream *stream)
+static struct sockaddr *
+stream_get_remote_address (CamelTcpStream *stream, socklen_t *len)
 {
 	PRFileDesc *sockfd = CAMEL_TCP_STREAM_SSL (stream)->priv->sockfd;
-	int family, length;
-	gpointer address;
 	PRNetAddr addr;
 	
-	PR_GetPeerName (sockfd, &addr);
-	
-	if (addr.inet.family == PR_AF_INET) {
-		family = CAMEL_TCP_ADDRESS_IPv4;
-		address = &addr.inet.ip;
-		length = sizeof (addr.inet.ip);
-#ifdef ENABLE_IPv6
-	} else if (addr.inet.family == PR_AF_INET6) {
-		family = CAMEL_TCP_ADDRESS_IPv6;
-		address = &addr.ipv6.ip;
-		length = sizeof (addr.ipv6.ip);
-#endif
-	} else
+	if (PR_GetPeerName(sockfd, &addr) != PR_SUCCESS)
 		return NULL;
-	
-	return camel_tcp_address_new (family, addr.inet.port, length, address);
+
+	return sockaddr_from_praddr(&addr, len);
 }
 
 #endif /* HAVE_NSS */
Index: camel/camel-tcp-stream.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-tcp-stream.c,v
retrieving revision 1.12
diff -u -3 -r1.12 camel-tcp-stream.c
--- camel/camel-tcp-stream.c	31 Jul 2002 01:03:10 -0000	1.12
+++ camel/camel-tcp-stream.c	13 Sep 2004 10:05:54 -0000
@@ -35,12 +35,11 @@
 /* Returns the class for a CamelTcpStream */
 #define CTS_CLASS(so) CAMEL_TCP_STREAM_CLASS (CAMEL_OBJECT_GET_CLASS(so))
 
-static int tcp_connect    (CamelTcpStream *stream, struct hostent *host, int port);
+static int tcp_connect    (CamelTcpStream *stream, struct addrinfo *host);
 static int tcp_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
 static int tcp_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
-static CamelTcpAddress *tcp_get_local_address (CamelTcpStream *stream);
-static CamelTcpAddress *tcp_get_remote_address (CamelTcpStream *stream);
-
+static struct sockaddr *tcp_get_local_address (CamelTcpStream *stream, socklen_t *len);
+static struct sockaddr *tcp_get_remote_address (CamelTcpStream *stream, socklen_t *len);
 
 static void
 camel_tcp_stream_class_init (CamelTcpStreamClass *camel_tcp_stream_class)
@@ -84,7 +83,7 @@
 
 
 static int
-tcp_connect (CamelTcpStream *stream, struct hostent *host, int port)
+tcp_connect (CamelTcpStream *stream, struct addrinfo *host)
 {
 	w(g_warning ("CamelTcpStream::connect called on default implementation"));
 	return -1;
@@ -93,22 +92,21 @@
 /**
  * camel_tcp_stream_connect:
  * @stream: a CamelTcpStream object.
- * @host: a hostent value
- * @port: port
+ * @host: A linked list of addrinfo structures to try to connect, in
+ * the order of most likely to least likely to work.
  *
  * Create a socket and connect based upon the data provided.
  *
  * Return value: zero on success or -1 on fail.
  **/
 int
-camel_tcp_stream_connect (CamelTcpStream *stream, struct hostent *host, int port)
+camel_tcp_stream_connect (CamelTcpStream *stream, struct addrinfo *host)
 {
 	g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), -1);
 	
-	return CTS_CLASS (stream)->connect (stream, host, port);
+	return CTS_CLASS (stream)->connect (stream, host);
 }
 
-
 static int
 tcp_getsockopt (CamelTcpStream *stream, CamelSockOptData *data)
 {
@@ -116,7 +114,6 @@
 	return -1;
 }
 
-
 /**
  * camel_tcp_stream_getsockopt:
  * @stream: tcp stream object
@@ -134,7 +131,6 @@
 	return CTS_CLASS (stream)->getsockopt (stream, data);
 }
 
-
 static int
 tcp_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data)
 {
@@ -142,7 +138,6 @@
 	return -1;
 }
 
-
 /**
  * camel_tcp_stream_setsockopt:
  * @stream: tcp stream object
@@ -160,9 +155,8 @@
 	return CTS_CLASS (stream)->setsockopt (stream, data);
 }
 
-
-static CamelTcpAddress *
-tcp_get_local_address (CamelTcpStream *stream)
+static struct sockaddr *
+tcp_get_local_address (CamelTcpStream *stream, socklen_t *len)
 {
 	w(g_warning ("CamelTcpStream::get_local_address called on default implementation"));
 	return NULL;
@@ -171,23 +165,24 @@
 /**
  * camel_tcp_stream_get_local_address:
  * @stream: tcp stream object
+ * @len: Pointer to address length which must be supplied.
  *
  * Get the local address of @stream.
  *
  * Return value: the stream's local address (which must be freed with
- * camel_tcp_address_free()) if the stream is connected, or %NULL if not.
+ * g_free()) if the stream is connected, or %NULL if not.
  **/
-CamelTcpAddress *
-camel_tcp_stream_get_local_address (CamelTcpStream *stream)
+struct sockaddr *
+camel_tcp_stream_get_local_address (CamelTcpStream *stream, socklen_t *len)
 {
 	g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), NULL);
+	g_return_val_if_fail(len != NULL, NULL);
 	
-	return CTS_CLASS (stream)->get_local_address (stream);
+	return CTS_CLASS (stream)->get_local_address (stream, len);
 }
 
-
-static CamelTcpAddress *
-tcp_get_remote_address (CamelTcpStream *stream)
+static struct sockaddr *
+tcp_get_remote_address (CamelTcpStream *stream, socklen_t *len)
 {
 	w(g_warning ("CamelTcpStream::get_remote_address called on default implementation"));
 	return NULL;
@@ -196,54 +191,18 @@
 /**
  * camel_tcp_stream_get_remote_address:
  * @stream: tcp stream object
+ * @len: Pointer to address length, which must be supplied.
  *
  * Get the remote address of @stream.
  *
  * Return value: the stream's remote address (which must be freed with
- * camel_tcp_address_free()) if the stream is connected, or %NULL if not.
+ * g_free()) if the stream is connected, or %NULL if not.
  **/
-CamelTcpAddress *
-camel_tcp_stream_get_remote_address (CamelTcpStream *stream)
+struct sockaddr *
+camel_tcp_stream_get_remote_address (CamelTcpStream *stream, socklen_t *len)
 {
 	g_return_val_if_fail (CAMEL_IS_TCP_STREAM (stream), NULL);
-	
-	return CTS_CLASS (stream)->get_remote_address (stream);
-}
+	g_return_val_if_fail(len != NULL, NULL);
 
-
-/**
- * camel_tcp_address_new:
- * @family: the address family
- * @port: the port number (in network byte order)
- * @length: the length of @address
- * @address: the address data (family dependent, in network byte order)
- *
- * Return value: a new CamelTcpAddress.
- **/
-CamelTcpAddress *
-camel_tcp_address_new (CamelTcpAddressFamily family, gushort port,
-		       gushort length, gpointer address)
-{
-	CamelTcpAddress *addr;
-	
-	addr = g_malloc (sizeof (CamelTcpAddress) + length - 1);
-	addr->family = family;
-	addr->port = port;
-	addr->length = length;
-	memcpy (&addr->address, address, length);
-	
-	return addr;
-}
-
-
-/**
- * camel_tcp_address_free:
- * @address: the address
- *
- * Frees @address.
- **/
-void
-camel_tcp_address_free (CamelTcpAddress *address)
-{
-	g_free (address);
+	return CTS_CLASS (stream)->get_remote_address (stream, len);
 }
Index: camel/camel-tcp-stream.h
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-tcp-stream.h,v
retrieving revision 1.10
diff -u -3 -r1.10 camel-tcp-stream.h
--- camel/camel-tcp-stream.h	31 Jul 2002 01:03:10 -0000	1.10
+++ camel/camel-tcp-stream.h	13 Sep 2004 10:05:54 -0000
@@ -88,18 +88,6 @@
 	} value;
 } CamelSockOptData;
 
-typedef enum {
-	CAMEL_TCP_ADDRESS_IPv4,
-	CAMEL_TCP_ADDRESS_IPv6
-} CamelTcpAddressFamily;
-
-typedef struct {
-	CamelTcpAddressFamily family;
-	gushort port, length;
-	guint8 address[1];
-} CamelTcpAddress;
-
-
 struct _CamelTcpStream {
 	CamelStream parent_object;
 	
@@ -109,29 +97,24 @@
 	CamelStreamClass parent_class;
 
 	/* Virtual methods */
-	int (*connect)    (CamelTcpStream *stream, struct hostent *host, int port);
+	int (*connect)    (CamelTcpStream *stream, struct addrinfo *host);
 	int (*getsockopt) (CamelTcpStream *stream, CamelSockOptData *data);
 	int (*setsockopt) (CamelTcpStream *stream, const CamelSockOptData *data);
 	
-	CamelTcpAddress * (*get_local_address)  (CamelTcpStream *stream);
-	CamelTcpAddress * (*get_remote_address) (CamelTcpStream *stream);
+	struct sockaddr * (*get_local_address)  (CamelTcpStream *stream, socklen_t *len);
+	struct sockaddr * (*get_remote_address) (CamelTcpStream *stream, socklen_t *len);
 } CamelTcpStreamClass;
 
 /* Standard Camel function */
 CamelType camel_tcp_stream_get_type (void);
 
 /* public methods */
-int         camel_tcp_stream_connect    (CamelTcpStream *stream, struct hostent *host, int port);
+int         camel_tcp_stream_connect    (CamelTcpStream *stream, struct addrinfo *host);
 int         camel_tcp_stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
 int         camel_tcp_stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
 
-CamelTcpAddress *camel_tcp_stream_get_local_address  (CamelTcpStream *stream);
-CamelTcpAddress *camel_tcp_stream_get_remote_address (CamelTcpStream *stream);
-
-CamelTcpAddress *camel_tcp_address_new  (CamelTcpAddressFamily family,
-					 gushort port, gushort length,
-					 gpointer address);
-void             camel_tcp_address_free (CamelTcpAddress *address);
+struct sockaddr *camel_tcp_stream_get_local_address  (CamelTcpStream *stream, socklen_t *len);
+struct sockaddr *camel_tcp_stream_get_remote_address (CamelTcpStream *stream, socklen_t *len);
 
 #ifdef __cplusplus
 }
Index: camel/providers/imap/camel-imap-store.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/providers/imap/camel-imap-store.c,v
retrieving revision 1.300
diff -u -3 -r1.300 camel-imap-store.c
--- camel/providers/imap/camel-imap-store.c	24 Aug 2004 14:02:22 -0000	1.300
+++ camel/providers/imap/camel-imap-store.c	13 Sep 2004 10:05:56 -0000
@@ -521,51 +521,60 @@
 	CamelStream *tcp_stream;
 	CamelSockOptData sockopt;
 	gboolean force_imap4 = FALSE;
-	struct hostent *h;
 	int clean_quit;
-	int port, ret;
+	int ret;
 	char *buf;
-	
-	if (!(h = camel_service_gethost (service, ex)))
-		return FALSE;
-	
-	port = service->url->port ? service->url->port : 143;
+	struct addrinfo *ai, hints = { 0 };
+	char *serv;
+
+	/* FIXME: this connect stuff is duplicated everywhere */
+
+	if (service->url->port) {
+		serv = g_alloca(16);
+		sprintf(serv, "%d", service->url->port);
+	} else
+		serv = "imap";
 	
 	if (ssl_mode != USE_SSL_NEVER) {
 #ifdef HAVE_SSL
 		if (try_starttls) {
 			tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS);
 		} else {
-			port = service->url->port ? service->url->port : 993;
+			if (service->url->port == 0)
+				serv = "imaps";
 			tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
 		}
 #else
-		if (!try_starttls)
-			port = service->url->port ? service->url->port : 993;
+		if (!try_starttls && service->url->port == 0)
+			serv = "imaps";
 		
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-				      _("Could not connect to %s (port %d): %s"),
-				      service->url->host, port,
+				      _("Could not connect to %s (port %s): %s"),
+				      service->url->host, serv,
 				      _("SSL unavailable"));
-		
-		camel_free_host (h);
-		
 		return FALSE;
 #endif /* HAVE_SSL */
 	} else {
 		tcp_stream = camel_tcp_stream_raw_new ();
 	}
+
+	hints.ai_socktype = SOCK_STREAM;
+	ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
+	if (ai == NULL) {
+		camel_object_unref(tcp_stream);
+		return FALSE;
+	}
 	
-	ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port);
-	camel_free_host (h);
+	ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai);
+	camel_freeaddrinfo(ai);
 	if (ret == -1) {
 		if (errno == EINTR)
 			camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
 					     _("Connection cancelled"));
 		else
 			camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-					      _("Could not connect to %s (port %d): %s"),
-					      service->url->host, port, g_strerror (errno));
+					      _("Could not connect to %s (port %s): %s"),
+					      service->url->host, serv, g_strerror (errno));
 		
 		camel_object_unref (tcp_stream);
 		
Index: camel/providers/imapp/camel-imapp-store.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/providers/imapp/camel-imapp-store.c,v
retrieving revision 1.10
diff -u -3 -r1.10 camel-imapp-store.c
--- camel/providers/imapp/camel-imapp-store.c	26 May 2004 04:24:01 -0000	1.10
+++ camel/providers/imapp/camel-imapp-store.c	13 Sep 2004 10:05:56 -0000
@@ -189,29 +189,32 @@
 	CamelIMAPPStore *store = CAMEL_IMAPP_STORE (service);
 	CamelStream * volatile tcp_stream = NULL;
 	CamelIMAPPStream * volatile imap_stream = NULL;
-	struct hostent *h = NULL;
-	int ret, port;
+	int ret;
 	CamelException *ex;
 
 	ex = camel_exception_new();
 	CAMEL_TRY {
+		char *serv;
+		struct addrinfo *ai, hints = { 0 };
+
 		/* parent class connect initialization */
 		CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex);
 		if (ex->id)
 			camel_exception_throw_ex(ex);
 
-		h = camel_service_gethost(service, ex);
-		if (ex->id)
-			camel_exception_throw_ex(ex);
-		
-		port = service->url->port ? service->url->port : IMAP_PORT;
-		
+		if (service->url->port) {
+			serv = g_alloca(16);
+			sprintf(serv, "%d", service->url->port);
+		} else
+			serv = "imap";
+
 #ifdef HAVE_SSL	
 		if (camel_url_get_param (service->url, "use_ssl")) {
 			if (try_starttls)
 				tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS);
 			else {
-				port = service->url->port ? service->url->port : 995;
+				if (service->url->port == 0)
+					serv = "imaps";
 				tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
 			}
 		} else {
@@ -220,16 +223,21 @@
 #else	
 		tcp_stream = camel_tcp_stream_raw_new ();
 #endif /* HAVE_SSL */
-		
-		ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port);
-		camel_free_host (h);
+
+		hints.ai_socktype = SOCK_STREAM;
+		ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
+		if (ex->id)
+			camel_exception_throw_ex(ex);
+	
+		ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai);
+		camel_freeaddrinfo(ai);
 		if (ret == -1) {
 			if (errno == EINTR)
 				camel_exception_throw(CAMEL_EXCEPTION_USER_CANCEL, _("Connection cancelled"));
 			else
 				camel_exception_throw(CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-						      _("Could not connect to %s (port %d): %s"),
-						      service->url->host, port, strerror(errno));
+						      _("Could not connect to %s (port %s): %s"),
+						      service->url->host, serv, strerror(errno));
 		}
 
 		imap_stream = (CamelIMAPPStream *)camel_imapp_stream_new(tcp_stream);
Index: camel/providers/nntp/camel-nntp-store.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/providers/nntp/camel-nntp-store.c,v
retrieving revision 1.66
diff -u -3 -r1.66 camel-nntp-store.c
--- camel/providers/nntp/camel-nntp-store.c	30 Aug 2004 04:21:22 -0000	1.66
+++ camel/providers/nntp/camel-nntp-store.c	13 Sep 2004 10:05:57 -0000
@@ -162,9 +162,10 @@
 	gboolean retval = FALSE;
 	unsigned char *buf;
 	unsigned int len;
-	struct hostent *h;
-	int port, ret;
+	int ret;
 	char *path;
+	struct addrinfo *ai, hints = { 0 };
+	char *serv;
 	
 	CAMEL_NNTP_STORE_LOCK(store, command_lock);
 
@@ -181,15 +182,17 @@
 		camel_data_cache_set_expire_age (store->cache, 60*60*24*14);
 		camel_data_cache_set_expire_access (store->cache, 60*60*24*5);
 	}
-	
-	if (!(h = camel_service_gethost (service, ex)))
-		goto fail;
-	
-	port = service->url->port ? service->url->port : NNTP_PORT;
+
+	if (service->url->port) {
+		serv = g_alloca(16);
+		sprintf(serv, "%d", service->url->port);
+	} else
+		serv = "nntp";
 	
 #ifdef HAVE_SSL
 	if (ssl_mode != USE_SSL_NEVER) {
-		port = service->url->port ? service->url->port : NNTPS_PORT;
+		if (service->url->port == 0)
+			serv = "nntps";
 		tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, CAMEL_TCP_STREAM_SSL_ENABLE_SSL2 | CAMEL_TCP_STREAM_SSL_ENABLE_SSL3);
 	} else {
 		tcp_stream = camel_tcp_stream_raw_new ();
@@ -197,17 +200,24 @@
 #else
 	tcp_stream = camel_tcp_stream_raw_new ();
 #endif /* HAVE_SSL */
+
+	hints.ai_socktype = SOCK_STREAM;
+	ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
+	if (ai == NULL) {
+		camel_object_unref(tcp_stream);
+		goto fail;
+	}
 	
-	ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port);
-	camel_free_host (h);
+	ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai);
+	camel_freeaddrinfo(ai);
 	if (ret == -1) {
 		if (errno == EINTR)
 			camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
 					     _("Connection cancelled"));
 		else
 			camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-					      _("Could not connect to %s (port %d): %s"),
-					      service->url->host, port, g_strerror (errno));
+					      _("Could not connect to %s (port %s): %s"),
+					      service->url->host, serv, g_strerror (errno));
 		
 		camel_object_unref (tcp_stream);
 		
Index: camel/providers/pop3/camel-pop3-store.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/providers/pop3/camel-pop3-store.c,v
retrieving revision 1.106
diff -u -3 -r1.106 camel-pop3-store.c
--- camel/providers/pop3/camel-pop3-store.c	24 Jun 2004 21:49:41 -0000	1.106
+++ camel/providers/pop3/camel-pop3-store.c	13 Sep 2004 10:05:57 -0000
@@ -148,52 +148,59 @@
 	CamelPOP3Store *store = CAMEL_POP3_STORE (service);
 	CamelStream *tcp_stream;
 	CamelPOP3Command *pc;
-	struct hostent *h;
 	guint32 flags = 0;
 	int clean_quit;
-	int ret, port;
-	
-	h = camel_service_gethost (service, ex);
-	if (!h)
-		return FALSE;
-	
-	port = service->url->port ? service->url->port : 110;
-	
+	int ret;
+	struct addrinfo *ai, hints = { 0 };
+	char *serv;
+
+	if (service->url->port) {
+		serv = g_alloca(16);
+		sprintf(serv, "%d", service->url->port);
+	} else
+		serv = "pop3";
+		
 	if (ssl_mode != USE_SSL_NEVER) {
 #ifdef HAVE_SSL
 		if (try_starttls) {
 			tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS);
 		} else {
-			port = service->url->port ? service->url->port : 995;
+			if (service->url->port == 0)
+				serv = "pop3s";
 			tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
 		}
 #else
-		if (!try_starttls)
-			port = service->url->port ? service->url->port : 995;
+		if (!try_starttls && service->url->port == 0)
+			serv = "pop3s";
 		
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-				      _("Could not connect to %s (port %d): %s"),
-				      service->url->host, port,
+				      _("Could not connect to %s (port %s): %s"),
+				      service->url->host, serv,
 				      _("SSL unavailable"));
 		
-		camel_free_host (h);
-		
 		return FALSE;
 #endif /* HAVE_SSL */
 	} else {
 		tcp_stream = camel_tcp_stream_raw_new ();
 	}
+
+	hints.ai_socktype = SOCK_STREAM;
+	ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
+	if (ai == NULL) {
+		camel_object_unref(tcp_stream);
+		return FALSE;
+	}
 	
-	ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port);
-	camel_free_host (h);
+	ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai);
+	camel_freeaddrinfo(ai);
 	if (ret == -1) {
 		if (errno == EINTR)
 			camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
 					     _("Connection cancelled"));
 		else
 			camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-					      _("Could not connect to POP server %s (port %d): %s"),
-					      service->url->host, port, g_strerror (errno));
+					      _("Could not connect to POP server %s (port %s): %s"),
+					      service->url->host, serv, g_strerror (errno));
 		
 		camel_object_unref (tcp_stream);
 		
@@ -211,8 +218,8 @@
 	
 	if (!(store->engine = camel_pop3_engine_new (tcp_stream, flags))) {
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-				      _("Failed to read a valid greeting from POP server %s (port %d)"),
-				      service->url->host, port);
+				      _("Failed to read a valid greeting from POP server %s (port %s)"),
+				      service->url->host, serv);
 		return FALSE;
 	}
 	
Index: camel/providers/smtp/camel-smtp-transport.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/providers/smtp/camel-smtp-transport.c,v
retrieving revision 1.157
diff -u -3 -r1.157 camel-smtp-transport.c
--- camel/providers/smtp/camel-smtp-transport.c	14 Jun 2004 02:46:03 -0000	1.157
+++ camel/providers/smtp/camel-smtp-transport.c	13 Sep 2004 10:05:58 -0000
@@ -237,53 +237,60 @@
 	CamelSmtpTransport *transport = CAMEL_SMTP_TRANSPORT (service);
 	CamelStream *tcp_stream;
 	char *respbuf = NULL;
-	struct hostent *h;
-	int port, ret;
+	int ret;
+	struct addrinfo *ai, hints = { 0 };
+	char *serv;
 	
 	if (!CAMEL_SERVICE_CLASS (parent_class)->connect (service, ex))
 		return FALSE;
 	
-	h = camel_service_gethost (service, ex);
-	if (!h)
-		return FALSE;
-	
 	/* set some smtp transport defaults */
 	transport->flags &= CAMEL_SMTP_TRANSPORT_USE_SSL; /* reset all but ssl flags */
 	transport->authtypes = NULL;
-	
-	port = service->url->port ? service->url->port : SMTP_PORT;
+
+	if (service->url->port) {
+		serv = g_alloca(16);
+		sprintf(serv, "%d", service->url->port);
+	} else
+		serv = "smtp";
 	
 	if (transport->flags & CAMEL_SMTP_TRANSPORT_USE_SSL) {
 #ifdef HAVE_SSL
 		if (try_starttls) {
 			tcp_stream = camel_tcp_stream_ssl_new_raw (service->session, service->url->host, STARTTLS_FLAGS);
 		} else {
-			port = service->url->port ? service->url->port : 465;
+			if (service->url->port == 0)
+				serv = "smtps";
 			tcp_stream = camel_tcp_stream_ssl_new (service->session, service->url->host, SSL_PORT_FLAGS);
 		}
 #else
-		if (!try_starttls)
-			port = service->url->port ? service->url->port : 465;
+		if (!try_starttls && service->url->port == 0)
+			serv = "smtps";
 		
 		camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-				      _("Could not connect to %s (port %d): %s"),
-				      service->url->host, port,
+				      _("Could not connect to %s (port %s): %s"),
+				      service->url->host, serv,
 				      _("SSL unavailable"));
-		
-		camel_free_host (h);
-		
+
 		return FALSE;
 #endif /* HAVE_SSL */
 	} else {
 		tcp_stream = camel_tcp_stream_raw_new ();
 	}
+
+	hints.ai_socktype = SOCK_STREAM;
+	ai = camel_getaddrinfo(service->url->host, serv, &hints, ex);
+	if (ai == NULL) {
+		camel_object_unref(tcp_stream);
+		return FALSE;
+	}
 	
-	ret = camel_tcp_stream_connect (CAMEL_TCP_STREAM (tcp_stream), h, port);
-	camel_free_host (h);
+	ret = camel_tcp_stream_connect(CAMEL_TCP_STREAM(tcp_stream), ai);
+	camel_freeaddrinfo(ai);
 	if (ret == -1) {
 		camel_exception_setv (ex, errno == EINTR ? CAMEL_EXCEPTION_USER_CANCEL : CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-				      _("Could not connect to %s (port %d): %s"),
-				      service->url->host, port,
+				      _("Could not connect to %s (port %s): %s"),
+				      service->url->host, serv,
 				      g_strerror (errno));
 		
 		camel_object_unref (tcp_stream);
@@ -294,7 +301,7 @@
 	transport->connected = TRUE;
 	
 	/* get the localaddr - needed later by smtp_helo */
-	transport->localaddr = camel_tcp_stream_get_local_address (CAMEL_TCP_STREAM (tcp_stream));
+	transport->localaddr = camel_tcp_stream_get_local_address (CAMEL_TCP_STREAM (tcp_stream), &transport->localaddrlen);
 	
 	transport->ostream = tcp_stream;
 	transport->istream = camel_stream_buffer_new (tcp_stream, CAMEL_STREAM_BUFFER_READ);
@@ -580,7 +587,7 @@
 		transport->ostream = NULL;
 	}
 	
-	camel_tcp_address_free (transport->localaddr);
+	g_free(transport->localaddr);
 	transport->localaddr = NULL;
 	
 	transport->connected = FALSE;
@@ -865,10 +872,7 @@
 {
 	/* say hello to the server */
 	char *name = NULL, *cmdbuf = NULL, *respbuf = NULL;
-	struct hostent *host;
-	CamelException err;
 	const char *token;
-	int af;
 	
 	/* these are flags that we set, so unset them in case we
 	   are being called a second time (ie, after a STARTTLS) */
@@ -883,42 +887,10 @@
 	}
 	
 	camel_operation_start_transient (NULL, _("SMTP Greeting"));
-	
-	/* get the local host name */
-	camel_exception_init (&err);
-#ifdef ENABLE_IPv6
-	af = transport->localaddr->family == CAMEL_TCP_ADDRESS_IPv6 ? AF_INET6 : AF_INET;
-#else
-	af = AF_INET;
-#endif
-	host = camel_gethostbyaddr ((char *) &transport->localaddr->address,
-				    transport->localaddr->length, af, &err);
-	
-	camel_exception_clear (&err);
-	
-	if (host && host->h_name && *host->h_name) {
-		name = g_strdup (host->h_name);
-	} else {
-#ifdef ENABLE_IPv6
-		char ip[MAXHOSTNAMELEN + 1];
-		const char *proto;
-		
-		proto = transport->localaddr->family == CAMEL_TCP_ADDRESS_IPv6 ? "IPv6:" : "";
-		name = g_strdup_printf ("[%s%s]", proto, inet_ntop (af, transport->localaddr->address, ip, MAXHOSTNAMELEN));
-#else
-		/* We *could* use inet_ntoa() here, but it's probably
-		   not worth it since we would have to worry about
-		   some systems not having inet_ntoa() */
-		name = g_strdup_printf ("[%d.%d.%d.%d]",
-					transport->localaddr->address[0],
-					transport->localaddr->address[1],
-					transport->localaddr->address[2],
-					transport->localaddr->address[3]);
-#endif
-	}
-	
-	if (host)
-		camel_free_host (host);
+
+	/* this can't really fail with the flags we're using, it should fallback to numerical */
+	if (camel_getnameinfo(transport->localaddr, transport->localaddrlen, &name, NULL, 0, NULL) != 0)
+		name = g_strdup("localhost.localdomain");
 	
 	/* hiya server! how are you today? */
 	if (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP)
Index: camel/providers/smtp/camel-smtp-transport.h
===================================================================
RCS file: /cvs/gnome/evolution/camel/providers/smtp/camel-smtp-transport.h,v
retrieving revision 1.17
diff -u -3 -r1.17 camel-smtp-transport.h
--- camel/providers/smtp/camel-smtp-transport.h	7 Oct 2002 18:13:53 -0000	1.17
+++ camel/providers/smtp/camel-smtp-transport.h	13 Sep 2004 10:05:58 -0000
@@ -22,17 +22,14 @@
  * USA
  */
 
-
 #ifndef CAMEL_SMTP_TRANSPORT_H
 #define CAMEL_SMTP_TRANSPORT_H 1
 
-
 #ifdef __cplusplus
 extern "C" {
 #pragma }
 #endif /* __cplusplus */
 
-
 #include "camel-transport.h"
 #include "camel-tcp-stream.h"
 
@@ -41,7 +38,6 @@
 #define CAMEL_SMTP_TRANSPORT_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_SMTP_TRANSPORT_TYPE, CamelSmtpTransportClass))
 #define CAMEL_IS_SMTP_TRANSPORT(o)    (CAMEL_CHECK_TYPE((o), CAMEL_SMTP_TRANSPORT_TYPE))
 
-
 #define CAMEL_SMTP_TRANSPORT_IS_ESMTP               (1 << 0)
 #define CAMEL_SMTP_TRANSPORT_8BITMIME               (1 << 1)
 #define CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES    (1 << 2)
@@ -63,20 +59,17 @@
 	guint32 flags;
 	
 	gboolean connected;
-	CamelTcpAddress *localaddr;
+	struct sockaddr *localaddr;
+	socklen_t localaddrlen;
 	
 	GHashTable *authtypes;
-	
 } CamelSmtpTransport;
 
-
-
 typedef struct {
 	CamelTransportClass parent_class;
 
 } CamelSmtpTransportClass;
 
-
 /* Standard Camel function */
 CamelType camel_smtp_transport_get_type (void);
 
@@ -85,5 +78,3 @@
 #endif /* __cplusplus */
 
 #endif /* CAMEL_SMTP_TRANSPORT_H */
-
-


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]