diff --git a/TODO b/TODO
index bd3662635..28bfdc80e 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,7 @@
 0.12
 ----
+*) Fix id3v1 encoding
+
 *) Abstract audio stuff into a plugin oriented thing
 	*) audio_ao & audio_oss & audio_shout
 	*) allow for sending to multiple audio devices
diff --git a/doc/mpdconf.example b/doc/mpdconf.example
index 76c652e64..f13cf2912 100644
--- a/doc/mpdconf.example
+++ b/doc/mpdconf.example
@@ -71,28 +71,25 @@ error_file 		"~/.mpd/mpd.error"
 ################## AUDIO OUTPUT ##########################
 #
 # 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
 #
 # OSS Audio Output
-#ao_driver 		"oss"
-#ao_driver_options 	"dsp=/dev/dsp"
+#audio_output {
+#	type		"ao"
+#	name		"my OSS device"
+#	driver 		"oss"
+#	options 	"dsp=/dev/dsp"
+#	write_size	"1024"
+#}
 #
 # ALSA Audio Output
-#ao_driver		"alsa09"
-#ao_driver_options	"dev=hw:0,0"
+#audio_output {
+#	type		"ao"
+#	name		"my ALSA device"
+#	driver		"alsa09"
+#	options		"dev=hw:0,0"
+#	write_size	"1024"
+#}
 #
 # Set this if you have problems 
 # playing audio files.
@@ -101,11 +98,24 @@ error_file 		"~/.mpd/mpd.error"
 #
 #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 ###################
 #
 # This setting exists as precaution against attacks.
diff --git a/src/audio.c b/src/audio.c
index 653fb55f5..e3a311abb 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -31,9 +31,6 @@ static AudioFormat audio_format;
 
 static AudioFormat * audio_configFormat = NULL;
 
-static AudioOutput * aoOutput = NULL;
-static AudioOutput * shoutOutput = NULL;
-
 void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
 	if(!src) return;
 
@@ -42,17 +39,34 @@ void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
         dest->channels = src->channels;
 }
 
+static AudioOutput ** audioOutputArray = NULL;
+static int audioOutputArraySize = 0;
+
 extern AudioOutputPlugin aoPlugin;
 extern AudioOutputPlugin shoutPlugin;
 
 void initAudioDriver() {
+	ConfigParam * param = NULL;
+	int i;
+
 	initAudioOutputPlugins();
 	loadAudioOutputPlugin(&aoPlugin);
 	loadAudioOutputPlugin(&shoutPlugin);
 
-	aoOutput = newAudioOutput("ao");
-	assert(aoOutput);
-	shoutOutput = newAudioOutput("shout");
+	while((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param))) {
+		i = audioOutputArraySize++;
+
+		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, 
@@ -65,13 +79,17 @@ void getOutputAudioFormat(AudioFormat * inAudioFormat,
 }
 
 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));
 
