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
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.
26 #include "mdns_interface.h"
30 #include "dns_sd_proxy.h"
32 #include "mdns_common.h"
35 static GSList
*pending_buddies
= NULL
;
39 PurpleAccount
*account
;
41 } DnsSDServiceRefHandlerData
;
43 /* data used by win32 bonjour implementation */
45 DnsSDServiceRefHandlerData
*presence_query
;
46 DnsSDServiceRefHandlerData
*browser_query
;
47 DNSRecordRef buddy_icon_rec
;
48 } Win32SessionImplData
;
51 DnsSDServiceRefHandlerData
*txt_query
;
56 /* This is a reference to the entry in BonjourBuddy->ips */
58 } Win32SvcResolverData
;
62 DnsSDServiceRefHandlerData
*null_query
;
65 /* data structure for the resolve callback */
67 DnsSDServiceRefHandlerData
*resolver_query
;
68 PurpleAccount
*account
;
70 Win32SvcResolverData
*res_data
;
71 gchar
*full_service_name
;
72 } ResolveCallbackArgs
;
76 _find_resolver_data(gconstpointer a
, gconstpointer b
) {
77 const Win32SvcResolverData
*rd_a
= a
;
78 const Win32SvcResolverData
*rd_b
= b
;
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
)) {
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
);
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."));
120 _mdns_parse_text_record(BonjourBuddy
*buddy
, const char *record
, uint16_t record_len
)
122 const char *txt_entry
;
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
) {
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
);
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");
196 if (errorCode
!= kDNSServiceErr_NoError
) {
197 purple_debug_error("bonjour", "host resolution - callback error (%d).\n", errorCode
);
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
);
223 purple_debug_error("bonjour", "Unable to set up record watcher for buddy %s (%d)\n", args
->bb
->name
, errorCode
);
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
) {
238 bonjour_buddy_signed_off(pb
);
240 bonjour_buddy_delete(args
->bb
);
242 /* Remove from the pending list */
243 pending_buddies
= g_slist_remove(pending_buddies
, args
->bb
);
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
);
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
);
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");
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 */
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
) {
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
);
304 /* Remove from the pending list */
305 pending_buddies
= g_slist_remove(pending_buddies
, args
->bb
);
306 bonjour_buddy_delete(args
->bb
);
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
);
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
;
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? */
360 BonjourBuddy
*bb_tmp
= tmp
->data
;
361 if (purple_strequal(bb_tmp
->name
, serviceName
)) {
370 bb
= bonjour_buddy_new(serviceName
, account
);
372 /* This is only necessary for the wacky case where someone previously manually added a buddy. */
374 pending_buddies
= g_slist_prepend(pending_buddies
, bb
);
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
);
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
);
399 purple_debug_error("bonjour", "service browser - failed to resolve service. (%d)\n", resErrorCode
);
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
);
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
);
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",
447 bonjour_buddy_signed_off(pb
);
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());
469 gboolean
_mdns_publish(BonjourDnsSd
*data
, PublishType type
, GSList
*records
) {
470 TXTRecordRef dns_data
;
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
);
480 PurpleKeyValuePair
*kvp
= records
->data
;
481 errorCode
= TXTRecordSetValue(&dns_data
, kvp
->key
, strlen(kvp
->value
), kvp
->value
);
482 if (errorCode
!= kDNSServiceErr_NoError
)
484 records
= records
->next
;
487 if (errorCode
!= kDNSServiceErr_NoError
) {
488 purple_debug_error("bonjour", "Unable to allocate memory for text record.(%d)\n", errorCode
);
491 /* OK, we're done constructing the text record, (re)publish the service */
492 DNSServiceRef presence_sr
;
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
);
504 purple_debug_info("bonjour", "Updating presence.\n");
505 errorCode
= DNSServiceUpdateRecord(idata
->presence_query
->sdRef
, NULL
, 0, TXTRecordGetLength(&dns_data
), TXTRecordGetBytesPtr(&dns_data
), 0);
509 if (errorCode
!= kDNSServiceErr_NoError
) {
510 purple_debug_error("bonjour", "Failed to publish presence service.(%d)\n", errorCode
);
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
);
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
,
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
);
548 purple_debug_error("bonjour", "Error registering Local Link presence browser. (%d)\n", errorCode
);
554 void _mdns_stop(BonjourDnsSd
*data
) {
555 Win32SessionImplData
*idata
= data
->mdns_impl_data
;
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
);
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
);
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
);
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
);
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
);
662 purple_debug_error("bonjour", "Unable to query buddy icon record for %s. (%d)\n", buddy
->name
, errorCode
);