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.
28 #include <glib/gi18n.h>
29 #include <glib-object.h>
31 /* stupid howl includes howl_config.h */
36 #include "rb-daap-mdns-publisher.h"
39 static void rb_daap_mdns_publisher_class_init (RBDaapMdnsPublisherClass
*klass
);
40 static void rb_daap_mdns_publisher_init (RBDaapMdnsPublisher
*publisher
);
41 static void rb_daap_mdns_publisher_finalize (GObject
*object
);
43 #define RB_DAAP_MDNS_PUBLISHER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_MDNS_PUBLISHER, RBDaapMdnsPublisherPrivate))
45 struct RBDaapMdnsPublisherPrivate
47 sw_discovery
*discovery
;
48 sw_discovery_oid
*oid
;
54 gboolean password_required
;
67 static guint signals
[LAST_SIGNAL
] = { 0, };
69 G_DEFINE_TYPE (RBDaapMdnsPublisher
, rb_daap_mdns_publisher
, G_TYPE_OBJECT
)
71 static gpointer publisher_object
= NULL
;
74 rb_daap_mdns_publisher_error_quark (void)
76 static GQuark quark
= 0;
78 quark
= g_quark_from_static_string ("rb_daap_mdns_publisher_error");
84 howl_in_cb (GIOChannel
*io_channel
,
85 GIOCondition condition
,
86 RBDaapMdnsPublisher
*publisher
)
90 if (sw_discovery_salt (*publisher
->priv
->discovery
, &salt
) == SW_OKAY
) {
92 sw_discovery_read_socket (*publisher
->priv
->discovery
);
93 sw_salt_unlock (salt
);
100 howl_client_init (RBDaapMdnsPublisher
*publisher
)
106 publisher
->priv
->discovery
= g_new0 (sw_discovery
, 1);
107 result
= sw_discovery_init (publisher
->priv
->discovery
);
109 if (result
!= SW_OKAY
) {
110 g_free (publisher
->priv
->discovery
);
111 publisher
->priv
->discovery
= NULL
;
115 fd
= sw_discovery_socket (*publisher
->priv
->discovery
);
117 channel
= g_io_channel_unix_new (fd
);
118 publisher
->priv
->watch_id
= g_io_add_watch (channel
, G_IO_IN
, (GIOFunc
)howl_in_cb
, publisher
);
119 g_io_channel_unref (channel
);
123 publish_cb (sw_discovery discovery
,
124 sw_discovery_oid oid
,
125 sw_discovery_publish_status status
,
126 RBDaapMdnsPublisher
*publisher
)
128 if (status
== SW_DISCOVERY_PUBLISH_STARTED
) {
129 g_signal_emit (publisher
, signals
[PUBLISHED
], 0, publisher
->priv
->name
);
130 } else if (status
== SW_DISCOVERY_PUBLISH_NAME_COLLISION
) {
131 /* This is all well and good, but howl won't report a name collision.
132 * http://lists.porchdogsoft.com/pipermail/howl-users/Week-of-Mon-20041206/000487.html
135 g_warning ("MDNS name collision");
137 g_signal_emit (publisher
, signals
[NAME_COLLISION
], 0, publisher
->priv
->name
);
144 howl_strerror (sw_result result
)
151 case SW_DISCOVERY_E_NO_MEM
:
152 str
= "Out of memory";
153 case SW_DISCOVERY_E_BAD_PARAM
:
154 str
= "Invalid paramater";
155 case SW_DISCOVERY_E_UNKNOWN
:
157 str
= "Unknown error";
164 create_service (RBDaapMdnsPublisher
*publisher
,
167 sw_text_record text_record
;
170 if (sw_text_record_init (&text_record
) != SW_OKAY
) {
171 rb_debug ("Error initializing Howl text record");
173 RB_DAAP_MDNS_PUBLISHER_ERROR
,
174 RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED
,
176 _("Error initializing Howl for publishing"));
180 if (publisher
->priv
->oid
!= NULL
) {
181 rb_daap_mdns_publisher_withdraw (publisher
, NULL
);
184 publisher
->priv
->oid
= g_new0 (sw_discovery_oid
, 1);
186 sw_text_record_add_key_and_string_value (text_record
,
188 publisher
->priv
->password_required
? "true" : "false");
190 result
= sw_discovery_publish (*publisher
->priv
->discovery
,
192 publisher
->priv
->name
,
196 publisher
->priv
->port
,
197 sw_text_record_bytes (text_record
),
198 sw_text_record_len (text_record
),
199 (sw_discovery_publish_reply
) publish_cb
,
200 (sw_opaque
) publisher
,
201 (sw_discovery_oid
*) publisher
->priv
->oid
);
203 sw_text_record_fina (text_record
);
205 if (result
!= SW_OKAY
) {
206 rb_debug ("Error starting mDNS publish with Howl: %s", howl_strerror (result
));
208 RB_DAAP_MDNS_PUBLISHER_ERROR
,
209 RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED
,
211 _("Error initializing Howl for publishing"),
212 howl_strerror (result
));
220 refresh_service (RBDaapMdnsPublisher
*publisher
,
223 return create_service (publisher
, error
);
227 rb_daap_mdns_publisher_publish (RBDaapMdnsPublisher
*publisher
,
230 gboolean password_required
,
233 if (publisher
->priv
->discovery
== NULL
) {
235 RB_DAAP_MDNS_PUBLISHER_ERROR
,
236 RB_DAAP_MDNS_PUBLISHER_ERROR_NOT_RUNNING
,
238 _("The howl MDNS service is not running"));
242 rb_daap_mdns_publisher_set_name (publisher
, name
, NULL
);
243 rb_daap_mdns_publisher_set_port (publisher
, port
, NULL
);
244 rb_daap_mdns_publisher_set_password_required (publisher
, password_required
, NULL
);
246 /* special case: the _set_ functions have updated the existing entry group */
247 if (publisher
->priv
->oid
!= NULL
) {
251 return create_service (publisher
, error
);
255 rb_daap_mdns_publisher_withdraw (RBDaapMdnsPublisher
*publisher
,
258 if (publisher
->priv
->discovery
== NULL
) {
260 RB_DAAP_MDNS_PUBLISHER_ERROR
,
261 RB_DAAP_MDNS_PUBLISHER_ERROR_NOT_RUNNING
,
263 _("The howl MDNS service is not running"));
267 if (publisher
->priv
->oid
== NULL
) {
269 RB_DAAP_MDNS_PUBLISHER_ERROR
,
270 RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED
,
272 _("The MDNS service is not published"));
276 sw_discovery_cancel (*publisher
->priv
->discovery
, *publisher
->priv
->oid
);
278 g_free (publisher
->priv
->oid
);
279 publisher
->priv
->oid
= NULL
;
285 rb_daap_mdns_publisher_set_name (RBDaapMdnsPublisher
*publisher
,
289 g_return_val_if_fail (publisher
!= NULL
, FALSE
);
291 g_free (publisher
->priv
->name
);
292 publisher
->priv
->name
= g_strdup (name
);
294 if (publisher
->priv
->oid
) {
295 refresh_service (publisher
, error
);
301 rb_daap_mdns_publisher_set_port (RBDaapMdnsPublisher
*publisher
,
305 g_return_val_if_fail (publisher
!= NULL
, FALSE
);
307 publisher
->priv
->port
= port
;
309 if (publisher
->priv
->oid
) {
310 refresh_service (publisher
, error
);
316 rb_daap_mdns_publisher_set_password_required (RBDaapMdnsPublisher
*publisher
,
320 g_return_val_if_fail (publisher
!= NULL
, FALSE
);
322 publisher
->priv
->password_required
= required
;
324 if (publisher
->priv
->oid
) {
325 refresh_service (publisher
, error
);
332 rb_daap_mdns_publisher_set_property (GObject
*object
,
339 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
345 rb_daap_mdns_publisher_get_property (GObject
*object
,
352 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
358 rb_daap_mdns_publisher_class_init (RBDaapMdnsPublisherClass
*klass
)
360 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
362 object_class
->finalize
= rb_daap_mdns_publisher_finalize
;
363 object_class
->get_property
= rb_daap_mdns_publisher_get_property
;
364 object_class
->set_property
= rb_daap_mdns_publisher_set_property
;
366 signals
[PUBLISHED
] =
367 g_signal_new ("published",
368 G_TYPE_FROM_CLASS (object_class
),
370 G_STRUCT_OFFSET (RBDaapMdnsPublisherClass
, published
),
373 g_cclosure_marshal_VOID__STRING
,
376 signals
[NAME_COLLISION
] =
377 g_signal_new ("name-collision",
378 G_TYPE_FROM_CLASS (object_class
),
380 G_STRUCT_OFFSET (RBDaapMdnsPublisherClass
, name_collision
),
383 g_cclosure_marshal_VOID__STRING
,
387 g_type_class_add_private (klass
, sizeof (RBDaapMdnsPublisherPrivate
));
391 rb_daap_mdns_publisher_init (RBDaapMdnsPublisher
*publisher
)
393 publisher
->priv
= RB_DAAP_MDNS_PUBLISHER_GET_PRIVATE (publisher
);
395 howl_client_init (publisher
);
399 rb_daap_mdns_publisher_finalize (GObject
*object
)
401 RBDaapMdnsPublisher
*publisher
;
403 g_return_if_fail (object
!= NULL
);
404 g_return_if_fail (RB_IS_DAAP_MDNS_PUBLISHER (object
));
406 publisher
= RB_DAAP_MDNS_PUBLISHER (object
);
408 g_return_if_fail (publisher
->priv
!= NULL
);
410 if (publisher
->priv
->oid
) {
411 rb_daap_mdns_publisher_withdraw (publisher
, NULL
);
414 if (publisher
->priv
->discovery
) {
415 sw_discovery_fina (*publisher
->priv
->discovery
);
416 g_free (publisher
->priv
->discovery
);
419 if (publisher
->priv
->watch_id
> 0) {
420 g_source_remove (publisher
->priv
->watch_id
);
423 g_free (publisher
->priv
->name
);
425 G_OBJECT_CLASS (rb_daap_mdns_publisher_parent_class
)->finalize (object
);
428 RBDaapMdnsPublisher
*
429 rb_daap_mdns_publisher_new (void)
431 if (publisher_object
) {
432 g_object_ref (publisher_object
);
434 publisher_object
= g_object_new (RB_TYPE_DAAP_MDNS_PUBLISHER
, NULL
);
435 g_object_add_weak_pointer (publisher_object
,
436 (gpointer
*) &publisher_object
);
439 return RB_DAAP_MDNS_PUBLISHER (publisher_object
);