~ubuntu-branches/ubuntu/precise/rhythmbox/precise-201203091205

« back to all changes in this revision

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

Tags: upstream-0.9.5
ImportĀ upstreamĀ versionĀ 0.9.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 *
16
16
 *  You should have received a copy of the GNU General Public License
17
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.
 
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
19
19
 *
20
20
 */
21
21
 
22
22
#include <config.h>
23
 
#if defined(HAVE_HAL_0_5) || defined(HAVE_HAL_0_2)
24
 
#define HAVE_HAL 1
25
 
#endif
26
23
 
27
24
 
28
25
#include <gtk/gtktreeview.h>
33
30
#include <libhal.h>
34
31
#include <dbus/dbus.h>
35
32
#endif
 
33
#include <libgnomevfs/gnome-vfs-utils.h>
36
34
#include <libgnomevfs/gnome-vfs-volume.h>
37
35
#include <libgnomevfs/gnome-vfs-volume-monitor.h>
38
36
#include <gpod/itdb.h>
39
37
#include "eel-gconf-extensions.h"
40
38
#include "rb-ipod-source.h"
41
39
#include "rb-debug.h"
 
40
#include "rb-file-helpers.h"
 
41
#include "rb-plugin.h"
 
42
#include "rb-removable-media-manager.h"
42
43
#include "rb-static-playlist-source.h"
43
44
#include "rb-util.h"
44
45
#include "rhythmdb.h"
45
46
 
46
 
static GObject *rb_ipod_source_constructor (GType type, guint n_construct_properties,
47
 
                               GObjectConstructParam *construct_properties);
 
47
#ifdef IPOD_PHONE_SUPPORT
 
48
#define PHONE_VENDOR_ID 0x22b8
 
49
#define PHONE_PRODUCT_ID 0x4810
 
50
#endif
 
51
 
 
52
static GObject *rb_ipod_source_constructor (GType type, 
 
53
                                            guint n_construct_properties,
 
54
                                            GObjectConstructParam *construct_properties);
48
55
static void rb_ipod_source_dispose (GObject *object);
49
56
 
50
57
static GObject *rb_ipod_source_constructor (GType type, guint n_construct_properties,
52
59
static void rb_ipod_source_dispose (GObject *object);
53
60
 
54
61
static gboolean impl_show_popup (RBSource *source);
 
62
static void impl_move_to_trash (RBSource *asource);
55
63
static void rb_ipod_load_songs (RBiPodSource *source);
56
64
static gchar *rb_ipod_get_mount_path (GnomeVFSVolume *volume);
57
65
static void impl_delete_thyself (RBSource *source);
58
 
 
 
66
static GList* impl_get_ui_actions (RBSource *source);
59
67
#ifdef HAVE_HAL
60
68
static gboolean hal_udi_is_ipod (const char *udi);
61
69
#endif
62
70
 
 
71
#ifdef ENABLE_IPOD_WRITING
 
72
static void impl_paste (RBSource *source, GList *entries);
 
73
static gboolean impl_receive_drag (RBSource *asource, GtkSelectionData *data);
 
74
static gchar *
 
75
ipod_get_filename_for_uri (const gchar *mount_point, const gchar *uri_str);
 
76
static gchar *
 
77
ipod_path_from_unix_path (const gchar *mount_point, const gchar *unix_path);
 
78
#endif
 
79
static void itdb_schedule_save (Itdb_iTunesDB *db);
 
80
 
 
81
 
63
82
typedef struct
64
83
{
65
84
        Itdb_iTunesDB *ipod_db;
66
85
        gchar *ipod_mount_path;
 
86
        GHashTable *entry_map;
67
87
} RBiPodSourcePrivate;
68
88
 
69
89
 
70
 
G_DEFINE_TYPE (RBiPodSource, rb_ipod_source, RB_TYPE_REMOVABLE_MEDIA_SOURCE)
 
90
RB_PLUGIN_DEFINE_TYPE(RBiPodSource, 
 
91
                      rb_ipod_source, 
 
92
                      RB_TYPE_REMOVABLE_MEDIA_SOURCE)
 
93
 
71
94
#define IPOD_SOURCE_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_IPOD_SOURCE, RBiPodSourcePrivate))
72
95
 
73
96
 
82
105
 
83
106
        source_class->impl_show_popup = impl_show_popup;
84
107
        source_class->impl_delete_thyself = impl_delete_thyself;
 
108
        source_class->impl_can_move_to_trash = (RBSourceFeatureFunc) rb_true_function;
 
109
        source_class->impl_move_to_trash = impl_move_to_trash;
 
110
        source_class->impl_can_rename = (RBSourceFeatureFunc) rb_true_function;
 
111
        source_class->impl_get_ui_actions = impl_get_ui_actions;
 
112
#ifdef ENABLE_IPOD_WRITING
 
113
        source_class->impl_can_paste = (RBSourceFeatureFunc) rb_true_function;
 
114
        source_class->impl_paste = impl_paste;
 
115
        source_class->impl_receive_drag = impl_receive_drag;
 
116
#endif
85
117
 
86
118
        g_type_class_add_private (klass, sizeof (RBiPodSourcePrivate));
87
119
}
88
120
 
89
121
static void
 
122
rb_ipod_source_set_ipod_name (RBiPodSource *source, const char *name)
 
123
{
 
124
        Itdb_Playlist *mpl;
 
125
        RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
 
126
 
 
127
        mpl = itdb_playlist_mpl (priv->ipod_db);
 
128
        rb_debug ("Renaming iPod from %s to %s", mpl->name, name);
 
129
        if (strcmp (mpl->name, name) == 0) {
 
130
                rb_debug ("iPod is already named %s", name);
 
131
                return;
 
132
        }
 
133
        g_free (mpl->name);
 
134
        mpl->name = g_strdup (name);
 
135
        itdb_schedule_save (priv->ipod_db);
 
136
}
 
137
 
 
138
static void
 
139
rb_ipod_source_name_changed_cb (RBiPodSource *source, GParamSpec *spec, 
 
140
                                gpointer data)
 
