--- /usr/tmp/clean/avahi-0.6.28/avahi-core/entry.c	2010-08-26 01:51:38.985153000 +0100
+++ avahi-0.6.28/avahi-core/entry.c	2011-01-20 12:01:24.322248863 +0000
@@ -50,6 +50,33 @@
 #include "rr-util.h"
 #include "domain-util.h"
 
+#ifdef HAVE_BONJOUR
+
+struct AvahiService {
+    AvahiServer *server;
+    AvahiSEntryGroup *group;
+
+    int dead;
+
+    AvahiPublishFlags flags;
+    AvahiIfIndex interface;
+    AvahiProtocol protocol;
+
+    char *name;
+    char *type;
+    char *domain;
+    char *host;
+    uint16_t port;
+
+    AvahiWatch *watch;
+    DNSServiceRef client;
+    size_t txtlen;
+    uint8_t *txtrecord;
+
+    AVAHI_LLIST_FIELDS(AvahiService, services);
+};
+#endif
+
 static void transport_flags_from_domain(AvahiServer *s, AvahiPublishFlags *flags, const char *domain) {
     assert(flags);
     assert(domain);
@@ -69,13 +96,146 @@
         *flags |= AVAHI_PUBLISH_USE_WIDE_AREA;
 }
 
+#ifdef HAVE_BONJOUR
+static void register_service_reply(DNSServiceRef client, const DNSServiceFlags flags, DNSServiceErrorType errorCode,
+        const char *name, const char *regtype, const char *domain, void *context) {
+    AvahiService *as = context;
+
+    switch (errorCode) {
+        case kDNSServiceErr_NoError:
+            as->group->n_probing--;
+            if (as->group->n_probing == 0) {
+                avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_ESTABLISHED);
+            }
+            break;
+        case kDNSServiceErr_NameConflict:
+            avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_COLLISION);
+            break;
+        default: 
+            avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_FAILURE);
+    }
+}
+
+static void register_service_socket_event(AvahiWatch *w, int fd, AvahiWatchEvent events, void *userdata) {
+    AvahiService *as = userdata;
+    DNSServiceErrorType ret;
+
+    assert(w);
+    assert(fd >= 0);
+    assert(events & AVAHI_WATCH_IN);
+
+    assert (fd == DNSServiceRefSockFD(as->client));
+    ret = DNSServiceProcessResult(as->client);
+    if (ret != kDNSServiceErr_NoError) {
+        if (as->watch) {
+            as->server->poll_api->watch_free(as->watch);
+            as->watch = NULL;
+        }
+        DNSServiceRefDeallocate(as->client);
+        as->client = NULL;
+        avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_FAILURE);
+    }
+}
+
+static void avahi_service_free(AvahiServer*s, AvahiService *as) {
+    AvahiService *t;
+
+    assert(s);
+    assert(as);
+
+    /* Remove from linked list */
+    AVAHI_LLIST_REMOVE(AvahiService, services, s->services, as);
+
+    /* Remove from associated group */
+    if (as->group && (as->group->services != NULL))
+        AVAHI_LLIST_REMOVE(AvahiService, services, as->group->services, as);
+
+    if (as->name)
+        avahi_free(as->name);
+
+    if (as->type)
+        avahi_free(as->type);
+
+    if (as->domain)
+        avahi_free(as->domain);
+
+    if (as->host)
+        avahi_free(as->host);
+
+    if (as->watch)
+        s->poll_api->watch_free(as->watch);
+    
+    if (as->client)
+        DNSServiceRefDeallocate (as->client);
+
+    if (as->txtrecord)
+        avahi_free(as->txtrecord);
+
+    avahi_free(as);
+}
+
+static void avahi_register_service(AvahiServer *s, AvahiService *as) {
+    DNSServiceErrorType ret;
+
+    ret = DNSServiceRegister(&as->client, 
+              as->interface == AVAHI_IF_UNSPEC ? 
+                  kDNSServiceInterfaceIndexAny :
+                  as->interface,
+              0, 
+              as->name,
+              as->type,
+              as->domain,
+              as->host,
+              htons(as->port),
+              as->txtlen,
+              as->txtrecord,
+              register_service_reply,
+              as);
+    if (ret == kDNSServiceErr_NoError) {
+        if  (!as->client) {
+            avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_FAILURE);
+        } else {
+            as->group->n_probing++;
+            as->watch = s->poll_api->watch_new(s->poll_api, DNSServiceRefSockFD(as->client), AVAHI_WATCH_IN, register_service_socket_event, as);
+        } 
+    } else {
+        if (ret == kDNSServiceErr_NameConflict) {
+            avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_COLLISION);
+        }
+        else {
+            avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_FAILURE);
+        }
+    }
+}
+
+static void register_record_reply(DNSServiceRef client, DNSRecordRef recordref, const DNSServiceFlags flags, DNSServiceErrorType errorCode, void *context) {
+    AvahiEntry *e = context;
+    DNSServiceErrorType ret;
+    
+    switch (errorCode) {
+        case kDNSServiceErr_NoError:
+            break;
+        case kDNSServiceErr_NameConflict:
+            e->recordref = NULL;
+            avahi_server_set_errno(e->server, AVAHI_ERR_COLLISION);
+            break;
+        default: 
+            e->recordref = NULL;
+            avahi_server_set_errno(e->server, AVAHI_ERR_FAILURE);
+            break;
+    }
+}
+#endif
+
 void avahi_entry_free(AvahiServer*s, AvahiEntry *e) {
     AvahiEntry *t;
 
     assert(s);
     assert(e);
 
+#ifndef HAVE_BONJOUR
     avahi_goodbye_entry(s, e, 1, 1);
+#endif
 
     /* Remove from linked list */
     AVAHI_LLIST_REMOVE(AvahiEntry, entries, s->entries, e);
@@ -102,6 +262,15 @@
 
     while (g->entries)
         avahi_entry_free(s, g->entries);
+#ifdef HAVE_BONJOUR
+    while (g->services)
+        avahi_service_free(s, g->services);
+
+    if (g->record_connection) {
+        DNSServiceRefDeallocate(g->record_connection);
+        g->record_connection = NULL;
+    }
+#endif
 
     if (g->register_time_event)
         avahi_time_event_free(g->register_time_event);
@@ -139,6 +308,21 @@
         s->need_entry_cleanup = 0;
     }
 
