# This file is part of shellfire core. It is subject to the licence terms in the COPYRIGHT file found in the top-level directory of this distribution and at https://raw.githubusercontent.com/shellfire-dev/core/master/COPYRIGHT. No part of shellfire core, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the COPYRIGHT file.
# Copyright © 2014-2015 The developers of shellfire core. See the COPYRIGHT file in the top-level directory of this distribution and at https://raw.githubusercontent.com/shellfire-dev/core/master/COPYRIGHT.


# Consider breaking this out
core_usesIn core path variable

core_configuration_blacklist()
{
	core_variable_array_append _core_configuration_blacklisted "$@"
}

# Rules taken from GNU rush
core_dependency_requires '*' ls
_core_configuration_validateConfigurationFileIsInsecurelyOwned()
{
	# We do not do checks for /usr/local/etc (as this can be user-owned in Homebrew) or /opt/etc
	if core_variable_doesNotStartWith "$actualPath" '/etc'; then
		return 1
	fi
	
	# We rely on ls as stat varies widely (GNU new vs GNU old vs BSD), and feature checking is painful
	# Example on MAC   -rw-r--r--@ 1 501  20  171202 11 Sep 08:48 miscellany/logo.key
	# Example on LINUX -rw-r--r-- 1 1000 1000 3637 Sep  8 08:37 .bashrc
	
	local permissions
	local links
	local uid
	local gid
	local size
	local garbageDateAndName
	IFS=' ' read -r permissions links uid gid size garbageDateAndName <<-EOF
		$(ls -a -l -L -n "$actualPath")
	EOF
	
	if [ $uid -ne 0 ]; then
		core_message WARN "Configuration file '$actualPath' is not owned by root; ignoring"
		return 0
	fi
	if [ $gid -ne 0 ]; then
		core_message WARN "Configuration file '$actualPath' is not in root's group; ignoring"
		return 0
	fi
	if core_variable_doesNotStartWith "$permissions" '-rw-r--r--'; then
		core_message WARN "Configuration file '$actualPath' has permissions that are not -rw-r--r--; ignoring"
		return 0
	fi
	
	local parentPath="$(core_compatibility_basename "$actualPath")"

	ls -a -l -L -n "$actualPath" | while IFS=' ' read -r permissions links uid gid size garbageDateAndName
	do
		if [ "$permissions" = 'total' ]; then
			continue
		fi
			if [ $uid -ne 0 ]; then
				core_message WARN "Configuration file '$actualPath' lives in a folder not owned by root; ignoring"
				return 0
			fi
			if [ $gid -ne 0 ]; then
				core_message WARN "Configuration file '$actualPath' lives in a folder not owned by root's group; ignoring"
				return 0
			fi
			if core_variable_doesNotStartWith "$permissions" '-rwxr-xr-x'; then
				core_message WARN "Configuration file '$actualPath' lives in a folder with permissions not set to '-rwxr-xr-x'; ignoring"
				return 0
			fi
		break
	done
	
	return 1
}

_core_configuration_load()
{
	local actualPath="$1"
	if [ ! -e "$actualPath" ]; then
		core_message INFO "Configuration file '$actualPath' does not exist; ignoring"
		return 0
	elif [ -f "$actualPath" ]; then
		if [ ! -r "$actualPath" ]; then
			core_message WARN "Configuration file '$actualPath' is not readable; ignoring"
			return 0
		fi
		if [ ! -s "$actualPath" ]; then
			core_message WARN "Configuration file '$actualPath' is empty; ignoring"
			return 0
		fi
		if [ -x "$actualPath" ]; then
			core_message WARN "Configuration file '$actualPath' is executable and should not be; ignoring"
			return 0
		fi
		
		if _core_configuration_validateConfigurationFileIsInsecurelyOwned; then
			return 0
		fi
		
		. "$actualPath" || core_exitError $core_commandLine_exitCode_OSFILE "Could not load '$actualPath'"
	elif [ -d "$actualPath" ]; then
		if [ ! -r "$actualPath" ]; then
			core_message WARN "Configuration folder '$actualPath' is not readable; ignoring"
			return 0
		fi
		if [ ! -x "$actualPath" ]; then
			core_message WARN "Configuration folder '$actualPath' is not searchable; ignoring"
			return 0
		fi
		
		local filePath
		pushd "$actualPath"
	
			set +f
				for filePath in *
				do
					set -f
					if [ ! -e "$filePath" ]; then
						continue
					fi
					_core_configuration_load "$filePath"
				done
			set -f
	
		popd
	else
		core_message WARN "Configuration path '$actualPath' resolves to neither a file or folder; ignoring"
		return 0
	fi
}

core_configuration_loadPath()
{
	local environmentVariable="$1"
	local folderOrFilePath="$2"
	
	if core_variable_isUnset "$environmentVariable"; then
		return 0
	fi
	
	if core_variable_array_isSet _core_configuration_blacklisted; then
		if core_variable_array_contains _core_configuration_blacklisted "$environmentVariable"; then
			core_message WARN "Configuration path '\$$environmentVariable/$folderOrFilePath' is blacklisted"
			return 0
		fi
	fi
	
	local core_variable_indirectValue_result
	core_variable_indirectValue "$environmentVariable"
	local parentPath="$core_variable_indirectValue_result"
	
	if [ -z "$folderOrFilePath" ]; then
		local actualPath="$parentPath"
	else
		local actualPath="$parentPath"/"$folderOrFilePath"
	fi

	if core_variable_array_contains _core_configuration_alreadyLoaded "$actualPath"; then
		return 0
	fi
	
	core_variable_array_append _core_configuration_alreadyLoaded "$actualPath"
	
	_core_configuration_load "$actualPath"
}

core_configuration_defaultsBlacklistedEnvironmentVariables=''
core_configuration_load()
{
	core_variable_array_initialise _core_configuration_blacklisted
	core_variable_array_initialise _core_configuration_alreadyLoaded
	
	core_configuration_loadPath _program_etcPath "${core_libraryName}"/rc
	core_configuration_loadPath _program_etcPath "${core_libraryName}"/rc.d
	
	core_configuration_loadPath _program_etcPath "${_program_namespace}"/rc
	core_configuration_loadPath _program_etcPath "${_program_namespace}"/rc.d
	
	core_configuration_loadPath HOME ."${core_libraryName}"/rc
	core_configuration_loadPath HOME ."${core_libraryName}"/rc.d
	
	core_configuration_loadPath ${core_libraryName}_RC ''
	core_configuration_loadPath ${core_libraryName}_RC_D ''
	
	core_configuration_loadPath HOME ."${_program_namespace}"/rc
	core_configuration_loadPath HOME ."${_program_namespace}"/rc.d
	
	core_configuration_loadPath ${_program_namespace}_RC ''
	core_configuration_loadPath ${_program_namespace}_RC_D ''
}

core_usesIn core compatibility
core_configuration_defaults()
{
	core_variable_setVariableIfUnset ${_program_namespace}_language $(core_init_language)
	core_variable_setVariableIfUnset ${_program_namespace}_verbose $(core_init_verbosity)
}
