~ubuntu-branches/ubuntu/utopic/rhythmbox/utopic-proposed

« back to all changes in this revision

Viewing changes to sources/rb-daap-source.c

Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Implementation of DAAP (iTunes Music Sharing) source object
 
3
 *
 
4
 *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 *
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
 
 
24
#include <gtk/gtktreeview.h>
 
25
#include <gtk/gtkicontheme.h>
 
26
#include <gtk/gtkiconfactory.h>
 
27
#include <string.h>
 
28
#include "rhythmdb.h"
 
29
#include "rb-shell.h"
 
30
#include <libgnome/gnome-i18n.h>
 
31
#include "eel-gconf-extensions.h"
 
32
#include "rb-daap-source.h"
 
33
#include "rb-stock-icons.h"
 
34
#include "rb-debug.h"
 
35
#include "rb-util.h"
 
36
#include "rb-dialog.h"
 
37
#include "rb-preferences.h"
 
38
 
 
39
#include "rb-daap-connection.h"
 
40
#include "rb-daap-mdns.h"
 
41
#include "rb-daap-src.h"
 
42
 
 
43
#include "rb-playlist-source.h"
 
44
 
 
45
 
 
46
static void rb_daap_source_dispose (GObject *object);
 
47
static void rb_daap_source_set_property  (GObject *object,
 
48
                                          guint prop_id,
 
49
                                          const GValue *value,
 
50
                                          GParamSpec *pspec);
 
51
static void rb_daap_source_get_property  (GObject *object,
 
52
                                          guint prop_id,
 
53
                                          GValue *value,
 
54
                                          GParamSpec *pspec);
 
55
static void rb_daap_source_activate (RBSource *source);
 
56
static void rb_daap_source_connection_cb (RBDAAPConnection *connection,
 
57
                                          gboolean result,
 
58
                                          RBSource *source);
 
59
static gboolean rb_daap_source_disconnect (RBSource *source);
 
60
static gboolean rb_daap_source_show_popup (RBSource *source);
 
61
static const gchar * rb_daap_source_get_browser_key (RBSource *source);
 
62
static const gchar * rb_daap_source_get_paned_key (RBLibrarySource *source);
 
63
 
 
64
 
 
65
#define CONF_ENABLE_BROWSING CONF_PREFIX "/sharing/enable_browsing"
 
66
#define CONF_STATE_SORTING CONF_PREFIX "/state/daap/sorting"
 
67
#define CONF_STATE_PANED_POSITION CONF_PREFIX "/state/daap/paned_position"
 
68
#define CONF_STATE_SHOW_BROWSER CONF_PREFIX "/state/daap/show_browser"
 
69
 
 
70
 
 
71
static RBDAAPmDNSBrowser browser = 0;
 
72
static GHashTable *service_name_to_resolver = NULL;
 
73
static GSList *sources = NULL;
 
74
static guint enable_browsing_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
 
75
 
 
76
 
 
77
struct RBDAAPSourcePrivate
 
78
{
 
79
        gchar *service_name;
 
80
        gchar *host;
 
81
        guint port;
 
82
        gboolean password_protected;
 
83
 
 
84
        RBDAAPConnection *connection;
 
85
        GSList *playlist_sources;
 
86
};
 
87
 
 
88
 
 
89
enum {
 
90
        PROP_0,
 
91
        PROP_SERVICE_NAME,
 
92
        PROP_HOST,
 
93
        PROP_PORT,
 
94
        PROP_PASSWORD_PROTECTED
 
95
};
 
96
 
 
97
G_DEFINE_TYPE (RBDAAPSource, rb_daap_source, RB_TYPE_LIBRARY_SOURCE)
 
98
 
 
99
 
 
100
static RhythmDBEntryType
 
101
rhythmdb_entry_daap_type_new (void)
 
102
{
 
103
        return rhythmdb_entry_register_type ();
 
104
}
 
105
 
 
106
static void
 
107
rb_daap_source_class_init (RBDAAPSourceClass *klass)
 
