Logo Search packages:      
Sourcecode: ncmpc version File versions  Download package

libmpdclient.c

/* libmpdclient
   (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
   This project's homepage is: http://www.musicpd.org
  
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:
                                                                                
   - Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
                                                                                
   - Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
                                                                                
   - Neither the name of the Music Player Daemon nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.
                                                                                
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/


#include "libmpdclient.h"

#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <sys/param.h>


#include <string.h>
#include <strings.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdarg.h>

#ifndef MSG_DONTWAIT
#define MSG_DONTWAIT 0
#endif

#define COMMAND_LIST    1
#define COMMAND_LIST_OK 2

char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] =
{
      "Artist",
      "Album",
      "Title",
      "Track",
      "Name",
      "Genre",
      "Date",
      "Composer",
      "Performer",
      "Comment",
      "filename"
};


static char * mpd_sanitizeArg(const char * arg) {
      size_t i;
      char * ret;
      register const char *c;
      register char *rc;
      
      /* 
      unsigned int count = 0;
      
      c = arg;
      for(i = strlen(arg); i != 0; --i) {
            if(*c=='"' || *c=='\\') count++;
            c++;
      }
      ret = malloc(strlen(arg)+count+1);
      */
      /* instead of counting in that loop above, just
       * use a bit more memory and half running time
       */
      ret = malloc(strlen(arg) * 2 + 1);

      c = arg;
      rc = ret;
      for(i = strlen(arg)+1; i != 0; --i) {
            if(*c=='"' || *c=='\\')
                  *rc++ = '\\';
            *(rc++) = *(c++);
      }

      return ret;
}

mpd_ReturnElement * mpd_newReturnElement(const char * name, const char * value)
{
      mpd_ReturnElement * ret = malloc(sizeof(mpd_ReturnElement));

      ret->name = (char *)strdup(name);
      ret->value = (char *)strdup(value);

      return ret;
}

void mpd_freeReturnElement(mpd_ReturnElement * re) {
      free(re->name);
      free(re->value);
      free(re);
}

void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout) {
            connection->timeout.tv_sec = (int)timeout;
            connection->timeout.tv_usec = (int)(timeout*1e6 -
                        connection->timeout.tv_sec*1000000+0.5);
}

mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
      int err;
      int error;
      char * rt;
      char * output;
      char service[20];
      mpd_Connection * connection = malloc(sizeof(mpd_Connection));
      struct timeval tv;
      struct addrinfo hints, *res;
      struct addrinfo *addrinfo = NULL;
      fd_set fds;
      strcpy(connection->buffer,"");
      connection->buflen = 0;
      connection->bufstart = 0;
      strcpy(connection->errorStr,"");
      connection->error = 0;
      connection->doneProcessing = 0;
      connection->commandList = 0;
      connection->listOks = 0;
      connection->doneListOk = 0;
      connection->returnElement = NULL;

      memset(&hints, 0, sizeof(hints));
      hints.ai_family = PF_UNSPEC;
      hints.ai_socktype = SOCK_STREAM;

      snprintf(service, sizeof(service), "%d", port);

      error = getaddrinfo(host, service, &hints, &addrinfo);

      if (error) {
            snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
                        "host \"%s\" not found: %s",host, gai_strerror(error));
            connection->error = MPD_ERROR_UNKHOST;
            return connection;
      }

      for (res = addrinfo; res; res = res->ai_next) {
            /* create socket */
            
            if((connection->sock = socket(res->ai_family,SOCK_STREAM,res->ai_protocol))<0) {
                  strcpy(connection->errorStr,"problems creating socket");
                  connection->error = MPD_ERROR_SYSTEM;
                  freeaddrinfo(addrinfo);
                  return connection;
            }

            mpd_setConnectionTimeout(connection,timeout);

            /* connect stuff */
            {
#ifdef WIN32
                  int iMode = 1; // 0 = blocking, else non-blocking
                  ioctlsocket(connection->sock, FIONBIO, (u_long FAR*) &iMode);
                  if(connect(connection->sock,res->ai_addr,res->ai_addrlen) == SOCKET_ERROR
                        && WSAGetLastError() != WSAEWOULDBLOCK)
#else
                        int flags = fcntl(connection->sock, F_GETFL, 0);
                  fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);

                  if(connect(connection->sock,res->ai_addr,res->ai_addrlen)<0 && 
                              errno!=EINPROGRESS) 
#endif
                  {
                        /* try the next address family */
                        close(connection->sock);
                        connection->sock = 0;
                        continue;
                  }
            }
      }

      freeaddrinfo(addrinfo);

      if (connection->sock == 0) {
            snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
                        "problems connecting to \"%s\" on port"
                        " %i: %s",host,port, strerror(errno));
            connection->error = MPD_ERROR_CONNPORT;

            return connection;
      }

      while(!(rt = strstr(connection->buffer,"\n"))) {
            tv.tv_sec = connection->timeout.tv_sec;
            tv.tv_usec = connection->timeout.tv_usec;
            FD_ZERO(&fds);
            FD_SET(connection->sock,&fds);
            if((err = select(connection->sock+1,&fds,NULL,NULL,&tv)) == 1) {
                  int readed;
                  readed = recv(connection->sock,
                        &(connection->buffer[connection->buflen]),
                        MPD_BUFFER_MAX_LENGTH-connection->buflen,0);
                  if(readed<=0) {
                        snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
                              "problems getting a response from"
                              " \"%s\" on port %i : %s",host,
                              port, strerror(errno));
                        connection->error = MPD_ERROR_NORESPONSE;
                        return connection;
                  }
                  connection->buflen+=readed;
                  connection->buffer[connection->buflen] = '\0';
                  tv.tv_sec = connection->timeout.tv_sec;
                  tv.tv_usec = connection->timeout.tv_usec;
            }
            else if(err<0) {
                  switch(errno) {
                  case EINTR:
                        continue;
                  default:
                        snprintf(connection->errorStr,
                              MPD_BUFFER_MAX_LENGTH,
                              "problems connecting to \"%s\" on port"
                              " %i",host,port);
                        connection->error = MPD_ERROR_CONNPORT;
                        return connection;
                  }
            }
            else {
                  snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
                        "timeout in attempting to get a response from"
                         " \"%s\" on port %i",host,port);
                  connection->error = MPD_ERROR_NORESPONSE;
                  return connection;
            }
      }

      *rt = '\0';
      output = strdup(connection->buffer);
      strcpy(connection->buffer,rt+1);
      connection->buflen = strlen(connection->buffer);

      if(strncmp(output,MPD_WELCOME_MESSAGE,strlen(MPD_WELCOME_MESSAGE))) {
            free(output);
            snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
                        "mpd not running on port %i on host \"%s\"",
                        port,host);
            connection->error = MPD_ERROR_NOTMPD;
            return connection;
      }

      {
            char * test;
            char * version[3];
            char * tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
            char * search = ".";
            int i;

            for(i=0;i<3;i++) {
                  char * tok;
                  if(i==3) search = " ";
                  version[i] = strtok_r(tmp,search,&tok);
                  if(!version[i]) {
                        free(output);
                        snprintf(connection->errorStr,
                              MPD_BUFFER_MAX_LENGTH,
                              "error parsing version number at "
                              "\"%s\"",
                              &output[strlen(MPD_WELCOME_MESSAGE)]);
                        connection->error = MPD_ERROR_NOTMPD;
                        return connection;
                  }
                  connection->version[i] = strtol(version[i],&test,10);
                  if(version[i]==test || *test!='\0') {
                        free(output);
                        snprintf(connection->errorStr,
                              MPD_BUFFER_MAX_LENGTH,
                              "error parsing version number at "
                              "\"%s\"",
                              &output[strlen(MPD_WELCOME_MESSAGE)]);
                        connection->error = MPD_ERROR_NOTMPD;
                        return connection;
                  }
                  tmp = NULL;
            }
      }

      free(output);

      connection->doneProcessing = 1;

      return connection;
}

