/** * Return a collection with several order-operators added. * * @param coll the original collection * @param order list of ordering strings or dicts. * * @return coll with order-operators added */ xmmsv_t * xmmsv_coll_add_order_operators (xmmsv_t *coll, xmmsv_t *order) { xmmsv_list_iter_t *it; xmmsv_t *current, *value; x_api_error_if (coll == NULL, "with a NULL coll", NULL); xmmsv_ref (coll); if (!order) { return coll; } x_api_error_if (!xmmsv_is_type (order, XMMSV_TYPE_LIST), "with a non list order", coll); current = coll; xmmsv_get_list_iter (order, &it); xmmsv_list_iter_last (it); while (xmmsv_list_iter_entry (it, &value)) { xmmsv_t *ordered; ordered = xmmsv_coll_add_order_operator (current, value); xmmsv_unref (current); current = ordered; xmmsv_list_iter_prev (it); } return current; }
/** * Create a new argument for a method. * * @param name The name of the argument. Must not be NULL. * @param docstring The docstring of the argument. * @param type The expected type of the argument. Use XMMSV_TYPE_NONE to * accept any type. XMMSV_TYPE_ERROR is reserved and should not be used. * @param default_value Value to set this argument to if it's missing in the * method call. Implies that the argument is optional. If NULL, the argument * is not optional. */ xmmsv_t * xmmsv_sc_argument_new (const char *name, const char *docstring, xmmsv_type_t type, xmmsv_t *default_value) { xmmsv_t *arg; x_api_error_if (!name, "with NULL name.", NULL); x_api_error_if (type == XMMSV_TYPE_ERROR, "with ERROR type.", NULL); x_api_error_if (default_value && type != XMMSV_TYPE_NONE && xmmsv_get_type (default_value) != type, "with wrong type for default value.", NULL); arg = xmmsv_new_dict (); if (!arg) { x_oom (); return NULL; } xmmsv_dict_set_string (arg, "name", name); xmmsv_dict_set_int (arg, "type", type); if (docstring) { xmmsv_dict_set_string (arg, "docstring", docstring); } if (default_value) { xmmsv_dict_set (arg, "default_value", default_value); } return arg; }
xmmsc_connection_t * xmmsc_init (const char *clientname) { xmmsc_connection_t *c; int i = 0; char j; x_api_error_if (!clientname, "with NULL clientname", NULL); if (!(c = x_new0 (xmmsc_connection_t, 1))) { return NULL; } while (clientname[i]) { j = clientname[i]; if (!isalnum (j) && j != '_' && j != '-') { /* snyggt! */ free (c); x_api_error_if (true, "clientname contains invalid chars, just alphanumeric chars are allowed!", NULL); } i++; } if (!(c->clientname = strdup (clientname))) { free (c); return NULL; } c->visc = 0; c->visv = NULL; return xmmsc_ref (c); }
xmmsc_result_t * xmmsc_visualization_start (xmmsc_connection_t *c, int vv) { xmmsc_result_t *res; xmmsc_visualization_t *v; x_check_conn (c, 0); v = get_dataset (c, vv); x_api_error_if (!v, "with unregistered/unconnected visualization dataset", 0); switch (v->state) { case VIS_WORKING: case VIS_ERRORED: break; case VIS_NEW: #ifdef HAVE_SEMTIMEDOP /* first try unixshm */ v->type = VIS_UNIXSHM; res = setup_shm_prepare (c, vv); v->state = VIS_TRYING_UNIXSHM; break; #endif case VIS_TO_TRY_UDP: v->type = VIS_UDP; res = setup_udp_prepare (c, vv); v->state = VIS_TRYING_UDP; break; default: v->state = VIS_ERRORED; x_api_warning ("out of sequence"); break; } return res; }
bool setup_udp_handle (xmmsc_result_t *res) { bool ret; xmmsc_vis_udp_t *t; xmmsc_visualization_t *visc; visc = xmmsc_result_visc_get (res); if (!visc) { x_api_error_if (1, "non vis result?", -1); } t = &visc->transport.udp; if (!xmmsc_result_iserror (res)) { xmmsv_t *val; int port; val = xmmsc_result_get_value (res); xmmsv_get_int (val, &port); ret = setup_socket (xmmsc_result_get_connection (res), t, visc->id, port); } else { ret = false; } return ret; }
/** * List the ids of all media matched by the given collection. * A list of ordering properties can be specified, as well as offsets * to only retrieve part of the result set. * * @param conn The connection to the server. * @param coll The collection used to query. * @param order The list of properties to order by, passed as an #xmmsv_t list of strings. * @param limit_start The offset at which to start retrieving results (0 to disable). * @param limit_len The maximum number of entries to retrieve (0 to disable). */ xmmsc_result_t* xmmsc_coll_query_ids (xmmsc_connection_t *conn, xmmsv_coll_t *coll, xmmsv_t *order, int limit_start, int limit_len) { xmms_ipc_msg_t *msg; x_check_conn (conn, NULL); x_api_error_if (!coll, "with a NULL collection", NULL); /* default to empty ordering */ if (!order) { order = xmmsv_new_list (); } else { xmmsv_ref (order); } msg = xmms_ipc_msg_new (XMMS_IPC_OBJECT_COLLECTION, XMMS_IPC_CMD_QUERY_IDS); xmms_ipc_msg_put_collection (msg, coll); xmms_ipc_msg_put_int32 (msg, limit_start); xmms_ipc_msg_put_int32 (msg, limit_len); xmms_ipc_msg_put_value_list (msg, order); /* purposedly skip typing */ xmmsv_unref (order); return xmmsc_send_msg (conn, msg); }
bool setup_shm_handle (xmmsc_result_t *res) { bool ret; xmmsc_visualization_t *visc; xmmsc_vis_unixshm_t *t; visc = xmmsc_result_visc_get (res); if (!visc) { x_api_error_if (1, "non vis result?", -1); } t = &visc->transport.shm; if (!xmmsc_result_iserror (res)) { xmmsv_t *val; t->size = XMMS_VISPACKET_SHMCOUNT; t->pos = 0; val = xmmsc_result_get_value (res); xmmsv_get_int (val, &t->semid); ret = true; } else { /* didn't work, detach from shm to get it removed later on */ shmdt (t->buffer); ret = false; } /* In either case, mark the shared memory segment to be destroyed. The segment will only actually be destroyed after the last process detaches it. */ shmctl (t->shmid, IPC_RMID, NULL); return ret; }
static xmmsv_t * xmmsv_coll_normalize_order_arguments (xmmsv_t *value) { xmmsv_t *order; const char *key; if (value == NULL) { return NULL; } if (xmmsv_is_type (value, XMMSV_TYPE_DICT)) { return xmmsv_ref (value); } x_api_error_if (!xmmsv_get_string (value, &key), "order entry must be string or dict", NULL); order = xmmsv_new_dict (); if (key[0] == '-') { xmmsv_dict_set_string (order, "direction", "DESC"); key++; } if (strcmp (key, "random") == 0) { xmmsv_dict_set_string (order, "type", "random"); } else if (strcmp (key, "id") == 0) { xmmsv_dict_set_string (order, "type", "id"); } else { xmmsv_dict_set_string (order, "type", "value"); xmmsv_dict_set_string (order, "field", key); } return order; }
/** * Check if collection is of specified type. * * @param val #xmmsv_t to check. * @param t #xmmsv_coll_type_t to check for. * @return 1 if value is of specified type, 0 otherwise. */ int xmmsv_coll_is_type (xmmsv_t *val, xmmsv_coll_type_t t) { x_api_error_if (!val, "NULL value", 0); return (xmmsv_coll_get_type (val) == t); }
/** * Save a collection structure on the server under the given name, in * the given namespace. * * @param conn The connection to the server. * @param coll The collection structure to save. * @param name The name under which to save the collection. * @param ns The namespace in which to save the collection. */ xmmsc_result_t* xmmsc_coll_save (xmmsc_connection_t *conn, xmmsv_coll_t *coll, const char* name, xmmsv_coll_namespace_t ns) { xmms_ipc_msg_t *msg; x_check_conn (conn, NULL); x_api_error_if (!coll, "with a NULL collection", NULL); x_api_error_if (!name, "with a NULL name", NULL); msg = xmms_ipc_msg_new (XMMS_IPC_OBJECT_COLLECTION, XMMS_IPC_CMD_COLLECTION_SAVE); xmms_ipc_msg_put_string (msg, name); xmms_ipc_msg_put_string (msg, ns); xmms_ipc_msg_put_collection (msg, coll); return xmmsc_send_msg (conn, msg); }
/** * Rename a saved collection. * * @param conn The connection to the server. * @param from_name The name of the collection to rename. * @param to_name The new name of the collection. * @param ns The namespace containing the collection. */ xmmsc_result_t* xmmsc_coll_rename (xmmsc_connection_t *conn, const char* from_name, const char* to_name, xmmsv_coll_namespace_t ns) { xmms_ipc_msg_t *msg; x_check_conn (conn, NULL); x_api_error_if (!from_name, "with a NULL from_name", NULL); x_api_error_if (!to_name, "with a NULL to_name", NULL); msg = xmms_ipc_msg_new (XMMS_IPC_OBJECT_COLLECTION, XMMS_IPC_CMD_COLLECTION_RENAME); xmms_ipc_msg_put_string (msg, from_name); xmms_ipc_msg_put_string (msg, to_name); xmms_ipc_msg_put_string (msg, ns); return xmmsc_send_msg (conn, msg); }
/** * Browse available media in a (already encoded) path. * * Retrieves a list of paths available (directly) under the specified * path. * */ xmmsc_result_t * xmmsc_xform_media_browse_encoded (xmmsc_connection_t *c, const char *url) { x_check_conn (c, NULL); x_api_error_if (!url, "with a NULL url", NULL); if (!_xmmsc_medialib_verify_url (url)) x_api_error ("with a non encoded url", NULL); return xmmsc_send_cmd (c, XMMS_IPC_OBJECT_XFORM, XMMS_IPC_CMD_BROWSE, XMMSV_LIST_ENTRY_STR (url), XMMSV_LIST_END); }
xmmsc_result_t * xmmsc_playback_volume_set (xmmsc_connection_t *c, const char *channel, int volume) { x_check_conn (c, NULL); x_api_error_if (!channel, "with a NULL channel", NULL); return xmmsc_send_cmd (c, XMMS_IPC_OBJECT_PLAYBACK, XMMS_IPC_CMD_VOLUME_SET, XMMSV_LIST_ENTRY_STR (channel), XMMSV_LIST_ENTRY_INT (volume), XMMSV_LIST_END); }
/** * Create a new empty playlist. */ xmmsc_result_t * xmmsc_playlist_create (xmmsc_connection_t *c, const char *playlist) { xmmsc_result_t *res; xmmsv_coll_t *plcoll; x_check_conn (c, NULL); x_api_error_if (!playlist, "playlist name cannot be NULL", NULL); plcoll = xmmsv_coll_new (XMMS_COLLECTION_TYPE_IDLIST); res = xmmsc_coll_save (c, plcoll, playlist, XMMS_COLLECTION_NS_PLAYLISTS); xmmsv_coll_unref (plcoll); return res; }
/** * Insert entry at given position in playlist with args. * * @param c The connection structure. * @param playlist The playlist in which to insert the media. * @param pos A position in the playlist * @param url The URL to insert * @param numargs The number of arguments * @param args array of numargs strings used as arguments */ xmmsc_result_t * xmmsc_playlist_insert_args (xmmsc_connection_t *c, const char *playlist, int pos, const char *url, int numargs, const char **args) { xmmsc_result_t *res; char *enc_url; x_check_conn (c, NULL); x_api_error_if (!url, "with a NULL url", NULL); enc_url = _xmmsc_medialib_encode_url_old (url, numargs, args); if (!enc_url) return NULL; res = xmmsc_playlist_insert_encoded (c, playlist, pos, enc_url); free (enc_url); return res; }
/** * Add the url to the playlist with arguments. * * @param c The connection structure. * @param playlist The playlist in which to add the media. * @param url path. * @param nargs The number of arguments * @param args array of numargs strings used as arguments */ xmmsc_result_t * xmmsc_playlist_add_full (xmmsc_connection_t *c, const char *playlist, const char *url, xmmsv_t *args) { xmmsc_result_t *res; char *enc_url; x_check_conn (c, NULL); x_api_error_if (!url, "with a NULL url", NULL); enc_url = _xmmsc_medialib_encode_url (url, args); if (!enc_url) return NULL; res = xmmsc_playlist_add_encoded (c, playlist, enc_url); free (enc_url); return res; }
/** * Sorts the playlist according to the list of properties * (#xmmsv_t containing a list of strings). */ xmmsc_result_t * xmmsc_playlist_sort (xmmsc_connection_t *c, const char *playlist, xmmsv_t *properties) { xmms_ipc_msg_t *msg; x_check_conn (c, NULL); x_api_error_if (!properties, "with a NULL property", NULL); /* default to the active playlist */ if (playlist == NULL) { playlist = XMMS_ACTIVE_PLAYLIST; } msg = xmms_ipc_msg_new (XMMS_IPC_OBJECT_PLAYLIST, XMMS_IPC_CMD_SORT); xmms_ipc_msg_put_string (msg, playlist); xmms_ipc_msg_put_value_list (msg, properties); /* purposedly skip typing */ return xmmsc_send_msg (c, msg); }
/** * Browse available media in a path. * * Retrieves a list of paths available (directly) under the specified * path. * */ xmmsc_result_t * xmmsc_xform_media_browse (xmmsc_connection_t *c, const char *url) { char *enc_url; xmmsc_result_t *res; x_check_conn (c, NULL); x_api_error_if (!url, "with a NULL url", NULL); enc_url = xmmsv_encode_url (url); if (!enc_url) return NULL; res = xmmsc_xform_media_browse_encoded (c, enc_url); free (enc_url); return res; }
char * _xmmsc_medialib_encode_url_old (const char *url, int narg, const char **args) { static const char hex[16] = "0123456789abcdef"; int i = 0, j = 0, extra = 0; char *res; x_api_error_if (!url, "with a NULL url", NULL); for (i = 0; i < narg; i++) { extra += strlen (args[i]) + 2; } res = malloc (strlen (url) * 3 + 1 + extra); if (!res) return NULL; for (i = 0; url[i]; i++) { unsigned char chr = url[i]; if (GOODCHAR (chr)) { res[j++] = chr; } else if (chr == ' ') { res[j++] = '+'; } else { res[j++] = '%'; res[j++] = hex[((chr & 0xf0) >> 4)]; res[j++] = hex[(chr & 0x0f)]; } } for (i = 0; i < narg; i++) { int l; l = strlen (args[i]); res[j] = (i == 0) ? '?' : '&'; j++; memcpy (&res[j], args[i], l); j += l; } res[j] = '\0'; return res; }
int xmmsc_visualization_init_handle (xmmsc_result_t *res) { xmmsc_visualization_t *visc; xmmsv_t *val; if (xmmsc_result_iserror (res)) { return -1; } visc = xmmsc_result_visc_get (res); if (!visc) { x_api_error_if (1, "non vis result?", -1); } val = xmmsc_result_get_value (res); xmmsv_get_int (val, &visc->id); visc->type = VIS_NONE; return visc->idx; }
/** * Add the url to the playlist. The url should be absolute to the * server-side AND encoded. * * @param c The connection structure. * @param playlist The playlist in which to add the media. * @param url path. * */ xmmsc_result_t * xmmsc_playlist_add_encoded (xmmsc_connection_t *c, const char *playlist, const char *url) { xmms_ipc_msg_t *msg; x_check_conn (c, NULL); x_api_error_if (!url, "with a NULL url", NULL); if (!_xmmsc_medialib_verify_url (url)) x_api_error ("with a non encoded url", NULL); /* default to the active playlist */ if (playlist == NULL) { playlist = XMMS_ACTIVE_PLAYLIST; } msg = xmms_ipc_msg_new (XMMS_IPC_OBJECT_PLAYLIST, XMMS_IPC_CMD_ADD_URL); xmms_ipc_msg_put_string (msg, playlist); xmms_ipc_msg_put_string (msg, url); return xmmsc_send_msg (c, msg); }
int xmmsc_connect (xmmsc_connection_t *c, const char *ipcpath) { xmmsc_ipc_t *ipc; xmmsc_result_t *result; xmmsv_t *value; const char *buf; x_api_error_if (!c, "with a NULL connection", false); if (!ipcpath) { if (!xmms_default_ipcpath_get (c->path, sizeof (c->path))) { return false; } } else { snprintf (c->path, sizeof (c->path), "%s", ipcpath); } ipc = xmmsc_ipc_init (); if (!xmmsc_ipc_connect (ipc, c->path)) { c->error = strdup ("xmms2d is not running."); xmmsc_ipc_destroy (ipc); return false; } c->ipc = ipc; result = xmmsc_send_hello (c); xmmsc_result_wait (result); value = xmmsc_result_get_value (result); if (xmmsv_is_error (value)) { xmmsv_get_error (value, &buf); c->error = strdup (buf); xmmsc_result_unref (result); return false; } xmmsc_result_unref (result); return true; }
/** * Encodes an url with arguments stored in dict args. * * The encoded url is allocated using malloc and has to be freed by the user. * * @param url The url to encode. * @param args The dict with arguments, or NULL. * @return The encoded url */ char * xmmsc_medialib_encode_url_full (const char *url, xmmsv_t *args) { static const char hex[16] = "0123456789abcdef"; int i = 0, j = 0, extra = 0, l; char *res; xmmsv_dict_iter_t *it; x_api_error_if (!url, "with a NULL url", NULL); if (args) { if (!xmmsv_dict_foreach (args, _sum_len_string_dict, (void *) &extra)) { return NULL; } } /* Provide enough room for the worst-case scenario (all characters of the URL must be encoded), the args, and a \0. */ res = malloc (strlen (url) * 3 + 1 + extra); if (!res) { return NULL; } for (i = 0; url[i]; i++) { unsigned char chr = url[i]; if (GOODCHAR (chr)) { res[j++] = chr; } else if (chr == ' ') { res[j++] = '+'; } else { res[j++] = '%'; res[j++] = hex[((chr & 0xf0) >> 4)]; res[j++] = hex[(chr & 0x0f)]; } } if (args) { for (xmmsv_get_dict_iter (args, &it), i = 0; xmmsv_dict_iter_valid (it); xmmsv_dict_iter_next (it), i++) { const char *arg, *key; xmmsv_t *val; xmmsv_dict_iter_pair (it, &key, &val); l = strlen (key); res[j] = (i == 0) ? '?' : '&'; j++; memcpy (&res[j], key, l); j += l; if (xmmsv_get_string (val, &arg)) { l = strlen (arg); res[j] = '='; j++; memcpy (&res[j], arg, l); j += l; } } } res[j] = '\0'; return res; }