merge shank-rewrite-config changes

git-svn-id: https://svn.musicpd.org/mpd/trunk@2375 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
Warren Dukes 2004-10-28 05:14:55 +00:00
parent 8f40569aee
commit 58dbe4bb5d
24 changed files with 947 additions and 625 deletions

2
TODO
View File

@ -1,5 +1,7 @@
0.12 0.12
---- ----
*) Fix id3v1 encoding
*) Abstract audio stuff into a plugin oriented thing *) Abstract audio stuff into a plugin oriented thing
*) audio_ao & audio_oss & audio_shout *) audio_ao & audio_oss & audio_shout
*) allow for sending to multiple audio devices *) allow for sending to multiple audio devices

View File

@ -71,28 +71,25 @@ error_file "~/.mpd/mpd.error"
################## AUDIO OUTPUT ########################## ################## AUDIO OUTPUT ##########################
# #
# libao (ao_driver) supports any of the following: # libao (ao_driver) supports any of the following:
#
# * Null output (handy for testing without a sound device)
# * WAV files
# * AU files
# * OSS (Open Sound System, used on Linux and FreeBSD)
# * aRts
# * esd (ESounD or Enlighten Sound Daemon)
# * ALSA (Advanced Linux Sound Architecture)
# * AIX
# * Sun/NetBSD/OpenBSD
# * IRIX
# * NAS (Network Audio Server)
#
# Refer to libao documentation for more information # Refer to libao documentation for more information
# #
# OSS Audio Output # OSS Audio Output
#ao_driver "oss" #audio_output {
#ao_driver_options "dsp=/dev/dsp" # type "ao"
# name "my OSS device"
# driver "oss"
# options "dsp=/dev/dsp"
# write_size "1024"
#}
# #
# ALSA Audio Output # ALSA Audio Output
#ao_driver "alsa09" #audio_output {
#ao_driver_options "dev=hw:0,0" # type "ao"
# name "my ALSA device"
# driver "alsa09"
# options "dev=hw:0,0"
# write_size "1024"
#}
# #
# Set this if you have problems # Set this if you have problems
# playing audio files. # playing audio files.
@ -101,11 +98,24 @@ error_file "~/.mpd/mpd.error"
# #
#audio_output_format "44100:16:2" #audio_output_format "44100:16:2"
# #
# You should not need mess with ##########################################################
# this value unless you know
# what you're doing.
################# SHOUT STREAMING ########################
# #
#audio_write_size "1024" # Set this to allow mpd to stream its output to icecast2
# (i.e. mpd is a icecast2 source)
#
#audio_output {
# type "shout"
# name "my cool stream"
# host "hostname"
# port "8000"
# user "source"
# password "hackme"
# quality "5.0"
# format "44100:16:1"
#}
# #
########################################################## ##########################################################
@ -179,20 +189,6 @@ error_file "~/.mpd/mpd.error"
########################################## ##########################################
################ SHOUT OPTIONS #####################
#
#shout_host "host"
#shout_port "8000"
#shout_user "source"
#shout_password "hackme"
#shout_name "My MPD!"
#shout_mount "/mpd.ogg"
#shout_quality "0.5"
#shout_format "44100:16:1"
#
####################################################
################ MISCELLANEOUS OPTIONS ################### ################ MISCELLANEOUS OPTIONS ###################
# #
# This setting exists as precaution against attacks. # This setting exists as precaution against attacks.

View File

@ -31,9 +31,6 @@ static AudioFormat audio_format;
static AudioFormat * audio_configFormat = NULL; static AudioFormat * audio_configFormat = NULL;
static AudioOutput * aoOutput = NULL;
static AudioOutput * shoutOutput = NULL;
void copyAudioFormat(AudioFormat * dest, AudioFormat * src) { void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
if(!src) return; if(!src) return;
@ -42,17 +39,34 @@ void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
dest->channels = src->channels; dest->channels = src->channels;
} }
static AudioOutput ** audioOutputArray = NULL;
static int audioOutputArraySize = 0;
extern AudioOutputPlugin aoPlugin; extern AudioOutputPlugin aoPlugin;
extern AudioOutputPlugin shoutPlugin; extern AudioOutputPlugin shoutPlugin;
void initAudioDriver() { void initAudioDriver() {
ConfigParam * param = NULL;
int i;
initAudioOutputPlugins(); initAudioOutputPlugins();
loadAudioOutputPlugin(&aoPlugin); loadAudioOutputPlugin(&aoPlugin);
loadAudioOutputPlugin(&shoutPlugin); loadAudioOutputPlugin(&shoutPlugin);
aoOutput = newAudioOutput("ao"); while((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param))) {
assert(aoOutput); i = audioOutputArraySize++;
shoutOutput = newAudioOutput("shout");
audioOutputArray = realloc(audioOutputArray,
audioOutputArraySize*sizeof(AudioOutput *));
audioOutputArray[i] = newAudioOutput(param);
if(!audioOutputArray[i]) {
ERROR("problems configuring output device defined at "
"line %i\n", param->line);
exit(EXIT_FAILURE);
}
}
} }
void getOutputAudioFormat(AudioFormat * inAudioFormat, void getOutputAudioFormat(AudioFormat * inAudioFormat,
@ -65,13 +79,17 @@ void getOutputAudioFormat(AudioFormat * inAudioFormat,
} }
void initAudioConfig() { void initAudioConfig() {
char * conf = getConf()[CONF_AUDIO_OUTPUT_FORMAT]; ConfigParam * param = getConfigParam(CONF_AUDIO_OUTPUT_FORMAT);
if(NULL == conf) return; if(NULL == param || NULL == param->value) return;
audio_configFormat = malloc(sizeof(AudioFormat)); audio_configFormat = malloc(sizeof(AudioFormat));
if(0 != parseAudioConfig(audio_configFormat, conf)) exit(EXIT_FAILURE); if(0 != parseAudioConfig(audio_configFormat, param->value)) {
ERROR("error parsing \"%s\" at line %i\n",
CONF_AUDIO_OUTPUT_FORMAT, param->line);
exit(EXIT_FAILURE);
}
} }
int parseAudioConfig(AudioFormat * audioFormat, char * conf) { int parseAudioConfig(AudioFormat * audioFormat, char * conf) {
@ -145,10 +163,15 @@ void finishAudioConfig() {
} }
void finishAudioDriver() { void finishAudioDriver() {
finishAudioOutput(aoOutput); int i;
if(shoutOutput) finishAudioOutput(shoutOutput);
shoutOutput = NULL; for(i = 0; i < audioOutputArraySize; i++) {
aoOutput = NULL; finishAudioOutput(audioOutputArray[i]);
}
free(audioOutputArray);
audioOutputArray = NULL;
audioOutputArraySize = 0;
} }
int isCurrentAudioFormat(AudioFormat * audioFormat) { int isCurrentAudioFormat(AudioFormat * audioFormat) {
@ -160,29 +183,65 @@ int isCurrentAudioFormat(AudioFormat * audioFormat) {
} }
int openAudioDevice(AudioFormat * audioFormat) { int openAudioDevice(AudioFormat * audioFormat) {
if(!aoOutput->open || !isCurrentAudioFormat(audioFormat)) { int isCurrentFormat = isCurrentAudioFormat(audioFormat);
if(audioFormat) copyAudioFormat(&audio_format, audioFormat); int ret = -1;
if(shoutOutput) openAudioOutput(shoutOutput, &audio_format); int i;
return openAudioOutput(aoOutput, &audio_format);
if(!audioOutputArray) return -1;
if(!isCurrentFormat) {
copyAudioFormat(&audio_format, audioFormat);
} }
return 0; for(i = 0; i < audioOutputArraySize; i++) {
if(!audioOutputArray[i]->open || !isCurrentFormat) {
if(0 == openAudioOutput(audioOutputArray[i],
&audio_format))
{
ret = 0;
}
}
}
return ret;
} }
int playAudio(char * playChunk, int size) { int playAudio(char * playChunk, int size) {
if(shoutOutput) playAudioOutput(shoutOutput, playChunk, size); int ret = -1;
return playAudioOutput(aoOutput, playChunk, size); int i;
for(i = 0; i < audioOutputArraySize; i++) {
if(0 == playAudioOutput(audioOutputArray[i], playChunk, size)) {
ret = 0;
}
}
return ret;
} }
int isAudioDeviceOpen() { int isAudioDeviceOpen() {
return aoOutput->open; int ret = 0;
int i;
for(i = 0; i < audioOutputArraySize; i++) {
ret |= audioOutputArray[i]->open;
}
return ret;
} }
void closeAudioDevice() { void closeAudioDevice() {
if(shoutOutput) closeAudioOutput(shoutOutput); int i;
closeAudioOutput(aoOutput);
for(i = 0; i < audioOutputArraySize; i++) {
closeAudioOutput(audioOutputArray[i]);
}
} }
void sendMetadataToAudioDevice(MpdTag * tag) { void sendMetadataToAudioDevice(MpdTag * tag) {
if(shoutOutput) sendMetadataToAudioOutput(shoutOutput, tag); int i;
for(i = 0; i < audioOutputArraySize; i++) {
sendMetadataToAudioOutput(audioOutputArray[i], tag);
}
} }

View File

@ -1,6 +1,12 @@
#include <audioOutput.h> #include "audioOutput.h"
#include <list.h> #include "list.h"
#include "log.h"
#include <string.h>
#define AUDIO_OUTPUT_TYPE "type"
#define AUDIO_OUTPUT_NAME "name"
static List * audioOutputPluginList; static List * audioOutputPluginList;
@ -21,13 +27,32 @@ void finishAudioOutputPlugins() {
freeList(audioOutputPluginList); freeList(audioOutputPluginList);
} }
AudioOutput * newAudioOutput(char * name) { #define getBlockParam(name, str) { \
BlockParam * bp; \
bp = getBlockParam(param, name); \
if(bp == NULL) { \
ERROR("couldn't find parameter \"%s\" in audio output " \
"definition begining at %i\n", \
name, param->line); \
exit(EXIT_FAILURE); \
} \
str = bp->value; \
}
AudioOutput * newAudioOutput(ConfigParam * param) {
AudioOutput * ret = NULL; AudioOutput * ret = NULL;
void * data = NULL; void * data = NULL;
char * name = NULL;
char * type = NULL;
if(findInList(audioOutputPluginList, name, &data)) { getBlockParam(AUDIO_OUTPUT_NAME, name);
getBlockParam(AUDIO_OUTPUT_TYPE, type);
if(findInList(audioOutputPluginList, type, &data)) {
AudioOutputPlugin * plugin = (AudioOutputPlugin *) data; AudioOutputPlugin * plugin = (AudioOutputPlugin *) data;
ret = malloc(sizeof(AudioOutput)); ret = malloc(sizeof(AudioOutput));
ret->name = strdup(name);
ret->type = strdup(type);
ret->finishDriverFunc = plugin->finishDriverFunc; ret->finishDriverFunc = plugin->finishDriverFunc;
ret->openDeviceFunc = plugin->openDeviceFunc; ret->openDeviceFunc = plugin->openDeviceFunc;
ret->playFunc = plugin->playFunc; ret->playFunc = plugin->playFunc;
@ -35,11 +60,16 @@ AudioOutput * newAudioOutput(char * name) {
ret->sendMetdataFunc = plugin->sendMetdataFunc; ret->sendMetdataFunc = plugin->sendMetdataFunc;
ret->open = 0; ret->open = 0;
if(plugin->initDriverFunc(ret) != 0) { if(plugin->initDriverFunc(ret, param) != 0) {
free(ret); free(ret);
ret = NULL; ret = NULL;
} }
} }
else {
ERROR("couldn't find audio output plugin for type \"%s\" at "
"line %i", type, param->line);
exit(EXIT_FAILURE);
}
return ret; return ret;
} }

View File

@ -24,12 +24,14 @@
#include "mpd_types.h" #include "mpd_types.h"
#include "audio.h" #include "audio.h"
#include "tag.h" #include "tag.h"
#include "conf.h"
#define AUDIO_AO_DRIVER_DEFAULT "default" #define AUDIO_AO_DRIVER_DEFAULT "default"
typedef struct _AudioOutput AudioOutput; typedef struct _AudioOutput AudioOutput;
typedef int (* AudioOutputInitDriverFunc) (AudioOutput * audioOutput); typedef int (* AudioOutputInitDriverFunc) (AudioOutput * audioOutput,
ConfigParam * param);
typedef void (* AudioOutputFinishDriverFunc) (AudioOutput * audioOutput); typedef void (* AudioOutputFinishDriverFunc) (AudioOutput * audioOutput);
@ -46,6 +48,8 @@ typedef void (* AudioOutputSendMetadataFunc) (AudioOutput * audioOutput,
struct _AudioOutput { struct _AudioOutput {
int open; int open;
char * name;
char * type;
AudioOutputFinishDriverFunc finishDriverFunc; AudioOutputFinishDriverFunc finishDriverFunc;
AudioOutputOpenDeviceFunc openDeviceFunc; AudioOutputOpenDeviceFunc openDeviceFunc;
@ -73,7 +77,7 @@ void finishAudioOutputPlugins();
void loadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin); void loadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
void unloadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin); void unloadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
AudioOutput * newAudioOutput(char * name); AudioOutput * newAudioOutput(ConfigParam * param);
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat); int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat);
int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size); int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size);
void closeAudioOutput(AudioOutput * audioOutput); void closeAudioOutput(AudioOutput * audioOutput);