+#ifdef HAVE_BONJOUR
+    if (s->need_service_cleanup) {
+        AvahiService *as, *next;
+
+        for (as = s->services; as; as = next) {
+            next = as->services_next;
+
+            if (as->dead)
+                avahi_service_free(s, as);
+        }
+
+        s->need_service_cleanup = 0;
+    }
+#endif
+
     if (s->need_browser_cleanup)
         avahi_browser_cleanup(s);
 
@@ -245,8 +429,54 @@
 
         /* Hmm, nothing found? */
         if (!e) {
+#ifdef HAVE_BONJOUR
+            /*
+             * Assume that we are updating a service's primary TXT record
+             * so find the service
+             */
+            DNSServiceErrorType ret;
+            uint16_t rlen;
+            uint8_t rdata[AVAHI_DNS_RDATA_MAX];
+            size_t l;
+            AvahiService *as;
+            int found_as = 0;
+
+            for (as = g->services; as; as = as->services_next) {
+                int a_ret = AVAHI_OK;
+                char svc_name[AVAHI_DOMAIN_NAME_MAX];
+
+                if ((a_ret = avahi_service_name_join(svc_name, sizeof(svc_name), as->name, as->type, as->domain ? as->domain : s->domain_name)) < 0) {
+                      avahi_server_set_errno(s, a_ret);
+                      return NULL;
+                }
+                if (!strcmp(svc_name, r->key->name)) {
+                    found_as = 1;
+                    break;
+                }
+            }
+
+            if (!found_as) {
+                avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND);
+                return NULL;
+            }
+            if ((l = avahi_rdata_serialize(r, rdata, sizeof(rdata))) == (size_t) -1) {
+                avahi_server_set_errno(s, AVAHI_ERR_FAILURE);
+                return NULL;
+            }
+            ret = DNSServiceUpdateRecord(as->client,
+                                         NULL,
+                                         0,
+                                         l,
+                                         rdata,
+                                         r->ttl);
+            if (ret != kDNSServiceErr_NoError) {
+                avahi_server_set_errno(s, AVAHI_ERR_FAILURE);
+            }
+            return NULL;
+#else
             avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND);
             return NULL;
