00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "xmms_configuration.h"
00018 #include "xmmspriv/xmms_medialib.h"
00019 #include "xmmspriv/xmms_xform.h"
00020 #include "xmmspriv/xmms_utils.h"
00021 #include "xmms/xmms_error.h"
00022 #include "xmms/xmms_config.h"
00023 #include "xmms/xmms_object.h"
00024 #include "xmms/xmms_ipc.h"
00025 #include "xmms/xmms_log.h"
00026
00027 #include <string.h>
00028 #include <stdlib.h>
00029
00030 #include <glib.h>
00031 #include <time.h>
00032
00033 #include <sqlite3.h>
00034
00035
00036
00037
00038
00039
00040
00041 static void xmms_medialib_client_entry_remove (xmms_medialib_t *medialib, gint32 entry, xmms_error_t *error);
00042 gchar *xmms_medialib_url_encode (const gchar *path);
00043 static gboolean xmms_medialib_check_id_in_session (xmms_medialib_entry_t entry, xmms_medialib_session_t *session);
00044
00045 static void xmms_medialib_client_add_entry (xmms_medialib_t *, const gchar *, xmms_error_t *);
00046 static void xmms_medialib_client_move_entry (xmms_medialib_t *, gint32 entry, const gchar *, xmms_error_t *);
00047 static void xmms_medialib_client_path_import (xmms_medialib_t *medialib, const gchar *path, xmms_error_t *error);
00048 static void xmms_medialib_client_rehash (xmms_medialib_t *medialib, gint32 id, xmms_error_t *error);
00049 static void xmms_medialib_client_property_set_str (xmms_medialib_t *medialib, gint32 entry, const gchar *source, const gchar *key, const gchar *value, xmms_error_t *error);
00050 static void xmms_medialib_client_property_set_str (xmms_medialib_t *medialib, gint32 entry, const gchar *source, const gchar *key, const gchar *value, xmms_error_t *error);
00051 static void xmms_medialib_client_property_set_int (xmms_medialib_t *medialib, gint32 entry, const gchar *source, const gchar *key, gint32 value, xmms_error_t *error);
00052 static void xmms_medialib_client_property_remove (xmms_medialib_t *medialib, gint32 entry, const gchar *source, const gchar *key, xmms_error_t *error);
00053 static GTree *xmms_medialib_client_info (xmms_medialib_t *medialib, gint32 id, xmms_error_t *err);
00054 static gint32 xmms_medialib_client_entry_get_id (xmms_medialib_t *medialib, const gchar *url, xmms_error_t *error);
00055
00056
00057 XMMS_CMD_DEFINE (info, xmms_medialib_client_info, xmms_medialib_t *, DICT, INT32, NONE);
00058 XMMS_CMD_DEFINE (mlib_add, xmms_medialib_client_add_entry, xmms_medialib_t *, NONE, STRING, NONE);
00059 XMMS_CMD_DEFINE (mlib_remove, xmms_medialib_client_entry_remove, xmms_medialib_t *, NONE, INT32, NONE);
00060 XMMS_CMD_DEFINE (mlib_move, xmms_medialib_client_move_entry, xmms_medialib_t *, NONE, INT32, STRING);
00061 XMMS_CMD_DEFINE (path_import, xmms_medialib_client_path_import, xmms_medialib_t *, NONE, STRING, NONE);
00062 XMMS_CMD_DEFINE (rehash, xmms_medialib_client_rehash, xmms_medialib_t *, NONE, INT32, NONE);
00063 XMMS_CMD_DEFINE (get_id, xmms_medialib_client_entry_get_id, xmms_medialib_t *, INT32, STRING, NONE);
00064
00065 XMMS_CMD_DEFINE4 (set_property_str, xmms_medialib_client_property_set_str, xmms_medialib_t *, NONE, INT32, STRING, STRING, STRING);
00066 XMMS_CMD_DEFINE4 (set_property_int, xmms_medialib_client_property_set_int, xmms_medialib_t *, NONE, INT32, STRING, STRING, INT32);
00067
00068 XMMS_CMD_DEFINE3 (remove_property, xmms_medialib_client_property_remove, xmms_medialib_t *, NONE, INT32, STRING, STRING);
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 struct xmms_medialib_St {
00085 xmms_object_t object;
00086
00087 xmms_playlist_t *playlist;
00088
00089 GMutex *source_lock;
00090 GHashTable *sources;
00091 };
00092
00093
00094
00095
00096 struct xmms_medialib_session_St {
00097 xmms_medialib_t *medialib;
00098
00099
00100 sqlite3 *sql;
00101
00102
00103 const gchar *file;
00104
00105 gint line;
00106
00107
00108 gboolean write;
00109
00110 gint next_id;
00111 };
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 static xmms_medialib_t *medialib;
00122
00123 static const char source_pref[] = "server:client/*:plugin/id3v2:plugin/*";
00124
00125
00126
00127
00128
00129
00130 static xmms_medialib_session_t *global_medialib_session;
00131
00132
00133 static GMutex *global_medialib_session_mutex;
00134
00135 static GMutex *xmms_medialib_debug_mutex;
00136 static GHashTable *xmms_medialib_debug_hash;
00137
00138 static void
00139 xmms_medialib_destroy (xmms_object_t *object)
00140 {
00141 xmms_medialib_t *mlib = (xmms_medialib_t *)object;
00142 if (global_medialib_session) {
00143 xmms_sqlite_close (global_medialib_session->sql);
00144 g_free (global_medialib_session);
00145 }
00146 g_mutex_free (mlib->source_lock);
00147 g_hash_table_destroy (mlib->sources);
00148 g_mutex_free (global_medialib_session_mutex);
00149 xmms_ipc_broadcast_unregister (XMMS_IPC_SIGNAL_MEDIALIB_ENTRY_UPDATE);
00150 xmms_ipc_object_unregister (XMMS_IPC_OBJECT_PLAYBACK);
00151 }
00152
00153 #define XMMS_MEDIALIB_SOURCE_SERVER "server"
00154 #define XMMS_MEDIALIB_SOURCE_SERVER_ID 1
00155
00156 static gint
00157 source_match_pattern (const gchar *source, const gchar *pattern,
00158 gint pattern_len)
00159 {
00160
00161
00162
00163 if (pattern_len > 0 && pattern[pattern_len - 1] == '*') {
00164
00165
00166
00167 if (pattern_len == 1) {
00168 return TRUE;
00169 }
00170
00171
00172
00173
00174 return !g_ascii_strncasecmp (source, pattern, pattern_len - 1);
00175 }
00176
00177
00178 return !g_ascii_strncasecmp (pattern, source, pattern_len);
00179 }
00180
00181 static int
00182 xmms_find_match_index (gint source, const gchar *pref, xmms_medialib_t *mlib)
00183 {
00184 gchar *source_name, *colon;
00185 gint i = 0;
00186
00187 g_mutex_lock (mlib->source_lock);
00188 source_name = g_hash_table_lookup (mlib->sources, GINT_TO_POINTER (source));
00189 g_mutex_unlock (mlib->source_lock);
00190
00191 do {
00192 gsize len;
00193
00194 colon = strchr (pref, ':');
00195
00196
00197 len = colon ? colon - pref : strlen (pref);
00198
00199
00200 if (source_match_pattern (source_name, pref, len)) {
00201 return i;
00202 }
00203
00204
00205 if (colon) {
00206 pref = colon + 1;
00207 }
00208 i++;
00209
00210
00211 } while (colon);
00212
00213 return i;
00214 }
00215
00216 static void
00217 xmms_sqlite_source_pref_binary (sqlite3_context *context, int args,
00218 sqlite3_value **val)
00219 {
00220 gint source;
00221 const gchar *pref;
00222 xmms_medialib_t *mlib;
00223
00224 mlib = sqlite3_user_data (context);
00225
00226 if (sqlite3_value_type (val[0]) != SQLITE_INTEGER) {
00227 sqlite3_result_error (context, "First argument to xmms_source_pref "
00228 "should be a integer", -1);
00229 return;
00230 }
00231 if (sqlite3_value_type (val[1]) != SQLITE3_TEXT) {
00232 sqlite3_result_error (context, "Second argument to xmms_source_pref "
00233 "should be a string", -1);
00234 return;
00235 }
00236
00237 source = sqlite3_value_int (val[0]);
00238 pref = (const gchar *) sqlite3_value_text (val[1]);
00239
00240 sqlite3_result_int (context, xmms_find_match_index (source, pref, mlib));
00241 }
00242
00243 static void
00244 xmms_sqlite_source_pref_unary (sqlite3_context *context, int args,
00245 sqlite3_value **val)
00246 {
00247 gint source;
00248 xmms_medialib_t *mlib;
00249
00250 mlib = sqlite3_user_data (context);
00251
00252 if (sqlite3_value_type (val[0]) != SQLITE_INTEGER) {
00253 sqlite3_result_error (context, "First argument to xmms_source_pref "
00254 "should be a integer", -1);
00255 return;
00256 }
00257
00258 source = sqlite3_value_int (val[0]);
00259
00260 sqlite3_result_int (context,
00261 xmms_find_match_index (source, source_pref, mlib));
00262 }
00263
00264 static int
00265 add_to_source (void *hash, int columns, char **vals, char **cols)
00266 {
00267 int source = strtol (vals[0], NULL, 10);
00268 g_hash_table_insert ((GHashTable*)hash, GINT_TO_POINTER (source), g_strdup (vals[1]));
00269 return 0;
00270 }
00271
00272 guint32
00273 xmms_medialib_source_to_id (xmms_medialib_session_t *session,
00274 const gchar *source)
00275 {
00276 gint32 ret = 0;
00277 g_return_val_if_fail (source, 0);
00278
00279 xmms_sqlite_query_int (session->sql, &ret,
00280 "SELECT id FROM Sources WHERE source=%Q",
00281 source);
00282 if (ret == 0) {
00283 xmms_sqlite_exec (session->sql,
00284 "INSERT INTO Sources (source) VALUES (%Q)", source);
00285 xmms_sqlite_query_int (session->sql, &ret,
00286 "SELECT id FROM Sources WHERE source=%Q",
00287 source);
00288 XMMS_DBG ("Added source %s with id %d", source, ret);
00289 g_mutex_lock (session->medialib->source_lock);
00290 g_hash_table_insert (session->medialib->sources, GUINT_TO_POINTER (ret), g_strdup (source));
00291 g_mutex_unlock (session->medialib->source_lock);
00292 }
00293
00294 return ret;
00295 }
00296
00297
00298 static xmms_medialib_session_t *
00299 xmms_medialib_session_new (const char *file, int line)
00300 {
00301 xmms_medialib_session_t *session;
00302
00303 session = g_new0 (xmms_medialib_session_t, 1);
00304 session->medialib = medialib;
00305 session->file = file;
00306 session->line = line;
00307 session->sql = xmms_sqlite_open ();
00308
00309 sqlite3_create_function (session->sql, "xmms_source_pref", 2, SQLITE_UTF8,
00310 session->medialib, xmms_sqlite_source_pref_binary, NULL, NULL);
00311 sqlite3_create_function (session->sql, "xmms_source_pref", 1, SQLITE_UTF8,
00312 session->medialib, xmms_sqlite_source_pref_unary, NULL, NULL);
00313
00314 return session;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 xmms_medialib_t *
00327 xmms_medialib_init (xmms_playlist_t *playlist)
00328 {
00329 gchar *path;
00330 xmms_medialib_session_t *session;
00331 gboolean create;
00332
00333 medialib = xmms_object_new (xmms_medialib_t, xmms_medialib_destroy);
00334 medialib->playlist = playlist;
00335
00336 xmms_ipc_object_register (XMMS_IPC_OBJECT_MEDIALIB, XMMS_OBJECT (medialib));
00337 xmms_ipc_broadcast_register (XMMS_OBJECT (medialib), XMMS_IPC_SIGNAL_MEDIALIB_ENTRY_ADDED);
00338 xmms_ipc_broadcast_register (XMMS_OBJECT (medialib), XMMS_IPC_SIGNAL_MEDIALIB_ENTRY_UPDATE);
00339
00340 xmms_object_cmd_add (XMMS_OBJECT (medialib),
00341 XMMS_IPC_CMD_INFO,
00342 XMMS_CMD_FUNC (info));
00343 xmms_object_cmd_add (XMMS_OBJECT (medialib),
00344 XMMS_IPC_CMD_MLIB_ADD_URL,
00345 XMMS_CMD_FUNC (mlib_add));
00346 xmms_object_cmd_add (XMMS_OBJECT (medialib),
00347 XMMS_IPC_CMD_REMOVE_ID,
00348 XMMS_CMD_FUNC (mlib_remove));
00349 xmms_object_cmd_add (XMMS_OBJECT (medialib),
00350 XMMS_IPC_CMD_PATH_IMPORT,
00351 XMMS_CMD_FUNC (path_import));
00352 xmms_object_cmd_add (XMMS_OBJECT (medialib),
00353 XMMS_IPC_CMD_REHASH,
00354 XMMS_CMD_FUNC (rehash));
00355 xmms_object_cmd_add (XMMS_OBJECT (medialib),
00356 XMMS_IPC_CMD_GET_ID,
00357 XMMS_CMD_FUNC (get_id));
00358 xmms_object_cmd_add (XMMS_OBJECT (medialib),
00359 XMMS_IPC_CMD_PROPERTY_SET_STR,
00360 XMMS_CMD_FUNC (set_property_str));
00361 xmms_object_cmd_add (XMMS_OBJECT (medialib),
00362 XMMS_IPC_CMD_PROPERTY_SET_INT,
00363 XMMS_CMD_FUNC (set_property_int));
00364 xmms_object_cmd_add (XMMS_OBJECT (medialib),
00365 XMMS_IPC_CMD_PROPERTY_REMOVE,
00366 XMMS_CMD_FUNC (remove_property));
00367 xmms_object_cmd_add (XMMS_OBJECT (medialib),
00368 XMMS_IPC_CMD_MOVE_URL,
00369 XMMS_CMD_FUNC (mlib_move));
00370
00371 path = XMMS_BUILD_PATH ("medialib.db");
00372
00373 xmms_config_property_register ("medialib.path", path, NULL, NULL);
00374 xmms_config_property_register ("medialib.analyze_on_startup", "0", NULL, NULL);
00375 xmms_config_property_register ("medialib.allow_remote_fs",
00376 "0", NULL, NULL);
00377
00378 g_free (path);
00379
00380
00381 xmms_medialib_debug_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
00382 xmms_medialib_debug_mutex = g_mutex_new ();
00383 global_medialib_session = NULL;
00384
00385
00386 xmms_sqlite_create (&create);
00387
00388 if (!sqlite3_threadsafe ()) {
00389 xmms_log_info ("********************************************************************");
00390 xmms_log_info ("* Using thread hack to compensate for sqlite without threadsafety! *");
00391 xmms_log_info ("* This can be a huge performance penalty - upgrade or recompile *");
00392 xmms_log_info ("********************************************************************");
00393
00394
00395 global_medialib_session = xmms_medialib_session_new ("global", 0);
00396 }
00397
00398 global_medialib_session_mutex = g_mutex_new ();
00399
00400
00401
00402
00403 medialib->source_lock = g_mutex_new ();
00404 medialib->sources = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
00405
00406 session = xmms_medialib_begin_write ();
00407 sqlite3_exec (session->sql, "SELECT id, source FROM Sources",
00408 add_to_source, medialib->sources, NULL);
00409
00410 if (create) {
00411 xmms_error_t error;
00412
00413 xmms_medialib_entry_new (session,
00414 "file://" SHAREDDIR
00415 "/mind.in.a.box-lament_snipplet.ogg",
00416 &error);
00417
00418
00419
00420 }
00421
00422 xmms_medialib_end (session);
00423
00424 return medialib;
00425 }
00426
00427
00428
00429 xmms_medialib_session_t *
00430 _xmms_medialib_begin (gboolean write, const char *file, int line)
00431 {
00432 xmms_medialib_session_t *session;
00433
00434 {
00435 gchar *r;
00436 void *me = g_thread_self ();
00437 g_mutex_lock (xmms_medialib_debug_mutex);
00438 r = g_hash_table_lookup (xmms_medialib_debug_hash, me);
00439 if (r) {
00440 xmms_log_fatal ("Medialib session begun recursivly at %s:%d, after %s", file, line, r);
00441 } else {
00442 g_hash_table_insert (xmms_medialib_debug_hash, me,
00443 g_strdup_printf ("%s:%d", file, line));
00444 }
00445 g_mutex_unlock (xmms_medialib_debug_mutex);
00446 }
00447 if (global_medialib_session) {
00448
00449 g_mutex_lock (global_medialib_session_mutex);
00450 return global_medialib_session;
00451 }
00452
00453 session = xmms_medialib_session_new (file, line);
00454 xmms_object_ref (XMMS_OBJECT (medialib));
00455 session->write = write;
00456
00457 if (write) {
00458
00459 if (!xmms_sqlite_exec (session->sql, "BEGIN EXCLUSIVE TRANSACTION")) {
00460 xmms_log_error ("transaction failed!");
00461 }
00462 }
00463
00464 session->next_id = -1;
00465
00466 return session;
00467 }
00468
00469 void
00470 xmms_medialib_end (xmms_medialib_session_t *session)
00471 {
00472 g_return_if_fail (session);
00473
00474 {
00475 void *me = g_thread_self ();
00476 g_mutex_lock (xmms_medialib_debug_mutex);
00477 g_hash_table_remove (xmms_medialib_debug_hash, me);
00478 g_mutex_unlock (xmms_medialib_debug_mutex);
00479 }
00480
00481 if (session->write) {
00482 xmms_sqlite_exec (session->sql, "COMMIT");
00483 }
00484
00485 if (session == global_medialib_session) {
00486 g_mutex_unlock (global_medialib_session_mutex);
00487 return;
00488 }
00489
00490 xmms_sqlite_close (session->sql);
00491 xmms_object_unref (XMMS_OBJECT (session->medialib));
00492 g_free (session);
00493 }
00494
00495 static int
00496 xmms_medialib_string_cb (xmmsv_t **row, gpointer udata)
00497 {
00498 gchar **str = udata;
00499 const gchar *buf;
00500
00501 if (row && row[0] && xmmsv_get_type (row[0]) == XMMSV_TYPE_STRING) {
00502 xmmsv_get_string (row[0], &buf);
00503 *str = g_strdup (buf);
00504 } else
00505 XMMS_DBG ("Expected string but got something else!");
00506
00507 return 0;
00508 }
00509
00510 static int
00511 xmms_medialib_value_cb (xmmsv_t **row, gpointer udata)
00512 {
00513 xmmsv_t **ret = udata;
00514
00515 *ret = xmmsv_ref (row[0]);
00516
00517 return 0;
00518 }
00519
00520
00521
00522
00523
00524
00525
00526 #define XMMS_MEDIALIB_RETRV_PROPERTY_SQL "SELECT IFNULL (intval, value) FROM Media WHERE key=%Q AND id=%d ORDER BY xmms_source_pref(source, %Q) LIMIT 1"
00527
00528 xmmsv_t *
00529 xmms_medialib_entry_property_get_value (xmms_medialib_session_t *session,
00530 xmms_medialib_entry_t entry,
00531 const gchar *property)
00532 {
00533 xmmsv_t *ret = NULL;
00534
00535 g_return_val_if_fail (property, NULL);
00536 g_return_val_if_fail (session, NULL);
00537
00538 if (!strcmp (property, XMMS_MEDIALIB_ENTRY_PROPERTY_ID)) {
00539 ret = xmmsv_new_int (entry);
00540 } else {
00541 xmms_sqlite_query_array (session->sql, xmms_medialib_value_cb,
00542 &ret, XMMS_MEDIALIB_RETRV_PROPERTY_SQL,
00543 property, entry, source_pref);
00544 }
00545
00546 return ret;
00547 }
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560 gchar *
00561 xmms_medialib_entry_property_get_str (xmms_medialib_session_t *session,
00562 xmms_medialib_entry_t entry,
00563 const gchar *property)
00564 {
00565 gchar *ret = NULL;
00566
00567 g_return_val_if_fail (property, NULL);
00568 g_return_val_if_fail (session, NULL);
00569
00570 xmms_sqlite_query_array (session->sql, xmms_medialib_string_cb, &ret,
00571 XMMS_MEDIALIB_RETRV_PROPERTY_SQL,
00572 property, entry, source_pref);
00573
00574 return ret;
00575 }
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587 gint
00588 xmms_medialib_entry_property_get_int (xmms_medialib_session_t *session,
00589 xmms_medialib_entry_t entry,
00590 const gchar *property)
00591 {
00592 gint32 ret = -1;
00593
00594 g_return_val_if_fail (property, -1);
00595 g_return_val_if_fail (session, -1);
00596
00597 xmms_sqlite_query_int (session->sql, &ret,
00598 XMMS_MEDIALIB_RETRV_PROPERTY_SQL,
00599 property, entry, source_pref);
00600
00601 return ret;
00602 }
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615 gboolean
00616 xmms_medialib_entry_property_set_int (xmms_medialib_session_t *session,
00617 xmms_medialib_entry_t entry,
00618 const gchar *property, gint value)
00619 {
00620 return xmms_medialib_entry_property_set_int_source (session, entry,
00621 property, value,
00622 XMMS_MEDIALIB_SOURCE_SERVER_ID);
00623 }
00624
00625
00626 gboolean
00627 xmms_medialib_entry_property_set_int_source (xmms_medialib_session_t *session,
00628 xmms_medialib_entry_t entry,
00629 const gchar *property, gint value,
00630 guint32 source)
00631 {
00632 gboolean ret;
00633
00634 g_return_val_if_fail (property, FALSE);
00635 g_return_val_if_fail (session, FALSE);
00636
00637 if (!xmms_medialib_check_id_in_session (entry, session)) {
00638 XMMS_DBG ("Trying to add property to id %d "
00639 "that is not yet in the medialib. Denied.", entry);
00640
00641 return FALSE;
00642 }
00643
00644 ret = xmms_sqlite_exec (session->sql,
00645 "INSERT OR REPLACE INTO Media "
00646 "(id, value, intval, key, source) VALUES "
00647 "(%d, '%d', %d, %Q, %d)",
00648 entry, value, value, property, source);
00649
00650 return ret;
00651
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 gboolean
00666 xmms_medialib_entry_property_set_str (xmms_medialib_session_t *session,
00667 xmms_medialib_entry_t entry,
00668 const gchar *property, const gchar *value)
00669 {
00670 return xmms_medialib_entry_property_set_str_source (session, entry,
00671 property, value,
00672 XMMS_MEDIALIB_SOURCE_SERVER_ID);
00673 }
00674
00675
00676 gboolean
00677 xmms_medialib_entry_property_set_str_source (xmms_medialib_session_t *session,
00678 xmms_medialib_entry_t entry,
00679 const gchar *property, const gchar *value,
00680 guint32 source)
00681 {
00682 gboolean ret;
00683
00684 g_return_val_if_fail (property, FALSE);
00685 g_return_val_if_fail (session, FALSE);
00686
00687 if (value && !g_utf8_validate (value, -1, NULL)) {
00688 XMMS_DBG ("OOOOOPS! Trying to set property %s to a NON UTF-8 string (%s) I will deny that!", property, value);
00689 return FALSE;
00690 }
00691
00692 if (!xmms_medialib_check_id_in_session (entry, session)) {
00693 XMMS_DBG ("Trying to add property to id %d "
00694 "that is not yet in the medialib. Denied.", entry);
00695
00696 return FALSE;
00697 }
00698
00699 ret = xmms_sqlite_exec (session->sql,
00700 "INSERT OR REPLACE INTO Media "
00701 "(id, value, intval, key, source) VALUES "
00702 "(%d, %Q, NULL, %Q, %d)",
00703 entry, value, property, source);
00704
00705 return ret;
00706
00707 }
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 void
00719 xmms_medialib_entry_send_update (xmms_medialib_entry_t entry)
00720 {
00721 xmms_object_emit_f (XMMS_OBJECT (medialib),
00722 XMMS_IPC_SIGNAL_MEDIALIB_ENTRY_UPDATE,
00723 XMMSV_TYPE_INT32, entry);
00724 }
00725
00726
00727
00728
00729
00730
00731
00732 void
00733 xmms_medialib_entry_send_added (xmms_medialib_entry_t entry)
00734 {
00735 xmms_object_emit_f (XMMS_OBJECT (medialib),
00736 XMMS_IPC_SIGNAL_MEDIALIB_ENTRY_ADDED,
00737 XMMSV_TYPE_INT32, entry);
00738 }
00739
00740 static void
00741 xmms_medialib_client_entry_remove (xmms_medialib_t *medialib, gint32 entry, xmms_error_t *error)
00742 {
00743 xmms_medialib_entry_remove (entry);
00744 }
00745
00746
00747
00748
00749
00750
00751
00752
00753 void
00754 xmms_medialib_entry_remove (xmms_medialib_entry_t entry)
00755 {
00756 xmms_medialib_session_t *session;
00757
00758 session = xmms_medialib_begin_write ();
00759 xmms_sqlite_exec (session->sql, "DELETE FROM Media WHERE id=%d", entry);
00760 xmms_medialib_end (session);
00761
00762
00763 xmms_playlist_remove_by_entry (medialib->playlist, entry);
00764 }
00765
00766 static xmms_medialib_entry_t xmms_medialib_entry_new_insert (xmms_medialib_session_t *session, guint32 id, const char *url, xmms_error_t *error);
00767
00768 static void
00769 process_file (xmms_medialib_session_t *session,
00770 const gchar *playlist,
00771 gint32 pos,
00772 const gchar *path,
00773 xmms_error_t *error)
00774 {
00775 xmms_medialib_entry_t entry;
00776
00777 entry = xmms_medialib_entry_new_encoded (session, path, error);
00778
00779 if (entry && playlist != NULL) {
00780 if (pos >= 0) {
00781 xmms_playlist_insert_entry (session->medialib->playlist,
00782 playlist, pos, entry, error);
00783 } else {
00784 xmms_playlist_add_entry (session->medialib->playlist,
00785 playlist, entry, error);
00786 }
00787 }
00788 }
00789
00790 static gint
00791 cmp_val (gconstpointer a, gconstpointer b)
00792 {
00793 xmmsv_t *v1, *v2;
00794 const gchar *s1, *s2;
00795 v1 = (xmmsv_t *) a;
00796 v2 = (xmmsv_t *) b;
00797 if (xmmsv_get_type (v1) != XMMSV_TYPE_DICT)
00798 return 0;
00799 if (xmmsv_get_type (v2) != XMMSV_TYPE_DICT)
00800 return 0;
00801
00802 xmmsv_dict_entry_get_string (v1, "path", &s1);
00803 xmmsv_dict_entry_get_string (v2, "path", &s2);
00804
00805 return strcmp (s1, s2);
00806 }
00807
00808
00809
00810 static gboolean
00811 process_dir (const gchar *directory,
00812 GList **ret,
00813 xmms_error_t *error)
00814 {
00815 GList *list;
00816
00817 list = xmms_xform_browse (directory, error);
00818 if (!list) {
00819 return FALSE;
00820 }
00821
00822 list = g_list_sort (list, cmp_val);
00823
00824 while (list) {
00825 xmmsv_t *val = list->data;
00826 const gchar *str;
00827 gint isdir;
00828
00829 xmmsv_dict_entry_get_string (val, "path", &str);
00830 xmmsv_dict_entry_get_int (val, "isdir", &isdir);
00831
00832 if (isdir == 1) {
00833 process_dir (str, ret, error);
00834 } else {
00835 *ret = g_list_prepend (*ret, g_strdup (str));
00836 }
00837
00838 xmmsv_unref (val);
00839 list = g_list_delete_link (list, list);
00840 }
00841
00842 return TRUE;
00843 }
00844
00845 void
00846 xmms_medialib_entry_cleanup (xmms_medialib_session_t *session,
00847 xmms_medialib_entry_t entry)
00848 {
00849 xmms_sqlite_exec (session->sql,
00850 "DELETE FROM Media WHERE id=%d AND source=%d "
00851 "AND key NOT IN (%Q, %Q, %Q, %Q, %Q)",
00852 entry,
00853 XMMS_MEDIALIB_SOURCE_SERVER_ID,
00854 XMMS_MEDIALIB_ENTRY_PROPERTY_URL,
00855 XMMS_MEDIALIB_ENTRY_PROPERTY_ADDED,
00856 XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS,
00857 XMMS_MEDIALIB_ENTRY_PROPERTY_LMOD,
00858 XMMS_MEDIALIB_ENTRY_PROPERTY_LASTSTARTED);
00859
00860 xmms_sqlite_exec (session->sql,
00861 "DELETE FROM Media WHERE id=%d AND source IN "
00862 "(SELECT id FROM Sources WHERE source LIKE 'plugin/%%' "
00863 "AND source != 'plugin/playlist')",
00864 entry);
00865
00866 }
00867
00868 static void
00869 xmms_medialib_client_rehash (xmms_medialib_t *medialib, gint32 id, xmms_error_t *error)
00870 {
00871 xmms_mediainfo_reader_t *mr;
00872 xmms_medialib_session_t *session;
00873
00874 session = xmms_medialib_begin_write ();
00875
00876 if (id) {
00877 xmms_sqlite_exec (session->sql,
00878 "UPDATE Media SET value = '%d', intval = %d "
00879 "WHERE key='%s' AND id=%d",
00880 XMMS_MEDIALIB_ENTRY_STATUS_REHASH,
00881 XMMS_MEDIALIB_ENTRY_STATUS_REHASH,
00882 XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS, id);
00883 } else {
00884 xmms_sqlite_exec (session->sql,
00885 "UPDATE Media SET value = '%d', intval = %d "
00886 "WHERE key='%s'",
00887 XMMS_MEDIALIB_ENTRY_STATUS_REHASH,
00888 XMMS_MEDIALIB_ENTRY_STATUS_REHASH,
00889 XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS);
00890 }
00891
00892 xmms_medialib_end (session);
00893
00894 mr = xmms_playlist_mediainfo_reader_get (medialib->playlist);
00895 xmms_mediainfo_reader_wakeup (mr);
00896
00897 }
00898
00899
00900
00901
00902
00903 void
00904 xmms_medialib_add_recursive (xmms_medialib_t *medialib, const gchar *playlist,
00905 const gchar *path, xmms_error_t *error)
00906 {
00907
00908 xmms_medialib_insert_recursive (medialib, playlist, -1, path, error);
00909 }
00910
00911
00912
00913
00914
00915
00916 void
00917 xmms_medialib_insert_recursive (xmms_medialib_t *medialib, const gchar *playlist,
00918 gint32 pos, const gchar *path,
00919 xmms_error_t *error)
00920 {
00921 xmms_medialib_session_t *session;
00922 GList *first, *list = NULL, *n;
00923
00924 g_return_if_fail (medialib);
00925 g_return_if_fail (path);
00926
00927
00928
00929
00930
00931 first = list = g_list_alloc ();
00932
00933 process_dir (path, &list, error);
00934
00935 XMMS_DBG ("taking the transaction!");
00936 session = xmms_medialib_begin_write ();
00937
00938
00939
00940
00941
00942
00943 for (n = first->prev; n; n = g_list_previous (n)) {
00944 process_file (session, playlist, pos, n->data, error);
00945 if (pos >= 0)
00946 pos++;
00947 g_free (n->data);
00948 }
00949
00950 g_list_free (list);
00951
00952 XMMS_DBG ("and we are done!");
00953 xmms_medialib_end (session);
00954 }
00955
00956 static void
00957 xmms_medialib_client_path_import (xmms_medialib_t *medialib, const gchar *path,
00958 xmms_error_t *error)
00959 {
00960 xmms_medialib_add_recursive (medialib, NULL, path, error);
00961 }
00962
00963 static xmms_medialib_entry_t
00964 xmms_medialib_entry_new_insert (xmms_medialib_session_t *session,
00965 guint32 id,
00966 const char *url,
00967 xmms_error_t *error)
00968 {
00969 xmms_mediainfo_reader_t *mr;
00970 guint source;
00971
00972 source = XMMS_MEDIALIB_SOURCE_SERVER_ID;
00973
00974 if (!xmms_sqlite_exec (session->sql,
00975 "INSERT INTO Media (id, key, value, source) VALUES "
00976 "(%d, '%s', %Q, %d)",
00977 id, XMMS_MEDIALIB_ENTRY_PROPERTY_URL, url,
00978 source)) {
00979 xmms_error_set (error, XMMS_ERROR_GENERIC,
00980 "Sql error/corruption inserting url");
00981 return 0;
00982 }
00983
00984 xmms_medialib_entry_status_set (session, id, XMMS_MEDIALIB_ENTRY_STATUS_NEW);
00985 mr = xmms_playlist_mediainfo_reader_get (medialib->playlist);
00986 xmms_mediainfo_reader_wakeup (mr);
00987
00988 return 1;
00989
00990 }
00991
00992
00993
00994
00995 xmms_medialib_entry_t
00996 xmms_medialib_entry_new_encoded (xmms_medialib_session_t *session,
00997 const char *url, xmms_error_t *error)
00998 {
00999 gint id = 0;
01000 guint ret = 0;
01001 guint source;
01002
01003 g_return_val_if_fail (url, 0);
01004 g_return_val_if_fail (session, 0);
01005 g_return_val_if_fail (session->write, 0);
01006
01007 source = XMMS_MEDIALIB_SOURCE_SERVER_ID;
01008
01009 xmms_sqlite_query_int (session->sql, &id,
01010 "SELECT id AS value FROM Media "
01011 "WHERE key='%s' AND value=%Q AND source=%d",
01012 XMMS_MEDIALIB_ENTRY_PROPERTY_URL, url,
01013 source);
01014
01015 if (id) {
01016 ret = id;
01017 } else {
01018 if (session->next_id <= 0 &&
01019 !xmms_sqlite_query_int (session->sql, &session->next_id,
01020 "SELECT IFNULL(MAX (id),0)+1 FROM Media")) {
01021 xmms_error_set (error, XMMS_ERROR_GENERIC,
01022 "SQL error/corruption selecting max(id)");
01023 return 0;
01024 }
01025
01026 ret = session->next_id++;
01027
01028 if (!xmms_medialib_entry_new_insert (session, ret, url, error))
01029 return 0;
01030 }
01031
01032 xmms_medialib_entry_send_added (ret);
01033 return ret;
01034
01035 }
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051 xmms_medialib_entry_t
01052 xmms_medialib_entry_new (xmms_medialib_session_t *session, const char *url, xmms_error_t *error)
01053 {
01054 gchar *enc_url;
01055 xmms_medialib_entry_t res;
01056
01057 enc_url = xmms_medialib_url_encode (url);
01058 if (!enc_url)
01059 return 0;
01060
01061 res = xmms_medialib_entry_new_encoded (session, enc_url, error);
01062
01063 g_free (enc_url);
01064
01065 return res;
01066 }
01067
01068 gint32
01069 xmms_medialib_client_entry_get_id (xmms_medialib_t *medialib, const gchar *url,
01070 xmms_error_t *error)
01071 {
01072 gint32 id = 0;
01073 xmms_medialib_session_t *session = xmms_medialib_begin ();
01074
01075 xmms_sqlite_query_int (session->sql, &id,
01076 "SELECT id AS value FROM Media WHERE key='%s' AND value=%Q AND source=%d",
01077 XMMS_MEDIALIB_ENTRY_PROPERTY_URL, url,
01078 XMMS_MEDIALIB_SOURCE_SERVER_ID);
01079 xmms_medialib_end (session);
01080
01081 return id;
01082 }
01083
01084 static void
01085 xmms_medialib_tree_add_tuple (GTree *tree, const char *key,
01086 const char *source, xmmsv_t *value)
01087 {
01088 xmmsv_t *keytreeval;
01089
01090
01091 keytreeval = (xmmsv_t *) g_tree_lookup (tree, key);
01092 if (!keytreeval) {
01093 keytreeval = xmmsv_new_dict ();
01094 g_tree_insert (tree, g_strdup (key), keytreeval);
01095 }
01096
01097
01098 xmmsv_dict_set (keytreeval, source, value);
01099 }
01100
01101 static gboolean
01102 xmms_medialib_list_cb (xmmsv_t **row, gpointer udata)
01103 {
01104 GList **list = (GList**)udata;
01105
01106
01107 *list = g_list_prepend (*list, xmmsv_ref (row[0]));
01108
01109
01110 *list = g_list_prepend (*list, xmmsv_ref (row[1]));
01111
01112
01113 *list = g_list_prepend (*list, xmmsv_ref (row[2]));
01114
01115 return TRUE;
01116 }
01117
01118 static gboolean
01119 xmms_medialib_tree_cb (xmmsv_t **row, gpointer udata)
01120 {
01121 const char *key, *source;
01122 xmmsv_t *value;
01123 GTree **tree = (GTree**)udata;
01124
01125 xmmsv_get_string (row[0], &source);
01126 xmmsv_get_string (row[1], &key);
01127 value = row[2];
01128
01129 xmms_medialib_tree_add_tuple (*tree, key, source, value);
01130
01131 return TRUE;
01132 }
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145 static GList *
01146 xmms_medialib_entry_to_list (xmms_medialib_session_t *session, xmms_medialib_entry_t entry)
01147 {
01148 GList *ret = NULL;
01149 gboolean s;
01150
01151 g_return_val_if_fail (session, NULL);
01152 g_return_val_if_fail (entry, NULL);
01153
01154 s = xmms_sqlite_query_array (session->sql, xmms_medialib_list_cb, &ret,
01155 "SELECT s.source, m.key, "
01156 "IFNULL (m.intval, m.value) "
01157 "FROM Media m LEFT JOIN "
01158 "Sources s ON m.source = s.id "
01159 "WHERE m.id=%d",
01160 entry);
01161 if (!s || !ret) {
01162 return NULL;
01163 }
01164
01165
01166 ret = g_list_prepend (ret, xmmsv_new_string ("server"));
01167
01168
01169 ret = g_list_prepend (ret, xmmsv_new_string ("id"));
01170
01171
01172 ret = g_list_prepend (ret, xmmsv_new_int (entry));
01173
01174 return g_list_reverse (ret);
01175 }
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188 static GTree *
01189 xmms_medialib_entry_to_tree (xmms_medialib_session_t *session, xmms_medialib_entry_t entry)
01190 {
01191 GTree *ret;
01192 xmmsv_t *v_entry;
01193 gboolean s;
01194
01195 g_return_val_if_fail (session, NULL);
01196 g_return_val_if_fail (entry, NULL);
01197
01198 if (!xmms_medialib_check_id_in_session (entry, session)) {
01199 return NULL;
01200 }
01201
01202 ret = g_tree_new_full ((GCompareDataFunc) strcmp, NULL, g_free,
01203 (GDestroyNotify) xmmsv_unref);
01204
01205 s = xmms_sqlite_query_array (session->sql, xmms_medialib_tree_cb,
01206 &ret,
01207 "SELECT s.source, m.key, "
01208 "IFNULL (m.intval, m.value) "
01209 "FROM Media m LEFT JOIN "
01210 "Sources s ON m.source = s.id "
01211 "WHERE m.id=%d",
01212 entry);
01213 if (!s || !ret) {
01214 return NULL;
01215 }
01216
01217 v_entry = xmmsv_new_int (entry);
01218 xmms_medialib_tree_add_tuple (ret, "id", "server", v_entry);
01219 xmmsv_unref (v_entry);
01220
01221 return ret;
01222 }
01223
01224
01225 GList *
01226 xmms_medialib_info_list (xmms_medialib_t *medialib, guint32 id, xmms_error_t *err)
01227 {
01228 xmms_medialib_session_t *session;
01229 GList *ret = NULL;
01230
01231 if (!id) {
01232 xmms_error_set (err, XMMS_ERROR_NOENT, "No such entry, 0");
01233 } else {
01234 session = xmms_medialib_begin ();
01235 ret = xmms_medialib_entry_to_list (session, id);
01236 xmms_medialib_end (session);
01237
01238 if (!ret) {
01239 xmms_error_set (err, XMMS_ERROR_NOENT,
01240 "Could not retrieve info for that entry!");
01241 }
01242 }
01243
01244 return ret;
01245 }
01246
01247 static GTree *
01248 xmms_medialib_client_info (xmms_medialib_t *medialib, gint32 id, xmms_error_t *err)
01249 {
01250 xmms_medialib_session_t *session;
01251 GTree *ret = NULL;
01252
01253 if (!id) {
01254 xmms_error_set (err, XMMS_ERROR_NOENT, "No such entry, 0");
01255 } else {
01256 session = xmms_medialib_begin ();
01257 ret = xmms_medialib_entry_to_tree (session, id);
01258 xmms_medialib_end (session);
01259
01260 if (!ret) {
01261 xmms_error_set (err, XMMS_ERROR_NOENT,
01262 "Could not retrieve info for that entry!");
01263 }
01264 }
01265
01266 return ret;
01267 }
01268
01269 static gboolean
01270 select_callback (xmmsv_t *row, gpointer udata)
01271 {
01272 GList **l = (GList **) udata;
01273 *l = g_list_prepend (*l, row);
01274 return TRUE;
01275 }
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286 static void
01287 xmms_medialib_client_add_entry (xmms_medialib_t *medialib, const gchar *url,
01288 xmms_error_t *error)
01289 {
01290 xmms_medialib_entry_t entry;
01291 xmms_medialib_session_t *session;
01292
01293 g_return_if_fail (medialib);
01294 g_return_if_fail (url);
01295
01296 session = xmms_medialib_begin_write ();
01297
01298 entry = xmms_medialib_entry_new_encoded (session, url, error);
01299
01300 xmms_medialib_end (session);
01301 }
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311 static void
01312 xmms_medialib_client_move_entry (xmms_medialib_t *medialib, gint32 entry,
01313 const gchar *url, xmms_error_t *error)
01314 {
01315 const gchar *key = XMMS_MEDIALIB_ENTRY_PROPERTY_URL;
01316 guint32 sourceid = XMMS_MEDIALIB_SOURCE_SERVER_ID;
01317 gchar *enc_url;
01318
01319 xmms_medialib_session_t *session;
01320
01321 enc_url = xmms_medialib_url_encode (url);
01322
01323 session = xmms_medialib_begin_write ();
01324 xmms_medialib_entry_property_set_str_source (session, entry, key, enc_url,
01325 sourceid);
01326 xmms_medialib_end (session);
01327
01328 g_free (enc_url);
01329
01330 xmms_medialib_entry_send_update (entry);
01331 }
01332
01333 static void
01334 xmms_medialib_client_property_set_str (xmms_medialib_t *medialib, gint32 entry,
01335 const gchar *source, const gchar *key,
01336 const gchar *value, xmms_error_t *error)
01337 {
01338 guint32 sourceid;
01339 xmms_medialib_session_t *session;
01340
01341 if (g_ascii_strcasecmp (source, "server") == 0) {
01342 xmms_error_set (error, XMMS_ERROR_GENERIC,
01343 "Can't write to source server!");
01344 return;
01345 }
01346
01347 session = xmms_medialib_begin_write ();
01348 sourceid = xmms_medialib_source_to_id (session, source);
01349
01350 xmms_medialib_entry_property_set_str_source (session, entry, key, value,
01351 sourceid);
01352 xmms_medialib_end (session);
01353
01354 xmms_medialib_entry_send_update (entry);
01355 }
01356
01357 static void
01358 xmms_medialib_client_property_set_int (xmms_medialib_t *medialib, gint32 entry,
01359 const gchar *source, const gchar *key,
01360 gint32 value, xmms_error_t *error)
01361 {
01362 guint32 sourceid;
01363 xmms_medialib_session_t *session;
01364
01365 if (g_ascii_strcasecmp (source, "server") == 0) {
01366 xmms_error_set (error, XMMS_ERROR_GENERIC,
01367 "Can't write to source server!");
01368 return;
01369 }
01370
01371 session = xmms_medialib_begin_write ();
01372 sourceid = xmms_medialib_source_to_id (session, source);
01373 xmms_medialib_entry_property_set_int_source (session, entry, key, value,
01374 sourceid);
01375 xmms_medialib_end (session);
01376
01377 xmms_medialib_entry_send_update (entry);
01378 }
01379
01380 static void
01381 xmms_medialib_property_remove (xmms_medialib_t *medialib, gint32 entry,
01382 const gchar *source, const gchar *key,
01383 xmms_error_t *error)
01384 {
01385 guint32 sourceid;
01386
01387 xmms_medialib_session_t *session = xmms_medialib_begin_write ();
01388 sourceid = xmms_medialib_source_to_id (session, source);
01389 xmms_sqlite_exec (session->sql,
01390 "DELETE FROM Media WHERE source=%d AND key='%s' AND "
01391 "id=%d",
01392 sourceid, key, entry);
01393 xmms_medialib_end (session);
01394
01395 xmms_medialib_entry_send_update (entry);
01396 }
01397
01398 static void
01399 xmms_medialib_client_property_remove (xmms_medialib_t *medialib, gint32 entry,
01400 const gchar *source, const gchar *key,
01401 xmms_error_t *error)
01402 {
01403 if (g_ascii_strcasecmp (source, "server") == 0) {
01404 xmms_error_set (error, XMMS_ERROR_GENERIC,
01405 "Can't remove properties set by the server!");
01406 return;
01407 }
01408
01409 return xmms_medialib_property_remove (medialib, entry, source, key, error);
01410 }
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421 GList *
01422 xmms_medialib_select (xmms_medialib_session_t *session,
01423 const gchar *query, xmms_error_t *error)
01424 {
01425 GList *res = NULL;
01426 gint ret;
01427
01428 g_return_val_if_fail (query, 0);
01429 g_return_val_if_fail (session, 0);
01430
01431 ret = xmms_sqlite_query_table (session->sql, select_callback,
01432 (void *)&res, error, "%s", query);
01433
01434 return ret ? g_list_reverse (res) : NULL;
01435 }
01436
01437
01438
01439
01440
01441
01442
01443 gboolean
01444 xmms_medialib_check_id (xmms_medialib_entry_t entry)
01445 {
01446 xmms_medialib_session_t *session;
01447 gboolean ret;
01448
01449 session = xmms_medialib_begin ();
01450 ret = xmms_medialib_check_id_in_session (entry, session);
01451 xmms_medialib_end (session);
01452
01453 return ret;
01454 }
01455
01456
01457
01458
01459
01460 static gboolean
01461 xmms_medialib_check_id_in_session (xmms_medialib_entry_t entry,
01462 xmms_medialib_session_t *session)
01463 {
01464 gint c = 0;
01465
01466 if (!xmms_sqlite_query_int (session->sql, &c,
01467 "SELECT COUNT(id) FROM Media WHERE id=%d",
01468 entry)) {
01469 return FALSE;
01470 }
01471
01472 return c > 0;
01473 }
01474
01475
01476
01477
01478
01479
01480
01481 xmms_medialib_entry_t
01482 xmms_medialib_entry_not_resolved_get (xmms_medialib_session_t *session)
01483 {
01484 gint32 ret = 0;
01485
01486 g_return_val_if_fail (session, 0);
01487
01488 xmms_sqlite_query_int (session->sql, &ret,
01489 "SELECT id FROM Media WHERE key='%s' "
01490 "AND source=%d AND intval IN (%d, %d) LIMIT 1",
01491 XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS,
01492 XMMS_MEDIALIB_SOURCE_SERVER_ID,
01493 XMMS_MEDIALIB_ENTRY_STATUS_NEW,
01494 XMMS_MEDIALIB_ENTRY_STATUS_REHASH);
01495
01496 return ret;
01497 }
01498
01499 guint
01500 xmms_medialib_num_not_resolved (xmms_medialib_session_t *session)
01501 {
01502 gint ret;
01503 g_return_val_if_fail (session, 0);
01504
01505 xmms_sqlite_query_int (session->sql, &ret,
01506 "SELECT COUNT(id) AS value FROM Media WHERE "
01507 "key='%s' AND intval IN (%d, %d) AND source=%d",
01508 XMMS_MEDIALIB_ENTRY_PROPERTY_STATUS,
01509 XMMS_MEDIALIB_ENTRY_STATUS_NEW,
01510 XMMS_MEDIALIB_ENTRY_STATUS_REHASH,
01511 XMMS_MEDIALIB_SOURCE_SERVER_ID);
01512
01513 return ret;
01514 }
01515
01516 gboolean
01517 xmms_medialib_decode_url (char *url)
01518 {
01519 int i = 0, j = 0;
01520
01521 g_return_val_if_fail (url, TRUE);
01522
01523 while (url[i]) {
01524 unsigned char chr = url[i++];
01525
01526 if (chr == '+') {
01527 url[j++] = ' ';
01528 } else if (chr == '%') {
01529 char ts[3];
01530 char *t;
01531
01532 ts[0] = url[i++];
01533 if (!ts[0])
01534 return FALSE;
01535 ts[1] = url[i++];
01536 if (!ts[1])
01537 return FALSE;
01538 ts[2] = '\0';
01539
01540 url[j++] = strtoul (ts, &t, 16);
01541 if (t != &ts[2])
01542 return FALSE;
01543 } else {
01544 url[j++] = chr;
01545 }
01546 }
01547
01548 url[j] = '\0';
01549
01550 return TRUE;
01551 }
01552
01553
01554 #define GOODCHAR(a) ((((a) >= 'a') && ((a) <= 'z')) || \
01555 (((a) >= 'A') && ((a) <= 'Z')) || \
01556 (((a) >= '0') && ((a) <= '9')) || \
01557 ((a) == ':') || \
01558 ((a) == '/') || \
01559 ((a) == '-') || \
01560 ((a) == '.') || \
01561 ((a) == '_'))
01562
01563
01564 gchar *
01565 xmms_medialib_url_encode (const gchar *path)
01566 {
01567 static gchar hex[16] = "0123456789abcdef";
01568 gchar *res;
01569 int i = 0, j = 0;
01570
01571 res = g_malloc (strlen (path) * 3 + 1);
01572 if (!res)
01573 return NULL;
01574
01575 while (path[i]) {
01576 guchar chr = path[i++];
01577 if (GOODCHAR (chr)) {
01578 res[j++] = chr;
01579 } else if (chr == ' ') {
01580 res[j++] = '+';
01581 } else {
01582 res[j++] = '%';
01583 res[j++] = hex[((chr & 0xf0) >> 4)];
01584 res[j++] = hex[(chr & 0x0f)];
01585 }
01586 }
01587
01588 res[j] = '\0';
01589
01590 return res;
01591 }