Merged in use-gresolver (pull request #1)

Tue, 22 Dec 2015 20:25:45 -0600

author
Gary Kramlich <grim@reaperworld.com>
date
Tue, 22 Dec 2015 20:25:45 -0600
changeset 37468
2a1934a1e457
parent 37436
1f30661ee575 (current diff)
parent 37467
37d053fc8907 (diff)
child 37469
f238b0a5ee69

Merged in use-gresolver (pull request #1)

Use gresolver

libpurple/dnsquery.c file | annotate | diff | comparison | revisions
libpurple/dnsquery.h file | annotate | diff | comparison | revisions
libpurple/dnssrv.c file | annotate | diff | comparison | revisions
libpurple/dnssrv.h file | annotate | diff | comparison | revisions
--- a/configure.ac	Mon Dec 21 21:51:27 2015 -0600
+++ b/configure.ac	Tue Dec 22 20:25:45 2015 -0600
@@ -477,13 +477,13 @@
 AM_CONDITIONAL(INSTALL_I18N, test "x$enable_i18n" = "xyes")
 
 dnl #######################################################################
-dnl # Check for GLib 2.20 (required)
+dnl # Check for GLib 2.34 (required)
 dnl #######################################################################
-PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.28.0 gio-2.0 gobject-2.0 gthread-2.0], , [
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.34.0 gio-2.0 gobject-2.0 gthread-2.0], , [
 	AC_MSG_RESULT(no)
 	AC_MSG_ERROR([
 
-You must have GLib 2.20.0 or newer development headers installed to build.
+You must have GLib 2.34.0 or newer development headers installed to build.
 
 If you have these installed already you may need to install pkg-config so
 I can find them.
--- a/libpurple/Makefile.am	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/Makefile.am	Tue Dec 22 20:25:45 2015 -0600
@@ -106,8 +106,6 @@
 	smiley-parser.c \
 	smiley-theme.c \
 	smiley.c \
-	dnsquery.c \
-	dnssrv.c\
 	status.c \
 	stringref.c \
 	stun.c \
@@ -187,8 +185,6 @@
 	smiley-parser.h \
 	smiley-theme.h \
 	smiley.h \
-	dnsquery.h \
-	dnssrv.h \
 	status.h \
 	stringref.h \
 	stun.h \
--- a/libpurple/core.c	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/core.c	Tue Dec 22 20:25:45 2015 -0600
@@ -26,7 +26,6 @@
 #include "conversation.h"
 #include "core.h"
 #include "debug.h"
-#include "dnsquery.h"
 #include "xfer.h"
 #include "glibcompat.h"
 #include "http.h"
@@ -200,7 +199,6 @@
 	purple_pounces_init();
 	_purple_socket_init();
 	purple_proxy_init();
-	purple_dnsquery_init();
 	purple_sound_init();
 	purple_ssl_init();
 	purple_stun_init();
@@ -276,7 +274,6 @@
 	purple_xfers_uninit();
 	purple_proxy_uninit();
 	_purple_socket_uninit();
-	purple_dnsquery_uninit();
 	_purple_image_store_uninit();
 	purple_network_uninit();
 
--- a/libpurple/dnsquery.c	Mon Dec 21 21:51:27 2015 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1080 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- *
- */
-#define _PURPLE_DNSQUERY_C_
-
-#include "internal.h"
-#include "debug.h"
-#include "dnsquery.h"
-#include "network.h"
-#include "notify.h"
-#include "prefs.h"
-#include "util.h"
-
-#ifndef _WIN32
-#include <resolv.h>
-#endif
-
-#define MAX_ADDR_RESPONSE_LEN 1048576
-
-#if (defined(__APPLE__) || defined (__unix__)) && !defined(__osf__)
-#define PURPLE_DNSQUERY_USE_FORK
-#endif
-/**************************************************************************
- * DNS query API
- **************************************************************************/
-
-static PurpleDnsQueryUiOps *dns_query_ui_ops = NULL;
-
-typedef struct _PurpleDnsQueryResolverProcess PurpleDnsQueryResolverProcess;
-
-struct _PurpleDnsQueryData {
-	char *hostname;
-	int port;
-	PurpleDnsQueryConnectFunction callback;
-	gpointer data;
-	guint timeout;
-	PurpleAccount *account;
-
-#if defined(PURPLE_DNSQUERY_USE_FORK)
-	PurpleDnsQueryResolverProcess *resolver;
-#elif defined _WIN32 /* end PURPLE_DNSQUERY_USE_FORK  */
-	GThread *resolver;
-	GSList *hosts;
-	gchar *error_message;
-#endif
-};
-
-#if defined(PURPLE_DNSQUERY_USE_FORK)
-
-#define MAX_DNS_CHILDREN 4
-
-/*
- * This structure keeps a reference to a child resolver process.
- */
-struct _PurpleDnsQueryResolverProcess {
-	guint inpa;
-	int fd_in, fd_out;
-	pid_t dns_pid;
-};
-
-static GSList *free_dns_children = NULL;
-static GQueue *queued_requests = NULL;
-
-static int number_of_dns_children = 0;
-
-/*
- * This is a convenience struct used to pass data to
- * the child resolver process.
- */
-typedef struct {
-	char hostname[512];
-	int port;
-} dns_params_t;
-#endif /* end PURPLE_DNSQUERY_USE_FORK */
-
-static void
-purple_dnsquery_resolved(PurpleDnsQueryData *query_data, GSList *hosts)
-{
-	purple_debug_info("dnsquery", "IP resolved for %s\n", query_data->hostname);
-	if (query_data->callback != NULL)
-		query_data->callback(hosts, query_data->data, NULL);
-	else
-	{
-		/*
-		 * Callback is a required parameter, but it can get set to
-		 * NULL if we cancel a thread-based DNS lookup.  So we need
-		 * to free hosts.
-		 */
-		while (hosts != NULL)
-		{
-			hosts = g_slist_remove(hosts, hosts->data);
-			g_free(hosts->data);
-			hosts = g_slist_remove(hosts, hosts->data);
-		}
-	}
-
-#ifdef PURPLE_DNSQUERY_USE_FORK
-	/*
-	 * Add the resolver to the list of available resolvers, and set it
-	 * to NULL so that it doesn't get destroyed along with the query_data
-	 */
-	if (query_data->resolver)
-	{
-		free_dns_children = g_slist_prepend(free_dns_children, query_data->resolver);
-		query_data->resolver = NULL;
-	}
-#endif /* PURPLE_DNSQUERY_USE_FORK */
-
-	purple_dnsquery_destroy(query_data);
-}
-
-static void
-purple_dnsquery_failed(PurpleDnsQueryData *query_data, const gchar *error_message)
-{
-	purple_debug_error("dnsquery", "%s\n", error_message);
-	if (query_data->callback != NULL)
-		query_data->callback(NULL, query_data->data, error_message);
-	purple_dnsquery_destroy(query_data);
-}
-
-static gboolean
-purple_dnsquery_ui_resolve(PurpleDnsQueryData *query_data)
-{
-	PurpleDnsQueryUiOps *ops = purple_dnsquery_get_ui_ops();
-
-	if (ops && ops->resolve_host)
-		return ops->resolve_host(query_data, purple_dnsquery_resolved, purple_dnsquery_failed);
-
-	return FALSE;
-}
-
-static gboolean
-resolve_ip(PurpleDnsQueryData *query_data)
-{
-#if defined(HAVE_GETADDRINFO) && defined(AI_NUMERICHOST)
-	struct addrinfo hints, *res;
-	char servname[20];
-
-	g_snprintf(servname, sizeof(servname), "%d", query_data->port);
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_family = AF_UNSPEC;
-	hints.ai_flags |= AI_NUMERICHOST;
-
-	if (0 == getaddrinfo(query_data->hostname, servname, &hints, &res))
-	{
-		GSList *hosts = NULL;
-		hosts = g_slist_append(hosts, GINT_TO_POINTER(res->ai_addrlen));
-		hosts = g_slist_append(hosts, g_memdup(res->ai_addr, res->ai_addrlen));
-		purple_dnsquery_resolved(query_data, hosts);
-
-		freeaddrinfo(res);
-		return TRUE;
-	}
-#else /* defined(HAVE_GETADDRINFO) && defined(AI_NUMERICHOST) */
-	struct sockaddr_in sin;
-	if (inet_aton(query_data->hostname, &sin.sin_addr))
-	{
-		/*
-		 * The given "hostname" is actually an IP address, so we
-		 * don't need to do anything.
-		 */
-		GSList *hosts = NULL;
-		sin.sin_family = AF_INET;
-		sin.sin_port = htons(query_data->port);
-		hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin)));
-		hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin)));
-		purple_dnsquery_resolved(query_data, hosts);
-
-		return TRUE;
-	}
-#endif
-
-	return FALSE;
-}
-
-#ifdef USE_IDN
-static gboolean
-dns_str_is_ascii(const char *name)
-{
-	guchar *c;
-	for (c = (guchar *)name; c && *c; ++c) {
-		if (*c > 0x7f)
-			return FALSE;
-	}
-
-	return TRUE;
-}
-#endif
-
-#if defined(PURPLE_DNSQUERY_USE_FORK)
-
-/*
- * Unix!
- */
-
-/*
- * Begin the DNS resolver child process functions.
- */
-#ifdef HAVE_SIGNAL_H
-G_GNUC_NORETURN static void
-trap_gdb_bug(int sig)
-{
-	const char *message =
-		"Purple's DNS child got a SIGTRAP signal.\n"
-		"This can be caused by trying to run purple inside gdb.\n"
-		"There is a known gdb bug which prevents this.  Supposedly purple\n"
-		"should have detected you were using gdb and used an ugly hack,\n"
-		"check cope_with_gdb_brokenness() in dnsquery.c.\n\n"
-		"For more info about this bug, see http://sources.redhat.com/ml/gdb/2001-07/msg00349.html\n";
-	fputs("\n* * *\n",stderr);
-	fputs(message,stderr);
-	fputs("* * *\n\n",stderr);
-	execlp("xmessage","xmessage","-center", message, NULL);
-	_exit(1);
-}
-#endif
-
-static void
-write_to_parent(int fd, const void *buf, size_t count)
-{
-	ssize_t written;
-
-	written = write(fd, buf, count);
-	if (written < 0 || (gsize)written != count) {
-		if (written < 0)
-			fprintf(stderr, "dns[%d]: Error writing data to "
-					"parent: %s\n", getpid(), strerror(errno));
-		else
-			fprintf(stderr, "dns[%d]: Error: Tried to write %"
-					G_GSIZE_FORMAT " bytes to parent but instead "
-					"wrote %" G_GSIZE_FORMAT " bytes\n",
-					getpid(), count, written);
-	}
-}
-
-G_GNUC_NORETURN static void
-purple_dnsquery_resolver_run(int child_out, int child_in, gboolean show_debug)
-{
-	dns_params_t dns_params;
-	const size_t zero = 0;
-	int rc;
-#ifdef HAVE_GETADDRINFO
-	struct addrinfo hints, *res, *tmp;
-	char servname[20];
-#else
-	struct sockaddr_in sin;
-	const size_t addrlen = sizeof(sin);
-#endif
-	char *hostname;
-
-#ifdef HAVE_SIGNAL_H
-	purple_restore_default_signal_handlers();
-	signal(SIGTRAP, trap_gdb_bug);
-#endif
-
-	/*
-	 * We resolve 1 host name for each iteration of this
-	 * while loop.
-	 *
-	 * The top half of this reads in the hostname and port
-	 * number from the socket with our parent.  The bottom
-	 * half of this resolves the IP (blocking) and sends
-	 * the result back to our parent, when finished.
-	 */
-	while (1) {
-		fd_set fds;
-		struct timeval tv = { .tv_sec = 20, .tv_usec = 0 };
-		FD_ZERO(&fds);
-		FD_SET(child_in, &fds);
-		rc = select(child_in + 1, &fds, NULL, NULL, &tv);
-		if (!rc) {
-			if (show_debug)
-				printf("dns[%d]: nobody needs me... =(\n", getpid());
-			break;
-		}
-		rc = read(child_in, &dns_params, sizeof(dns_params_t));
-		if (rc < 0) {
-			if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
-				/* Try again */
-				continue;
-			}
-			fprintf(stderr, "dns[%d]: Error: Could not read dns_params: "
-					"%s\n", getpid(), strerror(errno));
-			break;
-		}
-		if (rc == 0) {
-			if (show_debug)
-				printf("dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid());
-			_exit(0);
-		}
-		if (dns_params.hostname[0] == '\0') {
-			fprintf(stderr, "dns[%d]: Error: Parent requested resolution "
-					"of an empty hostname (port = %d)!!!\n", getpid(),
-					dns_params.port);
-			_exit(1);
-		}
-
-#ifdef USE_IDN
-		if (!dns_str_is_ascii(dns_params.hostname)) {
-			rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname);
-			if (rc != 0) {
-				write_to_parent(child_out, &rc, sizeof(rc));
-				if (show_debug)
-					fprintf(stderr, "dns[%d] Error: IDN conversion returned "
-							"%d\n", getpid(), rc);
-				dns_params.hostname[0] = '\0';
-				break;
-			}
-		} else /* intentional to execute the g_strdup */
-#endif
-		hostname = g_strdup(dns_params.hostname);
-
-		/* We have the hostname and port, now resolve the IP */
-
-#ifdef HAVE_GETADDRINFO
-		g_snprintf(servname, sizeof(servname), "%d", dns_params.port);
-		memset(&hints, 0, sizeof(hints));
-
-		/* This is only used to convert a service
-		 * name to a port number. As we know we are
-		 * passing a number already, we know this
-		 * value will not be really used by the C
-		 * library.
-		 */
-		hints.ai_socktype = SOCK_STREAM;
-#ifdef AI_ADDRCONFIG
-		hints.ai_flags |= AI_ADDRCONFIG;
-#endif /* AI_ADDRCONFIG */
-		rc = getaddrinfo(hostname, servname, &hints, &res);
-		write_to_parent(child_out, &rc, sizeof(rc));
-		if (rc != 0) {
-			if (show_debug)
-				printf("dns[%d] Error: getaddrinfo returned %d\n",
-					getpid(), rc);
-			dns_params.hostname[0] = '\0';
-			g_free(hostname);
-			hostname = NULL;
-			break;
-		}
-		tmp = res;
-		while (res) {
-			size_t ai_addrlen = res->ai_addrlen;
-			write_to_parent(child_out, &ai_addrlen, sizeof(ai_addrlen));
-			write_to_parent(child_out, res->ai_addr, res->ai_addrlen);
-			res = res->ai_next;
-		}
-		freeaddrinfo(tmp);
-#else
-		struct hostent *hp;
-		if (!(hp = gethostbyname(hostname))) {
-			write_to_parent(child_out, &h_errno, sizeof(int));
-			close(child_out);
-			if (show_debug)
-				printf("DNS Error: %d\n", h_errno);
-			_exit(0);
-		}
-		memset(&sin, 0, sizeof(struct sockaddr_in));
-		memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
-		sin.sin_family = hp->h_addrtype;
-
-		sin.sin_port = htons(dns_params.port);
-		rc = 0;
-		write_to_parent(child_out, &rc, sizeof(rc));
-		write_to_parent(child_out, &addrlen, sizeof(addrlen));
-		write_to_parent(child_out, &sin, addrlen);
-#endif
-		write_to_parent(child_out, &zero, sizeof(zero));
-		dns_params.hostname[0] = '\0';
-
-		g_free(hostname);
-		hostname = NULL;
-	}
-
-	close(child_out);
-	close(child_in);
-
-	_exit(0);
-}
-/*
- * End the DNS resolver child process functions.
- */
-
-/*
- * Begin the functions for dealing with the DNS child processes.
- */
-static void
-cope_with_gdb_brokenness(void)
-{
-#ifdef __linux__
-	static gboolean already_done = FALSE;
-	char s[256], e[512];
-	int n;
-	pid_t ppid;
-
-	if(already_done)
-		return;
-	already_done = TRUE;
-	ppid = getppid();
-	g_snprintf(s, sizeof(s), "/proc/%d/exe", ppid);
-	n = readlink(s, e, sizeof(e));
-	if(n < 0)
-		return;
-
-	e[MIN((gsize)n,sizeof(e)-1)] = '\0';
-
-	if(strstr(e,"gdb")) {
-		purple_debug_info("dns",
-				   "Debugger detected, performing useless query...\n");
-		gethostbyname("x.x.x.x.x");
-	}
-#endif
-}
-
-static void
-purple_dnsquery_resolver_destroy(PurpleDnsQueryResolverProcess *resolver)
-{
-	g_return_if_fail(resolver != NULL);
-
-	/* Keep this before the kill() call below. */
-	if (resolver->inpa != 0) {
-		purple_input_remove(resolver->inpa);
-		resolver->inpa = 0;
-	}
-
-	/*
-	 * We might as well attempt to kill our child process.  It really
-	 * doesn't matter if this fails, because children will expire on
-	 * their own after a few seconds.
-	 */
-	if (resolver->dns_pid > 0)
-		kill(resolver->dns_pid, SIGKILL);
-
-	close(resolver->fd_in);
-	close(resolver->fd_out);
-
-	g_free(resolver);
-
-	number_of_dns_children--;
-}
-
-static PurpleDnsQueryResolverProcess *
-purple_dnsquery_resolver_new(gboolean show_debug)
-{
-	PurpleDnsQueryResolverProcess *resolver;
-	int child_out[2], child_in[2];
-
-	/* Create pipes for communicating with the child process */
-	if (pipe(child_out) || pipe(child_in)) {
-		purple_debug_error("dns",
-				   "Could not create pipes: %s\n", g_strerror(errno));
-		return NULL;
-	}
-
-	resolver = g_new(PurpleDnsQueryResolverProcess, 1);
-	resolver->inpa = 0;
-
-	cope_with_gdb_brokenness();
-
-	/* "Go fork and multiply." --Tommy Caldwell (Emily's dad, not the climber) */
-	resolver->dns_pid = fork();
-
-	/* If we are the child process... */
-	if (resolver->dns_pid == 0) {
-		/* We should not access the parent's side of the pipes, so close them */
-		close(child_out[0]);
-		close(child_in[1]);
-
-		purple_dnsquery_resolver_run(child_out[1], child_in[0], show_debug);
-		/* The thread calls _exit() rather than returning, so we never get here */
-	}
-
-	/* We should not access the child's side of the pipes, so close them */
-	close(child_out[1]);
-	close(child_in[0]);
-	if (resolver->dns_pid == -1) {
-		purple_debug_error("dns",
-				   "Could not create child process for DNS: %s\n",
-				   g_strerror(errno));
-		purple_dnsquery_resolver_destroy(resolver);
-		return NULL;
-	}
-
-	resolver->fd_out = child_out[0];
-	resolver->fd_in = child_in[1];
-	number_of_dns_children++;
-	purple_debug_info("dns",
-			   "Created new DNS child %d, there are now %d children.\n",
-			   resolver->dns_pid, number_of_dns_children);
-
-	return resolver;
-}
-
-/*
- * send_dns_request_to_child:
- *
- * Returns: TRUE if the request was sent succesfully.  FALSE
- *          if the request could not be sent.  This isn't
- *          necessarily an error.  If the child has expired,
- *          for example, we won't be able to send the message.
- */
-static gboolean
-send_dns_request_to_child(PurpleDnsQueryData *query_data,
-		PurpleDnsQueryResolverProcess *resolver)
-{
-	pid_t pid;
-	dns_params_t dns_params;
-	ssize_t rc;
-
-	/* This waitpid might return the child's PID if it has recently
-	 * exited, or it might return an error if it exited "long
-	 * enough" ago that it has already been reaped; in either
-	 * instance, we can't use it. */
-	pid = waitpid(resolver->dns_pid, NULL, WNOHANG);
-	if (pid > 0) {
-		purple_debug_info("dns", "DNS child %d no longer exists\n",
-				resolver->dns_pid);
-		purple_dnsquery_resolver_destroy(resolver);
-		return FALSE;
-	} else if (pid < 0) {
-		purple_debug_info("dns", "Wait for DNS child %d failed: %s\n",
-				resolver->dns_pid, g_strerror(errno));
-		purple_dnsquery_resolver_destroy(resolver);
-		return FALSE;
-	}
-
-	/* Copy the hostname and port into a single data structure */
-	strncpy(dns_params.hostname, query_data->hostname, sizeof(dns_params.hostname) - 1);
-	dns_params.hostname[sizeof(dns_params.hostname) - 1] = '\0';
-	dns_params.port = query_data->port;
-
-	/* Send the data structure to the child */
-	rc = write(resolver->fd_in, &dns_params, sizeof(dns_params));
-	if (rc < 0) {
-		purple_debug_error("dns", "Unable to write to DNS child %d: %s\n",
-				resolver->dns_pid, g_strerror(errno));
-		purple_dnsquery_resolver_destroy(resolver);
-		return FALSE;
-	}
-	if ((gsize)rc < sizeof(dns_params)) {
-		purple_debug_error("dns", "Tried to write %" G_GSSIZE_FORMAT
-				" bytes to child but only wrote %" G_GSSIZE_FORMAT "\n",
-				sizeof(dns_params), rc);
-		purple_dnsquery_resolver_destroy(resolver);
-		return FALSE;
-	}
-
-	purple_debug_info("dns",
-			"Successfully sent DNS request to child %d\n",
-			resolver->dns_pid);
-
-	query_data->resolver = resolver;
-
-	return TRUE;
-}
-
-static void host_resolved(gpointer data, gint source, PurpleInputCondition cond);
-
-static void
-handle_next_queued_request(void)
-{
-	PurpleDnsQueryData *query_data;
-	PurpleDnsQueryResolverProcess *resolver;
-
-	if (g_queue_is_empty(queued_requests))
-		/* No more DNS queries, yay! */
-		return;
-
-	query_data = g_queue_pop_head(queued_requests);
-
-	/*
-	 * If we have any children, attempt to have them perform the DNS
-	 * query.  If we're able to send the query then resolver will be
-	 * set to the PurpleDnsQueryResolverProcess.  Otherwise, resolver
-	 * will be NULL and we'll need to create a new DNS request child.
-	 */
-	while (free_dns_children != NULL)
-	{
-		resolver = free_dns_children->data;
-		free_dns_children = g_slist_remove(free_dns_children, resolver);
-
-		if (send_dns_request_to_child(query_data, resolver))
-			/* We found an acceptable child, yay */
-			break;
-	}
-
-	/* We need to create a new DNS request child */
-	if (query_data->resolver == NULL)
-	{
-		if (number_of_dns_children >= MAX_DNS_CHILDREN)
-		{
-			/* Apparently all our children are busy */
-			g_queue_push_head(queued_requests, query_data);
-			return;
-		}
-
-		resolver = purple_dnsquery_resolver_new(purple_debug_is_enabled());
-		if (resolver == NULL)
-		{
-			purple_dnsquery_failed(query_data, _("Unable to create new resolver process\n"));
-			return;
-		}
-		if (!send_dns_request_to_child(query_data, resolver))
-		{
-			purple_dnsquery_failed(query_data, _("Unable to send request to resolver process\n"));
-			return;
-		}
-	}
-
-	query_data->resolver->inpa = purple_input_add(query_data->resolver->fd_out,
-			PURPLE_INPUT_READ, host_resolved, query_data);
-}
-
-/*
- * End the functions for dealing with the DNS child processes.
- */
-
-static void
-host_resolved(gpointer data, gint source, PurpleInputCondition cond)
-{
-	PurpleDnsQueryData *query_data;
-	int rc, err;
-	GSList *hosts = NULL;
-	struct sockaddr *addr = NULL;
-	size_t addrlen;
-	char message[1024];
-
-	query_data = data;
-
-	purple_debug_info("dns", "Got response for '%s'\n", query_data->hostname);
-	purple_input_remove(query_data->resolver->inpa);
-	query_data->resolver->inpa = 0;
-
-	rc = read(query_data->resolver->fd_out, &err, sizeof(err));
-	if ((rc == 4) && (err != 0))
-	{
-#ifdef HAVE_GETADDRINFO
-		g_snprintf(message, sizeof(message), _("Error resolving %s:\n%s"),
-				query_data->hostname, purple_gai_strerror(err));
-#else
-		g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
-				query_data->hostname, err);
-#endif
-		/* Re-read resolv.conf and friends in case DNS servers have changed */
-		res_init();
-
-		purple_dnsquery_failed(query_data, message);
-	} else if (rc > 0) {
-		/* Success! */
-		while (rc > 0) {
-			rc = read(query_data->resolver->fd_out, &addrlen, sizeof(addrlen));
-			if (rc > 0 && addrlen > 0 && addrlen < MAX_ADDR_RESPONSE_LEN) {
-				addr = g_malloc(addrlen);
-				rc = read(query_data->resolver->fd_out, addr, addrlen);
-				hosts = g_slist_append(hosts, GINT_TO_POINTER(addrlen));
-				hosts = g_slist_append(hosts, addr);
-			} else {
-				break;
-			}
-		}
-		/*	wait4(resolver->dns_pid, NULL, WNOHANG, NULL); */
-		purple_dnsquery_resolved(query_data, hosts);
-
-	} else if (rc == -1) {
-		g_snprintf(message, sizeof(message), _("Error reading from resolver process:\n%s"), g_strerror(errno));
-		purple_dnsquery_failed(query_data, message);
-
-	} else if (rc == 0) {
-		g_snprintf(message, sizeof(message), _("Resolver process exited without answering our request"));
-		purple_dnsquery_failed(query_data, message);
-	}
-
-	handle_next_queued_request();
-}
-
-static void
-resolve_host(PurpleDnsQueryData *query_data)
-{
-	g_queue_push_tail(queued_requests, query_data);
-
-	handle_next_queued_request();
-}
-
-#elif defined _WIN32 /* end PURPLE_DNSQUERY_USE_FORK  */
-
-/*
- * Windows!
- */
-
-static gboolean
-dns_main_thread_cb(gpointer data)
-{
-	PurpleDnsQueryData *query_data = data;
-
-	/* We're done, so purple_dnsquery_destroy() shouldn't think it is canceling an in-progress lookup */
-	query_data->resolver = NULL;
-
-	if (query_data->error_message != NULL)
-		purple_dnsquery_failed(query_data, query_data->error_message);
-	else
-	{
-		GSList *hosts;
-
-		/* We don't want purple_dns_query_resolved() to free(hosts) */
-		hosts = query_data->hosts;
-		query_data->hosts = NULL;
-		purple_dnsquery_resolved(query_data, hosts);
-	}
-
-	return FALSE;
-}
-
-static gpointer
-dns_thread(gpointer data)
-{
-	PurpleDnsQueryData *query_data;
-#if defined(HAVE_GETADDRINFO) || defined(USE_IDN)
-	int rc;
-#endif
-#ifdef HAVE_GETADDRINFO
-	struct addrinfo hints, *res, *tmp;
-	char servname[20];
-#else
-	struct sockaddr_in sin;
-	struct hostent *hp;
-#endif
-	char *hostname;
-
-	query_data = data;
-
-#ifdef USE_IDN
-	if (!dns_str_is_ascii(query_data->hostname)) {
-		rc = purple_network_convert_idn_to_ascii(query_data->hostname, &hostname);
-		if (rc != 0) {
-			query_data->error_message = g_strdup_printf(_("Error converting %s "
-					"to punycode: %d"), query_data->hostname, rc);
-			/* back to main thread */
-			purple_timeout_add(0, dns_main_thread_cb, query_data);
-			return 0;
-		}
-	} else /* intentional fallthru */
-#endif
-	hostname = g_strdup(query_data->hostname);
-
-#ifdef HAVE_GETADDRINFO
-	g_snprintf(servname, sizeof(servname), "%d", query_data->port);
-	memset(&hints,0,sizeof(hints));
-
-	/*
-	 * This is only used to convert a service
-	 * name to a port number. As we know we are
-	 * passing a number already, we know this
-	 * value will not be really used by the C
-	 * library.
-	 */
-	hints.ai_socktype = SOCK_STREAM;
-#ifdef AI_ADDRCONFIG
-	hints.ai_flags |= AI_ADDRCONFIG;
-#endif /* AI_ADDRCONFIG */
-	if ((rc = getaddrinfo(hostname, servname, &hints, &res)) == 0) {
-		tmp = res;
-		while(res) {
-			query_data->hosts = g_slist_append(query_data->hosts,
-				GSIZE_TO_POINTER(res->ai_addrlen));
-			query_data->hosts = g_slist_append(query_data->hosts,
-				g_memdup(res->ai_addr, res->ai_addrlen));
-			res = res->ai_next;
-		}
-		freeaddrinfo(tmp);
-	} else {
-		query_data->error_message = g_strdup_printf(_("Error resolving %s:\n%s"), query_data->hostname, purple_gai_strerror(rc));
-	}
-#else
-	if ((hp = gethostbyname(hostname))) {
-		memset(&sin, 0, sizeof(struct sockaddr_in));
-		memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
-		sin.sin_family = hp->h_addrtype;
-		sin.sin_port = htons(query_data->port);
-
-		query_data->hosts = g_slist_append(query_data->hosts,
-				GSIZE_TO_POINTER(sizeof(sin)));
-		query_data->hosts = g_slist_append(query_data->hosts,
-				g_memdup(&sin, sizeof(sin)));
-	} else {
-		query_data->error_message = g_strdup_printf(_("Error resolving %s: %d"), query_data->hostname, h_errno);
-	}
-#endif
-	g_free(hostname);
-
-	/* back to main thread */
-	purple_timeout_add(0, dns_main_thread_cb, query_data);
-
-	return 0;
-}
-
-static void
-resolve_host(PurpleDnsQueryData *query_data)
-{
-	GError *err = NULL;
-
-	/*
-	 * Spin off a separate thread to perform the DNS lookup so
-	 * that we don't block the UI.
-	 */
-	query_data->resolver = g_thread_try_new("dnsquery resolver", dns_thread,
-		query_data, &err);
-	if (query_data->resolver == NULL)
-	{
-		char message[1024];
-		g_snprintf(message, sizeof(message), _("Thread creation failure: %s"),
-				(err && err->message) ? err->message : _("Unknown reason"));
-		g_error_free(err);
-		purple_dnsquery_failed(query_data, message);
-	}
-	else
-		g_thread_unref(query_data->resolver);
-}
-
-#else /* not PURPLE_DNSQUERY_USE_FORK or _WIN32 */
-
-/*
- * We weren't able to do anything fancier above, so use the
- * fail-safe name resolution code, which is blocking.
- */
-
-static void
-resolve_host(PurpleDnsQueryData *query_data)
-{
-	struct sockaddr_in sin;
-	GSList *hosts = NULL;
-	struct hostent *hp;
-	gchar *hostname;
-#ifdef USE_IDN
-	if (!dns_str_is_ascii(query_data->hostname)) {
-		int ret = purple_network_convert_idn_to_ascii(query_data->hostname,
-				&hostname);
-		if (ret != 0) {
-			char message[1024];
-			g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
-					query_data->hostname, ret);
-			purple_dnsquery_failed(query_data, message);
-			return;
-		}
-	} else /* fallthrough is intentional to the g_strdup */
-#endif
-	hostname = g_strdup(query_data->hostname);
-
-	if(!(hp = gethostbyname(hostname))) {
-		char message[1024];
-		g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
-				query_data->hostname, h_errno);
-		purple_dnsquery_failed(query_data, message);
-		g_free(hostname);
-		return;
-	}
-	memset(&sin, 0, sizeof(struct sockaddr_in));
-	memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
-	sin.sin_family = hp->h_addrtype;
-	g_free(hostname);
-	sin.sin_port = htons(query_data->port);
-
-	hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin)));
-	hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin)));
-
-	purple_dnsquery_resolved(query_data, hosts);
-}
-
-#endif /* not PURPLE_DNSQUERY_USE_FORK or _WIN32 */
-
-static gboolean
-initiate_resolving(gpointer data)
-{
-	PurpleDnsQueryData *query_data;
-	PurpleProxyType proxy_type;
-
-	query_data = data;
-	query_data->timeout = 0;
-
-	if (resolve_ip(query_data))
-		/* resolve_ip calls purple_dnsquery_resolved */
-		return FALSE;
-
-	proxy_type = purple_proxy_info_get_proxy_type(
-		purple_proxy_get_setup(query_data->account));
-	if (proxy_type == PURPLE_PROXY_TOR) {
-		purple_dnsquery_failed(query_data,
-			_("Aborting DNS lookup in Tor Proxy mode."));
-		return FALSE;
-	}
-
-	if (purple_dnsquery_ui_resolve(query_data))
-		/* The UI is handling the resolve; we're done */
-		return FALSE;
-
-	resolve_host(query_data);
-
-	return FALSE;
-}
-
-PurpleDnsQueryData *
-purple_dnsquery_a(PurpleAccount *account, const char *hostname, int port,
-				PurpleDnsQueryConnectFunction callback, gpointer data)
-{
-	PurpleDnsQueryData *query_data;
-
-	g_return_val_if_fail(hostname != NULL, NULL);
-	g_return_val_if_fail(port != 0, NULL);
-	g_return_val_if_fail(callback != NULL, NULL);
-
-	purple_debug_info("dnsquery", "Performing DNS lookup for %s\n", hostname);
-
-	query_data = g_new0(PurpleDnsQueryData, 1);
-	query_data->hostname = g_strdup(hostname);
-	g_strstrip(query_data->hostname);
-	query_data->port = port;
-	query_data->callback = callback;
-	query_data->data = data;
-	query_data->account = account;
-
-	if (*query_data->hostname == '\0')
-	{
-		purple_dnsquery_destroy(query_data);
-		g_return_val_if_reached(NULL);
-	}
-
-	query_data->timeout = purple_timeout_add(0, initiate_resolving, query_data);
-
-	return query_data;
-}
-
-void
-purple_dnsquery_destroy(PurpleDnsQueryData *query_data)
-{
-	PurpleDnsQueryUiOps *ops = purple_dnsquery_get_ui_ops();
-
-	if (ops && ops->destroy)
-		ops->destroy(query_data);
-
-#if defined(PURPLE_DNSQUERY_USE_FORK)
-	g_queue_remove(queued_requests, query_data);
-
-	if (query_data->resolver != NULL)
-		/*
-		 * This is only non-NULL when we're cancelling an in-progress
-		 * query.  Ideally we would tell our resolver child to stop
-		 * resolving shit and then we would add it back to the
-		 * free_dns_children linked list.  However, it's hard to tell
-		 * children stuff, they just don't listen.  So we'll just
-		 * kill the process and allow a new child to be started if we
-		 * have more stuff to resolve.
-		 */
-		purple_dnsquery_resolver_destroy(query_data->resolver);
-#elif defined _WIN32 /* end PURPLE_DNSQUERY_USE_FORK */
-	if (query_data->resolver != NULL)
-	{
-		/*
-		 * It's not really possible to kill a thread.  So instead we
-		 * just set the callback to NULL and let the DNS lookup
-		 * finish.
-		 */
-		query_data->callback = NULL;
-		return;
-	}
-
-	while (query_data->hosts != NULL)
-	{
-		/* Discard the length... */
-		query_data->hosts = g_slist_remove(query_data->hosts, query_data->hosts->data);
-		/* Free the address... */
-		g_free(query_data->hosts->data);
-		query_data->hosts = g_slist_remove(query_data->hosts, query_data->hosts->data);
-	}
-	g_free(query_data->error_message);
-#endif /* end _WIN32 */
-
-	if (query_data->timeout > 0)
-		purple_timeout_remove(query_data->timeout);
-
-	g_free(query_data->hostname);
-	g_free(query_data);
-}
-
-char *
-purple_dnsquery_get_host(PurpleDnsQueryData *query_data)
-{
-	g_return_val_if_fail(query_data != NULL, NULL);
-
-	return query_data->hostname;
-}
-
-unsigned short
-purple_dnsquery_get_port(PurpleDnsQueryData *query_data)
-{
-	g_return_val_if_fail(query_data != NULL, 0);
-
-	return query_data->port;
-}
-
-static PurpleDnsQueryUiOps *
-purple_dnsquery_ui_ops_copy(PurpleDnsQueryUiOps *ops)
-{
-	PurpleDnsQueryUiOps *ops_new;
-
-	g_return_val_if_fail(ops != NULL, NULL);
-
-	ops_new = g_new(PurpleDnsQueryUiOps, 1);
-	*ops_new = *ops;
-
-	return ops_new;
-}
-
-GType
-purple_dnsquery_ui_ops_get_type(void)
-{
-	static GType type = 0;
-
-	if (type == 0) {
-		type = g_boxed_type_register_static("PurpleDnsQueryUiOps",
-				(GBoxedCopyFunc)purple_dnsquery_ui_ops_copy,
-				(GBoxedFreeFunc)g_free);
-	}
-
-	return type;
-}
-
-void
-purple_dnsquery_set_ui_ops(PurpleDnsQueryUiOps *ops)
-{
-	dns_query_ui_ops = ops;
-}
-
-PurpleDnsQueryUiOps *
-purple_dnsquery_get_ui_ops(void)
-{
-	/* It is perfectly acceptable for dns_query_ui_ops to be NULL; this just
-	 * means that the default platform-specific implementation will be used.
-	 */
-	return dns_query_ui_ops;
-}
-
-void
-purple_dnsquery_init(void)
-{
-#if defined(PURPLE_DNSQUERY_USE_FORK)
-	queued_requests = g_queue_new();
-#endif
-}
-
-void
-purple_dnsquery_uninit(void)
-{
-#if defined(PURPLE_DNSQUERY_USE_FORK)
-	while (free_dns_children != NULL)
-	{
-		purple_dnsquery_resolver_destroy(free_dns_children->data);
-		free_dns_children = g_slist_remove(free_dns_children, free_dns_children->data);
-	}
-
-	g_queue_free(queued_requests);
-	queued_requests = NULL;
-#endif /* end PURPLE_DNSQUERY_USE_FORK */
-}
-
--- a/libpurple/dnsquery.h	Mon Dec 21 21:51:27 2015 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#ifndef _PURPLE_DNSQUERY_H_
-#define _PURPLE_DNSQUERY_H_
-/**
- * SECTION:dnsquery
- * @section_id: libpurple-dnsquery
- * @short_description: <filename>dnsquery.h</filename>
- * @title: DNS Query API
- */
-
-#include <glib.h>
-#include "eventloop.h"
-#include "account.h"
-
-#define PURPLE_TYPE_DNSQUERY_UI_OPS (purple_dnsquery_ui_ops_get_type())
-
-/**
- * PurpleDnsQueryData:
- *
- * An opaque structure representing a DNS query.  The hostname and port
- * associated with the query can be retrieved using
- * purple_dnsquery_get_host() and purple_dnsquery_get_port().
- */
-typedef struct _PurpleDnsQueryData PurpleDnsQueryData;
-typedef struct _PurpleDnsQueryUiOps PurpleDnsQueryUiOps;
-
-/**
- * PurpleDnsQueryConnectFunction:
- *
- * The "hosts" parameter is a linked list containing pairs of
- * one size_t addrlen and one struct sockaddr *addr.  It should
- * be free'd by the callback function.
- */
-typedef void (*PurpleDnsQueryConnectFunction)(GSList *hosts, gpointer data, const char *error_message);
-
-/**
- * PurpleDnsQueryResolvedCallback:
- *
- * DNS query resolved callback used by the UI if it handles resolving DNS
- */
-typedef void  (*PurpleDnsQueryResolvedCallback) (PurpleDnsQueryData *query_data, GSList *hosts);
-
-/**
- * PurpleDnsQueryFailedCallback:
- *
- * DNS query failed callback used by the UI if it handles resolving DNS
- */
-typedef void  (*PurpleDnsQueryFailedCallback) (PurpleDnsQueryData *query_data, const gchar *error_message);
-
-/**
- * PurpleDnsQueryUiOps:
- * @resolve_host: If implemented, return %TRUE if the UI takes responsibility
- *                for DNS queries. When returning %FALSE, the standard
- *                implementation is used.
- * @destroy:      Called just before @query_data is freed; this should cancel
- *                any further use of @query_data the UI would make. Unneeded if
- *                @resolve_host is not implemented.
- *
- * DNS Request UI operations;  UIs should implement this if they want to do DNS
- * lookups themselves, rather than relying on the core.
- *
- * See <link linkend="chapter-ui-ops">List of <literal>UiOps</literal>
- *     Structures</link>
- */
-struct _PurpleDnsQueryUiOps
-{
-	gboolean (*resolve_host)(PurpleDnsQueryData *query_data,
-	                         PurpleDnsQueryResolvedCallback resolved_cb,
-	                         PurpleDnsQueryFailedCallback failed_cb);
-
-	void (*destroy)(PurpleDnsQueryData *query_data);
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/* DNS query API                                                          */
-/**************************************************************************/
-
-/**
- * purple_dnsquery_ui_ops_get_type:
- *
- * Returns: The #GType for the #PurpleDnsQueryUiOps boxed structure.
- */
-GType purple_dnsquery_ui_ops_get_type(void);
-
-/**
- * purple_dnsquery_a:
- * @account:  The account that the query is being done for (or NULL)
- * @hostname: The hostname to resolve.
- * @port:     A port number which is stored in the struct sockaddr.
- * @callback: (scope call): The callback function to call after resolving.
- * @data:     Extra data to pass to the callback function.
- *
- * Perform an asynchronous DNS query.
- *
- * Returns: NULL if there was an error, otherwise return a reference to
- *         a data structure that can be used to cancel the pending
- *         DNS query, if needed.
- *
- */
-PurpleDnsQueryData *purple_dnsquery_a(PurpleAccount *account, const char *hostname, int port, PurpleDnsQueryConnectFunction callback, gpointer data);
-
-/**
- * purple_dnsquery_destroy:
- * @query_data: The DNS query to cancel.  This data structure
- *        is freed by this function.
- *
- * Cancel a DNS query and destroy the associated data structure.
- */
-void purple_dnsquery_destroy(PurpleDnsQueryData *query_data);
-
-/**
- * purple_dnsquery_set_ui_ops:
- * @ops: The UI operations structure.
- *
- * Sets the UI operations structure to be used when doing a DNS
- * resolve.  The UI operations need only be set if the UI wants to
- * handle the resolve itself; otherwise, leave it as NULL.
- */
-void purple_dnsquery_set_ui_ops(PurpleDnsQueryUiOps *ops);
-
-/**
- * purple_dnsquery_get_ui_ops:
- *
- * Returns the UI operations structure to be used when doing a DNS
- * resolve.
- *
- * Returns: The UI operations structure.
- */
-PurpleDnsQueryUiOps *purple_dnsquery_get_ui_ops(void);
-
-/**
- * purple_dnsquery_get_host:
- * @query_data: The DNS query
- *
- * Get the host associated with a PurpleDnsQueryData
- *
- * Returns: The host.
- */
-char *purple_dnsquery_get_host(PurpleDnsQueryData *query_data);
-
-/**
- * purple_dnsquery_get_port:
- * @query_data: The DNS query
- *
- * Get the port associated with a PurpleDnsQueryData
- *
- * Returns: The port.
- */
-unsigned short purple_dnsquery_get_port(PurpleDnsQueryData *query_data);
-
-/**
- * purple_dnsquery_init:
- *
- * Initializes the DNS query subsystem.
- */
-void purple_dnsquery_init(void);
-
-/**
- * purple_dnsquery_uninit:
- *
- * Uninitializes the DNS query subsystem.
- */
-void purple_dnsquery_uninit(void);
-
-G_END_DECLS
-
-#endif /* _PURPLE_DNSQUERY_H_ */
--- a/libpurple/dnssrv.c	Mon Dec 21 21:51:27 2015 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1163 +0,0 @@
-/* purple
- *
- * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-#define _PURPLE_DNSSRV_C_
-
-#include "internal.h"
-#include "util.h"
-
-#ifndef _WIN32
-#include <arpa/nameser.h>
-#include <resolv.h>
-#ifdef HAVE_ARPA_NAMESER_COMPAT_H
-#include <arpa/nameser_compat.h>
-#endif
-#else /* WIN32 */
-#include <windns.h>
-/* Missing from the mingw headers */
-#ifndef DNS_TYPE_SRV
-# define DNS_TYPE_SRV PurpleDnsTypeSrv
-#endif
-#ifndef DNS_TYPE_TXT
-# define DNS_TYPE_TXT PurpleDnsTypeTxt
-#endif
-#endif
-
-#ifndef T_SRV
-#define T_SRV	PurpleDnsTypeSrv
-#endif
-#ifndef T_TXT
-#define T_TXT	PurpleDnsTypeTxt
-#endif
-
-#define MAX_ADDR_RESPONSE_LEN 1048576
-
-#include "debug.h"
-#include "dnssrv.h"
-#include "eventloop.h"
-#include "network.h"
-
-static PurpleSrvTxtQueryUiOps *srv_txt_query_ui_ops = NULL;
-
-#ifndef _WIN32
-typedef union {
-	HEADER hdr;
-	u_char buf[1024];
-} queryans;
-#endif
-
-enum PurpleDnsType {
-	PurpleDnsTypeTxt = 16,
-	PurpleDnsTypeSrv = 33
-};
-
-struct _PurpleSrvTxtQueryData {
-	union {
-		PurpleSrvCallback srv;
-		PurpleTxtCallback txt;
-	} cb;
-
-	gpointer extradata;
-	guint handle;
-	int type;
-	char *query;
-#ifdef _WIN32
-	GThread *resolver;
-	char *error_message;
-	GList *results;
-#else
-	int fd_in, fd_out;
-	pid_t pid;
-#endif
-};
-
-typedef struct _PurpleSrvInternalQuery {
-	int type;
-	char query[256];
-} PurpleSrvInternalQuery;
-
-typedef struct _PurpleSrvResponseContainer {
-	PurpleSrvResponse *response;
-	int sum;
-} PurpleSrvResponseContainer;
-
-static gboolean purple_srv_txt_query_ui_resolve(PurpleSrvTxtQueryData *query_data);
-
-/*
- * Sort by priority, then by weight.  Strictly numerically--no
- * randomness.  Technically we only need to sort by pref and then
- * make sure any records with weight 0 are at the beginning of
- * their group, but it's just as easy to sort by weight.
- */
-static gint
-responsecompare(gconstpointer ar, gconstpointer br)
-{
-	PurpleSrvResponse *a = (PurpleSrvResponse*)ar;
-	PurpleSrvResponse *b = (PurpleSrvResponse*)br;
-
-	if(a->pref == b->pref) {
-		if(a->weight == b->weight)
-			return 0;
-		if(a->weight < b->weight)
-			return -1;
-		return 1;
-	}
-	if(a->pref < b->pref)
-		return -1;
-	return 1;
-}
-
-/*
- * select_random_response:
- * @list: The list of PurpleSrvResponseContainer.  This function
- *        removes a node from this list and returns the new list.
- * @container_ptr: The PurpleSrvResponseContainer that was chosen
- *        will be returned here.
- *
- * Iterate over a list of PurpleSrvResponseContainer making the sum
- * the running total of the sums.  Select a random integer in the range
- * (1, sum+1), then find the first element greater than or equal to the
- * number selected.  From RFC 2782.
- */
-static GList *
-select_random_response(GList *list, PurpleSrvResponseContainer **container_ptr)
-{
-	GList *cur;
-	size_t runningtotal;
-	int r;
-
-	g_return_val_if_fail(list != NULL, NULL);
-
-	runningtotal = 0;
-	cur = list;
-
-	while (cur) {
-		PurpleSrvResponseContainer *container = cur->data;
-		runningtotal += container->response->weight;
-		container->sum = runningtotal;
-		cur = cur->next;
-	}
-
-	/*
-	 * If the running total is greater than 0, pick a number between
-	 * 1 and the runningtotal inclusive. (This is not precisely what
-	 * the RFC algorithm describes, but we wish to deal with integers
-	 * and avoid floats.  This is functionally equivalent.)
-	 * If running total is 0, then choose r = 0.
-	 */
-	r = runningtotal ? g_random_int_range(1, runningtotal + 1) : 0;
-	cur = list;
-	while (r > ((PurpleSrvResponseContainer *)cur->data)->sum) {
-		if (G_UNLIKELY(!cur->next))
-			break;
-		cur = cur->next;
-	}
-
-	/* Set the return parameter and remove cur from the list */
-	*container_ptr =  cur->data;
-	return g_list_delete_link(list, cur);
-}
-
-/*
- * Reorder a GList of PurpleSrvResponses that have the same priority
- * (aka "pref").
- */
-static void
-srv_reorder(GList *list, int num)
-{
-	int i;
-	GList *cur, *container_list = NULL;
-	PurpleSrvResponseContainer *container;
-
-	if (num < 2)
-		/* Nothing to sort */
-		return;
-
-	g_return_if_fail(list != NULL);
-
-	/* First build a list of container structs */
-	for (i = 0, cur = list; i < num; i++, cur = cur->next) {
-		container = g_new(PurpleSrvResponseContainer, 1);
-		container->response = cur->data;
-		container_list = g_list_prepend(container_list, container);
-	}
-	container_list = g_list_reverse(container_list);
-
-	/*
-	 * Re-order the list that was passed in as a parameter.  We leave
-	 * the list nodes in place, but replace their data pointers.
-	 */
-	cur = list;
-	while (container_list) {
-		g_return_if_fail(cur);
-		container_list = select_random_response(container_list, &container);
-		cur->data = container->response;
-		g_free(container);
-		cur = cur->next;
-	}
-}
-
-/*
- * purple_srv_sort:
- * @list: The original list, resorted
- *
- * Sorts a GList of PurpleSrvResponses according to the
- * algorithm described in RFC 2782.
- *
- * Returns: GList of PurpleSrvResponse's
- */
-static GList *
-purple_srv_sort(GList *list)
-{
-	int pref, count;
-	GList *cur, *start;
-
-	if (!list || !list->next) {
-		/* Nothing to sort */
-		return list;
-	}
-
-	list = g_list_sort(list, responsecompare);
-
-	start = cur = list;
-	count = 1;
-	while (cur) {
-		PurpleSrvResponse *next_response;
-
-		g_return_val_if_fail(cur->data, list);
-
-		pref = ((PurpleSrvResponse *)cur->data)->pref;
-		next_response = cur->next ? cur->next->data : NULL;
-		if (!next_response || next_response->pref != pref) {
-			/*
-			 * The 'count' records starting at 'start' all have the same
-			 * priority.  Sort them by weight.
-			 */
-			srv_reorder(start, count);
-			start = cur->next;
-			count = 0;
-		}
-		count++;
-		cur = cur->next;
-	}
-
-	return list;
-}
-
-static PurpleSrvTxtQueryData *
-query_data_new(int type, gchar *query, gpointer extradata)
-{
-	PurpleSrvTxtQueryData *query_data = g_new0(PurpleSrvTxtQueryData, 1);
-	query_data->type = type;
-	query_data->extradata = extradata;
-	query_data->query = query;
-#ifndef _WIN32
-	query_data->fd_in = -1;
-	query_data->fd_out = -1;
-#endif
-	return query_data;
-}
-
-void
-purple_srv_txt_query_destroy(PurpleSrvTxtQueryData *query_data)
-{
-	PurpleSrvTxtQueryUiOps *ops = purple_srv_txt_query_get_ui_ops();
-
-	if (ops && ops->destroy)
-		ops->destroy(query_data);
-
-	if (query_data->handle > 0)
-		purple_input_remove(query_data->handle);
-#ifdef _WIN32
-	if (query_data->resolver != NULL)
-	{
-		/*
-		 * It's not really possible to kill a thread.  So instead we
-		 * just set the callback to NULL and let the DNS lookup
-		 * finish.
-		 */
-		query_data->cb.srv = NULL;
-		return;
-	}
-	g_free(query_data->error_message);
-#else
-	if (query_data->fd_out != -1)
-		close(query_data->fd_out);
-	if (query_data->fd_in != -1)
-		close(query_data->fd_in);
-#endif
-	g_free(query_data->query);
-	g_free(query_data);
-}
-
-#ifdef USE_IDN
-static gboolean
-dns_str_is_ascii(const char *name)
-{
-	guchar *c;
-	for (c = (guchar *)name; c && *c; ++c) {
-		if (*c > 0x7f)
-			return FALSE;
-	}
-
-	return TRUE;
-}
-#endif
-
-#ifndef _WIN32
-static void
-write_to_parent(int in, int out, gconstpointer data, gsize size)
-{
-	const guchar *buf = data;
-	gssize w;
-
-	do {
-		w = write(out, buf, size);
-		if (w > 0) {
-			buf += w;
-			size -= w;
-		} else if (w < 0 && errno == EINTR) {
-			/* Let's try some more; */
-			w = 1;
-		}
-	} while (size > 0 && w > 0);
-
-	if (size != 0) {
-		/* An error occurred */
-		close(out);
-		close(in);
-		_exit(0);
-	}
-}
-
-/* Read size bytes to data. Dies if an error occurs. */
-static void
-read_from_parent(int in, int out, gpointer data, gsize size)
-{
-	guchar *buf = data;
-	gssize r;
-
-	do {
-		r = read(in, data, size);
-		if (r > 0) {
-			buf += r;
-			size -= r;
-		} else if (r < 0 && errno == EINTR) {
-			/* Let's try some more; */
-			r = 1;
-		}
-	} while (size > 0 && r > 0);
-
-	if (size != 0) {
-		/* An error occurred */
-		close(out);
-		close(in);
-		_exit(0);
-	}
-}
-
-
-G_GNUC_NORETURN static void
-resolve(int in, int out)
-{
-	GList *ret = NULL;
-	PurpleSrvResponse *srvres;
-	PurpleTxtResponse *txtres;
-	queryans answer;
-	int size, qdcount, ancount;
-	guchar *end, *cp;
-	gchar name[256];
-	guint16 type, dlen, pref, weight, port;
-	PurpleSrvInternalQuery query;
-
-#ifdef HAVE_SIGNAL_H
-	purple_restore_default_signal_handlers();
-#endif
-
-	read_from_parent(in, out, &query, sizeof(query));
-
-	size = res_query( query.query, C_IN, query.type, (u_char*)&answer, sizeof( answer));
-	if (size == -1) {
-		write_to_parent(in, out, &(query.type), sizeof(query.type));
-		write_to_parent(in, out, &size, sizeof(size));
-		close(out);
-		close(in);
-		_exit(0);
-	}
-
-	qdcount = ntohs(answer.hdr.qdcount);
-	ancount = ntohs(answer.hdr.ancount);
-	cp = (guchar*)&answer + sizeof(HEADER);
-	end = (guchar*)&answer + size;
-
-	/* skip over unwanted stuff */
-	while (qdcount-- > 0 && cp < end) {
-		size = dn_expand( (unsigned char*)&answer, end, cp, name, 256);
-		if(size < 0) goto end;
-		cp += size + QFIXEDSZ;
-	}
-
-	while (ancount-- > 0 && cp < end) {
-		size = dn_expand((unsigned char*)&answer, end, cp, name, 256);
-		if(size < 0)
-			goto end;
-		cp += size;
-		GETSHORT(type,cp);
-
-		/* skip ttl and class since we already know it */
-		cp += 6;
-
-		GETSHORT(dlen,cp);
-		if (type == T_SRV) {
-			GETSHORT(pref,cp);
-
-			GETSHORT(weight,cp);
-
-			GETSHORT(port,cp);
-
-			size = dn_expand( (unsigned char*)&answer, end, cp, name, 256);
-			if(size < 0 )
-				goto end;
-
-			cp += size;
-
-			srvres = g_new0(PurpleSrvResponse, 1);
-			if (strlen(name) > sizeof(srvres->hostname) - 1) {
-				purple_debug_error("dnssrv", "hostname is "
-					"longer than available buffer ('%s', %"
-					G_GSIZE_FORMAT " bytes)!",
-					name, strlen(name));
-			}
-			g_strlcpy(srvres->hostname, name, sizeof(srvres->hostname));
-			srvres->pref = pref;
-			srvres->port = port;
-			srvres->weight = weight;
-
-			ret = g_list_prepend(ret, srvres);
-		} else if (type == T_TXT) {
-			txtres = g_new0(PurpleTxtResponse, 1);
-			txtres->content = g_strndup((gchar*)(++cp), dlen-1);
-			ret = g_list_append(ret, txtres);
-			cp += dlen - 1;
-		} else {
-			cp += dlen;
-		}
-	}
-
-end:
-	size = g_list_length(ret);
-
-	if (query.type == T_SRV)
-		ret = purple_srv_sort(ret);
-
-	write_to_parent(in, out, &(query.type), sizeof(query.type));
-	write_to_parent(in, out, &size, sizeof(size));
-	while (ret != NULL)
-	{
-		if (query.type == T_SRV)
-			write_to_parent(in, out, ret->data, sizeof(PurpleSrvResponse));
-		if (query.type == T_TXT) {
-			PurpleTxtResponse *response = ret->data;
-			gsize l = strlen(response->content) + 1 /* null byte */;
-			write_to_parent(in, out, &l, sizeof(l));
-			write_to_parent(in, out, response->content, l);
-		}
-
-		g_free(ret->data);
-		ret = g_list_remove(ret, ret->data);
-	}
-
-	close(out);
-	close(in);
-
-	_exit(0);
-}
-
-static void
-resolved(gpointer data, gint source, PurpleInputCondition cond)
-{
-	int size;
-	int type;
-	PurpleSrvTxtQueryData *query_data = (PurpleSrvTxtQueryData*)data;
-	int i;
-	int status;
-
-	if (read(source, &type, sizeof(type)) == sizeof(type)) {
-		if (read(source, &size, sizeof(size)) == sizeof(size)) {
-			if (size < -1 || size > MAX_ADDR_RESPONSE_LEN) {
-				purple_debug_warning("dnssrv", "res_query returned invalid number\n");
-				size = 0;
-			}
-			if (size == -1 || size == 0) {
-				if (size == -1) {
-					purple_debug_warning("dnssrv", "res_query returned an error\n");
-					/* Re-read resolv.conf and friends in case DNS servers have changed */
-					res_init();
-				} else
-					purple_debug_info("dnssrv", "Found 0 entries, errno is %i\n", errno);
-
-				if (type == T_SRV) {
-					PurpleSrvCallback cb = query_data->cb.srv;
-					cb(NULL, 0, query_data->extradata);
-				} else if (type == T_TXT) {
-					PurpleTxtCallback cb = query_data->cb.txt;
-					cb(NULL, query_data->extradata);
-				} else {
-					purple_debug_error("dnssrv", "type unknown of DNS result entry; errno is %i\n", errno);
-				}
-
-			} else if (size) {
-				if (type == T_SRV) {
-					PurpleSrvResponse *res;
-					PurpleSrvResponse *tmp;
-					PurpleSrvCallback cb = query_data->cb.srv;
-					ssize_t red;
-					purple_debug_info("dnssrv","found %d SRV entries\n", size);
-					tmp = res = g_new0(PurpleSrvResponse, size);
-					for (i = 0; i < size; i++) {
-						red = read(source, tmp++, sizeof(PurpleSrvResponse));
-						if (red != sizeof(PurpleSrvResponse)) {
-							purple_debug_error("dnssrv","unable to read srv "
-									"response: %s\n", g_strerror(errno));
-							size = 0;
-							g_free(res);
-							res = NULL;
-						}
-					}
-
-					cb(res, size, query_data->extradata);
-				} else if (type == T_TXT) {
-					GList *responses = NULL;
-					PurpleTxtResponse *res;
-					PurpleTxtCallback cb = query_data->cb.txt;
-					ssize_t red;
-					purple_debug_info("dnssrv","found %d TXT entries\n", size);
-					for (i = 0; i < size; i++) {
-						gsize len;
-
-						red = read(source, &len, sizeof(len));
-						if (red != sizeof(len)) {
-							purple_debug_error("dnssrv","unable to read txt "
-									"response length: %s\n", g_strerror(errno));
-							size = 0;
-							g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
-							g_list_free(responses);
-							responses = NULL;
-							break;
-						}
-						if (len > MAX_ADDR_RESPONSE_LEN) {
-							purple_debug_error("dnssrv", "we've read invalid number\n");
-							size = 0;
-							g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
-							g_list_free(responses);
-							responses = NULL;
-							break;
-						}
-
-						res = g_new0(PurpleTxtResponse, 1);
-						res->content = g_new0(gchar, len);
-
-						red = read(source, res->content, len);
-						if (red < 0 || (gsize)red != len) {
-							purple_debug_error("dnssrv","unable to read txt "
-									"response: %s\n", g_strerror(errno));
-							size = 0;
-							purple_txt_response_destroy(res);
-							g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
-							g_list_free(responses);
-							responses = NULL;
-							break;
-						}
-						responses = g_list_prepend(responses, res);
-					}
-
-					responses = g_list_reverse(responses);
-					cb(responses, query_data->extradata);
-				} else {
-					purple_debug_error("dnssrv", "type unknown of DNS result entry; errno is %i\n", errno);
-				}
-			}
-		}
-	}
-
-	waitpid(query_data->pid, &status, 0);
-	purple_srv_txt_query_destroy(query_data);
-}
-
-#else /* _WIN32 */
-
-/* The Jabber Server code was inspiration for parts of this. */
-
-static gboolean
-res_main_thread_cb(gpointer data)
-{
-	PurpleSrvResponse *srvres = NULL;
-	PurpleSrvTxtQueryData *query_data = data;
-	if(query_data->error_message != NULL) {
-		purple_debug_error("dnssrv", "%s", query_data->error_message);
-		if (query_data->type == DNS_TYPE_SRV) {
-			if (query_data->cb.srv)
-				query_data->cb.srv(srvres, 0, query_data->extradata);
-		} else if (query_data->type == DNS_TYPE_TXT) {
-			if (query_data->cb.txt)
-				query_data->cb.txt(NULL, query_data->extradata);
-		}
-	} else {
-		if (query_data->type == DNS_TYPE_SRV) {
-			PurpleSrvResponse *srvres_tmp = NULL;
-			GList *lst = query_data->results;
-			int size = g_list_length(lst);
-
-			if(query_data->cb.srv && size > 0)
-				srvres_tmp = srvres = g_new0(PurpleSrvResponse, size);
-			while (lst) {
-				PurpleSrvResponse *lstdata = lst->data;
-				lst = g_list_delete_link(lst, lst);
-
-				if(query_data->cb.srv)
-					memcpy(srvres_tmp++, lstdata, sizeof(PurpleSrvResponse));
-				g_free(lstdata);
-			}
-
-			query_data->results = NULL;
-
-			purple_debug_info("dnssrv", "found %d SRV entries\n", size);
-
-			if(query_data->cb.srv) query_data->cb.srv(srvres, size, query_data->extradata);
-		} else if (query_data->type == DNS_TYPE_TXT) {
-			GList *lst = query_data->results;
-
-			purple_debug_info("dnssrv", "found %d TXT entries\n", g_list_length(lst));
-
-			if (query_data->cb.txt) {
-				query_data->results = NULL;
-				query_data->cb.txt(lst, query_data->extradata);
-			}
-		} else {
-			purple_debug_error("dnssrv", "unknown query type");
-		}
-	}
-
-	query_data->resolver = NULL;
-	query_data->handle = 0;
-
-	purple_srv_txt_query_destroy(query_data);
-
-	return FALSE;
-}
-
-static gpointer
-res_thread(gpointer data)
-{
-	PDNS_RECORD dr = NULL;
-	int type;
-	DNS_STATUS ds;
-	PurpleSrvTxtQueryData *query_data = data;
-	type = query_data->type;
-	ds = DnsQuery_UTF8(query_data->query, type, DNS_QUERY_STANDARD, NULL, &dr, NULL);
-	if (ds != ERROR_SUCCESS) {
-		gchar *msg = g_win32_error_message(ds);
-		if (type == DNS_TYPE_SRV) {
-			query_data->error_message = g_strdup_printf("Couldn't look up SRV record. %s (%lu).\n", msg, ds);
-		} else if (type == DNS_TYPE_TXT) {
-			query_data->error_message = g_strdup_printf("Couldn't look up TXT record. %s (%lu).\n", msg, ds);
-		}
-		g_free(msg);
-	} else {
-		if (type == DNS_TYPE_SRV) {
-			PDNS_RECORD dr_tmp;
-			GList *lst = NULL;
-			DNS_SRV_DATA *srv_data;
-			PurpleSrvResponse *srvres;
-
-			for (dr_tmp = dr; dr_tmp != NULL; dr_tmp = dr_tmp->pNext) {
-				/* Discard any incorrect entries. I'm not sure if this is necessary */
-				if (dr_tmp->wType != type || strcmp(dr_tmp->pName, query_data->query) != 0) {
-					continue;
-				}
-
-				srv_data = &dr_tmp->Data.SRV;
-				srvres = g_new0(PurpleSrvResponse, 1);
-				strncpy(srvres->hostname, srv_data->pNameTarget, 255);
-				srvres->hostname[255] = '\0';
-				srvres->pref = srv_data->wPriority;
-				srvres->port = srv_data->wPort;
-				srvres->weight = srv_data->wWeight;
-
-				lst = g_list_prepend(lst, srvres);
-			}
-
-			DnsRecordListFree(dr, DnsFreeRecordList);
-			query_data->results = purple_srv_sort(lst);
-		} else if (type == DNS_TYPE_TXT) {
-			PDNS_RECORD dr_tmp;
-			GList *lst = NULL;
-			DNS_TXT_DATA *txt_data;
-			PurpleTxtResponse *txtres;
-
-			for (dr_tmp = dr; dr_tmp != NULL; dr_tmp = dr_tmp->pNext) {
-				GString *s;
-				int i;
-
-				/* Discard any incorrect entries. I'm not sure if this is necessary */
-				if (dr_tmp->wType != type || strcmp(dr_tmp->pName, query_data->query) != 0) {
-					continue;
-				}
-
-				txt_data = &dr_tmp->Data.TXT;
-				txtres = g_new0(PurpleTxtResponse, 1);
-
-				s = g_string_new("");
-				for (i = 0; i < (int)txt_data->dwStringCount; ++i)
-					s = g_string_append(s, txt_data->pStringArray[i]);
-				txtres->content = g_string_free(s, FALSE);
-
-				lst = g_list_append(lst, txtres);
-			}
-
-			DnsRecordListFree(dr, DnsFreeRecordList);
-			query_data->results = lst;
-		} else {
-
-		}
-	}
-
-	/* back to main thread */
-	/* Note: this should *not* be attached to query_data->handle - it will cause leakage */
-	purple_timeout_add(0, res_main_thread_cb, query_data);
-
-	g_thread_exit(NULL);
-	return NULL;
-}
-
-#endif
-
-PurpleSrvTxtQueryData *
-purple_srv_resolve(PurpleAccount *account, const char *protocol,
-	const char *transport, const char *domain, PurpleSrvCallback cb,
-	gpointer extradata)
-{
-	char *query;
-	char *hostname;
-	PurpleSrvTxtQueryData *query_data;
-	PurpleProxyType proxy_type;
-#ifndef _WIN32
-	PurpleSrvInternalQuery internal_query;
-	int in[2], out[2];
-	int pid;
-#else
-	GError* err = NULL;
-#endif
-
-	if (!protocol || !*protocol || !transport || !*transport || !domain || !*domain) {
-		purple_debug_error("dnssrv", "Wrong arguments\n");
-		cb(NULL, 0, extradata);
-		g_return_val_if_reached(NULL);
-	}
-
-	proxy_type = purple_proxy_info_get_proxy_type(
-		purple_proxy_get_setup(account));
-	if (proxy_type == PURPLE_PROXY_TOR) {
-		purple_debug_info("dnssrv", "Aborting SRV lookup in Tor Proxy mode.\n");
-		cb(NULL, 0, extradata);
-		return NULL;
-	}
-
-#ifdef USE_IDN
-	if (!dns_str_is_ascii(domain)) {
-		int ret = purple_network_convert_idn_to_ascii(domain, &hostname);
-		if (ret != 0) {
-			purple_debug_error("dnssrv", "IDNA ToASCII failed\n");
-			cb(NULL, 0, extradata);
-			return NULL;
-		}
-	} else /* Fallthru is intentional */
-#endif
-	hostname = g_strdup(domain);
-
-	query = g_strdup_printf("_%s._%s.%s", protocol, transport, hostname);
-	purple_debug_info("dnssrv","querying SRV record for %s: %s\n", domain,
-			query);
-	g_free(hostname);
-
-	query_data = query_data_new(PurpleDnsTypeSrv, query, extradata);
-	query_data->cb.srv = cb;
-
-	if (purple_srv_txt_query_ui_resolve(query_data))
-	{
-		return query_data;
-	}
-
-#ifndef _WIN32
-	if(pipe(in) || pipe(out)) {
-		purple_debug_error("dnssrv", "Could not create pipe\n");
-		g_free(query);
-		g_free(query_data);
-		cb(NULL, 0, extradata);
-		return NULL;
-	}
-
-	/*
-	 * TODO: We should put a cap on the number of forked processes that we
-	 *       allow at any given time.  If we get too many requests they
-	 *       should be put into a queue and handled later.  (This is what
-	 *       we do for A record lookups.)
-	 */
-	pid = fork();
-	if (pid == -1) {
-		purple_debug_error("dnssrv", "Could not create process!\n");
-		g_free(query);
-		g_free(query_data);
-		cb(NULL, 0, extradata);
-		return NULL;
-	}
-
-	/* Child */
-	if (pid == 0)
-	{
-		g_free(query);
-		g_free(query_data);
-
-		close(out[0]);
-		close(in[1]);
-		resolve(in[0], out[1]);
-		/* resolve() does not return */
-	}
-
-	close(out[1]);
-	close(in[0]);
-
-	internal_query.type = T_SRV;
-	strncpy(internal_query.query, query, 255);
-	internal_query.query[255] = '\0';
-
-	if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
-		purple_debug_error("dnssrv", "Could not write to SRV resolver\n");
-
-	query_data->pid = pid;
-	query_data->fd_out = out[0];
-	query_data->fd_in = in[1];
-	query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data);
-
-	return query_data;
-#else
-	query_data->resolver = g_thread_try_new("dnssrv srv resolver", res_thread, query_data, &err);
-	if (query_data->resolver == NULL) {
-		query_data->error_message = g_strdup_printf("SRV thread create failure: %s\n", (err && err->message) ? err->message : "");
-		g_error_free(err);
-	}
-	else
-		g_thread_unref(query_data->resolver);
-
-	/* The query isn't going to happen, so finish the SRV lookup now.
-	 * Asynchronously call the callback since stuff may not expect
-	 * the callback to be called before this returns */
-	if (query_data->error_message != NULL)
-		query_data->handle = purple_timeout_add(0, res_main_thread_cb, query_data);
-
-	return query_data;
-#endif
-}
-
-PurpleSrvTxtQueryData *purple_txt_resolve(PurpleAccount *account,
-	const char *owner, const char *domain, PurpleTxtCallback cb,
-	gpointer extradata)
-{
-	char *query;
-	char *hostname;
-	PurpleSrvTxtQueryData *query_data;
-	PurpleProxyType proxy_type;
-#ifndef _WIN32
-	PurpleSrvInternalQuery internal_query;
-	int in[2], out[2];
-	int pid;
-#else
-	GError* err = NULL;
-#endif
-
-	proxy_type = purple_proxy_info_get_proxy_type(
-		purple_proxy_get_setup(account));
-	if (proxy_type == PURPLE_PROXY_TOR) {
-		purple_debug_info("dnssrv", "Aborting TXT lookup in Tor Proxy mode.\n");
-		cb(NULL, extradata);
-		return NULL;
-	}
-
-#ifdef USE_IDN
-	if (!dns_str_is_ascii(domain)) {
-		int ret = purple_network_convert_idn_to_ascii(domain, &hostname);
-		if (ret != 0) {
-			purple_debug_error("dnssrv", "IDNA ToASCII failed\n");
-			cb(NULL, extradata);
-			return NULL;
-		}
-	} else /* fallthru is intentional */
-#endif
-	hostname = g_strdup(domain);
-
-	query = g_strdup_printf("%s.%s", owner, hostname);
-	purple_debug_info("dnssrv","querying TXT record for %s: %s\n", domain,
-			query);
-	g_free(hostname);
-
-	query_data = query_data_new(PurpleDnsTypeTxt, query, extradata);
-	query_data->cb.txt = cb;
-
-	if (purple_srv_txt_query_ui_resolve(query_data)) {
-		/* query intentionally not freed
-		 */
-		return query_data;
-	}
-
-#ifndef _WIN32
-	if(pipe(in) || pipe(out)) {
-		purple_debug_error("dnssrv", "Could not create pipe\n");
-		g_free(query);
-		g_free(query_data);
-		cb(NULL, extradata);
-		return NULL;
-	}
-
-	/*
-	 * TODO: We should put a cap on the number of forked processes that we
-	 *       allow at any given time.  If we get too many requests they
-	 *       should be put into a queue and handled later.  (This is what
-	 *       we do for A record lookups.)
-	 */
-	pid = fork();
-	if (pid == -1) {
-		purple_debug_error("dnssrv", "Could not create process!\n");
-		g_free(query);
-		g_free(query_data);
-		cb(NULL, extradata);
-		return NULL;
-	}
-
-	/* Child */
-	if (pid == 0)
-	{
-		g_free(query);
-		g_free(query_data);
-
-		close(out[0]);
-		close(in[1]);
-		resolve(in[0], out[1]);
-		/* resolve() does not return */
-	}
-
-	close(out[1]);
-	close(in[0]);
-
-	internal_query.type = T_TXT;
-	strncpy(internal_query.query, query, 255);
-	internal_query.query[255] = '\0';
-
-	if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
-		purple_debug_error("dnssrv", "Could not write to TXT resolver\n");
-
-	query_data->pid = pid;
-	query_data->fd_out = out[0];
-	query_data->fd_in = in[1];
-	query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data);
-
-	return query_data;
-#else
-	query_data->resolver = g_thread_try_new("dnssrv srv resolver", res_thread, query_data, &err);
-	if (query_data->resolver == NULL) {
-		query_data->error_message = g_strdup_printf("TXT thread create failure: %s\n", (err && err->message) ? err->message : "");
-		g_error_free(err);
-	}
-	else
-		g_thread_unref(query_data->resolver);
-
-	/* The query isn't going to happen, so finish the TXT lookup now.
-	 * Asynchronously call the callback since stuff may not expect
-	 * the callback to be called before this returns */
-	if (query_data->error_message != NULL)
-		query_data->handle = purple_timeout_add(0, res_main_thread_cb, query_data);
-
-	return query_data;
-#endif
-}
-
-const gchar *
-purple_txt_response_get_content(PurpleTxtResponse *resp)
-{
-	g_return_val_if_fail(resp != NULL, NULL);
-
-	return resp->content;
-}
-
-void purple_txt_response_destroy(PurpleTxtResponse *resp)
-{
-	g_return_if_fail(resp != NULL);
-
-	g_free(resp->content);
-	g_free(resp);
-}
-
-/*
- * Only used as the callback for the ui ops.
- */
-static void
-purple_srv_query_resolved(PurpleSrvTxtQueryData *query_data, GList *records)
-{
-	GList *l;
-	PurpleSrvResponse *records_array;
-	int i = 0, length;
-
-	g_return_if_fail(records != NULL);
-
-	if (query_data->cb.srv == NULL) {
-		purple_srv_txt_query_destroy(query_data);
-
-		while (records) {
-			g_free(records->data);
-			records = g_list_delete_link(records, records);
-		}
-		return;
-	}
-
-	records = purple_srv_sort(records);
-	length = g_list_length(records);
-
-	purple_debug_info("dnssrv", "SRV records resolved for %s, count: %d\n",
-	                            query_data->query, length);
-
-	records_array = g_new(PurpleSrvResponse, length);
-	for (l = records; l; l = l->next, i++) {
-		records_array[i] = *(PurpleSrvResponse *)l->data;
-	}
-
-	query_data->cb.srv(records_array, length, query_data->extradata);
-
-	purple_srv_txt_query_destroy(query_data);
-
-	while (records) {
-		g_free(records->data);
-		records = g_list_delete_link(records, records);
-	}
-}
-
-/*
- * Only used as the callback for the ui ops.
- */
-static void
-purple_txt_query_resolved(PurpleSrvTxtQueryData *query_data, GList *entries)
-{
-	g_return_if_fail(entries != NULL);
-
-	purple_debug_info("dnssrv", "TXT entries resolved for %s, count: %d\n", query_data->query, g_list_length(entries));
-
-	/* the callback should g_free the entries.
-	 */
-	if (query_data->cb.txt != NULL)
-		query_data->cb.txt(entries, query_data->extradata);
-	else {
-		while (entries) {
-			g_free(entries->data);
-			entries = g_list_delete_link(entries, entries);
-		}
-	}
-
-	purple_srv_txt_query_destroy(query_data);
-}
-
-static void
-purple_srv_query_failed(PurpleSrvTxtQueryData *query_data, const gchar *error_message)
-{
-	purple_debug_error("dnssrv", "%s\n", error_message);
-
-	if (query_data->cb.srv != NULL)
-		query_data->cb.srv(NULL, 0, query_data->extradata);
-
-	purple_srv_txt_query_destroy(query_data);
-}
-
-static gboolean
-purple_srv_txt_query_ui_resolve(PurpleSrvTxtQueryData *query_data)
-{
-	PurpleSrvTxtQueryUiOps *ops = purple_srv_txt_query_get_ui_ops();
-
-	if (ops && ops->resolve)
-		return ops->resolve(query_data, (query_data->type == T_SRV ? purple_srv_query_resolved : purple_txt_query_resolved), purple_srv_query_failed);
-
-	return FALSE;
-}
-
-void
-purple_srv_txt_query_set_ui_ops(PurpleSrvTxtQueryUiOps *ops)
-{
-	srv_txt_query_ui_ops = ops;
-}
-
-PurpleSrvTxtQueryUiOps *
-purple_srv_txt_query_get_ui_ops(void)
-{
-	/* It is perfectly acceptable for srv_txt_query_ui_ops to be NULL; this just
-	 * means that the default platform-specific implementation will be used.
-	 */
-	return srv_txt_query_ui_ops;
-}
-
-char *
-purple_srv_txt_query_get_query(PurpleSrvTxtQueryData *query_data)
-{
-	g_return_val_if_fail(query_data != NULL, NULL);
-
-	return query_data->query;
-}
-
-
-int
-purple_srv_txt_query_get_query_type(PurpleSrvTxtQueryData *query_data)
-{
-	g_return_val_if_fail(query_data != NULL, 0);
-
-	return query_data->type;
-}
-
-/**************************************************************************
- * GBoxed code
- **************************************************************************/
-static PurpleSrvTxtQueryUiOps *
-purple_srv_txt_query_ui_ops_copy(PurpleSrvTxtQueryUiOps *ops)
-{
-	PurpleSrvTxtQueryUiOps *ops_new;
-
-	g_return_val_if_fail(ops != NULL, NULL);
-
-	ops_new = g_new(PurpleSrvTxtQueryUiOps, 1);
-	*ops_new = *ops;
-
-	return ops_new;
-}
-
-GType
-purple_srv_txt_query_ui_ops_get_type(void)
-{
-	static GType type = 0;
-
-	if (type == 0) {
-		type = g_boxed_type_register_static("PurpleSrvTxtQueryUiOps",
-				(GBoxedCopyFunc)purple_srv_txt_query_ui_ops_copy,
-				(GBoxedFreeFunc)g_free);
-	}
-
-	return type;
-}
--- a/libpurple/dnssrv.h	Mon Dec 21 21:51:27 2015 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-/* purple
- *
- * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
- */
-
-#ifndef _PURPLE_DNSSRV_H
-#define _PURPLE_DNSSRV_H
-/**
- * SECTION:dnssrv
- * @section_id: libpurple-dnssrv
- * @short_description: <filename>dnssrv.h</filename>
- * @title: DNS SRV Utilities
- */
-
-#define PURPLE_TYPE_SRV_TXT_QUERY_UI_OPS (purple_srv_txt_query_ui_ops_get_type())
-
-typedef struct _PurpleSrvTxtQueryData PurpleSrvTxtQueryData;
-typedef struct _PurpleSrvResponse PurpleSrvResponse;
-typedef struct _PurpleTxtResponse PurpleTxtResponse;
-typedef struct _PurpleSrvTxtQueryUiOps PurpleSrvTxtQueryUiOps;
-
-#include <glib.h>
-#include <glib-object.h>
-
-struct _PurpleSrvResponse {
-	char hostname[256];
-	int port;
-	int weight;
-	int pref;
-};
-
-struct _PurpleTxtResponse {
-	char *content;
-};
-
-typedef void  (*PurpleSrvTxtQueryResolvedCallback) (PurpleSrvTxtQueryData *query_data, GList *records);
-typedef void  (*PurpleSrvTxtQueryFailedCallback) (PurpleSrvTxtQueryData *query_data, const gchar *error_message);
-
-/**
- * PurpleSrvTxtQueryUiOps:
- * @resolve: implemented, return %TRUE if the UI takes responsibility for SRV
- *           queries. When returning %FALSE, the standard implementation is
- *           used. These callbacks <emphasis>MUST</emphasis> be called
- *           asynchronously.
- * @destroy: Called just before @query_data is freed; this should cancel any
- *           further use of @query_data the UI would make. Unneeded if @resolve
- *           is not implemented.
- *
- * SRV Request UI operations;  UIs should implement this if they want to do SRV
- * lookups themselves, rather than relying on the core.
- *
- * See <link linkend="chapter-ui-ops">List of <literal>UiOps</literal> Structures</link>
- */
-struct _PurpleSrvTxtQueryUiOps
-{
-	gboolean (*resolve)(PurpleSrvTxtQueryData *query_data,
-	                    PurpleSrvTxtQueryResolvedCallback resolved_cb,
-	                    PurpleSrvTxtQueryFailedCallback failed_cb);
-
-	void (*destroy)(PurpleSrvTxtQueryData *query_data);
-
-	/*< private >*/
-	void (*_purple_reserved1)(void);
-	void (*_purple_reserved2)(void);
-	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
-};
-
-/**
- * PurpleSrvCallback:
- * @resp: An array of PurpleSrvResponse of size results.  The array
- *        is sorted based on the order described in the DNS SRV RFC.
- *        Users of this API should try each record in resp in order,
- *        starting at the beginning.
- */
-typedef void (*PurpleSrvCallback)(PurpleSrvResponse *resp, int results, gpointer data);
-
-/**
- * PurpleTxtCallback:
- * @responses:   A GList of PurpleTxtResponse objects.
- * @data:        The extra data passed to purple_txt_resolve.
- *
- * Callback that returns the data retrieved from a DNS TXT lookup.
- */
-typedef void (*PurpleTxtCallback)(GList *responses, gpointer data);
-
-G_BEGIN_DECLS
-
-/**
- * purple_srv_txt_query_ui_ops_get_type:
- *
- * Returns: The #GType for the #PurpleSrvTxtQueryUiOps boxed structure.
- */
-GType purple_srv_txt_query_ui_ops_get_type(void);
-
-/**
- * purple_srv_resolve:
- * @account:   The account that the query is being done for (or %NULL)
- * @protocol:  Name of the protocol (e.g. "sip")
- * @transport: Name of the transport ("tcp" or "udp")
- * @domain:    Domain name to query (e.g. "blubb.com")
- * @cb:        (scope call): A callback which will be called with the results
- * @extradata: Extra data to be passed to the callback
- *
- * Queries an SRV record.
- *
- * Returns: %NULL if there was an error, otherwise return a reference to
- *          a data structure that can be used to cancel the pending
- *          DNS query, if needed.
- */
-PurpleSrvTxtQueryData *purple_srv_resolve(PurpleAccount *account, const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata);
-
-/**
- * purple_txt_resolve:
- * @account:   The account that the query is being done for (or %NULL)
- * @owner:     Name of the protocol (e.g. "_xmppconnect")
- * @domain:    Domain name to query (e.g. "blubb.com")
- * @cb:        (scope call): A callback which will be called with the results
- * @extradata: Extra data to be passed to the callback
- *
- * Queries an TXT record.
- *
- * Returns: %NULL if there was an error, otherwise return a reference to
- *          a data structure that can be used to cancel the pending
- *          DNS query, if needed.
- */
-PurpleSrvTxtQueryData *purple_txt_resolve(PurpleAccount *account, const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata);
-
-/**
- * purple_txt_response_get_content:
- * @response:  The TXT response record
- *
- * Get the value of the current TXT record.
- *
- * Returns: The value of the current TXT record.
- */
-const gchar *purple_txt_response_get_content(PurpleTxtResponse *response);
-
-/**
- * purple_txt_response_destroy:
- * @response: The PurpleTxtResponse to destroy.
- *
- * Destroy a TXT DNS response object.
- */
-void purple_txt_response_destroy(PurpleTxtResponse *response);
-
-/**
- * purple_srv_txt_query_destroy:
- * @query_data: The SRV/TXT query to cancel.  This data structure
- *        is freed by this function.
- *
- * Cancel a SRV/TXT query and destroy the associated data structure.
- */
-void purple_srv_txt_query_destroy(PurpleSrvTxtQueryData *query_data);
-
-/**
- * purple_srv_txt_query_set_ui_ops:
- * @ops: The UI operations structure.
- *
- * Sets the UI operations structure to be used when doing a SRV/TXT
- * resolve.  The UI operations need only be set if the UI wants to
- * handle the resolve itself; otherwise, leave it as NULL.
- */
-void purple_srv_txt_query_set_ui_ops(PurpleSrvTxtQueryUiOps *ops);
-
-/**
- * purple_srv_txt_query_get_ui_ops:
- *
- * Returns the UI operations structure to be used when doing a SRV/TXT
- * resolve.
- *
- * Returns: The UI operations structure.
- */
-PurpleSrvTxtQueryUiOps *purple_srv_txt_query_get_ui_ops(void);
-
-/**
- * purple_srv_txt_query_get_query:
- * @query_data: The SRV/TXT query
- *
- * Get the query from a PurpleSrvTxtQueryData
- *
- * Returns: The query.
- */
-char *purple_srv_txt_query_get_query(PurpleSrvTxtQueryData *query_data);
-
-/**
- * purple_srv_txt_query_get_query_type:
- * @query_data: The query
- *
- * Get the type from a PurpleSrvTxtQueryData (TXT or SRV)
- *
- * Returns: The query type.
- */
-int purple_srv_txt_query_get_query_type(PurpleSrvTxtQueryData *query_data);
-
-G_END_DECLS
-
-#endif /* _PURPLE_DNSSRV_H */
-
--- a/libpurple/glibcompat.h	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/glibcompat.h	Tue Dec 22 20:25:45 2015 -0600
@@ -61,65 +61,6 @@
 	return FALSE;
 }
 