141
{
 
142
        char *name;
 
143
 
 
144
        g_object_get (RB_SOURCE (source), "name", &name, NULL);
 
145
        rb_ipod_source_set_ipod_name (source, name);
 
146
        g_free (name);
 
147
}
 
148
 
 
149
static void
90
150
rb_ipod_source_init (RBiPodSource *source)
91
151
{
92
 
 
 
152
        g_signal_connect (G_OBJECT (source), "notify::name", 
 
153
                          (GCallback)rb_ipod_source_name_changed_cb, NULL);
93
154
}
94
155
 
95
156
static GObject *
96
157
rb_ipod_source_constructor (GType type, guint n_construct_properties,
97
 
                               GObjectConstructParam *construct_properties)
 
158
                            GObjectConstructParam *construct_properties)
98
159
{
99
 
        GObjectClass *klass, *parent_class; 
100
 
        RBiPodSource *source; 
101
 
 
102
 
        klass = G_OBJECT_CLASS (g_type_class_peek (type));
103
 
        parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
104
 
        source = RB_IPOD_SOURCE (parent_class->constructor (type, n_construct_properties, construct_properties));
 
160
        RBiPodSource *source;
 
161
        RBEntryView *songs;
 
162
        RBiPodSourcePrivate *priv;
 
163
 
 
164
        source = RB_IPOD_SOURCE (G_OBJECT_CLASS (rb_ipod_source_parent_class)->
 
165
                        constructor (type, n_construct_properties, construct_properties));
 
166
        priv = IPOD_SOURCE_GET_PRIVATE (source);
 
167
 
 
168
        songs = rb_source_get_entry_view (RB_SOURCE (source));
 
169
        rb_entry_view_append_column (songs, RB_ENTRY_VIEW_COL_RATING, FALSE);
 
170
        rb_entry_view_append_column (songs, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);
105
171
 
106
172
        rb_ipod_load_songs (source);
107
173
 
123
189
                priv->ipod_mount_path = NULL;
124
190
        }
125
191
 
 
192
        if (priv->entry_map) {
 
193
                g_hash_table_destroy (priv->entry_map);
 
194
                priv->entry_map = NULL;
 
195
        }
 
196
 
126
197
        G_OBJECT_CLASS (rb_ipod_source_parent_class)->dispose (object);
127
198
}
128
199
 
134
205
 
135
206
        g_assert (rb_ipod_is_volume_ipod (volume));
136
207
 
137
 
        entry_type =  rhythmdb_entry_register_type ();
 
208
        entry_type =  rhythmdb_entry_register_type (NULL);
138
209
 
139
210
        source = RB_IPOD_SOURCE (g_object_new (RB_TYPE_IPOD_SOURCE,
140
211
                                          "entry-type", entry_type,
141
212
                                          "volume", volume,
142
213
                                          "shell", shell,
 
214
                                          "sourcelist-group", RB_SOURCELIST_GROUP_REMOVABLE,
143
215
                                          NULL));
144
216
 
145
217
        rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), entry_type);
237
309
 
238
310
}
239
311
 
 
312
#ifdef ENABLE_IPOD_WRITING
 
313
static Itdb_Track *
 
314
create_ipod_song_from_entry (RhythmDBEntry *entry)
 
315
{
 
316
        Itdb_Track *track;
 
317
 
 
318
        track = itdb_track_new ();
 
319
 
 
320
        track->title = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_TITLE);
 
321
        track->album = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ALBUM);
 
322
        track->artist = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ARTIST);
 
323
        track->genre = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_GENRE);
 
324
        /*      track->filetype = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP);*/
 
325
        track->size = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE);
 
326
        track->tracklen = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION);
 
327
        track->tracklen *= 1000;
 
328
        track->cd_nr = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DISC_NUMBER);
 
329
        track->track_nr = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER);
 
330
        track->bitrate = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_BITRATE);
 
331
        track->year = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DATE);
 
332
        track->time_added = itdb_time_get_mac_time ();
 
333
        track->time_played = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_LAST_PLAYED);
 
334
        track->time_played = itdb_time_host_to_mac (track->time_played);
 
335
        track->rating = rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_RATING);
 
336
        track->app_rating = track->rating;
 
337
        track->playcount = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_PLAY_COUNT);
 
338
 
 
339
        return track;
 
340
}
 
341
#endif
 
342
 
 
343
static void
 
344
add_ipod_song_to_db (RBiPodSource *source, RhythmDB *db, Itdb_Track *song)
 
345
{       
 
346
        RhythmDBEntry *entry;
 
347
        RhythmDBEntryType entry_type;
 
348
        RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
 
349
        char *pc_path;
 
350
 
 
351
        /* Set URI */
 
352
        g_object_get (G_OBJECT (source), "entry-type", &entry_type, 
 
353
                      NULL);
 
354
 
 
355
        pc_path = ipod_path_to_uri (priv->ipod_mount_path, 
 
356
                                    song->ipod_path);
 
357
        entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type,
 
358
                                    pc_path);
 
359
 
 
360
        if (entry == NULL) {
 
361
                rb_debug ("cannot create entry %s", pc_path);
 
362
                g_free (pc_path);
 
363
                return;
 
364
        }
 
365
                
 
366
        rb_debug ("Adding %s from iPod", pc_path);
 
367
        g_free (pc_path);
 
368
 
 
369
        /* Set track number */
 
370
        if (song->track_nr != 0) {
 
371
                GValue value = {0, };
 
372
                g_value_init (&value, G_TYPE_ULONG);
 
373
                g_value_set_ulong (&value, song->track_nr);
 
374
                rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
 
375
                                               RHYTHMDB_PROP_TRACK_NUMBER, 
 
376
                                               &value);
 
377
                g_value_unset (&value);
 
378
        }
 
379
 
 
380
        /* Set disc number */
 
381
        if (song->cd_nr != 0) {
 
382
                GValue value = {0, };
 
383
                g_value_init (&value, G_TYPE_ULONG);
 
384
                g_value_set_ulong (&value, song->cd_nr);
 
385
                rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
 
386
                                               RHYTHMDB_PROP_DISC_NUMBER, 
 
387
                                               &value);
 
