1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2025-01-03 14:56:34 -05:00

sync with master excluding change in r18364.

svn path=/icecast/branches/ph3/icecast/; revision=19273
This commit is contained in:
Philipp Schafft 2014-11-07 12:08:06 +00:00
parent 6be7448832
commit bc1ff182df
23 changed files with 868 additions and 549 deletions

View File

@ -279,7 +279,7 @@ void admin_send_response (xmlDocPtr doc, client_t *client,
len = util_http_build_header(client->refbuf->data, buf_len, 0,
0, 200, NULL,
"text/xml", "utf-8",
NULL);
NULL, NULL);
len += snprintf (client->refbuf->data + len, buf_len - len, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff);
client->refbuf->len = len;
@ -573,7 +573,7 @@ static void html_success(client_t *client, char *message)
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
0, 200, NULL,
"text/html", "utf-8",
"");
"", NULL);
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
"<html><head><title>Admin request successful</title></head>"
"<body><p>%s</p></body></html>", message);
@ -712,7 +712,7 @@ static void command_buildm3u(client_t *client, const char *mount)
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
0, 200, NULL,
"audio/x-mpegurl", NULL,
NULL);
NULL, NULL);
config = config_get_config();
snprintf (client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
@ -1032,7 +1032,7 @@ static void command_list_mounts(client_t *client, int response)
util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
0, 200, NULL,
"text/plain", "utf-8",
"");
"", NULL);
client->refbuf->len = strlen (client->refbuf->data);
client->respcode = 200;

View File