108
{
 
109
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
110
        RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
 
111
        RBLibrarySourceClass *library_source_class = RB_LIBRARY_SOURCE_CLASS (klass);
 
112
 
 
113
        object_class->dispose = rb_daap_source_dispose;
 
114
        object_class->get_property = rb_daap_source_get_property;
 
115
        object_class->set_property = rb_daap_source_set_property;
 
116
 
 
117
        source_class->impl_activate = rb_daap_source_activate;
 
118
        source_class->impl_disconnect = rb_daap_source_disconnect;
 
119
        source_class->impl_can_search = (RBSourceFeatureFunc) rb_true_function;
 
120
        source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
 
121
        source_class->impl_can_copy = (RBSourceFeatureFunc) rb_false_function;
 
122
        source_class->impl_can_delete = (RBSourceFeatureFunc) rb_false_function;
 
123
        source_class->impl_paste = NULL;
 
124
        source_class->impl_receive_drag = NULL;
 
125
        source_class->impl_delete = NULL;
 
126
        source_class->impl_show_popup = rb_daap_source_show_popup;
 
127
        source_class->impl_get_config_widget = NULL;
 
128
        source_class->impl_get_browser_key = rb_daap_source_get_browser_key;
 
129
 
 
130
        library_source_class->impl_get_paned_key = rb_daap_source_get_paned_key;
 
131
        library_source_class->impl_has_first_added_column = (RBLibrarySourceFeatureFunc) rb_false_function;
 
132
        library_source_class->impl_has_drop_support = (RBLibrarySourceFeatureFunc) rb_false_function;
 
133
 
 
134
 
 
135
        g_object_class_install_property (object_class,
 
136
                                         PROP_SERVICE_NAME,
 
137
                                         g_param_spec_string ("service-name",
 
138
                                                              "Service name",
 
139
                                                              "mDNS/DNS-SD service name of the share",
 
140
                                                              NULL,
 
141
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
142
        
 
143
        g_object_class_install_property (object_class,
 
144
                                         PROP_HOST,
 
145
                                         g_param_spec_string ("host",
 
146
                                                              "Host",
 
147
                                                              "Host IP address",
 
148
                                                              NULL,
 
149
                                                              G_PARAM_READWRITE));
 
150
 
 
151
        g_object_class_install_property (object_class,
 
152
                                         PROP_PORT,
 
153
                                         g_param_spec_uint ("port",
 
154
                                                            "Port",
 
155
                                                            "Port of DAAP server on host",
 
156
                                                            0,
 
157
                                                            G_MAXUINT,
 
158
                                                            0,
 
159
                                                            G_PARAM_READWRITE));
 
160
        g_object_class_install_property (object_class,
 
161
                                         PROP_PASSWORD_PROTECTED,
 
162
                                         g_param_spec_boolean ("password-protected",
 
163
                                                               "Password Protected",
 
164
                                                               "Whether the share is password protected",
 
165
                                                               FALSE,
 
166
                                                               G_PARAM_READWRITE));
 
167
}
 
168
 
 
169
static void
 
170
rb_daap_source_init (RBDAAPSource *source)
 
171
{
 
172
        source->priv = g_new0 (RBDAAPSourcePrivate, 1);
 
173
}
 
174
 
 
175
 
 
176
static void
 
177
rb_daap_source_dispose (GObject *object)
 
178
{
 
179
        RBDAAPSource *source = RB_DAAP_SOURCE (object);
 
180
 
 
181
        if (source->priv) {
 
182
                /* we should already have been disconnected */
 
183
                g_assert (source->priv->connection == NULL);
 
184
        
 
185
                g_free (source->priv->service_name);
 
186
                g_free (source->priv->host);
 
187
                g_free (source->priv);
 
188
                source->priv = NULL;
 
189
        }
 
190
 
 
191
        G_OBJECT_CLASS (rb_daap_source_parent_class)->dispose (object);
 
192
}
 
193
 
 
194
static void
 
195
rb_daap_source_set_property (GObject *object,
 
196
                            guint prop_id,
 
197
                            const GValue *value,
 
198
                            GParamSpec *pspec)
 
199
{
 
200
        RBDAAPSource *source = RB_DAAP_SOURCE (object);
 
201
 
 
202
        switch (prop_id) {
 
203
                case PROP_SERVICE_NAME: 
 
204
                        source->priv->service_name = g_value_dup_string (value);
 
205
                        break;
 
206
                case PROP_HOST:
 
207
                        if (source->priv->host) {
 
208
                                g_free (source->priv->host);
 
209
                        }
 
210
                        source->priv->host = g_value_dup_string (value);
 
211
                        /* FIXME what do we do if its already connected and we
 
212
                         * get a new host? */
 
213
                        break;
 
214
                case PROP_PORT:
 
215
                        source->priv->port = g_value_get_uint (value);
 
216
                        break;
 
217
                case PROP_PASSWORD_PROTECTED:
 
218
                        source->priv->password_protected = g_value_get_boolean (value);
 
219
                        break;
 
220
                default:
 
221
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
222
                        break;
 
223
        }
 
224
}
 
225
 
 
226
static void
 
227
rb_daap_source_get_property (GObject *object,
 
228
                            guint prop_id,
 
229
                            GValue *value,
 
230
                            GParamSpec *pspec)
 
231
{
 
232
        RBDAAPSource *source = RB_DAAP_SOURCE (object);
 
233
 
 
234
        switch (prop_id) {
 
235
                case PROP_SERVICE_NAME:
 
236
                        g_value_set_string (value, source->priv->service_name);
 
237
                        break;
 
238
                case PROP_HOST:
 
239
                        g_value_set_string (value, source->priv->host);
 
240
                        break;
 
241
                case PROP_PORT:
 
242
                        g_value_set_uint (value, source->priv->port);
 
243
                        break;
 
244
                case PROP_PASSWORD_PROTECTED:
 
245
                        g_value_set_boolean (value, source->priv->password_protected);
 
246
                        break;
 
247
                default:
 
248
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
249
                        break;
 
250
        }
 
251
}
 
252
 
 
253
static GdkPixbuf *
 
254
rb_daap_get_icon (void)
 
255
{
 
256
        GdkPixbuf *icon;
 
257
        GtkIconTheme *theme;
 
258
        gint size;
 
259
 
 
260
        theme = gtk_icon_theme_get_default ();
 
261
        gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL);
 
262
        icon = gtk_icon_theme_load_icon (theme, "gnome-fs-network", size, 0, NULL);
 
263
 
 
264
        return icon;
 
265
}
 
266
 
 
267
static RBSource *
 
268
rb_daap_source_new (RBShell *shell,
 
269
                    const gchar *service_name,
 
270
                    const gchar *name,
 
271
                    const gchar *host,
 
272
                    guint port,
 
273
                    gboolean password_protected)
 
274
{
 
275
        RBSource *source;
 
276
        RhythmDBEntryType type;
 
277
 
 
278
        type = rhythmdb_entry_daap_type_new ();
 
279
 
 
280
        source = RB_SOURCE (g_object_new (RB_TYPE_DAAP_SOURCE,
 
281
                                          "service-name", service_name,
 
282
                                          "name", name,
 
283
                                          "host", host,
 
284
                                          "port", port,
 
285
                                          "entry-type", type,
 
286
                                          "icon", rb_daap_get_icon (),
 
287
                                          "shell", shell,
 
288
                                          "visibility", TRUE,
 
289
                                          "sorting-key", CONF_STATE_SORTING,
 
290
                                          "password-protected", password_protected,
 
291
                                          NULL));
 
292
 
 
293
        rb_shell_register_entry_type_for_source (shell, source,
 
294
                                                 type);
 
295
 
 
296
        return source;
 
297
}
 
298
 
 
299
 
 
300
static RBSource *
 
301
find_source_by_service_name (const gchar *service_name)
 
302
{
 
303
        GSList *l;
 
304
 
 
305
        for (l = sources; l != NULL; l = l->next) {
 
306
                RBSource *source = l->data;
 
307
 
 
308
                if (strcmp (service_name, RB_DAAP_SOURCE (source)->priv->service_name) == 0) {
 
309
                        return source;
 
310
                }
 
311
        }
 
312
 
 
313
        return NULL;
 
314
}
 
315
 
 
316
static void
 
317
resolve_cb (RBDAAPmDNSResolver resolver,
 
318
            RBDAAPmDNSResolverStatus status,
 
319
            const gchar *service_name,
 
320
            gchar *name,
 
321
            gchar *host,
 
322
            guint port,
 
323
            gboolean password_protected,
 
324
            RBShell *shell)
 
325
{
 
326
        if (status == RB_DAAP_MDNS_RESOLVER_FOUND) {
 
327
                RBSource *source = find_source_by_service_name (service_name);
 
328
 
 
329
                if (source == NULL) {
 
330
                        source = rb_daap_source_new (shell, service_name, name, host, port, password_protected);
 
331
                        sources = g_slist_prepend (sources, source);
 
332
                        rb_shell_append_source (shell, source, NULL);
 
333
                } else {
 
334
                        g_object_set (G_OBJECT (source),
 
335
                                      "name", name,
 
336
                                      "host", host,
 
337
                                      "port", port,
 
338
                                      "password-protected", password_protected,
 
339
                                      NULL);
 
340
                }
 
341
        } else if (status == RB_DAAP_MDNS_RESOLVER_TIMEOUT) {
 
342
                g_warning ("Unable to resolve %s", service_name);
 
343
        }
 
344
}
 
345
 
 
346
 
 
347
static void
 
348
browse_cb (RBDAAPmDNSBrowser b,
 
349
           RBDAAPmDNSBrowserStatus status,
 
350
           const gchar *service_name,
 
351
           RBShell *shell)
 
352
{
 
353
        if (status == RB_DAAP_MDNS_BROWSER_ADD_SERVICE) {
 
354
                gboolean ret;
 
355
                RBDAAPmDNSResolver *resolver;
 
356
 
 
357
                if (find_source_by_service_name (service_name)) {
 
358
                        rb_debug ("Ignoring duplicate DAAP source");
 
359
                        return;
 
360
                }
 
361
 
 
362
                rb_debug ("New DAAP (music sharing) source '%s' discovered", service_name);
 
363
 
 
364
                /* the resolver takes care of ignoring our own shares,
 
365
                 * if this is us, the callback won't fire
 
366
                 */
 
367
                resolver = g_new0 (RBDAAPmDNSResolver, 1);
 
368
                g_hash_table_insert (service_name_to_resolver, g_strdup (service_name), resolver);
 
369
                ret = rb_daap_mdns_resolve (resolver,
 
370
                                            service_name,
 
371
                                            (RBDAAPmDNSResolverCallback) resolve_cb,
 
372
                                            shell);
 
373
                if (!ret) {
 
374
                        g_warning ("could not start resolving host");
 
375
                }
 
376
 
 
377
        } else if (status == RB_DAAP_MDNS_BROWSER_REMOVE_SERVICE) {
 
378
                RBSource *source = find_source_by_service_name (service_name);
 
379
 
 
380
                rb_debug ("DAAP source '%s' went away", service_name);
 
381
                if (source == NULL) {
 
382
                        /* if this happens, its because the user's own share
 
383
                         * went away.  since that one doesnt resolve,
 
384
                         * it doesnt get added to the sources list
 
385
                         * it does have a resolver tho, so we should remove
 
386
                         * that.
 
387
                         */
 
388
                        g_hash_table_remove (service_name_to_resolver, service_name);
 
389
 
 
390
                        return;
 
391
                }
 
392
 
 
393
                g_hash_table_remove (service_name_to_resolver, service_name);
 
394
                sources = g_slist_remove (sources, source);
 
395
 
 
396
                rb_daap_source_disconnect (source);
 
397
                rb_source_delete_thyself (source);
 
398
                /* unref is done via gtk in rb_shell_source_delete_cb at
 
399
                 * gtk_notebook_remove_page */
 
400
        }
 
401
}
 
402
 
 
403
static void
 
404
stop_resolver (RBDAAPmDNSResolver *resolver)
 
405
{
 
406
        rb_daap_mdns_resolve_cancel (*resolver);
 
407
        g_free (resolver);
 
408
 
 
409
        resolver = NULL;
 
410
}
 
411
 
 
412
 
 
413
static void
 
414
start_browsing (RBShell *shell)
 
415
{
 
416
        if (service_name_to_resolver != NULL)
 
417
                return;
 
418
 
 
419
        gboolean ret = rb_daap_mdns_browse (&browser,
 
420
                                           (RBDAAPmDNSBrowserCallback) browse_cb,
 
421
                                           shell);
 
422
 
 
423
        if (!ret) {
 
424
                g_warning ("Unable to start mDNS browsing");
 
425
                return;
 
426
        }
 
427
 
 
428
        service_name_to_resolver = g_hash_table_new_full ((GHashFunc)g_str_hash,
 
429
                                                          (GEqualFunc)g_str_equal, 
 
430
                                                          (GDestroyNotify)g_free, 
 
431
                                                          (GDestroyNotify)stop_resolver);
 
432
 
 
433
        rb_daap_src_init ();
 
434
}
 
435
 
 
436
static void
 
437
stop_browsing (RBShell *shell)
 
438
{
 
439
        GSList *l;
 
440
 
 
441
        if (service_name_to_resolver == NULL)
 
442
                return;
 
443
 
 
444
        g_hash_table_destroy (service_name_to_resolver);
 
445
        service_name_to_resolver = NULL;
 
446
 
 
447
        for (l = sources; l != NULL; l = l->next) {
 
448
                RBSource *source = l->data;
 
449
 
 
450
                rb_daap_source_disconnect (source);
 
451
                rb_source_delete_thyself (source);
 
452
        }
 
453
 
 
454
        g_slist_free (sources);
 
455
        sources = NULL;
 
456
 
 
457
        if (browser) {
 
458
                rb_daap_mdns_browse_cancel (browser);
 
459
                browser = 0;
 
460
        }
 
461
 
 
462
        rb_daap_src_shutdown ();
 
463
}
 
464
 
 
465
static void
 
466
enable_browsing_changed_cb (GConfClient *client,
 
467
                            guint cnxn_id,
 
468
                            GConfEntry *entry,
 
469
                            RBShell *shell)
 
470
{
 
471
        gboolean enabled = eel_gconf_get_boolean (CONF_ENABLE_BROWSING);
 
472
 
 
473
        if (enabled) {
 
474
                start_browsing (shell);
 
475
        } else {
 
476
                stop_browsing (shell);
 
477
        }
 
478
}
 
479
 
 
480
RBSource *
 
481
rb_daap_sources_init (RBShell *shell)
 
482
{
 
483
        gboolean enabled = TRUE;
 
484
        GConfValue *value;
 
485
        GConfClient *client = eel_gconf_client_get_global ();
 
486
 
 
487
        value = gconf_client_get_without_default (client,
 
488
                                                  CONF_ENABLE_BROWSING, NULL);
 
489
        if (value != NULL) {
 
490
                enabled = gconf_value_get_bool (value);
 
491
                gconf_value_free (value);
 
492
        }
 
493
 
 
494
        g_object_ref (shell);
 
495
 
 
496
        if (enabled) {
 
497
                start_browsing (shell);
 
498
        }
 
499
 
 
500
        enable_browsing_notify_id =
 
501
                eel_gconf_notification_add (CONF_ENABLE_BROWSING,
 
502
                                            (GConfClientNotifyFunc) enable_browsing_changed_cb,
 
503
                                            shell);
 
504
 
 
505
        return NULL;
 
506
}
 
507
 
 
508
void
 
509
rb_daap_sources_shutdown (RBShell *shell)
 
510
{
 
511
        if (browser) {
 
512
                stop_browsing (shell);
 
513
        }
 
514
 
 
515
        if (enable_browsing_notify_id != EEL_GCONF_UNDEFINED_CONNECTION) {
 
516
                eel_gconf_notification_remove (enable_browsing_notify_id);
 
517
                enable_browsing_notify_id = EEL_GCONF_UNDEFINED_CONNECTION;
 
518
        }
 
519
 
 
520
        g_object_unref (shell);
 
521
}
 
522
 
 
523
 
 
524
static void
 
525
rb_daap_source_activate (RBSource *source)
 
526
{
 
527
        RBDAAPSource *daap_source = RB_DAAP_SOURCE (source);
 
528
        RBShell *shell = NULL;
 
529
        RhythmDB *db = NULL;
 
530
        gchar *name = NULL;
 
531
        RhythmDBEntryType type;
 
532
 
 
533
        if (daap_source->priv->connection != NULL) 
 
534
                return;
 
535
 
 
536
        g_object_get (G_OBJECT (daap_source), 
 
537
                      "shell", &shell, 
 
538
                      "entry-type", &type, 
 
539
                      "name", &name, 
 
540
                      NULL);
 
541
        g_object_get (G_OBJECT (shell), "db", &db, NULL);
 
542
 
 
543
        daap_source->priv->connection =
 
544
                rb_daap_connection_new (name,
 
545
                                        daap_source->priv->host,
 
546
                                        daap_source->priv->port,
 
547
                                        daap_source->priv->password_protected,
 
548
                                        db,
 
549
                                        type,
 
550
                                        (RBDAAPConnectionCallback) rb_daap_source_connection_cb,
 
551
                                        source);
 
552
        g_object_unref (G_OBJECT (db));
 
553
        g_object_unref (G_OBJECT (shell));
 
554
        if (daap_source->priv->connection == NULL) {
 
555
                /* XXX can this still happen? */
 
556
                daap_source->priv->playlist_sources = NULL;
 
557
                return;
 
558
        }
 
559
}
 
560
 
 
561
static void
 
562
rb_daap_source_connection_cb (RBDAAPConnection *connection,
 
563
                              gboolean result,
 
564
                              RBSource *source)
 
565
{
 
566
        RBDAAPSource *daap_source = RB_DAAP_SOURCE (source);
 
567
        RBShell *shell = NULL;
 
568
        GSList *playlists;
 
569
        GSList *l;
 
570
        RhythmDBEntryType entry_type;
 
571
 
 
572
        if (result == FALSE) {
 
573
                /* FIXME display error?  should get more info from the connection.. */
 
574
                return;
 
575
        }
 
576
 
 
577
        g_object_get (G_OBJECT (daap_source), 
 
578
                      "shell", &shell, 
 
579
                      "entry-type", &entry_type,
 
580
                      NULL);
 
581
        playlists = rb_daap_connection_get_playlists (daap_source->priv->connection);
 
582
        for (l = playlists; l != NULL; l = g_slist_next (l)) {
 
583
                RBDAAPPlaylist *playlist = l->data;
 
584
                RBSource *playlist_source;
 
585
 
 
586
                playlist_source = RB_SOURCE (g_object_new (RB_TYPE_PLAYLIST_SOURCE,
 
587
                                                           "name", playlist->name,
 
588
                                                           "shell", shell,
 
589
                                                           "visibility", TRUE,
 
590
                                                           "is-local", FALSE,
 
591
                                                           "entry-type", entry_type,
 
592
                                                           NULL));
 
593
                /* this is set here instead of in construction so that
 
594
                 * rb_playlist_source_constructor has a chance to be run to set things up */
 
595
                rb_playlist_source_add_locations (RB_PLAYLIST_SOURCE (playlist_source), playlist->uris);
 
596
 
 
597
                rb_shell_append_source (shell, playlist_source, RB_SOURCE (daap_source));
 
598
                daap_source->priv->playlist_sources = g_slist_prepend (daap_source->priv->playlist_sources, playlist_source);
 
599
        }
 
600
        g_object_unref (G_OBJECT (shell));
 
601
}
 
602
 
 
603
static void
 
604
rb_daap_source_disconnect_cb (RBDAAPConnection *connection,
 
605
                              gboolean result,
 
606
                              RBSource *source)
 
607
{
 
608
        RBDAAPSource *daap_source = RB_DAAP_SOURCE (source);
 
609
        g_object_unref (G_OBJECT (connection));
 
610
        daap_source->priv->connection = NULL;
 
611
        g_object_unref (source);
 
612
}
 
613
 
 
614
static gboolean
 
615
rb_daap_source_disconnect (RBSource *source)
 
616
{
 
617
        RBDAAPSource *daap_source = RB_DAAP_SOURCE (source);
 
618
 
 
619
        if (daap_source->priv->connection) {
 
620
                GSList *l;
 
621
                RBShell *shell;
 
622
                RhythmDB *db;
 
623
                RhythmDBEntryType type;
 
624
 
 
625
                rb_debug ("Disconnecting source");
 
626
 
 
627
                g_object_get (G_OBJECT (source), "shell", &shell, "entry-type", &type, NULL);
 
628
                g_object_get (G_OBJECT (shell), "db", &db, NULL);
 
629
                g_object_unref (G_OBJECT (shell));
 
630
 
 
631
                rhythmdb_entry_delete_by_type (db, type);
 
632
                rhythmdb_commit (db);
 
633
                g_object_unref (G_OBJECT (db));
 
634
 
 
635
                for (l = daap_source->priv->playlist_sources; l!= NULL; l = l->next) {
 
636
                        RBSource *playlist_source = RB_SOURCE (l->data);
 
637
 
 
638
                        rb_source_delete_thyself (playlist_source);
 
639
                }
 
640
 
 
641
                g_slist_free (daap_source->priv->playlist_sources);
 
642
                daap_source->priv->playlist_sources = NULL;
 
643
 
 
644
                /* keep the source alive until the disconnect completes */
 
645
                g_object_ref (daap_source);
 
646
                rb_daap_connection_logout (daap_source->priv->connection,
 
647
                                           (RBDAAPConnectionCallback) rb_daap_source_disconnect_cb,
 
648
                                           daap_source);
 
649
        }
 
650
 
 
651
        return TRUE;
 
652
}
 
653
 
 
654
static gboolean
 
655
rb_daap_source_show_popup (RBSource *source)
 
656
{
 
657
        _rb_source_show_popup (RB_SOURCE (source), "/DAAPSourcePopup");
 
658
        return TRUE;
 
659
}
 
660
 
 
661
RBDAAPSource *
 
662
rb_daap_source_find_for_uri (const gchar *uri)
 
663
{
 
664
        GSList *l;
 
665
        gchar *ip;
 
666
        gchar *s;
 
667
        RBDAAPSource *found_source = NULL;
 
668
 
 
669
        ip = strdup (uri + 7); // daap://
 
670
        s = strchr (ip, ':');
 
671
        *s = '\0';
 
672
 
 
673
        for (l = sources; l != NULL; l = l->next) {
 
674
                RBDAAPSource *source = l->data;
 
675
 
 
676
                if (strcmp (ip, source->priv->host) == 0) {
 
677
                        found_source = source;
 
678
                        break;
 
679
                }
 
680
 
 
681
        }
 
682
 
 
683
        g_free (ip);
 
684
 
 
685
        return found_source;
 
686
}
 
687
 
 
688
gchar *
 
689
rb_daap_source_get_headers (RBDAAPSource *source,
 
690
                            const gchar *uri,
 
691
                            glong time,
 
692
                            gint64 *bytes_out)
 
693
{
 
694
        gint64 bytes = 0;
 
695
 
 
696
        if (time != 0) {
 
697
                RhythmDB *db;
 
698
                RBShell *shell;
 
699
                RhythmDBEntry *entry;
 
700
                gulong bitrate;
 
701
                
 
702
                g_object_get (G_OBJECT (source), "shell", &shell, NULL);
 
703
                g_object_get (G_OBJECT (shell), "db", &db, NULL);
 
704
 
 
705
                entry = rhythmdb_entry_lookup_by_location (db, uri);
 
706
 
 
707
                g_object_unref (G_OBJECT (shell));
 
708
                g_object_unref (G_OBJECT (db));
 
709
                
 
710
                bitrate = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_BITRATE); 
 
711
                // bitrate is kilobits per second
 
712
                // a kilobit is 128 bytes
 
713
                bytes = (time * bitrate) * 128; 
 
714
        }
 
715
        
 
716
        *bytes_out = bytes;
 
717
        return rb_daap_connection_get_headers (source->priv->connection, uri, bytes);
 
718
}
 
719
 
 
720
 
 
721
static const gchar * 
 
722
rb_daap_source_get_browser_key (RBSource *source)
 
723
{
 
724
        return CONF_STATE_SHOW_BROWSER;
 
725
}
 
726
 
 
727
static const gchar * 
 
728
rb_daap_source_get_paned_key (RBLibrarySource *source)
 
729
{
 
730
        return CONF_STATE_PANED_POSITION;
 
731
}
 
732