-#if !GLIB_CHECK_VERSION(2, 32, 0)
-
-#include <glib-object.h>
-#include <string.h>
-
-#define G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-#define G_GNUC_END_IGNORE_DEPRECATIONS
-
-#define G_SOURCE_REMOVE FALSE
-#define G_SOURCE_CONTINUE TRUE
-
-#define g_signal_handlers_disconnect_by_data(instance, data) \
-	g_signal_handlers_disconnect_matched((instance), G_SIGNAL_MATCH_DATA, \
-			0, 0, NULL, NULL, (data))
-
-static inline GByteArray * g_byte_array_new_take(guint8 *data, gsize len)
-{
-	GByteArray *array;
-
-	array = g_byte_array_new();
-	g_byte_array_append(array, data, len);
-	g_free(data);
-
-	return array;
-}
-
-static inline void g_queue_free_full(GQueue *queue, GDestroyNotify free_func)
-{
-	g_queue_foreach(queue, (GFunc)free_func, NULL);
-	g_queue_free(queue);
-}
-
-static inline GThread * g_thread_try_new(const gchar *name, GThreadFunc func,
-	gpointer data, GError **error)
-{
-	return g_thread_create(func, data, TRUE, error);
-}
-
-#if !GLIB_CHECK_VERSION(2, 30, 0)
-
-#define G_VALUE_INIT {0, {{0}}}
-
-static inline gchar *g_utf8_substring(const gchar *str, glong start_pos,
-	glong end_pos)
-{
-	gchar *start = g_utf8_offset_to_pointer(str, start_pos);
-	gchar *end = g_utf8_offset_to_pointer(start, end_pos - start_pos);
-	gchar *out = g_malloc(end - start + 1);
-
-	memcpy(out, start, end - start);
-	out[end - start] = 0;
-
-	return out;
-}
-
-#endif /* < 2.30.0 */
-
-#endif /* < 2.32.0 */
-
 #endif /* < 2.36.0 */
 
 
