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

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

View File

@@ -6,4 +6,7 @@ rsp_LTLIBRARIES=rsp.la
rsp_la_LDFLAGS=-module -avoid-version
rsp_la_SOURCES = compat.c rsp.c xml-rpc.c
EXTRA_DIST = compat.h rsp.h mtd-plugins.h xml-rpc.h
EXTRA_DIST = compat.h rsp.h mtd-plugins.h xml-rpc.h
AM_CFLAGS = -I..

View File

@@ -1,204 +0,0 @@
/*
* $Id: $
*/
#ifndef _MTD_PLUGINS_H_
#define _MTD_PLUGINS_H_
#define PLUGIN_OUTPUT 1
#define PLUGIN_SCANNER 2
#define PLUGIN_DATABASE 4
#define PLUGIN_EVENT 8
#define PLUGIN_VERSION 1
#define PLUGIN_EVENT_LOG 0
#define PLUGIN_EVENT_FULLSCAN_START 1
#define PLUGIN_EVENT_FULLSCAN_END 2
#define PLUGIN_EVENT_STARTING 3
#define PLUGIN_EVENT_SHUTDOWN 4
#define PLUGIN_EVENT_STARTSTREAM 5
#define PLUGIN_EVENT_ABORTSTREAM 6
#define PLUGIN_EVENT_ENDSTREAM 7
typedef void* PARSETREE;
struct tag_ws_conninfo;
typedef struct tag_ws_conninfo WS_CONNINFO;
typedef struct tag_plugin_output_fn {
void(*handler)(WS_CONNINFO *pwsc);
int(*auth)(WS_CONNINFO *pwsc, char *username, char *pw);
} PLUGIN_OUTPUT_FN;
typedef struct tag_plugin_event_fn {
void(*handler)(int event_id, int intval, void *vp, int len);
} PLUGIN_EVENT_FN;
typedef struct tag_plugin_rend_info {
char *type;
char *txt;
} PLUGIN_REND_INFO;
typedef struct tag_plugin_info {
int version;
int type;
char *server;
char *url; /* regex of namespace to handle if OUTPUT type */
PLUGIN_OUTPUT_FN *output_fns;
PLUGIN_EVENT_FN *event_fns;
void *pi; /* exported functions */
PLUGIN_REND_INFO *rend_info;
} PLUGIN_INFO;
/* xml helpers for output plugins */
/* logging */
#define E_FATAL 0
#define E_LOG 1
#define E_INF 5
#define E_DBG 9
/* db stuff */
typedef enum {
queryTypeItems,
queryTypePlaylists,
queryTypePlaylistItems,
queryTypeBrowseArtists,
queryTypeBrowseAlbums,
queryTypeBrowseGenres,
queryTypeBrowseComposers
} QueryType_t;
typedef enum {
indexTypeNone,
indexTypeFirst,
indexTypeLast,
indexTypeSub
} IndexType_t;
typedef enum {
// generic meta data
metaItemId,
metaItemName,
metaItemKind,
metaPersistentId,
metaContainerItemId,
metaParentContainerId,
firstTypeSpecificMetaId,
// song meta data
metaSongAlbum = firstTypeSpecificMetaId,
metaSongArtist,
metaSongBPM,
metaSongBitRate,
metaSongComment,
metaSongCompilation,
metaSongComposer,
metaSongDataKind,
metaSongDataURL,
metaSongDateAdded,
metaSongDateModified,
metaSongDescription,
metaSongDisabled,
metaSongDiscCount,
metaSongDiscNumber,
metaSongEqPreset,
metaSongFormat,
metaSongGenre,
metaSongGrouping,
metaSongRelativeVolume,
metaSongSampleRate,
metaSongSize,
metaSongStartTime,
metaSongStopTime,
metaSongTime,
metaSongTrackCount,
metaSongTrackNumber,
metaSongUserRating,
metaSongYear,
/* iTunes 4.5 + */
metaSongCodecType,
metaSongCodecSubType,
metaItunesNormVolume,
metaItmsSongId,
metaItmsArtistId,
metaItmsPlaylistId,
metaItmsComposerId,
metaItmsGenreId,
metaItmsStorefrontId,
metaItunesSmartPlaylist,
/* iTunes 5.0 + */
metaSongContentRating,
metaHasChildContainers,
/* iTunes 6.0.2+ */
metaItunesHasVideo,
/* mt-daapd specific */
metaMPlaylistSpec,
metaMPlaylistType
} MetaFieldName_t;
typedef unsigned long long MetaField_t;
typedef struct tag_dbqueryinfo {
QueryType_t query_type;
IndexType_t index_type;
MetaField_t meta;
int zero_length; /* emit zero-length strings? */
int index_low;
int index_high;
int playlist_id;
int db_id;
int session_id;
int want_count;
int specifiedtotalcount;
int uri_count;
char *uri_sections[10];
PARSETREE pt;
void *output_info;
} DBQUERYINFO;
typedef struct tag_plugin_input_fn {
/* webserver helpers */
char* (*ws_uri)(WS_CONNINFO *);
void (*ws_close)(WS_CONNINFO *);
int (*ws_returnerror)(WS_CONNINFO *, int, char *);
char* (*ws_getvar)(WS_CONNINFO *, char *);
int (*ws_writefd)(WS_CONNINFO *, char *, ...);
int (*ws_addresponseheader)(WS_CONNINFO *, char *, char *, ...);
void (*ws_emitheaders)(WS_CONNINFO *);
int (*ws_fd)(WS_CONNINFO *);
char* (*ws_getrequestheader)(WS_CONNINFO *, char *);
int (*ws_writebinary)(WS_CONNINFO *, char *, int);
/* misc helpers */
char* (*server_ver)(void);
int (*server_name)(char *, int *);
void (*log)(int, char *, ...);
int (*db_count)(void);
int (*db_enum_start)(char **, DBQUERYINFO *);
int (*db_enum_fetch_row)(char **, char ***, DBQUERYINFO *);
int (*db_enum_end)(char **);
void (*stream)(WS_CONNINFO *, DBQUERYINFO *, char *);
PARSETREE (*sp_init)(void);
int (*sp_parse)(PARSETREE tree, char *term);
int (*sp_dispose)(PARSETREE tree);
char* (*sp_get_error)(PARSETREE tree);
char *(*conf_alloc_string)(char *, char *, char *);
void (*conf_dispose_string)(char *);
} PLUGIN_INPUT_FN;
/* these are the functions that must be exported by the plugin */
PLUGIN_INFO *plugin_info(void);
#endif /* _MTD_PLUGINS_H_ */

