2 * Purple is the legal property of its developers, whose names are too numerous
3 * to list here. Please refer to the COPYRIGHT file distributed with this
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Library General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA.
25 #include "mdns_interface.h"
29 #include "dns_sd_proxy.h"
31 #include "mdns_common.h"
34 static GSList
*pending_buddies
= NULL
;
38 PurpleAccount
*account
;
40 } DnsSDServiceRefHandlerData
;
42 /* data used by win32 bonjour implementation */
44 DnsSDServiceRefHandlerData
*presence_query
;
45 DnsSDServiceRefHandlerData
*browser_query
;
46 DNSRecordRef buddy_icon_rec
;
47 } Win32SessionImplData
;
50 DnsSDServiceRefHandlerData
*txt_query
;
55 /* This is a reference to the entry in BonjourBuddy->ips */
57 } Win32SvcResolverData
;
61 DnsSDServiceRefHandlerData
*null_query
;
64 /* data structure for the resolve callback */
66 DnsSDServiceRefHandlerData
*resolver_query
;
67 PurpleAccount
*account
;
69 Win32SvcResolverData
*res_data
;
70 gchar
*full_service_name
;
71 } ResolveCallbackArgs
;
75 _find_resolver_data(gconstpointer a
, gconstpointer b
) {
76 const Win32SvcResolverData
*rd_a
= a
;
77 const Win32SvcResolverData
*rd_b
= b
;
80 if(rd_a
->if_idx
== rd_b
->if_idx
81 && purple_strequal(rd_a
->name
, rd_b
->name
)
82 && purple_strequal(rd_a
->type
, rd_b
->type
)
83 && purple_strequal(rd_a
->domain
, rd_b
->domain
)) {
91 _cleanup_resolver_data(Win32SvcResolverData
*rd
) {
92 if (rd
->txt_query
!= NULL
) {
93 purple_input_remove(rd
->txt_query
->input_handler
);
94 DNSServiceRefDeallocate(rd
->txt_query
->sdRef
);
95 g_free(rd
->txt_query
);
104 _mdns_handle_event(gpointer data
, gint source
, PurpleInputCondition condition
) {
105 DnsSDServiceRefHandlerData
*srh
= data
;
106 DNSServiceErrorType errorCode
= DNSServiceProcessResult(srh
->sdRef
);
107 if (errorCode
!= kDNSServiceErr_NoError
) {
108 purple_debug_error("bonjour", "Error (%d) handling mDNS response.\n", errorCode
);
109 /* This happens when the mDNSResponder goes down, I haven't seen it happen any other time (in my limited testing) */
110 if (errorCode
== kDNSServiceErr_Unknown
) {
111 purple_connection_error(purple_account_get_connection(srh
->account
),
112 PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
113 _("Error communicating with local mDNSResponder."));
119 _mdns_parse_text_record(BonjourBuddy
*buddy
, const char *record
, uint16_t record_len
)
121 const char *txt_entry
;
125 clear_bonjour_buddy_values(buddy
);
126 for (i
= 0; buddy_TXT_records
[i
] != NULL
; i
++) {
127 txt_entry
= TXTRecordGetValuePtr(record_len
, record
, buddy_TXT_records
[i
], &txt_len
);
128 if (txt_entry
!= NULL
)
129 set_bonjour_buddy_value(buddy
, buddy_TXT_records
[i
], txt_entry
, txt_len
);
133 static void DNSSD_API
134 _mdns_record_query_callback(DNSServiceRef DNSServiceRef
, DNSServiceFlags flags
,
135 uint32_t interfaceIndex
, DNSServiceErrorType errorCode
, const char *fullname
,
136 uint16_t rrtype
, uint16_t rrclass
, uint16_t rdlen
, const void *rdata
,
137 uint32_t ttl
, void *context
)
140 if (errorCode
!= kDNSServiceErr_NoError
) {
141 purple_debug_error("bonjour", "record query - callback error (%d).\n", errorCode
);
142 /* TODO: Probably should remove the buddy when this happens */
143 } else if (flags
& kDNSServiceFlagsAdd
) {
144 if (rrtype
== kDNSServiceType_TXT
) {
146 BonjourBuddy
*bb
= (BonjourBuddy
*) context
;
147 _mdns_parse_text_record(bb
, rdata
, rdlen
);
148 bonjour_buddy_add_to_purple(bb
, NULL
);
149 } else if (rrtype
== kDNSServiceType_NULL
) {
150 /* Buddy Icon response */
151 BonjourBuddy
*bb
= (BonjourBuddy
*) context
;
152 Win32BuddyImplData
*idata
= bb
->mdns_impl_data
;
154 g_return_if_fail(idata
!= NULL
);
156 bonjour_buddy_got_buddy_icon(bb
, rdata
, rdlen
);
158 /* We've got what we need; stop listening */
159 purple_input_remove(idata
->null_query
->input_handler
);
160 DNSServiceRefDeallocate(idata
->null_query
->sdRef
);
161 g_free(idata
->null_query
);
162 idata
->null_query
= NULL
;
167 static void DNSSD_API
168 _mdns_resolve_host_callback(DNSServiceRef sdRef
, DNSServiceFlags flags
,
169 uint32_t interfaceIndex
, DNSServiceErrorType errorCode
,
170 const char *hostname
, const struct sockaddr
*address
,
171 uint32_t ttl
, void *context
)
173 ResolveCallbackArgs
*args
= (ResolveCallbackArgs
*) context
;
174 Win32BuddyImplData
*idata
= args
->bb
->mdns_impl_data
;
175 gboolean delete_buddy
= FALSE
;
176 PurpleBuddy
*pb
= NULL
;
178 purple_input_remove(args
->resolver_query
->input_handler
);
179 DNSServiceRefDeallocate(args
->resolver_query
->sdRef
);
180 g_free(args
->resolver_query
);
181 args
->resolver_query
= NULL
;
183 if ((pb
= purple_blist_find_buddy(args
->account
, args
->res_data
->name
))) {
184 if (purple_buddy_get_protocol_data(pb
) != args
->bb
) {
185 purple_debug_error("bonjour", "Found purple buddy for %s not matching bonjour buddy record.",
186 args
->res_data
->name
);
189 /* Make sure that the BonjourBuddy associated with this request is still around */
190 } else if (g_slist_find(pending_buddies
, args
->bb
) == NULL
) {
191 purple_debug_error("bonjour", "host resolution - complete, but buddy no longer pending.\n");
195 if (errorCode
!= kDNSServiceErr_NoError
) {
196 purple_debug_error("bonjour", "host resolution - callback error (%d).\n", errorCode
);
199 DNSServiceRef txt_query_sr
;
201 /* finally, set up the continuous txt record watcher, and add the buddy to purple */
202 errorCode
= DNSServiceQueryRecord(&txt_query_sr
, kDNSServiceFlagsLongLivedQuery
,
203 kDNSServiceInterfaceIndexAny
, args
->full_service_name
, kDNSServiceType_TXT
,
204 kDNSServiceClass_IN
, _mdns_record_query_callback
, args
->bb
);
205 if (errorCode
== kDNSServiceErr_NoError
) {
206 const char *ip
= inet_ntoa(((struct sockaddr_in
*) address
)->sin_addr
);
208 purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", args
->bb
->name
, ip
, args
->bb
->port_p2pj
);
210 args
->bb
->ips
= g_slist_prepend(args
->bb
->ips
, g_strdup(ip
));
211 args
->res_data
->ip
= args
->bb
->ips
->data
;
213 args
->res_data
->txt_query
= g_new(DnsSDServiceRefHandlerData
, 1);
214 args
->res_data
->txt_query
->sdRef
= txt_query_sr
;
215 args
->res_data
->txt_query
->account
= args
->account
;
217 args
->res_data
->txt_query
->input_handler
= purple_input_add(DNSServiceRefSockFD(txt_query_sr
),
218 PURPLE_INPUT_READ
, _mdns_handle_event
, args
->res_data
->txt_query
);
220 bonjour_buddy_add_to_purple(args
->bb
, NULL
);
222 purple_debug_error("bonjour", "Unable to set up record watcher for buddy %s (%d)\n", args
->bb
->name
, errorCode
);
231 idata
->resolvers
= g_slist_remove(idata
->resolvers
, args
->res_data
);
232 _cleanup_resolver_data(args
->res_data
);
234 /* If this was the last resolver, remove the buddy */
235 if (idata
->resolvers
== NULL
) {
237 bonjour_buddy_signed_off(pb
);
239 bonjour_buddy_delete(args
->bb
);
241 /* Remove from the pending list */
242 pending_buddies
= g_slist_remove(pending_buddies
, args
->bb
);
245 /* Remove from the pending list */
246 pending_buddies
= g_slist_remove(pending_buddies
, args
->bb
);
249 /* free the remaining args memory */
250 g_free(args
->full_service_name
);
254 static void DNSSD_API
255 _mdns_service_resolve_callback(DNSServiceRef sdRef
, DNSServiceFlags flags
, uint32_t interfaceIndex
, DNSServiceErrorType errorCode
,
256 const char *fullname
, const char *hosttarget
, uint16_t port
, uint16_t txtLen
, const unsigned char *txtRecord
, void *context
)
258 ResolveCallbackArgs
*args
= (ResolveCallbackArgs
*) context
;
259 Win32BuddyImplData
*idata
= args
->bb
->mdns_impl_data
;
261 /* remove the input fd and destroy the service ref */
262 purple_input_remove(args
->resolver_query
->input_handler
);
263 DNSServiceRefDeallocate(args
->resolver_query
->sdRef
);
265 if (errorCode
!= kDNSServiceErr_NoError
)
266 purple_debug_error("bonjour", "service resolver - callback error. (%d)\n", errorCode
);
268 DNSServiceRef getaddrinfo_sr
;
269 /* set more arguments, and start the host resolver */
270 errorCode
= DNSServiceGetAddrInfo(&getaddrinfo_sr
, 0, interfaceIndex
,
271 kDNSServiceProtocol_IPv4
, hosttarget
, _mdns_resolve_host_callback
, args
);
272 if (errorCode
!= kDNSServiceErr_NoError
)
273 purple_debug_error("bonjour", "service resolver - host resolution failed.\n");
275 args
->resolver_query
->sdRef
= getaddrinfo_sr
;
276 args
->resolver_query
->input_handler
= purple_input_add(DNSServiceRefSockFD(getaddrinfo_sr
),
277 PURPLE_INPUT_READ
, _mdns_handle_event
, args
->resolver_query
);
278 args
->full_service_name
= g_strdup(fullname
);
280 /* TODO: Should this be per resolver? */
281 args
->bb
->port_p2pj
= ntohs(port
);
283 /* We don't want to hit the cleanup code */
288 /* If we get this far, clean up */
290 g_free(args
->resolver_query
);
291 args
->resolver_query
= NULL
;
293 idata
->resolvers
= g_slist_remove(idata
->resolvers
, args
->res_data
);
294 _cleanup_resolver_data(args
->res_data
);
296 /* If this was the last resolver, remove the buddy */
297 if (idata
->resolvers
== NULL
) {
299 /* See if this is now attached to a PurpleBuddy */
300 if ((pb
= purple_blist_find_buddy(args
->account
, args
->bb
->name
)))
301 bonjour_buddy_signed_off(pb
);
303 /* Remove from the pending list */
304 pending_buddies
= g_slist_remove(pending_buddies
, args
->bb
);
305 bonjour_buddy_delete(args
->bb
);
313 static void DNSSD_API
314 _mdns_service_register_callback(DNSServiceRef sdRef
, DNSServiceFlags flags
, DNSServiceErrorType errorCode
,
315 const char *name
, const char *regtype
, const char *domain
, void *context
) {
317 /* TODO: deal with collision */
318 if (errorCode
!= kDNSServiceErr_NoError
)
319 purple_debug_error("bonjour", "service advertisement - callback error (%d).\n", errorCode
);
321 purple_debug_info("bonjour", "service advertisement - callback.\n");
324 static void DNSSD_API
325 _mdns_service_browse_callback(DNSServiceRef sdRef
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
326 DNSServiceErrorType errorCode
, const char *serviceName
, const char *regtype
, const char *replyDomain
, void *context
)
328 PurpleAccount
*account
= (PurpleAccount
*)context
;
330 if (errorCode
!= kDNSServiceErr_NoError
)
331 purple_debug_error("bonjour", "service browser - callback error (%d)\n", errorCode
);
332 else if (flags
& kDNSServiceFlagsAdd
) {
333 /* A presence service instance has been discovered... check it isn't us! */
334 if (purple_utf8_strcasecmp(serviceName
, bonjour_get_jid(account
)) != 0) {
335 DNSServiceErrorType resErrorCode
;
336 /* OK, lets go ahead and resolve it to add to the buddy list */
337 ResolveCallbackArgs
*args
= g_new0(ResolveCallbackArgs
, 1);
338 DNSServiceRef resolver_sr
;
340 purple_debug_info("bonjour", "Received new record for '%s' on iface %u (%s, %s)\n",
341 serviceName
, interfaceIndex
, regtype
? regtype
: "",
342 replyDomain
? replyDomain
: "");
344 resErrorCode
= DNSServiceResolve(&resolver_sr
, 0, interfaceIndex
, serviceName
, regtype
,
345 replyDomain
, _mdns_service_resolve_callback
, args
);
346 if (resErrorCode
== kDNSServiceErr_NoError
) {
347 GSList
*tmp
= pending_buddies
;
349 BonjourBuddy
* bb
= NULL
;
350 Win32SvcResolverData
*rd
;
351 Win32BuddyImplData
*idata
;
353 /* Is there an existing buddy? */
354 if ((pb
= purple_blist_find_buddy(account
, serviceName
)))
355 bb
= purple_buddy_get_protocol_data(pb
);
356 /* Is there a pending buddy? */
359 BonjourBuddy
*bb_tmp
= tmp
->data
;
360 if (purple_strequal(bb_tmp
->name
, serviceName
)) {
369 bb
= bonjour_buddy_new(serviceName
, account
);
371 /* This is only necessary for the wacky case where someone previously manually added a buddy. */
373 pending_buddies
= g_slist_prepend(pending_buddies
, bb
);
375 purple_buddy_set_protocol_data(pb
, bb
);
378 rd
= g_new0(Win32SvcResolverData
, 1);
379 rd
->if_idx
= interfaceIndex
;
380 rd
->name
= g_strdup(serviceName
);
381 rd
->type
= g_strdup(regtype
);
382 rd
->domain
= g_strdup(replyDomain
);
384 idata
= bb
->mdns_impl_data
;
385 idata
->resolvers
= g_slist_prepend(idata
->resolvers
, rd
);
389 args
->account
= account
;
391 args
->resolver_query
= g_new(DnsSDServiceRefHandlerData
, 1);
392 args
->resolver_query
->sdRef
= resolver_sr
;
393 args
->resolver_query
->account
= account
;
394 /* get a file descriptor for this service ref, and add it to the input list */
395 args
->resolver_query
->input_handler
= purple_input_add(DNSServiceRefSockFD(resolver_sr
),
396 PURPLE_INPUT_READ
, _mdns_handle_event
, args
->resolver_query
);
398 purple_debug_error("bonjour", "service browser - failed to resolve service. (%d)\n", resErrorCode
);
403 PurpleBuddy
*pb
= NULL
;
405 /* A peer has sent a goodbye packet, remove them from the buddy list */
406 purple_debug_info("bonjour", "Received remove notification for '%s' on iface %u (%s, %s)\n",
407 serviceName
, interfaceIndex
, regtype
? regtype
: "",
408 replyDomain
? replyDomain
: "");
410 pb
= purple_blist_find_buddy(account
, serviceName
);
413 /* There may be multiple presences, we should only get rid of this one */
414 Win32SvcResolverData
*rd_search
;
415 BonjourBuddy
*bb
= purple_buddy_get_protocol_data(pb
);
416 Win32BuddyImplData
*idata
;
418 g_return_if_fail(bb
!= NULL
);
420 idata
= bb
->mdns_impl_data
;
422 rd_search
= g_new0(Win32SvcResolverData
, 1);
423 rd_search
->if_idx
= interfaceIndex
;
424 rd_search
->name
= (gchar
*) serviceName
;
425 rd_search
->type
= (gchar
*) regtype
;
426 rd_search
->domain
= (gchar
*) replyDomain
;
428 l
= g_slist_find_custom(idata
->resolvers
, rd_search
, _find_resolver_data
);
433 Win32SvcResolverData
*rd
= l
->data
;
434 idata
->resolvers
= g_slist_delete_link(idata
->resolvers
, l
);
435 /* This IP is no longer available */
436 if (rd
->ip
!= NULL
) {
437 bb
->ips
= g_slist_remove(bb
->ips
, rd
->ip
);
438 g_free((gchar
*) rd
->ip
);
440 _cleanup_resolver_data(rd
);
442 /* If this was the last resolver, remove the buddy */
443 if (idata
->resolvers
== NULL
) {
444 purple_debug_info("bonjour", "Removed last presence for buddy '%s'; signing off buddy.\n",
446 bonjour_buddy_signed_off(pb
);
450 purple_debug_warning("bonjour", "Unable to find buddy (%s) to remove\n", serviceName
? serviceName
: "(null)");
451 /* TODO: Should we look in the pending buddies list? */
456 /****************************
457 * mdns_interface functions *
458 ****************************/
460 gboolean
_mdns_init_session(BonjourDnsSd
*data
) {
461 data
->mdns_impl_data
= g_new0(Win32SessionImplData
, 1);
463 bonjour_dns_sd_set_jid(data
->account
, purple_get_host_name());
468 gboolean
_mdns_publish(BonjourDnsSd
*data
, PublishType type
, GSList
*records
) {
469 TXTRecordRef dns_data
;
471 DNSServiceErrorType errorCode
= kDNSServiceErr_NoError
;
472 Win32SessionImplData
*idata
= data
->mdns_impl_data
;
474 g_return_val_if_fail(idata
!= NULL
, FALSE
);
476 TXTRecordCreate(&dns_data
, 256, NULL
);
479 PurpleKeyValuePair
*kvp
= records
->data
;
480 errorCode
= TXTRecordSetValue(&dns_data
, kvp
->key
, strlen(kvp
->value
), kvp
->value
);
481 if (errorCode
!= kDNSServiceErr_NoError
)
483 records
= records
->next
;
486 if (errorCode
!= kDNSServiceErr_NoError
) {
487 purple_debug_error("bonjour", "Unable to allocate memory for text record.(%d)\n", errorCode
);
490 /* OK, we're done constructing the text record, (re)publish the service */
491 DNSServiceRef presence_sr
;
495 purple_debug_info("bonjour", "Registering presence on port %d\n", data
->port_p2pj
);
496 errorCode
= DNSServiceRegister(&presence_sr
, kDNSServiceInterfaceIndexAny
,
497 0, bonjour_get_jid(data
->account
), LINK_LOCAL_RECORD_NAME
,
498 NULL
, NULL
, htons(data
->port_p2pj
), TXTRecordGetLength(&dns_data
), TXTRecordGetBytesPtr(&dns_data
),
499 _mdns_service_register_callback
, NULL
);
503 purple_debug_info("bonjour", "Updating presence.\n");
504 errorCode
= DNSServiceUpdateRecord(idata
->presence_query
->sdRef
, NULL
, 0, TXTRecordGetLength(&dns_data
), TXTRecordGetBytesPtr(&dns_data
), 0);
508 if (errorCode
!= kDNSServiceErr_NoError
) {
509 purple_debug_error("bonjour", "Failed to publish presence service.(%d)\n", errorCode
);
511 } else if (type
== PUBLISH_START
) {
512 /* We need to do this because according to the Apple docs:
513 * "the client is responsible for ensuring that DNSServiceProcessResult() is called
514 * whenever there is a reply from the daemon - the daemon may terminate its connection
515 * with a client that does not process the daemon's responses */
516 idata
->presence_query
= g_new(DnsSDServiceRefHandlerData
, 1);
517 idata
->presence_query
->sdRef
= presence_sr
;
518 idata
->presence_query
->account
= data
->account
;
519 idata
->presence_query
->input_handler
= purple_input_add(DNSServiceRefSockFD(presence_sr
),
520 PURPLE_INPUT_READ
, _mdns_handle_event
, idata
->presence_query
);
524 /* Free the memory used by temp data */
525 TXTRecordDeallocate(&dns_data
);
529 gboolean
_mdns_browse(BonjourDnsSd
*data
) {
530 DNSServiceErrorType errorCode
;
531 Win32SessionImplData
*idata
= data
->mdns_impl_data
;
532 DNSServiceRef browser_sr
;
534 g_return_val_if_fail(idata
!= NULL
, FALSE
);
536 errorCode
= DNSServiceBrowse(&browser_sr
, 0, kDNSServiceInterfaceIndexAny
,
537 LINK_LOCAL_RECORD_NAME
, NULL
,_mdns_service_browse_callback
,
539 if (errorCode
== kDNSServiceErr_NoError
) {
540 idata
->browser_query
= g_new(DnsSDServiceRefHandlerData
, 1);
541 idata
->browser_query
->sdRef
= browser_sr
;
542 idata
->browser_query
->account
= data
->account
;
543 idata
->browser_query
->input_handler
= purple_input_add(DNSServiceRefSockFD(browser_sr
),
544 PURPLE_INPUT_READ
, _mdns_handle_event
, idata
->browser_query
);
547 purple_debug_error("bonjour", "Error registering Local Link presence browser. (%d)\n", errorCode
);
553 void _mdns_stop(BonjourDnsSd
*data
) {
554 Win32SessionImplData
*idata
= data
->mdns_impl_data
;
559 if (idata
->presence_query
!= NULL
) {
560 purple_input_remove(idata
->presence_query
->input_handler
);
561 DNSServiceRefDeallocate(idata
->presence_query
->sdRef
);
562 g_free(idata
->presence_query
);
565 if (idata
->browser_query
!= NULL
) {
566 purple_input_remove(idata
->browser_query
->input_handler
);
567 DNSServiceRefDeallocate(idata
->browser_query
->sdRef
);
568 g_free(idata
->browser_query
);
573 data
->mdns_impl_data
= NULL
;
576 gboolean
_mdns_set_buddy_icon_data(BonjourDnsSd
*data
, gconstpointer avatar_data
, gsize avatar_len
) {
577 Win32SessionImplData
*idata
= data
->mdns_impl_data
;
578 DNSServiceErrorType errorCode
= kDNSServiceErr_NoError
;
580 g_return_val_if_fail(idata
!= NULL
, FALSE
);
582 if (avatar_data
!= NULL
&& idata
->buddy_icon_rec
== NULL
) {
583 purple_debug_info("bonjour", "Setting new buddy icon.\n");
584 errorCode
= DNSServiceAddRecord(idata
->presence_query
->sdRef
, &idata
->buddy_icon_rec
,
585 0, kDNSServiceType_NULL
, avatar_len
, avatar_data
, 0);
586 } else if (avatar_data
!= NULL
) {
587 purple_debug_info("bonjour", "Updating existing buddy icon.\n");
588 errorCode
= DNSServiceUpdateRecord(idata
->presence_query
->sdRef
, idata
->buddy_icon_rec
,
589 0, avatar_len
, avatar_data
, 0);
590 } else if (idata
->buddy_icon_rec
!= NULL
) {
591 purple_debug_info("bonjour", "Removing existing buddy icon.\n");
592 errorCode
= DNSServiceRemoveRecord(idata
->presence_query
->sdRef
, idata
->buddy_icon_rec
, 0);
593 idata
->buddy_icon_rec
= NULL
;
596 if (errorCode
!= kDNSServiceErr_NoError
) {
597 purple_debug_error("bonjour", "Error (%d) setting buddy icon record.\n", errorCode
);
604 void _mdns_init_buddy(BonjourBuddy
*buddy
) {
605 buddy
->mdns_impl_data
= g_new0(Win32BuddyImplData
, 1);
608 void _mdns_delete_buddy(BonjourBuddy
*buddy
) {
609 Win32BuddyImplData
*idata
= buddy
->mdns_impl_data
;
611 g_return_if_fail(idata
!= NULL
);
613 while (idata
->resolvers
) {
614 Win32SvcResolverData
*rd
= idata
->resolvers
->data
;
615 _cleanup_resolver_data(rd
);
616 idata
->resolvers
= g_slist_delete_link(idata
->resolvers
, idata
->resolvers
);
619 if (idata
->null_query
!= NULL
) {
620 purple_input_remove(idata
->null_query
->input_handler
);
621 DNSServiceRefDeallocate(idata
->null_query
->sdRef
);
622 g_free(idata
->null_query
);
627 buddy
->mdns_impl_data
= NULL
;
630 void _mdns_retrieve_buddy_icon(BonjourBuddy
* buddy
) {
631 Win32BuddyImplData
*idata
= buddy
->mdns_impl_data
;
632 char svc_name
[kDNSServiceMaxDomainName
];
634 g_return_if_fail(idata
!= NULL
);
636 /* Cancel any existing query */
637 if (idata
->null_query
!= NULL
) {
638 purple_input_remove(idata
->null_query
->input_handler
);
639 DNSServiceRefDeallocate(idata
->null_query
->sdRef
);
640 g_free(idata
->null_query
);
641 idata
->null_query
= NULL
;
644 if (DNSServiceConstructFullName(svc_name
, buddy
->name
, LINK_LOCAL_RECORD_NAME
, "local") != 0)
645 purple_debug_error("bonjour", "Unable to construct full name to retrieve buddy icon for %s.\n", buddy
->name
);
647 DNSServiceRef null_query_sr
;
649 DNSServiceErrorType errorCode
= DNSServiceQueryRecord(&null_query_sr
, 0, kDNSServiceInterfaceIndexAny
,
650 svc_name
, kDNSServiceType_NULL
, kDNSServiceClass_IN
, _mdns_record_query_callback
, buddy
);
652 if (errorCode
== kDNSServiceErr_NoError
) {
653 idata
->null_query
= g_new(DnsSDServiceRefHandlerData
, 1);
655 idata
->null_query
->sdRef
= null_query_sr
;
656 idata
->null_query
->account
= buddy
->account
;
658 idata
->null_query
->input_handler
= purple_input_add(DNSServiceRefSockFD(null_query_sr
),
659 PURPLE_INPUT_READ
, _mdns_handle_event
, idata
->null_query
);
661 purple_debug_error("bonjour", "Unable to query buddy icon record for %s. (%d)\n", buddy
->name
, errorCode
);