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:
		
							
								
								
									
										2
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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 | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
							
								
								
									
										107
									
								
								src/audio.c
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								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); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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)); | ||||
|   | ||||
							
								
								
									
										562
									
								
								src/conf.c
									
									
									
									
									
								
							
							
						
						
									
										562
									
								
								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; | ||||
| } | ||||
|   | ||||
							
								
								
									
										111
									
								
								src/conf.h
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								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 | ||||
|   | ||||
| @@ -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 " | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
							
								
								
									
										20
									
								
								src/listen.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								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); | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										16
									
								
								src/log.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								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 | ||||
|   | ||||
							
								
								
									
										35
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								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; | ||||
|                 } | ||||
|         } | ||||
|   | ||||
| @@ -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: */ | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
| 		} | ||||
|  | ||||
|   | ||||
							
								
								
									
										12
									
								
								src/tag.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								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 | ||||
|   | ||||
							
								
								
									
										85
									
								
								src/volume.c
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								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: */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Warren Dukes
					Warren Dukes