void mpd_clearError(mpd_Connection * connection) {
      connection->error = 0;
      connection->errorStr[0] = '\0';
}

void mpd_closeConnection(mpd_Connection * connection) {
      close(connection->sock);
      if(connection->returnElement) free(connection->returnElement);
      free(connection);
}

void mpd_executeCommand(mpd_Connection * connection, char * command) {
      int ret;
      struct timeval tv;
      fd_set fds;
      char * commandPtr = command;
      int commandLen = strlen(command);

      if(!connection->doneProcessing && !connection->commandList) {
            strcpy(connection->errorStr,"not done processing current command");
            connection->error = 1;
            return;
      }

      mpd_clearError(connection);

      FD_ZERO(&fds);
      FD_SET(connection->sock,&fds);
      tv.tv_sec = connection->timeout.tv_sec;
      tv.tv_usec = connection->timeout.tv_usec;

      while((ret = select(connection->sock+1,NULL,&fds,NULL,&tv)==1) || 
                  (ret==-1 && errno==EINTR)) {
            ret = send(connection->sock,commandPtr,commandLen,
#ifdef WIN32
                     ioctlsocket(connection->sock, commandLen, commandPtr));
#endif
#ifndef WIN32
                        MSG_DONTWAIT);
#endif
            if(ret<=0)
            {
                  if(ret==EAGAIN || ret==EINTR) continue;
                  snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
                        "problems giving command \"%s\"",command);
                  connection->error = MPD_ERROR_SENDING;
                  return;
            }
            else {
                  commandPtr+=ret;
                  commandLen-=ret;
            }

            if(commandLen<=0) break;
      }

      if(commandLen>0) {
            perror("");
            snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
                  "timeout sending command \"%s\"",command);
            connection->error = MPD_ERROR_TIMEOUT;
            return;
      }

      if(!connection->commandList) connection->doneProcessing = 0;
      else if(connection->commandList == COMMAND_LIST_OK) {
            connection->listOks++;
      }
}

void mpd_getNextReturnElement(mpd_Connection * connection) {
      char * output = NULL;
      char * rt = NULL;
      char * name = NULL;
      char * value = NULL;
      fd_set fds;
      struct timeval tv;
      char * tok = NULL;
      int readed;
      char * bufferCheck = NULL;
      int err;

      if(connection->returnElement) mpd_freeReturnElement(connection->returnElement);
      connection->returnElement = NULL;

      if(connection->doneProcessing || (connection->listOks &&
                  connection->doneListOk)) 
      {
            strcpy(connection->errorStr,"already done processing current command");
            connection->error = 1;
            return;
      }

      bufferCheck = connection->buffer+connection->bufstart;
      while(connection->bufstart>=connection->buflen || 
                  !(rt = strchr(bufferCheck,'\n'))) {
            if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) {
                  memmove(connection->buffer,
                              connection->buffer+
                              connection->bufstart,
                              connection->buflen-
                              connection->bufstart+1);
                  connection->buflen-=connection->bufstart;
                  connection->bufstart = 0;
            }
            if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) {
                  strcpy(connection->errorStr,"buffer overrun");
                  connection->error = MPD_ERROR_BUFFEROVERRUN;
                  connection->doneProcessing = 1;
                  connection->doneListOk = 0;
                  return;
            }
            bufferCheck = connection->buffer+connection->buflen;
            tv.tv_sec = connection->timeout.tv_sec;
            tv.tv_usec = connection->timeout.tv_usec;
            FD_ZERO(&fds);
            FD_SET(connection->sock,&fds);
            if((err = select(connection->sock+1,&fds,NULL,NULL,&tv) == 1)) {
                  readed = recv(connection->sock,
                        connection->buffer+connection->buflen,
                        MPD_BUFFER_MAX_LENGTH-connection->buflen,
#ifdef WIN32
                        ioctlsocket(connection->sock, 
                                  commandLen, 
                                  commandPtr));
#endif
#ifndef WIN32
                        MSG_DONTWAIT);
#endif
                  if(readed<0 && (errno==EAGAIN || errno==EINTR)) {
                        continue;
                  }
                  if(readed<=0) {
                        strcpy(connection->errorStr,"connection"
                              " closed");
                        connection->error = MPD_ERROR_CONNCLOSED;
                        connection->doneProcessing = 1;
                        connection->doneListOk = 0;
                        return;
                  }
                  connection->buflen+=readed;
                  connection->buffer[connection->buflen] = '\0';
            }
            else if(err<0 && errno==EINTR) continue;
            else {
                  strcpy(connection->errorStr,"connection timeout");
                  connection->error = MPD_ERROR_TIMEOUT;
                  connection->doneProcessing = 1;
                  connection->doneListOk = 0;
                  return;
            }
      }

      *rt = '\0';
      output = connection->buffer+connection->bufstart;
      connection->bufstart = rt - connection->buffer + 1;

      if(strcmp(output,"OK")==0) {
            if(connection->listOks > 0) {
                  strcpy(connection->errorStr, "expected more list_OK's");
                  connection->error = 1;
            }
            connection->listOks = 0;
            connection->doneProcessing = 1;
            connection->doneListOk = 0;
            return;
      }

      if(strcmp(output, "list_OK") == 0) {
            if(!connection->listOks) {
                  strcpy(connection->errorStr, 
                              "got an unexpected list_OK");
                  connection->error = 1;
            }
            else {
                  connection->doneListOk = 1;
                  connection->listOks--;
            }
            return;
      }

      if(strncmp(output,"ACK",strlen("ACK"))==0) {
            char * test;
            char * needle;
            int val;
      
            strcpy(connection->errorStr, output);
            connection->error = MPD_ERROR_ACK;
            connection->errorCode = MPD_ACK_ERROR_UNK;
            connection->errorAt = MPD_ERROR_AT_UNK;
            connection->doneProcessing = 1;
            connection->doneListOk = 0;

            needle = strchr(output, '[');
            if(!needle) return;
            val = strtol(needle+1, &test, 10);
            if(*test != '@') return;
            connection->errorCode = val;
            val = strtol(test+1, &test, 10);
            if(*test != ']') return;
            connection->errorAt = val;
            return;
      }

      name = strtok_r(output,":",&tok);
      if(name && (value = strtok_r(NULL,"",&tok)) && value[0]==' ') {
            connection->returnElement = mpd_newReturnElement(name,&(value[1]));
      }
      else {
            if(!name || !value) {
                  snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
                              "error parsing: %s",output);
            }
            else {
                  snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
                              "error parsing: %s:%s",name,value);
            }
            connection->errorStr[MPD_BUFFER_MAX_LENGTH] = '\0';
            connection->error = 1;
      }
}

void mpd_finishCommand(mpd_Connection * connection) {
      while(!connection->doneProcessing) {
            if(connection->doneListOk) connection->doneListOk = 0;
            mpd_getNextReturnElement(connection);
      }
}

void mpd_finishListOkCommand(mpd_Connection * connection) {
      while(!connection->doneProcessing && connection->listOks && 
                  !connection->doneListOk ) 
      {
            mpd_getNextReturnElement(connection);
      }
}

int mpd_nextListOkCommand(mpd_Connection * connection) {
      mpd_finishListOkCommand(connection);
      if(!connection->doneProcessing) connection->doneListOk = 0;
      if(connection->listOks == 0 || connection->doneProcessing) return -1;
      return 0;
}

void mpd_sendStatusCommand(mpd_Connection * connection) {
      mpd_executeCommand(connection,"status\n");
}

mpd_Status * mpd_getStatus(mpd_Connection * connection) {
      mpd_Status * status;

      /*mpd_executeCommand(connection,"status\n");
            
      if(connection->error) return NULL;*/

      if(connection->doneProcessing || (connection->listOks && 
                  connection->doneListOk))
      {
            return NULL;
      }

      if(!connection->returnElement) mpd_getNextReturnElement(connection);

      status = malloc(sizeof(mpd_Status));
      status->volume = -1;
      status->repeat = 0;
      status->random = 0;
      status->playlist = -1;
      status->playlistLength = -1;
      status->state = -1;
      status->song = 0;
      status->elapsedTime = 0;
      status->totalTime = 0;
      status->bitRate = 0;
      status->sampleRate = 0;
      status->bits = 0;
      status->channels = 0;
      status->crossfade = -1;
      status->error = NULL;
      status->updatingDb = 0;

      if(connection->error) {
            free(status);
            return NULL;
      }
      while(connection->returnElement) {
            mpd_ReturnElement * re = connection->returnElement;
            if(strcmp(re->name,"volume")==0) {
                  status->volume = atoi(re->value);
            }
            else if(strcmp(re->name,"repeat")==0) {
                  status->repeat = atoi(re->value);
            }
            else if(strcmp(re->name,"random")==0) {
                  status->random = atoi(re->value);
            }
            else if(strcmp(re->name,"playlist")==0) {
                  status->playlist = strtol(re->value,NULL,10);
            }
            else if(strcmp(re->name,"playlistlength")==0) {
                  status->playlistLength = atoi(re->value);
            }
            else if(strcmp(re->name,"bitrate")==0) {
                  status->bitRate = atoi(re->value);
            }
            else if(strcmp(re->name,"state")==0) {
                  if(strcmp(re->value,"play")==0) {
                        status->state = MPD_STATUS_STATE_PLAY;
                  }
                  else if(strcmp(re->value,"stop")==0) {
                        status->state = MPD_STATUS_STATE_STOP;
                  }
                  else if(strcmp(re->value,"pause")==0) {
                        status->state = MPD_STATUS_STATE_PAUSE;
                  }
                  else {
                        status->state = MPD_STATUS_STATE_UNKNOWN;
                  }
            }
            else if(strcmp(re->name,"song")==0) {
                  status->song = atoi(re->value);
            }
            else if(strcmp(re->name,"songid")==0) {
                  status->songid = atoi(re->value);
            }
            else if(strcmp(re->name,"time")==0) {
                  char * tok;
                  char * copy;
                  char * temp;
                  copy = strdup(re->value);
                  temp = strtok_r(copy,":",&tok);
                  if(temp) {
                        status->elapsedTime = atoi(temp);
                        temp = strtok_r(NULL,"",&tok);
                        if(temp) status->totalTime = atoi(temp);
                  }
                  free(copy);
            }
            else if(strcmp(re->name,"error")==0) {
                  status->error = strdup(re->value);
            }
            else if(strcmp(re->name,"xfade")==0) {
                  status->crossfade = atoi(re->value);
            }
            else if(strcmp(re->name,"updating_db")==0) {
                  status->updatingDb = atoi(re->value);
            }
            else if(strcmp(re->name,"audio")==0) {
                  char * tok;
                  char * copy;
                  char * temp;
                  copy = strdup(re->value);
                  temp = strtok_r(copy,":",&tok);
                  if(temp) {
                        status->sampleRate = atoi(temp);
                        temp = strtok_r(NULL,":",&tok);
                        if(temp) {
                              status->bits = atoi(temp);
                              temp = strtok_r(NULL,"",&tok);
                              if(temp) status->channels = atoi(temp);
                        }
                  }
                  free(copy);
            }

            mpd_getNextReturnElement(connection);
            if(connection->error) {
                  free(status);
                  return NULL;
            }
      }

      if(connection->error) {
            free(status);
            return NULL;
      }
      else if(status->state<0) {
            strcpy(connection->errorStr,"state not found");
            connection->error = 1;
            free(status);
            return NULL;
      }

      return status;
}

