diff libpurple/dnssrv.c @ 31426:08dcd2d4f0b7

Added PurpleSrvTxtQueryUiOps which allow UIs to specify their own mechanisms to resolve SRV and/or TXT queries. Additionally, some functions and datatypes have been renamed to show which are SRV only, which TXT only, and which are used by both.
author thijsalkemade@gmail.com
date Thu, 24 Mar 2011 23:22:29 +0000
parents 47ea27481972
children 25d12d5929e0
line wrap: on
line diff
--- a/libpurple/dnssrv.c	Thu Mar 24 15:18:14 2011 +0000
+++ b/libpurple/dnssrv.c	Thu Mar 24 23:22:29 2011 +0000
@@ -31,19 +31,19 @@
 #include <arpa/nameser_compat.h>
 #endif
 #ifndef T_SRV
-#define T_SRV	33
+#define T_SRV	PurpleDnsTypeSrv
 #endif
 #ifndef T_TXT
-#define T_TXT	16
+#define T_TXT	PurpleDnsTypeTxt
 #endif
 #else /* WIN32 */
 #include <windns.h>
 /* Missing from the mingw headers */
 #ifndef DNS_TYPE_SRV
-# define DNS_TYPE_SRV 33
+# define DNS_TYPE_SRV PurpleDnsTypeSrv
 #endif
 #ifndef DNS_TYPE_TXT
-# define DNS_TYPE_TXT 16
+# define DNS_TYPE_TXT PurpleDnsTypeTxt
 #endif
 #endif
 
@@ -52,6 +52,8 @@
 #include "eventloop.h"
 #include "network.h"
 
+static PurpleSrvTxtQueryUiOps *srv_txt_query_ui_ops = NULL;
+
 #ifndef _WIN32
 typedef union {
 	HEADER hdr;
@@ -66,11 +68,7 @@
 	DNS_FREE_TYPE FreeType) = NULL;
 #endif
 