388
                g_value_unset (&value);
 
389
        }
 
390
                
 
391
        /* Set bitrate */
 
392
        if (song->bitrate != 0) {
 
393
                GValue value = {0, };
 
394
                g_value_init (&value, G_TYPE_ULONG);
 
395
                g_value_set_ulong (&value, song->bitrate);
 
396
                rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
 
397
                                               RHYTHMDB_PROP_BITRATE, 
 
398
                                               &value);
 
399
                g_value_unset (&value);
 
400
        }
 
401
                
 
402
        /* Set length */
 
403
        if (song->tracklen != 0) {
 
404
                GValue value = {0, };
 
405
                g_value_init (&value, G_TYPE_ULONG);
 
406
                g_value_set_ulong (&value, song->tracklen/1000);
 
407
                rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
 
408
                                               RHYTHMDB_PROP_DURATION, 
 
409
                                               &value);
 
410
                g_value_unset (&value);
 
411
        }
 
412
                
 
413
        /* Set file size */
 
414
        if (song->size != 0) {
 
415
                GValue value = {0, };
 
416
                g_value_init (&value, G_TYPE_UINT64);
 
417
                g_value_set_uint64 (&value, song->size);
 
418
                rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
 
419
                                               RHYTHMDB_PROP_FILE_SIZE, 
 
420
                                               &value);
 
421
                g_value_unset (&value);
 
422
        }
 
423
 
 
424
        /* Set playcount */
 
425
        if (song->playcount != 0) {
 
426
                GValue value = {0, };
 
427
                g_value_init (&value, G_TYPE_ULONG);
 
428
                g_value_set_ulong (&value, song->playcount);
 
429
                rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
 
430
                                               RHYTHMDB_PROP_PLAY_COUNT,
 
431
                                               &value);
 
432
                g_value_unset (&value);
 
433
        }
 
434
 
 
435
        /* Set year */
 
436
        if (song->year != 0) {
 
437
                GDate *date = NULL;
 
438
                GType type;
 
439
                GValue value = {0, };
 
440
                        
 
441
                date = g_date_new_dmy (1, G_DATE_JANUARY, song->year);
 
442
 
 
443
                type = rhythmdb_get_property_type (RHYTHMDB(db),
 
444
                                                   RHYTHMDB_PROP_DATE);
 
445
                        
 
446
                g_value_init (&value, type);
 
447
                g_value_set_ulong (&value, (date ? g_date_get_julian (date) : 0));
 
448
                        
 
449
                rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
 
450
                                               RHYTHMDB_PROP_DATE,
 
451
                                               &value);
 
452
                g_value_unset (&value);
 
453
                if (date)
 
454
                        g_date_free (date);
 
455
        }
 
456
 
 
457
        /* Set rating */
 
458
        if (song->rating != 0) {
 
459
                GValue value = {0, };
 
460
                g_value_init (&value, G_TYPE_DOUBLE);
 
461
                g_value_set_double (&value, song->rating/20.0);
 
462
                rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
 
463
                                               RHYTHMDB_PROP_RATING,
 
464
                                               &value);
 
465
                g_value_unset (&value);
 
466
        }
 
467
                
 
468
        /* Set last played */
 
469
        if (song->time_played != 0) {
 
470
                GValue value = {0, };
 
471
                g_value_init (&value, G_TYPE_ULONG);
 
472
                g_value_set_ulong (&value, itdb_time_mac_to_host (song->time_played));
 
473
                rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
 
474
                                               RHYTHMDB_PROP_LAST_PLAYED,
 
475
                                               &value);
 
476
                g_value_unset (&value);
 
477
        }
 
478
                
 
479
        /* Set title */         
 
480
        entry_set_string_prop (RHYTHMDB (db), entry, 
 
481
                               RHYTHMDB_PROP_TITLE, song->title);
 
482
                
 
483
        /* Set album, artist and genre from iTunesDB */
 
484
        entry_set_string_prop (RHYTHMDB (db), entry, 
 
485
                               RHYTHMDB_PROP_ARTIST, song->artist);
 
486
                
 
487
        entry_set_string_prop (RHYTHMDB (db), entry, 
 
488
                               RHYTHMDB_PROP_ALBUM, song->album);
 
489
                
 
490
        entry_set_string_prop (RHYTHMDB (db), entry, 
 
491
                               RHYTHMDB_PROP_GENRE, song->genre);
 
492
 
 
493
 
 
494
        g_hash_table_insert (priv->entry_map, entry, song);
 
495
 
 
496
        rhythmdb_commit (RHYTHMDB (db));
 
497
}
 
498
 
240
499
static gboolean
241
500
load_ipod_db_idle_cb (RBiPodSource *source)
242
501
{
251
510
  
252
511
        g_assert (db != NULL);
253
512
        for (it = priv->ipod_db->tracks; it != NULL; it = it->next) {
254
 
                Itdb_Track *song;
255
 
                RhythmDBEntry *entry;
256
 
                RhythmDBEntryType entry_type;
257
 
                char *pc_path;
258
 
 
259
 
                song = (Itdb_Track *)it->data;
260
 
                
261
 
                /* Set URI */
262
 
                g_object_get (G_OBJECT (source), "entry-type", &entry_type, 
263
 
                              NULL);
264
 
 
265
 
                pc_path = ipod_path_to_uri (priv->ipod_mount_path, 
266
 
                                            song->ipod_path);
267
 
                entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type,
268
 
                                            pc_path);
269
 
 
270
 
                if (entry == NULL) {
271
 
                        rb_debug ("cannot create entry %s", pc_path);
272
 
                        g_free (pc_path);
273
 
                        continue;
274
 
                }
275
 
                
276
 
                rb_debug ("Adding %s from iPod", pc_path);
277
 
                g_free (pc_path);
278
 
 
279
 
                /* Set track number */
280
 
                if (song->track_nr != 0) {
281
 
                        GValue value = {0, };
282
 
                        g_value_init (&value, G_TYPE_ULONG);
283
 
                        g_value_set_ulong (&value, song->track_nr);
284
 
                        rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
285
 
                                                       RHYTHMDB_PROP_TRACK_NUMBER, 
286
 
                                                       &value);
287
 
                        g_value_unset (&value);
288
 
                }