void mpd_freeStatus(mpd_Status * status) {
      if(status->error) free(status->error);
      free(status);
}

void mpd_sendStatsCommand(mpd_Connection * connection) {
      mpd_executeCommand(connection,"stats\n");
}

mpd_Stats * mpd_getStats(mpd_Connection * connection) {
      mpd_Stats * stats;

      /*mpd_executeCommand(connection,"stats\n");
            
      if(connection->error) return NULL;*/

      if(connection->doneProcessing || (connection->listOks && 
                  connection->doneListOk))
      {
            return NULL;
      }

      if(!connection->returnElement) mpd_getNextReturnElement(connection);

      stats = malloc(sizeof(mpd_Stats));
      stats->numberOfArtists = 0;
      stats->numberOfAlbums = 0;
      stats->numberOfSongs = 0;
      stats->uptime = 0;
      stats->dbUpdateTime = 0;
      stats->playTime = 0;
      stats->dbPlayTime = 0;

      if(connection->error) {
            free(stats);
            return NULL;
      }
      while(connection->returnElement) {
            mpd_ReturnElement * re = connection->returnElement;
            if(strcmp(re->name,"artists")==0) {
                  stats->numberOfArtists = atoi(re->value);
            }
            else if(strcmp(re->name,"albums")==0) {
                  stats->numberOfAlbums = atoi(re->value);
            }
            else if(strcmp(re->name,"songs")==0) {
                  stats->numberOfSongs = atoi(re->value);
            }
            else if(strcmp(re->name,"uptime")==0) {
                  stats->uptime = strtol(re->value,NULL,10);
            }
            else if(strcmp(re->name,"db_update")==0) {
                  stats->dbUpdateTime = strtol(re->value,NULL,10);
            }
            else if(strcmp(re->name,"playtime")==0) {
                  stats->playTime = strtol(re->value,NULL,10);
            }
            else if(strcmp(re->name,"db_playtime")==0) {
                  stats->dbPlayTime = strtol(re->value,NULL,10);
            }

            mpd_getNextReturnElement(connection);
            if(connection->error) {
                  free(stats);
                  return NULL;
            }
      }

      if(connection->error) {
            free(stats);
            return NULL;
      }

      return stats;
}

void mpd_freeStats(mpd_Stats * stats) {
      free(stats);
}

void mpd_initSong(mpd_Song * song) {
      song->file = NULL;
      song->artist = NULL;
      song->album = NULL;
      song->track = NULL;
      song->title = NULL;
      song->name = NULL;
      song->date = NULL;
      /* added by Qball */
      song->genre = NULL;
      song->composer = NULL;

      song->time = MPD_SONG_NO_TIME;
      song->pos = MPD_SONG_NO_NUM;
      song->id = MPD_SONG_NO_ID;
}

void mpd_finishSong(mpd_Song * song) {
      if(song->file) free(song->file);
      if(song->artist) free(song->artist);
      if(song->album) free(song->album);
      if(song->title) free(song->title);
      if(song->track) free(song->track);
      if(song->name) free(song->name);
      if(song->date) free(song->date);
      if(song->genre) free(song->genre);
      if(song->composer) free(song->composer);
}

mpd_Song * mpd_newSong() {
      mpd_Song * ret = malloc(sizeof(mpd_Song));

      mpd_initSong(ret);

      return ret;
}

void mpd_freeSong(mpd_Song * song) {
      mpd_finishSong(song);
      free(song);
}

mpd_Song * mpd_songDup(mpd_Song * song) {
      mpd_Song * ret = mpd_newSong();

      if(song->file) ret->file = strdup(song->file);
      if(song->artist) ret->artist = strdup(song->artist);
      if(song->album) ret->album = strdup(song->album);
      if(song->title) ret->title = strdup(song->title);
      if(song->track) ret->track = strdup(song->track);
      if(song->name) ret->name = strdup(song->name);
      if(song->date) ret->date = strdup(song->date);
      if(song->genre) ret->genre= strdup(song->genre);
      if(song->composer) ret->composer= strdup(song->composer);
      ret->time = song->time;
      ret->pos = song->pos;
      ret->id = song->id;

      return ret;
}

