mirror of
https://github.com/owntone/owntone-server.git
synced 2025-11-11 14:30:20 -05:00
abstract the plugin interface to the db to prepare for db plugins and making daap a plugin
This commit is contained in:
@@ -6,4 +6,7 @@ rsp_LTLIBRARIES=rsp.la
|
||||
rsp_la_LDFLAGS=-module -avoid-version
|
||||
rsp_la_SOURCES = compat.c rsp.c xml-rpc.c
|
||||
|
||||
EXTRA_DIST = compat.h rsp.h mtd-plugins.h xml-rpc.h
|
||||
EXTRA_DIST = compat.h rsp.h mtd-plugins.h xml-rpc.h
|
||||
|
||||
AM_CFLAGS = -I..
|
||||
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
/*
|
||||
* $Id: $
|
||||
*/
|
||||
|
||||
#ifndef _MTD_PLUGINS_H_
|
||||
#define _MTD_PLUGINS_H_
|
||||
|
||||
#define PLUGIN_OUTPUT 1
|
||||
#define PLUGIN_SCANNER 2
|
||||
#define PLUGIN_DATABASE 4
|
||||
#define PLUGIN_EVENT 8
|
||||
|
||||
#define PLUGIN_VERSION 1
|
||||
|
||||
#define PLUGIN_EVENT_LOG 0
|
||||
#define PLUGIN_EVENT_FULLSCAN_START 1
|
||||
#define PLUGIN_EVENT_FULLSCAN_END 2
|
||||
#define PLUGIN_EVENT_STARTING 3
|
||||
#define PLUGIN_EVENT_SHUTDOWN 4
|
||||
#define PLUGIN_EVENT_STARTSTREAM 5
|
||||
#define PLUGIN_EVENT_ABORTSTREAM 6
|
||||
#define PLUGIN_EVENT_ENDSTREAM 7
|
||||
|
||||
typedef void* PARSETREE;
|
||||
|
||||
struct tag_ws_conninfo;
|
||||
typedef struct tag_ws_conninfo WS_CONNINFO;
|
||||
|
||||
typedef struct tag_plugin_output_fn {
|
||||
void(*handler)(WS_CONNINFO *pwsc);
|
||||
int(*auth)(WS_CONNINFO *pwsc, char *username, char *pw);
|
||||
} PLUGIN_OUTPUT_FN;
|
||||
|
||||
typedef struct tag_plugin_event_fn {
|
||||
void(*handler)(int event_id, int intval, void *vp, int len);
|
||||
} PLUGIN_EVENT_FN;
|
||||
|
||||
typedef struct tag_plugin_rend_info {
|
||||
char *type;
|
||||
char *txt;
|
||||
} PLUGIN_REND_INFO;
|
||||
|
||||
typedef struct tag_plugin_info {
|
||||
int version;
|
||||
int type;
|
||||
char *server;
|
||||
char *url; /* regex of namespace to handle if OUTPUT type */
|
||||
PLUGIN_OUTPUT_FN *output_fns;
|
||||
PLUGIN_EVENT_FN *event_fns;
|
||||
void *pi; /* exported functions */
|
||||
PLUGIN_REND_INFO *rend_info;
|
||||
} PLUGIN_INFO;
|
||||
|
||||
/* xml helpers for output plugins */
|
||||
|
||||
/* logging */
|
||||
#define E_FATAL 0
|
||||
#define E_LOG 1
|
||||
#define E_INF 5
|
||||
#define E_DBG 9
|
||||
|
||||
/* db stuff */
|
||||
typedef enum {
|
||||
queryTypeItems,
|
||||
queryTypePlaylists,
|
||||
queryTypePlaylistItems,
|
||||
queryTypeBrowseArtists,
|
||||
queryTypeBrowseAlbums,
|
||||
queryTypeBrowseGenres,
|
||||
queryTypeBrowseComposers
|
||||
} QueryType_t;
|
||||
|
||||
typedef enum {
|
||||
indexTypeNone,
|
||||
indexTypeFirst,
|
||||
indexTypeLast,
|
||||
indexTypeSub
|
||||
} IndexType_t;
|
||||
|
||||
typedef enum {
|
||||
// generic meta data
|
||||
metaItemId,
|
||||
metaItemName,
|
||||
metaItemKind,
|
||||
metaPersistentId,
|
||||
metaContainerItemId,
|
||||
metaParentContainerId,
|
||||
|
||||
firstTypeSpecificMetaId,
|
||||
|
||||
// song meta data
|
||||
metaSongAlbum = firstTypeSpecificMetaId,
|
||||
metaSongArtist,
|
||||
metaSongBPM,
|
||||
metaSongBitRate,
|
||||
metaSongComment,
|
||||
metaSongCompilation,
|
||||
metaSongComposer,
|
||||
metaSongDataKind,
|
||||
metaSongDataURL,
|
||||
metaSongDateAdded,
|
||||
metaSongDateModified,
|
||||
metaSongDescription,
|
||||
metaSongDisabled,
|
||||
metaSongDiscCount,
|
||||
metaSongDiscNumber,
|
||||
metaSongEqPreset,
|
||||
metaSongFormat,
|
||||
metaSongGenre,
|
||||
metaSongGrouping,
|
||||
metaSongRelativeVolume,
|
||||
metaSongSampleRate,
|
||||
metaSongSize,
|
||||
metaSongStartTime,
|
||||
metaSongStopTime,
|
||||
metaSongTime,
|
||||
metaSongTrackCount,
|
||||
metaSongTrackNumber,
|
||||
metaSongUserRating,
|
||||
metaSongYear,
|
||||
|
||||
/* iTunes 4.5 + */
|
||||
metaSongCodecType,
|
||||
metaSongCodecSubType,
|
||||
metaItunesNormVolume,
|
||||
metaItmsSongId,
|
||||
metaItmsArtistId,
|
||||
metaItmsPlaylistId,
|
||||
metaItmsComposerId,
|
||||
metaItmsGenreId,
|
||||
metaItmsStorefrontId,
|
||||
metaItunesSmartPlaylist,
|
||||
|
||||
/* iTunes 5.0 + */
|
||||
metaSongContentRating,
|
||||
metaHasChildContainers,
|
||||
|
||||
/* iTunes 6.0.2+ */
|
||||
metaItunesHasVideo,
|
||||
|
||||
/* mt-daapd specific */
|
||||
metaMPlaylistSpec,
|
||||
metaMPlaylistType
|
||||
} MetaFieldName_t;
|
||||
|
||||
typedef unsigned long long MetaField_t;
|
||||
|
||||
typedef struct tag_dbqueryinfo {
|
||||
QueryType_t query_type;
|
||||
IndexType_t index_type;
|
||||
MetaField_t meta;
|
||||
int zero_length; /* emit zero-length strings? */
|
||||
int index_low;
|
||||
int index_high;
|
||||
int playlist_id;
|
||||
int db_id;
|
||||
int session_id;
|
||||
int want_count;
|
||||
int specifiedtotalcount;
|
||||
int uri_count;
|
||||
char *uri_sections[10];
|
||||
PARSETREE pt;
|
||||
void *output_info;
|
||||
} DBQUERYINFO;
|
||||
|
||||
typedef struct tag_plugin_input_fn {
|
||||
/* webserver helpers */
|
||||
char* (*ws_uri)(WS_CONNINFO *);
|
||||
void (*ws_close)(WS_CONNINFO *);
|
||||
int (*ws_returnerror)(WS_CONNINFO *, int, char *);
|
||||
char* (*ws_getvar)(WS_CONNINFO *, char *);
|
||||
int (*ws_writefd)(WS_CONNINFO *, char *, ...);
|
||||
int (*ws_addresponseheader)(WS_CONNINFO *, char *, char *, ...);
|
||||
void (*ws_emitheaders)(WS_CONNINFO *);
|
||||
int (*ws_fd)(WS_CONNINFO *);
|
||||
char* (*ws_getrequestheader)(WS_CONNINFO *, char *);
|
||||
int (*ws_writebinary)(WS_CONNINFO *, char *, int);
|
||||
|
||||
/* misc helpers */
|
||||
char* (*server_ver)(void);
|
||||
int (*server_name)(char *, int *);
|
||||
void (*log)(int, char *, ...);
|
||||
|
||||
int (*db_count)(void);
|
||||
int (*db_enum_start)(char **, DBQUERYINFO *);
|
||||
int (*db_enum_fetch_row)(char **, char ***, DBQUERYINFO *);
|
||||
int (*db_enum_end)(char **);
|
||||
void (*stream)(WS_CONNINFO *, DBQUERYINFO *, char *);
|
||||
|
||||
PARSETREE (*sp_init)(void);
|
||||
int (*sp_parse)(PARSETREE tree, char *term);
|
||||
int (*sp_dispose)(PARSETREE tree);
|
||||
char* (*sp_get_error)(PARSETREE tree);
|
||||
|
||||
char *(*conf_alloc_string)(char *, char *, char *);
|
||||
void (*conf_dispose_string)(char *);
|
||||
} PLUGIN_INPUT_FN;
|
||||
|
||||
|
||||
/* these are the functions that must be exported by the plugin */
|
||||
PLUGIN_INFO *plugin_info(void);
|
||||
|
||||
|
||||
#endif /* _MTD_PLUGINS_H_ */
|
||||
@@ -11,20 +11,26 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "mtd-plugins.h"
|
||||
#include "ff-plugins.h"
|
||||
#include "rsp.h"
|
||||
#include "xml-rpc.h"
|
||||
|
||||
typedef struct tag_rsp_privinfo {
|
||||
DB_QUERY dq;
|
||||
int uri_count;
|
||||
char *uri_sections[10];
|
||||
} PRIVINFO;
|
||||
|
||||
/* Forwards */
|
||||
PLUGIN_INFO *plugin_info(void);
|
||||
void plugin_handler(WS_CONNINFO *pwsc);
|
||||
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *pw);
|
||||
void rsp_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
||||
void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
||||
void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
||||
void rsp_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
||||
void rsp_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
|
||||
void rsp_error(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, int eno, char *estr);
|
||||
void rsp_info(WS_CONNINFO *pwsc, PRIVINFO *ppi);
|
||||
void rsp_db(WS_CONNINFO *pwsc, PRIVINFO *ppi);
|
||||
void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi);
|
||||
void rsp_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi);
|
||||
void rsp_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi);
|
||||
void rsp_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, int eno, char *estr);
|
||||
|
||||
/* Globals */
|
||||
PLUGIN_OUTPUT_FN _pofn = { plugin_handler, plugin_auth };
|
||||
@@ -34,19 +40,21 @@ PLUGIN_REND_INFO _pri[] = {
|
||||
};
|
||||
|
||||
PLUGIN_INFO _pi = {
|
||||
PLUGIN_VERSION,
|
||||
PLUGIN_OUTPUT,
|
||||
"rsp/" RSP_VERSION,
|
||||
"/rsp/.*",
|
||||
&_pofn,
|
||||
NULL,
|
||||
NULL,
|
||||
_pri
|
||||
PLUGIN_VERSION, /* version */
|
||||
PLUGIN_OUTPUT, /* type */
|
||||
"rsp/" RSP_VERSION, /* server */
|
||||
"/rsp/.*", /* url */
|
||||
&_pofn, /* output fns */
|
||||
NULL, /* event fns */
|
||||
NULL, /* transcode fns */
|
||||
NULL, /* ff functions */
|
||||
_pri, /* rend info */
|
||||
NULL /* transcode info */
|
||||
};
|
||||
|
||||
typedef struct tag_response {
|
||||
char *uri[10];
|
||||
void (*dispatch)(WS_CONNINFO *, DBQUERYINFO *);
|
||||
void (*dispatch)(WS_CONNINFO *, PRIVINFO *);
|
||||
} PLUGIN_RESPONSE;
|
||||
|
||||
|
||||
@@ -155,26 +163,30 @@ int plugin_auth(WS_CONNINFO *pwsc, char *username, char *pw) {
|
||||
*/
|
||||
void plugin_handler(WS_CONNINFO *pwsc) {
|
||||
char *string, *save, *token;
|
||||
DBQUERYINFO *pqi;
|
||||
PRIVINFO *ppi;
|
||||
int elements;
|
||||
int index, part;
|
||||
int found;
|
||||
|
||||
|
||||
string = infn->ws_uri(pwsc);
|
||||
string++;
|
||||
|
||||
ppi = (PRIVINFO *)malloc(sizeof(PRIVINFO));
|
||||
if(ppi) {
|
||||
memset(ppi,0,sizeof(PRIVINFO));
|
||||
}
|
||||
|
||||
pqi = (DBQUERYINFO *)malloc(sizeof(DBQUERYINFO));
|
||||
if(!pqi) {
|
||||
if(!ppi) {
|
||||
infn->ws_returnerror(pwsc,500,"Malloc error in plugin_handler");
|
||||
return;
|
||||
}
|
||||
memset(pqi,0,sizeof(DBQUERYINFO));
|
||||
|
||||
memset((void*)&ppi->dq,0,sizeof(DB_QUERY));
|
||||
|
||||
infn->log(E_DBG,"Tokenizing url\n");
|
||||
while((pqi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
|
||||
while((ppi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
|
||||
string=NULL;
|
||||
pqi->uri_sections[pqi->uri_count++] = token;
|
||||
ppi->uri_sections[ppi->uri_count++] = token;
|
||||
}
|
||||
|
||||
elements = sizeof(rsp_uri_map) / sizeof(PLUGIN_RESPONSE);
|
||||
@@ -188,15 +200,15 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
||||
infn->log(E_DBG,"Checking reponse %d\n",index);
|
||||
part=0;
|
||||
while(part < 10) {
|
||||
if((rsp_uri_map[index].uri[part]) && (!pqi->uri_sections[part]))
|
||||
if((rsp_uri_map[index].uri[part]) && (!ppi->uri_sections[part]))
|
||||
break;
|
||||
if((pqi->uri_sections[part]) && (!rsp_uri_map[index].uri[part]))
|
||||
if((ppi->uri_sections[part]) && (!rsp_uri_map[index].uri[part]))
|
||||
break;
|
||||
|
||||
if((rsp_uri_map[index].uri[part]) &&
|
||||
(strcmp(rsp_uri_map[index].uri[part],"*") != 0)) {
|
||||
if(strcmp(rsp_uri_map[index].uri[part],
|
||||
pqi->uri_sections[part])!= 0)
|
||||
ppi->uri_sections[part])!= 0)
|
||||
break;
|
||||
}
|
||||
part++;
|
||||
@@ -211,20 +223,22 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
||||
}
|
||||
|
||||
if(found) {
|
||||
rsp_uri_map[index].dispatch(pwsc, pqi);
|
||||
rsp_uri_map[index].dispatch(pwsc, ppi);
|
||||
infn->ws_close(pwsc);
|
||||
free(ppi);
|
||||
return;
|
||||
}
|
||||
|
||||
rsp_error(pwsc, pqi, 1, "Bad path");
|
||||
rsp_error(pwsc, ppi, 1, "Bad path");
|
||||
infn->ws_close(pwsc);
|
||||
free(ppi);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* get server info
|
||||
*/
|
||||
void rsp_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
void rsp_info(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||
XMLSTRUCT *pxml;
|
||||
char servername[256];
|
||||
int size;
|
||||
@@ -262,17 +276,18 @@ void rsp_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
*
|
||||
* dump details about all playlists
|
||||
*/
|
||||
void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
void rsp_db(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||
XMLSTRUCT *pxml;
|
||||
char *pe;
|
||||
int err;
|
||||
char **row;
|
||||
int rowindex;
|
||||
|
||||
pqi->want_count = 1;
|
||||
pqi->query_type = queryTypePlaylists;
|
||||
if((err=infn->db_enum_start(&pe,pqi)) != 0) {
|
||||
rsp_error(pwsc, pqi, err | E_DB, pe);
|
||||
ppi->dq.query_type = QUERY_TYPE_PLAYLISTS;
|
||||
|
||||
if((err=infn->db_enum_start(&pe,&ppi->dq)) != 0) {
|
||||
rsp_error(pwsc, ppi, err | E_DB, pe);
|
||||
infn->db_enum_dispose(NULL,&ppi->dq);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -282,13 +297,13 @@ void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
xml_push(pxml,"status");
|
||||
xml_output(pxml,"errorcode","0");
|
||||
xml_output(pxml,"errorstring","");
|
||||
xml_output(pxml,"records","%d",pqi->specifiedtotalcount);
|
||||
xml_output(pxml,"totalrecords","%d",pqi->specifiedtotalcount);
|
||||
xml_output(pxml,"records","%d",ppi->dq.totalcount);
|
||||
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
|
||||
xml_pop(pxml); /* status */
|
||||
|
||||
xml_push(pxml,"playlists");
|
||||
|
||||
while((infn->db_enum_fetch_row(NULL,&row,pqi) == 0) && (row)) {
|
||||
while((infn->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
|
||||
xml_push(pxml,"playlist");
|
||||
rowindex=0;
|
||||
while(rsp_playlist_fields[rowindex].name) {
|
||||
@@ -302,6 +317,7 @@ void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
}
|
||||
|
||||
infn->db_enum_end(NULL);
|
||||
infn->db_enum_dispose(NULL,&ppi->dq);
|
||||
|
||||
xml_pop(pxml); /* playlists */
|
||||
xml_pop(pxml); /* response */
|
||||
@@ -312,7 +328,7 @@ void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
/**
|
||||
* get all items under the playlist
|
||||
*/
|
||||
void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||
XMLSTRUCT *pxml;
|
||||
char *pe;
|
||||
int err;
|
||||
@@ -321,8 +337,6 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
int returned;
|
||||
char *browse_type;
|
||||
int type;
|
||||
char *query;
|
||||
char *estr = NULL;
|
||||
char *transcode_codecs;
|
||||
int transcode;
|
||||
int samplerate;
|
||||
@@ -341,30 +355,15 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
}
|
||||
*/
|
||||
|
||||
query = infn->ws_getvar(pwsc,"query");
|
||||
if(query) {
|
||||
pqi->pt = infn->sp_init();
|
||||
if(!infn->sp_parse(pqi->pt,query)) {
|
||||
estr = strdup(infn->sp_get_error(pqi->pt));
|
||||
infn->log(E_LOG,"Ignoring bad query (%s): %s\n",query,estr);
|
||||
infn->sp_dispose(pqi->pt);
|
||||
pqi->pt = NULL;
|
||||
}
|
||||
}
|
||||
ppi->dq.filter = infn->ws_getvar(pwsc,"query");
|
||||
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
|
||||
|
||||
pqi->index_type = indexTypeNone;
|
||||
if(infn->ws_getvar(pwsc,"offset")) {
|
||||
pqi->index_low = atoi(infn->ws_getvar(pwsc,"offset"));
|
||||
ppi->dq.offset = atoi(infn->ws_getvar(pwsc,"offset"));
|
||||
}
|
||||
if(infn->ws_getvar(pwsc,"limit")) {
|
||||
pqi->index_high = pqi->index_low + atoi(infn->ws_getvar(pwsc,"limit")) -1;
|
||||
if(pqi->index_high < pqi->index_low) {
|
||||
pqi->index_high = 999999;
|
||||
}
|
||||
} else {
|
||||
pqi->index_high = 999999; /* FIXME */
|
||||
ppi->dq.limit = atoi(infn->ws_getvar(pwsc,"limit"));
|
||||
}
|
||||
pqi->index_type = indexTypeSub;
|
||||
|
||||
browse_type = infn->ws_getvar(pwsc,"type");
|
||||
type = F_FULL;
|
||||
@@ -376,26 +375,24 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
type = F_ID;
|
||||
}
|
||||
}
|
||||
ppi->dq.query_type = QUERY_TYPE_ITEMS;
|
||||
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
|
||||
|
||||
pqi->want_count = 1;
|
||||
pqi->query_type = queryTypePlaylistItems;
|
||||
pqi->playlist_id = atoi(pqi->uri_sections[2]);
|
||||
|
||||
if((err=infn->db_enum_start(&pe,pqi)) != 0) {
|
||||
if(pqi->pt) infn->sp_dispose(pqi->pt);
|
||||
if(estr) free(estr);
|
||||
rsp_error(pwsc, pqi, err | E_DB, pe);
|
||||
if((err=infn->db_enum_start(&pe,&ppi->dq)) != 0) {
|
||||
rsp_error(pwsc, ppi, err | E_DB, pe);
|
||||
infn->db_enum_dispose(NULL,&ppi->dq);
|
||||
free(pe);
|
||||
return;
|
||||
}
|
||||
|
||||
pxml = xml_init(pwsc,1);
|
||||
|
||||
if(pqi->index_low > pqi->specifiedtotalcount) {
|
||||
if(ppi->dq.offset > ppi->dq.totalcount) {
|
||||
returned = 0;
|
||||
} else {
|
||||
returned = pqi->index_high - pqi->index_low + 1;
|
||||
if(returned > (pqi->specifiedtotalcount - pqi->index_low))
|
||||
returned = pqi->specifiedtotalcount - pqi->index_low;
|
||||
returned = ppi->dq.limit;
|
||||
if(returned > (ppi->dq.totalcount - ppi->dq.offset))
|
||||
returned = ppi->dq.totalcount - ppi->dq.offset;
|
||||
}
|
||||
|
||||
transcode_codecs = infn->conf_alloc_string("general","ssc_codectypes","");
|
||||
@@ -403,14 +400,14 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
xml_push(pxml,"response");
|
||||
xml_push(pxml,"status");
|
||||
xml_output(pxml,"errorcode","0");
|
||||
xml_output(pxml,"errorstring",estr ? estr : "");
|
||||
xml_output(pxml,"errorstring","");
|
||||
xml_output(pxml,"records","%d",returned);
|
||||
xml_output(pxml,"totalrecords","%d",pqi->specifiedtotalcount);
|
||||
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
|
||||
xml_pop(pxml); /* status */
|
||||
|
||||
xml_push(pxml,"items");
|
||||
|
||||
while((infn->db_enum_fetch_row(NULL,&row,pqi) == 0) && (row)) {
|
||||
while((infn->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
|
||||
xml_push(pxml,"item");
|
||||
rowindex=0;
|
||||
transcode = 0;
|
||||
@@ -462,108 +459,75 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
xml_pop(pxml); /* items */
|
||||
xml_pop(pxml); /* response */
|
||||
xml_deinit(pxml);
|
||||
|
||||
if(pqi->pt) infn->sp_dispose(pqi->pt);
|
||||
if(estr) free(estr);
|
||||
}
|
||||
|
||||
void rsp_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
void rsp_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||
XMLSTRUCT *pxml;
|
||||
char *pe;
|
||||
int err;
|
||||
char **row;
|
||||
int returned;
|
||||
char *query;
|
||||
char *estr = NULL;
|
||||
|
||||
/* FIXME */
|
||||
if(!strcmp(pqi->uri_sections[3],"artist")) {
|
||||
pqi->query_type = queryTypeBrowseArtists;
|
||||
} else if(!strcmp(pqi->uri_sections[3],"genre")) {
|
||||
pqi->query_type = queryTypeBrowseGenres;
|
||||
} else if(!strcmp(pqi->uri_sections[3],"album")) {
|
||||
pqi->query_type = queryTypeBrowseAlbums;
|
||||
} else if(!strcmp(pqi->uri_sections[3],"composer")) {
|
||||
pqi->query_type = queryTypeBrowseComposers;
|
||||
} else {
|
||||
rsp_error(pwsc, pqi, 0 | E_RSP, "Unsupported browse type");
|
||||
return;
|
||||
/* this might fail if an unsupported browse type */
|
||||
ppi->dq.query_type = QUERY_TYPE_DISTINCT;
|
||||
ppi->dq.distinct_field = ppi->uri_sections[3];
|
||||
ppi->dq.filter = infn->ws_getvar(pwsc,"query");
|
||||
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
|
||||
|
||||
if(infn->ws_getvar(pwsc,"offset")) {
|
||||
ppi->dq.offset = atoi(infn->ws_getvar(pwsc,"offset"));
|
||||
}
|
||||
|
||||
query = infn->ws_getvar(pwsc,"query");
|
||||
if(query) {
|
||||
pqi->pt = infn->sp_init();
|
||||
if(!infn->sp_parse(pqi->pt,query)) {
|
||||
estr = strdup(infn->sp_get_error(pqi->pt));
|
||||
infn->log(E_LOG,"Ignoring bad query (%s): %s\n",query,estr);
|
||||
infn->sp_dispose(pqi->pt);
|
||||
pqi->pt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pqi->index_type = indexTypeNone;
|
||||
if(infn->ws_getvar(pwsc,"offset")) {
|
||||
pqi->index_low = atoi(infn->ws_getvar(pwsc,"offset"));
|
||||
}
|
||||
if(infn->ws_getvar(pwsc,"limit")) {
|
||||
pqi->index_high = pqi->index_low + atoi(infn->ws_getvar(pwsc,"limit")) -1;
|
||||
if(pqi->index_high < pqi->index_low) {
|
||||
pqi->index_high = 999999;
|
||||
}
|
||||
} else {
|
||||
pqi->index_high = 999999; /* FIXME */
|
||||
ppi->dq.limit = atoi(infn->ws_getvar(pwsc,"limit"));
|
||||
}
|
||||
pqi->index_type = indexTypeSub;
|
||||
pqi->want_count = 1;
|
||||
pqi->playlist_id = atoi(pqi->uri_sections[2]);
|
||||
|
||||
if((err=infn->db_enum_start(&pe,pqi)) != 0) {
|
||||
if(pqi->pt) infn->sp_dispose(pqi->pt);
|
||||
if(estr) free(estr);
|
||||
rsp_error(pwsc, pqi, err | E_DB, pe);
|
||||
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
|
||||
|
||||
if((err=infn->db_enum_start(&pe,&ppi->dq)) != 0) {
|
||||
rsp_error(pwsc, ppi, err | E_DB, pe);
|
||||
infn->db_enum_dispose(NULL,&ppi->dq);
|
||||
return;
|
||||
}
|
||||
|
||||
pxml = xml_init(pwsc,1);
|
||||
|
||||
if(pqi->index_low > pqi->specifiedtotalcount) {
|
||||
if(ppi->dq.offset > ppi->dq.totalcount) {
|
||||
returned = 0;
|
||||
} else {
|
||||
returned = pqi->index_high - pqi->index_low + 1;
|
||||
if(returned > (pqi->specifiedtotalcount - pqi->index_low))
|
||||
returned = pqi->specifiedtotalcount - pqi->index_low;
|
||||
returned = ppi->dq.limit;
|
||||
if(returned > (ppi->dq.totalcount - ppi->dq.offset))
|
||||
returned = ppi->dq.totalcount - ppi->dq.offset;
|
||||
}
|
||||
|
||||
xml_push(pxml,"response");
|
||||
xml_push(pxml,"status");
|
||||
xml_output(pxml,"errorcode","0");
|
||||
xml_output(pxml,"errorstring",estr ? estr : "");
|
||||
xml_output(pxml,"errorstring","");
|
||||
xml_output(pxml,"records","%d",returned);
|
||||
xml_output(pxml,"totalrecords","%d",pqi->specifiedtotalcount);
|
||||
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
|
||||
xml_pop(pxml); /* status */
|
||||
|
||||
xml_push(pxml,"items");
|
||||
|
||||
while((infn->db_enum_fetch_row(NULL,&row,pqi) == 0) && (row)) {
|
||||
while((infn->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
|
||||
xml_output(pxml,"item",row[0]);
|
||||
}
|
||||
|
||||
infn->db_enum_end(NULL);
|
||||
infn->db_enum_dispose(NULL,&ppi->dq);
|
||||
|
||||
xml_pop(pxml); /* items */
|
||||
xml_pop(pxml); /* response */
|
||||
xml_deinit(pxml);
|
||||
|
||||
if(pqi->pt) infn->sp_dispose(pqi->pt);
|
||||
if(estr) free(estr);
|
||||
}
|
||||
|
||||
void rsp_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
|
||||
infn->stream(pwsc, pqi, pqi->uri_sections[2]);
|
||||
void rsp_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||
infn->stream(pwsc, ppi->uri_sections[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
void rsp_error(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, int eno, char *estr) {
|
||||
void rsp_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, int eno, char *estr) {
|
||||
XMLSTRUCT *pxml;
|
||||
|
||||
pxml = xml_init(pwsc, 1);
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
#include <zlib.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "mtd-plugins.h"
|
||||
#include "ff-plugins.h"
|
||||
#include "rsp.h"
|
||||
#include "xml-rpc.h"
|
||||
|
||||
|
||||
/* typedefs */
|
||||
typedef struct tag_xmlstack {
|
||||
char *tag;
|
||||
@@ -135,7 +136,8 @@ int xml_stream_write(XMLSTRUCT *pxml, char *out) {
|
||||
if(result != Z_OK) {
|
||||
infn->log(E_FATAL,"Error in zlib: %d\n",result);
|
||||
}
|
||||
infn->ws_writebinary(pxml->pwsc,psb->out_buffer,XML_STREAM_BLOCK-psb->strm.avail_out);
|
||||
infn->ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
|
||||
XML_STREAM_BLOCK-psb->strm.avail_out);
|
||||
if(psb->strm.avail_out != 0) {
|
||||
done=1;
|
||||
} else {
|
||||
@@ -161,7 +163,8 @@ int xml_stream_close(XMLSTRUCT *pxml) {
|
||||
psb->strm.next_in = psb->in_buffer;
|
||||
|
||||
deflate(&psb->strm,Z_FINISH);
|
||||
infn->ws_writebinary(pxml->pwsc,psb->out_buffer,XML_STREAM_BLOCK - psb->strm.avail_out);
|
||||
infn->ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
|
||||
XML_STREAM_BLOCK - psb->strm.avail_out);
|
||||
|
||||
if(psb->strm.avail_out != 0)
|
||||
done=1;
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
#ifndef _XMLRPC_H_
|
||||
#define _XMLRPC_H_
|
||||
|
||||
#include "mtd-plugins.h"
|
||||
#include "ff-plugins.h"
|
||||
|
||||
struct tag_xmlstruct;
|
||||
typedef struct tag_xmlstruct XMLSTRUCT;
|
||||
typedef struct tag_ws_conninfo WS_CONNINFO;
|
||||
|
||||
extern XMLSTRUCT *xml_init(WS_CONNINFO *pwsc, int emit_header);
|
||||
extern void xml_push(XMLSTRUCT *pxml, char *term);
|
||||
|
||||
Reference in New Issue
Block a user