Replace functions which called once with their bodies
[pidgin-git.git] / libpurple / protocols / bonjour / mdns_dns_sd.c
blob08a7bfd7f80e2138f4aa08249fee8779b387227c
1 /*
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
4 * source distribution.
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.
21 #include "internal.h"
22 #include <purple.h>
24 #include "buddy.h"
25 #include "mdns_interface.h"
26 #ifdef __APPLE_CC__
27 #include <dns_sd.h>
28 #else
29 #include "dns_sd_proxy.h"
30 #endif
31 #include "mdns_common.h"
32 #include "bonjour.h"
34 static GSList *pending_buddies = NULL;
36 typedef struct {
37 DNSServiceRef sdRef;
38 PurpleAccount *account;
39 guint input_handler;
40 } DnsSDServiceRefHandlerData;
42 /* data used by win32 bonjour implementation */
43 typedef struct {
44 DnsSDServiceRefHandlerData *presence_query;
45 DnsSDServiceRefHandlerData *browser_query;
46 DNSRecordRef buddy_icon_rec;
47 } Win32SessionImplData;
49 typedef struct {
50 DnsSDServiceRefHandlerData *txt_query;
51 uint32_t if_idx;
52 gchar *name;
53 gchar *type;
54 gchar *domain;
55 /* This is a reference to the entry in BonjourBuddy->ips */
56 const char *ip;
57 } Win32SvcResolverData;
59 typedef struct {
60 GSList *resolvers;
61 DnsSDServiceRefHandlerData *null_query;
62 } Win32BuddyImplData;
64 /* data structure for the resolve callback */
65 typedef struct {
66 DnsSDServiceRefHandlerData *resolver_query;
67 PurpleAccount *account;
68 BonjourBuddy *bb;
69 Win32SvcResolverData *res_data;
70 gchar *full_service_name;
71 } ResolveCallbackArgs;
74 static gint
75 _find_resolver_data(gconstpointer a, gconstpointer b) {
76 const Win32SvcResolverData *rd_a = a;
77 const Win32SvcResolverData *rd_b = b;
78 gint ret = 1;
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)) {
84 ret = 0;
87 return ret;
90 static void
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);
97 g_free(rd->name);
98 g_free(rd->type);
99 g_free(rd->domain);
100 g_free(rd);
103 static void
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."));
118 static void
119 _mdns_parse_text_record(BonjourBuddy *buddy, const char *record, uint16_t record_len)
121 const char *txt_entry;
122 uint8_t txt_len;
123 int i;
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) {
145 /* New Buddy */
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);
187 goto cleanup;
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");
192 goto cleanup;
195 if (errorCode != kDNSServiceErr_NoError) {
196 purple_debug_error("bonjour", "host resolution - callback error (%d).\n", errorCode);
197 delete_buddy = TRUE;
198 } else {
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);
221 } else {
222 purple_debug_error("bonjour", "Unable to set up record watcher for buddy %s (%d)\n", args->bb->name, errorCode);
223 delete_buddy = TRUE;
228 cleanup:
230 if (delete_buddy) {
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) {
236 if (pb)
237 bonjour_buddy_signed_off(pb);
238 else
239 bonjour_buddy_delete(args->bb);
241 /* Remove from the pending list */
242 pending_buddies = g_slist_remove(pending_buddies, args->bb);
244 } else {
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);
251 g_free(args);
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);
267 else {
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");
274 else {
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 */
284 return;
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) {
298 PurpleBuddy *pb;
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);
302 else {
303 /* Remove from the pending list */
304 pending_buddies = g_slist_remove(pending_buddies, args->bb);
305 bonjour_buddy_delete(args->bb);
309 g_free(args);
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);
320 else
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;
348 PurpleBuddy *pb;
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? */
357 else {
358 while (tmp) {
359 BonjourBuddy *bb_tmp = tmp->data;
360 if (purple_strequal(bb_tmp->name, serviceName)) {
361 bb = bb_tmp;
362 break;
364 tmp = tmp->next;
368 if (bb == NULL) {
369 bb = bonjour_buddy_new(serviceName, account);
371 /* This is only necessary for the wacky case where someone previously manually added a buddy. */
372 if (pb == NULL)
373 pending_buddies = g_slist_prepend(pending_buddies, bb);
374 else
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);
387 args->bb = bb;
388 args->res_data = 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);
397 } else {
398 purple_debug_error("bonjour", "service browser - failed to resolve service. (%d)\n", resErrorCode);
399 g_free(args);
402 } else {
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);
411 if (pb != NULL) {
412 GSList *l;
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);
430 g_free(rd_search);
432 if (l != NULL) {
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",
445 serviceName);
446 bonjour_buddy_signed_off(pb);
449 } else {
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());
465 return TRUE;
468 gboolean _mdns_publish(BonjourDnsSd *data, PublishType type, GSList *records) {
469 TXTRecordRef dns_data;
470 gboolean ret = TRUE;
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);
478 while (records) {
479 PurpleKeyValuePair *kvp = records->data;
480 errorCode = TXTRecordSetValue(&dns_data, kvp->key, strlen(kvp->value), kvp->value);
481 if (errorCode != kDNSServiceErr_NoError)
482 break;
483 records = records->next;
486 if (errorCode != kDNSServiceErr_NoError) {
487 purple_debug_error("bonjour", "Unable to allocate memory for text record.(%d)\n", errorCode);
488 ret = FALSE;
489 } else {
490 /* OK, we're done constructing the text record, (re)publish the service */
491 DNSServiceRef presence_sr;
493 switch (type) {
494 case PUBLISH_START:
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);
500 break;
502 case PUBLISH_UPDATE:
503 purple_debug_info("bonjour", "Updating presence.\n");
504 errorCode = DNSServiceUpdateRecord(idata->presence_query->sdRef, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0);
505 break;
508 if (errorCode != kDNSServiceErr_NoError) {
509 purple_debug_error("bonjour", "Failed to publish presence service.(%d)\n", errorCode);
510 ret = FALSE;
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);
526 return ret;
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,
538 data->account);
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);
545 return TRUE;
546 } else
547 purple_debug_error("bonjour", "Error registering Local Link presence browser. (%d)\n", errorCode);
550 return FALSE;
553 void _mdns_stop(BonjourDnsSd *data) {
554 Win32SessionImplData *idata = data->mdns_impl_data;
556 if (idata == NULL)
557 return;
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);
571 g_free(idata);
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);
598 return FALSE;
601 return TRUE;
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);
625 g_free(idata);
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);
646 else {
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);
660 } else
661 purple_debug_error("bonjour", "Unable to query buddy icon record for %s. (%d)\n", buddy->name, errorCode);