--- a/libpurple/network.c	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/network.c	Tue Dec 22 20:25:45 2015 -0600
@@ -21,6 +21,8 @@
 
 #include "internal.h"
 
+#include <gio/gio.h>
+
 #ifndef _WIN32
 #include <arpa/nameser.h>
 #include <resolv.h>
@@ -46,7 +48,6 @@
 #include "prefs.h"
 #include "stun.h"
 #include "upnp.h"
-#include "dnsquery.h"
 
 #ifdef USE_IDN
 #include <idna.h>
@@ -977,40 +978,26 @@
 #endif
 
 static void
-purple_network_ip_lookup_cb(GSList *hosts, gpointer data,
-	const char *error_message)
-{
-	const gchar **ip = (const gchar **) data;
+purple_network_ip_lookup_cb(GObject *sender, GAsyncResult *result, gpointer data) {
+	GError *error = NULL;
+	GList *addresses = NULL;
+	GInetAddress *address = NULL;
+	const gchar **ip_address = (const gchar **)data;
 
-	if (error_message) {
-		purple_debug_error("network", "lookup of IP address failed: %s\n",
-			error_message);
-		g_slist_free(hosts);
+	addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error);
+	if(error) {
+		purple_debug_info("network", "lookup of IP address failed: %s\n", error->message);
+
+		g_error_free(error);
+
 		return;
 	}
 
-	if (hosts && g_slist_next(hosts)) {
-		common_sockaddr_t *addr = g_slist_next(hosts)->data;
-		char dst[INET6_ADDRSTRLEN];
+	address = G_INET_ADDRESS(addresses->data);
 
-		if (addr->sa.sa_family == AF_INET6) {
-			inet_ntop(addr->sa.sa_family, &addr->in6.sin6_addr,
-				dst, sizeof(dst));
-		} else {
-			inet_ntop(addr->sa.sa_family, &addr->in.sin_addr,
-				dst, sizeof(dst));
-		}
+	*ip_address = g_inet_address_to_string(address);
 
-		*ip = g_strdup(dst);
-		purple_debug_info("network", "set IP address: %s\n", *ip);
-	}
-
-	while (hosts != NULL) {
-		hosts = g_slist_delete_link(hosts, hosts);
-		/* Free the address */
-		g_free(hosts->data);
-		hosts = g_slist_delete_link(hosts, hosts);
-	}
+	g_resolver_free_addresses(addresses);
 }
 
 void
@@ -1018,9 +1005,11 @@
 {
 	if (stun_server && stun_server[0] != '\0') {
 		if (purple_network_is_available()) {
-			purple_debug_info("network", "running DNS query for STUN server\n");
-			purple_dnsquery_a(NULL, stun_server, 3478, purple_network_ip_lookup_cb,
-				&stun_ip);
+			g_resolver_lookup_by_name_async(g_resolver_get_default(),
+			                                stun_server,
+			                                NULL,
+			                                purple_network_ip_lookup_cb,
+			                                &stun_ip);
 		} else {
 			purple_debug_info("network",
 				"network is unavailable, don't try to update STUN IP");
@@ -1036,10 +1025,11 @@
 {
 	if (turn_server && turn_server[0] != '\0') {
 		if (purple_network_is_available()) {
-			purple_debug_info("network", "running DNS query for TURN server\n");
-			purple_dnsquery_a(NULL, turn_server,
-				purple_prefs_get_int("/purple/network/turn_port"),
-				purple_network_ip_lookup_cb, &turn_ip);
+			g_resolver_lookup_by_name_async(g_resolver_get_default(),
+			                                turn_server,
+			                                NULL,
+			                                purple_network_ip_lookup_cb,
+			                                &turn_server);
 		} else {
 			purple_debug_info("network",
 				"network is unavailable, don't try to update TURN IP");
--- a/libpurple/protocols/gg/resolver-purple.c	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/protocols/gg/resolver-purple.c	Tue Dec 22 20:25:45 2015 -0600
@@ -29,22 +29,22 @@
 
 #include <internal.h>
 #include <debug.h>
-#include <dnsquery.h>
 
 #include <libgadu.h>
 #include "resolver-purple.h"
 
+#include <gio/gio.h>
+
 static int ggp_resolver_purple_start(int *fd, void **private_data,
 	const char *hostname);
 
 static void ggp_resolver_purple_cleanup(void **private_data, int force);
 
-static void ggp_resolver_purple_cb(GSList *hosts, gpointer cbdata,
-	const char *error_message);
+static void ggp_resolver_purple_cb(GObject *sender, GAsyncResult *res, gpointer data);
 
 typedef struct
 {
-	PurpleDnsQueryData *purpleQuery;
+	GCancellable *cancellable;
 
 	/**
 	 * File descriptors:
@@ -64,67 +64,72 @@
 	}
 }
 
-void ggp_resolver_purple_cb(GSList *hosts, gpointer cbdata,
-	const char *error_message)
-{
+void ggp_resolver_purple_cb(GObject *sender, GAsyncResult *res, gpointer cbdata) {
+	GList *addresses = NULL, *in_addrs = NULL, *l = NULL;
+	GError *error = NULL;
+	gsize native_size = 0; /* this is kind of dirty, but it'll be initialized before we use it */
+
 	ggp_resolver_purple_data *data = (ggp_resolver_purple_data*)cbdata;
 	const int fd = data->pipes[1];
-	int ipv4_count, all_count, write_size;
-	struct in_addr *addresses;
-
-	purple_debug_misc("gg", "ggp_resolver_purple_cb(%p, %p, \"%s\")\n",
-		hosts, cbdata, error_message);
 
-	data->purpleQuery = NULL;
+	addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), res, &error);
+	if(addresses == NULL) {
+		purple_debug_error("gg", "ggp_resolver_purple_cb failed: %s\n",
+			error->message);
 
-	if (error_message) {
-		purple_debug_error("gg", "ggp_resolver_purple_cb failed: %s\n",
-			error_message);
+		g_error_free(error);
+	} else {
+		purple_debug_misc("gg", "ggp_resolver_purple_cb succeeded: (%p, %p)\n",
+			addresses, cbdata);
 	}
 
-	all_count = g_slist_length(hosts);
-	g_assert(all_count % 2 == 0);
-	all_count /= 2;
-	addresses = malloc((all_count + 1) * sizeof(struct in_addr));
+	g_object_unref(G_OBJECT(data->cancellable));
+	data->cancellable = NULL;
 
-	ipv4_count = 0;
-	while (hosts && (hosts = g_slist_delete_link(hosts, hosts))) {
-		common_sockaddr_t addr;
-		char dst[INET6_ADDRSTRLEN];
+	for(l = addresses; l; l = l->next) {
+		GInetAddress *inet_address = G_INET_ADDRESS(l->data);
+		GSocketFamily family = G_SOCKET_FAMILY_INVALID;
+		gchar *ip_address = g_inet_address_to_string(inet_address);
 
-		memcpy(&addr, hosts->data, sizeof(addr));
+		family = g_inet_address_get_family(inet_address);
+
+		switch(family) {
+			case G_SOCKET_FAMILY_IPV4:
+				purple_debug_misc("gg", "ggp_resolver_purple_cb "
+					"ipv4: %s\n", ip_address);
 
-		if (addr.sa.sa_family == AF_INET6) {
-			inet_ntop(addr.sa.sa_family, &addr.in6.sin6_addr,
-				dst, sizeof(dst));
-			purple_debug_misc("gg", "ggp_resolver_purple_cb "
-				"ipv6 (ignore): %s\n", dst);
-		} else if (addr.sa.sa_family == AF_INET) {
-			inet_ntop(addr.sa.sa_family, &addr.in.sin_addr,
-				dst, sizeof(dst));
-			purple_debug_misc("gg", "ggp_resolver_purple_cb "
-				"ipv4: %s\n", dst);
+				native_size = g_inet_address_get_native_size(inet_address);
+				in_addrs = g_list_append(in_addrs, g_memdup(g_inet_address_to_bytes(inet_address), native_size));
+
+				break;
+			case G_SOCKET_FAMILY_IPV6:
+				purple_debug_misc("gg", "ggp_resolver_purple_cb "
+					"ipv6 (ignore): %s\n", ip_address);
 
-			g_assert(ipv4_count < all_count);
-			addresses[ipv4_count++] = addr.in.sin_addr;
-		} else {
-			purple_debug_warning("gg", "ggp_resolver_purple_cb "
-				"unexpected sa_family: %d\n",
-				addr.sa.sa_family);
+				break;
+			default:
+				purple_debug_warning("gg", "ggp_resolver_purple_cb "
+					"unexpected sa_family: %d\n",
+					family);
+
+				break;
 		}
 
-		g_free(hosts->data);
-		hosts = g_slist_delete_link(hosts, hosts);
+		g_free(ip_address);
 	}
 
-	addresses[ipv4_count].s_addr = INADDR_NONE;
+	for(l = in_addrs; l; l = l->next) {
+		gint write_size = native_size;
+		if(write(fd, l->data, write_size) != write_size) {
+			purple_debug_error("gg",
+				"ggp_resolver_purple_cb write error on %p\n", l->data);
+		}
 
-	write_size = (ipv4_count + 1) * sizeof(struct in_addr);
-	if (write(fd, addresses, write_size) != write_size) {
-		purple_debug_error("gg",
-			"ggp_resolver_purple_cb write error\n");
+		g_free(l->data);
 	}
-	free(addresses);
+
+	g_list_free(in_addrs);
+	g_resolver_free_addresses(addresses);
 }
 
 int ggp_resolver_purple_start(int *fd, void **private_data,
@@ -136,7 +141,7 @@
 
 	data = malloc(sizeof(ggp_resolver_purple_data));
 	*private_data = (void*)data;
-	data->purpleQuery = NULL;
+	data->cancellable = NULL;
 	data->pipes[0] = 0;
 	data->pipes[1] = 0;
 
@@ -150,10 +155,15 @@
 	*fd = data->pipes[0];
 
 	/* account and port is unknown in this context */
-	data->purpleQuery = purple_dnsquery_a(NULL, hostname, 80,
-		ggp_resolver_purple_cb, (gpointer)data);
+	data->cancellable = g_cancellable_new();
 
-	if (!data->purpleQuery) {
+	g_resolver_lookup_by_name_async(g_resolver_get_default(),
+	                                hostname,
+	                                data->cancellable,
+	                                ggp_resolver_purple_cb,
+	                                (gpointer)data);
+
+	if (!data->cancellable) {
 		purple_debug_error("gg", "ggp_resolver_purple_start: "
 			"unable to call purple_dnsquery_a\n");
 		ggp_resolver_purple_cleanup(private_data, 0);
@@ -175,8 +185,12 @@
 		return;
 	*private_data = NULL;
 
-	if (data->purpleQuery)
-		purple_dnsquery_destroy(data->purpleQuery);
+	if (G_IS_CANCELLABLE(data->cancellable)) {
+		g_cancellable_cancel(data->cancellable);
+
+		g_object_unref(G_OBJECT(data->cancellable));
+	}
+
 	if (data->pipes[0])
 		close(data->pipes[0]);
 	if (data->pipes[1])
--- a/libpurple/protocols/jabber/disco.c	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/protocols/jabber/disco.c	Tue Dec 22 20:25:45 2015 -0600
@@ -419,76 +419,39 @@
 
 }
 
-/* should probably share this code with google.c, or maybe from 2.7.0
- introduce an abstracted hostname -> IP function in dns.c */
 static void
-jabber_disco_stun_lookup_cb(GSList *hosts, gpointer data,
-	const char *error_message)
-{
+jabber_disco_stun_srv_resolve_cb(GObject *sender, GAsyncResult *result, gpointer data) {
+	GError *error = NULL;
+	GList *services = NULL;
 	JabberStream *js = (JabberStream *) data;
+	gint results = 0;
 
-	if (error_message) {
-		purple_debug_error("jabber", "STUN lookup failed: %s\n",
-			error_message);
-		g_slist_free(hosts);
-		js->stun_query = NULL;
+	services = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error);
+
+	if(error != NULL) {
+		purple_debug_info("jabber", "Failed to look up a STUN record : %s\n", error->message);
+
+		g_error_free(error);
+
 		return;
 	}
 
-	if (hosts && g_slist_next(hosts)) {
-		common_sockaddr_t addr;
-		char dst[INET6_ADDRSTRLEN];
-		int port;
+	results = g_list_length(services);
 
-		memcpy(&addr, g_slist_next(hosts)->data, sizeof(addr));
+	purple_debug_info("jabber", "got %d SRV responses for STUN.\n", results);
 
-		if (addr.sa.sa_family == AF_INET6) {
-			inet_ntop(addr.sa.sa_family, &addr.in6.sin6_addr,
-				dst, sizeof(dst));
-			port = ntohs(addr.in6.sin6_port);
-		} else {
-			inet_ntop(addr.sa.sa_family, &addr.in.sin_addr,
-				dst, sizeof(dst));
-			port = ntohs(addr.in.sin_port);
-		}
+	if (results > 0) {
+		GSrvTarget *target = (GSrvTarget *)services->data;
+		const gchar *hostname = g_srv_target_get_hostname(target);
 
-		g_free(js->stun_ip);
-		js->stun_ip = g_strdup(dst);
-		js->stun_port = port;
+		js->stun_ip = g_strdup(hostname);
+		js->stun_port = g_srv_target_get_port(target);
 
-		purple_debug_info("jabber", "set STUN IP/port address: "
-		                  "%s:%d\n", dst, port);
-
-		/* unmark ongoing query */
-		js->stun_query = NULL;
+		purple_debug_info("jabber", "set stun address to %s:%d\n",
+			hostname, js->stun_port);
 	}
 
-	while (hosts != NULL) {
-		hosts = g_slist_delete_link(hosts, hosts);
-		/* Free the address */
-		g_free(hosts->data);
-		hosts = g_slist_delete_link(hosts, hosts);
-	}
-}
-
-
-static void
-jabber_disco_stun_srv_resolve_cb(PurpleSrvResponse *resp, int results, gpointer data)
-{
-	JabberStream *js = (JabberStream *) data;
-
-	purple_debug_info("jabber", "got %d SRV responses for STUN.\n", results);
-	js->srv_query_data = NULL;
-
-	if (results > 0) {
-		PurpleAccount *account;
-		purple_debug_info("jabber", "looking up IP for %s:%d\n",
-			resp[0].hostname, resp[0].port);
-		account = purple_connection_get_account(js->gc);
-		js->stun_query =
-			purple_dnsquery_a(account, resp[0].hostname, resp[0].port,
-				jabber_disco_stun_lookup_cb, js);
-	}
+	g_resolver_free_targets(services);
 }
 
 
@@ -552,11 +515,14 @@
 			}
 		} else if (purple_network_get_stun_ip() == NULL ||
 		    purple_strequal(purple_network_get_stun_ip(), "")) {
-			js->srv_query_data =
-				purple_srv_resolve(
-					purple_connection_get_account(js->gc), "stun", "udp",
-					js->user->domain,
-					jabber_disco_stun_srv_resolve_cb, js);
+
+			g_resolver_lookup_service_async(g_resolver_get_default(),
+			                                "stun",
+			                                "udp",
+			                                js->user->domain,
+			                                NULL,
+			                                jabber_disco_stun_srv_resolve_cb,
+			                                js);
 			/* TODO: add TURN support later... */
 		}
 	}
--- a/libpurple/protocols/jabber/google/jingleinfo.c	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/protocols/jabber/google/jingleinfo.c	Tue Dec 22 20:25:45 2015 -0600
@@ -22,54 +22,36 @@
 #include "debug.h"
 #include "jingleinfo.h"
 
+#include <gio/gio.h>
+
 static void
-jabber_google_stun_lookup_cb(GSList *hosts, gpointer data,
-	const char *error_message)
-{
+jabber_google_stun_lookup_cb(GObject *sender, GAsyncResult *result, gpointer data) {
+	GError *error = NULL;
+	GList *addresses = NULL;
 	JabberStream *js = (JabberStream *) data;
 
-	if (error_message) {
+	addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error);
+
+	if(error) {
 		purple_debug_error("jabber", "Google STUN lookup failed: %s\n",
-			error_message);
-		g_slist_free(hosts);
-		js->stun_query = NULL;
+			error->message);
+
+		g_error_free(error);
+
 		return;
 	}
 
-	if (hosts && g_slist_next(hosts)) {
-		common_sockaddr_t addr;
-		char dst[INET6_ADDRSTRLEN];
-		int port;
-
-		memcpy(&addr, g_slist_next(hosts)->data, sizeof(addr));
-
-		if (addr.sa.sa_family == AF_INET6) {
-			inet_ntop(addr.sa.sa_family, &addr.in6.sin6_addr,
-				dst, sizeof(dst));
-			port = ntohs(addr.in6.sin6_port);
-		} else {
-			inet_ntop(addr.sa.sa_family, &addr.in.sin_addr,
-				dst, sizeof(dst));
-			port = ntohs(addr.in.sin_port);
-		}
+	if(g_list_length(addresses) > 0) {
+		GInetAddress *inet_address = G_INET_ADDRESS(addresses->data);
 
 		g_free(js->stun_ip);
-		js->stun_ip = g_strdup(dst);
-		js->stun_port = port;
+		js->stun_ip = g_inet_address_to_string(inet_address);
 
 		purple_debug_info("jabber", "set Google STUN IP/port address: "
-		                  "%s:%d\n", dst, port);
-
-		/* unmark ongoing query */
-		js->stun_query = NULL;
+		                  "%s:%d\n", js->stun_ip, js->stun_port);
 	}
 
-	while (hosts != NULL) {
-		hosts = g_slist_delete_link(hosts, hosts);
-		/* Free the address */
-		g_free(hosts->data);
-		hosts = g_slist_delete_link(hosts, hosts);
-	}
+	g_resolver_free_addresses(addresses);
 }
 
 static void
@@ -110,16 +92,13 @@
 			const gchar *udp = purple_xmlnode_get_attrib(server, "udp");
 
 			if (host && udp) {
-				PurpleAccount *account;
-				int port = atoi(udp);
-				/* if there, would already be an ongoing query,
-				 cancel it */
-				if (js->stun_query)
-					purple_dnsquery_destroy(js->stun_query);
+				js->stun_port = atoi(udp);
 
-				account = purple_connection_get_account(js->gc);
-				js->stun_query = purple_dnsquery_a(account, host, port,
-					jabber_google_stun_lookup_cb, js);
+				g_resolver_lookup_by_name_async(g_resolver_get_default(),
+				                                host,
+				                                NULL,
+				                                jabber_google_stun_lookup_cb,
+				                                js);
 			}
 		}
 	}
--- a/libpurple/protocols/jabber/jabber.c	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/protocols/jabber/jabber.c	Tue Dec 22 20:25:45 2015 -0600
@@ -30,7 +30,6 @@
 #include "connection.h"
 #include "conversation.h"
 #include "debug.h"
-#include "dnssrv.h"
 #include "http.h"
 #include "message.h"
 #include "notify.h"
@@ -95,7 +94,6 @@
 static gint plugin_ref = 0;
 
 static void jabber_unregister_account_cb(JabberStream *js);
-static void try_srv_connect(JabberStream *js);
 
 static void jabber_stream_init(JabberStream *js)
 {
@@ -758,28 +756,54 @@
 }
 
 static void
-txt_resolved_cb(GList *responses, gpointer data)
+txt_resolved_cb(GObject *sender, GAsyncResult *result, gpointer data)
 {
+	GError *error = NULL;
+	GList *records = NULL, *l = NULL;
 	JabberStream *js = data;
 	gboolean found = FALSE;
 
-	js->srv_query_data = NULL;
-
-	while (responses) {
-		PurpleTxtResponse *resp = responses->data;
-		gchar **token;
-		token = g_strsplit(purple_txt_response_get_content(resp), "=", 2);
-		if (!strcmp(token[0], "_xmpp-client-xbosh")) {
-			purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]);
-			js->bosh = jabber_bosh_connection_new(js, token[1]);
+	records = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error);
+	if(error) {
+		purple_debug_warning("jabber", "Unable to find alternative XMPP connection "
+				  "methods after failing to connect directly. : %s\n",
+				  error->message);
+
+		purple_connection_error(js->gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				_("Unable to connect"));
+
+		g_error_free(error);
+
+		return;
+	}
+
+	for(l = records; l; l = l->next) {
+		GVariantIter *iter = NULL;
+		gchar *str = NULL;
+
+		g_variant_get((GVariant *)l->data, "(as)", &iter);
+		while(g_variant_iter_loop(iter, "s", &str)) {
+			gchar **token = g_strsplit(str, "=", 2);
+
+			if(!g_ascii_strcasecmp(token[0], "_xmpp-client-xbosh")) {
+				purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]);
+
+				js->bosh = jabber_bosh_connection_new(js, token[1]);
+
+				g_strfreev(token);
+
+				break;
+			}
+
 			g_strfreev(token);
-			break;
 		}
-		g_strfreev(token);
-		purple_txt_response_destroy(resp);
-		responses = g_list_delete_link(responses, responses);
+
+		g_variant_iter_free(iter);
 	}
 
+	g_list_free_full(records, (GDestroyNotify)g_variant_unref);
+
 	if (js->bosh)
 		found = TRUE;
 
@@ -791,11 +815,6 @@
 				_("Unable to connect"));
 		return;
 	}
-
-	if (responses) {
-		g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
-		g_list_free(responses);
-	}
 }
 
 static void
@@ -805,21 +824,21 @@
 	JabberStream *js = purple_connection_get_protocol_data(gc);
 
 	if (source < 0) {
-		if (js->srv_rec != NULL) {
-			purple_debug_error("jabber", "Unable to connect to server: %s.  Trying next SRV record or connecting directly.\n", error);
-			try_srv_connect(js);
-		} else {
-			purple_debug_info("jabber","Couldn't connect directly to %s.  Trying to find alternative connection methods, like BOSH.\n", js->user->domain);
-			js->srv_query_data = purple_txt_resolve(
-					purple_connection_get_account(gc), "_xmppconnect",
-					js->user->domain, txt_resolved_cb, js);
-		}
+		gchar *name = g_strdup_printf("_xmppconnect.%s", js->user->domain);
+
+		purple_debug_info("jabber", "Couldn't connect directly to %s.  Trying to find alternative connection methods, like BOSH.\n", js->user->domain);
+
+		g_resolver_lookup_records_async(g_resolver_get_default(),
+		                                name,
+		                                G_RESOLVER_RECORD_TXT,
+		                                js->cancellable,
+		                                txt_resolved_cb,
+		                                js);
+		g_free(name);
+
 		return;
 	}
 
-	g_free(js->srv_rec);
-	js->srv_rec = NULL;
-
 	js->fd = source;
 
 	if(js->state == JABBER_STREAM_CONNECTING)
@@ -881,37 +900,43 @@
 	return TRUE;
 }
 
-static void try_srv_connect(JabberStream *js)
+static void
+srv_resolved_cb(GObject *sender, GAsyncResult *result, gpointer data)
 {
-	while (js->srv_rec != NULL && js->srv_rec_idx < js->max_srv_rec_idx) {
-		PurpleSrvResponse *tmp_resp = js->srv_rec + (js->srv_rec_idx++);
-		if (jabber_login_connect(js, tmp_resp->hostname, tmp_resp->hostname, tmp_resp->port, FALSE))
-			return;
-	}
-
-	g_free(js->srv_rec);
-	js->srv_rec = NULL;
-
-	/* Fall back to the defaults (I'm not sure if we should actually do this) */
-	jabber_login_connect(js, js->user->domain, js->user->domain,
-			purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
-			TRUE);
-}
-
-static void srv_resolved_cb(PurpleSrvResponse *resp, int results, gpointer data)
-{
+	GError *error = NULL;
+	GList *targets = NULL, *l = NULL;
 	JabberStream *js = data;
-	js->srv_query_data = NULL;
-
-	if(results) {
-		js->srv_rec = resp;
-		js->srv_rec_idx = 0;
-		js->max_srv_rec_idx = results;
-		try_srv_connect(js);
-	} else {
+
+	targets = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error);
+	if(error) {
+		purple_debug_warning("jabber",
+		                     "SRV lookup failed, proceeding with normal connection : %s",
+		                     error->message);
+
+		g_error_free(error);
+
 		jabber_login_connect(js, js->user->domain, js->user->domain,
 				purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
 				TRUE);
+
+	} else {
+		for(l = targets; l; l = l->next) {
+			GSrvTarget *target = (GSrvTarget *)l->data;
+			const gchar *hostname = g_srv_target_get_hostname(target);
+			guint port = g_srv_target_get_port(target);
+
+			if(jabber_login_connect(js, hostname, hostname, port, FALSE)) {
+				g_resolver_free_targets(targets);
+
+				return;
+			}
+		}
+
+		g_resolver_free_targets(targets);
+
+		jabber_login_connect(js, js->user->domain, js->user->domain,
+				purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
+				TRUE);		
 	}
 }
 
@@ -930,6 +955,9 @@
 	js->fd = -1;
 	js->http_conns = purple_http_connection_set_new();
 
+	/* we might want to expose this at some point */
+	js->cancellable = g_cancellable_new();
+
 	user = g_strdup(purple_account_get_username(account));
 	/* jabber_id_new doesn't accept "user@domain/" as valid */
 	slash = strchr(user, '/');
@@ -1000,7 +1028,6 @@
 	js->sessions = NULL;
 	js->stun_ip = NULL;
 	js->stun_port = 0;
-	js->stun_query = NULL;
 	js->google_relay_token = NULL;
 	js->google_relay_host = NULL;
 
@@ -1062,8 +1089,13 @@
 		jabber_login_connect(js, js->user->domain, connect_server,
 				purple_account_get_int(account, "port", 5222), TRUE);
 	} else {
-		js->srv_query_data = purple_srv_resolve(account, "xmpp-client",
-				"tcp", js->user->domain, srv_resolved_cb, js);
+		g_resolver_lookup_service_async(g_resolver_get_default(),
+		                                "xmpp-client",
+		                                "tcp",
+		                                js->user->domain,
+		                                js->cancellable,
+		                                srv_resolved_cb,
+		                                js);
 	}
 }
 
