private: Silence compiler warnings in generated source files.
[platform/upstream/evolution-data-server.git] / camel / camel-net-utils.c
index a4d8159..5165dc7 100644 (file)
@@ -1,23 +1,23 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
  * Authors: Michael Zucchi <notzed@ximian.com>
- *         Jeffrey Stedfast <fejj@ximian.com>
+ *         Jeffrey Stedfast <fejj@ximian.com>
  *         Chris Toshok <toshok@ximian.com>
  *
- * Copyright (C) 2004 Ximian Inc.
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
- * This program is free software; you can redistribute it and/or 
- * modify it under the terms of version 2 of the GNU General Public 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
  * License as published by the Free Software Foundation.
  *
  * 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 General Public License for more details.
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
+ * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
  * USA
  */
 
 #include <config.h>
 #endif
 
-#include <sys/poll.h>
-#include <pthread.h>
-#include <stdio.h>
 #include <errno.h>
+#include <stdio.h>
 
-#include <glib.h>
+#include <glib/gi18n-lib.h>
 
-#include "camel-i18n.h"
-#include "camel-operation.h"
-#include "camel-exception.h"
+#include "camel-msgport.h"
 #include "camel-net-utils.h"
-
-#include "libedataserver/e-msgport.h"
+#ifdef G_OS_WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#ifdef HAVE_WSPIAPI_H
+#include <wspiapi.h>
+#endif
+#endif
+#include "camel-object.h"
+#include "camel-operation.h"
 
 #define d(x)
 
-/* gethostbyname emulation code for emulating getaddrinfo code ...
+/* These are GNU extensions */
+#ifndef NI_MAXHOST
+#define NI_MAXHOST     1025
+#endif
+#ifndef NI_MAXSERV
+#define NI_MAXSERV     32
+#endif
+
+#ifdef G_OS_WIN32
+
+typedef gshort in_port_t;
+
+#undef gai_strerror
+#define gai_strerror my_gai_strerror
 
-This should probably go away */
+/* gai_strerror() is implemented as an inline function in Microsoft's
+ * SDK, but mingw lacks that. So implement here. The EAI_* errors can
+ * be handled with the normal FormatMessage() API,
+ * i.e. g_win32_error_message().
+ */
+
+static const gchar *
+gai_strerror (gint error_code)
+{
+       gchar *msg = g_win32_error_message (error_code);
+       GQuark quark = g_quark_from_string (msg);
+       const gchar *retval = g_quark_to_string (quark);
+
+       g_free (msg);
+
+       return retval;
+}
+
+#endif
+
+/* gethostbyname emulation code for emulating getaddrinfo code ...
+ *
+ * This should probably go away */
 
 #ifdef NEED_ADDRINFO
 
@@ -51,14 +89,14 @@ This should probably go away */
 G_LOCK_DEFINE_STATIC (gethost_mutex);
 #endif
 
-#define ALIGN(x) (((x) + (sizeof (char *) - 1)) & ~(sizeof (char *) - 1))
+#define ALIGN(x) (((x) + (sizeof (gchar *) - 1)) & ~(sizeof (gchar *) - 1))
 
 #define GETHOST_PROCESS(h, host, buf, buflen, herr) G_STMT_START {     \
-       int num_aliases = 0, num_addrs = 0;                            \
-       int req_length;                                                \
-       char *p;                                                       \
-       int i;                                                         \
-                                                                      \
+       gint num_aliases = 0, num_addrs = 0;                            \
+       gint req_length;                                                \
+       gchar *p;                                                       \
+       gint i;                                                         \
+                                                                      \
        /* check to make sure we have enough room in our buffer */     \
        req_length = 0;                                                \
        if (h->h_aliases) {                                            \
@@ -66,45 +104,45 @@ G_LOCK_DEFINE_STATIC (gethost_mutex);
                        req_length += strlen (h->h_aliases[i]) + 1;    \
                num_aliases = i;                                       \
        }                                                              \
-                                                                      \
+                                                                      \
        if (h->h_addr_list) {                                          \
                for (i = 0; h->h_addr_list[i]; i++)                    \
                        req_length += h->h_length;                     \
                num_addrs = i;                                         \
        }                                                              \