View File

@@ -11,20 +11,26 @@
#include <string.h>
#include "compat.h"
#include "mtd-plugins.h"
#include "ff-plugins.h"
#include "rsp.h"
#include "xml-rpc.h"
typedef struct tag_rsp_privinfo {
DB_QUERY dq;
int uri_count;
char *uri_sections[10];
} PRIVINFO;
/* Forwards */
PLUGIN_INFO *plugin_info(void);
void plugin_handler(WS_CONNINFO *pwsc);
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *pw);
void rsp_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
void rsp_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
void rsp_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi);
void rsp_error(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, int eno, char *estr);
void rsp_info(WS_CONNINFO *pwsc, PRIVINFO *ppi);
void rsp_db(WS_CONNINFO *pwsc, PRIVINFO *ppi);
void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi);
void rsp_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi);
void rsp_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi);
void rsp_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, int eno, char *estr);
/* Globals */
PLUGIN_OUTPUT_FN _pofn = { plugin_handler, plugin_auth };
@@ -34,19 +40,21 @@ PLUGIN_REND_INFO _pri[] = {
};
PLUGIN_INFO _pi = {
PLUGIN_VERSION,
PLUGIN_OUTPUT,
"rsp/" RSP_VERSION,
"/rsp/.*",
&_pofn,
NULL,
NULL,
_pri
PLUGIN_VERSION, /* version */
PLUGIN_OUTPUT, /* type */
"rsp/" RSP_VERSION, /* server */
"/rsp/.*", /* url */
&_pofn, /* output fns */
NULL, /* event fns */
NULL, /* transcode fns */
NULL, /* ff functions */
_pri, /* rend info */
NULL /* transcode info */
};
typedef struct tag_response {
char *uri[10];
void (*dispatch)(WS_CONNINFO *, DBQUERYINFO *);
void (*dispatch)(WS_CONNINFO *, PRIVINFO *);
} PLUGIN_RESPONSE;
@@ -155,26 +163,30 @@ int plugin_auth(WS_CONNINFO *pwsc, char *username, char *pw) {
*/
void plugin_handler(WS_CONNINFO *pwsc) {
char *string, *save, *token;
DBQUERYINFO *pqi;
PRIVINFO *ppi;
int elements;
int index, part;
int found;
string = infn->ws_uri(pwsc);
string++;
ppi = (PRIVINFO *)malloc(sizeof(PRIVINFO));
if(ppi) {
memset(ppi,0,sizeof(PRIVINFO));
}
pqi = (DBQUERYINFO *)malloc(sizeof(DBQUERYINFO));
if(!pqi) {
if(!ppi) {
infn->ws_returnerror(pwsc,500,"Malloc error in plugin_handler");
return;
}
memset(pqi,0,sizeof(DBQUERYINFO));
memset((void*)&ppi->dq,0,sizeof(DB_QUERY));
infn->log(E_DBG,"Tokenizing url\n");
while((pqi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
while((ppi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
string=NULL;
pqi->uri_sections[pqi->uri_count++] = token;
ppi->uri_sections[ppi->uri_count++] = token;
}
elements = sizeof(rsp_uri_map) / sizeof(PLUGIN_RESPONSE);
@@ -188,15 +200,15 @@ void plugin_handler(WS_CONNINFO *pwsc) {
infn->log(E_DBG,"Checking reponse %d\n",index);
part=0;
while(part < 10) {
if((rsp_uri_map[index].uri[part]) && (!pqi->uri_sections[part]))
if((rsp_uri_map[index].uri[part]) && (!ppi->uri_sections[part]))
break;
if((pqi->uri_sections[part]) && (!rsp_uri_map[index].uri[part]))
if((ppi->uri_sections[part]) && (!rsp_uri_map[index].uri[part]))
break;
if((rsp_uri_map[index].uri[part]) &&
(strcmp(rsp_uri_map[index].uri[part],"*") != 0)) {
if(strcmp(rsp_uri_map[index].uri[part],
pqi->uri_sections[part])!= 0)
ppi->uri_sections[part])!= 0)
break;
}
part++;
@@ -211,20 +223,22 @@ void plugin_handler(WS_CONNINFO *pwsc) {
}
if(found) {
rsp_uri_map[index].dispatch(pwsc, pqi);
rsp_uri_map[index].dispatch(pwsc, ppi);
infn->ws_close(pwsc);
free(ppi);
return;
}
rsp_error(pwsc, pqi, 1, "Bad path");
rsp_error(pwsc, ppi, 1, "Bad path");
infn->ws_close(pwsc);
free(ppi);
return;
}
/**
* get server info
*/
void rsp_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
void rsp_info(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
XMLSTRUCT *pxml;
char servername[256];
int size;
@@ -262,17 +276,18 @@ void rsp_info(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
*
* dump details about all playlists
*/
void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
void rsp_db(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
XMLSTRUCT *pxml;
char *pe;
int err;
char **row;
int rowindex;
pqi->want_count = 1;
pqi->query_type = queryTypePlaylists;
if((err=infn->db_enum_start(&pe,pqi)) != 0) {
rsp_error(pwsc, pqi, err | E_DB, pe);
ppi->dq.query_type = QUERY_TYPE_PLAYLISTS;
if((err=infn->db_enum_start(&pe,&ppi->dq)) != 0) {
rsp_error(pwsc, ppi, err | E_DB, pe);
infn->db_enum_dispose(NULL,&ppi->dq);
return;
}
@@ -282,13 +297,13 @@ void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
xml_push(pxml,"status");
xml_output(pxml,"errorcode","0");
xml_output(pxml,"errorstring","");
xml_output(pxml,"records","%d",pqi->specifiedtotalcount);
xml_output(pxml,"totalrecords","%d",pqi->specifiedtotalcount);
xml_output(pxml,"records","%d",ppi->dq.totalcount);
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
xml_pop(pxml); /* status */
xml_push(pxml,"playlists");
while((infn->db_enum_fetch_row(NULL,&row,pqi) == 0) && (row)) {
while((infn->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
xml_push(pxml,"playlist");
rowindex=0;
while(rsp_playlist_fields[rowindex].name) {
@@ -302,6 +317,7 @@ void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
}
infn->db_enum_end(NULL);
infn->db_enum_dispose(NULL,&ppi->dq);
xml_pop(pxml); /* playlists */
xml_pop(pxml); /* response */
@@ -312,7 +328,7 @@ void rsp_db(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
/**
* get all items under the playlist
*/
void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
XMLSTRUCT *pxml;
char *pe;
int err;
@@ -321,8 +337,6 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
int returned;
char *browse_type;
int type;
char *query;
char *estr = NULL;
char *transcode_codecs;
int transcode;
int samplerate;
@@ -341,30 +355,15 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
}
*/
query = infn->ws_getvar(pwsc,"query");
if(query) {
pqi->pt = infn->sp_init();
if(!infn->sp_parse(pqi->pt,query)) {
estr = strdup(infn->sp_get_error(pqi->pt));
infn->log(E_LOG,"Ignoring bad query (%s): %s\n",query,estr);
infn->sp_dispose(pqi->pt);
pqi->pt = NULL;
}
}
ppi->dq.filter = infn->ws_getvar(pwsc,"query");
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
pqi->index_type = indexTypeNone;
if(infn->ws_getvar(pwsc,"offset")) {
pqi->index_low = atoi(infn->ws_getvar(pwsc,"offset"));
ppi->dq.offset = atoi(infn->ws_getvar(pwsc,"offset"));
}
if(infn->ws_getvar(pwsc,"limit")) {
pqi->index_high = pqi->index_low + atoi(infn->ws_getvar(pwsc,"limit")) -1;
if(pqi->index_high < pqi->index_low) {
pqi->index_high = 999999;
}
} else {
pqi->index_high = 999999; /* FIXME */
ppi->dq.limit = atoi(infn->ws_getvar(pwsc,"limit"));
}
pqi->index_type = indexTypeSub;
browse_type = infn->ws_getvar(pwsc,"type");
type = F_FULL;
@@ -376,26 +375,24 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
type = F_ID;
}
}
ppi->dq.query_type = QUERY_TYPE_ITEMS;
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
pqi->want_count = 1;
pqi->query_type = queryTypePlaylistItems;
pqi->playlist_id = atoi(pqi->uri_sections[2]);
if((err=infn->db_enum_start(&pe,pqi)) != 0) {
if(pqi->pt) infn->sp_dispose(pqi->pt);
if(estr) free(estr);
rsp_error(pwsc, pqi, err | E_DB, pe);
if((err=infn->db_enum_start(&pe,&ppi->dq)) != 0) {
rsp_error(pwsc, ppi, err | E_DB, pe);
infn->db_enum_dispose(NULL,&ppi->dq);
free(pe);
return;
}
pxml = xml_init(pwsc,1);
if(pqi->index_low > pqi->specifiedtotalcount) {
if(ppi->dq.offset > ppi->dq.totalcount) {
returned = 0;
} else {
returned = pqi->index_high - pqi->index_low + 1;
if(returned > (pqi->specifiedtotalcount - pqi->index_low))
returned = pqi->specifiedtotalcount - pqi->index_low;
returned = ppi->dq.limit;
if(returned > (ppi->dq.totalcount - ppi->dq.offset))
returned = ppi->dq.totalcount - ppi->dq.offset;
}
transcode_codecs = infn->conf_alloc_string("general","ssc_codectypes","");
@@ -403,14 +400,14 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
xml_push(pxml,"response");
xml_push(pxml,"status");
xml_output(pxml,"errorcode","0");
xml_output(pxml,"errorstring",estr ? estr : "");
xml_output(pxml,"errorstring","");
xml_output(pxml,"records","%d",returned);
xml_output(pxml,"totalrecords","%d",pqi->specifiedtotalcount);
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
xml_pop(pxml); /* status */
xml_push(pxml,"items");
while((infn->db_enum_fetch_row(NULL,&row,pqi) == 0) && (row)) {
while((infn->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
xml_push(pxml,"item");
rowindex=0;
transcode = 0;
@@ -462,108 +459,75 @@ void rsp_playlist(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
xml_pop(pxml); /* items */
xml_pop(pxml); /* response */
xml_deinit(pxml);
if(pqi->pt) infn->sp_dispose(pqi->pt);
if(estr) free(estr);
}
void rsp_browse(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
void rsp_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
XMLSTRUCT *pxml;
char *pe;
int err;
char **row;
int returned;
char *query;
char *estr = NULL;
/* FIXME */
if(!strcmp(pqi->uri_sections[3],"artist")) {
pqi->query_type = queryTypeBrowseArtists;
} else if(!strcmp(pqi->uri_sections[3],"genre")) {
pqi->query_type = queryTypeBrowseGenres;
} else if(!strcmp(pqi->uri_sections[3],"album")) {
pqi->query_type = queryTypeBrowseAlbums;
} else if(!strcmp(pqi->uri_sections[3],"composer")) {
pqi->query_type = queryTypeBrowseComposers;
} else {
rsp_error(pwsc, pqi, 0 | E_RSP, "Unsupported browse type");
return;
/* this might fail if an unsupported browse type */
ppi->dq.query_type = QUERY_TYPE_DISTINCT;
ppi->dq.distinct_field = ppi->uri_sections[3];
ppi->dq.filter = infn->ws_getvar(pwsc,"query");
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
if(infn->ws_getvar(pwsc,"offset")) {
ppi->dq.offset = atoi(infn->ws_getvar(pwsc,"offset"));
}
query = infn->ws_getvar(pwsc,"query");
if(query) {
pqi->pt = infn->sp_init();
if(!infn->sp_parse(pqi->pt,query)) {
estr = strdup(infn->sp_get_error(pqi->pt));
infn->log(E_LOG,"Ignoring bad query (%s): %s\n",query,estr);
infn->sp_dispose(pqi->pt);
pqi->pt = NULL;
}
}
pqi->index_type = indexTypeNone;
if(infn->ws_getvar(pwsc,"offset")) {
pqi->index_low = atoi(infn->ws_getvar(pwsc,"offset"));
}
if(infn->ws_getvar(pwsc,"limit")) {
pqi->index_high = pqi->index_low + atoi(infn->ws_getvar(pwsc,"limit")) -1;
if(pqi->index_high < pqi->index_low) {
pqi->index_high = 999999;
}
} else {
pqi->index_high = 999999; /* FIXME */
ppi->dq.limit = atoi(infn->ws_getvar(pwsc,"limit"));
}
pqi->index_type = indexTypeSub;
pqi->want_count = 1;
pqi->playlist_id = atoi(pqi->uri_sections[2]);
if((err=infn->db_enum_start(&pe,pqi)) != 0) {
if(pqi->pt) infn->sp_dispose(pqi->pt);
if(estr) free(estr);
rsp_error(pwsc, pqi, err | E_DB, pe);
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
if((err=infn->db_enum_start(&pe,&ppi->dq)) != 0) {
rsp_error(pwsc, ppi, err | E_DB, pe);
infn->db_enum_dispose(NULL,&ppi->dq);
return;
}
pxml = xml_init(pwsc,1);
if(pqi->index_low > pqi->specifiedtotalcount) {
if(ppi->dq.offset > ppi->dq.totalcount) {
returned = 0;
} else {
returned = pqi->index_high - pqi->index_low + 1;
if(returned > (pqi->specifiedtotalcount - pqi->index_low))
returned = pqi->specifiedtotalcount - pqi->index_low;
returned = ppi->dq.limit;
if(returned > (ppi->dq.totalcount - ppi->dq.offset))
returned = ppi->dq.totalcount - ppi->dq.offset;
}
xml_push(pxml,"response");
xml_push(pxml,"status");
xml_output(pxml,"errorcode","0");
xml_output(pxml,"errorstring",estr ? estr : "");
xml_output(pxml,"errorstring","");
xml_output(pxml,"records","%d",returned);
xml_output(pxml,"totalrecords","%d",pqi->specifiedtotalcount);
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
xml_pop(pxml); /* status */
xml_push(pxml,"items");
while((infn->db_enum_fetch_row(NULL,&row,pqi) == 0) && (row)) {
while((infn->db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
xml_output(pxml,"item",row[0]);
}
infn->db_enum_end(NULL);
infn->db_enum_dispose(NULL,&ppi->dq);
xml_pop(pxml); /* items */
xml_pop(pxml); /* response */
xml_deinit(pxml);
if(pqi->pt) infn->sp_dispose(pqi->pt);
if(estr) free(estr);
}
void rsp_stream(WS_CONNINFO *pwsc, DBQUERYINFO *pqi) {
infn->stream(pwsc, pqi, pqi->uri_sections[2]);
void rsp_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
infn->stream(pwsc, ppi->uri_sections[2]);
return;
}
void rsp_error(WS_CONNINFO *pwsc, DBQUERYINFO *pqi, int eno, char *estr) {
void rsp_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, int eno, char *estr) {
XMLSTRUCT *pxml;
pxml = xml_init(pwsc, 1);

View File

@@ -16,10 +16,11 @@
#include <zlib.h>
#include "compat.h"
#include "mtd-plugins.h"
#include "ff-plugins.h"
#include "rsp.h"
#include "xml-rpc.h"
/* typedefs */
typedef struct tag_xmlstack {
char *tag;
@@ -135,7 +136,8 @@ int xml_stream_write(XMLSTRUCT *pxml, char *out) {
if(result != Z_OK) {
infn->log(E_FATAL,"Error in zlib: %d\n",result);
}
infn->ws_writebinary(pxml->pwsc,psb->out_buffer,XML_STREAM_BLOCK-psb->strm.avail_out);
infn->ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
XML_STREAM_BLOCK-psb->strm.avail_out);
if(psb->strm.avail_out != 0) {
done=1;
} else {
@@ -161,7 +163,8 @@ int xml_stream_close(XMLSTRUCT *pxml) {
psb->strm.next_in = psb->in_buffer;
deflate(&psb->strm,Z_FINISH);
infn->ws_writebinary(pxml->pwsc,psb->out_buffer,XML_STREAM_BLOCK - psb->strm.avail_out);
infn->ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
XML_STREAM_BLOCK - psb->strm.avail_out);
if(psb->strm.avail_out != 0)
done=1;

View File

@@ -5,10 +5,11 @@
#ifndef _XMLRPC_H_
#define _XMLRPC_H_
#include "mtd-plugins.h"
#include "ff-plugins.h"
struct tag_xmlstruct;
typedef struct tag_xmlstruct XMLSTRUCT;
typedef struct tag_ws_conninfo WS_CONNINFO;
extern XMLSTRUCT *xml_init(WS_CONNINFO *pwsc, int emit_header);
extern void xml_push(XMLSTRUCT *pxml, char *term);