udapted vi.po
[rhythmbox.git] / daapsharing / rb-daap-mdns-browser-howl.c
blob0b22fae273d576094467334ca836884dafe4a8e4
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 #include <libgnomevfs/gnome-vfs-address.h>
33 #include <libgnomevfs/gnome-vfs-resolve.h>
35 /* stupid howl includes howl_config.h */
36 #undef PACKAGE
37 #undef VERSION
38 #include <howl.h>
40 #include "rb-daap-mdns-browser.h"
41 #include "rb-marshal.h"
42 #include "rb-debug.h"
44 static void rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass *klass);
45 static void rb_daap_mdns_browser_init (RBDaapMdnsBrowser *browser);
46 static void rb_daap_mdns_browser_finalize (GObject *object);
48 #define RB_DAAP_MDNS_BROWSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_MDNS_BROWSER, RBDaapMdnsBrowserPrivate))
50 struct RBDaapMdnsBrowserPrivate
52 sw_discovery *discovery;
53 sw_discovery_oid *oid;
55 GnomeVFSAddress *local_address;
56 guint watch_id;
57 GSList *resolvers;
60 enum {
61 SERVICE_ADDED,
62 SERVICE_REMOVED,
63 LAST_SIGNAL
66 enum {
67 PROP_0
70 static guint signals [LAST_SIGNAL] = { 0, };
72 G_DEFINE_TYPE (RBDaapMdnsBrowser, rb_daap_mdns_browser, G_TYPE_OBJECT)
74 static gpointer browser_object = NULL;
76 GQuark
77 rb_daap_mdns_browser_error_quark (void)
79 static GQuark quark = 0;
80 if (!quark)
81 quark = g_quark_from_static_string ("rb_daap_mdns_browser_error");
83 return quark;
86 static gboolean
87 howl_in_cb (GIOChannel *io_channel,
88 GIOCondition condition,
89 RBDaapMdnsBrowser *browser)
91 sw_salt salt;
93 if (sw_discovery_salt (*browser->priv->discovery, &salt) == SW_OKAY) {
94 sw_salt_lock (salt);
95 sw_discovery_read_socket (*browser->priv->discovery);
96 sw_salt_unlock (salt);
99 return TRUE;
102 static void
103 howl_client_init (RBDaapMdnsBrowser *browser)
105 sw_result result;
106 int fd;
107 GIOChannel *channel;
109 browser->priv->discovery = g_new0 (sw_discovery, 1);
110 result = sw_discovery_init (browser->priv->discovery);
112 if (result != SW_OKAY) {
113 g_free (browser->priv->discovery);
114 browser->priv->discovery = NULL;
115 return;
118 fd = sw_discovery_socket (*browser->priv->discovery);
120 channel = g_io_channel_unix_new (fd);
121 browser->priv->watch_id = g_io_add_watch (channel, G_IO_IN, (GIOFunc)howl_in_cb, browser);
122 g_io_channel_unref (channel);
125 static gboolean
126 host_is_local (RBDaapMdnsBrowser *browser,
127 const char *host)
129 GnomeVFSAddress *remote;
130 gboolean equal;
131 guint32 l_ip;
132 guint32 r_ip;
134 if (browser->priv->local_address == NULL) {
135 g_warning ("Unable to resolve address");
136 return FALSE;
139 remote = gnome_vfs_address_new_from_string (host);
140 if (remote == NULL) {
141 g_warning ("Unable to resolve address for %s", host);
142 return FALSE;
145 l_ip = gnome_vfs_address_get_ipv4 (browser->priv->local_address);
146 r_ip = gnome_vfs_address_get_ipv4 (remote);
147 equal = l_ip == r_ip;
149 /* FIXME: Use this when we can depend on gnome-vfs 2.14 */
150 /*equal = gnome_vfs_address_equal (browser->priv->local_address, remote);*/
152 gnome_vfs_address_free (remote);
154 return equal;
157 static void
158 set_local_address (RBDaapMdnsBrowser *browser)
160 char host_name [256];
161 GnomeVFSResolveHandle *rh;
162 GnomeVFSAddress *address;
163 GnomeVFSResult res;
165 if (gethostname (host_name, sizeof (host_name)) != 0) {
166 g_warning ("gethostname failed: %s", g_strerror (errno));
167 return;
170 res = gnome_vfs_resolve (host_name, &rh);
172 if (res != GNOME_VFS_OK) {
173 return;
176 address = NULL;
177 while (gnome_vfs_resolve_next_address (rh, &address)) {
178 if (browser->priv->local_address == NULL) {
179 browser->priv->local_address = gnome_vfs_address_dup (address);
181 gnome_vfs_address_free (address);
184 gnome_vfs_resolve_free (rh);
187 static sw_result
188 resolve_cb (sw_discovery discovery,
189 sw_discovery_oid oid,
190 sw_uint32 interface_index,
191 sw_const_string service_name,
192 sw_const_string type,
193 sw_const_string domain,
194 sw_ipv4_address address,
195 sw_port port,
196 sw_octets text_record,
197 sw_ulong text_record_length,
198 RBDaapMdnsBrowser *browser)
200 char *host;
201 char *name;
202 sw_text_record_iterator it;
203 gboolean pp = FALSE;
205 host = g_malloc (16);
206 name = NULL;
208 sw_ipv4_address_name (address, host, 16);
210 /* skip local services */
211 if (host_is_local (browser, host)) {
212 goto done;
215 if (sw_text_record_iterator_init (&it, text_record, text_record_length) == SW_OKAY) {
216 sw_char key [SW_TEXT_RECORD_MAX_LEN];
217 sw_octet val [SW_TEXT_RECORD_MAX_LEN];
218 sw_ulong val_len;
220 while (sw_text_record_iterator_next (it, (char *)key, val, &val_len) == SW_OKAY) {
221 if (strcmp ((char *)key, "Password") == 0) {
222 if (val_len >= 4 && strncmp ((char *)val, "true", 4) == 0) {
223 pp = TRUE;
226 if (strcmp ((char *)key, "Machine Name") == 0) {
227 if (name != NULL)
228 g_free (name);
229 name = g_strdup ((char *)val);
233 sw_text_record_iterator_fina (it);
236 if (name == NULL) {
237 name = g_strdup (service_name);
240 g_signal_emit (browser,
241 signals [SERVICE_ADDED],
243 service_name,
244 name,
245 host,
246 port,
247 pp);
248 done:
249 g_free (host);
250 g_free (name);
252 return SW_OKAY;
255 static gboolean
256 rb_daap_mdns_browser_resolve (RBDaapMdnsBrowser *browser,
257 const char *name)
259 sw_result result;
260 sw_discovery_oid oid;
262 result = sw_discovery_resolve (*browser->priv->discovery,
264 name,
265 "_daap._tcp",
266 "local",
267 (sw_discovery_resolve_reply) resolve_cb,
268 (sw_opaque) browser,
269 (sw_discovery_oid *) &oid);
271 return TRUE;
274 static void
275 browser_add_service (RBDaapMdnsBrowser *browser,
276 const char *service_name)
278 rb_daap_mdns_browser_resolve (browser, service_name);
281 static void
282 browser_remove_service (RBDaapMdnsBrowser *browser,
283 const char *service_name)
285 g_signal_emit (browser, signals [SERVICE_REMOVED], 0, service_name);
288 static sw_result
289 browse_cb (sw_discovery discovery,
290 sw_discovery_oid oid,
291 sw_discovery_browse_status status,
292 sw_uint32 interface_index,
293 sw_const_string name,
294 sw_const_string type,
295 sw_const_string domain,
296 RBDaapMdnsBrowser *browser)
298 if (status == SW_DISCOVERY_BROWSE_ADD_SERVICE) {
299 browser_add_service (browser, name);
300 } else if (status == SW_DISCOVERY_BROWSE_REMOVE_SERVICE) {
301 browser_remove_service (browser, name);
304 return SW_OKAY;
307 gboolean
308 rb_daap_mdns_browser_start (RBDaapMdnsBrowser *browser,
309 GError **error)
311 sw_result result;
313 if (browser->priv->discovery == NULL) {
314 g_set_error (error,
315 RB_DAAP_MDNS_BROWSER_ERROR,
316 RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING,
317 "%s",
318 _("MDNS service is not running"));
319 return FALSE;
322 if (browser->priv->oid != NULL) {
323 g_set_error (error,
324 RB_DAAP_MDNS_BROWSER_ERROR,
325 RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
326 "%s",
327 _("Browser already active"));
328 return FALSE;
331 browser->priv->oid = g_new0 (sw_discovery_oid, 1);
333 result = sw_discovery_browse (*browser->priv->discovery,
335 "_daap._tcp",
336 "local",
337 (sw_discovery_browse_reply) browse_cb,
338 (sw_opaque) browser,
339 (sw_discovery_oid *) browser->priv->oid);
341 if (result != SW_OKAY) {
342 rb_debug ("Error starting mDNS discovery using Howl");
343 g_set_error (error,
344 RB_DAAP_MDNS_BROWSER_ERROR,
345 RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
346 "%s",
347 _("Unable to activate browser"));
349 return FALSE;
352 return TRUE;
355 gboolean
356 rb_daap_mdns_browser_stop (RBDaapMdnsBrowser *browser,
357 GError **error)
359 if (browser->priv->discovery == NULL) {
360 g_set_error (error,
361 RB_DAAP_MDNS_BROWSER_ERROR,
362 RB_DAAP_MDNS_BROWSER_ERROR_NOT_RUNNING,
363 "%s",
364 _("MDNS service is not running"));
365 return FALSE;
367 if (browser->priv->oid == NULL) {
368 g_set_error (error,
369 RB_DAAP_MDNS_BROWSER_ERROR,
370 RB_DAAP_MDNS_BROWSER_ERROR_FAILED,
371 "%s",
372 _("Browser is not active"));
373 return FALSE;
377 sw_discovery_cancel (*browser->priv->discovery, *browser->priv->oid);
379 g_free (browser->priv->oid);
380 browser->priv->oid = NULL;
382 return TRUE;
385 static void
386 rb_daap_mdns_browser_set_property (GObject *object,
387 guint prop_id,
388 const GValue *value,
389 GParamSpec *pspec)
391 switch (prop_id) {
392 default:
393 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
394 break;
398 static void
399 rb_daap_mdns_browser_get_property (GObject *object,
400 guint prop_id,
401 GValue *value,
402 GParamSpec *pspec)
404 switch (prop_id) {
405 default:
406 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
407 break;
411 static void
412 rb_daap_mdns_browser_class_init (RBDaapMdnsBrowserClass *klass)
414 GObjectClass *object_class = G_OBJECT_CLASS (klass);
416 object_class->finalize = rb_daap_mdns_browser_finalize;
417 object_class->get_property = rb_daap_mdns_browser_get_property;
418 object_class->set_property = rb_daap_mdns_browser_set_property;
420 signals [SERVICE_ADDED] =
421 g_signal_new ("service-added",
422 G_TYPE_FROM_CLASS (object_class),
423 G_SIGNAL_RUN_LAST,
424 G_STRUCT_OFFSET (RBDaapMdnsBrowserClass, service_added),
425 NULL,
426 NULL,
427 rb_marshal_VOID__STRING_STRING_STRING_UINT_BOOLEAN,
428 G_TYPE_NONE,
429 5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_BOOLEAN);
430 signals [SERVICE_REMOVED] =
431 g_signal_new ("service-removed",
432 G_TYPE_FROM_CLASS (object_class),
433 G_SIGNAL_RUN_LAST,
434 G_STRUCT_OFFSET (RBDaapMdnsBrowserClass, service_removed),
435 NULL,
436 NULL,
437 g_cclosure_marshal_VOID__STRING,
438 G_TYPE_NONE,
439 1, G_TYPE_STRING);
441 g_type_class_add_private (klass, sizeof (RBDaapMdnsBrowserPrivate));
444 static void
445 rb_daap_mdns_browser_init (RBDaapMdnsBrowser *browser)
447 browser->priv = RB_DAAP_MDNS_BROWSER_GET_PRIVATE (browser);
449 set_local_address (browser);
451 howl_client_init (browser);
454 static void
455 resolver_free (sw_discovery_oid *oid,
456 RBDaapMdnsBrowser *browser)
458 sw_discovery_cancel (*browser->priv->discovery,
459 *oid);
460 g_free (oid);
463 static void
464 rb_daap_mdns_browser_finalize (GObject *object)
466 RBDaapMdnsBrowser *browser;
468 g_return_if_fail (object != NULL);
469 g_return_if_fail (RB_IS_DAAP_MDNS_BROWSER (object));
471 browser = RB_DAAP_MDNS_BROWSER (object);
473 g_return_if_fail (browser->priv != NULL);
475 if (browser->priv->oid) {
476 rb_daap_mdns_browser_stop (browser, NULL);
479 if (browser->priv->resolvers) {
480 g_slist_foreach (browser->priv->resolvers,
481 (GFunc)resolver_free,
482 browser);
483 g_slist_free (browser->priv->resolvers);
486 if (browser->priv->discovery) {
487 sw_discovery_fina (*browser->priv->discovery);
488 g_free (browser->priv->discovery);
491 if (browser->priv->watch_id > 0) {
492 g_source_remove (browser->priv->watch_id);
495 if (browser->priv->local_address) {
496 gnome_vfs_address_free (browser->priv->local_address);
499 G_OBJECT_CLASS (rb_daap_mdns_browser_parent_class)->finalize (object);
502 RBDaapMdnsBrowser *
503 rb_daap_mdns_browser_new (void)
505 if (browser_object) {
506 g_object_ref (browser_object);
507 } else {
508 browser_object = g_object_new (RB_TYPE_DAAP_MDNS_BROWSER, NULL);
509 g_object_add_weak_pointer (browser_object,
510 (gpointer *) &browser_object);
513 return RB_DAAP_MDNS_BROWSER (browser_object);