-                                                                      \
-       req_length += sizeof (char *) * (num_aliases + 1);             \
-       req_length += sizeof (char *) * (num_addrs + 1);               \
+                                                                      \
+       req_length += sizeof (gchar *) * (num_aliases + 1);             \
+       req_length += sizeof (gchar *) * (num_addrs + 1);               \
        req_length += strlen (h->h_name) + 1;                          \
-                                                                      \
+                                                                      \
        if (buflen < req_length) {                                     \
                *herr = ERANGE;                                        \
                G_UNLOCK (gethost_mutex);                              \
                return ERANGE;                                         \
        }                                                              \
-                                                                      \
+                                                                      \
        /* we store the alias/addr pointers in the buffer */           \
         /* their addresses here. */                                    \
        p = buf;                                                       \
        if (num_aliases) {                                             \
-               host->h_aliases = (char **) p;                         \
-               p += sizeof (char *) * (num_aliases + 1);              \
+               host->h_aliases = (gchar **) p;                         \
+               p += sizeof (gchar *) * (num_aliases + 1);              \
        } else                                                         \
                host->h_aliases = NULL;                                \
                                                                        \
        if (num_addrs) {                                               \
-               host->h_addr_list = (char **) p;                       \
-               p += sizeof (char *) * (num_addrs + 1);                \
+               host->h_addr_list = (gchar **) p;                       \
+               p += sizeof (gchar *) * (num_addrs + 1);                \
        } else                                                         \
                host->h_addr_list = NULL;                              \
-                                                                      \
+                                                                      \
        /* copy the host name into the buffer */                       \
        host->h_name = p;                                              \
        strcpy (p, h->h_name);                                         \
        p += strlen (h->h_name) + 1;                                   \
        host->h_addrtype = h->h_addrtype;                              \
        host->h_length = h->h_length;                                  \
-                                                                      \
+                                                                      \
        /* copy the aliases/addresses into the buffer */               \
         /* and assign pointers into the hostent */                     \
        *p = 0;                                                        \
@@ -116,7 +154,7 @@ G_LOCK_DEFINE_STATIC (gethost_mutex);
                }                                                      \
                host->h_aliases[num_aliases] = NULL;                   \
        }                                                              \
-                                                                      \
+                                                                      \
        if (num_addrs) {                                               \
                for (i = 0; i < num_addrs; i++) {                      \
                        memcpy (p, h->h_addr_list[i], h->h_length);    \
@@ -127,13 +165,12 @@ G_LOCK_DEFINE_STATIC (gethost_mutex);
        }                                                              \
 } G_STMT_END
 
-
 #ifdef ENABLE_IPv6
 /* some helpful utils for IPv6 lookups */
-#define IPv6_BUFLEN_MIN  (sizeof (char *) * 3)
+#define IPv6_BUFLEN_MIN  (sizeof (gchar *) * 3)
 