View File

@ -56,7 +56,9 @@ static void audioOutputAo_error() {
} }
} }
static int audioOutputAo_initDriver(AudioOutput * audioOutput) { static int audioOutputAo_initDriver(AudioOutput * audioOutput,
ConfigParam * param)
{
ao_info * ai; ao_info * ai;
char * dup; char * dup;
char * stk1; char * stk1;
@ -66,38 +68,51 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput) {
char * value; char * value;
char * test; char * test;
AoData * ad = newAoData(); AoData * ad = newAoData();
BlockParam * blockParam;
audioOutput->data = ad; audioOutput->data = ad;
ad->writeSize = strtol((getConf())[CONF_AUDIO_WRITE_SIZE],&test,10); if((blockParam = getBlockParam(param, "write_size"))) {
if (*test!='\0') { ad->writeSize = strtol(blockParam->value, &test, 10);
ERROR("\"%s\" is not a valid write size\n", if (*test!='\0') {
(getConf())[CONF_AUDIO_WRITE_SIZE]); ERROR("\"%s\" is not a valid write size at line %i\n",
exit(EXIT_FAILURE); blockParam->value, blockParam->line);
exit(EXIT_FAILURE);
}
} }
else ad->writeSize = 1024;
if(driverInitCount == 0) { if(driverInitCount == 0) {
ao_initialize(); ao_initialize();
} }
driverInitCount++; driverInitCount++;
if(strcmp(AUDIO_AO_DRIVER_DEFAULT,(getConf())[CONF_AO_DRIVER])==0) { blockParam = getBlockParam(param, "driver");
if(!blockParam || 0 == strcmp(blockParam->value,"default")) {
ad->driverId = ao_default_driver_id(); ad->driverId = ao_default_driver_id();
} }
else if((ad->driverId = else if((ad->driverId =
ao_driver_id((getConf())[CONF_AO_DRIVER]))<0) { ao_driver_id(blockParam->value))<0) {
ERROR("\"%s\" is not a valid ao driver\n", ERROR("\"%s\" is not a valid ao driver at line %i\n",
(getConf())[CONF_AO_DRIVER]); blockParam->value, blockParam->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if((ai = ao_driver_info(ad->driverId))==NULL) { if((ai = ao_driver_info(ad->driverId))==NULL) {
ERROR("problems getting ao_driver_info\n"); ERROR("problems getting driver info for device defined at "
"line %i\n", param->line);
ERROR("you may not have permission to the audio device\n"); ERROR("you may not have permission to the audio device\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
dup = strdup((getConf())[CONF_AO_DRIVER_OPTIONS]); blockParam = getBlockParam(param, "options");
if(blockParam) {
dup = strdup(blockParam->value);
}
else dup = strdup("");
if(strlen(dup)) { if(strlen(dup)) {
stk1 = NULL; stk1 = NULL;
n1 = strtok_r(dup,";",&stk1); n1 = strtok_r(dup,";",&stk1);

View File

@ -88,7 +88,16 @@ static void freeShoutData(ShoutData * sd) {
free(sd); free(sd);
} }
static int shout_initDriver(AudioOutput * audioOutput) { #define checkBlockParam(name) { \
blockParam = getBlockParam(param, name); \
if(!blockParam) { \
ERROR("no \"%s\" defined for shout device defined at line " \
"%i\n", name, param->line); \
exit(EXIT_FAILURE); \
} \
}
static int shout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
ShoutData * sd; ShoutData * sd;
char * test; char * test;
int port; int port;
@ -97,73 +106,50 @@ static int shout_initDriver(AudioOutput * audioOutput) {
char * passwd; char * passwd;
char * user; char * user;
char * name; char * name;
BlockParam * blockParam;
if(!getConf()[CONF_SHOUT_HOST]) {
return -1;
}
sd = newShoutData(); sd = newShoutData();
if(!getConf()[CONF_SHOUT_MOUNT]) { checkBlockParam("host");
ERROR("shout host defined but not shout mount point\n"); host = blockParam->value;
exit(EXIT_FAILURE);
}
if(!getConf()[CONF_SHOUT_PORT]) { checkBlockParam("mount");
ERROR("shout host defined but not shout port\n"); mount = blockParam->value;
exit(EXIT_FAILURE);
}
if(!getConf()[CONF_SHOUT_PASSWD]) { checkBlockParam("port");
ERROR("shout host defined but not shout password\n");
exit(EXIT_FAILURE);
}
if(!getConf()[CONF_SHOUT_NAME]) { port = strtol(blockParam->value, &test, 10);
ERROR("shout host defined but not shout name\n");
exit(EXIT_FAILURE);
}
if(!getConf()[CONF_SHOUT_USER]) {
ERROR("shout host defined but not shout user\n");
exit(EXIT_FAILURE);
}
if(!getConf()[CONF_SHOUT_QUALITY]) {
ERROR("shout host defined but not shout quality\n");
exit(EXIT_FAILURE);
}
if(!getConf()[CONF_SHOUT_FORMAT]) {
ERROR("shout host defined but not shout format\n");
exit(EXIT_FAILURE);
}
host = getConf()[CONF_SHOUT_HOST];
passwd = getConf()[CONF_SHOUT_PASSWD];
user = getConf()[CONF_SHOUT_USER];
mount = getConf()[CONF_SHOUT_MOUNT];
name = getConf()[CONF_SHOUT_NAME];
port = strtol(getConf()[CONF_SHOUT_PORT], &test, 10);
if(*test != '\0' || port <= 0) { if(*test != '\0' || port <= 0) {
ERROR("shout port \"%s\" is not a positive integer\n", ERROR("shout port \"%s\" is not a positive integer, line %i\n",
getConf()[CONF_SHOUT_PORT]); blockParam->value, blockParam->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
sd->quality = strtod(getConf()[CONF_SHOUT_QUALITY], &test); checkBlockParam("password");
passwd = blockParam->value;
checkBlockParam("name");
name = blockParam->value;
checkBlockParam("user");
user = blockParam->value;
checkBlockParam("quality");
sd->quality = strtod(blockParam->value, &test);
if(*test != '\0' || sd->quality < 0.0 || sd->quality > 10.0) { if(*test != '\0' || sd->quality < 0.0 || sd->quality > 10.0) {
ERROR("shout quality \"%s\" is not a number in the range " ERROR("shout quality \"%s\" is not a number in the range "
"0-10\n", getConf()[CONF_SHOUT_QUALITY]); "0-10, line %i\n", blockParam->value,
blockParam->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(0 != parseAudioConfig(&(sd->outAudioFormat), checkBlockParam("format");
getConf()[CONF_SHOUT_FORMAT]) )
{ if(0 != parseAudioConfig(&(sd->outAudioFormat), blockParam->value)) {
ERROR("error parsing format at line %i\n", blockParam->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -276,7 +262,7 @@ static int initEncoder(ShoutData * sd) {
vorbis_info_init(&(sd->vi)); vorbis_info_init(&(sd->vi));
if( 0 != vorbis_encode_init_vbr(&(sd->vi), sd->outAudioFormat.channels, if( 0 != vorbis_encode_init_vbr(&(sd->vi), sd->outAudioFormat.channels,
sd->outAudioFormat.sampleRate, sd->quality) ) sd->outAudioFormat.sampleRate, sd->quality/10.0) )
{ {
ERROR("problem seting up vorbis encoder for shout\n"); ERROR("problem seting up vorbis encoder for shout\n");
vorbis_info_clear(&(sd->vi)); vorbis_info_clear(&(sd->vi));

View File

@ -22,8 +22,7 @@
#include "utils.h" #include "utils.h"
#include "buffer2array.h" #include "buffer2array.h"
#include "audio.h" #include "list.h"
#include "volume.h"
#include <sys/param.h> #include <sys/param.h>
#include <stdio.h> #include <stdio.h>
@ -35,270 +34,385 @@
#define MAX_STRING_SIZE MAXPATHLEN+80 #define MAX_STRING_SIZE MAXPATHLEN+80
#define CONF_COMMENT '#' #define CONF_COMMENT '#'
#define CONF_BLOCK_BEGIN "{"
#define CONF_BLOCK_END "}"
#define CONF_NUMBER_OF_PARAMS 43 #define CONF_REPEATABLE_MASK 0x01
#define CONF_NUMBER_OF_PATHS 6 #define CONF_BLOCK_MASK 0x02
#define CONF_NUMBER_OF_REQUIRED 5
#define CONF_NUMBER_OF_ALLOW_CATS 1
#define CONF_CONNECTION_TIMEOUT_DEFAULT "60" typedef struct _configEntry {
#define CONF_MAX_CONNECTIONS_DEFAULT "5" unsigned char mask;
#define CONF_MAX_PLAYLIST_LENGTH_DEFAULT "16384" List * configParamList;
#define CONF_BUFFER_BEFORE_PLAY_DEFAULT "25%" } ConfigEntry;
#define CONF_MAX_COMMAND_LIST_SIZE_DEFAULT "2048"
#define CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT "2048"
#define CONF_AO_DRIVER_DEFAULT AUDIO_AO_DRIVER_DEFAULT
#define CONF_AO_DRIVER_OPTIONS_DEFAULT ""
#define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT "no"
#define CONF_BIND_TO_ADDRESS_DEFAULT "any"
#define CONF_USER_DEFAULT ""
#define CONF_LOG_LEVEL_DEFAULT "default"
#define CONF_AUDIO_WRITE_SIZE_DEFAULT "1024"
#define CONF_BUFFER_SIZE_DEFAULT "2048"
#ifndef NO_OSS_MIXER
#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_OSS
#define CONF_MIXER_DEVICE_DEFAULT ""
#else
#ifdef HAVE_ALSA
#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_ALSA
#define CONF_MIXER_DEVICE_DEFAULT ""
#else
#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_SOFTWARE
#define CONF_MIXER_DEVICE_DEFAULT ""
#endif
#endif
static char * conf_params[CONF_NUMBER_OF_PARAMS]; static List * configEntriesList = NULL;
void initConf() { static ConfigParam * newConfigParam(char * value, int line) {
int i; ConfigParam * ret = malloc(sizeof(ConfigParam));
for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) conf_params[i] = NULL; if(!value) ret->value = NULL;
else ret->value = strdup(value);
/* we don't specify these on the command line */ ret->line = line;
conf_params[CONF_CONNECTION_TIMEOUT] = strdup(CONF_CONNECTION_TIMEOUT_DEFAULT);
conf_params[CONF_MIXER_DEVICE] = strdup(CONF_MIXER_DEVICE_DEFAULT); ret->numberOfBlockParams = 0;
conf_params[CONF_MAX_CONNECTIONS] = strdup(CONF_MAX_CONNECTIONS_DEFAULT); ret->blockParams = NULL;
conf_params[CONF_MAX_PLAYLIST_LENGTH] = strdup(CONF_MAX_PLAYLIST_LENGTH_DEFAULT);
conf_params[CONF_BUFFER_BEFORE_PLAY] = strdup(CONF_BUFFER_BEFORE_PLAY_DEFAULT); return ret;
conf_params[CONF_MAX_COMMAND_LIST_SIZE] = strdup(CONF_MAX_COMMAND_LIST_SIZE_DEFAULT);
conf_params[CONF_MAX_OUTPUT_BUFFER_SIZE] = strdup(CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT);
conf_params[CONF_AO_DRIVER] = strdup(CONF_AO_DRIVER_DEFAULT);
conf_params[CONF_AO_DRIVER_OPTIONS] = strdup(CONF_AO_DRIVER_OPTIONS_DEFAULT);
conf_params[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS] = strdup(CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT);
conf_params[CONF_BIND_TO_ADDRESS] = strdup(CONF_BIND_TO_ADDRESS_DEFAULT);
conf_params[CONF_MIXER_TYPE] = strdup(CONF_MIXER_TYPE_DEFAULT);
conf_params[CONF_USER] = strdup(CONF_USER_DEFAULT);
conf_params[CONF_LOG_LEVEL] = strdup(CONF_LOG_LEVEL_DEFAULT);
conf_params[CONF_AUDIO_WRITE_SIZE] = strdup(CONF_AUDIO_WRITE_SIZE_DEFAULT);
conf_params[CONF_BUFFER_SIZE] = strdup(CONF_BUFFER_SIZE_DEFAULT);
} }
char ** readConf(char * file) { static void freeConfigParam(ConfigParam * param) {
char * conf_strings[CONF_NUMBER_OF_PARAMS] = { int i;
"port",
"music_directory",
"playlist_directory",
"log_file",
"error_file",
"connection_timeout",
"mixer_device",
"max_connections",
"max_playlist_length",
"buffer_before_play",
"max_command_list_size",
"max_output_buffer_size",
"ao_driver",
"ao_driver_options",
"save_absolute_paths_in_playlists",
"bind_to_address",
"mixer_type",
"state_file",
"user",
"db_file",
"log_level",
"mixer_control",
"audio_write_size",
"filesystem_charset",
"password",
"default_permissions",
"audio_buffer_size",
"replaygain",
"audio_output_format",
"http_proxy_host",
"http_proxy_port",
"http_proxy_user",
"http_proxy_password",
"replaygain_preamp",
"shout_host",
"shout_port",
"shout_password",
"shout_mount",
"shout_name",
"shout_user",
"shout_quality",
"id3v1_encoding",
"shout_format"
};
int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = { if(param->value) free(param->value);
CONF_MUSIC_DIRECTORY,
CONF_PLAYLIST_DIRECTORY,
CONF_LOG_FILE,
CONF_ERROR_FILE,
CONF_STATE_FILE,
CONF_DB_FILE
};
int conf_required[CONF_NUMBER_OF_REQUIRED] = { for(i=0; i<param->numberOfBlockParams; i++) {
CONF_MUSIC_DIRECTORY, if(param->blockParams[i].name) {
CONF_PLAYLIST_DIRECTORY, free(param->blockParams[i].name);
CONF_LOG_FILE, }
CONF_ERROR_FILE, if(param->blockParams[i].value) {
CONF_PORT free(param->blockParams[i].value);
}; }
}
short conf_allowCat[CONF_NUMBER_OF_ALLOW_CATS] = { if(param->numberOfBlockParams) free(param->blockParams);
CONF_PASSWORD
};
free(param);
}
ConfigEntry * newConfigEntry(int repeatable, int block) {
ConfigEntry * ret = malloc(sizeof(ConfigEntry));
ret->mask = 0;
ret->configParamList = makeList((ListFreeDataFunc *)freeConfigParam);
if(repeatable) ret->mask |= CONF_REPEATABLE_MASK;
if(block) ret->mask |= CONF_BLOCK_MASK;
return ret;
}
void freeConfigEntry(ConfigEntry * entry) {
freeList(entry->configParamList);
free(entry);
}
void registerConfigParam(char * name, int repeatable, int block) {
ConfigEntry * entry;
if(findInList(configEntriesList, name, NULL)) {
ERROR("config parameter \"%s\" already registered\n", name);
exit(EXIT_FAILURE);
}
entry = newConfigEntry(repeatable, block);
insertInList(configEntriesList, name, entry);
}
void initConf() {
configEntriesList = makeList((ListFreeDataFunc *)freeConfigEntry);
registerConfigParam(CONF_PORT, 0, 0);
registerConfigParam(CONF_MUSIC_DIR, 0, 0);
registerConfigParam(CONF_PLAYLIST_DIR, 0, 0);
registerConfigParam(CONF_LOG_FILE, 0, 0);
registerConfigParam(CONF_ERROR_FILE, 0, 0);
registerConfigParam(CONF_CONN_TIMEOUT, 0, 0);
registerConfigParam(CONF_MIXER_DEVICE, 0, 0);
registerConfigParam(CONF_MAX_CONN, 0, 0);
registerConfigParam(CONF_MAX_PLAYLIST_LENGTH, 0, 0);
registerConfigParam(CONF_BUFFER_BEFORE_PLAY, 0, 0);
registerConfigParam(CONF_MAX_COMMAND_LIST_SIZE, 0, 0);
registerConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE, 0, 0);
registerConfigParam(CONF_AUDIO_OUTPUT, 1, 1);
registerConfigParam(CONF_SAVE_ABSOLUTE_PATHS, 0, 0);
registerConfigParam(CONF_BIND_TO_ADDRESS, 1, 0);
registerConfigParam(CONF_MIXER_TYPE, 0, 0);
registerConfigParam(CONF_STATE_FILE, 0, 0);
registerConfigParam(CONF_USER, 0, 0);
registerConfigParam(CONF_DB_FILE, 0, 0);
registerConfigParam(CONF_LOG_LEVEL, 0, 0);
registerConfigParam(CONF_MIXER_CONTROL, 0, 0);
registerConfigParam(CONF_AUDIO_WRITE_SIZE, 0, 0);
registerConfigParam(CONF_FS_CHARSET, 0, 0);
registerConfigParam(CONF_PASSWORD, 1, 0);
registerConfigParam(CONF_DEFAULT_PERMS, 0, 0);
registerConfigParam(CONF_AUDIO_BUFFER_SIZE, 0, 0);
registerConfigParam(CONF_REPLAYGAIN, 0, 0);
registerConfigParam(CONF_AUDIO_OUTPUT_FORMAT, 0, 0);
registerConfigParam(CONF_HTTP_PROXY_HOST, 0, 0);
registerConfigParam(CONF_HTTP_PROXY_PORT, 0, 0);
registerConfigParam(CONF_HTTP_PROXY_USER, 0, 0);
registerConfigParam(CONF_HTTP_PROXY_PASSWORD, 0, 0);
registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0);
registerConfigParam(CONF_ID3V1_ENCODING, 0, 0);
}
static void addBlockParam(ConfigParam * param, char * name, char * value,
int line)
{
param->numberOfBlockParams++;
param->blockParams = realloc(param->blockParams,
param->numberOfBlockParams*sizeof(BlockParam));
param->blockParams[param->numberOfBlockParams-1].name = strdup(name);
param->blockParams[param->numberOfBlockParams-1].value = strdup(value);
param->blockParams[param->numberOfBlockParams-1].line = line;
}
static ConfigParam * readConfigBlock(FILE * fp, int * count, char * string) {
ConfigParam * ret = newConfigParam(NULL, *count);
char ** array;
int i;
int numberOfArgs;
int argsMinusComment;
while(myFgets(string, MAX_STRING_SIZE ,fp)) {
(*count)++;
numberOfArgs = buffer2array(string, &array);
for(i=0; i<numberOfArgs; i++) {
if(array[i][0] == CONF_COMMENT) break;
}
argsMinusComment = i;
if(0 == argsMinusComment) continue;
if(1 == argsMinusComment &&
0 == strcmp(array[0], CONF_BLOCK_END))
{
break;
}
if(2 != argsMinusComment) {
ERROR("improperly formated config file at line %i:"
" %s\n", count, string);
exit(EXIT_FAILURE);
}
if(0 == strcmp(array[0], CONF_BLOCK_BEGIN) ||
0 == strcmp(array[1], CONF_BLOCK_BEGIN) ||
0 == strcmp(array[0], CONF_BLOCK_END) ||
0 == strcmp(array[1], CONF_BLOCK_END))
{
ERROR("improperly formated config file at line %i:"
" %s\n", count, string);
ERROR("in block begging at line %i\n", ret->line);
exit(EXIT_FAILURE);
}
addBlockParam(ret, array[0], array[1], *count);
freeArgArray(array, numberOfArgs);
}
return ret;
}
void readConf(char * file) {
FILE * fp; FILE * fp;
char string[MAX_STRING_SIZE+1]; char string[MAX_STRING_SIZE+1];
char ** array; char ** array;
int i; int i;
int numberOfArgs; int numberOfArgs;
short allowCat[CONF_NUMBER_OF_PARAMS]; int argsMinusComment;
int count = 0; int count = 0;
ConfigEntry * entry;
for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) allowCat[i] = 0; void * voidPtr;
ConfigParam * param;
for(i=0;i<CONF_NUMBER_OF_ALLOW_CATS;i++) allowCat[conf_allowCat[i]] = 1;
if(!(fp=fopen(file,"r"))) { if(!(fp=fopen(file,"r"))) {
ERROR("problems opening file %s for reading\n",file); ERROR("problems opening file %s for reading\n",file);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
while(myFgets(string,sizeof(string),fp)) { while(myFgets(string, MAX_STRING_SIZE, fp)) {
count++; count++;
if(string[0]==CONF_COMMENT) continue; numberOfArgs = buffer2array(string, &array);
numberOfArgs = buffer2array(string,&array);
if(numberOfArgs==0) continue; for(i=0; i<numberOfArgs; i++) {
if(2!=numberOfArgs) { if(array[i][0] == CONF_COMMENT) break;
ERROR("improperly formated config file at line %i: %s\n",count,string); }
argsMinusComment = i;
if(0 == argsMinusComment) continue;
if(2 != argsMinusComment) {
ERROR("improperly formated config file at line %i:"
" %s\n", count, string);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
i = 0;
while(i<CONF_NUMBER_OF_PARAMS && 0!=strcmp(conf_strings[i],array[0])) i++; if(!findInList(configEntriesList, array[0], &voidPtr)) {
if(i>=CONF_NUMBER_OF_PARAMS) { ERROR("unrecognized paramater in config file at line "
ERROR("unrecognized paramater in conf at line %i: %s\n",count,string); "%i: %s\n", count, string);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(conf_params[i]!=NULL) { entry = (ConfigEntry *) voidPtr;
if(allowCat[i]) {
conf_params[i] = realloc(conf_params[i], if( !(entry->mask & CONF_REPEATABLE_MASK) &&
strlen(conf_params[i])+ entry->configParamList->numberOfNodes)
strlen(CONF_CAT_CHAR)+ {
strlen(array[1])+1); param = entry->configParamList->firstNode->data;
strcat(conf_params[i],CONF_CAT_CHAR); ERROR("config paramter \"%s\" is first defined on line "
strcat(conf_params[i],array[1]); "%i and redefined on line %i\n",
} array[0], param->line, count);
else { exit(EXIT_FAILURE);
free(conf_params[i]);
conf_params[i] = strdup(array[1]);
}
} }
else conf_params[i] = strdup(array[1]);
free(array[0]); if(entry->mask & CONF_BLOCK_MASK) {
free(array[1]); if(0 != strcmp(array[1], CONF_BLOCK_BEGIN)) {
free(array); ERROR("improperly formated config file at "
"line %i: %s\n", count, string);
exit(EXIT_FAILURE);
}
param = readConfigBlock(fp, &count, string);
}
else param = newConfigParam(array[1], count);
insertInListWithoutKey(entry->configParamList, param);
freeArgArray(array, numberOfArgs);
} }
}
fclose(fp); ConfigParam * getNextConfigParam(char * name, ConfigParam * last) {
void * voidPtr;
ConfigEntry * entry;
ListNode * node;
ConfigParam * param;
for(i=0;i<CONF_NUMBER_OF_REQUIRED;i++) { if(!findInList(configEntriesList, name, &voidPtr)) return NULL;
if(conf_params[conf_required[i]] == NULL) {
ERROR("%s is unassigned in conf file\n", entry = voidPtr;
conf_strings[conf_required[i]]);
exit(EXIT_FAILURE); node = entry->configParamList->firstNode;
if(last) {
while(node!=NULL) {
param = node->data;
node = node->nextNode;
if(param == last) break;
} }
} }
for(i=0;i<CONF_NUMBER_OF_PATHS;i++) { if(node == NULL) return NULL;
if(conf_params[conf_absolutePaths[i]] &&
conf_params[conf_absolutePaths[i]][0]!='/' && param = node->data;
conf_params[conf_absolutePaths[i]][0]!='~')
{ return param;
ERROR("\"%s\" is not an absolute path\n", }
conf_params[conf_absolutePaths[i]]);
exit(EXIT_FAILURE); char * getConfigParamValue(char * name) {
} ConfigParam * param = getConfigParam(name);
/* Parse ~ in path */
else if(conf_params[conf_absolutePaths[i]] && if(!param) return NULL;
conf_params[conf_absolutePaths[i]][0]=='~')
{ return param->value;
struct passwd * pwd = NULL; }
char * path;
int pos = 1; char * forceAndGetConfigParamValue(char * name) {
if(conf_params[conf_absolutePaths[i]][1]=='/' || ConfigParam * param = getConfigParam(name);
conf_params[conf_absolutePaths[i]][1]=='\0')
{ if(!param) {
if(conf_params[CONF_USER] && ERROR("\"%s\" not found in config file\n", name);
strlen(conf_params[CONF_USER])) exit(EXIT_FAILURE);
{ }
pwd = getpwnam(
conf_params[CONF_USER]); return param->value;
if(!pwd) { }
ERROR("no such user: %s\n",
conf_params[CONF_USER]); BlockParam * getBlockParam(ConfigParam * param, char * name) {
exit(EXIT_FAILURE); BlockParam * ret = NULL;
} int i;
}
else { for(i = 0; i < param->numberOfBlockParams; i++) {
uid_t uid = geteuid(); if(0 == strcmp(name, param->blockParams[i].name)) {
if((pwd = getpwuid(uid)) == NULL) { if(ret) {
ERROR("problems getting passwd " ERROR("\"%s\" first defined on line %i, and "
"entry " "redefined on line %i\n", name,
"for current user\n"); ret->line, param->blockParams[i].line);
exit(EXIT_FAILURE);
}
}
} }
else { ret = param->blockParams+i;
int foundSlash = 0; }
char * ch = &( }
conf_params[conf_absolutePaths[i]][1]);
for(;*ch!='\0' && *ch!='/';ch++); return ret;
if(*ch=='/') foundSlash = 1; }
* ch = '\0';
pos+= ch- char * parseConfigFilePath(char * name, int force) {
&(conf_params[ ConfigParam * param = getConfigParam(name);
conf_absolutePaths[i]][1]); char * path;
if((pwd = getpwnam(&(conf_params[
conf_absolutePaths[i]][1]))) == NULL) if(!param && force) {
{ ERROR("config parameter \"%s\" not found\n", name);
ERROR("user \"%s\" not found\n", exit(EXIT_FAILURE);
&(conf_params[ }
conf_absolutePaths[i]][1]));
if(!param) return NULL;
path = param->value;
if(path[0] != '/' && path[0] != '~') {
ERROR("\"%s\" is not an absolute path at line %i\n",
param->value, param->line);
exit(EXIT_FAILURE);
}
// Parse ~ in path
else if(path[0] == '~') {
struct passwd * pwd = NULL;
char * newPath;
int pos = 1;
if(path[1]=='/' || path[1] == '\0') {
ConfigParam * userParam = getConfigParam(CONF_USER);
if(userParam) {
pwd = getpwnam(userParam->value);
if(!pwd) {
ERROR("no such user %s at line %i\n",
userParam->value,
userParam->line);
exit(EXIT_FAILURE);
}
}
else {
uid_t uid = geteuid();
if((pwd = getpwuid(uid)) == NULL) {
ERROR("problems getting passwd entry "
"for current user\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(foundSlash) *ch = '/';
} }
path = malloc(strlen(pwd->pw_dir)+strlen(
&(conf_params[conf_absolutePaths[i]][pos]))+1);
strcpy(path,pwd->pw_dir);
strcat(path,&(conf_params[conf_absolutePaths[i]][pos]));
free(conf_params[conf_absolutePaths[i]]);
conf_params[conf_absolutePaths[i]] = path;
} }
else {
int foundSlash = 0;
char * ch = path+1;
for(;*ch!='\0' && *ch!='/';ch++);
if(*ch=='/') foundSlash = 1;
* ch = '\0';
pos+= ch-path+1;
if((pwd = getpwnam(path+1)) == NULL) {
ERROR("user \"%s\" not found at line %i\n",
path+1, param->line);
exit(EXIT_FAILURE);
}
if(foundSlash) *ch = '/';
}
newPath = malloc(strlen(pwd->pw_dir)+strlen(path+pos)+1);
strcpy(newPath, pwd->pw_dir);
strcat(newPath, path+pos);
free(param->value);
param->value = newPath;
} }
return conf_params; return param->value;
}
char ** getConf() {
return conf_params;
} }

View File

@ -21,59 +21,72 @@
#include "../config.h" #include "../config.h"
#define CONF_PORT 0 #define CONF_PORT "port"
#define CONF_MUSIC_DIRECTORY 1 #define CONF_MUSIC_DIR "music_directory"
#define CONF_PLAYLIST_DIRECTORY 2 #define CONF_PLAYLIST_DIR "playlist_directory"
#define CONF_LOG_FILE 3 #define CONF_LOG_FILE "log_file"
#define CONF_ERROR_FILE 4 #define CONF_ERROR_FILE "error_file"
#define CONF_CONNECTION_TIMEOUT 5 #define CONF_CONN_TIMEOUT "connection_timeout"
#define CONF_MIXER_DEVICE 6 #define CONF_MIXER_DEVICE "mixer_device"
#define CONF_MAX_CONNECTIONS 7 #define CONF_MAX_CONN "max_connections"
#define CONF_MAX_PLAYLIST_LENGTH 8 #define CONF_MAX_PLAYLIST_LENGTH "max_playlist_length"
#define CONF_BUFFER_BEFORE_PLAY 9 #define CONF_BUFFER_BEFORE_PLAY "buffer_before_play"
#define CONF_MAX_COMMAND_LIST_SIZE 10 #define CONF_MAX_COMMAND_LIST_SIZE "max_command_list_size"
#define CONF_MAX_OUTPUT_BUFFER_SIZE 11 #define CONF_MAX_OUTPUT_BUFFER_SIZE "max_output_buffer_size"
#define CONF_AO_DRIVER 12 #define CONF_AUDIO_OUTPUT "audio_output"
#define CONF_AO_DRIVER_OPTIONS 13 #define CONF_SAVE_ABSOLUTE_PATHS "save_absolute_paths_in_playlists"
#define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS 14 #define CONF_BIND_TO_ADDRESS "bind_to_address"
#define CONF_BIND_TO_ADDRESS 15 #define CONF_MIXER_TYPE "mixer_type"
#define CONF_MIXER_TYPE 16 #define CONF_STATE_FILE "state_file"
#define CONF_STATE_FILE 17 #define CONF_USER "user"
#define CONF_USER 18 #define CONF_DB_FILE "db_file"
#define CONF_DB_FILE 19 #define CONF_LOG_LEVEL "log_level"
#define CONF_LOG_LEVEL 20 #define CONF_MIXER_CONTROL "mixer_control"
#define CONF_MIXER_CONTROL 21 #define CONF_AUDIO_WRITE_SIZE "audio_write_size"
#define CONF_AUDIO_WRITE_SIZE 22 #define CONF_FS_CHARSET "filesystem_charset"
#define CONF_FS_CHARSET 23 #define CONF_PASSWORD "password"
#define CONF_PASSWORD 24 #define CONF_DEFAULT_PERMS "default_permissions"
#define CONF_DEFAULT_PERMISSIONS 25 #define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size"
#define CONF_BUFFER_SIZE 26 #define CONF_REPLAYGAIN "replaygain"
#define CONF_REPLAYGAIN 27 #define CONF_AUDIO_OUTPUT_FORMAT "audio_output_format"
#define CONF_AUDIO_OUTPUT_FORMAT 28 #define CONF_HTTP_PROXY_HOST "http_proxy_host"
#define CONF_HTTP_PROXY_HOST 29 #define CONF_HTTP_PROXY_PORT "http_proxy_port"
#define CONF_HTTP_PROXY_PORT 30 #define CONF_HTTP_PROXY_USER "http_proxy_user"
#define CONF_HTTP_PROXY_USER 31 #define CONF_HTTP_PROXY_PASSWORD "http_proxy_password"
#define CONF_HTTP_PROXY_PASSWORD 32 #define CONF_REPLAYGAIN_PREAMP "replaygain_preamp"
#define CONF_REPLAYGAIN_PREAMP 33 #define CONF_ID3V1_ENCODING "id3v1_encoding"
#define CONF_SHOUT_HOST 34
#define CONF_SHOUT_PORT 35
#define CONF_SHOUT_PASSWD 36
#define CONF_SHOUT_MOUNT 37
#define CONF_SHOUT_NAME 38
#define CONF_SHOUT_USER 39
#define CONF_SHOUT_QUALITY 40
#define CONF_ID3V1_ENCODING 41
#define CONF_SHOUT_FORMAT 42
#define CONF_CAT_CHAR "\n" typedef struct _BlockParam {
char * name;
char * value;
int line;
} BlockParam;
/* do not free the return value, it is a static variable */ typedef struct _ConfigParam {
char ** readConf(char * file); char * value;
unsigned int line;
char ** getConf(); BlockParam * blockParams;
int numberOfBlockParams;
} ConfigParam;
void initConf(); void initConf();
void writeConf(char * file); void readConf(char * file);
/* don't free the returned value
set _last_ to NULL to get first entry */
ConfigParam * getNextConfigParam(char * name, ConfigParam * last);
#define getConfigParam(name) getNextConfigParam(name, NULL)
char * getConfigParamValue(char * name);
char * forceAndGetConfigParamValue(char * name);
void registerConfigParam(char * name, int repeats, int block);
BlockParam * getBlockParam(ConfigParam * param, char * name);
char * parseConfigFilePath(char * name, int force);
#endif #endif

View File

@ -1053,7 +1053,8 @@ int readDirectoryDB() {
fsCharset = &(buffer[strlen( fsCharset = &(buffer[strlen(
DIRECTORY_FS_CHARSET)]); DIRECTORY_FS_CHARSET)]);
if((tempCharset = if((tempCharset =
getConf()[CONF_FS_CHARSET]) && getConfigParamValue(
CONF_FS_CHARSET)) &&
strcmp(fsCharset,tempCharset)) strcmp(fsCharset,tempCharset))
{ {
WARNING("Using \"%s\" for the " WARNING("Using \"%s\" for the "

View File

@ -47,6 +47,11 @@
#define HTTP_REDIRECT_MAX 10 #define HTTP_REDIRECT_MAX 10
static char * proxyHost = NULL;
static int proxyPort = 0;
static char * proxyUser = NULL;
static char * proxyPassword = NULL;
typedef struct _InputStreemHTTPData { typedef struct _InputStreemHTTPData {
char * host; char * host;
char * path; char * path;
@ -59,57 +64,73 @@ typedef struct _InputStreemHTTPData {
int icyMetaint; int icyMetaint;
int prebuffer; int prebuffer;
int icyOffset; int icyOffset;
char * proxyHost;
int proxyPort;
char * proxyAuth; char * proxyAuth;
char * httpAuth; char * httpAuth;
} InputStreamHTTPData; } InputStreamHTTPData;
void inputStream_initHttp() { void inputStream_initHttp() {
if(getConf()[CONF_HTTP_PROXY_HOST]) { ConfigParam * param = getConfigParam(CONF_HTTP_PROXY_HOST);
char * portStr = getConf()[CONF_HTTP_PROXY_PORT]; char * test;
int port = 0;
char * test;
if(!portStr) { if(param) {
ERROR("http_proxy_host specified but not the http_" proxyHost = param->value;
"proxy_port\n");
param = getConfigParam(CONF_HTTP_PROXY_PORT);
if(!param) {
ERROR("%s specified but not %s", CONF_HTTP_PROXY_HOST,
CONF_HTTP_PROXY_PORT);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
port = strtol(portStr, &test, 10); proxyPort = strtol(param->value, &test, 10);
if(port <= 0 || *test != '\0') { if(proxyPort <= 0 || *test != '\0') {
ERROR("http_proxy_port \"%s\" is not a positive integer" ERROR("%s \"%s\" is not a positive integer, line %i\n"
"\n", portStr); CONF_HTTP_PROXY_PORT, param->value,
param->line);
} }
if(getConf()[CONF_HTTP_PROXY_USER] && param = getConfigParam(CONF_HTTP_PROXY_USER);
!getConf()[CONF_HTTP_PROXY_PASSWORD])
{ if(param) {
ERROR("http_proxy_user specified, but not http_proxy_" proxyUser = param->value;
"password\n");
exit(EXIT_FAILURE); param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
if(!param) {
ERROR("%s specifid but not %s\n",
CONF_HTTP_PROXY_USER,
CONF_HTTP_PROXY_PASSWORD);
exit(EXIT_FAILURE);
}
proxyPassword = param->value;
} }
if(getConf()[CONF_HTTP_PROXY_PASSWORD] && param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
!getConf()[CONF_HTTP_PROXY_USER])
{ if(param) {
ERROR("http proxy password specified, but not http " ERROR("%s specifid but not %s\n",
"proxy user\n"); CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_USER);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
else if(getConf()[CONF_HTTP_PROXY_PORT]) { else if((param = getConfigParam(CONF_HTTP_PROXY_PORT))) {
ERROR("http_proxy_port specified but not http_proxy_host\n"); ERROR("%s specified but not %s, line %i\n",
CONF_HTTP_PROXY_PORT, CONF_HTTP_PROXY_HOST,
param->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
else if(getConf()[CONF_HTTP_PROXY_USER]) { else if((param = getConfigParam(CONF_HTTP_PROXY_USER))) {
ERROR("http_proxy_user specified but not http_proxy_host\n"); ERROR("%s specified but not %s, line %i\n",
CONF_HTTP_PROXY_USER, CONF_HTTP_PROXY_HOST,
param->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
else if(getConf()[CONF_HTTP_PROXY_PASSWORD]) { else if((param = getConfigParam(CONF_HTTP_PROXY_PASSWORD))) {
ERROR("http_proxy_password specified but not http_proxy_host" ERROR("%s specified but not %s, line %i\n",
"\n"); CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_HOST,
param->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@ -188,19 +209,10 @@ static char * authString(char * header, char * user, char * password) {
static InputStreamHTTPData * newInputStreamHTTPData() { static InputStreamHTTPData * newInputStreamHTTPData() {
InputStreamHTTPData * ret = malloc(sizeof(InputStreamHTTPData)); InputStreamHTTPData * ret = malloc(sizeof(InputStreamHTTPData));
if(getConf()[CONF_HTTP_PROXY_HOST]) { if(proxyHost) {
ret->proxyHost = getConf()[CONF_HTTP_PROXY_HOST]; ret->proxyAuth = proxyAuthString(proxyUser, proxyPassword);
DEBUG(__FILE__ ": Proxy host %s\n", ret->proxyHost);
ret->proxyPort = atoi(getConf()[CONF_HTTP_PROXY_PORT]);
DEBUG(__FILE__ ": Proxy port %i\n", ret->proxyPort);
ret->proxyAuth = proxyAuthString(
getConf()[CONF_HTTP_PROXY_USER],
getConf()[CONF_HTTP_PROXY_PASSWORD]);
}
else {
ret->proxyHost = NULL;
ret->proxyAuth = NULL;
} }
else ret->proxyAuth = NULL;
ret->httpAuth = NULL; ret->httpAuth = NULL;
ret->host = NULL; ret->host = NULL;
@ -299,7 +311,7 @@ static int parseUrl(InputStreamHTTPData * data, char * url) {
} }
/* fetch the path */ /* fetch the path */
if(data->proxyHost) data->path = strdup(url); if(proxyHost) data->path = strdup(url);
else data->path = strdup(slash ? slash : "/"); else data->path = strdup(slash ? slash : "/");
return 0; return 0;
@ -319,9 +331,9 @@ static int initHTTPConnection(InputStream * inStream) {
struct sockaddr_in6 sin6; struct sockaddr_in6 sin6;
#endif #endif
if(data->proxyHost) { if(proxyHost) {
connHost = data->proxyHost; connHost = proxyHost;
connPort = data->proxyPort; connPort = proxyPort;
} }
else { else {
connHost = data->host; connHost = data->host;

View File

@ -47,12 +47,18 @@
#define INTERFACE_LIST_MODE_BEGIN "command_list_begin" #define INTERFACE_LIST_MODE_BEGIN "command_list_begin"
#define INTERFACE_LIST_OK_MODE_BEGIN "command_list_ok_begin" #define INTERFACE_LIST_OK_MODE_BEGIN "command_list_ok_begin"
#define INTERFACE_LIST_MODE_END "command_list_end" #define INTERFACE_LIST_MODE_END "command_list_end"
#define INTERFACE_DEFAULT_OUT_BUFFER_SIZE 4096 #define INTERFACE_DEFAULT_OUT_BUFFER_SIZE 4096
#define INTERFACE_TIMEOUT_DEFAULT 60
#define INTERFACE_MAX_CONNECTIONS_DEFAULT 10
#define INTERFACE_MAX_COMMAND_LIST_DEFAULT (2048*1024)
#define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (2048*1024)
int interface_max_connections = 0; static int interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT;
int interface_timeout; static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT;
unsigned long long interface_max_command_list_size; static size_t interface_max_command_list_size =
unsigned long long interface_max_output_buffer_size; INTERFACE_MAX_COMMAND_LIST_DEFAULT;
static size_t interface_max_output_buffer_size =
INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT;
typedef struct _Interface { typedef struct _Interface {
char buffer[INTERFACE_MAX_BUFFER_LENGTH+2]; char buffer[INTERFACE_MAX_BUFFER_LENGTH+2];
@ -420,33 +426,58 @@ int doIOForInterfaces() {
void initInterfaces() { void initInterfaces() {
int i; int i;
char * test; char * test;
ConfigParam * param;
interface_timeout = strtol((getConf())[CONF_CONNECTION_TIMEOUT],&test,10); param = getConfigParam(CONF_CONN_TIMEOUT);
if(*test!='\0' || interface_timeout<=0) {
ERROR("connection timeout \"%s\" is not a positive integer\n",(getConf())[CONF_CONNECTION_TIMEOUT]); if(param) {
exit(EXIT_FAILURE); interface_timeout = strtol(param->value,&test,10);
if(*test!='\0' || interface_timeout<=0) {
ERROR("connection timeout \"%s\" is not a positive "
"integer, line %i\n", CONF_CONN_TIMEOUT,
param->line);
exit(EXIT_FAILURE);
}
} }
interface_max_connections = strtol((getConf())[CONF_MAX_CONNECTIONS],&test,10); param = getConfigParam(CONF_MAX_CONN);
if(*test!='\0' || interface_max_connections<=0) {
ERROR("max connections \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_CONNECTIONS]); if(param) {
exit(EXIT_FAILURE); interface_max_connections = strtol(param->value, &test, 10);
if(*test!='\0' || interface_max_connections<=0) {
ERROR("max connections \"%s\" is not a positive integer"
", line %i\n", param->value, param->line);
exit(EXIT_FAILURE);
}
} }
interface_max_command_list_size = strtoll((getConf())[CONF_MAX_COMMAND_LIST_SIZE],&test,10); param = getConfigParam(CONF_MAX_COMMAND_LIST_SIZE);
if(*test!='\0' || interface_max_command_list_size<=0) {
ERROR("max command list size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_COMMAND_LIST_SIZE]); if(param) {
exit(EXIT_FAILURE); interface_max_command_list_size = strtoll(param->value,
&test, 10);
if(*test!='\0' || interface_max_command_list_size<=0) {
ERROR("max command list size \"%s\" is not a positive "
"integer, line %i\n", param->value,
param->line);
exit(EXIT_FAILURE);
}
interface_max_command_list_size*=1024;
} }
interface_max_output_buffer_size = strtoll((getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE],&test,10); param = getConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE);
if(*test!='\0' || interface_max_output_buffer_size<=0) {
ERROR("max output buffer size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE]);
exit(EXIT_FAILURE);
}
interface_max_command_list_size*=1024; if(param) {
interface_max_output_buffer_size*=1024; interface_max_output_buffer_size = strtoll(param->value, &test,
10);
if(*test!='\0' || interface_max_output_buffer_size<=0) {
ERROR("max output buffer size \"%s\" is not a positive "
"integer, line %i\n", param->value,
param->line);
exit(EXIT_FAILURE);
}
interface_max_output_buffer_size*=1024;
}
interfaces = malloc(sizeof(Interface)*interface_max_connections); interfaces = malloc(sizeof(Interface)*interface_max_connections);

View File

@ -192,7 +192,7 @@ int findInList(List * list,char * key,void ** data) {
tmpNode = list->nodesArray[cur]; tmpNode = list->nodesArray[cur];
cmp = strcmp(tmpNode->key,key); cmp = strcmp(tmpNode->key,key);
if(cmp==0) { if(cmp==0) {
(*data) = tmpNode->data; if(data) *data = tmpNode->data;
return 1; return 1;
} }
else if(cmp>0) high = cur; else if(cmp>0) high = cur;

View File

@ -88,6 +88,7 @@ void deleteNodeFromList(List * list,ListNode * node);
* _key_ -> which node is being searched for * _key_ -> which node is being searched for
* _data_ -> a pointer to where data will be placed, * _data_ -> a pointer to where data will be placed,
* _data_ memory should not by allocated or freed * _data_ memory should not by allocated or freed
* _data_ can be NULL
* returns 1 if successful, 0 otherwise * returns 1 if successful, 0 otherwise
*/ */
int findInList(List * list, char * key, void ** data); int findInList(List * list, char * key, void ** data);

View File

@ -44,6 +44,7 @@
int listenSocket; int listenSocket;
int establish(unsigned short port) { int establish(unsigned short port) {
ConfigParam * param;
int allowReuse = ALLOW_REUSE; int allowReuse = ALLOW_REUSE;
int sock; int sock;
struct sockaddr * addrp; struct sockaddr * addrp;
@ -60,8 +61,10 @@ int establish(unsigned short port) {
memset(&sin, 0, sizeof(struct sockaddr_in)); memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_port = htons(port); sin.sin_port = htons(port);
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
param = getConfigParam(CONF_BIND_TO_ADDRESS);
if(strcmp((getConf())[CONF_BIND_TO_ADDRESS],"any")==0) { if(!param || 0==strcmp(param->value, "any")==0) {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if(ipv6Supported()) { if(ipv6Supported()) {
sin6.sin6_addr = in6addr_any; sin6.sin6_addr = in6addr_any;
@ -78,9 +81,9 @@ int establish(unsigned short port) {
} }
else { else {
struct hostent * he; struct hostent * he;
if(!(he = gethostbyname((getConf())[CONF_BIND_TO_ADDRESS]))) { if(!(he = gethostbyname(param->value))) {
ERROR("can't lookup host \"%s\"\n", ERROR("can't lookup host \"%s\" at line %i\n",
(getConf())[CONF_BIND_TO_ADDRESS]); param->value, param->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
switch(he->h_addrtype) { switch(he->h_addrtype) {
@ -88,8 +91,8 @@ int establish(unsigned short port) {
case AF_INET6: case AF_INET6:
if(!ipv6Supported()) { if(!ipv6Supported()) {
ERROR("no IPv6 support, but a IPv6 address " ERROR("no IPv6 support, but a IPv6 address "
"found for \"%s\"\n", "found for \"%s\" at line %i\n",
(getConf())[CONF_BIND_TO_ADDRESS]); param->value, param->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
bcopy((char *)he->h_addr,(char *) bcopy((char *)he->h_addr,(char *)
@ -105,8 +108,9 @@ int establish(unsigned short port) {
addrlen = sizeof(struct sockaddr_in); addrlen = sizeof(struct sockaddr_in);
break; break;
default: default:
ERROR("address type for \"%s\" is not IPv4 or IPv6\n", ERROR("address type for \"%s\" is not IPv4 or IPv6 "
(getConf())[CONF_BIND_TO_ADDRESS]); "at line %i\n",
param->value, param->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }

View File

@ -32,16 +32,24 @@ short warningFlushed = 0;
static char * warningBuffer = NULL; static char * warningBuffer = NULL;
void initLog() { void initLog() {
if(strcmp(getConf()[CONF_LOG_LEVEL],"default")==0) { ConfigParam * param = getConfigParam(CONF_LOG_LEVEL);
if(!param) return;
if(0 == strcmp(param->value, "default")) {
if(logLevel<LOG_LEVEL_LOW) logLevel = LOG_LEVEL_LOW; if(logLevel<LOG_LEVEL_LOW) logLevel = LOG_LEVEL_LOW;
} }
else if(strcmp(getConf()[CONF_LOG_LEVEL],"secure")==0) { else if(0 == strcmp(param->value, "secure")) {
if(logLevel<LOG_LEVEL_SECURE) logLevel = LOG_LEVEL_SECURE; if(logLevel<LOG_LEVEL_SECURE) logLevel = LOG_LEVEL_SECURE;
} }
else if(strcmp(getConf()[CONF_LOG_LEVEL],"verbose")==0) { else if(0 == strcmp(param->value, "verbose")) {
if(logLevel<LOG_LEVEL_DEBUG) logLevel = LOG_LEVEL_DEBUG; if(logLevel<LOG_LEVEL_DEBUG) logLevel = LOG_LEVEL_DEBUG;
} }
else ERROR("unknown log level \"%s\"\n",getConf()[CONF_LOG_LEVEL]); else {
ERROR("unknown log level \"%s\" at line %i\n",
param->value, param->line);
exit(EXIT_FAILURE);
}
} }
#define BUFFER_LENGTH 4096 #define BUFFER_LENGTH 4096

View File

@ -165,9 +165,12 @@ void parseOptions(int argc, char ** argv, Options * options) {
return; return;
} }
else if(argcLeft<=2) { else if(argcLeft<=2) {
char ** conf = NULL; int conf = 0;
if(argcLeft==2) conf = readConf(argv[argc-1]); if(argcLeft==2) {
if(argcLeft==1) { readConf(argv[argc-1]);
conf = 1;
}
else if(argcLeft==1) {
FILE * fp; FILE * fp;
char * homedir = getenv("HOME"); char * homedir = getenv("HOME");
char userfile[MAXPATHLEN+1] = ""; char userfile[MAXPATHLEN+1] = "";
@ -179,23 +182,27 @@ void parseOptions(int argc, char ** argv, Options * options) {
} }
if(strlen(userfile) && (fp=fopen(userfile,"r"))) { if(strlen(userfile) && (fp=fopen(userfile,"r"))) {
fclose(fp); fclose(fp);
conf = readConf(userfile); readConf(userfile);
conf = 1;
} }
else if((fp=fopen(SYSTEM_CONFIG_FILE_LOCATION,"r"))) { else if((fp=fopen(SYSTEM_CONFIG_FILE_LOCATION,"r"))) {
fclose(fp); fclose(fp);
conf = readConf(SYSTEM_CONFIG_FILE_LOCATION); readConf(SYSTEM_CONFIG_FILE_LOCATION);
conf = 1;
} }
} }
if(conf) { if(conf) {
options->portStr = conf[CONF_PORT]; options->portStr = forceAndGetConfigParamValue(
options->musicDirArg = conf[CONF_MUSIC_DIRECTORY]; CONF_PORT);
options->playlistDirArg = conf[CONF_PLAYLIST_DIRECTORY]; options->musicDirArg =
options->logFile = conf[CONF_LOG_FILE]; parseConfigFilePath(CONF_MUSIC_DIR, 1);
options->errorFile = conf[CONF_ERROR_FILE]; options->playlistDirArg =
options->usr = conf[CONF_USER]; parseConfigFilePath(CONF_PLAYLIST_DIR, 1);
if(conf[CONF_DB_FILE]) { options->logFile = parseConfigFilePath(CONF_LOG_FILE,1);
options->dbFile = conf[CONF_DB_FILE]; options->errorFile =
} parseConfigFilePath(CONF_ERROR_FILE, 1);
options->usr = parseConfigFilePath(CONF_USER, 0);
options->dbFile = parseConfigFilePath(CONF_DB_FILE, 0);
return; return;
} }
} }

View File

@ -114,6 +114,7 @@ void initPaths(char * playlistDirArg, char * musicDirArg) {
char * charset = NULL; char * charset = NULL;
char * originalLocale; char * originalLocale;
struct stat st; struct stat st;
ConfigParam * param;
playlistDir = prependCwdToPathDup(playlistDirArg); playlistDir = prependCwdToPathDup(playlistDirArg);
if((stat(playlistDir,&st))<0) { if((stat(playlistDir,&st))<0) {
@ -135,8 +136,10 @@ void initPaths(char * playlistDirArg, char * musicDirArg) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(getConf()[CONF_FS_CHARSET]) { param = getConfigParam(CONF_FS_CHARSET);
charset = strdup(getConf()[CONF_FS_CHARSET]);
if(param) {
charset = strdup(param->value);
} }
#ifdef HAVE_LOCALE #ifdef HAVE_LOCALE
#ifdef HAVE_LANGINFO_CODESET #ifdef HAVE_LANGINFO_CODESET
@ -296,5 +299,3 @@ char * prependCwdToPathDup(char * path) {
return realloc(ret,len+1); return realloc(ret,len+1);
} }
/* vim:set shiftwidth=4 tabstop=8 expandtab: */

View File

@ -69,56 +69,53 @@ unsigned int parsePermissions(char * string) {
} }
void initPermissions() { void initPermissions() {
char * passwordSets;
char * nextSet;
char * temp; char * temp;
char * cp1;
char * cp2; char * cp2;
char * password; char * password;
unsigned int * permission; unsigned int * permission;
ConfigParam * param;
permission_passwords = makeList(free); permission_passwords = makeList(free);
permission_default = PERMISSION_READ | PERMISSION_ADD | permission_default = PERMISSION_READ | PERMISSION_ADD |
PERMISSION_CONTROL | PERMISSION_ADMIN; PERMISSION_CONTROL | PERMISSION_ADMIN;
if(getConf()[CONF_DEFAULT_PERMISSIONS]) { param = getNextConfigParam(CONF_PASSWORD, NULL);
permission_default = parsePermissions(
getConf()[CONF_DEFAULT_PERMISSIONS]);
}
if(!getConf()[CONF_PASSWORD]) return; if(param) {
permission_default = 0;
if(!getConf()[CONF_DEFAULT_PERMISSIONS]) permission_default = 0; do {
if(!strstr(param->value, PERMISSION_PASSWORD_CHAR)) {
passwordSets = strdup(getConf()[CONF_PASSWORD]); ERROR("\"%s\" not found in password string "
"\"%s\", line %i\n",
nextSet = strtok_r(passwordSets,CONF_CAT_CHAR,&cp1);
while(nextSet && strlen(nextSet)) {
if(!strstr(nextSet,PERMISSION_PASSWORD_CHAR)) {
ERROR("\"%s\" not found in password string \"%s\"\n",
PERMISSION_PASSWORD_CHAR, PERMISSION_PASSWORD_CHAR,
nextSet); param->value,
exit(EXIT_FAILURE); param->line);
} exit(EXIT_FAILURE);
}
if(!(temp = strtok_r(nextSet,PERMISSION_PASSWORD_CHAR,&cp2))) { if(!(temp = strtok_r(param->value,
ERROR("something weird just happend in permission.c\n"); PERMISSION_PASSWORD_CHAR,&cp2))) {
exit(EXIT_FAILURE); ERROR("something weird just happend in permission.c\n");
} exit(EXIT_FAILURE);
password = temp; }
permission = malloc(sizeof(unsigned int));
*permission = parsePermissions(strtok_r(NULL,"",&cp2)); password = temp;
insertInList(permission_passwords,password,permission); permission = malloc(sizeof(unsigned int));
*permission = parsePermissions(strtok_r(NULL,"",&cp2));
nextSet = strtok_r(NULL,CONF_CAT_CHAR,&cp1); insertInList(permission_passwords,password,permission);
} while((param = getNextConfigParam(CONF_PASSWORD, param)));
} }
param = getConfigParam(CONF_DEFAULT_PERMS);
if(param) permission_default = parsePermissions(param->value);
sortList(permission_passwords); sortList(permission_passwords);
free(passwordSets);
} }
int getPermissionFromPassword(char * password, unsigned int * permission) { int getPermissionFromPassword(char * password, unsigned int * permission) {

View File

@ -30,23 +30,32 @@
int buffered_before_play; int buffered_before_play;
int buffered_chunks; int buffered_chunks;
#define DEFAULT_BUFFER_SIZE 2048
#define DEFAULT_BUFFER_BEFORE_PLAY 25
PlayerData * playerData_pd; PlayerData * playerData_pd;
void initPlayerData() { void initPlayerData() {
float perc; float perc = DEFAULT_BUFFER_BEFORE_PLAY;
char * test; char * test;
int shmid; int shmid;
int crossfade = 0; int crossfade = 0;
size_t bufferSize; size_t bufferSize = DEFAULT_BUFFER_SIZE;
size_t allocationSize; size_t allocationSize;
OutputBuffer * buffer; OutputBuffer * buffer;
ConfigParam * param;
bufferSize = strtol(getConf()[CONF_BUFFER_SIZE],&test,10); param = getConfigParam(CONF_AUDIO_BUFFER_SIZE);
if(*test!='\0' || bufferSize<=0) {
ERROR("buffer size \"%s\" is not a positive integer\n", if(param) {
getConf()[CONF_BUFFER_SIZE]); bufferSize = strtol(param->value, &test, 10);
exit(EXIT_FAILURE); if(*test!='\0' || bufferSize<=0) {
ERROR("buffer size \"%s\" is not a positive integer, "
"line %i\n", param->value, param->line);
exit(EXIT_FAILURE);
}
} }
bufferSize*=1024; bufferSize*=1024;
buffered_chunks = bufferSize/CHUNK_SIZE; buffered_chunks = bufferSize/CHUNK_SIZE;
@ -56,13 +65,18 @@ void initPlayerData() {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
perc = strtod((getConf())[CONF_BUFFER_BEFORE_PLAY],&test); param = getConfigParam(CONF_BUFFER_BEFORE_PLAY);
if(*test!='%' || perc<0 || perc>100) {
ERROR("buffered before play \"%s\" is not a positive " if(param) {
"percentage and less than 100 percent\n", perc = strtod(param->value, &test);
(getConf())[CONF_BUFFER_BEFORE_PLAY]); if(*test!='%' || perc<0 || perc>100) {
exit(EXIT_FAILURE); ERROR("buffered before play \"%s\" is not a positive "
"percentage and less than 100 percent, line %i"
"\n", param->value, param->line);
exit(EXIT_FAILURE);
}
} }
buffered_before_play = (perc/100)*buffered_chunks; buffered_before_play = (perc/100)*buffered_chunks;
if(buffered_before_play>buffered_chunks) { if(buffered_before_play>buffered_chunks) {
buffered_before_play = buffered_chunks; buffered_before_play = buffered_chunks;

View File

@ -60,6 +60,9 @@
#define PLAYLIST_HASH_MULT 4 #define PLAYLIST_HASH_MULT 4
#define DEFAULT_PLAYLIST_MAX_LENGTH (1024*16)
#define DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS 0
typedef struct _Playlist { typedef struct _Playlist {
Song ** songs; Song ** songs;
/* holds version a song was modified on */ /* holds version a song was modified on */
@ -77,13 +80,13 @@ typedef struct _Playlist {
static Playlist playlist; static Playlist playlist;
static int playlist_state = PLAYLIST_STATE_STOP; static int playlist_state = PLAYLIST_STATE_STOP;
static int playlist_max_length; static int playlist_max_length = DEFAULT_PLAYLIST_MAX_LENGTH;
static int playlist_stopOnError; static int playlist_stopOnError;
static int playlist_errorCount = 0; static int playlist_errorCount = 0;
static int playlist_queueError; static int playlist_queueError;
static int playlist_noGoToNext = 0; static int playlist_noGoToNext = 0;
static int playlist_saveAbsolutePaths; static int playlist_saveAbsolutePaths = DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS;
static char * playlist_stateFile = NULL; static char * playlist_stateFile = NULL;
@ -128,6 +131,7 @@ static void incrPlaylistCurrent() {
void initPlaylist() { void initPlaylist() {
char * test; char * test;
int i; int i;
ConfigParam * param;
playlist.length = 0; playlist.length = 0;
playlist.repeat = 0; playlist.repeat = 0;
@ -136,26 +140,32 @@ void initPlaylist() {
playlist.queued = -1; playlist.queued = -1;
playlist.current = -1; playlist.current = -1;
playlist_max_length = strtol((getConf())[CONF_MAX_PLAYLIST_LENGTH],&test,10); param = getConfigParam(CONF_MAX_PLAYLIST_LENGTH);
if(*test!='\0') {
ERROR("max playlist length \"%s\" is not an integer\n", if(param) {
(getConf())[CONF_MAX_PLAYLIST_LENGTH]); playlist_max_length = strtol(param->value, &test, 10);
exit(EXIT_FAILURE); if(*test!='\0') {
ERROR("max playlist length \"%s\" is not an integer, "
"line %i\n", param->value, param->line);
exit(EXIT_FAILURE);
}
} }
if(strcmp("yes",(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS]) param = getConfigParam(CONF_SAVE_ABSOLUTE_PATHS);
==0) {
playlist_saveAbsolutePaths = 1; if(param) {
} if(0 == strcmp("yes", param->value) ) {
else if(strcmp("no",(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS]) playlist_saveAbsolutePaths = 1;
==0) { }
playlist_saveAbsolutePaths = 0; else if(0 == strcmp("no", param->value) ) {
} playlist_saveAbsolutePaths = 0;
else { }
ERROR("save_absolute_paths_in_playlist \"%s\" is not yes or " else {
"no\n", ERROR("%s \"%s\" is not yes or no, line %i"
(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS]); CONF_SAVE_ABSOLUTE_PATHS,
exit(EXIT_FAILURE); param->value, param->line);
exit(EXIT_FAILURE);
}
} }
playlist.songs = malloc(sizeof(Song *)*playlist_max_length); playlist.songs = malloc(sizeof(Song *)*playlist_max_length);
@ -169,9 +179,7 @@ void initPlaylist() {
srand(time(NULL)); srand(time(NULL));
if(getConf()[CONF_STATE_FILE]) { playlist_stateFile = getConfigParamValue(CONF_STATE_FILE);
playlist_stateFile = getConf()[CONF_STATE_FILE];
}
for(i=0; i<playlist_max_length*PLAYLIST_HASH_MULT; i++) { for(i=0; i<playlist_max_length*PLAYLIST_HASH_MULT; i++) {
playlist.idToPosition[i] = -1; playlist.idToPosition[i] = -1;

View File

@ -32,34 +32,38 @@ static int replayGainState = REPLAYGAIN_OFF;
static float replayGainPreamp = 1.0; static float replayGainPreamp = 1.0;
void initReplayGainState() { void initReplayGainState() {
if(!getConf()[CONF_REPLAYGAIN]) return; ConfigParam * param = getConfigParam(CONF_REPLAYGAIN);
if(strcmp(getConf()[CONF_REPLAYGAIN],"track")==0) { if(!param) return;
if(strcmp(param->value, "track") == 0) {
replayGainState = REPLAYGAIN_TRACK; replayGainState = REPLAYGAIN_TRACK;
} }
else if(strcmp(getConf()[CONF_REPLAYGAIN],"album")==0) { else if(strcmp(param->value, "album") == 0) {
replayGainState = REPLAYGAIN_ALBUM; replayGainState = REPLAYGAIN_ALBUM;
} }
else { else {
ERROR("replaygain value \"%s\" is invalid\n", ERROR("replaygain value \"%s\" at line %i is invalid\n",
getConf()[CONF_REPLAYGAIN]); param->value, param->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(getConf()[CONF_REPLAYGAIN_PREAMP]) { param = getConfigParam(CONF_REPLAYGAIN_PREAMP);
if(param) {
char * test; char * test;
float f = strtod(getConf()[CONF_REPLAYGAIN_PREAMP], &test); float f = strtod(param->value, &test);
if(*test != '\0') { if(*test != '\0') {
ERROR("Replaygain preamp \"%s\" is not a number\n", ERROR("Replaygain preamp \"%s\" is not a number at "
getConf()[CONF_REPLAYGAIN_PREAMP]); "line %i\n", param->value, param->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(f < -15 || f > 15) { if(f < -15 || f > 15) {
ERROR("Replaygain preamp \"%s\" is not between -15 and" ERROR("Replaygain preamp \"%s\" is not between -15 and"
"15\n", "15 at line %i\n",
getConf()[CONF_REPLAYGAIN_PREAMP]); param->value, param->line);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

@ -93,18 +93,6 @@ char * getID3Info(struct id3_tag * tag, char * id) {
utf8 = id3_ucs4_utf8duplicate(ucs4); utf8 = id3_ucs4_utf8duplicate(ucs4);
if(!utf8) return NULL; if(!utf8) return NULL;
if(getConf()[CONF_ID3V1_ENCODING]
&& (id3_tag_options(tag, 0, 0) & ID3_TAG_OPTION_ID3V1)) {
char* isostr;
setCharSetConversion("ISO-8859-1", "UTF-8");
isostr = convStrDup(utf8);
free(utf8);
setCharSetConversion("UTF-8", getConf()[CONF_ID3V1_ENCODING]);
utf8 = convStrDup(isostr);
free(isostr);
}
return utf8; return utf8;
} }
#endif #endif

View File

@ -45,8 +45,21 @@
#define VOLUME_MIXER_ALSA_DEFAULT "default" #define VOLUME_MIXER_ALSA_DEFAULT "default"
#define VOLUME_MIXER_ALSA_CONTROL_DEFAULT "Master" #define VOLUME_MIXER_ALSA_CONTROL_DEFAULT "Master"
int volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE; #ifndef NO_OSS_MIXER
char * volume_mixerDevice; #define VOLUME_MIXER_TYPE_DEFAULT VOLUME_MIXER_TYPE_OSS
#define VOLUME_MIXER_DEVICE_DEFAULT VOLUME_MIXER_OSS_DEFAULT
#else
#ifdef HAVE_ALSA
#define VOLUME_MIXER_TYPE_DEFAULT VOLUME_MIXER_TYPE_ALSA
#define VOLUME_MIXER_DEVICE_DEFAULT VOLUME_MIXER_ALSA_DEFAULT
#else
#define VOLUME_MIXER_TYPE_DEFAULT VOLUME_MIXER_TYPE_SOFTWARE
#define VOLUME_MIXER_DEVICE_DEFAULT VOLUME_MIXER_SOFTWARE_DEFAULT
#endif
#endif
int volume_mixerType = VOLUME_MIXER_TYPE_DEFAULT;
char * volume_mixerDevice = VOLUME_MIXER_DEVICE_DEFAULT;
int volume_softwareSet = 100; int volume_softwareSet = 100;
@ -66,13 +79,16 @@ int volume_alsaSet = -1;
#ifndef NO_OSS_MIXER #ifndef NO_OSS_MIXER
int prepOssMixer(char * device) { int prepOssMixer(char * device) {
int devmask = 0; int devmask = 0;
ConfigParam * param;
if((volume_ossFd = open(device,O_RDONLY))<0) { if((volume_ossFd = open(device,O_RDONLY))<0) {
WARNING("unable to open oss mixer \"%s\"\n",device); WARNING("unable to open oss mixer \"%s\"\n",device);
return -1; return -1;
} }
if(getConf()[CONF_MIXER_CONTROL]) { param = getConfigParam(CONF_MIXER_CONTROL);
if(param) {
char * labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; char * labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
char * dup; char * dup;
int i,j; int i,j;
@ -88,7 +104,7 @@ int prepOssMixer(char * device) {
/* eliminate spaces at the end */ /* eliminate spaces at the end */
j = strlen(dup)-1; j = strlen(dup)-1;
while(j>=0 && dup[j]==' ') dup[j--] = '\0'; while(j>=0 && dup[j]==' ') dup[j--] = '\0';
if(strcasecmp(dup,getConf()[CONF_MIXER_CONTROL])==0) { if(strcasecmp(dup, param->value)==0) {
free(dup); free(dup);
break; break;
} }
@ -96,14 +112,14 @@ int prepOssMixer(char * device) {
} }
if(i>=SOUND_MIXER_NRDEVICES) { if(i>=SOUND_MIXER_NRDEVICES) {
WARNING("mixer control \"%s\" not found\n", WARNING("mixer control \"%s\" not found at line %i\n",
getConf()[CONF_MIXER_CONTROL]); param->value, param->line);
close(volume_ossFd); close(volume_ossFd);
return -1; return -1;
} }
else if(!( ( 1 << i ) & devmask )) { else if(!( ( 1 << i ) & devmask )) {
WARNING("mixer control \"%s\" not usable\n", WARNING("mixer control \"%s\" not usable at line %i\n",
getConf()[CONF_MIXER_CONTROL]); param->value, param->line);
close(volume_ossFd); close(volume_ossFd);
return -1; return -1;
} }
@ -173,6 +189,7 @@ int prepAlsaMixer(char * card) {
int err; int err;
snd_mixer_elem_t * elem; snd_mixer_elem_t * elem;
char * controlName = VOLUME_MIXER_ALSA_CONTROL_DEFAULT; char * controlName = VOLUME_MIXER_ALSA_CONTROL_DEFAULT;
ConfigParam * param;
if((err = snd_mixer_open(&volume_alsaMixerHandle,0))<0) { if((err = snd_mixer_open(&volume_alsaMixerHandle,0))<0) {
WARNING("problems opening alsa mixer: %s\n",snd_strerror(err)); WARNING("problems opening alsa mixer: %s\n",snd_strerror(err));
@ -201,8 +218,11 @@ int prepAlsaMixer(char * card) {
} }
elem = snd_mixer_first_elem(volume_alsaMixerHandle); elem = snd_mixer_first_elem(volume_alsaMixerHandle);
if(getConf()[CONF_MIXER_CONTROL]) {
controlName = getConf()[CONF_MIXER_CONTROL]; param = getConfigParam(CONF_MIXER_CONTROL);
if(param) {
controlName = param->value;
} }
while(elem) { while(elem) {
@ -340,29 +360,37 @@ void finishVolume() {
} }
void initVolume() { void initVolume() {
if(0); ConfigParam * param = getConfigParam(CONF_MIXER_TYPE);
if(param) {
if(0);
#ifdef HAVE_ALSA #ifdef HAVE_ALSA
else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_ALSA)==0) { else if(strcmp(param->value, VOLUME_MIXER_ALSA)==0) {
volume_mixerType = VOLUME_MIXER_TYPE_ALSA; volume_mixerType = VOLUME_MIXER_TYPE_ALSA;
volume_mixerDevice = VOLUME_MIXER_ALSA_DEFAULT; volume_mixerDevice = VOLUME_MIXER_ALSA_DEFAULT;
} }
#endif #endif
#ifndef NO_OSS_MIXER #ifndef NO_OSS_MIXER
else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_OSS)==0) { else if(strcmp(param->value, VOLUME_MIXER_OSS)==0) {
volume_mixerType = VOLUME_MIXER_TYPE_OSS; volume_mixerType = VOLUME_MIXER_TYPE_OSS;
volume_mixerDevice = VOLUME_MIXER_OSS_DEFAULT; volume_mixerDevice = VOLUME_MIXER_OSS_DEFAULT;
} }
#endif #endif
else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_SOFTWARE)==0) { else if(strcmp(param->value ,VOLUME_MIXER_SOFTWARE)==0) {
volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE; volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
volume_mixerDevice = VOLUME_MIXER_SOFTWARE_DEFAULT; volume_mixerDevice = VOLUME_MIXER_SOFTWARE_DEFAULT;
}
else {
ERROR("unknown mixer type %s at line %i\n",
param->value, param->line);
exit(EXIT_FAILURE);
}
} }
else {
ERROR("unknown mixer type: %s\n",(getConf())[CONF_MIXER_TYPE]); param = getConfigParam(CONF_MIXER_DEVICE);
exit(EXIT_FAILURE);
} if(param) {
if(strlen((getConf())[CONF_MIXER_DEVICE])) { volume_mixerDevice = param->value;
volume_mixerDevice = (getConf())[CONF_MIXER_DEVICE];
} }
} }
@ -431,4 +459,3 @@ int changeVolumeLevel(FILE * fp, int change, int rel) {
break; break;
} }
} }
/* vim:set shiftwidth=4 tabstop=8 expandtab: */