1 /*
2 | Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
3 | Copyright (C) 2009 Christophe Fergeau <cfergeau@mandriva.com>
4 | Copyright (C) 2009 Hector Martin <hector@marcansoft.com>
5 |
6 | The code contained in this file is free software; you can redistribute
7 | it and/or modify it under the terms of the GNU Lesser General Public
8 | License as published by the Free Software Foundation; either version
9 | 2.1 of the License, or (at your option) any later version.
10 |
11 | This file 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 GNU
14 | Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public
17 | License along with this code; if not, write to the Free Software
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 | USA
20 */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <unistd.h>
31
32 #include <glib.h>
33 #include <glib/gstdio.h>
34 #include <sqlite3.h>
35 #include <plist/plist.h>
36
37 #ifdef HAVE_LIBIMOBILEDEVICE
38 #include <libimobiledevice/libimobiledevice.h>
39 #include <libimobiledevice/lockdown.h>
40 #endif
41
42 #include "itdb.h"
43 #include "itdb_private.h"
44 #include "itdb_sqlite_queries.h"
45
46
47 /** time zone offset in seconds */
48 static uint32_t tzoffset = 0;
49
timeconv(time_t tv)50 static uint32_t timeconv(time_t tv)
51 {
52 /* quite strange. this is time_t - 01.01.2001 01:00:00 - tzoffset */
53 return tv - 978307200 - tzoffset;
54 }
55
56 enum sort_order {
57 ORDER_TITLE,
58 ORDER_ARTIST,
59 ORDER_ALBUM,
60 ORDER_GENRE,
61 ORDER_COMPOSER,
62 ORDER_ALBUM_ARTIST,
63 ORDER_ALBUM_BY_ARTIST,
64 ORDER_SERIES_NAME,
65 ORDER_END
66 };
67
68 static glong sort_offsets[][4] = {
69 { G_STRUCT_OFFSET(Itdb_Track, sort_title), G_STRUCT_OFFSET(Itdb_Track, title) },
70 { G_STRUCT_OFFSET(Itdb_Track, sort_artist), G_STRUCT_OFFSET(Itdb_Track, artist) },
71 { G_STRUCT_OFFSET(Itdb_Track, sort_album), G_STRUCT_OFFSET(Itdb_Track, album) },
72 { G_STRUCT_OFFSET(Itdb_Track, genre), 0 },
73 { G_STRUCT_OFFSET(Itdb_Track, sort_composer), G_STRUCT_OFFSET(Itdb_Track, composer) },
74 { G_STRUCT_OFFSET(Itdb_Track, sort_artist), G_STRUCT_OFFSET(Itdb_Track, artist) },
75 /* TODO: iTunes sorts first by album_artist, then by artist. */
76 { G_STRUCT_OFFSET(Itdb_Track, sort_albumartist), G_STRUCT_OFFSET(Itdb_Track, albumartist),
77 G_STRUCT_OFFSET(Itdb_Track, sort_artist), G_STRUCT_OFFSET(Itdb_Track, artist) },
78 { 0, 0 } /* TODO: Series Name: ignored for now. */
79 };
80
sort_field(Itdb_Track * track,guint member)81 static gchar *sort_field(Itdb_Track *track, guint member)
82 {
83 gchar *field;
84 int offset;
85 int i;
86
87 for (i = 0; i < 4; i++) {
88 offset = sort_offsets[member][i];
89 field = G_STRUCT_MEMBER(gchar *, track, offset);
90 if (offset != 0 && field != NULL && *field) {
91 return field;
92 }
93 }
94 return NULL;
95 }
96
lookup_order(GHashTable ** order_hashes,guint member,Itdb_Track * track)97 static int lookup_order(GHashTable **order_hashes, guint member, Itdb_Track *track)
98 {
99 const char *key;
100
101 g_assert (member < ORDER_END);
102
103 key = sort_field(track, member);
104 if (key == NULL) {
105 return 100;
106 }
107
108 return GPOINTER_TO_UINT(g_hash_table_lookup(order_hashes[member], key));
109 }
110
compare_track_fields(gconstpointer lhs,gconstpointer rhs)111 static gint compare_track_fields(gconstpointer lhs, gconstpointer rhs)
112 {
113 const gchar *field_lhs = (const gchar *)lhs;
114 const gchar *field_rhs = (const gchar *)rhs;
115
116 if (field_lhs == NULL && field_rhs == NULL) {
117 return 0;
118 }
119
120 if (field_lhs == NULL) {
121 return -1;
122 }
123
124 if (field_rhs == NULL) {
125 return 1;
126 }
127
128 /* FIXME: should probably generate collation keys first */
129 return g_utf8_collate(field_lhs, field_rhs);
130 }
131
traverse_tracks(gpointer key,gpointer value,gpointer data)132 static gboolean traverse_tracks(gpointer key, gpointer value, gpointer data)
133 {
134 GHashTable *hash = (GHashTable *)data;
135
136 if (key != NULL) {
137 g_hash_table_insert(hash, key, GUINT_TO_POINTER((g_hash_table_size(hash) + 1) * 100));
138 }
139 return FALSE;
140 }
141
compute_key_orders(GList * tracks)142 static GHashTable **compute_key_orders(GList *tracks)
143 {
144 GHashTable **result;
145 int i;
146
147 result = g_new0(GHashTable *, ORDER_END);
148 g_assert (result != NULL);
149
150 for (i = 0; i < ORDER_END; i++) {
151 GList *li;
152 GTree *tree;
153
154 tree = g_tree_new(compare_track_fields);
155
156 for (li = tracks; li != NULL; li = li->next) {
157 Itdb_Track *track = (Itdb_Track *)li->data;
158
159 g_tree_insert(tree, sort_field(track, i), 0);
160 }
161
162 result[i] = g_hash_table_new(g_str_hash, g_str_equal);
163 g_assert (result[i] != NULL);
164
165 g_tree_foreach(tree, traverse_tracks, (gpointer)result[i]);
166 g_tree_destroy(tree);
167 }
168
169 return result;
170 }
171
destroy_key_orders(GHashTable ** orders)172 static void destroy_key_orders(GHashTable **orders)
173 {
174 int i;
175
176 for (i = 0; i < ORDER_END; i++) {
177 g_hash_table_destroy(orders[i]);
178 }
179
180 g_free(orders);
181 }
182
mk_Dynamic(Itdb_iTunesDB * itdb,const char * outpath)183 static int mk_Dynamic(Itdb_iTunesDB *itdb, const char *outpath)
184 {
185 int res = -1;
186 gchar *dbf = NULL;
187 sqlite3 *db = NULL;
188 sqlite3_stmt *stmt = NULL;
189 char *errmsg = NULL;
190 struct stat fst;
191 int idx = 0;
192 GList *gl = NULL;
193
194 dbf = g_build_filename(outpath, "Dynamic.itdb", NULL);
195 printf("[%s] Processing '%s'\n", __func__, dbf);
196 if (stat(dbf, &fst) != 0) {
197 if (errno == ENOENT) {
198 /* file is not present. so we'll create it */
199 } else {
200 fprintf(stderr, "[%s] Error: stat: %s\n", __func__, strerror(errno));
201 goto leave;
202 }
203 } else {
204 /* file is present. delete it, we'll re-create it. */
205 if (unlink(dbf) != 0) {
206 fprintf(stderr, "[%s] could not delete '%s': %s\n", __func__, dbf, strerror(errno));
207 goto leave;
208 }
209 }
210
211 if (SQLITE_OK != sqlite3_open((const char*)dbf, &db)) {
212 fprintf(stderr, "Error opening database '%s': %s\n", dbf, sqlite3_errmsg(db));
213 goto leave;
214 }
215
216 sqlite3_exec(db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
217
218 fprintf(stderr, "[%s] creating table structure\n", __func__);
219 /* db structure needs to be created. */
220 if (SQLITE_OK != sqlite3_exec(db, Dynamic_create, NULL, NULL, &errmsg)) {
221 fprintf(stderr, "[%s] sqlite3_exec error: %s\n", __func__, sqlite3_errmsg(db));
222 if (errmsg) {
223 fprintf(stderr, "[%s] additional error information: %s\n", __func__, errmsg);
224 sqlite3_free(errmsg);
225 errmsg = NULL;
226 }
227 goto leave;
228 }
229
230 sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
231
232 if (itdb->tracks) {
233 printf("[%s] - processing %d tracks\n", __func__, g_list_length(itdb->tracks));
234 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"item_stats\" (item_pid,has_been_played,date_played,play_count_user,play_count_recent,date_skipped,skip_count_user,skip_count_recent,bookmark_time_ms,bookmark_time_ms_common,user_rating,user_rating_common) VALUES(?,?,?,?,?,?,?,?,?,?,?,?);", -1, &stmt, NULL)) {
235 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
236 goto leave;
237 }
238 for (gl=itdb->tracks; gl; gl=gl->next) {
239 Itdb_Track *track = gl->data;
240 if (!track->ipod_path) {
241 continue;
242 }
243 res = sqlite3_reset(stmt);
244 if (res != SQLITE_OK) {
245 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
246 }
247 idx = 0;
248 /* item_pid */
249 sqlite3_bind_int64(stmt, ++idx, track->dbid);
250 /* has_been_played */
251 sqlite3_bind_int(stmt, ++idx, (track->playcount > 0) ? 1 : 0);
252 /* date_played */
253 sqlite3_bind_int(stmt, ++idx, timeconv(track->time_played));
254 /* play_count_user */
255 sqlite3_bind_int(stmt, ++idx, track->playcount);
256 /* play_count_recent */
257 sqlite3_bind_int(stmt, ++idx, track->recent_playcount);
258 /* date_skipped */
259 sqlite3_bind_int(stmt, ++idx, timeconv(track->last_skipped));
260 /* skip_count_user */
261 sqlite3_bind_int(stmt, ++idx, track->skipcount);
262 /* skip_count_recent */
263 sqlite3_bind_int(stmt, ++idx, track->recent_skipcount);
264 /* bookmark_time_ms */
265 sqlite3_bind_double(stmt, ++idx, track->bookmark_time);
266 /* bookmark_time_ms_common */
267 /* FIXME: is this the same as bookmark_time_ms ??! */
268 sqlite3_bind_double(stmt, ++idx, track->bookmark_time);
269 /* user_rating */
270 sqlite3_bind_int(stmt, ++idx, track->rating);
271 /* user_rating_common */
272 /* FIXME: don't know if this is the right value */
273 sqlite3_bind_int(stmt, ++idx, track->app_rating);
274
275 res = sqlite3_step(stmt);
276 if (res == SQLITE_DONE) {
277 /* expected result */
278 } else {
279 fprintf(stderr, "[%s] 1 sqlite3_step returned %d\n", __func__, res);
280 }
281 }
282 if (stmt) {
283 sqlite3_finalize(stmt);
284 stmt = NULL;
285 }
286 } else {
287 printf("[%s] - No tracks available, none written.\n", __func__);
288 }
289
290 /* add playlist info to container_ui */
291 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"container_ui\" VALUES(?,?,?,?,?,?,?);", -1, &stmt, NULL)) {
292 fprintf(stderr, "[%s] 2 sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
293 goto leave;
294 }
295
296 printf("[%s] - processing %d playlists\n", __func__, g_list_length(itdb->playlists));
297 for (gl = itdb->playlists; gl; gl = gl->next) {
298 Itdb_Playlist *pl = (Itdb_Playlist*)gl->data;
299
300 res = sqlite3_reset(stmt);
301 if (res != SQLITE_OK) {
302 fprintf(stderr, "[%s] 2 sqlite3_reset returned %d\n", __func__, res);
303 }
304 idx = 0;
305 /* container_pid */
306 sqlite3_bind_int64(stmt, ++idx, pl->id);
307 /* play_order TODO: where does this value come from? */
308 /* FIXME: 5 --> 7, 24 --> 39 ??!? */
309 switch (pl->sortorder) {
310 case 5:
311 sqlite3_bind_int(stmt, ++idx, 7);
312 break;
313 case 24:
314 sqlite3_bind_int(stmt, ++idx, 39);
315 break;
316 default:
317 sqlite3_bind_int(stmt, ++idx, 7);
318 break;
319 }
320 /* is_reversed TODO where does this value come from? */
321 sqlite3_bind_int(stmt, ++idx, 0);
322 /* album_field_order TODO where does this value come from? */
323 sqlite3_bind_int(stmt, ++idx, 1);
324 /* repeat_mode TODO where does this value come from? */
325 sqlite3_bind_int(stmt, ++idx, 0);
326 /* shuffle_items TODO where does this value come from? */
327 sqlite3_bind_int(stmt, ++idx, 0);
328 /* has_been_shuffled TODO where does this value come from? */
329 sqlite3_bind_int(stmt, ++idx, 0);
330
331 res = sqlite3_step(stmt);
332 if (res == SQLITE_DONE) {
333 /* expected result */
334 } else {
335 fprintf(stderr, "[%s] 2 sqlite3_step returned %d\n", __func__, res);
336 }
337 }
338
339 sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
340
341 if (stmt) {
342 sqlite3_finalize(stmt);
343 stmt = NULL;
344 }
345
346 res = 0;
347 printf("[%s] done.\n", __func__);
348 leave:
349 if (db) {
350 sqlite3_close(db);
351 }
352 if (dbf) {
353 g_free(dbf);
354 }
355 return res;
356 }
357
mk_Extras(Itdb_iTunesDB * itdb,const char * outpath)358 static int mk_Extras(Itdb_iTunesDB *itdb, const char *outpath)
359 {
360 int res = -1;
361 int rebuild = 0;
362 gchar *dbf = NULL;
363 sqlite3 *db = NULL;
364 sqlite3_stmt *stmt_chapter = NULL;
365 char *errmsg = NULL;
366 struct stat fst;
367 GList *gl = NULL;
368
369 dbf = g_build_filename(outpath, "Extras.itdb", NULL);
370 printf("[%s] Processing '%s'\n", __func__, dbf);
371 if (stat(dbf, &fst) != 0) {
372 if (errno == ENOENT) {
373 /* file is not present. so we need to create the tables in it ;) */
374 rebuild = 1;
375 } else {
376 fprintf(stderr, "[%s] Error: stat: %s\n", __func__, strerror(errno));
377 goto leave;
378 }
379 }
380
381 if (SQLITE_OK != sqlite3_open((const char*)dbf, &db)) {
382 fprintf(stderr, "Error opening database '%s': %s\n", dbf, sqlite3_errmsg(db));
383 goto leave;
384 }
385
386 sqlite3_exec(db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
387
388 if (rebuild) {
389 fprintf(stderr, "[%s] re-building table structure\n", __func__);
390 /* db structure needs to be created. */
391 if (SQLITE_OK != sqlite3_exec(db, Extras_create, NULL, NULL, &errmsg)) {
392 fprintf(stderr, "[%s] sqlite3_exec error: %s\n", __func__, sqlite3_errmsg(db));
393 if (errmsg) {
394 fprintf(stderr, "[%s] additional error information: %s\n", __func__, errmsg);
395 sqlite3_free(errmsg);
396 errmsg = NULL;
397 }
398 goto leave;
399 }
400 }
401
402 sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
403 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"chapter\" VALUES(?,?);", -1, &stmt_chapter, NULL)) {
404 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
405 goto leave;
406 }
407
408 /* kill all entries in 'chapter' as they will be re-inserted */
409 if (SQLITE_OK != sqlite3_exec(db, "DELETE FROM chapter;", NULL, NULL, &errmsg)) {
410 fprintf(stderr, "[%s] sqlite3_exec error: %s\n", __func__, sqlite3_errmsg(db));
411 if (errmsg) {
412 fprintf(stderr, "[%s] additional error information: %s\n", __func__, errmsg);
413 sqlite3_free(errmsg);
414 errmsg = NULL;
415 }
416 goto leave;
417 }
418
419 /* kill all entries in 'lyrics' as they will be re-inserted */
420 /* TODO: we do not support this in the moment, so don't touch this */
421 /*if (SQLITE_OK != sqlite3_exec(db, "DELETE FROM lyrics;", NULL, NULL, &errmsg)) {
422 fprintf(stderr, "[%s] sqlite3_exec error: %s\n", __func__, sqlite3_errmsg(db));
423 if (errmsg) {
424 fprintf(stderr, "[%s] additional error information: %s\n", __func__, errmsg);
425 sqlite3_free(errmsg);
426 errmsg = NULL;
427 }
428 goto leave;
429 }*/
430
431 for (gl = itdb->tracks; gl; gl = gl->next) {
432 Itdb_Track *track = gl->data;
433 if (track->chapterdata) {
434 int idx = 0;
435 GByteArray *chapter_blob = itdb_chapterdata_build_chapter_blob(track->chapterdata, FALSE);
436 /* printf("[%s] -- inserting into \"chapter\"\n", __func__); */
437 res = sqlite3_reset(stmt_chapter);
438 if (res != SQLITE_OK) {
439 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
440 }
441 /* item_pid INTEGER NOT NULL */
442 sqlite3_bind_int64(stmt_chapter, ++idx, track->dbid);
443 /* data BLOB */
444 sqlite3_bind_blob(stmt_chapter, ++idx, chapter_blob->data, chapter_blob->len, SQLITE_TRANSIENT);
445
446 res = sqlite3_step(stmt_chapter);
447 if (res == SQLITE_DONE) {
448 /* expected result */
449 } else {
450 fprintf(stderr, "[%s] 8 sqlite3_step returned %d\n", __func__, res);
451 }
452 g_byte_array_free(chapter_blob, TRUE);
453 }
454 }
455 sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
456
457 res = 0;
458 printf("[%s] done.\n", __func__);
459 leave:
460 if (stmt_chapter) {
461 sqlite3_finalize(stmt_chapter);
462 }
463 if (db) {
464 sqlite3_close(db);
465 }
466 if (dbf) {
467 g_free(dbf);
468 }
469 return res;
470 }
471
mk_Genius(Itdb_iTunesDB * itdb,const char * outpath)472 static int mk_Genius(Itdb_iTunesDB *itdb, const char *outpath)
473 {
474 int res = -1;
475 int rebuild = 0;
476 gchar *dbf = NULL;
477 sqlite3 *db = NULL;
478 char *errmsg = NULL;
479 struct stat fst;
480
481 dbf = g_build_filename(outpath, "Genius.itdb", NULL);
482 printf("[%s] Processing '%s'\n", __func__, dbf);
483 if (stat(dbf, &fst) != 0) {
484 if (errno == ENOENT) {
485 /* file is not present. so we need to create the tables in it ;) */
486 rebuild = 1;
487 } else {
488 fprintf(stderr, "[%s] Error: stat: %s\n", __func__, strerror(errno));
489 goto leave;
490 }
491 }
492
493 if (SQLITE_OK != sqlite3_open((const char*)dbf, &db)) {
494 fprintf(stderr, "Error opening database '%s': %s\n", dbf, sqlite3_errmsg(db));
495 goto leave;
496 }
497
498 sqlite3_exec(db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
499
500 if (rebuild) {
501 fprintf(stderr, "[%s] re-building table structure\n", __func__);
502 /* db structure needs to be created. */
503 if (SQLITE_OK != sqlite3_exec(db, Genius_create, NULL, NULL, &errmsg)) {
504 fprintf(stderr, "[%s] sqlite3_exec error: %s\n", __func__, sqlite3_errmsg(db));
505 if (errmsg) {
506 fprintf(stderr, "[%s] additional error information: %s\n", __func__, errmsg);
507 sqlite3_free(errmsg);
508 errmsg = NULL;
509 }
510 goto leave;
511 }
512 }
513
514 sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
515
516 /* kill all entries in 'genius_config' as they will be re-inserted */
517 /* TODO: we do not support this in the moment, so don't touch this */
518 /*if (SQLITE_OK != sqlite3_exec(db, "DELETE FROM genius_config;", NULL, NULL, &errmsg)) {
519 fprintf(stderr, "[%s] sqlite3_exec error: %s\n", __func__, sqlite3_errmsg(db));
520 if (errmsg) {
521 fprintf(stderr, "[%s] additional error information: %s\n", __func__, errmsg);
522 sqlite3_free(errmsg);
523 errmsg = NULL;
524 }
525 goto leave;
526 }*/
527
528 /* kill all entries in 'genius_metadata' as they will be re-inserted */
529 /* TODO: we do not support this in the moment, so don't touch this */
530 /*if (SQLITE_OK != sqlite3_exec(db, "DELETE FROM genius_metadata;", NULL, NULL, &errmsg)) {
531 fprintf(stderr, "[%s] sqlite3_exec error: %s\n", __func__, sqlite3_errmsg(db));
532 if (errmsg) {
533 fprintf(stderr, "[%s] additional error information: %s\n", __func__, errmsg);
534 sqlite3_free(errmsg);
535 errmsg = NULL;
536 }
537 goto leave;
538 }*/
539
540 /* kill all entries in 'genius_similarities' as they will be re-inserted */
541 /* TODO: we do not support this in the moment, so don't touch this */
542 /*if (SQLITE_OK != sqlite3_exec(db, "DELETE FROM genius_similarities;", NULL, NULL, &errmsg)) {
543 fprintf(stderr, "[%s] sqlite3_exec error: %s\n", __func__, sqlite3_errmsg(db));
544 if (errmsg) {
545 fprintf(stderr, "[%s] additional error information: %s\n", __func__, errmsg);
546 sqlite3_free(errmsg);
547 errmsg = NULL;
548 }
549 goto leave;
550 }*/
551
552 sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
553
554 res = 0;
555 printf("[%s] done.\n", __func__);
556 leave:
557 if (db) {
558 sqlite3_close(db);
559 }
560 if (dbf) {
561 g_free(dbf);
562 }
563 return res;
564 }
565
free_key_val_strings(gpointer key,gpointer value,gpointer user_data)566 static void free_key_val_strings(gpointer key, gpointer value, gpointer user_data)
567 {
568 g_free(key);
569 g_free(value);
570 }
571
bind_first_text(sqlite3_stmt * stmt,int idx,int n,...)572 static void bind_first_text(sqlite3_stmt *stmt, int idx, int n, ...)
573 {
574 va_list ap;
575 int i;
576
577 va_start(ap, n);
578 for (i = 0; i < n; i++) {
579 char *str = va_arg(ap, char*);
580 if (str && *str) {
581 sqlite3_bind_text(stmt, idx, str, -1, SQLITE_STATIC);
582 goto done;
583 }
584 }
585 sqlite3_bind_null(stmt, idx);
586 done:
587 va_end(ap);
588 }
589
mk_Library(Itdb_iTunesDB * itdb,GHashTable * album_ids,GHashTable * artist_ids,GHashTable * composer_ids,const char * outpath)590 static int mk_Library(Itdb_iTunesDB *itdb,
591 GHashTable *album_ids, GHashTable *artist_ids,
592 GHashTable *composer_ids, const char *outpath)
593 {
594 int res = -1;
595 gchar *dbf = NULL;
596 sqlite3 *db = NULL;
597 sqlite3_stmt *stmt_version_info = NULL;
598 sqlite3_stmt *stmt_db_info = NULL;
599 sqlite3_stmt *stmt_container = NULL;
600 sqlite3_stmt *stmt_genre_map = NULL;
601 sqlite3_stmt *stmt_item = NULL;
602 sqlite3_stmt *stmt_location_kind_map = NULL;
603 sqlite3_stmt *stmt_avformat_info = NULL;
604 sqlite3_stmt *stmt_item_to_container = NULL;
605 sqlite3_stmt *stmt_album = NULL;
606 sqlite3_stmt *stmt_artist = NULL;
607 sqlite3_stmt *stmt_composer = NULL;
608 sqlite3_stmt *stmt_video_info = NULL;
609 char *errmsg = NULL;
610 struct stat fst;
611 GList *gl = NULL;
612 Itdb_Playlist *dev_playlist = NULL;
613 int idx = 0;
614 int pos = 0;
615 GHashTable *genre_map = NULL;
616 GHashTable **orders = NULL;
617 guint32 genre_index;
618 printf("library_persistent_id = 0x%016"G_GINT64_MODIFIER"x\n", itdb->priv->pid);
619
620 dbf = g_build_filename(outpath, "Library.itdb", NULL);
621 printf("[%s] Processing '%s'\n", __func__, dbf);
622 if (stat(dbf, &fst) != 0) {
623 if (errno == ENOENT) {
624 /* file is not present. so we will create it */
625 } else {
626 fprintf(stderr, "[%s] Error: stat: %s\n", __func__, strerror(errno));
627 goto leave;
628 }
629 } else {
630 /* file is present. delete it, we'll re-create it. */
631 if (unlink(dbf) != 0) {
632 fprintf(stderr, "[%s] could not delete '%s': %s\n", __func__, dbf, strerror(errno));
633 goto leave;
634 }
635 }
636
637 if (SQLITE_OK != sqlite3_open((const char*)dbf, &db)) {
638 fprintf(stderr, "Error opening database '%s': %s\n", dbf, sqlite3_errmsg(db));
639 goto leave;
640 }
641
642 sqlite3_exec(db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
643
644 fprintf(stderr, "[%s] building table structure\n", __func__);
645 /* db structure needs to be created. */
646 if (SQLITE_OK != sqlite3_exec(db, Library_create, NULL, NULL, &errmsg)) {
647 fprintf(stderr, "[%s] sqlite3_exec error: %s\n", __func__, sqlite3_errmsg(db));
648 if (errmsg) {
649 fprintf(stderr, "[%s] additional error information: %s\n", __func__, errmsg);
650 sqlite3_free(errmsg);
651 errmsg = NULL;
652 }
653 goto leave;
654 }
655
656 sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
657
658 fprintf(stderr, "[%s] compiling SQL statements\n", __func__);
659 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"version_info\" VALUES(?,?,?,?,?,?,?);", -1, &stmt_version_info, NULL)) {
660 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
661 goto leave;
662 }
663 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"db_info\" VALUES(?,?,?,?,?,?,?,?);", -1, &stmt_db_info, NULL)) {
664 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
665 goto leave;
666 }
667 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"container\" "
668 "VALUES(?,?,?,?,:name,?,?,?,?,?,?,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);", -1, &stmt_container, NULL)) {
669 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
670 goto leave;
671 }
672 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"genre_map\" (id,genre,genre_order) VALUES(?,?,0);", -1, &stmt_genre_map, NULL)) {
673 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
674 goto leave;
675 }
676 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"item\" "
677 "(pid,media_kind,date_modified,year,is_compilation,remember_bookmark,exclude_from_shuffle,artwork_status,artwork_cache_id,"
678 "start_time_ms,stop_time_ms,total_time_ms,total_burn_time_ms,track_number,track_count,disc_number,disc_count,"
679 "bpm,relative_volume,eq_preset,radio_stream_status,genre_id,album_pid,artist_pid,composer_pid,title,artist,album,"
680 "album_artist,composer,sort_title,sort_artist,sort_album,sort_album_artist,sort_composer,title_order,artist_order,"
681 "album_order,genre_order,composer_order,album_artist_order,album_by_artist_order,series_name_order,comment,grouping,"
682 "description,description_long) "
683 "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", -1, &stmt_item, NULL)) {
684 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
685 goto leave;
686 }
687 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT OR IGNORE INTO \"location_kind_map\" VALUES(?,:kind);", -1, &stmt_location_kind_map, NULL)) {
688 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
689 goto leave;
690 }
691 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"avformat_info\" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?);", -1, &stmt_avformat_info, NULL)) {
692 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
693 goto leave;
694 }
695 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"item_to_container\" VALUES(?,?,?,?);", -1, &stmt_item_to_container, NULL)) {
696 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
697 goto leave;
698 }
699 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT OR IGNORE INTO \"album\" VALUES(?,?,?,?,?,?,?,?,?,?,?);", -1, &stmt_album, NULL)) {
700 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
701 goto leave;
702 }
703 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT OR IGNORE INTO \"artist\" VALUES(?,?,?,?,?,?,?);", -1, &stmt_artist, NULL)) {
704 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
705 goto leave;
706 }
707 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT OR IGNORE INTO \"composer\" (pid,name,name_order,sort_name) VALUES(?,?,?,?);", -1, &stmt_composer, NULL)) {
708 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
709 goto leave;
710 }
711 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"video_info\" VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);", -1, &stmt_video_info, NULL)) {
712 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
713 goto leave;
714 }
715
716 printf("[%s] - inserting into \"version_info\"\n", __func__);
717 /* INSERT INTO "version_info" VALUES(1,2,40,0,0,0,2); */
718 idx = 0;
719 /* id */
720 sqlite3_bind_int(stmt_version_info, ++idx, 1);
721 /* major */
722 /* FIXME: the versioning scheme needs to be updated in libgpod using */
723 /* major+minor version, this is a workaround */
724 sqlite3_bind_int(stmt_version_info, ++idx, (itdb->version >= 0x28) ? 2 : 1);
725 /* minor */
726 sqlite3_bind_int(stmt_version_info, ++idx, itdb->version);
727 /* compatibility */
728 /* This has an unknown meaning. use 0. */
729 sqlite3_bind_int(stmt_version_info, ++idx, 0);
730 /* update_level */
731 /* This has an unknown meaning. use 0. */
732 sqlite3_bind_int(stmt_version_info, ++idx, 0);
733 /* device_update_level, default is 0 */
734 sqlite3_bind_int(stmt_version_info, ++idx, 0);
735 /* platform, 1 = MacOS, 2 = Windows */
736 sqlite3_bind_int(stmt_version_info, ++idx, itdb->priv->platform);
737
738 res = sqlite3_step(stmt_version_info);
739 if (res == SQLITE_DONE) {
740 /* expected result */
741 } else {
742 fprintf(stderr, "[%s] 2 sqlite3_step returned %d\n", __func__, res);
743 }
744
745 printf("[%s] - inserting into \"genre_map\"\n", __func__);
746 genre_map = g_hash_table_new(g_str_hash, g_str_equal);
747
748 /* build genre_map */
749 genre_index = 1;
750 for (gl = itdb->tracks; gl; gl = gl->next) {
751 Itdb_Track *track = gl->data;
752 if ((track->genre == NULL) || (g_hash_table_lookup(genre_map, track->genre) != NULL))
753 continue;
754 g_hash_table_insert(genre_map, track->genre, GUINT_TO_POINTER(genre_index));
755
756 res = sqlite3_reset(stmt_genre_map);
757 if (res != SQLITE_OK) {
758 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
759 }
760
761 idx = 0;
762 /* id */
763 sqlite3_bind_int(stmt_genre_map, ++idx, genre_index++);
764 /* genre */
765 sqlite3_bind_text(stmt_genre_map, ++idx, track->genre, -1, SQLITE_STATIC);
766
767 res = sqlite3_step(stmt_genre_map);
768 if (res != SQLITE_DONE) {
769 fprintf(stderr, "[%s] sqlite3_step returned %d\n", __func__, res);
770 goto leave;
771 }
772 }
773
774 pos = 0;
775
776 for (gl = itdb->playlists; gl; gl = gl->next) {
777 int tpos = 0;
778 GList *glt = NULL;
779 guint32 types = 0;
780 Itdb_Playlist *pl = (Itdb_Playlist*)gl->data;
781
782 if (pl->type == 1) {
783 dev_playlist = pl;
784 }
785
786 printf("[%s] - inserting songs into \"item_to_container\"\n", __func__);
787
788 for (glt = pl->members; glt; glt = glt->next) {
789 Itdb_Track *track = glt->data;
790
791 /* printf("[%s] -- inserting into \"item_to_container\"\n", __func__); */
792 res = sqlite3_reset(stmt_item_to_container);
793 if (res != SQLITE_OK) {
794 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
795 } /* INSERT INTO "item_to_container" VALUES(-6197982141081478573,959107999841118509,0,NULL); */
796 idx = 0;
797 /* item_pid */
798 sqlite3_bind_int64(stmt_item_to_container, ++idx, track->dbid);
799 /* container_pid */
800 sqlite3_bind_int64(stmt_item_to_container, ++idx, pl->id);
801 /* physical_order */
802 sqlite3_bind_int(stmt_item_to_container, ++idx, tpos++);
803 /* shuffle_order */
804 /* TODO what's this? set to NULL as iTunes does */
805 sqlite3_bind_null(stmt_item_to_container, ++idx);
806
807 res = sqlite3_step(stmt_item_to_container);
808 if (res == SQLITE_DONE) {
809 /* expected result */
810 } else {
811 fprintf(stderr, "[%s] 8 sqlite3_step returned %d\n", __func__, res);
812 }
813
814 types |= track->mediatype;
815 }
816
817 printf("[%s] - inserting playlist '%s' into \"container\"\n", __func__, pl->name);
818 res = sqlite3_reset(stmt_container);
819 if (res != SQLITE_OK) {
820 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
821 }
822 /* INSERT INTO "container" VALUES(959107999841118509,0,267295295,'Hamouda',400,0,1,0,1,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); */
823 idx = 0;
824 /* pid */
825 sqlite3_bind_int64(stmt_container, ++idx, pl->id);
826 /* distinguished_kind */
827 /* TODO: more values? */
828 if (pl->podcastflag) {
829 sqlite3_bind_int(stmt_container, ++idx, 11);
830 } else {
831 sqlite3_bind_int(stmt_container, ++idx, 0);
832 }
833 /* date_created */
834 sqlite3_bind_int(stmt_container, ++idx, timeconv(pl->timestamp));
835 /* date_modified */
836 sqlite3_bind_int(stmt_container, ++idx, timeconv(pl->timestamp));
837 /* name */
838 sqlite3_bind_text(stmt_container, ++idx, pl->name, -1, SQLITE_STATIC);
839 /* name order */
840 sqlite3_bind_int(stmt_container, ++idx, pos++);
841 /* parent_pid */
842 /* TODO: unkown meaning, always 0? */
843 sqlite3_bind_int(stmt_container, ++idx, 0);
844 /* media_kinds */
845 sqlite3_bind_int(stmt_container, ++idx, types);
846 /* workout_template_id */
847 /* TODO: seems to be always 0 */
848 sqlite3_bind_int(stmt_container, ++idx, 0);
849 /* is_hidden */
850 /* 1 for dev and podcasts, 0 elsewhere */
851 if (pl->podcastflag || pl->type == 1) {
852 sqlite3_bind_int(stmt_container, ++idx, 1);
853 } else {
854 sqlite3_bind_int(stmt_container, ++idx, 0);
855 }
856 /* smart_is_folder */
857 /* TODO: smart playlist stuff? */
858 sqlite3_bind_int(stmt_container, ++idx, 0);
859 /* iTunes leaves everything else NULL for normal playlists */
860
861 res = sqlite3_step(stmt_container);
862 if (res == SQLITE_DONE) {
863 /* expected result */
864 } else {
865 fprintf(stderr, "[%s] 4 sqlite3_step returned %d\n", __func__, res);
866 }
867 }
868
869 if (!dev_playlist) {
870 fprintf(stderr, "Could not find special device playlist!\n");
871 goto leave;
872 }
873 printf("library_persistent_id = 0x%016"G_GINT64_MODIFIER"x\n", itdb->priv->pid);
874
875 if (!dev_playlist->name) {
876 fprintf(stderr, "Could not fetch device name from itdb!\n");
877 goto leave;
878 }
879 printf("device name = %s\n", dev_playlist->name);
880
881 printf("[%s] - inserting into \"db_info\"\n", __func__);
882 idx = 0;
883 /* pid */
884 sqlite3_bind_int64(stmt_db_info, ++idx, itdb->priv->pid);
885 /* primary_container_pid */
886 /* ... stored in the playlists where the device name is stored too. */
887 sqlite3_bind_int64(stmt_db_info, ++idx, dev_playlist->id);
888 /* media_folder_url */
889 sqlite3_bind_null(stmt_db_info, ++idx);
890 /* audio_language */
891 /* this is +0xA0 */
892 sqlite3_bind_int(stmt_db_info, ++idx, itdb->priv->audio_language);
893 /* subtitle_language */
894 /* this is +0xA2 */
895 sqlite3_bind_int(stmt_db_info, ++idx, itdb->priv->subtitle_language);
896 /* genius cuid */
897 if (itdb->priv->genius_cuid) {
898 sqlite3_bind_text(stmt_db_info, ++idx, itdb->priv->genius_cuid, -1, SQLITE_STATIC);
899 } else {
900 sqlite3_bind_null(stmt_db_info, ++idx);
901 }
902 /* bib */
903 /* TODO: unkown meaning, set to NULL */
904 sqlite3_bind_null(stmt_db_info, ++idx);
905 /* rib */
906 /* TODO: unkown meaning, set to NULL */
907 sqlite3_bind_null(stmt_db_info, ++idx);
908
909 res = sqlite3_step(stmt_db_info);
910 if (res == SQLITE_DONE) {
911 /* expected result */
912 } else {
913 fprintf(stderr, "[%s] 3 sqlite3_step returned %d\n", __func__, res);
914 }
915
916 /* for each track: */
917 printf("[%s] - processing %d tracks\n", __func__, g_list_length(itdb->tracks));
918 orders = compute_key_orders(itdb->tracks);
919
920 for (gl = itdb->tracks; gl; gl = gl->next) {
921 Itdb_Track *track = gl->data;
922 Itdb_Item_Id *this_album = NULL;
923 Itdb_Item_Id *this_artist = NULL;
924 Itdb_Item_Id *this_composer = NULL;
925 uint64_t album_pid = 0;
926 uint64_t artist_pid = 0;
927 uint64_t composer_pid = 0;
928 gpointer genre_id = NULL;
929 int audio_format;
930 int aw_id;
931
932 /* printf("[%s] -- inserting into \"item\"\n", __func__); */
933 res = sqlite3_reset(stmt_item);
934 if (res != SQLITE_OK) {
935 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
936 }
937 /* INSERT INTO "item" VALUES(-6197982141081478573,NULL,1,1,0,0,0,0,0,0,0,0,0,0,2004,0,0,0,0,0,0,2,0,0.0,0.0,213812.0,NULL,1,0,0,0,0,0,NULL,NULL,0,0,0,-7670716306765259718,-7576753259813584028,0,'Enjoy the silence 2004 (Reinterpreted by Mike Shinoda)','Depeche Mode','Enjoy The Silence 04 CDS','Depeche Mode',NULL,'Enjoy the silence 2004 (Reinterpreted by Mike Shinoda)','Depeche Mode','Enjoy The Silence 04 CDS','Depeche Mode',NULL,100,100,100,100,100,100,NULL,100,'Lbl MUTE C:MUTE RCDBONG034',NULL,NULL,NULL,1,0,0,0,0,1,1,NULL,NULL,NULL,NULL,NULL,NULL,NULL); */
938 idx = 0;
939 /* pid */
940 sqlite3_bind_int64(stmt_item, ++idx, track->dbid);
941 /* media_kind */
942 /* NOTE: this is one of */
943 /* song = 1 */
944 /* audio_book = 8 */
945 /* music_video = 32 */
946 /* movie = 2 */
947 /* tv_show = 64 */
948 /* ringtone = 16384 */
949 /* podcast = 4 */
950 /* rental = 32768 */
951 sqlite3_bind_int(stmt_item, ++idx, track->mediatype);
952 /* date_modified */
953 sqlite3_bind_int(stmt_item, ++idx, timeconv(track->time_modified));
954 /* year */
955 sqlite3_bind_int(stmt_item, ++idx, track->year);
956 /* is_compilation */
957 sqlite3_bind_int(stmt_item, ++idx, track->compilation);
958 /* remember_bookmark */
959 sqlite3_bind_int(stmt_item, ++idx, track->remember_playback_position);
960 /* exclude_from_shuffle */
961 sqlite3_bind_int(stmt_item, ++idx, track->skip_when_shuffling);
962 /* artwork_status 1 = has artwork, 2 = doesn't */
963 sqlite3_bind_int(stmt_item, ++idx, track->has_artwork);
964 /* artwork_cache_id */
965 /* TODO check if this value is correct */
966 aw_id = 0;
967 if (track->artwork) {
968 aw_id = track->artwork->id;
969 }
970 sqlite3_bind_int(stmt_item, ++idx, aw_id);
971 /* start_time_ms */
972 sqlite3_bind_double(stmt_item, ++idx, track->starttime);
973 /* stop_time_ms */
974 sqlite3_bind_double(stmt_item, ++idx, track->stoptime);
975 /* total_time_ms */
976 sqlite3_bind_double(stmt_item, ++idx, track->tracklen);
977 /* total_burn_time_ms --> set to NULL */
978 /* TODO where is this stored? */
979 sqlite3_bind_null(stmt_item, ++idx);
980 /* track_number */
981 sqlite3_bind_int(stmt_item, ++idx, track->track_nr);
982 /* track_count */
983 sqlite3_bind_int(stmt_item, ++idx, track->tracks);
984 /* disc_number */
985 sqlite3_bind_int(stmt_item, ++idx, track->cd_nr);
986 /* disc_count */
987 sqlite3_bind_int(stmt_item, ++idx, track->cds);
988 /* bpm */
989 sqlite3_bind_int(stmt_item, ++idx, track->BPM);
990 /* relative_volume */
991 sqlite3_bind_int(stmt_item, ++idx, track->volume);
992 /* eq_preset --> set to NULL */
993 sqlite3_bind_null(stmt_item, ++idx);
994 /* radio_stream_status --> set to NULL */
995 sqlite3_bind_null(stmt_item, ++idx);
996 /* genre_id */
997 genre_id = NULL;
998 if (track->genre && *track->genre && (genre_id = g_hash_table_lookup(genre_map, track->genre)) != NULL) {
999 sqlite3_bind_int(stmt_item, ++idx, GPOINTER_TO_UINT(genre_id));
1000 }
1001 else
1002 sqlite3_bind_int(stmt_item, ++idx, 0);
1003 /* album_pid -7670716306765259718 */
1004 this_album = g_hash_table_lookup(album_ids, track);
1005 if (this_album) {
1006 album_pid = this_album->sql_id;
1007 }
1008 sqlite3_bind_int64(stmt_item, ++idx, album_pid);
1009 /* artist_pid -7576753259813584028 */
1010 this_artist = g_hash_table_lookup(artist_ids, track);
1011 if (this_artist) {
1012 artist_pid = this_artist->sql_id;
1013 }
1014 sqlite3_bind_int64(stmt_item, ++idx, artist_pid);
1015 /* composer_pid */
1016 this_composer = g_hash_table_lookup(composer_ids, track);
1017 if (this_composer) {
1018 composer_pid = this_composer->sql_id;
1019 }
1020 sqlite3_bind_int64(stmt_item, ++idx, composer_pid);
1021 /* title */
1022 bind_first_text(stmt_item, ++idx, 1, track->title);
1023 /* artist */
1024 bind_first_text(stmt_item, ++idx, 1, track->artist);
1025 /* album */
1026 bind_first_text(stmt_item, ++idx, 1, track->album);
1027 /* album_artist */
1028 bind_first_text(stmt_item, ++idx, 1, track->albumartist);
1029 /* composer */
1030 bind_first_text(stmt_item, ++idx, 1, track->composer);
1031 /* sort_title */
1032 bind_first_text(stmt_item, ++idx, 2, track->sort_title, track->title);
1033 /* sort_artist */
1034 bind_first_text(stmt_item, ++idx, 2, track->sort_artist, track->artist);
1035 /* sort_album */
1036 bind_first_text(stmt_item, ++idx, 2, track->sort_album, track->album);
1037 /* sort_album_artist */
1038 bind_first_text(stmt_item, ++idx, 2, track->sort_albumartist, track->albumartist);
1039 /* sort_composer */
1040 bind_first_text(stmt_item, ++idx, 2, track->sort_composer, track->composer);
1041
1042 /* TODO figure out where these values are stored */
1043 /* title_order */
1044 sqlite3_bind_int(stmt_item, ++idx, lookup_order(orders, ORDER_TITLE, track));
1045 /* artist_order */
1046 sqlite3_bind_int(stmt_item, ++idx, lookup_order(orders, ORDER_ARTIST, track));
1047 /* album_order */
1048 sqlite3_bind_int(stmt_item, ++idx, lookup_order(orders, ORDER_ALBUM, track));
1049 /* genre_order */
1050 sqlite3_bind_int(stmt_item, ++idx, lookup_order(orders, ORDER_GENRE, track));
1051 /* composer_order */
1052 sqlite3_bind_int(stmt_item, ++idx, lookup_order(orders, ORDER_COMPOSER, track));
1053 /* album_artist_order */
1054 sqlite3_bind_int(stmt_item, ++idx, lookup_order(orders, ORDER_ALBUM_ARTIST, track));
1055 /* album_by_artist_order */
1056 sqlite3_bind_int(stmt_item, ++idx, lookup_order(orders, ORDER_ALBUM_BY_ARTIST, track));
1057 /* series_name_order */
1058 sqlite3_bind_int(stmt_item, ++idx, lookup_order(orders, ORDER_SERIES_NAME, track));
1059 /* comment */
1060 sqlite3_bind_text(stmt_item, ++idx, track->comment, -1, SQLITE_STATIC);
1061 /* grouping */
1062 bind_first_text(stmt_item, ++idx, 1, track->grouping);
1063 /* description */
1064 bind_first_text(stmt_item, ++idx, 1, track->description);
1065 /* description_long */
1066 /* TODO libgpod doesn't know about it */
1067 sqlite3_bind_null(stmt_item, ++idx);
1068
1069 res = sqlite3_step(stmt_item);
1070 if (res != SQLITE_DONE) {
1071 fprintf(stderr, "[%s] 6 sqlite3_step returned %d\n", __func__, res);
1072 goto leave;
1073 }
1074
1075 /* printf("[%s] -- inserting into \"location_kind_map\" (if required)\n", __func__); */
1076 res = sqlite3_reset(stmt_location_kind_map);
1077 if (res != SQLITE_OK) {
1078 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
1079 } /* INSERT INTO "location_kind_map" VALUES(1,'MPEG-Audiodatei'); */
1080 idx = 0;
1081 /* id */
1082 sqlite3_bind_int(stmt_location_kind_map, ++idx, track->mediatype);
1083 /* kind */
1084 sqlite3_bind_text(stmt_location_kind_map, ++idx, track->filetype, -1, SQLITE_STATIC);
1085
1086 res = sqlite3_step(stmt_location_kind_map);
1087 if (res == SQLITE_DONE) {
1088 /* expected result */
1089 } else {
1090 fprintf(stderr, "[%s] 5 sqlite3_step returned %d: %s\n", __func__, res, sqlite3_errmsg(db));
1091 }
1092
1093 /* printf("[%s] -- inserting into \"avformat_info\"\n", __func__); */
1094 res = sqlite3_reset(stmt_avformat_info);
1095 if (res != SQLITE_OK) {
1096 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
1097 } /* INSERT INTO "avformat_info" VALUES(-6197982141081478573,0,301,232,44100.0,9425664,1,576,2880,6224207,0,0,0); */
1098 idx = 0;
1099 /* item_pid */
1100 sqlite3_bind_int64(stmt_avformat_info, ++idx, track->dbid);
1101 /* sub_id */
1102 /* TODO what is this? set to 0 */
1103 sqlite3_bind_int64(stmt_avformat_info, ++idx, 0);
1104 /* audio_format, TODO what's this? */
1105 switch (track->filetype_marker) {
1106 case 0x4d503320:
1107 audio_format = 301;
1108 break;
1109 case 0x4d344120:
1110 case 0x4d345220:
1111 case 0x4d503420:
1112 audio_format = 502;
1113 break;
1114 default:
1115 audio_format = 0;
1116 }
1117 sqlite3_bind_int(stmt_avformat_info, ++idx, audio_format);
1118 /* bit_rate */
1119 sqlite3_bind_int(stmt_avformat_info, ++idx, track->bitrate);
1120 /* sample_rate */
1121 sqlite3_bind_double(stmt_avformat_info, ++idx, track->samplerate);
1122 /* duration (in samples) (track->tracklen is in ms) */
1123 /* iTunes sometimes set it to 0, do that for now since it's easier */
1124 sqlite3_bind_int(stmt_avformat_info, ++idx, 0);
1125 /* gapless_heuristic_info */
1126 sqlite3_bind_int(stmt_avformat_info, ++idx, track->gapless_track_flag);
1127 /* gapless_encoding_delay */
1128 sqlite3_bind_int(stmt_avformat_info, ++idx, track->pregap);
1129 /* gapless_encoding_drain */
1130 sqlite3_bind_int(stmt_avformat_info, ++idx, track->postgap);
1131 /* gapless_last_frame_resynch */
1132 sqlite3_bind_int(stmt_avformat_info, ++idx, track->gapless_data);
1133 /* analysis_inhibit_flags */
1134 /* TODO don't know where this belongs to */
1135 sqlite3_bind_int(stmt_avformat_info, ++idx, 0);
1136 /* audio_fingerprint */
1137 /* TODO this either */
1138 sqlite3_bind_int(stmt_avformat_info, ++idx, 0);
1139 /* volume_normalization_energy */
1140 sqlite3_bind_int(stmt_avformat_info, ++idx, track->soundcheck);
1141
1142 res = sqlite3_step(stmt_avformat_info);
1143 if (res == SQLITE_DONE) {
1144 /* expected result */
1145 } else {
1146 fprintf(stderr, "[%s] 7 sqlite3_step returned %d\n", __func__, res);
1147 }
1148
1149 /* this is done by a trigger, so we don't need to do this :-D */
1150 /* INSERT INTO "ext_item_view_membership" VALUES(-6197982141081478573,0,0); */
1151
1152 if (this_album) {
1153 /* printf("[%s] -- inserting into \"album\" (if required)\n", __func__); */
1154 res = sqlite3_reset(stmt_album);
1155 if (res != SQLITE_OK) {
1156 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
1157 }
1158 /* INSERT INTO "album" VALUES(-7670716306765259718,2,0,0,-7576753259813584028,0,'Enjoy The Silence 04 CDS',100,0,NULL,0); */
1159 idx = 0;
1160 /* pid */
1161 sqlite3_bind_int64(stmt_album, ++idx, album_pid);
1162 /* kind */
1163 /* TODO use field from mhia */
1164 sqlite3_bind_int(stmt_album, ++idx, 2);
1165 /* artwork_status */
1166 /* TODO */
1167 sqlite3_bind_int(stmt_album, ++idx, 0);
1168 /* artwork_item_pid */
1169 /* TODO */
1170 sqlite3_bind_int(stmt_album, ++idx, 0);
1171 /* artist_pid */
1172 sqlite3_bind_int64(stmt_album, ++idx, artist_pid);
1173 /* user_rating */
1174 sqlite3_bind_int(stmt_album, ++idx, 0);
1175 /* name */
1176 sqlite3_bind_text(stmt_album, ++idx, track->album, -1, SQLITE_STATIC);
1177 /* name_order */
1178 sqlite3_bind_int(stmt_album, ++idx, lookup_order(orders, ORDER_ALBUM_ARTIST, track));
1179 /* all_compilations */
1180 /* TODO */
1181 sqlite3_bind_int(stmt_album, ++idx, 0);
1182 /* feed_url */
1183 /* TODO this is for podcasts? */
1184 sqlite3_bind_null(stmt_album, ++idx);
1185 /* season_number */
1186 /* TODO this is for tv shows?! */
1187 sqlite3_bind_int(stmt_album, ++idx, 0);
1188
1189 res = sqlite3_step(stmt_album);
1190 if (res == SQLITE_DONE) {
1191 /* expected result */
1192 } else {
1193 fprintf(stderr, "[%s] 8 sqlite3_step returned %d\n", __func__, res);
1194 }
1195 }
1196
1197
1198 if (this_artist) {
1199 /* printf("[%s] -- inserting into \"artist\" (if required)\n", __func__); */
1200 res = sqlite3_reset(stmt_artist);
1201 if (res != SQLITE_OK) {
1202 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
1203 }
1204 /* INSERT INTO "artist" VALUES(-7576753259813584028,2,0,0,'Depeche Mode',100,'Depeche Mode'); */
1205 idx = 0;
1206 /* pid */
1207 sqlite3_bind_int64(stmt_artist, ++idx, artist_pid);
1208 /* kind */
1209 /* TODO use field from mhii */
1210 sqlite3_bind_int(stmt_artist, ++idx, 2);
1211 /* artwork_status */
1212 /* TODO */
1213 sqlite3_bind_int(stmt_artist, ++idx, 0);
1214 /* artwork_album_pid */
1215 /* TODO */
1216 sqlite3_bind_int(stmt_artist, ++idx, 0);
1217 /* name */
1218 sqlite3_bind_text(stmt_artist, ++idx, track->artist, -1, SQLITE_STATIC);
1219 /* name_order */
1220 sqlite3_bind_int(stmt_artist, ++idx, lookup_order(orders, ORDER_ARTIST, track));
1221 /* sort_name */
1222 /* TODO always same as 'name'? */
1223 sqlite3_bind_text(stmt_artist, ++idx, track->artist, -1, SQLITE_STATIC);
1224
1225 res = sqlite3_step(stmt_artist);
1226 if (res == SQLITE_DONE) {
1227 /* expected result */
1228 } else {
1229 fprintf(stderr, "[%s] 8 sqlite3_step returned %d\n", __func__, res);
1230 }
1231 }
1232
1233 if (this_composer) {
1234 /* printf("[%s] -- inserting into \"composer\" (if required)\n", __func__); */
1235 res = sqlite3_reset(stmt_composer);
1236 if (res != SQLITE_OK) {
1237 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
1238 }
1239 idx = 0;
1240 /* pid */
1241 sqlite3_bind_int64(stmt_composer, ++idx, composer_pid);
1242 /* name */
1243 sqlite3_bind_text(stmt_composer, ++idx, track->composer, -1, SQLITE_STATIC);
1244 /* name_order */
1245 sqlite3_bind_int(stmt_composer, ++idx, lookup_order(orders, ORDER_COMPOSER, track));
1246 /* sort_name */
1247 /* TODO always same as 'name'? */
1248 sqlite3_bind_text(stmt_composer, ++idx, track->composer, -1, SQLITE_STATIC);
1249
1250 res = sqlite3_step(stmt_composer);
1251 if (res == SQLITE_DONE) {
1252 /* expected result */
1253 } else {
1254 fprintf(stderr, "[%s] 8 sqlite3_step returned %d\n", __func__, res);
1255 }
1256 }
1257 /* if it's a movie, music video or tv show */
1258 if ((track->mediatype & ITDB_MEDIATYPE_MOVIE)
1259 || (track->mediatype & ITDB_MEDIATYPE_MUSICVIDEO)
1260 || (track->mediatype & ITDB_MEDIATYPE_TVSHOW)) {
1261 /* printf("[%s] -- inserting into \"video_info\"\n", __func__); */
1262 res = sqlite3_reset(stmt_video_info);
1263 if (res != SQLITE_OK) {
1264 fprintf(stderr, "[%s] 1 sqlite3_reset returned %d\n", __func__, res);
1265 }
1266 idx = 0;
1267 /* item_pid INTEGER NOT NULL */
1268 sqlite3_bind_int64(stmt_video_info, ++idx, track->dbid);
1269 /* has_alternate_audio INTEGER */
1270 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1271 /* has_subtitles INTEGER */
1272 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1273 /* characteristics_valid INTEGER */
1274 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1275 /* has_closed_captions INTEGER */
1276 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1277 /* is_self_contained INTEGER */
1278 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1279 /* is_compressed INTEGER */
1280 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1281 /* is_anamorphic INTEGER */
1282 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1283 /* season_number INTEGER */
1284 sqlite3_bind_int(stmt_video_info, ++idx, track->season_nr);
1285 /* audio_language INTEGER */
1286 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1287 /* audio_track_index INTEGER */
1288 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1289 /* audio_track_id INTEGER */
1290 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1291 /* subtitle_language INTEGER */
1292 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1293 /* subtitle_track_index INTEGER */
1294 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1295 /* subtitle_track_id INTEGER */
1296 sqlite3_bind_int(stmt_video_info, ++idx, 0);
1297 /* series_name TEXT */
1298 sqlite3_bind_text(stmt_video_info, ++idx, track->tvshow, -1, SQLITE_STATIC);
1299 /* sort_series_name TEXT */
1300 bind_first_text(stmt_item, ++idx, 2, track->sort_tvshow, track->tvshow);
1301 /* episode_id TEXT */
1302 sqlite3_bind_text(stmt_video_info, ++idx, track->tvepisode, -1, SQLITE_STATIC);
1303 /* episode_sort_id INTEGER */
1304 sqlite3_bind_int(stmt_video_info, ++idx, track->season_nr << 16 | track->episode_nr);
1305 /* network_name TEXT */
1306 sqlite3_bind_text(stmt_video_info, ++idx, track->tvnetwork, -1, SQLITE_STATIC);
1307 /* extended_content_rating TEXT */
1308 sqlite3_bind_null(stmt_video_info, ++idx);
1309 /* movie_info TEXT */
1310 sqlite3_bind_null(stmt_video_info, ++idx);
1311
1312 res = sqlite3_step(stmt_video_info);
1313 if (res == SQLITE_DONE) {
1314 /* expected result */
1315 } else {
1316 fprintf(stderr, "[%s] 8 sqlite3_step returned %d\n", __func__, res);
1317 }
1318 }
1319 }
1320
1321 sqlite3_exec(db, "UPDATE album SET artwork_item_pid = (SELECT item.pid FROM item WHERE item.artwork_cache_id != 0 AND item.album_pid = album.pid LIMIT 1);", NULL, NULL, NULL);
1322
1323 sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
1324
1325 res = 0;
1326 printf("[%s] done.\n", __func__);
1327 leave:
1328 if (orders != NULL) {
1329 destroy_key_orders(orders);
1330 }
1331
1332 if (stmt_version_info) {
1333 sqlite3_finalize(stmt_version_info);
1334 }
1335 if (stmt_db_info) {
1336 sqlite3_finalize(stmt_db_info);
1337 }
1338 if (stmt_container) {
1339 sqlite3_finalize(stmt_container);
1340 }
1341 if (stmt_genre_map) {
1342 sqlite3_finalize(stmt_genre_map);
1343 }
1344 if (stmt_item) {
1345 sqlite3_finalize(stmt_item);
1346 }
1347 if (stmt_location_kind_map) {
1348 sqlite3_finalize(stmt_location_kind_map);
1349 }
1350 if (stmt_avformat_info) {
1351 sqlite3_finalize(stmt_avformat_info);
1352 }
1353 if (stmt_item_to_container) {
1354 sqlite3_finalize(stmt_item_to_container);
1355 }
1356 if (stmt_album) {
1357 sqlite3_finalize(stmt_album);
1358 }
1359 if (stmt_artist) {
1360 sqlite3_finalize(stmt_artist);
1361 }
1362 if (stmt_composer) {
1363 sqlite3_finalize(stmt_composer);
1364 }
1365 if (stmt_video_info) {
1366 sqlite3_finalize(stmt_video_info);
1367 }
1368 if (genre_map) {
1369 g_hash_table_destroy(genre_map);
1370 }
1371 if (db) {
1372 sqlite3_close(db);
1373 }
1374 if (dbf) {
1375 g_free(dbf);
1376 }
1377 return res;
1378 }
1379
mk_Locations(Itdb_iTunesDB * itdb,const char * outpath,const char * uuid)1380 static int mk_Locations(Itdb_iTunesDB *itdb, const char *outpath, const char *uuid)
1381 {
1382 int res = -1;
1383 gchar *dbf = NULL;
1384 sqlite3 *db = NULL;
1385 sqlite3_stmt *stmt = NULL;
1386 char *errmsg = NULL;
1387 int idx = 0;
1388
1389 dbf = g_build_filename(outpath, "Locations.itdb", NULL);
1390 printf("[%s] Processing '%s'\n", __func__, dbf);
1391 /* file is present. delete it, we'll re-create it. */
1392 if (g_unlink(dbf) != 0) {
1393 if (errno != ENOENT) {
1394 fprintf(stderr, "[%s] could not delete '%s': %s\n", __func__, dbf, strerror(errno));
1395 goto leave;
1396 }
1397 }
1398
1399 if (SQLITE_OK != sqlite3_open((const char*)dbf, &db)) {
1400 fprintf(stderr, "Error opening database '%s': %s\n", dbf, sqlite3_errmsg(db));
1401 goto leave;
1402 }
1403
1404 sqlite3_exec(db, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
1405
1406 fprintf(stderr, "[%s] re-building table structure\n", __func__);
1407 /* db structure needs to be created. */
1408 if (SQLITE_OK != sqlite3_exec(db, Locations_create, NULL, NULL, &errmsg)) {
1409 fprintf(stderr, "[%s] sqlite3_exec error: %s\n", __func__, sqlite3_errmsg(db));
1410 if (errmsg) {
1411 fprintf(stderr, "[%s] additional error information: %s\n", __func__, errmsg);
1412 sqlite3_free(errmsg);
1413 errmsg = NULL;
1414 }
1415 goto leave;
1416 }
1417
1418 sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
1419
1420 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"base_location\" (id, path) VALUES (?,?);", -1, &stmt, NULL)) {
1421 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
1422 goto leave;
1423 }
1424 idx = 0;
1425 res = sqlite3_reset(stmt);
1426 if (res != SQLITE_OK) {
1427 fprintf(stderr, "[%s] sqlite3_reset returned %d\n", __func__, res);
1428 }
1429
1430 sqlite3_bind_int(stmt, ++idx, 1);
1431 if (itdb_device_is_iphone_family(itdb->device)) {
1432 sqlite3_bind_text(stmt, ++idx, "iTunes_Control/Music", -1, SQLITE_STATIC);
1433 } else {
1434 sqlite3_bind_text(stmt, ++idx, "iPod_Control/Music", -1, SQLITE_STATIC);
1435 }
1436 res = sqlite3_step(stmt);
1437 if (res == SQLITE_DONE) {
1438 /* expected result */
1439 } else {
1440 fprintf(stderr, "[%s] sqlite3_step returned %d\n", __func__, res);
1441 }
1442
1443 if (itdb_device_is_iphone_family(itdb->device)) {
1444 idx = 0;
1445 res = sqlite3_reset(stmt);
1446 if (res != SQLITE_OK) {
1447 fprintf(stderr, "[%s] sqlite3_reset returned %d\n", __func__, res);
1448 }
1449 sqlite3_bind_int(stmt, ++idx, 4);
1450 sqlite3_bind_text(stmt, ++idx, "Podcasts", -1, SQLITE_STATIC);
1451 res = sqlite3_step(stmt);
1452 if (res == SQLITE_DONE) {
1453 /* expected result */
1454 } else {
1455 fprintf(stderr, "[%s] sqlite3_step returned %d\n", __func__, res);
1456 }
1457
1458 idx = 0;
1459 res = sqlite3_reset(stmt);
1460 if (res != SQLITE_OK) {
1461 fprintf(stderr, "[%s] sqlite3_reset returned %d\n", __func__, res);
1462 }
1463 sqlite3_bind_int(stmt, ++idx, 6);
1464 sqlite3_bind_text(stmt, ++idx, "iTunes_Control/Ringtones", -1, SQLITE_STATIC);
1465 res = sqlite3_step(stmt);
1466 if (res == SQLITE_DONE) {
1467 /* expected result */
1468 } else {
1469 fprintf(stderr, "[%s] sqlite3_step returned %d\n", __func__, res);
1470 }
1471 }
1472
1473 if (stmt) {
1474 sqlite3_finalize(stmt);
1475 }
1476
1477 if (SQLITE_OK != sqlite3_prepare_v2(db, "INSERT INTO \"location\" (item_pid, sub_id, base_location_id, location_type, location, extension, kind_id, date_created, file_size) VALUES(?,?,?,?,?,?,?,?,?);", -1, &stmt, NULL)) {
1478 fprintf(stderr, "[%s] sqlite3_prepare error: %s\n", __func__, sqlite3_errmsg(db));
1479 goto leave;
1480 }
1481
1482 if (itdb->tracks) {
1483 GList *gl = NULL;
1484
1485 printf("[%s] Processing %d tracks...\n", __func__, g_list_length(itdb->tracks));
1486 for (gl=itdb->tracks; gl; gl=gl->next) {
1487 Itdb_Track *track = gl->data;
1488 char *ipod_path;
1489 int i = 0;
1490 int cnt = 0;
1491 int pos = 0;
1492 int res;
1493
1494 if (!track->ipod_path) {
1495 continue;
1496 }
1497 ipod_path = strdup(track->ipod_path);
1498 idx = 0;
1499 res = sqlite3_reset(stmt);
1500 if (res != SQLITE_OK) {
1501 fprintf(stderr, "[%s] sqlite3_reset returned %d\n", __func__, res);
1502 }
1503 /* item_pid */
1504 sqlite3_bind_int64(stmt, ++idx, track->dbid);
1505 /* sub_id */
1506 /* TODO subitle id? set to 0. */
1507 sqlite3_bind_int64(stmt, ++idx, 0);
1508 /* base_location_id */
1509 /* use 1 here as this is 'iTunes_Control/Music' */
1510 sqlite3_bind_int(stmt, ++idx, 1);
1511 /* location_type */
1512 /* TODO this should always be 0x46494C45 = "FILE" for now, */
1513 /* perhaps later libgpod will support more. */
1514 sqlite3_bind_int(stmt, ++idx, 0x46494C45);
1515 /* location */
1516 for (i = 0; i < strlen(ipod_path); i++) {
1517 /* replace all ':' with '/' so that the path is valid */
1518 if (ipod_path[i] == ':') {
1519 ipod_path[i] = '/';
1520 cnt++;
1521 if (cnt == 3) {
1522 pos = i+1;
1523 }
1524 }
1525 }
1526 sqlite3_bind_text(stmt, ++idx, ipod_path + pos, -1, SQLITE_STATIC);
1527 /* extension */
1528 sqlite3_bind_int(stmt, ++idx, track->filetype_marker);
1529 /* kind_id, should match track->mediatype */
1530 sqlite3_bind_int(stmt, ++idx, track->mediatype);
1531 /* date_created */
1532 sqlite3_bind_int(stmt, ++idx, timeconv(track->time_modified));
1533 /* file_size */
1534 sqlite3_bind_int(stmt, ++idx, track->size);
1535 #if 0
1536 /* file_creator */
1537 /* TODO unknown, set to NULL */
1538 sqlite3_bind_null(stmt, ++idx);
1539 /* file_type */
1540 /* TODO unknown, set to NULL */
1541 sqlite3_bind_null(stmt, ++idx);
1542 /* num_dir_levels_file */
1543 /* TODO unknown, set to NULL */
1544 sqlite3_bind_null(stmt, ++idx);
1545 /* num_dir_levels_lib */
1546 /* TODO unknown, set to NULL */
1547 sqlite3_bind_null(stmt, ++idx);
1548 #endif
1549 res = sqlite3_step(stmt);
1550 if (res == SQLITE_DONE) {
1551 /* expected result */
1552 } else {
1553 fprintf(stderr, "[%s] 10 sqlite3_step returned %d\n", __func__, res);
1554 }
1555 if (ipod_path) {
1556 free(ipod_path);
1557 ipod_path = NULL;
1558 }
1559 }
1560 } else {
1561 printf("[%s] No tracks available, none written.\n", __func__);
1562 }
1563
1564 sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
1565
1566 res = 0;
1567 printf("[%s] done.\n", __func__);
1568 leave:
1569 if (stmt) {
1570 sqlite3_finalize(stmt);
1571 }
1572 if (db) {
1573 sqlite3_close(db);
1574 }
1575 if (dbf) {
1576 g_free(dbf);
1577 }
1578 return res;
1579 }
1580
sort_key_get_buffer_boundaries(const char * sval,int * length,int * word_offset)1581 static void sort_key_get_buffer_boundaries(const char* sval, int *length, int *word_offset)
1582 {
1583 int word_count = 0;
1584 int i = 0;
1585 int l = 0;
1586 int o = 0;
1587 char *sval_uppercase = NULL;
1588 if (sval && strlen(sval)) {
1589 sval_uppercase = g_ascii_strup(sval, strlen(sval));
1590 while (sval_uppercase[i]) {
1591 if (g_ascii_isalnum(sval_uppercase[i])) {
1592 l++;
1593 } else {
1594 switch (sval_uppercase[i]) {
1595 case ' ':
1596 word_count++;
1597 l++;
1598 break;
1599 case ':':
1600 case '-':
1601 case ',':
1602 case '.':
1603 case '\'':
1604 default:
1605 l += 2;
1606 break;
1607 }
1608 }
1609 i++;
1610 }
1611 free(sval_uppercase);
1612
1613 word_count++;
1614 /* magic + transformed string + length + word weights + null */
1615 o = 1 + l + 3;
1616 l = o + (word_count*2) + 1;
1617 } else {
1618 l = 4;
1619 }
1620
1621 *length = l;
1622 *word_offset = o;
1623 }
1624
sqlite_func_iphone_sort_key(sqlite3_context * context,int argc,sqlite3_value ** argv)1625 static void sqlite_func_iphone_sort_key(sqlite3_context *context, int argc, sqlite3_value **argv)
1626 {
1627 const char *sval;
1628 char *sval_uppercase = NULL;
1629
1630 char *buffer = NULL;
1631
1632 int word_count = 0;
1633 int word_offset = 0;
1634 int word_length = 0;
1635 int i = 0;
1636 int buffer_index = 0;
1637 int buffer_size = 0;
1638
1639 if (argc != 1)
1640 fprintf(stderr, "[%s] Error: Unexpected number of arguments: %d\n", __func__, argc);
1641
1642 switch (sqlite3_value_type(argv[0])) {
1643 case SQLITE_TEXT:
1644 sval = (const char*)sqlite3_value_text(argv[0]);
1645 sort_key_get_buffer_boundaries(sval, &buffer_size, &word_offset);
1646 buffer = (char*)malloc(buffer_size);
1647 memset(buffer, '\0', buffer_size);
1648 buffer[buffer_index] = 0x31;
1649 if (sval) {
1650 if (buffer_size > 4) {
1651 buffer[buffer_index++] = 0x30;
1652 /* transform text value */
1653 /* uppercase the text */
1654 sval_uppercase = g_ascii_strup(sval, strlen(sval));
1655 while (sval_uppercase[i]) {
1656 word_length++;
1657 if (g_ascii_isalnum(sval_uppercase[i])) {
1658 /* transform regular character */
1659 buffer[buffer_index++] = sval_uppercase[i] - (0x55 - sval_uppercase[i]);
1660 } else {
1661 /* transform special chars (punctuation,special) */
1662 switch (sval_uppercase[i]) {
1663 case ' ':
1664 buffer[buffer_index++] = 0x06;
1665 word_length--;
1666
1667 /* since we reached word end, calculate word weight */
1668 buffer[word_offset + word_count*2] = 0x8f;
1669 buffer[word_offset + word_count*2 + 1] = (char)(0x86 - word_length);
1670 word_count++;
1671 word_length = 0;
1672 break;
1673 case ':':
1674 buffer[buffer_index++] = 0x07;
1675 buffer[buffer_index++] = 0xd8;
1676 break;
1677 case '-':
1678 buffer[buffer_index++] = 0x07;
1679 buffer[buffer_index++] = 0x90;
1680 break;
1681 case ',':
1682 buffer[buffer_index++] = 0x07;
1683 buffer[buffer_index++] = 0xb2;
1684 break;
1685 case '.':
1686 buffer[buffer_index++] = 0x08;
1687 buffer[buffer_index++] = 0x51;
1688 break;
1689 case '\'':
1690 buffer[buffer_index++] = 0x07;
1691 buffer[buffer_index++] = 0x31;
1692 break;
1693 default:
1694 /* FIXME: We just simulate "-" for any other char, needs proper conversion */
1695 buffer[buffer_index++] = 0x07;
1696 buffer[buffer_index++] = 0x90;
1697 break;
1698 }
1699 }
1700 i++;
1701 }
1702 g_free(sval_uppercase);
1703
1704 /* calculate word weight for last word */
1705 buffer[word_offset + word_count*2] = 0x8f;
1706 buffer[word_offset + word_count*2 + 1] = 3 + word_length;
1707 word_count++;
1708 word_length = 0;
1709
1710 /* write length of input string */
1711 buffer[word_offset - 3] = 0x01;
1712 buffer[word_offset - 2] = i + 4; /* length of input string + 4 */
1713 buffer[word_offset - 1] = 0x01;
1714 } else {
1715 buffer[0] = 0x31;
1716 buffer[1] = 0x01;
1717 buffer[2] = 0x01;
1718 }
1719 }
1720 sqlite3_result_blob(context, buffer, buffer_size, free);
1721 break;
1722 case SQLITE_NULL:
1723 buffer = (char*)malloc(4);
1724 memcpy(buffer, "\x31\x01\x01\x00", 4);
1725 sqlite3_result_blob(context, buffer, 4, free);
1726 break;
1727 default:
1728 sqlite3_result_null(context);
1729 break;
1730 }
1731 }
1732
sqlite_func_iphone_sort_section(sqlite3_context * context,int argc,sqlite3_value ** argv)1733 static void sqlite_func_iphone_sort_section(sqlite3_context *context, int argc, sqlite3_value **argv)
1734 {
1735 const unsigned char *sval;
1736 int res = 26;
1737
1738 if (argc != 1)
1739 fprintf(stderr, "[%s] Error: Unexpected number of arguments: %d\n", __func__, argc);
1740
1741 switch (sqlite3_value_type(argv[0])) {
1742 case SQLITE_BLOB:
1743 case SQLITE_TEXT:
1744 sval = sqlite3_value_text(argv[0]);
1745 if (sval && (sval[0] == 0x30) && (sval[1] >= 0x2D) && (sval[1] <= 0x5F)) {
1746 res = (sval[1] - 0x2D) / 2;
1747 }
1748 break;
1749 default:
1750 break;
1751 }
1752 sqlite3_result_int(context, res);
1753 }
1754
run_post_process_commands(Itdb_iTunesDB * itdb,const char * outpath,const char * uuid)1755 static void run_post_process_commands(Itdb_iTunesDB *itdb, const char *outpath, const char *uuid)
1756 {
1757 plist_t plist_node = NULL;
1758 plist_t ppc_dict = NULL;
1759 const gchar *basedb = "Library.itdb";
1760 const gchar *otherdbs[] = {"Dynamic.itdb", "Extras.itdb", "Genius.itdb", "Locations.itdb", NULL};
1761 int res;
1762 sqlite3 *db = NULL;
1763
1764 #ifdef HAVE_LIBIMOBILEDEVICE
1765 if (itdb_device_is_iphone_family(itdb->device)) {
1766 /* get SQL post process commands via lockdown (iPhone/iPod Touch) */
1767 lockdownd_client_t client = NULL;
1768 idevice_t phone = NULL;
1769 idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
1770 lockdownd_error_t lockdownerr = LOCKDOWN_E_UNKNOWN_ERROR;
1771
1772 ret = idevice_new(&phone, uuid);
1773 if (ret != IDEVICE_E_SUCCESS) {
1774 printf("[%s] ERROR: Could not find device with uuid %s, is it plugged in?\n", __func__, uuid);
1775 goto leave;
1776 }
1777
1778 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(phone, &client, "libgpod")) {
1779 printf("[%s] ERROR: Could not connect to device's lockdownd!\n", __func__);
1780 idevice_free(phone);
1781 goto leave;
1782 }
1783
1784 lockdownerr = lockdownd_get_value(client, "com.apple.mobile.iTunes.SQLMusicLibraryPostProcessCommands", NULL, &plist_node);
1785 lockdownd_client_free(client);
1786 idevice_free(phone);
1787
1788 if (lockdownerr == LOCKDOWN_E_SUCCESS) {
1789 ppc_dict = plist_node;
1790 } else {
1791 if (plist_node) {
1792 plist_free(plist_node);
1793 plist_node = NULL;
1794 }
1795 }
1796 } else
1797 #endif
1798 if (itdb->device->sysinfo_extended != NULL) {
1799 /* try to get SQL post process commands via sysinfo_extended */
1800 gchar *dev_path = itdb_get_device_dir(itdb->device->mountpoint);
1801 if (dev_path) {
1802 const gchar *p_sysinfo_ex[] = {"SysInfoExtended", NULL};
1803 gchar *sysinfo_ex_path = itdb_resolve_path(dev_path, p_sysinfo_ex);
1804 g_free(dev_path);
1805 if (sysinfo_ex_path) {
1806 /* open plist file */
1807 char *xml_contents = NULL;
1808 gsize xml_length = 0;
1809 if (g_file_get_contents(sysinfo_ex_path, &xml_contents, &xml_length, NULL)) {
1810 plist_from_xml(xml_contents, xml_length, &plist_node);
1811 if (plist_node) {
1812 /* locate specific key */
1813 ppc_dict = plist_dict_get_item(plist_node, "com.apple.mobile.iTunes.SQLMusicLibraryPostProcessCommands");
1814 }
1815 }
1816 if (xml_contents) {
1817 g_free(xml_contents);
1818 }
1819 g_free(sysinfo_ex_path);
1820 }
1821 }
1822 }
1823
1824 if (ppc_dict) {
1825 plist_dict_iter iter = NULL;
1826 plist_t sql_cmds = NULL;
1827 plist_t user_ver_cmds = NULL;
1828
1829 printf("[%s] Getting SQL post process commands\n", __func__);
1830
1831 sql_cmds = plist_dict_get_item(ppc_dict, "SQLCommands");
1832 user_ver_cmds = plist_dict_get_item(ppc_dict, "UserVersionCommandSets");
1833
1834 if (sql_cmds && user_ver_cmds) {
1835 /* we found the SQLCommands and the UserVersionCommandSets keys */
1836 char *key = NULL;
1837 unsigned long int maxver = 0;
1838 plist_t curnode = user_ver_cmds;
1839 plist_t subnode = NULL;
1840
1841 user_ver_cmds = NULL;
1842
1843 /* now look for numbered subkey in the UserVersionCommandsSets */
1844 plist_dict_new_iter(curnode, &iter);
1845 if (iter) {
1846 plist_dict_next_item(curnode, iter, &key, &subnode);
1847 while (subnode) {
1848 unsigned long int intval = strtoul(key, NULL, 0);
1849 if ((intval > 0) && (intval > maxver)) {
1850 user_ver_cmds = subnode;
1851 maxver = intval;
1852 }
1853 subnode = NULL;
1854 free(key);
1855 key = NULL;
1856 plist_dict_next_item(curnode, iter, &key, &subnode);
1857 }
1858 free(iter);
1859 iter = NULL;
1860 }
1861 if (user_ver_cmds) {
1862 /* found numbered key (usually '8', for Nano 5G it is '9') */
1863 curnode = user_ver_cmds;
1864 /* now get the commands array */
1865 user_ver_cmds = plist_dict_get_item(curnode, "Commands");
1866 if (user_ver_cmds && (plist_get_node_type(user_ver_cmds) == PLIST_ARRAY)) {
1867 /* We found our array with the commands to execute, now
1868 * make a hashmap for the SQLCommands to find them faster
1869 * when we actually execute them in correct order. */
1870 GHashTable *sqlcmd_map = g_hash_table_new(g_str_hash, g_str_equal);
1871 if (sqlcmd_map) {
1872 char *val = NULL;
1873 gchar *dbf = NULL;
1874 gchar *attach_str = NULL;
1875 char *errmsg = NULL;
1876 guint32 i = 0, cnt = 0, ok_cnt = 0;
1877
1878 plist_dict_new_iter(sql_cmds, &iter);
1879 if (iter) {
1880 plist_dict_next_item(sql_cmds, iter, &key, &subnode);
1881 while (subnode) {
1882 if (plist_get_node_type(subnode) == PLIST_STRING) {
1883 plist_get_string_val(subnode, &val);
1884 g_hash_table_insert(sqlcmd_map, key, val);
1885 val = NULL;
1886 } else {
1887 printf("[%s] WARNING: ignoring non-string value for key '%s'\n", __func__, key);
1888 free(key);
1889 }
1890 subnode = NULL;
1891 key = NULL;
1892 plist_dict_next_item(sql_cmds, iter, &key, &subnode);
1893 }
1894 free(iter);
1895 iter = NULL;
1896 }
1897
1898 /* open Library.itdb first */
1899 dbf = g_build_filename(outpath, basedb, NULL);
1900
1901 if (SQLITE_OK != sqlite3_open((const char*)dbf, &db)) {
1902 fprintf(stderr, "Error opening database '%s': %s\n", dbf, sqlite3_errmsg(db));
1903 g_free(dbf);
1904 goto leave;
1905 }
1906 g_free(dbf);
1907
1908 /* now attach other required database files */
1909 i = 0;
1910 while (otherdbs[i]) {
1911 errmsg = NULL;
1912 dbf = g_build_filename(outpath, otherdbs[i], NULL);
1913 attach_str = g_strdup_printf("ATTACH DATABASE '%s' AS '%s';", dbf, otherdbs[i]);
1914 g_free(dbf);
1915 res = sqlite3_exec(db, attach_str, NULL, NULL, &errmsg);
1916 g_free(attach_str);
1917 if (res != SQLITE_OK) {
1918 printf("[%s] WARNING: Could not attach database '%s': %s\n", __func__, otherdbs[i], errmsg);
1919 }
1920 if (errmsg) {
1921 free(errmsg);
1922 }
1923 i++;
1924 }
1925
1926 printf("[%s] binding functions\n", __func__);
1927 sqlite3_create_function(db, "iPhoneSortKey", 1, SQLITE_ANY, NULL, &sqlite_func_iphone_sort_key, NULL, NULL);
1928 sqlite3_create_function(db, "iPhoneSortSection", 1, SQLITE_ANY, NULL, &sqlite_func_iphone_sort_section, NULL, NULL);
1929
1930 cnt = plist_array_get_size(user_ver_cmds);
1931 printf("[%s] Running %d post process commands now\n", __func__, cnt);
1932
1933 sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
1934 for (i=0; i<cnt; i++) {
1935 subnode = plist_array_get_item(user_ver_cmds, i);
1936 plist_get_string_val(subnode, &key);
1937 if (key) {
1938 val = g_hash_table_lookup(sqlcmd_map, key);
1939 if (val) {
1940 char *errmsg = NULL;
1941 if (SQLITE_OK == sqlite3_exec(db, val, NULL, NULL, &errmsg)) {
1942 /*printf("[%s] executing '%s': OK", __func__, key);*/
1943 ok_cnt++;
1944 } else {
1945 printf("[%s] ERROR when executing '%s': %s\n", __func__, key, errmsg);
1946 }
1947 if (errmsg) {
1948 sqlite3_free(errmsg);
1949 }
1950 } else {
1951 printf("[%s] value for '%s' not found in hashmap!\n", __func__, key);
1952 }
1953 free(key);
1954 key = NULL;
1955 }
1956 }
1957 g_hash_table_foreach(sqlcmd_map, free_key_val_strings, NULL);
1958 g_hash_table_destroy(sqlcmd_map);
1959
1960 printf("[%s] %d out of %d post process commands successfully executed\n", __func__, ok_cnt, cnt);
1961 /* TODO perhaps we want to roll back when an error has occured ? */
1962 sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
1963 } else {
1964 printf("[%s]: Error: could not create hash table!\n", __func__);
1965 }
1966 } else {
1967 printf("[%s]: Error fetching commands array\n", __func__);
1968 }
1969 } else {
1970 printf("[%s]: Error fetching user version command set\n", __func__);
1971 }
1972 } else {
1973 printf("[%s]: Error fetching post process commands from device!\n", __func__);
1974 }
1975 }
1976
1977 printf("[%s] done.\n", __func__);
1978
1979 leave:
1980 if (db) {
1981 sqlite3_close(db);
1982 }
1983 if (plist_node) {
1984 plist_free(plist_node);
1985 }
1986
1987 }
1988
cbk_calc_sha1_one_block(FILE * f,unsigned char sha1[20])1989 static int cbk_calc_sha1_one_block(FILE *f, unsigned char sha1[20])
1990 {
1991 const guint BLOCK_SIZE = 1024;
1992 unsigned char block[BLOCK_SIZE];
1993 size_t read_count;
1994 GChecksum *checksum;
1995 gsize sha1_len;
1996
1997 read_count = fread(block, BLOCK_SIZE, 1, f);
1998 if ((read_count != 1)) {
1999 if (feof(f)) {
2000 return 1;
2001 } else {
2002 return -1;
2003 }
2004 }
2005
2006 sha1_len = g_checksum_type_get_length(G_CHECKSUM_SHA1);
2007 g_assert (sha1_len == 20);
2008 checksum = g_checksum_new(G_CHECKSUM_SHA1);
2009 g_checksum_update(checksum, block, BLOCK_SIZE);
2010 g_checksum_get_digest(checksum, sha1, &sha1_len);
2011 g_checksum_free(checksum);
2012
2013 return 0;
2014 }
2015
cbk_calc_sha1s(const char * filename,GArray * sha1s)2016 static gboolean cbk_calc_sha1s(const char *filename, GArray *sha1s)
2017 {
2018 FILE *f;
2019 int calc_ok;
2020
2021 f = fopen(filename, "rb");
2022 if (f == NULL) {
2023 return FALSE;
2024 }
2025
2026 do {
2027 unsigned char sha1[20];
2028 calc_ok = cbk_calc_sha1_one_block(f, sha1);
2029 if (calc_ok != 0) {
2030 break;
2031 }
2032 g_array_append_vals(sha1s, sha1, sizeof(sha1));
2033 } while (calc_ok == 0);
2034
2035 if (calc_ok < 0) {
2036 goto error;
2037 }
2038
2039 fclose(f);
2040 return TRUE;
2041
2042 error:
2043 fclose(f);
2044 return FALSE;
2045 }
2046
cbk_calc_sha1_of_sha1s(GArray * cbk,guint cbk_header_size)2047 static void cbk_calc_sha1_of_sha1s(GArray *cbk, guint cbk_header_size)
2048 {
2049 GChecksum *checksum;
2050 unsigned char* final_sha1;
2051 unsigned char* sha1s;
2052 gsize final_sha1_len;
2053
2054 g_assert (cbk->len > cbk_header_size + 20);
2055
2056 final_sha1 = &g_array_index(cbk, guchar, cbk_header_size);
2057 sha1s = &g_array_index(cbk, guchar, cbk_header_size + 20);
2058 final_sha1_len = g_checksum_type_get_length(G_CHECKSUM_SHA1);
2059 g_assert (final_sha1_len == 20);
2060
2061 checksum = g_checksum_new(G_CHECKSUM_SHA1);
2062 g_checksum_update(checksum, sha1s, cbk->len - (cbk_header_size + 20));
2063 g_checksum_get_digest(checksum, final_sha1, &final_sha1_len);
2064 g_checksum_free(checksum);
2065 }
2066
mk_Locations_cbk(Itdb_iTunesDB * itdb,const char * dirname)2067 static gboolean mk_Locations_cbk(Itdb_iTunesDB *itdb, const char *dirname)
2068 {
2069 char *locations_filename;
2070 char *cbk_filename;
2071 GArray *cbk;
2072 gboolean success;
2073 guchar *cbk_hash;
2074 guchar *final_sha1;
2075 guint cbk_header_size = 0;
2076 guint checksum_type;
2077
2078 checksum_type = itdb_device_get_checksum_type(itdb->device);
2079 switch (checksum_type) {
2080 case ITDB_CHECKSUM_HASHAB:
2081 cbk_header_size = 57;
2082 break;
2083 case ITDB_CHECKSUM_HASH58:
2084 /* the nano 5g advertises DBVersion 3 but expects an hash72 on
2085 * its cbk file.
2086 */
2087 case ITDB_CHECKSUM_HASH72:
2088 cbk_header_size = 46;
2089 break;
2090 default:
2091 break;
2092 }
2093 if (cbk_header_size == 0) {
2094 fprintf(stderr, "ERROR: Unsupported checksum type '%d' in cbk file generation!\n", checksum_type);
2095 return FALSE;
2096 }
2097
2098 cbk = g_array_sized_new(FALSE, TRUE, 1,
2099 cbk_header_size + 20);
2100 g_array_set_size(cbk, cbk_header_size + 20);
2101
2102 locations_filename = g_build_filename(dirname, "Locations.itdb", NULL);
2103 success = cbk_calc_sha1s(locations_filename, cbk);
2104 g_free(locations_filename);
2105 if (!success) {
2106 g_array_free(cbk, TRUE);
2107 return FALSE;
2108 }
2109 cbk_calc_sha1_of_sha1s(cbk, cbk_header_size);
2110 final_sha1 = &g_array_index(cbk, guchar, cbk_header_size);
2111 cbk_hash = &g_array_index(cbk, guchar, 0);
2112 switch (checksum_type) {
2113 case ITDB_CHECKSUM_HASHAB:
2114 success = itdb_hashAB_compute_hash_for_sha1 (itdb->device, final_sha1, cbk_hash, NULL);
2115 break;
2116 case ITDB_CHECKSUM_HASH58:
2117 /* the nano 5g advertises DBVersion 3 but expects an hash72 on
2118 * its cbk file.
2119 */
2120 case ITDB_CHECKSUM_HASH72:
2121 success = itdb_hash72_compute_hash_for_sha1 (itdb->device, final_sha1, cbk_hash, NULL);
2122 break;
2123 default:
2124 break;
2125 }
2126 if (!success) {
2127 g_array_free(cbk, TRUE);
2128 return FALSE;
2129 }
2130
2131 cbk_filename = g_build_filename(dirname, "Locations.itdb.cbk", NULL);
2132 success = g_file_set_contents(cbk_filename, cbk->data, cbk->len, NULL);
2133 g_free(cbk_filename);
2134 g_array_free(cbk, TRUE);
2135 return success;
2136 }
2137
build_itdb_files(Itdb_iTunesDB * itdb,GHashTable * album_ids,GHashTable * artist_ids,GHashTable * composer_ids,const char * outpath,const char * uuid,GError ** error)2138 static int build_itdb_files(Itdb_iTunesDB *itdb,
2139 GHashTable *album_ids, GHashTable *artist_ids,
2140 GHashTable *composer_ids,
2141 const char *outpath, const char *uuid,
2142 GError **error)
2143 {
2144 if (mk_Dynamic(itdb, outpath) != 0) {
2145 g_set_error (error, ITDB_ERROR, ITDB_ERROR_SQLITE,
2146 "an error occurred during Dynamic.itdb generation");
2147 return -1;
2148 }
2149 if (mk_Extras(itdb, outpath) != 0) {
2150 g_set_error (error, ITDB_ERROR, ITDB_ERROR_SQLITE,
2151 "an error occurred during Extras.itdb generation");
2152 return -1;
2153 }
2154 if (mk_Genius(itdb, outpath) != 0) {
2155 g_set_error (error, ITDB_ERROR, ITDB_ERROR_SQLITE,
2156 "an error occurred during Genius.itdb generation");
2157 return -1;
2158 }
2159 if (mk_Library(itdb, album_ids, artist_ids, composer_ids, outpath) != 0) {
2160 g_set_error (error, ITDB_ERROR, ITDB_ERROR_SQLITE,
2161 "an error occurred during Library.itdb generation");
2162 return -1;
2163 }
2164 if (mk_Locations(itdb, outpath, uuid) != 0) {
2165 g_set_error (error, ITDB_ERROR, ITDB_ERROR_SQLITE,
2166 "an error occurred during Locations.itdb generation");
2167 return -1;
2168 }
2169
2170 run_post_process_commands(itdb, outpath, uuid);
2171
2172 if (!mk_Locations_cbk(itdb, outpath)) {
2173 g_set_error (error, ITDB_ERROR, ITDB_ERROR_SQLITE,
2174 "an error occurred during Locations.itdb.cbk generation");
2175 return -1;
2176 }
2177
2178 return 0;
2179 }
2180
ensure_itlp_dir_exists(const char * itlpdir,GError ** error)2181 static int ensure_itlp_dir_exists(const char *itlpdir, GError **error)
2182 {
2183 /* check if directory exists */
2184 if (!g_file_test(itlpdir, G_FILE_TEST_EXISTS)) {
2185 if (g_mkdir(itlpdir, 0755) != 0) {
2186 g_set_error (error, G_FILE_ERROR,
2187 g_file_error_from_errno(errno),
2188 "Could not create directory '%s': %s",
2189 itlpdir, strerror(errno));
2190 return FALSE;
2191 }
2192 } else if (!g_file_test(itlpdir, G_FILE_TEST_IS_DIR)) {
2193 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOTDIR,
2194 "'%s' is not a directory as it should be",
2195 itlpdir);
2196 return FALSE;
2197 }
2198
2199 return TRUE;
2200 }
2201
copy_itdb_file(const gchar * from_dir,const gchar * to_dir,const gchar * fname,GError ** error)2202 static int copy_itdb_file(const gchar *from_dir, const gchar *to_dir,
2203 const gchar *fname, GError **error)
2204 {
2205 int res = 0;
2206
2207 gchar *srcname = g_build_filename(from_dir, fname, NULL);
2208 gchar *dstname = g_build_filename(to_dir, fname, NULL);
2209
2210 if (itdb_cp(srcname, dstname, error)) {
2211 fprintf(stderr, "itdbprep: copying '%s'\n", fname);
2212 res++;
2213 }
2214 if (error && *error) {
2215 fprintf(stderr, "Error copying '%s' to '%s': %s\n", srcname, dstname, (*error)->message);
2216 }
2217
2218 if (srcname) {
2219 g_free(srcname);
2220 }
2221
2222 if (dstname) {
2223 g_free(dstname);
2224 }
2225
2226 return res;
2227 }
2228
rmdir_recursive(gchar * path)2229 static void rmdir_recursive(gchar *path)
2230 {
2231 GDir *cur_dir;
2232 const gchar *dir_file;
2233
2234 cur_dir = g_dir_open(path, 0, NULL);
2235 if (cur_dir) while ((dir_file = g_dir_read_name(cur_dir)))
2236 {
2237 gchar *fpath = g_build_filename(path, dir_file, NULL);
2238 if (fpath) {
2239 if (g_file_test(fpath, G_FILE_TEST_IS_DIR)) {
2240 rmdir_recursive(fpath);
2241 } else {
2242 g_unlink(fpath);
2243 }
2244 g_free(fpath);
2245 }
2246 }
2247 if (cur_dir) {
2248 g_dir_close(cur_dir);
2249 }
2250 g_rmdir(path);
2251 }
2252
itdb_sqlite_generate_itdbs(FExport * fexp)2253 int itdb_sqlite_generate_itdbs(FExport *fexp)
2254 {
2255 int res = 0;
2256 gchar *itlpdir;
2257 gchar *dirname;
2258 gchar *tmpdir = NULL;
2259
2260 printf("libitdbprep: %s called with file %s and uuid %s\n", __func__,
2261 fexp->itdb->filename, itdb_device_get_uuid(fexp->itdb->device));
2262
2263 dirname = itdb_get_itunes_dir(itdb_get_mountpoint(fexp->itdb));
2264 itlpdir = g_build_filename(dirname, "iTunes Library.itlp", NULL);
2265 g_free(dirname);
2266
2267 printf("itlp directory='%s'\n", itlpdir);
2268
2269 if (!ensure_itlp_dir_exists(itlpdir, &fexp->error)) {
2270 res = -1;
2271 goto leave;
2272 }
2273
2274 printf("*.itdb files will be stored in '%s'\n", itlpdir);
2275
2276 g_assert(fexp->itdb != NULL);
2277 g_assert(fexp->itdb->playlists != NULL);
2278
2279 tzoffset = fexp->itdb->tzoffset;
2280
2281 tmpdir = g_build_path(g_get_tmp_dir(), tmpnam(NULL), NULL);
2282 if (g_mkdir(tmpdir, 0755) != 0) {
2283 g_set_error (&fexp->error, G_FILE_ERROR, g_file_error_from_errno(errno),
2284 "Could not create temporary directory '%s': %s",
2285 tmpdir, strerror(errno));
2286 res = -1;
2287 goto leave;
2288 }
2289
2290 /* generate itdb files in temporary directory */
2291 if (build_itdb_files(fexp->itdb, fexp->albums, fexp->artists, fexp->composers, tmpdir,
2292 itdb_device_get_uuid(fexp->itdb->device), &fexp->error) != 0) {
2293 g_prefix_error (&fexp->error, "Failed to generate sqlite database: ");
2294 res = -1;
2295 goto leave;
2296 } else {
2297 /* copy files */
2298 const char *itdb_files[] = { "Dynamic.itdb", "Extras.itdb",
2299 "Genius.itdb", "Library.itdb",
2300 "Locations.itdb", "Locations.itdb.cbk",
2301 NULL };
2302 const char **file;
2303 GError *error = NULL;
2304 g_assert (fexp->error == NULL);
2305 for (file = itdb_files; *file != NULL; file++) {
2306 copy_itdb_file(tmpdir, itlpdir, *file, &error);
2307 if (error) {
2308 res = -1;
2309 /* only the last error will be reported, but this way we
2310 * copy as many files as possible even when errors occur
2311 */
2312 g_clear_error (&fexp->error);
2313 g_propagate_error (&fexp->error, error);
2314 }
2315 }
2316 if (fexp->error) {
2317 goto leave;
2318 }
2319 }
2320
2321 res = 0;
2322 leave:
2323 if (itlpdir) {
2324 g_free(itlpdir);
2325 }
2326 if (tmpdir) {
2327 /* cleanup tmpdir, this will also delete tmpdir itself */
2328 rmdir_recursive(tmpdir);
2329 g_free(tmpdir);
2330 }
2331
2332 return res;
2333 }
2334