# HG changeset patch # User Tobias Markmann # Date 1217594073 0 # Node ID affaa4c4836ea9b43985904ddd53858916d0a0f9 # Parent 6606566f15ff1eaea67d52b1131e98fc45d4b335 * some code style adjustments in caps.c * some DNS API changes to prepare TXT record resolving support diff -r 6606566f15ff -r affaa4c4836e libpurple/dnssrv.c --- a/libpurple/dnssrv.c Tue Jul 15 22:16:26 2008 +0000 +++ b/libpurple/dnssrv.c Fri Aug 01 12:34:33 2008 +0000 @@ -33,12 +33,18 @@ #ifndef T_SRV #define T_SRV 33 #endif +#ifndef T_TXT +#define T_TXT 16 +#endif #else #include /* Missing from the mingw headers */ #ifndef DNS_TYPE_SRV # define DNS_TYPE_SRV 33 #endif +#ifndef DNS_TYPE_TXT +# define DNS_TYPE_TXT 16 +#endif #endif #include "dnssrv.h" @@ -60,9 +66,11 @@ #endif struct _PurpleSrvQueryData { - PurpleSrvCallback cb; + PurpleSrvCallback srv_cb; + PurpleTxtCallback txt_cb; gpointer extradata; guint handle; + int type; #ifdef _WIN32 GThread *resolver; char *query; @@ -74,6 +82,11 @@ #endif }; +typedef struct _PurpleSrvInternalQuery { + int type; + char query[256]; +} PurpleSrvInternalQuery; + static gint responsecompare(gconstpointer ar, gconstpointer br) { @@ -99,6 +112,7 @@ { GList *ret = NULL; PurpleSrvResponse *srvres; + PurpleTxtResponse *txtres; queryans answer; int size; int qdcount; @@ -107,19 +121,19 @@ guchar *cp; gchar name[256]; guint16 type, dlen, pref, weight, port; - gchar query[256]; + PurpleSrvInternalQuery query; #ifdef HAVE_SIGNAL_H purple_restore_default_signal_handlers(); #endif - if (read(in, query, 256) <= 0) { + if (read(in, &query, sizeof(query)) <= 0) { close(out); close(in); _exit(0); } - size = res_query( query, C_IN, T_SRV, (u_char*)&answer, sizeof( answer)); + size = res_query( query.query, C_IN, query.type, (u_char*)&answer, sizeof( answer)); qdcount = ntohs(answer.hdr.qdcount); ancount = ntohs(answer.hdr.ancount); @@ -148,7 +162,7 @@ GETSHORT(dlen,cp); - if (type == T_SRV) { + if (query.type == T_SRV) { GETSHORT(pref,cp); GETSHORT(weight,cp); @@ -168,6 +182,14 @@ srvres->weight = weight; ret = g_list_insert_sorted(ret, srvres, responsecompare); + } else if (query.type == T_TXT) { + size = dn_expand( (unsigned char*)&answer, end, cp, name, 256); + if(size < 0 ) + goto end; + txtres = g_new0(PurpleTxtResponse, 1); + strcpy(txtres->content, name); + + ret = g_list_append(ret, txtres); } else { cp += dlen; } @@ -175,10 +197,12 @@ end: size = g_list_length(ret); + write(out, &(query.type), sizeof(query.type)); write(out, &size, sizeof(int)); while (ret != NULL) { - write(out, ret->data, sizeof(PurpleSrvResponse)); + if (query.type == T_SRV) write(out, ret->data, sizeof(PurpleSrvResponse)); + if (query.type == T_TXT) write(out, ret->data, sizeof(PurpleTxtResponse)); g_free(ret->data); ret = g_list_remove(ret, ret->data); } @@ -193,39 +217,67 @@ resolved(gpointer data, gint source, PurpleInputCondition cond) { int size; + int type; PurpleSrvQueryData *query_data = (PurpleSrvQueryData*)data; - PurpleSrvResponse *res; - PurpleSrvResponse *tmp; int i; - PurpleSrvCallback cb = query_data->cb; int status; - - if (read(source, &size, sizeof(int)) == sizeof(int)) - { - 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)); + + if (read(source, &type, sizeof(type)) == sizeof(type)) { + purple_debug_info("dnssrv","type: %d\n", type); + if (type == T_SRV) { + PurpleSrvResponse *res; + PurpleSrvResponse *tmp; + PurpleSrvCallback cb = query_data->srv_cb; + if (read(source, &size, sizeof(int)) == sizeof(int)) { + 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; + } + } + } else { + purple_debug_info("dnssrv","found 0 SRV entries; errno is %i\n", errno); size = 0; - g_free(res); res = NULL; } + cb(res, size, query_data->extradata); + } else if (type == T_TXT) { + PurpleTxtResponse *res; + PurpleTxtResponse *tmp; + PurpleTxtCallback cb = query_data->txt_cb; + if (read(source, &size, sizeof(int)) == sizeof(int)) { + ssize_t red; + purple_debug_info("dnssrv","found %d TXT entries\n", size); + tmp = res = g_new0(PurpleTxtResponse, size); + for (i = 0; i < size; i++) { + red = read(source, tmp++, sizeof(PurpleTxtResponse)); + if (red != sizeof(PurpleTxtResponse)) { + purple_debug_error("dnssrv","unable to read txt " + "response: %s\n", g_strerror(errno)); + size = 0; + g_free(res); + res = NULL; + } + } + } else { + purple_debug_info("dnssrv","found 0 SRV entries; errno is %i\n", errno); + size = 0; + res = NULL; + } + cb(res, size, query_data->extradata); + } else { + purple_debug_info("dnssrv","type unknown of DNS result entry; errno is %i\n", errno); } } - else - { - purple_debug_info("dnssrv","found 0 SRV entries; errno is %i\n", errno); - size = 0; - res = NULL; - } - cb(res, size, query_data->extradata); waitpid(query_data->pid, &status, 0); - purple_srv_cancel(query_data); } @@ -237,34 +289,57 @@ res_main_thread_cb(gpointer data) { PurpleSrvResponse *srvres = NULL; + PurpleTxtResponse *txtres = NULL; int size = 0; PurpleSrvQueryData *query_data = data; - if(query_data->error_message != NULL) purple_debug_error("dnssrv", query_data->error_message); else { - PurpleSrvResponse *srvres_tmp = NULL; - GSList *lst = query_data->results; + if (query_data->type == T_SRV) { + PurpleSrvResponse *srvres_tmp = NULL; + GSList *lst = query_data->results; + + size = g_slist_length(lst); - size = g_slist_length(lst); + if(query_data->srv_cb && size > 0) + srvres_tmp = srvres = g_new0(PurpleSrvResponse, size); + while (lst) { + if(query_data->cb) + memcpy(srvres_tmp++, lst->data, sizeof(PurpleSrvResponse)); + g_free(lst->data); + lst = g_slist_remove(lst, lst->data); + } + + query_data->results = NULL; - if(query_data->cb && size > 0) - srvres_tmp = srvres = g_new0(PurpleSrvResponse, size); - while (lst) { - if(query_data->cb) - memcpy(srvres_tmp++, lst->data, sizeof(PurpleSrvResponse)); - g_free(lst->data); - lst = g_slist_remove(lst, lst->data); + purple_debug_info("dnssrv", "found %d SRV entries\n", size); + + if(query_data->srv_cb) query_data->srv_cb(srvres, size, query_data->extradata); + } else if (query_data->type == T_TXT) { + PurpleTxtResponse *txtres_tmp = NULL; + GSList *lst = query_data->results; + + size = g_slist_length(lst); + + if(query_data->txt_cb && size > 0) + txtres_tmp = txtres = g_new0(PurpleTxtResponse, size); + while (lst) { + if(query_data->txt_cb) + memcpy(txtres_tmp++, lst->data, sizeof(PurpleTxtResponse)); + g_free(lst->data); + lst = g_slist_remove(lst, lst->data); + } + + query_data->results = NULL; + + purple_debug_info("dnssrv", "found %d TXT entries\n", size); + + if(query_data->txt_cb) query_data->txt_cb(txtres, size, query_data->extradata); + } else { + purple_debug_error("dnssrv", "unknown query type"); } - - query_data->results = NULL; - - purple_debug_info("dnssrv", "found %d SRV entries\n", size); } - if(query_data->cb) - query_data->cb(srvres, size, query_data->extradata); - query_data->resolver = NULL; query_data->handle = 0; @@ -277,40 +352,50 @@ res_thread(gpointer data) { PDNS_RECORD dr = NULL; - int type = DNS_TYPE_SRV; + int type; DNS_STATUS ds; PurpleSrvQueryData *query_data = data; - + type = query_data->type; ds = MyDnsQuery_UTF8(query_data->query, type, DNS_QUERY_STANDARD, NULL, &dr, NULL); if (ds != ERROR_SUCCESS) { gchar *msg = g_win32_error_message(ds); - query_data->error_message = g_strdup_printf("Couldn't look up SRV record. %s (%lu).\n", msg, ds); + if (type == T_SRV) { + query_data->error_message = g_strdup_printf("Couldn't look up SRV record. %s (%lu).\n", msg, ds); + } else if (type == T_TXT) { + query_data->error_message = g_strdup_printf("Couldn't look up TXT record. %s (%lu).\n", msg, ds); + } g_free(msg); } else { - PDNS_RECORD dr_tmp; - GSList *lst = NULL; - DNS_SRV_DATA *srv_data; - PurpleSrvResponse *srvres; + if (type == T_SRV) { + PDNS_RECORD dr_tmp; + GSList *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; + } - 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_slist_insert_sorted(lst, srvres, responsecompare); } - 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_slist_insert_sorted(lst, srvres, responsecompare); + MyDnsRecordListFree(dr, DnsFreeRecordList); + query_data->results = lst; + } else if (type == T_TXT) { + #error IMPLEMENTATION MISSING + } else { + } - - MyDnsRecordListFree(dr, DnsFreeRecordList); - query_data->results = lst; } /* back to main thread */ @@ -328,6 +413,7 @@ { char *query; PurpleSrvQueryData *query_data; + PurpleSrvInternalQuery internal_query; #ifndef _WIN32 int in[2], out[2]; int pid; @@ -369,11 +455,16 @@ close(out[1]); close(in[0]); - if (write(in[1], query, strlen(query)+1) < 0) + internal_query.type = T_SRV; + strncpy(internal_query.query, query, 255); + + 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->cb = cb; + query_data->type = T_SRV; + query_data->srv_cb = cb; query_data->extradata = extradata; query_data->pid = pid; query_data->fd_out = out[0]; @@ -392,7 +483,100 @@ } query_data = g_new0(PurpleSrvQueryData, 1); - query_data->cb = cb; + query_data->srv_cb = cb; + query_data->query = query; + query_data->extradata = extradata; + + if (!MyDnsQuery_UTF8 || !MyDnsRecordListFree) + query_data->error_message = g_strdup("System missing DNS API (Requires W2K+)\n"); + else { + query_data->resolver = g_thread_create(res_thread, query_data, FALSE, &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); + } + } + + /* 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 +} + +PurpleSrvQueryData *purple_txt_resolve(const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata) +{ + char *query; + PurpleSrvQueryData *query_data; +#ifndef _WIN32 + int in[2], out[2]; + int pid; +#else + GError* err = NULL; + static gboolean initialized = FALSE; +#endif + + query = g_strdup_printf("%s.%s", owner, domain); + purple_debug_info("dnssrv","querying TXT record for %s\n", query); + +#ifndef _WIN32 + if(pipe(in) || pipe(out)) { + purple_debug_error("dnssrv", "Could not create pipe\n"); + g_free(query); + cb(NULL, 0, extradata); + return NULL; + } + + pid = fork(); + if (pid == -1) { + purple_debug_error("dnssrv", "Could not create process!\n"); + cb(NULL, 0, extradata); + g_free(query); + return NULL; + } + + /* Child */ + if (pid == 0) + { + g_free(query); + + close(out[0]); + close(in[1]); + resolve(in[0], out[1]); + /* resolve() does not return */ + } + + close(out[1]); + close(in[0]); + + if (write(in[1], query, strlen(query)+1) < 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->txt_cb = cb; + query_data->extradata = extradata; + 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); + + g_free(query); + + return query_data; +#else + if (!initialized) { + MyDnsQuery_UTF8 = (void*) wpurple_find_and_loadproc("dnsapi.dll", "DnsQuery_UTF8"); + MyDnsRecordListFree = (void*) wpurple_find_and_loadproc( + "dnsapi.dll", "DnsRecordListFree"); + initialized = TRUE; + } + + query_data = g_new0(PurpleSrvQueryData, 1); + query_data->txt_cb = cb; query_data->query = query; query_data->extradata = extradata; @@ -440,3 +624,9 @@ #endif g_free(query_data); } + +void +purple_txt_cancel(PurpleSrvQueryData *query_data) +{ + purple_srv_cancel(query_data); +} diff -r 6606566f15ff -r affaa4c4836e libpurple/dnssrv.h --- a/libpurple/dnssrv.h Tue Jul 15 22:16:26 2008 +0000 +++ b/libpurple/dnssrv.h Fri Aug 01 12:34:33 2008 +0000 @@ -28,8 +28,9 @@ extern "C" { #endif +typedef struct _PurpleSrvQueryData PurpleSrvQueryData; typedef struct _PurpleSrvResponse PurpleSrvResponse; -typedef struct _PurpleSrvQueryData PurpleSrvQueryData; +typedef struct _PurpleTxtResponse PurpleTxtResponse; struct _PurpleSrvResponse { char hostname[256]; @@ -38,7 +39,12 @@ int pref; }; +struct _PurpleTxtResponse { + char content[256]; +}; + typedef void (*PurpleSrvCallback)(PurpleSrvResponse *resp, int results, gpointer data); +typedef void (*PurpleTxtCallback)(PurpleTxtResponse *resp, int results, gpointer data); /** * Queries an SRV record. @@ -58,6 +64,23 @@ */ void purple_srv_cancel(PurpleSrvQueryData *query_data); +/** + * Queries an TXT record. + * + * @param owner Name of the protocol (e.g. "_xmppconnect") + * @param domain Domain name to query (e.g. "blubb.com") + * @param cb A callback which will be called with the results + * @param extradata Extra data to be passed to the callback + */ +PurpleSrvQueryData *purple_txt_resolve(const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata); + +/** + * Cancel an TXT DNS query. + * + * @param query_data The request to cancel. + */ +void purple_txt_cancel(PurpleSrvQueryData *query_data); + #ifdef __cplusplus } #endif diff -r 6606566f15ff -r affaa4c4836e libpurple/protocols/jabber/caps.c --- a/libpurple/protocols/jabber/caps.c Tue Jul 15 22:16:26 2008 +0000 +++ b/libpurple/protocols/jabber/caps.c Fri Aug 01 12:34:33 2008 +0000 @@ -198,12 +198,12 @@ JabberCapsKey *clientinfo = key; JabberCapsValue *props = value; xmlnode *root = user_data; - xmlnode *client = xmlnode_new_child(root,"client"); + xmlnode *client = xmlnode_new_child(root, "client"); GList *iter; - xmlnode_set_attrib(client,"node", clientinfo->node); - xmlnode_set_attrib(client,"ver", clientinfo->ver); - xmlnode_set_attrib(client,"hash", clientinfo->hash); + xmlnode_set_attrib(client, "node", clientinfo->node); + xmlnode_set_attrib(client, "ver", clientinfo->ver); + xmlnode_set_attrib(client, "hash", clientinfo->hash); for(iter = props->identities; iter; iter = g_list_next(iter)) { JabberCapsIdentity *id = iter->data; xmlnode *identity = xmlnode_new_child(client, "identity"); diff -r 6606566f15ff -r affaa4c4836e libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Tue Jul 15 22:16:26 2008 +0000 +++ b/libpurple/protocols/jabber/jabber.c Fri Aug 01 12:34:33 2008 +0000 @@ -683,7 +683,7 @@ /* no old-ssl, so if they've specified a connect server, we'll use that, otherwise we'll * invoke the magic of SRV lookups, to figure out host and port */ if(!js->gsc) { - if(connect_server[0]) { + if(connect_server[0]) { jabber_login_connect(js, js->user->domain, connect_server, purple_account_get_int(account, "port", 5222)); } else { js->srv_query_data = purple_srv_resolve("xmpp-client",