@@ -1595,9 +1627,6 @@
 	} else if ((js->gsc && js->gsc->fd > 0) || js->fd > 0)
 		jabber_send_raw(js, "</stream:stream>", -1);
 
-	if (js->srv_query_data)
-		purple_srv_txt_query_destroy(js->srv_query_data);
-
 	if(js->gsc) {
 		purple_ssl_close(js->gsc);
 	} else if (js->fd > 0) {
@@ -1693,17 +1722,10 @@
 	if (js->conn_close_timeout != 0)
 		purple_timeout_remove(js->conn_close_timeout);
 
-	g_free(js->srv_rec);
-	js->srv_rec = NULL;
+	g_cancellable_cancel(js->cancellable);
+	g_object_unref(G_OBJECT(js->cancellable));
 
 	g_free(js->stun_ip);
-	js->stun_ip = NULL;
-
-	/* cancel DNS query for STUN, if one is ongoing */
-	if (js->stun_query) {
-		purple_dnsquery_destroy(js->stun_query);
-		js->stun_query = NULL;
-	}
 
 	/* remove Google relay-related stuff */
 	g_free(js->google_relay_token);
--- a/libpurple/protocols/jabber/jabber.h	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/protocols/jabber/jabber.h	Tue Dec 22 20:25:45 2015 -0600
@@ -57,10 +57,10 @@
 #include <libxml/parser.h>
 #include <glib.h>
 #include <gmodule.h>
+#include <gio/gio.h>
+
 #include "circularbuffer.h"
 #include "connection.h"
-#include "dnsquery.h"
-#include "dnssrv.h"
 #include "http.h"
 #include "media.h"
 #include "mediamanager.h"
@@ -120,7 +120,7 @@
 	int fd;
 	guint inpa;
 
-	PurpleSrvTxtQueryData *srv_query_data;
+	GCancellable *cancellable;
 
 	xmlParserCtxt *context;
 	PurpleXmlNode *current;
@@ -277,10 +277,6 @@
 	guint inactivity_timer;
 	guint conn_close_timeout;
 
-	PurpleSrvResponse *srv_rec;
-	guint srv_rec_idx;
-	guint max_srv_rec_idx;
-
 	PurpleJabberBOSHConnection *bosh;
 
 	PurpleHttpConnectionSet *http_conns;
@@ -291,7 +287,6 @@
 	/* maybe this should only be present when USE_VV? */
 	gchar *stun_ip;
 	int stun_port;
-	PurpleDnsQueryData *stun_query;
 
 	/* stuff for Google's relay handling */
 	gchar *google_relay_token;
--- a/libpurple/protocols/simple/simple.c	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/protocols/simple/simple.c	Tue Dec 22 20:25:45 2015 -0600
@@ -29,7 +29,6 @@
 #include "accountopt.h"
 #include "buddylist.h"
 #include "conversation.h"
-#include "dnsquery.h"
 #include "debug.h"
 #include "notify.h"
 #include "protocol.h"
@@ -41,7 +40,6 @@
 
 #include "simple.h"
 #include "sipmsg.h"
-#include "dnssrv.h"
 #include "ntlm.h"
 
 static PurpleProtocol *my_protocol = NULL;
@@ -1801,29 +1799,41 @@
 	do_register(sip);
 }
 