289
 
 
290
 
                /* Set disc number */
291
 
                if (song->cd_nr != 0) {
292
 
                        GValue value = {0, };
293
 
                        g_value_init (&value, G_TYPE_ULONG);
294
 
                        g_value_set_ulong (&value, song->cd_nr);
295
 
                        rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
296
 
                                                       RHYTHMDB_PROP_DISC_NUMBER, 
297
 
                                                       &value);
298
 
                        g_value_unset (&value);
299
 
                }
300
 
                
301
 
                /* Set bitrate */
302
 
                if (song->bitrate != 0) {
303
 
                        GValue value = {0, };
304
 
                        g_value_init (&value, G_TYPE_ULONG);
305
 
                        g_value_set_ulong (&value, song->bitrate);
306
 
                        rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
307
 
                                                       RHYTHMDB_PROP_BITRATE, 
308
 
                                                       &value);
309
 
                        g_value_unset (&value);
310
 
                }
311
 
                
312
 
                /* Set length */
313
 
                if (song->tracklen != 0) {
314
 
                        GValue value = {0, };
315
 
                        g_value_init (&value, G_TYPE_ULONG);
316
 
                        g_value_set_ulong (&value, song->tracklen/1000);
317
 
                        rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
318
 
                                                       RHYTHMDB_PROP_DURATION, 
319
 
                                                       &value);
320
 
                        g_value_unset (&value);
321
 
                }
322
 
                
323
 
                /* Set file size */
324
 
                if (song->size != 0) {
325
 
                        GValue value = {0, };
326
 
                        g_value_init (&value, G_TYPE_UINT64);
327
 
                        g_value_set_uint64 (&value, song->size);
328
 
                        rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry, 
329
 
                                                       RHYTHMDB_PROP_FILE_SIZE, 
330
 
                                                       &value);
331
 
                        g_value_unset (&value);
332
 
                }
333
 
 
334
 
                /* Set playcount */
335
 
                if (song->playcount != 0) {
336
 
                        GValue value = {0, };
337
 
                        g_value_init (&value, G_TYPE_ULONG);
338
 
                        g_value_set_ulong (&value, song->playcount);
339
 
                        rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
340
 
                                                       RHYTHMDB_PROP_PLAY_COUNT,
341
 
                                                       &value);
342
 
                        g_value_unset (&value);
343
 
                }
344
 
 
345
 
                /* Set year */
346
 
                if (song->year != 0) {
347
 
                        GDate *date = NULL;
348
 
                        GType type;
349
 
                        GValue value = {0, };
350
 
                        
351
 
                        date = g_date_new_dmy (1, G_DATE_JANUARY, song->year);
352
 
 
353
 
                        type = rhythmdb_get_property_type (RHYTHMDB(db),
354
 
                                                            RHYTHMDB_PROP_DATE);
355
 
                        
356
 
                        g_value_init (&value, type);
357
 
                        g_value_set_ulong (&value, (date ? g_date_get_julian (date) : 0));
358
 
                        
359
 
                        rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
360
 
                                                       RHYTHMDB_PROP_DATE,
361
 
                                                       &value);
362
 
                        g_value_unset (&value);
363
 
                        if (date)
364
 
                                g_date_free (date);
365
 
                }
366
 
 
367
 
                /* Set title */         
368
 
                entry_set_string_prop (RHYTHMDB (db), entry, 
369
 
                                       RHYTHMDB_PROP_TITLE, song->title);
370
 
                
371
 
                /* Set album, artist and genre from iTunesDB */
372
 
                entry_set_string_prop (RHYTHMDB (db), entry, 
373
 
                                       RHYTHMDB_PROP_ARTIST, song->artist);
374
 
                
375
 
                entry_set_string_prop (RHYTHMDB (db), entry, 
376
 
                                       RHYTHMDB_PROP_ALBUM, song->album);
377
 
                
378
 
                entry_set_string_prop (RHYTHMDB (db), entry, 
379
 
                                       RHYTHMDB_PROP_GENRE, song->genre);
380
 
                
381
 
                rhythmdb_commit (RHYTHMDB (db));
382
 
        
 
513
                add_ipod_song_to_db (source, db, (Itdb_Track *)it->data);
383
514
        }
384
515
 
385
516
        load_ipod_playlists (source);
398
529
        priv->ipod_mount_path = rb_ipod_get_mount_path (volume);
399
530
 
400
531
        priv->ipod_db = itdb_parse (priv->ipod_mount_path, NULL);
401
 
        if (priv->ipod_db != NULL) {
 
532
        priv->entry_map = g_hash_table_new (g_direct_hash, g_direct_equal);
 
533
        if ((priv->ipod_db != NULL) && (priv->entry_map != NULL)) {
 
534
                /* FIXME: we could set a different icon depending on the iPod
 
535
                 * model
 
536
                 */
 
537
                g_object_set (RB_SOURCE (source), 
 
538
                              "name", itdb_playlist_mpl (priv->ipod_db)->name, 
 
539
                              NULL);
402
540
                g_idle_add ((GSourceFunc)load_ipod_db_idle_cb, source);
403
541
        }
404
542
}
433
571
        if (mount_point == NULL) {
434
572
                return NULL;
435
573
        }
 
574
        
 
575
#ifdef IPOD_PHONE_SUPPORT
 
576
        result = itdb_get_itunesdb_path (mount_point);
 
577
#else
436
578
        result = g_build_filename (mount_point, 
437
579
                                   "iPod_Control/iTunes/iTunesDB",
438
580
                                   NULL);
 
581
#endif
 
582
        
439
583
        g_free (mount_point);
440
584
        return result;
441
585
}
442
586
 
 
587
static gboolean
 
