Remove RSP output plugin

This commit is contained in:
Julien BLACHE 2009-05-03 11:00:37 +02:00
parent ef1c2b2b89
commit 2be04db4d2
5 changed files with 0 additions and 990 deletions

View File

@ -1,11 +1,3 @@
rspdir = ${pkglibdir}/plugins
rsp_LTLIBRARIES=rsp.la
rsp_la_LDFLAGS=-module -avoid-version
rsp_la_SOURCES = rsp.c xml-rpc.c
EXTRA_DIST = rsp.h xml-rpc.h
AM_CFLAGS = -I..

View File

@ -1,559 +0,0 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ff-dbstruct.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_can_handle(WS_CONNINFO *pwsc);
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password);
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_can_handle, plugin_handler, plugin_auth };
PLUGIN_REND_INFO _pri[] = {
{ "_rsp._tcp", NULL },
{ NULL, NULL }
};
PLUGIN_INFO _pi = {
PLUGIN_VERSION, /* version */
PLUGIN_OUTPUT, /* type */
"rsp/" VERSION, /* server */
&_pofn, /* output fns */
NULL, /* event fns */
NULL, /* transcode fns */
_pri, /* rend info */
NULL /* transcode info */
};
typedef struct tag_response {
char *uri[10];
void (*dispatch)(WS_CONNINFO *, PRIVINFO *);
} PLUGIN_RESPONSE;
PLUGIN_RESPONSE rsp_uri_map[] = {
{{"rsp", "info",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }, rsp_info },
{{"rsp", "db" ,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL }, rsp_db },
{{"rsp", "db" , "*",NULL,NULL,NULL,NULL,NULL,NULL,NULL }, rsp_playlist },
{{"rsp", "db" , "*", "*",NULL,NULL,NULL,NULL,NULL,NULL }, rsp_browse },
{{"rsp","stream", "*",NULL,NULL,NULL,NULL,NULL,NULL,NULL }, rsp_stream }
};
#define E_RSP 0x0000
#define E_DB 0x1000
#define T_STRING 0
#define T_INT 1
#define T_DATE 2
#define F_FULL 1
#define F_BROWSE 2
#define F_ID 4
#define F_DETAILED 8
typedef struct tag_fieldspec {
char *name;
int flags; /* 1: full, 2: browse, 4: id */
int type; /* 0: string, 1: int, 2: date */
} FIELDSPEC;
FIELDSPEC rsp_playlist_fields[] = {
{ "id" , 15, T_INT },
{ "title" , 11, T_STRING },
{ "type" , 8, T_INT },
{ "items" , 11, T_INT },
{ "query" , 8, T_STRING },
{ "db_timestamp" , 8, T_DATE },
{ "path" , 8, T_STRING },
{ "index" , 8, T_INT },
{ NULL , 0, 0 }
};
FIELDSPEC rsp_fields[] = {
{ "id" , 15, T_INT },
{ "path" , 8, T_STRING },
{ "fname" , 8, T_STRING },
{ "title" , 15, T_STRING },
{ "artist" , 11, T_STRING },
{ "album" , 11, T_STRING },
{ "genre" , 9, T_STRING },
{ "comment" , 9, T_STRING },
{ "type" , 15, T_STRING },
{ "composer" , 9, T_STRING },
{ "orchestra" , 9, T_STRING },
{ "conductor" , 9, T_STRING },
{ "grouping" , 0, T_STRING },
{ "url" , 9, T_STRING },
{ "bitrate" , 9, T_INT },
{ "samplerate" , 9, T_INT },
{ "song_length" , 9, T_INT },
{ "file_size" , 9, T_INT },
{ "year" , 9, T_INT },
{ "track" , 11, T_INT },
{ "total_tracks" , 9, T_INT },
{ "disc" , 11, T_INT },
{ "total_discs" , 9, T_INT },
{ "bpm" , 9, T_INT },
{ "compilation" , 9, T_INT },
{ "rating" , 9, T_INT },
{ "play_count" , 9, T_INT },
{ "data_kind" , 8, T_INT },
{ "item_kind" , 8, T_INT },
{ "description" , 9, T_STRING },
{ "time_added" , 9, T_DATE },
{ "time_modified", 9, T_DATE },
{ "time_played" , 9, T_DATE },
{ "db_timestamp" , 8, T_DATE },
{ "disabled" , 15, T_INT },
{ "sample_count" , 8, T_INT },
{ "force_update" , 8, T_INT },
{ "codectype" , 15, T_INT },
{ "idx" , 8, T_INT },
{ "has_video" , 8, T_INT },
{ "contentrating", 8, T_INT },
{ NULL , 0 }
};
/**
* return info about this plugin module
*/
PLUGIN_INFO *plugin_info(void) {
return &_pi;
}
/**
* see if the plugin should handle this request
*/
int plugin_can_handle(WS_CONNINFO *pwsc) {
pi_log(E_DBG,"Checking url %s\n",pi_ws_uri(pwsc));
if(strncasecmp(pi_ws_uri(pwsc),"/rsp/",5) == 0)
return TRUE;
return FALSE;
}
/**
* check for auth. Kind of a ham-handed implementation, but
* works.
*/
int plugin_auth(WS_CONNINFO *pwsc, char *username, char *password) {
return pi_ws_matchesrole(pwsc,username,password,"user");
}
/**
* dispatch handler for web stuff
*/
void plugin_handler(WS_CONNINFO *pwsc) {
char *string, *save, *token;
PRIVINFO *ppi;
int elements;
int index, part;
int found;
pi_log(E_DBG,"Getting uri...\n");
string = pi_ws_uri(pwsc);
string++;
pi_log(E_DBG,"Mallocing privinfo...\n");
ppi = (PRIVINFO *)malloc(sizeof(PRIVINFO));
if(ppi) {
memset(ppi,0,sizeof(PRIVINFO));
}
if(!ppi) {
pi_ws_returnerror(pwsc,500,"Malloc error in plugin_handler");
return;
}
memset((void*)&ppi->dq,0,sizeof(DB_QUERY));
pi_log(E_DBG,"Tokenizing url\n");
save = NULL;
while((ppi->uri_count < 10) && (token=strtok_r(string,"/",&save))) {
string=NULL;
ppi->uri_sections[ppi->uri_count++] = token;
}
elements = sizeof(rsp_uri_map) / sizeof(PLUGIN_RESPONSE);
pi_log(E_DBG,"Found %d elements\n",elements);
index = 0;
found = 0;
while((!found) && (index < elements)) {
/* test this set */
pi_log(E_DBG,"Checking reponse %d\n",index);
part=0;
while(part < 10) {
if((rsp_uri_map[index].uri[part]) && (!ppi->uri_sections[part]))
break;
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],
ppi->uri_sections[part])!= 0)
break;
}
part++;
}
if(part == 10) {
found = 1;
pi_log(E_DBG,"Found it! Index: %d\n",index);
} else {
index++;
}
}
if(found) {
rsp_uri_map[index].dispatch(pwsc, ppi);
pi_ws_will_close(pwsc);
free(ppi);
return;
}
rsp_error(pwsc, ppi, 1, "Bad path");
pi_ws_will_close(pwsc);
free(ppi);
return;
}
/**
* get server info
*/
void rsp_info(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
XMLSTRUCT *pxml;
char servername[256];
int size;
pi_log(E_DBG,"Starting rsp_info\n");
pi_config_set_status(pwsc,0,"Getting server info");
pxml = xml_init(pwsc,1);
xml_push(pxml,"response");
xml_push(pxml,"status");
xml_output(pxml,"errorcode","0");
xml_output(pxml,"errorstring","");
xml_output(pxml,"records","0");
xml_output(pxml,"totalrecords","0");
xml_pop(pxml); /* status */
/* info block */
xml_push(pxml,"info");
xml_output(pxml,"count","%d",pi_db_count_items(COUNT_SONGS));
xml_output(pxml,"rsp-version","%s",RSP_VERSION);
xml_output(pxml,"server-version","%s",pi_server_ver());
size = sizeof(servername);
pi_server_name(servername,&size);
xml_output(pxml,"name","%s",servername);
xml_pop(pxml); /* info */
xml_pop(pxml); /* response */
xml_deinit(pxml);
pi_config_set_status(pwsc,0,NULL);
}
/**
* /rsp/db
*
* dump details about all playlists
*/
void rsp_db(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
XMLSTRUCT *pxml;
char *pe;
int err;
char **row;
int rowindex;
ppi->dq.query_type = QUERY_TYPE_PLAYLISTS;
if((err=pi_db_enum_start(&pe,&ppi->dq)) != 0) {
rsp_error(pwsc, ppi, err | E_DB, pe);
pi_db_enum_dispose(NULL,&ppi->dq);
return;
}
pi_config_set_status(pwsc,0,"Fetching playlist info");
pxml = xml_init(pwsc,1);
xml_push(pxml,"response");
xml_push(pxml,"status");
xml_output(pxml,"errorcode","0");
xml_output(pxml,"errorstring","");
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((pi_db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
xml_push(pxml,"playlist");
rowindex=0;
while(rsp_playlist_fields[rowindex].name) {
if(rsp_playlist_fields[rowindex].flags & F_FULL) {
xml_output(pxml,rsp_playlist_fields[rowindex].name,"%s",
row[rowindex]);
}
rowindex++;
}
xml_pop(pxml); /* playlist */
}
pi_db_enum_end(NULL);
pi_db_enum_dispose(NULL,&ppi->dq);
xml_pop(pxml); /* playlists */
xml_pop(pxml); /* response */
xml_deinit(pxml);
pi_config_set_status(pwsc,0,NULL);
}
/**
* get all items under the playlist
*/
void rsp_playlist(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
XMLSTRUCT *pxml;
char *pe;
int err;
char **row;
int rowindex;
int returned;
char *browse_type;
int type;
int transcode;
unsigned int samplerate;
int done = 0;
ppi->dq.filter = pi_ws_getvar(pwsc,"query");
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
if(pi_ws_getvar(pwsc,"offset")) {
ppi->dq.offset = atoi(pi_ws_getvar(pwsc,"offset"));
}
if(pi_ws_getvar(pwsc,"limit")) {
ppi->dq.limit = atoi(pi_ws_getvar(pwsc,"limit"));
}
browse_type = pi_ws_getvar(pwsc,"type");
type = F_FULL;
if(browse_type) {
if(strcasecmp(browse_type,"browse") == 0) {
type = F_BROWSE;
} else if(strcasecmp(browse_type,"id") == 0) {
type = F_ID;
} else if(strcasecmp(browse_type,"detailed") ==0) {
type = F_DETAILED;
}
}
ppi->dq.query_type = QUERY_TYPE_ITEMS;
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
if((err=pi_db_enum_start(&pe,&ppi->dq)) != 0) {
rsp_error(pwsc, ppi, err | E_DB, pe);
pi_db_enum_dispose(NULL,&ppi->dq);
free(pe);
return;
}
pi_config_set_status(pwsc,0,"Fetching playlist items");
pxml = xml_init(pwsc,1);
if(ppi->dq.offset > ppi->dq.totalcount) {
returned = 0;
} else {
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","");
xml_output(pxml,"records","%d",returned);
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
xml_pop(pxml); /* status */
xml_push(pxml,"items");
while((!done) && (pi_db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) &&
(row)) {
xml_push(pxml,"item");
rowindex=0;
transcode = 0;
transcode = pi_should_transcode(pwsc,row[37]);
pi_log(E_DBG,"Transcode: %d, %s: %s\n",transcode,row[37],row[2]);
while(rsp_fields[rowindex].name) {
if((rsp_fields[rowindex].flags & type) &&
(row[rowindex] && strlen(row[rowindex]))) {
if(transcode) {
switch(rowindex) {
case 8:
xml_output(pxml,rsp_fields[rowindex].name,"%s","wav");
break;
case 29:
xml_output(pxml,rsp_fields[rowindex].name,"%s",
"wav audio file");
break;
case 14: /* bitrate */
samplerate = atoi(row[15]);
if(samplerate) {
samplerate = (samplerate * 8) / 250;
} else {
samplerate = 1411;
}
xml_output(pxml,rsp_fields[rowindex].name,"%d",
samplerate);
break;
case 37:
xml_output(pxml,rsp_fields[rowindex].name,"%s","wav");
xml_output(pxml,"original_codec","%s",row[37]);
break;
default:
xml_output(pxml,rsp_fields[rowindex].name,"%s",
row[rowindex]);
break;
}
} else {
/* check for pushing against closed socket */
if(xml_output(pxml,rsp_fields[rowindex].name,"%s",
row[rowindex]) == -1)
done=1;
}
}
rowindex++;
}
xml_pop(pxml); /* item */
}
pi_db_enum_end(NULL);
xml_pop(pxml); /* items */
xml_pop(pxml); /* response */
xml_deinit(pxml);
pi_config_set_status(pwsc,0,NULL);
}
void rsp_browse(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
XMLSTRUCT *pxml;
char *pe;
int err;
char **row;
int returned;
/* 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 = pi_ws_getvar(pwsc,"query");
ppi->dq.filter_type = FILTER_TYPE_FIREFLY;
if(pi_ws_getvar(pwsc,"offset")) {
ppi->dq.offset = atoi(pi_ws_getvar(pwsc,"offset"));
}
if(pi_ws_getvar(pwsc,"limit")) {
ppi->dq.limit = atoi(pi_ws_getvar(pwsc,"limit"));
}
ppi->dq.playlist_id = atoi(ppi->uri_sections[2]);
if((err=pi_db_enum_start(&pe,&ppi->dq)) != 0) {
rsp_error(pwsc, ppi, err | E_DB, pe);
pi_db_enum_dispose(NULL,&ppi->dq);
return;
}
pi_config_set_status(pwsc,0,"Browsing");
pxml = xml_init(pwsc,1);
if(ppi->dq.offset > ppi->dq.totalcount) {
returned = 0;
} else {
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","");
xml_output(pxml,"records","%d",returned);
xml_output(pxml,"totalrecords","%d",ppi->dq.totalcount);
xml_pop(pxml); /* status */
xml_push(pxml,"items");
while((pi_db_enum_fetch_row(NULL,&row,&ppi->dq) == 0) && (row)) {
xml_output(pxml,"item","%s",row[0]);
}
pi_db_enum_end(NULL);
pi_db_enum_dispose(NULL,&ppi->dq);
xml_pop(pxml); /* items */
xml_pop(pxml); /* response */
xml_deinit(pxml);
pi_config_set_status(pwsc,0,NULL);
}
void rsp_stream(WS_CONNINFO *pwsc, PRIVINFO *ppi) {
pi_stream(pwsc, ppi->uri_sections[2]);
return;
}
void rsp_error(WS_CONNINFO *pwsc, PRIVINFO *ppi, int eno, char *estr) {
XMLSTRUCT *pxml;
pxml = xml_init(pwsc, 1);
xml_push(pxml,"response");
xml_push(pxml,"status");
xml_output(pxml,"errorcode","%d",eno);
xml_output(pxml,"errorstring","%s",estr);
xml_output(pxml,"records","0");
xml_output(pxml,"totalrecords","0");
xml_pop(pxml); /* status */
xml_pop(pxml); /* response */
xml_deinit(pxml);
pi_ws_will_close(pwsc);
}

View File

@ -1,14 +0,0 @@
#ifndef _RSP_H_
#define _RSP_H_
#define RSP_VERSION "1.0"
extern PLUGIN_INFO _pi;
#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif
#endif /* _RSP_H_ */

View File

@ -1,391 +0,0 @@
/*
* This really isn't xmlrpc. It's xmlrpc-ish. Emphasis on -ish.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <zlib.h>
#include "ff-dbstruct.h"
#include "ff-plugins.h"
#include "rsp.h"
#include "xml-rpc.h"
/* typedefs */
typedef struct tag_xmlstack {
char *tag;
struct tag_xmlstack *next;
} XMLSTACK;
#define XML_STREAM_BLOCK 4096
typedef struct tag_xml_streambuffer {
z_stream strm;
unsigned char *in_buffer;
unsigned char *out_buffer;
} XML_STREAMBUFFER;
struct tag_xmlstruct {
WS_CONNINFO *pwsc;
int stack_level;
XMLSTACK stack;
XML_STREAMBUFFER *psb;
};
/* Forwards */
void xml_get_stats(WS_CONNINFO *pwsc);
void xml_set_config(WS_CONNINFO *pwsc);
void xml_return_error(WS_CONNINFO *pwsc, int errno, char *errstr);
char *xml_entity_encode(char *original);
XML_STREAMBUFFER *xml_stream_open(void);
int xml_stream_write(XMLSTRUCT *pxml, char *out);
int xml_stream_close(XMLSTRUCT *pxml);
int xml_write(XMLSTRUCT *pxml, char *fmt, ...) {
char buffer[1024];
va_list ap;
int result=0;
va_start(ap, fmt);
vsnprintf(buffer, 1024, fmt, ap);
va_end(ap);
if(pxml->psb) {
result=xml_stream_write(pxml, buffer);
if(!result)
result = -1;
} else {
result=pi_ws_writefd(pxml->pwsc,"%s",buffer);
}
return result;
}
void xml_return_error(WS_CONNINFO *pwsc, int errno, char *errstr) {
XMLSTRUCT *pxml;
pxml=xml_init(pwsc,TRUE);
xml_push(pxml,"results");
xml_output(pxml,"status","%d",errno);
xml_output(pxml,"statusstring","%s",errstr);
xml_pop(pxml); /* results */
xml_deinit(pxml);
return;
}
/**
* open a gzip stream
*/
XML_STREAMBUFFER *xml_stream_open(void) {
XML_STREAMBUFFER *psb;
psb = (XML_STREAMBUFFER*) malloc(sizeof(XML_STREAMBUFFER));
if(!psb) {
pi_log(E_FATAL,"xml_stream_open: malloc\n");
}
psb->out_buffer = (unsigned char*) malloc(XML_STREAM_BLOCK);
psb->in_buffer = (unsigned char*) malloc(XML_STREAM_BLOCK);
if((!psb->out_buffer) || (!psb->in_buffer)) {
pi_log(E_FATAL,"xml_stream_open: malloc\n");
}
psb->strm.zalloc = Z_NULL;
psb->strm.zfree = Z_NULL;
psb->strm.opaque = Z_NULL;
psb->strm.next_in = psb->in_buffer;
psb->strm.next_out = psb->out_buffer;
deflateInit2(&psb->strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
24, 8, Z_DEFAULT_STRATEGY);
return psb;
}
/**
* write a block to the stream
*/
int xml_stream_write(XMLSTRUCT *pxml, char *out) {
int done = 0;
int result;
XML_STREAMBUFFER *psb = pxml->psb;
if((!out)||(!strlen(out)))
return TRUE;
if(strlen(out) > 1024)
return TRUE;
memcpy(psb->in_buffer,out,(int)strlen(out));
psb->strm.avail_in = (int)strlen(out);
psb->strm.next_in = psb->in_buffer;
psb->strm.next_out = psb->out_buffer;
psb->strm.avail_out = XML_STREAM_BLOCK;
while(!done) {
result = deflate(&psb->strm, Z_NO_FLUSH);
if(result != Z_OK) {
pi_log(E_FATAL,"Error in zlib: %d\n",result);
}
pi_ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
XML_STREAM_BLOCK-psb->strm.avail_out);
if(psb->strm.avail_out != 0) {
done=1;
} else {
psb->strm.avail_out = XML_STREAM_BLOCK;
psb->strm.next_out = psb->out_buffer;
}
}
return TRUE;
}
/**
* close the stream
*/
int xml_stream_close(XMLSTRUCT *pxml) {
int done = 0;
XML_STREAMBUFFER *psb = pxml->psb;
/* flush what's left */
while(!done) {
psb->strm.avail_out = XML_STREAM_BLOCK;
psb->strm.next_out = psb->out_buffer;
psb->strm.avail_in = 0;
psb->strm.next_in = psb->in_buffer;
deflate(&psb->strm,Z_FINISH);
pi_ws_writebinary(pxml->pwsc,(char*)psb->out_buffer,
XML_STREAM_BLOCK - psb->strm.avail_out);
if(psb->strm.avail_out != 0)
done=1;
}
pi_log(E_DBG,"Done sending xml stream\n");
deflateEnd(&psb->strm);
if(psb->out_buffer != NULL)
free(psb->out_buffer);
if(psb->in_buffer != NULL)
free(psb->in_buffer);
free(psb);
return TRUE;
}
/**
* create an xml response structure, a helper struct for
* building xml responses.
*
* @param pwsc the pwsc we are emitting to
* @param emit_header whether or not to throw out html headers and xml header
* @returns XMLSTRUCT on success, or NULL if failure
*/
XMLSTRUCT *xml_init(WS_CONNINFO *pwsc, int emit_header) {
XMLSTRUCT *pxml;
char *accept;
char *nogzip;
pxml=(XMLSTRUCT*)malloc(sizeof(XMLSTRUCT));
if(!pxml) {
pi_log(E_FATAL,"Malloc error\n");
}
memset(pxml,0,sizeof(XMLSTRUCT));
pxml->pwsc = pwsc;
/* should we compress output? */
nogzip = pi_ws_getvar(pwsc,"nogzip");
accept = pi_ws_getrequestheader(pwsc,"accept-encoding");
if((!nogzip) && (accept) && (strcasestr(accept,"gzip"))) {
pi_log(E_DBG,"Gzipping output\n");
pxml->psb = xml_stream_open();
if(pxml->psb) {
pi_ws_addresponseheader(pwsc,"Content-Encoding","gzip");
pi_ws_addresponseheader(pwsc,"Vary","Accept-Encoding");
pi_ws_addresponseheader(pwsc,"Connection","Close");
}
}
/* the world would be a wonderful place without ie */
pi_ws_addresponseheader(pwsc,"Cache-Control","no-cache");
pi_ws_addresponseheader(pwsc,"Expires","-1");
if(emit_header) {
pi_ws_addresponseheader(pwsc,"Content-Type","text/xml; charset=utf-8");
pi_ws_writefd(pwsc,"HTTP/1.0 200 OK\r\n");
pi_ws_emitheaders(pwsc);
xml_write(pxml,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
}
return pxml;
}
/**
* push a new term on the stack
*
* @param pxml xml struct obtained from xml_init
* @param term next xlm section to start
*/
void xml_push(XMLSTRUCT *pxml, char *term) {
XMLSTACK *pstack;
pstack = (XMLSTACK *)malloc(sizeof(XMLSTACK));
pstack->next=pxml->stack.next;
pstack->tag=strdup(term);
pxml->stack.next=pstack;
pxml->stack_level++;
xml_write(pxml,"<%s>",term);
}
/**
* end an xml section
*
* @param pxml xml struct we are working with
*/
void xml_pop(XMLSTRUCT *pxml) {
XMLSTACK *pstack;
pstack=pxml->stack.next;
if(!pstack) {
pi_log(E_LOG,"xml_pop: tried to pop an empty stack\n");
return;
}
pxml->stack.next = pstack->next;
xml_write(pxml,"</%s>",pstack->tag);
free(pstack->tag);
free(pstack);
pxml->stack_level--;
}
/* FIXME: Fixed at 256? And can't I get an expandable sprintf/cat? */
/**
* output a string
*/
int xml_output(XMLSTRUCT *pxml, char *section, char *fmt, ...) {
va_list ap;
char buf[256];
char *output;
int result=0;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
output = xml_entity_encode(buf);
if(section) {
xml_push(pxml,section);
}
result = xml_write(pxml,"%s",output);
free(output);
if(section) {
xml_pop(pxml);
}
return result;
}
/**
* clean up an xml struct
*
* @param pxml xml struct to clean up
*/
void xml_deinit(XMLSTRUCT *pxml) {
XMLSTACK *pstack;
if(pxml->stack.next) {
pi_log(E_LOG,"xml_deinit: entries still on stack (%s)\n",
pxml->stack.next->tag);
}
while((pstack=pxml->stack.next)) {
pxml->stack.next=pstack->next;
free(pstack->tag);
free(pstack);
}
if(pxml->psb) {
xml_stream_close(pxml);
}
free(pxml);
}
/**
* xml entity encoding, stupid style
*/
char *xml_entity_encode(char *original) {
char *new;
char *s, *d;
int destsize;
destsize = 6*(int)strlen(original)+1;
new=(char *)malloc(destsize);
if(!new) return NULL;
memset(new,0x00,destsize);
s=original;
d=new;
while(*s) {
switch(*s) {
case '>':
strcat(d,"&gt;");
d += 4;
s++;
break;
case '<':
strcat(d,"&lt;");
d += 4;
s++;
break;
case '"':
strcat(d,"&quot;");
d += 6;
s++;
break;
case '\'':
strcat(d,"&apos;");
d += 6;
s++;
break;
case '&':
strcat(d,"&amp;");
d += 5;
s++;
break;
default:
*d++ = *s++;
}
}
return new;
}

View File

@ -1,18 +0,0 @@
#ifndef _XMLRPC_H_
#define _XMLRPC_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);
extern void xml_pop(XMLSTRUCT *pxml);
extern int xml_output(XMLSTRUCT *pxml, char *section, char *fmt, ...);
extern void xml_deinit(XMLSTRUCT *pxml);
#endif /* _XMLRPC_H_ */