| 0 |      1 | diff -r fb5042644071 debian/patches/00list
 | 
|  |      2 | --- a/debian/patches/00list	Mon May 19 00:17:05 2008 -0400
 | 
|  |      3 | +++ b/debian/patches/00list	Mon May 19 01:12:49 2008 -0400
 | 
|  |      4 | @@ -1,2 +1,4 @@
 | 
|  |      5 |  01verbose-compilation
 | 
|  |      6 |  02compile-with-gcc-4.3
 | 
|  |      7 | +03mpd-client
 | 
|  |      8 | +04mpd-client-config-init
 | 
|  |      9 | diff -r fb5042644071 debian/patches/03mpd-client.dpatch
 | 
|  |     10 | --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
 | 
|  |     11 | +++ b/debian/patches/03mpd-client.dpatch	Mon May 19 01:12:49 2008 -0400
 | 
|  |     12 | @@ -0,0 +1,3597 @@
 | 
|  |     13 | +#! /bin/sh /usr/share/dpatch/dpatch-run
 | 
|  |     14 | +## mpd-client.dpatch by Fabien Niñoles <fabien@tzone.org>
 | 
|  |     15 | +##
 | 
|  |     16 | +## All lines beginning with `## DP:' are a description of the patch.
 | 
|  |     17 | +## DP: Add mpd to imms clients.
 | 
|  |     18 | +
 | 
|  |     19 | +@DPATCH@
 | 
|  |     20 | +
 | 
|  |     21 | +diff -r 171db9560cb5 clients/mpd/immsmpd.cc
 | 
|  |     22 | +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
 | 
|  |     23 | ++++ b/clients/mpd/immsmpd.cc	Mon May 19 00:21:51 2008 -0400
 | 
|  |     24 | +@@ -0,0 +1,282 @@
 | 
|  |     25 | ++#include "immsutil.h"
 | 
|  |     26 | ++#include "clientstub.h"
 | 
|  |     27 | ++
 | 
|  |     28 | ++#include <glib.h>
 | 
|  |     29 | ++#include <signal.h>
 | 
|  |     30 | ++
 | 
|  |     31 | ++#include "mpdinterface.h"
 | 
|  |     32 | ++#include <list>
 | 
|  |     33 | ++
 | 
|  |     34 | ++
 | 
|  |     35 | ++using std::endl;
 | 
|  |     36 | ++using std::list;
 | 
|  |     37 | ++using namespace mpd_interface;
 | 
|  |     38 | ++
 | 
|  |     39 | ++// interface for communication with IMMS server
 | 
|  |     40 | ++// comes from clientstub.h
 | 
|  |     41 | ++struct MPDOps;
 | 
|  |     42 | ++typedef IMMSClient<MPDOps> MPDClient;
 | 
|  |     43 | ++
 | 
|  |     44 | ++int poll_time = 250; // miliseconds
 | 
|  |     45 | ++const double reconnect_interval = 1.0; // seconds
 | 
|  |     46 | ++GMainLoop *loop = nullptr;
 | 
|  |     47 | ++GSource* ts;
 | 
|  |     48 | ++
 | 
|  |     49 | ++MPDClient imms;
 | 
|  |     50 | ++Player mpd;
 | 
|  |     51 | ++list<int> playqueue;
 | 
|  |     52 | ++const list<int>::size_type pq_capacity = 1;
 | 
|  |     53 | ++
 | 
|  |     54 | ++
 | 
|  |     55 | ++// that's the main function - it's called regularly and handles all the
 | 
|  |     56 | ++// IMMS and MPD communication and decides what to do when anything happens
 | 
|  |     57 | ++gboolean do_events(void *unused);
 | 
|  |     58 | ++
 | 
|  |     59 | ++// determines whether the currently playing song has been selected
 | 
|  |     60 | ++// specifically by the user
 | 
|  |     61 | ++bool next_jumped(); 
 | 
|  |     62 | ++
 | 
|  |     63 | ++void notify_song_ended(const Song& song, double elapsed_time, bool jumped);
 | 
|  |     64 | ++
 | 
|  |     65 | ++// resets the elapsed_timer and sets the jumped flag, too
 | 
|  |     66 | ++void notify_song_started(const Song& song, double& elapsed_time,
 | 
|  |     67 | ++    bool& jumped);
 | 
|  |     68 | ++
 | 
|  |     69 | ++void update_playqueue();
 | 
|  |     70 | ++bool playqueue_contains(int song);
 | 
|  |     71 | ++
 | 
|  |     72 | ++void quit(int signum);
 | 
|  |     73 | ++
 | 
|  |     74 | ++
 | 
|  |     75 | ++struct MPDOps
 | 
|  |     76 | ++{
 | 
|  |     77 | ++    // IMMS server's suggestion of the next song
 | 
|  |     78 | ++    static void set_next(int next)
 | 
|  |     79 | ++    {
 | 
|  |     80 | ++      if(playqueue.size() < pq_capacity) {
 | 
|  |     81 | ++	if(mpd.song(current).path() == mpd.song(next).path() ||
 | 
|  |     82 | ++	    mpd.song(previous).path() == mpd.song(next).path() ||
 | 
|  |     83 | ++	    playqueue_contains(next) || next >= mpd.playlist_length()) {
 | 
|  |     84 | ++          update_playqueue();
 | 
|  |     85 | ++	}
 | 
|  |     86 | ++	else {
 | 
|  |     87 | ++	  playqueue.push_back(next);
 | 
|  |     88 | ++	}
 | 
|  |     89 | ++      }
 | 
|  |     90 | ++    }
 | 
|  |     91 | ++    // no idea, works just peach as it is
 | 
|  |     92 | ++    // asked mag about it, waiting for an answer
 | 
|  |     93 | ++    // TODO if he doesn't answer, dig it out
 | 
|  |     94 | ++    static void reset_selection() { }
 | 
|  |     95 | ++    // path of the song at the given pos for IMMS server
 | 
|  |     96 | ++    static string get_item(int index) {return mpd.song(index).path(); }
 | 
|  |     97 | ++    // size of the playlist for the IMMS server
 | 
|  |     98 | ++    static int get_length() { return mpd.playlist_length(); }
 | 
|  |     99 | ++}; 
 | 
|  |    100 | ++
 | 
|  |    101 | ++int main(int argc, char **argv)
 | 
|  |    102 | ++{
 | 
|  |    103 | ++  // glib initialization
 | 
|  |    104 | ++  loop = g_main_loop_new(nullptr, FALSE);
 | 
|  |    105 | ++
 | 
|  |    106 | ++  signal(SIGINT,  quit);
 | 
|  |    107 | ++  signal(SIGTERM, quit);
 | 
|  |    108 | ++  signal(SIGPIPE, SIG_IGN);
 | 
|  |    109 | ++
 | 
|  |    110 | ++  ts = g_timeout_source_new(poll_time);
 | 
|  |    111 | ++  g_source_attach(ts, nullptr);
 | 
|  |    112 | ++  g_source_set_callback(ts, (GSourceFunc)do_events, nullptr, nullptr);
 | 
|  |    113 | ++  // end of glib init
 | 
|  |    114 | ++
 | 
|  |    115 | ++  g_main_loop_run(loop);
 | 
|  |    116 | ++
 | 
|  |    117 | ++  LOG(INFO) << "Exitting." << endl;
 | 
|  |    118 | ++  return 0;
 | 
|  |    119 | ++}
 | 
|  |    120 | ++
 | 
|  |    121 | ++gboolean do_events(void *unused)
 | 
|  |    122 | ++{
 | 
|  |    123 | ++  static const double time_inc = double(poll_time)/1000.0;
 | 
|  |    124 | ++    // the time that ACTUALLY elapsed when playing the song (in seconds)
 | 
|  |    125 | ++  static double elapsed_time = 0; 
 | 
|  |    126 | ++  static bool jumped = false;
 | 
|  |    127 | ++  static double reconnect_timeout = 0;
 | 
|  |    128 | ++
 | 
|  |    129 | ++  try {
 | 
|  |    130 | ++    if(!mpd.connected()) {
 | 
|  |    131 | ++      if(reconnect_timeout < time_inc) {
 | 
|  |    132 | ++	LOG(INFO) << "Not connected to MPD. Attempting to connect..."
 | 
|  |    133 | ++	  << endl;
 | 
|  |    134 | ++	reconnect_timeout = reconnect_interval;
 | 
|  |    135 | ++	mpd.connect();
 | 
|  |    136 | ++	LOG(INFO) << "Connected to MPD." << endl;
 | 
|  |    137 | ++	reconnect_timeout = 0;
 | 
|  |    138 | ++      }
 | 
|  |    139 | ++      else {
 | 
|  |    140 | ++	reconnect_timeout -= time_inc;
 | 
|  |    141 | ++	return TRUE;
 | 
|  |    142 | ++      }
 | 
|  |    143 | ++    }
 | 
|  |    144 | ++    if(imms.check_connection()) imms.setup(0);
 | 
|  |    145 | ++    if(!imms.isok()) return TRUE;
 | 
|  |    146 | ++
 | 
|  |    147 | ++    mpd.refresh();
 | 
|  |    148 | ++
 | 
|  |    149 | ++    if(mpd.playlist_changed()) {
 | 
|  |    150 | ++      imms.playlist_changed(mpd.playlist_length());
 | 
|  |    151 | ++      playqueue.clear();
 | 
|  |    152 | ++    }
 | 
|  |    153 | ++    if(mpd.radnom()) update_playqueue();
 | 
|  |    154 | ++
 | 
|  |    155 | ++    if(mpd.status_changed()) {
 | 
|  |    156 | ++      if(mpd.status(current) == stopped) {
 | 
|  |    157 | ++	notify_song_ended(mpd.song(current), elapsed_time, jumped);
 | 
|  |    158 | ++      }
 | 
|  |    159 | ++      else if(mpd.status(previous) == stopped &&
 | 
|  |    160 | ++	  mpd.status(current)==playing) {
 | 
|  |    161 | ++	notify_song_started(mpd.song(current), elapsed_time, jumped);
 | 
|  |    162 | ++	
 | 
|  |    163 | ++	// clear the song_changed() flag
 | 
|  |    164 | ++	if(mpd.song_changed()) mpd.refresh(); 
 | 
|  |    165 | ++      }
 | 
|  |    166 | ++    }
 | 
|  |    167 | ++    if(mpd.status(current) == playing) {
 | 
|  |    168 | ++      elapsed_time += time_inc;
 | 
|  |    169 | ++      if(mpd.song_changed()) {
 | 
|  |    170 | ++	notify_song_ended(mpd.song(previous), elapsed_time, jumped);
 | 
|  |    171 | ++
 | 
|  |    172 | ++	if(!mpd.radnom() || playqueue.empty()) {
 | 
|  |    173 | ++	  notify_song_started(mpd.song(current), elapsed_time, jumped);
 | 
|  |    174 | ++	}
 | 
|  |    175 | ++	else {
 | 
|  |    176 | ++	  mpd.play_song(playqueue.front());
 | 
|  |    177 | ++	  notify_song_started(mpd.song(playqueue.front()), elapsed_time,
 | 
|  |    178 | ++	      jumped);
 | 
|  |    179 | ++	  playqueue.erase(playqueue.begin());
 | 
|  |    180 | ++	  update_playqueue();
 | 
|  |    181 | ++	  // this could otherwise incorrectly set song_changed() flag
 | 
|  |    182 | ++	  mpd.refresh(); 
 | 
|  |    183 | ++	}
 | 
|  |    184 | ++      }
 | 
|  |    185 | ++      else {
 | 
|  |    186 | ++	// fix the real timer if it's inconsistent with what player
 | 
|  |    187 | ++	// says is the elapsed time of the current song
 | 
|  |    188 | ++	if(elapsed_time - double(mpd.song(current).elapsed()) >= 3.0) {
 | 
|  |    189 | ++	  if(mpd.song(current).elapsed() == 0) {
 | 
|  |    190 | ++	    Song tmp_ended = mpd.song(current);
 | 
|  |    191 | ++	    tmp_ended.set_length(int(elapsed_time) * 2);
 | 
|  |    192 | ++	    notify_song_ended(tmp_ended, elapsed_time, jumped);
 | 
|  |    193 | ++	    notify_song_started(mpd.song(current), elapsed_time, jumped);
 | 
|  |    194 | ++	    jumped = false;
 | 
|  |    195 | ++	  }
 | 
|  |    196 | ++	  elapsed_time = mpd.song(current).elapsed();
 | 
|  |    197 | ++	}
 | 
|  |    198 | ++      }
 | 
|  |    199 | ++    }
 | 
|  |    200 | ++  }
 | 
|  |    201 | ++  catch (connection_err) {
 | 
|  |    202 | ++    if(reconnect_timeout >= reconnect_interval) {
 | 
|  |    203 | ++	  LOG(INFO) << "Connecting to MPD was unsuccessful. "
 | 
|  |    204 | ++	    "Next attempt in " << reconnect_interval << " second"
 | 
|  |    205 | ++	    << (reconnect_interval == 1.0 ? "":"s") << "." << endl;
 | 
|  |    206 | ++    }
 | 
|  |    207 | ++    else {
 | 
|  |    208 | ++      LOG(INFO) << "Disconnected from MPD." << endl;
 | 
|  |    209 | ++    }
 | 
|  |    210 | ++  }
 | 
|  |    211 | ++  catch (mpd_err ex) {
 | 
|  |    212 | ++    LOG(ERROR) << "Error: " << ex.message() << endl;
 | 
|  |    213 | ++    g_main_quit(loop);
 | 
|  |    214 | ++    loop = nullptr;
 | 
|  |    215 | ++    exit(1);
 | 
|  |    216 | ++  }
 | 
|  |    217 | ++  return TRUE;
 | 
|  |    218 | ++}
 | 
|  |    219 | ++
 | 
|  |    220 | ++// determines whether the song has been played whole
 | 
|  |    221 | ++bool played_whole(double elapsed_time, int length)
 | 
|  |    222 | ++{
 | 
|  |    223 | ++  static const double abs_limit = 20.0;
 | 
|  |    224 | ++  static const double coeficient = 0.08;
 | 
|  |    225 | ++
 | 
|  |    226 | ++  double rel_limit = double(length) * coeficient;
 | 
|  |    227 | ++
 | 
|  |    228 | ++  double limit = (abs_limit < rel_limit) ? abs_limit : rel_limit;
 | 
|  |    229 | ++  return double(length)-elapsed_time < limit; 
 | 
|  |    230 | ++}
 | 
|  |    231 | ++// determines whether the song has been skipped early
 | 
|  |    232 | ++// (thus being set as not a prefed one)
 | 
|  |    233 | ++bool bad(double elapsed_time, int length)
 | 
|  |    234 | ++{
 | 
|  |    235 | ++  static const double abs_limit = 30.0;
 | 
|  |    236 | ++  static const double coeficient = 0.13;
 | 
|  |    237 | ++
 | 
|  |    238 | ++  double rel_limit = double(length) * coeficient;
 | 
|  |    239 | ++
 | 
|  |    240 | ++  double limit = (rel_limit < abs_limit) ? rel_limit : abs_limit;
 | 
|  |    241 | ++  return elapsed_time < limit;
 | 
|  |    242 | ++}
 | 
|  |    243 | ++bool next_jumped()
 | 
|  |    244 | ++{
 | 
|  |    245 | ++  if(mpd.radnom()) return false;
 | 
|  |    246 | ++
 | 
|  |    247 | ++  if(mpd.song(current).pos() == mpd.song(previous).pos()+1)
 | 
|  |    248 | ++    return false;
 | 
|  |    249 | ++  if(mpd.song(current).pos() == 0 &&
 | 
|  |    250 | ++      mpd.song(previous).pos() == mpd.playlist_length()-1)
 | 
|  |    251 | ++    return false;
 | 
|  |    252 | ++
 | 
|  |    253 | ++  return true;
 | 
|  |    254 | ++}
 | 
|  |    255 | ++void notify_song_ended(const Song& song, double elapsed_time, bool jumped)
 | 
|  |    256 | ++{
 | 
|  |    257 | ++  if(song.length() == Song::invalid_time) return;
 | 
|  |    258 | ++
 | 
|  |    259 | ++  imms.end_song(played_whole(elapsed_time, song.length()), jumped,
 | 
|  |    260 | ++      bad(elapsed_time, song.length()) );
 | 
|  |    261 | ++}
 | 
|  |    262 | ++
 | 
|  |    263 | ++void notify_song_started(const Song& song, double& elapsed_timer,
 | 
|  |    264 | ++    bool& jumped)
 | 
|  |    265 | ++{
 | 
|  |    266 | ++  imms.start_song(song.pos(), song.path());
 | 
|  |    267 | ++  elapsed_timer = 0;
 | 
|  |    268 | ++  jumped = next_jumped();
 | 
|  |    269 | ++  mpd.song_changed(); // clear the change notification
 | 
|  |    270 | ++}
 | 
|  |    271 | ++
 | 
|  |    272 | ++void update_playqueue()
 | 
|  |    273 | ++{
 | 
|  |    274 | ++  static const int timeout_value = 3;
 | 
|  |    275 | ++  static int timeout = 0;
 | 
|  |    276 | ++
 | 
|  |    277 | ++  if(timeout == 0)
 | 
|  |    278 | ++  {
 | 
|  |    279 | ++    if(playqueue.size() < pq_capacity) {
 | 
|  |    280 | ++      list<int>::size_type i;
 | 
|  |    281 | ++      for(i = pq_capacity - playqueue.size(); i!=0; i--) {
 | 
|  |    282 | ++	imms.select_next();
 | 
|  |    283 | ++      }
 | 
|  |    284 | ++      timeout = timeout_value;
 | 
|  |    285 | ++    }
 | 
|  |    286 | ++  }
 | 
|  |    287 | ++  else --timeout;
 | 
|  |    288 | ++}
 | 
|  |    289 | ++
 | 
|  |    290 | ++bool playqueue_contains(int song)
 | 
|  |    291 | ++{
 | 
|  |    292 | ++  list<int>::const_iterator i;
 | 
|  |    293 | ++  for(i = playqueue.begin(); i!= playqueue.end(); i++) {
 | 
|  |    294 | ++    if (*i == song) return true;
 | 
|  |    295 | ++  }
 | 
|  |    296 | ++  return false;
 | 
|  |    297 | ++}
 | 
|  |    298 | ++
 | 
|  |    299 | ++void quit(int signum)
 | 
|  |    300 | ++{
 | 
|  |    301 | ++  if (loop) g_main_quit(loop);
 | 
|  |    302 | ++  loop = nullptr;
 | 
|  |    303 | ++  signal(signum, SIG_DFL);
 | 
|  |    304 | ++}
 | 
|  |    305 | ++
 | 
|  |    306 | ++
 | 
|  |    307 | +diff -r 171db9560cb5 clients/mpd/libmpdclient.c
 | 
|  |    308 | +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
 | 
|  |    309 | ++++ b/clients/mpd/libmpdclient.c	Mon May 19 00:21:51 2008 -0400
 | 
|  |    310 | +@@ -0,0 +1,1955 @@
 | 
|  |    311 | ++/* libmpdclient
 | 
|  |    312 | ++   (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
 | 
|  |    313 | ++   This project's homepage is: http://www.musicpd.org
 | 
|  |    314 | ++
 | 
|  |    315 | ++   Redistribution and use in source and binary forms, with or without
 | 
|  |    316 | ++   modification, are permitted provided that the following conditions
 | 
|  |    317 | ++   are met:
 | 
|  |    318 | ++
 | 
|  |    319 | ++   - Redistributions of source code must retain the above copyright
 | 
|  |    320 | ++   notice, this list of conditions and the following disclaimer.
 | 
|  |    321 | ++
 | 
|  |    322 | ++   - Redistributions in binary form must reproduce the above copyright
 | 
|  |    323 | ++   notice, this list of conditions and the following disclaimer in the
 | 
|  |    324 | ++   documentation and/or other materials provided with the distribution.
 | 
|  |    325 | ++
 | 
|  |    326 | ++   - Neither the name of the Music Player Daemon nor the names of its
 | 
|  |    327 | ++   contributors may be used to endorse or promote products derived from
 | 
|  |    328 | ++   this software without specific prior written permission.
 | 
|  |    329 | ++
 | 
|  |    330 | ++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
|  |    331 | ++   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
|  |    332 | ++   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
|  |    333 | ++   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
 | 
|  |    334 | ++   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
|  |    335 | ++   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
|  |    336 | ++   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
|  |    337 | ++   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
|  |    338 | ++   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
|  |    339 | ++   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
|  |    340 | ++   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
|  |    341 | ++*/
 | 
|  |    342 | ++
 | 
|  |    343 | ++#include "libmpdclient.h"
 | 
|  |    344 | ++
 | 
|  |    345 | ++#include <errno.h>
 | 
|  |    346 | ++#include <ctype.h>
 | 
|  |    347 | ++#include <sys/types.h>
 | 
|  |    348 | ++#include <stdio.h>
 | 
|  |    349 | ++#include <sys/param.h>
 | 
|  |    350 | ++#include <string.h>
 | 
|  |    351 | ++#include <unistd.h>
 | 
|  |    352 | ++#include <stdlib.h>
 | 
|  |    353 | ++#include <fcntl.h>
 | 
|  |    354 | ++#include <limits.h>
 | 
|  |    355 | ++
 | 
|  |    356 | ++#ifdef WIN32
 | 
|  |    357 | ++#  include <ws2tcpip.h>
 | 
|  |    358 | ++#  include <winsock.h>
 | 
|  |    359 | ++#else
 | 
|  |    360 | ++#  include <netinet/in.h>
 | 
|  |    361 | ++#  include <arpa/inet.h>
 | 
|  |    362 | ++#  include <sys/socket.h>
 | 
|  |    363 | ++#  include <netdb.h>
 | 
|  |    364 | ++#endif
 | 
|  |    365 | ++
 | 
|  |    366 | ++/* (bits+1)/3 (plus the sign character) */
 | 
|  |    367 | ++#define INTLEN      ((sizeof(int)       * CHAR_BIT + 1) / 3 + 1)
 | 
|  |    368 | ++#define LONGLONGLEN ((sizeof(long long) * CHAR_BIT + 1) / 3 + 1)
 | 
|  |    369 | ++
 | 
|  |    370 | ++#define COMMAND_LIST    1
 | 
|  |    371 | ++#define COMMAND_LIST_OK 2
 | 
|  |    372 | ++
 | 
|  |    373 | ++#ifndef MPD_NO_GAI
 | 
|  |    374 | ++#  ifdef AI_ADDRCONFIG
 | 
|  |    375 | ++#    define MPD_HAVE_GAI
 | 
|  |    376 | ++#  endif
 | 
|  |    377 | ++#endif
 | 
|  |    378 | ++
 | 
|  |    379 | ++#ifndef MSG_DONTWAIT
 | 
|  |    380 | ++#  define MSG_DONTWAIT 0
 | 
|  |    381 | ++#endif
 | 
|  |    382 | ++
 | 
|  |    383 | ++#ifdef WIN32
 | 
|  |    384 | ++#  define SELECT_ERRNO_IGNORE   (errno == WSAEINTR || errno == WSAEINPROGRESS)
 | 
|  |    385 | ++#  define SENDRECV_ERRNO_IGNORE SELECT_ERRNO_IGNORE
 | 
|  |    386 | ++#else
 | 
|  |    387 | ++#  define SELECT_ERRNO_IGNORE   (errno == EINTR)
 | 
|  |    388 | ++#  define SENDRECV_ERRNO_IGNORE (errno == EINTR || errno == EAGAIN)
 | 
|  |    389 | ++#  define winsock_dll_error(c)  0
 | 
|  |    390 | ++#  define closesocket(s)        close(s)
 | 
|  |    391 | ++#  define WSACleanup()          do { /* nothing */ } while (0)
 | 
|  |    392 | ++#endif
 | 
|  |    393 | ++
 | 
|  |    394 | ++#ifdef WIN32
 | 
|  |    395 | ++static int winsock_dll_error(mpd_Connection *connection)
 | 
|  |    396 | ++{
 | 
|  |    397 | ++	WSADATA wsaData;
 | 
|  |    398 | ++	if ((WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0 ||
 | 
|  |    399 | ++			LOBYTE(wsaData.wVersion) != 2 ||
 | 
|  |    400 | ++			HIBYTE(wsaData.wVersion) != 2 ) {
 | 
|  |    401 | ++		strcpy(connection->errorStr,
 | 
|  |    402 | ++		       "Could not find usable WinSock DLL.");
 | 
|  |    403 | ++		connection->error = MPD_ERROR_SYSTEM;
 | 
|  |    404 | ++		return 1;
 | 
|  |    405 | ++	}
 | 
|  |    406 | ++	return 0;
 | 
|  |    407 | ++}
 | 
|  |    408 | ++
 | 
|  |    409 | ++static int do_connect_fail(mpd_Connection *connection,
 | 
|  |    410 | ++                           const struct sockaddr *serv_addr, int addrlen)
 | 
|  |    411 | ++{
 | 
|  |    412 | ++	int iMode = 1; /* 0 = blocking, else non-blocking */
 | 
|  |    413 | ++	ioctlsocket(connection->sock, FIONBIO, (u_long FAR*) &iMode);
 | 
|  |    414 | ++	return (connect(connection->sock,serv_addr,addrlen) == SOCKET_ERROR
 | 
|  |    415 | ++			&& WSAGetLastError() != WSAEWOULDBLOCK);
 | 
|  |    416 | ++}
 | 
|  |    417 | ++#else /* !WIN32 (sane operating systems) */
 | 
|  |    418 | ++static int do_connect_fail(mpd_Connection *connection,
 | 
|  |    419 | ++                           const struct sockaddr *serv_addr, int addrlen)
 | 
|  |    420 | ++{
 | 
|  |    421 | ++	int flags = fcntl(connection->sock, F_GETFL, 0);
 | 
|  |    422 | ++	fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
 | 
|  |    423 | ++	return (connect(connection->sock,serv_addr,addrlen)<0 &&
 | 
|  |    424 | ++				errno!=EINPROGRESS);
 | 
|  |    425 | ++}
 | 
|  |    426 | ++#endif /* !WIN32 */
 | 
|  |    427 | ++
 | 
|  |    428 | ++#ifdef MPD_HAVE_GAI
 | 
|  |    429 | ++static int mpd_connect(mpd_Connection * connection, const char * host, int port,
 | 
|  |    430 | ++                       float timeout)
 | 
|  |    431 | ++{
 | 
|  |    432 | ++	int error;
 | 
|  |    433 | ++	char service[INTLEN+1];
 | 
|  |    434 | ++	struct addrinfo hints;
 | 
|  |    435 | ++	struct addrinfo *res = NULL;
 | 
|  |    436 | ++	struct addrinfo *addrinfo = NULL;
 | 
|  |    437 | ++
 | 
|  |    438 | ++	/**
 | 
|  |    439 | ++	 * Setup hints
 | 
|  |    440 | ++	 */
 | 
|  |    441 | ++	hints.ai_flags     = AI_ADDRCONFIG;
 | 
|  |    442 | ++	hints.ai_family    = PF_UNSPEC;
 | 
|  |    443 | ++	hints.ai_socktype  = SOCK_STREAM;
 | 
|  |    444 | ++	hints.ai_protocol  = IPPROTO_TCP;
 | 
|  |    445 | ++	hints.ai_addrlen   = 0;
 | 
|  |    446 | ++	hints.ai_addr      = NULL;
 | 
|  |    447 | ++	hints.ai_canonname = NULL;
 | 
|  |    448 | ++	hints.ai_next      = NULL;
 | 
|  |    449 | ++
 | 
|  |    450 | ++	snprintf(service, sizeof(service), "%i", port);
 | 
|  |    451 | ++
 | 
|  |    452 | ++	error = getaddrinfo(host, service, &hints, &addrinfo);
 | 
|  |    453 | ++
 | 
|  |    454 | ++	if (error) {
 | 
|  |    455 | ++		snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    456 | ++		         "host \"%s\" not found: %s",
 | 
|  |    457 | ++		         host, gai_strerror(error));
 | 
|  |    458 | ++		connection->error = MPD_ERROR_UNKHOST;
 | 
|  |    459 | ++		return -1;
 | 
|  |    460 | ++	}
 | 
|  |    461 | ++
 | 
|  |    462 | ++	for (res = addrinfo; res; res = res->ai_next) {
 | 
|  |    463 | ++		/* create socket */
 | 
|  |    464 | ++		connection->sock = socket(res->ai_family, SOCK_STREAM,
 | 
|  |    465 | ++		                          res->ai_protocol);
 | 
|  |    466 | ++		if (connection->sock < 0) {
 | 
|  |    467 | ++			snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    468 | ++			         "problems creating socket: %s",
 | 
|  |    469 | ++			         strerror(errno));
 | 
|  |    470 | ++			connection->error = MPD_ERROR_SYSTEM;
 | 
|  |    471 | ++			freeaddrinfo(addrinfo);
 | 
|  |    472 | ++			return -1;
 | 
|  |    473 | ++		}
 | 
|  |    474 | ++
 | 
|  |    475 | ++		mpd_setConnectionTimeout(connection, timeout);
 | 
|  |    476 | ++
 | 
|  |    477 | ++		/* connect stuff */
 | 
|  |    478 | ++ 		if (do_connect_fail(connection,
 | 
|  |    479 | ++		                    res->ai_addr, res->ai_addrlen)) {
 | 
|  |    480 | ++ 			/* try the next address family */
 | 
|  |    481 | ++ 			closesocket(connection->sock);
 | 
|  |    482 | ++ 			connection->sock = -1;
 | 
|  |    483 | ++ 			continue;
 | 
|  |    484 | ++		}
 | 
|  |    485 | ++	}
 | 