-struct _PurpleTxtResponse {
-	char *content;
-};
-
-struct _PurpleSrvQueryData {
+struct _PurpleSrvTxtQueryData {
 	union {
 		PurpleSrvCallback srv;
 		PurpleTxtCallback txt;
@@ -79,9 +77,9 @@
 	gpointer extradata;
 	guint handle;
 	int type;
+	char *query;
 #ifdef _WIN32
 	GThread *resolver;
-	char *query;
 	char *error_message;
 	GList *results;
 #else
@@ -100,6 +98,8 @@
 	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
@@ -430,7 +430,7 @@
 {
 	int size;
 	int type;
-	PurpleSrvQueryData *query_data = (PurpleSrvQueryData*)data;
+	PurpleSrvTxtQueryData *query_data = (PurpleSrvTxtQueryData*)data;
 	int i;
 	int status;
 
@@ -532,7 +532,7 @@
 res_main_thread_cb(gpointer data)
 {
 	PurpleSrvResponse *srvres = NULL;
-	PurpleSrvQueryData *query_data = data;
+	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) {
@@ -592,7 +592,7 @@
 	PDNS_RECORD dr = NULL;
 	int type;
 	DNS_STATUS ds;
-	PurpleSrvQueryData *query_data = data;
+	PurpleSrvTxtQueryData *query_data = data;
 	type = query_data->type;
 	ds = MyDnsQuery_UTF8(query_data->query, type, DNS_QUERY_STANDARD, NULL, &dr, NULL);
 	if (ds != ERROR_SUCCESS) {
@@ -672,12 +672,12 @@
 
 #endif
 
-PurpleSrvQueryData *
+PurpleSrvTxtQueryData *
 purple_srv_resolve(const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata)
 {
 	char *query;
 	char *hostname;
-	PurpleSrvQueryData *query_data;
+	PurpleSrvTxtQueryData *query_data;
 #ifndef _WIN32
 	PurpleSrvInternalQuery internal_query;
 	int in[2], out[2];
@@ -709,6 +709,17 @@
 	purple_debug_info("dnssrv","querying SRV record for %s: %s\n", domain,
 			query);
 	g_free(hostname);
+	
+	query_data = g_new0(PurpleSrvTxtQueryData, 1);
+	query_data->type = T_SRV;
+	query_data->cb.srv = cb;
+	query_data->extradata = extradata;
+	query_data->query = query;
+	
+	if (purple_srv_txt_query_ui_resolve(query_data))
+	{
+		return query_data;
+	}
 
 #ifndef _WIN32
 	if(pipe(in) || pipe(out)) {
@@ -747,10 +758,6 @@
 	if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
 		purple_debug_error("dnssrv", "Could not write to SRV resolver\n");
 
-	query_data = g_new0(PurpleSrvQueryData, 1);
-	query_data->type = T_SRV;
-	query_data->cb.srv = cb;
-	query_data->extradata = extradata;
 	query_data->pid = pid;
 	query_data->fd_out = out[0];
 	query_data->fd_in = in[1];
@@ -767,7 +774,7 @@
 		initialized = TRUE;
 	}
 
-	query_data = g_new0(PurpleSrvQueryData, 1);
+	query_data = g_new0(PurpleSrvTxtQueryData, 1);
 	query_data->type = DNS_TYPE_SRV;
 	query_data->cb.srv = cb;
 	query_data->query = query;
@@ -793,11 +800,11 @@
 #endif
 }
 
-PurpleSrvQueryData *purple_txt_resolve(const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata)
+PurpleSrvTxtQueryData *purple_txt_resolve(const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata)
 {
 	char *query;
 	char *hostname;
-	PurpleSrvQueryData *query_data;
+	PurpleSrvTxtQueryData *query_data;
 #ifndef _WIN32
 	PurpleSrvInternalQuery internal_query;
 	int in[2], out[2];
@@ -823,6 +830,18 @@
 	purple_debug_info("dnssrv","querying TXT record for %s: %s\n", domain,
 			query);
 	g_free(hostname);
+	
+	query_data = g_new0(PurpleSrvTxtQueryData, 1);
+	query_data->type = T_TXT;
+	query_data->cb.txt = cb;
+	query_data->extradata = extradata;
+	query_data->query = query;
+	
+	if (purple_srv_txt_query_ui_resolve(query_data)) {
+		/* query intentionally not freed
+		 */
+		return query_data;
+	}
 
 #ifndef _WIN32
 	if(pipe(in) || pipe(out)) {
@@ -860,11 +879,7 @@
 
 	if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
 		purple_debug_error("dnssrv", "Could not write to TXT resolver\n");
-
-	query_data = g_new0(PurpleSrvQueryData, 1);
-	query_data->type = T_TXT;
-	query_data->cb.txt = cb;
-	query_data->extradata = extradata;
+	
 	query_data->pid = pid;
 	query_data->fd_out = out[0];
 	query_data->fd_in = in[1];
@@ -881,7 +896,7 @@
 		initialized = TRUE;
 	}
 
-	query_data = g_new0(PurpleSrvQueryData, 1);
+	query_data = g_new0(PurpleSrvTxtQueryData, 1);
 	query_data->type = DNS_TYPE_TXT;
 	query_data->cb.txt = cb;
 	query_data->query = query;
@@ -908,8 +923,13 @@
 }
 
 void
-purple_srv_cancel(PurpleSrvQueryData *query_data)
+purple_srv_cancel(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
@@ -933,7 +953,7 @@
 }
 
 void
-purple_txt_cancel(PurpleSrvQueryData *query_data)
+purple_txt_cancel(PurpleSrvTxtQueryData *query_data)
 {
 	purple_srv_cancel(query_data);
 }
@@ -953,3 +973,85 @@
 	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)
+{
+	g_return_if_fail(records != NULL);
+	
+	purple_debug_info("dnssrv", "SRV records resolved for %s, count: %d\n", query_data->query, g_list_length(records));
+	
+	if (query_data->cb.srv != NULL)
+		query_data->cb.srv(purple_srv_sort(records)->data, g_list_length(records), query_data->extradata);
+}
+
+/*
+ * 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));
+
+	if (query_data->cb.txt != NULL)
+		query_data->cb.txt(entries, query_data->extradata);
+}
+
+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_cancel(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_type(PurpleSrvTxtQueryData *query_data)
+{
+	g_return_val_if_fail(query_data != NULL, 0);
+	
+	return query_data->type;
+}
\ No newline at end of file