588
rb_ipod_volume_has_ipod_db (GnomeVFSVolume *volume)
 
589
{
 
590
        char *itunesdb_path;
 
591
        gboolean result;
 
592
 
 
593
        itunesdb_path = rb_ipod_get_itunesdb_path (volume);
 
594
 
 
595
        if (itunesdb_path != NULL) {
 
596
                result = g_file_test (itunesdb_path, G_FILE_TEST_EXISTS);
 
597
        } else {
 
598
                result = FALSE;
 
599
        }
 
600
        g_free (itunesdb_path);
 
601
 
 
602
        return result;
 
603
}
 
604
 
443
605
gboolean
444
606
rb_ipod_is_volume_ipod (GnomeVFSVolume *volume)
445
607
{
446
 
        gchar *itunesdb_path;
447
 
        gboolean result = FALSE;
448
608
#ifdef HAVE_HAL
449
609
        gchar *udi;
450
610
#endif
459
619
 
460
620
                result = hal_udi_is_ipod (udi);
461
621
                g_free (udi);
462
 
                return result;
 
622
                if (result == FALSE) {
 
623
                        return FALSE;
 
624
                }
463
625
        }
464
626
#endif
465
627
        
466
 
        itunesdb_path = rb_ipod_get_itunesdb_path (volume);
467
 
        if (itunesdb_path != NULL) {
468
 
                result = g_file_test (itunesdb_path, G_FILE_TEST_EXISTS);
469
 
                g_free (itunesdb_path);
470
 
        }
471
 
 
472
 
        return result;
 
628
        return rb_ipod_volume_has_ipod_db (volume);
473
629
}
474
630
 
475
631
#ifdef HAVE_HAL_0_5
510
666
                
511
667
        parent_name = libhal_device_get_property_string (ctx, parent_udi,
512
668
                        "storage.model", &error);
 
669
#ifdef IPOD_PHONE_SUPPORT
 
670
        {
 
671
                char *spider_udi;
 
672
                int vnd_id = 0;
 
673
                int product_id = 0;
 
674
 
 
675
                spider_udi = g_strdup(parent_udi);
 
676
                while (vnd_id == 0 && product_id == 0 && spider_udi != NULL) {
 
677
                        char *old_udi = spider_udi;
 
678
                        spider_udi =  libhal_device_get_property_string (ctx, spider_udi,
 
679
                                        "info.parent", &error);
 
680
                        if (dbus_error_is_set (&error)) {
 
681
                                dbus_error_free (&error);
 
682
                                dbus_error_init (&error);
 
683
                                spider_udi = NULL;
 
684
                                break;
 
685
                        }
 
686
                        g_free(old_udi);
 
687
 
 
688
                        vnd_id = libhal_device_get_property_int (ctx, spider_udi,
 
689
                                "usb.vendor_id", &error);
 
690
                        if (dbus_error_is_set(&error)) {
 
691
                                dbus_error_free (&error);
 
692
                                dbus_error_init (&error);
 
693
                                vnd_id = 0;
 
694
                        }
 
695
 
 
696
                        product_id = libhal_device_get_property_int (ctx, spider_udi,
 
697
                                "usb.product_id", &error);
 
698
                        if (dbus_error_is_set(&error)) {
 
699
                                dbus_error_free (&error);
 
700
                                dbus_error_init (&error);
 
701
                                product_id = 0;
 
702
                        }
 
703
                }
 
704
                g_free(spider_udi);
 
705
 
 
706
                if (vnd_id == PHONE_VENDOR_ID && product_id == PHONE_PRODUCT_ID) {
 
707
                        result = TRUE;
 
708
                }
 
709
        }
 
710
#endif
513
711
        g_free (parent_udi);
514
712
        if (parent_name == NULL || dbus_error_is_set (&error))
515
713
                goto end;
570
768
 
571
769
#endif
572
770
 
 
771
static GList*
 
772
impl_get_ui_actions (RBSource *source)
 
773
{
 
774
        GList *actions = NULL;
 
775
 
 
776
        actions = g_list_prepend (actions, g_strdup ("RemovableSourceEject"));
 
777
 
 
778
        return actions;
 
779
}
 
780
 
 
781
 
573
782
static gboolean
574
783
impl_show_popup (RBSource *source)
575
784
{
577
786
        return TRUE;
578
787
}
579
788
 
 
789
 
 
790
static void
 
791
remove_track_from_db (Itdb_Track *track)
 
792
{
 
793
        GList *it;
 
794
 
 
795
        for (it = track->itdb->playlists; it != NULL; it = it->next) {
 
796
                itdb_playlist_remove_track ((Itdb_Playlist *)it->data, track);
 
797
        }
 
798
        itdb_track_remove (track);
 
799
}
 
800
 
 
801
static void
 
802
impl_move_to_trash (RBSource *asource)
 
803
{
 
804
        GList *sel, *tem;
 
805
        RBEntryView *songs;
 
806
        RBShell *shell;
 
807
        RhythmDB *db;
 
808
        RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (asource);
 
809
        RBiPodSource *source = RB_IPOD_SOURCE (asource);
 
810
 
 
811
        g_object_get (G_OBJECT (source), "shell", &shell, NULL);
 
812
        g_object_get (G_OBJECT (shell), "db", &db, NULL);
 
813
        g_object_unref (G_OBJECT (shell));
 
814
 
 
815
        songs = rb_source_get_entry_view (RB_SOURCE (asource));
 
816
        sel = rb_entry_view_get_selected_entries (songs);
 
817
        for (tem = sel; tem != NULL; tem = tem->next) {
 
818
                RhythmDBEntry *entry;
 
819
                const gchar *uri;
 
820
                Itdb_Track *track;
 
821
 
 
822
                entry = (RhythmDBEntry *)tem->data;
 
823
                uri = rhythmdb_entry_get_string (entry, 
 
824
                                                 RHYTHMDB_PROP_LOCATION);
 
825
                track = g_hash_table_lookup (priv->entry_map, entry);
 
826
                if (track == NULL) {
 
827
                        g_warning ("Couldn't find track on ipod! (%s)", uri);
 
828
                        continue;
 
829
                }
 
830
 
 
831
                remove_track_from_db (track);
 
832
                g_hash_table_remove (priv->entry_map, entry);
 
833
                rhythmdb_entry_move_to_trash (db, entry);
 
834
                rhythmdb_commit (db);
 
835
        }
 
836
        if (sel != NULL) {
 
837
                itdb_write (priv->ipod_db, NULL);
 
838
        }
 
839
 
 
840
        g_list_free (sel);
 
841
}
 
842
 
 
843
static void
 
844
itdb_schedule_save (Itdb_iTunesDB *db)
 
845
{
 
846
       /* FIXME: should probably be delayed a bit to avoid doing
 
847
        * it after each file when we are copying several files
 
848
        * consecutively
 
849
        * FIXME: or this function could be called itdb_set_dirty, and we'd
 
850
        * have a timeout firing every 5 seconds and saving the db if it's
 
851
        * dirty
 
852
        */
 
853
       itdb_write (db, NULL);
 
854
}
 
855
 
 
856
 
 
857
#ifdef ENABLE_IPOD_WRITING
 
858
static char *
 
859
build_filename (RBSource *asource, RhythmDBEntry *entry)
 
860
{
 
861
        const char *uri;
 
862
        char *dest;
 
863
        char *dest_uri;
 
864
 
 
865
        RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (asource);
 
866
 
 
867
        uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
 
868
        dest = ipod_get_filename_for_uri (priv->ipod_mount_path,  uri);
 
869
        if (dest != NULL) {
 
870
                dest_uri = g_filename_to_uri (dest, NULL, NULL);
 
871
                g_free (dest);
 
872
                return dest_uri;
 
873
        }
 
874
 
 
875
        return NULL;
 
876
}
 
877
 
 
878
static void
 
879
completed_cb (RhythmDBEntry *entry, const char *dest, RBiPodSource *source)
 
880
{
 
881
        RBShell *shell;
 
882
        RhythmDB *db;
 
883
        Itdb_Track *song;
 
884
 
 
885
        g_object_get (G_OBJECT (source), "shell", &shell, NULL);
 
886
        g_object_get (G_OBJECT (shell), "db", &db, NULL);
 
887
        g_object_unref (G_OBJECT (shell));
 
888
 
 
889
        song = create_ipod_song_from_entry (entry);
 
890
        if (song != NULL) {
 
891
                RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
 
892
                char *filename;
 
893
 
 
894
                filename = g_filename_from_uri (dest, NULL, NULL);
 
895
                song->ipod_path = ipod_path_from_unix_path (priv->ipod_mount_path, filename);
 
896
                g_free (filename);
 
897
                itdb_track_add (priv->ipod_db, song, -1);
 
898
                itdb_playlist_add_track (itdb_playlist_mpl (priv->ipod_db),
 
899
                                         song, -1);
 
900
 
 
901
                add_ipod_song_to_db (source, db, song);
 
902
                itdb_schedule_save (priv->ipod_db);
 
903
        }
 
904
 
 
905
        g_object_unref (db);
 
906
}
 
907
 
 
908
static void
 
909
impl_paste (RBSource *asource, GList *entries)
 
910
{
 
911
        RBRemovableMediaManager *rm_mgr;
 
912
        GList *l;
 
913
        RBShell *shell;
 
914
 
 
915
        g_object_get (G_OBJECT (asource), "shell", &shell, NULL);
 
916
        g_object_get (G_OBJECT (shell),
 
917
                      "removable-media-manager", &rm_mgr,
 
918
                      NULL);
 
919
        g_object_unref (G_OBJECT (shell));
 
920
 
 
921
        for (l = entries; l != NULL; l = l->next) {
 
922
                RhythmDBEntry *entry;
 
923
                RhythmDBEntryType entry_type;
 
924
                RhythmDBEntryType ipod_entry_type;
 
925
                char *dest;
 
926
 
 
927
                entry = (RhythmDBEntry *)l->data;
 
928
                entry_type = rhythmdb_entry_get_entry_type (entry);
 
929
                g_object_get (G_OBJECT (asource),
 
930
                              "entry-type", &ipod_entry_type,
 
931
                              NULL);
 
932
                if (entry_type == RHYTHMDB_ENTRY_TYPE_IRADIO_STATION ||
 
933
                    entry_type == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED ||
 
934
//                  entry_type == RHYTHMDB_ENTRY_TYPE_PODCAST_EPISODE ||
 
935
                    entry_type == ipod_entry_type)
 
936
                        continue;
 
937
 
 
938
                dest = build_filename (asource, entry);
 
939
                if (dest == NULL) {
 
940
                        rb_debug ("could not create destination path for entry");
 
941
                        continue;
 
942
                }
 
943
                rb_removable_media_manager_queue_transfer (rm_mgr, entry,
 
944
                                                           dest, NULL,
 
945
                                                           (RBTranferCompleteCallback)completed_cb, asource);
 
946
                g_free (dest);
 
947
        }
 
948
        g_object_unref (G_OBJECT (rm_mgr));
 
949
}
 
950
 
 
951
 
 
952
static gboolean
 
953
impl_receive_drag (RBSource *asource, GtkSelectionData *data)
 
954
{
 
955
        RBBrowserSource *source = RB_BROWSER_SOURCE (asource);
 
956
        GList *list, *i;
 
957
        GList *entries = NULL;
 
958
        RBShell *shell;
 
959
        RhythmDB *db;
 
960
 
 
961
        rb_debug ("parsing uri list");
 
962
        list = rb_uri_list_parse ((const char *) data->data);
 
963
 
 
964
        g_object_get (G_OBJECT (source), "shell", &shell, NULL);
 
965
        g_object_get (G_OBJECT (shell), "db", &db, NULL);
 
966
        g_object_unref (G_OBJECT (shell));
 
967
 
 
968
        for (i = list; i != NULL; i = g_list_next (i)) {
 
969
                if (i->data != NULL) {
 
970
                        char *uri = i->data;
 
971
                        RhythmDBEntry *entry;
 
972
 
 
973
                        entry = rhythmdb_entry_lookup_by_location (db, uri);
 
974
 
 
975
                        if (entry == NULL) {
 
976
                                /* add to the library */
 
977
                                g_print ("Where does that come from?\n");
 
978
                        } else {
 
979
                                /* add to list of entries to copy */
 
980
                                entries = g_list_prepend (entries, entry);
 
981
                        }
 
982
 
 
983
                        g_free (uri);
 
984
                }
 
985
        }
 
986
        g_object_unref (db);
 
987
        g_list_free (list);
 
988
 
 
989
        if (entries) {
 
990
                entries = g_list_reverse (entries);
 
991
                if (rb_source_can_paste (asource))
 
992
                        rb_source_paste (asource, entries);
 
993
                g_list_free (entries);
 
994
        }
 
995
 
 
996
 
 
997
        return TRUE;
 
998
}
 
999
 
 
1000
 
 
1001
/* Generation of the filename for the ipod */
 
1002
 
 
1003
#define IPOD_MAX_PATH_LEN 56
 
1004
 
 
1005
static gboolean
 
1006
test_dir_on_ipod (const char *mountpoint, const char *dirname)
 
1007
{
 
1008
        char *fullpath;
 
1009
        gboolean result;
 
1010
 
 
1011
        fullpath  = g_build_filename (mountpoint, dirname, NULL);
 
1012
        result = g_file_test (fullpath, G_FILE_TEST_IS_DIR);
 
1013
        g_free (fullpath);
 
1014
        
 
1015
        return result;
 
1016
}
 
1017
 
 
1018
static int
 
1019
ipod_mkdir_with_parents (const char *mountpoint, const char *dirname)
 
1020
{
 
1021
        char *fullpath;
 
1022
        int result;
 
1023
 
 
1024
        fullpath  = g_build_filename (mountpoint, dirname, NULL);
 
1025
        result = g_mkdir_with_parents (fullpath, 0770);
 
1026
        g_free (fullpath);
 
1027
        
 
1028
        return result;
 
1029
}
 
1030
 
 
1031
static gchar *
 
1032
build_ipod_dir_name (const char *mountpoint)
 
1033
{
 
1034
        /* FAT sucks, filename can be lowercase or uppercase, and if we try to
 
1035
         * open the wrong one, we lose :-/
 
1036
         */
 
1037
        char *dirname;
 
1038
        char *relpath;
 
1039
        gint32 suffix;
 
1040
        
 
1041
        suffix = g_random_int_range (0, 100);
 
1042
        dirname = g_strdup_printf ("F%02d", suffix);
 
1043
        relpath = g_build_filename (G_DIR_SEPARATOR_S, "iPod_Control",
 
1044
                                    "Music", dirname, NULL);
 
1045
        g_free (dirname);
 
1046
 
 
1047
        if (test_dir_on_ipod (mountpoint, relpath) != FALSE) {
 
1048
                return relpath;
 
1049
        }
 
1050
 
 
1051
        g_free (relpath);
 
1052
        dirname = g_strdup_printf ("f%02d", g_random_int_range (0, 100));
 
1053
        relpath = g_build_filename (G_DIR_SEPARATOR_S, "iPod_Control",
 
1054
                                    "Music", dirname, NULL);
 
1055
        g_free (dirname);
 
1056
 
 
1057
        if (test_dir_on_ipod (mountpoint, relpath) != FALSE) {
 
1058
                return relpath;
 
1059
        }
 
1060
 
 
1061
        if (ipod_mkdir_with_parents (mountpoint, relpath) == 0) {
 
1062
                return relpath;
 
1063
        }
 
1064
 
 
1065
        g_free (relpath);
 
1066
        return NULL;
 
1067
}
 
1068
 
 
1069
static gchar *
 
1070
get_ipod_filename (const char *mount_point, const char *filename)
 
1071
{
 
1072
        char *dirname;
 
1073
        char *result;
 
1074
        char *tmp;
 
1075
 
 
1076
        dirname = build_ipod_dir_name (mount_point);
 
1077
        if (dirname == NULL) {
 
1078
                return NULL;
 
1079
        }
 
1080
        result = g_build_filename (dirname, filename, NULL);
 
1081
        g_free (dirname);
 
1082
 
 
1083
        if (strlen (result) >= IPOD_MAX_PATH_LEN) {
 
1084
                char *ext;
 
1085
 
 
1086
                ext = strrchr (result, '.');
 
1087
                if (ext == NULL) {
 
1088
                        result [IPOD_MAX_PATH_LEN - 1] = '\0';
 
1089
                } else {
 
1090
                        memmove (&result[IPOD_MAX_PATH_LEN - strlen (ext) - 1] ,
 
1091
                                 ext, strlen (ext) + 1);
 
1092
                }
 
1093
        }
 
1094
 
 
1095
        tmp = g_build_filename (mount_point, result, NULL);
 
1096
        g_free (result);
 
1097
        return tmp;
 
1098
}
 
1099
 
 
1100
#define MAX_TRIES 5
 
1101
 
 
1102
/* Strips non UTF8 characters from a string replacing them with _ */
 
1103
static gchar *
 
1104
utf8_to_ascii (const gchar *utf8)
 
1105
{
 
1106
        GString *string;
 
1107
        const guchar *it = (const guchar *)utf8;
 
1108
 
 
1109
        string = g_string_new ("");
 
1110
        while ((it != NULL) && (*it != '\0')) {
 
1111
                /* Do we have a 7 bit char ? */
 
1112
                if (*it < 0x80) {
 
1113
                        g_string_append_c (string, *it);
 
1114
                } else {
 
1115
                        g_string_append_c (string, '_');
 
1116
                }
 
1117
                it = (const guchar *)g_utf8_next_char (it);
 
1118
        }
 
1119
 
 
1120
        return g_string_free (string, FALSE);
 
1121
}
 
1122
 
 
1123
/* Copied from eel-vfs-extensions.c from eel CVS HEAD on 2004-05-09
 
1124
 * This function is (C) 1999, 2000 Eazel, Inc.
 
1125
 */
 
1126
static char *
 
1127
eel_make_valid_utf8 (const char *name)
 
1128
{
 
1129
        GString *string;
 
1130
        const char *remainder, *invalid;
 
1131
        int remaining_bytes, valid_bytes;
 
1132
 
 
1133
        string = NULL;
 
1134
        remainder = name;
 
1135
        remaining_bytes = strlen (name);
 
1136
 
 
1137
        while (remaining_bytes != 0) {
 
1138
                if (g_utf8_validate (remainder, remaining_bytes, &invalid)) {
 
1139
                        break;
 
1140
                }
 
1141
                valid_bytes = invalid - remainder;
 
1142
 
 
1143
                if (string == NULL) {
 
1144
                        string = g_string_sized_new (remaining_bytes);
 
1145
                }
 
1146
                g_string_append_len (string, remainder, valid_bytes);
 
1147
                g_string_append_c (string, '_');
 
1148
 
 
1149
                remaining_bytes -= valid_bytes + 1;
 
1150
                remainder = invalid + 1;
 
1151
        }
 
1152
 
 
1153
        if (string == NULL) {
 
1154
                return g_strdup (name);
 
1155
        }
 
1156
 
 
1157
        g_string_append (string, remainder);
 
1158
        g_assert (g_utf8_validate (string->str, -1, NULL));
 
1159
 
 
1160
        return g_string_free (string, FALSE);
 
1161
}
 
1162
 
 
1163
 
 
1164
static gchar *
 
1165
generate_ipod_filename (const gchar *mount_point, const gchar *filename)
 
1166
{
 
1167
        gchar *ipod_filename = NULL;
 
1168
        gchar *pc_filename;
 
1169
        gchar *tmp;
 
1170
        gint tries = 0;
 
1171
 
 
1172
        /* First, we need a valid UTF-8 filename, strip all non-UTF-8 chars */
 
1173
        tmp = eel_make_valid_utf8 (filename);
 
1174
        /* The iPod doesn't seem to recognize non-ascii chars in filenames,
 
1175
         * so we strip them
 
1176
         */
 
1177
        pc_filename = utf8_to_ascii (tmp);
 
1178
        g_free (tmp);
 
1179
 
 
1180
        g_assert (g_utf8_validate (pc_filename, -1, NULL));
 
1181
        /* Now we have a valid UTF-8 filename, try to find out where to put
 
1182
         * it on the iPod
 
1183
         */
 
1184
        do {
 
1185
                g_free (ipod_filename);
 
1186
                ipod_filename = get_ipod_filename (mount_point, pc_filename);
 
1187
                tries++;
 
1188
                if (tries > MAX_TRIES) {
 
1189
                        break;
 
1190
                }
 
1191
        } while ((ipod_filename == NULL) 
 
1192
                 || (g_file_test (ipod_filename, G_FILE_TEST_EXISTS)));
 
1193
 
 
1194
        g_free (pc_filename);
 
1195
 
 
1196
        if (tries > MAX_TRIES) {
 
1197
                /* FIXME: should create a unique filename */
 
1198
                return NULL;
 
1199
        } else {
 
1200
                return ipod_filename;
 
1201
        }
 
1202
}
 
1203
 
 
1204
static gchar *
 
1205
ipod_get_filename_for_uri (const gchar *mount_point, const gchar *uri_str)
 
1206
{
 
1207
        GnomeVFSURI *uri;
 
1208
        gchar *escaped;
 
1209
        gchar *filename;
 
1210
        gchar *result;
 
1211
 
 
1212
        uri = gnome_vfs_uri_new (uri_str);
 
1213
        if (uri == NULL) {
 
1214
                return NULL;
 
1215
        }
 
1216
        escaped = gnome_vfs_uri_extract_short_path_name (uri);
 
1217
        gnome_vfs_uri_unref (uri);
 
1218
        if (escaped == NULL) {
 
1219
                return NULL;
 
1220
        }
 
1221
        filename = gnome_vfs_unescape_string (escaped, G_DIR_SEPARATOR_S);
 
1222
        g_free (escaped);
 
1223
        if (filename == NULL) {
 
1224
                return NULL;
 
1225
        }
 
1226
 
 
1227
        result = generate_ipod_filename (mount_point, filename);
 
1228
        g_free (filename);
 
1229
 
 
1230
        return result;
 
1231
}
 
1232
 
 
1233
/* End of generation of the filename on the iPod */
 
1234
 
 
1235
static gchar *
 
1236
ipod_path_from_unix_path (const gchar *mount_point, const gchar *unix_path)
 
1237
{
 
1238
        gchar *ipod_path;
 
1239
 
 
1240
        g_assert (g_utf8_validate (unix_path, -1, NULL));
 
1241
 
 
1242
        if (!g_str_has_prefix (unix_path, mount_point)) {
 
1243
                return NULL;
 
1244
        }
 
1245
 
 
1246
        ipod_path = g_strdup (unix_path + strlen (mount_point));
 
1247
        if (*ipod_path != G_DIR_SEPARATOR) {
 
1248
                gchar *tmp;
 
1249
                tmp = g_strdup_printf ("/%s", ipod_path);
 
1250
                g_free (ipod_path);
 
1251
                ipod_path = tmp;
 
1252
        }
 
1253
 
 
1254
        /* Make sure the filename doesn't contain any ':' */
 
1255
        g_strdelimit (ipod_path, ":", ';');
 
1256
 
 
1257
 
 
1258
        /* Convert path to a Mac path where the dir separator is ':' */
 
1259
        itdb_filename_fs2ipod (ipod_path);
 
1260
 
 
1261
        return ipod_path;
 
1262
}
 
1263
#endif
 
1264
 
580
1265
static void
581
1266
impl_delete_thyself (RBSource *source)
582
1267
{
587
1272
 
588
1273
        RB_SOURCE_CLASS (rb_ipod_source_parent_class)->impl_delete_thyself (source);
589
1274
}
 
1275