#include "printf.h"
#include "regsub.h"
#include "signame.h"
+#include "authhash.h"
/** @brief Path to config file
*
}
static int parse_sample_format(const struct config_state *cs,
- ao_sample_format *ao,
+ struct stream_header *format,
int nvec, char **vec) {
char *p = vec[0];
long t;
- if (nvec != 1) {
+ if(nvec != 1) {
error(0, "%s:%d: wrong number of arguments", cs->path, cs->line);
return -1;
}
- if (xstrtol(&t, p, &p, 0)) {
+ if(xstrtol(&t, p, &p, 0)) {
error(errno, "%s:%d: converting bits-per-sample", cs->path, cs->line);
return -1;
}
- if (t != 8 && t != 16) {
+ if(t != 8 && t != 16) {
error(0, "%s:%d: bad bite-per-sample (%ld)", cs->path, cs->line, t);
return -1;
}
- if (ao) ao->bits = t;
+ if(format) format->bits = t;
switch (*p) {
- case 'l': case 'L': t = AO_FMT_LITTLE; p++; break;
- case 'b': case 'B': t = AO_FMT_BIG; p++; break;
- default: t = AO_FMT_NATIVE; break;
+ case 'l': case 'L': t = ENDIAN_LITTLE; p++; break;
+ case 'b': case 'B': t = ENDIAN_BIG; p++; break;
+ default: t = ENDIAN_NATIVE; break;
}
- if (ao) ao->byte_format = t;
- if (*p != '/') {
+ if(format) format->endian = t;
+ if(*p != '/') {
error(errno, "%s:%d: expected `/' after bits-per-sample",
cs->path, cs->line);
return -1;
}
p++;
- if (xstrtol(&t, p, &p, 0)) {
+ if(xstrtol(&t, p, &p, 0)) {
error(errno, "%s:%d: converting sample-rate", cs->path, cs->line);
return -1;
}
- if (t < 1 || t > INT_MAX) {
+ if(t < 1 || t > INT_MAX) {
error(0, "%s:%d: silly sample-rate (%ld)", cs->path, cs->line, t);
return -1;
}
- if (ao) ao->rate = t;
- if (*p != '/') {
+ if(format) format->rate = t;
+ if(*p != '/') {
error(0, "%s:%d: expected `/' after sample-rate",
cs->path, cs->line);
return -1;
}
p++;
- if (xstrtol(&t, p, &p, 0)) {
+ if(xstrtol(&t, p, &p, 0)) {
error(errno, "%s:%d: converting channels", cs->path, cs->line);
return -1;
}
- if (t < 1 || t > 8) {
+ if(t < 1 || t > 8) {
error(0, "%s:%d: silly number (%ld) of channels", cs->path, cs->line, t);
return -1;
}
- if (ao) ao->channels = t;
- if (*p) {
+ if(format) format->channels = t;
+ if(*p) {
error(0, "%s:%d: junk after channels", cs->path, cs->line);
return -1;
}
static int set_sample_format(const struct config_state *cs,
const struct conf *whoami,
int nvec, char **vec) {
- return parse_sample_format(cs, ADDRESS(cs->config, ao_sample_format),
+ return parse_sample_format(cs, ADDRESS(cs->config, struct stream_header),
nvec, vec);
}
}
}
-static int validate_address(const struct config_state attribute((unused)) *cs,
+static int validate_port(const struct config_state attribute((unused)) *cs,
int nvec,
char attribute((unused)) **vec) {
switch(nvec) {
case 2:
return 0;
default:
- error(0, "%s:%d: expected ADDRESS PORT",
+ error(0, "%s:%d: expected [ADDRESS] PORT",
cs->path, cs->line);
return -1;
}
}
+static int validate_algo(const struct config_state attribute((unused)) *cs,
+ int nvec,
+ char **vec) {
+ if(nvec != 1) {
+ error(0, "%s:%d: invalid algorithm specification", cs->path, cs->line);
+ return -1;
+ }
+ if(!valid_authhash(vec[0])) {
+ error(0, "%s:%d: unsuported algorithm '%s'", cs->path, cs->line, vec[0]);
+ return -1;
+ }
+ return 0;
+}
+
/** @brief Item name and and offset */
#define C(x) #x, offsetof(struct config, x)
/** @brief Item name and and offset */
static const struct conf conf[] = {
{ C(alias), &type_string, validate_alias },
{ C(allow), &type_stringlist_accum, validate_allow },
+ { C(authorization_algorithm), &type_string, validate_algo },
{ C(broadcast), &type_stringlist, validate_addrport },
- { C(broadcast_from), &type_stringlist, validate_address },
+ { C(broadcast_from), &type_stringlist, validate_addrport },
{ C(channel), &type_string, validate_channel },
{ C(checkpoint_kbyte), &type_integer, validate_non_negative },
{ C(checkpoint_min), &type_integer, validate_non_negative },
{ C(gap), &type_integer, validate_non_negative },
{ C(history), &type_integer, validate_positive },
{ C(home), &type_string, validate_isdir },
- { C(listen), &type_stringlist, validate_addrport },
+ { C(listen), &type_stringlist, validate_port },
{ C(lock), &type_boolean, validate_any },
{ C(mixer), &type_string, validate_ischr },
{ C(multicast_ttl), &type_integer, validate_non_negative },
{ C(nice_rescan), &type_integer, validate_non_negative },
{ C(nice_server), &type_integer, validate_any },
{ C(nice_speaker), &type_integer, validate_any },
+ { C(noticed_history), &type_integer, validate_positive },
{ C(password), &type_string, validate_any },
{ C(player), &type_stringlist_accum, validate_player },
{ C(plugins), &type_string_accum, validate_isdir },
c->sample_format.bits = 16;
c->sample_format.rate = 44100;
c->sample_format.channels = 2;
- c->sample_format.byte_format = AO_FMT_NATIVE;
+ c->sample_format.endian = ENDIAN_NATIVE;
c->queue_pad = 10;
c->speaker_backend = -1;
c->multicast_ttl = 1;
+ c->authorization_algorithm = xstrdup("sha1");
+ c->noticed_history = 31;
return c;
}
}
/** @brief Set post-parse defaults */
-static void config_postdefaults(struct config *c) {
+static void config_postdefaults(struct config *c,
+ int server) {
struct config_state cs;
const struct conf *whoami;
int n;
static const char *namepart[][4] = {
- { "title", "/([0-9]+:)?([^/]+)\\.[a-zA-Z0-9]+$", "$2", "display" },
+ { "title", "/([0-9]+ *[-:] *)?([^/]+)\\.[a-zA-Z0-9]+$", "$2", "display" },
{ "title", "/([^/]+)\\.[a-zA-Z0-9]+$", "$1", "sort" },
{ "album", "/([^/]+)/[^/]+$", "$1", "*" },
{ "artist", "/([^/]+)/[^/]+/[^/]+$", "$1", "*" },
#define NNAMEPART (int)(sizeof namepart / sizeof *namepart)
static const char *transform[][5] = {
- { "track", "^.*/([0-9]+:)?([^/]+)\\.[a-zA-Z0-9]+$", "$2", "display", "" },
+ { "track", "^.*/([0-9]+ *[-:] *)?([^/]+)\\.[a-zA-Z0-9]+$", "$2", "display", "" },
{ "track", "^.*/([^/]+)\\.[a-zA-Z0-9]+$", "$1", "sort", "" },
{ "dir", "^.*/([^/]+)$", "$1", "*", "" },
{ "dir", "^(the) ([^/]*)", "$2, $1", "sort", "i", },
#endif
}
}
- if(c->speaker_backend == BACKEND_COMMAND && !c->speaker_command)
- fatal(0, "speaker_backend is command but speaker_command is not set");
- if(c->speaker_backend == BACKEND_NETWORK && !c->broadcast.n)
- fatal(0, "speaker_backend is network but broadcast is not set");
+ if(server) {
+ if(c->speaker_backend == BACKEND_COMMAND && !c->speaker_command)
+ fatal(0, "speaker_backend is command but speaker_command is not set");
+ if(c->speaker_backend == BACKEND_NETWORK && !c->broadcast.n)
+ fatal(0, "speaker_backend is network but broadcast is not set");
+ }
+ if(c->speaker_backend) {
+ /* Override sample format */
+ c->sample_format.rate = 44100;
+ c->sample_format.channels = 2;
+ c->sample_format.bits = 16;
+ c->sample_format.endian = ENDIAN_BIG;
+ }
}
-/** @brief (Re-)read the config file */
-int config_read() {
+/** @brief (Re-)read the config file
+ * @param server If set, do extra checking
+ */
+int config_read(int server) {
struct config *c;
char *privconf;
struct passwd *pw;
return -1;
xfree(privconf);
/* install default namepart and transform settings */
- config_postdefaults(c);
+ config_postdefaults(c, server);
/* everything is good so we shall use the new config */
config_free(config);
config = c;