-static void simple_udp_host_resolved(GSList *hosts, gpointer data, const char *error_message) {
+static void
+simple_udp_host_resolved(GObject *sender, GAsyncResult *result, gpointer data) {
+	GError *error = NULL;
+	GList *addresses = NULL;
+	GInetAddress *inet_address = NULL;
+	GSocketAddress *socket_address = NULL;
 	struct simple_account_data *sip = (struct simple_account_data*) data;
-	int addr_size;
 
-	sip->query_data = NULL;
+	addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error);
+	if(error) {
+		gchar *msg = g_strdup_printf(_("Unable to resolve hostname : %s"),
+			error->message);
 
-	if (!hosts || !hosts->data) {
 		purple_connection_error(sip->gc,
 			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Unable to resolve hostname"));
+			msg
+			);
+
+		g_error_free(error);
+
 		return;
 	}
 
-	addr_size = GPOINTER_TO_INT(hosts->data);
-	hosts = g_slist_remove(hosts, hosts->data);
-	memcpy(&(sip->serveraddr), hosts->data, addr_size);
-	g_free(hosts->data);
-	hosts = g_slist_remove(hosts, hosts->data);
-	while(hosts) {
-		hosts = g_slist_remove(hosts, hosts->data);
-		g_free(hosts->data);
-		hosts = g_slist_remove(hosts, hosts->data);
-	}
+	inet_address = G_INET_ADDRESS(addresses->data);
+	socket_address = g_inet_socket_address_new(inet_address, sip->realport);
+	g_object_unref(G_OBJECT(inet_address));
+
+	g_socket_address_to_native(socket_address,
+	                           &(sip->serveraddr),
+	                           g_socket_address_get_native_size(socket_address),
+	                           NULL);
+
+	g_object_unref(G_OBJECT(socket_address));
+
+	g_resolver_free_addresses(addresses);
 
 	/* create socket for incoming connections */
 	sip->listen_data = purple_network_listen_range(5060, 5160, AF_UNSPEC, SOCK_DGRAM, TRUE,
@@ -1865,33 +1875,44 @@
 	}
 }
 
-static void srvresolved(PurpleSrvResponse *resp, int results, gpointer data) {
+static void
+srvresolved(GObject *sender, GAsyncResult *result, gpointer data) {
+	GError *error = NULL;
+	GList *targets = NULL;
 	struct simple_account_data *sip;
 	gchar *hostname;
 	int port;
 
 	sip = data;
-	sip->srv_query_data = NULL;
-
-	port = purple_account_get_int(sip->account, "port", 0);
 
-	/* find the host to connect to */
-	if(results) {
-		hostname = g_strdup(resp->hostname);
-		if(!port)
-			port = resp->port;
-		g_free(resp);
-	} else {
+	targets = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error);
+	if(error) {
+		purple_debug_info("simple",
+		                  "srv lookup failed, continuing with configured settings : %s",
+		                  error->message);
+
+		g_error_free(error);
+
 		if(!purple_account_get_bool(sip->account, "useproxy", FALSE)) {
 			hostname = g_strdup(sip->servername);
 		} else {
 			hostname = g_strdup(purple_account_get_string(sip->account, "proxy", sip->servername));
-		}
+		}		
+		port = purple_account_get_int(sip->account, "port", 0);
+	} else {
+		GSrvTarget *target = (GSrvTarget *)targets->data;
+
+		hostname = g_strdup(g_srv_target_get_hostname(target));
+		port = g_srv_target_get_port(target);
+
+		g_resolver_free_targets(targets);
 	}
 
 	sip->realhostname = hostname;
 	sip->realport = port;
-	if(!sip->realport) sip->realport = 5060;
+
+	if(!sip->realport)
+		sip->realport = 5060;
 
 	/* TCP case */
 	if(!sip->udp) {
@@ -1907,13 +1928,11 @@
 	} else { /* UDP */
 		purple_debug_info("simple", "using udp with server %s and port %d\n", hostname, port);
 
-		sip->query_data = purple_dnsquery_a(sip->account, hostname,
-			port, simple_udp_host_resolved, sip);
-		if (sip->query_data == NULL) {
-			purple_connection_error(sip->gc,
-				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-				_("Unable to resolve hostname"));
-		}
+		g_resolver_lookup_by_name_async(g_resolver_get_default(),
+		                                sip->realhostname,
+		                                sip->cancellable,
+		                                simple_udp_host_resolved,
+		                                sip);
 	}
 }
 
@@ -1975,8 +1994,13 @@
 		hosttoconnect = purple_account_get_string(account, "proxy", sip->servername);
 	}
 
