# HG changeset patch # User Daniel Atallah # Date 1181014702 0 # Node ID d7b50cac1c7a1fcfcbc27154fb3d5b49eb409d75 # Parent 7e856734b7122fec474ed514ec741739c9dfd81f This is a patch from Chris Davies to make Bonjour work on Windows using the Apple Bonjour framework. It turns out that the actual DNS-SD library is (3 clause) BSD licensed, so we can use it. There are a few changes by me, mainly to fix the howl implementation. Fixes #1117 . There appear to be a few bugs, but I believe that they were also present previously. I'm hoping to do some more tweaking before the next release. The howl implementation will eventually be supersceded by a native avahi implementation, so I opted for a somewhat dirty hack to enable it instead of doing something with config.h. diff -r 7e856734b712 -r d7b50cac1c7a COPYRIGHT --- a/COPYRIGHT Tue Jun 05 03:13:02 2007 +0000 +++ b/COPYRIGHT Tue Jun 05 03:38:22 2007 +0000 @@ -89,6 +89,7 @@ Jeramey Crawford Michael Culbertson Steven Danna +Chris Davies Martijn Dekker Vinicius Depizzol Philip Derrin diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/Makefile.am --- a/libpurple/protocols/bonjour/Makefile.am Tue Jun 05 03:13:02 2007 +0000 +++ b/libpurple/protocols/bonjour/Makefile.am Tue Jun 05 03:38:22 2007 +0000 @@ -1,4 +1,6 @@ EXTRA_DIST = \ + mdns_win32.c \ + mdns_win32.h \ Makefile.mingw pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) @@ -8,12 +10,16 @@ bonjour.h \ buddy.c \ buddy.h \ - dns_sd.c \ - dns_sd.h \ + dns_sd_proxy.h \ jabber.c \ - jabber.h + jabber.h \ + mdns_common.c \ + mdns_common.h \ + mdns_howl.c \ + mdns_howl.h \ + mdns_types.h -AM_CFLAGS = $(st) +AM_CFLAGS = $(st) -DUSE_BONJOUR_HOWL libbonjour_la_LDFLAGS = -module -avoid-version diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/Makefile.mingw --- a/libpurple/protocols/bonjour/Makefile.mingw Tue Jun 05 03:13:02 2007 +0000 +++ b/libpurple/protocols/bonjour/Makefile.mingw Tue Jun 05 03:38:22 2007 +0000 @@ -8,7 +8,6 @@ include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak TARGET = libbonjour -NEEDED_DLLS = $(HOWL_TOP)/bin/libhowl-1.dll TYPE = PLUGIN # Static or Plugin... @@ -24,17 +23,17 @@ ## ## INCLUDE PATHS ## -INCLUDE_PATHS += -I$(BONJOUR_ROOT) \ +INCLUDE_PATHS += -I. \ -I$(GTK_TOP)/include \ -I$(GTK_TOP)/include/glib-2.0 \ -I$(GTK_TOP)/lib/glib-2.0/include \ - -I$(HOWL_TOP)/include \ + -I$(BONJOUR_TOP)/include \ -I$(PURPLE_TOP) \ -I$(PURPLE_TOP)/win32 \ -I$(PIDGIN_TREE_TOP) LIB_PATHS += -L$(GTK_TOP)/lib \ - -L$(HOWL_TOP)/lib \ + -L$(BONJOUR_TOP)/lib \ -L$(PURPLE_TOP) ## @@ -42,7 +41,8 @@ ## C_SRC = bonjour.c \ buddy.c \ - dns_sd.c \ + mdns_common.c \ + mdns_win32.c \ jabber.c OBJECTS = $(C_SRC:%.c=%.o) @@ -54,7 +54,7 @@ -lglib-2.0 \ -lws2_32 \ -lintl \ - -lhowl \ + -ldnssd \ -lpurple include $(PIDGIN_COMMON_RULES) @@ -68,7 +68,6 @@ install: all $(DLL_INSTALL_DIR) cp $(TARGET).dll $(DLL_INSTALL_DIR) - cp $(NEEDED_DLLS) $(PURPLE_INSTALL_DIR) $(OBJECTS): $(PURPLE_CONFIG_H) diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/bonjour.c --- a/libpurple/protocols/bonjour/bonjour.c Tue Jun 05 03:13:02 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour.c Tue Jun 05 03:38:22 2007 +0000 @@ -37,7 +37,7 @@ #include "version.h" #include "bonjour.h" -#include "dns_sd.h" +#include "mdns_common.h" #include "jabber.h" #include "buddy.h" @@ -120,7 +120,7 @@ /* Connect to the mDNS daemon looking for buddies in the LAN */ bd->dns_sd_data = bonjour_dns_sd_new(); - bd->dns_sd_data->name = (sw_string)purple_account_get_username(account); + bd->dns_sd_data->name = purple_account_get_username(account); bd->dns_sd_data->txtvers = g_strdup("1"); bd->dns_sd_data->version = g_strdup("1"); bd->dns_sd_data->first = g_strdup(purple_account_get_string(account, "first", default_firstname)); @@ -491,8 +491,8 @@ LPUSER_INFO_10 user_info = NULL; LPSERVER_INFO_100 server_info = NULL; wchar_t *servername = NULL; - wchar_t username[UNLEN + 1] = {'\0'}; - DWORD dwLenUsername = sizeof(username); + wchar_t username[UNLEN + 1]; + DWORD dwLenUsername = UNLEN + 1; FARPROC myNetServerEnum = wpurple_find_and_loadproc( "Netapi32.dll", "NetServerEnum"); FARPROC myNetApiBufferFree = wpurple_find_and_loadproc( @@ -517,7 +517,7 @@ } } - if (!GetUserNameW(&username, &dwLenUsername)) { + if (!GetUserNameW((LPWSTR) &username, &dwLenUsername)) { purple_debug_warning("bonjour", "Unable to look up username\n"); } @@ -553,7 +553,7 @@ */ splitpoint = strchr(tmp, ','); if (splitpoint != NULL) - default_lastname = g_strndup(tmp, splitpoint - tmp); + default_lastname = g_strndup(tmp, splitpoint - tmp); else default_lastname = g_strdup(tmp); } diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/bonjour.h --- a/libpurple/protocols/bonjour/bonjour.h Tue Jun 05 03:13:02 2007 +0000 +++ b/libpurple/protocols/bonjour/bonjour.h Tue Jun 05 03:38:22 2007 +0000 @@ -26,9 +26,7 @@ #ifndef _BONJOUR_H_ #define _BONJOUR_H_ -#include - -#include "dns_sd.h" +#include "mdns_common.h" #include "internal.h" #include "jabber.h" diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/buddy.c --- a/libpurple/protocols/bonjour/buddy.c Tue Jun 05 03:13:02 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.c Tue Jun 05 03:38:22 2007 +0000 @@ -27,49 +27,109 @@ * Creates a new buddy. */ BonjourBuddy * -bonjour_buddy_new(const gchar *name, const gchar *first, gint port_p2pj, - const gchar *phsh, const gchar *status, const gchar *email, - const gchar *last, const gchar *jid, const gchar *AIM, - const gchar *vc, const gchar *ip, const gchar *msg) +bonjour_buddy_new(const gchar *name, PurpleAccount* account) { BonjourBuddy *buddy = malloc(sizeof(BonjourBuddy)); + buddy->account = account; buddy->name = g_strdup(name); - buddy->first = g_strdup(first); - buddy->port_p2pj = port_p2pj; - buddy->phsh = g_strdup(phsh); - buddy->status = g_strdup(status); - buddy->email = g_strdup(email); - buddy->last = g_strdup(last); - buddy->jid = g_strdup(jid); - buddy->AIM = g_strdup(AIM); - buddy->vc = g_strdup(vc); - buddy->ip = g_strdup(ip); - buddy->msg = g_strdup(msg); + buddy->first = NULL; + buddy->port_p2pj = 0; + buddy->phsh = NULL; + buddy->status = NULL; + buddy->email = NULL; + buddy->last = NULL; + buddy->jid = NULL; + buddy->AIM = NULL; + buddy->vc = NULL; + buddy->ip = NULL; + buddy->msg = NULL; buddy->conversation = NULL; + +#ifdef USE_BONJOUR_APPLE + buddy->txt_query = NULL; + buddy->txt_query_fd = 0; +#endif return buddy; } +void +set_bonjour_buddy_value(BonjourBuddy* buddy, bonjour_buddy_member member, const char* value, uint32_t len) +{ + gchar **key = NULL; + switch (member) + { + case E_BUDDY_FIRST: + key = &buddy->first; + break; + + case E_BUDDY_LAST: + key = &buddy->last; + break; + + case E_BUDDY_STATUS: + key = &buddy->status; + break; + + case E_BUDDY_EMAIL: + key = &buddy->email; + break; + + case E_BUDDY_PHSH: + key = &buddy->phsh; + break; + + case E_BUDDY_JID: + key = &buddy->jid; + break; + + case E_BUDDY_AIM: + key = &buddy->AIM; + break; + + case E_BUDDY_VC: + key = &buddy->vc; + break; + + case E_BUDDY_MSG: + key = &buddy->msg; + break; + } + + g_free(*key); + *key = NULL; + *key = g_strndup(value, len); +} + /** * Check if all the compulsory buddy data is present. */ gboolean bonjour_buddy_check(BonjourBuddy *buddy) { - if (buddy->name == NULL) { + if (buddy->account == NULL) + { + return FALSE; + } + + if (buddy->name == NULL) + { + return FALSE; + } + + if (buddy->first == NULL) + { return FALSE; } - if (buddy->first == NULL) { + if (buddy->last == NULL) + { return FALSE; } - if (buddy->last == NULL) { - return FALSE; - } - - if (buddy->status == NULL) { + if (buddy->status == NULL) + { return FALSE; } @@ -82,13 +142,13 @@ * the buddy. */ void -bonjour_buddy_add_to_purple(PurpleAccount *account, BonjourBuddy *bonjour_buddy) +bonjour_buddy_add_to_purple(BonjourBuddy *bonjour_buddy) { PurpleBuddy *buddy; PurpleGroup *group; const char *status_id, *first, *last; char *alias; - + /* Translate between the Bonjour status and the Purple status */ if (g_ascii_strcasecmp("dnd", bonjour_buddy->status) == 0) status_id = BONJOUR_STATUS_ID_AWAY; @@ -108,6 +168,7 @@ (first && *first && last && *last ? " " : ""), (last && *last ? last : "")); + /* Make sure the Bonjour group exists in our buddy list */ group = purple_find_group(BONJOUR_GROUP_NAME); /* Use the buddy's domain, instead? */ if (group == NULL) @@ -117,10 +178,11 @@ } /* Make sure the buddy exists in our buddy list */ - buddy = purple_find_buddy(account, bonjour_buddy->name); + buddy = purple_find_buddy(bonjour_buddy->account, bonjour_buddy->name); + if (buddy == NULL) { - buddy = purple_buddy_new(account, bonjour_buddy->name, alias); + buddy = purple_buddy_new(bonjour_buddy->account, bonjour_buddy->name, alias); buddy->proto_data = bonjour_buddy; purple_blist_node_set_flags((PurpleBlistNode *)buddy, PURPLE_BLIST_NODE_FLAG_NO_SAVE); purple_blist_add_buddy(buddy, NULL, group, NULL); @@ -128,13 +190,14 @@ /* Set the user's status */ if (bonjour_buddy->msg != NULL) - purple_prpl_got_user_status(account, buddy->name, status_id, + purple_prpl_got_user_status(bonjour_buddy->account, buddy->name, status_id, "message", bonjour_buddy->msg, NULL); else - purple_prpl_got_user_status(account, buddy->name, status_id, + purple_prpl_got_user_status(bonjour_buddy->account, buddy->name, status_id, NULL); - purple_prpl_got_user_idle(account, buddy->name, FALSE, 0); + purple_prpl_got_user_idle(bonjour_buddy->account, buddy->name, FALSE, 0); + g_free(alias); } @@ -162,6 +225,14 @@ g_free(buddy->conversation->buddy_name); g_free(buddy->conversation); } + +#ifdef USE_BONJOUR_APPLE + if (NULL != buddy->txt_query) + { + purple_input_remove(buddy->txt_query_fd); + DNSServiceRefDeallocate(buddy->txt_query); + } +#endif free(buddy); } diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/buddy.h --- a/libpurple/protocols/bonjour/buddy.h Tue Jun 05 03:13:02 2007 +0000 +++ b/libpurple/protocols/bonjour/buddy.h Tue Jun 05 03:38:22 2007 +0000 @@ -17,14 +17,22 @@ #ifndef _BONJOUR_BUDDY #define _BONJOUR_BUDDY -#include #include +#include "config.h" #include "account.h" #include "jabber.h" +#ifdef USE_BONJOUR_APPLE +#include "dns_sd_proxy.h" +#else /* USE_BONJOUR_HOWL */ +#include +#endif + typedef struct _BonjourBuddy { + PurpleAccount *account; + gchar *name; gchar *first; gint port_p2pj; @@ -37,16 +45,38 @@ gchar *vc; gchar *ip; gchar *msg; + BonjourJabberConversation *conversation; + +#ifdef USE_BONJOUR_APPLE + DNSServiceRef txt_query; + int txt_query_fd; +#endif + } BonjourBuddy; +typedef enum _bonjour_buddy_member +{ + E_BUDDY_FIRST, + E_BUDDY_LAST, + E_BUDDY_STATUS, + E_BUDDY_EMAIL, + E_BUDDY_PHSH, + E_BUDDY_JID, + E_BUDDY_AIM, + E_BUDDY_VC, + E_BUDDY_MSG +} bonjour_buddy_member; + /** * Creates a new buddy. */ -BonjourBuddy *bonjour_buddy_new(const gchar *name, const gchar *first, - gint port_p2pj, const gchar *phsh, const gchar *status, - const gchar *email, const gchar *last, const gchar *jid, - const gchar *AIM, const gchar *vc, const gchar *ip, const gchar *msg); +BonjourBuddy *bonjour_buddy_new(const gchar *name, PurpleAccount* account); + +/** + * Sets a value in the BonjourBuddy struct, destroying the old value + */ +void set_bonjour_buddy_value(BonjourBuddy* buddy, bonjour_buddy_member member, const char* value, uint32_t len); /** * Check if all the compulsory buddy data is present. @@ -56,7 +86,7 @@ /** * If the buddy doesn't previoulsy exists, it is created. Else, its data is changed (???) */ -void bonjour_buddy_add_to_purple(PurpleAccount *account, BonjourBuddy *buddy); +void bonjour_buddy_add_to_purple(BonjourBuddy *buddy); /** * Deletes a buddy from memory. diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/dns_sd.c --- a/libpurple/protocols/bonjour/dns_sd.c Tue Jun 05 03:13:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,387 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include - -#include "dns_sd.h" -#include "bonjour.h" -#include "buddy.h" -#include "debug.h" - -/* Private functions */ - -static sw_result HOWL_API -_publish_reply(sw_discovery discovery, sw_discovery_oid oid, - sw_discovery_publish_status status, sw_opaque extra) -{ - purple_debug_warning("bonjour", "_publish_reply --> Start\n"); - - /* Check the answer from the mDNS daemon */ - switch (status) - { - case SW_DISCOVERY_PUBLISH_STARTED : - purple_debug_info("bonjour", "_publish_reply --> Service started\n"); - break; - case SW_DISCOVERY_PUBLISH_STOPPED : - purple_debug_info("bonjour", "_publish_reply --> Service stopped\n"); - break; - case SW_DISCOVERY_PUBLISH_NAME_COLLISION : - purple_debug_info("bonjour", "_publish_reply --> Name collision\n"); - break; - case SW_DISCOVERY_PUBLISH_INVALID : - purple_debug_info("bonjour", "_publish_reply --> Service invalid\n"); - break; - } - - return SW_OKAY; -} - -static sw_result HOWL_API -_resolve_reply(sw_discovery discovery, sw_discovery_oid oid, - sw_uint32 interface_index, sw_const_string name, - sw_const_string type, sw_const_string domain, - sw_ipv4_address address, sw_port port, - sw_octets text_record, sw_ulong text_record_len, - sw_opaque extra) -{ - BonjourBuddy *buddy; - PurpleAccount *account = (PurpleAccount*)extra; - gchar *txtvers = NULL; - gchar *version = NULL; - gchar *first = NULL; - gchar *phsh = NULL; - gchar *status = NULL; - gchar *email = NULL; - gchar *last = NULL; - gchar *jid = NULL; - gchar *AIM = NULL; - gchar *vc = NULL; - gchar *msg = NULL; - gint address_length = 16; - gchar *ip = NULL; - sw_text_record_iterator iterator; - char key[SW_TEXT_RECORD_MAX_LEN]; - char value[SW_TEXT_RECORD_MAX_LEN]; - sw_uint32 value_length; - - sw_discovery_cancel(discovery, oid); - - /* Get the ip as a string */ - ip = malloc(address_length); - sw_ipv4_address_name(address, ip, address_length); - - /* Obtain the parameters from the text_record */ - if ((text_record_len > 0) && (text_record) && (*text_record != '\0')) - { - sw_text_record_iterator_init(&iterator, text_record, text_record_len); - while (sw_text_record_iterator_next(iterator, key, (sw_octet *)value, &value_length) == SW_OKAY) - { - /* Compare the keys with the possible ones and save them on */ - /* the appropiate place of the buddy_list */ - if (strcmp(key, "txtvers") == 0) { - txtvers = g_strdup(value); - } else if (strcmp(key, "version") == 0) { - version = g_strdup(value); - } else if (strcmp(key, "1st") == 0) { - first = g_strdup(value); - } else if (strcmp(key, "status") == 0) { - status = g_strdup(value); - } else if (strcmp(key, "email") == 0) { - email = g_strdup(value); - } else if (strcmp(key, "last") == 0) { - last = g_strdup(value); - } else if (strcmp(key, "jid") == 0) { - jid = g_strdup(value); - } else if (strcmp(key, "AIM") == 0) { - AIM = g_strdup(value); - } else if (strcmp(key, "vc") == 0) { - vc = g_strdup(value); - } else if (strcmp(key, "phsh") == 0) { - phsh = g_strdup(value); - } else if (strcmp(key, "msg") == 0) { - msg = g_strdup(value); - } - } - } - - /* Put the parameters of the text_record in a buddy and add the buddy to */ - /* the buddy list */ - buddy = bonjour_buddy_new(name, first, port, phsh, - status, email, last, jid, AIM, vc, ip, msg); - - if (bonjour_buddy_check(buddy) == FALSE) - { - bonjour_buddy_delete(buddy); - return SW_DISCOVERY_E_UNKNOWN; - } - - /* Add or update the buddy in our buddy list */ - bonjour_buddy_add_to_purple(account, buddy); - - /* Free all the temporal strings */ - g_free(txtvers); - g_free(version); - g_free(first); - g_free(last); - g_free(status); - g_free(email); - g_free(jid); - g_free(AIM); - g_free(vc); - g_free(phsh); - g_free(msg); - - return SW_OKAY; -} - -static sw_result HOWL_API -_browser_reply(sw_discovery discovery, sw_discovery_oid oid, - sw_discovery_browse_status status, - sw_uint32 interface_index, sw_const_string name, - sw_const_string type, sw_const_string domain, - sw_opaque_t extra) -{ - sw_discovery_resolve_id rid; - PurpleAccount *account = (PurpleAccount*)extra; - PurpleBuddy *gb = NULL; - - switch (status) - { - case SW_DISCOVERY_BROWSE_INVALID: - purple_debug_warning("bonjour", "_browser_reply --> Invalid\n"); - break; - case SW_DISCOVERY_BROWSE_RELEASE: - purple_debug_warning("bonjour", "_browser_reply --> Release\n"); - break; - case SW_DISCOVERY_BROWSE_ADD_DOMAIN: - purple_debug_warning("bonjour", "_browser_reply --> Add domain\n"); - break; - case SW_DISCOVERY_BROWSE_ADD_DEFAULT_DOMAIN: - purple_debug_warning("bonjour", "_browser_reply --> Add default domain\n"); - break; - case SW_DISCOVERY_BROWSE_REMOVE_DOMAIN: - purple_debug_warning("bonjour", "_browser_reply --> Remove domain\n"); - break; - case SW_DISCOVERY_BROWSE_ADD_SERVICE: - /* A new peer has joined the network and uses iChat bonjour */ - purple_debug_info("bonjour", "_browser_reply --> Add service\n"); - if (g_ascii_strcasecmp(name, account->username) != 0) - { - if (sw_discovery_resolve(discovery, interface_index, name, type, - domain, _resolve_reply, extra, &rid) != SW_OKAY) - { - purple_debug_warning("bonjour", "_browser_reply --> Cannot send resolve\n"); - } - } - break; - case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: - purple_debug_info("bonjour", "_browser_reply --> Remove service\n"); - gb = purple_find_buddy((PurpleAccount*)extra, name); - if (gb != NULL) - { - bonjour_buddy_delete(gb->proto_data); - purple_blist_remove_buddy(gb); - } - break; - case SW_DISCOVERY_BROWSE_RESOLVED: - purple_debug_info("bonjour", "_browse_reply --> Resolved\n"); - break; - default: - break; - } - - return SW_OKAY; -} - -static int -_dns_sd_publish(BonjourDnsSd *data, PublishType type) -{ - sw_text_record dns_data; - sw_result publish_result = SW_OKAY; - char portstring[6]; - - /* Fill the data for the service */ - if (sw_text_record_init(&dns_data) != SW_OKAY) - { - purple_debug_error("bonjour", "Unable to initialize the data for the mDNS.\n"); - return -1; - } - - /* Convert the port to a string */ - snprintf(portstring, sizeof(portstring), "%d", data->port_p2pj); - - /* Publish standard records */ - sw_text_record_add_key_and_string_value(dns_data, "txtvers", data->txtvers); - sw_text_record_add_key_and_string_value(dns_data, "version", data->version); - sw_text_record_add_key_and_string_value(dns_data, "1st", data->first); - sw_text_record_add_key_and_string_value(dns_data, "last", data->last); - sw_text_record_add_key_and_string_value(dns_data, "port.p2pj", portstring); - sw_text_record_add_key_and_string_value(dns_data, "phsh", data->phsh); - sw_text_record_add_key_and_string_value(dns_data, "status", data->status); - sw_text_record_add_key_and_string_value(dns_data, "vc", data->vc); - - /* Publish extra records */ - if ((data->email != NULL) && (*data->email != '\0')) - sw_text_record_add_key_and_string_value(dns_data, "email", data->email); - - if ((data->jid != NULL) && (*data->jid != '\0')) - sw_text_record_add_key_and_string_value(dns_data, "jid", data->jid); - - if ((data->AIM != NULL) && (*data->AIM != '\0')) - sw_text_record_add_key_and_string_value(dns_data, "AIM", data->AIM); - - if ((data->msg != NULL) && (*data->msg != '\0')) - sw_text_record_add_key_and_string_value(dns_data, "msg", data->msg); - - /* Publish the service */ - switch (type) - { - case PUBLISH_START: - publish_result = sw_discovery_publish(data->session, 0, data->name, ICHAT_SERVICE, NULL, - NULL, data->port_p2pj, sw_text_record_bytes(dns_data), sw_text_record_len(dns_data), - _publish_reply, NULL, &data->session_id); - break; - case PUBLISH_UPDATE: - publish_result = sw_discovery_publish_update(data->session, data->session_id, - sw_text_record_bytes(dns_data), sw_text_record_len(dns_data)); - break; - } - if (publish_result != SW_OKAY) - { - purple_debug_error("bonjour", "Unable to publish or change the status of the _presence._tcp service.\n"); - return -1; - } - - /* Free the memory used by temp data */ - sw_text_record_fina(dns_data); - - return 0; -} - -static void -_dns_sd_handle_packets(gpointer data, gint source, PurpleInputCondition condition) -{ - sw_discovery_read_socket((sw_discovery)data); -} - -/* End private functions */ - -/** - * Allocate space for the dns-sd data. - */ -BonjourDnsSd * -bonjour_dns_sd_new() -{ - BonjourDnsSd *data = g_new0(BonjourDnsSd, 1); - - return data; -} - -/** - * Deallocate the space of the dns-sd data. - */ -void -bonjour_dns_sd_free(BonjourDnsSd *data) -{ - g_free(data->first); - g_free(data->last); - g_free(data->email); - g_free(data); -} - -/** - * Send a new dns-sd packet updating our status. - */ -void -bonjour_dns_sd_send_status(BonjourDnsSd *data, const char *status, const char *status_message) -{ - g_free(data->status); - g_free(data->msg); - - data->status = g_strdup(status); - data->msg = g_strdup(status_message); - - /* Update our text record with the new status */ - _dns_sd_publish(data, PUBLISH_UPDATE); /* <--We must control the errors */ -} - -/** - * Advertise our presence within the dns-sd daemon and start browsing - * for other bonjour peers. - */ -gboolean -bonjour_dns_sd_start(BonjourDnsSd *data) -{ - PurpleAccount *account; - PurpleConnection *gc; - gint dns_sd_socket; - sw_discovery_oid session_id; - - account = data->account; - gc = purple_account_get_connection(account); - - /* Initialize the dns-sd data and session */ - if (sw_discovery_init(&data->session) != SW_OKAY) - { - purple_debug_error("bonjour", "Unable to initialize an mDNS session.\n"); - - /* In Avahi, sw_discovery_init frees data->session but doesn't clear it */ - data->session = NULL; - - return FALSE; - } - - /* Publish our bonjour IM client at the mDNS daemon */ - _dns_sd_publish(data, PUBLISH_START); /* <--We must control the errors */ - - /* Advise the daemon that we are waiting for connections */ - if (sw_discovery_browse(data->session, 0, ICHAT_SERVICE, NULL, _browser_reply, - data->account, &session_id) != SW_OKAY) - { - purple_debug_error("bonjour", "Unable to get service."); - return FALSE; - } - - /* Get the socket that communicates with the mDNS daemon and bind it to a */ - /* callback that will handle the dns_sd packets */ - dns_sd_socket = sw_discovery_socket(data->session); - gc->inpa = purple_input_add(dns_sd_socket, PURPLE_INPUT_READ, - _dns_sd_handle_packets, data->session); - - return TRUE; -} - -/** - * Unregister the "_presence._tcp" service at the mDNS daemon. - */ -void -bonjour_dns_sd_stop(BonjourDnsSd *data) -{ - PurpleAccount *account; - PurpleConnection *gc; - - if (data->session == NULL) - return; - - sw_discovery_cancel(data->session, data->session_id); - - account = data->account; - gc = purple_account_get_connection(account); - purple_input_remove(gc->inpa); - - g_free(data->session); - data->session = NULL; -} diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/dns_sd.h --- a/libpurple/protocols/bonjour/dns_sd.h Tue Jun 05 03:13:02 2007 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _BONJOUR_DNS_SD -#define _BONJOUR_DNS_SD - -#include -#include -#include "account.h" - -#define ICHAT_SERVICE "_presence._tcp." - -/** - * Data to be used by the dns-sd connection. - */ -typedef struct _BonjourDnsSd -{ - sw_discovery session; - sw_discovery_oid session_id; - PurpleAccount *account; - gchar *name; - gchar *txtvers; - gchar *version; - gchar *first; - gchar *last; - gint port_p2pj; - gchar *phsh; - gchar *status; - gchar *email; - gchar *vc; - gchar *jid; - gchar *AIM; - gchar *msg; - GHashTable *buddies; -} BonjourDnsSd; - -typedef enum _PublishType { - PUBLISH_START, - PUBLISH_UPDATE -} PublishType; - -/** - * Allocate space for the dns-sd data. - */ -BonjourDnsSd *bonjour_dns_sd_new(void); - -/** - * Deallocate the space of the dns-sd data. - */ -void bonjour_dns_sd_free(BonjourDnsSd *data); - -/** - * Send a new dns-sd packet updating our status. - */ -void bonjour_dns_sd_send_status(BonjourDnsSd *data, const char *status, const char *status_message); - -/** - * Advertise our presence within the dns-sd daemon and start - * browsing for other bonjour peers. - */ -gboolean bonjour_dns_sd_start(BonjourDnsSd *data); - -/** - * Unregister the "_presence._tcp" service at the mDNS daemon. - */ -void bonjour_dns_sd_stop(BonjourDnsSd *data); - -#endif diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/dns_sd_proxy.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/dns_sd_proxy.h Tue Jun 05 03:38:22 2007 +0000 @@ -0,0 +1,19 @@ +#ifndef _DNS_SD_PROXY +#define _DNS_SD_PROXY + +#include + +/* fixup to make pidgin compile against win32 bonjour */ +#ifdef _WIN32 +#define _MSL_STDINT_H +#undef bzero +#endif + +#include + +/* dns_sd.h defines bzero and we also do in libc_internal.h */ +#ifdef _WIN32 +#undef bzero +#endif + +#endif diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/jabber.c --- a/libpurple/protocols/bonjour/jabber.c Tue Jun 05 03:13:02 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Tue Jun 05 03:38:22 2007 +0000 @@ -51,18 +51,19 @@ gint socket_fd; gint retorno = 0; struct sockaddr_in buddy_address; + BonjourBuddy *bb = gb->proto_data; /* Create a socket and make it non-blocking */ socket_fd = socket(PF_INET, SOCK_STREAM, 0); buddy_address.sin_family = PF_INET; - buddy_address.sin_port = htons(((BonjourBuddy*)(gb->proto_data))->port_p2pj); - inet_aton(((BonjourBuddy*)(gb->proto_data))->ip, &(buddy_address.sin_addr)); + buddy_address.sin_port = htons(bb->port_p2pj); + inet_aton(bb->ip, &(buddy_address.sin_addr)); memset(&(buddy_address.sin_zero), '\0', 8); retorno = connect(socket_fd, (struct sockaddr*)&buddy_address, sizeof(struct sockaddr)); if (retorno == -1) { - purple_debug_warning("bonjour", "connect error: %s\n", strerror(errno)); + purple_debug_warning("bonjour", "Error connecting to buddy %s at %s:%d error: %s\n", purple_buddy_get_name(gb), bb->ip ? bb->ip : "(null)", buddy_address.sin_port, strerror(errno)); } fcntl(socket_fd, F_SETFL, O_NONBLOCK); diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/mdns_common.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_common.c Tue Jun 05 03:38:22 2007 +0000 @@ -0,0 +1,174 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "config.h" +#include "mdns_common.h" +#include "bonjour.h" +#include "buddy.h" +#include "debug.h" + + +/** + * Allocate space for the dns-sd data. + */ +BonjourDnsSd * +bonjour_dns_sd_new() +{ + BonjourDnsSd *data = g_new0(BonjourDnsSd, 1); + + return data; +} + +/** + * Deallocate the space of the dns-sd data. + */ +void +bonjour_dns_sd_free(BonjourDnsSd *data) +{ + g_free(data->first); + g_free(data->last); + g_free(data->email); + g_free(data); +} + +/** + * Send a new dns-sd packet updating our status. + */ +void +bonjour_dns_sd_send_status(BonjourDnsSd *data, const char *status, const char *status_message) +{ + g_free(data->status); + g_free(data->msg); + + data->status = g_strdup(status); + data->msg = g_strdup(status_message); + + /* Update our text record with the new status */ + _mdns_publish(data, PUBLISH_UPDATE); /* <--We must control the errors */ +} + +/** + * Advertise our presence within the dns-sd daemon and start browsing + * for other bonjour peers. + */ +gboolean +bonjour_dns_sd_start(BonjourDnsSd *data) +{ + PurpleAccount *account; + PurpleConnection *gc; + gint dns_sd_socket; + gpointer opaque_data; + +#ifdef USE_BONJOUR_HOWL + sw_discovery_oid session_id; +#endif + + account = data->account; + gc = purple_account_get_connection(account); + + /* Initialize the dns-sd data and session */ + +#ifndef USE_BONJOUR_APPLE + if (sw_discovery_init(&data->session) != SW_OKAY) + { + purple_debug_error("bonjour", "Unable to initialize an mDNS session.\n"); + + /* In Avahi, sw_discovery_init frees data->session but doesn't clear it */ + data->session = NULL; + + return FALSE; + } +#endif + + /* Publish our bonjour IM client at the mDNS daemon */ + + if (0 != _mdns_publish(data, PUBLISH_START)) + { + return FALSE; + } + + /* Advise the daemon that we are waiting for connections */ + +#ifdef USE_BONJOUR_APPLE + printf("account pointer here is %x\n,", account); + if (DNSServiceBrowse(&data->browser, 0, 0, ICHAT_SERVICE, NULL, _mdns_service_browse_callback, account) + != kDNSServiceErr_NoError) +#else /* USE_BONJOUR_HOWL */ + if (sw_discovery_browse(data->session, 0, ICHAT_SERVICE, NULL, _browser_reply, + account, &session_id) != SW_OKAY) +#endif + { + purple_debug_error("bonjour", "Unable to get service."); + return FALSE; + } + + /* Get the socket that communicates with the mDNS daemon and bind it to a */ + /* callback that will handle the dns_sd packets */ + +#ifdef USE_BONJOUR_APPLE + dns_sd_socket = DNSServiceRefSockFD(data->browser); + opaque_data = data->browser; +#else /* USE_BONJOUR_HOWL */ + dns_sd_socket = sw_discovery_socket(data->session); + opaque_data = data->session; +#endif + + gc->inpa = purple_input_add(dns_sd_socket, PURPLE_INPUT_READ, + _mdns_handle_event, opaque_data); + + return TRUE; +} + +/** + * Unregister the "_presence._tcp" service at the mDNS daemon. + */ + +void +bonjour_dns_sd_stop(BonjourDnsSd *data) +{ + PurpleAccount *account; + PurpleConnection *gc; + +#ifdef USE_BONJOUR_APPLE + if (NULL == data->advertisement || NULL == data->browser) +#else /* USE_BONJOUR_HOWL */ + if (data->session == NULL) +#endif + return; + +#ifdef USE_BONJOUR_HOWL + sw_discovery_cancel(data->session, data->session_id); +#endif + + account = data->account; + gc = purple_account_get_connection(account); + purple_input_remove(gc->inpa); + +#ifdef USE_BONJOUR_APPLE + /* hack: for win32, we need to stop listening to the advertisement pipe too */ + purple_input_remove(data->advertisement_fd); + + DNSServiceRefDeallocate(data->advertisement); + DNSServiceRefDeallocate(data->browser); + data->advertisement = NULL; + data->browser = NULL; +#else /* USE_BONJOUR_HOWL */ + g_free(data->session); + data->session = NULL; +#endif +} diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/mdns_common.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_common.h Tue Jun 05 03:38:22 2007 +0000 @@ -0,0 +1,51 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _BONJOUR_MDNS_COMMON +#define _BONJOUR_MDNS_COMMON + +#include "mdns_types.h" + +#include "mdns_win32.h" +#include "mdns_howl.h" + +/** + * Allocate space for the dns-sd data. + */ +BonjourDnsSd *bonjour_dns_sd_new(void); + +/** + * Deallocate the space of the dns-sd data. + */ +void bonjour_dns_sd_free(BonjourDnsSd *data); + +/** + * Send a new dns-sd packet updating our status. + */ +void bonjour_dns_sd_send_status(BonjourDnsSd *data, const char *status, const char *status_message); + +/** + * Advertise our presence within the dns-sd daemon and start + * browsing for other bonjour peers. + */ +gboolean bonjour_dns_sd_start(BonjourDnsSd *data); + +/** + * Unregister the "_presence._tcp" service at the mDNS daemon. + */ +void bonjour_dns_sd_stop(BonjourDnsSd *data); + +#endif diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/mdns_howl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_howl.c Tue Jun 05 03:38:22 2007 +0000 @@ -0,0 +1,264 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "mdns_howl.h" + +#include "debug.h" +#include "buddy.h" + +sw_result HOWL_API +_publish_reply(sw_discovery discovery, sw_discovery_oid oid, + sw_discovery_publish_status status, sw_opaque extra) +{ + purple_debug_warning("bonjour", "_publish_reply --> Start\n"); + + /* Check the answer from the mDNS daemon */ + switch (status) + { + case SW_DISCOVERY_PUBLISH_STARTED : + purple_debug_info("bonjour", "_publish_reply --> Service started\n"); + break; + case SW_DISCOVERY_PUBLISH_STOPPED : + purple_debug_info("bonjour", "_publish_reply --> Service stopped\n"); + break; + case SW_DISCOVERY_PUBLISH_NAME_COLLISION : + purple_debug_info("bonjour", "_publish_reply --> Name collision\n"); + break; + case SW_DISCOVERY_PUBLISH_INVALID : + purple_debug_info("bonjour", "_publish_reply --> Service invalid\n"); + break; + } + + return SW_OKAY; +} + +sw_result HOWL_API +_resolve_reply(sw_discovery discovery, sw_discovery_oid oid, + sw_uint32 interface_index, sw_const_string name, + sw_const_string type, sw_const_string domain, + sw_ipv4_address address, sw_port port, + sw_octets text_record, sw_ulong text_record_len, + sw_opaque extra) +{ + BonjourBuddy *buddy; + PurpleAccount *account = (PurpleAccount*)extra; + /*gchar *txtvers = NULL;*/ + /*gchar *version = NULL;*/ + gint address_length = 16; + sw_text_record_iterator iterator; + char key[SW_TEXT_RECORD_MAX_LEN]; + char value[SW_TEXT_RECORD_MAX_LEN]; + sw_uint32 value_length; + + sw_discovery_cancel(discovery, oid); + + /* create a buddy record */ + buddy = bonjour_buddy_new(name, account); + + /* Get the ip as a string */ + buddy->ip = g_malloc(address_length); + sw_ipv4_address_name(address, buddy->ip, address_length); + + buddy->port_p2pj = port; + + /* Obtain the parameters from the text_record */ + if ((text_record_len > 0) && (text_record) && (*text_record != '\0')) + { + sw_text_record_iterator_init(&iterator, text_record, text_record_len); + while (sw_text_record_iterator_next(iterator, key, (sw_octet *)value, &value_length) == SW_OKAY) + { + /* Compare the keys with the possible ones and save them on */ + /* the appropiate place of the buddy_list */ + if (strcmp(key, "txtvers") == 0) { + /*txtvers = g_strdup(value);*/ + } else if (strcmp(key, "version") == 0) { + /*version = g_strdup(value);*/ + } else if (strcmp(key, "1st") == 0) { + g_free(buddy->first); + buddy->first = g_strdup(value); + } else if (strcmp(key, "status") == 0) { + g_free(buddy->status); + buddy->status = g_strdup(value); + } else if (strcmp(key, "email") == 0) { + g_free(buddy->email); + buddy->email = g_strdup(value); + } else if (strcmp(key, "last") == 0) { + g_free(buddy->last); + buddy->last = g_strdup(value); + } else if (strcmp(key, "jid") == 0) { + g_free(buddy->jid); + buddy->jid = g_strdup(value); + } else if (strcmp(key, "AIM") == 0) { + g_free(buddy->AIM); + buddy->AIM = g_strdup(value); + } else if (strcmp(key, "vc") == 0) { + g_free(buddy->vc); + buddy->vc = g_strdup(value); + } else if (strcmp(key, "phsh") == 0) { + g_free(buddy->phsh); + buddy->phsh = g_strdup(value); + } else if (strcmp(key, "msg") == 0) { + g_free(buddy->msg); + buddy->msg = g_strdup(value); + } + } + } + + if (!bonjour_buddy_check(buddy)) + { + bonjour_buddy_delete(buddy); + return SW_DISCOVERY_E_UNKNOWN; + } + + /* Add or update the buddy in our buddy list */ + bonjour_buddy_add_to_purple(buddy); + + /* Free all the temporal strings */ + /*g_free(txtvers);*/ + /*g_free(version);*/ + + return SW_OKAY; +} + +sw_result HOWL_API +_browser_reply(sw_discovery discovery, sw_discovery_oid oid, + sw_discovery_browse_status status, + sw_uint32 interface_index, sw_const_string name, + sw_const_string type, sw_const_string domain, + sw_opaque_t extra) +{ + sw_discovery_resolve_id rid; + PurpleAccount *account = (PurpleAccount*)extra; + PurpleBuddy *gb = NULL; + + switch (status) + { + case SW_DISCOVERY_BROWSE_INVALID: + purple_debug_warning("bonjour", "_browser_reply --> Invalid\n"); + break; + case SW_DISCOVERY_BROWSE_RELEASE: + purple_debug_warning("bonjour", "_browser_reply --> Release\n"); + break; + case SW_DISCOVERY_BROWSE_ADD_DOMAIN: + purple_debug_warning("bonjour", "_browser_reply --> Add domain\n"); + break; + case SW_DISCOVERY_BROWSE_ADD_DEFAULT_DOMAIN: + purple_debug_warning("bonjour", "_browser_reply --> Add default domain\n"); + break; + case SW_DISCOVERY_BROWSE_REMOVE_DOMAIN: + purple_debug_warning("bonjour", "_browser_reply --> Remove domain\n"); + break; + case SW_DISCOVERY_BROWSE_ADD_SERVICE: + /* A new peer has joined the network and uses iChat bonjour */ + purple_debug_info("bonjour", "_browser_reply --> Add service\n"); + if (g_ascii_strcasecmp(name, account->username) != 0) + { + if (sw_discovery_resolve(discovery, interface_index, name, type, + domain, _resolve_reply, extra, &rid) != SW_OKAY) + { + purple_debug_warning("bonjour", "_browser_reply --> Cannot send resolve\n"); + } + } + break; + case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: + purple_debug_info("bonjour", "_browser_reply --> Remove service\n"); + gb = purple_find_buddy((PurpleAccount*)extra, name); + if (gb != NULL) + { + bonjour_buddy_delete(gb->proto_data); + purple_blist_remove_buddy(gb); + } + break; + case SW_DISCOVERY_BROWSE_RESOLVED: + purple_debug_info("bonjour", "_browse_reply --> Resolved\n"); + break; + default: + break; + } + + return SW_OKAY; +} + +int +_mdns_publish(BonjourDnsSd *data, PublishType type) +{ + sw_text_record dns_data; + sw_result publish_result = SW_OKAY; + char portstring[6]; + + /* Fill the data for the service */ + if (sw_text_record_init(&dns_data) != SW_OKAY) + { + purple_debug_error("bonjour", "Unable to initialize the data for the mDNS.\n"); + return -1; + } + + /* Convert the port to a string */ + snprintf(portstring, sizeof(portstring), "%d", data->port_p2pj); + + /* Publish standard records */ + sw_text_record_add_key_and_string_value(dns_data, "txtvers", data->txtvers); + sw_text_record_add_key_and_string_value(dns_data, "version", data->version); + sw_text_record_add_key_and_string_value(dns_data, "1st", data->first); + sw_text_record_add_key_and_string_value(dns_data, "last", data->last); + sw_text_record_add_key_and_string_value(dns_data, "port.p2pj", portstring); + sw_text_record_add_key_and_string_value(dns_data, "phsh", data->phsh); + sw_text_record_add_key_and_string_value(dns_data, "status", data->status); + sw_text_record_add_key_and_string_value(dns_data, "vc", data->vc); + + /* Publish extra records */ + if ((data->email != NULL) && (*data->email != '\0')) + sw_text_record_add_key_and_string_value(dns_data, "email", data->email); + + if ((data->jid != NULL) && (*data->jid != '\0')) + sw_text_record_add_key_and_string_value(dns_data, "jid", data->jid); + + if ((data->AIM != NULL) && (*data->AIM != '\0')) + sw_text_record_add_key_and_string_value(dns_data, "AIM", data->AIM); + + if ((data->msg != NULL) && (*data->msg != '\0')) + sw_text_record_add_key_and_string_value(dns_data, "msg", data->msg); + + /* Publish the service */ + switch (type) + { + case PUBLISH_START: + publish_result = sw_discovery_publish(data->session, 0, data->name, ICHAT_SERVICE, NULL, + NULL, data->port_p2pj, sw_text_record_bytes(dns_data), sw_text_record_len(dns_data), + _publish_reply, NULL, &data->session_id); + break; + case PUBLISH_UPDATE: + publish_result = sw_discovery_publish_update(data->session, data->session_id, + sw_text_record_bytes(dns_data), sw_text_record_len(dns_data)); + break; + } + if (publish_result != SW_OKAY) + { + purple_debug_error("bonjour", "Unable to publish or change the status of the _presence._tcp service.\n"); + return -1; + } + + /* Free the memory used by temp data */ + sw_text_record_fina(dns_data); + + return 0; +} + +void +_mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition) +{ + sw_discovery_read_socket((sw_discovery)data); +} diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/mdns_howl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_howl.h Tue Jun 05 03:38:22 2007 +0000 @@ -0,0 +1,47 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _BONJOUR_MDNS_HOWL +#define _BONJOUR_MDNS_HOWL + +#include "config.h" + +#ifdef USE_BONJOUR_HOWL + +#include +#include +#include "mdns_types.h" + +/* callback functions */ + +sw_result HOWL_API _publish_reply(sw_discovery discovery, sw_discovery_oid oid, sw_discovery_publish_status status, sw_opaque extra); + +sw_result HOWL_API _resolve_reply(sw_discovery discovery, sw_discovery_oid oid, sw_uint32 interface_index, sw_const_string name, + sw_const_string type, sw_const_string domain, sw_ipv4_address address, sw_port port, sw_octets text_record, + sw_ulong text_record_len, sw_opaque extra); + +sw_result HOWL_API _browser_reply(sw_discovery discovery, sw_discovery_oid oid, sw_discovery_browse_status status, + sw_uint32 interface_index, sw_const_string name, sw_const_string type, sw_const_string domain, sw_opaque_t extra); + + +/* interface functions */ + +int _mdns_publish(BonjourDnsSd *data, PublishType type); +void _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition); + +#endif + +#endif diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/mdns_types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_types.h Tue Jun 05 03:38:22 2007 +0000 @@ -0,0 +1,70 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _BONJOUR_MDNS_TYPES +#define _BONJOUR_MDNS_TYPES + +#include +#include "account.h" +#include "config.h" + +#ifdef USE_BONJOUR_APPLE +#include "dns_sd_proxy.h" +#else /* USE_BONJOUR_HOWL */ +#include +#endif + +#define ICHAT_SERVICE "_presence._tcp." + +/** + * Data to be used by the dns-sd connection. + */ +typedef struct _BonjourDnsSd +{ +#ifdef USE_BONJOUR_APPLE + DNSServiceRef advertisement; + DNSServiceRef browser; + + int advertisement_fd; /* hack... windows bonjour is broken, so we have to have this */ +#else /* USE_BONJOUR_HOWL */ + sw_discovery session; + sw_discovery_oid session_id; +#endif + + PurpleAccount *account; + const char *name; + gchar *txtvers; + gchar *version; + gchar *first; + gchar *last; + gint port_p2pj; + gchar *phsh; + gchar *status; + gchar *email; + gchar *vc; + gchar *jid; + gchar *AIM; + gchar *msg; + GHashTable *buddies; +} BonjourDnsSd; + +typedef enum _PublishType { + PUBLISH_START, + PUBLISH_UPDATE +} PublishType; + + +#endif diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/mdns_win32.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.c Tue Jun 05 03:38:22 2007 +0000 @@ -0,0 +1,323 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "mdns_win32.h" + +#include "debug.h" + +void +_mdns_resolve_host_callback(GSList *hosts, gpointer data, const char *error_message) +{ + ResolveCallbackArgs* args = (ResolveCallbackArgs*)data; + + if (!hosts || !hosts->data) + { + purple_debug_error("bonjour", "host resolution - callback error.\n"); + } + else + { + struct sockaddr_in *addr = (struct sockaddr_in*)g_slist_nth_data(hosts, 1); + BonjourBuddy* buddy = args->buddy; + + buddy->ip = inet_ntoa(addr->sin_addr); + + /* finally, set up the continuous txt record watcher, and add the buddy to purple */ + + if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&buddy->txt_query, 0, 0, args->fqn, + kDNSServiceType_TXT, kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy)) + { + gint fd = DNSServiceRefSockFD(buddy->txt_query); + buddy->txt_query_fd = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, buddy->txt_query); + + bonjour_buddy_add_to_purple(buddy); + } + else + { + bonjour_buddy_delete(buddy); + } + + } + + /* free the hosts list*/ + g_slist_free(hosts); + + /* free the remaining args memory */ + purple_dnsquery_destroy(args->query); + g_free(args->fqn); + free(args); +} + +void DNSSD_API +_mdns_text_record_query_callback(DNSServiceRef DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, + DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, + const void *rdata, uint32_t ttl, void *context) +{ + if (kDNSServiceErr_NoError != errorCode) + { + purple_debug_error("bonjour", "text record query - callback error.\n"); + } + else if (flags & kDNSServiceFlagsAdd) + { + BonjourBuddy *buddy = (BonjourBuddy*)context; + _mdns_parse_text_record(buddy, rdata, rdlen); + bonjour_buddy_add_to_purple(buddy); + } +} + +void DNSSD_API +_mdns_service_resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, + const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context) +{ + ResolveCallbackArgs *args = (ResolveCallbackArgs*)context; + + /* remove the input fd and destroy the service ref */ + purple_input_remove(args->resolver_fd); + DNSServiceRefDeallocate(args->resolver); + + if (kDNSServiceErr_NoError != errorCode) + { + purple_debug_error("bonjour", "service resolver - callback error.\n"); + bonjour_buddy_delete(args->buddy); + free(args); + } + else + { + args->buddy->port_p2pj = port; + + /* parse the text record */ + _mdns_parse_text_record(args->buddy, txtRecord, txtLen); + + /* set more arguments, and start the host resolver */ + args->fqn = g_strdup(fullname); + + if (NULL == (args->query = + purple_dnsquery_a(hosttarget, port, _mdns_resolve_host_callback, args))) + { + purple_debug_error("bonjour", "service resolver - host resolution failed.\n"); + bonjour_buddy_delete(args->buddy); + g_free(args->fqn); + free(args); + } + } + +} + +void DNSSD_API +_mdns_service_register_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, + const char *name, const char *regtype, const char *domain, void *context) +{ + /* we don't actually care about anything said in this callback - this is only here because Bonjour for windows is broken */ + if (kDNSServiceErr_NoError != errorCode) + { + purple_debug_error("bonjour", "service advertisement - callback error.\n"); + } + else + { + purple_debug_info("bonjour", "service advertisement - callback.\n"); + } +} + +void DNSSD_API +_mdns_service_browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, + DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) +{ + PurpleAccount *account = (PurpleAccount*)context; + PurpleBuddy *gb = NULL; + + if (kDNSServiceErr_NoError != errorCode) + { + purple_debug_error("bonjour", "service browser - callback error"); + } + else if (flags & kDNSServiceFlagsAdd) + { + /* A presence service instance has been discovered... check it isn't us! */ + if (0 != g_ascii_strcasecmp(serviceName, account->username)) + { + /* OK, lets go ahead and resolve it to add to the buddy list */ + ResolveCallbackArgs *args = malloc(sizeof(ResolveCallbackArgs)); + args->buddy = bonjour_buddy_new(serviceName, account); + + if (kDNSServiceErr_NoError != DNSServiceResolve(&args->resolver, 0, 0, serviceName, regtype, replyDomain, _mdns_service_resolve_callback, args)) + { + bonjour_buddy_delete(args->buddy); + free(args); + purple_debug_error("bonjour", "service browser - failed to resolve service.\n"); + } + else + { + /* get a file descriptor for this service ref, and add it to the input list */ + gint resolver_fd = DNSServiceRefSockFD(args->resolver); + args->resolver_fd = purple_input_add(resolver_fd, PURPLE_INPUT_READ, _mdns_handle_event, args->resolver); + } + } + } + else + { + /* A peer has sent a goodbye packet, remove them from the buddy list */ + purple_debug_info("bonjour", "service browser - remove notification\n"); + gb = purple_find_buddy(account, serviceName); + if (gb != NULL) + { + bonjour_buddy_delete(gb->proto_data); + purple_blist_remove_buddy(gb); + } + } +} + +void +_mdns_parse_text_record(BonjourBuddy* buddy, const char* record, uint16_t record_len) +{ + char *txt_entry; + uint8_t txt_len; + + if (NULL != (txt_entry = (char*)TXTRecordGetValuePtr(record_len, record, "1st", &txt_len))) + { + set_bonjour_buddy_value(buddy, E_BUDDY_FIRST, txt_entry, txt_len); + } + + if (NULL != (txt_entry = (char*)TXTRecordGetValuePtr(record_len, record, "last", &txt_len))) + { + set_bonjour_buddy_value(buddy, E_BUDDY_LAST, txt_entry, txt_len); + } + + if (NULL != (txt_entry = (char*)TXTRecordGetValuePtr(record_len, record, "status", &txt_len))) + { + set_bonjour_buddy_value(buddy, E_BUDDY_STATUS, txt_entry, txt_len); + } + + if (NULL != (txt_entry = (char*)TXTRecordGetValuePtr(record_len, record, "email", &txt_len))) + { + set_bonjour_buddy_value(buddy, E_BUDDY_EMAIL, txt_entry, txt_len); + } + + if (NULL != (txt_entry = (char*)TXTRecordGetValuePtr(record_len, record, "jid", &txt_len))) + { + set_bonjour_buddy_value(buddy, E_BUDDY_JID, txt_entry, txt_len); + } + + if (NULL != (txt_entry = (char*)TXTRecordGetValuePtr(record_len, record, "AIM", &txt_len))) + { + set_bonjour_buddy_value(buddy, E_BUDDY_AIM, txt_entry, txt_len); + } + + if (NULL != (txt_entry = (char*)TXTRecordGetValuePtr(record_len, record, "VC", &txt_len))) + { + set_bonjour_buddy_value(buddy, E_BUDDY_VC, txt_entry, txt_len); + } + + if (NULL != (txt_entry = (char*)TXTRecordGetValuePtr(record_len, record, "phsh", &txt_len))) + { + set_bonjour_buddy_value(buddy, E_BUDDY_PHSH, txt_entry, txt_len); + } + + if (NULL != (txt_entry = (char*)TXTRecordGetValuePtr(record_len, record, "msg", &txt_len))) + { + set_bonjour_buddy_value(buddy, E_BUDDY_MSG, txt_entry, txt_len); + } +} + +int +_mdns_publish(BonjourDnsSd *data, PublishType type) +{ + TXTRecordRef dns_data; + char portstring[6]; + int ret = 0; + + TXTRecordCreate(&dns_data, 256, NULL); + + /* Convert the port to a string */ + snprintf(portstring, sizeof(portstring), "%d", data->port_p2pj); + + /* Publish standard records */ + + if (kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "txtvers", strlen(data->txtvers), data->txtvers) || + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "version", strlen(data->version), data->version) || + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "1st", strlen(data->first), data->first) || + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "last", strlen(data->last), data->last) || + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "port", strlen(portstring), portstring) || + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "phsh", strlen(data->phsh), data->phsh) || + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "status", strlen(data->status), data->status) || + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "vc", strlen(data->vc), data->vc)) + { + purple_debug_error("bonjour", "Unable to allocate memory for text record.\n"); + ret = -1; + } + else if ((data->email != NULL) && (*data->email != '\0') && + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "email", strlen(data->email), data->email)) + { + purple_debug_error("bonjour", "Unable to allocate memory for text record.\n"); + ret = -1; + } + else if ((data->jid != NULL) && (*data->jid != '\0') && + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "email", strlen(data->jid), data->jid)) + { + purple_debug_error("bonjour", "Unable to allocate memory for text record.\n"); + ret = -1; + } + else if ((data->AIM != NULL) && (*data->AIM != '\0') && + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "AIM", strlen(data->AIM), data->AIM)) + { + purple_debug_error("bonjour", "Unable to allocate memory for text record.\n"); + ret = -1; + } + else if ((data->msg != NULL) && (*data->msg != '\0') && + kDNSServiceErr_NoError != TXTRecordSetValue(&dns_data, "msg", strlen(data->msg), data->msg)) + { + purple_debug_error("bonjour", "Unable to allocate memory for text record.\n"); + ret = -1; + } + else + { + DNSServiceErrorType err = kDNSServiceErr_NoError; + + /* OK, we're done constructing the text record, (re)publish the service */ + + switch (type) + { + case PUBLISH_START: + err = DNSServiceRegister(&data->advertisement, 0, 0, data->name, ICHAT_SERVICE, + NULL, NULL, data->port_p2pj, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), + _mdns_service_register_callback, NULL); + break; + + case PUBLISH_UPDATE: + err = DNSServiceUpdateRecord(data->advertisement, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); + break; + } + + if (kDNSServiceErr_NoError != err) + { + purple_debug_error("bonjour", "Failed to publish presence service.\n"); + ret = -1; + } + else if (PUBLISH_START == type) + { + /* hack: Bonjour on windows is broken. We don't care about the callback but we have to listen anyway */ + gint advertisement_fd = DNSServiceRefSockFD(data->advertisement); + data->advertisement_fd = purple_input_add(advertisement_fd, PURPLE_INPUT_READ, _mdns_handle_event, data->advertisement); + } + } + + /* Free the memory used by temp data */ + TXTRecordDeallocate(&dns_data); + return ret; +} + +void +_mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition) +{ + DNSServiceProcessResult((DNSServiceRef)data); +} diff -r 7e856734b712 -r d7b50cac1c7a libpurple/protocols/bonjour/mdns_win32.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.h Tue Jun 05 03:38:22 2007 +0000 @@ -0,0 +1,71 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _BONJOUR_MDNS_WIN32 +#define _BONJOUR_MDNS_WIN32 + +#include "config.h" + +#ifdef USE_BONJOUR_APPLE + +#include +#include "mdns_types.h" +#include "buddy.h" +#include "dnsquery.h" +#include "dns_sd_proxy.h" + +/* data structure for the resolve callback */ +typedef struct _ResolveCallbackArgs +{ + DNSServiceRef resolver; + int resolver_fd; + + PurpleDnsQueryData *query; + gchar *fqn; + + BonjourBuddy* buddy; +} ResolveCallbackArgs; + + +/* Bonjour async callbacks */ + +void _mdns_resolve_host_callback(GSList *hosts, gpointer data, const char *error_message); + +void DNSSD_API _mdns_text_record_query_callback(DNSServiceRef DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, + DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, + const void *rdata, uint32_t ttl, void *context); + +void DNSSD_API _mdns_service_resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, + const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context); + +void DNSSD_API _mdns_service_register_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, + const char *name, const char *regtype, const char *domain, void *context); + +void DNSSD_API _mdns_service_browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, + DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context); + + +/* utility functions */ +void _mdns_parse_text_record(BonjourBuddy* buddy, const char* record, uint16_t record_len); + +/* interface functions */ + +int _mdns_publish(BonjourDnsSd *data, PublishType type); +void _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition); + +#endif + +#endif