|  |    486 | ++
 | 
|  |    487 | ++	freeaddrinfo(addrinfo);
 | 
|  |    488 | ++
 | 
|  |    489 | ++	if (connection->sock < 0) {
 | 
|  |    490 | ++		snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    491 | ++		         "problems connecting to \"%s\" on port %i: %s",
 | 
|  |    492 | ++		         host, port, strerror(errno));
 | 
|  |    493 | ++		connection->error = MPD_ERROR_CONNPORT;
 | 
|  |    494 | ++
 | 
|  |    495 | ++		return -1;
 | 
|  |    496 | ++	}
 | 
|  |    497 | ++
 | 
|  |    498 | ++	return 0;
 | 
|  |    499 | ++}
 | 
|  |    500 | ++#else /* !MPD_HAVE_GAI */
 | 
|  |    501 | ++static int mpd_connect(mpd_Connection * connection, const char * host, int port,
 | 
|  |    502 | ++                       float timeout)
 | 
|  |    503 | ++{
 | 
|  |    504 | ++	struct hostent * he;
 | 
|  |    505 | ++	struct sockaddr * dest;
 | 
|  |    506 | ++	int destlen;
 | 
|  |    507 | ++	struct sockaddr_in sin;
 | 
|  |    508 | ++
 | 
|  |    509 | ++	if(!(he=gethostbyname(host))) {
 | 
|  |    510 | ++		snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    511 | ++				"host \"%s\" not found",host);
 | 
|  |    512 | ++		connection->error = MPD_ERROR_UNKHOST;
 | 
|  |    513 | ++		return -1;
 | 
|  |    514 | ++	}
 | 
|  |    515 | ++
 | 
|  |    516 | ++	memset(&sin,0,sizeof(struct sockaddr_in));
 | 
|  |    517 | ++	/*dest.sin_family = he->h_addrtype;*/
 | 
|  |    518 | ++	sin.sin_family = AF_INET;
 | 
|  |    519 | ++	sin.sin_port = htons(port);
 | 
|  |    520 | ++
 | 
|  |    521 | ++	switch(he->h_addrtype) {
 | 
|  |    522 | ++	case AF_INET:
 | 
|  |    523 | ++		memcpy((char *)&sin.sin_addr.s_addr,(char *)he->h_addr,
 | 
|  |    524 | ++				he->h_length);
 | 
|  |    525 | ++		dest = (struct sockaddr *)&sin;
 | 
|  |    526 | ++		destlen = sizeof(struct sockaddr_in);
 | 
|  |    527 | ++		break;
 | 
|  |    528 | ++	default:
 | 
|  |    529 | ++		strcpy(connection->errorStr,"address type is not IPv4");
 | 
|  |    530 | ++		connection->error = MPD_ERROR_SYSTEM;
 | 
|  |    531 | ++		return -1;
 | 
|  |    532 | ++		break;
 | 
|  |    533 | ++	}
 | 
|  |    534 | ++
 | 
|  |    535 | ++	if((connection->sock = socket(dest->sa_family,SOCK_STREAM,0))<0) {
 | 
|  |    536 | ++		strcpy(connection->errorStr,"problems creating socket");
 | 
|  |    537 | ++		connection->error = MPD_ERROR_SYSTEM;
 | 
|  |    538 | ++		return -1;
 | 
|  |    539 | ++	}
 | 
|  |    540 | ++
 | 
|  |    541 | ++	mpd_setConnectionTimeout(connection,timeout);
 | 
|  |    542 | ++
 | 
|  |    543 | ++	/* connect stuff */
 | 
|  |    544 | ++	if (do_connect_fail(connection, dest, destlen)) {
 | 
|  |    545 | ++		snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    546 | ++				"problems connecting to \"%s\" on port"
 | 
|  |    547 | ++				" %i",host,port);
 | 
|  |    548 | ++		connection->error = MPD_ERROR_CONNPORT;
 | 
|  |    549 | ++		return -1;
 | 
|  |    550 | ++	}
 | 
|  |    551 | ++
 | 
|  |    552 | ++	return 0;
 | 
|  |    553 | ++}
 | 
|  |    554 | ++#endif /* !MPD_HAVE_GAI */
 | 
|  |    555 | ++
 | 
|  |    556 | ++char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] =
 | 
|  |    557 | ++{
 | 
|  |    558 | ++	"Artist",
 | 
|  |    559 | ++	"Album",
 | 
|  |    560 | ++	"Title",
 | 
|  |    561 | ++	"Track",
 | 
|  |    562 | ++	"Name",
 | 
|  |    563 | ++	"Genre",
 | 
|  |    564 | ++	"Date",
 | 
|  |    565 | ++	"Composer",
 | 
|  |    566 | ++	"Performer",
 | 
|  |    567 | ++	"Comment",
 | 
|  |    568 | ++	"Disc",
 | 
|  |    569 | ++	"Filename",
 | 
|  |    570 | ++	"Any"
 | 
|  |    571 | ++};
 | 
|  |    572 | ++
 | 
|  |    573 | ++static char * mpd_sanitizeArg(const char * arg) {
 | 
|  |    574 | ++	size_t i;
 | 
|  |    575 | ++	char * ret;
 | 
|  |    576 | ++	register const char *c;
 | 
|  |    577 | ++	register char *rc;
 | 
|  |    578 | ++
 | 
|  |    579 | ++	/* instead of counting in that loop above, just
 | 
|  |    580 | ++	 * use a bit more memory and half running time
 | 
|  |    581 | ++	 */
 | 
|  |    582 | ++	ret = (char *)malloc(strlen(arg) * 2 + 1);
 | 
|  |    583 | ++
 | 
|  |    584 | ++	c = arg;
 | 
|  |    585 | ++	rc = ret;
 | 
|  |    586 | ++	for(i = strlen(arg)+1; i != 0; --i) {
 | 
|  |    587 | ++		if(*c=='"' || *c=='\\')
 | 
|  |    588 | ++			*rc++ = '\\';
 | 
|  |    589 | ++		*(rc++) = *(c++);
 | 
|  |    590 | ++	}
 | 
|  |    591 | ++
 | 
|  |    592 | ++	return ret;
 | 
|  |    593 | ++}
 | 
|  |    594 | ++
 | 
|  |    595 | ++static mpd_ReturnElement * mpd_newReturnElement(const char * name, const char * value)
 | 
|  |    596 | ++{
 | 
|  |    597 | ++	mpd_ReturnElement * ret = (mpd_ReturnElement *)malloc(sizeof(mpd_ReturnElement));
 | 
|  |    598 | ++
 | 
|  |    599 | ++	ret->name = strdup(name);
 | 
|  |    600 | ++	ret->value = strdup(value);
 | 
|  |    601 | ++
 | 
|  |    602 | ++	return ret;
 | 
|  |    603 | ++}
 | 
|  |    604 | ++
 | 
|  |    605 | ++static void mpd_freeReturnElement(mpd_ReturnElement * re) {
 | 
|  |    606 | ++	free(re->name);
 | 
|  |    607 | ++	free(re->value);
 | 
|  |    608 | ++	free(re);
 | 
|  |    609 | ++}
 | 
|  |    610 | ++
 | 
|  |    611 | ++void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout) {
 | 
|  |    612 | ++	connection->timeout.tv_sec = (int)timeout;
 | 
|  |    613 | ++	connection->timeout.tv_usec = (int)(timeout*1e6 -
 | 
|  |    614 | ++	                                    connection->timeout.tv_sec*1000000 +
 | 
|  |    615 | ++					    0.5);
 | 
|  |    616 | ++}
 | 
|  |    617 | ++
 | 
|  |    618 | ++static int mpd_parseWelcome(mpd_Connection * connection, const char * host, int port,
 | 
|  |    619 | ++                            char * rt, char * output) {
 | 
|  |    620 | ++	char * tmp;
 | 
|  |    621 | ++	char * test;
 | 
|  |    622 | ++	int i;
 | 
|  |    623 | ++
 | 
|  |    624 | ++	if(strncmp(output,MPD_WELCOME_MESSAGE,strlen(MPD_WELCOME_MESSAGE))) {
 | 
|  |    625 | ++		snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    626 | ++				"mpd not running on port %i on host \"%s\"",
 | 
|  |    627 | ++				port,host);
 | 
|  |    628 | ++		connection->error = MPD_ERROR_NOTMPD;
 | 
|  |    629 | ++		return 1;
 | 
|  |    630 | ++	}
 | 
|  |    631 | ++
 | 
|  |    632 | ++	tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
 | 
|  |    633 | ++
 | 
|  |    634 | ++	for(i=0;i<3;i++) {
 | 
|  |    635 | ++		if(tmp) connection->version[i] = strtol(tmp,&test,10);
 | 
|  |    636 | ++
 | 
|  |    637 | ++		if (!tmp || (test[0] != '.' && test[0] != '\0')) {
 | 
|  |    638 | ++			snprintf(connection->errorStr,
 | 
|  |    639 | ++			         MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    640 | ++			         "error parsing version number at "
 | 
|  |    641 | ++			         "\"%s\"",
 | 
|  |    642 | ++			         &output[strlen(MPD_WELCOME_MESSAGE)]);
 | 
|  |    643 | ++			connection->error = MPD_ERROR_NOTMPD;
 | 
|  |    644 | ++			return 1;
 | 
|  |    645 | ++		}
 | 
|  |    646 | ++		tmp = ++test;
 | 
|  |    647 | ++	}
 | 
|  |    648 | ++
 | 
|  |    649 | ++	return 0;
 | 
|  |    650 | ++}
 | 
|  |    651 | ++
 | 
|  |    652 | ++mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
 | 
|  |    653 | ++	int err;
 | 
|  |    654 | ++	char * rt;
 | 
|  |    655 | ++	char * output =  NULL;
 | 
|  |    656 | ++	mpd_Connection * connection = (mpd_Connection *)malloc(sizeof(mpd_Connection));
 | 
|  |    657 | ++	struct timeval tv;
 | 
|  |    658 | ++	fd_set fds;
 | 
|  |    659 | ++	strcpy(connection->buffer,"");
 | 
|  |    660 | ++	connection->buflen = 0;
 | 
|  |    661 | ++	connection->bufstart = 0;
 | 
|  |    662 | ++	strcpy(connection->errorStr,"");
 | 
|  |    663 | ++	connection->error = 0;
 | 
|  |    664 | ++	connection->doneProcessing = 0;
 | 
|  |    665 | ++	connection->commandList = 0;
 | 
|  |    666 | ++	connection->listOks = 0;
 | 
|  |    667 | ++	connection->doneListOk = 0;
 | 
|  |    668 | ++	connection->returnElement = NULL;
 | 
|  |    669 | ++	connection->request = NULL;
 | 
|  |    670 | ++
 | 
|  |    671 | ++	if (winsock_dll_error(connection))
 | 
|  |    672 | ++		return connection;
 | 
|  |    673 | ++
 | 
|  |    674 | ++	if (mpd_connect(connection, host, port, timeout) < 0)
 | 
|  |    675 | ++		return connection;
 | 
|  |    676 | ++
 | 
|  |    677 | ++	while(!(rt = strstr(connection->buffer,"\n"))) {
 | 
|  |    678 | ++		tv.tv_sec = connection->timeout.tv_sec;
 | 
|  |    679 | ++		tv.tv_usec = connection->timeout.tv_usec;
 | 
|  |    680 | ++		FD_ZERO(&fds);
 | 
|  |    681 | ++		FD_SET(connection->sock,&fds);
 | 
|  |    682 | ++		if((err = select(connection->sock+1,&fds,NULL,NULL,&tv)) == 1) {
 | 
|  |    683 | ++			int readed;
 | 
|  |    684 | ++			readed = recv(connection->sock,
 | 
|  |    685 | ++					&(connection->buffer[connection->buflen]),
 | 
|  |    686 | ++					MPD_BUFFER_MAX_LENGTH-connection->buflen,0);
 | 
|  |    687 | ++			if(readed<=0) {
 | 
|  |    688 | ++				snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    689 | ++						"problems getting a response from"
 | 
|  |    690 | ++						" \"%s\" on port %i : %s",host,
 | 
|  |    691 | ++						port, strerror(errno));
 | 
|  |    692 | ++				connection->error = MPD_ERROR_NORESPONSE;
 | 
|  |    693 | ++				return connection;
 | 
|  |    694 | ++			}
 | 
|  |    695 | ++			connection->buflen+=readed;
 | 
|  |    696 | ++			connection->buffer[connection->buflen] = '\0';
 | 
|  |    697 | ++		}
 | 
|  |    698 | ++		else if(err<0) {
 | 
|  |    699 | ++ 			if (SELECT_ERRNO_IGNORE)
 | 
|  |    700 | ++				continue;
 | 
|  |    701 | ++			snprintf(connection->errorStr,
 | 
|  |    702 | ++					MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    703 | ++					"problems connecting to \"%s\" on port"
 | 
|  |    704 | ++					" %i",host,port);
 | 
|  |    705 | ++			connection->error = MPD_ERROR_CONNPORT;
 | 
|  |    706 | ++			return connection;
 | 
|  |    707 | ++		}
 | 
|  |    708 | ++		else {
 | 
|  |    709 | ++			snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    710 | ++					"timeout in attempting to get a response from"
 | 
|  |    711 | ++					" \"%s\" on port %i",host,port);
 | 
|  |    712 | ++			connection->error = MPD_ERROR_NORESPONSE;
 | 
|  |    713 | ++			return connection;
 | 
|  |    714 | ++		}
 | 
|  |    715 | ++	}
 | 
|  |    716 | ++
 | 
|  |    717 | ++	*rt = '\0';
 | 
|  |    718 | ++	output = strdup(connection->buffer);
 | 
|  |    719 | ++	strcpy(connection->buffer,rt+1);
 | 
|  |    720 | ++	connection->buflen = strlen(connection->buffer);
 | 
|  |    721 | ++
 | 
|  |    722 | ++	if(mpd_parseWelcome(connection,host,port,rt,output) == 0) connection->doneProcessing = 1;
 | 
|  |    723 | ++
 | 
|  |    724 | ++	free(output);
 | 
|  |    725 | ++
 | 
|  |    726 | ++	return connection;
 | 
|  |    727 | ++}
 | 
|  |    728 | ++
 | 
|  |    729 | ++void mpd_clearError(mpd_Connection * connection) {
 | 
|  |    730 | ++	connection->error = 0;
 | 
|  |    731 | ++	connection->errorStr[0] = '\0';
 | 
|  |    732 | ++}
 | 
|  |    733 | ++
 | 
|  |    734 | ++void mpd_closeConnection(mpd_Connection * connection) {
 | 
|  |    735 | ++	closesocket(connection->sock);
 | 
|  |    736 | ++	if(connection->returnElement) free(connection->returnElement);
 | 
|  |    737 | ++	if(connection->request) free(connection->request);
 | 
|  |    738 | ++	free(connection);
 | 
|  |    739 | ++	WSACleanup();
 | 
|  |    740 | ++}
 | 
|  |    741 | ++
 | 
|  |    742 | ++static void mpd_executeCommand(mpd_Connection * connection, char * command) {
 | 
|  |    743 | ++	int ret;
 | 
|  |    744 | ++	struct timeval tv;
 | 
|  |    745 | ++	fd_set fds;
 | 
|  |    746 | ++	char * commandPtr = command;
 | 
|  |    747 | ++	int commandLen = strlen(command);
 | 
|  |    748 | ++
 | 
|  |    749 | ++	if(!connection->doneProcessing && !connection->commandList) {
 | 
|  |    750 | ++		strcpy(connection->errorStr,"not done processing current command");
 | 
|  |    751 | ++		connection->error = 1;
 | 
|  |    752 | ++		return;
 | 
|  |    753 | ++	}
 | 
|  |    754 | ++
 | 
|  |    755 | ++	mpd_clearError(connection);
 | 
|  |    756 | ++
 | 
|  |    757 | ++	FD_ZERO(&fds);
 | 
|  |    758 | ++	FD_SET(connection->sock,&fds);
 | 
|  |    759 | ++	tv.tv_sec = connection->timeout.tv_sec;
 | 
|  |    760 | ++	tv.tv_usec = connection->timeout.tv_usec;
 | 
|  |    761 | ++
 | 
|  |    762 | ++	while((ret = select(connection->sock+1,NULL,&fds,NULL,&tv)==1) ||
 | 
|  |    763 | ++			(ret==-1 && SELECT_ERRNO_IGNORE)) {
 | 
|  |    764 | ++		ret = send(connection->sock,commandPtr,commandLen,MSG_DONTWAIT);
 | 
|  |    765 | ++		if(ret<=0)
 | 
|  |    766 | ++		{
 | 
|  |    767 | ++			if (SENDRECV_ERRNO_IGNORE) continue;
 | 
|  |    768 | ++			snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    769 | ++			         "problems giving command \"%s\"",command);
 | 
|  |    770 | ++			connection->error = MPD_ERROR_SENDING;
 | 
|  |    771 | ++			return;
 | 
|  |    772 | ++		}
 | 
|  |    773 | ++		else {
 | 
|  |    774 | ++			commandPtr+=ret;
 | 
|  |    775 | ++			commandLen-=ret;
 | 
|  |    776 | ++		}
 | 
|  |    777 | ++
 | 
|  |    778 | ++		if(commandLen<=0) break;
 | 
|  |    779 | ++	}
 | 
|  |    780 | ++
 | 
|  |    781 | ++	if(commandLen>0) {
 | 
|  |    782 | ++		perror("");
 | 
|  |    783 | ++		snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    784 | ++		         "timeout sending command \"%s\"",command);
 | 
|  |    785 | ++		connection->error = MPD_ERROR_TIMEOUT;
 | 
|  |    786 | ++		return;
 | 
|  |    787 | ++	}
 | 
|  |    788 | ++
 | 
|  |    789 | ++	if(!connection->commandList) connection->doneProcessing = 0;
 | 
|  |    790 | ++	else if(connection->commandList == COMMAND_LIST_OK) {
 | 
|  |    791 | ++		connection->listOks++;
 | 
|  |    792 | ++	}
 | 
|  |    793 | ++}
 | 
|  |    794 | ++
 | 
|  |    795 | ++static void mpd_getNextReturnElement(mpd_Connection * connection) {
 | 
|  |    796 | ++	char * output = NULL;
 | 
|  |    797 | ++	char * rt = NULL;
 | 
|  |    798 | ++	char * name = NULL;
 | 
|  |    799 | ++	char * value = NULL;
 | 
|  |    800 | ++	fd_set fds;
 | 
|  |    801 | ++	struct timeval tv;
 | 
|  |    802 | ++	char * tok = NULL;
 | 
|  |    803 | ++	int readed;
 | 
|  |    804 | ++	char * bufferCheck = NULL;
 | 
|  |    805 | ++	int err;
 | 
|  |    806 | ++	int pos;
 | 
|  |    807 | ++
 | 
|  |    808 | ++	if(connection->returnElement) mpd_freeReturnElement(connection->returnElement);
 | 
|  |    809 | ++	connection->returnElement = NULL;
 | 
|  |    810 | ++
 | 
|  |    811 | ++	if(connection->doneProcessing || (connection->listOks &&
 | 
|  |    812 | ++	   connection->doneListOk))
 | 
|  |    813 | ++	{
 | 
|  |    814 | ++		strcpy(connection->errorStr,"already done processing current command");
 | 
|  |    815 | ++		connection->error = 1;
 | 
|  |    816 | ++		return;
 | 
|  |    817 | ++	}
 | 
|  |    818 | ++
 | 
|  |    819 | ++	bufferCheck = connection->buffer+connection->bufstart;
 | 
|  |    820 | ++	while(connection->bufstart>=connection->buflen ||
 | 
|  |    821 | ++			!(rt = strchr(bufferCheck,'\n'))) {
 | 
|  |    822 | ++		if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) {
 | 
|  |    823 | ++			memmove(connection->buffer,
 | 
|  |    824 | ++					connection->buffer+
 | 
|  |    825 | ++					connection->bufstart,
 | 
|  |    826 | ++					connection->buflen-
 | 
|  |    827 | ++					connection->bufstart+1);
 | 
|  |    828 | ++			connection->buflen-=connection->bufstart;
 | 
|  |    829 | ++			connection->bufstart = 0;
 | 
|  |    830 | ++		}
 | 
|  |    831 | ++		if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) {
 | 
|  |    832 | ++			strcpy(connection->errorStr,"buffer overrun");
 | 
|  |    833 | ++			connection->error = MPD_ERROR_BUFFEROVERRUN;
 | 
|  |    834 | ++			connection->doneProcessing = 1;
 | 
|  |    835 | ++			connection->doneListOk = 0;
 | 
|  |    836 | ++			return;
 | 
|  |    837 | ++		}
 | 
|  |    838 | ++		bufferCheck = connection->buffer+connection->buflen;
 | 
|  |    839 | ++		tv.tv_sec = connection->timeout.tv_sec;
 | 
|  |    840 | ++		tv.tv_usec = connection->timeout.tv_usec;
 | 
|  |    841 | ++		FD_ZERO(&fds);
 | 
|  |    842 | ++		FD_SET(connection->sock,&fds);
 | 
|  |    843 | ++		if((err = select(connection->sock+1,&fds,NULL,NULL,&tv) == 1)) {
 | 
|  |    844 | ++			readed = recv(connection->sock,
 | 
|  |    845 | ++					connection->buffer+connection->buflen,
 | 
|  |    846 | ++					MPD_BUFFER_MAX_LENGTH-connection->buflen,
 | 
|  |    847 | ++					MSG_DONTWAIT);
 | 
|  |    848 | ++			if(readed<0 && SENDRECV_ERRNO_IGNORE) {
 | 
|  |    849 | ++				continue;
 | 
|  |    850 | ++			}
 | 
|  |    851 | ++			if(readed<=0) {
 | 
|  |    852 | ++				strcpy(connection->errorStr,"connection"
 | 
|  |    853 | ++				       " closed");
 | 
|  |    854 | ++				connection->error = MPD_ERROR_CONNCLOSED;
 | 
|  |    855 | ++				connection->doneProcessing = 1;
 | 
|  |    856 | ++				connection->doneListOk = 0;
 | 
|  |    857 | ++				return;
 | 
|  |    858 | ++			}
 | 
|  |    859 | ++			connection->buflen+=readed;
 | 
|  |    860 | ++			connection->buffer[connection->buflen] = '\0';
 | 
|  |    861 | ++		}
 | 
|  |    862 | ++		else if(err<0 && SELECT_ERRNO_IGNORE) continue;
 | 
|  |    863 | ++		else {
 | 
|  |    864 | ++			strcpy(connection->errorStr,"connection timeout");
 | 
|  |    865 | ++			connection->error = MPD_ERROR_TIMEOUT;
 | 
|  |    866 | ++			connection->doneProcessing = 1;
 | 
|  |    867 | ++			connection->doneListOk = 0;
 | 
|  |    868 | ++			return;
 | 
|  |    869 | ++		}
 | 
|  |    870 | ++	}
 | 
|  |    871 | ++
 | 
|  |    872 | ++	*rt = '\0';
 | 
|  |    873 | ++	output = connection->buffer+connection->bufstart;
 | 
|  |    874 | ++	connection->bufstart = rt - connection->buffer + 1;
 | 
|  |    875 | ++
 | 
|  |    876 | ++	if(strcmp(output,"OK")==0) {
 | 
|  |    877 | ++		if(connection->listOks > 0) {
 | 
|  |    878 | ++			strcpy(connection->errorStr, "expected more list_OK's");
 | 
|  |    879 | ++			connection->error = 1;
 | 
|  |    880 | ++		}
 | 
|  |    881 | ++		connection->listOks = 0;
 | 
|  |    882 | ++		connection->doneProcessing = 1;
 | 
|  |    883 | ++		connection->doneListOk = 0;
 | 
|  |    884 | ++		return;
 | 
|  |    885 | ++	}
 | 
|  |    886 | ++
 | 
|  |    887 | ++	if(strcmp(output, "list_OK") == 0) {
 | 
|  |    888 | ++		if(!connection->listOks) {
 | 
|  |    889 | ++			strcpy(connection->errorStr,
 | 
|  |    890 | ++					"got an unexpected list_OK");
 | 
|  |    891 | ++			connection->error = 1;
 | 
|  |    892 | ++		}
 | 
|  |    893 | ++		else {
 | 
|  |    894 | ++			connection->doneListOk = 1;
 | 
|  |    895 | ++			connection->listOks--;
 | 
|  |    896 | ++		}
 | 
|  |    897 | ++		return;
 | 
|  |    898 | ++	}
 | 
|  |    899 | ++
 | 
|  |    900 | ++	if(strncmp(output,"ACK",strlen("ACK"))==0) {
 | 
|  |    901 | ++		char * test;
 | 
|  |    902 | ++		char * needle;
 | 
|  |    903 | ++		int val;
 | 
|  |    904 | ++
 | 
|  |    905 | ++		strcpy(connection->errorStr, output);
 | 
|  |    906 | ++		connection->error = MPD_ERROR_ACK;
 | 
|  |    907 | ++		connection->errorCode = MPD_ACK_ERROR_UNK;
 | 
|  |    908 | ++		connection->errorAt = MPD_ERROR_AT_UNK;
 | 
|  |    909 | ++		connection->doneProcessing = 1;
 | 
|  |    910 | ++		connection->doneListOk = 0;
 | 
|  |    911 | ++
 | 
|  |    912 | ++		needle = strchr(output, '[');
 | 
|  |    913 | ++		if(!needle) return;
 | 
|  |    914 | ++		val = strtol(needle+1, &test, 10);
 | 
|  |    915 | ++		if(*test != '@') return;
 | 
|  |    916 | ++		connection->errorCode = val;
 | 
|  |    917 | ++		val = strtol(test+1, &test, 10);
 | 
|  |    918 | ++		if(*test != ']') return;
 | 
|  |    919 | ++		connection->errorAt = val;
 | 
|  |    920 | ++		return;
 | 
|  |    921 | ++	}
 | 
|  |    922 | ++
 | 
|  |    923 | ++	tok = strchr(output, ':');
 | 
|  |    924 | ++	if (!tok) return;
 | 
|  |    925 | ++	pos = tok - output;
 | 
|  |    926 | ++	value = ++tok;
 | 
|  |    927 | ++	name = output;
 | 
|  |    928 | ++	name[pos] = '\0';
 | 
|  |    929 | ++
 | 
|  |    930 | ++	if(value[0]==' ') {
 | 
|  |    931 | ++		connection->returnElement = mpd_newReturnElement(name,&(value[1]));
 | 
|  |    932 | ++	}
 | 
|  |    933 | ++	else {
 | 
|  |    934 | ++		snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
 | 
|  |    935 | ++					"error parsing: %s:%s",name,value);
 | 
|  |    936 | ++		connection->error = 1;
 | 
|  |    937 | ++	}
 | 