-	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) {
@@ -145,10 +163,15 @@ void finishAudioConfig() {
 }
 
 void finishAudioDriver() {
-	finishAudioOutput(aoOutput);
-	if(shoutOutput) finishAudioOutput(shoutOutput);
-	shoutOutput = NULL;
-	aoOutput = NULL;
+	int i;
+
+	for(i = 0; i < audioOutputArraySize; i++) {
+		finishAudioOutput(audioOutputArray[i]);
+	}
+
+	free(audioOutputArray);
+	audioOutputArray = NULL;
+	audioOutputArraySize = 0;
 }
 
 int isCurrentAudioFormat(AudioFormat * audioFormat) {
@@ -160,29 +183,65 @@ int isCurrentAudioFormat(AudioFormat * audioFormat) {
 }
 
 int openAudioDevice(AudioFormat * audioFormat) {
-	if(!aoOutput->open || !isCurrentAudioFormat(audioFormat)) {
-		if(audioFormat) copyAudioFormat(&audio_format, audioFormat);
-		if(shoutOutput) openAudioOutput(shoutOutput, &audio_format);
-		return openAudioOutput(aoOutput, &audio_format);
+	int isCurrentFormat = isCurrentAudioFormat(audioFormat);
+	int ret = -1;
+	int i;
+
+	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) {
-	if(shoutOutput) playAudioOutput(shoutOutput, playChunk, size);
-	return playAudioOutput(aoOutput, playChunk, size);
+	int ret = -1;
+	int i;
+
+	for(i = 0; i < audioOutputArraySize; i++) {
+		if(0 == playAudioOutput(audioOutputArray[i], playChunk, size)) {
+			ret = 0;
+		}
+	}
+
+	return ret;
 }
 
 int isAudioDeviceOpen() {
-	return aoOutput->open;
+	int ret = 0;
+	int i;
+
+	for(i = 0; i < audioOutputArraySize; i++) {
+		ret |= audioOutputArray[i]->open;
+	}
+
+	return ret;
 }
 
 void closeAudioDevice() {
-	if(shoutOutput) closeAudioOutput(shoutOutput);
-	closeAudioOutput(aoOutput);
+	int i;
+
+	for(i = 0; i < audioOutputArraySize; i++) {
+		closeAudioOutput(audioOutputArray[i]);
+	}
 }
 
 void sendMetadataToAudioDevice(MpdTag * tag) {
-	if(shoutOutput) sendMetadataToAudioOutput(shoutOutput, tag);
+	int i;
+
+	for(i = 0; i < audioOutputArraySize; i++) {
+		sendMetadataToAudioOutput(audioOutputArray[i], tag);
+	}
 }
diff --git a/src/audioOutput.c b/src/audioOutput.c
index d85b9d978..0175ed04f 100644
--- a/src/audioOutput.c
+++ b/src/audioOutput.c
@@ -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;
 
@@ -21,13 +27,32 @@ void finishAudioOutputPlugins() {
 	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;
 	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;
 		ret = malloc(sizeof(AudioOutput));
+		ret->name = strdup(name);
+		ret->type = strdup(type);
 		ret->finishDriverFunc = plugin->finishDriverFunc;
 		ret->openDeviceFunc = plugin->openDeviceFunc;
 		ret->playFunc = plugin->playFunc;
@@ -35,11 +60,16 @@ AudioOutput * newAudioOutput(char * name) {
 		ret->sendMetdataFunc = plugin->sendMetdataFunc;
 		ret->open = 0;
 
-		if(plugin->initDriverFunc(ret) != 0) {
+		if(plugin->initDriverFunc(ret, param) != 0) {
 			free(ret);
 			ret = NULL;
 		}
 	}
+	else {
+		ERROR("couldn't find audio output plugin for type \"%s\" at "
+				"line %i", type, param->line);
+		exit(EXIT_FAILURE);
+	}
 
 	return ret;
 }
diff --git a/src/audioOutput.h b/src/audioOutput.h
index ec43e9e7c..49c7110f9 100644
--- a/src/audioOutput.h
+++ b/src/audioOutput.h
@@ -24,12 +24,14 @@
 #include "mpd_types.h"
 #include "audio.h"
 #include "tag.h"
+#include "conf.h"
 
 #define AUDIO_AO_DRIVER_DEFAULT	"default"
 
 typedef struct _AudioOutput AudioOutput;
 
-typedef int (* AudioOutputInitDriverFunc) (AudioOutput * audioOutput);
+typedef int (* AudioOutputInitDriverFunc) (AudioOutput * audioOutput, 
+		ConfigParam * param);
 
 typedef void (* AudioOutputFinishDriverFunc) (AudioOutput * audioOutput);
 
@@ -46,6 +48,8 @@ typedef void (* AudioOutputSendMetadataFunc) (AudioOutput * audioOutput,
 
 struct _AudioOutput {
 	int open;
+	char * name;
+	char * type;
 
         AudioOutputFinishDriverFunc finishDriverFunc;
         AudioOutputOpenDeviceFunc openDeviceFunc;
@@ -73,7 +77,7 @@ void finishAudioOutputPlugins();
 void loadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
 void unloadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
 
-AudioOutput * newAudioOutput(char * name);
+AudioOutput * newAudioOutput(ConfigParam * param);
 int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat);
 int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size);
 void closeAudioOutput(AudioOutput * audioOutput);
diff --git a/src/audioOutput_ao.c b/src/audioOutput_ao.c
index 7c997c99e..60c4ea402 100644
--- a/src/audioOutput_ao.c
+++ b/src/audioOutput_ao.c
@@ -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;
 	char * dup;
 	char * stk1;
@@ -66,38 +68,51 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput) {
 	char * value;
 	char * test;
 	AoData * ad  = newAoData();
+	BlockParam * blockParam;
 
 	audioOutput->data = ad;
 
-	ad->writeSize = strtol((getConf())[CONF_AUDIO_WRITE_SIZE],&test,10);
-	if (*test!='\0') {
-		ERROR("\"%s\" is not a valid write size\n",
-			(getConf())[CONF_AUDIO_WRITE_SIZE]);
-		exit(EXIT_FAILURE);
+	if((blockParam = getBlockParam(param, "write_size"))) {
+		ad->writeSize = strtol(blockParam->value, &test, 10);
+		if (*test!='\0') {
+			ERROR("\"%s\" is not a valid write size at line %i\n",
+				blockParam->value, blockParam->line);
+			exit(EXIT_FAILURE);
+		}
 	}
+	else ad->writeSize = 1024;
 
 	if(driverInitCount == 0) {
 		ao_initialize();
 	}
 	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();
 	}
 	else if((ad->driverId = 
-		ao_driver_id((getConf())[CONF_AO_DRIVER]))<0) {
-		ERROR("\"%s\" is not a valid ao driver\n",
-			(getConf())[CONF_AO_DRIVER]);
+		ao_driver_id(blockParam->value))<0) {
+		ERROR("\"%s\" is not a valid ao driver at line %i\n",
+			blockParam->value, blockParam->line);
 		exit(EXIT_FAILURE);
 	}
 	
 	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");
 		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)) {
 		stk1 = NULL;
 		n1 = strtok_r(dup,";",&stk1);
diff --git a/src/audioOutput_shout.c b/src/audioOutput_shout.c
index 45ef00846..f41b57359 100644
--- a/src/audioOutput_shout.c
+++ b/src/audioOutput_shout.c
@@ -88,7 +88,16 @@ static void freeShoutData(ShoutData * 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;
 	char * test;
 	int port;
@@ -97,73 +106,50 @@ static int shout_initDriver(AudioOutput * audioOutput) {
 	char * passwd;
 	char * user;
 	char * name;
-
-	if(!getConf()[CONF_SHOUT_HOST]) {
-		return -1;
-	}
+	BlockParam * blockParam;
 
 	sd = newShoutData();
 
-	if(!getConf()[CONF_SHOUT_MOUNT]) {
-		ERROR("shout host defined but not shout mount point\n");
-		exit(EXIT_FAILURE);
-	}
+	checkBlockParam("host");
+	host = blockParam->value;
 
-	if(!getConf()[CONF_SHOUT_PORT]) {
-		ERROR("shout host defined but not shout port\n");
-		exit(EXIT_FAILURE);
-	}
+	checkBlockParam("mount");
+	mount = blockParam->value;
 
-	if(!getConf()[CONF_SHOUT_PASSWD]) {
-		ERROR("shout host defined but not shout password\n");
-		exit(EXIT_FAILURE);
-	}
+	checkBlockParam("port");
 
-	if(!getConf()[CONF_SHOUT_NAME]) {
-		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);
+	port = strtol(blockParam->value, &test, 10);
 
 	if(*test != '\0' || port <= 0) {
-		ERROR("shout port \"%s\" is not a positive integer\n", 
-				getConf()[CONF_SHOUT_PORT]);
+		ERROR("shout port \"%s\" is not a positive integer, line %i\n", 
+				blockParam->value, blockParam->line);
 		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) {
 		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);
 	}
 
-	if(0 != parseAudioConfig(&(sd->outAudioFormat), 
-			getConf()[CONF_SHOUT_FORMAT]) )
-	{
+	checkBlockParam("format");
+
+	if(0 != parseAudioConfig(&(sd->outAudioFormat), blockParam->value)) {
+		ERROR("error parsing format at line %i\n", blockParam->line);
 		exit(EXIT_FAILURE);
 	}
 
@@ -276,7 +262,7 @@ static int initEncoder(ShoutData * sd) {
 	vorbis_info_init(&(sd->vi));
 
 	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");
 		vorbis_info_clear(&(sd->vi));
diff --git a/src/conf.c b/src/conf.c
index a89a1e334..ccbb99f1c 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -22,8 +22,7 @@
 
 #include "utils.h"
 #include "buffer2array.h"
-#include "audio.h"
-#include "volume.h"
+#include "list.h"
 
 #include <sys/param.h>
 #include <stdio.h>
@@ -35,270 +34,385 @@
 
 #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_NUMBER_OF_PATHS		6
-#define CONF_NUMBER_OF_REQUIRED		5
-#define CONF_NUMBER_OF_ALLOW_CATS	1
+#define CONF_REPEATABLE_MASK	0x01
+#define CONF_BLOCK_MASK		0x02
 
-#define CONF_CONNECTION_TIMEOUT_DEFAULT			"60"
-#define CONF_MAX_CONNECTIONS_DEFAULT			"5"
-#define CONF_MAX_PLAYLIST_LENGTH_DEFAULT		"16384"
-#define CONF_BUFFER_BEFORE_PLAY_DEFAULT			"25%"
-#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
+typedef struct _configEntry {
+	unsigned char mask;
+	List * configParamList;
+} ConfigEntry;
 
-static char * conf_params[CONF_NUMBER_OF_PARAMS];
+static List * configEntriesList = NULL;
 
-void initConf() {
-	int i;
+static ConfigParam * newConfigParam(char * value, int line) {
+	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 */
-	conf_params[CONF_CONNECTION_TIMEOUT] = strdup(CONF_CONNECTION_TIMEOUT_DEFAULT);
-	conf_params[CONF_MIXER_DEVICE] = strdup(CONF_MIXER_DEVICE_DEFAULT);
-	conf_params[CONF_MAX_CONNECTIONS] = strdup(CONF_MAX_CONNECTIONS_DEFAULT);
-	conf_params[CONF_MAX_PLAYLIST_LENGTH] = strdup(CONF_MAX_PLAYLIST_LENGTH_DEFAULT);
-	conf_params[CONF_BUFFER_BEFORE_PLAY] = strdup(CONF_BUFFER_BEFORE_PLAY_DEFAULT);
-	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);
+	ret->line = line;
+
+	ret->numberOfBlockParams = 0;
+	ret->blockParams = NULL;
+
+	return ret;
 }
 
-char ** readConf(char * file) {
-	char * conf_strings[CONF_NUMBER_OF_PARAMS] = {
-		"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"
-	};
+static void freeConfigParam(ConfigParam * param) {
+	int i;
 
-	int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {
-		CONF_MUSIC_DIRECTORY,
-		CONF_PLAYLIST_DIRECTORY,
-		CONF_LOG_FILE,
-		CONF_ERROR_FILE,
-		CONF_STATE_FILE,
-		CONF_DB_FILE
-	};
+	if(param->value) free(param->value);
 
-	int conf_required[CONF_NUMBER_OF_REQUIRED] = {
-		CONF_MUSIC_DIRECTORY,
-		CONF_PLAYLIST_DIRECTORY,
-		CONF_LOG_FILE,
-		CONF_ERROR_FILE,
-		CONF_PORT
-	};
+	for(i=0; i<param->numberOfBlockParams; i++) {
+		if(param->blockParams[i].name) {
+			free(param->blockParams[i].name);
+		}
+		if(param->blockParams[i].value) {
+			free(param->blockParams[i].value);
+		}
+	}
 
-	short conf_allowCat[CONF_NUMBER_OF_ALLOW_CATS] = {
-		CONF_PASSWORD
-	};
+	if(param->numberOfBlockParams) free(param->blockParams);
 
+	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;
 	char string[MAX_STRING_SIZE+1];
 	char ** array;
 	int i;
 	int numberOfArgs;
-	short allowCat[CONF_NUMBER_OF_PARAMS];
+	int argsMinusComment;
 	int count = 0;
-
-	for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) allowCat[i] = 0;
-
-	for(i=0;i<CONF_NUMBER_OF_ALLOW_CATS;i++) allowCat[conf_allowCat[i]] = 1;
+	ConfigEntry * entry;
+	void * voidPtr;
+	ConfigParam * param;
 
 	if(!(fp=fopen(file,"r"))) {
 		ERROR("problems opening file %s for reading\n",file);
 		exit(EXIT_FAILURE);
 	}
 
-	while(myFgets(string,sizeof(string),fp)) {
+	while(myFgets(string, MAX_STRING_SIZE, fp)) {
 		count++;
 
-		if(string[0]==CONF_COMMENT) continue;
-		numberOfArgs = buffer2array(string,&array);
-		if(numberOfArgs==0) continue;
-		if(2!=numberOfArgs) {
-			ERROR("improperly formated config file at line %i: %s\n",count,string);
+		numberOfArgs = buffer2array(string, &array);
+
+		for(i=0; i<numberOfArgs; i++) {
+			if(array[i][0] == CONF_COMMENT) break;
+		}
+
+		argsMinusComment = i;
+
+		if(0 == argsMinusComment) continue;
+
+		if(2 != argsMinusComment) {
+			ERROR("improperly formated config file at line %i:"
+					" %s\n", count, string);
 			exit(EXIT_FAILURE);
 		}
-		i = 0;
-		while(i<CONF_NUMBER_OF_PARAMS && 0!=strcmp(conf_strings[i],array[0])) i++;
-		if(i>=CONF_NUMBER_OF_PARAMS) {
-			ERROR("unrecognized paramater in conf at line %i: %s\n",count,string);
+
+		if(!findInList(configEntriesList, array[0], &voidPtr)) {
+			ERROR("unrecognized paramater in config file at line "
+					"%i: %s\n", count, string);
 			exit(EXIT_FAILURE);
 		}
-		
-		if(conf_params[i]!=NULL) {
-			if(allowCat[i]) {
-				conf_params[i] = realloc(conf_params[i],
-						strlen(conf_params[i])+
-						strlen(CONF_CAT_CHAR)+
-						strlen(array[1])+1);
-				strcat(conf_params[i],CONF_CAT_CHAR);
-				strcat(conf_params[i],array[1]);
-			}
-			else {
-				free(conf_params[i]);
-				conf_params[i] = strdup(array[1]);
-			}
+
+		entry = (ConfigEntry *) voidPtr;
+
+		if( !(entry->mask & CONF_REPEATABLE_MASK) &&
+			entry->configParamList->numberOfNodes)
+		{
+			param = entry->configParamList->firstNode->data;
+			ERROR("config paramter \"%s\" is first defined on line "
+					"%i and redefined on line %i\n",
+					array[0], param->line, count);
+			exit(EXIT_FAILURE);
 		}
-		else conf_params[i] = strdup(array[1]);
-		free(array[0]);
-		free(array[1]);
-		free(array);
+
+		if(entry->mask & CONF_BLOCK_MASK) {
+			if(0 != strcmp(array[1], CONF_BLOCK_BEGIN)) {
+				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(conf_params[conf_required[i]] == NULL) {
-			ERROR("%s is unassigned in conf file\n",
-					conf_strings[conf_required[i]]);
-			exit(EXIT_FAILURE);
+	if(!findInList(configEntriesList, name, &voidPtr)) return NULL;
+
+	entry = voidPtr;
+
+	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(conf_params[conf_absolutePaths[i]] && 
-			conf_params[conf_absolutePaths[i]][0]!='/' &&
-			conf_params[conf_absolutePaths[i]][0]!='~') 
-		{
-			ERROR("\"%s\" is not an absolute path\n",
-					conf_params[conf_absolutePaths[i]]);
-			exit(EXIT_FAILURE);
-		}
-		/* Parse ~ in path */
-		else if(conf_params[conf_absolutePaths[i]] &&
-			conf_params[conf_absolutePaths[i]][0]=='~') 
-		{
-			struct passwd * pwd = NULL;
-			char * path;
-			int pos = 1;
-			if(conf_params[conf_absolutePaths[i]][1]=='/' ||
-				conf_params[conf_absolutePaths[i]][1]=='\0') 
-			{
-				if(conf_params[CONF_USER] && 
-						strlen(conf_params[CONF_USER]))
-				{
-					pwd = getpwnam(
-						conf_params[CONF_USER]);
-					if(!pwd) {
-						ERROR("no such user: %s\n",
-							conf_params[CONF_USER]);
-						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);
-					}
-				}
+	if(node == NULL)  return NULL;
+
+	param = node->data;
+
+	return param;
+}
+
+char * getConfigParamValue(char * name) {
+	ConfigParam * param = getConfigParam(name);
+
+	if(!param) return NULL;
+
+	return param->value;
+}
+
+char * forceAndGetConfigParamValue(char * name) {
+	ConfigParam * param = getConfigParam(name);
+
+	if(!param) {
+		ERROR("\"%s\" not found in config file\n", name);
+		exit(EXIT_FAILURE);
+	}
+
+	return param->value;
+}
+
+BlockParam * getBlockParam(ConfigParam * param, char * name) {
+	BlockParam * ret = NULL;
+	int i;
+
+	for(i = 0; i < param->numberOfBlockParams; i++) {
+		if(0 == strcmp(name, param->blockParams[i].name)) {
+			if(ret) {
+				ERROR("\"%s\" first defined on line %i, and "
+					"redefined on line %i\n", name, 
+					ret->line, param->blockParams[i].line);
 			}
-			else {
-				int foundSlash = 0;
-				char * ch = &(
-					conf_params[conf_absolutePaths[i]][1]);
-				for(;*ch!='\0' && *ch!='/';ch++);
-				if(*ch=='/') foundSlash = 1;
-				* ch = '\0';
-				pos+= ch-
-					&(conf_params[
-					conf_absolutePaths[i]][1]);
-				if((pwd = getpwnam(&(conf_params[
-					conf_absolutePaths[i]][1]))) == NULL) 
-				{
-					ERROR("user \"%s\" not found\n",
-						&(conf_params[
-						conf_absolutePaths[i]][1]));
+			ret = param->blockParams+i;
+		}
+	}
+
+	return ret;
+}
+
+char * parseConfigFilePath(char * name, int force) {
+	ConfigParam * param = getConfigParam(name);
+	char * path;
+
+	if(!param && force) {
+		ERROR("config parameter \"%s\" not found\n", name);
+		exit(EXIT_FAILURE);
+	}
+
+	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);
 				}
-				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;
-}
-
-char ** getConf() {
-	return conf_params;
+	return param->value;
 }
diff --git a/src/conf.h b/src/conf.h
index f6bd5d283..1c9413654 100644
--- a/src/conf.h
+++ b/src/conf.h
@@ -21,59 +21,72 @@
 
 #include "../config.h"
 
-#define CONF_PORT				0
-#define CONF_MUSIC_DIRECTORY			1
-#define CONF_PLAYLIST_DIRECTORY			2
-#define CONF_LOG_FILE				3
-#define CONF_ERROR_FILE				4
-#define CONF_CONNECTION_TIMEOUT			5
-#define CONF_MIXER_DEVICE			6
-#define CONF_MAX_CONNECTIONS			7
-#define CONF_MAX_PLAYLIST_LENGTH		8
-#define CONF_BUFFER_BEFORE_PLAY			9
-#define CONF_MAX_COMMAND_LIST_SIZE		10
-#define CONF_MAX_OUTPUT_BUFFER_SIZE		11
-#define CONF_AO_DRIVER				12
-#define CONF_AO_DRIVER_OPTIONS			13
-#define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS	14
-#define CONF_BIND_TO_ADDRESS			15
-#define CONF_MIXER_TYPE				16
-#define CONF_STATE_FILE				17
-#define CONF_USER				18
-#define CONF_DB_FILE				19
-#define CONF_LOG_LEVEL				20
-#define CONF_MIXER_CONTROL			21
-#define CONF_AUDIO_WRITE_SIZE			22
-#define CONF_FS_CHARSET				23
-#define CONF_PASSWORD				24
-#define CONF_DEFAULT_PERMISSIONS		25
-#define CONF_BUFFER_SIZE			26
-#define CONF_REPLAYGAIN                         27
-#define CONF_AUDIO_OUTPUT_FORMAT                28
-#define CONF_HTTP_PROXY_HOST                    29
-#define CONF_HTTP_PROXY_PORT                    30
-#define CONF_HTTP_PROXY_USER			31
-#define CONF_HTTP_PROXY_PASSWORD		32
-#define CONF_REPLAYGAIN_PREAMP			33
-#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_PORT			"port"
+#define CONF_MUSIC_DIR			"music_directory"
+#define CONF_PLAYLIST_DIR		"playlist_directory"
+#define CONF_LOG_FILE			"log_file"
+#define CONF_ERROR_FILE			"error_file"
+#define CONF_CONN_TIMEOUT		"connection_timeout"
+#define CONF_MIXER_DEVICE		"mixer_device"
+#define CONF_MAX_CONN			"max_connections"
+#define CONF_MAX_PLAYLIST_LENGTH	"max_playlist_length"
+#define CONF_BUFFER_BEFORE_PLAY		"buffer_before_play"
+#define CONF_MAX_COMMAND_LIST_SIZE	"max_command_list_size"
+#define CONF_MAX_OUTPUT_BUFFER_SIZE	"max_output_buffer_size"
+#define CONF_AUDIO_OUTPUT		"audio_output"
+#define CONF_SAVE_ABSOLUTE_PATHS	"save_absolute_paths_in_playlists"
+#define CONF_BIND_TO_ADDRESS		"bind_to_address"
+#define CONF_MIXER_TYPE			"mixer_type"
+#define CONF_STATE_FILE			"state_file"
+#define CONF_USER			"user"
+#define CONF_DB_FILE			"db_file"
+#define CONF_LOG_LEVEL			"log_level"
+#define CONF_MIXER_CONTROL		"mixer_control"
+#define CONF_AUDIO_WRITE_SIZE		"audio_write_size"
+#define CONF_FS_CHARSET			"filesystem_charset"
+#define CONF_PASSWORD			"password"
+#define CONF_DEFAULT_PERMS		"default_permissions"
+#define CONF_AUDIO_BUFFER_SIZE		"audio_buffer_size"
+#define CONF_REPLAYGAIN			"replaygain"
+#define CONF_AUDIO_OUTPUT_FORMAT	"audio_output_format"
+#define CONF_HTTP_PROXY_HOST		"http_proxy_host"
+#define CONF_HTTP_PROXY_PORT		"http_proxy_port"
+#define CONF_HTTP_PROXY_USER		"http_proxy_user"
+#define CONF_HTTP_PROXY_PASSWORD	"http_proxy_password"
+#define CONF_REPLAYGAIN_PREAMP		"replaygain_preamp"
+#define CONF_ID3V1_ENCODING		"id3v1_encoding"
 
-#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 */
-char ** readConf(char * file);
-
-char ** getConf();
+typedef struct _ConfigParam {
+	char * value;
+	unsigned int line;
+	BlockParam * blockParams;
+	int numberOfBlockParams;
+} ConfigParam;
 
 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
diff --git a/src/directory.c b/src/directory.c
index b5c5ed965..85773489b 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -1053,7 +1053,8 @@ int readDirectoryDB() {
 					fsCharset = &(buffer[strlen(
 							DIRECTORY_FS_CHARSET)]);
 					if((tempCharset = 
-						getConf()[CONF_FS_CHARSET]) && 
+						getConfigParamValue(
+							CONF_FS_CHARSET)) && 
 						strcmp(fsCharset,tempCharset))
 					{
 						WARNING("Using \"%s\" for the "
diff --git a/src/inputStream_http.c b/src/inputStream_http.c
index 353285ebd..15768929f 100644
--- a/src/inputStream_http.c
+++ b/src/inputStream_http.c
@@ -47,6 +47,11 @@
 
 #define HTTP_REDIRECT_MAX    10
 
+static char * proxyHost = NULL;
+static int proxyPort = 0;
+static char * proxyUser = NULL;
+static char * proxyPassword = NULL;
+
 typedef struct _InputStreemHTTPData {
         char * host;
         char * path;
@@ -59,57 +64,73 @@ typedef struct _InputStreemHTTPData {
         int icyMetaint;
 	int prebuffer;
 	int icyOffset;
-	char * proxyHost;
-	int proxyPort;
 	char * proxyAuth;
 	char * httpAuth;
 } InputStreamHTTPData;
 
 void inputStream_initHttp() {
-	if(getConf()[CONF_HTTP_PROXY_HOST]) {
-		char * portStr = getConf()[CONF_HTTP_PROXY_PORT];
-		int port = 0;
-		char * test;
+	ConfigParam * param = getConfigParam(CONF_HTTP_PROXY_HOST);
+	char * test;
 
-		if(!portStr) {
-			ERROR("http_proxy_host specified but not the http_"
-				"proxy_port\n");
+	if(param) {
+		proxyHost = param->value;
+
+		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);
 		}
 
-		port = strtol(portStr, &test, 10);
-		if(port <= 0 || *test != '\0') {
-			ERROR("http_proxy_port \"%s\" is not a positive integer"
-				"\n", portStr);
+		proxyPort = strtol(param->value, &test, 10);
+		if(proxyPort <= 0 || *test != '\0') {
+			ERROR("%s \"%s\" is not a positive integer, line %i\n"
+				CONF_HTTP_PROXY_PORT, param->value, 
+				param->line);
 		}
 
-		if(getConf()[CONF_HTTP_PROXY_USER] && 
-			!getConf()[CONF_HTTP_PROXY_PASSWORD])
-		{
-			ERROR("http_proxy_user specified, but not http_proxy_"
-				"password\n");
-			exit(EXIT_FAILURE);
+		param = getConfigParam(CONF_HTTP_PROXY_USER);
+
+		if(param) {
+			proxyUser = param->value;
+		
+			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] && 
-			!getConf()[CONF_HTTP_PROXY_USER])
-		{
-			ERROR("http proxy password specified, but not http "
-					"proxy user\n");
+		param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
+
+		if(param) {
+			ERROR("%s specifid but not %s\n",
+				CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_USER);
 			exit(EXIT_FAILURE);
 		}
 	}
-	else if(getConf()[CONF_HTTP_PROXY_PORT]) {
-		ERROR("http_proxy_port specified but not http_proxy_host\n");
+	else if((param = getConfigParam(CONF_HTTP_PROXY_PORT))) {
+		ERROR("%s specified but not %s, line %i\n", 
+				CONF_HTTP_PROXY_PORT, CONF_HTTP_PROXY_HOST,
+				param->line);
 		exit(EXIT_FAILURE);
 	}
-	else if(getConf()[CONF_HTTP_PROXY_USER]) {
-		ERROR("http_proxy_user specified but not http_proxy_host\n");
+	else if((param = getConfigParam(CONF_HTTP_PROXY_USER))) {
+		ERROR("%s specified but not %s, line %i\n", 
+				CONF_HTTP_PROXY_USER, CONF_HTTP_PROXY_HOST,
+				param->line);
 		exit(EXIT_FAILURE);
 	}
-	else if(getConf()[CONF_HTTP_PROXY_PASSWORD]) {
-		ERROR("http_proxy_password specified but not http_proxy_host"
-				"\n");
+	else if((param = getConfigParam(CONF_HTTP_PROXY_PASSWORD))) {
+		ERROR("%s specified but not %s, line %i\n", 
+				CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_HOST,
+				param->line);
 		exit(EXIT_FAILURE);
 	}
 }
@@ -188,19 +209,10 @@ static char * authString(char * header, char * user, char * password) {
 static InputStreamHTTPData * newInputStreamHTTPData() {
         InputStreamHTTPData * ret = malloc(sizeof(InputStreamHTTPData));
 
-	if(getConf()[CONF_HTTP_PROXY_HOST]) {
-		ret->proxyHost = getConf()[CONF_HTTP_PROXY_HOST];
-		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;
+	if(proxyHost) {
+		ret->proxyAuth = proxyAuthString(proxyUser, proxyPassword);
 	}
+	else ret->proxyAuth = NULL;
 
 	ret->httpAuth = NULL;
 	ret->host = NULL;
@@ -299,7 +311,7 @@ static int parseUrl(InputStreamHTTPData * data, char * url) {
         }
 
         /* fetch the path */
-	if(data->proxyHost) data->path = strdup(url);
+	if(proxyHost) data->path = strdup(url);
         else data->path = strdup(slash ? slash : "/");
 
         return 0;
@@ -319,9 +331,9 @@ static int initHTTPConnection(InputStream * inStream) {
         struct sockaddr_in6 sin6;
 #endif
 
-	if(data->proxyHost) {
-		connHost = data->proxyHost;
-		connPort = data->proxyPort;
+	if(proxyHost) {
+		connHost = proxyHost;
+		connPort = proxyPort;
 	}
 	else {
 		connHost = data->host;
diff --git a/src/interface.c b/src/interface.c
index 196ff7706..4282b89be 100644
--- a/src/interface.c
+++ b/src/interface.c
@@ -47,12 +47,18 @@
 #define INTERFACE_LIST_MODE_BEGIN		"command_list_begin"
 #define INTERFACE_LIST_OK_MODE_BEGIN		"command_list_ok_begin"
 #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;
-int interface_timeout;
-unsigned long long interface_max_command_list_size;
-unsigned long long interface_max_output_buffer_size;
+static int interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT;
+static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT;
+static size_t interface_max_command_list_size = 
+		INTERFACE_MAX_COMMAND_LIST_DEFAULT;
+static size_t interface_max_output_buffer_size =
+		INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT;
 
 typedef struct _Interface {
 	char buffer[INTERFACE_MAX_BUFFER_LENGTH+2];
@@ -420,33 +426,58 @@ int doIOForInterfaces() {
 void initInterfaces() {
 	int i;
 	char * test;
+	ConfigParam * param;
 
-	interface_timeout = strtol((getConf())[CONF_CONNECTION_TIMEOUT],&test,10);
-	if(*test!='\0' || interface_timeout<=0) {
-		ERROR("connection timeout \"%s\" is not a positive integer\n",(getConf())[CONF_CONNECTION_TIMEOUT]);
-		exit(EXIT_FAILURE);
+	param = getConfigParam(CONF_CONN_TIMEOUT);
+
+	if(param) {
+		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);
-	if(*test!='\0' || interface_max_connections<=0) {
-		ERROR("max connections \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_CONNECTIONS]);
-		exit(EXIT_FAILURE);
+	param = getConfigParam(CONF_MAX_CONN);
+
+	if(param) {
+		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);
-	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]);
-		exit(EXIT_FAILURE);
+	param = getConfigParam(CONF_MAX_COMMAND_LIST_SIZE);
+
+	if(param) {
+		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);
-	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);
-	}
+	param = getConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE);
 
-	interface_max_command_list_size*=1024;
-	interface_max_output_buffer_size*=1024;
+	if(param) {
+		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);
 
diff --git a/src/list.c b/src/list.c
index 68ec8d9c3..8faa271c0 100644
--- a/src/list.c
+++ b/src/list.c
@@ -192,7 +192,7 @@ int findInList(List * list,char * key,void ** data) {
 			tmpNode = list->nodesArray[cur];
 			cmp = strcmp(tmpNode->key,key);
 			if(cmp==0) {
-				(*data) = tmpNode->data;
+				if(data) *data = tmpNode->data;
 				return 1;
 			}
 			else if(cmp>0) high = cur;
diff --git a/src/list.h b/src/list.h
index 7b08e7e51..9c879e91a 100644
--- a/src/list.h
+++ b/src/list.h
@@ -88,6 +88,7 @@ void deleteNodeFromList(List * list,ListNode * node);
  * _key_ -> which node is being searched for
  * _data_ -> a pointer to where data will be placed, 
  *	_data_ memory should not by allocated or freed
+ *      _data_ can be NULL
  * returns 1 if successful, 0 otherwise
  */
 int findInList(List * list, char * key, void ** data);
diff --git a/src/listen.c b/src/listen.c
index 49ff4c33e..065e1ccc6 100644
--- a/src/listen.c
+++ b/src/listen.c
@@ -44,6 +44,7 @@
 int listenSocket;
 
 int establish(unsigned short port) {
+        ConfigParam * param;
 	int allowReuse = ALLOW_REUSE;
 	int sock;
 	struct sockaddr * addrp;
@@ -60,8 +61,10 @@ int establish(unsigned short port) {
 	memset(&sin, 0, sizeof(struct sockaddr_in));
 	sin.sin_port = htons(port);
 	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
 		if(ipv6Supported()) {
 			sin6.sin6_addr = in6addr_any;
@@ -78,9 +81,9 @@ int establish(unsigned short port) {
 	}
 	else {
 		struct hostent * he;
-		if(!(he = gethostbyname((getConf())[CONF_BIND_TO_ADDRESS]))) {
-			ERROR("can't lookup host \"%s\"\n",
-					(getConf())[CONF_BIND_TO_ADDRESS]);
+		if(!(he = gethostbyname(param->value))) {
+			ERROR("can't lookup host \"%s\" at line %i\n",
+                                        param->value, param->line);
 			exit(EXIT_FAILURE);
 		}
 		switch(he->h_addrtype) {
@@ -88,8 +91,8 @@ int establish(unsigned short port) {
 		case AF_INET6:
 			if(!ipv6Supported()) {
 				ERROR("no IPv6 support, but a IPv6 address "
-					"found for \"%s\"\n",
-					(getConf())[CONF_BIND_TO_ADDRESS]);
+					"found for \"%s\" at line %i\n",
+					param->value, param->line);
 				exit(EXIT_FAILURE);
 			}
 			bcopy((char *)he->h_addr,(char *)
@@ -105,8 +108,9 @@ int establish(unsigned short port) {
 			addrlen = sizeof(struct sockaddr_in);
 			break;
 		default:
-			ERROR("address type for \"%s\" is not IPv4 or IPv6\n",
-					(getConf())[CONF_BIND_TO_ADDRESS]);
+			ERROR("address type for \"%s\" is not IPv4 or IPv6 "
+                                        "at line %i\n",
+					param->value, param->line);
 			exit(EXIT_FAILURE);
 		}
 	}
diff --git a/src/log.c b/src/log.c
index 835fa9e00..964b8aa66 100644
--- a/src/log.c
+++ b/src/log.c
@@ -32,16 +32,24 @@ short warningFlushed = 0;
 static char * warningBuffer = NULL;
 
 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;
 	}
-	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;
 	}
-	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;
 	}
-	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
diff --git a/src/main.c b/src/main.c
index ddde281a7..f56d74939 100644
--- a/src/main.c
+++ b/src/main.c
@@ -165,9 +165,12 @@ void parseOptions(int argc, char ** argv, Options * options) {
                 return;
         }
         else if(argcLeft<=2) {
-                char ** conf = NULL;
-                if(argcLeft==2) conf = readConf(argv[argc-1]);
-                if(argcLeft==1) {
+                int conf = 0;
+                if(argcLeft==2) {
+			readConf(argv[argc-1]);
+			conf = 1;
+		}
+                else if(argcLeft==1) {
                         FILE * fp;
                         char * homedir = getenv("HOME");
                         char userfile[MAXPATHLEN+1] = "";
@@ -179,23 +182,27 @@ void parseOptions(int argc, char ** argv, Options * options) {
                         }
                         if(strlen(userfile) && (fp=fopen(userfile,"r"))) {
                                 fclose(fp);
-                                conf = readConf(userfile);
+                                readConf(userfile);
+				conf = 1;
                         }
                         else if((fp=fopen(SYSTEM_CONFIG_FILE_LOCATION,"r"))) {
                                 fclose(fp);
-                                conf = readConf(SYSTEM_CONFIG_FILE_LOCATION);
+                                readConf(SYSTEM_CONFIG_FILE_LOCATION);
+				conf = 1;
                         }
                 }
                 if(conf) {
-                        options->portStr = conf[CONF_PORT];
-                        options->musicDirArg = conf[CONF_MUSIC_DIRECTORY];
-                        options->playlistDirArg = conf[CONF_PLAYLIST_DIRECTORY];
-                        options->logFile = conf[CONF_LOG_FILE];
-                        options->errorFile = conf[CONF_ERROR_FILE];
-                        options->usr = conf[CONF_USER];
-                        if(conf[CONF_DB_FILE]) {
-                                options->dbFile = conf[CONF_DB_FILE];
-                        }
+                        options->portStr = forceAndGetConfigParamValue(
+					CONF_PORT);
+                        options->musicDirArg = 
+				parseConfigFilePath(CONF_MUSIC_DIR, 1);
+                        options->playlistDirArg = 
+				parseConfigFilePath(CONF_PLAYLIST_DIR, 1);
+                        options->logFile = parseConfigFilePath(CONF_LOG_FILE,1);
+                        options->errorFile = 
+				parseConfigFilePath(CONF_ERROR_FILE, 1);
+                        options->usr = parseConfigFilePath(CONF_USER, 0);
+                        options->dbFile = parseConfigFilePath(CONF_DB_FILE, 0);
                         return;
                 }
         }
diff --git a/src/path.c b/src/path.c
index 48d5eff09..1d599bda3 100644
--- a/src/path.c
+++ b/src/path.c
@@ -114,6 +114,7 @@ void initPaths(char * playlistDirArg, char * musicDirArg) {
 	char * charset = NULL;
 	char * originalLocale;
         struct stat st;
+        ConfigParam * param;
 
         playlistDir = prependCwdToPathDup(playlistDirArg);
         if((stat(playlistDir,&st))<0) {
@@ -135,8 +136,10 @@ void initPaths(char * playlistDirArg, char * musicDirArg) {
                 exit(EXIT_FAILURE);
         }
 
-	if(getConf()[CONF_FS_CHARSET]) {
-		charset = strdup(getConf()[CONF_FS_CHARSET]);
+        param = getConfigParam(CONF_FS_CHARSET);
+
+	if(param) {
+		charset = strdup(param->value);
 	}
 #ifdef HAVE_LOCALE
 #ifdef HAVE_LANGINFO_CODESET
@@ -296,5 +299,3 @@ char * prependCwdToPathDup(char * path) {
 
         return realloc(ret,len+1);
 }
-
-/* vim:set shiftwidth=4 tabstop=8 expandtab: */
diff --git a/src/permission.c b/src/permission.c
index e9e74ad7a..795fe577d 100644
--- a/src/permission.c
+++ b/src/permission.c
@@ -69,56 +69,53 @@ unsigned int parsePermissions(char * string) {
 }
 
 void initPermissions() {
-	char * passwordSets;
-	char * nextSet;
 	char * temp;
-	char * cp1;
 	char * cp2;
 	char * password;
 	unsigned int * permission;
+        ConfigParam * param;
 
 	permission_passwords = makeList(free);
 
 	permission_default = PERMISSION_READ | PERMISSION_ADD | 
 				PERMISSION_CONTROL | PERMISSION_ADMIN;
 
-	if(getConf()[CONF_DEFAULT_PERMISSIONS]) {
-		permission_default = parsePermissions(
-				getConf()[CONF_DEFAULT_PERMISSIONS]);
-	}
+        param = getNextConfigParam(CONF_PASSWORD, NULL);
 
-	if(!getConf()[CONF_PASSWORD]) return;
+        if(param) {
+	        permission_default = 0;
 
-	if(!getConf()[CONF_DEFAULT_PERMISSIONS]) permission_default = 0;
-
-	passwordSets = strdup(getConf()[CONF_PASSWORD]);
-
-	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",
+                do {
+		        if(!strstr(param->value, PERMISSION_PASSWORD_CHAR)) {
+			        ERROR("\"%s\" not found in password string "
+                                        "\"%s\", line %i\n",
 					PERMISSION_PASSWORD_CHAR,
-					nextSet);
-			exit(EXIT_FAILURE);
-		}
+					param->value,
+                                        param->line);
+			        exit(EXIT_FAILURE);
+		        }
 
-		if(!(temp = strtok_r(nextSet,PERMISSION_PASSWORD_CHAR,&cp2))) {
-			ERROR("something weird just happend in permission.c\n");
-			exit(EXIT_FAILURE);
-		}
-		password = temp;
+		        if(!(temp = strtok_r(param->value,
+                                        PERMISSION_PASSWORD_CHAR,&cp2))) {
+			        ERROR("something weird just happend in permission.c\n");
+			        exit(EXIT_FAILURE);
+		        }
 
-		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);
-
-	free(passwordSets);
 }
 
 int getPermissionFromPassword(char * password, unsigned int * permission) {
diff --git a/src/playerData.c b/src/playerData.c
index 5804f306c..b851a99f9 100644
--- a/src/playerData.c
+++ b/src/playerData.c
@@ -30,23 +30,32 @@
 int buffered_before_play;
 int buffered_chunks;
 
+#define DEFAULT_BUFFER_SIZE		2048
+#define DEFAULT_BUFFER_BEFORE_PLAY	25
+
 PlayerData * playerData_pd;
 
 void initPlayerData() {
-	float perc;
+	float perc = DEFAULT_BUFFER_BEFORE_PLAY;
 	char * test;
 	int shmid;
 	int crossfade = 0;
-	size_t bufferSize;
+	size_t bufferSize = DEFAULT_BUFFER_SIZE;
 	size_t allocationSize;
 	OutputBuffer * buffer;
+	ConfigParam * param;
 
-	bufferSize = strtol(getConf()[CONF_BUFFER_SIZE],&test,10);
-	if(*test!='\0' || bufferSize<=0) {
-		ERROR("buffer size \"%s\" is not a positive integer\n",
-				getConf()[CONF_BUFFER_SIZE]);
-		exit(EXIT_FAILURE);
+	param = getConfigParam(CONF_AUDIO_BUFFER_SIZE);
+
+	if(param) {
+		bufferSize = strtol(param->value, &test, 10);
+		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;
 
 	buffered_chunks = bufferSize/CHUNK_SIZE;
@@ -56,13 +65,18 @@ void initPlayerData() {
 		exit(EXIT_FAILURE);
 	}
 
-	perc = strtod((getConf())[CONF_BUFFER_BEFORE_PLAY],&test);
-	if(*test!='%' || perc<0 || perc>100) {
-		ERROR("buffered before play \"%s\" is not a positive "
-				"percentage and less than 100 percent\n",
-				(getConf())[CONF_BUFFER_BEFORE_PLAY]);
-		exit(EXIT_FAILURE);
+	param = getConfigParam(CONF_BUFFER_BEFORE_PLAY);
+
+	if(param) {
+		perc = strtod(param->value, &test);
+		if(*test!='%' || perc<0 || perc>100) {
+			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;
 	if(buffered_before_play>buffered_chunks) {
 		buffered_before_play = buffered_chunks;
diff --git a/src/playlist.c b/src/playlist.c
index fd1873f93..74bb56116 100644
--- a/src/playlist.c
+++ b/src/playlist.c
@@ -60,6 +60,9 @@
 
 #define PLAYLIST_HASH_MULT	4
 
+#define DEFAULT_PLAYLIST_MAX_LENGTH		(1024*16)
+#define DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS	0
+
 typedef struct _Playlist {
 	Song ** songs;
 	/* holds version a song was modified on */
@@ -77,13 +80,13 @@ typedef struct _Playlist {
 
 static Playlist playlist;
 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_errorCount = 0;
 static int playlist_queueError;
 static int playlist_noGoToNext = 0;
 
-static int playlist_saveAbsolutePaths;
+static int playlist_saveAbsolutePaths = DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS;
 
 static char * playlist_stateFile = NULL;
 
@@ -128,6 +131,7 @@ static void incrPlaylistCurrent() {
 void initPlaylist() {
 	char * test;
 	int i;
+	ConfigParam * param;
 
 	playlist.length = 0;
 	playlist.repeat = 0;
@@ -136,26 +140,32 @@ void initPlaylist() {
 	playlist.queued = -1;
         playlist.current = -1;
 
-	playlist_max_length = strtol((getConf())[CONF_MAX_PLAYLIST_LENGTH],&test,10);
-	if(*test!='\0') {
-		ERROR("max playlist length \"%s\" is not an integer\n",
-				(getConf())[CONF_MAX_PLAYLIST_LENGTH]);
-		exit(EXIT_FAILURE);
+	param = getConfigParam(CONF_MAX_PLAYLIST_LENGTH);
+
+	if(param) {
+		playlist_max_length = strtol(param->value, &test, 10);
+		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])
-			==0) {
-		playlist_saveAbsolutePaths = 1;
-	}
-	else if(strcmp("no",(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS])
-			==0) {
-		playlist_saveAbsolutePaths = 0;
-	}
-	else {
-		ERROR("save_absolute_paths_in_playlist \"%s\" is not yes or "
-			"no\n",
-			(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS]);
-		exit(EXIT_FAILURE);
+	param = getConfigParam(CONF_SAVE_ABSOLUTE_PATHS);
+
+	if(param) {
+		if(0 == strcmp("yes", param->value) ) {
+			playlist_saveAbsolutePaths = 1;
+		}
+		else if(0 == strcmp("no", param->value) ) {
+			playlist_saveAbsolutePaths = 0;
+		}
+		else {
+			ERROR("%s \"%s\" is not yes or no, line %i"
+				CONF_SAVE_ABSOLUTE_PATHS,
+				param->value, param->line);
+			exit(EXIT_FAILURE);
+		}
 	}
 
 	playlist.songs = malloc(sizeof(Song *)*playlist_max_length);
@@ -169,9 +179,7 @@ void initPlaylist() {
 
 	srand(time(NULL));
 
-	if(getConf()[CONF_STATE_FILE]) {
-		playlist_stateFile = getConf()[CONF_STATE_FILE];
-	}
+	playlist_stateFile = getConfigParamValue(CONF_STATE_FILE);
 
 	for(i=0; i<playlist_max_length*PLAYLIST_HASH_MULT; i++) {
 		playlist.idToPosition[i] = -1;
diff --git a/src/replayGain.c b/src/replayGain.c
index dbd09aa36..4788d7d95 100644
--- a/src/replayGain.c
+++ b/src/replayGain.c
@@ -32,34 +32,38 @@ static int replayGainState = REPLAYGAIN_OFF;
 static float replayGainPreamp = 1.0;
 
 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;
 	}
-	else if(strcmp(getConf()[CONF_REPLAYGAIN],"album")==0) {
+	else if(strcmp(param->value, "album") == 0) {
 		replayGainState = REPLAYGAIN_ALBUM;
 	}
 	else {
-		ERROR("replaygain value \"%s\" is invalid\n",
-				getConf()[CONF_REPLAYGAIN]);
+		ERROR("replaygain value \"%s\" at line %i is invalid\n",
+				param->value, param->line);
 		exit(EXIT_FAILURE);
 	}
 
-	if(getConf()[CONF_REPLAYGAIN_PREAMP]) {
+	param = getConfigParam(CONF_REPLAYGAIN_PREAMP);
+
+	if(param) {
 		char * test;
-		float f = strtod(getConf()[CONF_REPLAYGAIN_PREAMP], &test);
+		float f = strtod(param->value, &test);
 
 		if(*test != '\0') {
-			ERROR("Replaygain preamp \"%s\" is not a number\n",
-					getConf()[CONF_REPLAYGAIN_PREAMP]);
+			ERROR("Replaygain preamp \"%s\" is not a number at "
+					"line %i\n", param->value, param->line);
 			exit(EXIT_FAILURE);
 		}
 
 		if(f < -15 || f > 15) {
 			ERROR("Replaygain preamp \"%s\" is not between -15 and"
-					"15\n", 
-					getConf()[CONF_REPLAYGAIN_PREAMP]);
+					"15 at line %i\n", 
+					param->value, param->line);
 			exit(EXIT_FAILURE);
 		}
 
diff --git a/src/tag.c b/src/tag.c
index 08b620289..b5c71c500 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -93,18 +93,6 @@ char * getID3Info(struct id3_tag * tag, char * id) {
 	utf8 = id3_ucs4_utf8duplicate(ucs4);
 	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;
 }
 #endif
diff --git a/src/volume.c b/src/volume.c
index fa2f8aaa9..cd48f76f4 100644
--- a/src/volume.c
+++ b/src/volume.c
@@ -45,8 +45,21 @@
 #define VOLUME_MIXER_ALSA_DEFAULT		"default"
 #define VOLUME_MIXER_ALSA_CONTROL_DEFAULT	"Master"
 
-int volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
-char * volume_mixerDevice;
+#ifndef NO_OSS_MIXER
+#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;
 
@@ -66,13 +79,16 @@ int volume_alsaSet = -1;
 #ifndef NO_OSS_MIXER
 int prepOssMixer(char * device) {
 	int devmask = 0;
+        ConfigParam * param;
 
 	if((volume_ossFd = open(device,O_RDONLY))<0) {
 		WARNING("unable to open oss mixer \"%s\"\n",device);
 		return -1;
 	}
 
-	if(getConf()[CONF_MIXER_CONTROL]) {
+        param = getConfigParam(CONF_MIXER_CONTROL);
+
+	if(param) {
 		char * labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
 		char * dup;
 		int i,j;
@@ -88,7 +104,7 @@ int prepOssMixer(char * device) {
 			/* eliminate spaces at the end */
 			j = strlen(dup)-1;
 			while(j>=0 && dup[j]==' ') dup[j--] = '\0';
-			if(strcasecmp(dup,getConf()[CONF_MIXER_CONTROL])==0) {
+			if(strcasecmp(dup, param->value)==0) {
 				free(dup);
 				break;
 			}
@@ -96,14 +112,14 @@ int prepOssMixer(char * device) {
 		}
 
 		if(i>=SOUND_MIXER_NRDEVICES) {
-			WARNING("mixer control \"%s\" not found\n",
-					getConf()[CONF_MIXER_CONTROL]);
+			WARNING("mixer control \"%s\" not found at line %i\n",
+					        param->value, param->line);
 			close(volume_ossFd);
 			return -1;
 		}
 		else if(!( ( 1 << i ) & devmask )) {
-			WARNING("mixer control \"%s\" not usable\n",
-					getConf()[CONF_MIXER_CONTROL]);
+			WARNING("mixer control \"%s\" not usable at line %i\n",
+					        param->value, param->line);
 			close(volume_ossFd);
 			return -1;
 		}
@@ -173,6 +189,7 @@ int prepAlsaMixer(char * card) {
 	int err;
 	snd_mixer_elem_t * elem;
 	char * controlName = VOLUME_MIXER_ALSA_CONTROL_DEFAULT;
+        ConfigParam * param;
 
 	if((err = snd_mixer_open(&volume_alsaMixerHandle,0))<0) {
 		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);
-	if(getConf()[CONF_MIXER_CONTROL]) {
-		controlName = getConf()[CONF_MIXER_CONTROL];
+
+        param = getConfigParam(CONF_MIXER_CONTROL);
+
+	if(param) {
+		controlName = param->value;
 	}
 
 	while(elem) {
@@ -340,29 +360,37 @@ void finishVolume() {
 }
 
 void initVolume() {
-	if(0);
+        ConfigParam * param = getConfigParam(CONF_MIXER_TYPE);
+
+        if(param) {
+	        if(0);
 #ifdef HAVE_ALSA
-	else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_ALSA)==0) {
-		volume_mixerType = VOLUME_MIXER_TYPE_ALSA;
-		volume_mixerDevice = VOLUME_MIXER_ALSA_DEFAULT;
-	}
+		else if(strcmp(param->value, VOLUME_MIXER_ALSA)==0) {
+			volume_mixerType = VOLUME_MIXER_TYPE_ALSA;
+			volume_mixerDevice = VOLUME_MIXER_ALSA_DEFAULT;
+		}
 #endif
 #ifndef NO_OSS_MIXER
-	else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_OSS)==0) {
-		volume_mixerType = VOLUME_MIXER_TYPE_OSS;
-		volume_mixerDevice = VOLUME_MIXER_OSS_DEFAULT;
-	}
+		else if(strcmp(param->value, VOLUME_MIXER_OSS)==0) {
+			volume_mixerType = VOLUME_MIXER_TYPE_OSS;
+			volume_mixerDevice = VOLUME_MIXER_OSS_DEFAULT;
+		}
 #endif
-	else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_SOFTWARE)==0) {
-		volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
-		volume_mixerDevice = VOLUME_MIXER_SOFTWARE_DEFAULT;
+		else if(strcmp(param->value ,VOLUME_MIXER_SOFTWARE)==0) {
+			volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
+			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]);
-		exit(EXIT_FAILURE);
-	}
-	if(strlen((getConf())[CONF_MIXER_DEVICE])) {
-		volume_mixerDevice = (getConf())[CONF_MIXER_DEVICE];
+
+	param = getConfigParam(CONF_MIXER_DEVICE);
+	
+	if(param) {
+		volume_mixerDevice = param->value;
 	}
 }
 
@@ -431,4 +459,3 @@ int changeVolumeLevel(FILE * fp, int change, int rel) {
                 break;
 	}
 }
-/* vim:set shiftwidth=4 tabstop=8 expandtab: */