-static int
-ai_to_herr (int error)
+static gint
+ai_to_herr (gint error)
 {
        switch (error) {
        case EAI_NONAME:
@@ -166,15 +203,18 @@ ai_to_herr (int error)
 
 #endif /* ENABLE_IPv6 */
 
-static int
-camel_gethostbyname_r (const char *name, struct hostent *host,
-                      char *buf, size_t buflen, int *herr)
+static gint
+camel_gethostbyname_r (const gchar *name,
+                       struct hostent *host,
+                       gchar *buf,
+                       gsize buflen,
+                       gint *herr)
 {
 #ifdef ENABLE_IPv6
        struct addrinfo hints, *res;
-       int retval, len;
-       char *addr;
-       
+       gint retval, len;
+       gchar *addr;
+
        memset (&hints, 0, sizeof (struct addrinfo));
 #ifdef HAVE_AI_ADDRCONFIG
        hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
@@ -184,49 +224,49 @@ camel_gethostbyname_r (const char *name, struct hostent *host,
        hints.ai_family = PF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
-       
+
        if ((retval = getaddrinfo (name, NULL, &hints, &res)) != 0) {
                *herr = ai_to_herr (retval);
                return -1;
        }
-       
+
        len = ALIGN (strlen (res->ai_canonname) + 1);
-       if (buflen < IPv6_BUFLEN_MIN + len + res->ai_addrlen + sizeof (char *))
+       if (buflen < IPv6_BUFLEN_MIN + len + res->ai_addrlen + sizeof (gchar *))
                return ERANGE;
-       
+
        /* h_name */
        strcpy (buf, res->ai_canonname);
        host->h_name = buf;
        buf += len;
-       
+
        /* h_aliases */
-       ((char **) buf)[0] = NULL;
-       host->h_aliases = (char **) buf;
-       buf += sizeof (char *);
-       
+       ((gchar **) buf)[0] = NULL;
+       host->h_aliases = (gchar **) buf;
+       buf += sizeof (gchar *);
+
        /* h_addrtype and h_length */
        host->h_length = res->ai_addrlen;
        if (res->ai_family == PF_INET6) {
                host->h_addrtype = AF_INET6;
-               
-               addr = (char *) &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
+
+               addr = (gchar *) &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
        } else {
                host->h_addrtype = AF_INET;
-               
-               addr = (char *) &((struct sockaddr_in *) res->ai_addr)->sin_addr;
+
+               addr = (gchar *) &((struct sockaddr_in *) res->ai_addr)->sin_addr;
        }
-       
+
        memcpy (buf, addr, host->h_length);
        addr = buf;
        buf += ALIGN (host->h_length);
-       
+
        /* h_addr_list */
-       ((char **) buf)[0] = addr;
-       ((char **) buf)[1] = NULL;
-       host->h_addr_list = (char **) buf;
-       
+       ((gchar **) buf)[0] = addr;
+       ((gchar **) buf)[1] = NULL;
+       host->h_addr_list = (gchar **) buf;
+
        freeaddrinfo (res);
-       
+
        return 0;
 #else /* No support for IPv6 addresses */
 #ifdef HAVE_GETHOSTBYNAME_R
@@ -237,8 +277,8 @@ camel_gethostbyname_r (const char *name, struct hostent *host,
                return errno;
 #else
        struct hostent *hp;
-       int retval;
-       
+       gint retval;
+
        retval = gethostbyname_r (name, host, buf, buflen, &hp, herr);
        if (hp != NULL) {
                *herr = 0;
@@ -252,69 +292,74 @@ camel_gethostbyname_r (const char *name, struct hostent *host,
                 */
                retval = -1;
        }
-       
+
        return retval;
 #endif
 #else /* No support for gethostbyname_r */
        struct hostent *h;
-       
+
        G_LOCK (gethost_mutex);
-       
+
        h = gethostbyname (name);
-       
+
        if (!h) {
                *herr = h_errno;
                G_UNLOCK (gethost_mutex);
                return -1;
        }
-       
+
        GETHOST_PROCESS (h, host, buf, buflen, herr);
-       
+
        G_UNLOCK (gethost_mutex);
-       
+
        return 0;
 #endif /* HAVE_GETHOSTBYNAME_R */
 #endif /* ENABLE_IPv6 */
 }
 
-static int
-camel_gethostbyaddr_r (const char *addr, int addrlen, int type, struct hostent *host,
-                      char *buf, size_t buflen, int *herr)
+static gint
+camel_gethostbyaddr_r (const gchar *addr,
+                       gint addrlen,
+                       gint type,
+                       struct hostent *host,
+                       gchar *buf,
+                       gsize buflen,
+                       gint *herr)
 {
 #ifdef ENABLE_IPv6
-       int retval, len;
-       
+       gint retval, len;
+
        if ((retval = getnameinfo (addr, addrlen, buf, buflen, NULL, 0, NI_NAMEREQD)) != 0) {
                *herr = ai_to_herr (retval);
                return -1;
        }
-       
+
        len = ALIGN (strlen (buf) + 1);
-       if (buflen < IPv6_BUFLEN_MIN + len + addrlen + sizeof (char *))
+       if (buflen < IPv6_BUFLEN_MIN + len + addrlen + sizeof (gchar *))
                return ERANGE;
-       
+
        /* h_name */
        host->h_name = buf;
        buf += len;
-       
+
        /* h_aliases */
-       ((char **) buf)[0] = NULL;
-       host->h_aliases = (char **) buf;
-       buf += sizeof (char *);
-       
+       ((gchar **) buf)[0] = NULL;
+       host->h_aliases = (gchar **) buf;
+       buf += sizeof (gchar *);
+
        /* h_addrtype and h_length */
        host->h_length = addrlen;
        host->h_addrtype = type;
-       
+
        memcpy (buf, addr, host->h_length);
        addr = buf;
        buf += ALIGN (host->h_length);
-       
+
        /* h_addr_list */
-       ((char **) buf)[0] = addr;
-       ((char **) buf)[1] = NULL;
-       host->h_addr_list = (char **) buf;
-       
+       ((gchar **) buf)[0] = addr;
+       ((gchar **) buf)[1] = NULL;
+       host->h_addr_list = (gchar **) buf;
+
        return 0;
 #else /* No support for IPv6 addresses */
 #ifdef HAVE_GETHOSTBYADDR_R
@@ -325,8 +370,8 @@ camel_gethostbyaddr_r (const char *addr, int addrlen, int type, struct hostent *
                return errno;
 #else
        struct hostent *hp;
-       int retval;
-       
+       gint retval;
+
        retval = gethostbyaddr_r (addr, addrlen, type, host, buf, buflen, &hp, herr);
        if (hp != NULL) {
                *herr = 0;
@@ -341,26 +386,26 @@ camel_gethostbyaddr_r (const char *addr, int addrlen, int type, struct hostent *
                 */
                retval = -1;
        }
-       
+
        return retval;
 #endif
 #else /* No support for gethostbyaddr_r */
        struct hostent *h;
-       
+
        G_LOCK (gethost_mutex);
-       
+
        h = gethostbyaddr (addr, addrlen, type);
-       
+
        if (!h) {
                *herr = h_errno;
                G_UNLOCK (gethost_mutex);
                return -1;
        }
-       
+
        GETHOST_PROCESS (h, host, buf, buflen, herr);
-       
+
        G_UNLOCK (gethost_mutex);
-       
+
        return 0;
 #endif /* HAVE_GETHOSTBYADDR_R */
 #endif /* ENABLE_IPv6 */
@@ -369,126 +414,160 @@ camel_gethostbyaddr_r (const char *addr, int addrlen, int type, struct hostent *
 
 /* ********************************************************************** */
 struct _addrinfo_msg {
-       EMsg msg;
-       unsigned int cancelled:1;
+       CamelMsg msg;
+       guint cancelled : 1;
 
        /* for host lookup */
-       const char *name;
-       const char *service;
-       int result;
+       const gchar *name;
+       const gchar *service;
+       gint result;
        const struct addrinfo *hints;
        struct addrinfo **res;
 
        /* for host lookup emulation */
 #ifdef NEED_ADDRINFO
        struct hostent hostbuf;
-       int hostbuflen;
-       char *hostbufmem;
+       gint hostbuflen;
+       gchar *hostbufmem;
 #endif
 
        /* for name lookup */
        const struct sockaddr *addr;
        socklen_t addrlen;
-       char *host;
-       int hostlen;
-       char *serv;
-       int servlen;
-       int flags;
+       gchar *host;
+       gint hostlen;
+       gchar *serv;
+       gint servlen;
+       gint flags;
 };
 
 static void
-cs_freeinfo(struct _addrinfo_msg *msg)
+cs_freeinfo (struct _addrinfo_msg *msg)
 {
-       g_free(msg->host);
-       g_free(msg->serv);
+       g_free (msg->host);
+       g_free (msg->serv);
 #ifdef NEED_ADDRINFO
-       g_free(msg->hostbufmem);
+       g_free (msg->hostbufmem);
 #endif
-       g_free(msg);
+       g_free (msg);
 }
 
-/* returns -1 if cancelled */
-static int
-cs_waitinfo(void *(worker)(void *), struct _addrinfo_msg *msg, const char *error, CamelException *ex)
+/* returns -1 if we didn't wait for reply from thread */
+static gint
+cs_waitinfo (gpointer (worker)(gpointer),
+             struct _addrinfo_msg *msg,
+             const gchar *errmsg,
+             GCancellable *cancellable,
+             GError **error)
 {
-       EMsgPort *reply_port;
-       pthread_t id;
-       int err, cancel_fd, cancel = 0, fd;
+       CamelMsgPort *reply_port;
+       GThread *thread;
+       gint cancel_fd, cancel = 0, fd;
 
-       cancel_fd = camel_operation_cancel_fd(NULL);
+       cancel_fd = g_cancellable_get_fd (cancellable);
        if (cancel_fd == -1) {
-               worker(msg);
+               worker (msg);
                return 0;
        }
-       
-       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;
+
+       reply_port = msg->msg.reply_port = camel_msgport_new ();
+       fd = camel_msgport_fd (msg->msg.reply_port);
+       if ((thread = g_thread_new (NULL, worker, msg)) != NULL) {
+               gint status;
+#ifndef G_OS_WIN32
+               GPollFD polls[2];
 
                polls[0].fd = fd;
-               polls[0].events = POLLIN;
+               polls[0].events = G_IO_IN;
                polls[1].fd = cancel_fd;
-               polls[1].events = POLLIN;
+               polls[1].events = G_IO_IN;
 
-               d(printf("waiting for name return/cancellation in main process\n"));
+               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);
+                       status = g_poll (polls, 2, -1);
                } while (status == -1 && errno == EINTR);
+#else
+               fd_set read_set;
 
-               if (status == -1 || (polls[1].revents & POLLIN)) {
+               FD_ZERO (&read_set);
+               FD_SET (fd, &read_set);
+               FD_SET (cancel_fd, &read_set);
+
+               status = select (MAX (fd, cancel_fd) + 1, &read_set, NULL, NULL, NULL);
+#endif
+
+               if (status == -1 ||
+#ifndef G_OS_WIN32
+                   (polls[1].revents & G_IO_IN)
+#else
+                   FD_ISSET (cancel_fd, &read_set)
+#endif
+                                                  ) {
                        if (status == -1)
-                               camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, "%s: %s", error, g_strerror(errno));
+                               g_set_error (
+                                       error, G_IO_ERROR,
+                                       g_io_error_from_errno (errno),
+                                       "%s: %s", errmsg,
+#ifndef G_OS_WIN32
+                                       g_strerror (errno)
+#else
+                                       g_win32_error_message (WSAGetLastError ())
+#endif
+                                       );
                        else
-                               camel_exception_setv(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
-                       
+                               g_set_error (
+                                       error, G_IO_ERROR,
+                                       G_IO_ERROR_CANCELLED,
+                                       _("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"));
+                        * We check the reply port incase we had a reply in the mean time, which we free later */
+                       d (printf ("Canceling lookup thread and leaving it\n"));
                        msg->cancelled = 1;
-                       pthread_detach(id);
-                       pthread_cancel(id);
+                       g_thread_join (thread);
                        cancel = 1;
                } else {
-                       struct _addrinfo_msg *reply = (struct _addrinfo_msg *)e_msgport_get(reply_port);
+                       struct _addrinfo_msg *reply;
+
+                       d (printf ("waiting for child to exit\n"));
+                       g_thread_join (thread);
+                       d (printf ("child done\n"));
 
-                       g_assert(reply == msg);
-                       d(printf("waiting for child to exit\n"));
-                       pthread_join(id, NULL);
-                       d(printf("child done\n"));
+                       reply = (struct _addrinfo_msg *) camel_msgport_try_pop (reply_port);
+                       if (reply != msg)
+                               g_warning ("%s: Received msg reply %p doesn't match msg %p", G_STRFUNC, reply, msg);
                }
-       } else {
-               camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, "%s: %s: %s", error, _("cannot create thread"), g_strerror(err));
        }
-       e_msgport_destroy(reply_port);
+       camel_msgport_destroy (reply_port);
+
+       g_cancellable_release_fd (cancellable);
 
        return cancel;
 }
 
 #ifdef NEED_ADDRINFO
-static void *
-cs_getaddrinfo(void *data)
+static gpointer
+cs_getaddrinfo (gpointer data)
 {
        struct _addrinfo_msg *msg = data;
-       int herr;
+       gint herr;
        struct hostent h;
        struct addrinfo *res, *last = NULL;
        struct sockaddr_in *sin;
        in_port_t port = 0;
-       int i;
+       gint i;
 
        /* This is a pretty simplistic emulation of getaddrinfo */
 
-       while ((msg->result = camel_gethostbyname_r(msg->name, &h, msg->hostbufmem, msg->hostbuflen, &herr)) == ERANGE) {
-               pthread_testcancel();
-                msg->hostbuflen *= 2;
-                msg->hostbufmem = g_realloc(msg->hostbufmem, msg->hostbuflen);
+       while ((msg->result = camel_gethostbyname_r (msg->name, &h, msg->hostbufmem, msg->hostbuflen, &herr)) == ERANGE) {
+               if (msg->cancelled)
+                       break;
+               msg->hostbuflen *= 2;
+               msg->hostbufmem = g_realloc (msg->hostbufmem, msg->hostbuflen);
        }
-       
+
        /* If we got cancelled, dont reply, just free it */
        if (msg->cancelled)
                goto cancel;
@@ -511,7 +590,7 @@ cs_getaddrinfo(void *data)
 
        /* check service mapping */
        if (msg->service) {
-               const char *p = msg->service;
+               const gchar *p = msg->service;
 
                while (*p) {
                        if (*p < '0' || *p > '9')
@@ -520,7 +599,7 @@ cs_getaddrinfo(void *data)
                }
 
                if (*p) {
-                       const char *socktype = NULL;
+                       const gchar *socktype = NULL;
                        struct servent *serv;
 
                        if (msg->hints && msg->hints->ai_socktype) {
@@ -530,23 +609,23 @@ cs_getaddrinfo(void *data)
                                        socktype = "udp";
                        }
 
-                       serv = getservbyname(msg->service, socktype);
+                       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));
+                       port = htons (strtoul (msg->service, NULL, 10));
                }
        }
 
-       for (i=0;h.h_addr_list[i];i++) {
-               res = g_malloc0(sizeof(*res));
+       for (i = 0; h.h_addr_list[i] && !msg->cancelled; 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_canonname = g_strdup (h.h_name);
                        res->ai_socktype = msg->hints->ai_socktype;
                        res->ai_protocol = msg->hints->ai_protocol;
                } else {
@@ -555,12 +634,12 @@ cs_getaddrinfo(void *data)
                        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;
+               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));
+               memcpy (&sin->sin_addr, h.h_addr_list[i], sizeof (sin->sin_addr));
 
                if (last == NULL) {
                        *msg->res = last = res;
@@ -570,106 +649,133 @@ cs_getaddrinfo(void *data)
                }
        }
 reply:
-       e_msgport_reply((EMsg *)msg);
-       return NULL;
+       camel_msgport_reply ((CamelMsg *) msg);
 cancel:
-       cs_freeinfo(msg);
        return NULL;
 }
 #else
-static void *
-cs_getaddrinfo(void *data)
+static gpointer
+cs_getaddrinfo (gpointer data)
 {
        struct _addrinfo_msg *info = data;
 
-       info->result = getaddrinfo(info->name, info->service, info->hints, info->res);
-       
-       if (info->cancelled) {
-               g_free(info);
-       } else {
-               e_msgport_reply((EMsg *)info);
+       info->result = getaddrinfo (info->name, info->service, info->hints, info->res);
+
+       /* On Solaris, the service name 'http' or 'https' is not defined.
+        * Use the port as the service name directly. */
+       if (info->result && info->service) {
+               if (strcmp (info->service, "http") == 0)
+                       info->result = getaddrinfo (info->name, "80", info->hints, info->res);
+               else if (strcmp (info->service, "https") == 0)
+                       info->result = getaddrinfo (info->name, "443", info->hints, info->res);
        }
-       
+
+       if (!info->cancelled)
+               camel_msgport_reply ((CamelMsg *) info);
+
        return NULL;
 }
 #endif /* NEED_ADDRINFO */
 
+/**
+ * camel_getaddrinfo:
+ *
+ * Since: 2.22
+ **/
 struct addrinfo *
-camel_getaddrinfo(const char *name, const char *service, const struct addrinfo *hints, CamelException *ex)
+camel_getaddrinfo (const gchar *name,
+                   const gchar *service,
+                   const struct addrinfo *hints,
+                   GCancellable *cancellable,
+                   GError **error)
 {
        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(ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+       g_return_val_if_fail (name != NULL, NULL);
+
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
                return NULL;
-       }
 
-       camel_operation_start_transient(NULL, _("Resolving: %s"), name);
+       camel_operation_push_message (
+               cancellable, _("Resolving: %s"), name);
 
        /* force ipv4 addresses only */
 #ifndef ENABLE_IPv6
        if (hints == NULL)
-               memset(&myhints, 0, sizeof(myhints));
+               memset (&myhints, 0, sizeof (myhints));
        else
                memcpy (&myhints, hints, sizeof (myhints));
-       
+
        myhints.ai_family = AF_INET;
        hints = &myhints;
 #endif
 
-       msg = g_malloc0(sizeof(*msg));
+       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);
-#endif 
-       if (cs_waitinfo(cs_getaddrinfo, msg, _("Host lookup failed"), ex) == 0) {
-               if (msg->result != 0)
-                       camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Host lookup failed: %s: %s"),
-                                             name, gai_strerror (msg->result));
-               
-               cs_freeinfo(msg);
+       msg->hostbufmem = g_malloc (msg->hostbuflen);
+#endif
+       if (cs_waitinfo (
+               cs_getaddrinfo, msg, _("Host lookup failed"),
+               cancellable, error) == 0) {
+
+               if (msg->result == EAI_NONAME || msg->result == EAI_FAIL) {
+                       g_set_error (
+                               error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+                               _("Host lookup '%s' failed. Check your host name for spelling errors."), name);
+               } else if (msg->result != 0) {
+                       g_set_error (
+                               error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+                               _("Host lookup '%s' failed: %s"),
+                               name, gai_strerror (msg->result));
+               }
        } else
                res = NULL;
-       
-       camel_operation_end(NULL);
+
+       cs_freeinfo (msg);
+
+       camel_operation_pop_message (cancellable);
 
        return res;
 }
 
+/**
+ * camel_freeaddrinfo:
+ *
+ * Since: 2.22
+ **/
 void
-camel_freeaddrinfo(struct addrinfo *host)
+camel_freeaddrinfo (struct addrinfo *host)
 {
 #ifdef NEED_ADDRINFO
        while (host) {
                struct addrinfo *next = host->ai_next;
 
-               g_free(host->ai_canonname);
-               g_free(host->ai_addr);
-               g_free(host);
+               g_free (host->ai_canonname);
+               g_free (host->ai_addr);
+               g_free (host);
                host = next;
        }
 #else
-       freeaddrinfo(host);
+       freeaddrinfo (host);
 #endif
 }
 
 #ifdef NEED_ADDRINFO
-static void *
-cs_getnameinfo(void *data)
+static gpointer
+cs_getnameinfo (gpointer data)
 {
        struct _addrinfo_msg *msg = data;
-       int herr;
+       gint herr;
        struct hostent h;
-       struct sockaddr_in *sin = (struct sockaddr_in *)msg->addr;
+       struct sockaddr_in *sin = (struct sockaddr_in *) msg->addr;
 
        /* FIXME: error code */
        if (msg->addr->sa_family != AF_INET) {
@@ -679,103 +785,118 @@ cs_getnameinfo(void *data)
 
        /* FIXME: honour getnameinfo flags: do we care, not really */
 
-       while ((msg->result = camel_gethostbyaddr_r((const char *)&sin->sin_addr, sizeof(sin->sin_addr), AF_INET, &h,
+       while ((msg->result = camel_gethostbyaddr_r ((const gchar *) &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)
+                       break;
+               msg->hostbuflen *= 2;
+               msg->hostbufmem = g_realloc (msg->hostbufmem, msg->hostbuflen);
        }
-       
+
        if (msg->cancelled)
                goto cancel;
 
        if (msg->host) {
-               g_free(msg->host);
+               g_free (msg->host);
                if (msg->result == 0 && h.h_name && h.h_name[0]) {
-                       msg->host = g_strdup(h.h_name);
+                       msg->host = g_strdup (h.h_name);
                } else {
-                       unsigned char *in = (unsigned char *)&sin->sin_addr;
-                       
+                       guchar *in = (guchar *) &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]);
+                       msg->host = g_strdup_printf ("%u.%u.%u.%u", in[0], in[1], in[2], in[3]);
                }
        }
 
        /* we never actually use this anyway */
        if (msg->serv)
-               sprintf(msg->serv, "%d", sin->sin_port);
+               sprintf (msg->serv, "%d", sin->sin_port);
 
-       e_msgport_reply((EMsg *)msg);
-       return NULL;
+       if (!msg->cancelled)
+               camel_msgport_reply ((CamelMsg *) msg);
 cancel:
-       cs_freeinfo(msg);
        return NULL;
 }
 #else
-static void *
-cs_getnameinfo(void *data)
+static gpointer
+cs_getnameinfo (gpointer 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 */
-       msg->result = getnameinfo(msg->addr, msg->addrlen, msg->host, msg->hostlen, msg->serv, msg->servlen, msg->flags);
-       
-       if (msg->cancelled)
-               cs_freeinfo(msg);
-       else
-               e_msgport_reply((EMsg *)msg);
+       msg->result = getnameinfo (msg->addr, msg->addrlen, msg->host, msg->hostlen, msg->serv, msg->servlen, msg->flags);
+
+       if (!msg->cancelled)
+               camel_msgport_reply ((CamelMsg *) msg);
 
        return NULL;
 }
 #endif
 
-int
-camel_getnameinfo(const struct sockaddr *sa, socklen_t salen, char **host, char **serv, int flags, CamelException *ex)
+/**
+ * camel_getnameinfo:
+ *
+ * Since: 2.22
+ **/
+gint
+camel_getnameinfo (const struct sockaddr *sa,
+                   socklen_t salen,
+                   gchar **host,
+                   gchar **serv,
+                   gint flags,
+                   GCancellable *cancellable,
+                   GError **error)
 {
        struct _addrinfo_msg *msg;
-       int result;
+       gint result;
 
-       if (camel_operation_cancel_check(NULL)) {
-               camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Cancelled"));
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
                return -1;
-       }
 
-       camel_operation_start_transient(NULL, _("Resolving address"));
+       camel_operation_push_message (
+               cancellable, _("Resolving address"));
 
-       msg = g_malloc0(sizeof(*msg));
+       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 = g_malloc (msg->hostlen);
                msg->host[0] = 0;
        }
        if (serv) {
                msg->servlen = NI_MAXSERV;
-               msg->serv = g_malloc(msg->servlen);
+               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);
+       msg->hostbufmem = g_malloc (msg->hostbuflen);
 #endif
-       cs_waitinfo(cs_getnameinfo, msg, _("Name lookup failed"), ex);
-
-       if ((result = msg->result) != 0)
-               camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Name lookup failed: %s"),
-                                     gai_strerror (result));
-
-       if (host)
-               *host = g_strdup(msg->host);
-       if (serv)
-               *serv = g_strdup(msg->serv);
+       cs_waitinfo (
+               cs_getnameinfo, msg, _("Name lookup failed"),
+               cancellable, error);
+
+       result = msg->result;
+       if (result == EAI_NONAME || result == EAI_FAIL) {
+               g_set_error_literal (
+                       error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+                       _("Name lookup failed. Check your host name for spelling errors."));
+       } else if (result) {
+               g_set_error (
+                       error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+                       _("Name lookup failed: %s"), gai_strerror (result));
+       } else {
+               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);
+       cs_freeinfo (msg);
 
-       camel_operation_end(NULL);
+       camel_operation_pop_message (cancellable);
 
        return result;
 }