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