|  |    938 | ++}
 | 
|  |    939 | ++
 | 
|  |    940 | ++void mpd_finishCommand(mpd_Connection * connection) {
 | 
|  |    941 | ++	while(!connection->doneProcessing) {
 | 
|  |    942 | ++		if(connection->doneListOk) connection->doneListOk = 0;
 | 
|  |    943 | ++		mpd_getNextReturnElement(connection);
 | 
|  |    944 | ++	}
 | 
|  |    945 | ++}
 | 
|  |    946 | ++
 | 
|  |    947 | ++static void mpd_finishListOkCommand(mpd_Connection * connection) {
 | 
|  |    948 | ++	while(!connection->doneProcessing && connection->listOks &&
 | 
|  |    949 | ++			!connection->doneListOk)
 | 
|  |    950 | ++	{
 | 
|  |    951 | ++		mpd_getNextReturnElement(connection);
 | 
|  |    952 | ++	}
 | 
|  |    953 | ++}
 | 
|  |    954 | ++
 | 
|  |    955 | ++int mpd_nextListOkCommand(mpd_Connection * connection) {
 | 
|  |    956 | ++	mpd_finishListOkCommand(connection);
 | 
|  |    957 | ++	if(!connection->doneProcessing) connection->doneListOk = 0;
 | 
|  |    958 | ++	if(connection->listOks == 0 || connection->doneProcessing) return -1;
 | 
|  |    959 | ++	return 0;
 | 
|  |    960 | ++}
 | 
|  |    961 | ++
 | 
|  |    962 | ++void mpd_sendStatusCommand(mpd_Connection * connection) {
 | 
|  |    963 | ++	mpd_executeCommand(connection,"status\n");
 | 
|  |    964 | ++}
 | 
|  |    965 | ++
 | 
|  |    966 | ++mpd_Status * mpd_getStatus(mpd_Connection * connection) {
 | 
|  |    967 | ++	mpd_Status * status;
 | 
|  |    968 | ++
 | 
|  |    969 | ++	/*mpd_executeCommand(connection,"status\n");
 | 
|  |    970 | ++
 | 
|  |    971 | ++	if(connection->error) return NULL;*/
 | 
|  |    972 | ++
 | 
|  |    973 | ++	if(connection->doneProcessing || (connection->listOks &&
 | 
|  |    974 | ++	   connection->doneListOk))
 | 
|  |    975 | ++	{
 | 
|  |    976 | ++		return NULL;
 | 
|  |    977 | ++	}
 | 
|  |    978 | ++
 | 
|  |    979 | ++	if(!connection->returnElement) mpd_getNextReturnElement(connection);
 | 
|  |    980 | ++
 | 
|  |    981 | ++	status = (mpd_Status *)malloc(sizeof(mpd_Status));
 | 
|  |    982 | ++	status->volume = -1;
 | 
|  |    983 | ++	status->repeat = 0;
 | 
|  |    984 | ++	status->random = 0;
 | 
|  |    985 | ++	status->playlist = -1;
 | 
|  |    986 | ++	status->playlistLength = -1;
 | 
|  |    987 | ++	status->state = -1;
 | 
|  |    988 | ++	status->song = 0;
 | 
|  |    989 | ++	status->songid = 0;
 | 
|  |    990 | ++	status->elapsedTime = 0;
 | 
|  |    991 | ++	status->totalTime = 0;
 | 
|  |    992 | ++	status->bitRate = 0;
 | 
|  |    993 | ++	status->sampleRate = 0;
 | 
|  |    994 | ++	status->bits = 0;
 | 
|  |    995 | ++	status->channels = 0;
 | 
|  |    996 | ++	status->crossfade = -1;
 | 
|  |    997 | ++	status->error = NULL;
 | 
|  |    998 | ++	status->updatingDb = 0;
 | 
|  |    999 | ++
 | 
|  |   1000 | ++	if(connection->error) {
 | 
|  |   1001 | ++		free(status);
 | 
|  |   1002 | ++		return NULL;
 | 
|  |   1003 | ++	}
 | 
|  |   1004 | ++	while(connection->returnElement) {
 | 
|  |   1005 | ++		mpd_ReturnElement * re = connection->returnElement;
 | 
|  |   1006 | ++		if(strcmp(re->name,"volume")==0) {
 | 
|  |   1007 | ++			status->volume = atoi(re->value);
 | 
|  |   1008 | ++		}
 | 
|  |   1009 | ++		else if(strcmp(re->name,"repeat")==0) {
 | 
|  |   1010 | ++			status->repeat = atoi(re->value);
 | 
|  |   1011 | ++		}
 | 
|  |   1012 | ++		else if(strcmp(re->name,"random")==0) {
 | 
|  |   1013 | ++			status->random = atoi(re->value);
 | 
|  |   1014 | ++		}
 | 
|  |   1015 | ++		else if(strcmp(re->name,"playlist")==0) {
 | 
|  |   1016 | ++			status->playlist = strtol(re->value,NULL,10);
 | 
|  |   1017 | ++		}
 | 
|  |   1018 | ++		else if(strcmp(re->name,"playlistlength")==0) {
 | 
|  |   1019 | ++			status->playlistLength = atoi(re->value);
 | 
|  |   1020 | ++		}
 | 
|  |   1021 | ++		else if(strcmp(re->name,"bitrate")==0) {
 | 
|  |   1022 | ++			status->bitRate = atoi(re->value);
 | 
|  |   1023 | ++		}
 | 
|  |   1024 | ++		else if(strcmp(re->name,"state")==0) {
 | 
|  |   1025 | ++			if(strcmp(re->value,"play")==0) {
 | 
|  |   1026 | ++				status->state = MPD_STATUS_STATE_PLAY;
 | 
|  |   1027 | ++			}
 | 
|  |   1028 | ++			else if(strcmp(re->value,"stop")==0) {
 | 
|  |   1029 | ++				status->state = MPD_STATUS_STATE_STOP;
 | 
|  |   1030 | ++			}
 | 
|  |   1031 | ++			else if(strcmp(re->value,"pause")==0) {
 | 
|  |   1032 | ++				status->state = MPD_STATUS_STATE_PAUSE;
 | 
|  |   1033 | ++			}
 | 
|  |   1034 | ++			else {
 | 
|  |   1035 | ++				status->state = MPD_STATUS_STATE_UNKNOWN;
 | 
|  |   1036 | ++			}
 | 
|  |   1037 | ++		}
 | 
|  |   1038 | ++		else if(strcmp(re->name,"song")==0) {
 | 
|  |   1039 | ++			status->song = atoi(re->value);
 | 
|  |   1040 | ++		}
 | 
|  |   1041 | ++		else if(strcmp(re->name,"songid")==0) {
 | 
|  |   1042 | ++			status->songid = atoi(re->value);
 | 
|  |   1043 | ++		}
 | 
|  |   1044 | ++		else if(strcmp(re->name,"time")==0) {
 | 
|  |   1045 | ++			char * tok = strchr(re->value,':');
 | 
|  |   1046 | ++			/* the second strchr below is a safety check */
 | 
|  |   1047 | ++			if (tok && (strchr(tok,0) > (tok+1))) {
 | 
|  |   1048 | ++				/* atoi stops at the first non-[0-9] char: */
 | 
|  |   1049 | ++				status->elapsedTime = atoi(re->value);
 | 
|  |   1050 | ++				status->totalTime = atoi(tok+1);
 | 
|  |   1051 | ++			}
 | 
|  |   1052 | ++		}
 | 
|  |   1053 | ++		else if(strcmp(re->name,"error")==0) {
 | 
|  |   1054 | ++			status->error = strdup(re->value);
 | 
|  |   1055 | ++		}
 | 
|  |   1056 | ++		else if(strcmp(re->name,"xfade")==0) {
 | 
|  |   1057 | ++			status->crossfade = atoi(re->value);
 | 
|  |   1058 | ++		}
 | 
|  |   1059 | ++		else if(strcmp(re->name,"updating_db")==0) {
 | 
|  |   1060 | ++			status->updatingDb = atoi(re->value);
 | 
|  |   1061 | ++		}
 | 
|  |   1062 | ++		else if(strcmp(re->name,"audio")==0) {
 | 
|  |   1063 | ++			char * tok = strchr(re->value,':');
 | 
|  |   1064 | ++			if (tok && (strchr(tok,0) > (tok+1))) {
 | 
|  |   1065 | ++				status->sampleRate = atoi(re->value);
 | 
|  |   1066 | ++				status->bits = atoi(++tok);
 | 
|  |   1067 | ++				tok = strchr(tok,':');
 | 
|  |   1068 | ++				if (tok && (strchr(tok,0) > (tok+1)))
 | 
|  |   1069 | ++					status->channels = atoi(tok+1);
 | 
|  |   1070 | ++			}
 | 
|  |   1071 | ++		}
 | 
|  |   1072 | ++
 | 
|  |   1073 | ++		mpd_getNextReturnElement(connection);
 | 
|  |   1074 | ++		if(connection->error) {
 | 
|  |   1075 | ++			free(status);
 | 
|  |   1076 | ++			return NULL;
 | 
|  |   1077 | ++		}
 | 
|  |   1078 | ++	}
 | 
|  |   1079 | ++
 | 
|  |   1080 | ++	if(connection->error) {
 | 
|  |   1081 | ++		free(status);
 | 
|  |   1082 | ++		return NULL;
 | 
|  |   1083 | ++	}
 | 
|  |   1084 | ++	else if(status->state<0) {
 | 
|  |   1085 | ++		strcpy(connection->errorStr,"state not found");
 | 
|  |   1086 | ++		connection->error = 1;
 | 
|  |   1087 | ++		free(status);
 | 
|  |   1088 | ++		return NULL;
 | 
|  |   1089 | ++	}
 | 
|  |   1090 | ++
 | 
|  |   1091 | ++	return status;
 | 
|  |   1092 | ++}
 | 
|  |   1093 | ++
 | 
|  |   1094 | ++void mpd_freeStatus(mpd_Status * status) {
 | 
|  |   1095 | ++	if(status->error) free(status->error);
 | 
|  |   1096 | ++	free(status);
 | 
|  |   1097 | ++}
 | 
|  |   1098 | ++
 | 
|  |   1099 | ++void mpd_sendStatsCommand(mpd_Connection * connection) {
 | 
|  |   1100 | ++	mpd_executeCommand(connection,"stats\n");
 | 
|  |   1101 | ++}
 | 
|  |   1102 | ++
 | 
|  |   1103 | ++mpd_Stats * mpd_getStats(mpd_Connection * connection) {
 | 
|  |   1104 | ++	mpd_Stats * stats;
 | 
|  |   1105 | ++
 | 
|  |   1106 | ++	/*mpd_executeCommand(connection,"stats\n");
 | 
|  |   1107 | ++
 | 
|  |   1108 | ++	if(connection->error) return NULL;*/
 | 
|  |   1109 | ++
 | 
|  |   1110 | ++	if(connection->doneProcessing || (connection->listOks &&
 | 
|  |   1111 | ++	   connection->doneListOk))
 | 
|  |   1112 | ++	{
 | 
|  |   1113 | ++		return NULL;
 | 
|  |   1114 | ++	}
 | 
|  |   1115 | ++
 | 
|  |   1116 | ++	if(!connection->returnElement) mpd_getNextReturnElement(connection);
 | 
|  |   1117 | ++
 | 
|  |   1118 | ++	stats = (mpd_Stats *)malloc(sizeof(mpd_Stats));
 | 
|  |   1119 | ++	stats->numberOfArtists = 0;
 | 
|  |   1120 | ++	stats->numberOfAlbums = 0;
 | 
|  |   1121 | ++	stats->numberOfSongs = 0;
 | 
|  |   1122 | ++	stats->uptime = 0;
 | 
|  |   1123 | ++	stats->dbUpdateTime = 0;
 | 
|  |   1124 | ++	stats->playTime = 0;
 | 
|  |   1125 | ++	stats->dbPlayTime = 0;
 | 
|  |   1126 | ++
 | 
|  |   1127 | ++	if(connection->error) {
 | 
|  |   1128 | ++		free(stats);
 | 
|  |   1129 | ++		return NULL;
 | 
|  |   1130 | ++	}
 | 
|  |   1131 | ++	while(connection->returnElement) {
 | 
|  |   1132 | ++		mpd_ReturnElement * re = connection->returnElement;
 | 
|  |   1133 | ++		if(strcmp(re->name,"artists")==0) {
 | 
|  |   1134 | ++			stats->numberOfArtists = atoi(re->value);
 | 
|  |   1135 | ++		}
 | 
|  |   1136 | ++		else if(strcmp(re->name,"albums")==0) {
 | 
|  |   1137 | ++			stats->numberOfAlbums = atoi(re->value);
 | 
|  |   1138 | ++		}
 | 
|  |   1139 | ++		else if(strcmp(re->name,"songs")==0) {
 | 
|  |   1140 | ++			stats->numberOfSongs = atoi(re->value);
 | 
|  |   1141 | ++		}
 | 
|  |   1142 | ++		else if(strcmp(re->name,"uptime")==0) {
 | 
|  |   1143 | ++			stats->uptime = strtol(re->value,NULL,10);
 | 
|  |   1144 | ++		}
 | 
|  |   1145 | ++		else if(strcmp(re->name,"db_update")==0) {
 | 
|  |   1146 | ++			stats->dbUpdateTime = strtol(re->value,NULL,10);
 | 
|  |   1147 | ++		}
 | 
|  |   1148 | ++		else if(strcmp(re->name,"playtime")==0) {
 | 
|  |   1149 | ++			stats->playTime = strtol(re->value,NULL,10);
 | 
|  |   1150 | ++		}
 | 
|  |   1151 | ++		else if(strcmp(re->name,"db_playtime")==0) {
 | 
|  |   1152 | ++			stats->dbPlayTime = strtol(re->value,NULL,10);
 | 
|  |   1153 | ++		}
 | 
|  |   1154 | ++
 | 
|  |   1155 | ++		mpd_getNextReturnElement(connection);
 | 
|  |   1156 | ++		if(connection->error) {
 | 
|  |   1157 | ++			free(stats);
 | 
|  |   1158 | ++			return NULL;
 | 
|  |   1159 | ++		}
 | 
|  |   1160 | ++	}
 | 
|  |   1161 | ++
 | 
|  |   1162 | ++	if(connection->error) {
 | 
|  |   1163 | ++		free(stats);
 | 
|  |   1164 | ++		return NULL;
 | 
|  |   1165 | ++	}
 | 
|  |   1166 | ++
 | 
|  |   1167 | ++	return stats;
 | 
|  |   1168 | ++}
 | 
|  |   1169 | ++
 | 
|  |   1170 | ++void mpd_freeStats(mpd_Stats * stats) {
 | 
|  |   1171 | ++	free(stats);
 | 
|  |   1172 | ++}
 | 
|  |   1173 | ++
 | 
|  |   1174 | ++mpd_SearchStats * mpd_getSearchStats(mpd_Connection * connection)
 | 
|  |   1175 | ++{
 | 
|  |   1176 | ++	mpd_SearchStats * stats;
 | 
|  |   1177 | ++	mpd_ReturnElement * re;
 | 
|  |   1178 | ++
 | 
|  |   1179 | ++	if (connection->doneProcessing ||
 | 
|  |   1180 | ++	    (connection->listOks && connection->doneListOk)) {
 | 
|  |   1181 | ++		return NULL;
 | 
|  |   1182 | ++	}
 | 
|  |   1183 | ++
 | 
|  |   1184 | ++	if (!connection->returnElement) mpd_getNextReturnElement(connection);
 | 
|  |   1185 | ++
 | 
|  |   1186 | ++	if (connection->error)
 | 
|  |   1187 | ++		return NULL;
 | 
|  |   1188 | ++
 | 
|  |   1189 | ++	stats = (mpd_SearchStats *)malloc(sizeof(mpd_SearchStats));
 | 
|  |   1190 | ++	stats->numberOfSongs = 0;
 | 
|  |   1191 | ++	stats->playTime = 0;
 | 
|  |   1192 | ++
 | 
|  |   1193 | ++	while (connection->returnElement) {
 | 
|  |   1194 | ++		re = connection->returnElement;
 | 
|  |   1195 | ++
 | 
|  |   1196 | ++		if (strcmp(re->name, "songs") == 0) {
 | 
|  |   1197 | ++			stats->numberOfSongs = atoi(re->value);
 | 
|  |   1198 | ++		} else if (strcmp(re->name, "playtime") == 0) {
 | 
|  |   1199 | ++			stats->playTime = strtol(re->value, NULL, 10);
 | 
|  |   1200 | ++		}
 | 
|  |   1201 | ++
 | 
|  |   1202 | ++		mpd_getNextReturnElement(connection);
 | 
|  |   1203 | ++		if (connection->error) {
 | 
|  |   1204 | ++			free(stats);
 | 
|  |   1205 | ++			return NULL;
 | 
|  |   1206 | ++		}
 | 
|  |   1207 | ++	}
 | 
|  |   1208 | ++
 | 
|  |   1209 | ++	if (connection->error) {
 | 
|  |   1210 | ++		free(stats);
 | 
|  |   1211 | ++		return NULL;
 | 
|  |   1212 | ++	}
 | 
|  |   1213 | ++
 | 
|  |   1214 | ++	return stats;
 | 
|  |   1215 | ++}
 | 
|  |   1216 | ++
 | 
|  |   1217 | ++void mpd_freeSearchStats(mpd_SearchStats * stats)
 | 
|  |   1218 | ++{
 | 
|  |   1219 | ++	free(stats);
 | 
|  |   1220 | ++}
 | 
|  |   1221 | ++
 | 
|  |   1222 | ++static void mpd_initSong(mpd_Song * song) {
 | 
|  |   1223 | ++	song->file = NULL;
 | 
|  |   1224 | ++	song->artist = NULL;
 | 
|  |   1225 | ++	song->album = NULL;
 | 
|  |   1226 | ++	song->track = NULL;
 | 
|  |   1227 | ++	song->title = NULL;
 | 
|  |   1228 | ++	song->name = NULL;
 | 
|  |   1229 | ++	song->date = NULL;
 | 
|  |   1230 | ++	/* added by Qball */
 | 
|  |   1231 | ++	song->genre = NULL;
 | 
|  |   1232 | ++	song->composer = NULL;
 | 
|  |   1233 | ++	song->performer = NULL;
 | 
|  |   1234 | ++	song->disc = NULL;
 | 
|  |   1235 | ++	song->comment = NULL;
 | 
|  |   1236 | ++
 | 
|  |   1237 | ++	song->time = MPD_SONG_NO_TIME;
 | 
|  |   1238 | ++	song->pos = MPD_SONG_NO_NUM;
 | 
|  |   1239 | ++	song->id = MPD_SONG_NO_ID;
 | 
|  |   1240 | ++}
 | 
|  |   1241 | ++
 | 
|  |   1242 | ++static void mpd_finishSong(mpd_Song * song) {
 | 
|  |   1243 | ++	if(song->file) free(song->file);
 | 
|  |   1244 | ++	if(song->artist) free(song->artist);
 | 
|  |   1245 | ++	if(song->album) free(song->album);
 | 
|  |   1246 | ++	if(song->title) free(song->title);
 | 
|  |   1247 | ++	if(song->track) free(song->track);
 | 
|  |   1248 | ++	if(song->name) free(song->name);
 | 
|  |   1249 | ++	if(song->date) free(song->date);
 | 
|  |   1250 | ++	if(song->genre) free(song->genre);
 | 
|  |   1251 | ++	if(song->composer) free(song->composer);
 | 
|  |   1252 | ++	if(song->disc) free(song->disc);
 | 
|  |   1253 | ++	if(song->comment) free(song->comment);
 | 
|  |   1254 | ++}
 | 
|  |   1255 | ++
 | 
|  |   1256 | ++mpd_Song * mpd_newSong(void) {
 | 
|  |   1257 | ++	mpd_Song * ret = (mpd_Song *)malloc(sizeof(mpd_Song));
 | 
|  |   1258 | ++
 | 
|  |   1259 | ++	mpd_initSong(ret);
 | 
|  |   1260 | ++
 | 
|  |   1261 | ++	return ret;
 | 
|  |   1262 | ++}
 | 
|  |   1263 | ++
 | 
|  |   1264 | ++void mpd_freeSong(mpd_Song * song) {
 | 
|  |   1265 | ++	mpd_finishSong(song);
 | 
|  |   1266 | ++	free(song);
 | 
|  |   1267 | ++}
 | 
|  |   1268 | ++
 | 
|  |   1269 | ++mpd_Song * mpd_songDup(mpd_Song * song) {
 | 
|  |   1270 | ++	mpd_Song * ret = mpd_newSong();
 | 
|  |   1271 | ++
 | 
|  |   1272 | ++	if(song->file) ret->file = strdup(song->file);
 | 
|  |   1273 | ++	if(song->artist) ret->artist = strdup(song->artist);
 | 
|  |   1274 | ++	if(song->album) ret->album = strdup(song->album);
 | 
|  |   1275 | ++	if(song->title) ret->title = strdup(song->title);
 | 
|  |   1276 | ++	if(song->track) ret->track = strdup(song->track);
 | 
|  |   1277 | ++	if(song->name) ret->name = strdup(song->name);
 | 
|  |   1278 | ++	if(song->date) ret->date = strdup(song->date);
 | 
|  |   1279 | ++	if(song->genre) ret->genre= strdup(song->genre);
 | 
|  |   1280 | ++	if(song->composer) ret->composer= strdup(song->composer);
 | 
|  |   1281 | ++	if(song->disc) ret->disc = strdup(song->disc);
 | 
|  |   1282 | ++	if(song->comment) ret->comment = strdup(song->comment);
 | 
|  |   1283 | ++	ret->time = song->time;
 | 
|  |   1284 | ++	ret->pos = song->pos;
 | 
|  |   1285 | ++	ret->id = song->id;
 | 
|  |   1286 | ++
 | 
|  |   1287 | ++	return ret;
 | 
|  |   1288 | ++}
 | 
|  |   1289 | ++
 | 
|  |   1290 | ++static void mpd_initDirectory(mpd_Directory * directory) {
 | 
|  |   1291 | ++	directory->path = NULL;
 | 
|  |   1292 | ++}
 | 
|  |   1293 | ++
 | 
|  |   1294 | ++static void mpd_finishDirectory(mpd_Directory * directory) {
 | 
|  |   1295 | ++	if(directory->path) free(directory->path);
 | 
|  |   1296 | ++}
 | 
|  |   1297 | ++
 | 
|  |   1298 | ++mpd_Directory * mpd_newDirectory(void) {
 | 
|  |   1299 | ++	mpd_Directory * directory = (mpd_Directory *)malloc(sizeof(mpd_Directory));;
 | 
|  |   1300 | ++
 | 
|  |   1301 | ++	mpd_initDirectory(directory);
 | 
|  |   1302 | ++
 | 
|  |   1303 | ++	return directory;
 | 
|  |   1304 | ++}
 | 
|  |   1305 | ++
 | 
|  |   1306 | ++void mpd_freeDirectory(mpd_Directory * directory) {
 | 
|  |   1307 | ++	mpd_finishDirectory(directory);
 | 
|  |   1308 | ++
 | 
|  |   1309 | ++	free(directory);
 | 
|  |   1310 | ++}
 | 
|  |   1311 | ++
 | 
|  |   1312 | ++mpd_Directory * mpd_directoryDup(mpd_Directory * directory) {
 | 
|  |   1313 | ++	mpd_Directory * ret = mpd_newDirectory();
 | 
|  |   1314 | ++
 | 
|  |   1315 | ++	if(directory->path) ret->path = strdup(directory->path);
 | 
|  |   1316 | ++
 | 
|  |   1317 | ++	return ret;
 | 
|  |   1318 | ++}
 | 
|  |   1319 | ++
 | 
|  |   1320 | ++static void mpd_initPlaylistFile(mpd_PlaylistFile * playlist) {
 | 
|  |   1321 | ++	playlist->path = NULL;
 | 
|  |   1322 | ++}
 | 
|  |   1323 | ++
 | 
|  |   1324 | ++static void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist) {
 | 
|  |   1325 | ++	if(playlist->path) free(playlist->path);
 | 
|  |   1326 | ++}
 | 
|  |   1327 | ++
 | 
|  |   1328 | ++mpd_PlaylistFile * mpd_newPlaylistFile(void) {
 | 
|  |   1329 | ++	mpd_PlaylistFile * playlist = (mpd_PlaylistFile *)malloc(sizeof(mpd_PlaylistFile));
 | 
|  |   1330 | ++
 | 
|  |   1331 | ++	mpd_initPlaylistFile(playlist);
 | 
|  |   1332 | ++
 | 
|  |   1333 | ++	return playlist;
 | 
|  |   1334 | ++}
 | 
|  |   1335 | ++
 | 
|  |   1336 | ++void mpd_freePlaylistFile(mpd_PlaylistFile * playlist) {
 | 
|  |   1337 | ++	mpd_finishPlaylistFile(playlist);
 | 
|  |   1338 | ++	free(playlist);
 | 
|  |   1339 | ++}
 | 
|  |   1340 | ++
 | 
|  |   1341 | ++mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist) {
 | 
|  |   1342 | ++	mpd_PlaylistFile * ret = mpd_newPlaylistFile();
 | 
|  |   1343 | ++
 | 
|  |   1344 | ++	if(playlist->path) ret->path = strdup(playlist->path);
 | 
|  |   1345 | ++
 | 
|  |   1346 | ++	return ret;
 | 
|  |   1347 | ++}
 | 
|  |   1348 | ++
 | 
|  |   1349 | ++static void mpd_initInfoEntity(mpd_InfoEntity * entity) {
 | 
|  |   1350 | ++	entity->info.directory = NULL;
 | 
|  |   1351 | ++}
 | 
|  |   1352 | ++
 | 
|  |   1353 | ++static void mpd_finishInfoEntity(mpd_InfoEntity * entity) {
 | 
|  |   1354 | ++	if(entity->info.directory) {
 | 
|  |   1355 | ++		if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
 | 
|  |   1356 | ++			mpd_freeDirectory(entity->info.directory);
 | 
|  |   1357 | ++		}
 | 
|  |   1358 | ++		else if(entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
 | 
|  |   1359 | ++			mpd_freeSong(entity->info.song);
 | 
|  |   1360 | ++		}
 | 
|  |   1361 | ++		else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
 | 
|  |   1362 | ++			mpd_freePlaylistFile(entity->info.playlistFile);
 | 
|  |   1363 | ++		}
 | 
|  |   1364 | ++	}
 | 
|  |   1365 | ++}
 | 
|  |   1366 | ++
 | 
|  |   1367 | ++mpd_InfoEntity * mpd_newInfoEntity(void) {
 | 
|  |   1368 | ++	mpd_InfoEntity * entity = (mpd_InfoEntity *)malloc(sizeof(mpd_InfoEntity));
 | 
|  |   1369 | ++
 | 
|  |   1370 | ++	mpd_initInfoEntity(entity);
 | 
|  |   1371 | ++
 | 
|  |   1372 | ++	return entity;
 | 
|  |   1373 | ++}
 | 
|  |   1374 | ++
 | 
|  |   1375 | ++void mpd_freeInfoEntity(mpd_InfoEntity * entity) {
 | 
|  |   1376 | ++	mpd_finishInfoEntity(entity);
 | 
|  |   1377 | ++	free(entity);
 | 
|  |   1378 | ++}
 | 
|  |   1379 | ++
 | 
|  |   1380 | ++static void mpd_sendInfoCommand(mpd_Connection * connection, char * command) {
 | 
|  |   1381 | ++	mpd_executeCommand(connection,command);
 | 
|  |   1382 | ++}
 | 
|  |   1383 | ++
 | 