+#endif
         }
 
         /* Update the entry */
@@ -256,6 +486,36 @@
 
         /* Announce our changes when needed */
         if (!avahi_record_equal_no_ttl(old_record, r) && (!g || g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)) {
+#ifdef HAVE_BONJOUR
+            DNSServiceErrorType ret;
+            uint16_t rlen;
+            uint8_t rdata[AVAHI_DNS_RDATA_MAX];
+            size_t l;
+
+            if (!g->record_connection) {
+                if (DNSServiceCreateConnection(&g->record_connection) != kDNSServiceErr_NoError) {
+                    avahi_entry_free(s, e);
+                    avahi_server_set_errno(s, AVAHI_ERR_FAILURE);
+                    return NULL;
+                }
+            }
+            if ((l = avahi_rdata_serialize(r, rdata, sizeof(rdata))) == (size_t) -1) {
+                avahi_entry_free(s, e);
+                avahi_server_set_errno(s, AVAHI_ERR_FAILURE);
+                return NULL;
+            }
+            ret = DNSServiceUpdateRecord(g->record_connection,
+                                         e->recordref,
+                                         0,
+                                         l,
+                                         rdata,
+                                         r->ttl);
+            if (ret != kDNSServiceErr_NoError) {
+                avahi_entry_free(s, e);
+                avahi_server_set_errno(s, AVAHI_ERR_FAILURE);
+                return NULL;
+            }
+#else
 
             /* Remove the old entry from all caches, if needed */
             if (!(e->flags & AVAHI_PUBLISH_UNIQUE))
@@ -263,6 +523,7 @@
 
             /* Reannounce our updated entry */
             avahi_reannounce_entry(s, e);
+#endif
         }
 
         /* If we were the first entry in the list, we need to update the key */
@@ -273,6 +534,14 @@
 
     } else {
         AvahiEntry *t;
+#ifdef HAVE_BONJOUR
+        DNSServiceErrorType ret;
+        DNSServiceFlags bflags;
+        uint16_t rlen;
+        uint8_t rdata[AVAHI_DNS_RDATA_MAX];
+        size_t l;
+        char *record_name;
+#endif
 
         /* Add a new record */
 
@@ -307,7 +576,69 @@
         if (g)
             AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e);
 
