hythmbox-2.98/plugins/daap/rb-daap-source.c

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,
Function call argument is an uninitialized value
(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 }