|  |   1384 | ++mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection) {
 | 
|  |   1385 | ++	mpd_InfoEntity * entity = NULL;
 | 
|  |   1386 | ++
 | 
|  |   1387 | ++	if(connection->doneProcessing || (connection->listOks &&
 | 
|  |   1388 | ++	   connection->doneListOk))
 | 
|  |   1389 | ++	{
 | 
|  |   1390 | ++		return NULL;
 | 
|  |   1391 | ++	}
 | 
|  |   1392 | ++
 | 
|  |   1393 | ++	if(!connection->returnElement) mpd_getNextReturnElement(connection);
 | 
|  |   1394 | ++
 | 
|  |   1395 | ++	if(connection->returnElement) {
 | 
|  |   1396 | ++		if(strcmp(connection->returnElement->name,"file")==0) {
 | 
|  |   1397 | ++			entity = mpd_newInfoEntity();
 | 
|  |   1398 | ++			entity->type = MPD_INFO_ENTITY_TYPE_SONG;
 | 
|  |   1399 | ++			entity->info.song = mpd_newSong();
 | 
|  |   1400 | ++			entity->info.song->file =
 | 
|  |   1401 | ++				strdup(connection->returnElement->value);
 | 
|  |   1402 | ++		}
 | 
|  |   1403 | ++		else if(strcmp(connection->returnElement->name,
 | 
|  |   1404 | ++					"directory")==0) {
 | 
|  |   1405 | ++			entity = mpd_newInfoEntity();
 | 
|  |   1406 | ++			entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
 | 
|  |   1407 | ++			entity->info.directory = mpd_newDirectory();
 | 
|  |   1408 | ++			entity->info.directory->path =
 | 
|  |   1409 | ++				strdup(connection->returnElement->value);
 | 
|  |   1410 | ++		}
 | 
|  |   1411 | ++		else if(strcmp(connection->returnElement->name,"playlist")==0) {
 | 
|  |   1412 | ++			entity = mpd_newInfoEntity();
 | 
|  |   1413 | ++			entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
 | 
|  |   1414 | ++			entity->info.playlistFile = mpd_newPlaylistFile();
 | 
|  |   1415 | ++			entity->info.playlistFile->path =
 | 
|  |   1416 | ++				strdup(connection->returnElement->value);
 | 
|  |   1417 | ++		}
 | 
|  |   1418 | ++		else if(strcmp(connection->returnElement->name, "cpos") == 0){
 | 
|  |   1419 | ++			entity = mpd_newInfoEntity();
 | 
|  |   1420 | ++			entity->type = MPD_INFO_ENTITY_TYPE_SONG;
 | 
|  |   1421 | ++			entity->info.song = mpd_newSong();
 | 
|  |   1422 | ++			entity->info.song->pos = atoi(connection->returnElement->value);
 | 
|  |   1423 | ++		}
 | 
|  |   1424 | ++		else {
 | 
|  |   1425 | ++			connection->error = 1;
 | 
|  |   1426 | ++			strcpy(connection->errorStr,"problem parsing song info");
 | 
|  |   1427 | ++			return NULL;
 | 
|  |   1428 | ++		}
 | 
|  |   1429 | ++	}
 | 
|  |   1430 | ++	else return NULL;
 | 
|  |   1431 | ++
 | 
|  |   1432 | ++	mpd_getNextReturnElement(connection);
 | 
|  |   1433 | ++	while(connection->returnElement) {
 | 
|  |   1434 | ++		mpd_ReturnElement * re = connection->returnElement;
 | 
|  |   1435 | ++
 | 
|  |   1436 | ++		if(strcmp(re->name,"file")==0) return entity;
 | 
|  |   1437 | ++		else if(strcmp(re->name,"directory")==0) return entity;
 | 
|  |   1438 | ++		else if(strcmp(re->name,"playlist")==0) return entity;
 | 
|  |   1439 | ++		else if(strcmp(re->name,"cpos")==0) return entity;
 | 
|  |   1440 | ++
 | 
|  |   1441 | ++		if(entity->type == MPD_INFO_ENTITY_TYPE_SONG &&
 | 
|  |   1442 | ++				strlen(re->value)) {
 | 
|  |   1443 | ++			if(!entity->info.song->artist &&
 | 
|  |   1444 | ++					strcmp(re->name,"Artist")==0) {
 | 
|  |   1445 | ++				entity->info.song->artist = strdup(re->value);
 | 
|  |   1446 | ++			}
 | 
|  |   1447 | ++			else if(!entity->info.song->album &&
 | 
|  |   1448 | ++					strcmp(re->name,"Album")==0) {
 | 
|  |   1449 | ++				entity->info.song->album = strdup(re->value);
 | 
|  |   1450 | ++			}
 | 
|  |   1451 | ++			else if(!entity->info.song->title &&
 | 
|  |   1452 | ++					strcmp(re->name,"Title")==0) {
 | 
|  |   1453 | ++				entity->info.song->title = strdup(re->value);
 | 
|  |   1454 | ++			}
 | 
|  |   1455 | ++			else if(!entity->info.song->track &&
 | 
|  |   1456 | ++					strcmp(re->name,"Track")==0) {
 | 
|  |   1457 | ++				entity->info.song->track = strdup(re->value);
 | 
|  |   1458 | ++			}
 | 
|  |   1459 | ++			else if(!entity->info.song->name &&
 | 
|  |   1460 | ++					strcmp(re->name,"Name")==0) {
 | 
|  |   1461 | ++				entity->info.song->name = strdup(re->value);
 | 
|  |   1462 | ++			}
 | 
|  |   1463 | ++			else if(entity->info.song->time==MPD_SONG_NO_TIME &&
 | 
|  |   1464 | ++					strcmp(re->name,"Time")==0) {
 | 
|  |   1465 | ++				entity->info.song->time = atoi(re->value);
 | 
|  |   1466 | ++			}
 | 
|  |   1467 | ++			else if(entity->info.song->pos==MPD_SONG_NO_NUM &&
 | 
|  |   1468 | ++					strcmp(re->name,"Pos")==0) {
 | 
|  |   1469 | ++				entity->info.song->pos = atoi(re->value);
 | 
|  |   1470 | ++			}
 | 
|  |   1471 | ++			else if(entity->info.song->id==MPD_SONG_NO_ID &&
 | 
|  |   1472 | ++					strcmp(re->name,"Id")==0) {
 | 
|  |   1473 | ++				entity->info.song->id = atoi(re->value);
 | 
|  |   1474 | ++			}
 | 
|  |   1475 | ++			else if(!entity->info.song->date &&
 | 
|  |   1476 | ++					strcmp(re->name, "Date") == 0) {
 | 
|  |   1477 | ++				entity->info.song->date = strdup(re->value);
 | 
|  |   1478 | ++			}
 | 
|  |   1479 | ++			else if(!entity->info.song->genre &&
 | 
|  |   1480 | ++					strcmp(re->name, "Genre") == 0) {
 | 
|  |   1481 | ++				entity->info.song->genre = strdup(re->value);
 | 
|  |   1482 | ++			}
 | 
|  |   1483 | ++			else if(!entity->info.song->composer &&
 | 
|  |   1484 | ++					strcmp(re->name, "Composer") == 0) {
 | 
|  |   1485 | ++				entity->info.song->composer = strdup(re->value);
 | 
|  |   1486 | ++			}
 | 
|  |   1487 | ++			else if(!entity->info.song->performer &&
 | 
|  |   1488 | ++					strcmp(re->name, "Performer") == 0) {
 | 
|  |   1489 | ++				entity->info.song->performer = strdup(re->value);
 | 
|  |   1490 | ++			}
 | 
|  |   1491 | ++			else if(!entity->info.song->disc &&
 | 
|  |   1492 | ++					strcmp(re->name, "Disc") == 0) {
 | 
|  |   1493 | ++				entity->info.song->disc = strdup(re->value);
 | 
|  |   1494 | ++			}
 | 
|  |   1495 | ++			else if(!entity->info.song->comment &&
 | 
|  |   1496 | ++					strcmp(re->name, "Comment") == 0) {
 | 
|  |   1497 | ++				entity->info.song->comment = strdup(re->value);
 | 
|  |   1498 | ++			}
 | 
|  |   1499 | ++		}
 | 
|  |   1500 | ++		else if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
 | 
|  |   1501 | ++		}
 | 
|  |   1502 | ++		else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
 | 
|  |   1503 | ++		}
 | 
|  |   1504 | ++
 | 
|  |   1505 | ++		mpd_getNextReturnElement(connection);
 | 
|  |   1506 | ++	}
 | 
|  |   1507 | ++
 | 
|  |   1508 | ++	return entity;
 | 
|  |   1509 | ++}
 | 
|  |   1510 | ++
 | 
|  |   1511 | ++static char * mpd_getNextReturnElementNamed(mpd_Connection * connection,
 | 
|  |   1512 | ++		const char * name)
 | 
|  |   1513 | ++{
 | 
|  |   1514 | ++	if(connection->doneProcessing || (connection->listOks &&
 | 
|  |   1515 | ++				connection->doneListOk))
 | 
|  |   1516 | ++	{
 | 
|  |   1517 | ++		return NULL;
 | 
|  |   1518 | ++	}
 | 
|  |   1519 | ++
 | 
|  |   1520 | ++	mpd_getNextReturnElement(connection);
 | 
|  |   1521 | ++	while(connection->returnElement) {
 | 
|  |   1522 | ++		mpd_ReturnElement * re = connection->returnElement;
 | 
|  |   1523 | ++
 | 
|  |   1524 | ++		if(strcmp(re->name,name)==0) return strdup(re->value);
 | 
|  |   1525 | ++		mpd_getNextReturnElement(connection);
 | 
|  |   1526 | ++	}
 | 
|  |   1527 | ++
 | 
|  |   1528 | ++	return NULL;
 | 
|  |   1529 | ++}
 | 
|  |   1530 | ++
 | 
|  |   1531 | ++char *mpd_getNextTag(mpd_Connection *connection, int type)
 | 
|  |   1532 | ++{
 | 
|  |   1533 | ++	if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES ||
 | 
|  |   1534 | ++	    type == MPD_TAG_ITEM_ANY)
 | 
|  |   1535 | ++		return NULL;
 | 
|  |   1536 | ++	if (type == MPD_TAG_ITEM_FILENAME)
 | 
|  |   1537 | ++		return mpd_getNextReturnElementNamed(connection, "file");
 | 
|  |   1538 | ++	return mpd_getNextReturnElementNamed(connection, mpdTagItemKeys[type]);
 | 
|  |   1539 | ++}
 | 
|  |   1540 | ++
 | 
|  |   1541 | ++char * mpd_getNextArtist(mpd_Connection * connection) {
 | 
|  |   1542 | ++	return mpd_getNextReturnElementNamed(connection,"Artist");
 | 
|  |   1543 | ++}
 | 
|  |   1544 | ++
 | 
|  |   1545 | ++char * mpd_getNextAlbum(mpd_Connection * connection) {
 | 
|  |   1546 | ++	return mpd_getNextReturnElementNamed(connection,"Album");
 | 
|  |   1547 | ++}
 | 
|  |   1548 | ++
 | 
|  |   1549 | ++void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos) {
 | 
|  |   1550 | ++	int len = strlen("playlistinfo")+2+INTLEN+3;
 | 
|  |   1551 | ++	char *string = (char *)malloc(len);
 | 
|  |   1552 | ++	snprintf(string, len, "playlistinfo \"%i\"\n", songPos);
 | 
|  |   1553 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1554 | ++	free(string);
 | 
|  |   1555 | ++}
 | 
|  |   1556 | ++
 | 
|  |   1557 | ++void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id) {
 | 
|  |   1558 | ++	int len = strlen("playlistid")+2+INTLEN+3;
 | 
|  |   1559 | ++	char *string = (char *)malloc(len);
 | 
|  |   1560 | ++	snprintf(string, len, "playlistid \"%i\"\n", id);
 | 
|  |   1561 | ++	mpd_sendInfoCommand(connection, string);
 | 
|  |   1562 | ++	free(string);
 | 
|  |   1563 | ++}
 | 
|  |   1564 | ++
 | 
|  |   1565 | ++void mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist) {
 | 
|  |   1566 | ++	int len = strlen("plchanges")+2+LONGLONGLEN+3;
 | 
|  |   1567 | ++	char *string = (char *)malloc(len);
 | 
|  |   1568 | ++	snprintf(string, len, "plchanges \"%lld\"\n", playlist);
 | 
|  |   1569 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1570 | ++	free(string);
 | 
|  |   1571 | ++}
 | 
|  |   1572 | ++
 | 
|  |   1573 | ++void mpd_sendPlChangesPosIdCommand(mpd_Connection * connection, long long playlist) {
 | 
|  |   1574 | ++	int len = strlen("plchangesposid")+2+LONGLONGLEN+3;
 | 
|  |   1575 | ++	char *string = (char *)malloc(len);
 | 
|  |   1576 | ++	snprintf(string, len, "plchangesposid \"%lld\"\n", playlist);
 | 
|  |   1577 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1578 | ++	free(string);
 | 
|  |   1579 | ++}
 | 
|  |   1580 | ++
 | 
|  |   1581 | ++void mpd_sendListallCommand(mpd_Connection * connection, const char * dir) {
 | 
|  |   1582 | ++	char * sDir = mpd_sanitizeArg(dir);
 | 
|  |   1583 | ++	int len = strlen("listall")+2+strlen(sDir)+3;
 | 
|  |   1584 | ++	char *string = (char *)malloc(len);
 | 
|  |   1585 | ++	snprintf(string, len, "listall \"%s\"\n", sDir);
 | 
|  |   1586 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1587 | ++	free(string);
 | 
|  |   1588 | ++	free(sDir);
 | 
|  |   1589 | ++}
 | 
|  |   1590 | ++
 | 
|  |   1591 | ++void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir) {
 | 
|  |   1592 | ++	char * sDir = mpd_sanitizeArg(dir);
 | 
|  |   1593 | ++	int len = strlen("listallinfo")+2+strlen(sDir)+3;
 | 
|  |   1594 | ++	char *string = (char *)malloc(len);
 | 
|  |   1595 | ++	snprintf(string, len, "listallinfo \"%s\"\n", sDir);
 | 
|  |   1596 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1597 | ++	free(string);
 | 
|  |   1598 | ++	free(sDir);
 | 
|  |   1599 | ++}
 | 
|  |   1600 | ++
 | 
|  |   1601 | ++void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir) {
 | 
|  |   1602 | ++	char * sDir = mpd_sanitizeArg(dir);
 | 
|  |   1603 | ++	int len = strlen("lsinfo")+2+strlen(sDir)+3;
 | 
|  |   1604 | ++	char *string = (char *)malloc(len);
 | 
|  |   1605 | ++	snprintf(string, len, "lsinfo \"%s\"\n", sDir);
 | 
|  |   1606 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1607 | ++	free(string);
 | 
|  |   1608 | ++	free(sDir);
 | 
|  |   1609 | ++}
 | 
|  |   1610 | ++
 | 
|  |   1611 | ++void mpd_sendCurrentSongCommand(mpd_Connection * connection) {
 | 
|  |   1612 | ++	mpd_executeCommand(connection,"currentsong\n");
 | 
|  |   1613 | ++}
 | 
|  |   1614 | ++
 | 
|  |   1615 | ++void mpd_sendSearchCommand(mpd_Connection * connection, int table,
 | 
|  |   1616 | ++		const char * str)
 | 
|  |   1617 | ++{
 | 
|  |   1618 | ++	mpd_startSearch(connection, 0);
 | 
|  |   1619 | ++	mpd_addConstraintSearch(connection, table, str);
 | 
|  |   1620 | ++	mpd_commitSearch(connection);
 | 
|  |   1621 | ++}
 | 
|  |   1622 | ++
 | 
|  |   1623 | ++void mpd_sendFindCommand(mpd_Connection * connection, int table,
 | 
|  |   1624 | ++		const char * str)
 | 
|  |   1625 | ++{
 | 
|  |   1626 | ++	mpd_startSearch(connection, 1);
 | 
|  |   1627 | ++	mpd_addConstraintSearch(connection, table, str);
 | 
|  |   1628 | ++	mpd_commitSearch(connection);
 | 
|  |   1629 | ++}
 | 
|  |   1630 | ++
 | 
|  |   1631 | ++void mpd_sendListCommand(mpd_Connection * connection, int table,
 | 
|  |   1632 | ++		const char * arg1)
 | 
|  |   1633 | ++{
 | 
|  |   1634 | ++	char st[10];
 | 
|  |   1635 | ++	int len;
 | 
|  |   1636 | ++	char *string;
 | 
|  |   1637 | ++	if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
 | 
|  |   1638 | ++	else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
 | 
|  |   1639 | ++	else {
 | 
|  |   1640 | ++		connection->error = 1;
 | 
|  |   1641 | ++		strcpy(connection->errorStr,"unknown table for list");
 | 
|  |   1642 | ++		return;
 | 
|  |   1643 | ++	}
 | 
|  |   1644 | ++	if(arg1) {
 | 
|  |   1645 | ++		char * sanitArg1 = mpd_sanitizeArg(arg1);
 | 
|  |   1646 | ++		len = strlen("list")+1+strlen(sanitArg1)+2+strlen(st)+3;
 | 
|  |   1647 | ++		string = (char *)malloc(len);
 | 
|  |   1648 | ++		snprintf(string, len, "list %s \"%s\"\n", st, sanitArg1);
 | 
|  |   1649 | ++		free(sanitArg1);
 | 
|  |   1650 | ++	}
 | 
|  |   1651 | ++	else {
 | 
|  |   1652 | ++		len = strlen("list")+1+strlen(st)+2;
 | 
|  |   1653 | ++		string = (char *)malloc(len);
 | 
|  |   1654 | ++		snprintf(string, len, "list %s\n", st);
 | 
|  |   1655 | ++	}
 | 
|  |   1656 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1657 | ++	free(string);
 | 
|  |   1658 | ++}
 | 
|  |   1659 | ++
 | 
|  |   1660 | ++void mpd_sendAddCommand(mpd_Connection * connection, const char * file) {
 | 
|  |   1661 | ++	char * sFile = mpd_sanitizeArg(file);
 | 
|  |   1662 | ++	int len = strlen("add")+2+strlen(sFile)+3;
 | 
|  |   1663 | ++	char *string = (char *)malloc(len);
 | 
|  |   1664 | ++	snprintf(string, len, "add \"%s\"\n", sFile);
 | 
|  |   1665 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1666 | ++	free(string);
 | 
|  |   1667 | ++	free(sFile);
 | 
|  |   1668 | ++}
 | 
|  |   1669 | ++
 | 
|  |   1670 | ++int mpd_sendAddIdCommand(mpd_Connection *connection, const char *file)
 | 
|  |   1671 | ++{
 | 
|  |   1672 | ++	int retval = -1;
 | 
|  |   1673 | ++	char *sFile = mpd_sanitizeArg(file);
 | 
|  |   1674 | ++	int len = strlen("addid")+2+strlen(sFile)+3;
 | 
|  |   1675 | ++	char *string = (char *)malloc(len);
 | 
|  |   1676 | ++
 | 
|  |   1677 | ++	snprintf(string, len, "addid \"%s\"\n", sFile);
 | 
|  |   1678 | ++	mpd_sendInfoCommand(connection, string);
 | 
|  |   1679 | ++	free(string);
 | 
|  |   1680 | ++	free(sFile);
 | 
|  |   1681 | ++
 | 
|  |   1682 | ++	string = mpd_getNextReturnElementNamed(connection, "Id");
 | 
|  |   1683 | ++	if (string) {
 | 
|  |   1684 | ++		retval = atoi(string);
 | 
|  |   1685 | ++		free(string);
 | 
|  |   1686 | ++	}
 | 
|  |   1687 | ++	
 | 
|  |   1688 | ++	return retval;
 | 
|  |   1689 | ++}
 | 
|  |   1690 | ++
 | 
|  |   1691 | ++void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos) {
 | 
|  |   1692 | ++	int len = strlen("delete")+2+INTLEN+3;
 | 
|  |   1693 | ++	char *string = (char *)malloc(len);
 | 
|  |   1694 | ++	snprintf(string, len, "delete \"%i\"\n", songPos);
 | 
|  |   1695 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1696 | ++	free(string);
 | 
|  |   1697 | ++}
 | 
|  |   1698 | ++
 | 
|  |   1699 | ++void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id) {
 | 
|  |   1700 | ++	int len = strlen("deleteid")+2+INTLEN+3;
 | 
|  |   1701 | ++	char *string = (char *)malloc(len);
 | 
|  |   1702 | ++	snprintf(string, len, "deleteid \"%i\"\n", id);
 | 
|  |   1703 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1704 | ++	free(string);
 | 
|  |   1705 | ++}
 | 
|  |   1706 | ++
 | 
|  |   1707 | ++void mpd_sendSaveCommand(mpd_Connection * connection, const char * name) {
 | 
|  |   1708 | ++	char * sName = mpd_sanitizeArg(name);
 | 
|  |   1709 | ++	int len = strlen("save")+2+strlen(sName)+3;
 | 
|  |   1710 | ++	char *string = (char *)malloc(len);
 | 
|  |   1711 | ++	snprintf(string, len, "save \"%s\"\n", sName);
 | 
|  |   1712 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1713 | ++	free(string);
 | 
|  |   1714 | ++	free(sName);
 | 
|  |   1715 | ++}
 | 
|  |   1716 | ++
 | 
|  |   1717 | ++void mpd_sendLoadCommand(mpd_Connection * connection, const char * name) {
 | 
|  |   1718 | ++	char * sName = mpd_sanitizeArg(name);
 | 
|  |   1719 | ++	int len = strlen("load")+2+strlen(sName)+3;
 | 
|  |   1720 | ++	char *string = (char *)malloc(len);
 | 
|  |   1721 | ++	snprintf(string, len, "load \"%s\"\n", sName);
 | 
|  |   1722 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1723 | ++	free(string);
 | 
|  |   1724 | ++	free(sName);
 | 
|  |   1725 | ++}
 | 
|  |   1726 | ++
 | 
|  |   1727 | ++void mpd_sendRmCommand(mpd_Connection * connection, const char * name) {
 | 
|  |   1728 | ++	char * sName = mpd_sanitizeArg(name);
 | 
|  |   1729 | ++	int len = strlen("rm")+2+strlen(sName)+3;
 | 
|  |   1730 | ++	char *string = (char *)malloc(len);
 | 
|  |   1731 | ++	snprintf(string, len, "rm \"%s\"\n", sName);
 | 
|  |   1732 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1733 | ++	free(string);
 | 
|  |   1734 | ++	free(sName);
 | 
|  |   1735 | ++}
 | 
|  |   1736 | ++
 | 
|  |   1737 | ++void mpd_sendRenameCommand(mpd_Connection *connection, const char *from,
 | 
|  |   1738 | ++                           const char *to)
 | 
|  |   1739 | ++{
 | 
|  |   1740 | ++	char *sFrom = mpd_sanitizeArg(from);
 | 
|  |   1741 | ++	char *sTo = mpd_sanitizeArg(to);
 | 
|  |   1742 | ++	int len = strlen("rename")+2+strlen(sFrom)+3+strlen(sTo)+3;
 | 
|  |   1743 | ++	char *string = (char *)malloc(len);
 | 
|  |   1744 | ++	snprintf(string, len, "rename \"%s\" \"%s\"\n", sFrom, sTo);
 | 
|  |   1745 | ++	mpd_executeCommand(connection, string);
 | 
|  |   1746 | ++	free(string);
 | 
|  |   1747 | ++	free(sFrom);
 | 
|  |   1748 | ++	free(sTo);
 | 
|  |   1749 | ++}
 | 
|  |   1750 | ++
 | 
|  |   1751 | ++void mpd_sendShuffleCommand(mpd_Connection * connection) {
 | 
|  |   1752 | ++	mpd_executeCommand(connection,"shuffle\n");
 | 
|  |   1753 | ++}
 | 
|  |   1754 | ++
 | 
|  |   1755 | ++void mpd_sendClearCommand(mpd_Connection * connection) {
 | 
|  |   1756 | ++	mpd_executeCommand(connection,"clear\n");
 | 
|  |   1757 | ++}
 | 
|  |   1758 | ++
 | 
|  |   1759 | ++void mpd_sendPlayCommand(mpd_Connection * connection, int songPos) {
 | 
|  |   1760 | ++	int len = strlen("play")+2+INTLEN+3;
 | 
|  |   1761 | ++	char *string = (char *)malloc(len);
 | 
|  |   1762 | ++	snprintf(string, len, "play \"%i\"\n", songPos);
 | 
|  |   1763 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1764 | ++	free(string);
 | 
|  |   1765 | ++}
 | 
|  |   1766 | ++
 | 
|  |   1767 | ++void mpd_sendPlayIdCommand(mpd_Connection * connection, int id) {
 | 
|  |   1768 | ++	int len = strlen("playid")+2+INTLEN+3;
 | 
|  |   1769 | ++	char *string = (char *)malloc(len);
 | 
|  |   1770 | ++	snprintf(string, len, "playid \"%i\"\n", id);
 | 
|  |   1771 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1772 | ++	free(string);
 | 
|  |   1773 | ++}
 | 
|  |   1774 | ++
 | 
|  |   1775 | ++void mpd_sendStopCommand(mpd_Connection * connection) {
 | 
|  |   1776 | ++	mpd_executeCommand(connection,"stop\n");
 | 
|  |   1777 | ++}
 | 
|  |   1778 | ++
 | 
|  |   1779 | ++void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode) {
 | 
|  |   1780 | ++	int len = strlen("pause")+2+INTLEN+3;
 | 
|  |   1781 | ++	char *string = (char *)malloc(len);
 | 
|  |   1782 | ++	snprintf(string, len, "pause \"%i\"\n", pauseMode);
 | 
|  |   1783 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1784 | ++	free(string);
 | 
|  |   1785 | ++}
 | 
|  |   1786 | ++
 | 
|  |   1787 | ++void mpd_sendNextCommand(mpd_Connection * connection) {
 | 
|  |   1788 | ++	mpd_executeCommand(connection,"next\n");
 | 
|  |   1789 | ++}
 | 
|  |   1790 | ++
 | 
|  |   1791 | ++void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to) {
 | 
|  |   1792 | ++	int len = strlen("move")+2+INTLEN+3+INTLEN+3;
 | 
|  |   1793 | ++	char *string = (char *)malloc(len);
 | 
|  |   1794 | ++	snprintf(string, len, "move \"%i\" \"%i\"\n", from, to);
 | 
|  |   1795 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1796 | ++	free(string);
 | 
|  |   1797 | ++}
 | 
|  |   1798 | ++
 | 
|  |   1799 | ++void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to) {
 | 
|  |   1800 | ++	int len = strlen("moveid")+2+INTLEN+3+INTLEN+3;
 | 
|  |   1801 | ++	char *string = (char *)malloc(len);
 | 
|  |   1802 | ++	snprintf(string, len, "moveid \"%i\" \"%i\"\n", id, to);
 | 
|  |   1803 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1804 | ++	free(string);
 | 
|  |   1805 | ++}
 | 
|  |   1806 | ++
 | 
|  |   1807 | ++void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2) {
 | 
|  |   1808 | ++	int len = strlen("swap")+2+INTLEN+3+INTLEN+3;
 | 
|  |   1809 | ++	char *string = (char *)malloc(len);
 | 
|  |   1810 | ++	snprintf(string, len, "swap \"%i\" \"%i\"\n", song1, song2);
 | 
|  |   1811 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1812 | ++	free(string);
 | 
|  |   1813 | ++}
 | 
|  |   1814 | ++
 | 
|  |   1815 | ++void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2) {
 | 
|  |   1816 | ++	int len = strlen("swapid")+2+INTLEN+3+INTLEN+3;
 | 
|  |   1817 | ++	char *string = (char *)malloc(len);
 | 
|  |   1818 | ++	snprintf(string, len, "swapid \"%i\" \"%i\"\n", id1, id2);
 | 
|  |   1819 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1820 | ++	free(string);
 | 
|  |   1821 | ++}
 | 
|  |   1822 | ++
 | 
|  |   1823 | ++void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time) {
 | 
|  |   1824 | ++	int len = strlen("seek")+2+INTLEN+3+INTLEN+3;
 | 
|  |   1825 | ++	char *string = (char *)malloc(len);
 | 
|  |   1826 | ++	snprintf(string, len, "seek \"%i\" \"%i\"\n", song, time);
 | 
|  |   1827 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1828 | ++	free(string);
 | 
|  |   1829 | ++}
 | 
|  |   1830 | ++
 | 