+#ifdef HAVE_BONJOUR
+        e->recordref = NULL;
+        if (!g->record_connection) {
+            if (DNSServiceCreateConnection(&g->record_connection) != kDNSServiceErr_NoError) {
+                avahi_entry_free(s, e);
+                avahi_server_set_errno(s, AVAHI_ERR_FAILURE);
+                return NULL;
+            }
+        }
+        bflags = 0;
+        if (flags & AVAHI_PUBLISH_ALLOW_MULTIPLE)
+            bflags |= kDNSServiceFlagsShared;
+        else
+            bflags |= kDNSServiceFlagsUnique;
+
+        switch (r->key->type) {
+            case AVAHI_DNS_TYPE_A:
+            case AVAHI_DNS_TYPE_AAAA:
+                record_name = avahi_strdup(r->key->name);
+                break;
+            default:
+                record_name = avahi_malloc(strlen(r->key->name) + strlen(s->host_name_fqdn) + 2);
+                strcpy(record_name, r->key->name);
+                strcat(record_name, ".");
+                strcat(record_name, s->host_name_fqdn);
+                break;
+        }
+
+        if ((l = avahi_rdata_serialize(r, rdata, sizeof(rdata))) == (size_t) -1) {
+            avahi_entry_free(s, e);
+            avahi_server_set_errno(s, AVAHI_ERR_FAILURE);
+            return NULL;
+        }
+
+        ret = DNSServiceRegisterRecord(g->record_connection,
+                  &e->recordref,
+                  bflags,
+                  interface == AVAHI_IF_UNSPEC ?
+                      kDNSServiceInterfaceIndexAny :
+                      interface,
+                  record_name,
+                  r->key->type,
+                  r->key->clazz,
+                  l,
+                  rdata,
+                  r->ttl,
+                  register_record_reply,
+                  e);
+        if (ret == kDNSServiceErr_NoError) {
+            ret = DNSServiceProcessResult(g->record_connection);
+            if (ret != kDNSServiceErr_NoError || e->recordref == NULL) {
+                avahi_entry_free(s, e);
+                return NULL;
+            }
+        } else {
+            avahi_entry_free(s, e);
+            avahi_server_set_errno(s, AVAHI_ERR_FAILURE);
+            return NULL;
+        }
+        avahi_free(record_name);
+#else
         avahi_announce_entry(s, e);
+#endif
     }
 
     return e;
@@ -583,6 +914,9 @@
     AvahiRecord *r = NULL;
     int ret = AVAHI_OK;
     AvahiEntry *srv_entry = NULL, *txt_entry = NULL, *ptr_entry = NULL, *enum_entry = NULL;
+#ifdef HAVE_BONJOUR
+    AvahiService *as;
+#endif
 
     assert(s);
     assert(type);
@@ -603,6 +937,36 @@
     if (!domain)
         domain = s->domain_name;
 
+#ifdef HAVE_BONJOUR
+    as = avahi_new (AvahiService, 1);
+    as->server = s;
+    as->group = g;
+    as->dead = 0;
+    as->flags = flags;
+    as->interface = interface;
+    as->protocol = protocol;
+    as->name = avahi_strdup(name);
+    as->type = avahi_strdup(type);
+    as->domain = avahi_strdup(domain);
+    as->host = avahi_strdup(host);
+    as->port = port;
+    as->watch = NULL;
+    as->client = NULL;
+    as->txtlen = avahi_string_list_serialize(strlst, NULL, 0);
+    if (as->txtlen > 0) {
+        as->txtrecord = avahi_new(uint8_t, as->txtlen);
+        if (as->txtrecord == NULL) {
+            as->txtlen = 0;
+            ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
+            goto fail;
+        }
+        avahi_string_list_serialize(strlst, as->txtrecord, as->txtlen);
+    } else
+        as->txtrecord = NULL;
+
+    AVAHI_LLIST_PREPEND(AvahiService, services, s->services, as);
+    AVAHI_LLIST_PREPEND(AvahiService, services, g->services, as);
+#else
     if (!host)
         host = s->host_name_fqdn;
 
@@ -667,6 +1031,7 @@
         ret = avahi_server_errno(s);
         goto fail;
     }
