aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libmpdclient.c166
-rw-r--r--src/libmpdclient.h33
-rw-r--r--src/screen_search.c255
3 files changed, 433 insertions, 21 deletions
diff --git a/src/libmpdclient.c b/src/libmpdclient.c
index bc1c1d6e7..a8bbabef7 100644
--- a/src/libmpdclient.c
+++ b/src/libmpdclient.c
@@ -31,6 +31,7 @@
*/
+
#include "libmpdclient.h"
#include <errno.h>
@@ -39,12 +40,16 @@
#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 MPD_NO_IPV6
#ifdef AF_INET6
@@ -59,6 +64,22 @@
#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"
+};
+
+
#ifdef MPD_HAVE_IPV6
int mpd_ipv6Supported() {
int s;
@@ -105,8 +126,8 @@ mpd_ReturnElement * mpd_newReturnElement(const char * name, const char * value)
{
mpd_ReturnElement * ret = malloc(sizeof(mpd_ReturnElement));
- ret->name = strdup(name);
- ret->value = strdup(value);
+ ret->name = (char *)strdup(name);
+ ret->value = (char *)strdup(value);
return ret;
}
@@ -1073,6 +1094,13 @@ char * mpd_getNextReturnElementNamed(mpd_Connection * 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");
}
@@ -1154,6 +1182,89 @@ void mpd_sendSearchCommand(mpd_Connection * connection, int table,
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)
@@ -1202,6 +1313,53 @@ void mpd_sendListCommand(mpd_Connection * connection, int table,
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);
@@ -1440,7 +1598,7 @@ mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection) {
mpd_OutputEntity * output = NULL;
if(connection->doneProcessing || (connection->listOks &&
- connection->doneListOk))
+ connection->doneListOk))
{
return NULL;
}
@@ -1472,7 +1630,7 @@ mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection) {
free(output);
return NULL;
}
-
+
}
return output;
diff --git a/src/libmpdclient.h b/src/libmpdclient.h
index 79a94d8ee..dbbd1019e 100644
--- a/src/libmpdclient.h
+++ b/src/libmpdclient.h
@@ -35,7 +35,7 @@
#define LIBMPDCLIENT_H
#include <sys/time.h>
-
+#include <stdarg.h>
#define MPD_BUFFER_MAX_LENGTH 50000
#define MPD_WELCOME_MESSAGE "OK MPD "
@@ -71,6 +71,26 @@
extern "C" {
#endif
+
+enum
+{
+ MPD_TAG_ITEM_ARTIST,
+ MPD_TAG_ITEM_ALBUM,
+ MPD_TAG_ITEM_TITLE,
+ MPD_TAG_ITEM_TRACK,
+ MPD_TAG_ITEM_NAME,
+ MPD_TAG_ITEM_GENRE,
+ MPD_TAG_ITEM_DATE,
+ MPD_TAG_ITEM_COMPOSER,
+ MPD_TAG_ITEM_PERFORMER,
+ MPD_TAG_ITEM_COMMENT,
+ MPD_TAG_ITEM_FILENAME,
+ MPD_TAG_NUM_OF_ITEM_TYPES
+}mpd_TagItems;
+
+
+extern char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES];
+
/* internal stuff don't touch this struct */
typedef struct _mpd_ReturnElement {
char * name;
@@ -388,21 +408,32 @@ void mpd_sendSearchCommand(mpd_Connection * connection, int table,
void mpd_sendFindCommand(mpd_Connection * connection, int table,
const char * str);
+
+void mpd_sendSearchTagCommand(mpd_Connection *connection, ...);
+void mpd_sendFindTagCommand(mpd_Connection *connection, ...);
+void mpd_sendVSearchTagCommand(mpd_Connection *connection, va_list arglist);
+void mpd_sendVFindTagCommand(mpd_Connection *connection, va_list arglist);
/* LIST TAG COMMANDS */
/* use this function fetch next artist entry, be sure to free the returned
* string. NULL means there are no more. Best used with sendListArtists
*/
+
char * mpd_getNextArtist(mpd_Connection * connection);
char * mpd_getNextAlbum(mpd_Connection * connection);
+char * mpd_getNextTag(mpd_Connection *connection, int table);
+
/* list artist or albums by artist, arg1 should be set to the artist if
* listing albums by a artist, otherwise NULL for listing all artists or albums
*/
void mpd_sendListCommand(mpd_Connection * connection, int table,
const char * arg1);
+void mpd_sendListTagCommand(mpd_Connection * connection, int table,...);
+void mpd_sendVListTagCommand(mpd_Connection * connection,int ret_table, va_list arglist);
+
/* SIMPLE COMMANDS */
void mpd_sendAddCommand(mpd_Connection * connection, const char * file);
diff --git a/src/screen_search.c b/src/screen_search.c
index 03ce11ad6..ebeb25592 100644
--- a/src/screen_search.c
+++ b/src/screen_search.c
@@ -33,13 +33,61 @@
#include "strfsong.h"
#include "command.h"
#include "screen.h"
+#include "utils.h"
#include "screen_utils.h"
#include "screen_browse.h"
-#define SEARCH_TITLE 0
-#define SEARCH_ARTIST 1
-#define SEARCH_ALBUM 2
-#define SEARCH_FILE 3
+/* new search stuff with qball's libmpdclient */
+#define FUTURE
+
+
+#ifdef FUTURE
+
+typedef struct
+{
+ int id;
+ char *name;
+ char *localname;
+} search_tag_t;
+
+static search_tag_t search_tag[] = {
+ { MPD_TAG_ITEM_ARTIST, "artist", N_("artist") },
+ { MPD_TAG_ITEM_ALBUM, "album", N_("album") },
+ { MPD_TAG_ITEM_TITLE, "title", N_("title") },
+ { MPD_TAG_ITEM_TRACK, "track", N_("track") },
+ { MPD_TAG_ITEM_NAME, "name", N_("name") },
+ { MPD_TAG_ITEM_GENRE, "genre", N_("genre") },
+ { MPD_TAG_ITEM_DATE, "date", N_("date") },
+ { MPD_TAG_ITEM_COMPOSER, "composer", N_("composer") },
+ { MPD_TAG_ITEM_PERFORMER,"performer", N_("performer") },
+ { MPD_TAG_ITEM_COMMENT, "comment", N_("comment") },
+ { MPD_TAG_ITEM_FILENAME, "filename", N_("file") },
+ { -1, NULL, NULL }
+};
+
+static int
+search_get_tag_id(char *name)
+{
+ int i;
+
+ i=0;
+ while( search_tag[i].name )
+ {
+ if( strcasecmp(search_tag[i].name, name)==0 ||
+ strcasecmp(search_tag[i].localname, name)==0 )
+ return search_tag[i].id;
+ i++;
+ }
+ return -1;
+}
+
+#endif
+
+
+#define SEARCH_TITLE 0
+#define SEARCH_ARTIST 1
+#define SEARCH_ALBUM 2
+#define SEARCH_FILE 3
typedef struct {
int table;
@@ -56,7 +104,44 @@ static search_type_t mode[] = {
static list_window_t *lw = NULL;
static mpdclient_filelist_t *filelist = NULL;
+static GList *search_history = NULL;
static gchar *pattern = NULL;
+static gboolean advanced_search_mode = FALSE;
+
+
+/* search info */
+static char *
+lw_search_help_callback(int index, int *highlight, void *data)
+{
+ int text_rows;
+ static char *text[] = {
+ "Welcome to ncmpc's search screen - SVN version.",
+ "",
+ "Quick search - just enter a string and ncmcp will search according",
+ " to the current search mode (displayed above).",
+ "",
+ "Advanced - bla bla bla.... syntax below",
+ ""
+ " <tag>:<search term> [<tag>:<search term>...]",
+ "",
+ "Example: artist:radiohead album:pablo honey",
+ "",
+ "##### SOMEONE - Write a proper help text, please! #####",
+ "",
+ "avalible tags: artist, album, title, track, name, genre, date",
+ " composer, performer, comment, file",
+ "",
+ NULL
+ };
+
+ text_rows=0;
+ while( text[text_rows] )
+ text_rows++;
+
+ if( index < text_rows )
+ return text[index];
+ return NULL;
+}
/* the playlist have been updated -> fix highlights */
static void
@@ -105,6 +190,130 @@ search_clear(screen_t *screen, mpdclient_t *c, gboolean clear_pattern)
}
}
+#ifdef FUTURE
+/*-----------------------------------------------------------------------
+ * NOTE: This code exists to test a new search ui,
+ * Its ugly and MUST be redesigned before the next release!
+ *-----------------------------------------------------------------------
+ */
+static mpdclient_filelist_t *
+search_advanced_query(char *query, mpdclient_t *c)
+{
+ int i,j;
+ char **strv;
+ int table[10];
+ char *arg[10];
+ mpdclient_filelist_t *filelist = NULL;
+
+ advanced_search_mode = FALSE;
+ if( g_strrstr(query, ":") == NULL )
+ return NULL;
+
+ strv = g_strsplit_set(query, ": ", 0);
+
+ i=0;
+ while( strv[i] )
+ {
+ D("strv[%d] = \"%s\"\n", i, strv[i]);
+ i++;
+ }
+
+ memset(table, 0, 10*sizeof(int));
+ memset(arg, 0, 10*sizeof(char *));
+
+ i=0;
+ j=0;
+ while( strv[i] && i<9 )
+ {
+ D("strv[%d] = \"%s\"\n", i, strv[i]);
+
+ int id = search_get_tag_id(strv[i]);
+ if( id==-1 )
+ {
+ if( table[j] )
+ {
+ char *tmp = arg[j];
+ arg[j] = g_strdup_printf("%s %s", arg[j], strv[i]);
+ g_free(tmp);
+ }
+ else
+ {
+ D("Bad search tag %s\n", strv[i]);
+ screen_status_printf(_("Bad search tag %s"), strv[i]);
+ }
+ i++;
+ }
+ else if( strv[i+1] == NULL )
+ {
+ D("No argument for search tag %s\n", strv[i]);
+ screen_status_printf(_("No argument for search tag %s"), strv[i]);
+ i++;
+ }
+ else
+ {
+ table[j] = id;
+ arg[j] = locale_to_utf8(strv[i+1]); // FREE ME
+ j++;
+ table[j] = -1;
+ arg[j] = NULL;
+ i = i + 2;
+ advanced_search_mode = TRUE;
+ }
+ }
+
+ g_strfreev(strv);
+
+
+ if( advanced_search_mode )
+ {
+ /*-----------------------------------------------------------------------
+ * NOTE (again): This code exists to test a new search ui,
+ * Its ugly and MUST be redesigned before the next release!
+ * + the code below should live in mpdclient.c
+ *-----------------------------------------------------------------------
+ */
+ mpd_InfoEntity *entity;
+
+ /** stupid - but this is just a test...... (fulhack) */
+ mpd_sendSearchTagCommand(c->connection,
+ table[0], arg[0],
+ table[1], arg[1],
+ table[2], arg[2],
+ table[3], arg[3],
+ table[4], arg[4],
+ table[5], arg[5],
+ table[6], arg[6],
+ table[7], arg[7],
+ table[8], arg[8],
+ table[9], arg[9]);
+
+ filelist = g_malloc0(sizeof(mpdclient_filelist_t));
+
+ while( (entity=mpd_getNextInfoEntity(c->connection)) )
+ {
+ filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
+
+ entry->entity = entity;
+ filelist->list = g_list_append(filelist->list, (gpointer) entry);
+ filelist->length++;
+ }
+
+ if( mpdclient_finish_command(c) )
+ filelist = mpdclient_filelist_free(filelist);
+
+ filelist->updated = TRUE;
+ }
+
+ i=0;
+ while( arg[i] )
+ g_free(arg[i++]);
+
+ return filelist;
+}
+#else
+#define search_advanced_query(pattern,c) (NULL)
+#endif
+
static void
search_new(screen_t *screen, mpdclient_t *c)
{
@@ -113,7 +322,7 @@ search_new(screen_t *screen, mpdclient_t *c)
pattern = screen_readln(screen->status_window.w,
_("Search: "),
NULL,
- NULL,
+ &search_history,
NULL);
if( pattern && strcmp(pattern,"")==0 )
@@ -128,15 +337,20 @@ search_new(screen_t *screen, mpdclient_t *c)
return;
}
- filelist = mpdclient_filelist_search(c,
- FALSE,
- mode[options.search_mode].table,
- pattern);
+ if( !MPD_VERSION_LT(c, 0, 12, 0) )
+ filelist = search_advanced_query(pattern, c);
+ if( !advanced_search_mode && filelist==NULL )
+ filelist = mpdclient_filelist_search(c,
+ FALSE,
+ mode[options.search_mode].table,
+ pattern);
sync_highlights(c, filelist);
mpdclient_install_playlist_callback(c, playlist_changed_callback);
list_window_check_selected(lw, filelist->length);
}
+
+
static void
init(WINDOW *w, int cols, int rows)
{
@@ -146,6 +360,8 @@ init(WINDOW *w, int cols, int rows)
static void
quit(void)
{
+ if( search_history )
+ string_list_free(search_history);
if( filelist )
filelist = mpdclient_filelist_free(filelist);
list_window_free(lw);
@@ -157,10 +373,10 @@ quit(void)
static void
open(screen_t *screen, mpdclient_t *c)
{
- if( pattern==NULL )
- search_new(screen, c);
- else
- screen_status_printf(_("Press %s for a new search"),
+ // if( pattern==NULL )
+ // search_new(screen, c);
+ // else
+ screen_status_printf(_("Press %s for a new search"),
get_key_names(CMD_SCREEN_SEARCH,0));
search_check_mode();
}
@@ -184,13 +400,18 @@ paint(screen_t *screen, mpdclient_t *c)
if( filelist )
{
+ lw->flags = 0;
list_window_paint(lw, browse_lw_callback, (void *) filelist);
filelist->updated = FALSE;
}
else
{
- wmove(lw->w, 0, 0);
- wclrtobot(lw->w);
+ lw->flags = LW_HIDE_CURSOR;
+ list_window_paint(lw, lw_search_help_callback, NULL);
+ if( !MPD_VERSION_LT(c, 0, 12, 0) )
+ g_strdup_printf("Advanced search disabled (MPD version < 0.12.0");
+ // wmove(lw->w, 0, 0);
+ //wclrtobot(lw->w);
}
wnoutrefresh(lw->w);
}
@@ -210,7 +431,9 @@ update(screen_t *screen, mpdclient_t *c)
static char *
get_title(char *str, size_t size)
{
- if( pattern )
+ if( advanced_search_mode && pattern )
+ g_snprintf(str, size, _("Search: %s"), pattern);
+ else if( pattern )
g_snprintf(str, size,
_("Search: Results for %s [%s]"),
pattern,