|  |   1831 | ++void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time) {
 | 
|  |   1832 | ++	int len = strlen("seekid")+2+INTLEN+3+INTLEN+3;
 | 
|  |   1833 | ++	char *string = (char *)malloc(len);
 | 
|  |   1834 | ++	snprintf(string, len, "seekid \"%i\" \"%i\"\n", id, time);
 | 
|  |   1835 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1836 | ++	free(string);
 | 
|  |   1837 | ++}
 | 
|  |   1838 | ++
 | 
|  |   1839 | ++void mpd_sendUpdateCommand(mpd_Connection * connection, char * path) {
 | 
|  |   1840 | ++	char * sPath = mpd_sanitizeArg(path);
 | 
|  |   1841 | ++	int len = strlen("update")+2+strlen(sPath)+3;
 | 
|  |   1842 | ++	char *string = (char *)malloc(len);
 | 
|  |   1843 | ++	snprintf(string, len, "update \"%s\"\n", sPath);
 | 
|  |   1844 | ++	mpd_sendInfoCommand(connection,string);
 | 
|  |   1845 | ++	free(string);
 | 
|  |   1846 | ++	free(sPath);
 | 
|  |   1847 | ++}
 | 
|  |   1848 | ++
 | 
|  |   1849 | ++int mpd_getUpdateId(mpd_Connection * connection) {
 | 
|  |   1850 | ++	char * jobid;
 | 
|  |   1851 | ++	int ret = 0;
 | 
|  |   1852 | ++
 | 
|  |   1853 | ++	jobid = mpd_getNextReturnElementNamed(connection,"updating_db");
 | 
|  |   1854 | ++	if(jobid) {
 | 
|  |   1855 | ++		ret = atoi(jobid);
 | 
|  |   1856 | ++		free(jobid);
 | 
|  |   1857 | ++	}
 | 
|  |   1858 | ++
 | 
|  |   1859 | ++	return ret;
 | 
|  |   1860 | ++}
 | 
|  |   1861 | ++
 | 
|  |   1862 | ++void mpd_sendPrevCommand(mpd_Connection * connection) {
 | 
|  |   1863 | ++	mpd_executeCommand(connection,"previous\n");
 | 
|  |   1864 | ++}
 | 
|  |   1865 | ++
 | 
|  |   1866 | ++void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode) {
 | 
|  |   1867 | ++	int len = strlen("repeat")+2+INTLEN+3;
 | 
|  |   1868 | ++	char *string = (char *)malloc(len);
 | 
|  |   1869 | ++	snprintf(string, len, "repeat \"%i\"\n", repeatMode);
 | 
|  |   1870 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1871 | ++	free(string);
 | 
|  |   1872 | ++}
 | 
|  |   1873 | ++
 | 
|  |   1874 | ++void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode) {
 | 
|  |   1875 | ++	int len = strlen("random")+2+INTLEN+3;
 | 
|  |   1876 | ++	char *string = (char *)malloc(len);
 | 
|  |   1877 | ++	snprintf(string, len, "random \"%i\"\n", randomMode);
 | 
|  |   1878 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1879 | ++	free(string);
 | 
|  |   1880 | ++}
 | 
|  |   1881 | ++
 | 
|  |   1882 | ++void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange) {
 | 
|  |   1883 | ++	int len = strlen("setvol")+2+INTLEN+3;
 | 
|  |   1884 | ++	char *string = (char *)malloc(len);
 | 
|  |   1885 | ++	snprintf(string, len, "setvol \"%i\"\n", volumeChange);
 | 
|  |   1886 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1887 | ++	free(string);
 | 
|  |   1888 | ++}
 | 
|  |   1889 | ++
 | 
|  |   1890 | ++void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange) {
 | 
|  |   1891 | ++	int len = strlen("volume")+2+INTLEN+3;
 | 
|  |   1892 | ++	char *string = (char *)malloc(len);
 | 
|  |   1893 | ++	snprintf(string, len, "volume \"%i\"\n", volumeChange);
 | 
|  |   1894 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1895 | ++	free(string);
 | 
|  |   1896 | ++}
 | 
|  |   1897 | ++
 | 
|  |   1898 | ++void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds) {
 | 
|  |   1899 | ++	int len = strlen("crossfade")+2+INTLEN+3;
 | 
|  |   1900 | ++	char *string = (char *)malloc(len);
 | 
|  |   1901 | ++	snprintf(string, len, "crossfade \"%i\"\n", seconds);
 | 
|  |   1902 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1903 | ++	free(string);
 | 
|  |   1904 | ++}
 | 
|  |   1905 | ++
 | 
|  |   1906 | ++void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass) {
 | 
|  |   1907 | ++	char * sPass = mpd_sanitizeArg(pass);
 | 
|  |   1908 | ++	int len = strlen("password")+2+strlen(sPass)+3;
 | 
|  |   1909 | ++	char *string = (char *)malloc(len);
 | 
|  |   1910 | ++	snprintf(string, len, "password \"%s\"\n", sPass);
 | 
|  |   1911 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1912 | ++	free(string);
 | 
|  |   1913 | ++	free(sPass);
 | 
|  |   1914 | ++}
 | 
|  |   1915 | ++
 | 
|  |   1916 | ++void mpd_sendCommandListBegin(mpd_Connection * connection) {
 | 
|  |   1917 | ++	if(connection->commandList) {
 | 
|  |   1918 | ++		strcpy(connection->errorStr,"already in command list mode");
 | 
|  |   1919 | ++		connection->error = 1;
 | 
|  |   1920 | ++		return;
 | 
|  |   1921 | ++	}
 | 
|  |   1922 | ++	connection->commandList = COMMAND_LIST;
 | 
|  |   1923 | ++	mpd_executeCommand(connection,"command_list_begin\n");
 | 
|  |   1924 | ++}
 | 
|  |   1925 | ++
 | 
|  |   1926 | ++void mpd_sendCommandListOkBegin(mpd_Connection * connection) {
 | 
|  |   1927 | ++	if(connection->commandList) {
 | 
|  |   1928 | ++		strcpy(connection->errorStr,"already in command list mode");
 | 
|  |   1929 | ++		connection->error = 1;
 | 
|  |   1930 | ++		return;
 | 
|  |   1931 | ++	}
 | 
|  |   1932 | ++	connection->commandList = COMMAND_LIST_OK;
 | 
|  |   1933 | ++	mpd_executeCommand(connection,"command_list_ok_begin\n");
 | 
|  |   1934 | ++	connection->listOks = 0;
 | 
|  |   1935 | ++}
 | 
|  |   1936 | ++
 | 
|  |   1937 | ++void mpd_sendCommandListEnd(mpd_Connection * connection) {
 | 
|  |   1938 | ++	if(!connection->commandList) {
 | 
|  |   1939 | ++		strcpy(connection->errorStr,"not in command list mode");
 | 
|  |   1940 | ++		connection->error = 1;
 | 
|  |   1941 | ++		return;
 | 
|  |   1942 | ++	}
 | 
|  |   1943 | ++	connection->commandList = 0;
 | 
|  |   1944 | ++	mpd_executeCommand(connection,"command_list_end\n");
 | 
|  |   1945 | ++}
 | 
|  |   1946 | ++
 | 
|  |   1947 | ++void mpd_sendOutputsCommand(mpd_Connection * connection) {
 | 
|  |   1948 | ++	mpd_executeCommand(connection,"outputs\n");
 | 
|  |   1949 | ++}
 | 
|  |   1950 | ++
 | 
|  |   1951 | ++mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection) {
 | 
|  |   1952 | ++	mpd_OutputEntity * output = NULL;
 | 
|  |   1953 | ++
 | 
|  |   1954 | ++	if(connection->doneProcessing || (connection->listOks &&
 | 
|  |   1955 | ++				connection->doneListOk))
 | 
|  |   1956 | ++	{
 | 
|  |   1957 | ++		return NULL;
 | 
|  |   1958 | ++	}
 | 
|  |   1959 | ++
 | 
|  |   1960 | ++	if(connection->error) return NULL;
 | 
|  |   1961 | ++
 | 
|  |   1962 | ++	output = (mpd_OutputEntity *)malloc(sizeof(mpd_OutputEntity));
 | 
|  |   1963 | ++	output->id = -10;
 | 
|  |   1964 | ++	output->name = NULL;
 | 
|  |   1965 | ++	output->enabled = 0;
 | 
|  |   1966 | ++
 | 
|  |   1967 | ++	if(!connection->returnElement) mpd_getNextReturnElement(connection);
 | 
|  |   1968 | ++
 | 
|  |   1969 | ++	while(connection->returnElement) {
 | 
|  |   1970 | ++		mpd_ReturnElement * re = connection->returnElement;
 | 
|  |   1971 | ++		if(strcmp(re->name,"outputid")==0) {
 | 
|  |   1972 | ++			if(output!=NULL && output->id>=0) return output;
 | 
|  |   1973 | ++			output->id = atoi(re->value);
 | 
|  |   1974 | ++		}
 | 
|  |   1975 | ++		else if(strcmp(re->name,"outputname")==0) {
 | 
|  |   1976 | ++			output->name = strdup(re->value);
 | 
|  |   1977 | ++		}
 | 
|  |   1978 | ++		else if(strcmp(re->name,"outputenabled")==0) {
 | 
|  |   1979 | ++			output->enabled = atoi(re->value);
 | 
|  |   1980 | ++		}
 | 
|  |   1981 | ++
 | 
|  |   1982 | ++		mpd_getNextReturnElement(connection);
 | 
|  |   1983 | ++		if(connection->error) {
 | 
|  |   1984 | ++			free(output);
 | 
|  |   1985 | ++			return NULL;
 | 
|  |   1986 | ++		}
 | 
|  |   1987 | ++
 | 
|  |   1988 | ++	}
 | 
|  |   1989 | ++
 | 
|  |   1990 | ++	return output;
 | 
|  |   1991 | ++}
 | 
|  |   1992 | ++
 | 
|  |   1993 | ++void mpd_sendEnableOutputCommand(mpd_Connection * connection, int outputId) {
 | 
|  |   1994 | ++	int len = strlen("enableoutput")+2+INTLEN+3;
 | 
|  |   1995 | ++	char *string = (char *)malloc(len);
 | 
|  |   1996 | ++	snprintf(string, len, "enableoutput \"%i\"\n", outputId);
 | 
|  |   1997 | ++	mpd_executeCommand(connection,string);
 | 
|  |   1998 | ++	free(string);
 | 
|  |   1999 | ++}
 | 
|  |   2000 | ++
 | 
|  |   2001 | ++void mpd_sendDisableOutputCommand(mpd_Connection * connection, int outputId) {
 | 
|  |   2002 | ++	int len = strlen("disableoutput")+2+INTLEN+3;
 | 
|  |   2003 | ++	char *string = (char *)malloc(len);
 | 
|  |   2004 | ++	snprintf(string, len, "disableoutput \"%i\"\n", outputId);
 | 
|  |   2005 | ++	mpd_executeCommand(connection,string);
 | 
|  |   2006 | ++	free(string);
 | 
|  |   2007 | ++}
 | 
|  |   2008 | ++
 | 
|  |   2009 | ++void mpd_freeOutputElement(mpd_OutputEntity * output) {
 | 
|  |   2010 | ++	free(output->name);
 | 
|  |   2011 | ++	free(output);
 | 
|  |   2012 | ++}
 | 
|  |   2013 | ++
 | 
|  |   2014 | ++/**
 | 
|  |   2015 | ++ * mpd_sendNotCommandsCommand
 | 
|  |   2016 | ++ * odd naming, but it gets the not allowed commands
 | 
|  |   2017 | ++ */
 | 
|  |   2018 | ++
 | 
|  |   2019 | ++void mpd_sendNotCommandsCommand(mpd_Connection * connection)
 | 
|  |   2020 | ++{
 | 
|  |   2021 | ++	mpd_executeCommand(connection, "notcommands\n");
 | 
|  |   2022 | ++}
 | 
|  |   2023 | ++
 | 
|  |   2024 | ++/**
 | 
|  |   2025 | ++ * mpd_sendCommandsCommand
 | 
|  |   2026 | ++ * odd naming, but it gets the allowed commands
 | 
|  |   2027 | ++ */
 | 
|  |   2028 | ++void mpd_sendCommandsCommand(mpd_Connection * connection)
 | 
|  |   2029 | ++{
 | 
|  |   2030 | ++	mpd_executeCommand(connection, "commands\n");
 | 
|  |   2031 | ++}
 | 
|  |   2032 | ++
 | 
|  |   2033 | ++/**
 | 
|  |   2034 | ++ * Get the next returned command
 | 
|  |   2035 | ++ */
 | 
|  |   2036 | ++char * mpd_getNextCommand(mpd_Connection * connection)
 | 
|  |   2037 | ++{
 | 
|  |   2038 | ++	return mpd_getNextReturnElementNamed(connection, "command");
 | 
|  |   2039 | ++}
 | 
|  |   2040 | ++
 | 
|  |   2041 | ++void mpd_sendUrlHandlersCommand(mpd_Connection * connection)
 | 
|  |   2042 | ++{
 | 
|  |   2043 | ++	mpd_executeCommand(connection, "urlhandlers\n");
 | 
|  |   2044 | ++}
 | 
|  |   2045 | ++
 | 
|  |   2046 | ++char * mpd_getNextHandler(mpd_Connection * connection)
 | 
|  |   2047 | ++{
 | 
|  |   2048 | ++	return mpd_getNextReturnElementNamed(connection, "handler");
 | 
|  |   2049 | ++}
 | 
|  |   2050 | ++
 | 
|  |   2051 | ++void mpd_sendTagTypesCommand(mpd_Connection * connection)
 | 
|  |   2052 | ++{
 | 
|  |   2053 | ++	mpd_executeCommand(connection, "tagtypes\n");
 | 
|  |   2054 | ++}
 | 
|  |   2055 | ++
 | 
|  |   2056 | ++char * mpd_getNextTagType(mpd_Connection * connection)
 | 
|  |   2057 | ++{
 | 
|  |   2058 | ++	return mpd_getNextReturnElementNamed(connection, "tagtype");
 | 
|  |   2059 | ++}
 | 
|  |   2060 | ++
 | 
|  |   2061 | ++void mpd_startSearch(mpd_Connection *connection, int exact)
 | 
|  |   2062 | ++{
 | 
|  |   2063 | ++	if (connection->request) {
 | 
|  |   2064 | ++		strcpy(connection->errorStr, "search already in progress");
 | 
|  |   2065 | ++		connection->error = 1;
 | 
|  |   2066 | ++		return;
 | 
|  |   2067 | ++	}
 | 
|  |   2068 | ++
 | 
|  |   2069 | ++	if (exact) connection->request = strdup("find");
 | 
|  |   2070 | ++	else connection->request = strdup("search");
 | 
|  |   2071 | ++}
 | 
|  |   2072 | ++
 | 
|  |   2073 | ++void mpd_startStatsSearch(mpd_Connection *connection)
 | 
|  |   2074 | ++{
 | 
|  |   2075 | ++	if (connection->request) {
 | 
|  |   2076 | ++		strcpy(connection->errorStr, "search already in progress");
 | 
|  |   2077 | ++		connection->error = 1;
 | 
|  |   2078 | ++		return;
 | 
|  |   2079 | ++	}
 | 
|  |   2080 | ++
 | 
|  |   2081 | ++	connection->request = strdup("count");
 | 
|  |   2082 | ++}
 | 
|  |   2083 | ++
 | 
|  |   2084 | ++void mpd_startPlaylistSearch(mpd_Connection *connection, int exact)
 | 
|  |   2085 | ++{
 | 
|  |   2086 | ++	if (connection->request) {
 | 
|  |   2087 | ++		strcpy(connection->errorStr, "search already in progress");
 | 
|  |   2088 | ++		connection->error = 1;
 | 
|  |   2089 | ++		return;
 | 
|  |   2090 | ++	}
 | 
|  |   2091 | ++
 | 
|  |   2092 | ++	if (exact) connection->request = strdup("playlistfind");
 | 
|  |   2093 | ++	else connection->request = strdup("playlistsearch");
 | 
|  |   2094 | ++}
 | 
|  |   2095 | ++
 | 
|  |   2096 | ++void mpd_startFieldSearch(mpd_Connection *connection, int type)
 | 
|  |   2097 | ++{
 | 
|  |   2098 | ++	char *strtype;
 | 
|  |   2099 | ++	int len;
 | 
|  |   2100 | ++
 | 
|  |   2101 | ++	if (connection->request) {
 | 
|  |   2102 | ++		strcpy(connection->errorStr, "search already in progress");
 | 
|  |   2103 | ++		connection->error = 1;
 | 
|  |   2104 | ++		return;
 | 
|  |   2105 | ++	}
 | 
|  |   2106 | ++
 | 
|  |   2107 | ++	if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES) {
 | 
|  |   2108 | ++		strcpy(connection->errorStr, "invalid type specified");
 | 
|  |   2109 | ++		connection->error = 1;
 | 
|  |   2110 | ++		return;
 | 
|  |   2111 | ++	}
 | 
|  |   2112 | ++
 | 
|  |   2113 | ++	strtype = mpdTagItemKeys[type];
 | 
|  |   2114 | ++
 | 
|  |   2115 | ++	len = 5+strlen(strtype)+1;
 | 
|  |   2116 | ++	connection->request = (char *)malloc(len);
 | 
|  |   2117 | ++
 | 
|  |   2118 | ++	snprintf(connection->request, len, "list %c%s",
 | 
|  |   2119 | ++	         tolower(strtype[0]), strtype+1);
 | 
|  |   2120 | ++}
 | 
|  |   2121 | ++
 | 
|  |   2122 | ++void mpd_addConstraintSearch(mpd_Connection *connection, int type, const char *name)
 | 
|  |   2123 | ++{
 | 
|  |   2124 | ++	char *strtype;
 | 
|  |   2125 | ++	char *arg;
 | 
|  |   2126 | ++	int len;
 | 
|  |   2127 | ++	char *string;
 | 
|  |   2128 | ++
 | 
|  |   2129 | ++	if (!connection->request) {
 | 
|  |   2130 | ++		strcpy(connection->errorStr, "no search in progress");
 | 
|  |   2131 | ++		connection->error = 1;
 | 
|  |   2132 | ++		return;
 | 
|  |   2133 | ++	}
 | 
|  |   2134 | ++
 | 
|  |   2135 | ++	if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES) {
 | 
|  |   2136 | ++		strcpy(connection->errorStr, "invalid type specified");
 | 
|  |   2137 | ++		connection->error = 1;
 | 
|  |   2138 | ++		return;
 | 
|  |   2139 | ++	}
 | 
|  |   2140 | ++
 | 
|  |   2141 | ++	if (name == NULL) {
 | 
|  |   2142 | ++		strcpy(connection->errorStr, "no name specified");
 | 
|  |   2143 | ++		connection->error = 1;
 | 
|  |   2144 | ++		return;
 | 
|  |   2145 | ++	}
 | 
|  |   2146 | ++
 | 
|  |   2147 | ++	string = strdup(connection->request);
 | 
|  |   2148 | ++	strtype = mpdTagItemKeys[type];
 | 
|  |   2149 | ++	arg = mpd_sanitizeArg(name);
 | 
|  |   2150 | ++
 | 
|  |   2151 | ++	len = strlen(string)+1+strlen(strtype)+2+strlen(arg)+2;
 | 
|  |   2152 | ++	connection->request = (char *)realloc(connection->request, len);
 | 
|  |   2153 | ++	snprintf(connection->request, len, "%s %c%s \"%s\"",
 | 
|  |   2154 | ++	         string, tolower(strtype[0]), strtype+1, arg);
 | 
|  |   2155 | ++
 | 
|  |   2156 | ++	free(string);
 | 
|  |   2157 | ++	free(arg);
 | 
|  |   2158 | ++}
 | 
|  |   2159 | ++
 | 
|  |   2160 | ++void mpd_commitSearch(mpd_Connection *connection)
 | 
|  |   2161 | ++{
 | 
|  |   2162 | ++	int len;
 | 
|  |   2163 | ++
 | 
|  |   2164 | ++	if (!connection->request) {
 | 
|  |   2165 | ++		strcpy(connection->errorStr, "no search in progress");
 | 
|  |   2166 | ++		connection->error = 1;
 | 
|  |   2167 | ++		return;
 | 
|  |   2168 | ++	}
 | 
|  |   2169 | ++
 | 
|  |   2170 | ++	len = strlen(connection->request)+2;
 | 
|  |   2171 | ++	connection->request = (char *)realloc(connection->request, len);
 | 
|  |   2172 | ++	connection->request[len-2] = '\n';
 | 
|  |   2173 | ++	connection->request[len-1] = '\0';
 | 
|  |   2174 | ++	mpd_sendInfoCommand(connection, connection->request);
 | 
|  |   2175 | ++
 | 
|  |   2176 | ++	free(connection->request);
 | 
|  |   2177 | ++	connection->request = NULL;
 | 
|  |   2178 | ++}
 | 
|  |   2179 | ++
 | 
|  |   2180 | ++/**
 | 
|  |   2181 | ++ * @param connection a MpdConnection
 | 
|  |   2182 | ++ * @param path	the path to the playlist.
 | 
|  |   2183 | ++ *
 | 
|  |   2184 | ++ * List the content, with full metadata, of a stored playlist.
 | 
|  |   2185 | ++ *
 | 
|  |   2186 | ++ */
 | 
|  |   2187 | ++void mpd_sendListPlaylistInfoCommand(mpd_Connection *connection, char *path)
 | 
|  |   2188 | ++{
 | 
|  |   2189 | ++	char *arg = mpd_sanitizeArg(path);
 | 
|  |   2190 | ++	int len = strlen("listplaylistinfo")+2+strlen(arg)+3;
 | 
|  |   2191 | ++	char *query = (char *)malloc(len);
 | 
|  |   2192 | ++	snprintf(query, len, "listplaylistinfo \"%s\"\n", arg);
 | 
|  |   2193 | ++	mpd_sendInfoCommand(connection, query);
 | 
|  |   2194 | ++	free(arg);
 | 
|  |   2195 | ++	free(query);
 | 
|  |   2196 | ++}
 | 
|  |   2197 | ++
 | 
|  |   2198 | ++/**
 | 
|  |   2199 | ++ * @param connection a MpdConnection
 | 
|  |   2200 | ++ * @param path	the path to the playlist.
 | 
|  |   2201 | ++ *
 | 
|  |   2202 | ++ * List the content of a stored playlist.
 | 
|  |   2203 | ++ *
 | 
|  |   2204 | ++ */
 | 
|  |   2205 | ++void mpd_sendListPlaylistCommand(mpd_Connection *connection, char *path)
 | 
|  |   2206 | ++{
 | 
|  |   2207 | ++	char *arg = mpd_sanitizeArg(path);
 | 
|  |   2208 | ++	int len = strlen("listplaylist")+2+strlen(arg)+3;
 | 
|  |   2209 | ++	char *query = (char *)malloc(len);
 | 
|  |   2210 | ++	snprintf(query, len, "listplaylist \"%s\"\n", arg);
 | 
|  |   2211 | ++	mpd_sendInfoCommand(connection, query);
 | 
|  |   2212 | ++	free(arg);
 | 
|  |   2213 | ++	free(query);
 | 
|  |   2214 | ++}
 | 
|  |   2215 | ++
 | 
|  |   2216 | ++void mpd_sendPlaylistClearCommand(mpd_Connection *connection, char *path)
 | 
|  |   2217 | ++{
 | 
|  |   2218 | ++	char *sPath = mpd_sanitizeArg(path);
 | 
|  |   2219 | ++	int len = strlen("playlistclear")+2+strlen(sPath)+3;
 | 
|  |   2220 | ++	char *string = (char *)malloc(len);
 | 
|  |   2221 | ++	snprintf(string, len, "playlistclear \"%s\"\n", sPath);
 | 
|  |   2222 | ++	mpd_executeCommand(connection, string);
 | 
|  |   2223 | ++	free(sPath);
 | 
|  |   2224 | ++	free(string);
 | 
|  |   2225 | ++}
 | 
|  |   2226 | ++
 | 
|  |   2227 | ++void mpd_sendPlaylistAddCommand(mpd_Connection *connection,
 | 
|  |   2228 | ++                                char *playlist, char *path)
 | 
|  |   2229 | ++{
 | 
|  |   2230 | ++	char *sPlaylist = mpd_sanitizeArg(playlist);
 | 
|  |   2231 | ++	char *sPath = mpd_sanitizeArg(path);
 | 
|  |   2232 | ++	int len = strlen("playlistadd")+2+strlen(sPlaylist)+3+strlen(sPath)+3;
 | 
|  |   2233 | ++	char *string = (char *)malloc(len);
 | 
|  |   2234 | ++	snprintf(string, len, "playlistadd \"%s\" \"%s\"\n", sPlaylist, sPath);
 | 
|  |   2235 | ++	mpd_executeCommand(connection, string);
 | 
|  |   2236 | ++	free(sPlaylist);
 | 
|  |   2237 | ++	free(sPath);
 | 
|  |   2238 | ++	free(string);
 | 
|  |   2239 | ++}
 | 
|  |   2240 | ++
 | 
|  |   2241 | ++void mpd_sendPlaylistMoveCommand(mpd_Connection *connection,
 | 
|  |   2242 | ++                                 char *playlist, int from, int to)
 | 
|  |   2243 | ++{
 | 
|  |   2244 | ++	char *sPlaylist = mpd_sanitizeArg(playlist);
 | 
|  |   2245 | ++	int len = strlen("playlistmove")+
 | 
|  |   2246 | ++	          2+strlen(sPlaylist)+3+INTLEN+3+INTLEN+3;
 | 
|  |   2247 | ++	char *string = (char *)malloc(len);
 | 
|  |   2248 | ++	snprintf(string, len, "playlistmove \"%s\" \"%i\" \"%i\"\n",
 | 
|  |   2249 | ++	         sPlaylist, from, to);
 | 
|  |   2250 | ++	mpd_executeCommand(connection, string);
 | 
|  |   2251 | ++	free(sPlaylist);
 | 
|  |   2252 | ++	free(string);
 | 
|  |   2253 | ++}
 | 
|  |   2254 | ++
 | 
|  |   2255 | ++void mpd_sendPlaylistDeleteCommand(mpd_Connection *connection,
 | 
|  |   2256 | ++                                   char *playlist, int pos)
 | 
|  |   2257 | ++{
 | 
|  |   2258 | ++	char *sPlaylist = mpd_sanitizeArg(playlist);
 | 
|  |   2259 | ++	int len = strlen("playlistdelete")+2+strlen(sPlaylist)+3+INTLEN+3;
 | 
|  |   2260 | ++	char *string = (char *)malloc(len);
 | 
|  |   2261 | ++	snprintf(string, len, "playlistdelete \"%s\" \"%i\"\n", sPlaylist, pos);
 | 
|  |   2262 | ++	mpd_executeCommand(connection, string);
 | 
|  |   2263 | ++	free(sPlaylist);
 | 
|  |   2264 | ++	free(string);
 | 
|  |   2265 | ++}
 | 
|  |   2266 | +diff -r 171db9560cb5 clients/mpd/libmpdclient.h
 | 
|  |   2267 | +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
 | 
|  |   2268 | ++++ b/clients/mpd/libmpdclient.h	Mon May 19 00:21:51 2008 -0400
 | 
|  |   2269 | +@@ -0,0 +1,670 @@
 | 
|  |   2270 | ++/* libmpdclient
 | 
|  |   2271 | ++   (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
 | 
|  |   2272 | ++   This project's homepage is: http://www.musicpd.org
 | 
|  |   2273 | ++
 | 
|  |   2274 | ++   Redistribution and use in source and binary forms, with or without
 | 
|  |   2275 | ++   modification, are permitted provided that the following conditions
 | 
|  |   2276 | ++   are met:
 | 
|  |   2277 | ++
 | 
|  |   2278 | ++   - Redistributions of source code must retain the above copyright
 | 
|  |   2279 | ++   notice, this list of conditions and the following disclaimer.
 | 
|  |   2280 | ++
 | 
|  |   2281 | ++   - Redistributions in binary form must reproduce the above copyright
 | 
|  |   2282 | ++   notice, this list of conditions and the following disclaimer in the
 | 
|  |   2283 | ++   documentation and/or other materials provided with the distribution.
 | 
|  |   2284 | ++
 | 
|  |   2285 | ++   - Neither the name of the Music Player Daemon nor the names of its
 | 
|  |   2286 | ++   contributors may be used to endorse or promote products derived from
 | 
|  |   2287 | ++   this software without specific prior written permission.
 | 
|  |   2288 | ++
 | 
|  |   2289 | ++   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
|  |   2290 | ++   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
|  |   2291 | ++   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
|  |   2292 | ++   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
 | 
|  |   2293 | ++   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
|  |   2294 | ++   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
|  |   2295 | ++   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
|  |   2296 | ++   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
|  |   2297 | ++   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
|  |   2298 | ++   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
|  |   2299 | ++   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
|  |   2300 | ++*/
 | 