-	sip->srv_query_data = purple_srv_resolve(account, "sip",
-			sip->udp ? "udp" : "tcp", hosttoconnect, srvresolved, sip);
+	g_resolver_lookup_service_async(g_resolver_get_default(),
+	                                "sip",
+	                                sip->udp ? "udp" : "tcp",
+	                                hosttoconnect,
+	                                sip->cancellable,
+	                                srvresolved,
+	                                sip);
 }
 
 static void simple_close(PurpleConnection *gc)
@@ -2008,11 +2032,9 @@
 		purple_timeout_remove(sip->resendtimeout);
 	if (sip->registertimeout)
 		purple_timeout_remove(sip->registertimeout);
-	if (sip->query_data != NULL)
-		purple_dnsquery_destroy(sip->query_data);
 
-	if (sip->srv_query_data != NULL)
-		purple_srv_txt_query_destroy(sip->srv_query_data);
+	g_cancellable_cancel(sip->cancellable);
+	g_object_unref(G_OBJECT(sip->cancellable));
 
 	if (sip->listen_data != NULL)
 		purple_network_listen_cancel(sip->listen_data);
--- a/libpurple/protocols/simple/simple.h	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/protocols/simple/simple.h	Tue Dec 22 20:25:45 2015 -0600
@@ -25,12 +25,11 @@
 
 #include <glib.h>
 #include <gmodule.h>
