1 /*
2  * rb-daap-plugin.c
3  *
4  * Copyright (C) 2006 James Livingston <doclivingston@gmail.com>
5  * Copyright (C) 2008 Alban Crequy <alban.crequy@collabora.co.uk>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * The Rhythmbox authors hereby grant permission for non-GPL compatible
13  * GStreamer plugins to be used and distributed together with GStreamer
14  * and Rhythmbox. This permission is above and beyond the permissions granted
15  * by the GPL license by which Rhythmbox is covered. If you modify this code
16  * you may extend this exception to your version of the code, but you are not
17  * obligated to do so. If you do not wish to do so, delete this exception
18  * statement from your version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, see <http://www.gnu.org/licenses/>.
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32 
33 #include <string.h>
34 #include <glib.h>
35 #include <glib/gi18n-lib.h>
36 #include <gmodule.h>
37 #include <gtk/gtk.h>
38 #include <gio/gio.h>
39 
40 #include <libsoup/soup.h>
41 
42 #include <libpeas-gtk/peas-gtk.h>
43 
44 #include "rb-plugin-macros.h"
45 #include "rb-daap-plugin.h"
46 #include "rb-debug.h"
47 #include "rb-shell.h"
48 #include "rb-dialog.h"
49 #include "rb-file-helpers.h"
50 #include "rb-builder-helpers.h"
51 #include "rb-uri-dialog.h"
52 #include "rb-display-page-group.h"
53 #include "rb-application.h"
54 
55 #include "rb-daap-container-record.h"
56 #include "rb-daap-record-factory.h"
57 #include "rb-daap-record.h"
58 #include "rb-daap-source.h"
59 #include "rb-daap-sharing.h"
60 #include "rb-daap-src.h"
61 #include "rb-dacp-pairing-page.h"
62 #include "rb-dacp-player.h"
63 #include "rb-dmap-container-db-adapter.h"
64 #include "rb-rhythmdb-dmap-db-adapter.h"
65 #include "rb-rhythmdb-query-model-dmap-db-adapter.h"
66 
67 #include <libdmapsharing/dmap.h>
68 
69 #define DAAP_DBUS_PATH	"/org/gnome/Rhythmbox3/DAAP"
70 #define DAAP_DBUS_IFACE "org.gnome.Rhythmbox3.DAAP"
71 
72 static const char *rb_daap_dbus_iface =
73 "<node>"
74 "  <interface name='org.gnome.Rhythmbox3.DAAP'>"
75 "    <method name='AddDAAPSource'>"
76 "     <arg type='s' name='service_name'/>"
77 "      <arg type='s' name='host'/>"
78 "      <arg type='u' name='port'/>"
79 "    </method>"
80 "    <method name='RemoveDAAPSource'>"
81 "      <arg type='s' name='service_name'/>"
82 "    </method>"
83 "  </interface>"
84 "</node>";
85 
86 struct _RBDaapPlugin
87 {
88 	PeasExtensionBase parent;
89 
90 	GtkBuilder *builder;
91 	GtkWidget *preferences;
92 	gboolean sharing;
93 	gboolean shutdown;
94 
95 	GSimpleAction *new_share_action;
96 
97 	DMAPMdnsBrowser *mdns_browser;
98 
99 	DACPShare *dacp_share;
100 
101 	GHashTable *source_lookup;
102 
103 	GSettings *settings;
104 	GSettings *dacp_settings;
105 
106 	GDBusConnection *bus;
107 	guint dbus_intf_id;
108 };
109 
110 struct _RBDaapPluginClass
111 {
112 	PeasExtensionBaseClass parent;
113 };
114 
115 
116 G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module);
117 
118 static void rb_daap_plugin_init (RBDaapPlugin *plugin);
119 
120 static void new_share_action_cb (GSimpleAction *, GVariant *, gpointer);
121 
122 static void start_browsing (RBDaapPlugin *plugin);
123 static void stop_browsing (RBDaapPlugin *plugin);
124 static void settings_changed_cb (GSettings *settings,
125 				 const char *key,
126 				 RBDaapPlugin *plugin);
127 static void dacp_settings_changed_cb (GSettings *settings,
128 				      const char *key,
129 				      RBDaapPlugin *plugin);
130 static void libdmapsharing_debug (const char *domain,
131 				  GLogLevelFlags level,
132 				  const char *message,
133 				  gpointer data);
134 
135 static void register_daap_dbus_iface (RBDaapPlugin *plugin);
136 static void unregister_daap_dbus_iface (RBDaapPlugin *plugin);
137 
138 static void peas_gtk_configurable_iface_init (PeasGtkConfigurableInterface *iface);
139 
140 RB_DEFINE_PLUGIN(RB_TYPE_DAAP_PLUGIN,
141 		 RBDaapPlugin,
142 		 rb_daap_plugin,
143 		 (G_IMPLEMENT_INTERFACE_DYNAMIC (PEAS_GTK_TYPE_CONFIGURABLE,
144 						peas_gtk_configurable_iface_init)))
145 
146 static void
rb_daap_plugin_init(RBDaapPlugin * plugin)147 rb_daap_plugin_init (RBDaapPlugin *plugin)
148 {
149 	GSettings *daap_settings;
150 
151 	rb_debug ("RBDaapPlugin initialising");
152 	rb_daap_src_set_plugin (G_OBJECT (plugin));
153 
154 	plugin->settings = g_settings_new ("org.gnome.rhythmbox.sharing");
155 
156 	daap_settings = g_settings_new ("org.gnome.rhythmbox.plugins.daap");
157 	plugin->dacp_settings = g_settings_get_child (daap_settings, "dacp");
158 	g_object_unref (daap_settings);
159 
160 	rb_register_gst_plugin ();
161 }
162 
163 static void
impl_activate(PeasActivatable * bplugin)164 impl_activate (PeasActivatable *bplugin)
165 {
166 	RBDaapPlugin *plugin = RB_DAAP_PLUGIN (bplugin);
167 	gboolean no_registration;
168 	RBShell *shell;
169 	GApplication *app;
170 
171 	plugin->shutdown = FALSE;
172 
173 	g_log_set_handler ("libdmapsharing",
174 			    G_LOG_LEVEL_MASK,
175 			    libdmapsharing_debug,
176 			    NULL);
177 
178 	g_object_get (plugin, "object", &shell, NULL);
179 
180 	g_signal_connect_object (plugin->settings, "changed", G_CALLBACK (settings_changed_cb), plugin, 0);
181 
182 	g_signal_connect_object (plugin->dacp_settings, "changed", G_CALLBACK (dacp_settings_changed_cb), plugin, 0);
183 
184 	if (g_settings_get_boolean (plugin->settings, "enable-browsing")) {
185 		start_browsing (plugin);
186 	}
187 
188 	app = g_application_get_default ();
189 	plugin->new_share_action = g_simple_action_new ("daap-new-share", NULL);
190 	g_signal_connect (plugin->new_share_action, "activate", G_CALLBACK (new_share_action_cb), plugin);
191 	g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (plugin->new_share_action));
192 
193 	rb_application_add_plugin_menu_item (RB_APPLICATION (app),
194 					     "display-page-add",
195 					     "daap-new-share",
196 					     g_menu_item_new (_("Connect to DAAP share..."), "app.daap-new-share"));
197 
198 	/*
199 	 * Don't use daap when the no-registration flag is set.
200 	 * This flag is only used to run multiple instances at the same time, and
201 	 * sharing from two instances would be silly
202 	 */
203 	g_object_get (shell, "no-registration", &no_registration, NULL);
204 	plugin->sharing = !no_registration;
205 	if (plugin->sharing)
206 		rb_daap_sharing_init (shell);
207 
208 	plugin->dacp_share = rb_daap_create_dacp_share (G_OBJECT (plugin));
209 	if (g_settings_get_boolean (plugin->dacp_settings, "enable-remote")) {
210 		dacp_share_start_lookup (plugin->dacp_share);
211 	}
212 
213 	register_daap_dbus_iface (plugin);
214 
215 	g_object_unref (shell);
216 }
217 
218 static void
impl_deactivate(PeasActivatable * bplugin)219 impl_deactivate	(PeasActivatable *bplugin)
220 {
221 	RBDaapPlugin *plugin = RB_DAAP_PLUGIN (bplugin);
222 	RBShell *shell;
223 
224 	rb_debug ("Shutting down DAAP plugin");
225 
226 	g_object_get (plugin, "object", &shell, NULL);
227 
228 	unregister_daap_dbus_iface (plugin);
229 	plugin->shutdown = TRUE;
230 
231 	rb_application_remove_plugin_menu_item (RB_APPLICATION (g_application_get_default ()),
232 						"display-page-add",
233 						"daap-new-share");
234 	if (plugin->sharing)
235 		rb_daap_sharing_shutdown (shell);
236 
237 	if (plugin->mdns_browser) {
238 		stop_browsing (plugin);
239 	}
240 
241 	if (plugin->settings) {
242 		g_object_unref (plugin->settings);
243 		plugin->settings = NULL;
244 	}
245 
246 	g_object_unref (plugin->dacp_share);
247 
248 	if (plugin->preferences) {
249 		gtk_widget_destroy (plugin->preferences);
250 		plugin->preferences = NULL;
251 	}
252 
253 	if (plugin->builder) {
254 		g_object_unref (plugin->builder);
255 		plugin->builder = NULL;
256 	}
257 
258 	if (plugin->bus) {
259 		g_object_unref (plugin->bus);
260 		plugin->bus = NULL;
261 	}
262 
263 	g_object_unref (shell);
264 }
265 
266 /* DAAP share icons */
267 
268 GIcon *
rb_daap_plugin_get_icon(RBDaapPlugin * plugin,gboolean password_protected,gboolean connected)269 rb_daap_plugin_get_icon (RBDaapPlugin *plugin,
270 			 gboolean password_protected,
271 			 gboolean connected)
272 {
273 	if (connected || (password_protected == FALSE)) {
274 		return g_themed_icon_new ("folder-remote-symbolic");
275 	} else {
276 		return g_themed_icon_new ("dialog-password-symbolic");
277 	}
278 }
279 
280 /* mDNS browsing */
281 
282 static RBSource *
find_source_by_service_name(RBDaapPlugin * plugin,const char * service_name)283 find_source_by_service_name (RBDaapPlugin *plugin,
284 			     const char *service_name)
285 {
286 	RBSource *source;
287 
288 	source = g_hash_table_lookup (plugin->source_lookup, service_name);
289 
290 	return source;
291 }
292 
293 static void
mdns_service_added(DMAPMdnsBrowser * browser,DMAPMdnsBrowserService * service,RBDaapPlugin * plugin)294 mdns_service_added (DMAPMdnsBrowser *browser,
295 		    DMAPMdnsBrowserService *service,
296 		    RBDaapPlugin *plugin)
297 {
298 	RBSource *source;
299 	RBShell *shell;
300 
301 	rb_debug ("New service: %s name=%s host=%s port=%u password=%d",
302 		   service->service_name,
303 		   service->name,
304 		   service->host,
305 		   service->port,
306 		   service->password_protected);
307 
308 	source = find_source_by_service_name (plugin, service->service_name);
309 
310 	if (source == NULL) {
311 		g_object_get (plugin, "object", &shell, NULL);
312 
313 		source = rb_daap_source_new (shell,
314 					     G_OBJECT (plugin),
315 					     service->service_name,
316 					     service->name,
317 					     service->host,
318 					     service->port,
319 					     service->password_protected);
320 		g_hash_table_insert (plugin->source_lookup, g_strdup (service->service_name), source);
321 		rb_shell_append_display_page (shell,
322 					      RB_DISPLAY_PAGE (source),
323 					      RB_DISPLAY_PAGE_GROUP_SHARED);
324 
325 		g_object_unref (shell);
326 	} else {
327 		g_object_set (source,
328 			      "name", service->name,
329 			      "host", service->host,
330 			      "port", service->port,
331 			      "password-protected", service->password_protected,
332 			      NULL);
333 	}
334 }
335 
336 static void
mdns_service_removed(DMAPMdnsBrowser * browser,const char * service_name,RBDaapPlugin * plugin)337 mdns_service_removed (DMAPMdnsBrowser *browser,
338 		      const char        *service_name,
339 		      RBDaapPlugin	*plugin)
340 {
341 	RBSource *source;
342 	source = find_source_by_service_name (plugin, service_name);
343 
344 	rb_debug ("DAAP source '%s' went away", service_name);
345 	if (source != NULL) {
346 		g_hash_table_remove (plugin->source_lookup, service_name);
347 	}
348 }
349 
350 static void
remove_source(RBSource * source)351 remove_source (RBSource *source)
352 {
353 	char *service_name;
354 
355 	g_object_get (source, "service-name", &service_name, NULL);
356 	rb_debug ("Removing DAAP source: %s", service_name);
357 
358 	rb_daap_source_disconnect (RB_DAAP_SOURCE (source));
359 	rb_display_page_delete_thyself (RB_DISPLAY_PAGE (source));
360 
361 	g_free (service_name);
362 }
363 
364 static void
start_browsing(RBDaapPlugin * plugin)365 start_browsing (RBDaapPlugin *plugin)
366 {
367 	GError *error;
368 
369 	if (plugin->mdns_browser != NULL) {
370 		return;
371 	}
372 
373 	plugin->mdns_browser = dmap_mdns_browser_new (DMAP_MDNS_BROWSER_SERVICE_TYPE_DAAP);
374 	if (plugin->mdns_browser == NULL) {
375 		g_warning ("Unable to start mDNS browsing");
376 		return;
377 	}
378 
379 	g_signal_connect_object (plugin->mdns_browser,
380 				 "service-added",
381 				 G_CALLBACK (mdns_service_added),
382 				 plugin,
383 				 0);
384 	g_signal_connect_object (plugin->mdns_browser,
385 				 "service-removed",
386 				 G_CALLBACK (mdns_service_removed),
387 				 plugin,
388 				 0);
389 
390 	error = NULL;
391 	dmap_mdns_browser_start (plugin->mdns_browser, &error);
392 	if (error != NULL) {
393 		g_warning ("Unable to start mDNS browsing: %s", error->message);
394 		g_error_free (error);
395 	}
396 
397 	plugin->source_lookup = g_hash_table_new_full ((GHashFunc)g_str_hash,
398 							     (GEqualFunc)g_str_equal,
399 							     (GDestroyNotify)g_free,
400 							     (GDestroyNotify)remove_source);
401 }
402 
403 static void
stop_browsing(RBDaapPlugin * plugin)404 stop_browsing (RBDaapPlugin *plugin)
405 {
406 	GError *error;
407 
408 	if (plugin->mdns_browser == NULL) {
409 		return;
410 	}
411 
412 	rb_debug ("Destroying DAAP source lookup");
413 
414 	g_hash_table_destroy (plugin->source_lookup);
415 	plugin->source_lookup = NULL;
416 
417 	g_signal_handlers_disconnect_by_func (plugin->mdns_browser, mdns_service_added, plugin);
418 	g_signal_handlers_disconnect_by_func (plugin->mdns_browser, mdns_service_removed, plugin);
419 
420 	error = NULL;
421 	dmap_mdns_browser_stop (plugin->mdns_browser, &error);
422 	if (error != NULL) {
423 		g_warning ("Unable to stop mDNS browsing: %s", error->message);
424 		g_error_free (error);
425 	}
426 
427 	g_object_unref (plugin->mdns_browser);
428 	plugin->mdns_browser = NULL;
429 }
430 
431 static void
dacp_settings_changed_cb(GSettings * settings,const char * key,RBDaapPlugin * plugin)432 dacp_settings_changed_cb (GSettings *settings, const char *key, RBDaapPlugin *plugin)
433 {
434 	if (g_strcmp0 (key, "enable-remote") == 0) {
435 		if (g_settings_get_boolean (settings, key)) {
436 			dacp_share_start_lookup (plugin->dacp_share);
437 		} else {
438 			dacp_share_stop_lookup (plugin->dacp_share);
439 		}
440 	}
441 }
442 
443 static void
settings_changed_cb(GSettings * settings,const char * key,RBDaapPlugin * plugin)444 settings_changed_cb (GSettings *settings, const char *key, RBDaapPlugin *plugin)
445 {
446 	if (g_strcmp0 (key, "enable-browsing") == 0) {
447 		if (g_settings_get_boolean (settings, key)) {
448 			start_browsing (plugin);
449 		} else {
450 			stop_browsing (plugin);
451 		}
452 	}
453 }
454 
455 static void
libdmapsharing_debug(const char * domain,GLogLevelFlags level,const char * message,gpointer data)456 libdmapsharing_debug (const char *domain,
457 		      GLogLevelFlags level,
458 		      const char *message,
459 		      gpointer data)
460 {
461 	if ((level & G_LOG_LEVEL_DEBUG) != 0) {
462 		rb_debug ("%s", message);
463 	} else {
464 		g_log_default_handler (domain, level, message, data);
465 	}
466 }
467 
468 static void
new_daap_share_location_added_cb(RBURIDialog * dialog,const char * location,RBDaapPlugin * plugin)469 new_daap_share_location_added_cb (RBURIDialog *dialog,
470 				  const char *location,
471 				  RBDaapPlugin *plugin)
472 {
473 	char *host;
474 	char *p;
475 	int port = 3689;
476 	DMAPMdnsBrowserService service;
477 
478 	host = g_strdup (location);
479 	p = strrchr (host, ':');
480 	if (p != NULL) {
481 		port = strtoul (p+1, NULL, 10);
482 		*p = '\0';
483 	}
484 
485 	rb_debug ("adding manually specified DAAP share at %s", location);
486 	service.name = (char *) location;
487 	service.host = (char *) host;
488 	service.service_name = service.name;
489 	service.port = port;
490 	service.password_protected = FALSE;
491 	mdns_service_added (NULL,
492 			    &service,
493 			    plugin);
494 
495 	g_free (host);
496 
497 }
498 
499 static void
new_daap_share_response_cb(GtkDialog * dialog,int response,gpointer meh)500 new_daap_share_response_cb (GtkDialog *dialog, int response, gpointer meh)
501 {
502 	gtk_widget_destroy (GTK_WIDGET (dialog));
503 }
504 
505 static void
new_share_action_cb(GSimpleAction * action,GVariant * parameter,gpointer data)506 new_share_action_cb (GSimpleAction *action, GVariant *parameter, gpointer data)
507 {
508 	RBDaapPlugin *plugin = RB_DAAP_PLUGIN (data);
509 	GtkWidget *dialog;
510 
511 	dialog = rb_uri_dialog_new (_("New DAAP share"), _("Host:port of DAAP share:"));
512 	g_signal_connect_object (dialog, "location-added",
513 				 G_CALLBACK (new_daap_share_location_added_cb),
514 				 plugin, 0);
515 	gtk_widget_show_all (dialog);
516 	g_signal_connect (dialog, "response", G_CALLBACK (new_daap_share_response_cb), NULL);
517 }
518 
519 /* daap:// URI -> RBDAAPSource mapping */
520 
521 static gboolean
source_host_and_port_find(const char * key,RBDAAPSource * source,const char * host_and_port)522 source_host_and_port_find (const char *key,
523 		           RBDAAPSource *source,
524 		           const char *host_and_port)
525 {
526 	guint    source_port          = 0;
527 	char    *source_host          = NULL;
528 	char    *source_host_and_port = NULL;
529 	gboolean result               = FALSE;
530 
531 	if (source == NULL || host_and_port == NULL) {
532 		goto out;
533 	}
534 
535 	g_object_get (source, "host", &source_host, NULL);
536 	g_object_get (source, "port", &source_port, NULL);
537 
538 	source_host_and_port = g_strdup_printf ("%s:%d", source_host, source_port);
539 
540 	result = (strcmp (host_and_port, source_host_and_port) == 0);
541 
542 out:
543 	g_free (source_host);
544 	g_free (source_host_and_port);
545 
546 	return result;
547 }
548 
549 RBDAAPSource *
rb_daap_plugin_find_source_for_uri(RBDaapPlugin * plugin,const char * uri)550 rb_daap_plugin_find_source_for_uri (RBDaapPlugin *plugin, const char *uri)
551 {
552 	char         *host_and_port = NULL;
553 	char         *s             = NULL;
554 	RBDAAPSource *source        = NULL;
555 
556 	if (NULL == uri) {
557 		goto out;
558 	}
559 
560 	host_and_port = g_strdup (uri + 7); /* Skip daap://. */
561 	if (NULL == host_and_port) {
562 		goto out;
563 	}
564 
565 	s = strchr (host_and_port, '/');  /* Include through port, but not path. */
566 	if (NULL != s) {
567 		*s = '\0';
568 	}
569 
570 	source = (RBDAAPSource *)g_hash_table_find (plugin->source_lookup, (GHRFunc)source_host_and_port_find, host_and_port);
571 
572 out:
573 	g_free (host_and_port);
574 
575 	return source;
576 }
577 
578 gboolean
rb_daap_plugin_shutdown(RBDaapPlugin * plugin)579 rb_daap_plugin_shutdown (RBDaapPlugin *plugin)
580 {
581 	return plugin->shutdown;
582 }
583 
584 /* preferences dialog */
585 
586 /* should move this to a separate class really */
587 
588 static void
forget_remotes_button_toggled_cb(GtkToggleButton * button,gpointer data)589 forget_remotes_button_toggled_cb (GtkToggleButton *button,
590 				  gpointer data)
591 {
592 	GSettings *dacp_settings;
593 	GSettings *daap_settings;
594 
595 	daap_settings = g_settings_new ("org.gnome.rhythmbox.plugins.daap");
596 	dacp_settings = g_settings_get_child (daap_settings, "dacp");
597 	g_settings_reset (dacp_settings, "known-remotes");
598 
599 	g_object_unref (dacp_settings);
600 	g_object_unref (daap_settings);
601 }
602 
603 static gboolean
share_name_entry_focus_out_event_cb(GtkEntry * entry,GdkEventFocus * event,gpointer data)604 share_name_entry_focus_out_event_cb (GtkEntry *entry,
605 				     GdkEventFocus *event,
606 				     gpointer data)
607 {
608 	GSettings  *settings;
609 	gboolean    changed;
610 	const char *name;
611 	char       *old_name;
612 
613 	settings = g_settings_new ("org.gnome.rhythmbox.sharing");
614 	name = gtk_entry_get_text (entry);
615 	old_name = g_settings_get_string (settings, "share-name");
616 
617 	if (name == NULL && old_name == NULL) {
618 		changed = FALSE;
619 	} else if (name == NULL || old_name == NULL) {
620 		changed = TRUE;
621 	} else if (strcmp (name, old_name) != 0) {
622 		changed = TRUE;
623 	} else {
624 		changed = FALSE;
625 	}
626 
627 	if (changed) {
628 		g_settings_set_string (settings, "share-name", name);
629 	}
630 
631 	g_free (old_name);
632 	g_object_unref (settings);
633 
634 	return FALSE;
635 }
636 
637 static gboolean
share_password_entry_focus_out_event_cb(GtkEntry * entry,GdkEventFocus * event,RBDaapPlugin * plugin)638 share_password_entry_focus_out_event_cb (GtkEntry *entry,
639 					 GdkEventFocus *event,
640 					 RBDaapPlugin *plugin)
641 {
642 	GSettings  *settings;
643 	gboolean    changed;
644 	const char *pw;
645 	char       *old_pw;
646 
647 	pw = gtk_entry_get_text (entry);
648 	settings = g_settings_new ("org.gnome.rhythmbox.sharing");
649 	old_pw = g_settings_get_string (settings, "share-password");
650 
651 	if (pw == NULL && old_pw == NULL) {
652 		changed = FALSE;
653 	} else if (pw == NULL || old_pw == NULL) {
654 		changed = TRUE;
655 	} else if (strcmp (pw, old_pw) != 0) {
656 		changed = TRUE;
657 	} else {
658 		changed = FALSE;
659 	}
660 
661 	if (changed) {
662 		g_settings_set_string (settings, "share-password", pw);
663 	}
664 
665 	g_free (old_pw);
666 	g_object_unref (settings);
667 
668 	return FALSE;
669 }
670 
671 static void
config_settings_changed_cb(GSettings * settings,const char * key,RBDaapPlugin * plugin)672 config_settings_changed_cb (GSettings *settings, const char *key, RBDaapPlugin *plugin)
673 {
674 	if (g_strcmp0 (key, "enable-sharing") == 0) {
675 		GtkToggleButton *password_check;
676 		GtkWidget *password_entry;
677 		gboolean enabled = g_settings_get_boolean (settings, key);
678 
679 		password_check = GTK_TOGGLE_BUTTON (gtk_builder_get_object (plugin->builder, "daap_password_check"));
680 		password_entry = GTK_WIDGET (gtk_builder_get_object (plugin->builder, "daap_password_entry"));
681 
682 		gtk_widget_set_sensitive (password_entry, enabled && gtk_toggle_button_get_active (password_check));
683 		gtk_widget_set_sensitive (GTK_WIDGET (password_check), enabled);
684 	}
685 }
686 
687 static void
update_config_widget(RBDaapPlugin * plugin)688 update_config_widget (RBDaapPlugin *plugin)
689 {
690 	GtkWidget *check;
691 	GtkWidget *remote_check;
692 	GtkWidget *name_entry;
693 	GtkWidget *password_entry;
694 	GtkWidget *password_check;
695 	GtkWidget *forget_remotes_button;
696 	char *name;
697 	char *password;
698 
699 	check = GTK_WIDGET (gtk_builder_get_object (plugin->builder, "daap_enable_check"));
700 	remote_check = GTK_WIDGET (gtk_builder_get_object (plugin->builder, "dacp_enable_check"));
701 	password_check = GTK_WIDGET (gtk_builder_get_object (plugin->builder, "daap_password_check"));
702 	name_entry = GTK_WIDGET (gtk_builder_get_object (plugin->builder, "daap_name_entry"));
703 	password_entry = GTK_WIDGET (gtk_builder_get_object (plugin->builder, "daap_password_entry"));
704 	forget_remotes_button = GTK_WIDGET (gtk_builder_get_object (plugin->builder, "forget_remotes_button"));
705 
706 	g_settings_bind (plugin->settings, "enable-sharing", check, "active", G_SETTINGS_BIND_DEFAULT);
707 	g_settings_bind (plugin->dacp_settings, "enable-remote", remote_check, "active", G_SETTINGS_BIND_DEFAULT);
708 
709 	g_signal_connect_object (plugin->settings, "changed", G_CALLBACK (config_settings_changed_cb), plugin, 0);
710 
711 	/*g_signal_connect (check, "toggled", G_CALLBACK (share_check_button_toggled_cb), plugin->builder);*/
712 
713 	/* probably needs rethinking to deal with remotes.. */
714 	g_settings_bind (plugin->settings, "require-password", password_check, "active", G_SETTINGS_BIND_DEFAULT);
715 	g_settings_bind (plugin->settings, "require-password", password_entry, "sensitive", G_SETTINGS_BIND_NO_SENSITIVITY);
716 
717 	g_signal_connect_object (forget_remotes_button, "clicked", G_CALLBACK (forget_remotes_button_toggled_cb), plugin, 0);
718 
719 	name = g_settings_get_string (plugin->settings, "share-name");
720 	if (name == NULL || name[0] == '\0') {
721 		g_free (name);
722 		name = rb_daap_sharing_default_share_name ();
723 	}
724 	if (name != NULL) {
725 		gtk_entry_set_text (GTK_ENTRY (name_entry), name);
726 		g_free (name);
727 	}
728 	g_signal_connect (name_entry,
729 			  "focus-out-event",
730 			  G_CALLBACK (share_name_entry_focus_out_event_cb),
731 			  NULL);
732 
733 	password = g_settings_get_string (plugin->settings, "share-password");
734 	if (password != NULL) {
735 		gtk_entry_set_text (GTK_ENTRY (password_entry), password);
736 		g_free (password);
737 	}
738 	g_signal_connect (password_entry,
739 			  "focus-out-event",
740 			  G_CALLBACK (share_password_entry_focus_out_event_cb),
741 			  NULL);
742 
743 	/*gtk_widget_set_sensitive (password_entry, require_password);*/
744 }
745 
746 static GtkWidget *
impl_create_configure_widget(PeasGtkConfigurable * bplugin)747 impl_create_configure_widget (PeasGtkConfigurable *bplugin)
748 {
749 	RBDaapPlugin *plugin = RB_DAAP_PLUGIN (bplugin);
750 
751 	plugin->builder = rb_builder_load_plugin_file (G_OBJECT (plugin), "daap-prefs.ui", NULL);
752 	update_config_widget (plugin);
753 
754 	return GTK_WIDGET (gtk_builder_get_object (plugin->builder, "daap_vbox"));
755 }
756 
757 static void
peas_gtk_configurable_iface_init(PeasGtkConfigurableInterface * iface)758 peas_gtk_configurable_iface_init (PeasGtkConfigurableInterface *iface)
759 {
760 	iface->create_configure_widget = impl_create_configure_widget;
761 }
762 
763 /* DAAP DBus interface */
764 
765 static void
daap_dbus_method_call(GDBusConnection * connection,const char * sender,const char * object_path,const char * interface_name,const char * method_name,GVariant * parameters,GDBusMethodInvocation * invocation,RBDaapPlugin * plugin)766 daap_dbus_method_call (GDBusConnection *connection,
767 		       const char *sender,
768 		       const char *object_path,
769 		       const char *interface_name,
770 		       const char *method_name,
771 		       GVariant *parameters,
772 		       GDBusMethodInvocation *invocation,
773 		       RBDaapPlugin *plugin)
774 {
775 	if (plugin->shutdown) {
776 		rb_debug ("ignoring %s call", method_name);
777 		return;
778 	}
779 
780 	if (g_strcmp0 (method_name, "AddDAAPSource") == 0) {
781 		DMAPMdnsBrowserService service = {0,};
782 		g_variant_get (parameters, "(&s&su)", &service.name, &service.host, &service.port);
783 		service.password_protected = FALSE;
784 		service.service_name = service.name;
785 
786 		rb_debug ("adding DAAP source %s (%s:%d)", service.name, service.host, service.port);
787 		mdns_service_added (NULL, &service, plugin);
788 
789 		g_dbus_method_invocation_return_value (invocation, NULL);
790 
791 	} else if (g_strcmp0 (method_name, "RemoveDAAPSource") == 0) {
792 		const char *service_name;
793 
794 		g_variant_get (parameters, "(&s)", &service_name);
795 		rb_debug ("removing DAAP source %s", service_name);
796 		mdns_service_removed (plugin->mdns_browser, service_name, plugin);
797 
798 		g_dbus_method_invocation_return_value (invocation, NULL);
799 	}
800 }
801 
802 static const GDBusInterfaceVTable daap_dbus_vtable = {
803 	(GDBusInterfaceMethodCallFunc) daap_dbus_method_call,
804 	NULL,
805 	NULL
806 };
807 
808 static void
register_daap_dbus_iface(RBDaapPlugin * plugin)809 register_daap_dbus_iface (RBDaapPlugin *plugin)
810 {
811 	GError *error = NULL;
812 	GDBusNodeInfo *node_info;
813 	GDBusInterfaceInfo *iface_info;
814 
815 	if (plugin->dbus_intf_id != 0) {
816 		rb_debug ("DAAP DBus interface already registered");
817 		return;
818 	}
819 
820 	if (plugin->bus == NULL) {
821 		plugin->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
822 		if (plugin->bus == NULL) {
823 			rb_debug ("Unable to register DAAP DBus interface: %s", error->message);
824 			g_clear_error (&error);
825 			return;
826 		}
827 	}
828 
829 	node_info = g_dbus_node_info_new_for_xml (rb_daap_dbus_iface, &error);
830 	if (error != NULL) {
831 		rb_debug ("Unable to parse DAAP DBus spec: %s", error->message);
832 		g_clear_error (&error);
833 		return;
834 	}
835 
836 	iface_info = g_dbus_node_info_lookup_interface (node_info, DAAP_DBUS_IFACE);
837 	plugin->dbus_intf_id =
838 		g_dbus_connection_register_object (plugin->bus,
839 						   DAAP_DBUS_PATH,
840 						   iface_info,
841 						   &daap_dbus_vtable,
842 						   g_object_ref (plugin),
843 						   g_object_unref,
844 						   &error);
845 	if (error != NULL) {
846 		rb_debug ("Unable to register DAAP DBus interface: %s", error->message);
847 		g_clear_error (&error);
848 	}
849 
850 	g_dbus_node_info_unref (node_info);
851 }
852 
853 static void
unregister_daap_dbus_iface(RBDaapPlugin * plugin)854 unregister_daap_dbus_iface (RBDaapPlugin *plugin)
855 {
856 	if (plugin->dbus_intf_id == 0) {
857 		rb_debug ("DAAP DBus interface not registered");
858 		return;
859 	}
860 
861 	if (plugin->bus == NULL) {
862 		rb_debug ("no bus connection");
863 		return;
864 	}
865 
866 	g_dbus_connection_unregister_object (plugin->bus, plugin->dbus_intf_id);
867 	plugin->dbus_intf_id = 0;
868 }
869 
870 G_MODULE_EXPORT void
peas_register_types(PeasObjectModule * module)871 peas_register_types (PeasObjectModule *module)
872 {
873 	rb_daap_plugin_register_type (G_TYPE_MODULE (module));
874 	_rb_daap_container_record_register_type (G_TYPE_MODULE (module));
875 	_rb_daap_record_factory_register_type (G_TYPE_MODULE (module));
876 	_rb_daap_record_register_type (G_TYPE_MODULE (module));
877 	_rb_daap_source_register_type (G_TYPE_MODULE (module));
878 	_rb_dacp_pairing_page_register_type (G_TYPE_MODULE (module));
879 	_rb_dacp_player_register_type (G_TYPE_MODULE (module));
880 	_rb_dmap_container_db_adapter_register_type (G_TYPE_MODULE (module));
881 	_rb_rhythmdb_dmap_db_adapter_register_type (G_TYPE_MODULE (module));
882 	_rb_rhythmdb_query_model_dmap_db_adapter_register_type (G_TYPE_MODULE (module));
883 
884 	peas_object_module_register_extension_type (module,
885 						    PEAS_TYPE_ACTIVATABLE,
886 						    RB_TYPE_DAAP_PLUGIN);
887 	peas_object_module_register_extension_type (module,
888 						    PEAS_GTK_TYPE_CONFIGURABLE,
889 						    RB_TYPE_DAAP_PLUGIN);
890 }
891