Updated Finnish translation
[rhythmbox.git] / daapsharing / rb-daap-mdns-browser-avahi.c
blob2c1f914b935ddc34819e78496d218fcad860de1d
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
4 * Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "config.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
28 #include <glib.h>
29 #include <glib/gi18n.h>
30 #include <glib-object.h>
32 #ifdef HAVE_AVAHI_0_6
33 #include <avahi-client/lookup.h>
34 #include <avahi-client/publish.h>
35 #endif
36 #include <avahi-client/client.h>
37 #include <avahi-common/error.h>
38 #include <avahi-glib/glib-malloc.h>
39 #include <avahi-glib/glib-watch.h>
41 #include "rb-daap-mdns-browser.h"
42 #include "rb-marshal.h"
43 #include "rb-debug.h"
45 #ifdef HAVE_AVAHI_0_5
46 #define AVAHI_ADDRESS_STR_MAX (40) /* IPv6 Max = 4*8 + 7 + 1 for NUL */
47 #endif
49 static void rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass *klass);
50 static void rb_daap_mdns_browser_init (RBDaapMdnsBrowser *browser);
51 static void rb_daap_mdns_browser_finalize (GObject *object);
53 #define RB_DAAP_MDNS_BROWSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_MDNS_BROWSER, RBDaapMdnsBrowserPrivate))
55 struct RBDaapMdnsBrowserPrivate
57 AvahiClient *client;
58 AvahiGLibPoll *poll;
59 AvahiServiceBrowser *service_browser;
61 GSList *resolvers;
64 enum {
65 SERVICE_ADDED,
66 SERVICE_REMOVED,
67 LAST_SIGNAL
70 enum {
71 PROP_0
74 static GObjectClass *parent_class = NULL;
75 static guint signals [LAST_SIGNAL] = { 0, };
77 G_DEFINE_TYPE (RBDaapMdnsBrowser, rb_daap_mdns_browser, G_TYPE_OBJECT)
79 static gpointer browser_object = NULL;
81 GQuark
82 rb_daap_mdns_browser_error_quark (void)
84 static GQuark quark = 0;
85 if (!quark)
86 quark = g_quark_from_static_string ("rb_daap_mdns_browser_error");
88 return quark;
91 static void
92 client_cb (AvahiClient *client,
93 AvahiClientState state,
94 RBDaapMdnsBrowser *browser)
96 /* Called whenever the client or server state changes */
98 switch (state) {
99 #ifdef HAVE_AVAHI_0_6
100 case AVAHI_CLIENT_FAILURE:
102 g_warning ("Client failure: %s\n", avahi_strerror (avahi_client_errno (client)));
103 break;
104 #endif
105 default:
106 break;
110 static void
111 avahi_client_init (RBDaapMdnsBrowser *browser)
113 int error = 0;
115 avahi_set_allocator (avahi_glib_allocator ());
117 browser->priv->poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT);
119 if (! browser->priv->poll) {
120 rb_debug ("Unable to create AvahiGlibPoll object for mDNS");
123 #ifdef HAVE_AVAHI_0_5
124 browser->priv->client = avahi_client_new (avahi_glib_poll_get (browser->priv->poll),
125 (AvahiClientCallback) client_cb,
126 browser,
127 &error);
128 #endif
129 #ifdef HAVE_AVAHI_0_6
131 AvahiClientFlags flags;
132 flags = 0;
134 browser->priv->client = avahi_client_new (avahi_glib_poll_get (browser->priv->poll),
135 flags,
136 (AvahiClientCallback)client_cb,
137 browser,
138 &error);
140 #endif
143 static void
144 resolve_cb (AvahiServiceResolver *service_resolver,
145 AvahiIfIndex interface,
146 AvahiProtocol protocol,
147 AvahiResolverEvent event,
148 const char *service_name,
149 const char *type,
150 const char *domain,
151 const char *host_name,
152 const AvahiAddress *address,
153 uint16_t port,
154 AvahiStringList *text,
155 #ifdef HAVE_AVAHI_0_6
156 AvahiLookupResultFlags flags,
157 #endif
158 RBDaapMdnsBrowser *browser)
160 if (event == AVAHI_RESOLVER_FOUND) {
161 char *name = NULL;
162 char host [AVAHI_ADDRESS_STR_MAX];
163 gboolean pp = FALSE;
165 if (text) {
166 AvahiStringList *l;
168 for (l = text; l != NULL; l = l->next) {
169 size_t size;
170 char *key;
171 char *value;
172 int ret;
174 ret = avahi_string_list_get_pair (l, &key, &value, &size);
175 if (ret != 0 || key == NULL) {
176 continue;
179 if (strcmp (key, "Password") == 0) {
180 if (size >= 4 && strncmp (value, "true", 4) == 0) {
181 pp = TRUE;
183 } else if (strcmp (key, "Machine Name") == 0) {
184 name = g_strdup (value);
187 g_free (key);
188 g_free (value);
192 if (name == NULL) {
193 name = g_strdup (service_name);
196 avahi_address_snprint (host, AVAHI_ADDRESS_STR_MAX, address);
198 g_signal_emit (browser,
199 signals [SERVICE_ADDED],
201 service_name,
202 name,
203 host,
204 port,
205 pp);
207 g_free (name);
210 browser->priv->resolvers = g_slist_remove (browser->priv->resolvers, service_resolver);
211 avahi_service_resolver_free (service_resolver);
214 static gboolean
215 rb_daap_mdns_browser_resolve (RBDaapMdnsBrowser *browser,
216 const char *name)
218 AvahiServiceResolver *service_resolver;
220 service_resolver = avahi_service_resolver_new (browser->priv->client,
221 AVAHI_IF_UNSPEC,
222 AVAHI_PROTO_INET,
223 name,
224 "_daap._tcp",
225 NULL,
226 AVAHI_PROTO_UNSPEC,
227 #ifdef HAVE_AVAHI_0_6
229 #endif
230 (AvahiServiceResolverCallback)resolve_cb,
231 browser);
232 if (service_resolver == NULL) {
233 rb_debug ("Error starting mDNS resolving using AvahiServiceResolver");
234 return FALSE;
237 browser->priv->resolvers = g_slist_prepend (browser->priv->resolvers, service_resolver);
239 return TRUE;
242 static void
243 browser_add_service (RBDaapMdnsBrowser *browser,
244 const char *service_name)
246 rb_daap_mdns_browser_resolve (browser, service_name);
249 static void
250 browser_remove_service (RBDaapMdnsBrowser *browser,
251 const char *service_name)
253 g_signal_emit (browser, signals [SERVICE_REMOVED], 0, service_name);
256 static void
257 browse_cb (AvahiServiceBrowser *service_browser,
258 AvahiIfIndex interface,
259 AvahiProtocol protocol,
260 AvahiBrowserEvent event,
261 const char *name,
262 const char *type,
263 const char *domain,
264 #ifdef HAVE_AVAHI_0_6
265 AvahiLookupResultFlags flags,
266 #endif
267 RBDaapMdnsBrowser *browser)
269 gboolean local;
271 #ifdef HAVE_AVAHI_0_5
272 local = avahi_client_is_service_local (browser->priv->client, interface, protocol, name, type, domain);
273 #endif
274 #ifdef HAVE_AVAHI_0_6
275 local = ((flags & AVAHI_LOOKUP_RESULT_LOCAL) != 0);
276 #endif
277 if (local) {
278 rb_debug ("Ignoring local service %s", name);
279 return;
282 if (event == AVAHI_BROWSER_NEW) {
283 browser_add_service (browser, name);
284 } else if (event == AVAHI_BROWSER_REMOVE) {
285 browser_remove_service (browser, name);
289 gboolean
290 rb_daap_mdns_browser_start (RBDaapMdnsBrowser *browser,
291 GError **error)
293 if (browser->priv->client == NULL) {
294 g_set_error (error,
295 RB_DAAP_MDNS_BROWSER_ERROR,
296 RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING,
297 "%s",
298 _("MDNS service is not running"));
299 return FALSE;
301 if (browser->priv->service_browser != NULL) {
302 g_set_error (error,
303 RB_DAAP_MDNS_BROWSER_ERROR,
304 RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
305 "%s",
306 _("Browser already active"));
307 return FALSE;
310 browser->priv->service_browser = avahi_service_browser_new (browser->priv->client,
311 AVAHI_IF_UNSPEC,
312 AVAHI_PROTO_UNSPEC,
313 "_daap._tcp",
314 NULL,
315 #ifdef HAVE_AVAHI_0_6
317 #endif
318 (AvahiServiceBrowserCallback)browse_cb,
319 browser);
320 if (browser->priv->service_browser == NULL) {
321 rb_debug ("Error starting mDNS discovery using AvahiServiceBrowser");
322 g_set_error (error,
323 RB_DAAP_MDNS_BROWSER_ERROR,
324 RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
325 "%s",
326 _("Unable to activate browser"));
328 return FALSE;
331 return TRUE;
334 gboolean
335 rb_daap_mdns_browser_stop (RBDaapMdnsBrowser *browser,
336 GError **error)
338 if (browser->priv->client == NULL) {
339 g_set_error (error,
340 RB_DAAP_MDNS_BROWSER_ERROR,
341 RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING,
342 "%s",
343 _("MDNS service is not running"));
344 return FALSE;
346 if (browser->priv->service_browser == NULL) {
347 g_set_error (error,
348 RB_DAAP_MDNS_BROWSER_ERROR,
349 RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
350 "%s",
351 _("Browser is not active"));
352 return FALSE;
355 avahi_service_browser_free (browser->priv->service_browser);
356 browser->priv->service_browser = NULL;
358 return TRUE;
361 static void
362 rb_daap_mdns_browser_set_property (GObject *object,
363 guint prop_id,
364 const GValue *value,
365 GParamSpec *pspec)
367 switch (prop_id) {
368 default:
369 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370 break;
374 static void
375 rb_daap_mdns_browser_get_property (GObject *object,
376 guint prop_id,
377 GValue *value,
378 GParamSpec *pspec)
380 switch (prop_id) {
381 default:
382 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
383 break;
387 static void
388 rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass *klass)
390 GObjectClass *object_class = G_OBJECT_CLASS (klass);
392 parent_class = g_type_class_peek_parent (klass);
394 object_class->finalize = rb_daap_mdns_browser_finalize;
395 object_class->get_property = rb_daap_mdns_browser_get_property;
396 object_class->set_property = rb_daap_mdns_browser_set_property;
398 signals [SERVICE_ADDED] =
399 g_signal_new ("service-added",
400 G_TYPE_FROM_CLASS (object_class),
401 G_SIGNAL_RUN_LAST,
402 G_STRUCT_OFFSET (RBDaapMdnsBrowserClass, service_added),
403 NULL,
404 NULL,
405 rb_marshal_VOID__STRING_STRING_STRING_UINT_BOOLEAN,
406 G_TYPE_NONE,
407 5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_BOOLEAN);
408 signals [SERVICE_REMOVED] =
409 g_signal_new ("service-removed",
410 G_TYPE_FROM_CLASS (object_class),
411 G_SIGNAL_RUN_LAST,
412 G_STRUCT_OFFSET (RBDaapMdnsBrowserClass, service_removed),
413 NULL,
414 NULL,
415 g_cclosure_marshal_VOID__STRING,
416 G_TYPE_NONE,
417 1, G_TYPE_STRING);
419 g_type_class_add_private (klass, sizeof (RBDaapMdnsBrowserPrivate));
422 static void
423 rb_daap_mdns_browser_init (RBDaapMdnsBrowser *browser)
425 browser->priv = RB_DAAP_MDNS_BROWSER_GET_PRIVATE (browser);
427 avahi_client_init (browser);
430 static void
431 rb_daap_mdns_browser_finalize (GObject *object)
433 RBDaapMdnsBrowser *browser;
435 g_return_if_fail (object != NULL);
436 g_return_if_fail (RB_IS_DAAP_MDNS_BROWSER (object));
438 browser = RB_DAAP_MDNS_BROWSER (object);
440 g_return_if_fail (browser->priv != NULL);
442 if (browser->priv->resolvers) {
443 g_slist_foreach (browser->priv->resolvers,
444 (GFunc)avahi_service_resolver_free,
445 NULL);
446 g_slist_free (browser->priv->resolvers);
449 if (browser->priv->service_browser) {
450 avahi_service_browser_free (browser->priv->service_browser);
453 if (browser->priv->client) {
454 avahi_client_free (browser->priv->client);
457 if (browser->priv->poll) {
458 avahi_glib_poll_free (browser->priv->poll);
461 G_OBJECT_CLASS (parent_class)->finalize (object);
464 RBDaapMdnsBrowser *
465 rb_daap_mdns_browser_new (void)
467 if (browser_object) {
468 g_object_ref (browser_object);
469 } else {
470 browser_object = g_object_new (RB_TYPE_DAAP_MDNS_BROWSER, NULL);
471 g_object_add_weak_pointer (browser_object,
472 (gpointer *) &browser_object);
475 return RB_DAAP_MDNS_BROWSER (browser_object);