+#include <gio/gio.h>
 #include <time.h>
 
 #include "cipher.h"
 #include "circularbuffer.h"
-#include "dnsquery.h"
-#include "dnssrv.h"
 #include "network.h"
 #include "proxy.h"
 #include "protocol.h"
@@ -100,8 +99,7 @@
 	gchar *servername;
 	gchar *username;
 	gchar *password;
-	PurpleDnsQueryData *query_data;
-	PurpleSrvTxtQueryData *srv_query_data;
+	GCancellable *cancellable;
 	PurpleNetworkListenData *listen_data;
 	int fd;
 	int cseq;
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c	Tue Dec 22 20:25:45 2015 -0600
@@ -23,7 +23,6 @@
 /* TODO: it needs further refactoring */
 
 #include "internal.h"
-#include "dnsquery.h"
 
 #include "protocol.h"
 #include "util.h"
@@ -39,6 +38,8 @@
 #include "yahoo_doodle.h"
 #include "yahoo_friend.h"
 
+#include <gio/gio.h>
+
 struct yahoo_xfer_data {
 	gchar *url;
 	gboolean is_relay;
@@ -498,14 +499,15 @@
 	return ans;
 }
 
-static void yahoo_xfer_dns_connected_15(GSList *hosts, gpointer data, const char *error_message)
+static void
+yahoo_xfer_dns_connected_15(GObject *sender, GAsyncResult *result, gpointer data) 
 {
+	GError *error = NULL;
+	GList *addresses = NULL;
+	GInetAddress *inet_address = NULL;
 	PurpleXfer *xfer;
 	struct yahoo_xfer_data *xd;
-	struct sockaddr_in *addr;
 	struct yahoo_packet *pkt;
-	unsigned long actaddr;
-	unsigned char a,b,c,d;
 	PurpleConnection *gc;
 	PurpleAccount *account;
 	YahooData *yd;
@@ -519,47 +521,22 @@
 	account = purple_connection_get_account(gc);
 	yd = purple_connection_get_protocol_data(gc);
 
-	if(!hosts)
-	{
-		purple_debug_error("yahoo", "Unable to find an IP address for relay.msg.yahoo.com\n");
-		purple_xfer_cancel_remote(xfer);
-		return;
-	}
+	addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error);
+	if(error) {
+		purple_debug_error("yahoo",
+		                   "Unable to find an IP address for relay.msg.yahoo.com : %s\n",
+		                   error->message);
 
-	/* Discard the length... */
-	hosts = g_slist_remove(hosts, hosts->data);
-	if(!hosts)
-	{
-		purple_debug_error("yahoo", "Unable to find an IP address for relay.msg.yahoo.com\n");
 		purple_xfer_cancel_remote(xfer);
+		g_error_free(error);
+
 		return;
 	}
 
-	/* TODO:actually, u must try with addr no.1 , if its not working addr no.2 ..... */
-	addr = hosts->data;
-	actaddr = addr->sin_addr.s_addr;
-	d = actaddr & 0xff;
-	actaddr >>= 8;
-	c = actaddr & 0xff;
-	actaddr >>= 8;
-	b = actaddr & 0xff;
-	actaddr >>= 8;
-	a = actaddr & 0xff;
-
-	xd->host = g_strdup_printf("%u.%u.%u.%u", d, c, b, a);
+	inet_address = G_INET_ADDRESS(addresses->data);
+	xd->host = g_inet_address_to_string(inet_address);
 
-	/* Free the address... */
-	g_free(hosts->data);
-	hosts = g_slist_remove(hosts, hosts->data);
-	addr = NULL;
-	while (hosts != NULL)
-	{
-		/* Discard the length... */
-		hosts = g_slist_remove(hosts, hosts->data);
-		/* Free the address... */
-		g_free(hosts->data);
-		hosts = g_slist_remove(hosts, hosts->data);
-	}
+	g_resolver_free_addresses(addresses);
 
 	pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
 	filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
@@ -700,7 +677,6 @@
 	}
 	if(val_222 == 3)
 	{
-		PurpleAccount *account;
 		struct yahoo_xfer_data *xd;
 
 		xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map,
@@ -726,10 +702,12 @@
 		}
 		xd->is_relay = TRUE;
 
-		account = purple_connection_get_account(gc);
-		purple_dnsquery_a(account, YAHOO_XFER_RELAY_HOST,
-			YAHOO_XFER_RELAY_PORT,
-			yahoo_xfer_dns_connected_15, xfer);
+		g_resolver_lookup_by_name_async(g_resolver_get_default(),
+		                                YAHOO_XFER_RELAY_HOST,
+		                                NULL,
+		                                yahoo_xfer_dns_connected_15,
+		                                xfer);
+
 		return;
 	}
 
--- a/libpurple/proxy.c	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/proxy.c	Tue Dec 22 20:25:45 2015 -0600
@@ -1,4 +1,4 @@
-/* purple
+ /* purple
  *
  * Purple is the legal property of its developers, whose names are too numerous
  * to list here.  Please refer to the COPYRIGHT file distributed with this
@@ -29,7 +29,6 @@
 #include "internal.h"
 #include "ciphers/md5hash.h"
 #include "debug.h"
-#include "dnsquery.h"
 #include "http.h"
 #include "notify.h"
 #include "ntlm.h"
@@ -37,6 +36,8 @@
 #include "proxy.h"
 #include "util.h"
 
+#include <gio/gio.h>
+
 struct _PurpleProxyInfo
 {
 	PurpleProxyType type; /* The proxy type.  */
