Beispiel #1
0
/**
 * 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;
}
Beispiel #2
0
/**
 * 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;
}
Beispiel #3
0
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);
}
Beispiel #4
0
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;
}
Beispiel #5
0
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);
}
Beispiel #7
0
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
/**
 * 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);
}
Beispiel #12
0
/**
 * 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);
}
Beispiel #13
0
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);
}
Beispiel #14
0
/**
 * 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;
}
Beispiel #15
0
/**
 * 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;
}
Beispiel #16
0
/**
 * 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;
}
Beispiel #17
0
/**
 * 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);
}
Beispiel #18
0
/**
 * 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;
}
Beispiel #19
0
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;
}
Beispiel #20
0
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;

}
Beispiel #21
0
/**
 * 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);
}
Beispiel #22
0
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;
}
Beispiel #23
0
/**
 * 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;
}