void mpd_initDirectory(mpd_Directory * directory) {
      directory->path = NULL;
}

void mpd_finishDirectory(mpd_Directory * directory) {
      if(directory->path) free(directory->path);
}

mpd_Directory * mpd_newDirectory () {
      mpd_Directory * directory = malloc(sizeof(mpd_Directory));;

      mpd_initDirectory(directory);
      
      return directory;
}

void mpd_freeDirectory(mpd_Directory * directory) {
      mpd_finishDirectory(directory);

      free(directory);
}

mpd_Directory * mpd_directoryDup(mpd_Directory * directory) {
      mpd_Directory * ret = mpd_newDirectory();

      if(directory->path) ret->path = strdup(directory->path);

      return ret;
}

void mpd_initPlaylistFile(mpd_PlaylistFile * playlist) {
      playlist->path = NULL;
}

void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist) {
      if(playlist->path) free(playlist->path);
}

mpd_PlaylistFile * mpd_newPlaylistFile() {
      mpd_PlaylistFile * playlist = malloc(sizeof(mpd_PlaylistFile));

      mpd_initPlaylistFile(playlist);

      return playlist;
}

void mpd_freePlaylistFile(mpd_PlaylistFile * playlist) {
      mpd_finishPlaylistFile(playlist);
      free(playlist);
}

mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist) {
      mpd_PlaylistFile * ret = mpd_newPlaylistFile();

      if(playlist->path) ret->path = strdup(playlist->path);

      return ret;
}

void mpd_initInfoEntity(mpd_InfoEntity * entity) {
      entity->info.directory = NULL;
} 

void mpd_finishInfoEntity(mpd_InfoEntity * entity) {
      if(entity->info.directory) {
            if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
                  mpd_freeDirectory(entity->info.directory);
            }
            else if(entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
                  mpd_freeSong(entity->info.song);
            }
            else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
                  mpd_freePlaylistFile(entity->info.playlistFile);
            }
      }
}

mpd_InfoEntity * mpd_newInfoEntity() {
      mpd_InfoEntity * entity = malloc(sizeof(mpd_InfoEntity));
      
      mpd_initInfoEntity(entity);

      return entity;
}

void mpd_freeInfoEntity(mpd_InfoEntity * entity) {
      mpd_finishInfoEntity(entity);
      free(entity);
}

void mpd_sendInfoCommand(mpd_Connection * connection, char * command) {
      mpd_executeCommand(connection,command);
}

mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection) {
      mpd_InfoEntity * entity = NULL;

      if(connection->doneProcessing || (connection->listOks && 
                  connection->doneListOk))
      {
            return NULL;
      }

      if(!connection->returnElement) mpd_getNextReturnElement(connection);

      if(connection->returnElement) { 
            if(strcmp(connection->returnElement->name,"file")==0) {
                  entity = mpd_newInfoEntity();
                  entity->type = MPD_INFO_ENTITY_TYPE_SONG;
                  entity->info.song = mpd_newSong();
                  entity->info.song->file = 
                        strdup(connection->returnElement->value);
            }
            else if(strcmp(connection->returnElement->name,
                              "directory")==0) {
                  entity = mpd_newInfoEntity();
                  entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
                  entity->info.directory = mpd_newDirectory();
                  entity->info.directory->path = 
                        strdup(connection->returnElement->value);
            }
            else if(strcmp(connection->returnElement->name,"playlist")==0) {
                  entity = mpd_newInfoEntity();
                  entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
                  entity->info.playlistFile = mpd_newPlaylistFile();
                  entity->info.playlistFile->path = 
                        strdup(connection->returnElement->value);
            }
            else {
                  connection->error = 1;
                  strcpy(connection->errorStr,"problem parsing song info");
                  return NULL;
            }
      }
      else return NULL;

      mpd_getNextReturnElement(connection);
      while(connection->returnElement) {
            mpd_ReturnElement * re = connection->returnElement;

            if(strcmp(re->name,"file")==0) return entity;
            else if(strcmp(re->name,"directory")==0) return entity;
            else if(strcmp(re->name,"playlist")==0) return entity;

            if(entity->type == MPD_INFO_ENTITY_TYPE_SONG && 
                        strlen(re->value)) {
                  if(!entity->info.song->artist &&
                              strcmp(re->name,"Artist")==0) {
                        entity->info.song->artist = strdup(re->value);
                  }
                  else if(!entity->info.song->album &&
                              strcmp(re->name,"Album")==0) {
                        entity->info.song->album = strdup(re->value);
                  }
                  else if(!entity->info.song->title &&
                              strcmp(re->name,"Title")==0) {
                        entity->info.song->title = strdup(re->value);
                  }
                  else if(!entity->info.song->track &&
                              strcmp(re->name,"Track")==0) {
                        entity->info.song->track = strdup(re->value);
                  }
                  else if(!entity->info.song->name &&
                              strcmp(re->name,"Name")==0) {
                        entity->info.song->name = strdup(re->value);
                  }
                  else if(entity->info.song->time==MPD_SONG_NO_TIME &&
                              strcmp(re->name,"Time")==0) {
                        entity->info.song->time = atoi(re->value);
                  }
                  else if(entity->info.song->pos==MPD_SONG_NO_NUM &&
                              strcmp(re->name,"Pos")==0) {
                        entity->info.song->pos = atoi(re->value);
                  }
                  else if(entity->info.song->id==MPD_SONG_NO_ID &&
                              strcmp(re->name,"Id")==0) {
                        entity->info.song->id = atoi(re->value);
                  }
                  else if(!entity->info.song->date &&
                              strcmp(re->name, "Date") == 0) {
                        entity->info.song->date = strdup(re->value);
                  }
                  else if(!entity->info.song->genre &&
                              strcmp(re->name, "Genre") == 0) {
                        entity->info.song->genre = strdup(re->value);
                  }
                  else if(!entity->info.song->composer &&
                              strcmp(re->name, "Composer") == 0) {
                        entity->info.song->composer = strdup(re->value);
                  }                                                                 
                  
            }
            else if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
            }
            else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
            }

            mpd_getNextReturnElement(connection);
      }

      return entity;
}