@@ -57,13 +58,14 @@
 	int socket_type;
 	guint inpa;
 	PurpleProxyInfo *gpi;
-	PurpleDnsQueryData *query_data;
+
+	GCancellable *cancellable;
 
 	/*
-	 * This contains alternating length/char* values.  The char*
-	 * values need to be freed when removed from the linked list.
+	 * This list contains GInetAddress and they should be freed with
+	 * g_resolver_free_addresses when done with.
 	 */
-	GSList *hosts;
+	GList *hosts;
 
 	PurpleProxyConnectData *child;
 
@@ -574,18 +576,16 @@
 
 	handles = g_slist_remove(handles, connect_data);
 
-	if (connect_data->query_data != NULL)
-		purple_dnsquery_destroy(connect_data->query_data);
-
-	while (connect_data->hosts != NULL)
-	{
-		/* Discard the length... */
-		connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data);
-		/* Free the address... */
-		g_free(connect_data->hosts->data);
-		connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data);
+	if(G_IS_CANCELLABLE(connect_data->cancellable)) {
+		g_cancellable_cancel(connect_data->cancellable);
+
+		g_object_unref(G_OBJECT(connect_data->cancellable));
+
+		connect_data->cancellable = NULL;
 	}
 
+	g_resolver_free_addresses(connect_data->hosts);
+
 	g_free(connect_data->host);
 	g_free(connect_data);
 }
@@ -1307,16 +1307,31 @@
 }
 
 static void
-s4_host_resolved(GSList *hosts, gpointer data, const char *error_message)
+s4_host_resolved(GObject *source_object, GAsyncResult *res, gpointer data)
 {
+	GResolver *resolver = NULL;
+	GInetAddress *address = NULL;
+	GError *error = NULL;
+	GList *hosts = NULL, *l = NULL;
 	PurpleProxyConnectData *connect_data = data;
 	unsigned char packet[9];
-	common_sockaddr_t *addr;
-
-	connect_data->query_data = NULL;
-
-	if (error_message != NULL) {
-		purple_proxy_connect_data_disconnect(connect_data, error_message);
+
+	if(G_IS_CANCELLABLE(connect_data->cancellable)) {
+		g_object_unref(G_OBJECT(connect_data->cancellable));
+
+		connect_data->cancellable = NULL;
+	}
+
+	resolver = g_resolver_get_default();
+
+	hosts = g_resolver_lookup_by_name_finish(resolver, res, &error);
+	g_object_unref(G_OBJECT(resolver));
+
+	if (error->message != NULL) {
+		purple_proxy_connect_data_disconnect(connect_data, error->message);
+
+		g_error_free(error);
+
 		return;
 	}
 
@@ -1326,37 +1341,37 @@
 		return;
 	}
 
-	/* Discard the length... */
-	hosts = g_slist_delete_link(hosts, hosts);
-	addr = hosts->data;
-	hosts = g_slist_delete_link(hosts, hosts);
-
-	packet[0] = 0x04;
-	packet[1] = 0x01;
-	packet[2] = connect_data->port >> 8;
-	packet[3] = connect_data->port & 0xff;
-	memcpy(packet + 4, &addr->in.sin_addr.s_addr, 4);
-	packet[8] = 0x00;
-
-	g_free(addr);
-
-	/* We could try the other hosts, but hopefully that shouldn't be necessary */
-	while (hosts != NULL) {
-		/* Discard the length... */
-		hosts = g_slist_delete_link(hosts, hosts);
-		/* Free the address... */
-		g_free(hosts->data);
-		hosts = g_slist_delete_link(hosts, hosts);
+	for(l = hosts; l; l = l->next) {
+		address = G_INET_ADDRESS(l->data);
+
+		if(!g_inet_address_get_is_loopback(address) && !g_inet_address_get_is_link_local(address))
+			break;
+
+		address = NULL;
 	}
 
-	connect_data->write_buffer = g_memdup(packet, sizeof(packet));
-	connect_data->write_buf_len = sizeof(packet);
-	connect_data->written_len = 0;
-	connect_data->read_cb = s4_canread;
-
-	connect_data->inpa = purple_input_add(connect_data->fd, PURPLE_INPUT_WRITE, proxy_do_write, connect_data);
-
-	proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
+	if(address != NULL) {
+		packet[0] = 0x04;
+		packet[1] = 0x01;
+		packet[2] = connect_data->port >> 8;
+		packet[3] = connect_data->port & 0xff;
+		memcpy(packet + 4, g_inet_address_to_bytes(address), 4);
+		packet[8] = 0x00;
+
+		connect_data->write_buffer = g_memdup(packet, sizeof(packet));
+		connect_data->write_buf_len = sizeof(packet);
+		connect_data->written_len = 0;
+		connect_data->read_cb = s4_canread;
+
+		connect_data->inpa = purple_input_add(connect_data->fd, PURPLE_INPUT_WRITE, proxy_do_write, connect_data);
+
+		proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
+	} else {
+		purple_proxy_connect_data_disconnect_formatted(connect_data,
+				_("Error resolving %s"), connect_data->host);
+	}
+
+	g_resolver_free_addresses(hosts);
 }
 
 static void
@@ -1416,11 +1431,21 @@
 
 		proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
 	} else {
-		connect_data->query_data = purple_dnsquery_a(
-				connect_data->account, connect_data->host,
-				connect_data->port, s4_host_resolved, connect_data);
-
-		if (connect_data->query_data == NULL) {
+		GResolver *resolver = NULL;
+
+		connect_data->cancellable = g_cancellable_new();
+
+		resolver = g_resolver_get_default();
+
+		g_resolver_lookup_by_name_async(resolver,
+		                                connect_data->host,
+		                                connect_data->cancellable,
+		                                s4_host_resolved,
+		                                connect_data);
+
+		g_object_unref(G_OBJECT(resolver));
+
+		if (connect_data->cancellable == NULL) {
 			purple_debug_error("proxy", "dns query failed unexpectedly.\n");
 			purple_proxy_connect_data_destroy(connect_data);
 		}
@@ -2134,83 +2159,98 @@
 
 static void try_connect(PurpleProxyConnectData *connect_data)
 {
-	socklen_t addrlen;
-	common_sockaddr_t *addr;
-	char ipaddr[INET6_ADDRSTRLEN];
-
-	addrlen = GPOINTER_TO_INT(connect_data->hosts->data);
-	connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data);
-	addr = connect_data->hosts->data;
-	connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data);
-#ifdef HAVE_INET_NTOP
-	if (addr->sa.sa_family == AF_INET)
-		inet_ntop(addr->sa.sa_family, &addr->in.sin_addr,
-				ipaddr, sizeof(ipaddr));
-	else if (addr->sa.sa_family == AF_INET6)
-		inet_ntop(addr->sa.sa_family, &addr->in6.sin6_addr,
-				ipaddr, sizeof(ipaddr));
-#else
-	memcpy(ipaddr, inet_ntoa(addr->in.sin_addr), sizeof(ipaddr));
-#endif
+	GInetAddress *address = NULL;
+	GSocketAddress *socket_address = NULL;
+	GError *error = NULL;
+	char *ipaddr;
+
+	common_sockaddr_t addr;
+	socklen_t addrlen = 0;
+
+	address = G_INET_ADDRESS(connect_data->hosts->data);
+	ipaddr = g_inet_address_to_string(address);
+
 	purple_debug_info("proxy", "Attempting connection to %s\n", ipaddr);
+	g_free(ipaddr);
+
+	socket_address = g_inet_socket_address_new(address, connect_data->port);
+	addrlen = g_socket_address_get_native_size(socket_address);
+
+	g_socket_address_to_native(socket_address, &addr, addrlen, &error);
+	if(error != NULL) {
+		purple_debug_info("proxy", "failed connnection : %s\n", error->message);
+
+		g_error_free(error);
+
+		return;
+	}
 
 	if (connect_data->socket_type == SOCK_DGRAM) {
-		proxy_connect_udp_none(connect_data, addr, addrlen);
-		g_free(addr);
+		proxy_connect_udp_none(connect_data, &addr, addrlen);
+
 		return;
 	}
 
 	switch (purple_proxy_info_get_proxy_type(connect_data->gpi)) {
 		case PURPLE_PROXY_NONE:
-			proxy_connect_none(connect_data, addr, addrlen);
+			proxy_connect_none(connect_data, &addr, addrlen);
 			break;
 
 		case PURPLE_PROXY_HTTP:
-			proxy_connect_http(connect_data, addr, addrlen);
+			proxy_connect_http(connect_data, &addr, addrlen);
 			break;
 
 		case PURPLE_PROXY_SOCKS4:
-			proxy_connect_socks4(connect_data, addr, addrlen);
+			proxy_connect_socks4(connect_data, &addr, addrlen);
 			break;
 
 		case PURPLE_PROXY_SOCKS5:
 		case PURPLE_PROXY_TOR:
-			proxy_connect_socks5(connect_data, addr, addrlen);
+			proxy_connect_socks5(connect_data, &addr, addrlen);
 			break;
 
 		case PURPLE_PROXY_USE_ENVVAR:
-			proxy_connect_http(connect_data, addr, addrlen);
+			proxy_connect_http(connect_data, &addr, addrlen);
 			break;
 
 		default:
 			break;
 	}
 
-	g_free(addr);
+	g_object_unref(G_OBJECT(socket_address));
 }
 
 static void
-connection_host_resolved(GSList *hosts, gpointer data,
-						 const char *error_message)
-{
-	PurpleProxyConnectData *connect_data;
-
-	connect_data = data;
-	connect_data->query_data = NULL;
-
-	if (error_message != NULL)
-	{
-		purple_proxy_connect_data_disconnect(connect_data, error_message);
+connection_host_resolved(GObject *source, GAsyncResult *res, gpointer data) {
+	PurpleProxyConnectData *connect_data = (PurpleProxyConnectData *)data;
+	GError *error = NULL;
+	GList *addresses = NULL;
+
+	addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), res, &error);
+
+	if(G_IS_CANCELLABLE(connect_data->cancellable)) {
+		g_object_unref(G_OBJECT(connect_data->cancellable));
+
+		connect_data->cancellable = NULL;
+	}
+
+	if (error != NULL) {
+		purple_proxy_connect_data_disconnect(connect_data, error->message);
+
+		g_error_free(error);
+
+		g_resolver_free_addresses(addresses);
+
 		return;
 	}
 
-	if (hosts == NULL)
-	{
+	if (addresses == NULL) {
 		purple_proxy_connect_data_disconnect(connect_data, _("Unable to resolve hostname"));
+
 		return;
 	}
 
-	connect_data->hosts = hosts;
+	connect_data->hosts = addresses;
 
 	try_connect(connect_data);
 }
@@ -2349,9 +2389,15 @@
 			return NULL;
 	}
 
-	connect_data->query_data = purple_dnsquery_a(account, connecthost,
-			connectport, connection_host_resolved, connect_data);
-	if (connect_data->query_data == NULL)
+	connect_data->cancellable = g_cancellable_new();
+
+	g_resolver_lookup_by_name_async(g_resolver_get_default(),
+	                                connecthost,
+	                                connect_data->cancellable,
+	                                connection_host_resolved,
+	                                connect_data);
+
+	if (connect_data->cancellable == NULL)
 	{
 		purple_debug_error("proxy", "dns query failed unexpectedly.\n");
 		purple_proxy_connect_data_destroy(connect_data);
@@ -2420,10 +2466,15 @@
 			return NULL;
 	}
 
-	connect_data->query_data = purple_dnsquery_a(account, connecthost,
-			connectport, connection_host_resolved, connect_data);
-	if (connect_data->query_data == NULL)
-	{
+	connect_data->cancellable = g_cancellable_new();
+
+	g_resolver_lookup_by_name_async(g_resolver_get_default(),
+	                                connecthost,
+	                                connect_data->cancellable,
+	                                connection_host_resolved,
+	                                connect_data);
+
+	if (connect_data->cancellable == NULL) {
 		purple_proxy_connect_data_destroy(connect_data);
 		return NULL;
 	}
--- a/libpurple/purple.h.in	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/purple.h.in	Tue Dec 22 20:25:45 2015 -0600
@@ -62,8 +62,6 @@
 #include <core.h>
 #include <debug.h>
 #include <desktopitem.h>
-#include <dnsquery.h>
-#include <dnssrv.h>
 #include <enums.h>
 #include <eventloop.h>
 #include <idle.h>
--- a/libpurple/stun.c	Mon Dec 21 21:51:27 2015 -0600
+++ b/libpurple/stun.c	Tue Dec 22 20:25:45 2015 -0600
@@ -29,6 +29,8 @@
 #include <sys/ioctl.h>
 #endif
 
+#include <gio/gio.h>
+
 /* Solaris */
 #if defined (__SVR4) && defined (__sun)
 #include <sys/sockio.h>
@@ -36,8 +38,6 @@
 
 #include "debug.h"
 #include "account.h"
-#include "dnsquery.h"
-#include "dnssrv.h"
 #include "network.h"
 #include "proxy.h"
 #include "stun.h"
@@ -82,6 +82,11 @@
 	size_t packetsize;
 };
 
+typedef struct {
+	gint port;
+	GList *addresses;
+} StunHBNListenData;
+
 static PurpleStunNatDiscovery nattype = {
 	PURPLE_STUN_STATUS_UNDISCOVERED,
 	PURPLE_STUN_NAT_TYPE_PUBLIC_IP,
@@ -283,8 +288,11 @@
 }
 
 
-static void hbn_listen_cb(int fd, gpointer data) {
-	GSList *hosts = data;
+static void
+hbn_listen_cb(int fd, gpointer data) {
+	StunHBNListenData *ld = (StunHBNListenData *)data;
+	GInetAddress *address = NULL;
+	GSocketAddress *socket_address = NULL;
 	struct stun_conn *sc;
 	static struct stun_header hdr_data;
 
@@ -304,15 +312,15 @@
 
 	sc->incb = purple_input_add(fd, PURPLE_INPUT_READ, reply_cb, sc);
 
-	hosts = g_slist_delete_link(hosts, hosts);
-	memcpy(&(sc->addr), hosts->data, sizeof(struct sockaddr_in));
-	g_free(hosts->data);
-	hosts = g_slist_delete_link(hosts, hosts);
-	while (hosts) {
-		hosts = g_slist_delete_link(hosts, hosts);
-		g_free(hosts->data);
-		hosts = g_slist_delete_link(hosts, hosts);
-	}
+	address = G_INET_ADDRESS(ld->addresses->data);
+	socket_address = g_inet_socket_address_new(address, ld->port);
+
+	g_socket_address_to_native(socket_address, &(sc->addr), g_socket_address_get_native_size(socket_address), NULL);
+
+	g_object_unref(G_OBJECT(address));
+	g_object_unref(G_OBJECT(socket_address));
+	g_resolver_free_addresses(ld->addresses);
+	g_free(ld);
 
 	hdr_data.type = htons(MSGTYPE_BINDINGREQUEST);
 	hdr_data.len = 0;
@@ -336,44 +344,59 @@
 	sc->timeout = purple_timeout_add(500, (GSourceFunc) timeoutfunc, sc);
 }
 
-static void hbn_cb(GSList *hosts, gpointer data, const char *error_message) {
+static void
+hbn_cb(GObject *sender, GAsyncResult *res, gpointer data) {
+	StunHBNListenData *ld = NULL;
+	GError *error = NULL;
 
-	if(!hosts || !hosts->data) {
+	ld = g_new0(StunHBNListenData, 1);
+
+	ld->addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), res, &error);
+	if(error != NULL) {
 		nattype.status = PURPLE_STUN_STATUS_UNDISCOVERED;
 		nattype.lookup_time = time(NULL);
+
 		do_callbacks();
+
 		return;
 	}
 
-	if (!purple_network_listen_range(12108, 12208, AF_UNSPEC, SOCK_DGRAM, TRUE, hbn_listen_cb, hosts)) {
-		while (hosts) {
-			hosts = g_slist_delete_link(hosts, hosts);
-			g_free(hosts->data);
-			hosts = g_slist_delete_link(hosts, hosts);
-		}
-
+	if (!purple_network_listen_range(12108, 12208, AF_UNSPEC, SOCK_DGRAM, TRUE, hbn_listen_cb, ld)) {
 		nattype.status = PURPLE_STUN_STATUS_UNKNOWN;
 		nattype.lookup_time = time(NULL);
+
 		do_callbacks();
+
 		return;
 	}
+}
+
+static void
+do_test1(GObject *sender, GAsyncResult *res, gpointer data) {
+	GList *services = NULL;
+	GError *error = NULL;
+	const char *servername = data;
+	int port = 3478;
+
+	services = g_resolver_lookup_service_finish(g_resolver_get_default(), res, &error);
+	if(error != NULL) {
+		purple_debug_info("stun", "Failed to look up srv record : %s\n", error->message);
+
+		g_error_free(error);
+	} else {
+		servername = g_srv_target_get_hostname((GSrvTarget *)services->data);
+		port = g_srv_target_get_port((GSrvTarget *)services->data);
+	}
 
-
-}
-
-static void do_test1(PurpleSrvResponse *resp, int results, gpointer sdata) {
-	const char *servername = sdata;
-	int port = 3478;
+	purple_debug_info("stun", "connecting to %s:%d\n", servername, port);
 
-	if(results) {
-		servername = resp[0].hostname;
-		port = resp[0].port;
-	}
-	purple_debug_info("stun", "got %d SRV responses, server: %s, port: %d\n",
-		results, servername, port);
+	g_resolver_lookup_by_name_async(g_resolver_get_default(),
+	                                servername,
+	                                NULL,
+	                                hbn_cb,
+	                                GINT_TO_POINTER(port));
 
-	purple_dnsquery_a(NULL, servername, port, hbn_cb, NULL);
-	g_free(resp);
+	g_resolver_free_targets(services);
 }
 
 static gboolean call_callback(gpointer data) {
@@ -431,8 +454,14 @@
 	nattype.servername = g_strdup(servername);
 
 	callbacks = g_slist_append(callbacks, cb);
-	purple_srv_resolve(NULL, "stun", "udp", servername, do_test1,
-		(gpointer) servername);
+
+	g_resolver_lookup_service_async(g_resolver_get_default(),
+	                                "stun",
+	                                "udp",
+	                                servername,
+	                                NULL,
+	                                do_test1,
+	                                (gpointer)servername);
 
 	return &nattype;
 }

mercurial