mirror of
https://gitlab.xiph.org/xiph/ezstream.git
synced 2024-11-03 04:17:18 -05:00
Add configuration migration tool
This commit is contained in:
parent
5287bbdd4b
commit
d81a3e23bb
4
NEWS
4
NEWS
@ -9,11 +9,13 @@ Changes in 1.0.0, released on XXXX-XX-XX:
|
||||
file settings have been added accordingly.
|
||||
* The real-time status information is now enabled explicitly with the new
|
||||
command line option -r.
|
||||
* The configuration file structure has changed.
|
||||
* TagLib (its C wrapper library) is now a mandatory dependency
|
||||
* Support the new '@b@' placeholder for separate album metadata.
|
||||
* The command line option -p has been added, causing ezstream to write a
|
||||
locked PID file to a given location
|
||||
* The configuration file structure has changed significantly. A configuration
|
||||
migration tool (ezstream-cfgmigrate) has been added to assist in the
|
||||
upgrade.
|
||||
|
||||
|
||||
Changes in 0.6.0, released on 2015-01-18:
|
||||
|
@ -212,6 +212,7 @@ AC_CONFIG_FILES([
|
||||
build-aux/Makefile
|
||||
compat/Makefile
|
||||
doc/Makefile
|
||||
doc/ezstream-cfgmigrate.1.in
|
||||
doc/ezstream-file.sh.1.in
|
||||
doc/ezstream.1.in
|
||||
examples/Makefile
|
||||
|
@ -1,6 +1,6 @@
|
||||
AUTOMAKE_OPTIONS = 1.10 foreign subdir-objects
|
||||
|
||||
man_MANS = ezstream.1 ezstream-file.sh.1
|
||||
man_MANS = ezstream.1 ezstream-cfgmigrate.1 ezstream-file.sh.1
|
||||
|
||||
do_subst = sed \
|
||||
-e 's|!!EXAMPLES_DIR!!|@EXAMPLES_DIR@|g'
|
||||
@ -10,6 +10,9 @@ do_subst = sed \
|
||||
ezstream.1: ezstream.1.in Makefile
|
||||
$(do_subst) < $(builddir)/ezstream.1.in > ezstream.1
|
||||
|
||||
ezstream-cfgmigrate.1: ezstream-cfgmigrate.1.in Makefile
|
||||
$(do_subst) < $(builddir)/ezstream-cfgmigrate.1.in > ezstream-cfgmigrate.1
|
||||
|
||||
ezstream-file.sh.1: ezstream-file.sh.1.in Makefile
|
||||
$(do_subst) < $(builddir)/ezstream-file.sh.1.in > ezstream-file.sh.1
|
||||
|
||||
|
61
doc/ezstream-cfgmigrate.1.in.in
Normal file
61
doc/ezstream-cfgmigrate.1.in.in
Normal file
@ -0,0 +1,61 @@
|
||||
.\" Copyright (c) 2018 Moritz Grimm <mgrimm@mrsserver.net>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd @BUILD_DATE@
|
||||
.Dt EZSTREAM-CFGMIGRATE 1
|
||||
.Os @PACKAGE_NAME@ @PACKAGE_VERSION@
|
||||
.Sh NAME
|
||||
.Nm ezstream-cfgmigrate
|
||||
.Nd migrate old ezstream configuration
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Bk -words
|
||||
.Op Fl hv
|
||||
.Fl 0 Ar v0-cfgfile
|
||||
.Ek
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility reads configuration files from older versions of
|
||||
.Nm ezstream
|
||||
and prints its current equivalent to standard output.
|
||||
.Pp
|
||||
It supports reading XML configuration from
|
||||
.Nm ezstream
|
||||
version 0.x
|
||||
.Pq zero .
|
||||
.Ss Command line arguments
|
||||
.Bl -tag -width Ds
|
||||
.It Fl 0 Ar v0-cfgfile
|
||||
.Pq The number zero.
|
||||
.Pp
|
||||
Read the XML configuration in
|
||||
.Ar v0-cfgfile
|
||||
and print its migrated content to standard output.
|
||||
.It Fl h
|
||||
Print a summary of available command line arguments with short descriptions
|
||||
and exit.
|
||||
.It Fl v
|
||||
Increase logging verbosity.
|
||||
May be used up to three times to also include debug logging output.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr ezstream 1 ,
|
||||
.Xr ezstream-file.sh 1
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm
|
||||
program and this manual were written by
|
||||
.An Moritz Grimm .
|
@ -114,7 +114,8 @@ Directory containing example configuration files for various uses of
|
||||
as well as example playlist and metadata scripts.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr ezstream 1
|
||||
.Xr ezstream 1 ,
|
||||
.Xr ezstream-cfgmigrate 1
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
|
@ -829,6 +829,7 @@ Directory containing example configuration files for various uses of
|
||||
as well as example playlist and metadata scripts.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr ezstream-cfgmigrate 1 ,
|
||||
.Xr ezstream-file.sh 1
|
||||
.Sh AUTHORS
|
||||
.Nm
|
||||
|
@ -10,8 +10,9 @@ noinst_HEADERS = \
|
||||
cfg_private.h \
|
||||
cfg_server.h \
|
||||
cfg_stream.h \
|
||||
cfg_xmlfile.h \
|
||||
cfgfile_xml.h \
|
||||
cmdline.h \
|
||||
ezconfig0.h \
|
||||
ezstream.h \
|
||||
log.h \
|
||||
mdata.h \
|
||||
@ -21,18 +22,18 @@ noinst_HEADERS = \
|
||||
xalloc.h
|
||||
|
||||
libcommon_la_SOURCES = \
|
||||
log.c \
|
||||
util.c \
|
||||
xalloc.c
|
||||
|
||||
libezstream_la_SOURCES = \
|
||||
cfg.c \
|
||||
cfg_decoder.c \
|
||||
cfg_encoder.c \
|
||||
cfg_intake.c \
|
||||
cfg_server.c \
|
||||
cfg_stream.c \
|
||||
cfg_xmlfile.c \
|
||||
cfgfile_xml.c \
|
||||
log.c \
|
||||
util.c \
|
||||
xalloc.c
|
||||
|
||||
libezstream_la_SOURCES = \
|
||||
cmdline.c \
|
||||
mdata.c \
|
||||
playlist.c \
|
||||
@ -44,12 +45,19 @@ libezstream_la_LIBADD = @EZ_LIBS@ \
|
||||
$(libezstream_la_DEPENDENCIES)
|
||||
|
||||
bin_SCRIPTS = ezstream-file.sh
|
||||
bin_PROGRAMS = ezstream
|
||||
bin_PROGRAMS = ezstream ezstream-cfgmigrate
|
||||
|
||||
ezstream_SOURCES = ezstream.c
|
||||
ezstream_DEPENDENCIES = libezstream.la
|
||||
ezstream_LDADD = $(ezstream_DEPENDENCIES)
|
||||
|
||||
ezstream_cfgmigrate_SOURCES = ezstream-cfgmigrate.c ezconfig0.c
|
||||
ezstream_cfgmigrate_DEPENDENCIES = \
|
||||
$(builddir)/libcommon.la \
|
||||
$(top_builddir)/compat/libcompat.la
|
||||
ezstream_cfgmigrate_LDADD = @EZ_LIBS@ \
|
||||
$(ezstream_cfgmigrate_DEPENDENCIES)
|
||||
|
||||
AM_CPPFLAGS = @EZ_CPPFLAGS@ -I$(top_srcdir)/compat
|
||||
AM_CFLAGS = @EZ_CFLAGS@
|
||||
AM_LDFLAGS = @EZ_LDFLAGS@ -avoid-version
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "cfg_private.h"
|
||||
#include "cfg_xmlfile.h"
|
||||
#include "cfgfile_xml.h"
|
||||
#include "log.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
@ -73,7 +73,7 @@ _cfg_load(void)
|
||||
{
|
||||
switch (cfg_program.config_type) {
|
||||
case CFG_TYPE_XMLFILE:
|
||||
if (0 > cfg_xmlfile_parse(cfg_program.config_file))
|
||||
if (0 > cfgfile_xml_parse(cfg_program.config_file))
|
||||
return (-1);
|
||||
break;
|
||||
default:
|
||||
|
@ -54,7 +54,7 @@ cfg_decoder_list_create(void)
|
||||
}
|
||||
|
||||
void
|
||||
cfg_decoder_list_destroy(cfg_decoder_list_t *dl_p)
|
||||
cfg_decoder_list_destroy(struct cfg_decoder_list **dl_p)
|
||||
{
|
||||
struct cfg_decoder_list *dl = *dl_p;
|
||||
struct cfg_decoder *d;
|
||||
@ -62,15 +62,26 @@ cfg_decoder_list_destroy(cfg_decoder_list_t *dl_p)
|
||||
if (!dl)
|
||||
return;
|
||||
|
||||
while (NULL != (d = TAILQ_FIRST(dl))) {
|
||||
TAILQ_REMOVE(dl, d, entry);
|
||||
cfg_decoder_destroy(&d);
|
||||
}
|
||||
while (NULL != (d = TAILQ_FIRST(dl)))
|
||||
cfg_decoder_list_remove(dl, &d);
|
||||
|
||||
xfree(dl);
|
||||
*dl_p = NULL;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
cfg_decoder_list_nentries(struct cfg_decoder_list *dl)
|
||||
{
|
||||
struct cfg_decoder *d;
|
||||
unsigned int n = 0;
|
||||
|
||||
TAILQ_FOREACH(d, dl, entry) {
|
||||
n++;
|
||||
}
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
struct cfg_decoder *
|
||||
cfg_decoder_list_find(struct cfg_decoder_list *dl, const char *name)
|
||||
{
|
||||
@ -115,6 +126,24 @@ cfg_decoder_list_get(struct cfg_decoder_list *dl, const char *name)
|
||||
return (d);
|
||||
}
|
||||
|
||||
void
|
||||
cfg_decoder_list_remove(struct cfg_decoder_list *dl, struct cfg_decoder **d_p)
|
||||
{
|
||||
TAILQ_REMOVE(dl, *d_p, entry);
|
||||
cfg_decoder_destroy(d_p);
|
||||
}
|
||||
|
||||
void
|
||||
cfg_decoder_list_foreach(struct cfg_decoder_list *dl,
|
||||
void (*cb)(cfg_decoder_t, void *), void *cb_arg)
|
||||
{
|
||||
struct cfg_decoder *d;
|
||||
|
||||
TAILQ_FOREACH(d, dl, entry) {
|
||||
cb(d, cb_arg);
|
||||
}
|
||||
}
|
||||
|
||||
struct cfg_decoder *
|
||||
cfg_decoder_create(const char *name)
|
||||
{
|
||||
@ -271,6 +300,17 @@ cfg_decoder_extsupport(struct cfg_decoder *d, const char *ext)
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
cfg_decoder_ext_foreach(struct cfg_decoder *d,
|
||||
void (*cb)(const char *, void *), void *cb_arg)
|
||||
{
|
||||
struct file_ext *e;
|
||||
|
||||
TAILQ_FOREACH(e, &d->exts, entry) {
|
||||
cb(e->ext, cb_arg);
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
cfg_decoder_get_name(struct cfg_decoder *d)
|
||||
{
|
||||
|
@ -23,6 +23,8 @@ typedef struct cfg_decoder_list * cfg_decoder_list_t;
|
||||
cfg_decoder_list_t
|
||||
cfg_decoder_list_create(void);
|
||||
void cfg_decoder_list_destroy(cfg_decoder_list_t *);
|
||||
unsigned int
|
||||
cfg_decoder_list_nentries(cfg_decoder_list_t);
|
||||
|
||||
cfg_decoder_t
|
||||
cfg_decoder_list_find(cfg_decoder_list_t, const char *);
|
||||
@ -30,6 +32,9 @@ cfg_decoder_t
|
||||
cfg_decoder_list_findext(cfg_decoder_list_t, const char *);
|
||||
cfg_decoder_t
|
||||
cfg_decoder_list_get(cfg_decoder_list_t, const char *);
|
||||
void cfg_decoder_list_remove(cfg_decoder_list_t, cfg_decoder_t *);
|
||||
void cfg_decoder_list_foreach(cfg_decoder_list_t, void (*)(cfg_decoder_t,
|
||||
void *), void *);
|
||||
|
||||
cfg_decoder_t
|
||||
cfg_decoder_create(const char *);
|
||||
@ -45,6 +50,8 @@ int cfg_decoder_add_match(cfg_decoder_t, cfg_decoder_list_t, const char *,
|
||||
int cfg_decoder_validate(cfg_decoder_t, const char **);
|
||||
|
||||
int cfg_decoder_extsupport(cfg_decoder_t, const char *);
|
||||
void cfg_decoder_ext_foreach(cfg_decoder_t, void (*)(const char *, void *),
|
||||
void *);
|
||||
|
||||
const char *
|
||||
cfg_decoder_get_name(cfg_decoder_t);
|
||||
|
@ -48,7 +48,7 @@ cfg_encoder_list_create(void)
|
||||
}
|
||||
|
||||
void
|
||||
cfg_encoder_list_destroy(cfg_encoder_list_t *el_p)
|
||||
cfg_encoder_list_destroy(struct cfg_encoder_list **el_p)
|
||||
{
|
||||
struct cfg_encoder_list *el = *el_p;
|
||||
struct cfg_encoder *e;
|
||||
@ -56,15 +56,26 @@ cfg_encoder_list_destroy(cfg_encoder_list_t *el_p)
|
||||
if (!el)
|
||||
return;
|
||||
|
||||
while (NULL != (e = TAILQ_FIRST(el))) {
|
||||
TAILQ_REMOVE(el, e, entry);
|
||||
cfg_encoder_destroy(&e);
|
||||
}
|
||||
while (NULL != (e = TAILQ_FIRST(el)))
|
||||
cfg_encoder_list_remove(el, &e);
|
||||
|
||||
xfree(el);
|
||||
*el_p = NULL;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
cfg_encoder_list_nentries(struct cfg_encoder_list *el)
|
||||
{
|
||||
struct cfg_encoder *e;
|
||||
unsigned int n = 0;
|
||||
|
||||
TAILQ_FOREACH(e, el, entry) {
|
||||
n++;
|
||||
}
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
struct cfg_encoder *
|
||||
cfg_encoder_list_find(struct cfg_encoder_list *el, const char *name)
|
||||
{
|
||||
@ -95,6 +106,24 @@ cfg_encoder_list_get(struct cfg_encoder_list *el, const char *name)
|
||||
return (e);
|
||||
}
|
||||
|
||||
void
|
||||
cfg_encoder_list_foreach(struct cfg_encoder_list *el,
|
||||
void (*cb)(cfg_encoder_t, void *), void *cb_arg)
|
||||
{
|
||||
struct cfg_encoder *e;
|
||||
|
||||
TAILQ_FOREACH(e, el, entry) {
|
||||
cb(e, cb_arg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cfg_encoder_list_remove(struct cfg_encoder_list *el, struct cfg_encoder **e_p)
|
||||
{
|
||||
TAILQ_REMOVE(el, *e_p, entry);
|
||||
cfg_encoder_destroy(e_p);
|
||||
}
|
||||
|
||||
struct cfg_encoder *
|
||||
cfg_encoder_create(const char *name)
|
||||
{
|
||||
|
@ -25,11 +25,16 @@ typedef struct cfg_encoder_list * cfg_encoder_list_t;
|
||||
cfg_encoder_list_t
|
||||
cfg_encoder_list_create(void);
|
||||
void cfg_encoder_list_destroy(cfg_encoder_list_t *);
|
||||
unsigned int
|
||||
cfg_encoder_list_nentries(cfg_encoder_list_t);
|
||||
|
||||
cfg_encoder_t
|
||||
cfg_encoder_list_find(cfg_encoder_list_t, const char *);
|
||||
cfg_encoder_t
|
||||
cfg_encoder_list_get(cfg_encoder_list_t, const char *);
|
||||
void cfg_encoder_list_remove(cfg_encoder_list_t, cfg_encoder_t *o);
|
||||
void cfg_encoder_list_foreach(cfg_encoder_list_t, void (*)(cfg_encoder_t,
|
||||
void *), void *);
|
||||
|
||||
cfg_encoder_t
|
||||
cfg_encoder_create(const char *);
|
||||
|
@ -68,6 +68,19 @@ cfg_intake_list_destroy(cfg_intake_list_t *il_p)
|
||||
*il_p = NULL;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
cfg_intake_list_nentries(struct cfg_intake_list *il)
|
||||
{
|
||||
struct cfg_intake *i;
|
||||
unsigned int n = 0;
|
||||
|
||||
TAILQ_FOREACH(i, il, entry) {
|
||||
n++;
|
||||
}
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
struct cfg_intake *
|
||||
cfg_intake_list_find(struct cfg_intake_list *il, const char *name)
|
||||
{
|
||||
@ -98,6 +111,17 @@ cfg_intake_list_get(struct cfg_intake_list *il, const char *name)
|
||||
return (i);
|
||||
}
|
||||
|
||||
void
|
||||
cfg_intake_list_foreach(struct cfg_intake_list *il,
|
||||
void (*cb)(cfg_intake_t, void *), void *cb_arg)
|
||||
{
|
||||
struct cfg_intake *i;
|
||||
|
||||
TAILQ_FOREACH(i, il, entry) {
|
||||
cb(i, cb_arg);
|
||||
}
|
||||
}
|
||||
|
||||
struct cfg_intake *
|
||||
cfg_intake_create(const char *name)
|
||||
{
|
||||
@ -228,6 +252,24 @@ cfg_intake_get_type(struct cfg_intake *i)
|
||||
return (i->type);
|
||||
}
|
||||
|
||||
const char *
|
||||
cfg_intake_get_type_str(struct cfg_intake *i)
|
||||
{
|
||||
switch (i->type) {
|
||||
case CFG_INTAKE_FILE:
|
||||
return ("file");
|
||||
case CFG_INTAKE_PLAYLIST:
|
||||
return ("playlist");
|
||||
case CFG_INTAKE_PROGRAM:
|
||||
return ("program");
|
||||
case CFG_INTAKE_STDIN:
|
||||
return ("stdin");
|
||||
case CFG_INTAKE_AUTODETECT:
|
||||
default:
|
||||
return ("autodetect");
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
cfg_intake_get_filename(struct cfg_intake *i)
|
||||
{
|
||||
|
@ -33,11 +33,15 @@ typedef struct cfg_intake_list * cfg_intake_list_t;
|
||||
cfg_intake_list_t
|
||||
cfg_intake_list_create(void);
|
||||
void cfg_intake_list_destroy(cfg_intake_list_t *);
|
||||
unsigned int
|
||||
cfg_intake_list_nentries(cfg_intake_list_t);
|
||||
|
||||
cfg_intake_t
|
||||
cfg_intake_list_find(cfg_intake_list_t, const char *);
|
||||
cfg_intake_t
|
||||
cfg_intake_list_get(cfg_intake_list_t, const char *);
|
||||
void cfg_intake_list_foreach(cfg_intake_list_t, void (*)(cfg_intake_t,
|
||||
void *), void *);
|
||||
|
||||
cfg_intake_t
|
||||
cfg_intake_create(const char *);
|
||||
@ -60,6 +64,8 @@ const char *
|
||||
cfg_intake_get_name(cfg_intake_t);
|
||||
enum cfg_intake_type
|
||||
cfg_intake_get_type(cfg_intake_t);
|
||||
const char *
|
||||
cfg_intake_get_type_str(cfg_intake_t);
|
||||
const char *
|
||||
cfg_intake_get_filename(cfg_intake_t);
|
||||
int cfg_intake_get_shuffle(cfg_intake_t);
|
||||
|
@ -30,9 +30,6 @@
|
||||
#define UCREDS_SIZE 256
|
||||
#define CSUITE_SIZE 2048
|
||||
|
||||
#define DEFAULT_PORT 8000
|
||||
#define DEFAULT_USER "source"
|
||||
|
||||
struct cfg_program {
|
||||
char name[PATH_MAX];
|
||||
enum cfg_config_type config_type;
|
||||
|
@ -76,6 +76,19 @@ cfg_server_list_destroy(cfg_server_list_t *sl_p)
|
||||
*sl_p = NULL;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
cfg_server_list_nentries(struct cfg_server_list *sl)
|
||||
{
|
||||
struct cfg_server *s;
|
||||
unsigned int n = 0;
|
||||
|
||||
TAILQ_FOREACH(s, sl, entry) {
|
||||
n++;
|
||||
}
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
struct cfg_server *
|
||||
cfg_server_list_find(struct cfg_server_list *sl, const char *name)
|
||||
{
|
||||
@ -106,6 +119,17 @@ cfg_server_list_get(struct cfg_server_list *sl, const char *name)
|
||||
return (s);
|
||||
}
|
||||
|
||||
void
|
||||
cfg_server_list_foreach(struct cfg_server_list *sl,
|
||||
void (*cb)(cfg_server_t, void *), void *cb_arg)
|
||||
{
|
||||
struct cfg_server *s;
|
||||
|
||||
TAILQ_FOREACH(s, sl, entry) {
|
||||
cb(s, cb_arg);
|
||||
}
|
||||
}
|
||||
|
||||
struct cfg_server *
|
||||
cfg_server_create(const char *name)
|
||||
{
|
||||
@ -355,13 +379,13 @@ cfg_server_get_hostname(struct cfg_server *s)
|
||||
unsigned int
|
||||
cfg_server_get_port(struct cfg_server *s)
|
||||
{
|
||||
return (s->port ? s->port : DEFAULT_PORT);
|
||||
return (s->port ? s->port : CFG_SERVER_DEFAULT_PORT);
|
||||
}
|
||||
|
||||
const char *
|
||||
cfg_server_get_user(struct cfg_server *s)
|
||||
{
|
||||
return (s->user[0] ? s->user : DEFAULT_USER);
|
||||
return (s->user[0] ? s->user : CFG_SERVER_DEFAULT_USER);
|
||||
}
|
||||
|
||||
const char *
|
||||
@ -376,6 +400,20 @@ cfg_server_get_tls(struct cfg_server *s)
|
||||
return (s->tls);
|
||||
}
|
||||
|
||||
const char *
|
||||
cfg_server_get_tls_str(struct cfg_server *s)
|
||||
{
|
||||
switch (s->tls) {
|
||||
case CFG_TLS_NONE:
|
||||
return ("none");
|
||||
case CFG_TLS_REQUIRED:
|
||||
return ("required");
|
||||
case CFG_TLS_MAY:
|
||||
default:
|
||||
return ("may");
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
cfg_server_get_tls_cipher_suite(struct cfg_server *s)
|
||||
{
|
||||
|
@ -17,6 +17,9 @@
|
||||
#ifndef __CFG_SERVER_H__
|
||||
#define __CFG_SERVER_H__
|
||||
|
||||
#define CFG_SERVER_DEFAULT_PORT 8000
|
||||
#define CFG_SERVER_DEFAULT_USER "source"
|
||||
|
||||
enum cfg_server_protocol {
|
||||
CFG_PROTO_HTTP = 0,
|
||||
CFG_PROTO_HTTPS,
|
||||
@ -38,11 +41,15 @@ typedef struct cfg_server_list * cfg_server_list_t;
|
||||
cfg_server_list_t
|
||||
cfg_server_list_create(void);
|
||||
void cfg_server_list_destroy(cfg_server_list_t *);
|
||||
unsigned int
|
||||
cfg_server_list_nentries(cfg_server_list_t);
|
||||
|
||||
cfg_server_t
|
||||
cfg_server_list_find(cfg_server_list_t, const char *);
|
||||
cfg_server_t
|
||||
cfg_server_list_get(cfg_server_list_t, const char *);
|
||||
void cfg_server_list_foreach(cfg_server_list_t, void (*)(cfg_server_t,
|
||||
void *), void *);
|
||||
|
||||
cfg_server_t
|
||||
cfg_server_create(const char *);
|
||||
@ -91,6 +98,8 @@ const char *
|
||||
cfg_server_get_password(cfg_server_t);
|
||||
enum cfg_server_tls
|
||||
cfg_server_get_tls(cfg_server_t);
|
||||
const char *
|
||||
cfg_server_get_tls_str(cfg_server_t);
|
||||
const char *
|
||||
cfg_server_get_tls_cipher_suite(cfg_server_t);
|
||||
const char *
|
||||
|
@ -76,6 +76,19 @@ cfg_stream_list_destroy(cfg_stream_list_t *sl_p)
|
||||
*sl_p = NULL;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
cfg_stream_list_nentries(struct cfg_stream_list *sl)
|
||||
{
|
||||
struct cfg_stream *s;
|
||||
unsigned int n = 0;
|
||||
|
||||
TAILQ_FOREACH(s, sl, entry) {
|
||||
n++;
|
||||
}
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
struct cfg_stream *
|
||||
cfg_stream_list_find(struct cfg_stream_list *sl, const char *name)
|
||||
{
|
||||
@ -106,6 +119,17 @@ cfg_stream_list_get(struct cfg_stream_list *sl, const char *name)
|
||||
return (s);
|
||||
}
|
||||
|
||||
void
|
||||
cfg_stream_list_foreach(struct cfg_stream_list *sl,
|
||||
void (*cb)(cfg_stream_t, void *), void *cb_arg)
|
||||
{
|
||||
struct cfg_stream *s;
|
||||
|
||||
TAILQ_FOREACH(s, sl, entry) {
|
||||
cb(s, cb_arg);
|
||||
}
|
||||
}
|
||||
|
||||
struct cfg_stream *
|
||||
cfg_stream_create(const char *name)
|
||||
{
|
||||
|
@ -36,11 +36,15 @@ typedef struct cfg_stream_list * cfg_stream_list_t;
|
||||
cfg_stream_list_t
|
||||
cfg_stream_list_create(void);
|
||||
void cfg_stream_list_destroy(cfg_stream_list_t *);
|
||||
unsigned int
|
||||
cfg_stream_list_nentries(cfg_stream_list_t);
|
||||
|
||||
cfg_stream_t
|
||||
cfg_stream_list_find(cfg_stream_list_t, const char *);
|
||||
cfg_stream_t
|
||||
cfg_stream_list_get(cfg_stream_list_t, const char *);
|
||||
void cfg_stream_list_foreach(cfg_stream_list_t, void (*)(cfg_stream_t,
|
||||
void *), void *);
|
||||
|
||||
cfg_stream_t
|
||||
cfg_stream_create(const char *);
|
||||
|
@ -18,24 +18,33 @@
|
||||
# include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cfg.h"
|
||||
#include "cfg_xmlfile.h"
|
||||
#include "cfgfile_xml.h"
|
||||
#include "log.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#include <libxml/parser.h>
|
||||
|
||||
static int _cfg_xmlfile_parse_server(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfg_xmlfile_parse_servers(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfg_xmlfile_parse_stream(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfg_xmlfile_parse_streams(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfg_xmlfile_parse_intake(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfg_xmlfile_parse_intakes(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfg_xmlfile_parse_metadata(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfg_xmlfile_parse_decoder(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfg_xmlfile_parse_decoders(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfg_xmlfile_parse_encoder(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfg_xmlfile_parse_encoders(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_server(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_servers(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_stream(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_streams(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_intake(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_intakes(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_metadata(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_decoder(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_decoders(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_encoder(xmlDocPtr, xmlNodePtr);
|
||||
static int _cfgfile_xml_parse_encoders(xmlDocPtr, xmlNodePtr);
|
||||
static void _cfgfile_xml_print_server(cfg_server_t, void *);
|
||||
static void _cfgfile_xml_print_stream(cfg_stream_t, void *);
|
||||
static void _cfgfile_xml_print_intake(cfg_intake_t, void *);
|
||||
static void _cfgfile_xml_print_decoder_ext(const char *, void *);
|
||||
static void _cfgfile_xml_print_decoder(cfg_decoder_t, void *);
|
||||
static void _cfgfile_xml_print_encoder(cfg_encoder_t, void *);
|
||||
|
||||
#define XML_CHAR(s) (const xmlChar *)(s)
|
||||
#define STD_CHAR(s) (const char *)(s)
|
||||
@ -60,7 +69,7 @@ static int _cfg_xmlfile_parse_encoders(xmlDocPtr, xmlNodePtr);
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_server(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_server(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
cfg_server_list_t sl;
|
||||
cfg_server_t s;
|
||||
@ -95,11 +104,11 @@ _cfg_xmlfile_parse_server(xmlDocPtr doc, xmlNodePtr cur)
|
||||
}
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_servers(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_servers(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("server")) &&
|
||||
0 > _cfg_xmlfile_parse_server(doc, cur))
|
||||
0 > _cfgfile_xml_parse_server(doc, cur))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -126,7 +135,7 @@ _cfg_xmlfile_parse_servers(xmlDocPtr doc, xmlNodePtr cur)
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_stream(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_stream(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
cfg_stream_list_t sl;
|
||||
cfg_stream_t s;
|
||||
@ -163,11 +172,11 @@ _cfg_xmlfile_parse_stream(xmlDocPtr doc, xmlNodePtr cur)
|
||||
}
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_streams(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_streams(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("stream")) &&
|
||||
0 > _cfg_xmlfile_parse_stream(doc, cur))
|
||||
0 > _cfgfile_xml_parse_stream(doc, cur))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -194,7 +203,7 @@ _cfg_xmlfile_parse_streams(xmlDocPtr doc, xmlNodePtr cur)
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_intake(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_intake(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
cfg_intake_list_t il;
|
||||
cfg_intake_t i;
|
||||
@ -222,11 +231,11 @@ _cfg_xmlfile_parse_intake(xmlDocPtr doc, xmlNodePtr cur)
|
||||
}
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_intakes(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_intakes(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("intake")) &&
|
||||
0 > _cfg_xmlfile_parse_intake(doc, cur))
|
||||
0 > _cfgfile_xml_parse_intake(doc, cur))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -249,7 +258,7 @@ _cfg_xmlfile_parse_intakes(xmlDocPtr doc, xmlNodePtr cur)
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_metadata(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_metadata(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
@ -289,7 +298,7 @@ _cfg_xmlfile_parse_metadata(xmlDocPtr doc, xmlNodePtr cur)
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_decoder(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_decoder(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
cfg_decoder_list_t dl;
|
||||
cfg_decoder_t d;
|
||||
@ -315,11 +324,11 @@ _cfg_xmlfile_parse_decoder(xmlDocPtr doc, xmlNodePtr cur)
|
||||
}
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_decoders(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_decoders(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("decoder")) &&
|
||||
0 > _cfg_xmlfile_parse_decoder(doc, cur))
|
||||
0 > _cfgfile_xml_parse_decoder(doc, cur))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -346,7 +355,7 @@ _cfg_xmlfile_parse_decoders(xmlDocPtr doc, xmlNodePtr cur)
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_encoder(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_encoder(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
cfg_encoder_list_t el;
|
||||
cfg_encoder_t e;
|
||||
@ -372,11 +381,11 @@ _cfg_xmlfile_parse_encoder(xmlDocPtr doc, xmlNodePtr cur)
|
||||
}
|
||||
|
||||
static int
|
||||
_cfg_xmlfile_parse_encoders(xmlDocPtr doc, xmlNodePtr cur)
|
||||
_cfgfile_xml_parse_encoders(xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("encoder")) &&
|
||||
0 > _cfg_xmlfile_parse_encoder(doc, cur))
|
||||
0 > _cfgfile_xml_parse_encoder(doc, cur))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -395,20 +404,20 @@ _cfg_xmlfile_parse_encoders(xmlDocPtr doc, xmlNodePtr cur)
|
||||
* port
|
||||
* user
|
||||
* password
|
||||
* reconnect_attempts
|
||||
* tls
|
||||
* tls_cipher_suite
|
||||
* ca_dir
|
||||
* ca_file
|
||||
* client_cert
|
||||
* reconnect_attempts
|
||||
* ...
|
||||
* streams
|
||||
* stream
|
||||
* name
|
||||
* mountpoint
|
||||
* public
|
||||
* intake
|
||||
* server
|
||||
* public
|
||||
* format
|
||||
* encoder
|
||||
* stream_name
|
||||
@ -448,7 +457,7 @@ _cfg_xmlfile_parse_encoders(xmlDocPtr doc, xmlNodePtr cur)
|
||||
* ...
|
||||
*/
|
||||
int
|
||||
cfg_xmlfile_parse(const char *config_file)
|
||||
cfgfile_xml_parse(const char *config_file)
|
||||
{
|
||||
xmlDocPtr doc = NULL;
|
||||
xmlNodePtr cur = NULL;
|
||||
@ -478,32 +487,32 @@ cfg_xmlfile_parse(const char *config_file)
|
||||
|
||||
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("servers"))) {
|
||||
if (0 > _cfg_xmlfile_parse_servers(doc, cur))
|
||||
if (0 > _cfgfile_xml_parse_servers(doc, cur))
|
||||
error = 1;
|
||||
continue;
|
||||
}
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("streams"))) {
|
||||
if (0 > _cfg_xmlfile_parse_streams(doc, cur))
|
||||
if (0 > _cfgfile_xml_parse_streams(doc, cur))
|
||||
error = 1;
|
||||
continue;
|
||||
}
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("intakes"))) {
|
||||
if (0 > _cfg_xmlfile_parse_intakes(doc, cur))
|
||||
if (0 > _cfgfile_xml_parse_intakes(doc, cur))
|
||||
error = 1;
|
||||
continue;
|
||||
}
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("metadata"))) {
|
||||
if (0 > _cfg_xmlfile_parse_metadata(doc, cur))
|
||||
if (0 > _cfgfile_xml_parse_metadata(doc, cur))
|
||||
error = 1;
|
||||
continue;
|
||||
}
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("decoders"))) {
|
||||
if (0 > _cfg_xmlfile_parse_decoders(doc, cur))
|
||||
if (0 > _cfgfile_xml_parse_decoders(doc, cur))
|
||||
error = 1;
|
||||
continue;
|
||||
}
|
||||
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("encoders"))) {
|
||||
if (0 > _cfg_xmlfile_parse_encoders(doc, cur))
|
||||
if (0 > _cfgfile_xml_parse_encoders(doc, cur))
|
||||
error = 1;
|
||||
continue;
|
||||
}
|
||||
@ -521,3 +530,220 @@ error:
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void
|
||||
_cfgfile_xml_print_server(cfg_server_t s, void *arg)
|
||||
{
|
||||
FILE *fp = (FILE *)arg;
|
||||
|
||||
fprintf(fp, " <server>\n");
|
||||
if (0 != strcasecmp(cfg_server_get_name(s), CFG_DEFAULT))
|
||||
fprintf(fp, " <name>%s</name>\n",
|
||||
cfg_server_get_name(s));
|
||||
fprintf(fp, " <protocol>%s</protocol>\n",
|
||||
cfg_server_get_protocol_str(s));
|
||||
if (cfg_server_get_hostname(s))
|
||||
fprintf(fp, " <hostname>%s</hostname>\n",
|
||||
cfg_server_get_hostname(s));
|
||||
if (cfg_server_get_port(s) != CFG_SERVER_DEFAULT_PORT)
|
||||
fprintf(fp, " <port>%u</port>\n",
|
||||
cfg_server_get_port(s));
|
||||
if (0 != strcasecmp(cfg_server_get_user(s), CFG_SERVER_DEFAULT_USER))
|
||||
fprintf(fp, " <user>%s</user>\n",
|
||||
cfg_server_get_user(s));
|
||||
if (cfg_server_get_password(s))
|
||||
fprintf(fp, " <password>%s</password>\n",
|
||||
cfg_server_get_password(s));
|
||||
if (cfg_server_get_tls(s) != CFG_TLS_MAY)
|
||||
fprintf(fp, " <tls>%s</tls>\n",
|
||||
cfg_server_get_tls_str(s));
|
||||
if (cfg_server_get_tls_cipher_suite(s))
|
||||
fprintf(fp, " <tls_cipher_suite>%s</tls_cipher_suite>\n",
|
||||
cfg_server_get_tls_cipher_suite(s));
|
||||
if (cfg_server_get_ca_dir(s))
|
||||
fprintf(fp, " <ca_dir>%s</ca_dir>\n",
|
||||
cfg_server_get_ca_dir(s));
|
||||
if (cfg_server_get_ca_file(s))
|
||||
fprintf(fp, " <ca_file>%s</ca_file>\n",
|
||||
cfg_server_get_ca_file(s));
|
||||
if (cfg_server_get_client_cert(s))
|
||||
fprintf(fp, " <client_cert>%s</client_cert>\n",
|
||||
cfg_server_get_client_cert(s));
|
||||
if (cfg_server_get_reconnect_attempts(s))
|
||||
fprintf(fp, " <reconnect_attempts>%u</reconnect_attempts>\n",
|
||||
cfg_server_get_reconnect_attempts(s));
|
||||
fprintf(fp, " </server>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
_cfgfile_xml_print_stream(cfg_stream_t s, void *arg)
|
||||
{
|
||||
FILE *fp = (FILE *)arg;
|
||||
|
||||
fprintf(fp, " <stream>\n");
|
||||
if (0 != strcasecmp(cfg_stream_get_name(s), CFG_DEFAULT))
|
||||
fprintf(fp, " <name>%s</name>\n",
|
||||
cfg_stream_get_name(s));
|
||||
if (cfg_stream_get_mountpoint(s))
|
||||
fprintf(fp, " <mountpoint>%s</mountpoint>\n",
|
||||
cfg_stream_get_mountpoint(s));
|
||||
if (cfg_stream_get_intake(s))
|
||||
fprintf(fp, " <intake>%s</intake>\n",
|
||||
cfg_stream_get_intake(s));
|
||||
if (cfg_stream_get_server(s))
|
||||
fprintf(fp, " <server>%s</server>\n",
|
||||
cfg_stream_get_server(s));
|
||||
if (cfg_stream_get_public(s))
|
||||
fprintf(fp, " <public>yes</public>\n");
|
||||
fprintf(fp, " <format>%s</format>\n",
|
||||
cfg_stream_get_format_str(s));
|
||||
if (cfg_stream_get_encoder(s))
|
||||
fprintf(fp, " <encoder>%s</encoder>\n",
|
||||
cfg_stream_get_encoder(s));
|
||||
if (cfg_stream_get_stream_name(s))
|
||||
fprintf(fp, " <stream_name>%s</stream_name>\n",
|
||||
cfg_stream_get_stream_name(s));
|
||||
if (cfg_stream_get_stream_url(s))
|
||||
fprintf(fp, " <stream_url>%s</stream_url>\n",
|
||||
cfg_stream_get_stream_url(s));
|
||||
if (cfg_stream_get_stream_genre(s))
|
||||
fprintf(fp, " <stream_genre>%s</stream_genre>\n",
|
||||
cfg_stream_get_stream_genre(s));
|
||||
if (cfg_stream_get_stream_description(s))
|
||||
fprintf(fp, " <stream_description>%s</stream_description>\n",
|
||||
cfg_stream_get_stream_description(s));
|
||||
if (cfg_stream_get_stream_quality(s))
|
||||
fprintf(fp, " <stream_quality>%s</stream_quality>\n",
|
||||
cfg_stream_get_stream_quality(s));
|
||||
if (cfg_stream_get_stream_bitrate(s))
|
||||
fprintf(fp, " <stream_bitrate>%s</stream_bitrate>\n",
|
||||
cfg_stream_get_stream_bitrate(s));
|
||||
if (cfg_stream_get_stream_samplerate(s))
|
||||
fprintf(fp, " <stream_samplerate>%s</stream_samplerate>\n",
|
||||
cfg_stream_get_stream_samplerate(s));
|
||||
if (cfg_stream_get_stream_channels(s))
|
||||
fprintf(fp, " <stream_channels>%s</stream_channels>\n",
|
||||
cfg_stream_get_stream_channels(s));
|
||||
fprintf(fp, " </stream>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
_cfgfile_xml_print_intake(cfg_intake_t i, void *arg)
|
||||
{
|
||||
FILE *fp = (FILE *)arg;
|
||||
|
||||
fprintf(fp, " <intake>\n");
|
||||
if (0 != strcasecmp(cfg_intake_get_name(i), CFG_DEFAULT))
|
||||
fprintf(fp, " <name>%s</name>\n",
|
||||
cfg_intake_get_name(i));
|
||||
if (cfg_intake_get_type(i))
|
||||
fprintf(fp, " <type>%s</type>\n",
|
||||
cfg_intake_get_type_str(i));
|
||||
if (cfg_intake_get_filename(i))
|
||||
fprintf(fp, " <filename>%s</filename>\n",
|
||||
cfg_intake_get_filename(i));
|
||||
if (cfg_intake_get_shuffle(i))
|
||||
fprintf(fp, " <shuffle>yes</shuffle>\n");
|
||||
if (cfg_intake_get_stream_once(i))
|
||||
fprintf(fp, " <stream_once>yes</stream_once>\n");
|
||||
fprintf(fp, " </intake>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
_cfgfile_xml_print_decoder_ext(const char *ext, void *arg)
|
||||
{
|
||||
FILE *fp = (FILE *)arg;
|
||||
|
||||
fprintf(fp, " <file_ext>%s</file_ext>\n", ext);
|
||||
}
|
||||
|
||||
static void
|
||||
_cfgfile_xml_print_decoder(cfg_decoder_t d, void *arg)
|
||||
{
|
||||
FILE *fp = (FILE *)arg;
|
||||
|
||||
fprintf(fp, " <decoder>\n");
|
||||
if (0 != strcasecmp(cfg_decoder_get_name(d), CFG_DEFAULT))
|
||||
fprintf(fp, " <name>%s</name>\n",
|
||||
cfg_decoder_get_name(d));
|
||||
if (cfg_decoder_get_program(d))
|
||||
fprintf(fp, " <program>%s</program>\n",
|
||||
cfg_decoder_get_program(d));
|
||||
cfg_decoder_ext_foreach(d, _cfgfile_xml_print_decoder_ext, fp);
|
||||
fprintf(fp, " </decoder>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
_cfgfile_xml_print_encoder(cfg_encoder_t e, void *arg)
|
||||
{
|
||||
FILE *fp = (FILE *)arg;
|
||||
|
||||
fprintf(fp, " <encoder>\n");
|
||||
if (0 != strcasecmp(cfg_encoder_get_name(e), CFG_DEFAULT))
|
||||
fprintf(fp, " <name>%s</name>\n",
|
||||
cfg_encoder_get_name(e));
|
||||
fprintf(fp, " <format>%s</format>\n",
|
||||
cfg_stream_fmt2str(cfg_encoder_get_format(e)));
|
||||
if (cfg_encoder_get_program(e))
|
||||
fprintf(fp, " <program>%s</program>\n",
|
||||
cfg_encoder_get_program(e));
|
||||
fprintf(fp, " </encoder>\n");
|
||||
}
|
||||
|
||||
void
|
||||
cfgfile_xml_print(FILE *fp)
|
||||
{
|
||||
fprintf(fp, "<ezstream>\n");
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, " <servers>\n");
|
||||
cfg_server_list_foreach(cfg_get_servers(), _cfgfile_xml_print_server,
|
||||
fp);
|
||||
fprintf(fp, " </servers>\n");
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, " <streams>\n");
|
||||
cfg_stream_list_foreach(cfg_get_streams(), _cfgfile_xml_print_stream,
|
||||
fp);
|
||||
fprintf(fp, " </streams>\n");
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, " <intakes>\n");
|
||||
cfg_intake_list_foreach(cfg_get_intakes(), _cfgfile_xml_print_intake,
|
||||
fp);
|
||||
fprintf(fp, " </intakes>\n");
|
||||
if (cfg_decoder_list_nentries(cfg_get_decoders())) {
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, " <decoders>\n");
|
||||
cfg_decoder_list_foreach(cfg_get_decoders(),
|
||||
_cfgfile_xml_print_decoder, fp);
|
||||
fprintf(fp, " </decoders>\n");
|
||||
}
|
||||
if (cfg_encoder_list_nentries(cfg_get_encoders())) {
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, " <encoders>\n");
|
||||
cfg_encoder_list_foreach(cfg_get_encoders(),
|
||||
_cfgfile_xml_print_encoder, fp);
|
||||
fprintf(fp, " </encoders>\n");
|
||||
}
|
||||
if (cfg_get_metadata_program() ||
|
||||
cfg_get_metadata_format_str() ||
|
||||
0 <= cfg_get_metadata_refresh_interval() ||
|
||||
cfg_get_metadata_normalize_strings() ||
|
||||
cfg_get_metadata_no_updates()) {
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, " <metadata>\n");
|
||||
if (cfg_get_metadata_program())
|
||||
fprintf(fp, " <program>%s</program>\n",
|
||||
cfg_get_metadata_program());
|
||||
if (cfg_get_metadata_format_str())
|
||||
fprintf(fp, " <format_str>%s</format_str>\n",
|
||||
cfg_get_metadata_format_str());
|
||||
if (0 <= cfg_get_metadata_refresh_interval())
|
||||
fprintf(fp, " <refresh_interval>%d</refresh_interval>\n",
|
||||
cfg_get_metadata_refresh_interval());
|
||||
if (cfg_get_metadata_normalize_strings())
|
||||
fprintf(fp, " <normalize_strings>yes</normalize_strings>\n");
|
||||
if (cfg_get_metadata_no_updates())
|
||||
fprintf(fp, " <no_updates>yes</no_updates>\n");
|
||||
fprintf(fp, " </metadata>\n");
|
||||
}
|
||||
fprintf(fp, "</ezstream>\n");
|
||||
}
|
@ -14,9 +14,10 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __CFG_XMLFILE_H__
|
||||
#define __CFG_XMLFILE_H__
|
||||
#ifndef __CFGFILE_XML_H__
|
||||
#define __CFGFILE_XML_H__
|
||||
|
||||
int cfg_xmlfile_parse(const char *);
|
||||
int cfgfile_xml_parse(const char *);
|
||||
void cfgfile_xml_print(FILE *);
|
||||
|
||||
#endif /* __CFG_XMLFILE_H__ */
|
||||
#endif /* __CFGFILE_XML_H__ */
|
814
src/ezconfig0.c
Normal file
814
src/ezconfig0.c
Normal file
@ -0,0 +1,814 @@
|
||||
/*
|
||||
* ezstream - source client for Icecast with external en-/decoder support
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
|
||||
* Copyright (C) 2007, 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ezconfig0.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <libxml/parser.h>
|
||||
|
||||
#define XML_CHAR(s) (const xmlChar *)(s)
|
||||
#define STD_CHAR(s) (const char *)(s)
|
||||
|
||||
static EZCONFIG ezConfig;
|
||||
static const char *blankString = "";
|
||||
|
||||
unsigned int checkDecoderLine(const char *, const char *, long);
|
||||
unsigned int checkEncoderLine(const char *, const char *, long);
|
||||
unsigned int checkFormatLine(const char *, const char *, long);
|
||||
|
||||
EZCONFIG *
|
||||
getEZConfig(void)
|
||||
{
|
||||
return (&ezConfig);
|
||||
}
|
||||
|
||||
const char *
|
||||
getFormatEncoder(const char *format)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ezConfig.numEncoderDecoders; i++) {
|
||||
if (ezConfig.encoderDecoders[i] != NULL &&
|
||||
ezConfig.encoderDecoders[i]->format != NULL &&
|
||||
strcmp(ezConfig.encoderDecoders[i]->format, format) == 0) {
|
||||
if (ezConfig.encoderDecoders[i]->encoder != NULL)
|
||||
return (ezConfig.encoderDecoders[i]->encoder);
|
||||
else
|
||||
return (blankString);
|
||||
}
|
||||
}
|
||||
|
||||
return (blankString);
|
||||
}
|
||||
|
||||
const char *
|
||||
getFormatDecoder(const char *match)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ezConfig.numEncoderDecoders; i++) {
|
||||
if (ezConfig.encoderDecoders[i] != NULL &&
|
||||
ezConfig.encoderDecoders[i]->match != NULL &&
|
||||
strcmp(ezConfig.encoderDecoders[i]->match, match) == 0) {
|
||||
if (ezConfig.encoderDecoders[i]->decoder != NULL)
|
||||
return (ezConfig.encoderDecoders[i]->decoder);
|
||||
else
|
||||
return (blankString);
|
||||
}
|
||||
}
|
||||
|
||||
return (blankString);
|
||||
}
|
||||
|
||||
int
|
||||
parseConfig(const char *fileName)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr cur;
|
||||
xmlChar *ls_xmlContentPtr;
|
||||
int program_set, reconnect_set, shuffle_set,
|
||||
streamOnce_set, svrinfopublic_set,
|
||||
refresh_set;
|
||||
unsigned int config_error;
|
||||
|
||||
xmlLineNumbersDefault(1);
|
||||
if ((doc = xmlParseFile(fileName)) == NULL) {
|
||||
log_error("%s: Parse error (not well-formed XML.)\n", fileName);
|
||||
return (0);
|
||||
}
|
||||
|
||||
cur = xmlDocGetRootElement(doc);
|
||||
|
||||
if (cur == NULL) {
|
||||
log_error("%s: Parse error (empty XML document.)\n", fileName);
|
||||
xmlFreeDoc(doc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
memset(&ezConfig, 0, sizeof(ezConfig));
|
||||
ezConfig.metadataRefreshInterval = -1;
|
||||
|
||||
config_error = 0;
|
||||
program_set = 0;
|
||||
reconnect_set = 0;
|
||||
refresh_set = 0;
|
||||
shuffle_set = 0;
|
||||
streamOnce_set = 0;
|
||||
svrinfopublic_set = 0;
|
||||
|
||||
for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"url")) {
|
||||
if (ezConfig.URL != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <url> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.URL = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"sourceuser")) {
|
||||
if (ezConfig.username != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <sourceuser> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.username = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"sourcepassword")) {
|
||||
if (ezConfig.password != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <sourcepassword> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.password = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"format")) {
|
||||
if (ezConfig.format != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <format> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
char *p;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.format = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
for (p = ezConfig.format; *p != '\0'; p++)
|
||||
*p = (char)toupper((int)*p);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"filename")) {
|
||||
if (ezConfig.fileName != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <filename> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if (strlen(STD_CHAR(ls_xmlContentPtr)) > PATH_MAX - 1) {
|
||||
log_error("%s[%ld]: Error: Path or filename in <filename> is too long\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
ezConfig.fileName = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"metadata_progname")) {
|
||||
if (ezConfig.metadataProgram != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <metadata_progname> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if (strlen(STD_CHAR(ls_xmlContentPtr)) > PATH_MAX - 1) {
|
||||
log_error("%s[%ld]: Error: Path or filename in <metadata_progname> is too long\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
ezConfig.metadataProgram = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"metadata_format")) {
|
||||
if (ezConfig.metadataFormat != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <metadata_format> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
unsigned int ret;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.metadataFormat = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
if ((ret = checkFormatLine(ezConfig.metadataFormat,
|
||||
fileName, xmlGetLineNo(cur)))
|
||||
> 0) {
|
||||
config_error += ret;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"metadata_refreshinterval")) {
|
||||
if (refresh_set) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <metadata_refreshinterval> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
const char *errstr;
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.metadataRefreshInterval = (int)strtonum(STD_CHAR(ls_xmlContentPtr), -1LL, (long long)INT_MAX, &errstr);
|
||||
if (errstr) {
|
||||
log_error("%s[%ld]: Error: In <metadata_refreshinterval>: '%s' is %s\n",
|
||||
fileName, xmlGetLineNo(cur), STD_CHAR(ls_xmlContentPtr), errstr);
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
refresh_set = 1;
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"playlist_program")) {
|
||||
if (program_set) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <playlist_program> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
const char *errstr;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.fileNameIsProgram = (int)strtonum(STD_CHAR(ls_xmlContentPtr), 0LL, 1LL, &errstr);
|
||||
if (errstr) {
|
||||
log_error("%s[%ld]: Error: <playlist_program> may only contain 1 or 0\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
program_set = 1;
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"shuffle")) {
|
||||
if (shuffle_set) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <shuffle> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
const char *errstr;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.shuffle = (int)strtonum(STD_CHAR(ls_xmlContentPtr), 0LL, 1LL, &errstr);
|
||||
if (errstr) {
|
||||
log_error("%s[%ld]: Error: <shuffle> may only contain 1 or 0\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
shuffle_set = 1;
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"stream_once")) {
|
||||
if (streamOnce_set) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <stream_once> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
const char *errstr;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.streamOnce = (int)strtonum(STD_CHAR(ls_xmlContentPtr), 0LL, 1LL, &errstr);
|
||||
if (errstr) {
|
||||
log_error("%s[%ld]: Error: <stream_once> may only contain 1 or 0\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
streamOnce_set = 1;
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"reconnect_tries")) {
|
||||
if (reconnect_set) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <reconnect_tries> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
const char *errstr;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.reconnectAttempts = (unsigned int)strtonum(STD_CHAR(ls_xmlContentPtr), 0LL, (long long)UINT_MAX, &errstr);
|
||||
if (errstr) {
|
||||
log_error("%s[%ld]: Error: In <reconnect_tries>: '%s' is %s\n",
|
||||
fileName, xmlGetLineNo(cur), STD_CHAR(ls_xmlContentPtr), errstr);
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
reconnect_set = 1;
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"svrinfoname")) {
|
||||
if (ezConfig.serverName != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <svrinfoname> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.serverName = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"svrinfourl")) {
|
||||
if (ezConfig.serverURL != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <svrinfourl> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.serverURL = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"svrinfogenre")) {
|
||||
if (ezConfig.serverGenre != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <svrinfogenre> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.serverGenre = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"svrinfodescription")) {
|
||||
if (ezConfig.serverDescription != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <svrinfodescription> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.serverDescription = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"svrinfobitrate")) {
|
||||
if (ezConfig.serverBitrate != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <svrinfobitrate> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.serverBitrate = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"svrinfochannels")) {
|
||||
if (ezConfig.serverChannels != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <svrinfochannels> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.serverChannels = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"svrinfosamplerate")) {
|
||||
if (ezConfig.serverSamplerate != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <svrinfosamplerate> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.serverSamplerate = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"svrinfoquality")) {
|
||||
if (ezConfig.serverQuality != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <svrinfoquality> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.serverQuality = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"svrinfopublic")) {
|
||||
if (svrinfopublic_set) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <svrinfopublic> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur->xmlChildrenNode != NULL) {
|
||||
const char *errstr;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
ezConfig.serverPublic = (int)strtonum(STD_CHAR(ls_xmlContentPtr), 0LL, 1LL, &errstr);
|
||||
if (errstr) {
|
||||
log_error("%s[%ld]: Error: <svrinfopublic> may only contain 1 or 0\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
svrinfopublic_set = 1;
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *)"reencode")) {
|
||||
xmlNodePtr cur2;
|
||||
int enable_set;
|
||||
|
||||
enable_set = 0;
|
||||
for (cur2 = cur->xmlChildrenNode; cur2 != NULL;
|
||||
cur2 = cur2->next) {
|
||||
if (!xmlStrcmp(cur2->name, (const xmlChar *)"enable")) {
|
||||
if (enable_set) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <enable> elements\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur2->xmlChildrenNode != NULL) {
|
||||
const char *errstr;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur2->xmlChildrenNode, 1);
|
||||
ezConfig.reencode = (int)strtonum(STD_CHAR(ls_xmlContentPtr), 0LL, 1LL, &errstr);
|
||||
if (errstr) {
|
||||
log_error("%s[%ld]: Error: <enable> may only contain 1 or 0\n",
|
||||
fileName, xmlGetLineNo(cur));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
enable_set = 1;
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur2->name, (const xmlChar *)"encdec")) {
|
||||
xmlNodePtr cur3;
|
||||
FORMAT_ENCDEC *pformatEncDec;
|
||||
|
||||
pformatEncDec = calloc(1UL, sizeof(FORMAT_ENCDEC));
|
||||
|
||||
for (cur3 = cur2->xmlChildrenNode;
|
||||
cur3 != NULL; cur3 = cur3->next) {
|
||||
if (!xmlStrcmp(cur3->name, (const xmlChar *)"format")) {
|
||||
if (pformatEncDec->format != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <format> elements\n",
|
||||
fileName, xmlGetLineNo(cur3));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur3->xmlChildrenNode != NULL) {
|
||||
char *p;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
|
||||
pformatEncDec->format = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
for (p = pformatEncDec->format; *p != '\0'; p++)
|
||||
*p = (char)toupper((int)*p);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur3->name, (const xmlChar *)"match")) {
|
||||
if (pformatEncDec->match != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <match> elements\n",
|
||||
fileName, xmlGetLineNo(cur3));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur3->xmlChildrenNode != NULL) {
|
||||
char *p;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
|
||||
pformatEncDec->match = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
for (p = pformatEncDec->match; *p != '\0'; p++)
|
||||
*p = (char)tolower((int)*p);
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur3->name, (const xmlChar *)"decode")) {
|
||||
if (pformatEncDec->decoder != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <decode> elements\n",
|
||||
fileName, xmlGetLineNo(cur3));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur3->xmlChildrenNode != NULL) {
|
||||
unsigned int ret;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
|
||||
pformatEncDec->decoder = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
if ((ret = checkDecoderLine(pformatEncDec->decoder,
|
||||
fileName, xmlGetLineNo(cur3)))
|
||||
> 0) {
|
||||
config_error += ret;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!xmlStrcmp(cur3->name, (const xmlChar *)"encode")) {
|
||||
if (pformatEncDec->encoder != NULL) {
|
||||
log_error("%s[%ld]: Error: Cannot have multiple <encode> elements\n",
|
||||
fileName, xmlGetLineNo(cur3));
|
||||
config_error++;
|
||||
continue;
|
||||
}
|
||||
if (cur3->xmlChildrenNode != NULL) {
|
||||
unsigned int ret;
|
||||
|
||||
ls_xmlContentPtr = xmlNodeListGetString(doc, cur3->xmlChildrenNode, 1);
|
||||
pformatEncDec->encoder = strdup(STD_CHAR(ls_xmlContentPtr));
|
||||
xmlFree(ls_xmlContentPtr);
|
||||
if ((ret = checkEncoderLine(pformatEncDec->encoder,
|
||||
fileName, xmlGetLineNo(cur3)))
|
||||
> 0) {
|
||||
config_error += ret;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ezConfig.encoderDecoders[ezConfig.numEncoderDecoders] = pformatEncDec;
|
||||
ezConfig.numEncoderDecoders++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
if (config_error == 0)
|
||||
return (1);
|
||||
|
||||
freeConfig(&ezConfig);
|
||||
log_error("%u configuration error(s) in %s\n",
|
||||
config_error, fileName);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
freeConfig(EZCONFIG *cfg)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (cfg == NULL)
|
||||
return;
|
||||
|
||||
if (cfg->URL != NULL)
|
||||
free(cfg->URL);
|
||||
if (cfg->password != NULL)
|
||||
free(cfg->password);
|
||||
if (cfg->format != NULL)
|
||||
free(cfg->format);
|
||||
if (cfg->fileName != NULL)
|
||||
free(cfg->fileName);
|
||||
if (cfg->metadataProgram != NULL)
|
||||
free(cfg->metadataProgram);
|
||||
if (cfg->metadataFormat != NULL)
|
||||
free(cfg->metadataFormat);
|
||||
if (cfg->serverName != NULL)
|
||||
free(cfg->serverName);
|
||||
if (cfg->serverURL != NULL)
|
||||
free(cfg->serverURL);
|
||||
if (cfg->serverGenre != NULL)
|
||||
free(cfg->serverGenre);
|
||||
if (cfg->serverDescription != NULL)
|
||||
free(cfg->serverDescription);
|
||||
if (cfg->serverBitrate != NULL)
|
||||
free(cfg->serverBitrate);
|
||||
if (cfg->serverChannels != NULL)
|
||||
free(cfg->serverChannels);
|
||||
if (cfg->serverSamplerate != NULL)
|
||||
free(cfg->serverSamplerate);
|
||||
if (cfg->serverQuality != NULL)
|
||||
free(cfg->serverQuality);
|
||||
if (cfg->encoderDecoders != NULL) {
|
||||
for (i = 0; i < MAX_FORMAT_ENCDEC; i++) {
|
||||
if (cfg->encoderDecoders[i] != NULL) {
|
||||
if (cfg->encoderDecoders[i]->format != NULL)
|
||||
free(cfg->encoderDecoders[i]->format);
|
||||
if (cfg->encoderDecoders[i]->match != NULL)
|
||||
free(cfg->encoderDecoders[i]->match);
|
||||
if (cfg->encoderDecoders[i]->encoder != NULL)
|
||||
free(cfg->encoderDecoders[i]->encoder);
|
||||
if (cfg->encoderDecoders[i]->decoder != NULL)
|
||||
free(cfg->encoderDecoders[i]->decoder);
|
||||
free(cfg->encoderDecoders[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(cfg, 0, sizeof(EZCONFIG));
|
||||
}
|
||||
|
||||
unsigned int
|
||||
checkDecoderLine(const char *str, const char *file, long line)
|
||||
{
|
||||
unsigned int errors;
|
||||
char *p;
|
||||
int have_track = 0;
|
||||
|
||||
errors = 0;
|
||||
if ((p = strstr(str, STRING_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: `%s' placeholder not allowed in decoder command\n",
|
||||
file, line, STRING_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
if ((p = strstr(str, TRACK_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(TRACK_PLACEHOLDER);
|
||||
if ((p = strstr(p, TRACK_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in decoder command\n",
|
||||
file, line, TRACK_PLACEHOLDER);
|
||||
errors++;
|
||||
} else
|
||||
have_track = 1;
|
||||
}
|
||||
if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(METADATA_PLACEHOLDER);
|
||||
if ((p = strstr(p, METADATA_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in decoder command\n",
|
||||
file, line, METADATA_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if ((p = strstr(str, ARTIST_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(ARTIST_PLACEHOLDER);
|
||||
if ((p = strstr(p, ARTIST_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in decoder command\n",
|
||||
file, line, ARTIST_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if ((p = strstr(str, TITLE_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(TITLE_PLACEHOLDER);
|
||||
if ((p = strstr(p, TITLE_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in decoder command\n",
|
||||
file, line, TITLE_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_track) {
|
||||
log_error("%s[%ld]: Error: The decoder command requires the '%s' track placeholder\n",
|
||||
file, line, TRACK_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
|
||||
return (errors);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
checkEncoderLine(const char *str, const char *file, long line)
|
||||
{
|
||||
unsigned int errors;
|
||||
char *p;
|
||||
|
||||
errors = 0;
|
||||
if ((p = strstr(str, TRACK_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: `%s' placeholder not allowed in encoder command\n",
|
||||
file, line, TRACK_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
if ((p = strstr(str, STRING_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: `%s' placeholder not allowed in encoder command\n",
|
||||
file, line, STRING_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(METADATA_PLACEHOLDER);
|
||||
if ((p = strstr(p, METADATA_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in encoder command\n",
|
||||
file, line, METADATA_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if ((p = strstr(str, ARTIST_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(ARTIST_PLACEHOLDER);
|
||||
if ((p = strstr(p, ARTIST_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in encoder command\n",
|
||||
file, line, ARTIST_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if ((p = strstr(str, TITLE_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(TITLE_PLACEHOLDER);
|
||||
if ((p = strstr(p, TITLE_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in encoder command\n",
|
||||
file, line, TITLE_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
return (errors);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
checkFormatLine(const char *str, const char *file, long line)
|
||||
{
|
||||
unsigned int errors;
|
||||
char *p;
|
||||
|
||||
errors = 0;
|
||||
if ((p = strstr(str, METADATA_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: `%s' placeholder not allowed in <metadata_format>\n",
|
||||
file, line, METADATA_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
if ((p = strstr(str, TRACK_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(TRACK_PLACEHOLDER);
|
||||
if ((p = strstr(p, TRACK_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
|
||||
file, line, TRACK_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if ((p = strstr(str, STRING_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(STRING_PLACEHOLDER);
|
||||
if ((p = strstr(p, STRING_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
|
||||
file, line, STRING_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if ((p = strstr(str, ARTIST_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(ARTIST_PLACEHOLDER);
|
||||
if ((p = strstr(p, ARTIST_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
|
||||
file, line, ARTIST_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if ((p = strstr(str, TITLE_PLACEHOLDER)) != NULL) {
|
||||
p += strlen(TITLE_PLACEHOLDER);
|
||||
if ((p = strstr(p, TITLE_PLACEHOLDER)) != NULL) {
|
||||
log_error("%s[%ld]: Error: Multiple `%s' placeholders in <metadata_format>\n",
|
||||
file, line, TITLE_PLACEHOLDER);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
return (errors);
|
||||
}
|
75
src/ezconfig0.h
Normal file
75
src/ezconfig0.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* ezstream - source client for Icecast with external en-/decoder support
|
||||
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
|
||||
* Copyright (C) 2007, 2015 Moritz Grimm <mgrimm@mrsserver.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __EZCONFIG0_H__
|
||||
#define __EZCONFIG0_H__
|
||||
|
||||
#define MP3_FORMAT "MP3"
|
||||
#define VORBIS_FORMAT "VORBIS"
|
||||
#define THEORA_FORMAT "THEORA"
|
||||
|
||||
#define MAX_FORMAT_ENCDEC 15
|
||||
|
||||
#define TRACK_PLACEHOLDER "@T@"
|
||||
#define METADATA_PLACEHOLDER "@M@"
|
||||
#define ARTIST_PLACEHOLDER "@a@"
|
||||
#define TITLE_PLACEHOLDER "@t@"
|
||||
#define STRING_PLACEHOLDER "@s@"
|
||||
|
||||
typedef struct tag_FORMAT_ENCDEC {
|
||||
char *format;
|
||||
char *match;
|
||||
char *encoder;
|
||||
char *decoder;
|
||||
} FORMAT_ENCDEC;
|
||||
|
||||
typedef struct tag_EZCONFIG {
|
||||
char *URL;
|
||||
char *username;
|
||||
char *password;
|
||||
char *format;
|
||||
char *fileName;
|
||||
char *metadataProgram;
|
||||
char *metadataFormat;
|
||||
char *serverName;
|
||||
char *serverURL;
|
||||
char *serverGenre;
|
||||
char *serverDescription;
|
||||
char *serverBitrate;
|
||||
char *serverChannels;
|
||||
char *serverSamplerate;
|
||||
char *serverQuality;
|
||||
int serverPublic;
|
||||
int reencode;
|
||||
FORMAT_ENCDEC *encoderDecoders[MAX_FORMAT_ENCDEC];
|
||||
int numEncoderDecoders;
|
||||
int shuffle;
|
||||
int fileNameIsProgram;
|
||||
int streamOnce;
|
||||
unsigned int reconnectAttempts;
|
||||
int metadataRefreshInterval;
|
||||
} EZCONFIG;
|
||||
|
||||
EZCONFIG * getEZConfig(void);
|
||||
const char * getFormatEncoder(const char *format);
|
||||
const char * getFormatDecoder(const char *match);
|
||||
int parseConfig(const char *fileName);
|
||||
void freeConfig(EZCONFIG *);
|
||||
|
||||
#endif /* __EZCONFIG0_H__ */
|
423
src/ezstream-cfgmigrate.c
Normal file
423
src/ezstream-cfgmigrate.c
Normal file
@ -0,0 +1,423 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Moritz Grimm <mgrimm@mrsserver.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cfg.h"
|
||||
#include "cfgfile_xml.h"
|
||||
#include "ezconfig0.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static char *v0_cfgfile;
|
||||
static unsigned int cfg_verbosity;
|
||||
|
||||
#define OPTSTRING "0:hv"
|
||||
enum opt_vals {
|
||||
OPT_V0CONFIGFILE = '0',
|
||||
OPT_HELP = 'h',
|
||||
OPT_VERBOSE = 'v',
|
||||
OPT_INVALID = '?'
|
||||
};
|
||||
|
||||
static void _usage(void);
|
||||
static void _usage_help(void);
|
||||
static int _cmdline_parse(int, char *[], int *);
|
||||
static int _url_parse(const char *, char **, char **, char **);
|
||||
static int _parse_ezconfig0(EZCONFIG *);
|
||||
|
||||
static void
|
||||
_usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-hv] -0 v0-cfgfile\n",
|
||||
util_get_progname(NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
_usage_help(void)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " -0 v0-cfgfile migrate from v0-cfgfile (ezstream version 0.x)\n");
|
||||
fprintf(stderr, " -h print this help and exit\n");
|
||||
fprintf(stderr, " -v increase logging verbosity\n");
|
||||
}
|
||||
|
||||
static int
|
||||
_cmdline_parse(int argc, char *argv[], int *ret_p)
|
||||
{
|
||||
v0_cfgfile = NULL;
|
||||
cfg_verbosity = 0;
|
||||
optind = 1;
|
||||
for (;;) {
|
||||
int ch;
|
||||
|
||||
ch = getopt(argc, argv, OPTSTRING);
|
||||
if (0 > ch)
|
||||
break;
|
||||
|
||||
switch (ch) {
|
||||
case OPT_V0CONFIGFILE:
|
||||
v0_cfgfile = optarg;
|
||||
break;
|
||||
case OPT_HELP:
|
||||
_usage();
|
||||
_usage_help();
|
||||
*ret_p = 0;
|
||||
return (-1);
|
||||
case OPT_VERBOSE:
|
||||
cfg_verbosity++;
|
||||
break;
|
||||
case OPT_INVALID:
|
||||
default:
|
||||
_usage();
|
||||
*ret_p = 2;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!v0_cfgfile) {
|
||||
fprintf(stderr, "-%c must be provided\n",
|
||||
OPT_V0CONFIGFILE);
|
||||
_usage();
|
||||
*ret_p = 2;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
_url_parse(const char *url, char **hostname, char **port,
|
||||
char **mountname)
|
||||
{
|
||||
const char *p1, *p2, *p3;
|
||||
size_t hostsiz, portsiz, mountsiz;
|
||||
|
||||
if (strncasecmp(url, "http://", strlen("http://")) != 0) {
|
||||
log_error("%s: Invalid <url>: Not an HTTP address",
|
||||
v0_cfgfile);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
p1 = url + strlen("http://");
|
||||
p2 = strchr(p1, ':');
|
||||
if (p2 == NULL) {
|
||||
log_error("%s: Invalid <url>: Missing port", v0_cfgfile);
|
||||
return (-1);
|
||||
}
|
||||
hostsiz = (size_t)(p2 - p1) + 1;
|
||||
*hostname = xmalloc(hostsiz);
|
||||
strlcpy(*hostname, p1, hostsiz);
|
||||
|
||||
p2++;
|
||||
p3 = strchr(p2, '/');
|
||||
if (p3 == NULL) {
|
||||
log_error("%s: Invalid <url>: Missing mountpoint or too long port number",
|
||||
v0_cfgfile);
|
||||
xfree(*hostname);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
portsiz = (size_t)(p3 - p2) + 1;
|
||||
*port = xmalloc(portsiz);
|
||||
strlcpy(*port, p2, portsiz);
|
||||
|
||||
mountsiz = strlen(p3) + 1;
|
||||
*mountname = xmalloc(mountsiz);
|
||||
strlcpy(*mountname, p3, mountsiz);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define ENTITY_SET(e, el, func, ctx, val) do { \
|
||||
const char *err_str2; \
|
||||
\
|
||||
if (0 > (func)((e), (el), (val), &err_str2)) { \
|
||||
log_warning("%s: %s: %s: %s", v0_cfgfile, (ctx), \
|
||||
err_str2, (val)); \
|
||||
warnings++; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
_parse_ezconfig0(EZCONFIG *ez)
|
||||
{
|
||||
char *hostname, *port, *mountname;
|
||||
const char *err_str;
|
||||
int warnings = 0;
|
||||
cfg_server_list_t srv_list = cfg_get_servers();
|
||||
cfg_server_t srv = cfg_server_list_get(srv_list, CFG_DEFAULT);
|
||||
cfg_stream_list_t str_list = cfg_get_streams();
|
||||
cfg_stream_t str = cfg_stream_list_get(str_list, CFG_DEFAULT);
|
||||
cfg_intake_list_t in_list = cfg_get_intakes();
|
||||
cfg_intake_t in = cfg_intake_list_get(in_list, CFG_DEFAULT);
|
||||
cfg_encoder_list_t enc_list = cfg_get_encoders();
|
||||
cfg_decoder_list_t dec_list = cfg_get_decoders();;
|
||||
unsigned int i;
|
||||
char strbuf[BUFSIZ];
|
||||
|
||||
if (NULL == ez->URL || 0 == strlen(ez->URL)) {
|
||||
log_error("%s: Missing <url> -- not an ezstream version 0.x configuration?",
|
||||
v0_cfgfile);
|
||||
return (-1);
|
||||
}
|
||||
if (0 > _url_parse(ez->URL, &hostname, &port, &mountname))
|
||||
return (-1);
|
||||
ENTITY_SET(srv, srv_list, cfg_server_set_protocol, "<url>", "HTTP");
|
||||
ENTITY_SET(srv, srv_list, cfg_server_set_hostname, "<url>", hostname);
|
||||
xfree(hostname);
|
||||
ENTITY_SET(srv, srv_list, cfg_server_set_port, "<url>", port);
|
||||
xfree(port);
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_mountpoint, "<url>",
|
||||
mountname);
|
||||
xfree(mountname);
|
||||
|
||||
if (ez->username)
|
||||
ENTITY_SET(srv, srv_list, cfg_server_set_user,
|
||||
"<sourceuser>", ez->username);
|
||||
if (ez->password)
|
||||
ENTITY_SET(srv, srv_list, cfg_server_set_password,
|
||||
"<sourcepassword>", ez->password);
|
||||
if (ez->format)
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_format,
|
||||
"<format>", ez->format);
|
||||
if (ez->fileName) {
|
||||
if (0 == strcasecmp(ez->fileName, "stdin"))
|
||||
ENTITY_SET(in, in_list, cfg_intake_set_type,
|
||||
"<filename>", "stdin");
|
||||
else
|
||||
ENTITY_SET(in, in_list, cfg_intake_set_filename,
|
||||
"<filename>", ez->fileName);
|
||||
}
|
||||
if (ez->metadataProgram) {
|
||||
if (0 > cfg_set_metadata_program(ez->metadataProgram,
|
||||
&err_str)) {
|
||||
log_warning("%s: %s: %s: %s", v0_cfgfile,
|
||||
"<metadata_progname>", err_str,
|
||||
ez->metadataProgram);
|
||||
warnings++;
|
||||
}
|
||||
}
|
||||
if (ez->metadataFormat) {
|
||||
if (0 > cfg_set_metadata_format_str(ez->metadataFormat,
|
||||
&err_str)) {
|
||||
log_warning("%s: %s: %s: %s", v0_cfgfile,
|
||||
"<metadata_format>", err_str, ez->metadataFormat);
|
||||
warnings++;
|
||||
}
|
||||
}
|
||||
if (ez->metadataRefreshInterval) {
|
||||
snprintf(strbuf, sizeof(strbuf), "%d",
|
||||
ez->metadataRefreshInterval);
|
||||
if (0 > cfg_set_metadata_refresh_interval(strbuf, &err_str)) {
|
||||
log_warning("%s: %s: %s: %s", v0_cfgfile,
|
||||
"<metadata_refreshinterval>", err_str, strbuf);
|
||||
warnings++;
|
||||
}
|
||||
}
|
||||
if (ez->fileNameIsProgram)
|
||||
ENTITY_SET(in, in_list, cfg_intake_set_type,
|
||||
"playlist_program", "program");
|
||||
snprintf(strbuf, sizeof(strbuf), "%d", ez->shuffle);
|
||||
ENTITY_SET(in, in_list, cfg_intake_set_shuffle,
|
||||
"<shuffle>", strbuf);
|
||||
snprintf(strbuf, sizeof(strbuf), "%d", ez->streamOnce);
|
||||
ENTITY_SET(in, in_list, cfg_intake_set_stream_once,
|
||||
"<stream_once>", strbuf);
|
||||
snprintf(strbuf, sizeof(strbuf), "%u", ez->reconnectAttempts);
|
||||
ENTITY_SET(srv, srv_list, cfg_server_set_reconnect_attempts,
|
||||
"<reconnect_tries>", strbuf);
|
||||
if (ez->serverName)
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_stream_name,
|
||||
"<svrinfoname>", ez->serverName);
|
||||
if (ez->serverURL)
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_stream_url,
|
||||
"<svrinfourl>", ez->serverURL);
|
||||
if (ez->serverGenre)
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_stream_genre,
|
||||
"<svrinfogenre>", ez->serverGenre);
|
||||
if (ez->serverDescription)
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_stream_description,
|
||||
"<svrinfodescription>", ez->serverDescription);
|
||||
if (ez->serverBitrate)
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_stream_bitrate,
|
||||
"<svrinfobitrate>", ez->serverBitrate);
|
||||
if (ez->serverChannels)
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_stream_channels,
|
||||
"<svrinfochannels>", ez->serverChannels);
|
||||
if (ez->serverSamplerate)
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_stream_samplerate,
|
||||
"<svrinfosamplerate>", ez->serverSamplerate);
|
||||
if (ez->serverQuality)
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_stream_quality,
|
||||
"<svrinfoquality>", ez->serverQuality);
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_public,
|
||||
"<svrinfopublic>", ez->serverPublic ? "yes" : "no");
|
||||
if (ez->reencode)
|
||||
ENTITY_SET(str, str_list, cfg_stream_set_encoder, "<reencode>",
|
||||
ez->format);
|
||||
|
||||
for (i = 0; i < MAX_FORMAT_ENCDEC; i++) {
|
||||
FORMAT_ENCDEC *ed = ez->encoderDecoders[i];
|
||||
|
||||
if (!ed)
|
||||
continue;
|
||||
|
||||
if (ed->encoder) {
|
||||
cfg_encoder_t enc = cfg_encoder_list_get(enc_list,
|
||||
CFG_DEFAULT);
|
||||
|
||||
ENTITY_SET(enc, enc_list, cfg_encoder_set_program,
|
||||
"<encode>", ed->encoder);
|
||||
if (ed->format) {
|
||||
ENTITY_SET(enc, enc_list, cfg_encoder_set_name,
|
||||
"<format> (encoder)", ed->format);
|
||||
ENTITY_SET(enc, enc_list, cfg_encoder_set_format_str,
|
||||
"<format> (encoder)", ed->format);
|
||||
}
|
||||
if (0 > cfg_encoder_validate(enc, &err_str)) {
|
||||
log_warning("%s: %s: %s", v0_cfgfile,
|
||||
"<encdec> (encoder)", err_str);
|
||||
cfg_encoder_list_remove(enc_list, &enc);
|
||||
warnings++;
|
||||
}
|
||||
} else {
|
||||
if (ed->format &&
|
||||
0 == strcasecmp(ed->format, "THEORA")) {
|
||||
cfg_encoder_t enc = NULL;
|
||||
|
||||
enc = cfg_encoder_list_find(enc_list,
|
||||
ed->format);
|
||||
if (NULL == enc)
|
||||
enc = cfg_encoder_list_get(enc_list,
|
||||
CFG_DEFAULT);
|
||||
ENTITY_SET(enc, enc_list, cfg_encoder_set_name,
|
||||
"<format> (encoder)", ed->format);
|
||||
ENTITY_SET(enc, enc_list, cfg_encoder_set_format_str,
|
||||
"<format> (encoder)", ed->format);
|
||||
if (0 > cfg_encoder_validate(enc, &err_str)) {
|
||||
log_warning("%s: %s: %s", v0_cfgfile,
|
||||
"<encdec> (encoder)", err_str);
|
||||
cfg_encoder_list_remove(enc_list, &enc);
|
||||
warnings++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ed->decoder) {
|
||||
cfg_decoder_t dec = NULL;
|
||||
|
||||
if (ed->format)
|
||||
dec = cfg_decoder_list_find(dec_list, ed->format);
|
||||
if (NULL == dec)
|
||||
dec = cfg_decoder_list_get(dec_list, CFG_DEFAULT);
|
||||
|
||||
ENTITY_SET(dec, dec_list, cfg_decoder_set_program,
|
||||
"<decode>", ed->decoder);
|
||||
if (ed->format)
|
||||
ENTITY_SET(dec, dec_list, cfg_decoder_set_name,
|
||||
"<format> (decoder)", ed->format);
|
||||
if (ed->match)
|
||||
ENTITY_SET(dec, dec_list, cfg_decoder_add_match,
|
||||
"<match>", ed->match);
|
||||
|
||||
if (0 > cfg_decoder_validate(dec, &err_str)) {
|
||||
log_warning("%s: %s: %s", v0_cfgfile,
|
||||
"<encdec> (decoder)", err_str);
|
||||
cfg_decoder_list_remove(dec_list, &dec);
|
||||
warnings++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (warnings)
|
||||
log_warning("%s: %u warnings", v0_cfgfile, warnings);
|
||||
|
||||
if (cfg_stream_get_encoder(str) &&
|
||||
NULL == cfg_encoder_list_find(enc_list,
|
||||
cfg_stream_get_encoder(str))) {
|
||||
log_error("%s: %s encoder not found due to errors",
|
||||
v0_cfgfile, cfg_stream_get_encoder(str));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (0 > cfg_server_validate(srv, &err_str) ||
|
||||
0 > cfg_stream_validate(str, &err_str) ||
|
||||
0 > cfg_intake_validate(in, &err_str)) {
|
||||
log_error("%s: configuration invalid: %s", v0_cfgfile,
|
||||
err_str);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
EZCONFIG *ez;
|
||||
|
||||
ret = 1;
|
||||
if (0 > cfg_init() ||
|
||||
0 > log_init(util_get_progname(argv[0])) ||
|
||||
0 > _cmdline_parse(argc, argv, &ret))
|
||||
return (ret);
|
||||
(void)cfg_set_program_name(util_get_progname(argv[0]), NULL);
|
||||
|
||||
if (0 > parseConfig(v0_cfgfile))
|
||||
goto error;
|
||||
ez = getEZConfig();
|
||||
|
||||
if (0 > _parse_ezconfig0(ez))
|
||||
goto error;
|
||||
|
||||
printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
|
||||
printf("<!--\n");
|
||||
printf(" This ezstream version 1.x configuration file was generated by\n");
|
||||
printf(" %s.\n\n", util_get_progname(argv[0]));
|
||||
printf(" Source (ezstream version 0.x):\n");
|
||||
printf(" %s\n", basename(v0_cfgfile));
|
||||
printf(" -->\n\n");
|
||||
cfgfile_xml_print(stdout);
|
||||
|
||||
freeConfig(ez);
|
||||
|
||||
log_exit();
|
||||
cfg_exit();
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
if (ez)
|
||||
freeConfig(ez);
|
||||
|
||||
log_exit();
|
||||
cfg_exit();
|
||||
|
||||
return (1);
|
||||
}
|
@ -7,7 +7,7 @@ TESTS = \
|
||||
check_cfg_intake \
|
||||
check_cfg_server \
|
||||
check_cfg_stream \
|
||||
check_cfg_xmlfile \
|
||||
check_cfgfile_xml \
|
||||
check_cmdline \
|
||||
check_log \
|
||||
check_mdata \
|
||||
@ -43,9 +43,9 @@ check_cfg_stream_SOURCES = check_cfg_stream.c
|
||||
check_cfg_stream_DEPENDENCIES = $(top_builddir)/src/libezstream.la
|
||||
check_cfg_stream_LDADD = $(check_cfg_stream_DEPENDENCIES) @CHECK_LIBS@
|
||||
|
||||
check_cfg_xmlfile_SOURCES = check_cfg_xmlfile.c
|
||||
check_cfg_xmlfile_DEPENDENCIES = $(top_builddir)/src/libezstream.la
|
||||
check_cfg_xmlfile_LDADD = $(check_cfg_xmlfile_DEPENDENCIES) @CHECK_LIBS@
|
||||
check_cfgfile_xml_SOURCES = check_cfgfile_xml.c
|
||||
check_cfgfile_xml_DEPENDENCIES = $(top_builddir)/src/libezstream.la
|
||||
check_cfgfile_xml_LDADD = $(check_cfgfile_xml_DEPENDENCIES) @CHECK_LIBS@
|
||||
|
||||
check_cmdline_SOURCES = check_cmdline.c
|
||||
check_cmdline_DEPENDENCIES = $(top_builddir)/src/libezstream.la
|
||||
|
@ -7,15 +7,36 @@
|
||||
|
||||
#include "check_cfg.h"
|
||||
|
||||
static void _d_cb(const char *, void *);
|
||||
static void _dl_cb(cfg_decoder_t, void *);
|
||||
|
||||
Suite * cfg_suite(void);
|
||||
void setup_checked(void);
|
||||
void teardown_checked(void);
|
||||
|
||||
cfg_decoder_list_t decoders;
|
||||
|
||||
static void
|
||||
_d_cb(const char *ext, void *unused)
|
||||
{
|
||||
(void)unused;
|
||||
ck_assert_str_ne(ext, "");
|
||||
}
|
||||
|
||||
static void
|
||||
_dl_cb(cfg_decoder_t dec, void *arg)
|
||||
{
|
||||
int *count = (int *)arg;
|
||||
|
||||
ck_assert_ptr_ne(cfg_decoder_get_name(dec), NULL);
|
||||
cfg_decoder_ext_foreach(dec, _d_cb, NULL);
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
START_TEST(test_decoder_list_get)
|
||||
{
|
||||
cfg_decoder_t dec, dec2;
|
||||
int count = 0;
|
||||
|
||||
ck_assert_ptr_eq(cfg_decoder_list_get(decoders, NULL), NULL);
|
||||
ck_assert_ptr_eq(cfg_decoder_list_get(decoders, ""), NULL);
|
||||
@ -23,6 +44,12 @@ START_TEST(test_decoder_list_get)
|
||||
dec = cfg_decoder_list_get(decoders, "TeSt");
|
||||
dec2 = cfg_decoder_list_get(decoders, "test");
|
||||
ck_assert_ptr_eq(dec, dec2);
|
||||
|
||||
(void)cfg_decoder_list_get(decoders, "test2");
|
||||
ck_assert_int_eq(cfg_decoder_add_match(dec, decoders, ".test", NULL), 0);
|
||||
ck_assert_uint_eq(cfg_decoder_list_nentries(decoders), 2);
|
||||
cfg_decoder_list_foreach(decoders, _dl_cb, &count);
|
||||
ck_assert_int_eq(count, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
@ -7,15 +7,27 @@
|
||||
|
||||
#include "check_cfg.h"
|
||||
|
||||
static void _el_cb(cfg_encoder_t, void *);
|
||||
|
||||
Suite * cfg_suite(void);
|
||||
void setup_checked(void);
|
||||
void teardown_checked(void);
|
||||
|
||||
cfg_encoder_list_t encoders;
|
||||
|
||||
static void
|
||||
_el_cb(cfg_encoder_t enc, void *arg)
|
||||
{
|
||||
int *count = (int *)arg;
|
||||
|
||||
ck_assert_ptr_ne(cfg_encoder_get_name(enc), NULL);
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
START_TEST(test_encoder_list_get)
|
||||
{
|
||||
cfg_encoder_t enc, enc2;
|
||||
int count = 0;
|
||||
|
||||
ck_assert_ptr_eq(cfg_encoder_list_get(encoders, NULL), NULL);
|
||||
ck_assert_ptr_eq(cfg_encoder_list_get(encoders, ""), NULL);
|
||||
@ -23,6 +35,11 @@ START_TEST(test_encoder_list_get)
|
||||
enc = cfg_encoder_list_get(encoders, "TeSt");
|
||||
enc2 = cfg_encoder_list_get(encoders, "test");
|
||||
ck_assert_ptr_eq(enc, enc2);
|
||||
|
||||
(void)cfg_encoder_list_get(encoders, "test2");
|
||||
ck_assert_uint_eq(cfg_encoder_list_nentries(encoders), 2);
|
||||
cfg_encoder_list_foreach(encoders, _el_cb, &count);
|
||||
ck_assert_int_eq(count, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
@ -7,15 +7,27 @@
|
||||
|
||||
#include "check_cfg.h"
|
||||
|
||||
static void _il_cb(cfg_intake_t, void *);
|
||||
|
||||
Suite * cfg_suite(void);
|
||||
void setup_checked(void);
|
||||
void teardown_checked(void);
|
||||
|
||||
cfg_intake_list_t intakes;
|
||||
|
||||
static void
|
||||
_il_cb(cfg_intake_t in, void *arg)
|
||||
{
|
||||
int *count = (int *)arg;
|
||||
|
||||
ck_assert_ptr_ne(cfg_intake_get_name(in), NULL);
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
START_TEST(test_intake_list_get)
|
||||
{
|
||||
cfg_intake_t in, in2;
|
||||
int count = 0;
|
||||
|
||||
ck_assert_ptr_eq(cfg_intake_list_get(intakes, NULL), NULL);
|
||||
ck_assert_ptr_eq(cfg_intake_list_get(intakes, ""), NULL);
|
||||
@ -23,6 +35,11 @@ START_TEST(test_intake_list_get)
|
||||
in = cfg_intake_list_get(intakes, "TeSt");
|
||||
in2 = cfg_intake_list_get(intakes, "test");
|
||||
ck_assert_ptr_eq(in, in2);
|
||||
|
||||
(void)cfg_intake_list_get(intakes, "test2");
|
||||
ck_assert_uint_eq(cfg_intake_list_nentries(intakes), 2);
|
||||
cfg_intake_list_foreach(intakes, _il_cb, &count);
|
||||
ck_assert_int_eq(count, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
@ -50,15 +67,20 @@ START_TEST(test_intake_set_type)
|
||||
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "aUtOdEtEcT", NULL),
|
||||
0);
|
||||
ck_assert_int_eq(cfg_intake_get_type(in), CFG_INTAKE_AUTODETECT);
|
||||
ck_assert_str_eq(cfg_intake_get_type_str(in), "autodetect");
|
||||
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "FiLe", NULL), 0);
|
||||
ck_assert_int_eq(cfg_intake_get_type(in), CFG_INTAKE_FILE);
|
||||
ck_assert_str_eq(cfg_intake_get_type_str(in), "file");
|
||||
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "pLaYlIsT", NULL),
|
||||
0);
|
||||
ck_assert_int_eq(cfg_intake_get_type(in), CFG_INTAKE_PLAYLIST);
|
||||
ck_assert_str_eq(cfg_intake_get_type_str(in), "playlist");
|
||||
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "PrOgRaM", NULL), 0);
|
||||
ck_assert_int_eq(cfg_intake_get_type(in), CFG_INTAKE_PROGRAM);
|
||||
ck_assert_str_eq(cfg_intake_get_type_str(in), "program");
|
||||
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "sTdIn", NULL), 0);
|
||||
ck_assert_int_eq(cfg_intake_get_type(in), CFG_INTAKE_STDIN);
|
||||
ck_assert_str_eq(cfg_intake_get_type_str(in), "stdin");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
@ -7,15 +7,27 @@
|
||||
|
||||
#include "check_cfg.h"
|
||||
|
||||
static void _sl_cb(cfg_server_t, void *);
|
||||
|
||||
Suite * cfg_suite(void);
|
||||
void setup_checked(void);
|
||||
void teardown_checked(void);
|
||||
|
||||
cfg_server_list_t servers;
|
||||
|
||||
static void
|
||||
_sl_cb(cfg_server_t srv, void *arg)
|
||||
{
|
||||
int *count = (int *)arg;
|
||||
|
||||
ck_assert_ptr_ne(cfg_server_get_name(srv), NULL);
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
START_TEST(test_server_list_get)
|
||||
{
|
||||
cfg_server_t srv, srv2;
|
||||
int count = 0;
|
||||
|
||||
ck_assert_ptr_eq(cfg_server_list_get(servers, NULL), NULL);
|
||||
ck_assert_ptr_eq(cfg_server_list_get(servers, ""), NULL);
|
||||
@ -23,6 +35,11 @@ START_TEST(test_server_list_get)
|
||||
srv = cfg_server_list_get(servers, "TeSt");
|
||||
srv2 = cfg_server_list_get(servers, "test");
|
||||
ck_assert_ptr_eq(srv, srv2);
|
||||
|
||||
(void)cfg_server_list_get(servers, "test2");
|
||||
ck_assert_uint_eq(cfg_server_list_nentries(servers), 2);
|
||||
cfg_server_list_foreach(servers, _sl_cb, &count);
|
||||
ck_assert_int_eq(count, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
@ -65,7 +82,7 @@ START_TEST(test_server_port)
|
||||
cfg_server_t srv = cfg_server_list_get(servers, "test_server_port");
|
||||
const char *errstr2;
|
||||
|
||||
ck_assert_uint_eq(cfg_server_get_port(srv), DEFAULT_PORT);
|
||||
ck_assert_uint_eq(cfg_server_get_port(srv), CFG_SERVER_DEFAULT_PORT);
|
||||
|
||||
TEST_EMPTYSTR_T(cfg_server_t, cfg_server_list_get, servers,
|
||||
cfg_server_set_port);
|
||||
@ -89,7 +106,7 @@ START_TEST(test_server_user)
|
||||
{
|
||||
cfg_server_t srv = cfg_server_list_get(servers, "test_server_user");
|
||||
|
||||
ck_assert_str_eq(cfg_server_get_user(srv), DEFAULT_USER);
|
||||
ck_assert_str_eq(cfg_server_get_user(srv), CFG_SERVER_DEFAULT_USER);
|
||||
TEST_STRLCPY_T(cfg_server_t, cfg_server_list_get, servers,
|
||||
cfg_server_set_user, cfg_server_get_user, UCREDS_SIZE);
|
||||
}
|
||||
@ -123,11 +140,14 @@ START_TEST(test_server_tls)
|
||||
ck_assert_int_eq(cfg_server_get_tls(srv), CFG_TLS_MAY);
|
||||
ck_assert_int_eq(cfg_server_set_tls(srv, servers, "None", NULL), 0);
|
||||
ck_assert_int_eq(cfg_server_get_tls(srv), CFG_TLS_NONE);
|
||||
ck_assert_str_eq(cfg_server_get_tls_str(srv), "none");
|
||||
ck_assert_int_eq(cfg_server_set_tls(srv, servers, "Required", NULL),
|
||||
0);
|
||||
ck_assert_int_eq(cfg_server_get_tls(srv), CFG_TLS_REQUIRED);
|
||||
ck_assert_str_eq(cfg_server_get_tls_str(srv), "required");
|
||||
ck_assert_int_eq(cfg_server_set_tls(srv, servers, "May", NULL), 0);
|
||||
ck_assert_int_eq(cfg_server_get_tls(srv), CFG_TLS_MAY);
|
||||
ck_assert_str_eq(cfg_server_get_tls_str(srv), "may");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
@ -7,15 +7,27 @@
|
||||
|
||||
#include "check_cfg.h"
|
||||
|
||||
static void _sl_cb(cfg_stream_t, void *);
|
||||
|
||||
Suite * cfg_suite(void);
|
||||
void setup_checked(void);
|
||||
void teardown_checked(void);
|
||||
|
||||
cfg_stream_list_t streams;
|
||||
|
||||
static void
|
||||
_sl_cb(cfg_stream_t str, void *arg)
|
||||
{
|
||||
int *count = (int *)arg;
|
||||
|
||||
ck_assert_ptr_ne(cfg_stream_get_name(str), NULL);
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
START_TEST(test_stream_list_get)
|
||||
{
|
||||
cfg_stream_t str, str2;
|
||||
int count = 0;
|
||||
|
||||
ck_assert_ptr_eq(cfg_stream_list_get(streams, NULL), NULL);
|
||||
ck_assert_ptr_eq(cfg_stream_list_get(streams, ""), NULL);
|
||||
@ -23,6 +35,11 @@ START_TEST(test_stream_list_get)
|
||||
str = cfg_stream_list_get(streams, "TeSt");
|
||||
str2 = cfg_stream_list_get(streams, "test");
|
||||
ck_assert_ptr_eq(str, str2);
|
||||
|
||||
(void)cfg_stream_list_get(streams, "test2");
|
||||
ck_assert_uint_eq(cfg_stream_list_nentries(streams), 2);
|
||||
cfg_stream_list_foreach(streams, _sl_cb, &count);
|
||||
ck_assert_int_eq(count, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
@ -1,29 +1,61 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <check.h>
|
||||
|
||||
#include "cfg_private.h"
|
||||
#include "cfgfile_xml.h"
|
||||
#include "log.h"
|
||||
|
||||
static void _test_cfgfile_rw(const char *cfgfile);
|
||||
|
||||
Suite * cfg_xmlfile_suite(void);
|
||||
void setup_checked(void);
|
||||
void teardown_checked(void);
|
||||
|
||||
static void
|
||||
_test_cfgfile_rw(const char *cfgfile)
|
||||
{
|
||||
const char *testfile = BUILDDIR "/check_cfgfile_xml.xml";
|
||||
FILE *fp;
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
ck_assert_int_eq(cfg_set_program_config_file(cfgfile, NULL), 0);
|
||||
ck_assert_int_eq(cfg_file_reload(), 0);
|
||||
|
||||
fd = open(testfile, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
|
||||
ck_assert_int_ge(fd, 0);
|
||||
fp = fdopen(fd, "w");
|
||||
if (NULL == fp) {
|
||||
unlink(testfile);
|
||||
close(fd);
|
||||
}
|
||||
ck_assert_ptr_ne(fp, NULL);
|
||||
cfgfile_xml_print(fp);
|
||||
ck_assert_int_eq(fclose(fp), 0);
|
||||
|
||||
ck_assert_int_eq(cfg_set_program_config_file(testfile, NULL), 0);
|
||||
ret = cfg_file_reload();
|
||||
ck_assert_int_eq(unlink(testfile), 0);
|
||||
ck_assert_int_eq(ret, 0);
|
||||
}
|
||||
|
||||
START_TEST(test_reload)
|
||||
{
|
||||
ck_assert_int_eq(cfg_set_program_config_file(EXAMPLESDIR "/ezstream-file_template.xml",
|
||||
NULL), 0);
|
||||
ck_assert_int_eq(cfg_file_reload(), 0);
|
||||
_test_cfgfile_rw(EXAMPLESDIR "/ezstream-file_template.xml");
|
||||
_test_cfgfile_rw(EXAMPLESDIR "/ezstream-full.xml");
|
||||
_test_cfgfile_rw(EXAMPLESDIR "/ezstream-metadata.xml");
|
||||
_test_cfgfile_rw(EXAMPLESDIR "/ezstream-minimal.xml");
|
||||
_test_cfgfile_rw(EXAMPLESDIR "/ezstream-stdin.xml");
|
||||
_test_cfgfile_rw(EXAMPLESDIR "/ezstream-video.xml");
|
||||
ck_assert_int_eq(cfg_set_program_config_file(EXAMPLESDIR "/ezstream-full.xml",
|
||||
NULL), 0);
|
||||
ck_assert_int_eq(cfg_file_reload(), 0);
|
||||
ck_assert_int_eq(cfg_set_program_config_file(EXAMPLESDIR "/ezstream-minimal.xml",
|
||||
NULL), 0);
|
||||
ck_assert_int_eq(cfg_file_reload(), 0);
|
||||
ck_assert_int_eq(cfg_set_program_config_file(EXAMPLESDIR "/ezstream-stdin.xml",
|
||||
NULL), 0);
|
||||
ck_assert_int_eq(cfg_file_reload(), 0);
|
||||
ck_assert_int_eq(cfg_set_program_config_file(EXAMPLESDIR "/ezstream-video.xml",
|
||||
NULL), 0);
|
||||
ck_assert_int_eq(cfg_file_reload(), 0);
|
||||
ck_assert_int_eq(cfg_file_reload(), 0);
|
||||
ck_assert_int_eq(cfg_set_program_config_file(SRCDIR "/config-bad.xml",
|
||||
NULL), 0);
|
Loading…
Reference in New Issue
Block a user