char * mpd_getNextReturnElementNamed(mpd_Connection * connection, 
            const char * name) 
{
      if(connection->doneProcessing || (connection->listOks && 
                  connection->doneListOk)) 
      {
            return NULL;
      }

      mpd_getNextReturnElement(connection);
      while(connection->returnElement) {
            mpd_ReturnElement * re = connection->returnElement;

            if(strcmp(re->name,name)==0) return strdup(re->value);
            mpd_getNextReturnElement(connection);
      }

      return NULL;
}

char * mpd_getNextTag(mpd_Connection * connection,int table) {
      if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
      {
            return mpd_getNextReturnElementNamed(connection,mpdTagItemKeys[table]);
      }
      return NULL;
}
char * mpd_getNextArtist(mpd_Connection * connection) {
      return mpd_getNextReturnElementNamed(connection,"Artist");
}

char * mpd_getNextAlbum(mpd_Connection * connection) {
      return mpd_getNextReturnElementNamed(connection,"Album");
}

void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos) {
      char * string = malloc(strlen("playlistinfo")+25);
      sprintf(string,"playlistinfo \"%i\"\n",songPos);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id) {
      char * string = malloc(strlen("playlistid")+25);
      sprintf(string, "playlistid \"%i\"\n", id);
      mpd_sendInfoCommand(connection, string);
      free(string);
}

void mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist) {
      char * string = malloc(strlen("plchanges")+25);
      sprintf(string,"plchanges \"%lld\"\n",playlist);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendListallCommand(mpd_Connection * connection, const char * dir) {
      char * sDir = mpd_sanitizeArg(dir);
      char * string = malloc(strlen("listall")+strlen(sDir)+5);
      sprintf(string,"listall \"%s\"\n",sDir);
      mpd_sendInfoCommand(connection,string);
      free(string);
      free(sDir);
}

void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir) {
      char * sDir = mpd_sanitizeArg(dir);
      char * string = malloc(strlen("listallinfo")+strlen(sDir)+5);
      sprintf(string,"listallinfo \"%s\"\n",sDir);
      mpd_sendInfoCommand(connection,string);
      free(string);
      free(sDir);
}

void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir) {
      char * sDir = mpd_sanitizeArg(dir);
      char * string = malloc(strlen("lsinfo")+strlen(sDir)+5);
      sprintf(string,"lsinfo \"%s\"\n",sDir);
      mpd_sendInfoCommand(connection,string);
      free(string);
      free(sDir);
}

void mpd_sendCurrentSongCommand(mpd_Connection * connection) {
      mpd_executeCommand(connection,"currentsong\n");
}

void mpd_sendSearchCommand(mpd_Connection * connection, int table, 
            const char * str) 
{
      char st[10];
      char * string;
      char * sanitStr = mpd_sanitizeArg(str);
      if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
      else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
      else if(table == MPD_TABLE_TITLE) strcpy(st,"title");
      else if(table == MPD_TABLE_FILENAME) strcpy(st,"filename");
      else {
            connection->error = 1;
            strcpy(connection->errorStr,"unknown table for search");
            return;
      }
      string = malloc(strlen("search")+strlen(sanitStr)+strlen(st)+6);
      sprintf(string,"search %s \"%s\"\n",st,sanitStr);
      mpd_sendInfoCommand(connection,string);
      free(string);
      free(sanitStr);
}
void mpd_sendSearchTagCommand(mpd_Connection *connection, ...)
{
      va_list arglist;
      va_start(arglist, connection);
      mpd_sendVSearchTagCommand(connection, arglist);
      va_end(arglist);
}

void mpd_sendVSearchTagCommand(mpd_Connection * connection, va_list arglist) 
{
      char *st, *str;
      char * string=NULL;
      int table;
      char * sanitStr;
      string = realloc(string,strlen("search")+1);
      strcpy(string, "search");
      while((table = va_arg(arglist, int)) != -1)
      {
            if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
            {
                  st = mpdTagItemKeys[table];
                  str = va_arg(arglist,char *);
                  sanitStr = mpd_sanitizeArg(str);
                  string = realloc(string, strlen(string)+strlen(st)+strlen(sanitStr)+6);
                  sprintf(string, "%s %s \"%s\"",string,st,sanitStr);
                  free(sanitStr);
            }     
            else {
                  connection->error = 1;
                  sprintf(connection->errorStr,"unknown table for search %i",table);
                  va_end(arglist);
                  return;
            }
      }
      /* set the last to '\n', should be sufficient space in the string for this */
      sprintf(string, "%s\n", string);
      mpd_sendInfoCommand(connection,string);
      free(string);
}


void mpd_sendFindTagCommand(mpd_Connection *connection, ...)
{
      va_list arglist;
      va_start(arglist, connection);
      mpd_sendVFindTagCommand(connection, arglist);
      va_end(arglist);
}




