Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
rb-daap-source.c:390:3 | clang-analyzer | Function call argument is an uninitialized value |
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Implementation of DAAP (iTunes Music Sharing) source object
4 *
5 * Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
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 of the License, or
10 * (at your option) 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, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28 *
29 */
30
31 #include "config.h"
32
33 #include <string.h>
34
35 #include <glib/gi18n.h>
36 #include <gtk/gtk.h>
37
38 #ifdef WITH_GNOME_KEYRING
39 #include <gnome-keyring.h>
40 #endif
41
42 #include "rhythmdb.h"
43 #include "rb-shell.h"
44 #include "rb-daap-source.h"
45 #include "rb-stock-icons.h"
46 #include "rb-debug.h"
47 #include "rb-util.h"
48 #include "rb-file-helpers.h"
49 #include "rb-dialog.h"
50 #include "rb-daap-src.h"
51 #include "rb-daap-record-factory.h"
52 #include "rb-rhythmdb-dmap-db-adapter.h"
53 #include "rb-display-page.h"
54
55 #include "rb-daap-plugin.h"
56
57 #include "rb-static-playlist-source.h"
58
59 #include <libdmapsharing/dmap.h>
60
61 typedef struct _RhythmDBEntryType RBDAAPEntryType;
62 typedef struct _RhythmDBEntryTypeClass RBDAAPEntryTypeClass;
63
64 static void rb_daap_source_dispose (GObject *object);
65 static void rb_daap_source_set_property (GObject *object,
66 guint prop_id,
67 const GValue *value,
68 GParamSpec *pspec);
69 static void rb_daap_source_get_property (GObject *object,
70 guint prop_id,
71 GValue *value,
72 GParamSpec *pspec);
73
74 static void rb_daap_source_selected (RBDisplayPage *page);
75 static gboolean rb_daap_source_show_popup (RBDisplayPage *page);
76 static void rb_daap_source_get_status (RBDisplayPage *page, char **text, char **progress_text, float *progress);
77
78 static void rb_daap_entry_type_class_init (RBDAAPEntryTypeClass *klass);
79 static void rb_daap_entry_type_init (RBDAAPEntryType *etype);
80 GType rb_daap_entry_type_get_type (void);
81
82 struct RBDAAPSourcePrivate
83 {
84 GtkActionGroup *action_group;
85
86 char *service_name;
87 char *host;
88 guint port;
89 gboolean password_protected;
90
91 gpointer connection;
92
93 GSList *playlist_sources;
94
95 const char *connection_status;
96 float connection_progress;
97
98 gboolean tried_password;
99 gboolean disconnecting;
100 };
101
102 enum {
103 PROP_0,
104 PROP_SERVICE_NAME,
105 PROP_HOST,
106 PROP_PORT,
107 PROP_PASSWORD_PROTECTED
108 };
109
110 G_DEFINE_DYNAMIC_TYPE (RBDAAPSource, rb_daap_source, RB_TYPE_BROWSER_SOURCE);
111
112 G_DEFINE_DYNAMIC_TYPE (RBDAAPEntryType, rb_daap_entry_type, RHYTHMDB_TYPE_ENTRY_TYPE);
113
114 static char *
115 rb_daap_entry_type_get_playback_uri (RhythmDBEntryType *etype, RhythmDBEntry *entry)
116 {
117 const char *location;
118
119 location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MOUNTPOINT);
120 if (location == NULL) {
121 location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
122 }
123
124 return g_strdup (location);
125 }
126
127 static void
128 rb_daap_entry_type_class_init (RBDAAPEntryTypeClass *klass)
129 {
130 RhythmDBEntryTypeClass *etype_class = RHYTHMDB_ENTRY_TYPE_CLASS (klass);
131 etype_class->get_playback_uri = rb_daap_entry_type_get_playback_uri;
132 }
133
134 static void
135 rb_daap_entry_type_class_finalize (RBDAAPEntryTypeClass *klass)
136 {
137 }
138
139 static void
140 rb_daap_entry_type_init (RBDAAPEntryType *etype)
141 {
142 }
143
144 static void
145 rb_daap_source_dispose (GObject *object)
146 {
147 RBDAAPSource *source = RB_DAAP_SOURCE (object);
148
149 /* we should already have been disconnected */
150 g_assert (source->priv->connection == NULL);
151
152 G_OBJECT_CLASS (rb_daap_source_parent_class)->dispose (object);
153 }
154
155 static void
156 rb_daap_source_finalize (GObject *object)
157 {
158 RBDAAPSource *source = RB_DAAP_SOURCE (object);
159
160 g_free (source->priv->service_name);
161 g_free (source->priv->host);
162
163 G_OBJECT_CLASS (rb_daap_source_parent_class)->finalize (object);
164 }
165
166 static void
167 rb_daap_source_class_init (RBDAAPSourceClass *klass)
168 {
169 GObjectClass *object_class = G_OBJECT_CLASS (klass);
170 RBDisplayPageClass *page_class = RB_DISPLAY_PAGE_CLASS (klass);
171 RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
172 RBBrowserSourceClass *browser_source_class = RB_BROWSER_SOURCE_CLASS (klass);
173
174 object_class->dispose = rb_daap_source_dispose;
175 object_class->finalize = rb_daap_source_finalize;
176 object_class->get_property = rb_daap_source_get_property;
177 object_class->set_property = rb_daap_source_set_property;
178
179 page_class->selected = rb_daap_source_selected;
180 page_class->get_status = rb_daap_source_get_status;
181 page_class->show_popup = rb_daap_source_show_popup;
182
183 source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
184 source_class->impl_can_copy = (RBSourceFeatureFunc) rb_true_function;
185 source_class->impl_can_delete = (RBSourceFeatureFunc) rb_false_function;
186
187 browser_source_class->has_drop_support = (RBBrowserSourceFeatureFunc) rb_false_function;
188
189 g_object_class_install_property (object_class,
190 PROP_SERVICE_NAME,
191 g_param_spec_string ("service-name",
192 "Service name",
193 "mDNS/DNS-SD service name of the share",
194 NULL,
195 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
196
197 g_object_class_install_property (object_class,
198 PROP_HOST,
199 g_param_spec_string ("host",
200 "Host",
201 "Host IP address",
202 NULL,
203 G_PARAM_READWRITE));
204
205 g_object_class_install_property (object_class,
206 PROP_PORT,
207 g_param_spec_uint ("port",
208 "Port",
209 "Port of DAAP server on host",
210 0,
211 G_MAXUINT,
212 0,
213 G_PARAM_READWRITE));
214 g_object_class_install_property (object_class,
215 PROP_PASSWORD_PROTECTED,
216 g_param_spec_boolean ("password-protected",
217 "Password Protected",
218 "Whether the share is password protected",
219 FALSE,
220 G_PARAM_READWRITE));
221
222 g_type_class_add_private (klass, sizeof (RBDAAPSourcePrivate));
223 }
224
225 static void
226 rb_daap_source_class_finalize (RBDAAPSourceClass *klass)
227 {
228 }
229
230 static void
231 rb_daap_source_init (RBDAAPSource *source)
232 {
233 source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source,
234 RB_TYPE_DAAP_SOURCE,
235 RBDAAPSourcePrivate);
236 }
237
238 static void
239 rb_daap_source_set_property (GObject *object,
240 guint prop_id,
241 const GValue *value,
242 GParamSpec *pspec)
243 {
244 RBDAAPSource *source = RB_DAAP_SOURCE (object);
245
246 switch (prop_id) {
247 case PROP_SERVICE_NAME:
248 source->priv->service_name = g_value_dup_string (value);
249 break;
250 case PROP_HOST:
251 if (source->priv->host) {
252 g_free (source->priv->host);
253 }
254 source->priv->host = g_value_dup_string (value);
255 /* FIXME what do we do if its already connected and we
256 * get a new host? */
257 break;
258 case PROP_PORT:
259 source->priv->port = g_value_get_uint (value);
260 break;
261 case PROP_PASSWORD_PROTECTED:
262 source->priv->password_protected = g_value_get_boolean (value);
263 break;
264 default:
265 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
266 break;
267 }
268 }
269
270 static void
271 rb_daap_source_get_property (GObject *object,
272 guint prop_id,
273 GValue *value,
274 GParamSpec *pspec)
275 {
276 RBDAAPSource *source = RB_DAAP_SOURCE (object);
277
278 switch (prop_id) {
279 case PROP_SERVICE_NAME:
280 g_value_set_string (value, source->priv->service_name);
281 break;
282 case PROP_HOST:
283 g_value_set_string (value, source->priv->host);
284 break;
285 case PROP_PORT:
286 g_value_set_uint (value, source->priv->port);
287 break;
288 case PROP_PASSWORD_PROTECTED:
289 g_value_set_boolean (value, source->priv->password_protected);
290 break;
291 default:
292 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
293 break;
294 }
295 }
296
297
298 RBSource *
299 rb_daap_source_new (RBShell *shell,
300 GObject *plugin,
301 const char *service_name,
302 const char *name,
303 const char *host,
304 guint port,
305 gboolean password_protected)
306 {
307 RBSource *source;
308 RhythmDBEntryType *entry_type;
309 GdkPixbuf *icon;
310 RhythmDB *db;
311 char *entry_type_name;
312 GSettings *settings;
313
314 g_object_get (shell, "db", &db, NULL);
315 entry_type_name = g_strdup_printf ("daap:%s:%s:%s", service_name, name, host);
316
317 entry_type = g_object_new (rb_daap_entry_type_get_type (),
318 "db", db,
319 "name", entry_type_name,
320 "save-to-disk", FALSE,
321 "category", RHYTHMDB_ENTRY_NORMAL,
322 NULL);
323 rhythmdb_register_entry_type (db, entry_type);
324 g_object_unref (db);
325 g_free (entry_type_name);
326
327 icon = rb_daap_plugin_get_icon (RB_DAAP_PLUGIN (plugin), password_protected, FALSE);
328
329 settings = g_settings_new ("org.gnome.rhythmbox.plugins.daap");
330 source = RB_SOURCE (g_object_new (RB_TYPE_DAAP_SOURCE,
331 "service-name", service_name,
332 "name", name,
333 "host", host,
334 "port", port,
335 "entry-type", entry_type,
336 "pixbuf", icon,
337 "shell", shell,
338 "visibility", TRUE,
339 "password-protected", password_protected,
340 "plugin", G_OBJECT (plugin),
341 "load-status", RB_SOURCE_LOAD_STATUS_NOT_LOADED,
342 "settings", g_settings_get_child (settings, "source"),
343 "toolbar-path", "/DAAPSourceToolBar",
344 NULL));
345 g_object_unref (settings);
346
347 if (icon != NULL) {
348 g_object_unref (icon);
349 }
350
351 rb_shell_register_entry_type_for_source (shell, source,
352 entry_type);
353
354 return source;
355 }
356
357 typedef struct {
358 RBDAAPSource *source;
359 DMAPConnection *connection;
360 SoupSession *session;
361 SoupMessage *message;
362 SoupAuth *auth;
363 char *name;
364 } AuthData;
365
366 static void
367 mount_op_reply_cb (GMountOperation *op,
368 GMountOperationResult result,
369 AuthData *auth_data)
370 {
371 const char *password;
372 gchar *keyring;
373 #ifdef WITH_GNOME_KEYRING
374 guint32 item_id;
375 #endif
376
377 rb_debug ("mount op reply: %d", result);
378 password = g_mount_operation_get_password (op);
379
380 #ifdef WITH_GNOME_KEYRING
381 switch (g_mount_operation_get_password_save (op)) {
382 case G_PASSWORD_SAVE_NEVER:
383 break;
384
385 case G_PASSWORD_SAVE_FOR_SESSION:
386 keyring = "session";
387 /* fall through */
388
389 case G_PASSWORD_SAVE_PERMANENTLY:
390 gnome_keyring_set_network_password_sync (keyring,
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
391 NULL,
392 "DAAP", auth_data->name,
393 NULL, "daap",
394 NULL, 0,
395 password,
396 &item_id);
397 break;
398
399 default:
400 g_assert_not_reached ();
401 }
402 #endif
403
404 if (password) {
405 dmap_connection_authenticate_message (auth_data->connection,
406 auth_data->session,
407 auth_data->message,
408 auth_data->auth,
409 password);
410 } else {
411 rb_daap_source_disconnect (auth_data->source);
412 }
413
414 g_object_unref (auth_data->source);
415 g_free (auth_data->name);
416 g_free (auth_data);
417 g_object_unref (op);
418 }
419
420 static void
421 ask_password (RBDAAPSource *source, const char *name, const char *keyring, SoupSession *session, SoupMessage *msg, SoupAuth *auth)
422 {
423 GtkWindow *parent;
424 GMountOperation *mount_op;
425 GAskPasswordFlags flags;
426 AuthData *auth_data;
427 char *message;
428
429 g_object_set (source, "load-status", RB_SOURCE_LOAD_STATUS_WAITING, NULL);
430 parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (source)));
431
432 mount_op = gtk_mount_operation_new (parent);
433 auth_data = g_new0 (AuthData, 1);
434 auth_data->source = g_object_ref (source);
435 auth_data->connection = source->priv->connection;
436 auth_data->session = session;
437 auth_data->message = msg;
438 auth_data->auth = auth;
439 auth_data->name = g_strdup (name);
440 g_signal_connect (mount_op, "reply", G_CALLBACK (mount_op_reply_cb), auth_data);
441
442 flags = G_ASK_PASSWORD_NEED_PASSWORD;
443 #ifdef WITH_GNOME_KEYRING
444 if (gnome_keyring_is_available ()) {
445 flags |= G_ASK_PASSWORD_SAVING_SUPPORTED;
446 }
447 #endif
448 message = g_strdup_printf (_("The music share '%s' requires a password to connect"), name);
449 g_signal_emit_by_name (mount_op, "ask-password", message, NULL, "DAAP", flags);
450 g_free (message);
451 }
452
453 static void
454 connection_auth_cb (DMAPConnection *connection,
455 const char *name,
456 SoupSession *session,
457 SoupMessage *msg,
458 SoupAuth *auth,
459 gboolean retrying,
460 RBDAAPSource *source)
461 {
462 gchar *password = NULL;
463 #ifdef WITH_GNOME_KEYRING
464 GnomeKeyringResult keyringret;
465 gchar *keyring;
466 GList *list = NULL;
467
468 keyring = NULL;
469 if (!source->priv->tried_password) {
470 gnome_keyring_get_default_keyring_sync (&keyring);
471 keyringret = gnome_keyring_find_network_password_sync (
472 NULL,
473 "DAAP", name,
474 NULL, "daap",
475 NULL, 0, &list);
476 } else {
477 keyringret = GNOME_KEYRING_RESULT_CANCELLED;
478 }
479
480 if (keyringret == GNOME_KEYRING_RESULT_OK) {
481 GnomeKeyringNetworkPasswordData *pwd_data;
482
483 if (list != NULL) {
484 pwd_data = (GnomeKeyringNetworkPasswordData*)list->data;
485 password = g_strdup (pwd_data->password);
486 }
487 source->priv->tried_password = TRUE;
488 }
489
490 if (password == NULL) {
491 ask_password (source, name, keyring, session, msg, auth);
492 } else {
493 dmap_connection_authenticate_message (connection, session, msg, auth, password);
494 }
495
496 if (list)
497 gnome_keyring_network_password_list_free (list);
498 g_free (keyring);
499 #else
500 ask_password (source, name, NULL, session, msg, auth);
501 #endif
502 }
503
504 static void
505 connection_connecting_cb (DMAPConnection *connection,
506 DMAPConnectionState state,
507 float progress,
508 RBDAAPSource *source)
509 {
510 GdkPixbuf *icon;
511 gboolean is_connected;
512 GObject *plugin;
513
514 rb_debug ("DAAP connection status: %d/%f", state, progress);
515
516 switch (state) {
517 case DMAP_GET_INFO:
518 case DMAP_LOGIN:
519 source->priv->connection_status = _("Connecting to music share");
520 break;
521 case DMAP_GET_REVISION_NUMBER:
522 g_object_set (source, "load-status", RB_SOURCE_LOAD_STATUS_LOADING, NULL);
523 case DMAP_GET_DB_INFO:
524 case DMAP_GET_SONGS:
525 case DMAP_GET_PLAYLISTS:
526 case DMAP_GET_PLAYLIST_ENTRIES:
527 source->priv->connection_status = _("Retrieving songs from music share");
528 break;
529 case DMAP_DONE:
530 g_object_set (source, "load-status", RB_SOURCE_LOAD_STATUS_LOADED, NULL);
531 case DMAP_LOGOUT:
532 source->priv->connection_status = NULL;
533 break;
534 }
535
536 source->priv->connection_progress = progress;
537
538 rb_display_page_notify_status_changed (RB_DISPLAY_PAGE (source));
539
540 is_connected = dmap_connection_is_connected (DMAP_CONNECTION (connection));
541
542 g_object_get (source, "plugin", &plugin, NULL);
543 g_assert (plugin != NULL);
544
545 icon = rb_daap_plugin_get_icon (RB_DAAP_PLUGIN (plugin),
546 source->priv->password_protected,
547 is_connected);
548 g_object_set (source, "pixbuf", icon, NULL);
549 if (icon != NULL) {
550 g_object_unref (icon);
551 }
552
553 g_object_unref (plugin);
554 }
555
556 static void
557 connection_disconnected_cb (DMAPConnection *connection,
558 RBDAAPSource *source)
559 {
560 GdkPixbuf *icon;
561 GObject *plugin;
562
563 rb_debug ("DAAP connection disconnected");
564
565 g_object_get (source, "plugin", &plugin, NULL);
566 g_assert (plugin != NULL);
567
568 if (rb_daap_plugin_shutdown (RB_DAAP_PLUGIN (plugin)) == FALSE) {
569
570 icon = rb_daap_plugin_get_icon (RB_DAAP_PLUGIN (plugin),
571 source->priv->password_protected,
572 FALSE);
573 g_object_set (source, "pixbuf", icon, NULL);
574 if (icon != NULL) {
575 g_object_unref (icon);
576 }
577 }
578
579 g_object_unref (plugin);
580 }
581
582 static void
583 release_connection (RBDAAPSource *daap_source)
584 {
585 rb_debug ("Releasing connection");
586
587 g_object_unref (daap_source->priv->connection);
588 daap_source->priv->connection = NULL;
589 }
590
591 static void
592 _add_location_to_playlist (const char *uri, RBStaticPlaylistSource *source)
593 {
594 rb_static_playlist_source_add_location (source, uri, -1);
595 }
596
597 static void
598 rb_daap_source_connection_cb (DMAPConnection *connection,
599 gboolean result,
600 const char *reason,
601 RBSource *source)
602 {
603 RBDAAPSource *daap_source = RB_DAAP_SOURCE (source);
604 RBShell *shell = NULL;
605 GSList *playlists;
606 GSList *l;
607 RhythmDBEntryType *entry_type;
608
609 rb_debug ("Connection callback result: %s", result ? "success" : "failure");
610 daap_source->priv->tried_password = FALSE;
611
612 if (result == FALSE) {
613 if (reason != NULL) {
614 rb_error_dialog (NULL, _("Could not connect to shared music"), "%s", reason);
615 }
616
617 /* Don't release the connection if we are already disconnecting */
618 if (! daap_source->priv->disconnecting) {
619 release_connection (daap_source);
620 }
621
622 return;
623 }
624
625 g_object_get (daap_source,
626 "shell", &shell,
627 "entry-type", &entry_type,
628 NULL);
629 playlists = dmap_connection_get_playlists (DMAP_CONNECTION (daap_source->priv->connection));
630 for (l = playlists; l != NULL; l = g_slist_next (l)) {
631 DMAPPlaylist *playlist = l->data;
632 RBSource *playlist_source;
633 char *settings_name;
634
635 /* Construct a unique settings name for this playlist, as <Share Name>_<Playlist> */
636 /* XXX disabled for now, not sure it's a good idea */
637 /*settings_name = g_strjoin (NULL, daap_source->priv->service_name, "_", playlist->name, NULL); */
638
639 settings_name = "/org/gnome/rhythmbox/plugins/daap/source";
640
641 playlist_source = rb_static_playlist_source_new (shell, playlist->name, settings_name, FALSE, entry_type);
642 /*g_free (settings_name);*/
643
644 g_list_foreach (playlist->uris, (GFunc)_add_location_to_playlist, playlist_source);
645
646 rb_shell_append_display_page (shell, RB_DISPLAY_PAGE (playlist_source), RB_DISPLAY_PAGE (daap_source));
647 daap_source->priv->playlist_sources = g_slist_prepend (daap_source->priv->playlist_sources, playlist_source);
648 }
649
650 g_object_unref (shell);
651 g_object_unref (entry_type);
652 }
653
654 static void
655 rb_daap_source_selected (RBDisplayPage *page)
656 {
657 RBDAAPSource *daap_source = RB_DAAP_SOURCE (page);
658 RBShell *shell = NULL;
659 DMAPRecordFactory *factory;
660 RhythmDB *rdb = NULL;
661 DMAPDb *db = NULL;
662 char *name = NULL;
663 RhythmDBEntryType *entry_type;
664
665 RB_DISPLAY_PAGE_CLASS (rb_daap_source_parent_class)->selected (page);
666
667 if (daap_source->priv->connection != NULL) {
668 return;
669 }
670
671 g_object_get (daap_source,
672 "shell", &shell,
673 "name", &name,
674 "entry-type", &entry_type,
675 NULL);
676 g_object_get (shell, "db", &rdb, NULL);
677 db = DMAP_DB (rb_rhythmdb_dmap_db_adapter_new (rdb, entry_type));
678
679 factory = DMAP_RECORD_FACTORY (rb_daap_record_factory_new ());
680
681 daap_source->priv->connection = daap_connection_new (name,
682 daap_source->priv->host,
683 daap_source->priv->port,
684 db,
685 factory);
686 g_object_unref (entry_type);
687 g_object_add_weak_pointer (G_OBJECT (daap_source->priv->connection), (gpointer *)&daap_source->priv->connection);
688
689 g_free (name);
690
691 g_signal_connect (daap_source->priv->connection,
692 "authenticate",
693 G_CALLBACK (connection_auth_cb),
694 page);
695 g_signal_connect (daap_source->priv->connection,
696 "connecting",
697 G_CALLBACK (connection_connecting_cb),
698 page);
699 g_signal_connect (daap_source->priv->connection,
700 "disconnected",
701 G_CALLBACK (connection_disconnected_cb),
702 page);
703
704 dmap_connection_connect (DMAP_CONNECTION (daap_source->priv->connection),
705 (DMAPConnectionCallback) rb_daap_source_connection_cb,
706 page);
707
708 g_object_unref (rdb);
709 g_object_unref (shell);
710 }
711
712 static void
713 rb_daap_source_disconnect_cb (DMAPConnection *connection,
714 gboolean result,
715 const char *reason,
716 RBSource *source)
717 {
718 RBDAAPSource *daap_source = RB_DAAP_SOURCE (source);
719
720 rb_debug ("DAAP source disconnected");
721
722 release_connection (daap_source);
723
724 g_object_unref (source);
725 }
726
727 void
728 rb_daap_source_disconnect (RBDAAPSource *daap_source)
729 {
730 GSList *l;
731 RBShell *shell;
732 RhythmDB *db;
733 RhythmDBEntryType *entry_type;
734
735 if (daap_source->priv->connection == NULL
736 || daap_source->priv->disconnecting == TRUE) {
737 return;
738 }
739
740 rb_debug ("Disconnecting source");
741
742 daap_source->priv->disconnecting = TRUE;
743
744 g_object_get (daap_source, "shell", &shell, "entry-type", &entry_type, NULL);
745 g_object_get (shell, "db", &db, NULL);
746 g_object_unref (shell);
747
748 rhythmdb_entry_delete_by_type (db, entry_type);
749 g_object_unref (entry_type);
750 rhythmdb_commit (db);
751
752 g_object_unref (db);
753
754 for (l = daap_source->priv->playlist_sources; l!= NULL; l = l->next) {
755 RBSource *playlist_source = RB_SOURCE (l->data);
756 char *name;
757
758 g_object_get (playlist_source, "name", &name, NULL);
759 rb_debug ("destroying DAAP playlist %s", name);
760 g_free (name);
761
762 rb_display_page_delete_thyself (RB_DISPLAY_PAGE (playlist_source));
763 }
764
765 g_slist_free (daap_source->priv->playlist_sources);
766 daap_source->priv->playlist_sources = NULL;
767
768 /* we don't want these firing while we are disconnecting */
769 g_signal_handlers_disconnect_by_func (daap_source->priv->connection,
770 G_CALLBACK (connection_connecting_cb),
771 daap_source);
772 g_signal_handlers_disconnect_by_func (daap_source->priv->connection,
773 G_CALLBACK (connection_auth_cb),
774 daap_source);
775
776 /* keep the source alive until the disconnect completes */
777 g_object_ref (daap_source);
778 dmap_connection_disconnect (daap_source->priv->connection,
779 (DMAPConnectionCallback) rb_daap_source_disconnect_cb,
780 daap_source);
781
782 /* wait until disconnected */
783 rb_debug ("Waiting for DAAP connection to finish");
784 while (daap_source->priv->connection != NULL) {
785 rb_debug ("Waiting for DAAP connection to finish...");
786 GDK_THREADS_ENTER ();
787 gtk_main_iteration ();
788 GDK_THREADS_LEAVE ();
789 }
790
791 daap_source->priv->disconnecting = FALSE;
792 rb_debug ("DAAP connection finished");
793 }
794
795 static gboolean
796 rb_daap_source_show_popup (RBDisplayPage *page)
797 {
798 _rb_display_page_show_popup (page, "/DAAPSourcePopup");
799 return TRUE;
800 }
801
802 SoupMessageHeaders *
803 rb_daap_source_get_headers (RBDAAPSource *source,
804 const char *uri)
805 {
806 /* If there is no connection then bail */
807 if (source->priv->connection == NULL) {
808 return NULL;
809 }
810
811 return dmap_connection_get_headers (source->priv->connection, uri);
812 }
813
814 static void
815 rb_daap_source_get_status (RBDisplayPage *page,
816 char **text,
817 char **progress_text,
818 float *progress)
819 {
820 RBDAAPSource *daap_source = RB_DAAP_SOURCE (page);
821
822 if (daap_source->priv->connection_status != NULL) {
823 if (text != NULL) {
824 *text = g_strdup (daap_source->priv->connection_status);
825 }
826
827 if (progress != NULL) {
828 *progress = daap_source->priv->connection_progress;
829 }
830
831 return;
832 }
833
834 RB_DISPLAY_PAGE_CLASS (rb_daap_source_parent_class)->get_status (page, text, progress_text, progress);
835 }
836
837 void
838 _rb_daap_source_register_type (GTypeModule *module)
839 {
840 rb_daap_source_register_type (module);
841 rb_daap_entry_type_register_type (module);
842 }