/*** 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.1 of the License, or (at your option) any later version. avahi 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 avahi; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <stdarg.h> #include <net/if.h> #include <gtk/gtk.h> #include <avahi-glib/glib-watch.h> #include <avahi-client/client.h> #include <avahi-client/lookup.h> #include <avahi-common/error.h> #include <avahi-common/address.h> #include <avahi-common/domain.h> #include <avahi-common/i18n.h> #include "avahi-ui.h" #if defined(HAVE_GDBM) || defined(HAVE_DBM) #include "../avahi-utils/stdb.h" #endif /* todo: i18n, HIGify */ struct _AuiServiceDialogPrivate { AvahiGLibPoll *glib_poll; AvahiClient *client; AvahiServiceBrowser **browsers; AvahiServiceResolver *resolver; AvahiDomainBrowser *domain_browser; gchar **browse_service_types; gchar *service_type; gchar *domain; gchar *service_name; AvahiProtocol address_family; AvahiAddress address; gchar *host_name; AvahiStringList *txt_data; guint16 port; gboolean resolve_service, resolve_service_done; gboolean resolve_host_name, resolve_host_name_done; GtkWidget *domain_label; GtkWidget *domain_button; GtkWidget *service_tree_view; GtkWidget *service_progress_bar; GtkListStore *service_list_store, *domain_list_store; GHashTable *service_type_names; guint service_pulse_timeout; guint domain_pulse_timeout; guint start_idle; AvahiIfIndex common_interface; AvahiProtocol common_protocol; GtkWidget *domain_dialog; GtkWidget *domain_entry; GtkWidget *domain_tree_view; GtkWidget *domain_progress_bar; GtkWidget *domain_ok_button; gint forward_response_id; }; enum { PROP_0, PROP_BROWSE_SERVICE_TYPES, PROP_DOMAIN, PROP_SERVICE_TYPE, PROP_SERVICE_NAME, PROP_ADDRESS, PROP_PORT, PROP_HOST_NAME, PROP_TXT_DATA, PROP_RESOLVE_SERVICE, PROP_RESOLVE_HOST_NAME, PROP_ADDRESS_FAMILY }; enum { SERVICE_COLUMN_IFACE, SERVICE_COLUMN_PROTO, SERVICE_COLUMN_TYPE, SERVICE_COLUMN_NAME, SERVICE_COLUMN_PRETTY_IFACE, SERVICE_COLUMN_PRETTY_TYPE, N_SERVICE_COLUMNS }; enum { DOMAIN_COLUMN_NAME, DOMAIN_COLUMN_REF, N_DOMAIN_COLUMNS }; static void aui_service_dialog_finalize(GObject *object); static void aui_service_dialog_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void aui_service_dialog_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static int get_default_response(GtkDialog *dlg) { gint ret = GTK_RESPONSE_NONE; if (gtk_window_get_default_widget(GTK_WINDOW(dlg))) /* Use the response of the default widget, if possible */ ret = gtk_dialog_get_response_for_widget(dlg, gtk_window_get_default_widget(GTK_WINDOW(dlg))); if (ret == GTK_RESPONSE_NONE) { /* Fall back to finding the first positive response */ GList *children, *t; gint bad = GTK_RESPONSE_NONE; t = children = gtk_container_get_children(GTK_CONTAINER(gtk_dialog_get_action_area(dlg))); while (t) { GtkWidget *child = t->data; ret = gtk_dialog_get_response_for_widget(dlg, child); if (ret == GTK_RESPONSE_ACCEPT || ret == GTK_RESPONSE_OK || ret == GTK_RESPONSE_YES || ret == GTK_RESPONSE_APPLY) break; if (ret != GTK_RESPONSE_NONE && bad == GTK_RESPONSE_NONE) bad = ret; t = t->next; } g_list_free (children); /* Fall back to finding the first negative response */ if (ret == GTK_RESPONSE_NONE) ret = bad; } return ret; } G_DEFINE_TYPE(AuiServiceDialog, aui_service_dialog, GTK_TYPE_DIALOG) static void aui_service_dialog_class_init(AuiServiceDialogClass *klass) { GObjectClass *object_class; avahi_init_i18n(); object_class = (GObjectClass*) klass; object_class->finalize = aui_service_dialog_finalize; object_class->set_property = aui_service_dialog_set_property; object_class->get_property = aui_service_dialog_get_property; g_object_class_install_property( object_class, PROP_BROWSE_SERVICE_TYPES, g_param_spec_pointer("browse_service_types", _("Browse Service Types"), _("A NULL terminated list of service types to browse for"), G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property( object_class, PROP_DOMAIN, g_param_spec_string("domain", _("Domain"), _("The domain to browse in, or NULL for the default domain"), NULL, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property( object_class, PROP_SERVICE_TYPE, g_param_spec_string("service_type", _("Service Type"), _("The service type of the selected service"), NULL, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property( object_class, PROP_SERVICE_NAME, g_param_spec_string("service_name", _("Service Name"), _("The service name of the selected service"), NULL, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property( object_class, PROP_ADDRESS, g_param_spec_pointer("address", _("Address"), _("The address of the resolved service"), G_PARAM_READABLE)); g_object_class_install_property( object_class, PROP_PORT, g_param_spec_uint("port", _("Port"), _("The IP port number of the resolved service"), 0, 0xFFFF, 0, G_PARAM_READABLE)); g_object_class_install_property( object_class, PROP_HOST_NAME, g_param_spec_string("host_name", _("Host Name"), _("The host name of the resolved service"), NULL, G_PARAM_READABLE)); g_object_class_install_property( object_class, PROP_TXT_DATA, g_param_spec_pointer("txt_data", _("TXT Data"), _("The TXT data of the resolved service"), G_PARAM_READABLE)); g_object_class_install_property( object_class, PROP_RESOLVE_SERVICE, g_param_spec_boolean("resolve_service", _("Resolve Service"), _("Resolve the selected service automatically before returning"), TRUE, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property( object_class, PROP_RESOLVE_HOST_NAME, g_param_spec_boolean("resolve_host_name", _("Resolve Service Host Name"), _("Resolve the host name of the selected service automatically before returning"), TRUE, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property( object_class, PROP_ADDRESS_FAMILY, g_param_spec_int("address_family", _("Address family"), _("The address family for host name resolution"), AVAHI_PROTO_UNSPEC, AVAHI_PROTO_INET6, AVAHI_PROTO_UNSPEC, G_PARAM_READABLE | G_PARAM_WRITABLE)); } GtkWidget *aui_service_dialog_new_valist( const gchar *title, GtkWindow *parent, const gchar *first_button_text, va_list varargs) { const gchar *button_text; gint dr; GtkWidget *w = (GtkWidget*)g_object_new( AUI_TYPE_SERVICE_DIALOG, #if !GTK_CHECK_VERSION (2,21,8) "has-separator", FALSE, #endif "title", title, NULL); if (parent) gtk_window_set_transient_for(GTK_WINDOW(w), parent); button_text = first_button_text; while (button_text) { gint response_id; response_id = va_arg(varargs, gint); gtk_dialog_add_button(GTK_DIALOG(w), button_text, response_id); button_text = va_arg(varargs, const gchar *); } gtk_dialog_set_response_sensitive(GTK_DIALOG(w), GTK_RESPONSE_ACCEPT, FALSE); gtk_dialog_set_response_sensitive(GTK_DIALOG(w), GTK_RESPONSE_OK, FALSE); gtk_dialog_set_response_sensitive(GTK_DIALOG(w), GTK_RESPONSE_YES, FALSE); gtk_dialog_set_response_sensitive(GTK_DIALOG(w), GTK_RESPONSE_APPLY, FALSE); if ((dr = get_default_response(GTK_DIALOG(w))) != GTK_RESPONSE_NONE) gtk_dialog_set_default_response(GTK_DIALOG(w), dr); return w; } GtkWidget* aui_service_dialog_new( const gchar *title, GtkWindow *parent, const gchar *first_button_text, ...) { GtkWidget *w; va_list varargs; va_start(varargs, first_button_text); w = aui_service_dialog_new_valist(title, parent, first_button_text, varargs); va_end(varargs); return w; } static gboolean service_pulse_callback(gpointer data) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(data); gtk_progress_bar_pulse(GTK_PROGRESS_BAR(d->priv->service_progress_bar)); return TRUE; } static gboolean domain_pulse_callback(gpointer data) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(data); gtk_progress_bar_pulse(GTK_PROGRESS_BAR(d->priv->domain_progress_bar)); return TRUE; } static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(userdata); if (state == AVAHI_CLIENT_FAILURE) { GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(d), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Avahi client failure: %s"), avahi_strerror(avahi_client_errno(c))); gtk_dialog_run(GTK_DIALOG(m)); gtk_widget_destroy(m); gtk_dialog_response(GTK_DIALOG(d), GTK_RESPONSE_CANCEL); } } static void resolve_callback( AvahiServiceResolver *r G_GNUC_UNUSED, AvahiIfIndex interface G_GNUC_UNUSED, AvahiProtocol protocol G_GNUC_UNUSED, 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 G_GNUC_UNUSED, void *userdata) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(userdata); switch (event) { case AVAHI_RESOLVER_FOUND: d->priv->resolve_service_done = 1; g_free(d->priv->service_name); d->priv->service_name = g_strdup(name); g_free(d->priv->service_type); d->priv->service_type = g_strdup(type); g_free(d->priv->domain); d->priv->domain = g_strdup(domain); g_free(d->priv->host_name); d->priv->host_name = g_strdup(host_name); d->priv->port = port; avahi_string_list_free(d->priv->txt_data); d->priv->txt_data = avahi_string_list_copy(txt); if (a) { d->priv->resolve_host_name_done = 1; d->priv->address = *a; } gtk_dialog_response(GTK_DIALOG(d), d->priv->forward_response_id); break; case AVAHI_RESOLVER_FAILURE: { GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(d), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Avahi resolver failure: %s"), avahi_strerror(avahi_client_errno(d->priv->client))); gtk_dialog_run(GTK_DIALOG(m)); gtk_widget_destroy(m); gtk_dialog_response(GTK_DIALOG(d), GTK_RESPONSE_CANCEL); break; } } } static void browse_callback( AvahiServiceBrowser *b G_GNUC_UNUSED, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(userdata); switch (event) { case AVAHI_BROWSER_NEW: { gchar *ifs; const gchar *pretty_type = NULL; char ifname[IFNAMSIZ]; GtkTreeIter iter; GtkTreeSelection *selection; if (!(if_indextoname(interface, ifname))) g_snprintf(ifname, sizeof(ifname), "%i", interface); ifs = g_strdup_printf("%s %s", ifname, protocol == AVAHI_PROTO_INET ? "IPv4" : "IPv6"); if (d->priv->service_type_names) pretty_type = g_hash_table_lookup (d->priv->service_type_names, type); if (!pretty_type) { #if defined(HAVE_GDBM) || defined(HAVE_DBM) pretty_type = stdb_lookup(type); #else pretty_type = type; #endif } gtk_list_store_append(d->priv->service_list_store, &iter); gtk_list_store_set(d->priv->service_list_store, &iter, SERVICE_COLUMN_IFACE, interface, SERVICE_COLUMN_PROTO, protocol, SERVICE_COLUMN_NAME, name, SERVICE_COLUMN_TYPE, type, SERVICE_COLUMN_PRETTY_IFACE, ifs, SERVICE_COLUMN_PRETTY_TYPE, pretty_type, -1); g_free(ifs); if (d->priv->common_protocol == AVAHI_PROTO_UNSPEC) d->priv->common_protocol = protocol; if (d->priv->common_interface == AVAHI_IF_UNSPEC) d->priv->common_interface = interface; if (d->priv->common_interface != interface || d->priv->common_protocol != protocol) { gtk_tree_view_column_set_visible(gtk_tree_view_get_column(GTK_TREE_VIEW(d->priv->service_tree_view), 0), TRUE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(d->priv->service_tree_view), TRUE); } selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(d->priv->service_tree_view)); if (!gtk_tree_selection_get_selected(selection, NULL, NULL)) { if (!d->priv->service_type || !d->priv->service_name || (avahi_domain_equal(d->priv->service_type, type) && strcasecmp(d->priv->service_name, name) == 0)) { GtkTreePath *path; gtk_tree_selection_select_iter(selection, &iter); path = gtk_tree_model_get_path(GTK_TREE_MODEL(d->priv->service_list_store), &iter); gtk_tree_view_set_cursor(GTK_TREE_VIEW(d->priv->service_tree_view), path, NULL, FALSE); gtk_tree_path_free(path); } } break; } case AVAHI_BROWSER_REMOVE: { GtkTreeIter iter; gboolean valid; valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(d->priv->service_list_store), &iter); while (valid) { gint _interface, _protocol; gchar *_name, *_type; gboolean found; gtk_tree_model_get(GTK_TREE_MODEL(d->priv->service_list_store), &iter, SERVICE_COLUMN_IFACE, &_interface, SERVICE_COLUMN_PROTO, &_protocol, SERVICE_COLUMN_NAME, &_name, SERVICE_COLUMN_TYPE, &_type, -1); found = _interface == interface && _protocol == protocol && strcasecmp(_name, name) == 0 && avahi_domain_equal(_type, type); g_free(_name); if (found) { gtk_list_store_remove(d->priv->service_list_store, &iter); break; } valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(d->priv->service_list_store), &iter); } break; } case AVAHI_BROWSER_FAILURE: { GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(d), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Browsing for service type %s in domain %s failed: %s"), type, domain ? domain : _("n/a"), avahi_strerror(avahi_client_errno(d->priv->client))); gtk_dialog_run(GTK_DIALOG(m)); gtk_widget_destroy(m); /* Fall through */ } case AVAHI_BROWSER_ALL_FOR_NOW: if (d->priv->service_pulse_timeout > 0) { g_source_remove(d->priv->service_pulse_timeout); d->priv->service_pulse_timeout = 0; gtk_widget_hide(d->priv->service_progress_bar); } break; case AVAHI_BROWSER_CACHE_EXHAUSTED: ; } } static void domain_make_default_selection(AuiServiceDialog *d, const gchar *name, GtkTreeIter *iter) { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(d->priv->domain_tree_view)); if (!gtk_tree_selection_get_selected(selection, NULL, NULL)) { if (avahi_domain_equal(gtk_entry_get_text(GTK_ENTRY(d->priv->domain_entry)), name)) { GtkTreePath *path; gtk_tree_selection_select_iter(selection, iter); path = gtk_tree_model_get_path(GTK_TREE_MODEL(d->priv->domain_list_store), iter); gtk_tree_view_set_cursor(GTK_TREE_VIEW(d->priv->domain_tree_view), path, NULL, FALSE); gtk_tree_path_free(path); } } } static void domain_browse_callback( AvahiDomainBrowser *b G_GNUC_UNUSED, AvahiIfIndex interface G_GNUC_UNUSED, AvahiProtocol protocol G_GNUC_UNUSED, AvahiBrowserEvent event, const char *name, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(userdata); switch (event) { case AVAHI_BROWSER_NEW: { GtkTreeIter iter; gboolean found = FALSE, valid; gint ref; valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(d->priv->domain_list_store), &iter); while (valid) { gchar *_name; gtk_tree_model_get(GTK_TREE_MODEL(d->priv->domain_list_store), &iter, DOMAIN_COLUMN_NAME, &_name, DOMAIN_COLUMN_REF, &ref, -1); found = avahi_domain_equal(_name, name); g_free(_name); if (found) break; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(d->priv->domain_list_store), &iter); } if (found) gtk_list_store_set(d->priv->domain_list_store, &iter, DOMAIN_COLUMN_REF, ref + 1, -1); else { gtk_list_store_append(d->priv->domain_list_store, &iter); gtk_list_store_set(d->priv->domain_list_store, &iter, DOMAIN_COLUMN_NAME, name, DOMAIN_COLUMN_REF, 1, -1); } domain_make_default_selection(d, name, &iter); break; } case AVAHI_BROWSER_REMOVE: { gboolean valid; GtkTreeIter iter; valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(d->priv->domain_list_store), &iter); while (valid) { gint ref; gchar *_name; gboolean found; gtk_tree_model_get(GTK_TREE_MODEL(d->priv->domain_list_store), &iter, DOMAIN_COLUMN_NAME, &_name, DOMAIN_COLUMN_REF, &ref, -1); found = avahi_domain_equal(_name, name); g_free(_name); if (found) { if (ref <= 1) gtk_list_store_remove(d->priv->service_list_store, &iter); else gtk_list_store_set(d->priv->domain_list_store, &iter, DOMAIN_COLUMN_REF, ref - 1, -1); break; } valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(d->priv->domain_list_store), &iter); } break; } case AVAHI_BROWSER_FAILURE: { GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(d), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Avahi domain browser failure: %s"), avahi_strerror(avahi_client_errno(d->priv->client))); gtk_dialog_run(GTK_DIALOG(m)); gtk_widget_destroy(m); /* Fall through */ } case AVAHI_BROWSER_ALL_FOR_NOW: if (d->priv->domain_pulse_timeout > 0) { g_source_remove(d->priv->domain_pulse_timeout); d->priv->domain_pulse_timeout = 0; gtk_widget_hide(d->priv->domain_progress_bar); } break; case AVAHI_BROWSER_CACHE_EXHAUSTED: ; } } static const gchar *get_domain_name(AuiServiceDialog *d) { const gchar *domain; g_return_val_if_fail(d, NULL); g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), NULL); if (d->priv->domain) return d->priv->domain; if (!(domain = avahi_client_get_domain_name(d->priv->client))) { GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(d), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to read Avahi domain: %s"), avahi_strerror(avahi_client_errno(d->priv->client))); gtk_dialog_run(GTK_DIALOG(m)); gtk_widget_destroy(m); return NULL; } return domain; } static gboolean start_callback(gpointer data) { int error; AuiServiceDialog *d = AUI_SERVICE_DIALOG(data); gchar **st; AvahiServiceBrowser **sb; unsigned i; const char *domain; d->priv->start_idle = 0; if (!d->priv->browse_service_types || !*d->priv->browse_service_types) { g_warning(_("Browse service type list is empty!")); return FALSE; } if (!d->priv->client) { if (!(d->priv->client = avahi_client_new(avahi_glib_poll_get(d->priv->glib_poll), 0, client_callback, d, &error))) { GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(d), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to connect to Avahi server: %s"), avahi_strerror(error)); gtk_dialog_run(GTK_DIALOG(m)); gtk_widget_destroy(m); gtk_dialog_response(GTK_DIALOG(d), GTK_RESPONSE_CANCEL); return FALSE; } } if (!(domain = get_domain_name(d))) { gtk_dialog_response(GTK_DIALOG(d), GTK_RESPONSE_CANCEL); return FALSE; } g_assert(domain); if (avahi_domain_equal(domain, "local.")) gtk_label_set_markup(GTK_LABEL(d->priv->domain_label), _("Browsing for services on <b>local network</b>:")); else { gchar *t = g_strdup_printf(_("Browsing for services in domain <b>%s</b>:"), domain); gtk_label_set_markup(GTK_LABEL(d->priv->domain_label), t); g_free(t); } if (d->priv->browsers) { for (sb = d->priv->browsers; *sb; sb++) avahi_service_browser_free(*sb); g_free(d->priv->browsers); d->priv->browsers = NULL; } gtk_list_store_clear(GTK_LIST_STORE(d->priv->service_list_store)); d->priv->common_interface = AVAHI_IF_UNSPEC; d->priv->common_protocol = AVAHI_PROTO_UNSPEC; gtk_tree_view_column_set_visible(gtk_tree_view_get_column(GTK_TREE_VIEW(d->priv->service_tree_view), 0), FALSE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(d->priv->service_tree_view), FALSE); gtk_widget_show(d->priv->service_progress_bar); if (d->priv->service_pulse_timeout <= 0) d->priv->service_pulse_timeout = g_timeout_add(100, service_pulse_callback, d); for (i = 0; d->priv->browse_service_types[i]; i++) ; g_assert(i > 0); d->priv->browsers = g_new0(AvahiServiceBrowser*, i+1); for (st = d->priv->browse_service_types, sb = d->priv->browsers; *st; st++, sb++) { if (!(*sb = avahi_service_browser_new(d->priv->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, *st, d->priv->domain, 0, browse_callback, d))) { GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(d), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to create browser for %s: %s"), *st, avahi_strerror(avahi_client_errno(d->priv->client))); gtk_dialog_run(GTK_DIALOG(m)); gtk_widget_destroy(m); gtk_dialog_response(GTK_DIALOG(d), GTK_RESPONSE_CANCEL); return FALSE; } } return FALSE; } static void aui_service_dialog_finalize(GObject *object) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(object); if (d->priv->domain_pulse_timeout > 0) g_source_remove(d->priv->domain_pulse_timeout); if (d->priv->service_pulse_timeout > 0) g_source_remove(d->priv->service_pulse_timeout); if (d->priv->start_idle > 0) g_source_remove(d->priv->start_idle); g_free(d->priv->host_name); g_free(d->priv->domain); g_free(d->priv->service_name); avahi_string_list_free(d->priv->txt_data); g_strfreev(d->priv->browse_service_types); if (d->priv->domain_browser) avahi_domain_browser_free(d->priv->domain_browser); if (d->priv->resolver) avahi_service_resolver_free(d->priv->resolver); if (d->priv->browsers) { AvahiServiceBrowser **sb; for (sb = d->priv->browsers; *sb; sb++) avahi_service_browser_free(*sb); g_free(d->priv->browsers); } if (d->priv->client) avahi_client_free(d->priv->client); if (d->priv->glib_poll) avahi_glib_poll_free(d->priv->glib_poll); if (d->priv->service_list_store) g_object_unref(d->priv->service_list_store); if (d->priv->domain_list_store) g_object_unref(d->priv->domain_list_store); if (d->priv->service_type_names) g_hash_table_unref (d->priv->service_type_names); g_free(d->priv); d->priv = NULL; G_OBJECT_CLASS(aui_service_dialog_parent_class)->finalize(object); } static void service_row_activated_callback(GtkTreeView *tree_view G_GNUC_UNUSED, GtkTreePath *path G_GNUC_UNUSED, GtkTreeViewColumn *column G_GNUC_UNUSED, gpointer user_data) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(user_data); gtk_dialog_response(GTK_DIALOG(d), get_default_response(GTK_DIALOG(d))); } static void service_selection_changed_callback(GtkTreeSelection *selection, gpointer user_data) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(user_data); gboolean b; b = gtk_tree_selection_get_selected(selection, NULL, NULL); gtk_dialog_set_response_sensitive(GTK_DIALOG(d), GTK_RESPONSE_ACCEPT, b); gtk_dialog_set_response_sensitive(GTK_DIALOG(d), GTK_RESPONSE_OK, b); gtk_dialog_set_response_sensitive(GTK_DIALOG(d), GTK_RESPONSE_YES, b); gtk_dialog_set_response_sensitive(GTK_DIALOG(d), GTK_RESPONSE_APPLY, b); } static void response_callback(GtkDialog *dialog, gint response, gpointer user_data) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(user_data); if ((response == GTK_RESPONSE_ACCEPT || response == GTK_RESPONSE_OK || response == GTK_RESPONSE_YES || response == GTK_RESPONSE_APPLY) && ((d->priv->resolve_service && !d->priv->resolve_service_done) || (d->priv->resolve_host_name && !d->priv->resolve_host_name_done))) { GtkTreeIter iter; gint interface, protocol; gchar *name, *type; GdkCursor *cursor; g_signal_stop_emission(dialog, g_signal_lookup("response", gtk_dialog_get_type()), 0); d->priv->forward_response_id = response; if (d->priv->resolver) return; g_return_if_fail(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(d->priv->service_tree_view)), NULL, &iter)); gtk_tree_model_get(GTK_TREE_MODEL(d->priv->service_list_store), &iter, SERVICE_COLUMN_IFACE, &interface, SERVICE_COLUMN_PROTO, &protocol, SERVICE_COLUMN_NAME, &name, SERVICE_COLUMN_TYPE, &type, -1); g_return_if_fail(d->priv->client); gtk_widget_set_sensitive(GTK_WIDGET(dialog), FALSE); cursor = gdk_cursor_new(GDK_WATCH); gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(dialog)), cursor); g_object_unref(G_OBJECT(cursor)); if (!(d->priv->resolver = avahi_service_resolver_new( d->priv->client, interface, protocol, name, type, d->priv->domain, d->priv->address_family, !d->priv->resolve_host_name ? AVAHI_LOOKUP_NO_ADDRESS : 0, resolve_callback, d))) { GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(d), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to create resolver for %s of type %s in domain %s: %s"), name, type, d->priv->domain, avahi_strerror(avahi_client_errno(d->priv->client))); gtk_dialog_run(GTK_DIALOG(m)); gtk_widget_destroy(m); gtk_dialog_response(GTK_DIALOG(d), GTK_RESPONSE_CANCEL); return; } } } static gboolean is_valid_domain_suffix(const gchar *n) { gchar label[AVAHI_LABEL_MAX]; if (!avahi_is_valid_domain_name(n)) return FALSE; if (!avahi_unescape_label(&n, label, sizeof(label))) return FALSE; /* At least one label */ return !!label[0]; } static void domain_row_activated_callback(GtkTreeView *tree_view G_GNUC_UNUSED, GtkTreePath *path G_GNUC_UNUSED, GtkTreeViewColumn *column G_GNUC_UNUSED, gpointer user_data) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(user_data); if (is_valid_domain_suffix(gtk_entry_get_text(GTK_ENTRY(d->priv->domain_entry)))) gtk_dialog_response(GTK_DIALOG(d->priv->domain_dialog), GTK_RESPONSE_ACCEPT); } static void domain_selection_changed_callback(GtkTreeSelection *selection G_GNUC_UNUSED, gpointer user_data) { GtkTreeIter iter; AuiServiceDialog *d = AUI_SERVICE_DIALOG(user_data); gchar *name; g_return_if_fail(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(d->priv->domain_tree_view)), NULL, &iter)); gtk_tree_model_get(GTK_TREE_MODEL(d->priv->domain_list_store), &iter, DOMAIN_COLUMN_NAME, &name, -1); gtk_entry_set_text(GTK_ENTRY(d->priv->domain_entry), name); } static void domain_entry_changed_callback(GtkEditable *editable G_GNUC_UNUSED, gpointer user_data) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(user_data); gtk_widget_set_sensitive(d->priv->domain_ok_button, is_valid_domain_suffix(gtk_entry_get_text(GTK_ENTRY(d->priv->domain_entry)))); } static void domain_button_clicked(GtkButton *button G_GNUC_UNUSED, gpointer user_data) { GtkWidget *vbox, *vbox2, *scrolled_window; GtkTreeSelection *selection; GtkCellRenderer *renderer; GtkTreeViewColumn *column; AuiServiceDialog *d = AUI_SERVICE_DIALOG(user_data); AuiServiceDialogPrivate *p = d->priv; const gchar *domain; GtkTreeIter iter; g_return_if_fail(!p->domain_dialog); g_return_if_fail(!p->domain_browser); if (!(domain = get_domain_name(d))) { gtk_dialog_response(GTK_DIALOG(d), GTK_RESPONSE_CANCEL); return; } if (!(p->domain_browser = avahi_domain_browser_new(p->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, NULL, AVAHI_DOMAIN_BROWSER_BROWSE, 0, domain_browse_callback, d))) { GtkWidget *m = gtk_message_dialog_new(GTK_WINDOW(d), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to create domain browser: %s"), avahi_strerror(avahi_client_errno(p->client))); gtk_dialog_run(GTK_DIALOG(m)); gtk_widget_destroy(m); gtk_dialog_response(GTK_DIALOG(d), GTK_RESPONSE_CANCEL); return; } p->domain_dialog = gtk_dialog_new(); gtk_container_set_border_width(GTK_CONTAINER(p->domain_dialog), 5); gtk_window_set_title(GTK_WINDOW(p->domain_dialog), _("Change domain")); #if !GTK_CHECK_VERSION(2,21,8) gtk_dialog_set_has_separator(GTK_DIALOG(p->domain_dialog), FALSE); #endif vbox = gtk_vbox_new(FALSE, 8); gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(p->domain_dialog))), vbox, TRUE, TRUE, 0); p->domain_entry = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(p->domain_entry), AVAHI_DOMAIN_NAME_MAX); gtk_entry_set_text(GTK_ENTRY(p->domain_entry), domain); gtk_entry_set_activates_default(GTK_ENTRY(p->domain_entry), TRUE); g_signal_connect(p->domain_entry, "changed", G_CALLBACK(domain_entry_changed_callback), d); gtk_box_pack_start(GTK_BOX(vbox), p->domain_entry, FALSE, FALSE, 0); vbox2 = gtk_vbox_new(FALSE, 8); gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0); scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(vbox2), scrolled_window, TRUE, TRUE, 0); p->domain_list_store = gtk_list_store_new(N_DOMAIN_COLUMNS, G_TYPE_STRING, G_TYPE_INT); p->domain_tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(p->domain_list_store)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(p->domain_tree_view), FALSE); g_signal_connect(p->domain_tree_view, "row-activated", G_CALLBACK(domain_row_activated_callback), d); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(p->domain_tree_view)); gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); g_signal_connect(selection, "changed", G_CALLBACK(domain_selection_changed_callback), d); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Service Name"), renderer, "text", DOMAIN_COLUMN_NAME, NULL); gtk_tree_view_column_set_expand(column, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(p->domain_tree_view), column); gtk_tree_view_set_search_column(GTK_TREE_VIEW(p->domain_tree_view), DOMAIN_COLUMN_NAME); gtk_container_add(GTK_CONTAINER(scrolled_window), p->domain_tree_view); p->domain_progress_bar = gtk_progress_bar_new(); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(p->domain_progress_bar), _("Browsing...")); gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(p->domain_progress_bar), 0.1); gtk_box_pack_end(GTK_BOX(vbox2), p->domain_progress_bar, FALSE, FALSE, 0); gtk_dialog_add_button(GTK_DIALOG(p->domain_dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); p->domain_ok_button = GTK_WIDGET(gtk_dialog_add_button(GTK_DIALOG(p->domain_dialog), GTK_STOCK_OK, GTK_RESPONSE_ACCEPT)); gtk_dialog_set_default_response(GTK_DIALOG(p->domain_dialog), GTK_RESPONSE_ACCEPT); gtk_widget_set_sensitive(p->domain_ok_button, is_valid_domain_suffix(gtk_entry_get_text(GTK_ENTRY(p->domain_entry)))); gtk_widget_grab_default(p->domain_ok_button); gtk_widget_grab_focus(p->domain_entry); gtk_window_set_default_size(GTK_WINDOW(p->domain_dialog), 300, 300); gtk_widget_show_all(vbox); gtk_list_store_append(p->domain_list_store, &iter); gtk_list_store_set(p->domain_list_store, &iter, DOMAIN_COLUMN_NAME, "local", DOMAIN_COLUMN_REF, 1, -1); domain_make_default_selection(d, "local", &iter); p->domain_pulse_timeout = g_timeout_add(100, domain_pulse_callback, d); if (gtk_dialog_run(GTK_DIALOG(p->domain_dialog)) == GTK_RESPONSE_ACCEPT) aui_service_dialog_set_domain(d, gtk_entry_get_text(GTK_ENTRY(p->domain_entry))); gtk_widget_destroy(p->domain_dialog); p->domain_dialog = NULL; if (p->domain_pulse_timeout > 0) { g_source_remove(p->domain_pulse_timeout); p->domain_pulse_timeout = 0; } avahi_domain_browser_free(p->domain_browser); p->domain_browser = NULL; } static void aui_service_dialog_init(AuiServiceDialog *d) { GtkWidget *vbox, *vbox2, *scrolled_window; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *selection; AuiServiceDialogPrivate *p; p = d->priv = g_new(AuiServiceDialogPrivate, 1); p->host_name = NULL; p->domain = NULL; p->service_name = NULL; p->service_type = NULL; p->txt_data = NULL; p->browse_service_types = NULL; memset(&p->address, 0, sizeof(p->address)); p->port = 0; p->resolve_host_name = p->resolve_service = TRUE; p->resolve_host_name_done = p->resolve_service_done = FALSE; p->address_family = AVAHI_PROTO_UNSPEC; p->glib_poll = NULL; p->client = NULL; p->browsers = NULL; p->resolver = NULL; p->domain_browser = NULL; p->service_pulse_timeout = 0; p->domain_pulse_timeout = 0; p->start_idle = 0; p->common_interface = AVAHI_IF_UNSPEC; p->common_protocol = AVAHI_PROTO_UNSPEC; p->domain_dialog = NULL; p->domain_entry = NULL; p->domain_tree_view = NULL; p->domain_progress_bar = NULL; p->domain_ok_button = NULL; p->forward_response_id = GTK_RESPONSE_NONE; p->service_list_store = p->domain_list_store = NULL; p->service_type_names = NULL; gtk_widget_push_composite_child(); gtk_container_set_border_width(GTK_CONTAINER(d), 5); vbox = gtk_vbox_new(FALSE, 8); gtk_container_set_border_width(GTK_CONTAINER(vbox), 8); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(d))), vbox, TRUE, TRUE, 0); p->domain_label = gtk_label_new(_("Initializing...")); gtk_label_set_ellipsize(GTK_LABEL(p->domain_label), TRUE); gtk_misc_set_alignment(GTK_MISC(p->domain_label), 0, 0.5); gtk_box_pack_start(GTK_BOX(vbox), p->domain_label, FALSE, FALSE, 0); vbox2 = gtk_vbox_new(FALSE, 8); gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0); scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(vbox2), scrolled_window, TRUE, TRUE, 0); p->service_list_store = gtk_list_store_new(N_SERVICE_COLUMNS, G_TYPE_INT, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); p->service_tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(p->service_list_store)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(p->service_tree_view), FALSE); g_signal_connect(p->service_tree_view, "row-activated", G_CALLBACK(service_row_activated_callback), d); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(p->service_tree_view)); gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); g_signal_connect(selection, "changed", G_CALLBACK(service_selection_changed_callback), d); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Location"), renderer, "text", SERVICE_COLUMN_PRETTY_IFACE, NULL); gtk_tree_view_column_set_visible(column, FALSE); gtk_tree_view_append_column(GTK_TREE_VIEW(p->service_tree_view), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", SERVICE_COLUMN_NAME, NULL); gtk_tree_view_column_set_expand(column, TRUE); gtk_tree_view_append_column(GTK_TREE_VIEW(p->service_tree_view), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Type"), renderer, "text", SERVICE_COLUMN_PRETTY_TYPE, NULL); gtk_tree_view_column_set_visible(column, FALSE); gtk_tree_view_append_column(GTK_TREE_VIEW(p->service_tree_view), column); gtk_tree_view_set_search_column(GTK_TREE_VIEW(p->service_tree_view), SERVICE_COLUMN_NAME); gtk_container_add(GTK_CONTAINER(scrolled_window), p->service_tree_view); p->service_progress_bar = gtk_progress_bar_new(); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(p->service_progress_bar), _("Browsing...")); gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(p->service_progress_bar), 0.1); gtk_box_pack_end(GTK_BOX(vbox2), p->service_progress_bar, FALSE, FALSE, 0); p->domain_button = gtk_button_new_with_mnemonic(_("_Domain...")); gtk_button_set_image(GTK_BUTTON(p->domain_button), gtk_image_new_from_stock(GTK_STOCK_NETWORK, GTK_ICON_SIZE_BUTTON)); g_signal_connect(p->domain_button, "clicked", G_CALLBACK(domain_button_clicked), d); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(d))), p->domain_button, FALSE, TRUE, 0); gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(gtk_dialog_get_action_area(GTK_DIALOG(d))), p->domain_button, TRUE); gtk_widget_show(p->domain_button); gtk_dialog_set_default_response(GTK_DIALOG(d), GTK_RESPONSE_ACCEPT); gtk_widget_grab_focus(p->service_tree_view); gtk_window_set_default_size(GTK_WINDOW(d), 400, 300); gtk_widget_show_all(vbox); gtk_widget_pop_composite_child(); p->glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT); p->service_pulse_timeout = g_timeout_add(100, service_pulse_callback, d); p->start_idle = g_idle_add(start_callback, d); g_signal_connect(d, "response", G_CALLBACK(response_callback), d); } static void restart_browsing(AuiServiceDialog *d) { g_return_if_fail(AUI_IS_SERVICE_DIALOG(d)); if (d->priv->start_idle <= 0) d->priv->start_idle = g_idle_add(start_callback, d); } void aui_service_dialog_set_browse_service_types(AuiServiceDialog *d, const char *type, ...) { va_list ap; const char *t; unsigned u; g_return_if_fail(AUI_IS_SERVICE_DIALOG(d)); g_return_if_fail(type); g_strfreev(d->priv->browse_service_types); va_start(ap, type); for (u = 1; va_arg(ap, const char *); u++) ; va_end(ap); d->priv->browse_service_types = g_new0(gchar*, u+1); d->priv->browse_service_types[0] = g_strdup(type); va_start(ap, type); for (u = 1; (t = va_arg(ap, const char*)); u++) d->priv->browse_service_types[u] = g_strdup(t); va_end(ap); if (d->priv->browse_service_types[0] && d->priv->browse_service_types[1]) { /* Multiple service types, show type-column */ gtk_tree_view_column_set_visible(gtk_tree_view_get_column(GTK_TREE_VIEW(d->priv->service_tree_view), 2), TRUE); } restart_browsing(d); } void aui_service_dialog_set_browse_service_typesv(AuiServiceDialog *d, const char *const*types) { g_return_if_fail(AUI_IS_SERVICE_DIALOG(d)); g_return_if_fail(types); g_return_if_fail(*types); g_strfreev(d->priv->browse_service_types); d->priv->browse_service_types = g_strdupv((char**) types); if (d->priv->browse_service_types[0] && d->priv->browse_service_types[1]) { /* Multiple service types, show type-column */ gtk_tree_view_column_set_visible(gtk_tree_view_get_column(GTK_TREE_VIEW(d->priv->service_tree_view), 2), TRUE); } restart_browsing(d); } const gchar*const* aui_service_dialog_get_browse_service_types(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), NULL); return (const char* const*) d->priv->browse_service_types; } void aui_service_dialog_set_service_type_name(AuiServiceDialog *d, const gchar *type, const gchar *name) { GtkTreeModel *m = NULL; GtkTreeIter iter; g_return_if_fail(AUI_IS_SERVICE_DIALOG(d)); g_return_if_fail(NULL != type); g_return_if_fail(NULL != name); if (NULL == d->priv->service_type_names) d->priv->service_type_names = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert(d->priv->service_type_names, g_strdup(type), g_strdup(name)); if (d->priv->service_list_store) m = GTK_TREE_MODEL(d->priv->service_list_store); if (m && gtk_tree_model_get_iter_first(m, &iter)) { do { char *stored_type = NULL; gtk_tree_model_get(m, &iter, SERVICE_COLUMN_TYPE, &stored_type, -1); if (stored_type && g_str_equal(stored_type, type)) gtk_list_store_set(d->priv->service_list_store, &iter, SERVICE_COLUMN_PRETTY_TYPE, name, -1); } while (gtk_tree_model_iter_next(m, &iter)); } } void aui_service_dialog_set_domain(AuiServiceDialog *d, const char *domain) { g_return_if_fail(AUI_IS_SERVICE_DIALOG(d)); g_return_if_fail(!domain || is_valid_domain_suffix(domain)); g_free(d->priv->domain); d->priv->domain = domain ? avahi_normalize_name_strdup(domain) : NULL; restart_browsing(d); } const char* aui_service_dialog_get_domain(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), NULL); return d->priv->domain; } void aui_service_dialog_set_service_name(AuiServiceDialog *d, const char *name) { g_return_if_fail(AUI_IS_SERVICE_DIALOG(d)); g_free(d->priv->service_name); d->priv->service_name = g_strdup(name); } const char* aui_service_dialog_get_service_name(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), NULL); return d->priv->service_name; } void aui_service_dialog_set_service_type(AuiServiceDialog *d, const char*stype) { g_return_if_fail(AUI_IS_SERVICE_DIALOG(d)); g_free(d->priv->service_type); d->priv->service_type = g_strdup(stype); } const char* aui_service_dialog_get_service_type(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), NULL); return d->priv->service_type; } const AvahiAddress* aui_service_dialog_get_address(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), NULL); g_return_val_if_fail(d->priv->resolve_service_done && d->priv->resolve_host_name_done, NULL); return &d->priv->address; } guint16 aui_service_dialog_get_port(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), 0); g_return_val_if_fail(d->priv->resolve_service_done, 0); return d->priv->port; } const char* aui_service_dialog_get_host_name(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), NULL); g_return_val_if_fail(d->priv->resolve_service_done, NULL); return d->priv->host_name; } const AvahiStringList *aui_service_dialog_get_txt_data(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), NULL); g_return_val_if_fail(d->priv->resolve_service_done, NULL); return d->priv->txt_data; } void aui_service_dialog_set_resolve_service(AuiServiceDialog *d, gboolean resolve) { g_return_if_fail(AUI_IS_SERVICE_DIALOG(d)); d->priv->resolve_service = resolve; } gboolean aui_service_dialog_get_resolve_service(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), FALSE); return d->priv->resolve_service; } void aui_service_dialog_set_resolve_host_name(AuiServiceDialog *d, gboolean resolve) { g_return_if_fail(AUI_IS_SERVICE_DIALOG(d)); d->priv->resolve_host_name = resolve; } gboolean aui_service_dialog_get_resolve_host_name(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), FALSE); return d->priv->resolve_host_name; } void aui_service_dialog_set_address_family(AuiServiceDialog *d, AvahiProtocol proto) { g_return_if_fail(AUI_IS_SERVICE_DIALOG(d)); g_return_if_fail(proto == AVAHI_PROTO_UNSPEC || proto == AVAHI_PROTO_INET || proto == AVAHI_PROTO_INET6); d->priv->address_family = proto; } AvahiProtocol aui_service_dialog_get_address_family(AuiServiceDialog *d) { g_return_val_if_fail(AUI_IS_SERVICE_DIALOG(d), AVAHI_PROTO_UNSPEC); return d->priv->address_family; } static void aui_service_dialog_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(object); switch (prop_id) { case PROP_BROWSE_SERVICE_TYPES: aui_service_dialog_set_browse_service_typesv(d, g_value_get_pointer(value)); break; case PROP_DOMAIN: aui_service_dialog_set_domain(d, g_value_get_string(value)); break; case PROP_SERVICE_TYPE: aui_service_dialog_set_service_type(d, g_value_get_string(value)); break; case PROP_SERVICE_NAME: aui_service_dialog_set_service_name(d, g_value_get_string(value)); break; case PROP_RESOLVE_SERVICE: aui_service_dialog_set_resolve_service(d, g_value_get_boolean(value)); break; case PROP_RESOLVE_HOST_NAME: aui_service_dialog_set_resolve_host_name(d, g_value_get_boolean(value)); break; case PROP_ADDRESS_FAMILY: aui_service_dialog_set_address_family(d, g_value_get_int(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void aui_service_dialog_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { AuiServiceDialog *d = AUI_SERVICE_DIALOG(object); switch (prop_id) { case PROP_BROWSE_SERVICE_TYPES: g_value_set_pointer(value, (gpointer) aui_service_dialog_get_browse_service_types(d)); break; case PROP_DOMAIN: g_value_set_string(value, aui_service_dialog_get_domain(d)); break; case PROP_SERVICE_TYPE: g_value_set_string(value, aui_service_dialog_get_service_type(d)); break; case PROP_SERVICE_NAME: g_value_set_string(value, aui_service_dialog_get_service_name(d)); break; case PROP_ADDRESS: g_value_set_pointer(value, (gpointer) aui_service_dialog_get_address(d)); break; case PROP_PORT: g_value_set_uint(value, aui_service_dialog_get_port(d)); break; case PROP_HOST_NAME: g_value_set_string(value, aui_service_dialog_get_host_name(d)); break; case PROP_TXT_DATA: g_value_set_pointer(value, (gpointer) aui_service_dialog_get_txt_data(d)); break; case PROP_RESOLVE_SERVICE: g_value_set_boolean(value, aui_service_dialog_get_resolve_service(d)); break; case PROP_RESOLVE_HOST_NAME: g_value_set_boolean(value, aui_service_dialog_get_resolve_host_name(d)); break; case PROP_ADDRESS_FAMILY: g_value_set_int(value, aui_service_dialog_get_address_family(d)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } }