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;
86
118
g_type_class_add_private (klass, sizeof (RBiPodSourcePrivate));
122
rb_ipod_source_set_ipod_name (RBiPodSource *source, const char *name)
125
RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
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);
134
mpl->name = g_strdup (name);
135
itdb_schedule_save (priv->ipod_db);
139
rb_ipod_source_name_changed_cb (RBiPodSource *source, GParamSpec *spec,
144
g_object_get (RB_SOURCE (source), "name", &name, NULL);
145
rb_ipod_source_set_ipod_name (source, name);
90
150
rb_ipod_source_init (RBiPodSource *source)
152
g_signal_connect (G_OBJECT (source), "notify::name",
153
(GCallback)rb_ipod_source_name_changed_cb, NULL);
96
157
rb_ipod_source_constructor (GType type, guint n_construct_properties,
97
GObjectConstructParam *construct_properties)
158
GObjectConstructParam *construct_properties)
99
GObjectClass *klass, *parent_class;
100
RBiPodSource *source;
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;
162
RBiPodSourcePrivate *priv;
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);
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);
106
172
rb_ipod_load_songs (source);
312
#ifdef ENABLE_IPOD_WRITING
314
create_ipod_song_from_entry (RhythmDBEntry *entry)
318
track = itdb_track_new ();
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);
344
add_ipod_song_to_db (RBiPodSource *source, RhythmDB *db, Itdb_Track *song)
346
RhythmDBEntry *entry;
347
RhythmDBEntryType entry_type;
348
RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
352
g_object_get (G_OBJECT (source), "entry-type", &entry_type,
355
pc_path = ipod_path_to_uri (priv->ipod_mount_path,
357
entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type,
361
rb_debug ("cannot create entry %s", pc_path);
366
rb_debug ("Adding %s from iPod", pc_path);
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,
377
g_value_unset (&value);
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,
388
g_value_unset (&value);
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,
399
g_value_unset (&value);
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,
410
g_value_unset (&value);
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,
421
g_value_unset (&value);
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,
432
g_value_unset (&value);
436
if (song->year != 0) {
439
GValue value = {0, };
441
date = g_date_new_dmy (1, G_DATE_JANUARY, song->year);
443
type = rhythmdb_get_property_type (RHYTHMDB(db),
446
g_value_init (&value, type);
447
g_value_set_ulong (&value, (date ? g_date_get_julian (date) : 0));
449
rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
452
g_value_unset (&value);
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,
465
g_value_unset (&value);
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,
476
g_value_unset (&value);
480
entry_set_string_prop (RHYTHMDB (db), entry,
481
RHYTHMDB_PROP_TITLE, song->title);
483
/* Set album, artist and genre from iTunesDB */
484
entry_set_string_prop (RHYTHMDB (db), entry,
485
RHYTHMDB_PROP_ARTIST, song->artist);
487
entry_set_string_prop (RHYTHMDB (db), entry,
488
RHYTHMDB_PROP_ALBUM, song->album);
490
entry_set_string_prop (RHYTHMDB (db), entry,
491
RHYTHMDB_PROP_GENRE, song->genre);
494
g_hash_table_insert (priv->entry_map, entry, song);
496
rhythmdb_commit (RHYTHMDB (db));
241
500
load_ipod_db_idle_cb (RBiPodSource *source)
252
511
g_assert (db != NULL);
253
512
for (it = priv->ipod_db->tracks; it != NULL; it = it->next) {
255
RhythmDBEntry *entry;
256
RhythmDBEntryType entry_type;
259
song = (Itdb_Track *)it->data;
262
g_object_get (G_OBJECT (source), "entry-type", &entry_type,
265
pc_path = ipod_path_to_uri (priv->ipod_mount_path,
267
entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type,
271
rb_debug ("cannot create entry %s", pc_path);
276
rb_debug ("Adding %s from iPod", pc_path);
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,
287
g_value_unset (&value);
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,
298
g_value_unset (&value);
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,
309
g_value_unset (&value);
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,
320
g_value_unset (&value);
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,
331
g_value_unset (&value);
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,
342
g_value_unset (&value);
346
if (song->year != 0) {
349
GValue value = {0, };
351
date = g_date_new_dmy (1, G_DATE_JANUARY, song->year);
353
type = rhythmdb_get_property_type (RHYTHMDB(db),
356
g_value_init (&value, type);
357
g_value_set_ulong (&value, (date ? g_date_get_julian (date) : 0));
359
rhythmdb_entry_set_uninserted (RHYTHMDB (db), entry,
362
g_value_unset (&value);
368
entry_set_string_prop (RHYTHMDB (db), entry,
369
RHYTHMDB_PROP_TITLE, song->title);
371
/* Set album, artist and genre from iTunesDB */
372
entry_set_string_prop (RHYTHMDB (db), entry,
373
RHYTHMDB_PROP_ARTIST, song->artist);
375
entry_set_string_prop (RHYTHMDB (db), entry,
376
RHYTHMDB_PROP_ALBUM, song->album);
378
entry_set_string_prop (RHYTHMDB (db), entry,
379
RHYTHMDB_PROP_GENRE, song->genre);
381
rhythmdb_commit (RHYTHMDB (db));
513
add_ipod_song_to_db (source, db, (Itdb_Track *)it->data);
385
516
load_ipod_playlists (source);
791
remove_track_from_db (Itdb_Track *track)
795
for (it = track->itdb->playlists; it != NULL; it = it->next) {
796
itdb_playlist_remove_track ((Itdb_Playlist *)it->data, track);
798
itdb_track_remove (track);
802
impl_move_to_trash (RBSource *asource)
808
RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (asource);
809
RBiPodSource *source = RB_IPOD_SOURCE (asource);
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));
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;
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);
827
g_warning ("Couldn't find track on ipod! (%s)", uri);
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);
837
itdb_write (priv->ipod_db, NULL);
844
itdb_schedule_save (Itdb_iTunesDB *db)
846
/* FIXME: should probably be delayed a bit to avoid doing
847
* it after each file when we are copying several files
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
853
itdb_write (db, NULL);
857
#ifdef ENABLE_IPOD_WRITING
859
build_filename (RBSource *asource, RhythmDBEntry *entry)
865
RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (asource);
867
uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
868
dest = ipod_get_filename_for_uri (priv->ipod_mount_path, uri);
870
dest_uri = g_filename_to_uri (dest, NULL, NULL);
879
completed_cb (RhythmDBEntry *entry, const char *dest, RBiPodSource *source)
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));
889
song = create_ipod_song_from_entry (entry);
891
RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
894
filename = g_filename_from_uri (dest, NULL, NULL);
895
song->ipod_path = ipod_path_from_unix_path (priv->ipod_mount_path, filename);
897
itdb_track_add (priv->ipod_db, song, -1);
898
itdb_playlist_add_track (itdb_playlist_mpl (priv->ipod_db),
901
add_ipod_song_to_db (source, db, song);
902
itdb_schedule_save (priv->ipod_db);
909
impl_paste (RBSource *asource, GList *entries)
911
RBRemovableMediaManager *rm_mgr;
915
g_object_get (G_OBJECT (asource), "shell", &shell, NULL);
916
g_object_get (G_OBJECT (shell),
917
"removable-media-manager", &rm_mgr,
919
g_object_unref (G_OBJECT (shell));
921
for (l = entries; l != NULL; l = l->next) {
922
RhythmDBEntry *entry;
923
RhythmDBEntryType entry_type;
924
RhythmDBEntryType ipod_entry_type;
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,
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)
938
dest = build_filename (asource, entry);
940
rb_debug ("could not create destination path for entry");
943
rb_removable_media_manager_queue_transfer (rm_mgr, entry,
945
(RBTranferCompleteCallback)completed_cb, asource);
948
g_object_unref (G_OBJECT (rm_mgr));
953
impl_receive_drag (RBSource *asource, GtkSelectionData *data)
955
RBBrowserSource *source = RB_BROWSER_SOURCE (asource);
957
GList *entries = NULL;
961
rb_debug ("parsing uri list");
962
list = rb_uri_list_parse ((const char *) data->data);
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));
968
for (i = list; i != NULL; i = g_list_next (i)) {
969
if (i->data != NULL) {
971
RhythmDBEntry *entry;
973
entry = rhythmdb_entry_lookup_by_location (db, uri);
976
/* add to the library */
977
g_print ("Where does that come from?\n");
979
/* add to list of entries to copy */
980
entries = g_list_prepend (entries, entry);
990
entries = g_list_reverse (entries);
991
if (rb_source_can_paste (asource))
992
rb_source_paste (asource, entries);
993
g_list_free (entries);
1001
/* Generation of the filename for the ipod */
1003
#define IPOD_MAX_PATH_LEN 56
1006
test_dir_on_ipod (const char *mountpoint, const char *dirname)
1011
fullpath = g_build_filename (mountpoint, dirname, NULL);
1012
result = g_file_test (fullpath, G_FILE_TEST_IS_DIR);
1019
ipod_mkdir_with_parents (const char *mountpoint, const char *dirname)
1024
fullpath = g_build_filename (mountpoint, dirname, NULL);
1025
result = g_mkdir_with_parents (fullpath, 0770);
1032
build_ipod_dir_name (const char *mountpoint)
1034
/* FAT sucks, filename can be lowercase or uppercase, and if we try to
1035
* open the wrong one, we lose :-/
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);
1047
if (test_dir_on_ipod (mountpoint, relpath) != FALSE) {
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);
1057
if (test_dir_on_ipod (mountpoint, relpath) != FALSE) {
1061
if (ipod_mkdir_with_parents (mountpoint, relpath) == 0) {
1070
get_ipod_filename (const char *mount_point, const char *filename)
1076
dirname = build_ipod_dir_name (mount_point);
1077
if (dirname == NULL) {
1080
result = g_build_filename (dirname, filename, NULL);
1083
if (strlen (result) >= IPOD_MAX_PATH_LEN) {
1086
ext = strrchr (result, '.');
1088
result [IPOD_MAX_PATH_LEN - 1] = '\0';
1090
memmove (&result[IPOD_MAX_PATH_LEN - strlen (ext) - 1] ,
1091
ext, strlen (ext) + 1);
1095
tmp = g_build_filename (mount_point, result, NULL);
1102
/* Strips non UTF8 characters from a string replacing them with _ */
1104
utf8_to_ascii (const gchar *utf8)
1107
const guchar *it = (const guchar *)utf8;
1109
string = g_string_new ("");
1110
while ((it != NULL) && (*it != '\0')) {
1111
/* Do we have a 7 bit char ? */
1113
g_string_append_c (string, *it);
1115
g_string_append_c (string, '_');
1117
it = (const guchar *)g_utf8_next_char (it);
1120
return g_string_free (string, FALSE);
1123
/* Copied from eel-vfs-extensions.c from eel CVS HEAD on 2004-05-09
1124
* This function is (C) 1999, 2000 Eazel, Inc.
1127
eel_make_valid_utf8 (const char *name)
1130
const char *remainder, *invalid;
1131
int remaining_bytes, valid_bytes;
1135
remaining_bytes = strlen (name);
1137
while (remaining_bytes != 0) {
1138
if (g_utf8_validate (remainder, remaining_bytes, &invalid)) {
1141
valid_bytes = invalid - remainder;
1143
if (string == NULL) {
1144
string = g_string_sized_new (remaining_bytes);
1146
g_string_append_len (string, remainder, valid_bytes);
1147
g_string_append_c (string, '_');
1149
remaining_bytes -= valid_bytes + 1;
1150
remainder = invalid + 1;
1153
if (string == NULL) {
1154
return g_strdup (name);
1157
g_string_append (string, remainder);
1158
g_assert (g_utf8_validate (string->str, -1, NULL));
1160
return g_string_free (string, FALSE);
1165
generate_ipod_filename (const gchar *mount_point, const gchar *filename)
1167
gchar *ipod_filename = NULL;
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,
1177
pc_filename = utf8_to_ascii (tmp);
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
1185
g_free (ipod_filename);
1186
ipod_filename = get_ipod_filename (mount_point, pc_filename);
1188
if (tries > MAX_TRIES) {
1191
} while ((ipod_filename == NULL)
1192
|| (g_file_test (ipod_filename, G_FILE_TEST_EXISTS)));
1194
g_free (pc_filename);
1196
if (tries > MAX_TRIES) {
1197
/* FIXME: should create a unique filename */
1200
return ipod_filename;
1205
ipod_get_filename_for_uri (const gchar *mount_point, const gchar *uri_str)
1212
uri = gnome_vfs_uri_new (uri_str);
1216
escaped = gnome_vfs_uri_extract_short_path_name (uri);
1217
gnome_vfs_uri_unref (uri);
1218
if (escaped == NULL) {
1221
filename = gnome_vfs_unescape_string (escaped, G_DIR_SEPARATOR_S);
1223
if (filename == NULL) {
1227
result = generate_ipod_filename (mount_point, filename);
1233
/* End of generation of the filename on the iPod */
1236
ipod_path_from_unix_path (const gchar *mount_point, const gchar *unix_path)
1240
g_assert (g_utf8_validate (unix_path, -1, NULL));
1242
if (!g_str_has_prefix (unix_path, mount_point)) {
1246
ipod_path = g_strdup (unix_path + strlen (mount_point));
1247
if (*ipod_path != G_DIR_SEPARATOR) {
1249
tmp = g_strdup_printf ("/%s", ipod_path);
1254
/* Make sure the filename doesn't contain any ':' */
1255
g_strdelimit (ipod_path, ":", ';');
1258
/* Convert path to a Mac path where the dir separator is ':' */
1259
itdb_filename_fs2ipod (ipod_path);
581
1266
impl_delete_thyself (RBSource *source)