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