diff src/libaudacious/beepctrl.c @ 2313:3149d4b1a9a9 trunk

[svn] - objective-make autodepend fixes - move all sourcecode into src/ and adjust Makefiles accordingly
author nenolod
date Fri, 12 Jan 2007 11:43:40 -0800
parents
children f24ae4f40e29
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libaudacious/beepctrl.c	Fri Jan 12 11:43:40 2007 -0800
@@ -0,0 +1,1703 @@
+/*  Audacious
+ *  Copyright (C) 2005-2007  Audacious team
+ *
+ *  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2003  Peter Alm, Mikael Alm, Olle Hallnas,
+ *                           Thomas Nilsson and 4Front Technologies
+ *  Copyright (C) 1999-2003  Haavard Kvaalen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "beepctrl.h"
+#include "audacious/controlsocket.h"
+#include "libaudacious/configdb.h"
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <grp.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+
+/* overrides audacious_get_session_uri(). */
+gchar *audacious_session_uri = NULL;
+gint  audacious_session_type = 0;
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+static gpointer
+remote_read_packet(gint fd)
+{
+    gpointer data = NULL;
+    ServerPktHeader pkt_hdr = { 0, 0 };
+
+    if (read(fd, &pkt_hdr, sizeof(ServerPktHeader)) ==
+        sizeof(ServerPktHeader))
+    {
+        if (pkt_hdr.version == XMMS_PROTOCOL_VERSION && 
+		pkt_hdr.data_length > 0)
+        {
+            size_t data_length = pkt_hdr.data_length;
+            data = g_malloc0(data_length);
+            if ((size_t)read(fd, data, data_length) < data_length)
+            {
+                g_free(data);
+                data = NULL;
+            }
+        }
+    }
+
+    return data;
+}
+
+static void
+remote_read_ack(gint fd)
+{
+    gpointer data;
+
+    data = remote_read_packet(fd);
+    if (data)
+        g_free(data);
+
+}
+
+static void
+remote_send_packet(gint fd, guint32 command, gpointer data,
+                   guint32 data_length)
+{
+    ClientPktHeader pkt_hdr;
+
+    memset(&pkt_hdr, '\0', sizeof(ClientPktHeader));
+
+    pkt_hdr.version = XMMS_PROTOCOL_VERSION;
+    pkt_hdr.command = command;
+    pkt_hdr.data_length = data_length;
+    if ((size_t)write(fd, &pkt_hdr, sizeof(ClientPktHeader)) < sizeof(pkt_hdr))
+        return;
+    if (data_length && data)
+        write(fd, data, data_length);
+}
+
+static void
+remote_send_guint32(gint session, guint32 cmd, guint32 val)
+{
+    gint fd;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    remote_send_packet(fd, cmd, &val, sizeof(guint32));
+    remote_read_ack(fd);
+    close(fd);
+}
+
+static void
+remote_send_boolean(gint session, guint32 cmd, gboolean val)
+{
+    gint fd;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    remote_send_packet(fd, cmd, &val, sizeof(gboolean));
+    remote_read_ack(fd);
+    close(fd);
+}
+
+static void
+remote_send_gfloat(gint session, guint32 cmd, gfloat value)
+{
+    gint fd;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    remote_send_packet(fd, cmd, &value, sizeof(gfloat));
+    remote_read_ack(fd);
+    close(fd);
+}
+
+static void
+remote_send_string(gint session, guint32 cmd, gchar * string)
+{
+    gint fd;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    remote_send_packet(fd, cmd, string, string ? strlen(string) + 1 : 0);
+    remote_read_ack(fd);
+    close(fd);
+}
+
+static gboolean
+remote_cmd(gint session, guint32 cmd)
+{
+    gint fd;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return FALSE;
+    remote_send_packet(fd, cmd, NULL, 0);
+    remote_read_ack(fd);
+    close(fd);
+
+    return TRUE;
+}
+
+static gboolean
+remote_get_gboolean(gint session, gint cmd)
+{
+    gboolean ret = FALSE;
+    gpointer data;
+    gint fd;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return ret;
+    remote_send_packet(fd, cmd, NULL, 0);
+    data = remote_read_packet(fd);
+    if (data) {
+        ret = *((gboolean *) data);
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+
+    return ret;
+}
+
+static guint32
+remote_get_gint(gint session, gint cmd)
+{
+    gpointer data;
+    gint fd, ret = 0;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return ret;
+    remote_send_packet(fd, cmd, NULL, 0);
+    data = remote_read_packet(fd);
+    if (data) {
+        ret = *((gint *) data);
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+    return ret;
+}
+
+static gfloat
+remote_get_gfloat(gint session, gint cmd)
+{
+    gpointer data;
+    gint fd;
+    gfloat ret = 0.0;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return ret;
+    remote_send_packet(fd, cmd, NULL, 0);
+    data = remote_read_packet(fd);
+    if (data) {
+        ret = *((gfloat *) data);
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+    return ret;
+}
+
+gchar *
+remote_get_string(gint session, gint cmd)
+{
+    gpointer data;
+    gint fd;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return NULL;
+    remote_send_packet(fd, cmd, NULL, 0);
+    data = remote_read_packet(fd);
+    remote_read_ack(fd);
+    close(fd);
+    return data;
+}
+
+gchar *
+remote_get_string_pos(gint session, gint cmd, guint32 pos)
+{
+    gpointer data;
+    gint fd;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return NULL;
+    remote_send_packet(fd, cmd, &pos, sizeof(guint32));
+    data = remote_read_packet(fd);
+    remote_read_ack(fd);
+    close(fd);
+    return data;
+}
+
+/**
+ * audacious_set_session_uri:
+ * @uri: The session URI to set the client API to.
+ *
+ * Sets the Session URI where Audacious can be reached at.
+ **/
+void
+audacious_set_session_uri(gchar *uri)
+{
+    audacious_session_uri = uri;
+}
+
+/**
+ * audacious_get_session_uri:
+ * @session: Legacy XMMS session id (usually 0).
+ *
+ * Attempts to determine what the Session URI may be.
+ *
+ * Return value: A session URI.
+ **/
+gchar *
+audacious_get_session_uri(gint session)
+{
+    ConfigDb *db;
+    gchar *value = NULL;
+
+    if (audacious_session_uri != NULL)
+    {
+        return g_strdup(audacious_session_uri);
+    }
+
+    if (audacious_session_type != AUDACIOUS_TYPE_UNIX)
+    {
+        db = bmp_cfg_db_open();
+
+        bmp_cfg_db_get_string(db, NULL, "listen_uri_base", &value);
+
+        bmp_cfg_db_close(db);
+    }
+
+    if (value == NULL)
+        return g_strdup_printf("unix://localhost/%s/%s_%s.%d", g_get_tmp_dir(),
+		CTRLSOCKET_NAME, g_get_user_name(), session);
+
+    audacious_session_uri = value;
+
+    return value;
+}
+
+/**
+ * audacious_set_session_type:
+ * @type: The type to set the session type to.
+ *
+ * Sets the type of session used by the audacious server.
+ **/
+void
+audacious_set_session_type(gint type)
+{
+   audacious_session_type = type;
+}
+
+/**
+ * audacious_determine_session_type:
+ * @session: Legacy XMMS session id (usually 0).
+ *
+ * Attempts to determine what the session type may be.
+ **/
+gint
+audacious_determine_session_type(gint session)
+{
+    gchar *uri = NULL;
+
+    if (audacious_session_type != 0)
+    {
+        return audacious_session_type;
+    }
+
+    uri = audacious_get_session_uri(session);
+
+    if (!g_strncasecmp(uri, "tcp://", 6))
+        audacious_session_type = AUDACIOUS_TYPE_TCP;
+    else
+        audacious_session_type = AUDACIOUS_TYPE_UNIX;
+
+    if (audacious_session_type == 0)
+        audacious_session_type = AUDACIOUS_TYPE_UNIX;
+
+    /* memory leak! */
+    g_free(uri);
+
+    return audacious_session_type;
+}
+
+/* tcp://192.168.100.1:5900/zyzychynxi389xvmfewqaxznvnw */
+
+/**
+ * audacious_decode_tcp_uri:
+ * @session: The legacy XMMS session id (usually 0).
+ * @in: A TCP:// Session URI to decode.
+ * @host: Pointer to a host buffer.
+ * @port: Pointer to the TCP port.
+ * @key: Pointer to a security key buffer.
+ *
+ * Decodes a tcp:// session URI.
+ **/
+void
+audacious_decode_tcp_uri(gint session, gchar *in, gchar **host, gint *port, gchar **key)
+{
+    static gchar *workbuf, *keybuf;
+    gint iport;
+    gchar *tmp = g_strdup(in);
+
+    /* split out the host/port and key */
+    workbuf = tmp;
+    workbuf += 6;
+
+    keybuf = strchr(workbuf, '/');
+    *keybuf++ = '\0';
+
+    *key = g_strdup(keybuf);
+
+    if (strchr(workbuf, ':') == NULL)
+    {
+        *host = g_strdup(workbuf);
+        *port = 37370 + session;
+    }
+    else
+    {
+        gchar *hostbuf = NULL;
+        sscanf(workbuf, "%s:%d", hostbuf, &iport);
+
+        *port = iport + session;
+    }
+
+    g_free(tmp);
+}
+
+/* unix://localhost/tmp/audacious_nenolod.0 */
+
+/**
+ * audacious_decode_unix_uri:
+ * @session: The legacy XMMS session id (usually 0).
+ * @in: A UNIX:// Session URI to decode.
+ * @key: Pointer to a UNIX path buffer.
+ *
+ * Decodes a unix:// session URI.
+ **/
+void
+audacious_decode_unix_uri(gint session, gchar *in, gchar **key)
+{
+    static gchar *workbuf, *keybuf;
+    gchar *tmp = g_strdup(in);
+
+    /* split out the host/port and key */
+    workbuf = tmp;
+    workbuf += 7;
+
+    keybuf = strchr(workbuf, '/');
+    *keybuf++ = '\0';
+
+    *key = g_strdup(keybuf);
+
+    g_free(tmp);
+}
+
+/**
+ * xmms_connect_to_session:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Connects to an audacious server.
+ *
+ * Return value: an FD on success, otherwise -1.
+ **/
+gint
+xmms_connect_to_session(gint session)
+{
+    gint fd;
+    gint type = audacious_determine_session_type(session);
+    gchar *uri = audacious_get_session_uri(session);
+
+    if (type == AUDACIOUS_TYPE_UNIX)
+    {
+        if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) != -1)
+        {
+            uid_t stored_uid, euid;
+            struct sockaddr_un saddr;
+	    gchar *path;
+
+            saddr.sun_family = AF_UNIX;
+            stored_uid = getuid();
+            euid = geteuid();
+            setuid(euid);
+	    
+	    audacious_decode_unix_uri(session, uri, &path);
+
+	    g_strlcpy(saddr.sun_path, path, 108);
+            g_free(path);
+            setreuid(stored_uid, euid);
+
+	    g_free(uri);
+
+            if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) != -1)
+                return fd;
+        }
+    }
+    else
+    {
+        if ((fd = socket(AF_INET, SOCK_STREAM, 0)) != -1)
+        {
+	    struct hostent *hp;
+	    struct sockaddr_in saddr;
+	    gchar *host, *key;
+	    gint port;
+
+	    audacious_decode_tcp_uri(session, uri, &host, &port, &key);
+
+            /* resolve it */
+            if ((hp = gethostbyname(host)) == NULL)
+            {
+                 close(fd);
+                 return -1;
+            }
+
+	    memset(&saddr, '\0', sizeof(saddr));
+            saddr.sin_family = AF_INET;
+            saddr.sin_port = htons(port);
+            memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
+
+            g_free(host);
+            g_free(key);
+
+	    g_free(uri);
+
+            if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) != -1)
+                return fd;
+        }
+    }
+
+    close(fd);
+    return -1;
+}
+
+/**
+ * xmms_remote_playlist:
+ * @session: Legacy XMMS-style session identifier.
+ * @list: A list of URIs to play.
+ * @num: Number of URIs to play.
+ * @enqueue: Whether or not the new playlist should be added on, or replace the current playlist.
+ *
+ * Sends a playlist to audacious.
+ **/
+void
+xmms_remote_playlist(gint session, gchar ** list, gint num, gboolean enqueue)
+{
+    gint fd, i;
+    gchar *data, *ptr;
+    gint data_length;
+    guint32 len;
+
+    g_return_if_fail(list != NULL);
+    g_return_if_fail(num > 0);
+
+    if (!enqueue)
+        xmms_remote_playlist_clear(session);
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+
+    for (i = 0, data_length = 0; i < num; i++)
+        data_length += (((strlen(list[i]) + 1) + 3) / 4) * 4 + 4;
+    if (data_length) {
+        data_length += 4;
+        data = g_malloc(data_length);
+        for (i = 0, ptr = data; i < num; i++) {
+            len = strlen(list[i]) + 1;
+            *((guint32 *) ptr) = len;
+            ptr += 4;
+            memcpy(ptr, list[i], len);
+            ptr += ((len + 3) / 4) * 4;
+        }
+        *((guint32 *) ptr) = 0;
+        remote_send_packet(fd, CMD_PLAYLIST_ADD, data, data_length);
+        remote_read_ack(fd);
+        close(fd);
+        g_free(data);
+    }
+
+    if (!enqueue)
+        xmms_remote_play(session);
+}
+
+/**
+ * xmms_remote_get_version:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious for it's protocol version.
+ *
+ * Return value: The protocol version used by Audacious.
+ **/
+gint
+xmms_remote_get_version(gint session)
+{
+    return remote_get_gint(session, CMD_GET_VERSION);
+}
+
+/**
+ * xmms_remote_play_files:
+ * @session: Legacy XMMS-style session identifier.
+ * @list: A GList of URIs to play.
+ *
+ * Sends a list of URIs to Audacious to play.
+ **/
+void
+xmms_remote_play_files(gint session, GList * list)
+{
+    g_return_if_fail(list != NULL);
+
+    xmms_remote_playlist_clear(session);
+    xmms_remote_playlist_add(session, list);
+    xmms_remote_play(session);
+}
+
+/**
+ * xmms_remote_playlist_add:
+ * @session: Legacy XMMS-style session identifier.
+ * @list: A GList of URIs to add to the playlist.
+ *
+ * Sends a list of URIs to Audacious to add to the playlist.
+ **/
+void
+xmms_remote_playlist_add(gint session, GList * list)
+{
+    gchar **str_list;
+    GList *node;
+    gint i, num;
+
+    g_return_if_fail(list != NULL);
+
+    num = g_list_length(list);
+    str_list = g_malloc0(num * sizeof(gchar *));
+    for (i = 0, node = list; i < num && node; i++, node = g_list_next(node))
+        str_list[i] = node->data;
+
+    xmms_remote_playlist(session, str_list, num, TRUE);
+    g_free(str_list);
+}
+
+/**
+ * xmms_remote_playlist_delete:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: The playlist position to delete.
+ *
+ * Deletes a playlist entry.
+ **/
+void
+xmms_remote_playlist_delete(gint session, gint pos)
+{
+    remote_send_guint32(session, CMD_PLAYLIST_DELETE, pos);
+}
+
+/**
+ * xmms_remote_play:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to begin playback.
+ **/
+void
+xmms_remote_play(gint session)
+{
+    remote_cmd(session, CMD_PLAY);
+}
+
+/**
+ * xmms_remote_pause:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to pause.
+ **/
+void
+xmms_remote_pause(gint session)
+{
+    remote_cmd(session, CMD_PAUSE);
+}
+
+/**
+ * xmms_remote_stop:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to stop.
+ **/
+void
+xmms_remote_stop(gint session)
+{
+    remote_cmd(session, CMD_STOP);
+}
+
+/**
+ * xmms_remote_play_pause:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to either play or pause.
+ **/
+void
+xmms_remote_play_pause(gint session)
+{
+    remote_cmd(session, CMD_PLAY_PAUSE);
+}
+
+/**
+ * xmms_remote_is_playing:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about whether it is playing or not.
+ *
+ * Return value: TRUE if playing, FALSE otherwise.
+ **/
+gboolean
+xmms_remote_is_playing(gint session)
+{
+    return remote_get_gboolean(session, CMD_IS_PLAYING);
+}
+
+/**
+ * xmms_remote_is_paused:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about whether it is paused or not.
+ *
+ * Return value: TRUE if playing, FALSE otherwise.
+ **/
+gboolean
+xmms_remote_is_paused(gint session)
+{
+    return remote_get_gboolean(session, CMD_IS_PAUSED);
+}
+
+/**
+ * xmms_remote_get_playlist_pos:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about the current playlist position.
+ *
+ * Return value: The current playlist position.
+ **/
+gint
+xmms_remote_get_playlist_pos(gint session)
+{
+    return remote_get_gint(session, CMD_GET_PLAYLIST_POS);
+}
+
+/**
+ * xmms_remote_set_playlist_pos:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: Playlist position to jump to.
+ *
+ * Tells audacious to jump to a different playlist position.
+ **/
+void
+xmms_remote_set_playlist_pos(gint session, gint pos)
+{
+    remote_send_guint32(session, CMD_SET_PLAYLIST_POS, pos);
+}
+
+/**
+ * xmms_remote_get_playlist_length:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about the current playlist length.
+ *
+ * Return value: The amount of entries in the playlist.
+ **/
+gint
+xmms_remote_get_playlist_length(gint session)
+{
+    return remote_get_gint(session, CMD_GET_PLAYLIST_LENGTH);
+}
+
+/**
+ * xmms_remote_playlist_clear:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Clears the playlist.
+ **/
+void
+xmms_remote_playlist_clear(gint session)
+{
+    remote_cmd(session, CMD_PLAYLIST_CLEAR);
+}
+
+/**
+ * xmms_remote_get_output_time:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about the current output position.
+ *
+ * Return value: The current output position.
+ **/
+gint
+xmms_remote_get_output_time(gint session)
+{
+    return remote_get_gint(session, CMD_GET_OUTPUT_TIME);
+}
+
+/**
+ * xmms_remote_jump_to_time:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: The time (in milliseconds) to jump to.
+ *
+ * Tells audacious to seek to a new time position.
+ **/
+void
+xmms_remote_jump_to_time(gint session, gint pos)
+{
+    remote_send_guint32(session, CMD_JUMP_TO_TIME, pos);
+}
+
+/**
+ * xmms_remote_get_volume:
+ * @session: Legacy XMMS-style session identifier.
+ * @vl: Pointer to integer containing the left channel's volume.
+ * @vr: Pointer to integer containing the right channel's volume.
+ *
+ * Queries audacious about the current volume.
+ **/
+void
+xmms_remote_get_volume(gint session, gint * vl, gint * vr)
+{
+    gint fd;
+    gpointer data;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+
+    remote_send_packet(fd, CMD_GET_VOLUME, NULL, 0);
+    data = remote_read_packet(fd);
+    if (data) {
+        *vl = ((guint32 *) data)[0];
+        *vr = ((guint32 *) data)[1];
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+}
+
+/**
+ * xmms_remote_get_main_volume:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about the current volume.
+ *
+ * Return value: The current volume.
+ **/
+gint
+xmms_remote_get_main_volume(gint session)
+{
+    gint vl, vr;
+
+    xmms_remote_get_volume(session, &vl, &vr);
+
+    return (vl > vr) ? vl : vr;
+}
+
+/**
+ * xmms_remote_get_balance:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about the current balance.
+ *
+ * Return value: The current balance.
+ **/
+gint
+xmms_remote_get_balance(gint session)
+{
+    return remote_get_gint(session, CMD_GET_BALANCE);
+}
+
+/**
+ * xmms_remote_set_volume:
+ * @session: Legacy XMMS-style session identifier.
+ * @vl: The volume for the left channel.
+ * @vr: The volume for the right channel.
+ *
+ * Sets the volume for the left and right channels in Audacious.
+ **/
+void
+xmms_remote_set_volume(gint session, gint vl, gint vr)
+{
+    gint fd;
+    guint32 v[2];
+
+    if (vl < 0)
+        vl = 0;
+    if (vl > 100)
+        vl = 100;
+    if (vr < 0)
+        vr = 0;
+    if (vr > 100)
+        vr = 100;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    v[0] = vl;
+    v[1] = vr;
+    remote_send_packet(fd, CMD_SET_VOLUME, v, 2 * sizeof(guint32));
+    remote_read_ack(fd);
+    close(fd);
+}
+
+/**
+ * xmms_remote_set_main_volume:
+ * @session: Legacy XMMS-style session identifier.
+ * @v: The volume to set.
+ *
+ * Sets the volume in Audacious.
+ **/
+void
+xmms_remote_set_main_volume(gint session, gint v)
+{
+    gint b, vl, vr;
+
+    b = xmms_remote_get_balance(session);
+
+    if (b < 0) {
+        vl = v;
+        vr = (v * (100 - abs(b))) / 100;
+    }
+    else if (b > 0) {
+        vl = (v * (100 - b)) / 100;
+        vr = v;
+    }
+    else
+        vl = vr = v;
+    xmms_remote_set_volume(session, vl, vr);
+}
+
+/**
+ * xmms_remote_set_balance:
+ * @session: Legacy XMMS-style session identifier.
+ * @b: The balance to set.
+ *
+ * Sets the balance in Audacious.
+ **/
+void
+xmms_remote_set_balance(gint session, gint b)
+{
+    gint v, vl, vr;
+
+    if (b < -100)
+        b = -100;
+    if (b > 100)
+        b = 100;
+
+    v = xmms_remote_get_main_volume(session);
+
+    if (b < 0) {
+        vl = v;
+        vr = (v * (100 - abs(b))) / 100;
+    }
+    else if (b > 0) {
+        vl = (v * (100 - b)) / 100;
+        vr = v;
+    }
+    else
+        vl = vr = v;
+    xmms_remote_set_volume(session, vl, vr);
+}
+
+/**
+ * xmms_remote_get_skin:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries Audacious about it's skin.
+ *
+ * Return value: A path to the currently selected skin.
+ **/
+gchar *
+xmms_remote_get_skin(gint session)
+{
+    return remote_get_string(session, CMD_GET_SKIN);
+}
+
+/**
+ * xmms_remote_set_skin:
+ * @session: Legacy XMMS-style session identifier.
+ * @skinfile: Path to a skinfile to use with Audacious.
+ *
+ * Tells audacious to start using the skinfile provided.
+ **/
+void
+xmms_remote_set_skin(gint session, gchar * skinfile)
+{
+    remote_send_string(session, CMD_SET_SKIN, skinfile);
+}
+
+/**
+ * xmms_remote_get_playlist_file:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: The playlist position to query for.
+ *
+ * Queries Audacious about a playlist entry's file.
+ *
+ * Return value: A path to the file in the playlist at %pos position.
+ **/
+gchar *
+xmms_remote_get_playlist_file(gint session, gint pos)
+{
+    return remote_get_string_pos(session, CMD_GET_PLAYLIST_FILE, pos);
+}
+
+/**
+ * xmms_remote_get_playlist_title:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: The playlist position to query for.
+ *
+ * Queries Audacious about a playlist entry's title.
+ *
+ * Return value: The title for the entry in the playlist at %pos position.
+ **/
+gchar *
+xmms_remote_get_playlist_title(gint session, gint pos)
+{
+    return remote_get_string_pos(session, CMD_GET_PLAYLIST_TITLE, pos);
+}
+
+/**
+ * xmms_remote_get_playlist_time:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: The playlist position to query for.
+ *
+ * Queries Audacious about a playlist entry's length.
+ *
+ * Return value: The length of the entry in the playlist at %pos position.
+ **/
+gint
+xmms_remote_get_playlist_time(gint session, gint pos)
+{
+    gpointer data;
+    gint fd, ret = 0;
+    guint32 p = pos;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return ret;
+    remote_send_packet(fd, CMD_GET_PLAYLIST_TIME, &p, sizeof(guint32));
+    data = remote_read_packet(fd);
+    if (data) {
+        ret = *((gint *) data);
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+    return ret;
+}
+
+/**
+ * xmms_remote_get_info:
+ * @session: Legacy XMMS-style session identifier.
+ * @rate: Pointer to an integer containing the bitrate.
+ * @freq: Pointer to an integer containing the frequency.
+ * @nch: Pointer to an integer containing the number of channels.
+ *
+ * Queries Audacious about the current audio format.
+ **/
+void
+xmms_remote_get_info(gint session, gint * rate, gint * freq, gint * nch)
+{
+    gint fd;
+    gpointer data;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    remote_send_packet(fd, CMD_GET_INFO, NULL, 0);
+    data = remote_read_packet(fd);
+    if (data) {
+        *rate = ((guint32 *) data)[0];
+        *freq = ((guint32 *) data)[1];
+        *nch = ((guint32 *) data)[2];
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+}
+
+/**
+ * xmms_remote_get_eq_data:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Not implemented, present for compatibility with libxmms API.
+ **/
+void
+xmms_remote_get_eq_data(gint session)
+{
+    /* Obsolete */
+}
+
+/**
+ * xmms_remote_set_eq_data:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Not implemented, present for compatibility with libxmms API.
+ **/
+void
+xmms_remote_set_eq_data(gint session)
+{
+    /* Obsolete */
+}
+
+/**
+ * xmms_remote_pl_win_toggle:
+ * @session: Legacy XMMS-style session identifier.
+ * @show: Whether or not to show the playlist window.
+ *
+ * Toggles the playlist window's visibility.
+ **/
+void
+xmms_remote_pl_win_toggle(gint session, gboolean show)
+{
+    remote_send_boolean(session, CMD_PL_WIN_TOGGLE, show);
+}
+
+/**
+ * xmms_remote_eq_win_toggle:
+ * @session: Legacy XMMS-style session identifier.
+ * @show: Whether or not to show the equalizer window.
+ *
+ * Toggles the equalizer window's visibility.
+ **/
+void
+xmms_remote_eq_win_toggle(gint session, gboolean show)
+{
+    remote_send_boolean(session, CMD_EQ_WIN_TOGGLE, show);
+}
+
+/**
+ * xmms_remote_main_win_toggle:
+ * @session: Legacy XMMS-style session identifier.
+ * @show: Whether or not to show the main window.
+ *
+ * Toggles the main window's visibility.
+ **/
+void
+xmms_remote_main_win_toggle(gint session, gboolean show)
+{
+    remote_send_boolean(session, CMD_MAIN_WIN_TOGGLE, show);
+}
+
+/**
+ * xmms_remote_is_main_win:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries Audacious about the main window's visibility.
+ *
+ * Return value: TRUE if visible, FALSE otherwise.
+ **/
+gboolean
+xmms_remote_is_main_win(gint session)
+{
+    return remote_get_gboolean(session, CMD_IS_MAIN_WIN);
+}
+
+/**
+ * xmms_remote_is_pl_win:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries Audacious about the playlist window's visibility.
+ *
+ * Return value: TRUE if visible, FALSE otherwise.
+ **/
+gboolean
+xmms_remote_is_pl_win(gint session)
+{
+    return remote_get_gboolean(session, CMD_IS_PL_WIN);
+}
+
+/**
+ * xmms_remote_is_eq_win:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries Audacious about the equalizer window's visibility.
+ *
+ * Return value: TRUE if visible, FALSE otherwise.
+ **/
+gboolean
+xmms_remote_is_eq_win(gint session)
+{
+    return remote_get_gboolean(session, CMD_IS_EQ_WIN);
+}
+
+/**
+ * xmms_remote_show_prefs_box:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to show the preferences pane.
+ **/
+void
+xmms_remote_show_prefs_box(gint session)
+{
+    remote_cmd(session, CMD_SHOW_PREFS_BOX);
+}
+
+/**
+ * xmms_remote_show_jtf_box:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to show the Jump-to-File pane.
+ **/
+void
+xmms_remote_show_jtf_box(gint session)
+{
+    remote_cmd(session, CMD_SHOW_JTF_BOX);
+}
+
+/**
+ * xmms_remote_toggle_aot:
+ * @session: Legacy XMMS-style session identifier.
+ * @ontop: Whether or not Audacious should be always-on-top.
+ *
+ * Tells audacious to toggle the always-on-top feature.
+ **/
+void
+xmms_remote_toggle_aot(gint session, gboolean ontop)
+{
+    remote_send_boolean(session, CMD_TOGGLE_AOT, ontop);
+}
+
+/**
+ * xmms_remote_show_about_box:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to show the about pane.
+ **/
+void
+xmms_remote_show_about_box(gint session)
+{
+    remote_cmd(session, CMD_SHOW_ABOUT_BOX);
+}
+
+/**
+ * xmms_remote_eject:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to display the open files pane.
+ **/
+void
+xmms_remote_eject(gint session)
+{
+    remote_cmd(session, CMD_EJECT);
+}
+
+/**
+ * xmms_remote_playlist_prev:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to move backwards in the playlist.
+ **/
+void
+xmms_remote_playlist_prev(gint session)
+{
+    remote_cmd(session, CMD_PLAYLIST_PREV);
+}
+
+/**
+ * xmms_remote_playlist_next:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to move forward in the playlist.
+ **/
+void
+xmms_remote_playlist_next(gint session)
+{
+    remote_cmd(session, CMD_PLAYLIST_NEXT);
+}
+
+/**
+ * xmms_remote_playlist_add_url_string:
+ * @session: Legacy XMMS-style session identifier.
+ * @string: The URI to add.
+ *
+ * Tells audacious to add an URI to the playlist.
+ **/
+void
+xmms_remote_playlist_add_url_string(gint session, gchar * string)
+{
+    g_return_if_fail(string != NULL);
+    remote_send_string(session, CMD_PLAYLIST_ADD_URL_STRING, string);
+}
+
+/**
+ * xmms_remote_playlist_enqueue_to_temp:
+ * @session: Legacy XMMS-style session identifier.
+ * @string: The URI to enqueue to a temporary playlist.
+ *
+ * Tells audacious to add an URI to a temporary playlist.
+ **/
+void
+xmms_remote_playlist_enqueue_to_temp(gint session, gchar * string)
+{
+    g_return_if_fail(string != NULL);
+    remote_send_string(session, CMD_PLAYLIST_ENQUEUE_TO_TEMP, string);
+}
+
+/**
+ * xmms_remote_playlist_ins_url_string:
+ * @session: Legacy XMMS-style session identifier.
+ * @string: The URI to add.
+ * @pos: The position to add the URI at.
+ *
+ * Tells audacious to add an URI to the playlist at a specific position.
+ **/
+void
+xmms_remote_playlist_ins_url_string(gint session, gchar * string, gint pos)
+{
+    gint fd, size;
+    gchar *packet;
+
+    g_return_if_fail(string != NULL);
+
+    size = strlen(string) + 1 + sizeof(gint);
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+
+    packet = g_malloc0(size);
+    *((gint *) packet) = pos;
+    strcpy(packet + sizeof(gint), string);
+    remote_send_packet(fd, CMD_PLAYLIST_INS_URL_STRING, packet, size);
+    remote_read_ack(fd);
+    close(fd);
+    g_free(packet);
+}
+
+/**
+ * xmms_remote_is_running:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Checks to see if an Audacious server is running.
+ *
+ * Return value: TRUE if yes, otherwise FALSE.
+ **/
+gboolean
+xmms_remote_is_running(gint session)
+{
+    return remote_cmd(session, CMD_PING);
+}
+
+/**
+ * xmms_remote_toggle_repeat:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to toggle the repeat feature.
+ **/
+void
+xmms_remote_toggle_repeat(gint session)
+{
+    remote_cmd(session, CMD_TOGGLE_REPEAT);
+}
+
+/**
+ * xmms_remote_toggle_shuffle:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to toggle the shuffle feature.
+ **/
+void
+xmms_remote_toggle_shuffle(gint session)
+{
+    remote_cmd(session, CMD_TOGGLE_SHUFFLE);
+}
+
+/**
+ * xmms_remote_toggle_advance:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to toggle the no-playlist-advance feature.
+ **/
+void
+xmms_remote_toggle_advance(int session)
+{
+    remote_cmd(session, CMD_TOGGLE_ADVANCE);
+}
+
+/**
+ * xmms_remote_is_repeat:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about whether or not the repeat feature is active.
+ *
+ * Return value: TRUE if yes, otherwise FALSE.
+ **/
+gboolean
+xmms_remote_is_repeat(gint session)
+{
+    return remote_get_gboolean(session, CMD_IS_REPEAT);
+}
+
+/**
+ * xmms_remote_is_shuffle:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about whether or not the shuffle feature is active.
+ *
+ * Return value: TRUE if yes, otherwise FALSE.
+ **/
+gboolean
+xmms_remote_is_shuffle(gint session)
+{
+    return remote_get_gboolean(session, CMD_IS_SHUFFLE);
+}
+
+/**
+ * xmms_remote_is_advance:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about whether or not the no-playlist-advance feature is active.
+ *
+ * Return value: TRUE if yes, otherwise FALSE.
+ **/
+gboolean
+xmms_remote_is_advance(gint session)
+{
+    return remote_get_gboolean(session, CMD_IS_ADVANCE);
+}
+
+/**
+ * xmms_remote_playqueue_add:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: The playlist position to add to the queue.
+ *
+ * Tells audacious to add a playlist entry to the playqueue.
+ **/
+void
+xmms_remote_playqueue_add(gint session, gint pos)
+{
+    remote_send_guint32(session, CMD_PLAYQUEUE_ADD, pos);
+}
+
+/**
+ * xmms_remote_playqueue_remove:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: The playlist position to remove from the queue.
+ *
+ * Tells audacious to remove a playlist entry from the playqueue.
+ **/
+void
+xmms_remote_playqueue_remove(gint session, gint pos)
+{
+    remote_send_guint32(session, CMD_PLAYQUEUE_REMOVE, pos);
+}
+
+/**
+ * xmms_remote_playqueue_clear:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to clear the playqueue.
+ **/
+void
+xmms_remote_playqueue_clear(gint session)
+{
+    remote_cmd(session, CMD_PLAYQUEUE_CLEAR);
+}
+
+/**
+ * xmms_remote_get_playqueue_length:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about the playqueue's length.
+ *
+ * Return value: The number of entries in the playqueue.
+ **/
+gint
+xmms_remote_get_playqueue_length(gint session)
+{
+    return remote_get_gint(session, CMD_GET_PLAYQUEUE_LENGTH);
+}
+
+/**
+ * xmms_remote_playqueue_is_queued:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: Position to check queue for.
+ *
+ * Queries audacious about whether or not a playlist entry is in the playqueue.
+ *
+ * Return value: TRUE if yes, FALSE otherwise.
+ **/
+gboolean
+xmms_remote_playqueue_is_queued(gint session, gint pos)
+{
+    gpointer data;
+    gint fd, ret = 0;
+    guint32 p = pos;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return ret;
+    remote_send_packet(fd, CMD_PLAYQUEUE_IS_QUEUED, &p, sizeof(guint32));
+    data = remote_read_packet(fd);
+    if (data) {
+        ret = *((gint *) data);
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+    return ret;
+}
+
+/**
+ * xmms_remote_get_playqueue_position:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: Position to check queue for.
+ *
+ * Queries audacious about what the playqueue position is for a playlist entry.
+ *
+ * Return value: TRUE if yes, FALSE otherwise.
+ **/
+gint
+xmms_remote_get_playqueue_position(gint session, gint pos)
+{
+    gpointer data;
+    gint fd, ret = 0;
+    guint32 p = pos;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return ret;
+    remote_send_packet(fd, CMD_PLAYQUEUE_GET_POS, &p, sizeof(guint32));
+    data = remote_read_packet(fd);
+    if (data) {
+        ret = *((gint *) data);
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+    return ret;
+}
+
+/**
+ * xmms_remote_get_playqueue_queue_position:
+ * @session: Legacy XMMS-style session identifier.
+ * @pos: Position to check queue for.
+ *
+ * Queries audacious about what the playlist position is for a playqueue entry.
+ *
+ * Return value: TRUE if yes, FALSE otherwise.
+ **/
+gint
+xmms_remote_get_playqueue_queue_position(gint session, gint pos)
+{
+    gpointer data;
+    gint fd, ret = 0;
+    guint32 p = pos;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return ret;
+    remote_send_packet(fd, CMD_PLAYQUEUE_GET_QPOS, &p, sizeof(guint32));
+    data = remote_read_packet(fd);
+    if (data) {
+        ret = *((gint *) data);
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+    return ret;
+}
+
+/**
+ * xmms_remote_get_eq:
+ * @session: Legacy XMMS-style session identifier.
+ * @preamp: Pointer to value for preamp setting.
+ * @bands: Pointer to array of band settings.
+ *
+ * Queries audacious about the equalizer settings.
+ **/
+void
+xmms_remote_get_eq(gint session, gfloat * preamp, gfloat ** bands)
+{
+    gint fd;
+    gpointer data;
+
+    if (preamp)
+        *preamp = 0.0;
+
+    if (bands)
+        *bands = NULL;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    remote_send_packet(fd, CMD_GET_EQ, NULL, 0);
+    data = remote_read_packet(fd);
+    if (data) {
+            if (preamp)
+                *preamp = *((gfloat *) data);
+            if (bands)
+                *bands =
+                    (gfloat *) g_memdup((gfloat *) data + 1,
+                                        10 * sizeof(gfloat));
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+}
+
+/**
+ * xmms_remote_get_eq_preamp:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Queries audacious about the equalizer preamp's setting.
+ *
+ * Return value: The equalizer preamp's setting.
+ **/
+gfloat
+xmms_remote_get_eq_preamp(gint session)
+{
+    return remote_get_gfloat(session, CMD_GET_EQ_PREAMP);
+}
+
+/**
+ * xmms_remote_get_eq_band:
+ * @session: Legacy XMMS-style session identifier.
+ * @band: Which band to lookup the value for.
+ *
+ * Queries audacious about an equalizer band's value.
+ *
+ * Return value: The equalizer band's value.
+ **/
+gfloat
+xmms_remote_get_eq_band(gint session, gint band)
+{
+    gint fd;
+    gpointer data;
+    gfloat val = 0.0;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return val;
+    remote_send_packet(fd, CMD_GET_EQ_BAND, &band, sizeof(band));
+    data = remote_read_packet(fd);
+    if (data) {
+        val = *((gfloat *) data);
+        g_free(data);
+    }
+    remote_read_ack(fd);
+    close(fd);
+    return val;
+}
+
+/**
+ * xmms_remote_set_eq:
+ * @session: Legacy XMMS-style session identifier.
+ * @preamp: Value for preamp setting.
+ * @bands: Array of band settings.
+ *
+ * Tells audacious to set the equalizer up using the provided values.
+ **/
+void
+xmms_remote_set_eq(gint session, gfloat preamp, gfloat * bands)
+{
+    gint fd, i;
+    gfloat data[11];
+
+    g_return_if_fail(bands != NULL);
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    data[0] = preamp;
+    for (i = 0; i < 10; i++)
+        data[i + 1] = bands[i];
+    remote_send_packet(fd, CMD_SET_EQ, data, sizeof(data));
+    remote_read_ack(fd);
+    close(fd);
+}
+
+/**
+ * xmms_remote_set_eq_preamp:
+ * @session: Legacy XMMS-style session identifier.
+ * @preamp: Value for preamp setting.
+ *
+ * Tells audacious to set the equalizer's preamp setting.
+ **/
+void
+xmms_remote_set_eq_preamp(gint session, gfloat preamp)
+{
+    remote_send_gfloat(session, CMD_SET_EQ_PREAMP, preamp);
+}
+
+/**
+ * xmms_remote_set_eq_band:
+ * @session: Legacy XMMS-style session identifier.
+ * @band: The band to set the value for.
+ * @value: The value to set that band to.
+ *
+ * Tells audacious to set an equalizer band's setting.
+ **/
+void
+xmms_remote_set_eq_band(gint session, gint band, gfloat value)
+{
+    gint fd;
+    gchar data[sizeof(gint) + sizeof(gfloat)];
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    *((gint *) data) = band;
+    *((gfloat *) (data + sizeof(gint))) = value;
+    remote_send_packet(fd, CMD_SET_EQ_BAND, data, sizeof(data));
+    remote_read_ack(fd);
+    close(fd);
+}
+
+/**
+ * xmms_remote_quit:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to quit.
+ **/
+void
+xmms_remote_quit(gint session)
+{
+    gint fd;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    remote_send_packet(fd, CMD_QUIT, NULL, 0);
+    remote_read_ack(fd);
+    close(fd);
+}
+
+/**
+ * xmms_remote_activate:
+ * @session: Legacy XMMS-style session identifier.
+ *
+ * Tells audacious to display the main window and become the selected window.
+ **/
+void
+xmms_remote_activate(gint session)
+{
+    gint fd;
+
+    if ((fd = xmms_connect_to_session(session)) == -1)
+        return;
+    remote_send_packet(fd, CMD_ACTIVATE, NULL, 0);
+    remote_read_ack(fd);
+    close(fd);
+}