|  |   2301 | ++
 | 
|  |   2302 | ++#ifndef LIBMPDCLIENT_H
 | 
|  |   2303 | ++#define LIBMPDCLIENT_H
 | 
|  |   2304 | ++
 | 
|  |   2305 | ++#ifdef WIN32
 | 
|  |   2306 | ++#  define __W32API_USE_DLLIMPORT__ 1
 | 
|  |   2307 | ++#endif
 | 
|  |   2308 | ++
 | 
|  |   2309 | ++#include <sys/time.h>
 | 
|  |   2310 | ++#include <stdarg.h>
 | 
|  |   2311 | ++#define MPD_BUFFER_MAX_LENGTH	50000
 | 
|  |   2312 | ++#define MPD_ERRORSTR_MAX_LENGTH	1000
 | 
|  |   2313 | ++#define MPD_WELCOME_MESSAGE	"OK MPD "
 | 
|  |   2314 | ++
 | 
|  |   2315 | ++#define MPD_ERROR_TIMEOUT	10 /* timeout trying to talk to mpd */
 | 
|  |   2316 | ++#define MPD_ERROR_SYSTEM	11 /* system error */
 | 
|  |   2317 | ++#define MPD_ERROR_UNKHOST	12 /* unknown host */
 | 
|  |   2318 | ++#define MPD_ERROR_CONNPORT	13 /* problems connecting to port on host */
 | 
|  |   2319 | ++#define MPD_ERROR_NOTMPD	14 /* mpd not running on port at host */
 | 
|  |   2320 | ++#define MPD_ERROR_NORESPONSE	15 /* no response on attempting to connect */
 | 
|  |   2321 | ++#define MPD_ERROR_SENDING	16 /* error sending command */
 | 
|  |   2322 | ++#define MPD_ERROR_CONNCLOSED	17 /* connection closed by mpd */
 | 
|  |   2323 | ++#define MPD_ERROR_ACK		18 /* ACK returned! */
 | 
|  |   2324 | ++#define MPD_ERROR_BUFFEROVERRUN	19 /* Buffer was overrun! */
 | 
|  |   2325 | ++
 | 
|  |   2326 | ++#define MPD_ACK_ERROR_UNK	-1
 | 
|  |   2327 | ++#define MPD_ERROR_AT_UNK	-1
 | 
|  |   2328 | ++
 | 
|  |   2329 | ++#define MPD_ACK_ERROR_NOT_LIST			1
 | 
|  |   2330 | ++#define MPD_ACK_ERROR_ARG			2
 | 
|  |   2331 | ++#define MPD_ACK_ERROR_PASSWORD			3
 | 
|  |   2332 | ++#define MPD_ACK_ERROR_PERMISSION		4
 | 
|  |   2333 | ++#define MPD_ACK_ERROR_UNKNOWN_CMD		5
 | 
|  |   2334 | ++
 | 
|  |   2335 | ++#define MPD_ACK_ERROR_NO_EXIST			50
 | 
|  |   2336 | ++#define MPD_ACK_ERROR_PLAYLIST_MAX		51
 | 
|  |   2337 | ++#define MPD_ACK_ERROR_SYSTEM			52
 | 
|  |   2338 | ++#define MPD_ACK_ERROR_PLAYLIST_LOAD		53
 | 
|  |   2339 | ++#define MPD_ACK_ERROR_UPDATE_ALREADY		54
 | 
|  |   2340 | ++#define MPD_ACK_ERROR_PLAYER_SYNC		55
 | 
|  |   2341 | ++#define MPD_ACK_ERROR_EXIST			56
 | 
|  |   2342 | ++
 | 
|  |   2343 | ++#ifdef __cplusplus
 | 
|  |   2344 | ++extern "C" {
 | 
|  |   2345 | ++#endif
 | 
|  |   2346 | ++
 | 
|  |   2347 | ++typedef enum mpd_TagItems
 | 
|  |   2348 | ++{
 | 
|  |   2349 | ++	MPD_TAG_ITEM_ARTIST,
 | 
|  |   2350 | ++	MPD_TAG_ITEM_ALBUM,
 | 
|  |   2351 | ++	MPD_TAG_ITEM_TITLE,
 | 
|  |   2352 | ++	MPD_TAG_ITEM_TRACK,
 | 
|  |   2353 | ++	MPD_TAG_ITEM_NAME,
 | 
|  |   2354 | ++	MPD_TAG_ITEM_GENRE,
 | 
|  |   2355 | ++	MPD_TAG_ITEM_DATE,
 | 
|  |   2356 | ++	MPD_TAG_ITEM_COMPOSER,
 | 
|  |   2357 | ++	MPD_TAG_ITEM_PERFORMER,
 | 
|  |   2358 | ++	MPD_TAG_ITEM_COMMENT,
 | 
|  |   2359 | ++	MPD_TAG_ITEM_DISC,
 | 
|  |   2360 | ++	MPD_TAG_ITEM_FILENAME,
 | 
|  |   2361 | ++	MPD_TAG_ITEM_ANY,
 | 
|  |   2362 | ++	MPD_TAG_NUM_OF_ITEM_TYPES
 | 
|  |   2363 | ++} mpd_TagItems;
 | 
|  |   2364 | ++
 | 
|  |   2365 | ++extern char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES];
 | 
|  |   2366 | ++
 | 
|  |   2367 | ++/* internal stuff don't touch this struct */
 | 
|  |   2368 | ++typedef struct _mpd_ReturnElement {
 | 
|  |   2369 | ++	char * name;
 | 
|  |   2370 | ++	char * value;
 | 
|  |   2371 | ++} mpd_ReturnElement;
 | 
|  |   2372 | ++
 | 
|  |   2373 | ++/* mpd_Connection
 | 
|  |   2374 | ++ * holds info about connection to mpd
 | 
|  |   2375 | ++ * use error, and errorStr to detect errors
 | 
|  |   2376 | ++ */
 | 
|  |   2377 | ++typedef struct _mpd_Connection {
 | 
|  |   2378 | ++	/* use this to check the version of mpd */
 | 
|  |   2379 | ++	int version[3];
 | 
|  |   2380 | ++	/* IMPORTANT, you want to get the error messages from here */
 | 
|  |   2381 | ++	char errorStr[MPD_ERRORSTR_MAX_LENGTH+1];
 | 
|  |   2382 | ++	int errorCode;
 | 
|  |   2383 | ++	int errorAt;
 | 
|  |   2384 | ++	/* this will be set to MPD_ERROR_* if there is an error, 0 if not */
 | 
|  |   2385 | ++	int error;
 | 
|  |   2386 | ++	/* DON'T TOUCH any of the rest of this stuff */
 | 
|  |   2387 | ++	int sock;
 | 
|  |   2388 | ++	char buffer[MPD_BUFFER_MAX_LENGTH+1];
 | 
|  |   2389 | ++	int buflen;
 | 
|  |   2390 | ++	int bufstart;
 | 
|  |   2391 | ++	int doneProcessing;
 | 
|  |   2392 | ++	int listOks;
 | 
|  |   2393 | ++	int doneListOk;
 | 
|  |   2394 | ++	int commandList;
 | 
|  |   2395 | ++	mpd_ReturnElement * returnElement;
 | 
|  |   2396 | ++	struct timeval timeout;
 | 
|  |   2397 | ++	char *request;
 | 
|  |   2398 | ++} mpd_Connection;
 | 
|  |   2399 | ++
 | 
|  |   2400 | ++/* mpd_newConnection
 | 
|  |   2401 | ++ * use this to open a new connection
 | 
|  |   2402 | ++ * you should use mpd_closeConnection, when your done with the connection,
 | 
|  |   2403 | ++ * even if an error has occurred
 | 
|  |   2404 | ++ * _timeout_ is the connection timeout period in seconds
 | 
|  |   2405 | ++ */
 | 
|  |   2406 | ++mpd_Connection * mpd_newConnection(const char * host, int port, float timeout);
 | 
|  |   2407 | ++
 | 
|  |   2408 | ++void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout);
 | 
|  |   2409 | ++
 | 
|  |   2410 | ++/* mpd_closeConnection
 | 
|  |   2411 | ++ * use this to close a connection and free'ing subsequent memory
 | 
|  |   2412 | ++ */
 | 
|  |   2413 | ++void mpd_closeConnection(mpd_Connection * connection);
 | 
|  |   2414 | ++
 | 
|  |   2415 | ++/* mpd_clearError
 | 
|  |   2416 | ++ * clears error
 | 
|  |   2417 | ++ */
 | 
|  |   2418 | ++void mpd_clearError(mpd_Connection * connection);
 | 
|  |   2419 | ++
 | 
|  |   2420 | ++/* STATUS STUFF */
 | 
|  |   2421 | ++
 | 
|  |   2422 | ++/* use these with status.state to determine what state the player is in */
 | 
|  |   2423 | ++#define MPD_STATUS_STATE_UNKNOWN	0
 | 
|  |   2424 | ++#define MPD_STATUS_STATE_STOP		1
 | 
|  |   2425 | ++#define MPD_STATUS_STATE_PLAY		2
 | 
|  |   2426 | ++#define MPD_STATUS_STATE_PAUSE		3
 | 
|  |   2427 | ++
 | 
|  |   2428 | ++/* us this with status.volume to determine if mpd has volume support */
 | 
|  |   2429 | ++#define MPD_STATUS_NO_VOLUME		-1
 | 
|  |   2430 | ++
 | 
|  |   2431 | ++/* mpd_Status
 | 
|  |   2432 | ++ * holds info return from status command
 | 
|  |   2433 | ++ */
 | 
|  |   2434 | ++typedef struct mpd_Status {
 | 
|  |   2435 | ++	/* 0-100, or MPD_STATUS_NO_VOLUME when there is no volume support */
 | 
|  |   2436 | ++	int volume;
 | 
|  |   2437 | ++	/* 1 if repeat is on, 0 otherwise */
 | 
|  |   2438 | ++	int repeat;
 | 
|  |   2439 | ++	/* 1 if random is on, 0 otherwise */
 | 
|  |   2440 | ++	int random;
 | 
|  |   2441 | ++	/* playlist length */
 | 
|  |   2442 | ++	int playlistLength;
 | 
|  |   2443 | ++	/* playlist, use this to determine when the playlist has changed */
 | 
|  |   2444 | ++	long long playlist;
 | 
|  |   2445 | ++	/* use with MPD_STATUS_STATE_* to determine state of player */
 | 
|  |   2446 | ++	int state;
 | 
|  |   2447 | ++	/* crossfade setting in seconds */
 | 
|  |   2448 | ++	int crossfade;
 | 
|  |   2449 | ++	/* if a song is currently selected (always the case when state is
 | 
|  |   2450 | ++	 * PLAY or PAUSE), this is the position of the currently
 | 
|  |   2451 | ++	 * playing song in the playlist, beginning with 0
 | 
|  |   2452 | ++	 */
 | 
|  |   2453 | ++	int song;
 | 
|  |   2454 | ++	/* Song ID of the currently selected song */
 | 
|  |   2455 | ++	int songid;
 | 
|  |   2456 | ++	/* time in seconds that have elapsed in the currently playing/paused
 | 
|  |   2457 | ++	 * song
 | 
|  |   2458 | ++	 */
 | 
|  |   2459 | ++	int elapsedTime;
 | 
|  |   2460 | ++	/* length in seconds of the currently playing/paused song */
 | 
|  |   2461 | ++	int totalTime;
 | 
|  |   2462 | ++	/* current bit rate in kbs */
 | 
|  |   2463 | ++	int bitRate;
 | 
|  |   2464 | ++	/* audio sample rate */
 | 
|  |   2465 | ++	unsigned int sampleRate;
 | 
|  |   2466 | ++	/* audio bits */
 | 
|  |   2467 | ++	int bits;
 | 
|  |   2468 | ++	/* audio channels */
 | 
|  |   2469 | ++	int channels;
 | 
|  |   2470 | ++	/* 1 if mpd is updating, 0 otherwise */
 | 
|  |   2471 | ++	int updatingDb;
 | 
|  |   2472 | ++	/* error */
 | 
|  |   2473 | ++	char * error;
 | 
|  |   2474 | ++} mpd_Status;
 | 
|  |   2475 | ++
 | 
|  |   2476 | ++void mpd_sendStatusCommand(mpd_Connection * connection);
 | 
|  |   2477 | ++
 | 
|  |   2478 | ++/* mpd_getStatus
 | 
|  |   2479 | ++ * returns status info, be sure to free it with mpd_freeStatus()
 | 
|  |   2480 | ++ * call this after mpd_sendStatusCommand()
 | 
|  |   2481 | ++ */
 | 
|  |   2482 | ++mpd_Status * mpd_getStatus(mpd_Connection * connection);
 | 
|  |   2483 | ++
 | 
|  |   2484 | ++/* mpd_freeStatus
 | 
|  |   2485 | ++ * free's status info malloc'd and returned by mpd_getStatus
 | 
|  |   2486 | ++ */
 | 
|  |   2487 | ++void mpd_freeStatus(mpd_Status * status);
 | 
|  |   2488 | ++
 | 
|  |   2489 | ++typedef struct _mpd_Stats {
 | 
|  |   2490 | ++	int numberOfArtists;
 | 
|  |   2491 | ++	int numberOfAlbums;
 | 
|  |   2492 | ++	int numberOfSongs;
 | 
|  |   2493 | ++	unsigned long uptime;
 | 
|  |   2494 | ++	unsigned long dbUpdateTime;
 | 
|  |   2495 | ++	unsigned long playTime;
 | 
|  |   2496 | ++	unsigned long dbPlayTime;
 | 
|  |   2497 | ++} mpd_Stats;
 | 
|  |   2498 | ++
 | 
|  |   2499 | ++typedef struct _mpd_SearchStats {
 | 
|  |   2500 | ++	int numberOfSongs;
 | 
|  |   2501 | ++	unsigned long playTime;
 | 
|  |   2502 | ++} mpd_SearchStats;
 | 
|  |   2503 | ++
 | 
|  |   2504 | ++void mpd_sendStatsCommand(mpd_Connection * connection);
 | 
|  |   2505 | ++
 | 
|  |   2506 | ++mpd_Stats * mpd_getStats(mpd_Connection * connection);
 | 
|  |   2507 | ++
 | 
|  |   2508 | ++void mpd_freeStats(mpd_Stats * stats);
 | 
|  |   2509 | ++
 | 
|  |   2510 | ++mpd_SearchStats * mpd_getSearchStats(mpd_Connection * connection);
 | 
|  |   2511 | ++
 | 
|  |   2512 | ++void mpd_freeSearchStats(mpd_SearchStats * stats);
 | 
|  |   2513 | ++
 | 
|  |   2514 | ++/* SONG STUFF */
 | 
|  |   2515 | ++
 | 
|  |   2516 | ++#define MPD_SONG_NO_TIME	-1
 | 
|  |   2517 | ++#define MPD_SONG_NO_NUM		-1
 | 
|  |   2518 | ++#define MPD_SONG_NO_ID		-1
 | 
|  |   2519 | ++
 | 
|  |   2520 | ++/* mpd_Song
 | 
|  |   2521 | ++ * for storing song info returned by mpd
 | 
|  |   2522 | ++ */
 | 
|  |   2523 | ++typedef struct _mpd_Song {
 | 
|  |   2524 | ++	/* filename of song */
 | 
|  |   2525 | ++	char * file;
 | 
|  |   2526 | ++	/* artist, maybe NULL if there is no tag */
 | 
|  |   2527 | ++	char * artist;
 | 
|  |   2528 | ++	/* title, maybe NULL if there is no tag */
 | 
|  |   2529 | ++	char * title;
 | 
|  |   2530 | ++	/* album, maybe NULL if there is no tag */
 | 
|  |   2531 | ++	char * album;
 | 
|  |   2532 | ++	/* track, maybe NULL if there is no tag */
 | 
|  |   2533 | ++	char * track;
 | 
|  |   2534 | ++	/* name, maybe NULL if there is no tag; it's the name of the current
 | 
|  |   2535 | ++	 * song, f.e. the icyName of the stream */
 | 
|  |   2536 | ++	char * name;
 | 
|  |   2537 | ++	/* date */
 | 
|  |   2538 | ++	char *date;
 | 
|  |   2539 | ++
 | 
|  |   2540 | ++	/* added by qball */
 | 
|  |   2541 | ++	/* Genre */
 | 
|  |   2542 | ++	char *genre;
 | 
|  |   2543 | ++	/* Composer */
 | 
|  |   2544 | ++	char *composer;
 | 
|  |   2545 | ++	/* Performer */
 | 
|  |   2546 | ++	char *performer;
 | 
|  |   2547 | ++	/* Disc */
 | 
|  |   2548 | ++	char *disc;
 | 
|  |   2549 | ++	/* Comment */
 | 
|  |   2550 | ++	char *comment;
 | 
|  |   2551 | ++
 | 
|  |   2552 | ++	/* length of song in seconds, check that it is not MPD_SONG_NO_TIME  */
 | 
|  |   2553 | ++	int time;
 | 
|  |   2554 | ++	/* if plchanges/playlistinfo/playlistid used, is the position of the
 | 
|  |   2555 | ++	 * song in the playlist */
 | 
|  |   2556 | ++	int pos;
 | 
|  |   2557 | ++	/* song id for a song in the playlist */
 | 
|  |   2558 | ++	int id;
 | 
|  |   2559 | ++} mpd_Song;
 | 
|  |   2560 | ++
 | 
|  |   2561 | ++/* mpd_newSong
 | 
|  |   2562 | ++ * use to allocate memory for a new mpd_Song
 | 
|  |   2563 | ++ * file, artist, etc all initialized to NULL
 | 
|  |   2564 | ++ * if your going to assign values to file, artist, etc
 | 
|  |   2565 | ++ * be sure to malloc or strdup the memory
 | 
|  |   2566 | ++ * use mpd_freeSong to free the memory for the mpd_Song, it will also
 | 
|  |   2567 | ++ * free memory for file, artist, etc, so don't do it yourself
 | 
|  |   2568 | ++ */
 | 
|  |   2569 | ++mpd_Song * mpd_newSong(void);
 | 
|  |   2570 | ++
 | 
|  |   2571 | ++/* mpd_freeSong
 | 
|  |   2572 | ++ * use to free memory allocated by mpd_newSong
 | 
|  |   2573 | ++ * also it will free memory pointed to by file, artist, etc, so be careful
 | 
|  |   2574 | ++ */
 | 
|  |   2575 | ++void mpd_freeSong(mpd_Song * song);
 | 
|  |   2576 | ++
 | 
|  |   2577 | ++/* mpd_songDup
 | 
|  |   2578 | ++ * works like strDup, but for a mpd_Song
 | 
|  |   2579 | ++ */
 | 
|  |   2580 | ++mpd_Song * mpd_songDup(mpd_Song * song);
 | 
|  |   2581 | ++
 | 
|  |   2582 | ++/* DIRECTORY STUFF */
 | 
|  |   2583 | ++
 | 
|  |   2584 | ++/* mpd_Directory
 | 
|  |   2585 | ++ * used to store info fro directory (right now that just the path)
 | 
|  |   2586 | ++ */
 | 
|  |   2587 | ++typedef struct _mpd_Directory {
 | 
|  |   2588 | ++	char * path;
 | 
|  |   2589 | ++} mpd_Directory;
 | 
|  |   2590 | ++
 | 
|  |   2591 | ++/* mpd_newDirectory
 | 
|  |   2592 | ++ * allocates memory for a new directory
 | 
|  |   2593 | ++ * use mpd_freeDirectory to free this memory
 | 
|  |   2594 | ++ */
 | 
|  |   2595 | ++mpd_Directory * mpd_newDirectory(void);
 | 
|  |   2596 | ++
 | 
|  |   2597 | ++/* mpd_freeDirectory
 | 
|  |   2598 | ++ * used to free memory allocated with mpd_newDirectory, and it frees
 | 
|  |   2599 | ++ * path of mpd_Directory, so be careful
 | 
|  |   2600 | ++ */
 | 
|  |   2601 | ++void mpd_freeDirectory(mpd_Directory * directory);
 | 
|  |   2602 | ++
 | 
|  |   2603 | ++/* mpd_directoryDup
 | 
|  |   2604 | ++ * works like strdup, but for mpd_Directory
 | 
|  |   2605 | ++ */
 | 
|  |   2606 | ++mpd_Directory * mpd_directoryDup(mpd_Directory * directory);
 | 
|  |   2607 | ++
 | 
|  |   2608 | ++/* PLAYLISTFILE STUFF */
 | 
|  |   2609 | ++
 | 
|  |   2610 | ++/* mpd_PlaylistFile
 | 
|  |   2611 | ++ * stores info about playlist file returned by lsinfo
 | 
|  |   2612 | ++ */
 | 
|  |   2613 | ++typedef struct _mpd_PlaylistFile {
 | 
|  |   2614 | ++	char * path;
 | 
|  |   2615 | ++} mpd_PlaylistFile;
 | 
|  |   2616 | ++
 | 
|  |   2617 | ++/* mpd_newPlaylistFile
 | 
|  |   2618 | ++ * allocates memory for new mpd_PlaylistFile, path is set to NULL
 | 
|  |   2619 | ++ * free this memory with mpd_freePlaylistFile
 | 
|  |   2620 | ++ */
 | 
|  |   2621 | ++mpd_PlaylistFile * mpd_newPlaylistFile(void);
 | 
|  |   2622 | ++
 | 
|  |   2623 | ++/* mpd_freePlaylist
 | 
|  |   2624 | ++ * free memory allocated for freePlaylistFile, will also free
 | 
|  |   2625 | ++ * path, so be careful
 | 
|  |   2626 | ++ */
 | 
|  |   2627 | ++void mpd_freePlaylistFile(mpd_PlaylistFile * playlist);
 | 
|  |   2628 | ++
 | 
|  |   2629 | ++/* mpd_playlistFileDup
 | 
|  |   2630 | ++ * works like strdup, but for mpd_PlaylistFile
 | 
|  |   2631 | ++ */
 | 
|  |   2632 | ++mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist);
 | 
|  |   2633 | ++
 | 
|  |   2634 | ++/* INFO ENTITY STUFF */
 | 
|  |   2635 | ++
 | 
|  |   2636 | ++/* the type of entity returned from one of the commands that generates info
 | 
|  |   2637 | ++ * use in conjunction with mpd_InfoEntity.type
 | 
|  |   2638 | ++ */
 | 
|  |   2639 | ++#define MPD_INFO_ENTITY_TYPE_DIRECTORY		0
 | 
|  |   2640 | ++#define MPD_INFO_ENTITY_TYPE_SONG		1
 | 
|  |   2641 | ++#define MPD_INFO_ENTITY_TYPE_PLAYLISTFILE	2
 | 
|  |   2642 | ++
 | 
|  |   2643 | ++/* mpd_InfoEntity
 | 
|  |   2644 | ++ * stores info on stuff returned info commands
 | 
|  |   2645 | ++ */
 | 
|  |   2646 | ++typedef struct mpd_InfoEntity {
 | 
|  |   2647 | ++	/* the type of entity, use with MPD_INFO_ENTITY_TYPE_* to determine
 | 
|  |   2648 | ++	 * what this entity is (song, directory, etc...)
 | 
|  |   2649 | ++	 */
 | 
|  |   2650 | ++	int type;
 | 
|  |   2651 | ++	/* the actual data you want, mpd_Song, mpd_Directory, etc */
 | 
|  |   2652 | ++	union {
 | 
|  |   2653 | ++		mpd_Directory * directory;
 | 
|  |   2654 | ++		mpd_Song * song;
 | 
|  |   2655 | ++		mpd_PlaylistFile * playlistFile;
 | 
|  |   2656 | ++	} info;
 | 
|  |   2657 | ++} mpd_InfoEntity;
 | 
|  |   2658 | ++
 | 
|  |   2659 | ++mpd_InfoEntity * mpd_newInfoEntity(void);
 | 
|  |   2660 | ++
 | 
|  |   2661 | ++void mpd_freeInfoEntity(mpd_InfoEntity * entity);
 | 
|  |   2662 | ++
 | 
|  |   2663 | ++/* INFO COMMANDS AND STUFF */
 | 
|  |   2664 | ++
 | 
|  |   2665 | ++/* use this function to loop over after calling Info/Listall functions */
 | 
|  |   2666 | ++mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection);
 | 
|  |   2667 | ++
 | 
|  |   2668 | ++/* fetches the currently seeletect song (the song referenced by status->song
 | 
|  |   2669 | ++ * and status->songid*/
 | 
|  |   2670 | ++void mpd_sendCurrentSongCommand(mpd_Connection * connection);
 | 
|  |   2671 | ++
 | 
|  |   2672 | ++/* songNum of -1, means to display the whole list */
 | 
|  |   2673 | ++void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songNum);
 | 
|  |   2674 | ++
 | 
|  |   2675 | ++/* songId of -1, means to display the whole list */
 | 
|  |   2676 | ++void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int songId);
 | 
|  |   2677 | ++
 | 
|  |   2678 | ++/* use this to get the changes in the playlist since version _playlist_ */
 | 
|  |   2679 | ++void mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist);
 | 
|  |   2680 | ++
 | 
|  |   2681 | ++/**
 | 
|  |   2682 | ++ * @param connection: A valid and connected mpd_Connection.
 | 
|  |   2683 | ++ * @param playlist: The playlist version you want the diff with.
 | 
|  |   2684 | ++ * A more bandwidth efficient version of the mpd_sendPlChangesCommand.
 | 
|  |   2685 | ++ * It only returns the pos+id of the changes song.
 | 
|  |   2686 | ++ */
 | 
|  |   2687 | ++void mpd_sendPlChangesPosIdCommand(mpd_Connection * connection, long long playlist);
 | 
|  |   2688 | ++
 | 
|  |   2689 | ++/* recursivel fetches all songs/dir/playlists in "dir* (no metadata is
 | 
|  |   2690 | ++ * returned) */
 | 
|  |   2691 | ++void mpd_sendListallCommand(mpd_Connection * connection, const char * dir);
 | 
|  |   2692 | ++
 | 
|  |   2693 | ++/* same as sendListallCommand, but also metadata is returned */
 | 
|  |   2694 | ++void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir);
 | 
|  |   2695 | ++
 | 
|  |   2696 | ++/* non-recursive version of ListallInfo */
 | 
|  |   2697 | ++void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir);
 | 
|  |   2698 | ++
 | 
|  |   2699 | ++#define MPD_TABLE_ARTIST	MPD_TAG_ITEM_ARTIST
 | 
|  |   2700 | ++#define MPD_TABLE_ALBUM		MPD_TAG_ITEM_ALBUM
 | 
|  |   2701 | ++#define MPD_TABLE_TITLE		MPD_TAG_ITEM_TITLE
 | 
|  |   2702 | ++#define MPD_TABLE_FILENAME	MPD_TAG_ITEM_FILENAME
 | 
|  |   2703 | ++
 | 
|  |   2704 | ++void mpd_sendSearchCommand(mpd_Connection * connection, int table,
 | 
|  |   2705 | ++		const char * str);
 | 
|  |   2706 | ++
 | 
|  |   2707 | ++void mpd_sendFindCommand(mpd_Connection * connection, int table,
 | 
|  |   2708 | ++		const char * str);
 | 
|  |   2709 | ++
 | 
|  |   2710 | ++/* LIST TAG COMMANDS */
 | 
|  |   2711 | ++
 | 
|  |   2712 | ++/* use this function fetch next artist entry, be sure to free the returned
 | 
|  |   2713 | ++ * string.  NULL means there are no more.  Best used with sendListArtists
 | 
|  |   2714 | ++ */
 | 
|  |   2715 | ++char * mpd_getNextArtist(mpd_Connection * connection);
 | 
