1
0
Fork 0

Add configuration migration tool

This commit is contained in:
Moritz Grimm 2018-01-23 01:51:48 +01:00
parent 5287bbdd4b
commit d81a3e23bb
31 changed files with 2050 additions and 98 deletions

4
NEWS
View File

@ -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:

View File

@ -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

View File

@ -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

View 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 .

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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)
{

View File

@ -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);

View File

@ -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)
{

View File

@ -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 *);

View File

@ -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)
{

View File

@ -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);

View File

@ -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;

View File

@ -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)
{

View File

@ -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 *);
@ -51,27 +58,27 @@ void cfg_server_destroy(cfg_server_t *);
int cfg_server_set_name(cfg_server_t, cfg_server_list_t, const char *,
const char **);
int cfg_server_set_protocol(cfg_server_t, cfg_server_list_t, const char *,
const char **);
const char **);
int cfg_server_set_hostname(cfg_server_t, cfg_server_list_t, const char *,
const char **);
const char **);
int cfg_server_set_port(cfg_server_t, cfg_server_list_t, const char *,
const char **);
const char **);
int cfg_server_set_user(cfg_server_t, cfg_server_list_t, const char *,
const char **);
const char **);
int cfg_server_set_password(cfg_server_t, cfg_server_list_t, const char *,
const char **);
const char **);
int cfg_server_set_tls(cfg_server_t, cfg_server_list_t, const char *,
const char **);
const char **);
int cfg_server_set_tls_cipher_suite(cfg_server_t, cfg_server_list_t,
const char *, const char **);
const char *, const char **);
int cfg_server_set_ca_dir(cfg_server_t, cfg_server_list_t, const char *,
const char **);
const char **);
int cfg_server_set_ca_file(cfg_server_t, cfg_server_list_t, const char *,
const char **);
const char **);
int cfg_server_set_client_cert(cfg_server_t, cfg_server_list_t,
const char *, const char **);
const char *, const char **);
int cfg_server_set_reconnect_attempts(cfg_server_t, cfg_server_list_t,
const char *, const char **);
const char *, const char **);
int cfg_server_validate(cfg_server_t, 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 *

View File

@ -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)
{

View File

@ -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 *);

View File

@ -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");
}

View File

@ -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
View 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
View 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
View 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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);