void mpd_sendVFindTagCommand(mpd_Connection * connection, va_list arglist) 
{
      char *st, *str;
      char * string=NULL;
      int table;
      char * sanitStr;
      string = realloc(string,strlen("find")+1);
      strcpy(string, "find");
      while((table = va_arg(arglist, int)) != -1)
      {
            if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
            {
                  st = mpdTagItemKeys[table];
                  str = va_arg(arglist,char *);
                  sanitStr = mpd_sanitizeArg(str);
                  string = realloc(string, strlen(string)+strlen(st)+strlen(sanitStr)+6);
                  sprintf(string, "%s %s \"%s\"",string,st,sanitStr);
                  free(sanitStr);
            }     
            else {
                  connection->error = 1;
                  sprintf(connection->errorStr,"unknown table for find %i",table);
                  va_end(arglist);
                  return;
            }
      }
      /* set the last to '\n', should be sufficient space in the string for this */
      sprintf(string, "%s\n", string);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendFindCommand(mpd_Connection * connection, int table, 
            const char * str) 
{
      char st[10];
      char * string;
      char * sanitStr = mpd_sanitizeArg(str);
      if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
      else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
      else if(table == MPD_TABLE_TITLE) strcpy(st,"title");
      else {
            connection->error = 1;
            strcpy(connection->errorStr,"unknown table for find");
            return;
      }
      string = malloc(strlen("find")+strlen(sanitStr)+strlen(st)+6);
      sprintf(string,"find %s \"%s\"\n",st,sanitStr);
      mpd_sendInfoCommand(connection,string);
      free(string);
      free(sanitStr);
}

void mpd_sendListCommand(mpd_Connection * connection, int table, 
            const char * arg1) 
{
      char st[10];
      char * string;
      if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
      else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
      else {
            connection->error = 1;
            strcpy(connection->errorStr,"unknown table for list");
            return;
      }
      if(arg1) {
            char * sanitArg1 = mpd_sanitizeArg(arg1);
            string = malloc(strlen("list")+strlen(sanitArg1)+strlen(st)+6);
            sprintf(string,"list %s \"%s\"\n",st,sanitArg1);
            free(sanitArg1);
      }
      else {
            string = malloc(strlen("list")+strlen(st)+3);
            sprintf(string,"list %s\n",st);
      }
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendListTagCommand(mpd_Connection *connection, int ret_table, ...)
{
      va_list arglist;
      va_start(arglist, ret_table);
      mpd_sendVListTagCommand(connection, ret_table, arglist);
      va_end(arglist);
}
void mpd_sendVListTagCommand(mpd_Connection * connection,int ret_table, va_list arglist) 
{
      char *st, *str;
      char * string=NULL;
      int table;
      char * sanitStr;
      if(ret_table < 0 && ret_table >= MPD_TAG_NUM_OF_ITEM_TYPES)
      {
            connection->error = 1;
            sprintf(connection->errorStr,"unknown ret_table for search %i",ret_table);
            return;
      }

      string = realloc(string,strlen("list")+3+strlen(mpdTagItemKeys[ret_table]));
      sprintf(string, "list %s",mpdTagItemKeys[ret_table]);
      while((table = va_arg(arglist, int)) != -1)
      {
            if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
            {
                  st = mpdTagItemKeys[table];
                  str = va_arg(arglist,char *);
                  sanitStr = mpd_sanitizeArg(str);
                  string = realloc(string, strlen(string)+strlen(st)+strlen(sanitStr)+7);
                  sprintf(string, "%s %s \"%s\"",string,st,sanitStr);
                  free(sanitStr);
            }     
            else {
                  connection->error = 1;
                  sprintf(connection->errorStr,"unknown table for search %i",table);
                  va_end(arglist);
                  return;
            }
      }
      /* set the last to '\n', should be sufficient space in the string for this */
      sprintf(string,"%s\n", string);
      mpd_sendInfoCommand(connection,string);
      free(string);
}


void mpd_sendAddCommand(mpd_Connection * connection, const char * file) {
      char * sFile = mpd_sanitizeArg(file);
      char * string = malloc(strlen("add")+strlen(sFile)+5);
      sprintf(string,"add \"%s\"\n",sFile);
      mpd_executeCommand(connection,string);
      free(string);
      free(sFile);
}

void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos) {
      char * string = malloc(strlen("delete")+25);
      sprintf(string,"delete \"%i\"\n",songPos);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id) {
      char * string = malloc(strlen("deleteid")+25);
      sprintf(string, "deleteid \"%i\"\n", id);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendSaveCommand(mpd_Connection * connection, const char * name) {
      char * sName = mpd_sanitizeArg(name);
      char * string = malloc(strlen("save")+strlen(sName)+5);
      sprintf(string,"save \"%s\"\n",sName);
      mpd_executeCommand(connection,string);
      free(string);
      free(sName);
}

void mpd_sendLoadCommand(mpd_Connection * connection, const char * name) {
      char * sName = mpd_sanitizeArg(name);
      char * string = malloc(strlen("load")+strlen(sName)+5);
      sprintf(string,"load \"%s\"\n",sName);
      mpd_executeCommand(connection,string);
      free(string);
      free(sName);
}

void mpd_sendRmCommand(mpd_Connection * connection, const char * name) {
      char * sName = mpd_sanitizeArg(name);
      char * string = malloc(strlen("rm")+strlen(sName)+5);
      sprintf(string,"rm \"%s\"\n",sName);
      mpd_executeCommand(connection,string);
      free(string);
      free(sName);
}

void mpd_sendShuffleCommand(mpd_Connection * connection) {
      mpd_executeCommand(connection,"shuffle\n");
}

void mpd_sendClearCommand(mpd_Connection * connection) {
      mpd_executeCommand(connection,"clear\n");
}

void mpd_sendPlayCommand(mpd_Connection * connection, int songPos) {
      char * string = malloc(strlen("play")+25);
      sprintf(string,"play \"%i\"\n",songPos);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendPlayIdCommand(mpd_Connection * connection, int id) {
      char * string = malloc(strlen("playid")+25);
      sprintf(string,"playid \"%i\"\n",id);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendStopCommand(mpd_Connection * connection) {
      mpd_executeCommand(connection,"stop\n");
}

void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode) {
      char * string = malloc(strlen("pause")+25);
      sprintf(string,"pause \"%i\"\n",pauseMode);
      mpd_executeCommand(connection,string);
      free(string);
}

void mpd_sendNextCommand(mpd_Connection * connection) {
      mpd_executeCommand(connection,"next\n");
}

void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to) {
      char * string = malloc(strlen("move")+25);
      sprintf(string,"move \"%i\" \"%i\"\n",from,to);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to) {
      char * string = malloc(strlen("moveid")+25);
      sprintf(string, "moveid \"%i\" \"%i\"\n", id, to);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2) {
      char * string = malloc(strlen("swap")+25);
      sprintf(string,"swap \"%i\" \"%i\"\n",song1,song2);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2) {
      char * string = malloc(strlen("swapid")+25);
      sprintf(string, "swapid \"%i\" \"%i\"\n", id1, id2);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time) {
      char * string = malloc(strlen("seek")+25);
      sprintf(string,"seek \"%i\" \"%i\"\n",song,time);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time) {
      char * string = malloc(strlen("seekid")+25);
      sprintf(string,"seekid \"%i\" \"%i\"\n",id,time);
      mpd_sendInfoCommand(connection,string);
      free(string);
}

void mpd_sendUpdateCommand(mpd_Connection * connection, char * path) {
      char * sPath = mpd_sanitizeArg(path);
      char * string = malloc(strlen("update")+strlen(sPath)+5);
      sprintf(string,"update \"%s\"\n",sPath);
      mpd_sendInfoCommand(connection,string);
      free(string);
      free(sPath);
}

int mpd_getUpdateId(mpd_Connection * connection) {
      char * jobid;
      int ret = 0;

      jobid = mpd_getNextReturnElementNamed(connection,"updating_db");
      if(jobid) {
            ret = atoi(jobid);
            free(jobid);
      }

      return ret;
}

void mpd_sendPrevCommand(mpd_Connection * connection) {
      mpd_executeCommand(connection,"previous\n");
}

void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode) {
      char * string = malloc(strlen("repeat")+25);
      sprintf(string,"repeat \"%i\"\n",repeatMode);
      mpd_executeCommand(connection,string);
      free(string);
}

void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode) {
      char * string = malloc(strlen("random")+25);
      sprintf(string,"random \"%i\"\n",randomMode);
      mpd_executeCommand(connection,string);
      free(string);
}