+#endif
 
 fail:
     if (ret != AVAHI_OK && !(flags & AVAHI_PUBLISH_UPDATE)) {
@@ -1013,7 +1378,11 @@
     if (g->state == state)
         return;
 
+#ifdef HAVE_BONJOUR
+    assert(state <= AVAHI_ENTRY_GROUP_FAILURE);
+#else
     assert(state <= AVAHI_ENTRY_GROUP_COLLISION);
+#endif
 
     if (g->state == AVAHI_ENTRY_GROUP_ESTABLISHED) {
 
@@ -1063,6 +1432,10 @@
     g->register_time.tv_sec = 0;
     g->register_time.tv_usec = 0;
     AVAHI_LLIST_HEAD_INIT(AvahiEntry, g->entries);
+#ifdef HAVE_BONJOUR
+    AVAHI_LLIST_HEAD_INIT(AvahiService, g->services);
+    g->record_connection = NULL;
+#endif
 
     AVAHI_LLIST_PREPEND(AvahiSEntryGroup, groups, s->groups, g);
     return g;
@@ -1087,16 +1460,26 @@
 
 void avahi_s_entry_group_free(AvahiSEntryGroup *g) {
     AvahiEntry *e;
+#ifdef HAVE_BONJOUR
+    AvahiService *s;
+#endif
 
     assert(g);
     assert(g->server);
 
     for (e = g->entries; e; e = e->by_group_next) {
         if (!e->dead) {
+#ifndef HAVE_BONJOUR
             avahi_goodbye_entry(g->server, e, 1, 1);
+#endif
             e->dead = 1;
         }
     }
+#ifdef HAVE_BONJOUR
+    for (s = g->services; s; s = s->services_next) {
+        s->dead = 1;
+    }
+#endif
 
     if (g->register_time_event) {
         avahi_time_event_free(g->register_time_event);
@@ -1107,11 +1490,17 @@
 
     g->server->need_group_cleanup = 1;
     g->server->need_entry_cleanup = 1;
+#ifdef HAVE_BONJOUR
+    g->server->need_service_cleanup = 1;
+#endif
 
     schedule_cleanup(g->server);
 }
 
 static void entry_group_commit_real(AvahiSEntryGroup *g) {
+#ifdef HAVE_BONJOUR
+    AvahiService *s;
+#endif
     assert(g);
 
     gettimeofday(&g->register_time, NULL);
@@ -1121,8 +1510,15 @@
     if (g->dead)
         return;
 
+#ifdef HAVE_BONJOUR
+    assert(g->server);
+    for (s = g->services; s; s = s->services_next)
+        if (!s->dead)
+            avahi_register_service(g->server, s);
+#else
     avahi_announce_group(g->server, g);
     avahi_s_entry_group_check_probed(g, 0);
+#endif
 }
 
 static void entry_group_register_time_event_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void* userdata) {
@@ -1175,16 +1571,28 @@
 
 void avahi_s_entry_group_reset(AvahiSEntryGroup *g) {
     AvahiEntry *e;
+#ifdef HAVE_BONJOUR
+    AvahiService *s;
+#endif
     assert(g);
 
     for (e = g->entries; e; e = e->by_group_next) {
         if (!e->dead) {
+#ifndef HAVE_BONJOUR
             avahi_goodbye_entry(g->server, e, 1, 1);
+#endif
             e->dead = 1;
         }
     }
     g->server->need_entry_cleanup = 1;
 
+#ifdef HAVE_BONJOUR
+    for (s = g->services; s; s = s->services_next) {
+        s->dead = 1;
+    }
+    g->server->need_service_cleanup = 1;
+#endif
+
     g->n_probing = 0;
 
     avahi_s_entry_group_change_state(g, AVAHI_ENTRY_GROUP_UNCOMMITED);
@@ -1222,12 +1630,23 @@
 
 int avahi_s_entry_group_is_empty(AvahiSEntryGroup *g) {
     AvahiEntry *e;
+#ifdef HAVE_BONJOUR
+    AvahiService *s;
+#endif
+
     assert(g);
 
+#ifdef HAVE_BONJOUR
+    for (s = g->services; s; s = s->services_next)
+        if (!s->dead)
+            return 0;
+#else
     /* Look for an entry that is not dead */
     for (e = g->entries; e; e = e->by_group_next)
         if (!e->dead)
             return 0;
+#endif
 
     return 1;
 }
+
