abstract the plugin interface to the db to prepare for db plugins and making daap a plugin

This commit is contained in:
Ron Pedde 2006-05-27 08:02:39 +00:00
parent 9e547e6c16
commit b3fbb9bbd5
12 changed files with 215 additions and 451 deletions

View File

@ -354,7 +354,8 @@ char *db_error_list[] = {
"Could not initialize thread pool",
"Passed buffer too small for result",
"Wrong db schema. Use mtd-update to upgrade the db.",
"Database error: %s"
"Database error: %s",
"Malloc error"
};
/* Globals */

View File

@ -216,6 +216,7 @@ extern void db_dispose_playlist(M3UFILE *pm3u);
#define DB_E_SIZE 0x0B /**< passed buffer too small */
#define DB_E_WRONGVERSION 0x0C /**< must upgrade db */
#define DB_E_DB_ERROR 0x0D /**< gdbm error */
#define DB_E_MALLOC 0x0E /**< malloc error */
/* describes the individual database handlers */
typedef struct tag_dbinfo {

View File

@ -737,7 +737,7 @@ char *dispatch_xml_encode(char *original, int len) {
return new;
}
void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
void dispatch_stream_id(WS_CONNINFO *pwsc, int session, char *id) {
MP3FILE *pmp3;
FILE *file_ptr;
int file_fd;
@ -763,7 +763,7 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
pmp3=db_fetch_item(NULL,item);
if(!pmp3) {
DPRINTF(E_LOG,L_DAAP|L_WS|L_DB,"Could not find requested item %lu\n",item);
config_set_status(pwsc,pqi->session_id,NULL);
config_set_status(pwsc,session,NULL);
ws_returnerror(pwsc,404,"File Not Found");
} else if (server_side_convert(pmp3->codectype)) {
/************************
@ -820,12 +820,12 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
ws_emitheaders(pwsc);
config_set_status(pwsc,pqi->session_id,
config_set_status(pwsc,session,
"Transcoding '%s' (id %d)",
pmp3->title,pmp3->id);
DPRINTF(E_LOG,L_WS,
"Session %d: Streaming file '%s' to %s (offset %ld)\n",
pqi->session_id,pmp3->fname, pwsc->hostname,(long)offset);
session,pmp3->fname, pwsc->hostname,(long)offset);
if(!offset)
config.stats.songs_served++; /* FIXME: remove stat races */
@ -840,7 +840,7 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
}
server_side_convert_close(file_ptr);
config_set_status(pwsc,pqi->session_id,NULL);
config_set_status(pwsc,session,NULL);
db_dispose_item(pmp3);
}
} else {
@ -853,7 +853,7 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
DPRINTF(E_WARN,L_WS,"Thread %d: Error opening %s: %s\n",
pwsc->threadno,pmp3->path,strerror(errno));
ws_returnerror(pwsc,404,"Not found");
config_set_status(pwsc,pqi->session_id,NULL);
config_set_status(pwsc,session,NULL);
db_dispose_item(pmp3);
} else {
real_len=lseek(file_fd,0,SEEK_END);
@ -903,10 +903,10 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
ws_emitheaders(pwsc);
config_set_status(pwsc,pqi->session_id,"Streaming '%s' (id %d)",
config_set_status(pwsc,session,"Streaming '%s' (id %d)",
pmp3->title, pmp3->id);
DPRINTF(E_LOG,L_WS,"Session %d: Streaming file '%s' to %s (offset %d)\n",
pqi->session_id,pmp3->fname, pwsc->hostname,(long)offset);
session,pmp3->fname, pwsc->hostname,(long)offset);
if(!offset)
config.stats.songs_served++; /* FIXME: remove stat races */
@ -940,7 +940,7 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
}
}
config_set_status(pwsc,pqi->session_id,NULL);
config_set_status(pwsc,session,NULL);
r_close(file_fd);
db_dispose_item(pmp3);
}
@ -950,7 +950,7 @@ void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
}
void dispatch_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
dispatch_stream_id(pwsc, pqi, pqi->uri_sections[3]);
dispatch_stream_id(pwsc, pqi->session_id, pqi->uri_sections[3]);
}
/**

View File

@ -9,6 +9,6 @@
extern void daap_handler(WS_CONNINFO *pwsc);
extern int daap_auth(WS_CONNINFO *pwsc, char *username, char *password);
extern void dispatch_stream_id(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id);
extern void dispatch_stream_id(WS_CONNINFO *pwsc, int session, char *id);
#endif

View File

@ -43,6 +43,7 @@
#include "smart-parser.h"
#include "xml-rpc.h"
#include "webserver.h"
#include "ff-plugins.h"
typedef struct tag_pluginentry {
void *phandle;
@ -87,12 +88,13 @@ void pi_log(int, char *, ...);
/* db helpers */
int pi_db_count(void);
int pi_db_enum_start(char **pe, DBQUERYINFO *pinfo);
int pi_db_enum_fetch_row(char **pe, char ***row, DBQUERYINFO *pinfo);
int pi_db_enum_start(char **pe, DB_QUERY *pinfo);
int pi_db_enum_fetch_row(char **pe, char ***row, DB_QUERY *pinfo);
int pi_db_enum_end(char **pe);
void pi_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id);
void pi_db_enum_dispose(char **pe, DB_QUERY *pinfo);
void pi_stream(WS_CONNINFO *pwsc, char *id);
void pi_conf_dispose_string(char *str);
int pi_sp_parse(PARSETREE tree, char *term);
PLUGIN_INPUT_FN pi = {
pi_ws_uri,
@ -114,13 +116,9 @@ PLUGIN_INPUT_FN pi = {
pi_db_enum_start,
pi_db_enum_fetch_row,
pi_db_enum_end,
pi_db_enum_dispose,
pi_stream,
sp_init,
pi_sp_parse,
sp_dispose,
sp_get_error,
conf_alloc_string,
pi_conf_dispose_string
};
@ -577,25 +575,99 @@ int pi_db_count(void) {
return count;
}
int pi_db_enum_start(char **pe, DBQUERYINFO *pinfo) {
return db_enum_start(pe, pinfo);
int pi_db_enum_start(char **pe, DB_QUERY *pinfo) {
DBQUERYINFO *pqi;
int result;
pqi = (DBQUERYINFO*)malloc(sizeof(DBQUERYINFO));
if(!pqi) {
if(pe) *pe = strdup("Malloc error");
return DB_E_MALLOC;
}
memset(pqi,0,sizeof(DBQUERYINFO));
pinfo->private = (void*)pqi;
if(pinfo->filter) {
pqi->pt = sp_init();
if(!sp_parse(pqi->pt,pinfo->filter,pinfo->filter_type)) {
DPRINTF(E_LOG,L_PLUG,"Ignoring bad query (%s): %s\n",
pinfo->filter,sp_get_error(pqi->pt));
sp_dispose(pqi->pt);
pqi->pt = NULL;
}
}
if((pinfo->limit) || (pinfo->offset)) {
pqi->index_low = pinfo->offset;
pqi->index_high = pinfo->offset + pinfo->limit - 1;
if(pqi->index_high < pqi->index_low)
pqi->index_high = 9999999;
pqi->index_type = indexTypeSub;
} else {
pqi->index_type = indexTypeNone;
}
pqi->want_count = 1;
switch(pinfo->query_type) {
case QUERY_TYPE_PLAYLISTS:
pqi->query_type = queryTypePlaylists;
break;
case QUERY_TYPE_DISTINCT:
if((strcmp(pinfo->distinct_field,"artist") == 0)) {
pqi->query_type = queryTypeBrowseArtists;
} else if((strcmp(pinfo->distinct_field,"genre") == 0)) {
pqi->query_type = queryTypeBrowseGenres;
} else if((strcmp(pinfo->distinct_field,"album") == 0)) {
pqi->query_type = queryTypeBrowseAlbums;
} else if((strcmp(pinfo->distinct_field,"composer") == 0)) {
pqi->query_type = queryTypeBrowseComposers;
} else {
if(pe) *pe = strdup("Unsupported browse type");
sp_dispose(pqi->pt);
pqi->pt = NULL;
return -1; /* not really a db error for this */
}
break;
case QUERY_TYPE_ITEMS:
default:
pqi->query_type = queryTypePlaylistItems;
break;
}
pqi->playlist_id = pinfo->playlist_id;
result = db_enum_start(pe, pqi);
pinfo->totalcount = pqi->specifiedtotalcount;
}
int pi_db_enum_fetch_row(char **pe, char ***row, DBQUERYINFO *pinfo) {
return db_enum_fetch_row(pe, (PACKED_MP3FILE*)row, pinfo);
int pi_db_enum_fetch_row(char **pe, char ***row, DB_QUERY *pinfo) {
return db_enum_fetch_row(pe, (PACKED_MP3FILE*)row,
(DBQUERYINFO*)pinfo->private);
}
int pi_db_enum_end(char **pe) {
return db_enum_end(pe);
}
void pi_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, char *id) {
dispatch_stream_id(pwsc, pqi,id);
void pi_stream(WS_CONNINFO *pwsc, char *id) {
dispatch_stream_id(pwsc, 0, id);
return;
}
int pi_sp_parse(PARSETREE tree, char *term) {
return sp_parse(tree, term, 0);
void pi_db_enum_dispose(char **pe, DB_QUERY *pinfo) {
DBQUERYINFO *pqi;
if(!pinfo)
return;
if(pinfo->private) {
pqi = (DBQUERYINFO *)pinfo->private;
if(pqi->pt) {
sp_dispose(pqi->pt);
pqi->pt = NULL;
}
}
}
void pi_conf_dispose_string(char *str) {

View File

@ -37,87 +37,10 @@ extern int plugin_auth_handle(WS_CONNINFO *pwsc, char *username, char *pw);
extern int plugin_rend_register(char *name, int port, char *iface, char *txt);
extern void plugin_event_dispatch(int event_id, int intval, void *vp, int len);
#define PLUGIN_E_SUCCESS 0
#define PLUGIN_E_NOLOAD 1
#define PLUGIN_E_BADFUNCS 2
#define PLUGIN_OUTPUT 1
#define PLUGIN_SCANNER 2
#define PLUGIN_DATABASE 4
#define PLUGIN_EVENT 8
#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
#define PLUGIN_VERSION 1
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;
/* version 1 plugin info */
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; /* for output plugins */
PLUGIN_OUTPUT_FN *output_fns;
PLUGIN_EVENT_FN *event_fns;
void *pi; /* exported functions */
PLUGIN_REND_INFO *rend_info;
} PLUGIN_INFO;
/* version 1 plugin imports */
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 *section, char *key, char *dflt);
void (*conf_dispose_string)(char *str);
} PLUGIN_INPUT_FN;
#include "ff-plugins.h"
#endif /* _PLUGIN_H_ */

View File

@ -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..

View File

@ -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_ */

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -717,9 +717,9 @@ int sp_parse(PARSETREE tree, char *term, int type) {
tree->tree = sp_parse_phrase(tree);
if(tree->tree) {
DPRINTF(E_SPAM,L_PARSE,"Parsed successfully\n");
DPRINTF(E_SPAM,L_PARSE,"Parsed successfully (type %d)\n",type);
} else {
DPRINTF(E_SPAM,L_PARSE,"Parsing error\n");
DPRINTF(E_SPAM,L_PARSE,"Parsing error (type %d)\n",type);
}
return tree->tree ? 1 : 0;