remove function backpointers for dll plugins
This commit is contained in:
parent
366ae9913c
commit
0429230d00
|
@ -23,6 +23,8 @@ AC_CHECK_HEADERS([dirent.h])
|
||||||
AC_CHECK_FUNCS(strptime)
|
AC_CHECK_FUNCS(strptime)
|
||||||
AC_CHECK_FUNCS(strtok_r)
|
AC_CHECK_FUNCS(strtok_r)
|
||||||
AC_CHECK_FUNCS(timegm)
|
AC_CHECK_FUNCS(timegm)
|
||||||
|
AC_CHECK_FUNCS(va_copy)
|
||||||
|
AC_CHECK_FUNCS(__va_copy)
|
||||||
|
|
||||||
AM_CONDITIONAL(COND_REND_OSX,false)
|
AM_CONDITIONAL(COND_REND_OSX,false)
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ wavstreamer_SOURCES = wavstreamer.c
|
||||||
mt_daapd_SOURCES = main.c daapd.h rend.h webserver.c \
|
mt_daapd_SOURCES = main.c daapd.h rend.h webserver.c \
|
||||||
webserver.h configfile.c configfile.h err.c err.h restart.c restart.h \
|
webserver.h configfile.c configfile.h err.c err.h restart.c restart.h \
|
||||||
mp3-scanner.h mp3-scanner.c rend-unix.h \
|
mp3-scanner.h mp3-scanner.c rend-unix.h \
|
||||||
db-generic.c db-generic.h \
|
db-generic.c db-generic.h ff-plugins.c ff-plugins.h \
|
||||||
rxml.c rxml.h redblack.c redblack.h scan-mp3.c scan-mp4.c scan-aif.c \
|
rxml.c rxml.h redblack.c redblack.h scan-mp3.c scan-mp4.c scan-aif.c \
|
||||||
scan-xml.c scan-wma.c scan-aac.c scan-aac.h scan-wav.c scan-url.c \
|
scan-xml.c scan-wma.c scan-aac.c scan-aac.h scan-wav.c scan-url.c \
|
||||||
smart-parser.c smart-parser.h xml-rpc.c xml-rpc.h \
|
smart-parser.c smart-parser.h xml-rpc.c xml-rpc.h \
|
||||||
|
|
14
src/daapd.h
14
src/daapd.h
|
@ -39,6 +39,20 @@
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# ifndef ASSERT
|
||||||
|
# define ASSERT(f) \
|
||||||
|
if(f) \
|
||||||
|
{} \
|
||||||
|
else \
|
||||||
|
err_log(0,"Assert error in %s, line %d\n",__FILE__,__LINE__)
|
||||||
|
# endif /* ndef ASSERT */
|
||||||
|
#else /* ndef DEBUG */
|
||||||
|
# ifndef ASSERT
|
||||||
|
# define ASSERT(f)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "memdebug.h" /* redefine free/malloc/etc */
|
#include "memdebug.h" /* redefine free/malloc/etc */
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
|
@ -24,6 +24,13 @@
|
||||||
|
|
||||||
#include "ff-dbstruct.h"
|
#include "ff-dbstruct.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
# define EXPORT __declspec(dllimport)
|
||||||
|
#else
|
||||||
|
# define EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef TRUE
|
#ifndef TRUE
|
||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
#define FALSE 0
|
#define FALSE 0
|
||||||
|
@ -122,51 +129,49 @@ typedef struct tag_db_query {
|
||||||
void *priv;
|
void *priv;
|
||||||
} DB_QUERY;
|
} DB_QUERY;
|
||||||
|
|
||||||
|
/* webserver functions */
|
||||||
|
extern EXPORT EXPORT char *pi_ws_uri(struct tag_ws_conninfo *);
|
||||||
|
extern EXPORT EXPORT void pi_ws_will_close(struct tag_ws_conninfo *);
|
||||||
|
extern EXPORT EXPORT int pi_ws_returnerror(struct tag_ws_conninfo *, int, char *);
|
||||||
|
extern EXPORT char *pi_ws_getvar(struct tag_ws_conninfo *, char *);
|
||||||
|
extern EXPORT int pi_ws_writefd(struct tag_ws_conninfo *, char *, ...);
|
||||||
|
extern EXPORT int pi_ws_addresponseheader(struct tag_ws_conninfo *, char *, char *, ...);
|
||||||
|
extern EXPORT void pi_ws_emitheaders(struct tag_ws_conninfo *);
|
||||||
|
extern EXPORT char *pi_ws_getrequestheader(struct tag_ws_conninfo *, char *);
|
||||||
|
extern EXPORT int pi_ws_writebinary(struct tag_ws_conninfo *, char *, int);
|
||||||
|
extern EXPORT char *pi_ws_gethostname(struct tag_ws_conninfo *);
|
||||||
|
extern EXPORT int pi_ws_matchesrole(struct tag_ws_conninfo *, char *, char *, char *);
|
||||||
|
|
||||||
/* version 1 plugin imports */
|
/* misc helpers */
|
||||||
typedef struct tag_plugin_input_fn {
|
extern EXPORT char *pi_server_ver(void);
|
||||||
/* webserver helpers */
|
extern EXPORT int pi_server_name(char *, int *);
|
||||||
char* (*ws_uri)(struct tag_ws_conninfo *);
|
extern EXPORT void pi_log(int, char *, ...);
|
||||||
void (*ws_will_close)(struct tag_ws_conninfo *);
|
extern EXPORT int pi_should_transcode(struct tag_ws_conninfo *, char *);
|
||||||
int (*ws_returnerror)(struct tag_ws_conninfo *, int, char *);
|
|
||||||
char* (*ws_getvar)(struct tag_ws_conninfo *, char *);
|
|
||||||
int (*ws_writefd)(struct tag_ws_conninfo *, char *, ...);
|
|
||||||
int (*ws_addresponseheader)(struct tag_ws_conninfo *, char *, char *, ...);
|
|
||||||
void (*ws_emitheaders)(struct tag_ws_conninfo *);
|
|
||||||
char* (*ws_getrequestheader)(struct tag_ws_conninfo *, char *);
|
|
||||||
int (*ws_writebinary)(struct tag_ws_conninfo *, char *, int);
|
|
||||||
char* (*ws_gethostname)(struct tag_ws_conninfo *);
|
|
||||||
int (*ws_matchesrole)(struct tag_ws_conninfo *, char *, char *, char *);
|
|
||||||
|
|
||||||
/* misc helpers */
|
/* db functions */
|
||||||
char* (*server_ver)(void);
|
extern EXPORT int pi_db_count(void);
|
||||||
int (*server_name)(char *, int *);
|
extern EXPORT int pi_db_enum_start(char **, DB_QUERY *);
|
||||||
void (*log)(int, char *, ...);
|
extern EXPORT int pi_db_enum_fetch_row(char **, char ***, DB_QUERY *);
|
||||||
int (*should_transcode)(struct tag_ws_conninfo *, char *);
|
extern EXPORT int pi_db_enum_end(char **);
|
||||||
|
extern EXPORT int pi_db_enum_restart(char **, DB_QUERY *);
|
||||||
|
extern EXPORT void pi_db_enum_dispose(char **, DB_QUERY*);
|
||||||
|
extern EXPORT void pi_stream(struct tag_ws_conninfo *, char *);
|
||||||
|
|
||||||
int (*db_count)(void);
|
extern EXPORT int pi_db_add_playlist(char **pe, char *name, int type, char *clause, char *path, int index, int *playlistid);
|
||||||
int (*db_enum_start)(char **, DB_QUERY *);
|
extern EXPORT int pi_db_add_playlist_item(char **pe, int playlistid, int songid);
|
||||||
int (*db_enum_fetch_row)(char **, char ***, DB_QUERY *);
|
extern EXPORT int pi_db_edit_playlist(char **pe, int id, char *name, char *clause);
|
||||||
int (*db_enum_end)(char **);
|
extern EXPORT int pi_db_delete_playlist(char **pe, int playlistid);
|
||||||
int (*db_enum_restart)(char **, DB_QUERY *);
|
extern EXPORT int pi_db_delete_playlist_item(char **pe, int playlistid, int songid);
|
||||||
void (*db_enum_dispose)(char **, DB_QUERY*);
|
extern EXPORT int pi_db_revision(void);
|
||||||
void (*stream)(struct tag_ws_conninfo *, char *);
|
extern EXPORT int pi_db_count_items(int what);
|
||||||
|
extern EXPORT int pi_db_wait_update(struct tag_ws_conninfo *);
|
||||||
|
|
||||||
int (*db_add_playlist)(char **pe, char *name, int type, char *clause, char *path, int index, int *playlistid);
|
/* config/misc functions */
|
||||||
int (*db_add_playlist_item)(char **pe, int playlistid, int songid);
|
extern EXPORT char *pi_conf_alloc_string(char *section, char *key, char *dflt);
|
||||||
int (*db_edit_playlist)(char **pe, int id, char *name, char *clause);
|
extern EXPORT void pi_conf_dispose_string(char *str);
|
||||||
int (*db_delete_playlist)(char **pe, int playlistid);
|
extern EXPORT int pi_conf_get_int(char *section, char *key, int dflt);
|
||||||
int (*db_delete_playlist_item)(char **pe, int playlistid, int songid);
|
|
||||||
int (*db_revision)(void);
|
|
||||||
int (*db_count_items)(int what);
|
|
||||||
int (*db_wait_update)(struct tag_ws_conninfo *);
|
|
||||||
|
|
||||||
char *(*conf_alloc_string)(char *section, char *key, char *dflt);
|
extern EXPORT void pi_config_set_status(struct tag_ws_conninfo *pwsc, int session, char *fmt, ...);
|
||||||
void (*conf_dispose_string)(char *str);
|
|
||||||
int (*conf_get_int)(char *section, char *key, int dflt);
|
|
||||||
|
|
||||||
void (*config_set_status)(struct tag_ws_conninfo *pwsc, int session, char *fmt, ...);
|
|
||||||
} PLUGIN_INPUT_FN;
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _FF_PLUGINS_ */
|
#endif /* _FF_PLUGINS_ */
|
||||||
|
|
657
src/plugin.c
657
src/plugin.c
|
@ -92,74 +92,6 @@ void _plugin_free(int *pi);
|
||||||
void _plugin_recalc_codecs(void);
|
void _plugin_recalc_codecs(void);
|
||||||
int _plugin_ssc_transcode(WS_CONNINFO *pwsc, MP3FILE *pmp3, int offset, int headers);
|
int _plugin_ssc_transcode(WS_CONNINFO *pwsc, MP3FILE *pmp3, int offset, int headers);
|
||||||
|
|
||||||
/* webserver helpers */
|
|
||||||
void pi_ws_will_close(WS_CONNINFO *pwsc);
|
|
||||||
int pi_ws_fd(WS_CONNINFO *pwsc);
|
|
||||||
char *pi_ws_gethostname(WS_CONNINFO *pwsc);
|
|
||||||
|
|
||||||
/* misc helpers */
|
|
||||||
char *pi_server_ver(void);
|
|
||||||
int pi_server_name(char *, int *);
|
|
||||||
void pi_log(int, char *, ...);
|
|
||||||
|
|
||||||
/* db helpers */
|
|
||||||
int pi_db_count(void);
|
|
||||||
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);
|
|
||||||
int pi_db_enum_restart(char **pe, DB_QUERY *pinfo);
|
|
||||||
void pi_db_enum_dispose(char **pe, DB_QUERY *pinfo);
|
|
||||||
void pi_stream(WS_CONNINFO *pwsc, char *id);
|
|
||||||
int pi_db_count_items(int what);
|
|
||||||
int pi_db_wait_update(WS_CONNINFO *pwsc);
|
|
||||||
void pi_conf_dispose_string(char *str);
|
|
||||||
|
|
||||||
/* transcode helpers */
|
|
||||||
int pi_ssc_should_transcode(WS_CONNINFO *pwsc, char *codec);
|
|
||||||
|
|
||||||
PLUGIN_INPUT_FN pi = {
|
|
||||||
ws_uri,
|
|
||||||
pi_ws_will_close,
|
|
||||||
ws_returnerror,
|
|
||||||
ws_getvar,
|
|
||||||
ws_writefd,
|
|
||||||
ws_addresponseheader,
|
|
||||||
ws_emitheaders,
|
|
||||||
ws_getrequestheader,
|
|
||||||
ws_writebinary,
|
|
||||||
pi_ws_gethostname,
|
|
||||||
config_matches_role,
|
|
||||||
|
|
||||||
pi_server_ver,
|
|
||||||
pi_server_name,
|
|
||||||
pi_log,
|
|
||||||
pi_ssc_should_transcode,
|
|
||||||
|
|
||||||
pi_db_count,
|
|
||||||
pi_db_enum_start,
|
|
||||||
pi_db_enum_fetch_row,
|
|
||||||
pi_db_enum_end,
|
|
||||||
pi_db_enum_restart,
|
|
||||||
pi_db_enum_dispose,
|
|
||||||
pi_stream,
|
|
||||||
|
|
||||||
db_add_playlist,
|
|
||||||
db_add_playlist_item,
|
|
||||||
db_edit_playlist,
|
|
||||||
db_delete_playlist,
|
|
||||||
db_delete_playlist_item,
|
|
||||||
db_revision,
|
|
||||||
pi_db_count_items,
|
|
||||||
pi_db_wait_update,
|
|
||||||
|
|
||||||
conf_alloc_string,
|
|
||||||
pi_conf_dispose_string,
|
|
||||||
conf_get_int,
|
|
||||||
|
|
||||||
config_set_status
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initialize stuff for plugins
|
* initialize stuff for plugins
|
||||||
*
|
*
|
||||||
|
@ -294,7 +226,7 @@ void *plugin_enum(void *where) {
|
||||||
int plugin_load(char **pe, char *path) {
|
int plugin_load(char **pe, char *path) {
|
||||||
PLUGIN_ENTRY *ppi;
|
PLUGIN_ENTRY *ppi;
|
||||||
void *phandle;
|
void *phandle;
|
||||||
PLUGIN_INFO *(*info_func)(PLUGIN_INPUT_FN *);
|
PLUGIN_INFO *(*info_func)(void);
|
||||||
PLUGIN_INFO *pinfo;
|
PLUGIN_INFO *pinfo;
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_PLUG,"Attempting to load plugin %s\n",path);
|
DPRINTF(E_DBG,L_PLUG,"Attempting to load plugin %s\n",path);
|
||||||
|
@ -310,7 +242,7 @@ int plugin_load(char **pe, char *path) {
|
||||||
|
|
||||||
ppi->phandle = phandle;
|
ppi->phandle = phandle;
|
||||||
|
|
||||||
info_func = (PLUGIN_INFO*(*)(PLUGIN_INPUT_FN*)) os_libfunc(pe, phandle,"plugin_info");
|
info_func = (PLUGIN_INFO*(*)(void)) os_libfunc(pe, phandle,"plugin_info");
|
||||||
if(info_func == NULL) {
|
if(info_func == NULL) {
|
||||||
DPRINTF(E_INF,L_PLUG,"Couldn't get info_func for %s\n",path);
|
DPRINTF(E_INF,L_PLUG,"Couldn't get info_func for %s\n",path);
|
||||||
os_unload(phandle);
|
os_unload(phandle);
|
||||||
|
@ -318,7 +250,7 @@ int plugin_load(char **pe, char *path) {
|
||||||
return PLUGIN_E_BADFUNCS;
|
return PLUGIN_E_BADFUNCS;
|
||||||
}
|
}
|
||||||
|
|
||||||
pinfo = info_func(&pi);
|
pinfo = info_func();
|
||||||
ppi->pinfo = pinfo;
|
ppi->pinfo = pinfo;
|
||||||
|
|
||||||
if(!pinfo) {
|
if(!pinfo) {
|
||||||
|
@ -486,25 +418,137 @@ void plugin_event_dispatch(int event_id, int intval, void *vp, int len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check to see if we can transcode
|
* stupid helper to copy transcode stream to the fd
|
||||||
*
|
|
||||||
* @param codec the codec we are trying to serve
|
|
||||||
* @returns TRUE if we can transcode, FALSE otherwise
|
|
||||||
*/
|
*/
|
||||||
int pi_ssc_should_transcode(WS_CONNINFO *pwsc, char *codec) {
|
int __plugin_ssc_copy(WS_CONNINFO *pwsc, PLUGIN_TRANSCODE_FN *pfn,
|
||||||
|
void *vp,int offset) {
|
||||||
|
int bytes_read;
|
||||||
|
int bytes_to_read;
|
||||||
|
int total_bytes_read = 0;
|
||||||
|
char buffer[1024];
|
||||||
|
|
||||||
|
/* first, skip past the offset */
|
||||||
|
while(offset) {
|
||||||
|
bytes_to_read = sizeof(buffer);
|
||||||
|
if(bytes_to_read > offset)
|
||||||
|
bytes_to_read = offset;
|
||||||
|
|
||||||
|
bytes_read = pfn->ssc_read(vp,buffer,bytes_to_read);
|
||||||
|
if(bytes_read <= 0)
|
||||||
|
return bytes_read;
|
||||||
|
|
||||||
|
offset -= bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
while((bytes_read=pfn->ssc_read(vp,buffer,sizeof(buffer))) > 0) {
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
if(ws_writebinary(pwsc,buffer,bytes_read) != bytes_read) {
|
||||||
|
return total_bytes_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if(bytes_read < 0) {
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return total_bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do the transcode, emitting the headers, content type,
|
||||||
|
* and shoving the file down the wire
|
||||||
|
*
|
||||||
|
* @param pwsc connection to transcode to
|
||||||
|
* @param file file to transcode
|
||||||
|
* @param codec source codec
|
||||||
|
* @param duration time in ms
|
||||||
|
* @returns bytes transferred, or -1 on error
|
||||||
|
*/
|
||||||
|
int plugin_ssc_transcode(WS_CONNINFO *pwsc, MP3FILE *pmp3, int offset, int headers) {
|
||||||
|
PLUGIN_ENTRY *ppi, *ptc=NULL;
|
||||||
|
PLUGIN_TRANSCODE_FN *pfn = NULL;
|
||||||
|
void *vp_ssc;
|
||||||
|
int post_error = 1;
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
|
/* first, find the plugin that will do the conversion */
|
||||||
|
ppi = _plugin_list.next;
|
||||||
|
while((ppi) && (!pfn)) {
|
||||||
|
if(ppi->pinfo->type & PLUGIN_TRANSCODE) {
|
||||||
|
if(strstr(ppi->pinfo->codeclist,pmp3->codectype)) {
|
||||||
|
ptc = ppi;
|
||||||
|
pfn = ppi->pinfo->transcode_fns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ppi = ppi->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pfn) {
|
||||||
|
DPRINTF(E_DBG,L_PLUG,"Transcoding %s with %s\n",pmp3->path,
|
||||||
|
ptc->pinfo->server);
|
||||||
|
|
||||||
|
vp_ssc = pfn->ssc_init();
|
||||||
|
if(vp_ssc) {
|
||||||
|
if(pfn->ssc_open(vp_ssc,pmp3)) {
|
||||||
|
/* start reading and throwing */
|
||||||
|
if(headers) {
|
||||||
|
ws_addresponseheader(pwsc,"Content-Type","audio/wav");
|
||||||
|
ws_addresponseheader(pwsc,"Connection","Close");
|
||||||
|
if(!offset) {
|
||||||
|
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
||||||
|
} else {
|
||||||
|
ws_addresponseheader(pwsc,"Content-Range",
|
||||||
|
"bytes %ld-*/*",
|
||||||
|
(long)offset);
|
||||||
|
ws_writefd(pwsc,"HTTP/1.1 206 Partial Content\r\n");
|
||||||
|
}
|
||||||
|
ws_emitheaders(pwsc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start reading/writing */
|
||||||
|
result = __plugin_ssc_copy(pwsc,pfn,vp_ssc,offset);
|
||||||
|
post_error = 0;
|
||||||
|
pfn->ssc_close(vp_ssc);
|
||||||
|
} else {
|
||||||
|
DPRINTF(E_LOG,L_PLUG,"Error opening %s for ssc: %s\n",
|
||||||
|
pmp3->path,pfn->ssc_error(vp_ssc));
|
||||||
|
}
|
||||||
|
pfn->ssc_deinit(vp_ssc);
|
||||||
|
} else {
|
||||||
|
DPRINTF(E_LOG,L_PLUG,"Error initializing transcoder: %s\n",
|
||||||
|
ptc->pinfo->server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(post_error) {
|
||||||
|
pwsc->error = EPERM; /* ?? */
|
||||||
|
ws_returnerror(pwsc,500,"Internal error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int plugin_ssc_should_transcode(WS_CONNINFO *pwsc, char *codec) {
|
||||||
int result;
|
int result;
|
||||||
char *native_codecs=NULL;
|
char *native_codecs=NULL;
|
||||||
char *user_agent=NULL;
|
char *user_agent=NULL;
|
||||||
char *never_transcode = NULL;
|
char *never_transcode = NULL;
|
||||||
char *always_transcode = NULL;
|
char *always_transcode = NULL;
|
||||||
|
|
||||||
|
ASSERT((pwsc) && (codec));
|
||||||
|
|
||||||
|
if(!pwsc)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if(!codec) {
|
if(!codec) {
|
||||||
DPRINTF(E_LOG,L_PLUG,"testing transcode on null codec?\n");
|
DPRINTF(E_LOG,L_PLUG,"testing transcode on null codec?\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
never_transcode = conf_alloc_string("general","never_transcode",NULL);
|
never_transcode = conf_alloc_string("general","never_transcode",NULL);
|
||||||
if(never_transcode) {
|
if(never_transcode) {
|
||||||
if(strstr(never_transcode,codec)) {
|
if(strstr(never_transcode,codec)) {
|
||||||
|
@ -558,462 +602,3 @@ int pi_ssc_should_transcode(WS_CONNINFO *pwsc, char *codec) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* stupid helper to copy transcode stream to the fd
|
|
||||||
*/
|
|
||||||
int _plugin_ssc_copy(WS_CONNINFO *pwsc, PLUGIN_TRANSCODE_FN *pfn,
|
|
||||||
void *vp,int offset) {
|
|
||||||
int bytes_read;
|
|
||||||
int bytes_to_read;
|
|
||||||
int total_bytes_read = 0;
|
|
||||||
char buffer[1024];
|
|
||||||
|
|
||||||
/* first, skip past the offset */
|
|
||||||
while(offset) {
|
|
||||||
bytes_to_read = sizeof(buffer);
|
|
||||||
if(bytes_to_read > offset)
|
|
||||||
bytes_to_read = offset;
|
|
||||||
|
|
||||||
bytes_read = pfn->ssc_read(vp,buffer,bytes_to_read);
|
|
||||||
if(bytes_read <= 0)
|
|
||||||
return bytes_read;
|
|
||||||
|
|
||||||
offset -= bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
while((bytes_read=pfn->ssc_read(vp,buffer,sizeof(buffer))) > 0) {
|
|
||||||
total_bytes_read += bytes_read;
|
|
||||||
if(ws_writebinary(pwsc,buffer,bytes_read) != bytes_read) {
|
|
||||||
return total_bytes_read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if(bytes_read < 0) {
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return total_bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* do the transcode, emitting the headers, content type,
|
|
||||||
* and shoving the file down the wire
|
|
||||||
*
|
|
||||||
* @param pwsc connection to transcode to
|
|
||||||
* @param file file to transcode
|
|
||||||
* @param codec source codec
|
|
||||||
* @param duration time in ms
|
|
||||||
* @returns bytes transferred, or -1 on error
|
|
||||||
*/
|
|
||||||
int _plugin_ssc_transcode(WS_CONNINFO *pwsc, MP3FILE *pmp3, int offset, int headers) {
|
|
||||||
PLUGIN_ENTRY *ppi, *ptc=NULL;
|
|
||||||
PLUGIN_TRANSCODE_FN *pfn = NULL;
|
|
||||||
void *vp_ssc;
|
|
||||||
int post_error = 1;
|
|
||||||
int result = -1;
|
|
||||||
|
|
||||||
/* first, find the plugin that will do the conversion */
|
|
||||||
ppi = _plugin_list.next;
|
|
||||||
while((ppi) && (!pfn)) {
|
|
||||||
if(ppi->pinfo->type & PLUGIN_TRANSCODE) {
|
|
||||||
if(strstr(ppi->pinfo->codeclist,pmp3->codectype)) {
|
|
||||||
ptc = ppi;
|
|
||||||
pfn = ppi->pinfo->transcode_fns;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ppi = ppi->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pfn) {
|
|
||||||
DPRINTF(E_DBG,L_PLUG,"Transcoding %s with %s\n",pmp3->path,
|
|
||||||
ptc->pinfo->server);
|
|
||||||
|
|
||||||
vp_ssc = pfn->ssc_init();
|
|
||||||
if(vp_ssc) {
|
|
||||||
if(pfn->ssc_open(vp_ssc,pmp3)) {
|
|
||||||
/* start reading and throwing */
|
|
||||||
if(headers) {
|
|
||||||
ws_addresponseheader(pwsc,"Content-Type","audio/wav");
|
|
||||||
ws_addresponseheader(pwsc,"Connection","Close");
|
|
||||||
if(!offset) {
|
|
||||||
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
|
||||||
} else {
|
|
||||||
ws_addresponseheader(pwsc,"Content-Range",
|
|
||||||
"bytes %ld-*/*",
|
|
||||||
(long)offset);
|
|
||||||
ws_writefd(pwsc,"HTTP/1.1 206 Partial Content\r\n");
|
|
||||||
}
|
|
||||||
ws_emitheaders(pwsc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* start reading/writing */
|
|
||||||
result = _plugin_ssc_copy(pwsc,pfn,vp_ssc,offset);
|
|
||||||
post_error = 0;
|
|
||||||
pfn->ssc_close(vp_ssc);
|
|
||||||
} else {
|
|
||||||
DPRINTF(E_LOG,L_PLUG,"Error opening %s for ssc: %s\n",
|
|
||||||
pmp3->path,pfn->ssc_error(vp_ssc));
|
|
||||||
}
|
|
||||||
pfn->ssc_deinit(vp_ssc);
|
|
||||||
} else {
|
|
||||||
DPRINTF(E_LOG,L_PLUG,"Error initializing transcoder: %s\n",
|
|
||||||
ptc->pinfo->server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(post_error) {
|
|
||||||
pwsc->error = EPERM; /* ?? */
|
|
||||||
ws_returnerror(pwsc,500,"Internal error");
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* plugin wrappers for utility functions & stuff
|
|
||||||
*
|
|
||||||
* these functions need to be wrapped so we can maintain a stable
|
|
||||||
* interface to older plugins even if we get newer functions or apis
|
|
||||||
* upstream... it's a binary compatibility layer.
|
|
||||||
*/
|
|
||||||
void pi_ws_will_close(WS_CONNINFO *pwsc) {
|
|
||||||
ws_should_close(pwsc,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *pi_ws_gethostname(WS_CONNINFO *pwsc) {
|
|
||||||
return ws_hostname(pwsc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pi_log(int level, char *fmt, ...) {
|
|
||||||
char buf[256];
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap,fmt);
|
|
||||||
vsnprintf(buf,sizeof(buf),fmt,ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
DPRINTF(level,L_PLUG,"%s",buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *pi_server_ver(void) {
|
|
||||||
return VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pi_server_name(char *name, int *len) {
|
|
||||||
char *servername;
|
|
||||||
|
|
||||||
servername = conf_get_servername();
|
|
||||||
if((servername) && (strlen(servername) < (size_t)len)) {
|
|
||||||
strcpy(name,servername);
|
|
||||||
} else {
|
|
||||||
if((size_t)len > strlen("Firefly Media Server"))
|
|
||||||
strcpy(name,"Firefly Media Server");
|
|
||||||
}
|
|
||||||
|
|
||||||
free(servername);
|
|
||||||
return CONF_E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pi_db_count(void) {
|
|
||||||
int count;
|
|
||||||
db_get_song_count(NULL, &count);
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
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->priv = (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");
|
|
||||||
if(pqi->pt)
|
|
||||||
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;
|
|
||||||
pqi->correct_order = conf_get_int("scan","correct_order",1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pqi->playlist_id = pinfo->playlist_id;
|
|
||||||
result = db_enum_start(pe, pqi);
|
|
||||||
pinfo->totalcount = pqi->specifiedtotalcount;
|
|
||||||
|
|
||||||
return DB_E_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pi_db_enum_fetch_row(char **pe, char ***row, DB_QUERY *pinfo) {
|
|
||||||
return db_enum_fetch_row(pe, (PACKED_MP3FILE*)row,
|
|
||||||
(DBQUERYINFO*)pinfo->priv);
|
|
||||||
}
|
|
||||||
|
|
||||||
int pi_db_enum_end(char **pe) {
|
|
||||||
return db_enum_end(pe);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: error checking */
|
|
||||||
int pi_db_count_items(int what) {
|
|
||||||
int count=0;
|
|
||||||
|
|
||||||
switch(what) {
|
|
||||||
case COUNT_SONGS:
|
|
||||||
db_get_song_count(NULL,&count);
|
|
||||||
break;
|
|
||||||
case COUNT_PLAYLISTS:
|
|
||||||
db_get_playlist_count(NULL,&count);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int pi_db_enum_restart(char **pe, DB_QUERY *pinfo) {
|
|
||||||
DBQUERYINFO *pqi;
|
|
||||||
|
|
||||||
pqi = (DBQUERYINFO*)pinfo->priv;
|
|
||||||
return db_enum_reset(pe,pqi);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pi_db_enum_dispose(char **pe, DB_QUERY *pinfo) {
|
|
||||||
DBQUERYINFO *pqi;
|
|
||||||
|
|
||||||
if(!pinfo)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(pinfo->priv) {
|
|
||||||
pqi = (DBQUERYINFO *)pinfo->priv;
|
|
||||||
if(pqi->pt) {
|
|
||||||
sp_dispose(pqi->pt);
|
|
||||||
pqi->pt = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int pi_db_wait_update(WS_CONNINFO *pwsc) {
|
|
||||||
int clientver=1;
|
|
||||||
int lastver=0;
|
|
||||||
IO_WAITHANDLE hwait;
|
|
||||||
uint32_t ms;
|
|
||||||
|
|
||||||
if(ws_getvar(pwsc,"revision-number")) {
|
|
||||||
clientver=atoi(ws_getvar(pwsc,"revision-number"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* wait for db_version to be stable for 30 seconds */
|
|
||||||
hwait = io_wait_new();
|
|
||||||
if(!hwait)
|
|
||||||
DPRINTF(E_FATAL,L_MISC,"Can't get wait handle in db_wait_update\n");
|
|
||||||
|
|
||||||
/* FIXME: Move this up into webserver to avoid groping around
|
|
||||||
* inside reserved data structures */
|
|
||||||
|
|
||||||
io_wait_add(hwait,pwsc->hclient,IO_WAIT_ERROR);
|
|
||||||
|
|
||||||
while((clientver == db_revision()) ||
|
|
||||||
(lastver && (db_revision() != lastver))) {
|
|
||||||
lastver = db_revision();
|
|
||||||
|
|
||||||
if(!io_wait(hwait,&ms) && (ms != 0)) {
|
|
||||||
/* can't be ready for read, must be error */
|
|
||||||
DPRINTF(E_DBG,L_DAAP,"Update session stopped\n");
|
|
||||||
io_wait_dispose(hwait);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
io_wait_dispose(hwait);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pi_stream(WS_CONNINFO *pwsc, char *id) {
|
|
||||||
int session = 0;
|
|
||||||
MP3FILE *pmp3;
|
|
||||||
IOHANDLE hfile;
|
|
||||||
uint64_t bytes_copied=0;
|
|
||||||
uint64_t real_len;
|
|
||||||
uint64_t file_len;
|
|
||||||
uint64_t offset=0;
|
|
||||||
int item;
|
|
||||||
|
|
||||||
/* stream out the song */
|
|
||||||
ws_should_close(pwsc,1);
|
|
||||||
|
|
||||||
item = atoi(id);
|
|
||||||
|
|
||||||
if(ws_getrequestheader(pwsc,"range")) {
|
|
||||||
offset=(off_t)atol(ws_getrequestheader(pwsc,"range") + 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: error handling */
|
|
||||||
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,session,NULL);
|
|
||||||
ws_returnerror(pwsc,404,"File Not Found");
|
|
||||||
} else if (pi_ssc_should_transcode(pwsc,pmp3->codectype)) {
|
|
||||||
/************************
|
|
||||||
* Server side conversion
|
|
||||||
************************/
|
|
||||||
config_set_status(pwsc,session,
|
|
||||||
"Transcoding '%s' (id %d)",
|
|
||||||
pmp3->title,pmp3->id);
|
|
||||||
|
|
||||||
DPRINTF(E_WARN,L_WS,
|
|
||||||
"Session %d: Streaming file '%s' to %s (offset %ld)\n",
|
|
||||||
session,pmp3->fname, ws_hostname(pwsc),(long)offset);
|
|
||||||
|
|
||||||
/* estimate the real length of this thing */
|
|
||||||
bytes_copied = _plugin_ssc_transcode(pwsc,pmp3,offset,1);
|
|
||||||
if(bytes_copied != -1)
|
|
||||||
real_len = bytes_copied;
|
|
||||||
|
|
||||||
config_set_status(pwsc,session,NULL);
|
|
||||||
db_dispose_item(pmp3);
|
|
||||||
} else {
|
|
||||||
/**********************
|
|
||||||
* stream file normally
|
|
||||||
**********************/
|
|
||||||
if(pmp3->data_kind != 0) {
|
|
||||||
ws_returnerror(pwsc,500,"Can't stream radio station");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hfile = io_new();
|
|
||||||
if(!hfile)
|
|
||||||
DPRINTF(E_FATAL,L_WS,"Cannot allocate file handle\n");
|
|
||||||
|
|
||||||
if(!io_open(hfile,"file://%U",pmp3->path)) {
|
|
||||||
/* FIXME: ws_set_errstr */
|
|
||||||
ws_set_err(pwsc,E_WS_NATIVE);
|
|
||||||
DPRINTF(E_WARN,L_WS,"Thread %d: Error opening %s: %s\n",
|
|
||||||
ws_threadno(pwsc),pmp3->path,io_errstr(hfile));
|
|
||||||
ws_returnerror(pwsc,404,"Not found");
|
|
||||||
config_set_status(pwsc,session,NULL);
|
|
||||||
db_dispose_item(pmp3);
|
|
||||||
io_dispose(hfile);
|
|
||||||
} else {
|
|
||||||
io_size(hfile,&real_len);
|
|
||||||
file_len = real_len - offset;
|
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_WS,"Thread %d: Length of file (remaining): %lld\n",
|
|
||||||
ws_threadno(pwsc),file_len);
|
|
||||||
|
|
||||||
// DWB: fix content-type to correctly reflect data
|
|
||||||
// content type (dmap tagged) should only be used on
|
|
||||||
// dmap protocol requests, not the actually song data
|
|
||||||
if(pmp3->type)
|
|
||||||
ws_addresponseheader(pwsc,"Content-Type","audio/%s",pmp3->type);
|
|
||||||
|
|
||||||
ws_addresponseheader(pwsc,"Content-Length","%ld",(long)file_len);
|
|
||||||
|
|
||||||
if((ws_getrequestheader(pwsc,"user-agent")) &&
|
|
||||||
(!strncmp(ws_getrequestheader(pwsc,"user-agent"),
|
|
||||||
"Hifidelio",9))) {
|
|
||||||
ws_addresponseheader(pwsc,"Connection","Keep-Alive");
|
|
||||||
ws_should_close(pwsc,0);
|
|
||||||
} else {
|
|
||||||
ws_addresponseheader(pwsc,"Connection","Close");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!offset)
|
|
||||||
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
|
||||||
else {
|
|
||||||
ws_addresponseheader(pwsc,"Content-Range","bytes %ld-%ld/%ld",
|
|
||||||
(long)offset,(long)real_len,
|
|
||||||
(long)real_len+1);
|
|
||||||
ws_writefd(pwsc,"HTTP/1.1 206 Partial Content\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
ws_emitheaders(pwsc);
|
|
||||||
|
|
||||||
config_set_status(pwsc,session,"Streaming '%s' (id %d)",
|
|
||||||
pmp3->title, pmp3->id);
|
|
||||||
DPRINTF(E_WARN,L_WS,"Session %d: Streaming file '%s' to %s (offset %d)\n",
|
|
||||||
session,pmp3->fname, ws_hostname(pwsc),(long)offset);
|
|
||||||
|
|
||||||
if(offset) {
|
|
||||||
DPRINTF(E_INF,L_WS,"Seeking to offset %ld\n",(long)offset);
|
|
||||||
io_setpos(hfile,offset,SEEK_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ws_copyfile(pwsc,hfile,&bytes_copied)) {
|
|
||||||
DPRINTF(E_INF,L_WS,"Error copying file to remote... %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
ws_should_close(pwsc,1);
|
|
||||||
} else {
|
|
||||||
DPRINTF(E_INF,L_WS,"Finished streaming file to remote: %lld bytes\n",
|
|
||||||
bytes_copied);
|
|
||||||
}
|
|
||||||
|
|
||||||
config_set_status(pwsc,session,NULL);
|
|
||||||
io_close(hfile);
|
|
||||||
io_dispose(hfile);
|
|
||||||
db_dispose_item(pmp3);
|
|
||||||
}
|
|
||||||
/* update play counts */
|
|
||||||
if(bytes_copied >= (real_len * 80 / 100)) {
|
|
||||||
db_playcount_increment(NULL,pmp3->id);
|
|
||||||
if(!offset)
|
|
||||||
config.stats.songs_served++; /* FIXME: remove stat races */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// free(pqi);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pi_conf_dispose_string(char *str) {
|
|
||||||
free(str);
|
|
||||||
}
|
|
||||||
|
|
|
@ -40,6 +40,9 @@ extern void plugin_event_dispatch(int event_id, int intval, void *vp, int len);
|
||||||
extern void *plugin_enum(void *);
|
extern void *plugin_enum(void *);
|
||||||
extern char *plugin_get_description(void *);
|
extern char *plugin_get_description(void *);
|
||||||
|
|
||||||
|
extern int plugin_ssc_should_transcode(WS_CONNINFO *pwsc, char *codec);
|
||||||
|
extern int plugin_ssc_transcode(WS_CONNINFO *pwsc, MP3FILE *pmp3, int offset, int headers);
|
||||||
|
|
||||||
/* these should really get rows */
|
/* these should really get rows */
|
||||||
|
|
||||||
#define PLUGIN_E_SUCCESS 0
|
#define PLUGIN_E_SUCCESS 0
|
||||||
|
|
|
@ -262,10 +262,10 @@ MetaField_t daap_encode_meta(char *meta) {
|
||||||
if(m->tag)
|
if(m->tag)
|
||||||
bits |= (((MetaField_t) 1) << m->bit);
|
bits |= (((MetaField_t) 1) << m->bit);
|
||||||
else
|
else
|
||||||
_ppi->log(E_WARN,"Unknown meta code: %.*s\n", len, start);
|
pi_log(E_WARN,"Unknown meta code: %.*s\n", len, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG, "meta codes: %llu\n", bits);
|
pi_log(E_DBG, "meta codes: %llu\n", bits);
|
||||||
|
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
@ -475,12 +475,12 @@ int daap_enum_size(char **pe, PRIVINFO *pinfo, int *count, int *total_size) {
|
||||||
int record_size;
|
int record_size;
|
||||||
char **row;
|
char **row;
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Enumerating size\n");
|
pi_log(E_DBG,"Enumerating size\n");
|
||||||
|
|
||||||
*count=0;
|
*count=0;
|
||||||
*total_size = 0;
|
*total_size = 0;
|
||||||
|
|
||||||
while((!(err=_ppi->db_enum_fetch_row(pe,&row,&pinfo->dq))) && (row)) {
|
while((!(err=pi_db_enum_fetch_row(pe,&row,&pinfo->dq))) && (row)) {
|
||||||
if((record_size = daap_get_size(pinfo,row))) {
|
if((record_size = daap_get_size(pinfo,row))) {
|
||||||
*total_size += record_size;
|
*total_size += record_size;
|
||||||
*count = *count + 1;
|
*count = *count + 1;
|
||||||
|
@ -488,14 +488,14 @@ int daap_enum_size(char **pe, PRIVINFO *pinfo, int *count, int *total_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(err) {
|
if(err) {
|
||||||
_ppi->db_enum_end(NULL);
|
pi_db_enum_end(NULL);
|
||||||
_ppi->db_enum_dispose(NULL,&pinfo->dq);
|
pi_db_enum_dispose(NULL,&pinfo->dq);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err=_ppi->db_enum_restart(pe, &pinfo->dq);
|
err=pi_db_enum_restart(pe, &pinfo->dq);
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Got size: %d\n",*total_size);
|
pi_log(E_DBG,"Got size: %d\n",*total_size);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,10 +508,10 @@ int daap_enum_fetch(char **pe, PRIVINFO *pinfo, int *size, unsigned char **pdmap
|
||||||
unsigned char *presult;
|
unsigned char *presult;
|
||||||
char **row;
|
char **row;
|
||||||
|
|
||||||
err=_ppi->db_enum_fetch_row(pe, &row, &pinfo->dq);
|
err=pi_db_enum_fetch_row(pe, &row, &pinfo->dq);
|
||||||
if(err) {
|
if(err) {
|
||||||
_ppi->db_enum_end(NULL);
|
pi_db_enum_end(NULL);
|
||||||
_ppi->db_enum_dispose(NULL,&pinfo->dq);
|
pi_db_enum_dispose(NULL,&pinfo->dq);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,7 +520,7 @@ int daap_enum_fetch(char **pe, PRIVINFO *pinfo, int *size, unsigned char **pdmap
|
||||||
if(result_size) {
|
if(result_size) {
|
||||||
presult = (unsigned char*)malloc(result_size);
|
presult = (unsigned char*)malloc(result_size);
|
||||||
if(!presult) {
|
if(!presult) {
|
||||||
_ppi->log(E_FATAL,"Malloc error\n");
|
pi_log(E_FATAL,"Malloc error\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
daap_build_dmap(pinfo,row,presult,result_size);
|
daap_build_dmap(pinfo,row,presult,result_size);
|
||||||
|
@ -570,7 +570,7 @@ int daap_get_size(PRIVINFO *pinfo, char **valarray) {
|
||||||
break;
|
break;
|
||||||
case QUERY_TYPE_ITEMS:
|
case QUERY_TYPE_ITEMS:
|
||||||
/* see if this is going to be transcoded */
|
/* see if this is going to be transcoded */
|
||||||
transcode = _ppi->should_transcode(pinfo->pwsc,valarray[SG_CODECTYPE]);
|
transcode = pi_should_transcode(pinfo->pwsc,valarray[SG_CODECTYPE]);
|
||||||
|
|
||||||
/* Items that get changed by transcode:
|
/* Items that get changed by transcode:
|
||||||
*
|
*
|
||||||
|
@ -720,7 +720,7 @@ int daap_get_size(PRIVINFO *pinfo, char **valarray) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_ppi->log(E_LOG,"Unknown query type: %d\n",(int)pinfo->dq.query_type);
|
pi_log(E_LOG,"Unknown query type: %d\n",(int)pinfo->dq.query_type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -759,7 +759,7 @@ int daap_build_dmap(PRIVINFO *pinfo, char **valarray, unsigned char *presult, in
|
||||||
break;
|
break;
|
||||||
case QUERY_TYPE_ITEMS:
|
case QUERY_TYPE_ITEMS:
|
||||||
/* see if this is going to be transcoded */
|
/* see if this is going to be transcoded */
|
||||||
transcode = _ppi->should_transcode(pinfo->pwsc,valarray[SG_CODECTYPE]);
|
transcode = pi_should_transcode(pinfo->pwsc,valarray[SG_CODECTYPE]);
|
||||||
|
|
||||||
/* Items that get changed by transcode:
|
/* Items that get changed by transcode:
|
||||||
*
|
*
|
||||||
|
@ -924,7 +924,7 @@ int daap_build_dmap(PRIVINFO *pinfo, char **valarray, unsigned char *presult, in
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_ppi->log(E_LOG,"Unknown query type: %d\n",(int)pinfo->dq.query_type);
|
pi_log(E_LOG,"Unknown query type: %d\n",(int)pinfo->dq.query_type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -90,18 +90,17 @@ static int out_daap_output_xml_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned
|
||||||
|
|
||||||
static void out_daap_cleanup(PRIVINFO *ppi);
|
static void out_daap_cleanup(PRIVINFO *ppi);
|
||||||
|
|
||||||
PLUGIN_INFO *plugin_info(PLUGIN_INPUT_FN *);
|
|
||||||
void plugin_handler(WS_CONNINFO *pwsc);
|
void plugin_handler(WS_CONNINFO *pwsc);
|
||||||
int plugin_can_handle(WS_CONNINFO *pwsc);
|
int plugin_can_handle(WS_CONNINFO *pwsc);
|
||||||
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password);
|
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password);
|
||||||
|
|
||||||
PLUGIN_INFO *plugin_info(PLUGIN_INPUT_FN *);
|
PLUGIN_INFO *plugin_info(void);
|
||||||
PLUGIN_OUTPUT_FN _pofn = { plugin_can_handle, plugin_handler, plugin_auth };
|
PLUGIN_OUTPUT_FN _pofn = { plugin_can_handle, plugin_handler, plugin_auth };
|
||||||
PLUGIN_REND_INFO _pri[] = {
|
PLUGIN_REND_INFO _pri[] = {
|
||||||
{ "_daap._tcp", NULL },
|
{ "_daap._tcp", NULL },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
PLUGIN_INPUT_FN *_ppi;
|
|
||||||
PLUGIN_INFO _pi = {
|
PLUGIN_INFO _pi = {
|
||||||
PLUGIN_VERSION, /* version */
|
PLUGIN_VERSION, /* version */
|
||||||
PLUGIN_OUTPUT, /* type */
|
PLUGIN_OUTPUT, /* type */
|
||||||
|
@ -161,8 +160,7 @@ PLUGIN_RESPONSE daap_uri_map[] = {
|
||||||
/**
|
/**
|
||||||
* return info about this plugin module
|
* return info about this plugin module
|
||||||
*/
|
*/
|
||||||
PLUGIN_INFO *plugin_info(PLUGIN_INPUT_FN *ppi) {
|
PLUGIN_INFO *plugin_info(void) {
|
||||||
_ppi = ppi;
|
|
||||||
return &_pi;
|
return &_pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,9 +168,9 @@ PLUGIN_INFO *plugin_info(PLUGIN_INPUT_FN *ppi) {
|
||||||
* see if the plugin should handle this request
|
* see if the plugin should handle this request
|
||||||
*/
|
*/
|
||||||
int plugin_can_handle(WS_CONNINFO *pwsc) {
|
int plugin_can_handle(WS_CONNINFO *pwsc) {
|
||||||
char *uri = _ppi->ws_uri(pwsc);
|
char *uri = pi_ws_uri(pwsc);
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Checking url %s\n",uri);
|
pi_log(E_DBG,"Checking url %s\n",uri);
|
||||||
if(strncasecmp(uri,"/databases",10) == 0)
|
if(strncasecmp(uri,"/databases",10) == 0)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
if(strncasecmp(uri,"/server-info",12) == 0)
|
if(strncasecmp(uri,"/server-info",12) == 0)
|
||||||
|
@ -194,7 +192,7 @@ int plugin_can_handle(WS_CONNINFO *pwsc) {
|
||||||
* works.
|
* works.
|
||||||
*/
|
*/
|
||||||
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password) {
|
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password) {
|
||||||
char *uri = _ppi->ws_uri(pwsc);
|
char *uri = pi_ws_uri(pwsc);
|
||||||
|
|
||||||
/* don't auth for stuff we shouldn't */
|
/* don't auth for stuff we shouldn't */
|
||||||
if(strncasecmp(uri,"/server-info",12) == 0)
|
if(strncasecmp(uri,"/server-info",12) == 0)
|
||||||
|
@ -204,7 +202,7 @@ int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password) {
|
||||||
if(strncasecmp(uri,"/databases/1/items/",19) == 0)
|
if(strncasecmp(uri,"/databases/1/items/",19) == 0)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
return _ppi->ws_matchesrole(pwsc,username,password,"user");
|
return pi_ws_matchesrole(pwsc,username,password,"user");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -249,7 +247,7 @@ int daap_auth(WS_CONNINFO *pwsc, char *username, char *password) {
|
||||||
char *readpassword;
|
char *readpassword;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
readpassword = _ppi->conf_alloc_string("general","password",NULL);
|
readpassword = pi_conf_alloc_string("general","password",NULL);
|
||||||
|
|
||||||
if(password == NULL) {
|
if(password == NULL) {
|
||||||
if((readpassword == NULL)||(strlen(readpassword) == 0)) {
|
if((readpassword == NULL)||(strlen(readpassword) == 0)) {
|
||||||
|
@ -265,7 +263,7 @@ int daap_auth(WS_CONNINFO *pwsc, char *username, char *password) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(readpassword) _ppi->conf_dispose_string(readpassword);
|
if(readpassword) pi_conf_dispose_string(readpassword);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,46 +280,46 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
||||||
long l,h;
|
long l,h;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Getting uri...\n");
|
pi_log(E_DBG,"Getting uri...\n");
|
||||||
|
|
||||||
string = _ppi->ws_uri(pwsc);
|
string = pi_ws_uri(pwsc);
|
||||||
string++;
|
string++;
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Mallocing privinfo...\n");
|
pi_log(E_DBG,"Mallocing privinfo...\n");
|
||||||
ppi = (PRIVINFO *)malloc(sizeof(PRIVINFO));
|
ppi = (PRIVINFO *)malloc(sizeof(PRIVINFO));
|
||||||
if(ppi) {
|
if(ppi) {
|
||||||
memset(ppi,0,sizeof(PRIVINFO));
|
memset(ppi,0,sizeof(PRIVINFO));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ppi) {
|
if(!ppi) {
|
||||||
_ppi->ws_returnerror(pwsc,500,"Malloc error in plugin_handler");
|
pi_ws_returnerror(pwsc,500,"Malloc error in plugin_handler");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset((void*)&ppi->dq,0,sizeof(DB_QUERY));
|
memset((void*)&ppi->dq,0,sizeof(DB_QUERY));
|
||||||
|
|
||||||
ppi->empty_strings = _ppi->conf_get_int("daap","empty_strings",0);
|
ppi->empty_strings = pi_conf_get_int("daap","empty_strings",0);
|
||||||
ppi->pwsc = pwsc;
|
ppi->pwsc = pwsc;
|
||||||
|
|
||||||
_ppi->ws_addresponseheader(pwsc,"Accept-Ranges","bytes");
|
pi_ws_addresponseheader(pwsc,"Accept-Ranges","bytes");
|
||||||
_ppi->ws_addresponseheader(pwsc,"DAAP-Server","firefly/" VERSION);
|
pi_ws_addresponseheader(pwsc,"DAAP-Server","firefly/" VERSION);
|
||||||
_ppi->ws_addresponseheader(pwsc,"Content-Type","application/x-dmap-tagged");
|
pi_ws_addresponseheader(pwsc,"Content-Type","application/x-dmap-tagged");
|
||||||
_ppi->ws_addresponseheader(pwsc,"Cache-Control","no-cache");
|
pi_ws_addresponseheader(pwsc,"Cache-Control","no-cache");
|
||||||
_ppi->ws_addresponseheader(pwsc,"Expires","-1");
|
pi_ws_addresponseheader(pwsc,"Expires","-1");
|
||||||
|
|
||||||
if(_ppi->ws_getvar(pwsc,"session-id"))
|
if(pi_ws_getvar(pwsc,"session-id"))
|
||||||
ppi->session_id = atoi(_ppi->ws_getvar(pwsc,"session-id"));
|
ppi->session_id = atoi(pi_ws_getvar(pwsc,"session-id"));
|
||||||
|
|
||||||
ppi->dq.offset = 0;
|
ppi->dq.offset = 0;
|
||||||
ppi->dq.limit = 999999;
|
ppi->dq.limit = 999999;
|
||||||
|
|
||||||
l=h=0;
|
l=h=0;
|
||||||
if(_ppi->ws_getvar(pwsc,"index")) {
|
if(pi_ws_getvar(pwsc,"index")) {
|
||||||
index_req = _ppi->ws_getvar(pwsc,"index");
|
index_req = pi_ws_getvar(pwsc,"index");
|
||||||
l = strtol(index_req,&ptr,10);
|
l = strtol(index_req,&ptr,10);
|
||||||
|
|
||||||
if(l<0) { /* "-h"... tail range, last "h" entries */
|
if(l<0) { /* "-h"... tail range, last "h" entries */
|
||||||
_ppi->log(E_LOG,"Unsupported index range: %s\n",index_req);
|
pi_log(E_LOG,"Unsupported index range: %s\n",index_req);
|
||||||
} else if(*ptr == 0) {
|
} else if(*ptr == 0) {
|
||||||
/* single item */
|
/* single item */
|
||||||
ppi->dq.offset = l;
|
ppi->dq.offset = l;
|
||||||
|
@ -334,31 +332,31 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Index %s: offset %d, limit %d\n",index_req,
|
pi_log(E_DBG,"Index %s: offset %d, limit %d\n",index_req,
|
||||||
ppi->dq.offset,ppi->dq.limit);
|
ppi->dq.offset,ppi->dq.limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(_ppi->ws_getvar(pwsc,"query")) {
|
if(pi_ws_getvar(pwsc,"query")) {
|
||||||
ppi->dq.filter_type = FILTER_TYPE_APPLE;
|
ppi->dq.filter_type = FILTER_TYPE_APPLE;
|
||||||
ppi->dq.filter = _ppi->ws_getvar(pwsc,"query");
|
ppi->dq.filter = pi_ws_getvar(pwsc,"query");
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Tokenizing url\n");
|
pi_log(E_DBG,"Tokenizing url\n");
|
||||||
while((ppi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
|
while((ppi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
|
||||||
string=NULL;
|
string=NULL;
|
||||||
ppi->uri_sections[ppi->uri_count++] = token;
|
ppi->uri_sections[ppi->uri_count++] = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
elements = sizeof(daap_uri_map) / sizeof(PLUGIN_RESPONSE);
|
elements = sizeof(daap_uri_map) / sizeof(PLUGIN_RESPONSE);
|
||||||
_ppi->log(E_DBG,"Found %d elements\n",elements);
|
pi_log(E_DBG,"Found %d elements\n",elements);
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
found = 0;
|
found = 0;
|
||||||
|
|
||||||
while((!found) && (index < elements)) {
|
while((!found) && (index < elements)) {
|
||||||
/* test this set */
|
/* test this set */
|
||||||
_ppi->log(E_DBG,"Checking reponse %d\n",index);
|
pi_log(E_DBG,"Checking reponse %d\n",index);
|
||||||
part=0;
|
part=0;
|
||||||
while(part < 10) {
|
while(part < 10) {
|
||||||
if((daap_uri_map[index].uri[part]) && (!ppi->uri_sections[part]))
|
if((daap_uri_map[index].uri[part]) && (!ppi->uri_sections[part]))
|
||||||
|
@ -377,7 +375,7 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
||||||
|
|
||||||
if(part == 10) {
|
if(part == 10) {
|
||||||
found = 1;
|
found = 1;
|
||||||
_ppi->log(E_DBG,"Found it! Index: %d\n",index);
|
pi_log(E_DBG,"Found it! Index: %d\n",index);
|
||||||
} else {
|
} else {
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
@ -389,8 +387,8 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->ws_returnerror(pwsc,400,"Bad request");
|
pi_ws_returnerror(pwsc,400,"Bad request");
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
out_daap_cleanup(ppi);
|
out_daap_cleanup(ppi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -408,33 +406,33 @@ int out_daap_output_start(WS_CONNINFO *pwsc, PRIVINFO *ppi, int content_length)
|
||||||
|
|
||||||
poi=(OUTPUT_INFO*)calloc(1,sizeof(OUTPUT_INFO));
|
poi=(OUTPUT_INFO*)calloc(1,sizeof(OUTPUT_INFO));
|
||||||
if(!poi) {
|
if(!poi) {
|
||||||
_ppi->log(E_LOG,"Malloc error in out_daap_ouput_start\n");
|
pi_log(E_LOG,"Malloc error in out_daap_ouput_start\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ppi->output_info = (void*) poi;
|
ppi->output_info = (void*) poi;
|
||||||
poi->dmap_response_length = content_length;
|
poi->dmap_response_length = content_length;
|
||||||
|
|
||||||
if(_ppi->ws_getvar(pwsc,"output")) {
|
if(pi_ws_getvar(pwsc,"output")) {
|
||||||
if(strcasecmp(_ppi->ws_getvar(pwsc,"output"),"readable") == 0)
|
if(strcasecmp(pi_ws_getvar(pwsc,"output"),"readable") == 0)
|
||||||
poi->readable=1;
|
poi->readable=1;
|
||||||
|
|
||||||
poi->xml_output=1;
|
poi->xml_output=1;
|
||||||
_ppi->ws_addresponseheader(pwsc,"Content-Type","text/xml");
|
pi_ws_addresponseheader(pwsc,"Content-Type","text/xml");
|
||||||
_ppi->ws_addresponseheader(pwsc,"Connection","Close");
|
pi_ws_addresponseheader(pwsc,"Connection","Close");
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
_ppi->ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
pi_ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
||||||
_ppi->ws_emitheaders(pwsc);
|
pi_ws_emitheaders(pwsc);
|
||||||
_ppi->ws_writefd(pwsc,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
pi_ws_writefd(pwsc,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
||||||
if(poi->readable)
|
if(poi->readable)
|
||||||
_ppi->ws_writefd(pwsc,"\n");
|
pi_ws_writefd(pwsc,"\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->ws_addresponseheader(pwsc,"Content-Length","%d",
|
pi_ws_addresponseheader(pwsc,"Content-Length","%d",
|
||||||
poi->dmap_response_length);
|
poi->dmap_response_length);
|
||||||
_ppi->ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
pi_ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
|
||||||
_ppi->ws_emitheaders(pwsc);
|
pi_ws_emitheaders(pwsc);
|
||||||
|
|
||||||
/* I guess now we would start writing the output */
|
/* I guess now we would start writing the output */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -458,7 +456,7 @@ int out_daap_output_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned char *block
|
||||||
if(poi->xml_output)
|
if(poi->xml_output)
|
||||||
return out_daap_output_xml_write(pwsc, ppi, block, len);
|
return out_daap_output_xml_write(pwsc, ppi, block, len);
|
||||||
|
|
||||||
result=_ppi->ws_writebinary(pwsc,(char*)block,len);
|
result=pi_ws_writebinary(pwsc,(char*)block,len);
|
||||||
|
|
||||||
if(result != len)
|
if(result != len)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -493,7 +491,7 @@ int out_daap_output_xml_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned char *b
|
||||||
block_done=1;
|
block_done=1;
|
||||||
len_left=(int)((block+len) - current);
|
len_left=(int)((block+len) - current);
|
||||||
if(len_left < 8) {
|
if(len_left < 8) {
|
||||||
_ppi->log(E_FATAL,"Badly formatted dmap block - frag size: %d",len_left);
|
pi_log(E_FATAL,"Badly formatted dmap block - frag size: %d",len_left);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set up block */
|
/* set up block */
|
||||||
|
@ -509,49 +507,49 @@ int out_daap_output_xml_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned char *b
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lookup and serialize */
|
/* lookup and serialize */
|
||||||
_ppi->log(E_SPAM,"%*s %s: %d\n",poi->stack_height,"",block_tag,block_len);
|
pi_log(E_SPAM,"%*s %s: %d\n",poi->stack_height,"",block_tag,block_len);
|
||||||
pitem=out_daap_xml_lookup_tag(block_tag);
|
pitem=out_daap_xml_lookup_tag(block_tag);
|
||||||
if(poi->readable)
|
if(poi->readable)
|
||||||
_ppi->ws_writefd(pwsc,"%*s",poi->stack_height,"");
|
pi_ws_writefd(pwsc,"%*s",poi->stack_height,"");
|
||||||
_ppi->ws_writefd(pwsc,"<%s>",pitem->description);
|
pi_ws_writefd(pwsc,"<%s>",pitem->description);
|
||||||
switch(pitem->type) {
|
switch(pitem->type) {
|
||||||
case 0x01: /* byte */
|
case 0x01: /* byte */
|
||||||
if(block_len != 1) {
|
if(block_len != 1) {
|
||||||
_ppi->log(E_FATAL,"tag %s, size %d, wanted 1\n",block_tag, block_len);
|
pi_log(E_FATAL,"tag %s, size %d, wanted 1\n",block_tag, block_len);
|
||||||
}
|
}
|
||||||
_ppi->ws_writefd(pwsc,"%d",*((char *)data));
|
pi_ws_writefd(pwsc,"%d",*((char *)data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x02: /* unsigned byte */
|
case 0x02: /* unsigned byte */
|
||||||
if(block_len != 1) {
|
if(block_len != 1) {
|
||||||
_ppi->log(E_FATAL,"tag %s, size %d, wanted 1\n",block_tag, block_len);
|
pi_log(E_FATAL,"tag %s, size %d, wanted 1\n",block_tag, block_len);
|
||||||
}
|
}
|
||||||
_ppi->ws_writefd(pwsc,"%ud",*((char *)data));
|
pi_ws_writefd(pwsc,"%ud",*((char *)data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x03: /* short */
|
case 0x03: /* short */
|
||||||
if(block_len != 2) {
|
if(block_len != 2) {
|
||||||
_ppi->log(E_FATAL,"tag %s, size %d, wanted 2\n",block_tag, block_len);
|
pi_log(E_FATAL,"tag %s, size %d, wanted 2\n",block_tag, block_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
ivalue = data[0] << 8 | data[1];
|
ivalue = data[0] << 8 | data[1];
|
||||||
_ppi->ws_writefd(pwsc,"%d",ivalue);
|
pi_ws_writefd(pwsc,"%d",ivalue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x05: /* int */
|
case 0x05: /* int */
|
||||||
case 0x0A: /* epoch */
|
case 0x0A: /* epoch */
|
||||||
if(block_len != 4) {
|
if(block_len != 4) {
|
||||||
_ppi->log(E_FATAL,"tag %s, size %d, wanted 4\n",block_tag, block_len);
|
pi_log(E_FATAL,"tag %s, size %d, wanted 4\n",block_tag, block_len);
|
||||||
}
|
}
|
||||||
ivalue = data[0] << 24 |
|
ivalue = data[0] << 24 |
|
||||||
data[1] << 16 |
|
data[1] << 16 |
|
||||||
data[2] << 8 |
|
data[2] << 8 |
|
||||||
data[3];
|
data[3];
|
||||||
_ppi->ws_writefd(pwsc,"%d",ivalue);
|
pi_ws_writefd(pwsc,"%d",ivalue);
|
||||||
break;
|
break;
|
||||||
case 0x07: /* long long */
|
case 0x07: /* long long */
|
||||||
if(block_len != 8) {
|
if(block_len != 8) {
|
||||||
_ppi->log(E_FATAL,"tag %s, size %d, wanted 8\n",block_tag, block_len);
|
pi_log(E_FATAL,"tag %s, size %d, wanted 8\n",block_tag, block_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
ivalue = data[0] << 24 |
|
ivalue = data[0] << 24 |
|
||||||
|
@ -564,29 +562,29 @@ int out_daap_output_xml_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned char *b
|
||||||
data[6] << 8 |
|
data[6] << 8 |
|
||||||
data[7];
|
data[7];
|
||||||
lvalue = (lvalue << 32) | ivalue;
|
lvalue = (lvalue << 32) | ivalue;
|
||||||
_ppi->ws_writefd(pwsc,"%ll",ivalue);
|
pi_ws_writefd(pwsc,"%ll",ivalue);
|
||||||
break;
|
break;
|
||||||
case 0x09: /* string */
|
case 0x09: /* string */
|
||||||
if(block_len) {
|
if(block_len) {
|
||||||
encoded_string=out_daap_xml_encode((char*)data,block_len);
|
encoded_string=out_daap_xml_encode((char*)data,block_len);
|
||||||
_ppi->ws_writefd(pwsc,"%s",encoded_string);
|
pi_ws_writefd(pwsc,"%s",encoded_string);
|
||||||
free(encoded_string);
|
free(encoded_string);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0B: /* version? */
|
case 0x0B: /* version? */
|
||||||
if(block_len != 4) {
|
if(block_len != 4) {
|
||||||
_ppi->log(E_FATAL,"tag %s, size %d, wanted 4\n",block_tag, block_len);
|
pi_log(E_FATAL,"tag %s, size %d, wanted 4\n",block_tag, block_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
ivalue=data[0] << 8 | data[1];
|
ivalue=data[0] << 8 | data[1];
|
||||||
_ppi->ws_writefd(pwsc,"%d.%d.%d",ivalue,data[2],data[3]);
|
pi_ws_writefd(pwsc,"%d.%d.%d",ivalue,data[2],data[3]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0C:
|
case 0x0C:
|
||||||
if((poi->browse_response)&&(strcmp(block_tag,"mlit") ==0)) {
|
if((poi->browse_response)&&(strcmp(block_tag,"mlit") ==0)) {
|
||||||
if(block_len) {
|
if(block_len) {
|
||||||
encoded_string=out_daap_xml_encode((char*)data,block_len);
|
encoded_string=out_daap_xml_encode((char*)data,block_len);
|
||||||
_ppi->ws_writefd(pwsc,"%s",encoded_string);
|
pi_ws_writefd(pwsc,"%s",encoded_string);
|
||||||
free(encoded_string);
|
free(encoded_string);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -599,29 +597,29 @@ int out_daap_output_xml_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned char *b
|
||||||
memcpy(poi->stack[poi->stack_height].tag,block_tag,5);
|
memcpy(poi->stack[poi->stack_height].tag,block_tag,5);
|
||||||
poi->stack_height++;
|
poi->stack_height++;
|
||||||
if(poi->stack_height == 10) {
|
if(poi->stack_height == 10) {
|
||||||
_ppi->log(E_FATAL,"Stack overflow\n");
|
pi_log(E_FATAL,"Stack overflow\n");
|
||||||
}
|
}
|
||||||
block_done=0;
|
block_done=0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_ppi->log(E_FATAL,"Bad dmap type: %d, %s\n",
|
pi_log(E_FATAL,"Bad dmap type: %d, %s\n",
|
||||||
pitem->type, pitem->description);
|
pitem->type, pitem->description);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(block_done) {
|
if(block_done) {
|
||||||
_ppi->ws_writefd(pwsc,"</%s>",pitem->description);
|
pi_ws_writefd(pwsc,"</%s>",pitem->description);
|
||||||
if(poi->readable)
|
if(poi->readable)
|
||||||
_ppi->ws_writefd(pwsc,"\n");
|
pi_ws_writefd(pwsc,"\n");
|
||||||
|
|
||||||
block_len += 8;
|
block_len += 8;
|
||||||
} else {
|
} else {
|
||||||
/* must be a container */
|
/* must be a container */
|
||||||
block_len = 8;
|
block_len = 8;
|
||||||
if(poi->readable)
|
if(poi->readable)
|
||||||
_ppi->ws_writefd(pwsc,"\n");
|
pi_ws_writefd(pwsc,"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
current += block_len;
|
current += block_len;
|
||||||
|
@ -631,17 +629,17 @@ int out_daap_output_xml_write(WS_CONNINFO *pwsc, PRIVINFO *ppi, unsigned char *b
|
||||||
while(stack_ptr--) {
|
while(stack_ptr--) {
|
||||||
poi->stack[stack_ptr].bytes_left -= block_len;
|
poi->stack[stack_ptr].bytes_left -= block_len;
|
||||||
if(poi->stack[stack_ptr].bytes_left < 0) {
|
if(poi->stack[stack_ptr].bytes_left < 0) {
|
||||||
_ppi->log(E_FATAL,"negative container\n");
|
pi_log(E_FATAL,"negative container\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!poi->stack[stack_ptr].bytes_left) {
|
if(!poi->stack[stack_ptr].bytes_left) {
|
||||||
poi->stack_height--;
|
poi->stack_height--;
|
||||||
pitem=out_daap_xml_lookup_tag(poi->stack[stack_ptr].tag);
|
pitem=out_daap_xml_lookup_tag(poi->stack[stack_ptr].tag);
|
||||||
if(poi->readable)
|
if(poi->readable)
|
||||||
_ppi->ws_writefd(pwsc,"%*s",poi->stack_height,"");
|
pi_ws_writefd(pwsc,"%*s",poi->stack_height,"");
|
||||||
_ppi->ws_writefd(pwsc,"</%s>",pitem->description);
|
pi_ws_writefd(pwsc,"</%s>",pitem->description);
|
||||||
if(poi->readable)
|
if(poi->readable)
|
||||||
_ppi->ws_writefd(pwsc,"\n");
|
pi_ws_writefd(pwsc,"\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -662,10 +660,10 @@ int out_daap_output_end(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
OUTPUT_INFO *poi = ppi->output_info;
|
OUTPUT_INFO *poi = ppi->output_info;
|
||||||
|
|
||||||
if((poi) && (poi->xml_output) && (poi->stack_height)) {
|
if((poi) && (poi->xml_output) && (poi->stack_height)) {
|
||||||
_ppi->log(E_LOG,"Badly formed xml -- still stack\n");
|
pi_log(E_LOG,"Badly formed xml -- still stack\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->config_set_status(pwsc,ppi->session_id,NULL);
|
pi_config_set_status(pwsc,ppi->session_id,NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -680,7 +678,7 @@ DAAP_ITEMS *out_daap_xml_lookup_tag(char *tag) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!pitem->tag)
|
if(!pitem->tag)
|
||||||
_ppi->log(E_FATAL,"Unknown daap tag: %c%c%c%c\n",tag[0],tag[1],tag[2],tag[3]);
|
pi_log(E_FATAL,"Unknown daap tag: %c%c%c%c\n",tag[0],tag[1],tag[2],tag[3]);
|
||||||
|
|
||||||
return pitem;
|
return pitem;
|
||||||
}
|
}
|
||||||
|
@ -747,7 +745,7 @@ char *out_daap_xml_encode(char *original, int len) {
|
||||||
|
|
||||||
void out_daap_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
void out_daap_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
/* should show sesson id */
|
/* should show sesson id */
|
||||||
_ppi->stream(pwsc, ppi->uri_sections[3]);
|
pi_stream(pwsc, ppi->uri_sections[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -762,19 +760,19 @@ void out_daap_addplaylistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
|
|
||||||
playlist_id = atoi(ppi->uri_sections[3]);
|
playlist_id = atoi(ppi->uri_sections[3]);
|
||||||
|
|
||||||
if(!_ppi->ws_getvar(pwsc,"dmap.itemid")) {
|
if(!pi_ws_getvar(pwsc,"dmap.itemid")) {
|
||||||
_ppi->log(E_LOG,"Attempt to add playlist item w/o dmap.itemid\n");
|
pi_log(E_LOG,"Attempt to add playlist item w/o dmap.itemid\n");
|
||||||
out_daap_error(pwsc,ppi,"MAPI","No item id specified (dmap.itemid)");
|
out_daap_error(pwsc,ppi,"MAPI","No item id specified (dmap.itemid)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tempstring=strdup(_ppi->ws_getvar(pwsc,"dmap.itemid"));
|
tempstring=strdup(pi_ws_getvar(pwsc,"dmap.itemid"));
|
||||||
current=(unsigned char*)tempstring;
|
current=(unsigned char*)tempstring;
|
||||||
|
|
||||||
while((token=_strsep((char**)(char*)¤t,","))) {
|
while((token=_strsep((char**)(char*)¤t,","))) {
|
||||||
if(token) {
|
if(token) {
|
||||||
/* FIXME: error handling */
|
/* FIXME: error handling */
|
||||||
_ppi->db_add_playlist_item(NULL,playlist_id,atoi(token));
|
pi_db_add_playlist_item(NULL,playlist_id,atoi(token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -789,7 +787,7 @@ void out_daap_addplaylistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
out_daap_output_write(pwsc,ppi,playlist_response,20);
|
out_daap_output_write(pwsc,ppi,playlist_response,20);
|
||||||
out_daap_output_end(pwsc,ppi);
|
out_daap_output_end(pwsc,ppi);
|
||||||
|
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -801,14 +799,14 @@ void out_daap_deleteplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
unsigned char playlist_response[20];
|
unsigned char playlist_response[20];
|
||||||
unsigned char *current;
|
unsigned char *current;
|
||||||
|
|
||||||
if(!_ppi->ws_getvar(pwsc,"dmap.itemid")) {
|
if(!pi_ws_getvar(pwsc,"dmap.itemid")) {
|
||||||
_ppi->log(E_LOG,"Attempt to delete playlist w/o dmap.itemid\n");
|
pi_log(E_LOG,"Attempt to delete playlist w/o dmap.itemid\n");
|
||||||
out_daap_error(pwsc,ppi,"MDPR","No playlist id specified");
|
out_daap_error(pwsc,ppi,"MDPR","No playlist id specified");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: error handling */
|
/* FIXME: error handling */
|
||||||
_ppi->db_delete_playlist(NULL,atoi(_ppi->ws_getvar(pwsc,"dmap.itemid")));
|
pi_db_delete_playlist(NULL,atoi(pi_ws_getvar(pwsc,"dmap.itemid")));
|
||||||
|
|
||||||
/* success(ish)... spool out a dmap block */
|
/* success(ish)... spool out a dmap block */
|
||||||
current = playlist_response;
|
current = playlist_response;
|
||||||
|
@ -819,7 +817,7 @@ void out_daap_deleteplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
out_daap_output_write(pwsc,ppi,playlist_response,20);
|
out_daap_output_write(pwsc,ppi,playlist_response,20);
|
||||||
out_daap_output_end(pwsc,ppi);
|
out_daap_output_end(pwsc,ppi);
|
||||||
|
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -834,22 +832,22 @@ void out_daap_deleteplaylistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
char *token;
|
char *token;
|
||||||
int playlist_id;
|
int playlist_id;
|
||||||
|
|
||||||
if(!_ppi->ws_getvar(pwsc,"dmap.itemid")) {
|
if(!pi_ws_getvar(pwsc,"dmap.itemid")) {
|
||||||
_ppi->log(E_LOG,"Delete playlist item w/o dmap.itemid\n");
|
pi_log(E_LOG,"Delete playlist item w/o dmap.itemid\n");
|
||||||
out_daap_error(pwsc,ppi,"MDPI","No playlist item specified");
|
out_daap_error(pwsc,ppi,"MDPI","No playlist item specified");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist_id = atoi(ppi->uri_sections[3]);
|
playlist_id = atoi(ppi->uri_sections[3]);
|
||||||
|
|
||||||
tempstring=strdup(_ppi->ws_getvar(pwsc,"dmap.itemid"));
|
tempstring=strdup(pi_ws_getvar(pwsc,"dmap.itemid"));
|
||||||
current=(unsigned char *)tempstring;
|
current=(unsigned char *)tempstring;
|
||||||
|
|
||||||
/* this looks strange, but gets rid of gcc 4 warnings */
|
/* this looks strange, but gets rid of gcc 4 warnings */
|
||||||
while((token=_strsep((char**)(char*)¤t,","))) {
|
while((token=_strsep((char**)(char*)¤t,","))) {
|
||||||
if(token) {
|
if(token) {
|
||||||
/* FIXME: Error handling */
|
/* FIXME: Error handling */
|
||||||
_ppi->db_delete_playlist_item(NULL,playlist_id,atoi(token));
|
pi_db_delete_playlist_item(NULL,playlist_id,atoi(token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,7 +862,7 @@ void out_daap_deleteplaylistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
out_daap_output_write(pwsc,ppi,playlist_response,20);
|
out_daap_output_write(pwsc,ppi,playlist_response,20);
|
||||||
out_daap_output_end(pwsc,ppi);
|
out_daap_output_end(pwsc,ppi);
|
||||||
|
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -880,21 +878,21 @@ void out_daap_addplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
int retval, playlistid;
|
int retval, playlistid;
|
||||||
char *estring = NULL;
|
char *estring = NULL;
|
||||||
|
|
||||||
if((!_ppi->ws_getvar(pwsc,"org.mt-daapd.playlist-type")) ||
|
if((!pi_ws_getvar(pwsc,"org.mt-daapd.playlist-type")) ||
|
||||||
(!_ppi->ws_getvar(pwsc,"dmap.itemname"))) {
|
(!pi_ws_getvar(pwsc,"dmap.itemname"))) {
|
||||||
_ppi->log(E_LOG,"attempt to add playlist with invalid type\n");
|
pi_log(E_LOG,"attempt to add playlist with invalid type\n");
|
||||||
out_daap_error(pwsc,ppi,"MAPR","bad playlist info specified");
|
out_daap_error(pwsc,ppi,"MAPR","bad playlist info specified");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
type=atoi(_ppi->ws_getvar(pwsc,"org.mt-daapd.playlist-type"));
|
type=atoi(pi_ws_getvar(pwsc,"org.mt-daapd.playlist-type"));
|
||||||
name=_ppi->ws_getvar(pwsc,"dmap.itemname");
|
name=pi_ws_getvar(pwsc,"dmap.itemname");
|
||||||
query=_ppi->ws_getvar(pwsc,"org.mt-daapd.smart-playlist-spec");
|
query=pi_ws_getvar(pwsc,"org.mt-daapd.smart-playlist-spec");
|
||||||
|
|
||||||
retval=_ppi->db_add_playlist(&estring,name,type,query,NULL,0,&playlistid);
|
retval=pi_db_add_playlist(&estring,name,type,query,NULL,0,&playlistid);
|
||||||
if(retval) {
|
if(retval) {
|
||||||
out_daap_error(pwsc,ppi,"MAPR",estring);
|
out_daap_error(pwsc,ppi,"MAPR",estring);
|
||||||
_ppi->log(E_LOG,"error adding playlist %s: %s\n",name,estring);
|
pi_log(E_LOG,"error adding playlist %s: %s\n",name,estring);
|
||||||
free(estring);
|
free(estring);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -908,7 +906,7 @@ void out_daap_addplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
out_daap_output_write(pwsc,ppi,playlist_response,32);
|
out_daap_output_write(pwsc,ppi,playlist_response,32);
|
||||||
out_daap_output_end(pwsc,ppi);
|
out_daap_output_end(pwsc,ppi);
|
||||||
|
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,20 +922,20 @@ void out_daap_editplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
|
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if(!_ppi->ws_getvar(pwsc,"dmap.itemid")) {
|
if(!pi_ws_getvar(pwsc,"dmap.itemid")) {
|
||||||
_ppi->log(E_LOG,"Missing itemid on playlist edit");
|
pi_log(E_LOG,"Missing itemid on playlist edit");
|
||||||
out_daap_error(pwsc,ppi,"MEPR","No itemid specified");
|
out_daap_error(pwsc,ppi,"MEPR","No itemid specified");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
name=_ppi->ws_getvar(pwsc,"dmap.itemname");
|
name=pi_ws_getvar(pwsc,"dmap.itemname");
|
||||||
query=_ppi->ws_getvar(pwsc,"org.mt-daapd.smart-playlist-spec");
|
query=pi_ws_getvar(pwsc,"org.mt-daapd.smart-playlist-spec");
|
||||||
id=atoi(_ppi->ws_getvar(pwsc,"dmap.itemid"));
|
id=atoi(pi_ws_getvar(pwsc,"dmap.itemid"));
|
||||||
|
|
||||||
/* FIXME: Error handling */
|
/* FIXME: Error handling */
|
||||||
retval=_ppi->db_edit_playlist(&pe,id,name,query);
|
retval=pi_db_edit_playlist(&pe,id,name,query);
|
||||||
if(retval) {
|
if(retval) {
|
||||||
_ppi->log(E_LOG,"error editing playlist.\n");
|
pi_log(E_LOG,"error editing playlist.\n");
|
||||||
out_daap_error(pwsc,ppi,"MEPR",pe);
|
out_daap_error(pwsc,ppi,"MEPR",pe);
|
||||||
if(pe) free(pe);
|
if(pe) free(pe);
|
||||||
return;
|
return;
|
||||||
|
@ -950,7 +948,7 @@ void out_daap_editplaylist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
out_daap_output_write(pwsc,ppi,edit_response,20);
|
out_daap_output_write(pwsc,ppi,edit_response,20);
|
||||||
out_daap_output_end(pwsc,ppi);
|
out_daap_output_end(pwsc,ppi);
|
||||||
|
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -967,8 +965,8 @@ void out_daap_playlistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
char *pe = NULL;
|
char *pe = NULL;
|
||||||
int mtco;
|
int mtco;
|
||||||
|
|
||||||
if(_ppi->ws_getvar(pwsc,"meta")) {
|
if(pi_ws_getvar(pwsc,"meta")) {
|
||||||
ppi->meta = daap_encode_meta(_ppi->ws_getvar(pwsc,"meta"));
|
ppi->meta = daap_encode_meta(pi_ws_getvar(pwsc,"meta"));
|
||||||
} else {
|
} else {
|
||||||
ppi->meta = ((1ll << metaItemId) |
|
ppi->meta = ((1ll << metaItemId) |
|
||||||
(1ll << metaItemName) |
|
(1ll << metaItemName) |
|
||||||
|
@ -980,21 +978,21 @@ void out_daap_playlistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
ppi->dq.query_type = QUERY_TYPE_ITEMS;
|
ppi->dq.query_type = QUERY_TYPE_ITEMS;
|
||||||
ppi->dq.playlist_id = atoi(ppi->uri_sections[3]);
|
ppi->dq.playlist_id = atoi(ppi->uri_sections[3]);
|
||||||
|
|
||||||
if(_ppi->db_enum_start(&pe,&ppi->dq)) {
|
if(pi_db_enum_start(&pe,&ppi->dq)) {
|
||||||
_ppi->log(E_LOG,"Could not start enum: %s\n",pe);
|
pi_log(E_LOG,"Could not start enum: %s\n",pe);
|
||||||
out_daap_error(pwsc,ppi,"apso",pe);
|
out_daap_error(pwsc,ppi,"apso",pe);
|
||||||
if(pe) free(pe);
|
if(pe) free(pe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(daap_enum_size(&pe,ppi,&song_count,&list_length)) {
|
if(daap_enum_size(&pe,ppi,&song_count,&list_length)) {
|
||||||
_ppi->log(E_LOG,"Could not enum size: %s\n",pe);
|
pi_log(E_LOG,"Could not enum size: %s\n",pe);
|
||||||
out_daap_error(pwsc,ppi,"apso",pe);
|
out_daap_error(pwsc,ppi,"apso",pe);
|
||||||
if(pe) free(pe);
|
if(pe) free(pe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Item enum: got %d songs, dmap size: %d\n",song_count,list_length);
|
pi_log(E_DBG,"Item enum: got %d songs, dmap size: %d\n",song_count,list_length);
|
||||||
|
|
||||||
mtco = song_count;
|
mtco = song_count;
|
||||||
if(ppi->dq.offset || ppi->dq.limit)
|
if(ppi->dq.offset || ppi->dq.limit)
|
||||||
|
@ -1013,15 +1011,15 @@ void out_daap_playlistitems(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
/* FIXME: Error checking */
|
/* FIXME: Error checking */
|
||||||
while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) &&
|
while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) &&
|
||||||
(list_length)) {
|
(list_length)) {
|
||||||
_ppi->log(E_SPAM,"Got block of size %d\n",list_length);
|
pi_log(E_SPAM,"Got block of size %d\n",list_length);
|
||||||
out_daap_output_write(pwsc,ppi,block,list_length);
|
out_daap_output_write(pwsc,ppi,block,list_length);
|
||||||
free(block);
|
free(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Done enumerating.\n");
|
pi_log(E_DBG,"Done enumerating.\n");
|
||||||
|
|
||||||
_ppi->db_enum_end(NULL);
|
pi_db_enum_end(NULL);
|
||||||
_ppi->db_enum_dispose(NULL,&ppi->dq);
|
pi_db_enum_dispose(NULL,&ppi->dq);
|
||||||
|
|
||||||
out_daap_output_end(pwsc,ppi);
|
out_daap_output_end(pwsc,ppi);
|
||||||
return;
|
return;
|
||||||
|
@ -1042,7 +1040,7 @@ void out_daap_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
which_field = 3;
|
which_field = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Browsing by %s (field %d)\n",
|
pi_log(E_DBG,"Browsing by %s (field %d)\n",
|
||||||
ppi->uri_sections[which_field],which_field);
|
ppi->uri_sections[which_field],which_field);
|
||||||
|
|
||||||
ppi->dq.query_type = QUERY_TYPE_DISTINCT;
|
ppi->dq.query_type = QUERY_TYPE_DISTINCT;
|
||||||
|
@ -1062,25 +1060,25 @@ void out_daap_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
response_type = "abcp";
|
response_type = "abcp";
|
||||||
ppi->dq.distinct_field = "composer";
|
ppi->dq.distinct_field = "composer";
|
||||||
} else {
|
} else {
|
||||||
_ppi->log(E_WARN,"Invalid browse request type %s\n",ppi->uri_sections[3]);
|
pi_log(E_WARN,"Invalid browse request type %s\n",ppi->uri_sections[3]);
|
||||||
out_daap_error(pwsc,ppi,"abro","Invalid browse type");
|
out_daap_error(pwsc,ppi,"abro","Invalid browse type");
|
||||||
_ppi->config_set_status(pwsc,ppi->session_id,NULL);
|
pi_config_set_status(pwsc,ppi->session_id,NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_ppi->db_enum_start(&pe,&ppi->dq)) {
|
if(pi_db_enum_start(&pe,&ppi->dq)) {
|
||||||
_ppi->log(E_LOG,"Could not start enum: %s\n",pe);
|
pi_log(E_LOG,"Could not start enum: %s\n",pe);
|
||||||
out_daap_error(pwsc,ppi,"abro",pe);
|
out_daap_error(pwsc,ppi,"abro",pe);
|
||||||
if(pe) free(pe);
|
if(pe) free(pe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Getting enum size.\n");
|
pi_log(E_DBG,"Getting enum size.\n");
|
||||||
|
|
||||||
/* FIXME: Error handling */
|
/* FIXME: Error handling */
|
||||||
daap_enum_size(NULL,ppi,&item_count,&list_length);
|
daap_enum_size(NULL,ppi,&item_count,&list_length);
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Item enum: got %d items, dmap size: %d\n",
|
pi_log(E_DBG,"Item enum: got %d items, dmap size: %d\n",
|
||||||
item_count,list_length);
|
item_count,list_length);
|
||||||
|
|
||||||
mtco = item_count;
|
mtco = item_count;
|
||||||
|
@ -1099,15 +1097,15 @@ void out_daap_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) &&
|
while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) &&
|
||||||
(list_length))
|
(list_length))
|
||||||
{
|
{
|
||||||
_ppi->log(E_SPAM,"Got block of size %d\n",list_length);
|
pi_log(E_SPAM,"Got block of size %d\n",list_length);
|
||||||
out_daap_output_write(pwsc,ppi,block,list_length);
|
out_daap_output_write(pwsc,ppi,block,list_length);
|
||||||
free(block);
|
free(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Done enumerating\n");
|
pi_log(E_DBG,"Done enumerating\n");
|
||||||
|
|
||||||
_ppi->db_enum_end(NULL);
|
pi_db_enum_end(NULL);
|
||||||
_ppi->db_enum_dispose(NULL,&ppi->dq);
|
pi_db_enum_dispose(NULL,&ppi->dq);
|
||||||
|
|
||||||
out_daap_output_end(pwsc,ppi);
|
out_daap_output_end(pwsc,ppi);
|
||||||
return;
|
return;
|
||||||
|
@ -1123,8 +1121,8 @@ void out_daap_playlists(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
int mtco;
|
int mtco;
|
||||||
|
|
||||||
/* currently, this is ignored for playlist queries */
|
/* currently, this is ignored for playlist queries */
|
||||||
if(_ppi->ws_getvar(pwsc,"meta")) {
|
if(pi_ws_getvar(pwsc,"meta")) {
|
||||||
ppi->meta = daap_encode_meta(_ppi->ws_getvar(pwsc,"meta"));
|
ppi->meta = daap_encode_meta(pi_ws_getvar(pwsc,"meta"));
|
||||||
} else {
|
} else {
|
||||||
ppi->meta = ((1ll << metaItemId) |
|
ppi->meta = ((1ll << metaItemId) |
|
||||||
(1ll << metaItemName) |
|
(1ll << metaItemName) |
|
||||||
|
@ -1135,21 +1133,21 @@ void out_daap_playlists(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
|
|
||||||
ppi->dq.query_type = QUERY_TYPE_PLAYLISTS;
|
ppi->dq.query_type = QUERY_TYPE_PLAYLISTS;
|
||||||
|
|
||||||
if(_ppi->db_enum_start(&pe,&ppi->dq)) {
|
if(pi_db_enum_start(&pe,&ppi->dq)) {
|
||||||
_ppi->log(E_LOG,"Could not start enum: %s\n",pe);
|
pi_log(E_LOG,"Could not start enum: %s\n",pe);
|
||||||
out_daap_error(pwsc,ppi,"aply",pe);
|
out_daap_error(pwsc,ppi,"aply",pe);
|
||||||
if(pe) free(pe);
|
if(pe) free(pe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(daap_enum_size(NULL,ppi,&pl_count,&list_length)) {
|
if(daap_enum_size(NULL,ppi,&pl_count,&list_length)) {
|
||||||
_ppi->log(E_LOG,"error in enumerating size: %s\n",pe);
|
pi_log(E_LOG,"error in enumerating size: %s\n",pe);
|
||||||
out_daap_error(pwsc,ppi,"aply",pe);
|
out_daap_error(pwsc,ppi,"aply",pe);
|
||||||
if(pe) free(pe);
|
if(pe) free(pe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Item enum: got %d playlists, dmap size: %d\n",pl_count,list_length);
|
pi_log(E_DBG,"Item enum: got %d playlists, dmap size: %d\n",pl_count,list_length);
|
||||||
|
|
||||||
mtco = pl_count;
|
mtco = pl_count;
|
||||||
if((ppi->dq.offset) || (ppi->dq.limit))
|
if((ppi->dq.offset) || (ppi->dq.limit))
|
||||||
|
@ -1169,15 +1167,15 @@ void out_daap_playlists(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) &&
|
while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) &&
|
||||||
(list_length))
|
(list_length))
|
||||||
{
|
{
|
||||||
_ppi->log(E_SPAM,"Got block of size %d\n",list_length);
|
pi_log(E_SPAM,"Got block of size %d\n",list_length);
|
||||||
out_daap_output_write(pwsc,ppi,block,list_length);
|
out_daap_output_write(pwsc,ppi,block,list_length);
|
||||||
free(block);
|
free(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Done enumerating.\n");
|
pi_log(E_DBG,"Done enumerating.\n");
|
||||||
|
|
||||||
_ppi->db_enum_end(NULL);
|
pi_db_enum_end(NULL);
|
||||||
_ppi->db_enum_dispose(NULL,&ppi->dq);
|
pi_db_enum_dispose(NULL,&ppi->dq);
|
||||||
|
|
||||||
out_daap_output_end(pwsc,ppi);
|
out_daap_output_end(pwsc,ppi);
|
||||||
return;
|
return;
|
||||||
|
@ -1192,16 +1190,16 @@ void out_daap_items(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
char *pe = NULL;
|
char *pe = NULL;
|
||||||
int mtco;
|
int mtco;
|
||||||
|
|
||||||
if(_ppi->ws_getvar(pwsc,"meta")) {
|
if(pi_ws_getvar(pwsc,"meta")) {
|
||||||
ppi->meta = daap_encode_meta(_ppi->ws_getvar(pwsc,"meta"));
|
ppi->meta = daap_encode_meta(pi_ws_getvar(pwsc,"meta"));
|
||||||
} else {
|
} else {
|
||||||
ppi->meta = (MetaField_t) -1ll;
|
ppi->meta = (MetaField_t) -1ll;
|
||||||
}
|
}
|
||||||
|
|
||||||
ppi->dq.query_type = QUERY_TYPE_ITEMS;
|
ppi->dq.query_type = QUERY_TYPE_ITEMS;
|
||||||
|
|
||||||
if(_ppi->db_enum_start(&pe,&ppi->dq)) {
|
if(pi_db_enum_start(&pe,&ppi->dq)) {
|
||||||
_ppi->log(E_LOG,"Could not start enum: %s\n",pe);
|
pi_log(E_LOG,"Could not start enum: %s\n",pe);
|
||||||
out_daap_error(pwsc,ppi,"adbs",pe);
|
out_daap_error(pwsc,ppi,"adbs",pe);
|
||||||
if(pe) free(pe);
|
if(pe) free(pe);
|
||||||
return;
|
return;
|
||||||
|
@ -1209,13 +1207,13 @@ void out_daap_items(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
|
|
||||||
/* FIXME: Error handling */
|
/* FIXME: Error handling */
|
||||||
if(daap_enum_size(&pe,ppi,&song_count,&list_length)) {
|
if(daap_enum_size(&pe,ppi,&song_count,&list_length)) {
|
||||||
_ppi->log(E_LOG,"Error getting dmap size: %s\n",pe);
|
pi_log(E_LOG,"Error getting dmap size: %s\n",pe);
|
||||||
out_daap_error(pwsc,ppi,"adbs",pe);
|
out_daap_error(pwsc,ppi,"adbs",pe);
|
||||||
if(pe) free(pe);
|
if(pe) free(pe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Item enum: got %d songs, dmap size: %d\n",song_count,
|
pi_log(E_DBG,"Item enum: got %d songs, dmap size: %d\n",song_count,
|
||||||
list_length);
|
list_length);
|
||||||
|
|
||||||
mtco = song_count;
|
mtco = song_count;
|
||||||
|
@ -1235,13 +1233,13 @@ void out_daap_items(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
/* FIXME: check errors */
|
/* FIXME: check errors */
|
||||||
while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) &&
|
while((daap_enum_fetch(NULL,ppi,&list_length,&block)==0) &&
|
||||||
(list_length)) {
|
(list_length)) {
|
||||||
_ppi->log(E_SPAM,"Got block of size %d\n",list_length);
|
pi_log(E_SPAM,"Got block of size %d\n",list_length);
|
||||||
out_daap_output_write(pwsc,ppi,block,list_length);
|
out_daap_output_write(pwsc,ppi,block,list_length);
|
||||||
free(block);
|
free(block);
|
||||||
}
|
}
|
||||||
_ppi->log(E_DBG,"Done enumerating.\n");
|
pi_log(E_DBG,"Done enumerating.\n");
|
||||||
_ppi->db_enum_end(NULL);
|
pi_db_enum_end(NULL);
|
||||||
_ppi->db_enum_dispose(NULL,&ppi->dq);
|
pi_db_enum_dispose(NULL,&ppi->dq);
|
||||||
out_daap_output_end(pwsc,ppi);
|
out_daap_output_end(pwsc,ppi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1250,18 +1248,18 @@ void out_daap_update(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
unsigned char update_response[32];
|
unsigned char update_response[32];
|
||||||
unsigned char *current=update_response;
|
unsigned char *current=update_response;
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Preparing to send update response\n");
|
pi_log(E_DBG,"Preparing to send update response\n");
|
||||||
_ppi->config_set_status(pwsc,ppi->session_id,"Waiting for DB update");
|
pi_config_set_status(pwsc,ppi->session_id,"Waiting for DB update");
|
||||||
|
|
||||||
if(!_ppi->db_wait_update(pwsc)) {
|
if(!pi_db_wait_update(pwsc)) {
|
||||||
_ppi->log(E_DBG,"Update session stopped\n");
|
pi_log(E_DBG,"Update session stopped\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* otherwise, send the info about this version */
|
/* otherwise, send the info about this version */
|
||||||
current += dmap_add_container(current,"mupd",24);
|
current += dmap_add_container(current,"mupd",24);
|
||||||
current += dmap_add_int(current,"mstt",200); /* 12 */
|
current += dmap_add_int(current,"mstt",200); /* 12 */
|
||||||
current += dmap_add_int(current,"musr",_ppi->db_revision()); /* 12 */
|
current += dmap_add_int(current,"musr",pi_db_revision()); /* 12 */
|
||||||
|
|
||||||
out_daap_output_start(pwsc,ppi,32);
|
out_daap_output_start(pwsc,ppi,32);
|
||||||
out_daap_output_write(pwsc,ppi,update_response,32);
|
out_daap_output_write(pwsc,ppi,update_response,32);
|
||||||
|
@ -1279,7 +1277,7 @@ void out_daap_dbinfo(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
int servername_size;
|
int servername_size;
|
||||||
|
|
||||||
servername_size = sizeof(servername);
|
servername_size = sizeof(servername);
|
||||||
_ppi->server_name(servername,&servername_size);
|
pi_server_name(servername,&servername_size);
|
||||||
|
|
||||||
namelen=(int) strlen(servername);
|
namelen=(int) strlen(servername);
|
||||||
|
|
||||||
|
@ -1293,9 +1291,9 @@ void out_daap_dbinfo(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
current += dmap_add_int(current,"miid",1); /* 12 */
|
current += dmap_add_int(current,"miid",1); /* 12 */
|
||||||
current += dmap_add_long(current,"mper",1); /* 16 */
|
current += dmap_add_long(current,"mper",1); /* 16 */
|
||||||
current += dmap_add_string(current,"minm",servername); /* 8 + namelen */
|
current += dmap_add_string(current,"minm",servername); /* 8 + namelen */
|
||||||
count = _ppi->db_count_items(COUNT_SONGS);
|
count = pi_db_count_items(COUNT_SONGS);
|
||||||
current += dmap_add_int(current,"mimc",count); /* 12 */
|
current += dmap_add_int(current,"mimc",count); /* 12 */
|
||||||
count = _ppi->db_count_items(COUNT_PLAYLISTS);
|
count = pi_db_count_items(COUNT_PLAYLISTS);
|
||||||
current += dmap_add_int(current,"mctc",count); /* 12 */
|
current += dmap_add_int(current,"mctc",count); /* 12 */
|
||||||
|
|
||||||
out_daap_output_start(pwsc,ppi,129+namelen);
|
out_daap_output_start(pwsc,ppi,129+namelen);
|
||||||
|
@ -1306,8 +1304,8 @@ void out_daap_dbinfo(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void out_daap_logout(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
void out_daap_logout(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
_ppi->config_set_status(pwsc,ppi->session_id,NULL);
|
pi_config_set_status(pwsc,ppi->session_id,NULL);
|
||||||
_ppi->ws_returnerror(pwsc,204,"Logout Successful");
|
pi_ws_returnerror(pwsc,204,"Logout Successful");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1368,9 +1366,9 @@ void out_daap_content_codes(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
int out_daap_conf_isset(char *section, char *key) {
|
int out_daap_conf_isset(char *section, char *key) {
|
||||||
char *value;
|
char *value;
|
||||||
|
|
||||||
value = _ppi->conf_alloc_string(section,key,NULL);
|
value = pi_conf_alloc_string(section,key,NULL);
|
||||||
if(value) {
|
if(value) {
|
||||||
_ppi->conf_dispose_string(value);
|
pi_conf_dispose_string(value);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1389,7 +1387,7 @@ void out_daap_server_info(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
int supports_update=0;
|
int supports_update=0;
|
||||||
|
|
||||||
size = sizeof(servername);
|
size = sizeof(servername);
|
||||||
_ppi->server_name(servername,&size);
|
pi_server_name(servername,&size);
|
||||||
// supports_update = conf_get_int("daap","supports_update",1);
|
// supports_update = conf_get_int("daap","supports_update",1);
|
||||||
|
|
||||||
actual_length=139 + (int) strlen(servername);
|
actual_length=139 + (int) strlen(servername);
|
||||||
|
@ -1397,10 +1395,10 @@ void out_daap_server_info(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
actual_length -= 9;
|
actual_length -= 9;
|
||||||
|
|
||||||
if(actual_length > sizeof(server_info)) {
|
if(actual_length > sizeof(server_info)) {
|
||||||
_ppi->log(E_FATAL,"Server name too long.\n");
|
pi_log(E_FATAL,"Server name too long.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
client_version=_ppi->ws_getrequestheader(pwsc,"Client-DAAP-Version");
|
client_version=pi_ws_getrequestheader(pwsc,"Client-DAAP-Version");
|
||||||
|
|
||||||
current += dmap_add_container(current,"msrv",actual_length - 8);
|
current += dmap_add_container(current,"msrv",actual_length - 8);
|
||||||
current += dmap_add_int(current,"mstt",200); /* 12 */
|
current += dmap_add_int(current,"mstt",200); /* 12 */
|
||||||
|
@ -1453,7 +1451,7 @@ void out_daap_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, char *container, char *err
|
||||||
block = (unsigned char *)malloc(len);
|
block = (unsigned char *)malloc(len);
|
||||||
|
|
||||||
if(!block)
|
if(!block)
|
||||||
_ppi->log(E_FATAL,"Malloc error\n");
|
pi_log(E_FATAL,"Malloc error\n");
|
||||||
|
|
||||||
current = block;
|
current = block;
|
||||||
current += dmap_add_container(current,container,len - 8);
|
current += dmap_add_container(current,container,len - 8);
|
||||||
|
@ -1466,7 +1464,7 @@ void out_daap_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, char *container, char *err
|
||||||
|
|
||||||
free(block);
|
free(block);
|
||||||
|
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,5 @@ typedef struct tag_daap_privinfo {
|
||||||
WS_CONNINFO *pwsc;
|
WS_CONNINFO *pwsc;
|
||||||
} PRIVINFO;
|
} PRIVINFO;
|
||||||
|
|
||||||
extern PLUGIN_INPUT_FN *_ppi;
|
|
||||||
|
|
||||||
#endif /* _OUT_DAAP_H_ */
|
#endif /* _OUT_DAAP_H_ */
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ typedef struct tag_rsp_privinfo {
|
||||||
} PRIVINFO;
|
} PRIVINFO;
|
||||||
|
|
||||||
/* Forwards */
|
/* Forwards */
|
||||||
PLUGIN_INFO *plugin_info(PLUGIN_INPUT_FN *);
|
PLUGIN_INFO *plugin_info(void);
|
||||||
void plugin_handler(WS_CONNINFO *pwsc);
|
void plugin_handler(WS_CONNINFO *pwsc);
|
||||||
int plugin_can_handle(WS_CONNINFO *pwsc);
|
int plugin_can_handle(WS_CONNINFO *pwsc);
|
||||||
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password);
|
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password);
|
||||||
|
@ -45,7 +45,6 @@ PLUGIN_REND_INFO _pri[] = {
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INPUT_FN *_ppi;
|
|
||||||
PLUGIN_INFO _pi = {
|
PLUGIN_INFO _pi = {
|
||||||
PLUGIN_VERSION, /* version */
|
PLUGIN_VERSION, /* version */
|
||||||
PLUGIN_OUTPUT, /* type */
|
PLUGIN_OUTPUT, /* type */
|
||||||
|
@ -150,8 +149,7 @@ FIELDSPEC rsp_fields[] = {
|
||||||
/**
|
/**
|
||||||
* return info about this plugin module
|
* return info about this plugin module
|
||||||
*/
|
*/
|
||||||
PLUGIN_INFO *plugin_info(PLUGIN_INPUT_FN *ppi) {
|
PLUGIN_INFO *plugin_info(void) {
|
||||||
_ppi = ppi;
|
|
||||||
return &_pi;
|
return &_pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,8 +157,8 @@ PLUGIN_INFO *plugin_info(PLUGIN_INPUT_FN *ppi) {
|
||||||
* see if the plugin should handle this request
|
* see if the plugin should handle this request
|
||||||
*/
|
*/
|
||||||
int plugin_can_handle(WS_CONNINFO *pwsc) {
|
int plugin_can_handle(WS_CONNINFO *pwsc) {
|
||||||
_ppi->log(E_DBG,"Checking url %s\n",_ppi->ws_uri(pwsc));
|
pi_log(E_DBG,"Checking url %s\n",pi_ws_uri(pwsc));
|
||||||
if(strncasecmp(_ppi->ws_uri(pwsc),"/rsp/",5) == 0)
|
if(strncasecmp(pi_ws_uri(pwsc),"/rsp/",5) == 0)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -170,7 +168,7 @@ int plugin_can_handle(WS_CONNINFO *pwsc) {
|
||||||
* works.
|
* works.
|
||||||
*/
|
*/
|
||||||
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password) {
|
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password) {
|
||||||
return _ppi->ws_matchesrole(pwsc,username,password,"user");
|
return pi_ws_matchesrole(pwsc,username,password,"user");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,39 +181,39 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
||||||
int index, part;
|
int index, part;
|
||||||
int found;
|
int found;
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Getting uri...\n");
|
pi_log(E_DBG,"Getting uri...\n");
|
||||||
|
|
||||||
string = _ppi->ws_uri(pwsc);
|
string = pi_ws_uri(pwsc);
|
||||||
string++;
|
string++;
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Mallocing privinfo...\n");
|
pi_log(E_DBG,"Mallocing privinfo...\n");
|
||||||
ppi = (PRIVINFO *)malloc(sizeof(PRIVINFO));
|
ppi = (PRIVINFO *)malloc(sizeof(PRIVINFO));
|
||||||
if(ppi) {
|
if(ppi) {
|
||||||
memset(ppi,0,sizeof(PRIVINFO));
|
memset(ppi,0,sizeof(PRIVINFO));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ppi) {
|
if(!ppi) {
|
||||||
_ppi->ws_returnerror(pwsc,500,"Malloc error in plugin_handler");
|
pi_ws_returnerror(pwsc,500,"Malloc error in plugin_handler");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset((void*)&ppi->dq,0,sizeof(DB_QUERY));
|
memset((void*)&ppi->dq,0,sizeof(DB_QUERY));
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Tokenizing url\n");
|
pi_log(E_DBG,"Tokenizing url\n");
|
||||||
while((ppi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
|
while((ppi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
|
||||||
string=NULL;
|
string=NULL;
|
||||||
ppi->uri_sections[ppi->uri_count++] = token;
|
ppi->uri_sections[ppi->uri_count++] = token;
|
||||||
}
|
}
|
||||||
|
|
||||||
elements = sizeof(rsp_uri_map) / sizeof(PLUGIN_RESPONSE);
|
elements = sizeof(rsp_uri_map) / sizeof(PLUGIN_RESPONSE);
|
||||||
_ppi->log(E_DBG,"Found %d elements\n",elements);
|
pi_log(E_DBG,"Found %d elements\n",elements);
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
found = 0;
|
found = 0;
|
||||||
|
|
||||||
while((!found) && (index < elements)) {
|
while((!found) && (index < elements)) {
|
||||||
/* test this set */
|
/* test this set */
|
||||||
_ppi->log(E_DBG,"Checking reponse %d\n",index);
|
pi_log(E_DBG,"Checking reponse %d\n",index);
|
||||||
part=0;
|
part=0;
|
||||||
while(part < 10) {
|
while(part < 10) {
|
||||||
if((rsp_uri_map[index].uri[part]) && (!ppi->uri_sections[part]))
|
if((rsp_uri_map[index].uri[part]) && (!ppi->uri_sections[part]))
|
||||||
|
@ -234,7 +232,7 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
||||||
|
|
||||||
if(part == 10) {
|
if(part == 10) {
|
||||||
found = 1;
|
found = 1;
|
||||||
_ppi->log(E_DBG,"Found it! Index: %d\n",index);
|
pi_log(E_DBG,"Found it! Index: %d\n",index);
|
||||||
} else {
|
} else {
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
@ -242,13 +240,13 @@ void plugin_handler(WS_CONNINFO *pwsc) {
|
||||||
|
|
||||||
if(found) {
|
if(found) {
|
||||||
rsp_uri_map[index].dispatch(pwsc, ppi);
|
rsp_uri_map[index].dispatch(pwsc, ppi);
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
free(ppi);
|
free(ppi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rsp_error(pwsc, ppi, 1, "Bad path");
|
rsp_error(pwsc, ppi, 1, "Bad path");
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
free(ppi);
|
free(ppi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -261,7 +259,7 @@ void rsp_info(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
char servername[256];
|
char servername[256];
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Starting rsp_info\n");
|
pi_log(E_DBG,"Starting rsp_info\n");
|
||||||
|
|
||||||
pxml = xml_init(pwsc,1);
|
pxml = xml_init(pwsc,1);
|
||||||
|
|
||||||
|
@ -275,13 +273,13 @@ void rsp_info(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
|
|
||||||
/* info block */
|
/* info block */
|
||||||
xml_push(pxml,"info");
|
xml_push(pxml,"info");
|
||||||
xml_output(pxml,"count","%d",_ppi->db_count());
|
xml_output(pxml,"count","%d",pi_db_count());
|
||||||
xml_output(pxml,"rsp-version","%s",RSP_VERSION);
|
xml_output(pxml,"rsp-version","%s",RSP_VERSION);
|
||||||
|
|
||||||
xml_output(pxml,"server-version","%s",_ppi->server_ver());
|
xml_output(pxml,"server-version","%s",pi_server_ver());
|
||||||
|
|
||||||
size = sizeof(servername);
|
size = sizeof(servername);
|
||||||
_ppi->server_name(servername,&size);
|
pi_server_name(servername,&size);
|
||||||
xml_output(pxml,"name","%s",servername);
|
xml_output(pxml,"name","%s",servername);
|
||||||
xml_pop(pxml); /* info */
|
xml_pop(pxml); /* info */
|
||||||
|
|
||||||
|
@ -303,9 +301,9 @@ void rsp_db(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
|
|
||||||
ppi->dq.query_type = QUERY_TYPE_PLAYLISTS;
|
ppi->dq.query_type = QUERY_TYPE_PLAYLISTS;
|
||||||
|
|
||||||
if((err=_ppi->db_enum_start(&pe,&ppi->dq)) != 0) {
|
if((err=pi_db_enum_start(&pe,&ppi->dq)) != 0) {
|
||||||
rsp_error(pwsc, ppi, err | E_DB, pe);
|
rsp_error(pwsc, ppi, err | E_DB, pe);
|
||||||
_ppi->db_enum_dispose(NULL,&ppi->dq);
|
pi_db_enum_dispose(NULL,&ppi->dq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +319,7 @@ void rsp_db(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
|
|
||||||
xml_push(pxml,"playlists");
|
xml_push(pxml,"playlists");
|
||||||
|
|
||||||
while((_ppi->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
|
while((pi_db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
|
||||||
xml_push(pxml,"playlist");
|
xml_push(pxml,"playlist");
|
||||||
rowindex=0;
|
rowindex=0;
|
||||||
while(rsp_playlist_fields[rowindex].name) {
|
while(rsp_playlist_fields[rowindex].name) {
|
||||||
|
@ -334,8 +332,8 @@ void rsp_db(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
xml_pop(pxml); /* playlist */
|
xml_pop(pxml); /* playlist */
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->db_enum_end(NULL);
|
pi_db_enum_end(NULL);
|
||||||
_ppi->db_enum_dispose(NULL,&ppi->dq);
|
pi_db_enum_dispose(NULL,&ppi->dq);
|
||||||
|
|
||||||
xml_pop(pxml); /* playlists */
|
xml_pop(pxml); /* playlists */
|
||||||
xml_pop(pxml); /* response */
|
xml_pop(pxml); /* response */
|
||||||
|
@ -359,17 +357,17 @@ void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
unsigned int samplerate;
|
unsigned int samplerate;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
|
|
||||||
ppi->dq.filter = _ppi->ws_getvar(pwsc,"query");
|
ppi->dq.filter = pi_ws_getvar(pwsc,"query");
|
||||||
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
|
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
|
||||||
|
|
||||||
if(_ppi->ws_getvar(pwsc,"offset")) {
|
if(pi_ws_getvar(pwsc,"offset")) {
|
||||||
ppi->dq.offset = atoi(_ppi->ws_getvar(pwsc,"offset"));
|
ppi->dq.offset = atoi(pi_ws_getvar(pwsc,"offset"));
|
||||||
}
|
}
|
||||||
if(_ppi->ws_getvar(pwsc,"limit")) {
|
if(pi_ws_getvar(pwsc,"limit")) {
|
||||||
ppi->dq.limit = atoi(_ppi->ws_getvar(pwsc,"limit"));
|
ppi->dq.limit = atoi(pi_ws_getvar(pwsc,"limit"));
|
||||||
}
|
}
|
||||||
|
|
||||||
browse_type = _ppi->ws_getvar(pwsc,"type");
|
browse_type = pi_ws_getvar(pwsc,"type");
|
||||||
type = F_FULL;
|
type = F_FULL;
|
||||||
|
|
||||||
if(browse_type) {
|
if(browse_type) {
|
||||||
|
@ -385,9 +383,9 @@ void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
ppi->dq.query_type = QUERY_TYPE_ITEMS;
|
ppi->dq.query_type = QUERY_TYPE_ITEMS;
|
||||||
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
|
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
|
||||||
|
|
||||||
if((err=_ppi->db_enum_start(&pe,&ppi->dq)) != 0) {
|
if((err=pi_db_enum_start(&pe,&ppi->dq)) != 0) {
|
||||||
rsp_error(pwsc, ppi, err | E_DB, pe);
|
rsp_error(pwsc, ppi, err | E_DB, pe);
|
||||||
_ppi->db_enum_dispose(NULL,&ppi->dq);
|
pi_db_enum_dispose(NULL,&ppi->dq);
|
||||||
free(pe);
|
free(pe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -412,15 +410,15 @@ void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
|
|
||||||
xml_push(pxml,"items");
|
xml_push(pxml,"items");
|
||||||
|
|
||||||
while((!done) && (_ppi->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) &&
|
while((!done) && (pi_db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) &&
|
||||||
(row)) {
|
(row)) {
|
||||||
xml_push(pxml,"item");
|
xml_push(pxml,"item");
|
||||||
rowindex=0;
|
rowindex=0;
|
||||||
transcode = 0;
|
transcode = 0;
|
||||||
|
|
||||||
transcode = _ppi->should_transcode(pwsc,row[37]);
|
transcode = pi_should_transcode(pwsc,row[37]);
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Transcode: %d, %s: %s\n",transcode,row[37],row[2]);
|
pi_log(E_DBG,"Transcode: %d, %s: %s\n",transcode,row[37],row[2]);
|
||||||
|
|
||||||
while(rsp_fields[rowindex].name) {
|
while(rsp_fields[rowindex].name) {
|
||||||
if((rsp_fields[rowindex].flags & type) &&
|
if((rsp_fields[rowindex].flags & type) &&
|
||||||
|
@ -466,7 +464,7 @@ void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
xml_pop(pxml); /* item */
|
xml_pop(pxml); /* item */
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->db_enum_end(NULL);
|
pi_db_enum_end(NULL);
|
||||||
|
|
||||||
xml_pop(pxml); /* items */
|
xml_pop(pxml); /* items */
|
||||||
xml_pop(pxml); /* response */
|
xml_pop(pxml); /* response */
|
||||||
|
@ -483,22 +481,22 @@ void rsp_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
/* this might fail if an unsupported browse type */
|
/* this might fail if an unsupported browse type */
|
||||||
ppi->dq.query_type = QUERY_TYPE_DISTINCT;
|
ppi->dq.query_type = QUERY_TYPE_DISTINCT;
|
||||||
ppi->dq.distinct_field = ppi->uri_sections[3];
|
ppi->dq.distinct_field = ppi->uri_sections[3];
|
||||||
ppi->dq.filter = _ppi->ws_getvar(pwsc,"query");
|
ppi->dq.filter = pi_ws_getvar(pwsc,"query");
|
||||||
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
|
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
|
||||||
|
|
||||||
if(_ppi->ws_getvar(pwsc,"offset")) {
|
if(pi_ws_getvar(pwsc,"offset")) {
|
||||||
ppi->dq.offset = atoi(_ppi->ws_getvar(pwsc,"offset"));
|
ppi->dq.offset = atoi(pi_ws_getvar(pwsc,"offset"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_ppi->ws_getvar(pwsc,"limit")) {
|
if(pi_ws_getvar(pwsc,"limit")) {
|
||||||
ppi->dq.limit = atoi(_ppi->ws_getvar(pwsc,"limit"));
|
ppi->dq.limit = atoi(pi_ws_getvar(pwsc,"limit"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
|
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
|
||||||
|
|
||||||
if((err=_ppi->db_enum_start(&pe,&ppi->dq)) != 0) {
|
if((err=pi_db_enum_start(&pe,&ppi->dq)) != 0) {
|
||||||
rsp_error(pwsc, ppi, err | E_DB, pe);
|
rsp_error(pwsc, ppi, err | E_DB, pe);
|
||||||
_ppi->db_enum_dispose(NULL,&ppi->dq);
|
pi_db_enum_dispose(NULL,&ppi->dq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,12 +520,12 @@ void rsp_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
|
|
||||||
xml_push(pxml,"items");
|
xml_push(pxml,"items");
|
||||||
|
|
||||||
while((_ppi->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
|
while((pi_db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
|
||||||
xml_output(pxml,"item","%s",row[0]);
|
xml_output(pxml,"item","%s",row[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->db_enum_end(NULL);
|
pi_db_enum_end(NULL);
|
||||||
_ppi->db_enum_dispose(NULL,&ppi->dq);
|
pi_db_enum_dispose(NULL,&ppi->dq);
|
||||||
|
|
||||||
xml_pop(pxml); /* items */
|
xml_pop(pxml); /* items */
|
||||||
xml_pop(pxml); /* response */
|
xml_pop(pxml); /* response */
|
||||||
|
@ -535,7 +533,7 @@ void rsp_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void rsp_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
void rsp_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
|
||||||
_ppi->stream(pwsc, ppi->uri_sections[2]);
|
pi_stream(pwsc, ppi->uri_sections[2]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,6 +550,6 @@ void rsp_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, int eno, char *estr) {
|
||||||
xml_pop(pxml); /* status */
|
xml_pop(pxml); /* status */
|
||||||
xml_pop(pxml); /* response */
|
xml_pop(pxml); /* response */
|
||||||
xml_deinit(pxml);
|
xml_deinit(pxml);
|
||||||
_ppi->ws_will_close(pwsc);
|
pi_ws_will_close(pwsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@ int ssc_ffmpeg_open(void *vp, MP3FILE *pmp3) {
|
||||||
handle->first_frame = 1;
|
handle->first_frame = 1;
|
||||||
handle->raw=0;
|
handle->raw=0;
|
||||||
|
|
||||||
_ppi->log(E_DBG,"opening %s\n",file);
|
pi_log(E_DBG,"opening %s\n",file);
|
||||||
|
|
||||||
if(strcasecmp(codec,"flac") == 0) {
|
if(strcasecmp(codec,"flac") == 0) {
|
||||||
handle->raw=1;
|
handle->raw=1;
|
||||||
|
@ -211,7 +211,7 @@ int ssc_ffmpeg_open(void *vp, MP3FILE *pmp3) {
|
||||||
handle->samples = (uint32_t)pmp3->sample_count;
|
handle->samples = (uint32_t)pmp3->sample_count;
|
||||||
handle->sample_rate = pmp3->samplerate;
|
handle->sample_rate = pmp3->samplerate;
|
||||||
|
|
||||||
_ppi->log(E_DBG,"opening file raw\n");
|
pi_log(E_DBG,"opening file raw\n");
|
||||||
handle->pCodec = avcodec_find_decoder(id);
|
handle->pCodec = avcodec_find_decoder(id);
|
||||||
if(!handle->pCodec) {
|
if(!handle->pCodec) {
|
||||||
handle->errnum = SSC_FFMPEG_E_BADCODEC;
|
handle->errnum = SSC_FFMPEG_E_BADCODEC;
|
||||||
|
@ -235,7 +235,7 @@ int ssc_ffmpeg_open(void *vp, MP3FILE *pmp3) {
|
||||||
handle->fin = fopen(file,"rb");
|
handle->fin = fopen(file,"rb");
|
||||||
#endif
|
#endif
|
||||||
if(!handle->fin) {
|
if(!handle->fin) {
|
||||||
_ppi->log(E_DBG,"could not open file\n");
|
pi_log(E_DBG,"could not open file\n");
|
||||||
handle->errnum = SSC_FFMPEG_E_FILEOPEN;
|
handle->errnum = SSC_FFMPEG_E_FILEOPEN;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -243,9 +243,9 @@ int ssc_ffmpeg_open(void *vp, MP3FILE *pmp3) {
|
||||||
/* check to see if there is an id3 tag there... if so, skip it. */
|
/* check to see if there is an id3 tag there... if so, skip it. */
|
||||||
if(fread((unsigned char *)&id3,1,sizeof(id3),handle->fin) != sizeof(id3)) {
|
if(fread((unsigned char *)&id3,1,sizeof(id3),handle->fin) != sizeof(id3)) {
|
||||||
if(ferror(handle->fin)) {
|
if(ferror(handle->fin)) {
|
||||||
_ppi->log(E_LOG,"Error reading file: %s\n",file);
|
pi_log(E_LOG,"Error reading file: %s\n",file);
|
||||||
} else {
|
} else {
|
||||||
_ppi->log(E_LOG,"Short file: %s\n",file);
|
pi_log(E_LOG,"Short file: %s\n",file);
|
||||||
}
|
}
|
||||||
handle->errnum = SSC_FFMPEG_E_FILEOPEN;
|
handle->errnum = SSC_FFMPEG_E_FILEOPEN;
|
||||||
fclose(handle->fin);
|
fclose(handle->fin);
|
||||||
|
@ -255,11 +255,11 @@ int ssc_ffmpeg_open(void *vp, MP3FILE *pmp3) {
|
||||||
|
|
||||||
if(strncmp(id3.id,"ID3",3)==0) {
|
if(strncmp(id3.id,"ID3",3)==0) {
|
||||||
/* found an ID3 header... */
|
/* found an ID3 header... */
|
||||||
_ppi->log(E_DBG,"Found ID3 header\n");
|
pi_log(E_DBG,"Found ID3 header\n");
|
||||||
size = (id3.size[0] << 21 | id3.size[1] << 14 |
|
size = (id3.size[0] << 21 | id3.size[1] << 14 |
|
||||||
id3.size[2] << 7 | id3.size[3]);
|
id3.size[2] << 7 | id3.size[3]);
|
||||||
fseek(handle->fin,size + sizeof(SCAN_ID3HEADER),SEEK_SET);
|
fseek(handle->fin,size + sizeof(SCAN_ID3HEADER),SEEK_SET);
|
||||||
_ppi->log(E_DBG,"Header length: %d\n",size);
|
pi_log(E_DBG,"Header length: %d\n",size);
|
||||||
} else {
|
} else {
|
||||||
fseek(handle->fin,0,SEEK_SET);
|
fseek(handle->fin,0,SEEK_SET);
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,7 @@ int ssc_ffmpeg_open(void *vp, MP3FILE *pmp3) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"opening file with format\n");
|
pi_log(E_DBG,"opening file with format\n");
|
||||||
if(av_open_input_file(&handle->pFmtCtx,file,handle->pFormat,0,NULL) < 0) {
|
if(av_open_input_file(&handle->pFmtCtx,file,handle->pFormat,0,NULL) < 0) {
|
||||||
handle->errnum = SSC_FFMPEG_E_FILEOPEN;
|
handle->errnum = SSC_FFMPEG_E_FILEOPEN;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -501,10 +501,10 @@ int ssc_ffmpeg_read(void *vp, char *buffer, int len) {
|
||||||
byte_rate = sample_rate * channels * bits_per_sample / 8;
|
byte_rate = sample_rate * channels * bits_per_sample / 8;
|
||||||
block_align = channels * bits_per_sample / 8;
|
block_align = channels * bits_per_sample / 8;
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Channels.......: %d\n",channels);
|
pi_log(E_DBG,"Channels.......: %d\n",channels);
|
||||||
_ppi->log(E_DBG,"Sample rate....: %d\n",sample_rate);
|
pi_log(E_DBG,"Sample rate....: %d\n",sample_rate);
|
||||||
_ppi->log(E_DBG,"Bits/Sample....: %d\n",bits_per_sample);
|
pi_log(E_DBG,"Bits/Sample....: %d\n",bits_per_sample);
|
||||||
_ppi->log(E_DBG,"Swab...........: %d\n",handle->swab);
|
pi_log(E_DBG,"Swab...........: %d\n",handle->swab);
|
||||||
|
|
||||||
memcpy(&handle->wav_header[0],"RIFF",4);
|
memcpy(&handle->wav_header[0],"RIFF",4);
|
||||||
_ssc_ffmpeg_le32(&handle->wav_header[4],36 + data_len);
|
_ssc_ffmpeg_le32(&handle->wav_header[4],36 + data_len);
|
||||||
|
|
|
@ -30,7 +30,7 @@ int ssc_script_close(void *vp);
|
||||||
int ssc_script_read(void *vp, char *buffer, int len);
|
int ssc_script_read(void *vp, char *buffer, int len);
|
||||||
char *ssc_script_error(void *vp);
|
char *ssc_script_error(void *vp);
|
||||||
|
|
||||||
PLUGIN_INFO *plugin_info(PLUGIN_INPUT_FN *);
|
PLUGIN_INFO *plugin_info(void);
|
||||||
|
|
||||||
#define infn ((PLUGIN_INPUT_FN *)(_pi.pi))
|
#define infn ((PLUGIN_INPUT_FN *)(_pi.pi))
|
||||||
|
|
||||||
|
@ -44,8 +44,6 @@ PLUGIN_TRANSCODE_FN _ptfn = {
|
||||||
ssc_script_error
|
ssc_script_error
|
||||||
};
|
};
|
||||||
|
|
||||||
PLUGIN_INPUT_FN *_ppi;
|
|
||||||
|
|
||||||
PLUGIN_INFO _pi = {
|
PLUGIN_INFO _pi = {
|
||||||
PLUGIN_VERSION, /* version */
|
PLUGIN_VERSION, /* version */
|
||||||
PLUGIN_TRANSCODE, /* type */
|
PLUGIN_TRANSCODE, /* type */
|
||||||
|
@ -66,21 +64,19 @@ static char *_ssc_script_program = NULL;
|
||||||
/**
|
/**
|
||||||
* return the plugininfo struct to firefly
|
* return the plugininfo struct to firefly
|
||||||
*/
|
*/
|
||||||
PLUGIN_INFO *plugin_info(PLUGIN_INPUT_FN *ppi) {
|
PLUGIN_INFO *plugin_info(void) {
|
||||||
char *codeclist;
|
char *codeclist;
|
||||||
|
|
||||||
_ppi = ppi;
|
_ssc_script_program = pi_conf_alloc_string("general","ssc_prog",NULL);
|
||||||
|
|
||||||
_ssc_script_program = _ppi->conf_alloc_string("general","ssc_prog",NULL);
|
|
||||||
if(!_ssc_script_program) {
|
if(!_ssc_script_program) {
|
||||||
_ppi->log(E_INF,"No ssc program specified for script transcoder.\n");
|
pi_log(E_INF,"No ssc program specified for script transcoder.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: need an unload function to stop leak */
|
/* FIXME: need an unload function to stop leak */
|
||||||
codeclist = _ppi->conf_alloc_string("general","ssc_codectypes",NULL);
|
codeclist = pi_conf_alloc_string("general","ssc_codectypes",NULL);
|
||||||
if(!codeclist) {
|
if(!codeclist) {
|
||||||
_ppi->log(E_INF,"No codectypes specified for script transcoder.\n");
|
pi_log(E_INF,"No codectypes specified for script transcoder.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +157,7 @@ int ssc_script_open(void *vp, MP3FILE *pmp3) {
|
||||||
if(metachars) {
|
if(metachars) {
|
||||||
newpath = (char*)malloc(strlen(file) + metacount + 1);
|
newpath = (char*)malloc(strlen(file) + metacount + 1);
|
||||||
if(!newpath) {
|
if(!newpath) {
|
||||||
_ppi->log(E_FATAL,"ssc_script_open: malloc\n");
|
pi_log(E_FATAL,"ssc_script_open: malloc\n");
|
||||||
}
|
}
|
||||||
src=file;
|
src=file;
|
||||||
dst=newpath;
|
dst=newpath;
|
||||||
|
@ -189,7 +185,7 @@ int ssc_script_open(void *vp, MP3FILE *pmp3) {
|
||||||
sprintf(cmd, "%s \"%s\" 0 %lu.%03lu \"%s\"",
|
sprintf(cmd, "%s \"%s\" 0 %lu.%03lu \"%s\"",
|
||||||
_ssc_script_program, newpath, (unsigned long) duration / 1000,
|
_ssc_script_program, newpath, (unsigned long) duration / 1000,
|
||||||
(unsigned long)duration % 1000, (codec && *codec) ? codec : "*");
|
(unsigned long)duration % 1000, (codec && *codec) ? codec : "*");
|
||||||
_ppi->log(E_INF,"Executing %s\n",cmd);
|
pi_log(E_INF,"Executing %s\n",cmd);
|
||||||
handle->fin = popen(cmd, "r");
|
handle->fin = popen(cmd, "r");
|
||||||
free(newpath);
|
free(newpath);
|
||||||
free(cmd); /* should really have in-place expanded the path */
|
free(cmd); /* should really have in-place expanded the path */
|
||||||
|
|
|
@ -46,8 +46,6 @@ struct tag_xmlstruct {
|
||||||
XML_STREAMBUFFER *psb;
|
XML_STREAMBUFFER *psb;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern PLUGIN_INPUT_FN *_ppi;
|
|
||||||
|
|
||||||
/* Forwards */
|
/* Forwards */
|
||||||
void xml_get_stats(WS_CONNINFO *pwsc);
|
void xml_get_stats(WS_CONNINFO *pwsc);
|
||||||
void xml_set_config(WS_CONNINFO *pwsc);
|
void xml_set_config(WS_CONNINFO *pwsc);
|
||||||
|
@ -72,7 +70,7 @@ int xml_write(XMLSTRUCT *pxml, char *fmt, ...) {
|
||||||
if(!result)
|
if(!result)
|
||||||
result = -1;
|
result = -1;
|
||||||
} else {
|
} else {
|
||||||
result=_ppi->ws_writefd(pxml->pwsc,"%s",buffer);
|
result=pi_ws_writefd(pxml->pwsc,"%s",buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -101,14 +99,14 @@ XML_STREAMBUFFER *xml_stream_open(void) {
|
||||||
|
|
||||||
psb = (XML_STREAMBUFFER*) malloc(sizeof(XML_STREAMBUFFER));
|
psb = (XML_STREAMBUFFER*) malloc(sizeof(XML_STREAMBUFFER));
|
||||||
if(!psb) {
|
if(!psb) {
|
||||||
_ppi->log(E_FATAL,"xml_stream_open: malloc\n");
|
pi_log(E_FATAL,"xml_stream_open: malloc\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
psb->out_buffer = (unsigned char*) malloc(XML_STREAM_BLOCK);
|
psb->out_buffer = (unsigned char*) malloc(XML_STREAM_BLOCK);
|
||||||
psb->in_buffer = (unsigned char*) malloc(XML_STREAM_BLOCK);
|
psb->in_buffer = (unsigned char*) malloc(XML_STREAM_BLOCK);
|
||||||
|
|
||||||
if((!psb->out_buffer) || (!psb->in_buffer)) {
|
if((!psb->out_buffer) || (!psb->in_buffer)) {
|
||||||
_ppi->log(E_FATAL,"xml_stream_open: malloc\n");
|
pi_log(E_FATAL,"xml_stream_open: malloc\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
psb->strm.zalloc = Z_NULL;
|
psb->strm.zalloc = Z_NULL;
|
||||||
|
@ -146,9 +144,9 @@ int xml_stream_write(XMLSTRUCT *pxml, char *out) {
|
||||||
while(!done) {
|
while(!done) {
|
||||||
result = deflate(&psb->strm, Z_NO_FLUSH);
|
result = deflate(&psb->strm, Z_NO_FLUSH);
|
||||||
if(result != Z_OK) {
|
if(result != Z_OK) {
|
||||||
_ppi->log(E_FATAL,"Error in zlib: %d\n",result);
|
pi_log(E_FATAL,"Error in zlib: %d\n",result);
|
||||||
}
|
}
|
||||||
_ppi->ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
|
pi_ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
|
||||||
XML_STREAM_BLOCK-psb->strm.avail_out);
|
XML_STREAM_BLOCK-psb->strm.avail_out);
|
||||||
if(psb->strm.avail_out != 0) {
|
if(psb->strm.avail_out != 0) {
|
||||||
done=1;
|
done=1;
|
||||||
|
@ -175,14 +173,14 @@ int xml_stream_close(XMLSTRUCT *pxml) {
|
||||||
psb->strm.next_in = psb->in_buffer;
|
psb->strm.next_in = psb->in_buffer;
|
||||||
|
|
||||||
deflate(&psb->strm,Z_FINISH);
|
deflate(&psb->strm,Z_FINISH);
|
||||||
_ppi->ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
|
pi_ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
|
||||||
XML_STREAM_BLOCK - psb->strm.avail_out);
|
XML_STREAM_BLOCK - psb->strm.avail_out);
|
||||||
|
|
||||||
if(psb->strm.avail_out != 0)
|
if(psb->strm.avail_out != 0)
|
||||||
done=1;
|
done=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ppi->log(E_DBG,"Done sending xml stream\n");
|
pi_log(E_DBG,"Done sending xml stream\n");
|
||||||
deflateEnd(&psb->strm);
|
deflateEnd(&psb->strm);
|
||||||
if(psb->out_buffer != NULL)
|
if(psb->out_buffer != NULL)
|
||||||
free(psb->out_buffer);
|
free(psb->out_buffer);
|
||||||
|
@ -208,7 +206,7 @@ XMLSTRUCT *xml_init(WS_CONNINFO *pwsc, int emit_header) {
|
||||||
|
|
||||||
pxml=(XMLSTRUCT*)malloc(sizeof(XMLSTRUCT));
|
pxml=(XMLSTRUCT*)malloc(sizeof(XMLSTRUCT));
|
||||||
if(!pxml) {
|
if(!pxml) {
|
||||||
_ppi->log(E_FATAL,"Malloc error\n");
|
pi_log(E_FATAL,"Malloc error\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(pxml,0,sizeof(XMLSTRUCT));
|
memset(pxml,0,sizeof(XMLSTRUCT));
|
||||||
|
@ -216,27 +214,27 @@ XMLSTRUCT *xml_init(WS_CONNINFO *pwsc, int emit_header) {
|
||||||
pxml->pwsc = pwsc;
|
pxml->pwsc = pwsc;
|
||||||
|
|
||||||
/* should we compress output? */
|
/* should we compress output? */
|
||||||
nogzip = _ppi->ws_getvar(pwsc,"nogzip");
|
nogzip = pi_ws_getvar(pwsc,"nogzip");
|
||||||
accept = _ppi->ws_getrequestheader(pwsc,"accept-encoding");
|
accept = pi_ws_getrequestheader(pwsc,"accept-encoding");
|
||||||
|
|
||||||
if((!nogzip) && (accept) && (strcasestr(accept,"gzip"))) {
|
if((!nogzip) && (accept) && (strcasestr(accept,"gzip"))) {
|
||||||
_ppi->log(E_DBG,"Gzipping output\n");
|
pi_log(E_DBG,"Gzipping output\n");
|
||||||
pxml->psb = xml_stream_open();
|
pxml->psb = xml_stream_open();
|
||||||
if(pxml->psb) {
|
if(pxml->psb) {
|
||||||
_ppi->ws_addresponseheader(pwsc,"Content-Encoding","gzip");
|
pi_ws_addresponseheader(pwsc,"Content-Encoding","gzip");
|
||||||
_ppi->ws_addresponseheader(pwsc,"Vary","Accept-Encoding");
|
pi_ws_addresponseheader(pwsc,"Vary","Accept-Encoding");
|
||||||
_ppi->ws_addresponseheader(pwsc,"Connection","Close");
|
pi_ws_addresponseheader(pwsc,"Connection","Close");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the world would be a wonderful place without ie */
|
/* the world would be a wonderful place without ie */
|
||||||
_ppi->ws_addresponseheader(pwsc,"Cache-Control","no-cache");
|
pi_ws_addresponseheader(pwsc,"Cache-Control","no-cache");
|
||||||
_ppi->ws_addresponseheader(pwsc,"Expires","-1");
|
pi_ws_addresponseheader(pwsc,"Expires","-1");
|
||||||
|
|
||||||
if(emit_header) {
|
if(emit_header) {
|
||||||
_ppi->ws_addresponseheader(pwsc,"Content-Type","text/xml; charset=utf-8");
|
pi_ws_addresponseheader(pwsc,"Content-Type","text/xml; charset=utf-8");
|
||||||
_ppi->ws_writefd(pwsc,"HTTP/1.0 200 OK\r\n");
|
pi_ws_writefd(pwsc,"HTTP/1.0 200 OK\r\n");
|
||||||
_ppi->ws_emitheaders(pwsc);
|
pi_ws_emitheaders(pwsc);
|
||||||
|
|
||||||
|
|
||||||
xml_write(pxml,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
xml_write(pxml,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
||||||
|
@ -275,7 +273,7 @@ void xml_pop(XMLSTRUCT *pxml) {
|
||||||
|
|
||||||
pstack=pxml->stack.next;
|
pstack=pxml->stack.next;
|
||||||
if(!pstack) {
|
if(!pstack) {
|
||||||
_ppi->log(E_LOG,"xml_pop: tried to pop an empty stack\n");
|
pi_log(E_LOG,"xml_pop: tried to pop an empty stack\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +324,7 @@ void xml_deinit(XMLSTRUCT *pxml) {
|
||||||
XMLSTACK *pstack;
|
XMLSTACK *pstack;
|
||||||
|
|
||||||
if(pxml->stack.next) {
|
if(pxml->stack.next) {
|
||||||
_ppi->log(E_LOG,"xml_deinit: entries still on stack (%s)\n",
|
pi_log(E_LOG,"xml_deinit: entries still on stack (%s)\n",
|
||||||
pxml->stack.next->tag);
|
pxml->stack.next->tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
77
src/util.c
77
src/util.c
|
@ -13,6 +13,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -23,6 +24,7 @@
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
/* Globals */
|
/* Globals */
|
||||||
pthread_mutex_t util_locks[(int)l_last];
|
pthread_mutex_t util_locks[(int)l_last];
|
||||||
pthread_mutex_t util_mutex = PTHREAD_MUTEX_INITIALIZER;
|
pthread_mutex_t util_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
@ -587,6 +589,81 @@ void util_dispose_split(char **argv) {
|
||||||
free(argv);
|
free(argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a formatted string to an allocated string. Leverage
|
||||||
|
* the existing util_vasprintf to do so
|
||||||
|
*/
|
||||||
|
char *util_asprintf(char *fmt, ...) {
|
||||||
|
char *outbuf;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
ASSERT(fmt);
|
||||||
|
|
||||||
|
if(!fmt)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
va_start(ap,fmt);
|
||||||
|
outbuf = util_vasprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return outbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a formatted string to an allocated string. This deals with
|
||||||
|
* versions of vsnprintf that return either the C99 way, or the pre-C99
|
||||||
|
* way, by increasing the buffer until it works.
|
||||||
|
*
|
||||||
|
* @param
|
||||||
|
* @param fmt format string of print (compatible with printf(2))
|
||||||
|
* @returns TRUE on success
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_VA_COPY
|
||||||
|
# define VA_COPY(a,b) va_copy((a),(b))
|
||||||
|
#else
|
||||||
|
# ifdef HAVE___VA_COPY
|
||||||
|
# define VA_COPY(a,b) __va_copy((a),(b))
|
||||||
|
# else
|
||||||
|
# define VA_COPY(a,b) a=b;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *util_vasprintf(char *fmt, va_list ap) {
|
||||||
|
char *outbuf;
|
||||||
|
char *newbuf;
|
||||||
|
va_list ap2;
|
||||||
|
int size=200;
|
||||||
|
int new_size;
|
||||||
|
|
||||||
|
outbuf = (char*)malloc(size);
|
||||||
|
if(!outbuf)
|
||||||
|
DPRINTF(E_FATAL,L_MISC,"Could not allocate buffer in vasprintf\n");
|
||||||
|
|
||||||
|
VA_COPY(ap2,ap);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
new_size=vsnprintf(outbuf,size,fmt,ap);
|
||||||
|
|
||||||
|
if(new_size > -1 && new_size < size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(new_size > -1)
|
||||||
|
size = new_size + 1;
|
||||||
|
else
|
||||||
|
size *= 2;
|
||||||
|
|
||||||
|
if((newbuf = realloc(outbuf,size)) == NULL) {
|
||||||
|
free(outbuf);
|
||||||
|
DPRINTF(E_FATAL,L_MISC,"malloc error in vasprintf\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
outbuf = newbuf;
|
||||||
|
VA_COPY(ap,ap2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return outbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_MEM
|
#ifdef DEBUG_MEM
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -54,7 +55,8 @@ extern int util_utf16toutf8(unsigned char *utf8, int dlen, unsigned char *utf16,
|
||||||
extern int util_utf16_byte_len(unsigned char *utf16);
|
extern int util_utf16_byte_len(unsigned char *utf16);
|
||||||
|
|
||||||
extern void util_hexdump(unsigned char *block, int len);
|
extern void util_hexdump(unsigned char *block, int len);
|
||||||
|
extern char *util_vasprintf(char *fmt, va_list ap);
|
||||||
|
extern char *util_asprintf(char *fmt, ...);
|
||||||
|
|
||||||
#endif /* _UTIL_H_ */
|
#endif /* _UTIL_H_ */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue