]> git.meshlink.io Git - catta/commitdiff
Merge Sjoerd Simon's Avahi/GObject patch
authorLennart Poettering <lennart@poettering.net>
Sun, 21 Oct 2007 23:39:22 +0000 (23:39 +0000)
committerLennart Poettering <lennart@poettering.net>
Sun, 21 Oct 2007 23:39:22 +0000 (23:39 +0000)
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@1557 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

14 files changed:
avahi-glib/Makefile.am
avahi-glib/ga-client.c [new file with mode: 0644]
avahi-glib/ga-client.h [new file with mode: 0644]
avahi-glib/ga-entry-group.c [new file with mode: 0644]
avahi-glib/ga-entry-group.h [new file with mode: 0644]
avahi-glib/ga-enums.h [new file with mode: 0644]
avahi-glib/ga-errors.c [new file with mode: 0644]
avahi-glib/ga-errors.h [new file with mode: 0644]
avahi-glib/ga-record-browser.c [new file with mode: 0644]
avahi-glib/ga-record-browser.h [new file with mode: 0644]
avahi-glib/ga-service-browser.c [new file with mode: 0644]
avahi-glib/ga-service-browser.h [new file with mode: 0644]
avahi-glib/ga-service-resolver.c [new file with mode: 0644]
avahi-glib/ga-service-resolver.h [new file with mode: 0644]

index 69bd51ea60ac6dbc7ae3f66f155021940e5fd3a2..a507529529deb46c01dc7229985096a80922055c 100644 (file)
@@ -1,7 +1,7 @@
 # $Id$
 #
 # This file is part of avahi.
-# 
+#
 # avahi is free software; you can redistribute it and/or modify it
 # under the terms of the GNU Lesser General Public License as
 # published by the Free Software Foundation; either version 2 of the
@@ -28,10 +28,17 @@ avahiincludedir=$(includedir)/avahi-glib
 
 avahiinclude_HEADERS = \
        glib-watch.h \
-       glib-malloc.h
+       glib-malloc.h \
+       ga-client.h \
+       ga-entry-group.h \
+       ga-enums.h \
+       ga-errors.h \
+       ga-record-browser.h \
+       ga-service-browser.h \
+       ga-service-resolver.h
 
 lib_LTLIBRARIES = \
-       libavahi-glib.la 
+       libavahi-glib.la
 
 if ENABLE_TESTS
 
@@ -40,9 +47,33 @@ noinst_PROGRAMS = \
 
 endif
 
+BUILT_SOURCES = \
+    signals-marshal.list \
+    signals-marshal.h \
+    signals-marshal.c \
+    ga-client-enumtypes.h \
+    ga-client-enumtypes.c  \
+    ga-entry-group-enumtypes.h \
+    ga-entry-group-enumtypes.c  \
+    ga-enums-enumtypes.h \
+    ga-enums-enumtypes.c
+
+
+CORE_SOURCES = \
+       ga-client.c ga-client.h \
+       ga-entry-group.c ga-entry-group.h \
+       ga-enums.h \
+       ga-errors.c ga-errors.h \
+       ga-record-browser.c ga-record-browser.h \
+       ga-service-browser.c ga-service-browser.h \
+       ga-service-resolver.c ga-service-resolver.h
+
 libavahi_glib_la_SOURCES = \
        glib-watch.c glib-watch.h \
-       glib-malloc.h glib-malloc.c
+       glib-malloc.h glib-malloc.c \
+       $(CORE_SOURCES) \
+       $(BUILT_SOURCES)
+
 libavahi_glib_la_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS)
 libavahi_glib_la_LIBADD = $(AM_LDADD) ../avahi-common/libavahi-common.la $(GLIB20_LIBS)
 libavahi_glib_la_LDFLAGS = $(AM_LDFLAGS) -export-dynamic -version-info $(LIBAVAHI_GLIB_VERSION_INFO)
@@ -53,4 +84,50 @@ glib_watch_test_SOURCES = \
 glib_watch_test_CFLAGS = $(AM_CFLAGS) $(GLIB20_CFLAGS)
 glib_watch_test_LDADD = $(AM_LDADD) ../avahi-common/libavahi-common.la $(GLIB20_LIBS)
 
+
+# correctly clean the generated source files
+CLEANFILES = $(BUILT_SOURCES)
+
+dist-hook:
+       $(shell for x in $(BUILT_SOURCES); do rm -f $(distdir)/$$x ; done)
+
+signals-marshal.list: $(CORE_SOURCES) Makefile.am
+       ( cd $(srcdir) && \
+       sed -n -e 's/.*ga_signals_marshal_\([A-Z]*__[A-Z_]*\).*/\1/p' \
+               $(CORE_SOURCES) ) \
+               | sed -e 's/__/:/' -e 'y/_/,/' | sort -u > $@.tmp
+       if cmp -s $@.tmp $@; then \
+               rm $@.tmp; \
+       else \
+               mv $@.tmp $@; \
+       fi
+
+signals-marshal.h: signals-marshal.list
+       glib-genmarshal --header --prefix=ga_signals_marshal $< > $@
+
+signals-marshal.c: signals-marshal.list
+       glib-genmarshal --body --prefix=ga_signals_marshal $< > $@
+
+
+# rules for making the glib enum objects
+%-enumtypes.h: %.h Makefile.in
+       glib-mkenums \
+       --fhead "#ifndef __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__\n#define __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
+       --fprod "/* enumerations from \"@filename@\" */\n" \
+       --vhead "GType @enum_name@_get_type (void);\n#define $(shell echo $* | tr [:lower:]- [:upper:]_ | sed 's/_.*//')_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n"         \
+       --ftail "G_END_DECLS\n\n#endif /* __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__ */" \
+       $< > $@
+
+%-enumtypes.c: %.h Makefile.in
+       glib-mkenums \
+       --fhead "#include <$*.h>" \
+       --fprod "\n/* enumerations from \"@filename@\" */" \
+       --vhead "GType\n@enum_name@_get_type (void)\n{\n  static GType etype = 0;\n  if (etype == 0) {\n    static const G@Type@Value values[] = {"     \
+       --vprod "      { @VALUENAME@, \"@VALUENAME@\", \"@VALUENAME@\" }," \
+       --vtail "      { 0, NULL, NULL }\n    };\n    etype = g_@type@_register_static (\"@EnumName@\", values);\n  }\n  return etype;\n}\n" \
+       $< > $@
+
 endif
