mark PurpleImageClass as private
[pidgin-git.git] / libpurple / protocols / bonjour / mdns_dns_sd.c
blobe8d0de1fa10bb7fa1bd3820ce75c72db7b31b86b
1 /*
3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA.
22 #include "internal.h"
23 #include "debug.h"
25 #include "buddy.h"
26 #include "mdns_interface.h"
27 #ifdef __APPLE_CC__
28 #include <dns_sd.h>
29 #else
30 #include "dns_sd_proxy.h"
31 #endif
32 #include "mdns_common.h"
33 #include "bonjour.h"
35 static GSList *pending_buddies = NULL;
37 typedef struct {
38 DNSServiceRef sdRef;
39 PurpleAccount *account;
40 guint input_handler;
41 } DnsSDServiceRefHandlerData;
43 /* data used by win32 bonjour implementation */
44 typedef struct {
45 DnsSDServiceRefHandlerData *presence_query;
46 DnsSDServiceRefHandlerData *browser_query;
47 DNSRecordRef buddy_icon_rec;
48 } Win32SessionImplData;
50 typedef struct {
51 DnsSDServiceRefHandlerData *txt_query;
52 uint32_t if_idx;
53 gchar *name;
54 gchar *type;
55 gchar *domain;
56 /* This is a reference to the entry in BonjourBuddy->ips */
57 const char *ip;
58 } Win32SvcResolverData;
60 typedef struct {
61 GSList *resolvers;
62 DnsSDServiceRefHandlerData *null_query;
63 } Win32BuddyImplData;
65 /* data structure for the resolve callback */
66 typedef struct {
67 DnsSDServiceRefHandlerData *resolver_query;
68 PurpleAccount *account;
69 BonjourBuddy *bb;
70 Win32SvcResolverData *res_data;
71 gchar *full_service_name;
72 } ResolveCallbackArgs;
75 static gint
76 _find_resolver_data(gconstpointer a, gconstpointer b) {
77 const Win32SvcResolverData *rd_a = a;
78 const Win32SvcResolverData *rd_b = b;
79 gint ret = 1;
81 if(rd_a->if_idx == rd_b->if_idx
82 && purple_strequal(rd_a->name, rd_b->name)
83 && purple_strequal(rd_a->type, rd_b->type)
84 && purple_strequal(rd_a->domain, rd_b->domain)) {
85 ret = 0;
88 return ret;
91 static void
92 _cleanup_resolver_data(Win32SvcResolverData *rd) {
93 if (rd->txt_query != NULL) {
94 purple_input_remove(rd->txt_query->input_handler);
95 DNSServiceRefDeallocate(rd->txt_query->sdRef);
96 g_free(rd->txt_query);
98 g_free(rd->name);
99 g_free(rd->type);
100 g_free(rd->domain);
101 g_free(rd);
104 static void
105 _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition) {
106 DnsSDServiceRefHandlerData *srh = data;
107 DNSServiceErrorType errorCode = DNSServiceProcessResult(srh->sdRef);
108 if (errorCode != kDNSServiceErr_NoError) {
109 purple_debug_error("bonjour", "Error (%d) handling mDNS response.\n", errorCode);
110 /* This happens when the mDNSResponder goes down, I haven't seen it happen any other time (in my limited testing) */
111 if (errorCode == kDNSServiceErr_Unknown) {
112 purple_connection_error(purple_account_get_connection(srh->account),
113 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
114 _("Error communicating with local mDNSResponder."));
119 static void
120 _mdns_parse_text_record(BonjourBuddy *buddy, const char *record, uint16_t record_len)
122 const char *txt_entry;
123 uint8_t txt_len;
124 int i;
126 clear_bonjour_buddy_values(buddy);
127 for (i = 0; buddy_TXT_records[i] != NULL; i++) {
128 txt_entry = TXTRecordGetValuePtr(record_len, record, buddy_TXT_records[i], &txt_len);
129 if (txt_entry != NULL)
130 set_bonjour_buddy_value(buddy, buddy_TXT_records[i], txt_entry, txt_len);
134 static void DNSSD_API
135 _mdns_record_query_callback(DNSServiceRef DNSServiceRef, DNSServiceFlags flags,
136 uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname,
137 uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata,
138 uint32_t ttl, void *context)
141 if (errorCode != kDNSServiceErr_NoError) {
142 purple_debug_error("bonjour", "record query - callback error (%d).\n", errorCode);
143 /* TODO: Probably should remove the buddy when this happens */
144 } else if (flags & kDNSServiceFlagsAdd) {
145 if (rrtype == kDNSServiceType_TXT) {
146 /* New Buddy */
147 BonjourBuddy *bb = (BonjourBuddy*) context;
148 _mdns_parse_text_record(bb, rdata, rdlen);
149 bonjour_buddy_add_to_purple(bb, NULL);
150 } else if (rrtype == kDNSServiceType_NULL) {
151 /* Buddy Icon response */
152 BonjourBuddy *bb = (BonjourBuddy*) context;
153 Win32BuddyImplData *idata = bb->mdns_impl_data;
155 g_return_if_fail(idata != NULL);
157 bonjour_buddy_got_buddy_icon(bb, rdata, rdlen);
159 /* We've got what we need; stop listening */
160 purple_input_remove(idata->null_query->input_handler);
161 DNSServiceRefDeallocate(idata->null_query->sdRef);
162 g_free(idata->null_query);
163 idata->null_query = NULL;
168 static void DNSSD_API
169 _mdns_resolve_host_callback(DNSServiceRef sdRef, DNSServiceFlags flags,
170 uint32_t interfaceIndex, DNSServiceErrorType errorCode,
171 const char *hostname, const struct sockaddr *address,
172 uint32_t ttl, void *context)
174 ResolveCallbackArgs *args = (ResolveCallbackArgs*) context;
175 Win32BuddyImplData *idata = args->bb->mdns_impl_data;
176 gboolean delete_buddy = FALSE;
177 PurpleBuddy *pb = NULL;
179 purple_input_remove(args->resolver_query->input_handler);
180 DNSServiceRefDeallocate(args->resolver_query->sdRef);
181 g_free(args->resolver_query);
182 args->resolver_query = NULL;
184 if ((pb = purple_blist_find_buddy(args->account, args->res_data->name))) {
185 if (purple_buddy_get_protocol_data(pb) != args->bb) {
186 purple_debug_error("bonjour", "Found purple buddy for %s not matching bonjour buddy record.",
187 args->res_data->name);
188 goto cleanup;
190 /* Make sure that the BonjourBuddy associated with this request is still around */
191 } else if (g_slist_find(pending_buddies, args->bb) == NULL) {
192 purple_debug_error("bonjour", "host resolution - complete, but buddy no longer pending.\n");
193 goto cleanup;
196 if (errorCode != kDNSServiceErr_NoError) {
197 purple_debug_error("bonjour", "host resolution - callback error (%d).\n", errorCode);
198 delete_buddy = TRUE;
199 } else {
200 DNSServiceRef txt_query_sr;
202 /* finally, set up the continuous txt record watcher, and add the buddy to purple */
203 errorCode = DNSServiceQueryRecord(&txt_query_sr, kDNSServiceFlagsLongLivedQuery,
204 kDNSServiceInterfaceIndexAny, args->full_service_name, kDNSServiceType_TXT,
205 kDNSServiceClass_IN, _mdns_record_query_callback, args->bb);
206 if (errorCode == kDNSServiceErr_NoError) {
207 const char *ip = inet_ntoa(((struct sockaddr_in *) address)->sin_addr);
209 purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", args->bb->name, ip, args->bb->port_p2pj);
211 args->bb->ips = g_slist_prepend(args->bb->ips, g_strdup(ip));
212 args->res_data->ip = args->bb->ips->data;
214 args->res_data->txt_query = g_new(DnsSDServiceRefHandlerData, 1);
215 args->res_data->txt_query->sdRef = txt_query_sr;
216 args->res_data->txt_query->account = args->account;
218 args->res_data->txt_query->input_handler = purple_input_add(DNSServiceRefSockFD(txt_query_sr),
219 PURPLE_INPUT_READ, _mdns_handle_event, args->res_data->txt_query);
221 bonjour_buddy_add_to_purple(args->bb, NULL);
222 } else {
223 purple_debug_error("bonjour", "Unable to set up record watcher for buddy %s (%d)\n", args->bb->name, errorCode);
224 delete_buddy = TRUE;
229 cleanup:
231 if (delete_buddy) {
232 idata->resolvers = g_slist_remove(idata->resolvers, args->res_data);
233 _cleanup_resolver_data(args->res_data);
235 /* If this was the last resolver, remove the buddy */
236 if (idata->resolvers == NULL) {
237 if (pb)
238 bonjour_buddy_signed_off(pb);
239 else
240 bonjour_buddy_delete(args->bb);
242 /* Remove from the pending list */
243 pending_buddies = g_slist_remove(pending_buddies, args->bb);
245 } else {
246 /* Remove from the pending list */
247 pending_buddies = g_slist_remove(pending_buddies, args->bb);
250 /* free the remaining args memory */
251 g_free(args->full_service_name);
252 g_free(args);
255 static void DNSSD_API
256 _mdns_service_resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
257 const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context)
259 ResolveCallbackArgs *args = (ResolveCallbackArgs*) context;
260 Win32BuddyImplData *idata = args->bb->mdns_impl_data;
262 /* remove the input fd and destroy the service ref */
263 purple_input_remove(args->resolver_query->input_handler);
264 DNSServiceRefDeallocate(args->resolver_query->sdRef);
266 if (errorCode != kDNSServiceErr_NoError)
267 purple_debug_error("bonjour", "service resolver - callback error. (%d)\n", errorCode);
268 else {
269 DNSServiceRef getaddrinfo_sr;
270 /* set more arguments, and start the host resolver */
271 errorCode = DNSServiceGetAddrInfo(&getaddrinfo_sr, 0, interfaceIndex,
272 kDNSServiceProtocol_IPv4, hosttarget, _mdns_resolve_host_callback, args);
273 if (errorCode != kDNSServiceErr_NoError)
274 purple_debug_error("bonjour", "service resolver - host resolution failed.\n");
275 else {
276 args->resolver_query->sdRef = getaddrinfo_sr;
277 args->resolver_query->input_handler = purple_input_add(DNSServiceRefSockFD(getaddrinfo_sr),
278 PURPLE_INPUT_READ, _mdns_handle_event, args->resolver_query);
279 args->full_service_name = g_strdup(fullname);
281 /* TODO: Should this be per resolver? */
282 args->bb->port_p2pj = ntohs(port);
284 /* We don't want to hit the cleanup code */
285 return;
289 /* If we get this far, clean up */
291 g_free(args->resolver_query);
292 args->resolver_query = NULL;
294 idata->resolvers = g_slist_remove(idata->resolvers, args->res_data);
295 _cleanup_resolver_data(args->res_data);
297 /* If this was the last resolver, remove the buddy */
298 if (idata->resolvers == NULL) {
299 PurpleBuddy *pb;
300 /* See if this is now attached to a PurpleBuddy */
301 if ((pb = purple_blist_find_buddy(args->account, args->bb->name)))
302 bonjour_buddy_signed_off(pb);
303 else {
304 /* Remove from the pending list */
305 pending_buddies = g_slist_remove(pending_buddies, args->bb);
306 bonjour_buddy_delete(args->bb);
310 g_free(args);
314 static void DNSSD_API
315 _mdns_service_register_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
316 const char *name, const char *regtype, const char *domain, void *context) {
318 /* TODO: deal with collision */
319 if (errorCode != kDNSServiceErr_NoError)
320 purple_debug_error("bonjour", "service advertisement - callback error (%d).\n", errorCode);
321 else
322 purple_debug_info("bonjour", "service advertisement - callback.\n");
325 static void DNSSD_API
326 _mdns_service_browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
327 DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context)
329 PurpleAccount *account = (PurpleAccount*)context;
331 if (errorCode != kDNSServiceErr_NoError)
332 purple_debug_error("bonjour", "service browser - callback error (%d)\n", errorCode);
333 else if (flags & kDNSServiceFlagsAdd) {
334 /* A presence service instance has been discovered... check it isn't us! */
335 if (purple_utf8_strcasecmp(serviceName, bonjour_get_jid(account)) != 0) {
336 DNSServiceErrorType resErrorCode;
337 /* OK, lets go ahead and resolve it to add to the buddy list */
338 ResolveCallbackArgs *args = g_new0(ResolveCallbackArgs, 1);
339 DNSServiceRef resolver_sr;
341 purple_debug_info("bonjour", "Received new record for '%s' on iface %u (%s, %s)\n",
342 serviceName, interfaceIndex, regtype ? regtype : "",
343 replyDomain ? replyDomain : "");
345 resErrorCode = DNSServiceResolve(&resolver_sr, 0, interfaceIndex, serviceName, regtype,
346 replyDomain, _mdns_service_resolve_callback, args);
347 if (resErrorCode == kDNSServiceErr_NoError) {
348 GSList *tmp = pending_buddies;
349 PurpleBuddy *pb;
350 BonjourBuddy* bb = NULL;
351 Win32SvcResolverData *rd;
352 Win32BuddyImplData *idata;
354 /* Is there an existing buddy? */
355 if ((pb = purple_blist_find_buddy(account, serviceName)))
356 bb = purple_buddy_get_protocol_data(pb);
357 /* Is there a pending buddy? */
358 else {
359 while (tmp) {
360 BonjourBuddy *bb_tmp = tmp->data;
361 if (purple_strequal(bb_tmp->name, serviceName)) {
362 bb = bb_tmp;
363 break;
365 tmp = tmp->next;
369 if (bb == NULL) {
370 bb = bonjour_buddy_new(serviceName, account);
372 /* This is only necessary for the wacky case where someone previously manually added a buddy. */
373 if (pb == NULL)
374 pending_buddies = g_slist_prepend(pending_buddies, bb);
375 else
376 purple_buddy_set_protocol_data(pb, bb);
379 rd = g_new0(Win32SvcResolverData, 1);
380 rd->if_idx = interfaceIndex;
381 rd->name = g_strdup(serviceName);
382 rd->type = g_strdup(regtype);
383 rd->domain = g_strdup(replyDomain);
385 idata = bb->mdns_impl_data;
386 idata->resolvers = g_slist_prepend(idata->resolvers, rd);
388 args->bb = bb;
389 args->res_data = rd;
390 args->account = account;
392 args->resolver_query = g_new(DnsSDServiceRefHandlerData, 1);
393 args->resolver_query->sdRef = resolver_sr;
394 args->resolver_query->account = account;
395 /* get a file descriptor for this service ref, and add it to the input list */
396 args->resolver_query->input_handler = purple_input_add(DNSServiceRefSockFD(resolver_sr),
397 PURPLE_INPUT_READ, _mdns_handle_event, args->resolver_query);
398 } else {
399 purple_debug_error("bonjour", "service browser - failed to resolve service. (%d)\n", resErrorCode);
400 g_free(args);
403 } else {
404 PurpleBuddy *pb = NULL;
406 /* A peer has sent a goodbye packet, remove them from the buddy list */
407 purple_debug_info("bonjour", "Received remove notification for '%s' on iface %u (%s, %s)\n",
408 serviceName, interfaceIndex, regtype ? regtype : "",
409 replyDomain ? replyDomain : "");
411 pb = purple_blist_find_buddy(account, serviceName);
412 if (pb != NULL) {
413 GSList *l;
414 /* There may be multiple presences, we should only get rid of this one */
415 Win32SvcResolverData *rd_search;
416 BonjourBuddy *bb = purple_buddy_get_protocol_data(pb);
417 Win32BuddyImplData *idata;
419 g_return_if_fail(bb != NULL);
421 idata = bb->mdns_impl_data;
423 rd_search = g_new0(Win32SvcResolverData, 1);
424 rd_search->if_idx = interfaceIndex;
425 rd_search->name = (gchar *) serviceName;
426 rd_search->type = (gchar *) regtype;
427 rd_search->domain = (gchar *) replyDomain;
429 l = g_slist_find_custom(idata->resolvers, rd_search, _find_resolver_data);
431 g_free(rd_search);
433 if (l != NULL) {
434 Win32SvcResolverData *rd = l->data;
435 idata->resolvers = g_slist_delete_link(idata->resolvers, l);
436 /* This IP is no longer available */
437 if (rd->ip != NULL) {
438 bb->ips = g_slist_remove(bb->ips, rd->ip);
439 g_free((gchar *) rd->ip);
441 _cleanup_resolver_data(rd);
443 /* If this was the last resolver, remove the buddy */
444 if (idata->resolvers == NULL) {
445 purple_debug_info("bonjour", "Removed last presence for buddy '%s'; signing off buddy.\n",
446 serviceName);
447 bonjour_buddy_signed_off(pb);
450 } else {
451 purple_debug_warning("bonjour", "Unable to find buddy (%s) to remove\n", serviceName ? serviceName : "(null)");
452 /* TODO: Should we look in the pending buddies list? */
457 /****************************
458 * mdns_interface functions *
459 ****************************/
461 gboolean _mdns_init_session(BonjourDnsSd *data) {
462 data->mdns_impl_data = g_new0(Win32SessionImplData, 1);
464 bonjour_dns_sd_set_jid(data->account, purple_get_host_name());
466 return TRUE;
469 gboolean _mdns_publish(BonjourDnsSd *data, PublishType type, GSList *records) {
470 TXTRecordRef dns_data;
471 gboolean ret = TRUE;
472 DNSServiceErrorType errorCode = kDNSServiceErr_NoError;
473 Win32SessionImplData *idata = data->mdns_impl_data;
475 g_return_val_if_fail(idata != NULL, FALSE);
477 TXTRecordCreate(&dns_data, 256, NULL);
479 while (records) {
480 PurpleKeyValuePair *kvp = records->data;
481 errorCode = TXTRecordSetValue(&dns_data, kvp->key, strlen(kvp->value), kvp->value);
482 if (errorCode != kDNSServiceErr_NoError)
483 break;
484 records = records->next;
487 if (errorCode != kDNSServiceErr_NoError) {
488 purple_debug_error("bonjour", "Unable to allocate memory for text record.(%d)\n", errorCode);
489 ret = FALSE;
490 } else {
491 /* OK, we're done constructing the text record, (re)publish the service */
492 DNSServiceRef presence_sr;
494 switch (type) {
495 case PUBLISH_START:
496 purple_debug_info("bonjour", "Registering presence on port %d\n", data->port_p2pj);
497 errorCode = DNSServiceRegister(&presence_sr, kDNSServiceInterfaceIndexAny,
498 0, bonjour_get_jid(data->account), LINK_LOCAL_RECORD_NAME,
499 NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data),
500 _mdns_service_register_callback, NULL);
501 break;
503 case PUBLISH_UPDATE:
504 purple_debug_info("bonjour", "Updating presence.\n");
505 errorCode = DNSServiceUpdateRecord(idata->presence_query->sdRef, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0);
506 break;
509 if (errorCode != kDNSServiceErr_NoError) {
510 purple_debug_error("bonjour", "Failed to publish presence service.(%d)\n", errorCode);
511 ret = FALSE;
512 } else if (type == PUBLISH_START) {
513 /* We need to do this because according to the Apple docs:
514 * "the client is responsible for ensuring that DNSServiceProcessResult() is called
515 * whenever there is a reply from the daemon - the daemon may terminate its connection
516 * with a client that does not process the daemon's responses */
517 idata->presence_query = g_new(DnsSDServiceRefHandlerData, 1);
518 idata->presence_query->sdRef = presence_sr;
519 idata->presence_query->account = data->account;
520 idata->presence_query->input_handler = purple_input_add(DNSServiceRefSockFD(presence_sr),
521 PURPLE_INPUT_READ, _mdns_handle_event, idata->presence_query);
525 /* Free the memory used by temp data */
526 TXTRecordDeallocate(&dns_data);
527 return ret;
530 gboolean _mdns_browse(BonjourDnsSd *data) {
531 DNSServiceErrorType errorCode;
532 Win32SessionImplData *idata = data->mdns_impl_data;
533 DNSServiceRef browser_sr;
535 g_return_val_if_fail(idata != NULL, FALSE);
537 errorCode = DNSServiceBrowse(&browser_sr, 0, kDNSServiceInterfaceIndexAny,
538 LINK_LOCAL_RECORD_NAME, NULL,_mdns_service_browse_callback,
539 data->account);
540 if (errorCode == kDNSServiceErr_NoError) {
541 idata->browser_query = g_new(DnsSDServiceRefHandlerData, 1);
542 idata->browser_query->sdRef = browser_sr;
543 idata->browser_query->account = data->account;
544 idata->browser_query->input_handler = purple_input_add(DNSServiceRefSockFD(browser_sr),
545 PURPLE_INPUT_READ, _mdns_handle_event, idata->browser_query);
546 return TRUE;
547 } else
548 purple_debug_error("bonjour", "Error registering Local Link presence browser. (%d)\n", errorCode);
551 return FALSE;
554 void _mdns_stop(BonjourDnsSd *data) {
555 Win32SessionImplData *idata = data->mdns_impl_data;
557 if (idata == NULL)
558 return;
560 if (idata->presence_query != NULL) {
561 purple_input_remove(idata->presence_query->input_handler);
562 DNSServiceRefDeallocate(idata->presence_query->sdRef);
563 g_free(idata->presence_query);
566 if (idata->browser_query != NULL) {
567 purple_input_remove(idata->browser_query->input_handler);
568 DNSServiceRefDeallocate(idata->browser_query->sdRef);
569 g_free(idata->browser_query);
572 g_free(idata);
574 data->mdns_impl_data = NULL;
577 gboolean _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) {
578 Win32SessionImplData *idata = data->mdns_impl_data;
579 DNSServiceErrorType errorCode = kDNSServiceErr_NoError;
581 g_return_val_if_fail(idata != NULL, FALSE);
583 if (avatar_data != NULL && idata->buddy_icon_rec == NULL) {
584 purple_debug_info("bonjour", "Setting new buddy icon.\n");
585 errorCode = DNSServiceAddRecord(idata->presence_query->sdRef, &idata->buddy_icon_rec,
586 0, kDNSServiceType_NULL, avatar_len, avatar_data, 0);
587 } else if (avatar_data != NULL) {
588 purple_debug_info("bonjour", "Updating existing buddy icon.\n");
589 errorCode = DNSServiceUpdateRecord(idata->presence_query->sdRef, idata->buddy_icon_rec,
590 0, avatar_len, avatar_data, 0);
591 } else if (idata->buddy_icon_rec != NULL) {
592 purple_debug_info("bonjour", "Removing existing buddy icon.\n");
593 errorCode = DNSServiceRemoveRecord(idata->presence_query->sdRef, idata->buddy_icon_rec, 0);
594 idata->buddy_icon_rec = NULL;
597 if (errorCode != kDNSServiceErr_NoError) {
598 purple_debug_error("bonjour", "Error (%d) setting buddy icon record.\n", errorCode);
599 return FALSE;
602 return TRUE;
605 void _mdns_init_buddy(BonjourBuddy *buddy) {
606 buddy->mdns_impl_data = g_new0(Win32BuddyImplData, 1);
609 void _mdns_delete_buddy(BonjourBuddy *buddy) {
610 Win32BuddyImplData *idata = buddy->mdns_impl_data;
612 g_return_if_fail(idata != NULL);
614 while (idata->resolvers) {
615 Win32SvcResolverData *rd = idata->resolvers->data;
616 _cleanup_resolver_data(rd);
617 idata->resolvers = g_slist_delete_link(idata->resolvers, idata->resolvers);
620 if (idata->null_query != NULL) {
621 purple_input_remove(idata->null_query->input_handler);
622 DNSServiceRefDeallocate(idata->null_query->sdRef);
623 g_free(idata->null_query);
626 g_free(idata);
628 buddy->mdns_impl_data = NULL;
631 void _mdns_retrieve_buddy_icon(BonjourBuddy* buddy) {
632 Win32BuddyImplData *idata = buddy->mdns_impl_data;
633 char svc_name[kDNSServiceMaxDomainName];
635 g_return_if_fail(idata != NULL);
637 /* Cancel any existing query */
638 if (idata->null_query != NULL) {
639 purple_input_remove(idata->null_query->input_handler);
640 DNSServiceRefDeallocate(idata->null_query->sdRef);
641 g_free(idata->null_query);
642 idata->null_query = NULL;
645 if (DNSServiceConstructFullName(svc_name, buddy->name, LINK_LOCAL_RECORD_NAME, "local") != 0)
646 purple_debug_error("bonjour", "Unable to construct full name to retrieve buddy icon for %s.\n", buddy->name);
647 else {
648 DNSServiceRef null_query_sr;
650 DNSServiceErrorType errorCode = DNSServiceQueryRecord(&null_query_sr, 0, kDNSServiceInterfaceIndexAny,
651 svc_name, kDNSServiceType_NULL, kDNSServiceClass_IN, _mdns_record_query_callback, buddy);
653 if (errorCode == kDNSServiceErr_NoError) {
654 idata->null_query = g_new(DnsSDServiceRefHandlerData, 1);
656 idata->null_query->sdRef = null_query_sr;
657 idata->null_query->account = buddy->account;
659 idata->null_query->input_handler = purple_input_add(DNSServiceRefSockFD(null_query_sr),
660 PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query);
661 } else
662 purple_debug_error("bonjour", "Unable to query buddy icon record for %s. (%d)\n", buddy->name, errorCode);