|  |   2716 | ++
 | 
|  |   2717 | ++char * mpd_getNextAlbum(mpd_Connection * connection);
 | 
|  |   2718 | ++
 | 
|  |   2719 | ++char * mpd_getNextTag(mpd_Connection *connection, int type);
 | 
|  |   2720 | ++
 | 
|  |   2721 | ++/* list artist or albums by artist, arg1 should be set to the artist if
 | 
|  |   2722 | ++ * listing albums by a artist, otherwise NULL for listing all artists or albums
 | 
|  |   2723 | ++ */
 | 
|  |   2724 | ++void mpd_sendListCommand(mpd_Connection * connection, int table,
 | 
|  |   2725 | ++		const char * arg1);
 | 
|  |   2726 | ++
 | 
|  |   2727 | ++/* SIMPLE COMMANDS */
 | 
|  |   2728 | ++
 | 
|  |   2729 | ++void mpd_sendAddCommand(mpd_Connection * connection, const char * file);
 | 
|  |   2730 | ++
 | 
|  |   2731 | ++int mpd_sendAddIdCommand(mpd_Connection *connection, const char *file);
 | 
|  |   2732 | ++
 | 
|  |   2733 | ++void mpd_sendDeleteCommand(mpd_Connection * connection, int songNum);
 | 
|  |   2734 | ++
 | 
|  |   2735 | ++void mpd_sendDeleteIdCommand(mpd_Connection * connection, int songNum);
 | 
|  |   2736 | ++
 | 
|  |   2737 | ++void mpd_sendSaveCommand(mpd_Connection * connection, const char * name);
 | 
|  |   2738 | ++
 | 
|  |   2739 | ++void mpd_sendLoadCommand(mpd_Connection * connection, const char * name);
 | 
|  |   2740 | ++
 | 
|  |   2741 | ++void mpd_sendRmCommand(mpd_Connection * connection, const char * name);
 | 
|  |   2742 | ++
 | 
|  |   2743 | ++void mpd_sendRenameCommand(mpd_Connection *connection, const char *from,
 | 
|  |   2744 | ++                           const char *to);
 | 
|  |   2745 | ++
 | 
|  |   2746 | ++void mpd_sendShuffleCommand(mpd_Connection * connection);
 | 
|  |   2747 | ++
 | 
|  |   2748 | ++void mpd_sendClearCommand(mpd_Connection * connection);
 | 
|  |   2749 | ++
 | 
|  |   2750 | ++/* use this to start playing at the beginning, useful when in random mode */
 | 
|  |   2751 | ++#define MPD_PLAY_AT_BEGINNING	-1
 | 
|  |   2752 | ++
 | 
|  |   2753 | ++void mpd_sendPlayCommand(mpd_Connection * connection, int songNum);
 | 
|  |   2754 | ++
 | 
|  |   2755 | ++void mpd_sendPlayIdCommand(mpd_Connection * connection, int songNum);
 | 
|  |   2756 | ++
 | 
|  |   2757 | ++void mpd_sendStopCommand(mpd_Connection * connection);
 | 
|  |   2758 | ++
 | 
|  |   2759 | ++void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode);
 | 
|  |   2760 | ++
 | 
|  |   2761 | ++void mpd_sendNextCommand(mpd_Connection * connection);
 | 
|  |   2762 | ++
 | 
|  |   2763 | ++void mpd_sendPrevCommand(mpd_Connection * connection);
 | 
|  |   2764 | ++
 | 
|  |   2765 | ++void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to);
 | 
|  |   2766 | ++
 | 
|  |   2767 | ++void mpd_sendMoveIdCommand(mpd_Connection * connection, int from, int to);
 | 
|  |   2768 | ++
 | 
|  |   2769 | ++void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2);
 | 
|  |   2770 | ++
 | 
|  |   2771 | ++void mpd_sendSwapIdCommand(mpd_Connection * connection, int song1, int song2);
 | 
|  |   2772 | ++
 | 
|  |   2773 | ++void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time);
 | 
|  |   2774 | ++
 | 
|  |   2775 | ++void mpd_sendSeekIdCommand(mpd_Connection * connection, int song, int time);
 | 
|  |   2776 | ++
 | 
|  |   2777 | ++void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode);
 | 
|  |   2778 | ++
 | 
|  |   2779 | ++void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode);
 | 
|  |   2780 | ++
 | 
|  |   2781 | ++void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange);
 | 
|  |   2782 | ++
 | 
|  |   2783 | ++/* WARNING: don't use volume command, its depreacted */
 | 
|  |   2784 | ++void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange);
 | 
|  |   2785 | ++
 | 
|  |   2786 | ++void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds);
 | 
|  |   2787 | ++
 | 
|  |   2788 | ++void mpd_sendUpdateCommand(mpd_Connection * connection, char * path);
 | 
|  |   2789 | ++
 | 
|  |   2790 | ++/* returns the update job id, call this after a update command*/
 | 
|  |   2791 | ++int mpd_getUpdateId(mpd_Connection * connection);
 | 
|  |   2792 | ++
 | 
|  |   2793 | ++void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass);
 | 
|  |   2794 | ++
 | 
|  |   2795 | ++/* after executing a command, when your done with it to get its status
 | 
|  |   2796 | ++ * (you want to check connection->error for an error)
 | 
|  |   2797 | ++ */
 | 
|  |   2798 | ++void mpd_finishCommand(mpd_Connection * connection);
 | 
|  |   2799 | ++
 | 
|  |   2800 | ++/* command list stuff, use this to do things like add files very quickly */
 | 
|  |   2801 | ++void mpd_sendCommandListBegin(mpd_Connection * connection);
 | 
|  |   2802 | ++
 | 
|  |   2803 | ++void mpd_sendCommandListOkBegin(mpd_Connection * connection);
 | 
|  |   2804 | ++
 | 
|  |   2805 | ++void mpd_sendCommandListEnd(mpd_Connection * connection);
 | 
|  |   2806 | ++
 | 
|  |   2807 | ++/* advance to the next listOk
 | 
|  |   2808 | ++ * returns 0 if advanced to the next list_OK,
 | 
|  |   2809 | ++ * returns -1 if it advanced to an OK or ACK */
 | 
|  |   2810 | ++int mpd_nextListOkCommand(mpd_Connection * connection);
 | 
|  |   2811 | ++
 | 
|  |   2812 | ++typedef struct _mpd_OutputEntity {
 | 
|  |   2813 | ++	int id;
 | 
|  |   2814 | ++	char * name;
 | 
|  |   2815 | ++	int enabled;
 | 
|  |   2816 | ++} mpd_OutputEntity;
 | 
|  |   2817 | ++
 | 
|  |   2818 | ++void mpd_sendOutputsCommand(mpd_Connection * connection);
 | 
|  |   2819 | ++
 | 
|  |   2820 | ++mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection);
 | 
|  |   2821 | ++
 | 
|  |   2822 | ++void mpd_sendEnableOutputCommand(mpd_Connection * connection, int outputId);
 | 
|  |   2823 | ++
 | 
|  |   2824 | ++void mpd_sendDisableOutputCommand(mpd_Connection * connection, int outputId);
 | 
|  |   2825 | ++
 | 
|  |   2826 | ++void mpd_freeOutputElement(mpd_OutputEntity * output);
 | 
|  |   2827 | ++
 | 
|  |   2828 | ++/**
 | 
|  |   2829 | ++ * @param connection a #mpd_Connection
 | 
|  |   2830 | ++ *
 | 
|  |   2831 | ++ * Queries mpd for the allowed commands
 | 
|  |   2832 | ++ */
 | 
|  |   2833 | ++void mpd_sendCommandsCommand(mpd_Connection * connection);
 | 
|  |   2834 | ++
 | 
|  |   2835 | ++/**
 | 
|  |   2836 | ++ * @param connection a #mpd_Connection
 | 
|  |   2837 | ++ *
 | 
|  |   2838 | ++ * Queries mpd for the not allowed commands
 | 
|  |   2839 | ++ */
 | 
|  |   2840 | ++void mpd_sendNotCommandsCommand(mpd_Connection * connection);
 | 
|  |   2841 | ++
 | 
|  |   2842 | ++/**
 | 
|  |   2843 | ++ * @param connection a #mpd_Connection
 | 
|  |   2844 | ++ *
 | 
|  |   2845 | ++ * returns the next supported command.
 | 
|  |   2846 | ++ *
 | 
|  |   2847 | ++ * @returns a string, needs to be free'ed
 | 
|  |   2848 | ++ */
 | 
|  |   2849 | ++char *mpd_getNextCommand(mpd_Connection *connection);
 | 
|  |   2850 | ++
 | 
|  |   2851 | ++void mpd_sendUrlHandlersCommand(mpd_Connection * connection);
 | 
|  |   2852 | ++
 | 
|  |   2853 | ++char *mpd_getNextHandler(mpd_Connection * connection);
 | 
|  |   2854 | ++
 | 
|  |   2855 | ++void mpd_sendTagTypesCommand(mpd_Connection * connection);
 | 
|  |   2856 | ++
 | 
|  |   2857 | ++char *mpd_getNextTagType(mpd_Connection * connection);
 | 
|  |   2858 | ++
 | 
|  |   2859 | ++/**
 | 
|  |   2860 | ++ * @param connection a MpdConnection
 | 
|  |   2861 | ++ * @param path	the path to the playlist.
 | 
|  |   2862 | ++ *
 | 
|  |   2863 | ++ * List the content, with full metadata, of a stored playlist.
 | 
|  |   2864 | ++ *
 | 
|  |   2865 | ++ */
 | 
|  |   2866 | ++void mpd_sendListPlaylistInfoCommand(mpd_Connection *connection, char *path);
 | 
|  |   2867 | ++
 | 
|  |   2868 | ++/**
 | 
|  |   2869 | ++ * @param connection a MpdConnection
 | 
|  |   2870 | ++ * @param path	the path to the playlist.
 | 
|  |   2871 | ++ *
 | 
|  |   2872 | ++ * List the content of a stored playlist.
 | 
|  |   2873 | ++ *
 | 
|  |   2874 | ++ */
 | 
|  |   2875 | ++void mpd_sendListPlaylistCommand(mpd_Connection *connection, char *path);
 | 
|  |   2876 | ++
 | 
|  |   2877 | ++/**
 | 
|  |   2878 | ++ * @param connection a #mpd_Connection
 | 
|  |   2879 | ++ * @param exact if to match exact
 | 
|  |   2880 | ++ *
 | 
|  |   2881 | ++ * starts a search, use mpd_addConstraintSearch to add
 | 
|  |   2882 | ++ * a constraint to the search, and mpd_commitSearch to do the actual search
 | 
|  |   2883 | ++ */
 | 
|  |   2884 | ++void mpd_startSearch(mpd_Connection *connection, int exact);
 | 
|  |   2885 | ++
 | 
|  |   2886 | ++/**
 | 
|  |   2887 | ++ * @param connection a #mpd_Connection
 | 
|  |   2888 | ++ * @param type
 | 
|  |   2889 | ++ * @param name
 | 
|  |   2890 | ++ */
 | 
|  |   2891 | ++void mpd_addConstraintSearch(mpd_Connection *connection, int type, const char *name);
 | 
|  |   2892 | ++
 | 
|  |   2893 | ++/**
 | 
|  |   2894 | ++ * @param connection a #mpd_Connection
 | 
|  |   2895 | ++ */
 | 
|  |   2896 | ++void mpd_commitSearch(mpd_Connection *connection);
 | 
|  |   2897 | ++
 | 
|  |   2898 | ++/**
 | 
|  |   2899 | ++ * @param connection a #mpd_Connection
 | 
|  |   2900 | ++ * @param type The type to search for
 | 
|  |   2901 | ++ *
 | 
|  |   2902 | ++ * starts a search for fields... f.e. get a list of artists would be:
 | 
|  |   2903 | ++ * @code
 | 
|  |   2904 | ++ * mpd_startFieldSearch(connection, MPD_TAG_ITEM_ARTIST);
 | 
|  |   2905 | ++ * mpd_commitSearch(connection);
 | 
|  |   2906 | ++ * @endcode
 | 
|  |   2907 | ++ *
 | 
|  |   2908 | ++ * or get a list of artist in genre "jazz" would be:
 | 
|  |   2909 | ++ * @code
 | 
|  |   2910 | ++ * mpd_startFieldSearch(connection, MPD_TAG_ITEM_ARTIST);
 | 
|  |   2911 | ++ * mpd_addConstraintSearch(connection, MPD_TAG_ITEM_GENRE, "jazz")
 | 
|  |   2912 | ++ * mpd_commitSearch(connection);
 | 
|  |   2913 | ++ * @endcode
 | 
|  |   2914 | ++ *
 | 
|  |   2915 | ++ * mpd_startSearch will return  a list of songs (and you need mpd_getNextInfoEntity)
 | 
|  |   2916 | ++ * this one will return a list of only one field (the one specified with type) and you need
 | 
|  |   2917 | ++ * mpd_getNextTag to get the results
 | 
|  |   2918 | ++ */
 | 
|  |   2919 | ++void mpd_startFieldSearch(mpd_Connection *connection, int type);
 | 
|  |   2920 | ++
 | 
|  |   2921 | ++void mpd_startPlaylistSearch(mpd_Connection *connection, int exact);
 | 
|  |   2922 | ++
 | 
|  |   2923 | ++void mpd_startStatsSearch(mpd_Connection *connection);
 | 
|  |   2924 | ++
 | 
|  |   2925 | ++void mpd_sendPlaylistClearCommand(mpd_Connection *connection, char *path);
 | 
|  |   2926 | ++
 | 
|  |   2927 | ++void mpd_sendPlaylistAddCommand(mpd_Connection *connection,
 | 
|  |   2928 | ++                                char *playlist, char *path);
 | 
|  |   2929 | ++
 | 
|  |   2930 | ++void mpd_sendPlaylistMoveCommand(mpd_Connection *connection,
 | 
|  |   2931 | ++                                 char *playlist, int from, int to);
 | 
|  |   2932 | ++
 | 
|  |   2933 | ++void mpd_sendPlaylistDeleteCommand(mpd_Connection *connection,
 | 
|  |   2934 | ++                                   char *playlist, int pos);
 | 
|  |   2935 | ++#ifdef __cplusplus
 | 
|  |   2936 | ++}
 | 
|  |   2937 | ++#endif
 | 
|  |   2938 | ++
 | 
|  |   2939 | ++#endif
 | 
|  |   2940 | +diff -r 171db9560cb5 clients/mpd/mpdinterface.cc
 | 
|  |   2941 | +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
 | 
|  |   2942 | ++++ b/clients/mpd/mpdinterface.cc	Mon May 19 00:21:51 2008 -0400
 | 
|  |   2943 | +@@ -0,0 +1,404 @@
 | 
|  |   2944 | ++#include "mpdinterface.h"
 | 
|  |   2945 | ++#include "immsutil.h"
 | 
|  |   2946 | ++#include <cctype>
 | 
|  |   2947 | ++#include <fstream>
 | 
|  |   2948 | ++#include <sstream>
 | 
|  |   2949 | ++
 | 
|  |   2950 | ++namespace mpd_interface
 | 
|  |   2951 | ++{
 | 
|  |   2952 | ++  position_err::position_err(int position, int playlist_length)
 | 
|  |   2953 | ++  {
 | 
|  |   2954 | ++    std::ostringstream s;
 | 
|  |   2955 | ++    s << "Attempted to access song of invalid position in playlist. "
 | 
|  |   2956 | ++      "Used position: " << position << ", playlist size: "
 | 
|  |   2957 | ++      << playlist_length;
 | 
|  |   2958 | ++    msg = s.str();
 | 
|  |   2959 | ++  }
 | 
|  |   2960 | ++
 | 
|  |   2961 | ++  std::string Song::music_directory = "";
 | 
|  |   2962 | ++
 | 
|  |   2963 | ++  void Song::set_default_dir(std::string path)
 | 
|  |   2964 | ++  {
 | 
|  |   2965 | ++    music_directory = path;
 | 
|  |   2966 | ++    if(!path.empty() && path[path.length()-1]!='/') {
 | 
|  |   2967 | ++      music_directory.append("/");
 | 
|  |   2968 | ++    }
 | 
|  |   2969 | ++  }
 | 
|  |   2970 | ++
 | 
|  |   2971 | ++  bool operator==(const Song& first, const Song& second)
 | 
|  |   2972 | ++  {
 | 
|  |   2973 | ++    return (first.song_path == second.song_path) &&
 | 
|  |   2974 | ++      (first.pl_pos == second.pl_pos) &&
 | 
|  |   2975 | ++      (first.song_length == second.song_length);
 | 
|  |   2976 | ++  }
 | 
|  |   2977 | ++  bool operator!=(const Song& first, const Song& second)
 | 
|  |   2978 | ++  {
 | 
|  |   2979 | ++    return !(first == second);
 | 
|  |   2980 | ++  }
 | 
|  |   2981 | ++
 | 
|  |   2982 | ++  // determines whether the line contains the given parameter in the
 | 
|  |   2983 | ++  // mpd.conf fashion
 | 
|  |   2984 | ++  bool contains_parameter(const std::string& line, const std::string& parameter)
 | 
|  |   2985 | ++  {
 | 
|  |   2986 | ++    if(line.empty() || line[0]=='#') return false;
 | 
|  |   2987 | ++    
 | 
|  |   2988 | ++    std::string::size_type pos = line.find(parameter);
 | 
|  |   2989 | ++    if(pos == std::string::npos) return false;
 | 
|  |   2990 | ++
 | 
|  |   2991 | ++    while(pos>0) {
 | 
|  |   2992 | ++      if(!isspace(line[pos-1])) return false;
 | 
|  |   2993 | ++      --pos;
 | 
|  |   2994 | ++    }
 | 
|  |   2995 | ++    return true;
 | 
|  |   2996 | ++  }
 | 
|  |   2997 | ++
 | 
|  |   2998 | ++  // returns the value of the given parameter from an mpd.config line
 | 
|  |   2999 | ++  std::string get_value(const std::string& line,
 | 
|  |   3000 | ++      const std::string& parameter)
 | 
|  |   3001 | ++  {
 | 
|  |   3002 | ++    if(!contains_parameter(line, parameter)) return "";
 | 
|  |   3003 | ++
 | 
|  |   3004 | ++    std::string::size_type start = line.find_first_of("\"");
 | 
|  |   3005 | ++    ++start; // position of the first non-quote char
 | 
|  |   3006 | ++    if(start == std::string::npos || start>=line.size()) return "";
 | 
|  |   3007 | ++
 | 
|  |   3008 | ++    std::string::size_type end = line.find_last_of("\"");
 | 
|  |   3009 | ++    if(end == std::string::npos) return "";
 | 
|  |   3010 | ++
 | 
|  |   3011 | ++    std::string result = line.substr(start, end-start);
 | 
|  |   3012 | ++    return result;
 | 
|  |   3013 | ++  }
 | 
|  |   3014 | ++
 | 
|  |   3015 | ++  config read_configuration(std::string conf_path) throw(config_err)
 | 
|  |   3016 | ++  {
 | 
|  |   3017 | ++    static const std::string address_param = "bind_to_address";
 | 
|  |   3018 | ++    static const std::string port_param = "port";
 | 
|  |   3019 | ++    static const std::string dir_param = "music_directory";
 | 
|  |   3020 | ++
 | 
|  |   3021 | ++    if(conf_path == "")
 | 
|  |   3022 | ++    {
 | 
|  |   3023 | ++      std::string user_path = getenv("HOME");
 | 
|  |   3024 | ++      if(user_path[user_path.size()-1] != '/') user_path.append("/");
 | 
|  |   3025 | ++      user_path.append(".mpdconf");
 | 
|  |   3026 | ++
 | 
|  |   3027 | ++      try {
 | 
|  |   3028 | ++	// read the "~/.mpdconf" file
 | 
|  |   3029 | ++	return read_configuration(user_path);
 | 
|  |   3030 | ++      }
 | 
|  |   3031 | ++      catch (config_err) { // "~/.mpdconf" not found
 | 
|  |   3032 | ++	  // read the "/etc/mpd.conf" instead
 | 
|  |   3033 | ++	  return read_configuration("/etc/mpd.conf");
 | 
|  |   3034 | ++      }
 | 
|  |   3035 | ++    }
 | 
|  |   3036 | ++    else
 | 
|  |   3037 | ++    {
 | 
|  |   3038 | ++      std::ifstream con_f(conf_path.c_str());
 | 
|  |   3039 | ++      if(!con_f) {
 | 
|  |   3040 | ++	throw config_err("cannot open the MPD config file \"" +
 | 
|  |   3041 | ++	    conf_path + "\"");
 | 
|  |   3042 | ++      }
 | 
|  |   3043 | ++
 | 
|  |   3044 | ++      config result;
 | 
|  |   3045 | ++      std::string line;
 | 
|  |   3046 | ++      while(getline(con_f, line)) {
 | 
|  |   3047 | ++	if(contains_parameter(line, address_param)) {
 | 
|  |   3048 | ++	  result.hostname = get_value(line, address_param);
 | 
|  |   3049 | ++	  if(result.hostname.empty()) result.hostname = "localhost";
 | 
|  |   3050 | ++	}
 | 
|  |   3051 | ++	else if(contains_parameter(line, port_param)) {
 | 
|  |   3052 | ++	  std::stringstream s;
 | 
|  |   3053 | ++	  s << get_value(line, port_param);
 | 
|  |   3054 | ++	  if(!(s >> result.port)) result.port = 6600;
 | 
|  |   3055 | ++	}
 | 
|  |   3056 | ++	else if(contains_parameter(line, dir_param)) {
 | 
|  |   3057 | ++	  result.music_dir = get_value(line, dir_param);
 | 
|  |   3058 | ++	}
 | 
|  |   3059 | ++      }
 | 
|  |   3060 | ++      con_f.close();
 | 
|  |   3061 | ++      if(result.music_dir.empty()) {
 | 
|  |   3062 | ++	throw config_err("infalid format of the MPD config file \"" + 
 | 
|  |   3063 | ++	    conf_path + "\"");
 | 
|  |   3064 | ++      }
 | 
|  |   3065 | ++
 | 
|  |   3066 | ++      return result;
 | 
|  |   3067 | ++    }
 | 
|  |   3068 | ++  }
 | 
|  |   3069 | ++
 | 
|  |   3070 | ++  
 | 
|  |   3071 | ++  bool Server::connect(const std::string& hostname, int port)
 | 
|  |   3072 | ++    throw(connection_err)
 | 
|  |   3073 | ++  {
 | 
|  |   3074 | ++    if(connected()) disconnect();
 | 
|  |   3075 | ++
 | 
|  |   3076 | ++    try {
 | 
|  |   3077 | ++      connection = mpd_newConnection(hostname.c_str(), port, 10);
 | 
|  |   3078 | ++      if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3079 | ++    }
 | 
|  |   3080 | ++    catch(connection_err) {
 | 
|  |   3081 | ++      disconnect();
 | 
|  |   3082 | ++      throw;
 | 
|  |   3083 | ++    }
 | 
|  |   3084 | ++    
 | 
|  |   3085 | ++    if(connected()) {
 | 
|  |   3086 | ++    }
 | 
|  |   3087 | ++    return connected();
 | 
|  |   3088 | ++  }
 | 
|  |   3089 | ++
 | 
|  |   3090 | ++  void Server::disconnect()
 | 
|  |   3091 | ++  {
 | 
|  |   3092 | ++    if(connection!=nullptr) {
 | 
|  |   3093 | ++      mpd_closeConnection(connection);
 | 
|  |   3094 | ++    }
 | 
|  |   3095 | ++    connection = nullptr;
 | 
|  |   3096 | ++  }
 | 
|  |   3097 | ++
 | 
|  |   3098 | ++  bool Server::ack_error() const throw(connection_err)
 | 
|  |   3099 | ++  {
 | 
|  |   3100 | ++    if(!connected()) throw connection_err();
 | 
|  |   3101 | ++    return connection->error == MPD_ERROR_ACK;
 | 
|  |   3102 | ++  }
 | 
|  |   3103 | ++  // determines whether the MPD is in error state which is not the ACK error
 | 
|  |   3104 | ++  bool Server::mpd_error() const throw(connection_err)
 | 
|  |   3105 | ++  {
 | 
|  |   3106 | ++    if(!connected()) throw connection_err();
 | 
|  |   3107 | ++    return connection->error!=0 && !ack_error();
 | 
|  |   3108 | ++  }
 | 
|  |   3109 | ++
 | 
|  |   3110 | ++  // changes the mpd internal status to the playback_status type
 | 
|  |   3111 | ++  playback_status resolve_state(int mpd_state)
 | 
|  |   3112 | ++  {
 | 
|  |   3113 | ++    switch(mpd_state)
 | 
|  |   3114 | ++    {
 | 
|  |   3115 | ++      case MPD_STATUS_STATE_PLAY:
 | 
|  |   3116 | ++	return playing;
 | 
|  |   3117 | ++      case MPD_STATUS_STATE_STOP:
 | 
|  |   3118 | ++	return stopped;
 | 
|  |   3119 | ++      case MPD_STATUS_STATE_PAUSE:
 | 
|  |   3120 | ++	return paused;
 | 
|  |   3121 | ++      default:
 | 
|  |   3122 | ++	return playing;
 | 
|  |   3123 | ++    }
 | 
|  |   3124 | ++  }
 | 
|  |   3125 | ++
 | 
|  |   3126 | ++  void Server::refresh() throw(connection_err)
 | 
|  |   3127 | ++  {
 | 
|  |   3128 | ++    if(!connected()) throw connection_err();
 | 
|  |   3129 | ++    try {
 | 
|  |   3130 | ++      
 | 
|  |   3131 | ++// the mess below is here because otherwise the results in nasty problems
 | 
|  |   3132 | ++// when MPD connection times out
 | 
|  |   3133 | ++//TODO prolly doesn't have to be everywhere, though. Weed it out
 | 
|  |   3134 | ++if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3135 | ++      mpd_sendCommandListOkBegin(connection);
 | 
|  |   3136 | ++if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3137 | ++      mpd_sendStatusCommand(connection);
 | 
|  |   3138 | ++if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3139 | ++      mpd_sendCurrentSongCommand(connection);
 | 
|  |   3140 | ++if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3141 | ++      mpd_sendCommandListEnd(connection);
 | 
|  |   3142 | ++if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3143 | ++
 | 
|  |   3144 | ++      mpd_Status * status = mpd_getStatus(connection);
 | 
|  |   3145 | ++      if(status!=nullptr) {
 | 
|  |   3146 | ++
 | 
|  |   3147 | ++      pl_length = status->playlistLength;
 | 
|  |   3148 | ++      pl_version = status->playlist;
 | 
|  |   3149 | ++      pb_status = resolve_state(status->state);
 | 
|  |   3150 | ++      current_song.set_elapsed(status->elapsedTime);
 | 
|  |   3151 | ++      random = status->random;
 | 
|  |   3152 | ++
 | 
|  |   3153 | ++      mpd_freeStatus(status);
 | 
|  |   3154 | ++      }
 | 
|  |   3155 | ++
 | 
|  |   3156 | ++      if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3157 | ++
 | 
|  |   3158 | ++      mpd_nextListOkCommand(connection);
 | 
|  |   3159 | ++      mpd_InfoEntity *entity;
 | 
|  |   3160 | ++      while((entity = mpd_getNextInfoEntity(connection))) {
 | 
|  |   3161 | ++	mpd_Song *song = entity->info.song;
 | 
|  |   3162 | ++
 | 
|  |   3163 | ++	if(entity->type!=MPD_INFO_ENTITY_TYPE_SONG) {
 | 
|  |   3164 | ++	  mpd_freeInfoEntity(entity);
 | 
|  |   3165 | ++	  continue;
 | 
|  |   3166 | ++	}
 | 
|  |   3167 | ++	
 | 
|  |   3168 | ++	current_song.set_path(song->file);
 | 
|  |   3169 | ++	current_song.set_pos(song->pos);
 | 
|  |   3170 | ++	current_song.set_length(song->time);
 | 
|  |   3171 | ++	mpd_freeInfoEntity(entity);
 | 
|  |   3172 | ++      }
 | 
|  |   3173 | ++      if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3174 | ++
 | 
|  |   3175 | ++      mpd_finishCommand(connection);
 | 
|  |   3176 | ++      if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3177 | ++    }
 | 
|  |   3178 | ++    catch(connection_err) {
 | 
|  |   3179 | ++      disconnect();
 | 
|  |   3180 | ++      throw;
 | 
|  |   3181 | ++    }
 | 
|  |   3182 | ++  }
 | 
|  |   3183 | ++
 | 
|  |   3184 | ++  Song Server::get_song_info(int pl_pos)
 | 
|  |   3185 | ++    throw(connection_err, position_err)   
 | 
|  |   3186 | ++  {
 | 
|  |   3187 | ++    if(!connected()) throw connection_err();
 | 
|  |   3188 | ++    if(pl_pos < 0 || pl_pos >= get_playlist_length()) {
 | 
|  |   3189 | ++      throw position_err(pl_pos, get_playlist_length());
 | 
|  |   3190 | ++    }
 | 
|  |   3191 | ++
 | 
|  |   3192 | ++    Song result;
 | 
|  |   3193 | ++    try {
 | 
|  |   3194 | ++      mpd_sendPlaylistInfoCommand(connection, pl_pos);
 | 
|  |   3195 | ++      if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3196 | ++
 | 
|  |   3197 | ++      mpd_InfoEntity *entity;
 | 
|  |   3198 | ++      while((entity = mpd_getNextInfoEntity(connection)))
 | 
|  |   3199 | ++      {
 | 
|  |   3200 | ++	mpd_Song *song = entity->info.song;
 | 
|  |   3201 | ++
 | 
|  |   3202 | ++	if(entity->type!=MPD_INFO_ENTITY_TYPE_SONG)
 | 
|  |   3203 | ++	{
 | 
|  |   3204 | ++	  mpd_freeInfoEntity(entity);
 | 
|  |   3205 | ++	  continue;
 | 
|  |   3206 | ++	}
 | 
|  |   3207 | ++	
 | 
|  |   3208 | ++	result = Song(song->file,song->pos,song->time);
 | 
|  |   3209 | ++
 | 
|  |   3210 | ++	mpd_freeInfoEntity(entity);
 | 
|  |   3211 | ++      }
 | 
|  |   3212 | ++      if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3213 | ++
 | 
|  |   3214 | ++      mpd_finishCommand(connection);
 | 
|  |   3215 | ++      if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3216 | ++      // shouldn't happen, but just in case
 | 
|  |   3217 | ++      if(ack_error())  {
 | 
|  |   3218 | ++	refresh();
 | 
|  |   3219 | ++	throw position_err(pl_pos, get_playlist_length());
 | 
|  |   3220 | ++      }
 | 
|  |   3221 | ++    }
 | 
|  |   3222 | ++    catch(connection_err)
 | 
|  |   3223 | ++    {
 | 
|  |   3224 | ++      disconnect();
 | 
|  |   3225 | ++      throw;
 | 
|  |   3226 | ++    }
 | 
|  |   3227 | ++
 | 
|  |   3228 | ++    return result;
 | 
|  |   3229 | ++  }
 | 
|  |   3230 | ++
 | 
|  |   3231 | ++  void Server::play_song(int pl_pos) throw(connection_err, position_err)
 | 
|  |   3232 | ++  {
 | 
|  |   3233 | ++    if(!connected()) throw connection_err();
 | 
|  |   3234 | ++    if(pl_pos < 0 || pl_pos >= pl_length) {
 | 
|  |   3235 | ++      throw position_err(pl_pos, get_playlist_length());
 | 
|  |   3236 | ++    }
 | 
|  |   3237 | ++
 | 
|  |   3238 | ++    try {
 | 
|  |   3239 | ++      mpd_sendPlayCommand(connection, pl_pos);
 | 
|  |   3240 | ++      mpd_finishCommand(connection);
 | 
|  |   3241 | ++      if(mpd_error()) throw connection_err(connection->errorStr);
 | 
|  |   3242 | ++      if(ack_error()) throw position_err(pl_pos, get_playlist_length());
 | 
|  |   3243 | ++    }
 | 
|  |   3244 | ++    catch(connection_err) {
 | 
|  |   3245 | ++      disconnect();
 | 
|  |   3246 | ++      throw;
 | 
|  |   3247 | ++    }
 | 
|  |   3248 | ++  }
 | 
|  |   3249 | ++  // end of SERVER section
 | 
|  |   3250 | ++
 | 
|  |   3251 | ++
 | 
|  |   3252 | ++  // Player class
 | 
|  |   3253 | ++  Player::Player(): previous_status(stopped), current_status(stopped),
 | 
|  |   3254 | ++  previous_song_pos(Song::invalid_pos), current_song_pos(Song::invalid_pos),
 | 
|  |   3255 | ++  null_song()
 | 
|  |   3256 | ++  {
 | 
|  |   3257 | ++  }
 | 
|  |   3258 | ++
 | 
|  |   3259 | ++  bool Player::connect() throw(config_err, connection_err)
 | 
|  |   3260 | ++  {
 | 
|  |   3261 | ++    config conf = read_configuration();
 | 
|  |   3262 | ++    Song::set_default_dir(conf.music_dir);
 | 
|  |   3263 | ++    return mpd.connect(conf.hostname, conf.port);
 | 
|  |   3264 | ++  }
 | 
|  |   3265 | ++
 | 
|  |   3266 | ++  void Player::disconnect()
 | 
|  |   3267 | ++  {
 | 
|  |   3268 | ++    mpd.disconnect();
 | 
|  |   3269 | ++  }
 | 
|  |   3270 | ++
 | 
|  |   3271 | ++  void Player::refresh()
 | 
|  |   3272 | ++  {
 | 
|  |   3273 | ++    mpd.refresh();
 | 
|  |   3274 | ++
 | 
|  |   3275 | ++    playlist__changed = pl_ver != mpd.get_playlist_version();
 | 
|  |   3276 | ++    if(playlist__changed) {
 | 
|  |   3277 | ++      pl_ver = mpd.get_playlist_version();
 | 
|  |   3278 | ++
 | 
|  |   3279 | ++      // update the internal playlist
 | 
|  |   3280 | ++      playlist.clear();
 | 
|  |   3281 | ++      playlist.reserve(mpd.get_playlist_length());
 | 
|  |   3282 | ++      for(int i = 0; i<mpd.get_playlist_length(); i++) {
 | 
|  |   3283 | ++	playlist.push_back(mpd.get_song_info(i));
 | 
|  |   3284 | ++      }
 | 
|  |   3285 | ++    }
 | 
|  |   3286 | ++
 | 
|  |   3287 | ++    song__changed = mpd.get_current_song() != song(current);
 | 
|  |   3288 | ++    if(song__changed) {
 | 
|  |   3289 | ++      previous_song_pos = current_song_pos;
 | 
|  |   3290 | ++      current_song_pos = mpd.get_current_song().pos();
 | 
|  |   3291 | ++    }
 | 
|  |   3292 | ++    else if(!playlist.empty() && current_song_pos != Song::invalid_pos) {
 | 
|  |   3293 | ++      playlist[current_song_pos].set_elapsed(mpd.get_current_song().
 | 
|  |   3294 | ++	  elapsed());
 | 
|  |   3295 | ++    }
 | 
|  |   3296 | ++
 | 
|  |   3297 | ++    status__changed = current_status != mpd.get_playback_status();
 | 
|  |   3298 | ++    if(status__changed) {
 | 
|  |   3299 | ++      previous_status = current_status;
 | 
|  |   3300 | ++      current_status = mpd.get_playback_status();
 | 
|  |   3301 | ++    }
 | 
|  |   3302 | ++  }
 | 
|  |   3303 | ++
 | 
|  |   3304 | ++  const Song& Player::song(recent value) const
 | 
|  |   3305 | ++  {
 | 
|  |   3306 | ++    if(playlist.empty()) return null_song;
 | 
|  |   3307 | ++
 | 
|  |   3308 | ++    switch(value) {
 | 
|  |   3309 | ++      case previous:
 | 
|  |   3310 | ++	return previous_song_pos == Song::invalid_pos ?
 | 
|  |   3311 | ++	  null_song : song(previous_song_pos);
 | 
|  |   3312 | ++
 | 
|  |   3313 | ++      case current:
 | 
|  |   3314 | ++      default:
 | 
|  |   3315 | ++	return current_song_pos == Song::invalid_pos ?
 | 
|  |   3316 | ++	  null_song : song(current_song_pos);
 | 
|  |   3317 | ++    }
 | 
|  |   3318 | ++  }
 | 
|  |   3319 | ++  const Song& Player::song(int position) const throw(position_err)
 | 
|  |   3320 | ++  {
 | 
|  |   3321 | ++    try {
 | 
|  |   3322 | ++      return playlist.at(position);
 | 
|  |   3323 | ++    }
 | 
|  |   3324 | ++    catch (...) {
 | 
|  |   3325 | ++      throw position_err(position, playlist.size());
 | 
|  |   3326 | ++    }
 | 
|  |   3327 | ++  }
 | 
|  |   3328 | ++
 | 
|  |   3329 | ++  playback_status Player::status(recent value) const
 | 
|  |   3330 | ++  {
 | 
|  |   3331 | ++    switch (value) {
 | 
|  |   3332 | ++      case previous: return previous_status;
 | 
|  |   3333 | ++      case current:
 | 
|  |   3334 | ++      default: return current_status;
 | 
|  |   3335 | ++    }
 | 
|  |   3336 | ++  }
 | 
|  |   3337 | ++
 | 
|  |   3338 | ++  void Player::play_song(int pl_pos)
 | 
|  |   3339 | ++  {
 | 
|  |   3340 | ++    mpd.play_song(pl_pos);
 | 
|  |   3341 | ++  }
 | 
|  |   3342 | ++  // end of Player class
 | 
|  |   3343 | ++
 | 
|  |   3344 | ++
 | 
|  |   3345 | ++} // namespace end
 | 
|  |   3346 | ++
 | 
|  |   3347 | ++
 | 
|  |   3348 | +diff -r 171db9560cb5 clients/mpd/mpdinterface.h
 | 
|  |   3349 | +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
 | 
|  |   3350 | ++++ b/clients/mpd/mpdinterface.h	Mon May 19 00:21:51 2008 -0400
 | 
|  |   3351 | +@@ -0,0 +1,209 @@
 | 
|  |   3352 | ++#ifndef MPDINTERFACE_H
 | 
|  |   3353 | ++#define MPDINTERFACE_H
 | 
|  |   3354 | ++
 | 
|  |   3355 | ++#include "libmpdclient.h"
 | 
|  |   3356 | ++#include <string>
 | 
|  |   3357 | ++#include <vector>
 | 
|  |   3358 | ++
 | 
|  |   3359 | ++namespace mpd_interface
 | 
|  |   3360 | ++{
 | 
|  |   3361 | ++const int nullptr = 0; 
 | 
|  |   3362 | ++
 | 
|  |   3363 | ++/* list of thrown exceptions */
 | 
|  |   3364 | ++
 | 
|  |   3365 | ++  // generic exception that can be thrown by MPD
 | 
|  |   3366 | ++  class mpd_err
 | 
|  |   3367 | ++  {
 | 
|  |   3368 | ++  protected:
 | 
|  |   3369 | ++    std::string msg;
 | 
|  |   3370 | ++  public:
 | 
|  |   3371 | ++    mpd_err(const std::string& message = "unknown error"): msg(message) { }
 | 
|  |   3372 | ++    std::string message() const { return msg; }
 | 
|  |   3373 | ++  };
 | 
|  |   3374 | ++
 | 
|  |   3375 | ++  // thrown when for whatever reason the connection cannot be maintained
 | 
|  |   3376 | ++  // the Player is always set to the disconnected state when this is thrown
 | 
|  |   3377 | ++  class connection_err: public mpd_err
 | 
|  |   3378 | ++  {
 | 
|  |   3379 | ++  public:
 | 
|  |   3380 | ++    connection_err(const std::string& message = "not connected"):
 | 
|  |   3381 | ++      mpd_err(message) { }
 | 
|  |   3382 | ++  };
 | 
|  |   3383 | ++
 | 
|  |   3384 | ++  class config_err: public mpd_err
 | 
|  |   3385 | ++  {
 | 
|  |   3386 | ++  public:
 | 
|  |   3387 | ++    config_err(const std::string& message = "") : mpd_err(message) { }
 | 
|  |   3388 | ++  };
 | 
|  |   3389 | ++
 | 
|  |   3390 | ++  // thrown when trying to access element out of the playlist range
 | 
|  |   3391 | ++  // contains information about the length of the playlist
 | 
|  |   3392 | ++  // and the invalid position
 | 
|  |   3393 | ++  class position_err: public mpd_err
 | 
|  |   3394 | ++  {
 | 
|  |   3395 | ++    int invalid_position;
 | 
|  |   3396 | ++    int pl_length;
 | 
|  |   3397 | ++  public:
 | 
|  |   3398 | ++    position_err(int position, int playlist_length);
 | 
|  |   3399 | ++    int pos() const { return invalid_position; }
 | 
|  |   3400 | ++    int playlist_length() const {return pl_length; }
 | 
|  |   3401 | ++  };
 | 
|  |   3402 | ++/* end of the exception list */
 | 
|  |   3403 | ++
 | 
|  |   3404 | ++
 | 
|  |   3405 | ++  // information about the configuration of MPD
 | 
|  |   3406 | ++  // it's the relevant info read from the mpd.config file
 | 
|  |   3407 | ++  struct config
 | 
|  |   3408 | ++  {
 | 
|  |   3409 | ++    std::string hostname;
 | 
|  |   3410 | ++    int port;
 | 
|  |   3411 | ++    std::string music_dir;
 | 
|  |   3412 | ++  };
 | 
|  |   3413 | ++
 | 
|  |   3414 | ++  // attempts to read the configuration file
 | 
|  |   3415 | ++  // if no path is specified following actions are taken:
 | 
|  |   3416 | ++  // first, the ~/.mpdconf file is looked for
 | 
|  |   3417 | ++  // then, the /etc/mpd.conf file is tried.
 | 
|  |   3418 | ++  config read_configuration(std::string conf_path="") throw(config_err);
 | 
|  |   3419 | ++
 | 
|  |   3420 | ++
 | 
|  |   3421 | ++  // Represents one song in playlist.
 | 
|  |   3422 | ++  // Note that when one song is twice in a playlist (their positions differ)
 | 
|  |   3423 | ++  // they are two different songs from this class' point of view.
 | 
|  |   3424 | ++  class Song
 | 
|  |   3425 | ++  {
 | 
|  |   3426 | ++    static std::string music_directory; // directory in which the songs are
 | 
|  |   3427 | ++
 | 
|  |   3428 | ++    std::string song_path; 
 | 
|  |   3429 | ++    int pl_pos; 
 | 
|  |   3430 | ++    int song_length; // time - in seconds
 | 
|  |   3431 | ++    int song_elapsed; // time - in seconds
 | 
|  |   3432 | ++
 | 
|  |   3433 | ++  public:
 | 
|  |   3434 | ++    static const int invalid_pos = MPD_SONG_NO_NUM;
 | 
|  |   3435 | ++    static const int invalid_time = MPD_SONG_NO_TIME;
 | 
|  |   3436 | ++
 | 
|  |   3437 | ++    static void set_default_dir(std::string path); // set the music directory
 | 
|  |   3438 | ++
 | 
|  |   3439 | ++    Song(std::string path = "", int position = invalid_pos,
 | 
|  |   3440 | ++	int length = invalid_time, int elapsed = invalid_time):
 | 
|  |   3441 | ++      song_path(music_directory+path), pl_pos(position),
 | 
|  |   3442 | ++      song_length(length), song_elapsed(elapsed) { }
 | 
|  |   3443 | ++
 | 
|  |   3444 | ++    friend bool operator==(const Song& first, const Song& second);
 | 
|  |   3445 | ++    friend bool operator!=(const Song& first, const Song& second);
 | 
|  |   3446 | ++
 | 
|  |   3447 | ++    std::string path() const { return song_path; }
 | 
|  |   3448 | ++    void set_path(std::string path) { song_path = music_directory+path; }
 | 
|  |   3449 | ++    int pos() const { return pl_pos; }
 | 
|  |   3450 | ++    void set_pos(int position) { pl_pos = position; }
 | 
|  |   3451 | ++    int length() const { return song_length; }
 | 
|  |   3452 | ++    void set_length(int length) { song_length = length; }
 | 
|  |   3453 | ++    int elapsed() const {return song_elapsed; }
 | 
|  |   3454 | ++    void set_elapsed(int elapsed) { song_elapsed = elapsed; }
 | 
|  |   3455 | ++  };
 | 
|  |   3456 | ++
 | 
|  |   3457 | ++
 | 
|  |   3458 | ++
 | 
|  |   3459 | ++  // the status of the playback - whether it's stopped, paused
 | 
|  |   3460 | ++  // or is playing a song right now
 | 
|  |   3461 | ++  enum playback_status {playing, stopped, paused} ;
 | 
|  |   3462 | ++
 | 
|  |   3463 | ++  // represents the communication with the MPD server
 | 
|  |   3464 | ++  // It's a confortable wrapper around the libmpdclient library
 | 
|  |   3465 | ++  // When its refresh() method is called it gets all information from server
 | 
|  |   3466 | ++  // and stores them so as not to flood the MPD with commands
 | 
|  |   3467 | ++  class Server
 | 
|  |   3468 | ++  {
 | 
|  |   3469 | ++  public:
 | 
|  |   3470 | ++    Server(): connection(nullptr) {};
 | 
|  |   3471 | ++    ~Server() { disconnect(); }
 | 
|  |   3472 | ++
 | 
|  |   3473 | ++    bool connect(const std::string& hostname="localhost", int port = 6600)
 | 
|  |   3474 | ++      throw(connection_err);
 | 
|  |   3475 | ++    void disconnect();
 | 
|  |   3476 | ++    bool connected() const {return connection!=nullptr; }
 | 
|  |   3477 | ++
 | 
|  |   3478 | ++
 | 
|  |   3479 | ++    void refresh() throw(connection_err); // the Server asks MPD for new values
 | 
|  |   3480 | ++    int get_playlist_length() const { return pl_length; }
 | 
|  |   3481 | ++    long long get_playlist_version() { return pl_version; }
 | 
|  |   3482 | ++    playback_status get_playback_status() { return pb_status; }
 | 
|  |   3483 | ++    bool get_random() const {return random; }
 | 
|  |   3484 | ++
 | 
|  |   3485 | ++    Song get_song_info(int pl_pos) throw(connection_err,position_err);
 | 
|  |   3486 | ++    Song get_current_song() const { return current_song; }
 | 
|  |   3487 | ++
 | 
|  |   3488 | ++    // plays the song at the specified position
 | 
|  |   3489 | ++    void play_song(int pl_pos) throw(connection_err, position_err);
 | 
|  |   3490 | ++
 | 
|  |   3491 | ++  private:
 | 
|  |   3492 | ++    Server& operator=(const Server&);
 | 
|  |   3493 | ++    Server(const Server&);
 | 
|  |   3494 | ++
 | 
|  |   3495 | ++    mpd_Connection *connection;
 | 
|  |   3496 | ++    int pl_length;
 | 
|  |   3497 | ++    long long pl_version;
 | 
|  |   3498 | ++    playback_status pb_status;
 | 
|  |   3499 | ++    Song current_song;
 | 
|  |   3500 | ++    bool random;
 | 
|  |   3501 | ++
 | 
|  |   3502 | ++
 | 
|  |   3503 | ++    // determines whether the actual MPD error state is the ACK error
 | 
|  |   3504 | ++    bool ack_error() const throw(connection_err);
 | 
|  |   3505 | ++
 | 
|  |   3506 | ++    // determines whether the MPD is in error state which is not the ACK error
 | 
|  |   3507 | ++    bool mpd_error() const throw(connection_err);
 | 
|  |   3508 | ++  };
 | 
|  |   3509 | ++
 | 
|  |   3510 | ++
 | 
|  |   3511 | ++
 | 
|  |   3512 | ++  enum recent {previous, current};
 | 
|  |   3513 | ++
 | 
|  |   3514 | ++  class Player
 | 
|  |   3515 | ++  {
 | 
|  |   3516 | ++  public:
 | 
|  |   3517 | ++
 | 
|  |   3518 | ++    Player();
 | 
|  |   3519 | ++
 | 
|  |   3520 | ++    bool connect() throw(config_err, connection_err);
 | 
|  |   3521 | ++    void disconnect();
 | 
|  |   3522 | ++    bool connected() const { return mpd.connected(); }
 | 
|  |   3523 | ++
 | 
|  |   3524 | ++    void refresh();
 | 
|  |   3525 | ++    
 | 
|  |   3526 | ++    bool song_changed() {return song__changed; }
 | 
|  |   3527 | ++    bool playlist_changed() { return playlist__changed; }
 | 
|  |   3528 | ++    bool status_changed() { return status__changed; }
 | 
|  |   3529 | ++
 | 
|  |   3530 | ++    // gets the current or the previously played song
 | 
|  |   3531 | ++    // song(current) returns currently played song
 | 
|  |   3532 | ++    // song(previous) returns the previously played song
 | 
|  |   3533 | ++    const Song& song(recent) const;
 | 
|  |   3534 | ++    const Song& song(int position) const throw(position_err);
 | 
|  |   3535 | ++    int playlist_length() const { return mpd.get_playlist_length(); }
 | 
|  |   3536 | ++    bool radnom() const { return mpd.get_random(); }
 | 
|  |   3537 | ++    void play_song(int pl_pos);
 | 
|  |   3538 | ++
 | 
|  |   3539 | ++    // gets the current or the previous playback status
 | 
|  |   3540 | ++    playback_status status(recent) const;
 | 
|  |   3541 | ++
 | 
|  |   3542 | ++
 | 
|  |   3543 | ++  private:
 | 
|  |   3544 | ++    Player& operator=(const Player&);
 | 
|  |   3545 | ++    Player(const Player&);
 | 
|  |   3546 | ++
 | 
|  |   3547 | ++    Server mpd;
 | 
|  |   3548 | ++    long long pl_ver;
 | 
|  |   3549 | ++    playback_status previous_status, current_status;
 | 
|  |   3550 | ++    int previous_song_pos, current_song_pos;
 | 
|  |   3551 | ++    const Song null_song;
 | 
|  |   3552 | ++    std::vector<Song> playlist;
 | 
|  |   3553 | ++
 | 
|  |   3554 | ++    bool song__changed, playlist__changed, status__changed;
 | 
|  |   3555 | ++  };
 | 
|  |   3556 | ++
 | 
|  |   3557 | ++}
 | 
|  |   3558 | ++
 | 
|  |   3559 | ++#endif
 | 
|  |   3560 | ++
 | 
|  |   3561 | +diff -r 171db9560cb5 clients/mpd/rules.mk
 | 
|  |   3562 | +--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
 | 
|  |   3563 | ++++ b/clients/mpd/rules.mk	Mon May 19 00:21:51 2008 -0400
 | 
|  |   3564 | +@@ -0,0 +1,16 @@
 | 
|  |   3565 | ++MDPCPPFLAGS= $(GLIB2CPPFLAGS)
 | 
|  |   3566 | ++MPDLDFLAGS= $(GLIB2LDFLAGS)
 | 
|  |   3567 | ++MPDCOMMON= mpdinterface.o libmpdclient.o clientstubbase.o libimmscore.a libmodel.a
 | 
|  |   3568 | ++
 | 
|  |   3569 | ++
 | 
|  |   3570 | ++immsmpd: immsmpd.o $(MPDCOMMON)
 | 
|  |   3571 | ++immsmpd: $(call objects,../clients/mpd)
 | 
|  |   3572 | ++immsmpd-CPPFLAGS=$(MDPCPPFLAGS)
 | 
|  |   3573 | ++immsmpd-LIBS=$(MPDLDFLAGS)
 | 
|  |   3574 | ++
 | 
|  |   3575 | ++
 | 
|  |   3576 | ++MPDDESTDIR=/usr/bin
 | 
|  |   3577 | ++
 | 
|  |   3578 | ++immsmpd_install: immsmpd
 | 
|  |   3579 | ++	${INSTALL} -D $^ $(MPDDESTDIR)
 | 
|  |   3580 | ++
 | 
|  |   3581 | +diff -r 171db9560cb5 configure.ac
 | 
|  |   3582 | +--- a/configure.ac	Mon May 19 00:16:56 2008 -0400
 | 
|  |   3583 | ++++ b/configure.ac	Mon May 19 00:21:51 2008 -0400
 | 
|  |   3584 | +@@ -260,6 +260,13 @@
 | 
|  |   3585 | + saved_libs="$LIBS"
 | 
|  |   3586 | + 
 | 
|  |   3587 | + PLUGINS=""
 | 
|  |   3588 | ++
 | 
|  |   3589 | ++AC_CHECK_PROG(with_mdp, mpd --help, "yes", "no")
 | 
|  |   3590 | ++if test "$with_mpd" != "no"; then
 | 
|  |   3591 | ++    AC_APPEND(PLUGINS, immsmpd)
 | 
|  |   3592 | ++fi
 | 
|  |   3593 | ++
 | 
|  |   3594 | ++
 | 
|  |   3595 | + AC_CHECK_PROG(with_xmms, xmms-config, "yes", "no")
 | 
|  |   3596 | + if test "$with_xmms" != "no"; then
 | 
|  |   3597 | +     CPPFLAGS=`xmms-config --cflags`
 | 
|  |   3598 | +diff -r 171db9560cb5 vars.mk.in
 | 
|  |   3599 | +--- a/vars.mk.in	Mon May 19 00:16:56 2008 -0400
 | 
|  |   3600 | ++++ b/vars.mk.in	Mon May 19 00:21:51 2008 -0400
 | 
|  |   3601 | +@@ -10,7 +10,7 @@
 | 
|  |   3602 | + bindir = @bindir@
 | 
|  |   3603 | + datadir = @datadir@
 | 
|  |   3604 | + 
 | 
|  |   3605 | +-VPATH = ../immscore:../analyzer:../model:../autotag:../immsremote:../utils:../clients:../immsd:../data:../clients/xmms:../clients/bmp:../clients/audacious
 | 
|  |   3606 | ++VPATH = ../immscore:../analyzer:../model:../autotag:../immsremote:../utils:../clients:../immsd:../data:../clients/xmms:../clients/bmp:../clients/audacious:../clients/mpd
 | 
|  |   3607 | + ARFLAGS = rs
 | 
|  |   3608 | + 
 | 
|  |   3609 | + SHELL = bash
 | 
|  |   3610 | diff -r fb5042644071 debian/patches/04mpd-client-config-init.dpatch
 | 
|  |   3611 | --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
 | 
|  |   3612 | +++ b/debian/patches/04mpd-client-config-init.dpatch	Mon May 19 01:12:49 2008 -0400
 | 
|  |   3613 | @@ -0,0 +1,20 @@
 | 
|  |   3614 | +#! /bin/sh /usr/share/dpatch/dpatch-run
 | 
|  |   3615 | +## mpd-client-config-init.dpatch by Fabien Niñoles <fabien@tzone.org>
 | 
|  |   3616 | +##
 | 
|  |   3617 | +## All lines beginning with `## DP:' are a description of the patch.
 | 
|  |   3618 | +## DP: Initialize default configuration.
 | 
|  |   3619 | +
 | 
|  |   3620 | +@DPATCH@
 | 
|  |   3621 | +
 | 
|  |   3622 | +diff -r 019508c19157 clients/mpd/mpdinterface.cc
 | 
|  |   3623 | +--- a/clients/mpd/mpdinterface.cc	Mon May 19 00:21:51 2008 -0400
 | 
|  |   3624 | ++++ b/clients/mpd/mpdinterface.cc	Mon May 19 00:51:06 2008 -0400
 | 
|  |   3625 | +@@ -98,7 +98,7 @@
 | 
|  |   3626 | + 	    conf_path + "\"");
 | 
|  |   3627 | +       }
 | 
|  |   3628 | + 
 | 
|  |   3629 | +-      config result;
 | 
|  |   3630 | ++      config result = { "localhost", 6600, "" };
 | 
|  |   3631 | +       std::string line;
 | 
|  |   3632 | +       while(getline(con_f, line)) {
 | 
|  |   3633 | + 	if(contains_parameter(line, address_param)) {
 |