+
+indent:
+       indent -brf -nbbo -nbc -ip0 -cs -nbfde -npsl -br -brs -bap -i4 -bs -cdw -ce -npcs -hnl -cli4 -nut -ci8 ga-*.[ch]
diff --git a/avahi-glib/ga-client.c b/avahi-glib/ga-client.c
new file mode 100644 (file)
index 0000000..d34933f
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * ga-client.c - Source for GaClient
+ * Copyright (C) 2005 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ga-client.h"
+
+#include "ga-client-enumtypes.h"
+#include "ga-errors.h"
+
+/* FIXME what to do about glib-malloc ? */
+#include <avahi-glib/glib-watch.h>
+#include <avahi-glib/glib-malloc.h>
+#include <avahi-common/error.h>
+#include <avahi-common/timeval.h>
+
+G_DEFINE_TYPE(GaClient, ga_client, G_TYPE_OBJECT)
+
+/* signal enum */
+enum {
+    STATE_CHANGED,
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* properties */
+enum {
+    PROP_STATE = 1,
+    PROP_FLAGS
+};
+
+/* private structure */
+typedef struct _GaClientPrivate GaClientPrivate;
+
+struct _GaClientPrivate {
+    AvahiGLibPoll *poll;
+    GaClientFlags flags;
+    GaClientState state;
+    gboolean dispose_has_run;
+};
+
+#define GA_CLIENT_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), GA_TYPE_CLIENT, GaClientPrivate))
+
+static void ga_client_init(GaClient * self) {
+    GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(self);
+    /* allocate any data required by the object here */
+    self->avahi_client = NULL;
+    priv->state = GA_CLIENT_STATE_NOT_STARTED;
+    priv->flags = GA_CLIENT_FLAG_NO_FLAGS;
+}
+
+static void ga_client_dispose(GObject * object);
+static void ga_client_finalize(GObject * object);
+
+static void ga_client_set_property(GObject * object,
+                       guint property_id,
+                       const GValue * value, GParamSpec * pspec) {
+    GaClient *client = GA_CLIENT(object);
+    GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(client);
+
+    switch (property_id) {
+        case PROP_FLAGS:
+            g_assert(client->avahi_client == NULL);
+            priv->flags = g_value_get_enum(value);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void ga_client_get_property(GObject * object,
+                       guint property_id,
+                       GValue * value, GParamSpec * pspec) {
+    GaClient *client = GA_CLIENT(object);
+    GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(client);
+
+    switch (property_id) {
+        case PROP_STATE:
+            g_value_set_enum(value, priv->state);
+            break;
+        case PROP_FLAGS:
+            g_value_set_enum(value, priv->flags);
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void ga_client_class_init(GaClientClass * ga_client_class) {
+    GObjectClass *object_class = G_OBJECT_CLASS(ga_client_class);
+    GParamSpec *param_spec;
+
+    g_type_class_add_private(ga_client_class, sizeof (GaClientPrivate));
+
+
+    object_class->dispose = ga_client_dispose;
+    object_class->finalize = ga_client_finalize;
+
+    object_class->set_property = ga_client_set_property;
+    object_class->get_property = ga_client_get_property;
+
+    param_spec = g_param_spec_enum("state", "Client state",
+                                   "The state of the Avahi client",
+                                   GA_TYPE_CLIENT_STATE,
+                                   GA_CLIENT_STATE_NOT_STARTED,
+                                   G_PARAM_READABLE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_STATE, param_spec);
+
+    param_spec = g_param_spec_enum("flags", "Client flags",
+                                   "The flags the Avahi client is started with",
+                                   GA_TYPE_CLIENT_FLAGS,
+                                   GA_CLIENT_FLAG_NO_FLAGS,
+                                   G_PARAM_READWRITE |
+                                   G_PARAM_CONSTRUCT_ONLY |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_FLAGS, param_spec);
+
+    signals[STATE_CHANGED] =
+            g_signal_new("state-changed",
+                         G_OBJECT_CLASS_TYPE(ga_client_class),
+                         G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                         0,
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__ENUM,
+                         G_TYPE_NONE, 1, GA_TYPE_CLIENT_STATE);
+
+}
+
+void ga_client_dispose(GObject * object) {
+    GaClient *self = GA_CLIENT(object);
+    GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(self);
+
+    if (priv->dispose_has_run)
+        return;
+
+    priv->dispose_has_run = TRUE;
+
+    if (self->avahi_client) {
+        avahi_client_free(self->avahi_client);
+        self->avahi_client = NULL;
+    }
+    if (priv->poll) {
+        avahi_glib_poll_free(priv->poll);
+        priv->poll = NULL;
+    }
+
+    /* release any references held by the object here */
+    if (G_OBJECT_CLASS(ga_client_parent_class)->dispose)
+        G_OBJECT_CLASS(ga_client_parent_class)->dispose(object);
+}
+
+void ga_client_finalize(GObject * object) {
+
+    /* free any data held directly by the object here */
+    G_OBJECT_CLASS(ga_client_parent_class)->finalize(object);
+}
+
+GaClient *ga_client_new(GaClientFlags flags) {
+    return g_object_new(GA_TYPE_CLIENT, "flags", flags, NULL);
+}
+
+static GQuark detail_for_state(AvahiClientState state) {
+    static struct {
+        AvahiClientState state;
+        const gchar *name;
+        GQuark quark;
+    } states[] = {
+        { AVAHI_CLIENT_S_REGISTERING, "registering", 0},
+        { AVAHI_CLIENT_S_RUNNING, "running", 0},
+        { AVAHI_CLIENT_S_COLLISION, "collistion", 0},
+        { AVAHI_CLIENT_FAILURE, "failure", 0},
+        { AVAHI_CLIENT_CONNECTING, "connecting", 0},
+        { 0, NULL, 0}
+    };
+    int i;
+
+    for (i = 0; states[i].name != NULL; i++) {
+        if (state != states[i].state)
+            continue;
+
+        if (!states[i].quark)
+            states[i].quark = g_quark_from_static_string(states[i].name);
+/*         printf("Detail: %s\n", states[i].name); */
+        return states[i].quark;
+    }
+    g_assert_not_reached();
+}
+
+static void _avahi_client_cb(AvahiClient * c, AvahiClientState state, void *data) {
+    GaClient *self = GA_CLIENT(data);
+    GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(self);
+
+/*     printf("CLIENT CB: %d\n", state); */
+
+    /* Avahi can call the callback before return from _client_new */
+    if (self->avahi_client == NULL)
+        self->avahi_client = c;
+
+    g_assert(c == self->avahi_client);
+    priv->state = state;
+    g_signal_emit(self, signals[STATE_CHANGED],
+                  detail_for_state(state), state);
+}
+
+gboolean ga_client_start(GaClient * client, GError ** error) {
+    GaClientPrivate *priv = GA_CLIENT_GET_PRIVATE(client);
+    AvahiClient *aclient;
+    int aerror;
+
+    g_assert(client->avahi_client == NULL);
+    g_assert(priv->poll == NULL);
+
+    avahi_set_allocator(avahi_glib_allocator());
+
+    priv->poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
+
+    aclient = avahi_client_new(avahi_glib_poll_get(priv->poll),
+                               priv->flags,
+                               _avahi_client_cb, client, &aerror);
+    if (aclient == NULL) {
+        if (error != NULL) {
+            *error = g_error_new(GA_ERRORS, aerror,
+                                 "Failed to create avahi client: %s",
+                                 avahi_strerror(aerror));
+        }
+        return FALSE;
+    }
+    client->avahi_client = aclient;
+    return TRUE;
+}
diff --git a/avahi-glib/ga-client.h b/avahi-glib/ga-client.h
new file mode 100644 (file)
index 0000000..7776d41
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * ga-client.h - Header for GaClient
+ * Copyright (C) 2005 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GA_CLIENT_H__
+#define __GA_CLIENT_H__
+
+#include <glib-object.h>
+#include <avahi-client/client.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+    GA_CLIENT_STATE_NOT_STARTED = -1,
+    GA_CLIENT_STATE_S_REGISTERING = AVAHI_CLIENT_S_REGISTERING,
+    GA_CLIENT_STATE_S_RUNNING = AVAHI_CLIENT_S_RUNNING,
+    GA_CLIENT_STATE_S_COLLISION = AVAHI_CLIENT_S_COLLISION,
+    GA_CLIENT_STATE_FAILURE = AVAHI_CLIENT_FAILURE,
+    GA_CLIENT_STATE_CONNECTING = AVAHI_CLIENT_CONNECTING
+} GaClientState;
+
+typedef enum {
+    GA_CLIENT_FLAG_NO_FLAGS = 0,
+    GA_CLIENT_FLAG_IGNORE_USER_CONFIG = AVAHI_CLIENT_IGNORE_USER_CONFIG,
+    GA_CLIENT_FLAG_NO_FAIL = AVAHI_CLIENT_NO_FAIL
+} GaClientFlags;
+
+typedef struct _GaClient GaClient;
+typedef struct _GaClientClass GaClientClass;
+
+struct _GaClientClass {
+    GObjectClass parent_class;
+};
+
+struct _GaClient {
+    GObject parent;
+    /* Raw avahi_client handle, only reuse if you have reffed this instance */
+    AvahiClient *avahi_client;
+};
+
+GType ga_client_get_type(void);
+
+/* TYPE MACROS */
+#define GA_TYPE_CLIENT \
+    (ga_client_get_type())
+#define GA_CLIENT(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST((obj), GA_TYPE_CLIENT, GaClient))
+#define GA_CLIENT_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST((klass), GA_TYPE_CLIENT, GaClientClass))
+#define IS_GA_CLIENT(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE((obj), GA_TYPE_CLIENT))
+#define IS_GA_CLIENT_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE((klass), GA_TYPE_CLIENT))
+#define GA_CLIENT_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GA_TYPE_CLIENT, GaClientClass))
+
+GaClient *ga_client_new(GaClientFlags flags);
+
+gboolean ga_client_start(GaClient * client, GError ** error);
+
+G_END_DECLS
+
+#endif /* #ifndef __GA_CLIENT_H__ */
diff --git a/avahi-glib/ga-entry-group.c b/avahi-glib/ga-entry-group.c
new file mode 100644 (file)
index 0000000..9b79e83
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * ga-entry-group.c - Source for GaEntryGroup
+ * Copyright (C) 2005 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <avahi-common/malloc.h>
+
+#include "ga-errors.h"
+#include "ga-entry-group.h"
+#include "ga-entry-group-enumtypes.h"
+
+G_DEFINE_TYPE(GaEntryGroup, ga_entry_group, G_TYPE_OBJECT)
+
+static void _free_service(gpointer data);
+
+/* signal enum */
+enum {
+    STATE_CHANGED,
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* properties */
+enum {
+    PROP_STATE = 1
+};
+
+/* private structures */
+typedef struct _GaEntryGroupPrivate GaEntryGroupPrivate;
+
+struct _GaEntryGroupPrivate {
+    GaEntryGroupState state;
+    GaClient *client;
+    AvahiEntryGroup *group;
+    GHashTable *services;
+    gboolean dispose_has_run;
+};
+
+typedef struct _GaEntryGroupServicePrivate GaEntryGroupServicePrivate;
+
+struct _GaEntryGroupServicePrivate {
+    GaEntryGroupService public;
+    GaEntryGroup *group;
+    gboolean frozen;
+    GHashTable *entries;
+};
+
+typedef struct _GaEntryGroupServiceEntry GaEntryGroupServiceEntry;
+
+struct _GaEntryGroupServiceEntry {
+    guint8 *value;
+    gsize size;
+};
+
+
+#define GA_ENTRY_GROUP_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), GA_TYPE_ENTRY_GROUP, GaEntryGroupPrivate))
+
+static void ga_entry_group_init(GaEntryGroup * obj) {
+    GaEntryGroupPrivate *priv = GA_ENTRY_GROUP_GET_PRIVATE(obj);
+    /* allocate any data required by the object here */
+    priv->state = GA_ENTRY_GROUP_STATE_UNCOMMITED;
+    priv->client = NULL;
+    priv->group = NULL;
+    priv->services = g_hash_table_new_full(g_direct_hash,
+                                           g_direct_equal,
+                                           NULL, _free_service);
+}
+
+static void ga_entry_group_dispose(GObject * object);
+static void ga_entry_group_finalize(GObject * object);
+
+static void ga_entry_group_get_property(GObject * object,
+                            guint property_id,
+                            GValue * value, GParamSpec * pspec) {
+    GaEntryGroup *group = GA_ENTRY_GROUP(object);
+    GaEntryGroupPrivate *priv = GA_ENTRY_GROUP_GET_PRIVATE(group);
+
+    switch (property_id) {
+        case PROP_STATE:
+            g_value_set_enum(value, priv->state);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void ga_entry_group_class_init(GaEntryGroupClass * ga_entry_group_class) {
+    GObjectClass *object_class = G_OBJECT_CLASS(ga_entry_group_class);
+    GParamSpec *param_spec;
+
+    g_type_class_add_private(ga_entry_group_class,
+                             sizeof (GaEntryGroupPrivate));
+
+    object_class->dispose = ga_entry_group_dispose;
+    object_class->finalize = ga_entry_group_finalize;
+    object_class->get_property = ga_entry_group_get_property;
+
+    param_spec = g_param_spec_enum("state", "Entry Group state",
+                                   "The state of the avahi entry group",
+                                   GA_TYPE_ENTRY_GROUP_STATE,
+                                   GA_ENTRY_GROUP_STATE_UNCOMMITED,
+                                   G_PARAM_READABLE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_STATE, param_spec);
+
+    signals[STATE_CHANGED] =
+            g_signal_new("state-changed",
+                         G_OBJECT_CLASS_TYPE(ga_entry_group_class),
+                         G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                         0,
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__ENUM,
+                         G_TYPE_NONE, 1, GA_TYPE_ENTRY_GROUP_STATE);
+}
+
+void ga_entry_group_dispose(GObject * object) {
+    GaEntryGroup *self = GA_ENTRY_GROUP(object);
+    GaEntryGroupPrivate *priv = GA_ENTRY_GROUP_GET_PRIVATE(self);
+
+    if (priv->dispose_has_run)
+        return;
+    priv->dispose_has_run = TRUE;
+
+    /* release any references held by the object here */
+    if (priv->group) {
+        avahi_entry_group_free(priv->group);
+        priv->group = NULL;
+    }
+
+    if (priv->client) {
+        g_object_unref(priv->client);
+        priv->client = NULL;
+    }
+
+    if (G_OBJECT_CLASS(ga_entry_group_parent_class)->dispose)
+        G_OBJECT_CLASS(ga_entry_group_parent_class)->dispose(object);
+}
+
+void ga_entry_group_finalize(GObject * object) {
+    GaEntryGroup *self = GA_ENTRY_GROUP(object);
+    GaEntryGroupPrivate *priv = GA_ENTRY_GROUP_GET_PRIVATE(self);
+
+    /* free any data held directly by the object here */
+    g_hash_table_destroy(priv->services);
+    priv->services = NULL;
+
+    G_OBJECT_CLASS(ga_entry_group_parent_class)->finalize(object);
+}
+
+static void _free_service(gpointer data) {
+    GaEntryGroupService *s = (GaEntryGroupService *) data;
+    GaEntryGroupServicePrivate *p = (GaEntryGroupServicePrivate *) s;
+    g_free(s->name);
+    g_free(s->type);
+    g_free(s->domain);
+    g_free(s->host);
+    g_hash_table_destroy(p->entries);
+    g_free(s);
+}
+
+static GQuark detail_for_state(AvahiEntryGroupState state) {
+    static struct {
+        AvahiClientState state;
+        const gchar *name;
+        GQuark quark;
+    } states[] = {
+        { AVAHI_ENTRY_GROUP_UNCOMMITED, "uncommited", 0},
+        { AVAHI_ENTRY_GROUP_REGISTERING, "registering", 0},
+        { AVAHI_ENTRY_GROUP_ESTABLISHED, "established", 0},
+        { AVAHI_ENTRY_GROUP_COLLISION, "collistion", 0},
+        { AVAHI_ENTRY_GROUP_FAILURE, "failure", 0},
+        { 0, NULL, 0}
+    };
+    int i;
+
+    for (i = 0; states[i].name != NULL; i++) {
+        if (state != states[i].state)
+            continue;
+
+        if (!states[i].quark)
+            states[i].quark = g_quark_from_static_string(states[i].name);
+        return states[i].quark;
+    }
+    g_assert_not_reached();
+}
+
+static void _avahi_entry_group_cb(AvahiEntryGroup * g,
+                      AvahiEntryGroupState state, void *data) {
+    GaEntryGroup *self = GA_ENTRY_GROUP(data);
+    GaEntryGroupPrivate *priv = GA_ENTRY_GROUP_GET_PRIVATE(self);
+
+    /* Avahi can call the callback before return from _client_new */
+    if (priv->group == NULL)
+        priv->group = g;
+
+    g_assert(g == priv->group);
+    priv->state = state;
+    g_signal_emit(self, signals[STATE_CHANGED],
+                  detail_for_state(state), state);
+}
+
+GaEntryGroup *ga_entry_group_new(void) {
+    return g_object_new(GA_TYPE_ENTRY_GROUP, NULL);
+}
+
+static guint _entry_hash(gconstpointer v) {
+    const GaEntryGroupServiceEntry *entry =
+            (const GaEntryGroupServiceEntry *) v;
+    guint32 h = 0;
+    guint i;
+
+    for (i = 0; i < entry->size; i++) {
+        h = (h << 5) - h + entry->value[i];
+    }
+
+    return h;
+}
+
+static gboolean _entry_equal(gconstpointer a, gconstpointer b) {
+    const GaEntryGroupServiceEntry *aentry =
+            (const GaEntryGroupServiceEntry *) a;
+    const GaEntryGroupServiceEntry *bentry =
+            (const GaEntryGroupServiceEntry *) b;
+
+    if (aentry->size != bentry->size) {
+        return FALSE;
+    }
+
+    return memcmp(aentry->value, bentry->value, aentry->size) == 0;
+}
+
+static GaEntryGroupServiceEntry *_new_entry(const guint8 * value, gsize size) {
+    GaEntryGroupServiceEntry *entry;
+
+    if (value == NULL) {
+        return NULL;
+    }
+
+    entry = g_slice_new(GaEntryGroupServiceEntry);
+    entry->value = g_malloc(size + 1);
+    memcpy(entry->value, value, size);
+    /* for string keys, make sure it's NUL-terminated too */
+    entry->value[size] = 0;
+    entry->size = size;
+
+    return entry;
+}
+
+static void _set_entry(GHashTable * table, const guint8 * key, gsize ksize,
+           const guint8 * value, gsize vsize) {
+
+    g_hash_table_insert(table, _new_entry(key, ksize),
+                        _new_entry(value, vsize));
+}
+
+static void _free_entry(gpointer data) {
+    GaEntryGroupServiceEntry *entry = (GaEntryGroupServiceEntry *) data;
+
+    if (entry == NULL) {
+        return;
+    }
+
+    g_free(entry->value);
+    g_slice_free(GaEntryGroupServiceEntry, entry);
+}
+
+static GHashTable *_string_list_to_hash(AvahiStringList * list) {
+    GHashTable *ret;
+    AvahiStringList *t;
+
+    ret = g_hash_table_new_full(_entry_hash,
+                                _entry_equal, _free_entry, _free_entry);
+
+    for (t = list; t != NULL; t = avahi_string_list_get_next(t)) {
+        gchar *key;
+        gchar *value;
+        gsize size;
+        int r;
+
+        /* list_get_pair only fails if if memory allocation fails. Normal glib
+         * behaviour is to assert/abort when that happens */
+        r = avahi_string_list_get_pair(t, &key, &value, &size);
+        g_assert(r == 0);
+
+        if (value == NULL) {
+            _set_entry(ret, t->text, t->size, NULL, 0);
+        } else {
+            _set_entry(ret, (const guint8 *) key, strlen(key),
+                       (const guint8 *) value, size);
+        }
+        avahi_free(key);
+        avahi_free(value);
+    }
+    return ret;
+}
+
+static void _hash_to_string_list_foreach(gpointer key, gpointer value, gpointer data) {
+    AvahiStringList **list = (AvahiStringList **) data;
+    GaEntryGroupServiceEntry *kentry = (GaEntryGroupServiceEntry *) key;
+    GaEntryGroupServiceEntry *ventry = (GaEntryGroupServiceEntry *) value;
+
+    if (value != NULL) {
+        *list = avahi_string_list_add_pair_arbitrary(*list,
+                                                     (gchar *) kentry->value,
+                                                     ventry->value,
+                                                     ventry->size);
+    } else {
+        *list = avahi_string_list_add_arbitrary(*list,
+                                                kentry->value, kentry->size);
+    }
+}
+
+static AvahiStringList *_hash_to_string_list(GHashTable * table) {
+    AvahiStringList *list = NULL;
+    g_hash_table_foreach(table, _hash_to_string_list_foreach,
+                         (gpointer) & list);
+    return list;
+}
+
+GaEntryGroupService *ga_entry_group_add_service_strlist(GaEntryGroup * group,
+                                                        const gchar * name,
+                                                        const gchar * type,
+                                                        guint16 port,
+                                                        GError ** error,
+                                                        AvahiStringList *
+                                                        txt) {
+    return ga_entry_group_add_service_full_strlist(group, AVAHI_IF_UNSPEC,
+                                                   AVAHI_PROTO_UNSPEC, 0,
+                                                   name, type, NULL, NULL,
+                                                   port, error, txt);
+}
+
+GaEntryGroupService *ga_entry_group_add_service_full_strlist(GaEntryGroup *
+                                                             group,
+                                                             AvahiIfIndex
+                                                             interface,
+                                                             AvahiProtocol
+                                                             protocol,
+                                                             AvahiPublishFlags
+                                                             flags,
+                                                             const gchar *
+                                                             name,
+                                                             const gchar *
+                                                             type,
+                                                             const gchar *
+                                                             domain,
+                                                             const gchar *
+                                                             host,
+                                                             guint16 port,
+                                                             GError ** error,
+                                                             AvahiStringList *
+                                                             txt) {
+    GaEntryGroupPrivate *priv = GA_ENTRY_GROUP_GET_PRIVATE(group);
+    GaEntryGroupServicePrivate *service = NULL;
+    int ret;
+
+    ret = avahi_entry_group_add_service_strlst(priv->group,
+                                               interface, protocol,
+                                               flags,
+                                               name, type,
+                                               domain, host, port, txt);
+    if (ret) {
+        if (error != NULL) {
+            *error = g_error_new(GA_ERRORS, ret,
+                                 "Adding service to group failed: %s",
+                                 avahi_strerror(ret));
+        }
+        goto out;
+    }
+
+    service = g_new0(GaEntryGroupServicePrivate, 1);
+    service->public.interface = interface;
+    service->public.protocol = protocol;
+    service->public.flags = flags;
+    service->public.name = g_strdup(name);
+    service->public.type = g_strdup(type);
+    service->public.domain = g_strdup(domain);
+    service->public.host = g_strdup(host);
+    service->public.port = port;
+    service->group = group;
+    service->frozen = FALSE;
+    service->entries = _string_list_to_hash(txt);
+    g_hash_table_insert(priv->services, group, service);
+  out:
+    return (GaEntryGroupService *) service;
+}
+
+GaEntryGroupService *ga_entry_group_add_service(GaEntryGroup * group,
+                                                const gchar * name,
+                                                const gchar * type,
+                                                guint16 port,
+                                                GError ** error, ...) {
+    GaEntryGroupService *ret;
+    AvahiStringList *txt = NULL;
+    va_list va;
+    va_start(va, error);
+    txt = avahi_string_list_new_va(va);
+
+    ret = ga_entry_group_add_service_full_strlist(group,
+                                                  AVAHI_IF_UNSPEC,
+                                                  AVAHI_PROTO_UNSPEC,
+                                                  0,
+                                                  name, type,
+                                                  NULL, NULL,
+                                                  port, error, txt);
+    avahi_string_list_free(txt);
+    va_end(va);
+    return ret;
+}
+
+GaEntryGroupService *ga_entry_group_add_service_full(GaEntryGroup * group,
+                                                     AvahiIfIndex interface,
+                                                     AvahiProtocol protocol,
+                                                     AvahiPublishFlags flags,
+                                                     const gchar * name,
+                                                     const gchar * type,
+                                                     const gchar * domain,
+                                                     const gchar * host,
+                                                     guint16 port,
+                                                     GError ** error, ...) {
+    GaEntryGroupService *ret;
+    AvahiStringList *txt = NULL;
+    va_list va;
+
+    va_start(va, error);
+    txt = avahi_string_list_new_va(va);
+
+    ret = ga_entry_group_add_service_full_strlist(group,
+                                                  interface, protocol,
+                                                  flags,
+                                                  name, type,
+                                                  domain, host,
+                                                  port, error, txt);
+    avahi_string_list_free(txt);
+    va_end(va);
+    return ret;
+}
+
+gboolean ga_entry_group_add_record(GaEntryGroup * group,
+                          AvahiPublishFlags flags,
+                          const gchar * name,
+                          guint16 type,
+                          guint32 ttl,
+                          const void *rdata, gsize size, GError ** error) {
+    return ga_entry_group_add_record_full(group,
+                                          AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+                                          flags, name, AVAHI_DNS_CLASS_IN,
+                                          type, ttl, rdata, size, error);
+}
+
+gboolean ga_entry_group_add_record_full(GaEntryGroup * group,
+                               AvahiIfIndex interface,
+                               AvahiProtocol protocol,
+                               AvahiPublishFlags flags,
+                               const gchar * name,
+                               guint16 clazz,
+                               guint16 type,
+                               guint32 ttl,
+                               const void *rdata,
+                               gsize size, GError ** error) {
+    int ret;
+    GaEntryGroupPrivate *priv = GA_ENTRY_GROUP_GET_PRIVATE(group);
+    g_assert(group != NULL && priv->group != NULL);
+
+    ret = avahi_entry_group_add_record(priv->group, interface, protocol,
+                                       flags, name, clazz, type, ttl, rdata,
+                                       size);
+    if (ret) {
+        if (error != NULL) {
+            *error = g_error_new(GA_ERRORS, ret,
+                                 "Setting raw record failed: %s",
+                                 avahi_strerror(ret));
+        }
+        return FALSE;
+    }
+    return TRUE;
+}
+
+
+void ga_entry_group_service_freeze(GaEntryGroupService * service) {
+    GaEntryGroupServicePrivate *p = (GaEntryGroupServicePrivate *) service;
+    p->frozen = TRUE;
+}
+
+gboolean ga_entry_group_service_thaw(GaEntryGroupService * service, GError ** error) {
+    GaEntryGroupServicePrivate *priv = (GaEntryGroupServicePrivate *) service;
+    int ret;
+    gboolean result = TRUE;
+
+    AvahiStringList *txt = _hash_to_string_list(priv->entries);
+    ret = avahi_entry_group_update_service_txt_strlst
+            (GA_ENTRY_GROUP_GET_PRIVATE(priv->group)->group,
+             service->interface, service->protocol, service->flags,
+             service->name, service->type, service->domain, txt);
+    if (ret) {
+        if (error != NULL) {
+            *error = g_error_new(GA_ERRORS, ret,
+                                 "Updating txt record failed: %s",
+                                 avahi_strerror(ret));
+        }
+        result = FALSE;
+    }
+
+    avahi_string_list_free(txt);
+    priv->frozen = FALSE;
+    return result;
+}
+
+gboolean ga_entry_group_service_set(GaEntryGroupService * service,
+                           const gchar * key, const gchar * value,
+                           GError ** error) {
+    return ga_entry_group_service_set_arbitrary(service, key,
+                                                (const guint8 *) value,
+                                                strlen(value), error);
+
+}
+
+gboolean ga_entry_group_service_set_arbitrary(GaEntryGroupService * service,
+                                     const gchar * key, const guint8 * value,
+                                     gsize size, GError ** error) {
+    GaEntryGroupServicePrivate *priv = (GaEntryGroupServicePrivate *) service;
+
+    _set_entry(priv->entries, (const guint8 *) key, strlen(key), value, size);
+
+    if (!priv->frozen)
+        return ga_entry_group_service_thaw(service, error);
+    else
+        return TRUE;
+}
+
+gboolean ga_entry_group_service_remove_key(GaEntryGroupService * service,
+                                  const gchar * key, GError ** error) {
+    GaEntryGroupServicePrivate *priv = (GaEntryGroupServicePrivate *) service;
+
+    g_hash_table_remove(priv->entries, key);
+
+    if (!priv->frozen)
+        return ga_entry_group_service_thaw(service, error);
+    else
+        return TRUE;
+}
+
+
+gboolean ga_entry_group_attach(GaEntryGroup * group,
+                      GaClient * client, GError ** error) {
+    GaEntryGroupPrivate *priv = GA_ENTRY_GROUP_GET_PRIVATE(group);
+
+    g_assert(priv->client == NULL || priv->client == client);
+    g_assert(priv->group == NULL);
+
+    priv->client = client;
+    g_object_ref(client);
+
+    priv->group = avahi_entry_group_new(client->avahi_client,
+                                        _avahi_entry_group_cb, group);
+    if (priv->group == NULL) {
+        if (error != NULL) {
+            int aerrno = avahi_client_errno(client->avahi_client);
+            *error = g_error_new(GA_ERRORS, aerrno,
+                                 "Attaching group failed: %s",
+                                 avahi_strerror(aerrno));
+        }
+        return FALSE;
+    }
+    return TRUE;
+}
+
+gboolean ga_entry_group_commit(GaEntryGroup * group, GError ** error) {
+    GaEntryGroupPrivate *priv = GA_ENTRY_GROUP_GET_PRIVATE(group);
+    int ret;
+    ret = avahi_entry_group_commit(priv->group);
+    if (ret) {
+        if (error != NULL) {
+            *error = g_error_new(GA_ERRORS, ret,
+                                 "Committing group failed: %s",
+                                 avahi_strerror(ret));
+        }
+        return FALSE;
+    }
+    return TRUE;
+}
+
+gboolean ga_entry_group_reset(GaEntryGroup * group, GError ** error) {
+    GaEntryGroupPrivate *priv = GA_ENTRY_GROUP_GET_PRIVATE(group);
+    int ret;
+    ret = avahi_entry_group_reset(priv->group);
+    if (ret) {
+        if (error != NULL) {
+            *error = g_error_new(GA_ERRORS, ret,
+                                 "Resetting group failed: %s",
+                                 avahi_strerror(ret));
+        }
+        return FALSE;
+    }
+    return TRUE;
+}
diff --git a/avahi-glib/ga-entry-group.h b/avahi-glib/ga-entry-group.h
new file mode 100644 (file)
index 0000000..5d2f6ba
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * ga-entry-group.h - Header for GaEntryGroup
+ * Copyright (C) 2005 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GA_ENTRY_GROUP_H__
+#define __GA_ENTRY_GROUP_H__
+
+#include <glib-object.h>
+#include <avahi-client/publish.h>
+#include <avahi-client/client.h>
+
+#include "ga-client.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+    GA_ENTRY_GROUP_STATE_UNCOMMITED = AVAHI_ENTRY_GROUP_UNCOMMITED,
+    GA_ENTRY_GROUP_STATE_REGISTERING = AVAHI_ENTRY_GROUP_REGISTERING,
+    GA_ENTRY_GROUP_STATE_ESTABLISHED = AVAHI_ENTRY_GROUP_ESTABLISHED,
+    GA_ENTRY_GROUP_STATE_COLLISTION = AVAHI_ENTRY_GROUP_COLLISION,
+    GA_ENTRY_GROUP_STATE_FAILURE = AVAHI_ENTRY_GROUP_FAILURE
+} GaEntryGroupState;
+
+typedef struct _GaEntryGroupService GaEntryGroupService;
+typedef struct _GaEntryGroup GaEntryGroup;
+typedef struct _GaEntryGroupClass GaEntryGroupClass;
+
+struct _GaEntryGroupService {
+    AvahiIfIndex interface;
+    AvahiProtocol protocol;
+    AvahiPublishFlags flags;
+    gchar *name;
+    gchar *type;
+    gchar *domain;
+    gchar *host;
+    guint16 port;
+};
+
+struct _GaEntryGroupClass {
+    GObjectClass parent_class;
+};
+
+struct _GaEntryGroup {
+    GObject parent;
+};
+
+GType ga_entry_group_get_type(void);
+
+/* TYPE MACROS */
+#define GA_TYPE_ENTRY_GROUP \
+  (ga_entry_group_get_type())
+#define GA_ENTRY_GROUP(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GA_TYPE_ENTRY_GROUP, GaEntryGroup))
+#define GA_ENTRY_GROUP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GA_TYPE_ENTRY_GROUP, GaEntryGroupClass))
+#define IS_GA_ENTRY_GROUP(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GA_TYPE_ENTRY_GROUP))
+#define IS_GA_ENTRY_GROUP_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GA_TYPE_ENTRY_GROUP))
+#define GA_ENTRY_GROUP_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GA_TYPE_ENTRY_GROUP, GaEntryGroupClass))
+
+GaEntryGroup *ga_entry_group_new(void);
+
+gboolean ga_entry_group_attach(GaEntryGroup * group,
+                      GaClient * client, GError ** error);
+
+GaEntryGroupService *ga_entry_group_add_service_strlist(GaEntryGroup * group,
+                                                        const gchar * name,
+                                                        const gchar * type,
+                                                        guint16 port,
+                                                        GError ** error,
+                                                        AvahiStringList *
+                                                        txt);
+
+GaEntryGroupService *ga_entry_group_add_service_full_strlist(GaEntryGroup *
+                                                             group,
+                                                             AvahiIfIndex
+                                                             interface,
+                                                             AvahiProtocol
+                                                             protocol,
+                                                             AvahiPublishFlags
+                                                             flags,
+                                                             const gchar *
+                                                             name,
+                                                             const gchar *
+                                                             type,
+                                                             const gchar *
+                                                             domain,
+                                                             const gchar *
+                                                             host,
+                                                             guint16 port,
+                                                             GError ** error,
+                                                             AvahiStringList *
+                                                             txt);
+GaEntryGroupService *ga_entry_group_add_service(GaEntryGroup * group,
+                                                const gchar * name,
+                                                const gchar * type,
+                                                guint16 port, GError ** error,
+                                                ...);
+
+GaEntryGroupService *ga_entry_group_add_service_full(GaEntryGroup * group,
+                                                     AvahiIfIndex interface,
+                                                     AvahiProtocol protocol,
+                                                     AvahiPublishFlags flags,
+                                                     const gchar * name,
+                                                     const gchar * type,
+                                                     const gchar * domain,
+                                                     const gchar * host,
+                                                     guint16 port,
+                                                     GError ** error, ...);
+
+/* Add raw record */
+gboolean ga_entry_group_add_record(GaEntryGroup * group,
+                          AvahiPublishFlags flags,
+                          const gchar * name,
+                          guint16 type,
+                          guint32 ttl,
+                          const void *rdata, gsize size, GError ** error);
+gboolean ga_entry_group_add_record_full(GaEntryGroup * group,
+                               AvahiIfIndex interface,
+                               AvahiProtocol protocol,
+                               AvahiPublishFlags flags,
+                               const gchar * name,
+                               guint16 clazz,
+                               guint16 type,
+                               guint32 ttl,
+                               const void *rdata,
+                               gsize size, GError ** error);
+
+
+
+void ga_entry_group_service_freeze(GaEntryGroupService * service);
+
+/* Set a key in the service record. If the service isn't frozen it's committed
+ * immediately */
+gboolean ga_entry_group_service_set(GaEntryGroupService * service,
+                           const gchar * key, const gchar * value,
+                           GError ** error);
+
+gboolean ga_entry_group_service_set_arbitrary(GaEntryGroupService * service,
+                                     const gchar * key, const guint8 * value,
+                                     gsize size, GError ** error);
+
+/* Remove one key from the service record */
+gboolean ga_entry_group_service_remove_key(GaEntryGroupService * service,
+                                  const gchar * key, GError ** error);
+
+/* Update the txt record of the frozen service */
+gboolean ga_entry_group_service_thaw(GaEntryGroupService * service, GError ** error);
+
+/* Commit all newly added services */
+gboolean ga_entry_group_commit(GaEntryGroup * group, GError ** error);
+
+/* Invalidated all GaEntryGroupServices */
+gboolean ga_entry_group_reset(GaEntryGroup * group, GError ** error);
+
+G_END_DECLS
+#endif /* #ifndef __GA_ENTRY_GROUP_H__ */
diff --git a/avahi-glib/ga-enums.h b/avahi-glib/ga-enums.h
new file mode 100644 (file)
index 0000000..9298686
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * ga-enums.h
+ * Copyright (C) 2005 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GA_ENUMS_H__
+#define __GA_ENUMS_H__
+
+#include <glib-object.h>
+#include <avahi-common/defs.h>
+#include <avahi-common/address.h>
+
+G_BEGIN_DECLS
+/** Values for GaProtocol */
+        typedef enum {
+    GA_PROTOCOL_INET = AVAHI_PROTO_INET,     /**< IPv4 */
+    GA_PROTOCOL_INET6 = AVAHI_PROTO_INET6,   /**< IPv6 */
+    GA_PROTOCOL_UNSPEC = AVAHI_PROTO_UNSPEC  /**< Unspecified/all protocol(s) */
+} GaProtocol;
+
+
+/** Some flags for lookup callback functions */
+typedef enum {
+    GA_LOOKUP_RESULT_CACHED = AVAHI_LOOKUP_RESULT_CACHED,     /**< This response originates from the cache */
+    GA_LOOKUP_RESULT_WIDE_AREA = AVAHI_LOOKUP_RESULT_WIDE_AREA,
+                                                              /**< This response originates from wide area DNS */
+    GA_LOOKUP_RESULT_MULTICAST = AVAHI_LOOKUP_RESULT_MULTICAST,
+                                                              /**< This response originates from multicast DNS */
+    GA_LOOKUP_RESULT_LOCAL = AVAHI_LOOKUP_RESULT_LOCAL,       /**< This record/service resides on and was announced by the local host. Only available in service and record browsers and only on AVAHI_BROWSER_NEW. */
+    GA_LOOKUP_RESULT_OUR_OWN = AVAHI_LOOKUP_RESULT_OUR_OWN,   /**< This service belongs to the same local client as the browser object. Only available in avahi-client, and only for service browsers and only on AVAHI_BROWSER_NEW. */
+    GA_LOOKUP_RESULT_STATIC = AVAHI_LOOKUP_RESULT_STATIC      /**< The returned data has been defined statically by some configuration option */
+} GaLookupResultFlags;
+
+typedef enum {
+    GA_LOOKUP_NO_FLAGS = 0,
+    GA_LOOKUP_USE_WIDE_AREA = AVAHI_LOOKUP_USE_WIDE_AREA,    /**< Force lookup via wide area DNS */
+    GA_LOOKUP_USE_MULTICAST = AVAHI_LOOKUP_USE_MULTICAST,    /**< Force lookup via multicast DNS */
+    GA_LOOKUP_NO_TXT = AVAHI_LOOKUP_NO_TXT,                  /**< When doing service resolving, don't lookup TXT record */
+    GA_LOOKUP_NO_ADDRESS = AVAHI_LOOKUP_NO_ADDRESS           /**< When doing service resolving, don't lookup A/AAAA record */
+} GaLookupFlags;
+
+typedef enum {
+    GA_RESOLVER_FOUND = AVAHI_RESOLVER_FOUND,           /**< RR found, resolving successful */
+    GA_RESOLVER_FAILURE = AVAHI_RESOLVER_FAILURE        /**< Resolving failed due to some reason which can be retrieved using avahi_server_errno()/avahi_client_errno() */
+} GaResolverEvent;
+
+typedef enum {
+    GA_BROWSER_NEW = AVAHI_BROWSER_NEW,             /**< The object is new on the network */
+    GA_BROWSER_REMOVE = AVAHI_BROWSER_REMOVE,                     /**< The object has been removed from the network */
+    GA_BROWSER_CACHE_EXHAUSTED = AVAHI_BROWSER_CACHE_EXHAUSTED,   /**< One-time event, to notify the user that all entries from the caches have been send */
+    GA_BROWSER_ALL_FOR_NOW = AVAHI_BROWSER_ALL_FOR_NOW,           /**< One-time event, to notify the user that more records will probably not show up in the near future, i.e. all cache entries have been read and all static servers been queried */
+    GA_BROWSER_FAILURE = AVAHI_BROWSER_FAILURE                    /**< Browsing failed due to some reason which can be retrieved using avahi_server_errno()/avahi_client_errno() */
+} GaBrowserEvent;
+
+G_END_DECLS
+#endif /* #ifndef __GA_CLIENT_H__ */
diff --git a/avahi-glib/ga-errors.c b/avahi-glib/ga-errors.c
new file mode 100644 (file)
index 0000000..5abe36a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * ga-errors.c - Source for error types used
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include "ga-errors.h"
+
+GQuark ga_errors_quark(void) {
+    static GQuark quark = 0;
+    if (!quark)
+        quark = g_quark_from_static_string("ga_errors");
+    return quark;
+}
diff --git a/avahi-glib/ga-errors.h b/avahi-glib/ga-errors.h
new file mode 100644 (file)
index 0000000..9ed10e0
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * ga-errors.h - Header for Avahi error types
+ * Copyright (C) 2005 Collabora Ltd.
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GA_ERRORS_H__
+#define __GA_ERRORS_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+#include <avahi-common/error.h>
+
+GQuark ga_errors_quark(void);
+
+#define GA_ERRORS ga_errors_quark()
+
+G_END_DECLS
+#endif /* #ifndef __GA_ERRORS_H__ */
diff --git a/avahi-glib/ga-record-browser.c b/avahi-glib/ga-record-browser.c
new file mode 100644 (file)
index 0000000..f6747cd
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * ga-record-browser.c - Source for GaRecordBrowser
+ * Copyright (C) 2007 Collabora Ltd.
+ * @author Sjoerd Simons <sjoerd@luon.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ga-record-browser.h"
+#include "signals-marshal.h"
+#include "ga-errors.h"
+#include "ga-enums-enumtypes.h"
+
+G_DEFINE_TYPE(GaRecordBrowser, ga_record_browser, G_TYPE_OBJECT)
+
+/* signal enum */
+enum {
+    NEW,
+    REMOVED,
+    FAILURE,
+    ALL_FOR_NOW,
+    CACHE_EXHAUSTED,
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* properties */
+enum {
+    PROP_PROTOCOL = 1,
+    PROP_IFINDEX,
+    PROP_NAME,
+    PROP_CLASS,
+    PROP_TYPE,
+    PROP_FLAGS
+};
+
+/* private structure */
+typedef struct _GaRecordBrowserPrivate GaRecordBrowserPrivate;
+
+struct _GaRecordBrowserPrivate {
+    gboolean dispose_has_run;
+    GaClient *client;
+    AvahiRecordBrowser *browser;
+    AvahiProtocol protocol;
+    AvahiIfIndex interface;
+    gchar *name;
+    guint16 class;
+    guint16 type;
+    AvahiLookupFlags flags;
+};
+
+#define GA_RECORD_BROWSER_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), GA_TYPE_RECORD_BROWSER, GaRecordBrowserPrivate))
+
+static void ga_record_browser_init(AVAHI_GCC_UNUSED GaRecordBrowser * obj) {
+    /* allocate any data required by the object here */
+}
+
+static void ga_record_browser_dispose(GObject * object);
+static void ga_record_browser_finalize(GObject * object);
+
+static void ga_record_browser_set_property(GObject * object,
+                               guint property_id,
+                               const GValue * value, GParamSpec * pspec) {
+    GaRecordBrowser *browser = GA_RECORD_BROWSER(object);
+    GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(browser);
+
+    g_assert(priv->browser == NULL);
+
+    switch (property_id) {
+        case PROP_PROTOCOL:
+            priv->protocol = g_value_get_enum(value);
+            break;
+        case PROP_IFINDEX:
+            priv->interface = g_value_get_int(value);
+            break;
+        case PROP_NAME:
+            priv->name = g_value_dup_string(value);
+            break;
+        case PROP_CLASS:
+            priv->class = g_value_get_uint(value);
+            break;
+        case PROP_TYPE:
+            priv->type = g_value_get_uint(value);
+            break;
+        case PROP_FLAGS:
+            priv->flags = g_value_get_enum(value);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void ga_record_browser_get_property(GObject * object,
+                               guint property_id,
+                               GValue * value, GParamSpec * pspec) {
+    GaRecordBrowser *browser = GA_RECORD_BROWSER(object);
+    GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(browser);
+
+    switch (property_id) {
+        case PROP_PROTOCOL:
+            g_value_set_int(value, priv->protocol);
+            break;
+        case PROP_IFINDEX:
+            g_value_set_int(value, priv->interface);
+            break;
+        case PROP_TYPE:
+            g_value_set_uint(value, priv->type);
+            break;
+        case PROP_CLASS:
+            g_value_set_uint(value, priv->class);
+            break;
+        case PROP_NAME:
+            g_value_set_string(value, priv->name);
+            break;
+        case PROP_FLAGS:
+            g_value_set_enum(value, priv->flags);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+
+static void ga_record_browser_class_init(GaRecordBrowserClass * ga_record_browser_class) {
+    GObjectClass *object_class = G_OBJECT_CLASS(ga_record_browser_class);
+    GParamSpec *param_spec;
+
+    g_type_class_add_private(ga_record_browser_class,
+                             sizeof (GaRecordBrowserPrivate));
+
+    object_class->dispose = ga_record_browser_dispose;
+    object_class->finalize = ga_record_browser_finalize;
+
+    object_class->set_property = ga_record_browser_set_property;
+    object_class->get_property = ga_record_browser_get_property;
+
+    signals[NEW] =
+            g_signal_new("new-record",
+                         G_OBJECT_CLASS_TYPE(ga_record_browser_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         ga_signals_marshal_VOID__INT_ENUM_STRING_UINT_UINT_POINTER_INT_INT,
+                         G_TYPE_NONE, 8,
+                         G_TYPE_INT,
+                         GA_TYPE_PROTOCOL,
+                         G_TYPE_STRING,
+                         G_TYPE_UINT,
+                         G_TYPE_UINT,
+                         G_TYPE_POINTER,
+                         G_TYPE_INT, GA_TYPE_LOOKUP_RESULT_FLAGS);
+
+    signals[REMOVED] =
+            g_signal_new("removed-record",
+                         G_OBJECT_CLASS_TYPE(ga_record_browser_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         ga_signals_marshal_VOID__INT_ENUM_STRING_UINT_UINT_POINTER_INT_INT,
+                         G_TYPE_NONE, 8,
+                         G_TYPE_INT,
+                         GA_TYPE_PROTOCOL,
+                         G_TYPE_STRING,
+                         G_TYPE_UINT,
+                         G_TYPE_UINT,
+                         G_TYPE_POINTER,
+                         G_TYPE_INT, GA_TYPE_LOOKUP_RESULT_FLAGS);
+
+    signals[ALL_FOR_NOW] =
+            g_signal_new("all-for-now",
+                         G_OBJECT_CLASS_TYPE(ga_record_browser_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+    signals[CACHE_EXHAUSTED] =
+            g_signal_new("cache-exhausted",
+                         G_OBJECT_CLASS_TYPE(ga_record_browser_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+    signals[FAILURE] =
+            g_signal_new("failure",
+                         G_OBJECT_CLASS_TYPE(ga_record_browser_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__POINTER,
+                         G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+    param_spec = g_param_spec_enum("protocol", "Avahi protocol to browse",
+                                   "Avahi protocol to browse",
+                                   GA_TYPE_PROTOCOL,
+                                   GA_PROTOCOL_UNSPEC,
+                                   G_PARAM_READWRITE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_PROTOCOL, param_spec);
+
+    param_spec = g_param_spec_int("interface", "interface index",
+                                  "Interface use for browser",
+                                  AVAHI_IF_UNSPEC,
+                                  G_MAXINT,
+                                  AVAHI_IF_UNSPEC,
+                                  G_PARAM_READWRITE |
+                                  G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_IFINDEX, param_spec);
+
+    param_spec = g_param_spec_string("name", "record name",
+                                     "Record name to browse for",
+                                     NULL,
+                                     G_PARAM_READWRITE |
+                                     G_PARAM_STATIC_NAME |
+                                     G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_NAME, param_spec);
+
+    param_spec = g_param_spec_uint("type", "record type",
+                                   "Record type to browse for",
+                                   0, G_MAXUINT16, 0,
+                                   G_PARAM_READWRITE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_TYPE, param_spec);
+
+    param_spec = g_param_spec_uint("class", "record class",
+                                   "Record class to browse for",
+                                   0, G_MAXUINT16, 0,
+                                   G_PARAM_READWRITE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_CLASS, param_spec);
+
+    param_spec = g_param_spec_enum("flags", "Lookup flags for the browser",
+                                   "Browser lookup flags",
+                                   GA_TYPE_PROTOCOL,
+                                   GA_LOOKUP_NO_FLAGS,
+                                   G_PARAM_READWRITE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_FLAGS, param_spec);
+}
+
+void ga_record_browser_dispose(GObject * object) {
+    GaRecordBrowser *self = GA_RECORD_BROWSER(object);
+    GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(self);
+
+    if (priv->dispose_has_run)
+        return;
+
+    priv->dispose_has_run = TRUE;
+
+    /* release any references held by the object here */
+    if (priv->client)
+        g_object_unref(priv->client);
+    priv->client = NULL;
+
+    if (priv->browser)
+        avahi_record_browser_free(priv->browser);
+    priv->browser = NULL;
+
+    if (G_OBJECT_CLASS(ga_record_browser_parent_class)->dispose)
+        G_OBJECT_CLASS(ga_record_browser_parent_class)->dispose(object);
+}
+
+void ga_record_browser_finalize(GObject * object) {
+    GaRecordBrowser *self = GA_RECORD_BROWSER(object);
+    GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(self);
+
+    /* free any data held directly by the object here */
+    g_free(priv->name);
+
+    G_OBJECT_CLASS(ga_record_browser_parent_class)->finalize(object);
+}
+
+
+GaRecordBrowser *ga_record_browser_new(const gchar * name, guint16 type) {
+    return ga_record_browser_new_full(AVAHI_IF_UNSPEC,
+                                      AVAHI_PROTO_UNSPEC, name,
+                                      AVAHI_DNS_CLASS_IN, type, 0);
+}
+
+GaRecordBrowser *ga_record_browser_new_full(AvahiIfIndex interface,
+                                            AvahiProtocol protocol,
+                                            const gchar * name,
+                                            guint16 clazz,
+                                            guint16 type,
+                                            GaLookupFlags flags) {
+    return g_object_new(GA_TYPE_RECORD_BROWSER,
+                        "interface", interface,
+                        "protocol", protocol,
+                        "name", name,
+                        "class", clazz, "type", type, "flags", flags, NULL);
+
+}
+
+static void _avahi_record_browser_cb(AVAHI_GCC_UNUSED AvahiRecordBrowser * r, AvahiIfIndex interface,
+                         AvahiProtocol protocol, AvahiBrowserEvent event,
+                         const char *name, uint16_t clazz, uint16_t type,
+                         const void *rdata, size_t rdata_size,
+                         AvahiLookupResultFlags flags, void *userdata) {
+    GaRecordBrowser *self = GA_RECORD_BROWSER(userdata);
+    GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(userdata);
+
+    switch (event) {
+        case AVAHI_BROWSER_NEW:
+        case AVAHI_BROWSER_REMOVE:{
+                guint signalid = (event == AVAHI_BROWSER_NEW ? NEW : REMOVED);
+                g_signal_emit(self, signals[signalid], 0,
+                              interface, protocol, name, clazz, type,
+                              rdata, rdata_size, flags);
+                break;
+            }
+        case AVAHI_BROWSER_CACHE_EXHAUSTED:
+            g_signal_emit(self, signals[CACHE_EXHAUSTED], 0);
+            break;
+        case AVAHI_BROWSER_ALL_FOR_NOW:
+            g_signal_emit(self, signals[ALL_FOR_NOW], 0);
+            break;
+        case AVAHI_BROWSER_FAILURE:{
+                GError *error;
+                int aerrno = avahi_client_errno(priv->client->avahi_client);
+                error = g_error_new(GA_ERRORS, aerrno,
+                                    "Browsing failed: %s",
+                                    avahi_strerror(aerrno));
+                g_signal_emit(self, signals[FAILURE], 0, error);
+                g_error_free(error);
+                break;
+            }
+    }
+}
+
+gboolean ga_record_browser_attach(GaRecordBrowser * browser,
+                         GaClient * client, GError ** error) {
+    GaRecordBrowserPrivate *priv = GA_RECORD_BROWSER_GET_PRIVATE(browser);
+
+    priv->client = g_object_ref(client);
+    priv->browser = avahi_record_browser_new(client->avahi_client,
+                                             priv->interface,
+                                             priv->protocol,
+                                             priv->name,
+                                             priv->class,
+                                             priv->type,
+                                             priv->flags,
+                                             _avahi_record_browser_cb,
+                                             browser);
+    if (priv->browser == NULL) {
+        if (error != NULL) {
+            int aerrno = avahi_client_errno(client->avahi_client);
+            *error = g_error_new(GA_ERRORS, aerrno,
+                                 "Attaching record browser failed: %s",
+                                 avahi_strerror(aerrno));
+        }
+        return FALSE;
+    }
+    return TRUE;
+}
diff --git a/avahi-glib/ga-record-browser.h b/avahi-glib/ga-record-browser.h
new file mode 100644 (file)
index 0000000..c27c061
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * ga-record-browser.h - Header for GaRecordBrowser
+ * Copyright (C) 2007 Collabora Ltd.
+ * @author Sjoerd Simons <sjoerd@luon.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GA_RECORD_BROWSER_H__
+#define __GA_RECORD_BROWSER_H__
+
+#include <glib-object.h>
+#include <avahi-client/lookup.h>
+#include <avahi-common/defs.h>
+#include "ga-client.h"
+#include "ga-enums.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GaRecordBrowser GaRecordBrowser;
+typedef struct _GaRecordBrowserClass GaRecordBrowserClass;
+
+struct _GaRecordBrowserClass {
+    GObjectClass parent_class;
+};
+
+struct _GaRecordBrowser {
+    GObject parent;
+};
+
+GType ga_record_browser_get_type(void);
+
+/* TYPE MACROS */
+#define GA_TYPE_RECORD_BROWSER \
+  (ga_record_browser_get_type())
+#define GA_RECORD_BROWSER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GA_TYPE_RECORD_BROWSER, GaRecordBrowser))
+#define GA_RECORD_BROWSER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GA_TYPE_RECORD_BROWSER, GaRecordBrowserClass))
+#define IS_GA_RECORD_BROWSER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GA_TYPE_RECORD_BROWSER))
+#define IS_GA_RECORD_BROWSER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GA_TYPE_RECORD_BROWSER))
+#define GA_RECORD_BROWSER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GA_TYPE_RECORD_BROWSER, GaRecordBrowserClass))
+
+GaRecordBrowser *ga_record_browser_new(const gchar * name, guint16 type);
+
+GaRecordBrowser *ga_record_browser_new_full(AvahiIfIndex interface,
+                                            AvahiProtocol protocol,
+                                            const gchar * name,
+                                            guint16 clazz,
+                                            guint16 type,
+                                            GaLookupFlags flags);
+
+gboolean
+ga_record_browser_attach(GaRecordBrowser * browser,
+                         GaClient * client, GError ** error);
+
+
+G_END_DECLS
+#endif /* #ifndef __GA_RECORD_BROWSER_H__ */
diff --git a/avahi-glib/ga-service-browser.c b/avahi-glib/ga-service-browser.c
new file mode 100644 (file)
index 0000000..f694ca5
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * ga-service-browser.c - Source for GaServiceBrowser
+ * Copyright (C) 2005 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <avahi-client/client.h>
+#include <avahi-client/lookup.h>
+#include <avahi-common/error.h>
+
+#include "ga-service-browser.h"
+#include "signals-marshal.h"
+#include "ga-errors.h"
+#include "ga-enums-enumtypes.h"
+
+G_DEFINE_TYPE(GaServiceBrowser, ga_service_browser, G_TYPE_OBJECT)
+
+/* signal enum */
+enum {
+    NEW,
+    REMOVED,
+    CACHE_EXHAUSTED,
+    ALL_FOR_NOW,
+    FAILURE,
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* properties */
+enum {
+    PROP_PROTOCOL = 1,
+    PROP_IFINDEX,
+    PROP_TYPE,
+    PROP_DOMAIN,
+    PROP_FLAGS
+};
+
+/* private structure */
+typedef struct _GaServiceBrowserPrivate GaServiceBrowserPrivate;
+
+struct _GaServiceBrowserPrivate {
+    GaClient *client;
+    AvahiServiceBrowser *browser;
+    AvahiIfIndex interface;
+    AvahiProtocol protocol;
+    char *type;
+    char *domain;
+    AvahiLookupFlags flags;
+    gboolean dispose_has_run;
+};
+
+#define GA_SERVICE_BROWSER_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), GA_TYPE_SERVICE_BROWSER, GaServiceBrowserPrivate))
+
+static void ga_service_browser_init(GaServiceBrowser * obj) {
+    GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(obj);
+
+    /* allocate any data required by the object here */
+    priv->client = NULL;
+    priv->browser = NULL;
+    priv->type = NULL;
+    priv->domain = NULL;
+
+}
+
+static void ga_service_browser_dispose(GObject * object);
+static void ga_service_browser_finalize(GObject * object);
+
+static void ga_service_browser_set_property(GObject * object,
+                                guint property_id,
+                                const GValue * value, GParamSpec * pspec) {
+    GaServiceBrowser *browser = GA_SERVICE_BROWSER(object);
+    GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(browser);
+
+    g_assert(priv->browser == NULL);
+    switch (property_id) {
+        case PROP_PROTOCOL:
+            priv->protocol = g_value_get_enum(value);
+            break;
+        case PROP_IFINDEX:
+            priv->interface = g_value_get_int(value);
+            break;
+        case PROP_TYPE:
+            priv->type = g_strdup(g_value_get_string(value));
+            break;
+        case PROP_DOMAIN:
+            priv->domain = g_strdup(g_value_get_string(value));
+            break;
+        case PROP_FLAGS:
+            priv->flags = g_value_get_enum(value);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void ga_service_browser_get_property(GObject * object,
+                                guint property_id,
+                                GValue * value, GParamSpec * pspec) {
+    GaServiceBrowser *browser = GA_SERVICE_BROWSER(object);
+    GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(browser);
+
+    switch (property_id) {
+        case PROP_PROTOCOL:
+            g_value_set_int(value, priv->protocol);
+            break;
+        case PROP_IFINDEX:
+            g_value_set_int(value, priv->interface);
+            break;
+        case PROP_TYPE:
+            g_value_set_string(value, priv->type);
+            break;
+        case PROP_DOMAIN:
+            g_value_set_string(value, priv->domain);
+            break;
+        case PROP_FLAGS:
+            g_value_set_enum(value, priv->flags);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+
+static void ga_service_browser_class_init(GaServiceBrowserClass *
+                              ga_service_browser_class) {
+    GObjectClass *object_class = G_OBJECT_CLASS(ga_service_browser_class);
+    GParamSpec *param_spec;
+
+    g_type_class_add_private(ga_service_browser_class,
+                             sizeof (GaServiceBrowserPrivate));
+
+    object_class->dispose = ga_service_browser_dispose;
+    object_class->finalize = ga_service_browser_finalize;
+
+    object_class->set_property = ga_service_browser_set_property;
+    object_class->get_property = ga_service_browser_get_property;
+
+    signals[NEW] =
+            g_signal_new("new-service",
+                         G_OBJECT_CLASS_TYPE(ga_service_browser_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         ga_signals_marshal_VOID__INT_ENUM_STRING_STRING_STRING_UINT,
+                         G_TYPE_NONE, 6,
+                         G_TYPE_INT,
+                         GA_TYPE_PROTOCOL,
+                         G_TYPE_STRING,
+                         G_TYPE_STRING,
+                         G_TYPE_STRING, GA_TYPE_LOOKUP_RESULT_FLAGS);
+
+    signals[REMOVED] =
+            g_signal_new("removed-service",
+                         G_OBJECT_CLASS_TYPE(ga_service_browser_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         ga_signals_marshal_VOID__INT_ENUM_STRING_STRING_STRING_UINT,
+                         G_TYPE_NONE, 6,
+                         G_TYPE_INT,
+                         GA_TYPE_PROTOCOL,
+                         G_TYPE_STRING,
+                         G_TYPE_STRING,
+                         G_TYPE_STRING, GA_TYPE_LOOKUP_RESULT_FLAGS);
+
+    signals[ALL_FOR_NOW] =
+            g_signal_new("all-for-now",
+                         G_OBJECT_CLASS_TYPE(ga_service_browser_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+    signals[CACHE_EXHAUSTED] =
+            g_signal_new("cache-exhausted",
+                         G_OBJECT_CLASS_TYPE(ga_service_browser_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+    signals[FAILURE] =
+            g_signal_new("failure",
+                         G_OBJECT_CLASS_TYPE(ga_service_browser_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__POINTER,
+                         G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+    param_spec = g_param_spec_enum("protocol", "Avahi protocol to browse",
+                                   "Avahi protocol to browse",
+                                   GA_TYPE_PROTOCOL,
+                                   GA_PROTOCOL_UNSPEC,
+                                   G_PARAM_READWRITE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_PROTOCOL, param_spec);
+
+    param_spec = g_param_spec_int("interface", "interface index",
+                                  "Interface use for browser",
+                                  AVAHI_IF_UNSPEC,
+                                  G_MAXINT,
+                                  AVAHI_IF_UNSPEC,
+                                  G_PARAM_READWRITE |
+                                  G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_IFINDEX, param_spec);
+
+    param_spec = g_param_spec_string("type", "service type",
+                                     "Service type to browse for",
+                                     NULL,
+                                     G_PARAM_READWRITE |
+                                     G_PARAM_STATIC_NAME |
+                                     G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_TYPE, param_spec);
+
+    param_spec = g_param_spec_string("domain", "service domain",
+                                     "Domain to browse in",
+                                     NULL,
+                                     G_PARAM_READWRITE |
+                                     G_PARAM_STATIC_NAME |
+                                     G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_DOMAIN, param_spec);
+
+    param_spec = g_param_spec_enum("flags", "Lookup flags for the browser",
+                                   "Browser lookup flags",
+                                   GA_TYPE_PROTOCOL,
+                                   GA_LOOKUP_NO_FLAGS,
+                                   G_PARAM_READWRITE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_FLAGS, param_spec);
+}
+
+void ga_service_browser_dispose(GObject * object) {
+    GaServiceBrowser *self = GA_SERVICE_BROWSER(object);
+    GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(self);
+
+    if (priv->dispose_has_run)
+        return;
+
+    priv->dispose_has_run = TRUE;
+
+    if (priv->browser)
+        avahi_service_browser_free(priv->browser);
+    priv->browser = NULL;
+    if (priv->client)
+        g_object_unref(priv->client);
+    priv->client = NULL;
+
+    /* release any references held by the object here */
+
+    if (G_OBJECT_CLASS(ga_service_browser_parent_class)->dispose)
+        G_OBJECT_CLASS(ga_service_browser_parent_class)->dispose(object);
+}
+
+void ga_service_browser_finalize(GObject * object) {
+    GaServiceBrowser *self = GA_SERVICE_BROWSER(object);
+    GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(self);
+
+    /* free any data held directly by the object here */
+    g_free(priv->type);
+    priv->type = NULL;
+    g_free(priv->domain);
+    priv->domain = NULL;
+
+    G_OBJECT_CLASS(ga_service_browser_parent_class)->finalize(object);
+}
+
+static void _avahi_service_browser_cb(AvahiServiceBrowser * b, AvahiIfIndex interface,
+                          AvahiProtocol protocol, AvahiBrowserEvent event,
+                          const char *name, const char *type,
+                          const char *domain, AvahiLookupResultFlags flags,
+                          void *userdata) {
+    GaServiceBrowser *self = GA_SERVICE_BROWSER(userdata);
+    GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(self);
+    if (priv->browser == NULL) {
+        priv->browser = b;
+    }
+    g_assert(priv->browser == b);
+
+    switch (event) {
+        case AVAHI_BROWSER_NEW:
+        case AVAHI_BROWSER_REMOVE:{
+                guint signalid;
+                signalid = (event == AVAHI_BROWSER_NEW ? NEW : REMOVED);
+                g_signal_emit(self, signals[signalid], 0,
+                              interface, protocol, name, type, domain, flags);
+                break;
+            }
+        case AVAHI_BROWSER_CACHE_EXHAUSTED:
+            g_signal_emit(self, signals[CACHE_EXHAUSTED], 0);
+            break;
+        case AVAHI_BROWSER_ALL_FOR_NOW:
+            g_signal_emit(self, signals[ALL_FOR_NOW], 0);
+            break;
+        case AVAHI_BROWSER_FAILURE:{
+                GError *error;
+                int aerrno = avahi_client_errno(priv->client->avahi_client);
+                error = g_error_new(GA_ERRORS, aerrno,
+                                    "Browsing failed: %s",
+                                    avahi_strerror(aerrno));
+                g_signal_emit(self, signals[FAILURE], 0, error);
+                g_error_free(error);
+                break;
+            }
+    }
+}
+
+GaServiceBrowser *ga_service_browser_new(gchar * type) {
+    return ga_service_browser_new_full(AVAHI_IF_UNSPEC,
+                                       AVAHI_PROTO_UNSPEC, type, NULL, 0);
+}
+
+GaServiceBrowser *ga_service_browser_new_full(AvahiIfIndex interface,
+                                              AvahiProtocol protocol,
+                                              gchar * type, gchar * domain,
+                                              GaLookupFlags flags) {
+    return g_object_new(GA_TYPE_SERVICE_BROWSER,
+                        "interface", interface,
+                        "protocol", protocol,
+                        "type", type, "domain", domain, "flags", flags, NULL);
+}
+
+gboolean ga_service_browser_attach(GaServiceBrowser * browser,
+                          GaClient * client, GError ** error) {
+    GaServiceBrowserPrivate *priv = GA_SERVICE_BROWSER_GET_PRIVATE(browser);
+
+    g_object_ref(client);
+    priv->client = client;
+
+    priv->browser = avahi_service_browser_new(client->avahi_client,
+                                              priv->interface,
+                                              priv->protocol,
+                                              priv->type, priv->domain,
+                                              priv->flags,
+                                              _avahi_service_browser_cb,
+                                              browser);
+    if (priv->browser == NULL) {
+        if (error != NULL) {
+            int aerrno = avahi_client_errno(client->avahi_client);
+            *error = g_error_new(GA_ERRORS, aerrno,
+                                 "Attaching group failed: %s",
+                                 avahi_strerror(aerrno));
+        }
+        return FALSE;
+    }
+    return TRUE;
+}
diff --git a/avahi-glib/ga-service-browser.h b/avahi-glib/ga-service-browser.h
new file mode 100644 (file)
index 0000000..c610dbe
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * ga-service-browser.h - Header for GaServiceBrowser
+ * Copyright (C) 2005 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GA_SERVICE_BROWSER_H__
+#define __GA_SERVICE_BROWSER_H__
+
+#include <glib-object.h>
+#include <avahi-client/lookup.h>
+#include <avahi-common/defs.h>
+#include "ga-client.h"
+#include "ga-enums.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GaServiceBrowser GaServiceBrowser;
+typedef struct _GaServiceBrowserClass GaServiceBrowserClass;
+
+struct _GaServiceBrowserClass {
+    GObjectClass parent_class;
+};
+
+struct _GaServiceBrowser {
+    GObject parent;
+};
+
+GType ga_service_browser_get_type(void);
+
+/* TYPE MACROS */
+#define GA_TYPE_SERVICE_BROWSER \
+  (ga_service_browser_get_type())
+#define GA_SERVICE_BROWSER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GA_TYPE_SERVICE_BROWSER, GaServiceBrowser))
+#define GA_SERVICE_BROWSER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GA_TYPE_SERVICE_BROWSER, GaServiceBrowserClass))
+#define IS_GA_SERVICE_BROWSER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GA_TYPE_SERVICE_BROWSER))
+#define IS_GA_SERVICE_BROWSER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GA_TYPE_SERVICE_BROWSER))
+#define GA_SERVICE_BROWSER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GA_TYPE_SERVICE_BROWSER, GaServiceBrowserClass))
+
+GaServiceBrowser *ga_service_browser_new(gchar * type);
+
+GaServiceBrowser *ga_service_browser_new_full(AvahiIfIndex interface,
+                                              AvahiProtocol protocol,
+                                              gchar * type, gchar * domain,
+                                              GaLookupFlags flags);
+
+gboolean
+ga_service_browser_attach(GaServiceBrowser * browser,
+                          GaClient * client, GError ** error);
+
+
+G_END_DECLS
+#endif /* #ifndef __GA_SERVICE_BROWSER_H__ */
diff --git a/avahi-glib/ga-service-resolver.c b/avahi-glib/ga-service-resolver.c
new file mode 100644 (file)
index 0000000..380e0a5
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * ga-service-resolver.c - Source for GaServiceResolver
+ * Copyright (C) 2005 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ga-service-resolver.h"
+#include "signals-marshal.h"
+
+#include "ga-errors.h"
+
+#include "ga-enums.h"
+#include "ga-enums-enumtypes.h"
+
+#include <avahi-client/lookup.h>
+
+G_DEFINE_TYPE(GaServiceResolver, ga_service_resolver, G_TYPE_OBJECT)
+
+/* signal enum */
+enum {
+    FOUND,
+    FAILURE,
+    LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* properties */
+enum {
+    PROP_PROTOCOL = 1,
+    PROP_IFINDEX,
+    PROP_NAME,
+    PROP_TYPE,
+    PROP_DOMAIN,
+    PROP_FLAGS,
+    PROP_APROTOCOL
+};
+
+/* private structure */
+typedef struct _GaServiceResolverPrivate GaServiceResolverPrivate;
+
+struct _GaServiceResolverPrivate {
+    GaClient *client;
+    AvahiServiceResolver *resolver;
+    AvahiIfIndex interface;
+    AvahiProtocol protocol;
+    AvahiAddress address;
+    uint16_t port;
+    char *name;
+    char *type;
+    char *domain;
+    AvahiProtocol aprotocol;
+    AvahiLookupFlags flags;
+    gboolean dispose_has_run;
+};
+
+#define GA_SERVICE_RESOLVER_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), GA_TYPE_SERVICE_RESOLVER, GaServiceResolverPrivate))
+
+static void ga_service_resolver_init(GaServiceResolver * obj) {
+    GaServiceResolverPrivate *priv = GA_SERVICE_RESOLVER_GET_PRIVATE(obj);
+
+    /* allocate any data required by the object here */
+    priv->client = NULL;
+    priv->resolver = NULL;
+    priv->name = NULL;
+    priv->type = NULL;
+    priv->domain = NULL;
+    priv->port = 0;
+}
+
+static void ga_service_resolver_dispose(GObject * object);
+static void ga_service_resolver_finalize(GObject * object);
+
+static void ga_service_resolver_set_property(GObject * object,
+                                 guint property_id,
+                                 const GValue * value, GParamSpec * pspec) {
+    GaServiceResolver *resolver = GA_SERVICE_RESOLVER(object);
+    GaServiceResolverPrivate *priv =
+            GA_SERVICE_RESOLVER_GET_PRIVATE(resolver);
+
+    g_assert(priv->resolver == NULL);
+    switch (property_id) {
+        case PROP_PROTOCOL:
+            priv->protocol = g_value_get_enum(value);
+            break;
+        case PROP_APROTOCOL:
+            priv->aprotocol = g_value_get_enum(value);
+            break;
+        case PROP_IFINDEX:
+            priv->interface = g_value_get_int(value);
+            break;
+        case PROP_NAME:
+            priv->name = g_strdup(g_value_get_string(value));
+            break;
+        case PROP_TYPE:
+            priv->type = g_strdup(g_value_get_string(value));
+            break;
+        case PROP_DOMAIN:
+            priv->domain = g_strdup(g_value_get_string(value));
+            break;
+        case PROP_FLAGS:
+            priv->flags = g_value_get_enum(value);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void ga_service_resolver_get_property(GObject * object,
+                                 guint property_id,
+                                 GValue * value, GParamSpec * pspec) {
+    GaServiceResolver *resolver = GA_SERVICE_RESOLVER(object);
+    GaServiceResolverPrivate *priv =
+            GA_SERVICE_RESOLVER_GET_PRIVATE(resolver);
+
+    switch (property_id) {
+        case PROP_APROTOCOL:
+            g_value_set_enum(value, priv->aprotocol);
+            break;
+        case PROP_PROTOCOL:
+            g_value_set_enum(value, priv->protocol);
+            break;
+        case PROP_IFINDEX:
+            g_value_set_int(value, priv->interface);
+            break;
+        case PROP_NAME:
+            g_value_set_string(value, priv->name);
+            break;
+        case PROP_TYPE:
+            g_value_set_string(value, priv->type);
+            break;
+        case PROP_DOMAIN:
+            g_value_set_string(value, priv->domain);
+            break;
+        case PROP_FLAGS:
+            g_value_set_enum(value, priv->flags);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+
+static void ga_service_resolver_class_init(GaServiceResolverClass *
+                               ga_service_resolver_class) {
+    GObjectClass *object_class = G_OBJECT_CLASS(ga_service_resolver_class);
+    GParamSpec *param_spec;
+
+    g_type_class_add_private(ga_service_resolver_class,
+                             sizeof (GaServiceResolverPrivate));
+
+    object_class->set_property = ga_service_resolver_set_property;
+    object_class->get_property = ga_service_resolver_get_property;
+
+    object_class->dispose = ga_service_resolver_dispose;
+    object_class->finalize = ga_service_resolver_finalize;
+
+    signals[FOUND] =
+            g_signal_new("found",
+                         G_OBJECT_CLASS_TYPE(ga_service_resolver_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         ga_signals_marshal_VOID__INT_ENUM_STRING_STRING_STRING_STRING_POINTER_INT_POINTER_INT,
+                         G_TYPE_NONE, 10,
+                         G_TYPE_INT,
+                         GA_TYPE_PROTOCOL,
+                         G_TYPE_STRING,
+                         G_TYPE_STRING,
+                         G_TYPE_STRING,
+                         G_TYPE_STRING,
+                         G_TYPE_POINTER,
+                         G_TYPE_INT,
+                         G_TYPE_POINTER, GA_TYPE_LOOKUP_RESULT_FLAGS);
+
+    signals[FAILURE] =
+            g_signal_new("failure",
+                         G_OBJECT_CLASS_TYPE(ga_service_resolver_class),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__POINTER,
+                         G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+    param_spec = g_param_spec_enum("protocol", "Avahi protocol to resolve on",
+                                   "Avahi protocol to resolve on",
+                                   GA_TYPE_PROTOCOL,
+                                   GA_PROTOCOL_UNSPEC,
+                                   G_PARAM_READWRITE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_PROTOCOL, param_spec);
+
+    param_spec = g_param_spec_enum("aprotocol", "Address protocol",
+                                   "Avahi protocol of the address to be resolved",
+                                   GA_TYPE_PROTOCOL,
+                                   GA_PROTOCOL_UNSPEC,
+                                   G_PARAM_READWRITE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_APROTOCOL, param_spec);
+
+    param_spec = g_param_spec_int("interface", "interface index",
+                                  "Interface use for resolver",
+                                  AVAHI_IF_UNSPEC,
+                                  G_MAXINT,
+                                  AVAHI_IF_UNSPEC,
+                                  G_PARAM_READWRITE |
+                                  G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_IFINDEX, param_spec);
+
+    param_spec = g_param_spec_string("name", "service name",
+                                     "name to resolve",
+                                     NULL,
+                                     G_PARAM_READWRITE |
+                                     G_PARAM_STATIC_NAME |
+                                     G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_NAME, param_spec);
+
+    param_spec = g_param_spec_string("type", "service type",
+                                     "Service type to browse for",
+                                     NULL,
+                                     G_PARAM_READWRITE |
+                                     G_PARAM_STATIC_NAME |
+                                     G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_TYPE, param_spec);
+
+    param_spec = g_param_spec_string("domain", "service domain",
+                                     "Domain to browse in",
+                                     NULL,
+                                     G_PARAM_READWRITE |
+                                     G_PARAM_STATIC_NAME |
+                                     G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_DOMAIN, param_spec);
+
+    param_spec = g_param_spec_enum("flags", "Lookup flags for the resolver",
+                                   "Resolver lookup flags",
+                                   GA_TYPE_PROTOCOL,
+                                   GA_LOOKUP_NO_FLAGS,
+                                   G_PARAM_READWRITE |
+                                   G_PARAM_STATIC_NAME |
+                                   G_PARAM_STATIC_BLURB);
+    g_object_class_install_property(object_class, PROP_FLAGS, param_spec);
+}
+
+void ga_service_resolver_dispose(GObject * object) {
+    GaServiceResolver *self = GA_SERVICE_RESOLVER(object);
+    GaServiceResolverPrivate *priv = GA_SERVICE_RESOLVER_GET_PRIVATE(self);
+
+    if (priv->dispose_has_run)
+        return;
+
+    priv->dispose_has_run = TRUE;
+
+    if (priv->client)
+        g_object_unref(priv->client);
+    priv->client = NULL;
+
+    if (priv->resolver)
+        avahi_service_resolver_free(priv->resolver);
+    priv->resolver = NULL;
+
+    /* release any references held by the object here */
+
+    if (G_OBJECT_CLASS(ga_service_resolver_parent_class)->dispose)
+        G_OBJECT_CLASS(ga_service_resolver_parent_class)->dispose(object);
+}
+
+void ga_service_resolver_finalize(GObject * object) {
+    GaServiceResolver *self = GA_SERVICE_RESOLVER(object);
+    GaServiceResolverPrivate *priv = GA_SERVICE_RESOLVER_GET_PRIVATE(self);
+
+    /* free any data held directly by the object here */
+    g_free(priv->name);
+    priv->name = NULL;
+
+    g_free(priv->type);
+    priv->type = NULL;
+
+    g_free(priv->domain);
+    priv->domain = NULL;
+
+    G_OBJECT_CLASS(ga_service_resolver_parent_class)->finalize(object);
+}
+
+static void _avahi_service_resolver_cb(AVAHI_GCC_UNUSED AvahiServiceResolver * resolver,
+                           AvahiIfIndex interface,
+                           AvahiProtocol protocol,
+                           AvahiResolverEvent event,
+                           const char *name, const char *type,
+                           const char *domain, const char *host_name,
+                           const AvahiAddress * a,
+                           uint16_t port,
+                           AvahiStringList * txt,
+                           AvahiLookupResultFlags flags, void *userdata) {
+    GaServiceResolver *self = GA_SERVICE_RESOLVER(userdata);
+    GaServiceResolverPrivate *priv = GA_SERVICE_RESOLVER_GET_PRIVATE(self);
+
+    switch (event) {
+        case AVAHI_RESOLVER_FOUND:{
+                /* FIXME: Double check if this address is always the same */
+                priv->address = *a;
+                priv->port = port;
+                g_signal_emit(self, signals[FOUND], 0,
+                              interface, protocol,
+                              name, type,
+                              domain, host_name, a, port, txt, flags);
+                break;
+            }
+        case AVAHI_RESOLVER_FAILURE:{
+                GError *error;
+                int aerrno = avahi_client_errno(priv->client->avahi_client);
+                error = g_error_new(GA_ERRORS, aerrno,
+                                    "Resolving failed: %s",
+                                    avahi_strerror(aerrno));
+                g_signal_emit(self, signals[FAILURE], 0, error);
+                g_error_free(error);
+                break;
+            }
+    }
+}
+
+
+GaServiceResolver *ga_service_resolver_new(AvahiIfIndex interface,
+                                           AvahiProtocol protocol,
+                                           const gchar * name,
+                                           const gchar * type,
+                                           const gchar * domain,
+                                           AvahiProtocol address_protocol,
+                                           GaLookupFlags flags) {
+    return g_object_new(GA_TYPE_SERVICE_RESOLVER, "interface", interface,
+                        "protocol", protocol, "name", name, "type", type,
+                        "domain", domain, "aprotocol", address_protocol,
+                        "flags", flags, NULL);
+}
+
+gboolean ga_service_resolver_attach(GaServiceResolver * resolver,
+                           GaClient * client, GError ** error) {
+    GaServiceResolverPrivate *priv =
+            GA_SERVICE_RESOLVER_GET_PRIVATE(resolver);
+
+    g_assert(client != NULL);
+    g_object_ref(client);
+
+    priv->client = client;
+
+    priv->resolver = avahi_service_resolver_new(client->avahi_client,
+                                                priv->interface,
+                                                priv->protocol,
+                                                priv->name,
+                                                priv->type, priv->domain,
+                                                priv->aprotocol,
+                                                priv->flags,
+                                                _avahi_service_resolver_cb,
+                                                resolver);
+    if (priv->resolver == NULL) {
+        if (error != NULL) {
+            int aerrno = avahi_client_errno(client->avahi_client);
+            *error = g_error_new(GA_ERRORS, aerrno,
+                                 "Attaching group failed: %s",
+                                 avahi_strerror(aerrno));
+        }
+/*         printf("Failed to add resolver\n"); */
+        return FALSE;
+    }
+    return TRUE;
+}
+
+gboolean ga_service_resolver_get_address(GaServiceResolver * resolver,
+                                AvahiAddress * address, uint16_t * port) {
+    GaServiceResolverPrivate *priv =
+            GA_SERVICE_RESOLVER_GET_PRIVATE(resolver);
+    if (priv->port == 0) {
+/*         printf("PORT == 0\n"); */
+        return FALSE;
+    }
+
+    *address = priv->address;
+    *port = priv->port;
+    return TRUE;
+}
diff --git a/avahi-glib/ga-service-resolver.h b/avahi-glib/ga-service-resolver.h
new file mode 100644 (file)
index 0000000..b01f524
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * ga-service-resolver.h - Header for GaServiceResolver
+ * Copyright (C) 2005 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GA_SERVICE_RESOLVER_H__
+#define __GA_SERVICE_RESOLVER_H__
+
+
+#include <avahi-common/address.h>
+
+#include <glib-object.h>
+#include "ga-client.h"
+#include "ga-enums.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GaServiceResolver GaServiceResolver;
+typedef struct _GaServiceResolverClass GaServiceResolverClass;
+
+struct _GaServiceResolverClass {
+    GObjectClass parent_class;
+};
+
+struct _GaServiceResolver {
+    GObject parent;
+};
+
+GType ga_service_resolver_get_type(void);
+
+/* TYPE MACROS */
+#define GA_TYPE_SERVICE_RESOLVER \
+  (ga_service_resolver_get_type())
+#define GA_SERVICE_RESOLVER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GA_TYPE_SERVICE_RESOLVER, GaServiceResolver))
+#define GA_SERVICE_RESOLVER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GA_TYPE_SERVICE_RESOLVER, GaServiceResolverClass))
+#define IS_GA_SERVICE_RESOLVER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GA_TYPE_SERVICE_RESOLVER))
+#define IS_GA_SERVICE_RESOLVER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GA_TYPE_SERVICE_RESOLVER))
+#define GA_SERVICE_RESOLVER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GA_TYPE_SERVICE_RESOLVER, GaServiceResolverClass))
+
+GaServiceResolver *ga_service_resolver_new(AvahiIfIndex interface,
+                                           AvahiProtocol protocol,
+                                           const gchar * name,
+                                           const gchar * type,
+                                           const gchar * domain,
+                                           AvahiProtocol address_protocol,
+                                           GaLookupFlags flags);
+
+gboolean
+ga_service_resolver_attach(GaServiceResolver * resolver,
+                           GaClient * client, GError ** error);
+
+gboolean
+ga_service_resolver_get_address(GaServiceResolver * resolver,
+                                AvahiAddress * address, uint16_t * port);
+G_END_DECLS
+#endif /* #ifndef __GA_SERVICE_RESOLVER_H__ */