pidgin/pidgin

Remove all of the dns code
use-gresolver
2015-12-15, Gary Kramlich
0e80c61f83d3
Parents 03b1fd2e362b
Children a89108f1030a
Remove all of the dns code
--- a/libpurple/Makefile.am Tue Dec 15 19:37:32 2015 -0500
+++ b/libpurple/Makefile.am Tue Dec 15 22:03: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/dnsquery.c Tue Dec 15 19:37:32 2015 -0500
+++ /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 Tue Dec 15 19:37:32 2015 -0500
+++ /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 Tue Dec 15 19:37:32 2015 -0500
+++ /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 Tue Dec 15 19:37:32 2015 -0500
+++ /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 */
-