00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdio.h>
00023 #include <unistd.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <glib.h>
00027 #include <math.h>
00028
00029 #include "xmmspriv/xmms_collection.h"
00030 #include "xmmspriv/xmms_playlist.h"
00031 #include "xmmspriv/xmms_collquery.h"
00032 #include "xmmspriv/xmms_collserial.h"
00033 #include "xmmspriv/xmms_collsync.h"
00034 #include "xmmspriv/xmms_xform.h"
00035 #include "xmmspriv/xmms_streamtype.h"
00036 #include "xmms/xmms_ipc.h"
00037 #include "xmms/xmms_config.h"
00038 #include "xmms/xmms_log.h"
00039
00040
00041
00042
00043 typedef struct {
00044 const gchar *name;
00045 const gchar *namespace;
00046 xmmsv_coll_t *oldtarget;
00047 xmmsv_coll_t *newtarget;
00048 } coll_rebind_infos_t;
00049
00050 typedef struct {
00051 const gchar* oldname;
00052 const gchar* newname;
00053 const gchar* namespace;
00054 } coll_rename_infos_t;
00055
00056 typedef struct {
00057 xmms_coll_dag_t *dag;
00058 FuncApplyToColl func;
00059 void *udata;
00060 } coll_call_infos_t;
00061
00062 typedef struct {
00063 const gchar *target_name;
00064 const gchar *target_namespace;
00065 gboolean found;
00066 } coll_refcheck_t;
00067
00068 typedef struct {
00069 const gchar *key;
00070 xmmsv_coll_t *value;
00071 } coll_table_pair_t;
00072
00073 typedef enum {
00074 XMMS_COLLECTION_FIND_STATE_UNCHECKED,
00075 XMMS_COLLECTION_FIND_STATE_MATCH,
00076 XMMS_COLLECTION_FIND_STATE_NOMATCH,
00077 } coll_find_state_t;
00078
00079 typedef struct add_metadata_from_tree_user_data_St {
00080 xmms_medialib_session_t *session;
00081 xmms_medialib_entry_t entry;
00082 guint src;
00083 } add_metadata_from_tree_user_data_t;
00084
00085 static GList *global_stream_type;
00086
00087
00088
00089 static void xmms_collection_destroy (xmms_object_t *object);
00090
00091 static gboolean xmms_collection_validate (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, const gchar *save_name, const gchar *save_namespace);
00092 static gboolean xmms_collection_validate_recurs (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, const gchar *save_name, const gchar *save_namespace);
00093 static gboolean xmms_collection_unreference (xmms_coll_dag_t *dag, const gchar *name, guint nsid);
00094
00095 static gboolean xmms_collection_has_reference_to (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, const gchar *tg_name, const gchar *tg_ns);
00096
00097 static void xmms_collection_apply_to_collection_recurs (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, FuncApplyToColl f, void *udata);
00098
00099 static void call_apply_to_coll (gpointer name, gpointer coll, gpointer udata);
00100 static void prepend_key_string (gpointer key, gpointer value, gpointer udata);
00101 static gboolean value_match_save_key (gpointer key, gpointer val, gpointer udata);
00102
00103 static void rebind_references (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, void *udata);
00104 static void rename_references (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, void *udata);
00105 static void strip_references (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, void *udata);
00106 static void check_for_reference (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, void *udata);
00107
00108 static void coll_unref (void *coll);
00109
00110 static GHashTable *xmms_collection_media_info (guint mid, xmms_error_t *err);
00111
00112 static gboolean filter_get_mediainfo_field_string (xmmsv_coll_t *coll, GHashTable *mediainfo, gchar **val);
00113 static gboolean filter_get_mediainfo_field_int (xmmsv_coll_t *coll, GHashTable *mediainfo, gint *val);
00114 static gboolean filter_get_operator_value_string (xmmsv_coll_t *coll, const gchar **val);
00115 static gboolean filter_get_operator_value_int (xmmsv_coll_t *coll, gint *val);
00116 static gboolean filter_get_operator_case (xmmsv_coll_t *coll, gboolean *val);
00117
00118 static void build_match_table (gpointer key, gpointer value, gpointer udata);
00119 static gboolean find_unchecked (gpointer name, gpointer value, gpointer udata);
00120 static void build_list_matches (gpointer key, gpointer value, gpointer udata);
00121
00122 static gboolean xmms_collection_media_match (xmms_coll_dag_t *dag, GHashTable *mediainfo, xmmsv_coll_t *coll, guint nsid, GHashTable *match_table);
00123 static gboolean xmms_collection_media_match_operand (xmms_coll_dag_t *dag, GHashTable *mediainfo, xmmsv_coll_t *coll, guint nsid, GHashTable *match_table);
00124 static gboolean xmms_collection_media_match_reference (xmms_coll_dag_t *dag, GHashTable *mediainfo, xmmsv_coll_t *coll, guint nsid, GHashTable *match_table, const gchar *refname, const gchar *refns);
00125 static gboolean xmms_collection_media_filter_has (xmms_coll_dag_t *dag, GHashTable *mediainfo, xmmsv_coll_t *coll, guint nsid, GHashTable *match_table);
00126 static gboolean xmms_collection_media_filter_equals (xmms_coll_dag_t *dag, GHashTable *mediainfo, xmmsv_coll_t *coll, guint nsid, GHashTable *match_table);
00127 static gboolean xmms_collection_media_filter_match (xmms_coll_dag_t *dag, GHashTable *mediainfo, xmmsv_coll_t *coll, guint nsid, GHashTable *match_table);
00128 static gboolean xmms_collection_media_filter_smaller (xmms_coll_dag_t *dag, GHashTable *mediainfo, xmmsv_coll_t *coll, guint nsid, GHashTable *match_table);
00129 static gboolean xmms_collection_media_filter_greater (xmms_coll_dag_t *dag, GHashTable *mediainfo, xmmsv_coll_t *coll, guint nsid, GHashTable *match_table);
00130
00131 static xmmsv_coll_t * xmms_collection_client_get (xmms_coll_dag_t *dag, const gchar *collname, const gchar *namespace, xmms_error_t *error);
00132 static GList * xmms_collection_client_list (xmms_coll_dag_t *dag, const gchar *namespace, xmms_error_t *error);
00133 static void xmms_collection_client_save (xmms_coll_dag_t *dag, const gchar *name, const gchar *namespace, xmmsv_coll_t *coll, xmms_error_t *error);
00134 static void xmms_collection_client_remove (xmms_coll_dag_t *dag, const gchar *collname, const gchar *namespace, xmms_error_t *error);
00135 static GList * xmms_collection_client_find (xmms_coll_dag_t *dag, gint32 mid, const gchar *namespace, xmms_error_t *error);
00136 static void xmms_collection_client_rename (xmms_coll_dag_t *dag, const gchar *from_name, const gchar *to_name, const gchar *namespace, xmms_error_t *error);
00137
00138 static GList * xmms_collection_client_query_infos (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, gint32 lim_start, gint32 lim_len, xmmsv_t *order, xmmsv_t *fetch, xmmsv_t *group, xmms_error_t *err);
00139 static GList * xmms_collection_client_query_ids (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, gint32 lim_start, gint32 lim_len, xmmsv_t *order, xmms_error_t *err);
00140 static xmmsv_coll_t *xmms_collection_client_idlist_from_pls (xmms_coll_dag_t *dag, const gchar *mediainfo, xmms_error_t *err);
00141 static void xmms_collection_client_sync (xmms_coll_dag_t *dag, xmms_error_t *err);
00142
00143
00144 XMMS_CMD_DEFINE (collection_get, xmms_collection_client_get, xmms_coll_dag_t *, COLL, STRING, STRING);
00145 XMMS_CMD_DEFINE (collection_list, xmms_collection_client_list, xmms_coll_dag_t *, LIST, STRING, NONE);
00146 XMMS_CMD_DEFINE3 (collection_save, xmms_collection_client_save, xmms_coll_dag_t *, NONE, STRING, STRING, COLL);
00147 XMMS_CMD_DEFINE (collection_remove, xmms_collection_client_remove, xmms_coll_dag_t *, NONE, STRING, STRING);
00148 XMMS_CMD_DEFINE (collection_find, xmms_collection_client_find, xmms_coll_dag_t *, LIST, INT32, STRING);
00149 XMMS_CMD_DEFINE3 (collection_rename, xmms_collection_client_rename, xmms_coll_dag_t *, NONE, STRING, STRING, STRING);
00150 XMMS_CMD_DEFINE (collection_from_pls, xmms_collection_client_idlist_from_pls, xmms_coll_dag_t *, COLL, STRING, NONE);
00151 XMMS_CMD_DEFINE (collection_sync, xmms_collection_client_sync, xmms_coll_dag_t *, NONE, NONE, NONE);
00152
00153
00154 XMMS_CMD_DEFINE4 (query_ids, xmms_collection_client_query_ids, xmms_coll_dag_t *, LIST, COLL, INT32, INT32, LIST);
00155 XMMS_CMD_DEFINE6 (query_infos, xmms_collection_client_query_infos, xmms_coll_dag_t *, LIST, COLL, INT32, INT32, LIST, LIST, LIST);
00156
00157
00158 GTree *
00159 xmms_collection_changed_msg_new (xmms_collection_changed_actions_t type,
00160 const gchar *plname, const gchar *namespace)
00161 {
00162 GTree *dict;
00163
00164 dict = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
00165 NULL, (GDestroyNotify)xmmsv_unref);
00166
00167 g_tree_insert (dict, (gpointer) "type", xmmsv_new_int (type));
00168 g_tree_insert (dict, (gpointer) "name", xmmsv_new_string (plname));
00169 g_tree_insert (dict, (gpointer) "namespace", xmmsv_new_string (namespace));
00170
00171 return dict;
00172 }
00173
00174 void
00175 xmms_collection_changed_msg_send (xmms_coll_dag_t *colldag, GTree *dict)
00176 {
00177 g_return_if_fail (colldag);
00178 g_return_if_fail (dict);
00179
00180 xmms_object_emit_f (XMMS_OBJECT (colldag),
00181 XMMS_IPC_SIGNAL_COLLECTION_CHANGED,
00182 XMMSV_TYPE_DICT,
00183 dict);
00184
00185 g_tree_destroy (dict);
00186 }
00187
00188 #define XMMS_COLLECTION_CHANGED_MSG(type, name, namespace) xmms_collection_changed_msg_send (dag, xmms_collection_changed_msg_new (type, name, namespace))
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 struct xmms_coll_dag_St {
00204 xmms_object_t object;
00205
00206
00207 xmms_playlist_t *playlist;
00208
00209 GHashTable *collrefs[XMMS_COLLECTION_NUM_NAMESPACES];
00210
00211 GMutex *mutex;
00212
00213 };
00214
00215 static void
00216 coll_sync_cb (xmms_object_t *object, xmmsv_t *val, gpointer udata)
00217 {
00218 xmms_coll_sync_schedule_sync ();
00219 }
00220
00221
00222
00223
00224
00225 xmms_coll_dag_t *
00226 xmms_collection_init (xmms_playlist_t *playlist)
00227 {
00228 gint i;
00229 xmms_coll_dag_t *ret;
00230 xmms_stream_type_t *f;
00231
00232 ret = xmms_object_new (xmms_coll_dag_t, xmms_collection_destroy);
00233 ret->mutex = g_mutex_new ();
00234 ret->playlist = playlist;
00235
00236 xmms_coll_sync_init (ret);
00237
00238 for (i = 0; i < XMMS_COLLECTION_NUM_NAMESPACES; ++i) {
00239 ret->collrefs[i] = g_hash_table_new_full (g_str_hash, g_str_equal,
00240 g_free, coll_unref);
00241 }
00242
00243 xmms_ipc_object_register (XMMS_IPC_OBJECT_COLLECTION, XMMS_OBJECT (ret));
00244
00245 xmms_ipc_broadcast_register (XMMS_OBJECT (ret),
00246 XMMS_IPC_SIGNAL_COLLECTION_CHANGED);
00247
00248
00249 xmms_object_connect (XMMS_OBJECT (ret),
00250 XMMS_IPC_SIGNAL_COLLECTION_CHANGED,
00251 coll_sync_cb, ret);
00252
00253
00254 xmms_object_connect (XMMS_OBJECT (playlist),
00255 XMMS_IPC_SIGNAL_PLAYLIST_CHANGED,
00256 coll_sync_cb, ret);
00257
00258 xmms_object_connect (XMMS_OBJECT (playlist),
00259 XMMS_IPC_SIGNAL_PLAYLIST_CURRENT_POS,
00260 coll_sync_cb, ret);
00261
00262 xmms_object_connect (XMMS_OBJECT (playlist),
00263 XMMS_IPC_SIGNAL_PLAYLIST_LOADED,
00264 coll_sync_cb, ret);
00265
00266
00267 xmms_object_cmd_add (XMMS_OBJECT (ret),
00268 XMMS_IPC_CMD_COLLECTION_GET,
00269 XMMS_CMD_FUNC (collection_get));
00270
00271 xmms_object_cmd_add (XMMS_OBJECT (ret),
00272 XMMS_IPC_CMD_COLLECTION_LIST,
00273 XMMS_CMD_FUNC (collection_list));
00274
00275 xmms_object_cmd_add (XMMS_OBJECT (ret),
00276 XMMS_IPC_CMD_COLLECTION_SAVE,
00277 XMMS_CMD_FUNC (collection_save));
00278
00279 xmms_object_cmd_add (XMMS_OBJECT (ret),
00280 XMMS_IPC_CMD_COLLECTION_REMOVE,
00281 XMMS_CMD_FUNC (collection_remove));
00282
00283 xmms_object_cmd_add (XMMS_OBJECT (ret),
00284 XMMS_IPC_CMD_COLLECTION_FIND,
00285 XMMS_CMD_FUNC (collection_find));
00286
00287 xmms_object_cmd_add (XMMS_OBJECT (ret),
00288 XMMS_IPC_CMD_COLLECTION_RENAME,
00289 XMMS_CMD_FUNC (collection_rename));
00290
00291 xmms_object_cmd_add (XMMS_OBJECT (ret),
00292 XMMS_IPC_CMD_QUERY_IDS,
00293 XMMS_CMD_FUNC (query_ids));
00294
00295 xmms_object_cmd_add (XMMS_OBJECT (ret),
00296 XMMS_IPC_CMD_QUERY_INFOS,
00297 XMMS_CMD_FUNC (query_infos));
00298
00299 xmms_object_cmd_add (XMMS_OBJECT (ret),
00300 XMMS_IPC_CMD_IDLIST_FROM_PLS,
00301 XMMS_CMD_FUNC (collection_from_pls));
00302
00303 xmms_object_cmd_add (XMMS_OBJECT (ret),
00304 XMMS_IPC_CMD_COLLECTION_SYNC,
00305 XMMS_CMD_FUNC (collection_sync));
00306
00307 xmms_collection_dag_restore (ret);
00308
00309 f = _xmms_stream_type_new (NULL,
00310 XMMS_STREAM_TYPE_MIMETYPE,
00311 "application/x-xmms2-playlist-entries",
00312 XMMS_STREAM_TYPE_END);
00313 global_stream_type = g_list_prepend (NULL, f);
00314
00315 return ret;
00316 }
00317
00318 static void
00319 add_metadata_from_tree (const gchar *key, xmmsv_t *value, gpointer user_data)
00320 {
00321 add_metadata_from_tree_user_data_t *ud = user_data;
00322
00323 if (xmmsv_get_type (value) == XMMSV_TYPE_INT32) {
00324 gint iv;
00325 xmmsv_get_int (value, &iv);
00326 xmms_medialib_entry_property_set_int_source (ud->session, ud->entry,
00327 key,
00328 iv,
00329 ud->src);
00330 } else if (xmmsv_get_type (value) == XMMSV_TYPE_STRING) {
00331 const gchar *sv;
00332 xmmsv_get_string (value, &sv);
00333 xmms_medialib_entry_property_set_str_source (ud->session, ud->entry,
00334 key,
00335 sv,
00336 ud->src);
00337 }
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347 static xmmsv_coll_t *
00348 xmms_collection_client_idlist_from_pls (xmms_coll_dag_t *dag, const gchar *path,
00349 xmms_error_t *err)
00350 {
00351 xmms_xform_t *xform;
00352 GList *lst, *n;
00353 xmmsv_coll_t *coll;
00354 xmms_medialib_session_t *session;
00355 guint src;
00356 const gchar *buf;
00357
00358
00359 xform = xmms_xform_chain_setup_url (0, path, global_stream_type, TRUE);
00360
00361 if (!xform) {
00362 xmms_error_set (err, XMMS_ERROR_NO_SAUSAGE, "We can't handle this type of playlist or URL");
00363 return NULL;
00364 }
00365
00366 lst = xmms_xform_browse_method (xform, "/", err);
00367 if (xmms_error_iserror (err)) {
00368 xmms_object_unref (xform);
00369 return NULL;
00370 }
00371
00372 coll = xmmsv_coll_new (XMMS_COLLECTION_TYPE_IDLIST);
00373 session = xmms_medialib_begin_write ();
00374 src = xmms_medialib_source_to_id (session, "plugin/playlist");
00375
00376 n = lst;
00377 while (n) {
00378 xmms_medialib_entry_t entry;
00379
00380 xmmsv_t *a = n->data;
00381 xmmsv_t *b;
00382
00383 if (!xmmsv_dict_get (a, "realpath", &b)) {
00384 xmms_log_error ("Playlist plugin did not set realpath; probably a bug in plugin");
00385 xmmsv_unref (a);
00386 n = g_list_delete_link (n, n);
00387 continue;
00388 }
00389
00390 xmmsv_get_string (b, &buf);
00391 entry = xmms_medialib_entry_new_encoded (session, buf, err);
00392 xmmsv_dict_remove (a, "realpath");
00393 xmmsv_dict_remove (a, "path");
00394
00395 if (entry) {
00396 add_metadata_from_tree_user_data_t udata;
00397 udata.session = session;
00398 udata.entry = entry;
00399 udata.src = src;
00400
00401 xmmsv_dict_foreach(a, add_metadata_from_tree, &udata);
00402
00403 xmmsv_coll_idlist_append (coll, entry);
00404 } else {
00405 xmmsv_get_string (b, &buf);
00406 xmms_log_error ("couldn't add %s to collection!", buf);
00407 }
00408
00409 xmmsv_unref (a);
00410 n = g_list_delete_link (n, n);
00411 }
00412
00413 xmms_medialib_end (session);
00414 xmms_object_unref (xform);
00415
00416 return coll;
00417 }
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 void
00430 xmms_collection_client_remove (xmms_coll_dag_t *dag, const gchar *name,
00431 const gchar *namespace, xmms_error_t *err)
00432 {
00433 guint nsid;
00434 gboolean retval = FALSE;
00435 guint i;
00436
00437 nsid = xmms_collection_get_namespace_id (namespace);
00438 if (nsid == XMMS_COLLECTION_NSID_INVALID) {
00439 xmms_error_set (err, XMMS_ERROR_INVAL, "invalid collection namespace");
00440 return;
00441 }
00442
00443 g_mutex_lock (dag->mutex);
00444
00445
00446 if (nsid == XMMS_COLLECTION_NSID_ALL) {
00447 for (i = 0; i < XMMS_COLLECTION_NUM_NAMESPACES; ++i) {
00448 retval = xmms_collection_unreference (dag, name, i) || retval;
00449 }
00450 } else {
00451 retval = xmms_collection_unreference (dag, name, nsid);
00452 }
00453
00454 g_mutex_unlock (dag->mutex);
00455
00456 if (retval == FALSE) {
00457 xmms_error_set (err, XMMS_ERROR_NOENT, "Failed to remove this collection!");
00458 }
00459
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471 void
00472 xmms_collection_client_save (xmms_coll_dag_t *dag, const gchar *name, const gchar *namespace,
00473 xmmsv_coll_t *coll, xmms_error_t *err)
00474 {
00475 xmmsv_coll_t *existing;
00476 guint nsid;
00477 const gchar *alias;
00478 gchar *newkey = NULL;
00479
00480 nsid = xmms_collection_get_namespace_id (namespace);
00481 if (nsid == XMMS_COLLECTION_NSID_INVALID) {
00482 xmms_error_set (err, XMMS_ERROR_INVAL, "invalid collection namespace");
00483 return;
00484 } else if (nsid == XMMS_COLLECTION_NSID_ALL) {
00485 xmms_error_set (err, XMMS_ERROR_GENERIC, "cannot save collection in all namespaces");
00486 return;
00487 }
00488
00489
00490 if (!xmms_collection_validate (dag, coll, name, namespace)) {
00491 xmms_error_set (err, XMMS_ERROR_INVAL, "invalid collection structure");
00492 return;
00493 }
00494
00495 g_mutex_lock (dag->mutex);
00496
00497
00498 existing = xmms_collection_get_pointer (dag, name, nsid);
00499 if (existing != NULL) {
00500
00501 coll_rebind_infos_t infos = { name, namespace, existing, coll };
00502 xmms_collection_apply_to_all_collections (dag, rebind_references, &infos);
00503 }
00504
00505
00506 xmms_collection_apply_to_collection (dag, coll, bind_all_references, NULL);
00507
00508
00509 if (existing != NULL) {
00510 while ((alias = xmms_collection_find_alias (dag, nsid,
00511 existing, NULL)) != NULL) {
00512 newkey = g_strdup (alias);
00513
00514
00515 xmms_collection_dag_replace (dag, nsid, newkey, coll);
00516 xmmsv_coll_ref (coll);
00517
00518 XMMS_COLLECTION_CHANGED_MSG (XMMS_COLLECTION_CHANGED_UPDATE,
00519 newkey,
00520 namespace);
00521 }
00522
00523
00524 } else {
00525 newkey = g_strdup (name);
00526 xmms_collection_dag_replace (dag, nsid, newkey, coll);
00527 xmmsv_coll_ref (coll);
00528
00529 XMMS_COLLECTION_CHANGED_MSG (XMMS_COLLECTION_CHANGED_ADD,
00530 newkey,
00531 namespace);
00532 }
00533
00534 g_mutex_unlock (dag->mutex);
00535
00536
00537 if (nsid == XMMS_COLLECTION_NSID_PLAYLISTS) {
00538 XMMS_PLAYLIST_COLLECTION_CHANGED_MSG (dag->playlist, newkey);
00539 }
00540
00541 }
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554 xmmsv_coll_t *
00555 xmms_collection_client_get (xmms_coll_dag_t *dag, const gchar *name,
00556 const gchar *namespace, xmms_error_t *err)
00557 {
00558 xmmsv_coll_t *coll = NULL;
00559 guint nsid;
00560
00561 nsid = xmms_collection_get_namespace_id (namespace);
00562 if (nsid == XMMS_COLLECTION_NSID_INVALID) {
00563 xmms_error_set (err, XMMS_ERROR_INVAL, "invalid collection namespace");
00564 return NULL;
00565 }
00566
00567 g_mutex_lock (dag->mutex);
00568
00569 coll = xmms_collection_get_pointer (dag, name, nsid);
00570
00571
00572 if (coll == NULL) {
00573 xmms_error_set (err, XMMS_ERROR_NOENT, "no such collection");
00574
00575
00576 } else {
00577 xmmsv_coll_ref (coll);
00578 }
00579
00580 g_mutex_unlock (dag->mutex);
00581
00582 return coll;
00583 }
00584
00585
00586
00587
00588
00589
00590
00591
00592 void
00593 xmms_collection_sync (xmms_coll_dag_t *dag)
00594 {
00595 g_return_if_fail (dag);
00596
00597 g_mutex_lock (dag->mutex);
00598
00599 xmms_collection_dag_save (dag);
00600
00601 g_mutex_unlock (dag->mutex);
00602 }
00603
00604
00605 void
00606 xmms_collection_client_sync (xmms_coll_dag_t *dag, xmms_error_t *err)
00607 {
00608 xmms_collection_sync (dag);
00609 }
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621 GList *
00622 xmms_collection_client_list (xmms_coll_dag_t *dag, const gchar *namespace,
00623 xmms_error_t *err)
00624 {
00625 GList *r = NULL;
00626 guint nsid;
00627
00628 nsid = xmms_collection_get_namespace_id (namespace);
00629 if (nsid == XMMS_COLLECTION_NSID_INVALID) {
00630 xmms_error_set (err, XMMS_ERROR_INVAL, "invalid collection namespace");
00631 return NULL;
00632 }
00633
00634 g_mutex_lock (dag->mutex);
00635
00636
00637 xmms_collection_foreach_in_namespace (dag, nsid, prepend_key_string, &r);
00638
00639 g_mutex_unlock (dag->mutex);
00640
00641 return r;
00642 }
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653 GList *
00654 xmms_collection_client_find (xmms_coll_dag_t *dag, gint32 mid, const gchar *namespace,
00655 xmms_error_t *err)
00656 {
00657 GHashTable *mediainfo;
00658 GList *ret = NULL;
00659 guint nsid;
00660 gchar *open_name;
00661 GHashTable *match_table;
00662 xmmsv_coll_t *coll;
00663
00664
00665 nsid = xmms_collection_get_namespace_id (namespace);
00666 if (nsid == XMMS_COLLECTION_NSID_INVALID) {
00667 xmms_error_set (err, XMMS_ERROR_INVAL, "invalid collection namespace");
00668 return NULL;
00669 }
00670 if (nsid == XMMS_COLLECTION_NSID_ALL) {
00671 xmms_error_set (err, XMMS_ERROR_INVAL, "cannot search in all namespaces");
00672 return NULL;
00673 }
00674
00675
00676 match_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
00677 xmms_collection_foreach_in_namespace (dag, nsid, build_match_table, match_table);
00678
00679
00680 mediainfo = xmms_collection_media_info (mid, err);
00681
00682
00683 while (g_hash_table_find (match_table, find_unchecked, &open_name) != NULL) {
00684 coll_find_state_t *match = g_new (coll_find_state_t, 1);
00685 coll = xmms_collection_get_pointer (dag, open_name, nsid);
00686 if (xmms_collection_media_match (dag, mediainfo, coll, nsid, match_table)) {
00687 *match = XMMS_COLLECTION_FIND_STATE_MATCH;
00688 } else {
00689 *match = XMMS_COLLECTION_FIND_STATE_NOMATCH;
00690 }
00691 g_hash_table_replace (match_table, g_strdup (open_name), match);
00692 }
00693
00694
00695 g_hash_table_foreach (match_table, build_list_matches, &ret);
00696 g_hash_table_destroy (match_table);
00697
00698 g_hash_table_destroy (mediainfo);
00699
00700 return ret;
00701 }
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713 void
00714 xmms_collection_client_rename (xmms_coll_dag_t *dag, const gchar *from_name,
00715 const gchar *to_name, const gchar *namespace,
00716 xmms_error_t *err)
00717 {
00718 gboolean retval;
00719 guint nsid;
00720 xmmsv_coll_t *from_coll, *to_coll;
00721
00722 nsid = xmms_collection_get_namespace_id (namespace);
00723 if (nsid == XMMS_COLLECTION_NSID_INVALID) {
00724 xmms_error_set (err, XMMS_ERROR_INVAL, "invalid collection namespace");
00725 return;
00726 } else if (nsid == XMMS_COLLECTION_NSID_ALL) {
00727 xmms_error_set (err, XMMS_ERROR_GENERIC, "cannot rename collection in all namespaces");
00728 return;
00729 }
00730
00731 g_mutex_lock (dag->mutex);
00732
00733 from_coll = xmms_collection_get_pointer (dag, from_name, nsid);
00734 to_coll = xmms_collection_get_pointer (dag, to_name, nsid);
00735
00736
00737 if (from_coll == NULL) {
00738 xmms_error_set (err, XMMS_ERROR_NOENT, "no such collection");
00739 retval = FALSE;
00740
00741 } else if (to_coll != NULL) {
00742 xmms_error_set (err, XMMS_ERROR_NOENT, "a collection already exists with the target name");
00743 retval = FALSE;
00744
00745
00746 } else {
00747 GTree *dict;
00748
00749
00750 xmms_collection_dag_replace (dag, nsid, g_strdup (to_name), from_coll);
00751 xmmsv_coll_ref (from_coll);
00752
00753
00754 g_hash_table_remove (dag->collrefs[nsid], from_name);
00755
00756
00757 coll_rename_infos_t infos = { from_name, to_name, namespace };
00758 xmms_collection_apply_to_all_collections (dag, rename_references, &infos);
00759
00760
00761 dict = xmms_collection_changed_msg_new (XMMS_COLLECTION_CHANGED_RENAME,
00762 from_name, namespace);
00763 g_tree_insert (dict, (gpointer) "newname", xmmsv_new_string (to_name));
00764 xmms_collection_changed_msg_send (dag, dict);
00765
00766 retval = TRUE;
00767 }
00768
00769 g_mutex_unlock (dag->mutex);
00770
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784 GList *
00785 xmms_collection_query_ids (xmms_coll_dag_t *dag, xmmsv_coll_t *coll,
00786 gint32 lim_start, gint32 lim_len, xmmsv_t *order,
00787 xmms_error_t *err)
00788 {
00789 GList *res, *n;
00790 xmmsv_t *fetch, *group, *idval;
00791
00792
00793 group = xmmsv_new_list ();
00794 fetch = xmmsv_new_list ();
00795 idval = xmmsv_new_string ("id");
00796 xmmsv_list_append (fetch, idval);
00797
00798 res = xmms_collection_client_query_infos (dag, coll, lim_start, lim_len, order, fetch, group, err);
00799
00800
00801 for (n = res; n; n = n->next) {
00802 xmms_medialib_entry_t id;
00803 xmmsv_t *id_val, *cmdval = n->data;
00804
00805 xmmsv_dict_get (cmdval, "id", &id_val);
00806 xmmsv_get_int (id_val, &id);
00807 n->data = xmmsv_new_int (id);
00808
00809 xmmsv_unref (cmdval);
00810 }
00811
00812 xmmsv_unref (group);
00813 xmmsv_unref (fetch);
00814 xmmsv_unref (idval);
00815
00816 return res;
00817 }
00818
00819
00820 GList *
00821 xmms_collection_client_query_ids (xmms_coll_dag_t *dag, xmmsv_coll_t *coll,
00822 gint32 lim_start, gint32 lim_len, xmmsv_t *order,
00823 xmms_error_t *err)
00824 {
00825 return xmms_collection_query_ids (dag, coll, lim_start, lim_len, order, err);
00826 }
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839 GList *
00840 xmms_collection_client_query_infos (xmms_coll_dag_t *dag, xmmsv_coll_t *coll,
00841 gint32 lim_start, gint32 lim_len, xmmsv_t *order,
00842 xmmsv_t *fetch, xmmsv_t *group, xmms_error_t *err)
00843 {
00844 GList *res = NULL;
00845 GString *query;
00846
00847
00848 if (xmmsv_list_get_size (fetch) == 0) {
00849 xmms_error_set (err, XMMS_ERROR_INVAL, "fetch list must not be empty!");
00850 return NULL;
00851 }
00852
00853
00854 if (!check_string_list (order)) {
00855 xmms_error_set (err, XMMS_ERROR_NOENT, "invalid order list!");
00856 return NULL;
00857 }
00858 if (!check_string_list (fetch)) {
00859 xmms_error_set (err, XMMS_ERROR_NOENT, "invalid fetch list!");
00860 return NULL;
00861 }
00862 if (!check_string_list (group)) {
00863 xmms_error_set (err, XMMS_ERROR_NOENT, "invalid group list!");
00864 return NULL;
00865 }
00866
00867
00868 if (!xmms_collection_validate (dag, coll, NULL, NULL)) {
00869 if (err) {
00870 xmms_error_set (err, XMMS_ERROR_INVAL, "invalid collection structure");
00871 }
00872 return NULL;
00873 }
00874
00875 g_mutex_lock (dag->mutex);
00876
00877 query = xmms_collection_get_query (dag, coll, lim_start, lim_len,
00878 order, fetch, group);
00879
00880 g_mutex_unlock (dag->mutex);
00881
00882 XMMS_DBG ("COLLECTIONS: query_infos with %s", query->str);
00883
00884
00885 xmms_medialib_session_t *session = xmms_medialib_begin ();
00886 res = xmms_medialib_select (session, query->str, err);
00887 xmms_medialib_end (session);
00888
00889 g_string_free (query, TRUE);
00890
00891 return res;
00892 }
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902 void
00903 xmms_collection_update_pointer (xmms_coll_dag_t *dag, const gchar *name,
00904 guint nsid, xmmsv_coll_t *newtarget)
00905 {
00906 xmms_collection_dag_replace (dag, nsid, g_strdup (name), newtarget);
00907 xmmsv_coll_ref (newtarget);
00908 }
00909
00910
00911 void
00912 xmms_collection_dag_replace (xmms_coll_dag_t *dag,
00913 xmms_collection_namespace_id_t nsid,
00914 gchar *key, xmmsv_coll_t *newcoll)
00915 {
00916 g_hash_table_replace (dag->collrefs[nsid], key, newcoll);
00917 }
00918
00919
00920
00921
00922
00923
00924
00925
00926 xmmsv_coll_t *
00927 xmms_collection_get_pointer (xmms_coll_dag_t *dag, const gchar *collname,
00928 guint nsid)
00929 {
00930 gint i;
00931 xmmsv_coll_t *coll = NULL;
00932
00933 if (nsid == XMMS_COLLECTION_NSID_ALL) {
00934 for (i = 0; i < XMMS_COLLECTION_NUM_NAMESPACES && coll == NULL; ++i) {
00935 coll = g_hash_table_lookup (dag->collrefs[i], collname);
00936 }
00937 } else {
00938 coll = g_hash_table_lookup (dag->collrefs[nsid], collname);
00939 }
00940
00941 return coll;
00942 }
00943
00944
00945
00946
00947
00948
00949
00950
00951 gboolean
00952 xmms_collection_get_int_attr (xmmsv_coll_t *coll, const gchar *attrname, gint *val)
00953 {
00954 gboolean retval = FALSE;
00955 gint buf;
00956 gchar *str;
00957 gchar *endptr;
00958
00959 if (xmmsv_coll_attribute_get (coll, attrname, &str)) {
00960 buf = strtol (str, &endptr, 10);
00961
00962
00963 if (*endptr == '\0') {
00964 *val = buf;
00965 retval = TRUE;
00966 }
00967 }
00968
00969 return retval;
00970 }
00971
00972
00973
00974
00975
00976
00977
00978
00979 gboolean
00980 xmms_collection_set_int_attr (xmmsv_coll_t *coll, const gchar *attrname,
00981 gint newval)
00982 {
00983 gboolean retval = FALSE;
00984 gchar str[XMMS_MAX_INT_ATTRIBUTE_LEN + 1];
00985 gint written;
00986
00987 written = g_snprintf (str, sizeof (str), "%d", newval);
00988 if (written < XMMS_MAX_INT_ATTRIBUTE_LEN) {
00989 xmmsv_coll_attribute_set (coll, attrname, str);
00990 retval = TRUE;
00991 }
00992
00993 return retval;
00994 }
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008 const gchar *
01009 xmms_collection_find_alias (xmms_coll_dag_t *dag, guint nsid,
01010 xmmsv_coll_t *value, const gchar *key)
01011 {
01012 const gchar *otherkey = NULL;
01013 coll_table_pair_t search_pair = { key, value };
01014
01015 if (g_hash_table_find (dag->collrefs[nsid], value_match_save_key,
01016 &search_pair) != NULL) {
01017 otherkey = search_pair.key;
01018 }
01019
01020 return otherkey;
01021 }
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031 xmms_medialib_entry_t
01032 xmms_collection_get_random_media (xmms_coll_dag_t *dag, xmmsv_coll_t *source)
01033 {
01034 GList *res;
01035 xmms_medialib_entry_t mid = 0;
01036 xmmsv_t *rorder = xmmsv_new_list ();
01037 xmmsv_t *randval = xmmsv_new_string ("~RANDOM()");
01038
01039
01040 xmmsv_list_append (rorder, randval);
01041
01042 res = xmms_collection_query_ids (dag, source, 0, 1, rorder, NULL);
01043
01044 if (res != NULL) {
01045 xmmsv_t *val = (xmmsv_t *) res->data;
01046 xmmsv_get_int (val, &mid);
01047 xmmsv_unref (val);
01048 g_list_free (res);
01049 }
01050
01051 xmmsv_unref (rorder);
01052 xmmsv_unref (randval);
01053
01054 return mid;
01055 }
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065 static void
01066 xmms_collection_destroy (xmms_object_t *object)
01067 {
01068 gint i;
01069 xmms_coll_dag_t *dag = (xmms_coll_dag_t *)object;
01070
01071 g_return_if_fail (dag);
01072
01073 xmms_coll_sync_shutdown ();
01074 xmms_collection_dag_save (dag);
01075
01076 g_mutex_free (dag->mutex);
01077
01078 for (i = 0; i < XMMS_COLLECTION_NUM_NAMESPACES; ++i) {
01079 g_hash_table_destroy (dag->collrefs[i]);
01080 }
01081
01082 xmms_ipc_broadcast_unregister (XMMS_IPC_SIGNAL_COLLECTION_CHANGED);
01083
01084 xmms_ipc_object_unregister (XMMS_IPC_OBJECT_COLLECTION);
01085 }
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097 static gboolean
01098 xmms_collection_validate (xmms_coll_dag_t *dag, xmmsv_coll_t *coll,
01099 const gchar *save_name, const gchar *save_namespace)
01100 {
01101
01102 if (save_namespace != NULL &&
01103 strcmp (save_namespace, XMMS_COLLECTION_NS_PLAYLISTS) == 0) {
01104
01105 if (xmmsv_coll_get_type (coll) != XMMS_COLLECTION_TYPE_IDLIST &&
01106 xmmsv_coll_get_type (coll) != XMMS_COLLECTION_TYPE_QUEUE &&
01107 xmmsv_coll_get_type (coll) != XMMS_COLLECTION_TYPE_PARTYSHUFFLE) {
01108 return FALSE;
01109 }
01110 }
01111
01112
01113 return xmms_collection_validate_recurs (dag, coll, save_name,
01114 save_namespace);
01115 }
01116
01117
01118
01119
01120
01121 static gboolean
01122 xmms_collection_validate_recurs (xmms_coll_dag_t *dag, xmmsv_coll_t *coll,
01123 const gchar *save_name, const gchar *save_namespace)
01124 {
01125 guint num_operands = 0;
01126 xmmsv_coll_t *op, *ref;
01127 gchar *attr, *attr2;
01128 gboolean valid = TRUE;
01129 xmmsv_coll_type_t type;
01130 xmms_collection_namespace_id_t nsid;
01131
01132
01133 num_operands = xmmsv_list_get_size (xmmsv_coll_operands_get (coll));
01134
01135
01136 type = xmmsv_coll_get_type (coll);
01137 switch (type) {
01138 case XMMS_COLLECTION_TYPE_REFERENCE:
01139
01140 if (num_operands > 1) {
01141 return FALSE;
01142 }
01143
01144
01145 xmmsv_coll_attribute_get (coll, "reference", &attr);
01146 if (attr == NULL) {
01147 return FALSE;
01148 } else if (strcmp (attr, "All Media") != 0) {
01149 xmmsv_coll_attribute_get (coll, "namespace", &attr2);
01150
01151 if (attr2 == NULL) {
01152 return FALSE;
01153 }
01154
01155 nsid = xmms_collection_get_namespace_id (attr2);
01156 if (nsid == XMMS_COLLECTION_NSID_INVALID) {
01157 return FALSE;
01158 }
01159
01160 g_mutex_lock (dag->mutex);
01161 ref = xmms_collection_get_pointer (dag, attr, nsid);
01162 if (ref == NULL) {
01163 g_mutex_unlock (dag->mutex);
01164 return FALSE;
01165 }
01166
01167 if (save_name && save_namespace) {
01168
01169 if (strcmp (attr, save_name) == 0 &&
01170 strcmp (attr2, save_namespace) == 0) {
01171
01172 g_mutex_unlock (dag->mutex);
01173 return FALSE;
01174
01175
01176 } else if (xmms_collection_has_reference_to (dag, ref, save_name,
01177 save_namespace)) {
01178 g_mutex_unlock (dag->mutex);
01179 return FALSE;
01180 }
01181 }
01182
01183 g_mutex_unlock (dag->mutex);
01184 } else {
01185
01186 ref = NULL;
01187 }
01188
01189
01190 if (num_operands == 1) {
01191 xmmsv_t *val;
01192 xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &val);
01193 xmmsv_get_coll (val, &op);
01194
01195 if (op != ref) {
01196 return FALSE;
01197 }
01198 }
01199 break;
01200
01201 case XMMS_COLLECTION_TYPE_UNION:
01202 case XMMS_COLLECTION_TYPE_INTERSECTION:
01203
01204 if (num_operands == 0) {
01205 return FALSE;
01206 }
01207 break;
01208
01209 case XMMS_COLLECTION_TYPE_COMPLEMENT:
01210
01211 if (num_operands != 1) {
01212 return FALSE;
01213 }
01214 break;
01215
01216 case XMMS_COLLECTION_TYPE_HAS:
01217
01218 if (num_operands != 1) {
01219 return FALSE;
01220 }
01221
01222
01223
01224 if (!xmmsv_coll_attribute_get (coll, "field", &attr)) {
01225 return FALSE;
01226 }
01227 break;
01228
01229 case XMMS_COLLECTION_TYPE_EQUALS:
01230 case XMMS_COLLECTION_TYPE_MATCH:
01231 case XMMS_COLLECTION_TYPE_SMALLER:
01232 case XMMS_COLLECTION_TYPE_GREATER:
01233
01234 if (num_operands != 1) {
01235 return FALSE;
01236 }
01237
01238
01239
01240 if (!xmmsv_coll_attribute_get (coll, "field", &attr)) {
01241 return FALSE;
01242 }
01243
01244
01245
01246
01247
01248
01249 if (!xmmsv_coll_attribute_get (coll, "value", &attr)) {
01250 return FALSE;
01251 }
01252 break;
01253
01254 case XMMS_COLLECTION_TYPE_IDLIST:
01255 case XMMS_COLLECTION_TYPE_QUEUE:
01256
01257 if (num_operands > 0) {
01258 return FALSE;
01259 }
01260 break;
01261
01262 case XMMS_COLLECTION_TYPE_PARTYSHUFFLE:
01263
01264 if (num_operands != 1) {
01265 return FALSE;
01266 }
01267 break;
01268
01269
01270 default:
01271 return FALSE;
01272 break;
01273 }
01274
01275
01276
01277 if (num_operands > 0 && type != XMMS_COLLECTION_TYPE_REFERENCE) {
01278 xmmsv_list_iter_t *iter;
01279 xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &iter);
01280
01281 for (xmmsv_list_iter_first (iter);
01282 valid && xmmsv_list_iter_valid (iter);
01283 xmmsv_list_iter_next (iter)) {
01284
01285 xmmsv_t *val;
01286 xmmsv_list_iter_entry (iter, &val);
01287 xmmsv_get_coll (val, &op);
01288
01289 if (!xmms_collection_validate_recurs (dag, op, save_name,
01290 save_namespace)) {
01291 valid = FALSE;
01292 }
01293 }
01294
01295 xmmsv_list_iter_explicit_destroy (iter);
01296 }
01297
01298 return valid;
01299 }
01300
01301
01302
01303
01304
01305
01306
01307
01308 static gboolean
01309 xmms_collection_unreference (xmms_coll_dag_t *dag, const gchar *name, guint nsid)
01310 {
01311 xmmsv_coll_t *existing, *active_pl;
01312 gboolean retval = FALSE;
01313
01314 existing = g_hash_table_lookup (dag->collrefs[nsid], name);
01315 active_pl = g_hash_table_lookup (dag->collrefs[XMMS_COLLECTION_NSID_PLAYLISTS],
01316 XMMS_ACTIVE_PLAYLIST);
01317
01318
01319 if (existing != NULL && existing != active_pl) {
01320 const gchar *matchkey;
01321 const gchar *nsname = xmms_collection_get_namespace_string (nsid);
01322 coll_rebind_infos_t infos = { name, nsname, existing, NULL };
01323
01324
01325
01326
01327
01328 xmms_collection_apply_to_all_collections (dag, strip_references, &infos);
01329
01330
01331 while ((matchkey = xmms_collection_find_alias (dag, nsid,
01332 existing, NULL)) != NULL) {
01333
01334 XMMS_COLLECTION_CHANGED_MSG (XMMS_COLLECTION_CHANGED_REMOVE,
01335 matchkey,
01336 nsname);
01337
01338 g_hash_table_remove (dag->collrefs[nsid], matchkey);
01339 }
01340
01341 retval = TRUE;
01342 }
01343
01344 return retval;
01345 }
01346
01347
01348
01349
01350
01351
01352 xmms_collection_namespace_id_t
01353 xmms_collection_get_namespace_id (const gchar *namespace)
01354 {
01355 guint nsid;
01356
01357 if (strcmp (namespace, XMMS_COLLECTION_NS_ALL) == 0) {
01358 nsid = XMMS_COLLECTION_NSID_ALL;
01359 } else if (strcmp (namespace, XMMS_COLLECTION_NS_COLLECTIONS) == 0) {
01360 nsid = XMMS_COLLECTION_NSID_COLLECTIONS;
01361 } else if (strcmp (namespace, XMMS_COLLECTION_NS_PLAYLISTS) == 0) {
01362 nsid = XMMS_COLLECTION_NSID_PLAYLISTS;
01363 } else {
01364 nsid = XMMS_COLLECTION_NSID_INVALID;
01365 }
01366
01367 return nsid;
01368 }
01369
01370
01371
01372
01373
01374
01375 const gchar *
01376 xmms_collection_get_namespace_string (xmms_collection_namespace_id_t nsid)
01377 {
01378 const gchar *name;
01379
01380 switch (nsid) {
01381 case XMMS_COLLECTION_NSID_ALL:
01382 name = XMMS_COLLECTION_NS_ALL;
01383 break;
01384 case XMMS_COLLECTION_NSID_COLLECTIONS:
01385 name = XMMS_COLLECTION_NS_COLLECTIONS;
01386 break;
01387 case XMMS_COLLECTION_NSID_PLAYLISTS:
01388 name = XMMS_COLLECTION_NS_PLAYLISTS;
01389 break;
01390
01391 case XMMS_COLLECTION_NSID_INVALID:
01392 default:
01393 name = NULL;
01394 break;
01395 }
01396
01397 return name;
01398 }
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410 static gboolean
01411 xmms_collection_has_reference_to (xmms_coll_dag_t *dag, xmmsv_coll_t *coll,
01412 const gchar *tg_name, const gchar *tg_ns)
01413 {
01414 coll_refcheck_t check = { tg_name, tg_ns, FALSE };
01415 xmms_collection_apply_to_collection (dag, coll, check_for_reference, &check);
01416
01417 return check.found;
01418 }
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428 void
01429 xmms_collection_foreach_in_namespace (xmms_coll_dag_t *dag, guint nsid, GHFunc f, void *udata)
01430 {
01431 gint i;
01432
01433 if (nsid == XMMS_COLLECTION_NSID_ALL) {
01434 for (i = 0; i < XMMS_COLLECTION_NUM_NAMESPACES; ++i) {
01435 g_hash_table_foreach (dag->collrefs[i], f, udata);
01436 }
01437 } else if (nsid != XMMS_COLLECTION_NSID_INVALID) {
01438 g_hash_table_foreach (dag->collrefs[nsid], f, udata);
01439 }
01440 }
01441
01442
01443
01444
01445
01446
01447
01448 void
01449 xmms_collection_apply_to_all_collections (xmms_coll_dag_t *dag,
01450 FuncApplyToColl f, void *udata)
01451 {
01452 gint i;
01453 coll_call_infos_t callinfos = { dag, f, udata };
01454
01455 for (i = 0; i < XMMS_COLLECTION_NUM_NAMESPACES; ++i) {
01456 g_hash_table_foreach (dag->collrefs[i], call_apply_to_coll, &callinfos);
01457 }
01458 }
01459
01460
01461
01462
01463
01464
01465
01466
01467 void
01468 xmms_collection_apply_to_collection (xmms_coll_dag_t *dag,
01469 xmmsv_coll_t *coll,
01470 FuncApplyToColl f, void *udata)
01471 {
01472 xmms_collection_apply_to_collection_recurs (dag, coll, NULL, f, udata);
01473 }
01474
01475
01476 static void
01477 xmms_collection_apply_to_collection_recurs (xmms_coll_dag_t *dag,
01478 xmmsv_coll_t *coll,
01479 xmmsv_coll_t *parent,
01480 FuncApplyToColl f, void *udata)
01481 {
01482 xmmsv_coll_t *op;
01483
01484
01485 f (dag, coll, parent, udata);
01486
01487
01488 if (xmmsv_coll_get_type (coll) != XMMS_COLLECTION_TYPE_REFERENCE) {
01489 xmmsv_list_iter_t *iter;
01490 xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &iter);
01491
01492 for (xmmsv_list_iter_first (iter);
01493 xmmsv_list_iter_valid (iter);
01494 xmmsv_list_iter_next (iter)) {
01495
01496 xmmsv_t *val;
01497 xmmsv_list_iter_entry (iter, &val);
01498
01499 xmmsv_get_coll (val, &op);
01500
01501 xmms_collection_apply_to_collection_recurs (dag, op, coll, f,
01502 udata);
01503 }
01504
01505 xmmsv_list_iter_explicit_destroy (iter);
01506 }
01507 }
01508
01509
01510
01511
01512
01513 static void
01514 call_apply_to_coll (gpointer name, gpointer coll, gpointer udata)
01515 {
01516 coll_call_infos_t *callinfos = (coll_call_infos_t*)udata;
01517
01518 xmms_collection_apply_to_collection (callinfos->dag, coll,
01519 callinfos->func, callinfos->udata);
01520 }
01521
01522
01523
01524
01525 static void
01526 prepend_key_string (gpointer key, gpointer value, gpointer udata)
01527 {
01528 GList **list = (GList**)udata;
01529 *list = g_list_prepend (*list, xmmsv_new_string (key));
01530 }
01531
01532
01533
01534
01535
01536
01537 static gboolean
01538 value_match_save_key (gpointer key, gpointer val, gpointer udata)
01539 {
01540 gboolean found = FALSE;
01541 coll_table_pair_t *pair = (coll_table_pair_t*)udata;
01542 xmmsv_coll_t *coll = (xmmsv_coll_t*)val;
01543
01544
01545 if ((coll == pair->value) &&
01546 (pair->key == NULL || strcmp (pair->key, key) != 0)) {
01547 pair->key = key;
01548 found = TRUE;
01549 }
01550
01551 return found;
01552 }
01553
01554
01555
01556
01557
01558 void
01559 bind_all_references (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, void *udata)
01560 {
01561 if (xmmsv_coll_get_type (coll) == XMMS_COLLECTION_TYPE_REFERENCE) {
01562 xmmsv_coll_t *target;
01563 gchar *target_name;
01564 gchar *target_namespace;
01565 gint target_nsid;
01566
01567 xmmsv_coll_attribute_get (coll, "reference", &target_name);
01568 xmmsv_coll_attribute_get (coll, "namespace", &target_namespace);
01569 if (target_name == NULL || target_namespace == NULL ||
01570 strcmp (target_name, "All Media") == 0) {
01571 return;
01572 }
01573
01574 target_nsid = xmms_collection_get_namespace_id (target_namespace);
01575 if (target_nsid == XMMS_COLLECTION_NSID_INVALID) {
01576 return;
01577 }
01578
01579 target = xmms_collection_get_pointer (dag, target_name, target_nsid);
01580 if (target == NULL) {
01581 return;
01582 }
01583
01584 xmmsv_coll_add_operand (coll, target);
01585 }
01586 }
01587
01588
01589
01590
01591
01592
01593 static void
01594 rebind_references (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, void *udata)
01595 {
01596 if (xmmsv_coll_get_type (coll) == XMMS_COLLECTION_TYPE_REFERENCE) {
01597 coll_rebind_infos_t *infos;
01598
01599 gchar *target_name = NULL;
01600 gchar *target_namespace = NULL;
01601
01602 infos = (coll_rebind_infos_t*)udata;
01603
01604
01605
01606 xmmsv_coll_attribute_get (coll, "reference", &target_name);
01607 xmmsv_coll_attribute_get (coll, "namespace", &target_namespace);
01608 if (strcmp (infos->name, target_name) != 0 ||
01609 strcmp (infos->namespace, target_namespace) != 0) {
01610 return;
01611 }
01612
01613 xmmsv_coll_remove_operand (coll, infos->oldtarget);
01614 xmmsv_coll_add_operand (coll, infos->newtarget);
01615 }
01616 }
01617
01618
01619
01620
01621
01622 static void
01623 rename_references (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, void *udata)
01624 {
01625 if (xmmsv_coll_get_type (coll) == XMMS_COLLECTION_TYPE_REFERENCE) {
01626 coll_rename_infos_t *infos;
01627
01628 gchar *target_name = NULL;
01629 gchar *target_namespace = NULL;
01630
01631 infos = (coll_rename_infos_t*)udata;
01632
01633 xmmsv_coll_attribute_get (coll, "reference", &target_name);
01634 xmmsv_coll_attribute_get (coll, "namespace", &target_namespace);
01635 if (strcmp (infos->oldname, target_name) == 0 &&
01636 strcmp (infos->namespace, target_namespace) == 0) {
01637 xmmsv_coll_attribute_set (coll, "reference", infos->newname);
01638 }
01639 }
01640 }
01641
01642
01643
01644
01645
01646 static void
01647 strip_references (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, void *udata)
01648 {
01649 xmmsv_coll_t *op;
01650 coll_rebind_infos_t *infos;
01651 gchar *target_name = NULL;
01652 gchar *target_namespace = NULL;
01653 xmmsv_list_iter_t *iter;
01654 xmmsv_t *tmp;
01655
01656 infos = (coll_rebind_infos_t*)udata;
01657
01658 xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &iter);
01659 for (xmmsv_list_iter_first (iter);
01660 xmmsv_list_iter_valid (iter);
01661 xmmsv_list_iter_next (iter)) {
01662
01663 xmmsv_list_iter_entry (iter, &tmp);
01664 xmmsv_get_coll (tmp, &op);
01665
01666
01667 if (xmmsv_coll_get_type (op) != XMMS_COLLECTION_TYPE_REFERENCE) {
01668 continue;
01669 }
01670
01671 xmmsv_coll_attribute_get (op, "reference", &target_name);
01672 xmmsv_coll_attribute_get (op, "namespace", &target_namespace);
01673 if (strcmp (infos->name, target_name) != 0 ||
01674 strcmp (infos->namespace, target_namespace) != 0) {
01675 continue;
01676 }
01677
01678
01679
01680 xmmsv_list_clear (xmmsv_coll_operands_get (op));
01681
01682 xmmsv_list_iter_remove (iter);
01683
01684 tmp = xmmsv_new_coll (infos->oldtarget);
01685 xmmsv_list_iter_insert (iter, tmp);
01686 xmmsv_unref (tmp);
01687 }
01688 xmmsv_list_iter_explicit_destroy (iter);
01689 }
01690
01691
01692
01693
01694
01695 static void
01696 check_for_reference (xmms_coll_dag_t *dag, xmmsv_coll_t *coll, xmmsv_coll_t *parent, void *udata)
01697 {
01698 coll_refcheck_t *check = (coll_refcheck_t*)udata;
01699 if (xmmsv_coll_get_type (coll) == XMMS_COLLECTION_TYPE_REFERENCE && !check->found) {
01700 gchar *target_name, *target_namespace;
01701
01702 xmmsv_coll_attribute_get (coll, "reference", &target_name);
01703 xmmsv_coll_attribute_get (coll, "namespace", &target_namespace);
01704 if (strcmp (check->target_name, target_name) == 0 &&
01705 strcmp (check->target_namespace, target_namespace) == 0) {
01706 check->found = TRUE;
01707 } else {
01708 xmmsv_coll_t *op;
01709 xmmsv_t *tmp;
01710
01711 if (xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &tmp)) {
01712 xmmsv_get_coll (tmp, &op);
01713 xmms_collection_apply_to_collection_recurs (dag, op, coll,
01714 check_for_reference,
01715 udata);
01716 }
01717 }
01718 }
01719 }
01720
01721
01722
01723
01724
01725
01726 static void
01727 coll_unref (void *coll)
01728 {
01729 xmmsv_coll_unref (coll);
01730 }
01731
01732
01733
01734
01735
01736
01737 static void
01738 build_match_table (gpointer key, gpointer value, gpointer udata)
01739 {
01740 GHashTable *match_table = udata;
01741 coll_find_state_t *match = g_new (coll_find_state_t, 1);
01742 *match = XMMS_COLLECTION_FIND_STATE_UNCHECKED;
01743 g_hash_table_replace (match_table, g_strdup (key), match);
01744 }
01745
01746
01747
01748
01749 static gboolean
01750 find_unchecked (gpointer name, gpointer value, gpointer udata)
01751 {
01752 coll_find_state_t *match = value;
01753 gchar **open = udata;
01754 *open = name;
01755 return (*match == XMMS_COLLECTION_FIND_STATE_UNCHECKED);
01756 }
01757
01758
01759
01760
01761 static void
01762 build_list_matches (gpointer key, gpointer value, gpointer udata)
01763 {
01764 gchar *coll_name = key;
01765 coll_find_state_t *state = value;
01766 GList **list = udata;
01767 if (*state == XMMS_COLLECTION_FIND_STATE_MATCH) {
01768 *list = g_list_prepend (*list, xmmsv_new_string (coll_name));
01769 }
01770 }
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781 static gboolean
01782 xmms_collection_media_match (xmms_coll_dag_t *dag, GHashTable *mediainfo,
01783 xmmsv_coll_t *coll, guint nsid,
01784 GHashTable *match_table)
01785 {
01786 gboolean match = FALSE;
01787 xmmsv_coll_t *op;
01788 gchar *attr1 = NULL, *attr2 = NULL;
01789 xmmsv_t *val;
01790 guint32 *idlist;
01791 gint i;
01792 gint id;
01793 xmmsv_list_iter_t *iter;
01794
01795 switch (xmmsv_coll_get_type (coll)) {
01796 case XMMS_COLLECTION_TYPE_REFERENCE:
01797 if (xmmsv_coll_attribute_get (coll, "reference", &attr1)) {
01798 if (strcmp (attr1, "All Media") == 0) {
01799 match = TRUE;
01800 } else if (xmmsv_coll_attribute_get (coll, "namespace", &attr2)) {
01801 match = xmms_collection_media_match_reference (dag, mediainfo,
01802 coll, nsid,
01803 match_table,
01804 attr1, attr2);
01805 }
01806 }
01807 break;
01808
01809 case XMMS_COLLECTION_TYPE_UNION:
01810
01811 xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &iter);
01812
01813 for (xmmsv_list_iter_first (iter);
01814 !match && xmmsv_list_iter_valid (iter);
01815 xmmsv_list_iter_next (iter)) {
01816
01817 xmmsv_list_iter_entry (iter, &val);
01818 xmmsv_get_coll (val, &op);
01819
01820 match = xmms_collection_media_match (dag, mediainfo, op,
01821 nsid, match_table);
01822 }
01823 xmmsv_list_iter_explicit_destroy (iter);
01824 break;
01825
01826 case XMMS_COLLECTION_TYPE_INTERSECTION:
01827
01828 match = TRUE;
01829 xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &iter);
01830
01831 for (xmmsv_list_iter_first (iter);
01832 match && xmmsv_list_iter_valid (iter);
01833 xmmsv_list_iter_next (iter)) {
01834
01835 xmmsv_list_iter_entry (iter, &val);
01836 xmmsv_get_coll (val, &op);
01837
01838 match = xmms_collection_media_match (dag, mediainfo, op,
01839 nsid, match_table);
01840 }
01841 xmmsv_list_iter_explicit_destroy (iter);
01842 break;
01843
01844 case XMMS_COLLECTION_TYPE_COMPLEMENT:
01845
01846 match = !xmms_collection_media_match_operand (dag, mediainfo, coll,
01847 nsid, match_table);
01848 break;
01849
01850 case XMMS_COLLECTION_TYPE_HAS:
01851 match = xmms_collection_media_filter_has (dag, mediainfo, coll,
01852 nsid, match_table);
01853 break;
01854
01855 case XMMS_COLLECTION_TYPE_EQUALS:
01856 match = xmms_collection_media_filter_equals (dag, mediainfo, coll,
01857 nsid, match_table);
01858 break;
01859
01860 case XMMS_COLLECTION_TYPE_MATCH:
01861 match = xmms_collection_media_filter_match (dag, mediainfo, coll,
01862 nsid, match_table);
01863 break;
01864
01865 case XMMS_COLLECTION_TYPE_SMALLER:
01866 match = xmms_collection_media_filter_smaller (dag, mediainfo, coll,
01867 nsid, match_table);
01868 break;
01869
01870 case XMMS_COLLECTION_TYPE_GREATER:
01871 match = xmms_collection_media_filter_greater (dag, mediainfo, coll,
01872 nsid, match_table);
01873 break;
01874
01875 case XMMS_COLLECTION_TYPE_IDLIST:
01876 case XMMS_COLLECTION_TYPE_QUEUE:
01877 case XMMS_COLLECTION_TYPE_PARTYSHUFFLE:
01878
01879 val = g_hash_table_lookup (mediainfo, "id");
01880 if (val != NULL) {
01881 xmmsv_get_int (val, &id);
01882 idlist = xmmsv_coll_get_idlist (coll);
01883 for (i = 0; idlist[i] != 0; i++) {
01884
01885 if (idlist[i] == id) {
01886 match = TRUE;
01887 break;
01888 }
01889 }
01890 }
01891 break;
01892
01893
01894 default:
01895 XMMS_DBG ("invalid collection operator in xmms_collection_media_match");
01896 g_assert_not_reached ();
01897 break;
01898 }
01899
01900 return match;
01901 }
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914 static gboolean
01915 xmms_collection_media_match_reference (xmms_coll_dag_t *dag, GHashTable *mediainfo,
01916 xmmsv_coll_t *coll, guint nsid,
01917 GHashTable *match_table,
01918 const gchar *refname, const gchar *refns)
01919 {
01920 gboolean match;
01921 guint refnsid;
01922 coll_find_state_t *matchstate;
01923
01924
01925 refnsid = xmms_collection_get_namespace_id (refns);
01926 if (refnsid == nsid) {
01927 matchstate = g_hash_table_lookup (match_table, refname);
01928 if (*matchstate == XMMS_COLLECTION_FIND_STATE_UNCHECKED) {
01929
01930 matchstate = g_new (coll_find_state_t, 1);
01931 match = xmms_collection_media_match_operand (dag,
01932 mediainfo,
01933 coll, nsid,
01934 match_table);
01935
01936 if (match) {
01937 *matchstate = XMMS_COLLECTION_FIND_STATE_MATCH;
01938 } else {
01939 *matchstate = XMMS_COLLECTION_FIND_STATE_NOMATCH;
01940 }
01941
01942 g_hash_table_replace (match_table, g_strdup (refname), matchstate);
01943
01944 } else {
01945 match = (*matchstate == XMMS_COLLECTION_FIND_STATE_MATCH);
01946 }
01947
01948
01949 } else {
01950 match = xmms_collection_media_match_operand (dag, mediainfo, coll,
01951 nsid, match_table);
01952 }
01953
01954 return match;
01955 }
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967 static gboolean
01968 xmms_collection_media_match_operand (xmms_coll_dag_t *dag, GHashTable *mediainfo,
01969 xmmsv_coll_t *coll, guint nsid,
01970 GHashTable *match_table)
01971 {
01972 xmmsv_coll_t *op;
01973 xmmsv_t *tmp;
01974 gboolean match = FALSE;
01975
01976 if (xmmsv_list_get (xmmsv_coll_operands_get (coll), 0, &tmp)) {
01977 xmmsv_get_coll (tmp, &op);
01978
01979 match = xmms_collection_media_match (dag, mediainfo, op, nsid, match_table);
01980 }
01981
01982 return match;
01983 }
01984
01985
01986
01987
01988
01989
01990 static GHashTable *
01991 xmms_collection_media_info (guint mid, xmms_error_t *err)
01992 {
01993 GList *res;
01994 GList *n;
01995 GHashTable *infos;
01996 gchar *name;
01997 const gchar *buf;
01998 xmmsv_t *cmdval;
01999 xmmsv_t *value;
02000 guint state;
02001
02002
02003 res = xmms_medialib_info_list (NULL, mid, err);
02004
02005
02006 infos = g_hash_table_new_full (g_str_hash, g_str_equal,
02007 g_free, (GDestroyNotify) xmmsv_unref);
02008 for (state = 0, n = res; n; state = (state + 1) % 3, n = n->next) {
02009 switch (state) {
02010 case 0:
02011 break;
02012
02013 case 1:
02014 cmdval = n->data;
02015 xmmsv_get_string (cmdval, &buf);
02016 name = g_strdup (buf);
02017 break;
02018
02019 case 2:
02020 value = xmmsv_ref (n->data);
02021
02022
02023 if (g_hash_table_lookup (infos, name) == NULL) {
02024 g_hash_table_replace (infos, name, value);
02025 }
02026 break;
02027 }
02028
02029 xmmsv_unref (n->data);
02030 }
02031
02032 g_list_free (res);
02033
02034 return infos;
02035 }
02036
02037
02038
02039
02040
02041
02042 static gboolean
02043 filter_get_mediainfo_field_string (xmmsv_coll_t *coll,
02044 GHashTable *mediainfo, gchar **val)
02045 {
02046 gboolean retval = FALSE;
02047 gchar *attr;
02048 xmmsv_t *cmdval;
02049
02050 if (xmmsv_coll_attribute_get (coll, "field", &attr)) {
02051 cmdval = g_hash_table_lookup (mediainfo, attr);
02052 if (cmdval != NULL) {
02053 switch (xmmsv_get_type (cmdval)) {
02054 case XMMSV_TYPE_STRING:
02055 {
02056 const gchar *s;
02057 xmmsv_get_string (cmdval, &s);
02058 *val = g_strdup (s);
02059 retval = TRUE;
02060 break;
02061 }
02062 case XMMSV_TYPE_INT32:
02063 {
02064 gint i;
02065 xmmsv_get_int (cmdval, &i);
02066 *val = g_strdup_printf ("%d", i);
02067 retval = TRUE;
02068 break;
02069 }
02070 default:
02071 break;
02072 }
02073 }
02074 }
02075
02076 return retval;
02077 }
02078
02079
02080
02081
02082
02083
02084 static gboolean
02085 filter_get_mediainfo_field_int (xmmsv_coll_t *coll, GHashTable *mediainfo, gint *val)
02086 {
02087 gboolean retval = FALSE;
02088 gchar *attr;
02089 xmmsv_t *cmdval;
02090
02091 if (xmmsv_coll_attribute_get (coll, "field", &attr)) {
02092 cmdval = g_hash_table_lookup (mediainfo, attr);
02093 if (cmdval != NULL && xmmsv_get_type (cmdval) == XMMSV_TYPE_INT32) {
02094 xmmsv_get_int (cmdval, val);
02095 retval = TRUE;
02096 }
02097 }
02098
02099 return retval;
02100 }
02101
02102
02103 static gboolean
02104 filter_get_operator_value_string (xmmsv_coll_t *coll, const gchar **val)
02105 {
02106 gchar *attr;
02107 gboolean valid;
02108
02109 valid = xmmsv_coll_attribute_get (coll, "value", &attr);
02110 if (valid) {
02111 *val = attr;
02112 }
02113
02114 return valid;
02115 }
02116
02117
02118 static gboolean
02119 filter_get_operator_value_int (xmmsv_coll_t *coll, gint *val)
02120 {
02121 gint buf;
02122 gboolean valid;
02123
02124 valid = xmms_collection_get_int_attr (coll, "value", &buf);
02125 if (valid) {
02126 *val = buf;
02127 }
02128
02129 return valid;
02130 }
02131
02132
02133
02134 static gboolean
02135 filter_get_operator_case (xmmsv_coll_t *coll, gboolean *val)
02136 {
02137 gchar *attr;
02138
02139 if (xmmsv_coll_attribute_get (coll, "case-sensitive", &attr)) {
02140 *val = (strcmp (attr, "true") == 0);
02141 }
02142 else {
02143 *val = FALSE;
02144 }
02145
02146 return TRUE;
02147 }
02148
02149
02150 static gboolean
02151 xmms_collection_media_filter_has (xmms_coll_dag_t *dag, GHashTable *mediainfo,
02152 xmmsv_coll_t *coll, guint nsid,
02153 GHashTable *match_table)
02154 {
02155 gboolean match = FALSE;
02156 gchar *mediaval;
02157
02158
02159 if (filter_get_mediainfo_field_string (coll, mediainfo, &mediaval)) {
02160 match = xmms_collection_media_match_operand (dag, mediainfo, coll,
02161 nsid, match_table);
02162
02163 g_free (mediaval);
02164 }
02165
02166 return match;
02167 }
02168
02169
02170 static gboolean
02171 xmms_collection_media_filter_equals (xmms_coll_dag_t *dag, GHashTable *mediainfo,
02172 xmmsv_coll_t *coll, guint nsid,
02173 GHashTable *match_table)
02174 {
02175 gboolean match = FALSE;
02176 gchar *mediaval = NULL;
02177 const gchar *opval;
02178 gboolean case_sens;
02179
02180 if (filter_get_mediainfo_field_string (coll, mediainfo, &mediaval) &&
02181 filter_get_operator_value_string (coll, &opval) &&
02182 filter_get_operator_case (coll, &case_sens)) {
02183
02184 if (case_sens) {
02185 match = (strcmp (mediaval, opval) == 0);
02186 } else {
02187 match = (g_ascii_strcasecmp (mediaval, opval) == 0);
02188 }
02189 }
02190
02191
02192 if (match) {
02193 match = xmms_collection_media_match_operand (dag, mediainfo, coll,
02194 nsid, match_table);
02195 }
02196
02197 if (mediaval != NULL) {
02198 g_free (mediaval);
02199 }
02200
02201 return match;
02202 }
02203
02204
02205 static gboolean
02206 xmms_collection_media_filter_match (xmms_coll_dag_t *dag, GHashTable *mediainfo,
02207 xmmsv_coll_t *coll, guint nsid,
02208 GHashTable *match_table)
02209 {
02210 gboolean match = FALSE;
02211 gchar *buf, *opval, *mediaval;
02212 const gchar *s;
02213 gboolean case_sens;
02214
02215 if (filter_get_mediainfo_field_string (coll, mediainfo, &buf) &&
02216 filter_get_operator_value_string (coll, &s) &&
02217 filter_get_operator_case (coll, &case_sens)) {
02218
02219
02220 if (case_sens) {
02221 opval = g_strdup (s);
02222 mediaval = g_strdup (buf);
02223 } else {
02224 opval = g_utf8_strdown (s, -1);
02225 mediaval = g_utf8_strdown (buf, -1);
02226 }
02227
02228 match = g_pattern_match_simple (opval, mediaval);
02229
02230 g_free (buf);
02231 g_free (opval);
02232 g_free (mediaval);
02233
02234
02235 if (match) {
02236 match = xmms_collection_media_match_operand (dag, mediainfo, coll,
02237 nsid, match_table);
02238 }
02239 }
02240
02241 return match;
02242 }
02243
02244
02245 static gboolean
02246 xmms_collection_media_filter_smaller (xmms_coll_dag_t *dag, GHashTable *mediainfo,
02247 xmmsv_coll_t *coll, guint nsid,
02248 GHashTable *match_table)
02249 {
02250 gboolean match = FALSE;
02251 gint mediaval;
02252 gint opval;
02253
02254
02255 if (filter_get_mediainfo_field_int (coll, mediainfo, &mediaval) &&
02256 filter_get_operator_value_int (coll, &opval) &&
02257 (mediaval < opval) ) {
02258
02259 match = xmms_collection_media_match_operand (dag, mediainfo, coll,
02260 nsid, match_table);
02261 }
02262
02263 return match;
02264 }
02265
02266
02267 static gboolean
02268 xmms_collection_media_filter_greater (xmms_coll_dag_t *dag, GHashTable *mediainfo,
02269 xmmsv_coll_t *coll, guint nsid,
02270 GHashTable *match_table)
02271 {
02272 gboolean match = FALSE;
02273 gint mediaval;
02274 gint opval;
02275
02276
02277 if (filter_get_mediainfo_field_int (coll, mediainfo, &mediaval) &&
02278 filter_get_operator_value_int (coll, &opval) &&
02279 (mediaval > opval) ) {
02280
02281 match = xmms_collection_media_match_operand (dag, mediainfo, coll,
02282 nsid, match_table);
02283 }
02284
02285 return match;
02286 }