changeset 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 5043fc53f957
children feb07422513c
files ChangeLog.API libpurple/dnsquery.h libpurple/dnssrv.c libpurple/dnssrv.h libpurple/gaim-compat.h libpurple/protocols/jabber/jabber.h libpurple/protocols/simple/simple.h
diffstat 7 files changed, 230 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.API	Thu Mar 24 15:18:14 2011 +0000
+++ b/ChangeLog.API	Thu Mar 24 23:22:29 2011 +0000
@@ -14,6 +14,9 @@
 		* purple_media_manager_set_video_caps (Jakub Adam) (#13095)
 		* Added add_buddy_with_invite to PurplePluginProtocolInfo
 		* Added add_buddies_with_invite to PurplePluginProtocolInfo
+		* Added PurpleSrvTxtQueryUiOps which allow UIs to specify their
+		  own mechanisms to resolve SRV and/or TXT queries. It works
+		  similar to PurpleDnsQueryUiOps
 
 		Deprecated:
 		* purple_account_add_buddy
--- a/libpurple/dnsquery.h	Thu Mar 24 15:18:14 2011 +0000
+++ b/libpurple/dnsquery.h	Thu Mar 24 23:22:29 2011 +0000
@@ -58,7 +58,8 @@
  */
 typedef struct
 {
-	/** If implemented, the UI is responsible for DNS queries */
+	/** If implemented, return TRUE if the UI takes responsibility for DNS
+	  * queries. When returning FALSE, the standard implementation is used. */
 	gboolean (*resolve_host)(PurpleDnsQueryData *query_data,
 	                         PurpleDnsQueryResolvedCallback resolved_cb,
 	                         PurpleDnsQueryFailedCallback failed_cb);
--- 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
--- a/libpurple/dnssrv.h	Thu Mar 24 15:18:14 2011 +0000
+++ b/libpurple/dnssrv.h	Thu Mar 24 23:22:29 2011 +0000
@@ -28,12 +28,21 @@
 extern "C" {
 #endif
 
-typedef struct _PurpleSrvQueryData PurpleSrvQueryData;
+typedef struct _PurpleSrvTxtQueryData PurpleSrvTxtQueryData;
 typedef struct _PurpleSrvResponse PurpleSrvResponse;
 typedef struct _PurpleTxtResponse PurpleTxtResponse;
 
+/* For compatibility, should be removed for 3.0.0
+ */
+typedef struct _PurpleSrvTxtQueryData PurpleSrvQueryData;
+
 #include <glib.h>
 
+enum PurpleDnsType {
+	PurpleDnsTypeTxt = 16,
+	PurpleDnsTypeSrv = 33
+};
+
 struct _PurpleSrvResponse {
 	char hostname[256];
 	int port;
@@ -41,6 +50,40 @@
 	int pref;
 };
 
+struct _PurpleTxtResponse {
+	char *content;
+};
+
+typedef void  (*PurpleSrvTxtQueryResolvedCallback) (PurpleSrvTxtQueryData *query_data, GList *records);
+typedef void  (*PurpleSrvTxtQueryFailedCallback) (PurpleSrvTxtQueryData *query_data, const gchar *error_message);
+
+/**
+ * SRV Request UI operations;  UIs should implement this if they want to do SRV
+ * lookups themselves, rather than relying on the core.
+ *
+ * @see @ref ui-ops
+ */
+typedef struct
+{
+	/** If implemented, return TRUE if the UI takes responsibility for SRV
+	  * queries. When returning FALSE, the standard implementation is used. 
+	  * These callbacks MUST be called asynchronously. */
+	gboolean (*resolve)(PurpleSrvTxtQueryData *query_data,
+	                    PurpleSrvTxtQueryResolvedCallback resolved_cb,
+	                    PurpleSrvTxtQueryFailedCallback failed_cb);
+
+	/** Called just before @a query_data is freed; this should cancel any
+	 *  further use of @a query_data the UI would make. Unneeded if
+	 *  #resolve_host is not implemented.
+	 */
+	void (*destroy)(PurpleSrvTxtQueryData *query_data);
+
+	void (*_purple_reserved1)(void);
+	void (*_purple_reserved2)(void);
+	void (*_purple_reserved3)(void);
+	void (*_purple_reserved4)(void);
+} PurpleSrvTxtQueryUiOps;
+
 /**
  * @param resp An array of PurpleSrvResponse of size results.  The array
  *        is sorted based on the order described in the DNS SRV RFC.
@@ -66,14 +109,14 @@
  * @param cb A callback which will be called with the results
  * @param extradata Extra data to be passed to the callback
  */
-PurpleSrvQueryData *purple_srv_resolve(const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata);
+PurpleSrvTxtQueryData *purple_srv_resolve(const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata);
 
 /**
- * Cancel an SRV DNS query.
+ * Cancel an SRV or DNS query.
  *
  * @param query_data The request to cancel.
  */
-void purple_srv_cancel(PurpleSrvQueryData *query_data);
+void purple_srv_cancel(PurpleSrvTxtQueryData *query_data);
 
 /**
  * Queries an TXT record.
@@ -85,7 +128,7 @@
  *
  * @since 2.6.0
  */
-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);
 
 /**
  * Cancel an TXT DNS query.
@@ -93,7 +136,7 @@
  * @param query_data The request to cancel.
  * @since 2.6.0
  */
-void purple_txt_cancel(PurpleSrvQueryData *query_data);
+void purple_txt_cancel(PurpleSrvTxtQueryData *query_data);
 
 /**
  * Get the value of the current TXT record.
@@ -112,6 +155,47 @@
  */
 void purple_txt_response_destroy(PurpleTxtResponse *response);
 
+/**
+ * Cancel a SRV/TXT query and destroy the associated data structure.
+ *
+ * @param query_data The SRV/TXT query to cancel.  This data structure
+ *        is freed by this function.
+ */
+void purple_srv_txt_query_destroy(PurpleSrvTxtQueryData *query_data);
+
+/**
+ * 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.
+ *
+ * @param ops The UI operations structure.
+ */
+void purple_srv_txt_query_set_ui_ops(PurpleSrvTxtQueryUiOps *ops);
+
+/**
+ * Returns the UI operations structure to be used when doing a SRV/TXT
+ * resolve.
+ *
+ * @return The UI operations structure.
+ */
+PurpleSrvTxtQueryUiOps *purple_srv_txt_query_get_ui_ops(void);
+
+/**
+ * Get the query from a PurpleDnsQueryData
+ *
+ * @param query_data The SRV/TXT query
+ * @return The query.
+ */
+char *purple_srv_txt_query_get_query(PurpleSrvTxtQueryData *query_data);
+
+/**
+ * Get the type from a PurpleDnsQueryData (TXT or SRV)
+ *
+ * @param query_data The query
+ * @return The query.
+ */
+int purple_srv_txt_query_get_type(PurpleSrvTxtQueryData *query_data);
+
 #ifdef __cplusplus
 }
 #endif
--- a/libpurple/gaim-compat.h	Thu Mar 24 15:18:14 2011 +0000
+++ b/libpurple/gaim-compat.h	Thu Mar 24 23:22:29 2011 +0000
@@ -841,7 +841,7 @@
 /* from dnssrv.h */
 
 #define GaimSrvResponse   PurpleSrvResponse
-#define GaimSrvQueryData  PurpleSrvQueryData
+#define GaimSrvQueryData  PurpleSrvTxtQueryData
 #define GaimSrvCallback   PurpleSrvCallback
 
 #define gaim_srv_resolve  purple_srv_resolve
--- a/libpurple/protocols/jabber/jabber.h	Thu Mar 24 15:18:14 2011 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Thu Mar 24 23:22:29 2011 +0000
@@ -100,7 +100,7 @@
 {
 	int fd;
 
-	PurpleSrvQueryData *srv_query_data;
+	PurpleSrvTxtQueryData *srv_query_data;
 
 	xmlParserCtxt *context;
 	xmlnode *current;
--- a/libpurple/protocols/simple/simple.h	Thu Mar 24 15:18:14 2011 +0000
+++ b/libpurple/protocols/simple/simple.h	Thu Mar 24 23:22:29 2011 +0000
@@ -83,7 +83,7 @@
 	gchar *username;
 	gchar *password;
 	PurpleDnsQueryData *query_data;
-	PurpleSrvQueryData *srv_query_data;
+	PurpleSrvTxtQueryData *srv_query_data;
 	PurpleNetworkListenData *listen_data;
 	int fd;
 	int cseq;