@ -59,7 +59,7 @@
#define CONFIG_DEFAULT_GROUP NULL
#define CONFIG_MASTER_UPDATE_INTERVAL 120
#define CONFIG_YP_URL_TIMEOUT 10
#define CONFIG_DEFAULT_CIPHER_LIST "ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM"
#define CONFIG_DEFAULT_CIPHER_LIST "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS"
#ifndef _WIN32
#define CONFIG_DEFAULT_BASE_DIR "/usr/local/icecast"
@ -87,6 +87,8 @@ static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
ice_config_t *c);
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node,
ice_config_http_header_t **http_headers);
static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
@ -124,6 +126,58 @@ void config_init_configuration(ice_config_t *configuration)
_set_defaults(configuration);
}
static void config_clear_http_header(ice_config_http_header_t *header) {
ice_config_http_header_t *old;
while (header) {
xmlFree(header->name);
xmlFree(header->value);
old = header;
header = header->next;
free(old);
}
}
static inline ice_config_http_header_t * config_copy_http_header(ice_config_http_header_t *header) {
ice_config_http_header_t *ret = NULL;
ice_config_http_header_t *cur = NULL;
ice_config_http_header_t *old = NULL;
while (header) {
if (cur) {
cur->next = calloc(1, sizeof(ice_config_http_header_t));
old = cur;
cur = cur->next;
} else {
ret = calloc(1, sizeof(ice_config_http_header_t));
cur = ret;
}
if (!cur) return ret; /* TODO: do better error handling */
cur->type = header->type;
cur->name = (char *)xmlCharStrdup(header->name);
cur->value = (char *)xmlCharStrdup(header->value);
cur->status = header->status;
if (!cur->name || !cur->value) {
if (cur->name) xmlFree(cur->name);
if (cur->value) xmlFree(cur->value);
if (old) {
old->next = NULL;
} else {
ret = NULL;
}
free(cur);
return ret;
}
header = header->next;
}
return ret;
}
static void config_clear_mount (mount_proxy *mount)
{
config_options_t *option;
@ -156,6 +210,7 @@ static void config_clear_mount (mount_proxy *mount)
option = nextopt;
}
auth_release (mount->auth);
config_clear_http_header(mount->http_headers);
free (mount);
}
@ -295,6 +350,8 @@ void config_clear(ice_config_t *c)
while ((c->cpis = config_clear_cpi (c->cpis)))
;
config_clear_http_header(c->http_headers);
memset(c, 0, sizeof(ice_config_t));
}
@ -476,9 +533,13 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
_parse_plugins(doc, node->xmlChildrenNode, configuration);
} else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->port = atoi(tmp);
configuration->listen_sock->port = atoi(tmp);
if (tmp) xmlFree(tmp);
if (tmp) {
configuration->port = atoi(tmp);
configuration->listen_sock->port = atoi(tmp);
xmlFree(tmp);
} else {
ICECAST_LOG_WARN("<port> must not be empty.");
}
} else if (xmlStrcmp (node->name, XMLSTR("bind-address")) == 0) {
if (configuration->listen_sock->bind_address)
xmlFree(configuration->listen_sock->bind_address);
@ -505,6 +566,8 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
configuration->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
} else if (xmlStrcmp (node->name, XMLSTR("limits")) == 0) {
_parse_limits(doc, node->xmlChildrenNode, configuration);
} else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
_parse_http_headers(doc, node->xmlChildrenNode, &(configuration->http_headers));
} else if (xmlStrcmp (node->name, XMLSTR("relay")) == 0) {
_parse_relay(doc, node->xmlChildrenNode, configuration);
} else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
@ -741,6 +804,8 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
} else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) {
mount->subtype = (char *)xmlNodeListGetString(
doc, node->xmlChildrenNode, 1);
} else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
_parse_http_headers(doc, node->xmlChildrenNode, &(mount->http_headers));
}
} while ((node = node->next));
@ -775,6 +840,63 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
configuration->mounts = mount;
}
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_http_header_t **http_headers) {
ice_config_http_header_t *header;
ice_config_http_header_t *next;
char *name = NULL;
char *value = NULL;
char *tmp;
int status;
http_header_type type;
do {
if (node == NULL) break;
if (xmlIsBlankNode(node)) continue;
if (xmlStrcmp (node->name, XMLSTR("header")) != 0) break;
if (!(name = (char *)xmlGetProp(node, XMLSTR("name")))) break;
if (!(value = (char *)xmlGetProp(node, XMLSTR("value")))) break;
type = HTTP_HEADER_TYPE_STATIC; /* default */
if ((tmp = (char *)xmlGetProp(node, XMLSTR("type")))) {
if (strcmp(tmp, "static") == 0) {
type = HTTP_HEADER_TYPE_STATIC;
} else {
ICECAST_LOG_WARN("Unknown type %s for HTTP Header %s", tmp, name);
xmlFree(tmp);
break;
}
xmlFree(tmp);
}
status = 0; /* default: any */
if ((tmp = (char *)xmlGetProp(node, XMLSTR("status")))) {
status = atoi(tmp);
xmlFree(tmp);
}
header = calloc(1, sizeof(ice_config_http_header_t));
if (!header) break;
header->type = type;
header->name = name;
header->value = value;
header->status = status;
name = NULL;
value = NULL;
if (!*http_headers) {
*http_headers = header;
continue;
}
next = *http_headers;
while (next->next) next = next->next;
next->next = header;
} while ((node = node->next));
/* in case we used break we may need to clean those up */
if (name)
xmlFree(name);
if (value)
xmlFree(value);
}
static void _parse_relay(xmlDocPtr doc, xmlNodePtr node,
ice_config_t *configuration)
@ -811,8 +933,12 @@ static void _parse_relay(xmlDocPtr doc, xmlNodePtr node,
}
else if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
relay->port = atoi(tmp);
if(tmp) xmlFree(tmp);
if (tmp) {
relay->port = atoi(tmp);
xmlFree(tmp);
} else {
ICECAST_LOG_WARN("<port> must not be empty.");
}
}
else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
if (relay->mount) xmlFree (relay->mount);
@ -869,10 +995,14 @@ static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
if (xmlStrcmp (node->name, XMLSTR("port")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
if(configuration->port == 0)
configuration->port = atoi(tmp);
listener->port = atoi(tmp);
if(tmp) xmlFree(tmp);
if (tmp) {
if(configuration->port == 0)
configuration->port = atoi(tmp);
listener->port = atoi(tmp);
xmlFree(tmp);
} else {
ICECAST_LOG_WARN("<port> must not be empty.");
}
}
else if (xmlStrcmp (node->name, XMLSTR("ssl")) == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
@ -1119,8 +1249,12 @@ static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
if (configuration->base_dir) xmlFree(configuration->base_dir);
configuration->base_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
} else if (xmlStrcmp (node->name, XMLSTR("logdir")) == 0) {
if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
ICECAST_LOG_WARN("<logdir> must not be empty.");
continue;
}
if (configuration->log_dir) xmlFree(configuration->log_dir);
configuration->log_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->log_dir = temp;
} else if (xmlStrcmp (node->name, XMLSTR("pidfile")) == 0) {
if (configuration->pidfile) xmlFree(configuration->pidfile);
configuration->pidfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
@ -1137,14 +1271,22 @@ static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
if (configuration->cipher_list) xmlFree(configuration->cipher_list);
configuration->cipher_list = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
} else if (xmlStrcmp (node->name, XMLSTR("webroot")) == 0) {
if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
ICECAST_LOG_WARN("<webroot> must not be empty.");
continue;
}
if (configuration->webroot_dir) xmlFree(configuration->webroot_dir);
configuration->webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->webroot_dir = temp;
if(configuration->webroot_dir[strlen(configuration->webroot_dir)-1] == '/')
configuration->webroot_dir[strlen(configuration->webroot_dir)-1] = 0;
} else if (xmlStrcmp (node->name, XMLSTR("adminroot")) == 0) {
if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
ICECAST_LOG_WARN("<adminroot> must not be empty.");
continue;
}
if (configuration->adminroot_dir)
xmlFree(configuration->adminroot_dir);
configuration->adminroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->adminroot_dir = (char *)temp;
if(configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/')
configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0;
} else if (xmlStrcmp (node->name, XMLSTR("alias")) == 0) {
@ -1189,16 +1331,25 @@ static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
static void _parse_logging(xmlDocPtr doc, xmlNodePtr node,
ice_config_t *configuration)
{
char *tmp;
do {
if (node == NULL) break;
if (xmlIsBlankNode(node)) continue;
if (xmlStrcmp (node->name, XMLSTR("accesslog")) == 0) {
if (!(tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
ICECAST_LOG_WARN("<accesslog> must not be empty.");
continue;
}
if (configuration->access_log) xmlFree(configuration->access_log);
configuration->access_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->access_log = tmp;
} else if (xmlStrcmp (node->name, XMLSTR("errorlog")) == 0) {
if (!(tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
ICECAST_LOG_WARN("<errorlog> must not be empty.");
continue;
}
if (configuration->error_log) xmlFree(configuration->error_log);
configuration->error_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
configuration->error_log = tmp;
} else if (xmlStrcmp (node->name, XMLSTR("playlistlog")) == 0) {
if (configuration->playlist_log) xmlFree(configuration->playlist_log);
configuration->playlist_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
@ -1299,6 +1450,9 @@ static void _add_server(xmlDocPtr doc, xmlNodePtr node,
}
static void merge_mounts(mount_proxy * dst, mount_proxy * src) {
ice_config_http_header_t *http_header_next;
ice_config_http_header_t **http_header_tail;
if (!dst || !src)
return;
@ -1360,6 +1514,15 @@ static void merge_mounts(mount_proxy * dst, mount_proxy * src) {
dst->subtype = (char*)xmlStrdup((xmlChar*)src->subtype);
if (dst->yp_public == -1)
dst->yp_public = src->yp_public;
if (dst->http_headers) {
http_header_next = dst->http_headers;
while (http_header_next->next) http_header_next = http_header_next->next;
http_header_tail = &(http_header_next->next);
} else {
http_header_tail = &(dst->http_headers);
}
*http_header_tail = config_copy_http_header(src->http_headers);
}
static inline void _merge_mounts_all(ice_config_t *c) {

View File

@ -3,7 +3,7 @@
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2000-2004, Jack Moffitt <jack@xiph.org,
* Copyright 2000-2004, Jack Moffitt <jack@xiph.org>,
* Michael Smith <msmith@xiph.org>,
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
@ -32,8 +32,27 @@ struct _mount_proxy;
#define XMLSTR(str) ((xmlChar *)(str))
typedef struct ice_config_dir_tag
{
typedef enum _http_header_type {
/* static: headers are passed as is to the client. */
HTTP_HEADER_TYPE_STATIC
} http_header_type;
typedef struct ice_config_http_header_tag {
/* type of this header. See http_header_type */
http_header_type type;
/* name and value of the header */
char *name;
char *value;
/* filters */
int status;
/* link to the next list element */
struct ice_config_http_header_tag *next;
} ice_config_http_header_t;
typedef struct ice_config_dir_tag {
char *host;
int touch_interval;
struct ice_config_dir_tag *next;
@ -79,6 +98,8 @@ typedef struct _mount_proxy {
char *charset; /* character set if not utf8 */
int mp3_meta_interval; /* outgoing per-stream metadata interval */
ice_config_http_header_t *http_headers; /* additional HTTP headers */
char *auth_type; /* Authentication type */
struct auth_tag *auth;
char *cluster_password;
@ -131,8 +152,7 @@ typedef struct _cpi_t {
int autoload;
} cpi_t;
typedef struct ice_config_tag
{
typedef struct ice_config_tag {
char *config_filename;
char *location;
@ -173,6 +193,8 @@ typedef struct ice_config_tag
char *master_username;
char *master_password;
ice_config_http_header_t *http_headers;
relay_server *relay;
mount_proxy *mounts;
@ -238,6 +260,3 @@ void config_release_config(void);
ice_config_t *config_get_config_unlocked(void);
#endif /* __CFGFILE_H__ */

View File

@ -190,7 +190,7 @@ static void client_send_error(client_t *client, int status, int plain, const cha
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
0, status, NULL,
plain ? "text/plain" : "text/html", "utf-8",
plain ? message : "");
plain ? message : "", NULL);
if (!plain)
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,

View File

@ -204,7 +204,11 @@ static void get_ssl_certificate (ice_config_t *config)
method = SSLv23_server_method();
ssl_ctx = SSL_CTX_new (method);
ssl_opts = SSL_CTX_get_options (ssl_ctx);
SSL_CTX_set_options (ssl_ctx, ssl_opts|SSL_OP_NO_SSLv2);
#ifdef SSL_OP_NO_COMPRESSION
SSL_CTX_set_options (ssl_ctx, ssl_opts|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION);
#else
SSL_CTX_set_options (ssl_ctx, ssl_opts|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
#endif
do
{

View File

@ -299,7 +299,7 @@ static int format_prepare_headers (source_t *source, client_t *client)
ptr = client->refbuf->data;
client->respcode = 200;
bytes = util_http_build_header (ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL);
bytes = util_http_build_header (ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source);
remaining -= bytes;
ptr += bytes;

View File

@ -458,7 +458,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
httpclient->respcode = 200;
ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
0, 200, NULL,
"audio/x-mpegurl", NULL, "");
"audio/x-mpegurl", NULL, "", NULL);
if (host == NULL)
{
config = config_get_config();
@ -501,7 +501,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
config = config_get_config();
if (config->fileserve == 0)
{
ICECAST_LOG_DEBUG("on demand file \"%H\" refused", fullpath);
ICECAST_LOG_DEBUG("on demand file \"%H\" refused. Serving static files has been disabled in the config", fullpath);
client_send_404 (httpclient, "The file you requested could not be found");
config_release_config();
free (fullpath);
@ -567,7 +567,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
0, 206, NULL,
type, NULL,
NULL);
NULL, NULL);
bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes,
"Accept-Ranges: bytes\r\n"
"Content-Length: %" PRI_OFF_T "\r\n"
@ -593,7 +593,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
0, 200, NULL,
type, NULL,
NULL);
NULL, NULL);
bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes,
"Accept-Ranges: bytes\r\n"
"Content-Length: %" PRI_OFF_T "\r\n\r\n",

View File

@ -209,6 +209,16 @@ static int _parse_config_opts(int argc, char **argv, char *filename, int size)
return -1;
}
static int _start_logging_stdout(void) {
errorlog = log_open_file(stderr);
if ( errorlog < 0 )
return 0;
log_set_level(errorlog, 2 /* WARN */);
return 1;
}
static int _start_logging(void)
{
char fn_error[FILENAME_MAX];
@ -227,8 +237,7 @@ static int _start_logging(void)
log_set_trigger (errorlog, config->logsize);
log_set_archive_timestamp(errorlog, config->logarchive);
} else {
errorlog = log_open_file(stderr);
log_to_stderr = 1;
/* this is already in place because of _start_logging_stdout() */
}
if (errorlog < 0) {
@ -443,6 +452,11 @@ int main(int argc, char **argv)
#if !defined(_WIN32) || defined(_CONSOLE) || defined(__MINGW32__) || defined(__MINGW64__)
/* startup all the modules */
initialize_subsystems();
if (!_start_logging_stdout()) {
_fatal_error("FATAL: Could not start logging on stderr.");
shutdown_subsystems();
return 1;
}
#endif
/* parse the config file */
config_get_config();

View File

@ -45,6 +45,7 @@
#include "refbuf.h"
#include "connection.h"
#include "client.h"
#include "source.h"
#define CATMODULE "util"
@ -486,11 +487,65 @@ char *util_base64_decode(const char *data)
return result;
}
/* TODO, FIXME: handle memory allocation errors better. */
static inline void _build_headers_loop(char **ret, size_t *len, ice_config_http_header_t *header, int status) {
size_t headerlen;
const char *name;
const char *value;
char * r = *ret;
if (!header)
return;
do {
/* filter out header's we don't use. */
if (header->status != 0 && header->status != status) continue;
/* get the name of the header */
name = header->name;
/* handle type of the header */
switch (header->type) {
case HTTP_HEADER_TYPE_STATIC:
value = header->value;
break;
}
/* append the header to the buffer */
headerlen = strlen(name) + strlen(value) + 4;
*len += headerlen;
r = realloc(r, *len);
strcat(r, name);
strcat(r, ": ");
strcat(r, value);
strcat(r, "\r\n");
} while ((header = header->next));
*ret = r;
}
static inline char * _build_headers(int status, ice_config_t *config, source_t *source) {
mount_proxy *mountproxy = NULL;
char *ret = NULL;
size_t len = 1;
if (source)
mountproxy = config_find_mount(config, source->mount, MOUNT_TYPE_NORMAL);
ret = calloc(1, 1);
*ret = 0;
_build_headers_loop(&ret, &len, config->http_headers, status);
if (mountproxy && mountproxy->http_headers)
_build_headers_loop(&ret, &len, mountproxy->http_headers, status);
return ret;
}
ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
int cache,
int status, const char * statusmsg,
const char * contenttype, const char * charset,
const char * datablock) {
const char * datablock,
struct source_tag * source) {
const char * http_version = "1.0";
ice_config_t *config;
time_t now;
@ -500,6 +555,7 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
char status_buffer[80];
char contenttype_buffer[80];
ssize_t ret;
char * extra_headers;
if (!out)
return -1;
@ -563,7 +619,8 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
currenttime_buffer[0] = '\0';
config = config_get_config();
ret = snprintf (out, len, "%sServer: %s\r\n%s%s%s%s%s%s",
extra_headers = _build_headers(status, config, source);
ret = snprintf (out, len, "%sServer: %s\r\n%s%s%s%s%s%s%s",
status_buffer,
config->server_id,
currenttime_buffer,
@ -572,8 +629,10 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
(cache ? "" : "Cache-Control: no-cache\r\n"
"Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"
"Pragma: no-cache\r\n"),
extra_headers,
(datablock ? "\r\n" : ""),
(datablock ? datablock : ""));
free(extra_headers);
config_release_config();
return ret;

View File

@ -56,11 +56,14 @@ char *util_url_escape(const char *src);
* If datablock is NULL no end-of-header nor any data is appended.
* Returns the number of bytes written or -1 on error.
*/
struct source_tag; /* use forward decleration so we do not need to
* include <source.h> that would cause other conflicts. */
ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
int cache,
int status, const char * statusmsg,
const char * contenttype, const char * charset,
const char * datablock);
const char * datablock,
struct source_tag * source);
/* String dictionary type, without support for NULL keys, or multiple
* instances of the same key */

View File

@ -238,7 +238,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
if (string == NULL)
string = xmlCharStrdup ("");
ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL);
ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL);
snprintf (refbuf->data + ret, full_len - ret,
"Content-Length: %d\r\n\r\n%s",
len, string);

View File

@ -4,15 +4,11 @@ AUTOMAKE_OPTIONS = foreign
webdir = $(pkgdatadir)/web
dist_web_DATA = status.xsl \
status2.xsl \
corner_bottomleft.jpg \
corner_bottomright.jpg \
corner_topleft.jpg \
corner_topright.jpg \
icecast.png \
key.gif \
style.css \
auth.xsl \
server_version.xsl \
tunein.png \
key.png
key.png \
status-json.xsl \
xml2json.xslt

View File

@ -1,57 +1,59 @@
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0" >
<xsl:output omit-xml-declaration="no" method="html" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" encoding="UTF-8" />
<xsl:template match = "/icestats" >
<html>
<head>
<title>Icecast Streaming Media Server</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0">
<table border="0" width="100%%">
<tr>
<td width="50"></td>
<td>
<h2>Authorization Page</h2>
<div class="roundcont">
<div class="roundtop">
<img src="/corner_topleft.jpg" class="corner" style="display: none" />
</div>
<div class="newscontent">
<xsl:for-each select="source">
<xsl:choose>
<xsl:when test="listeners">
<xsl:if test="authenticator">
<xsl:if test="server_name"><xsl:value-of select="server_name" /> </xsl:if>
<h3>(<xsl:value-of select="@mount" />)</h3>
<form method="GET" action="/admin/buildm3u">
<table border="0" cellpadding="4">
<tr><td>Username : <input type="text" name="username"/></td></tr>
<tr><td>Password : <input type="password" name="password"/></td></tr>
<tr><td><input type="Submit" value="Login"/></td></tr>
</table>
<input type="hidden" name="mount" value="{@mount}"/>
</form>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<h3><xsl:value-of select="@mount" /> - Not Connected</h3>
</xsl:otherwise>
</xsl:choose>
<br></br>
<br></br>
</xsl:for-each>
<xsl:text disable-output-escaping="yes">&amp;</xsl:text>nbsp;
</div>
<div class="roundbottom">
<img src="/corner_bottomleft.jpg" class="corner" style="display: none" />
</div>
</div>
<br></br><br></br>
</td>
<td width="25"></td></tr>
</table>
<div class="poster">Support icecast development at <a class="nav" target="_blank" href="http://www.icecast.org">www.icecast.org</a></div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0" >
<xsl:output omit-xml-declaration="no" method="xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" encoding="UTF-8" />
<xsl:template match = "/icestats" >
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Icecast Streaming Media Server</title>
<link rel="stylesheet" type="text/css" href="style.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
</head>
<body>
<h1 id="header">Icecast2 Status</h1>
<!--index header menu -->
<div id="menu">
<ul>
<li><a href="admin/">Administration</a></li>
<li><a href="status.xsl">Server Status</a></li>
<li><a href="server_version.xsl">Version</a></li>
</ul>
</div>
<!--end index header menu -->
<h2>Authorization Page</h2>
<xsl:for-each select="source">
<xsl:choose>
<xsl:when test="listeners">
<xsl:if test="authenticator">
<div class="roundbox">
<h3 class="mount">
Mount Point <xsl:value-of select="@mount" />
<xsl:if test="server_name">
<small><xsl:value-of select="server_name" /></small>
</xsl:if>
</h3>
<form class="alignedform" method="get" action="/admin/buildm3u">
<p>
<label for="name">Username: </label>
<input id="name" name="username" type="text" />
</p>
<p>
<label for="password">Password: </label>
<input id="password" name="password" type="password" />
</p>
<input type="hidden" name="mount" value="{@mount}" />
<input type="submit" value="Login" />
</form>
</div>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<h3><xsl:value-of select="@mount" /> - Not Connected</h3>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<div id="footer">
Support icecast development at <a href="http://www.icecast.org">www.icecast.org</a>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,91 +1,73 @@
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0" >
<xsl:output omit-xml-declaration="no" method="html" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" encoding="UTF-8" />
<xsl:template match = "/icestats" >
<html>
<head>
<title>Icecast Streaming Media Server</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0">
<h2>Server Information</h2>
<br />
<!--index header menu -->
<div class="roundcont">
<div class="roundtop">
<img src="/corner_topleft.jpg" class="corner" style="display: none" />
</div>
<table border="0" width="100%" id="table1" cellspacing="0" cellpadding="4">
<tr>
<td bgcolor="#656565">
<a class="nav" href="admin/">Administration</a>
<a class="nav" href="status.xsl">Server Status</a>
<a class="nav" href="server_version.xsl">Version</a></td>
</tr>
</table>
<div class="roundbottom">
<img src="/corner_bottomleft.jpg" class="corner" style="display: none" />
</div>
</div>
<br />
<br />
<!--end index header menu -->
<div class="roundcont">
<div class="roundtop">
<img src="/corner_topleft.jpg" class="corner" style="display: none" />
</div>
<div class="newscontent">
<h3>Server Information</h3>
<table border="0" cellpadding="4">
<xsl:for-each select="/icestats">
<tr>
<td width="130">Location</td>
<td class="streamdata"><xsl:value-of select="location" /></td>
</tr>
<tr>
<td width="130">Admin</td>
<td class="streamdata"><xsl:value-of select="admin" /></td>
</tr>
<tr>
<td width="130">Host</td>
<td class="streamdata"><xsl:value-of select="host" /></td>
</tr>
<tr>
<td width="130">Version</td>
<td class="streamdata"><xsl:value-of select="server_id" /></td>
</tr>
</xsl:for-each>
<tr>
<td width="130">Download</td>
<td class="streamdata"><a class="nav" target="_blank" href="http://icecast.org/download.php">icecast.org</a></td>
</tr>
<tr>
<td width="130">Subversion</td>
<td class="streamdata"><a class="nav" target="_blank" href="http://icecast.org/svn.php">click here</a></td>
</tr>
<tr>
<td width="130">Documentation</td>
<td class="streamdata"><a class="nav" target="_blank" href="http://icecast.org/docs.php">click here</a></td>
</tr>
<tr>
<td width="130">Stream Directory </td>
<td class="streamdata"><a class="nav" target="_blank" href="http://dir.xiph.org/index.php">dir.xiph.org</a></td>
</tr>
<tr>
<td width="130">Community</td>
<td class="streamdata"><a class="nav" target="_blank" href="http://forum.icecast.org/">forum.icecast.org</a></td>
</tr>
</table>
</div>
<div class="roundbottom">
<img src="/corner_bottomleft.jpg" class="corner" style="display: none" />
</div>
</div>
<br />
<br />
<div class="poster">Support icecast development at <a class="nav" target="_blank" href="http://www.icecast.org">www.icecast.org</a></div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0">
<xsl:output omit-xml-declaration="no" method="xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" encoding="UTF-8" />
<xsl:template match = "/icestats">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Icecast Streaming Media Server</title>
<link rel="stylesheet" type="text/css" href="style.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
</head>
<body>
<h1 id="header">Server Information</h1>
<!--index header menu -->
<div id="menu">
<ul>
<li><a href="admin/">Administration</a></li>
<li><a href="status.xsl">Server Status</a></li>
<li><a href="server_version.xsl">Version</a></li>
</ul>
</div>
<!--end index header menu -->
<div class="roundbox">
<h3>Server Information</h3>
<table class="yellowkeys">
<tbody>
<xsl:for-each select="/icestats">
<tr>
<td>Location</td>
<td><xsl:value-of select="location" /></td>
</tr>
<tr>
<td>Admin</td>
<td><xsl:value-of select="admin" /></td>
</tr>
<tr>
<td>Host</td>
<td><xsl:value-of select="host" /></td>
</tr>
<tr>
<td>Version</td>
<td><xsl:value-of select="server_id" /></td>
</tr>
</xsl:for-each>
<tr>
<td>Download</td>
<td><a href="http://icecast.org/download.php">icecast.org</a></td>
</tr>
<tr>
<td>Subversion</td>
<td><a href="http://icecast.org/svn.php">icecast.org/svn.php</a></td>
</tr>
<tr>
<td>Documentation</td>
<td><a href="http://icecast.org/docs.php">icecast.org/docs.php</a></td>
</tr>
<tr>
<td>Stream Directory</td>
<td><a href="http://dir.xiph.org/index.php">dir.xiph.org</a></td>
</tr>
<tr>
<td>Community</td>
<td><a href="http://icecast.org/community.php">icecast.org/community.php</a></td>
</tr>
</tbody>
</table>
</div>
<div id="footer">
Support icecast development at <a href="http://www.icecast.org">www.icecast.org</a>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

24
web/status-json.xsl Normal file
View File

@ -0,0 +1,24 @@
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="xml2json.xslt"/>
<xsl:output indent="no" omit-xml-declaration="yes" method="text" encoding="UTF-8" media-type="application/json"/>
<xsl:strip-space elements="*"/>
<!-- override imported transform variable to enable output -->
<xsl:variable name="output">true</xsl:variable>
<!-- hide certain nodes from all sources -->
<xsl:template match="icestats/source/max_listeners"><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
<xsl:template match="icestats/source/public"><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
<xsl:template match="icestats/source/source_ip"><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
<xsl:template match="icestats/source/slow_listeners"><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
<xsl:template match="icestats/source/*[contains(name(), 'total_bytes')]"><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
<xsl:template match="icestats/source/user_agent" ><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
<!-- hide certain global nodes -->
<xsl:template match="icestats/sources"><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
<xsl:template match="icestats/clients"><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
<xsl:template match="icestats/stats"><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
<xsl:template match="icestats/listeners"><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
<xsl:template match="node()[contains(name(), 'connections')]"><xsl:if test="not(following-sibling::*)">"dummy":null}</xsl:if></xsl:template>
</xsl:stylesheet>

View File

@ -1,126 +1,167 @@
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0" >
<xsl:output omit-xml-declaration="no" method="html" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" encoding="UTF-8" />
<xsl:template match = "/icestats" >
<html>
<head>
<title>Icecast Streaming Media Server</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0">
<h2>Icecast2 Status</h2>
<br />
<!--index header menu -->
<div class="roundcont">
<div class="roundtop">
<img src="/corner_topleft.jpg" class="corner" style="display: none" />
</div>
<table border="0" width="100%" id="table1" cellspacing="0" cellpadding="4">
<tr>
<td bgcolor="#656565">
<a class="nav" href="admin/">Administration</a>
<a class="nav" href="status.xsl">Server Status</a>
<a class="nav" href="server_version.xsl">Version</a></td>
</tr>
</table>
<div class="roundbottom">
<img src="/corner_bottomleft.jpg" class="corner" style="display: none" />
</div>
</div>
<br />
<br />
<!--end index header menu -->
<!--mount point stats-->
<xsl:for-each select="source">
<xsl:choose>
<xsl:when test="listeners">
<div class="roundcont">
<div class="roundtop">
<img src="/corner_topleft.jpg" class="corner" style="display: none" />
</div>
<div class="newscontent">
<div class="streamheader">
<table cellspacing="0" cellpadding="0">
<colgroup align="left" />
<colgroup align="right" width="300" />
<tr>
<td><h3>Mount Point <xsl:value-of select="@mount" /></h3></td>
<xsl:choose>
<xsl:when test="authenticator">
<td align="right"><a class="auth" href="/auth.xsl">Login</a></td>
</xsl:when>
<xsl:otherwise>
<td align="right">
<a href="{@mount}.m3u">M3U</a>
<a href="{@mount}.xspf">XSPF</a>
<a href="{@mount}.vclt">VCLT</a>
</td>
</xsl:otherwise>
</xsl:choose>
</tr></table>
</div>
<table border="0" cellpadding="4">
<xsl:if test="server_name">
<tr><td>Stream Title:</td><td class="streamdata"> <xsl:value-of select="server_name" /></td></tr>
</xsl:if>
<xsl:if test="server_description">
<tr><td>Stream Description:</td><td class="streamdata"> <xsl:value-of select="server_description" /></td></tr>
</xsl:if>
<xsl:if test="server_type">
<tr><td>Content Type:</td><td class="streamdata"><xsl:value-of select="server_type" /></td></tr>
</xsl:if>
<xsl:if test="stream_start">
<tr><td>Mount started:</td><td class="streamdata"><xsl:value-of select="stream_start" /></td></tr>
</xsl:if>
<xsl:if test="bitrate">
<tr><td>Bitrate:</td><td class="streamdata"> <xsl:value-of select="bitrate" /></td></tr>
</xsl:if>
<xsl:if test="quality">
<tr><td>Quality:</td><td class="streamdata"> <xsl:value-of select="quality" /></td></tr>
</xsl:if>
<xsl:if test="video_quality">
<tr><td>Video Quality:</td><td class="streamdata"> <xsl:value-of select="video_quality" /></td></tr>
</xsl:if>
<xsl:if test="frame_size">
<tr><td>Framesize:</td><td class="streamdata"> <xsl:value-of select="frame_size" /></td></tr>
</xsl:if>
<xsl:if test="frame_rate">
<tr><td>Framerate:</td><td class="streamdata"> <xsl:value-of select="frame_rate" /></td></tr>
</xsl:if>
<xsl:if test="listeners">
<tr><td>Current Listeners:</td><td class="streamdata"> <xsl:value-of select="listeners" /></td></tr>
</xsl:if>
<xsl:if test="listener_peak">
<tr><td>Peak Listeners:</td><td class="streamdata"> <xsl:value-of select="listener_peak" /></td></tr>
</xsl:if>
<xsl:if test="genre">
<tr><td>Stream Genre:</td><td class="streamdata"> <xsl:value-of select="genre" /></td></tr>
</xsl:if>
<xsl:if test="server_url">
<tr><td>Stream URL:</td><td class="streamdata"> <a target="_blank" href="{server_url}"><xsl:value-of select="server_url" /></a></td></tr>
</xsl:if>
<tr><td>Current Song:</td><td class="streamdata">
<xsl:if test="artist"><xsl:value-of select="artist" /> - </xsl:if><xsl:value-of select="title" /></td></tr>
</table>
</div>
<div class="roundbottom">
<img src="/corner_bottomleft.jpg" class="corner" style="display: none" />
</div>
</div>
<br />
<br />
</xsl:when>
<xsl:otherwise>
<h3><xsl:value-of select="@mount" /> - Not Connected</h3>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:text disable-output-escaping="yes">&amp;</xsl:text>nbsp;
<div class="poster">Support icecast development at <a class="nav" target="_blank" href="http://www.icecast.org">www.icecast.org</a></div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0">
<xsl:output omit-xml-declaration="no" method="xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" encoding="UTF-8" />
<xsl:template match = "/icestats">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Icecast Streaming Media Server</title>
<link rel="stylesheet" type="text/css" href="style.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
</head>
<body>
<h1 id="header">Icecast2 Status</h1>
<!--index header menu -->
<div id="menu">
<ul>
<li><a href="admin/">Administration</a></li>
<li><a href="status.xsl">Server Status</a></li>
<li><a href="server_version.xsl">Version</a></li>
</ul>
</div>
<!--end index header menu -->
<xsl:text disable-output-escaping="yes">
&lt;!-- WARNING:
DO NOT ATTEMPT TO PARSE ICECAST HTML OUTPUT!
The web interface may change completely between releases.
If you have a need for automatic processing of server data,
please read the appropriate documentation. Latest docs:
http://icecast.org/docs/icecast-latest/icecast2_stats.html
-->
</xsl:text>
<!--mount point stats-->
<xsl:for-each select="source">
<xsl:choose>
<xsl:when test="listeners">
<div class="roundbox">
<div class="mounthead">
<h3 class="mount">Mount Point <xsl:value-of select="@mount" /></h3>
<div class="right">
<xsl:choose>
<xsl:when test="authenticator">
<a class="auth" href="/auth.xsl">Login</a>
</xsl:when>
<xsl:otherwise>
<ul class="mountlist">
<li><a class="play" href="{@mount}.m3u">M3U</a></li>
<li><a class="play" href="{@mount}.xspf">XSPF</a></li>
<li><a class="play" href="{@mount}.vclt">VCLT</a></li>
</ul>
</xsl:otherwise>
</xsl:choose>
</div>
</div>
<div class="mountcont">
<xsl:if test="server_type and ((server_type = 'application/ogg') or (server_type = 'audio/ogg'))">
<div class="audioplayer">
<audio controls="controls" preload="none">
<source src="{@mount}" type="{server_type}" />
</audio>
</div>
</xsl:if>
<table class="yellowkeys">
<tbody>
<xsl:if test="server_name">
<tr>
<td>Stream Name:</td>
<td><xsl:value-of select="server_name" /></td>
</tr>
</xsl:if>
<xsl:if test="server_description">
<tr>
<td>Stream Description:</td>
<td><xsl:value-of select="server_description" /></td>
</tr>
</xsl:if>
<xsl:if test="server_type">
<tr>
<td>Content Type:</td>
<td><xsl:value-of select="server_type" /></td>
</tr>
</xsl:if>
<xsl:if test="stream_start">
<tr>
<td>Stream started:</td>
<td class="streamstats"><xsl:value-of select="stream_start" /></td>
</tr>
</xsl:if>
<xsl:if test="bitrate">
<tr>
<td>Bitrate:</td>
<td class="streamstats"><xsl:value-of select="bitrate" /></td>
</tr>
</xsl:if>
<xsl:if test="quality">
<tr>
<td>Quality:</td>
<td class="streamstats"><xsl:value-of select="quality" /></td>
</tr>
</xsl:if>
<xsl:if test="video_quality">
<tr>
<td>Video Quality:</td>
<td class="streamstats"><xsl:value-of select="video_quality" /></td>
</tr>
</xsl:if>
<xsl:if test="frame_size">
<tr>
<td>Framesize:</td>
<td class="streamstats"><xsl:value-of select="frame_size" /></td>
</tr>
</xsl:if>
<xsl:if test="frame_rate">
<tr>
<td>Framerate:</td>
<td class="streamstats"><xsl:value-of select="frame_rate" /></td>
</tr>
</xsl:if>
<xsl:if test="listeners">
<tr>
<td>Listeners (current):</td>
<td class="streamstats"><xsl:value-of select="listeners" /></td>
</tr>
</xsl:if>
<xsl:if test="listener_peak">
<tr>
<td>Listeners (peak):</td>
<td class="streamstats"><xsl:value-of select="listener_peak" /></td>
</tr>
</xsl:if>
<xsl:if test="genre">
<tr>
<td>Genre:</td>
<td class="streamstats"><xsl:value-of select="genre" /></td>
</tr>
</xsl:if>
<xsl:if test="server_url">
<tr>
<td>Stream URL:</td>
<td class="streamstats">
<a href="{server_url}"><xsl:value-of select="server_url" /></a>
</td>
</tr>
</xsl:if>
<tr>
<td>Currently playing:</td>
<td class="streamstats">
<xsl:if test="artist">
<xsl:value-of select="artist" /> -
</xsl:if>
<xsl:value-of select="title" />
</td>
</tr>
</tbody>
</table>
</div>
</div>
</xsl:when>
<xsl:otherwise>
<h3><xsl:value-of select="@mount" /> - Not Connected</h3>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<div id="footer">
Support icecast development at <a href="http://www.icecast.org">www.icecast.org</a>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View File

@ -1,12 +0,0 @@
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0" >
<xsl:output omit-xml-declaration="no" method="xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" encoding="UTF-8" />
<xsl:template match = "/icestats" >
<pre>
MountPoint,Connections,Stream Name,Current Listeners,Description,Currently Playing,Stream URL
Global,Client:<xsl:value-of select="connections" /> Source: <xsl:value-of select="source_connections" />,,<xsl:value-of select="listeners" />,,
<xsl:for-each select="source">
<xsl:value-of select="@mount" />,,<xsl:value-of select="name" />,<xsl:value-of select="listeners" />,<xsl:value-of select="description" />,<xsl:value-of select="artist" /> - <xsl:value-of select="title" />,<xsl:value-of select="url" />
</xsl:for-each>
</pre>
</xsl:template>
</xsl:stylesheet>

View File

@ -1,250 +1,274 @@
/******************************************************************************
This file styles the bar that goes across the top of all Xiph.Org
pages.
The style that comes from this was first (to my knowledge) at
http://alistapart.com/stories/practicalcss/ in the
"Splitting the Difference" section.
******************************************************************************/
/* This effect doesn't work at all if all content is pinched in a bit. */
html, body {
html {
margin: 0;
padding: 0;
}
body {
margin-left: 50px;
margin-right: 25px;
background-color: #000;
}
.xiphnav {
body {
padding: 0 25px 0 50px;
background-color: #000;
font-family: Verdana, sans-serif;
font-weight: normal;
padding: .25em;
margin-bottom: .5em;
border-bottom: 1px solid #000;
color: #000;
background: #aaa;
text-decoration: none;
color: #fff;
}
h2 {
a {
color: #f8ef64;
text-decoration: none;
border-bottom: 1px dotted #f8ef64;
}
a:hover {
color: #f8ef64;
text-decoration: none;
border-bottom: 1px solid #f8ef64;
}
h1 {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: bold;
font-size: 3em;
color: #fff;
padding: 10px 0px 10px 80px;
margin-top:3px;
background: transparent url(/icecast.png) no-repeat scroll left center
}
h1 {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: bold;
font-size: 100%;
color: #fff;
margin-top:3px;
}
.nav {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: bold;
font-size: 110%;
color: #fff;
}
.nav:hover {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: bold;
color: #f8ef64;
}
.xiphnav_a {
text-decoration: none;
font-weight: normal;
color: #000;
}
.news {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: normal;
color: #fff;
}
.newsheader {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: normal;
font-size: 110%;
color: #f8ef64;
background: #444;
}
.streamtd {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: normal;
font-size: 85%;
color: #fff;
padding:15px;
}
.streamtd_alt {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: normal;
font-size: 85%;
color: #fff;
margin-top: 3px;
}
.streamtd_alt_2 {
font-family: Verdana, sans-serif;
text-decoration: underline;
font-weight: normal;
font-size: 85%;
color: #fff;
}
td {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: normal;
color: #fff;
}
.roundcont {
width: 90%;
background-color: #656565;
color: #fff;
}
.roundcont a {
margin: 0px 10px;
}
.newscontent {
margin: 0 20px;
}
h3 {
margin: 0px;
padding: 0px;
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: bold;
font-size: 110%;
color: #f8ef64;
}
.newscontent h3 {
margin-bottom: 10px;
border-bottom: 1px groove #ACACAC;
h1#header{
padding: 10px 0px 10px 80px;
background: transparent url(/icecast.png) no-repeat scroll left center;
}
.newscontent h4 {
margin: 10px 0px;
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: bold;
font-size: 110%;
h3 small {
color: #fff;
font-size: 70%;
padding-left: 15px;
}
form.alignedform label {
text-align: right;
display: inline-block;
vertical-align: middle;
width: 10em;
margin: 0 1em 0 0;
}
form.alignedform input {
display: inline-block;
vertical-align: middle;
border: 1px solid #f8ef64;
background-color: #333;
color: #f8ef64;
}
.newscontent p {
margin: 0 0;
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: none;
font-size: 90%;
}
.newscontent td {
margin: 0 0;
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: none;
font-size: 90%;
}
.newscontent td.streamdata {
margin: 0 0;
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: none;
font-size: 90%;
color: #f8ef64;
}
.streamheader table {
width: 100%;
margin-bottom: 5px;
border-bottom: 1px groove #ACACAC;
}
.streamheader td {
margin: 0px;
padding-top: 10px;
padding-bottom: 10px;
padding: 10 5 10 5;
border: 0px solid white;
}
.streamheader h3 {
border: 0px;
}
.streamheader a {
padding: 8px 5px 3px 30px;
text-decoration: none;
background: transparent url("/tunein.png") no-repeat left center;
}
.streamheader a.auth {
padding-top: 10px;
padding-bottom: 10px;
padding-left: 32px;
background: transparent url("/key.png") no-repeat left center;
}
.newscontent a {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: bold;
margin: 0px;
color: #f8ef64;
}
.newscontent a:hover {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: bold;
color: #fff;
}
.newscontent a.nav2 {
font-family: Verdana, sans-serif;
text-decoration: none;
font-weight: bold;
padding: 2px 9px;
background: #444;
color: #f8ef64;
}
.newscontent a.nav2:hover {
font-family: Verdana, sans-serif;
text-decoration: none;
background: #777;
font-weight: bold;
color: #fff;
}
.poster {
font-family: Verdana, sans-serif;
margin: 50px 120px 20px 0px;
display: block;
text-decoration: none;
font-size: 100%;
color: #f8ef64;
padding: 5px;
border-top: 1px groove #ACACAC;
}
.roundcont p {
margin: 10px 50px;
padding: 5px;
}
.roundtop {
background: url(/corner_topright.jpg) no-repeat top right;
#menu {
border-top: 3px solid #7B96C6;
border-bottom: 3px solid #7B96C6;
text-align: center;
margin-bottom: 35px;
}
.roundbottom {
background: url(/corner_bottomright.jpg) no-repeat top right;
#menu ul {
margin: 0;
padding: 0;
list-style: none;
display: inline-block;
vertical-align: middle;
}
img.corner {
width: 15px;
height: 15px;
#menu ul li {
float: left;
padding-left: 25px;
padding-right: 25px;
}
#menu ul li a {
font-family: Verdana, sans-serif;
text-decoration: none;
color: #fff;
font-size: 18px;
border: none;
display: block !important;
}
#menu ul li a:hover {
color: #f8ef64;
}
.roundbox {
width: 90%;
background-color: #656565;
border-radius: 10px;
padding: 15px 20px;
margin-bottom: 35px;
}
.roundbox h3 {
margin-bottom: 10px;
border-bottom: 1px groove #ACACAC;
}
.roundbox table.yellowkeys tr td:last-child {
color: #f8ef64;
}
table.colortable {
border-collapse: collapse;
padding: 20px 0 20px 0;
margin: 0 auto;
}
table.colortable td {
border: 1px solid #000;
text-align: center;
padding: 5px;
}
table.colortable thead tr td {
color: #656565;
background: #f8ef64;
border-color: white;
}
.roundbox table.yellowkeys tr td {
padding: 5px 5px 0 0;
word-wrap: break-word;
word-break: break-all;
}
.right {
float: right;
}
.mounthead h3 {
float: left;
margin-bottom: 0px;
border-bottom: none;
}
.mountcont {
border-top: 1px groove #ACACAC;
clear: both;
}
ul.mountlist {
margin: 0;
padding: 0;
list-style: none;
text-align: right;
}
.mountlist li {
display: inline;
}
a.play {
padding-left: 22px;
margin-left: 25px;
border: none;
background: transparent url(/tunein.png) no-repeat scroll left center;
background-size: auto 100%;
}
a.auth {
padding-left: 22px;
margin-left: 25px;
border: none;
background: transparent url(/key.png) no-repeat scroll left top;
background-size: auto 100%;
}
/* Admin navigation */
ul.nav {
margin: 0;
padding: 5px 0 10px 0;
clear: both;
list-style: none;
text-align: center;
}
ul.nav li {
display: inline;
}
ul.nav li a {
border: none;
display: inline-block;
padding: .2em .7em;
margin-top: .2em;
background-color: #333;
white-space: nowrap;
}
ul.nav li a:hover {
color: #fff;
}
/* Footer */
#footer {
border-top: 1px groove #ACACAC;
margin-top: 20px;
font-size: 80%;
}
@media (max-width: 800px) {
body {
padding: 0;
}
.roundbox {
width: auto;
border-radius: 0;
}
.roundbox table.yellowkeys tr td {
display: block;
padding: 5px 5px 0 0;
}
.roundbox table.yellowkeys tr td:last-child {
margin-bottom: 5px;
margin-left: 5px;
}
.scrolltable {
overflow: auto;
}
}
@media (max-width: 320px) {
ul.nav, #menu ul {
display: block;
}
ul.nav li, #menu ul li {
float: none;
}
ul.nav li a, #menu ul li a {
display: block;
}
ul.nav li + li, #menu ul li + li {
border-top: 1px solid #ACACAC;
}
a.play {
margin-left: 15px;
}
}