void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange) {
      char * string = malloc(strlen("setvol")+25);
      sprintf(string,"setvol \"%i\"\n",volumeChange);
      mpd_executeCommand(connection,string);
      free(string);
}

void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange) {
      char * string = malloc(strlen("volume")+25);
      sprintf(string,"volume \"%i\"\n",volumeChange);
      mpd_executeCommand(connection,string);
      free(string);
}

void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds) {
      char * string = malloc(strlen("crossfade")+25);
      sprintf(string,"crossfade \"%i\"\n",seconds);
      mpd_executeCommand(connection,string);
      free(string);
}

void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass) {
      char * sPass = mpd_sanitizeArg(pass);
      char * string = malloc(strlen("password")+strlen(sPass)+5);
      sprintf(string,"password \"%s\"\n",sPass);
      mpd_executeCommand(connection,string);
      free(string);
      free(sPass);
}

void mpd_sendCommandListBegin(mpd_Connection * connection) {
      if(connection->commandList) {
            strcpy(connection->errorStr,"already in command list mode");
            connection->error = 1;
            return;
      }
      connection->commandList = COMMAND_LIST;
      mpd_executeCommand(connection,"command_list_begin\n");
}

void mpd_sendCommandListOkBegin(mpd_Connection * connection) {
      if(connection->commandList) {
            strcpy(connection->errorStr,"already in command list mode");
            connection->error = 1;
            return;
      }
      connection->commandList = COMMAND_LIST_OK;
      mpd_executeCommand(connection,"command_list_ok_begin\n");
      connection->listOks = 0;
}

void mpd_sendCommandListEnd(mpd_Connection * connection) {
      if(!connection->commandList) {
            strcpy(connection->errorStr,"not in command list mode");
            connection->error = 1;
            return;
      }
      connection->commandList = 0;
      mpd_executeCommand(connection,"command_list_end\n");
}

void mpd_sendOutputsCommand(mpd_Connection * connection) {
      mpd_executeCommand(connection,"outputs\n");
}

mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection) {
      mpd_OutputEntity * output = NULL;

      if(connection->doneProcessing || (connection->listOks &&
                        connection->doneListOk))
      {
            return NULL;
      }

      if(connection->error) return NULL;

      output = malloc(sizeof(mpd_OutputEntity));
      output->id = -10;
      output->name = NULL;
      output->enabled = 0;

      if(!connection->returnElement) mpd_getNextReturnElement(connection);

      while(connection->returnElement) {
            mpd_ReturnElement * re = connection->returnElement;
            if(strcmp(re->name,"outputid")==0) {
                  if(output!=NULL && output->id>=0) return output;
                  output->id = atoi(re->value);
            }
            else if(strcmp(re->name,"outputname")==0) {
                  output->name = strdup(re->value);
            }
            else if(strcmp(re->name,"outputenabled")==0) {
                  output->enabled = atoi(re->value);
            }

            mpd_getNextReturnElement(connection);
            if(connection->error) {
                  free(output);
                  return NULL;
            }

      }

      return output;
}

void mpd_sendEnableOutputCommand(mpd_Connection * connection, int outputId) {
      char * string = malloc(strlen("enableoutput")+25);
      sprintf(string,"enableoutput \"%i\"\n",outputId);
      mpd_executeCommand(connection,string);
      free(string);
}

void mpd_sendDisableOutputCommand(mpd_Connection * connection, int outputId) {
      char * string = malloc(strlen("disableoutput")+25);
      sprintf(string,"disableoutput \"%i\"\n",outputId);
      mpd_executeCommand(connection,string);
      free(string);
}

void mpd_freeOutputElement(mpd_OutputEntity * output) {
      free(output->name);
      free(output);
}

Generated by  Doxygen 1.6.0   Back to index