#!/bin/sh

. /lib/functions.sh
. /lib/logmngr/logrotate.sh

CONF_FILE=/etc/syslog-ng.conf
TMP_CONF_FILE=/tmp/syslog-ng/syslog-ng.conf

create_config_file() {
	mkdir -p /tmp/syslog-ng
	rm -f ${TMP_CONF_FILE}
	touch ${TMP_CONF_FILE}
}

create_option_section() {
	# the option section of the syslog-ng.conf file has hardcoded values,
	# no need to lookup any uci section to configure this section
	local syslog_version=$(syslog-ng -V | grep -i "Installer-Version" | awk -F': ' '{print $2}' | cut -d '.' -f1,2)

	if [ -n "$syslog_version" ]; then
		echo -e "@version: $syslog_version" >> ${TMP_CONF_FILE}
	else
		echo -e "@version: 4.7" >> ${TMP_CONF_FILE}
	fi

	echo -e '@include "scl.conf"' >> ${TMP_CONF_FILE}
	echo -e "options {" >> ${TMP_CONF_FILE}
	echo -e "\tchain_hostnames(no);" >> ${TMP_CONF_FILE}
	echo -e "\tcreate_dirs(yes);" >> ${TMP_CONF_FILE}
	echo -e "\tkeep_hostname(yes);" >> ${TMP_CONF_FILE}
	echo -e "\tlog_fifo_size(256);" >> ${TMP_CONF_FILE}
	echo -e "\tlog_msg_size(1024);" >> ${TMP_CONF_FILE}
	echo -e "\tstats(freq(0));" >> ${TMP_CONF_FILE}
	echo -e "\tflush_lines(0);" >> ${TMP_CONF_FILE}
	echo -e "\tuse_fqdn(no);" >> ${TMP_CONF_FILE}
	echo "};" >> ${TMP_CONF_FILE}

}

create_input_section() {
	local tag="$1"
	# the input in our case is always syslog, hence, this section of the
	# fluent-bit.conf file has hardcoded values as well that do not depend
	# on any uci value
	echo -e "source $tag {" >> ${TMP_CONF_FILE}
	echo -e "\tinternal();" >> ${TMP_CONF_FILE}
	echo -e "\tunix-dgram(\"/dev/log\");" >> ${TMP_CONF_FILE}
	echo -e "\tfile(\"/proc/kmsg\" program_override(\"kernel\"));" >> ${TMP_CONF_FILE}
	echo "};" >> ${TMP_CONF_FILE}
}

generate_facility_regex() {
	local facility_level=$1

	if [ "$facility_level" == "24" ]; then
		# value 24 means all facility level, which is as good as not
		# generating a filter section, so return
		return
	fi

	# facility_level is a list value, hence, generate regex for
	# each value
	IFS=" "
	for val in $facility_level; do
		echo -e "\tfacility($val);" >> ${TMP_CONF_FILE}
	done

}

generate_severity_regex() {
	local sev_level="$1"
	local sev_compare="$2"
	local sev_action="$3"

	if [ "$sev_compare" == "0" ]; then
		case $sev_level in
		"0") echo -e "\tlevel(emerg)" >> ${TMP_CONF_FILE}
		;;
		"1") echo -e "\tlevel(alert)" >> ${TMP_CONF_FILE}
		;;
		"2") echo -e "\tlevel(crit)" >> ${TMP_CONF_FILE}
		;;
		"3") echo -e "\tlevel(err)" >> ${TMP_CONF_FILE}
		;;
		"4") echo -e "\tlevel(warning)" >> ${TMP_CONF_FILE}
		;;
		"5") echo -e "\tlevel(notice)" >> ${TMP_CONF_FILE}
		;;
		"6") echo -e "\tlevel(info)" >> ${TMP_CONF_FILE}
		;;
		"7") echo -e "\tlevel(debug)" >> ${TMP_CONF_FILE}
		;;
		esac
	elif [ "$sev_compare" == "1" ]; then
		# generate regex for all severity value greater than or equal to
		# sev_level
		case $sev_level in
		"0") echo -e "\tlevel(emerg)" >> ${TMP_CONF_FILE}
		;;
		"1") echo -e "\tlevel(alert..emerg)" >> ${TMP_CONF_FILE}
		;;
		"2") echo -e "\tlevel(crit..emerg)" >> ${TMP_CONF_FILE}
		;;
		"3") echo -e "\tlevel(err..emerg)" >> ${TMP_CONF_FILE}
		;;
		"4") echo -e "\tlevel(warning..emerg)" >> ${TMP_CONF_FILE}
		;;
		"5") echo -e "\tlevel(notice..emerg)" >> ${TMP_CONF_FILE}
		;;
		"6") echo -e "\tlevel(info..emerg)" >> ${TMP_CONF_FILE}
		;;
		"7") echo -e "\tlevel(debug..emerg)" >> ${TMP_CONF_FILE}
		;;
		esac
	fi
}

handle_filter_conf() {
	local section="$1" # config filter
	local filter_name="$2"
	local name

	# no need to proceed if name of filter section is not one of the values
	# listed in option filter in config action section
	config_get name $section name
	if [ "$name" != "$filter_name" ]; then
		return
	fi
	echo -e "filter $name {" >> ${TMP_CONF_FILE}

	# as per data model, at a time either facility_level or severity_level can
	# be specified along with pattern_match. hence, first process and generate
	# regex for pattern_match which is common in both condition. Next, we will
	# process facility_level and return if facility level is defined and not
	# process severity related params at all.

	local pattern_match
	config_get pattern_match $section pattern_match
	if [ -n "$pattern_match" ]; then
		# the pattern here is in tag=>value pair, hence, break the pattern
		# and fill this filed
		local tag=$(echo $pattern_match | awk '{print $1}')
		local value=$(echo $pattern_match | awk '{print $2}')
		echo -e "\tmatch("$value" value("$tag"))" >> ${TMP_CONF_FILE}
	fi

	local facility_level
	config_get facility_level $section facility_level

	if [ -n "$facility_level" ]; then
		generate_facility_regex $facility_level
		# return from here since if facility_level is defined, then no
		# need to process severity_level
		echo "};" >> ${TMP_CONF_FILE}
		return
	fi

	local sev_level
	local sev_compare
	local sev_action
	config_get sev_level $section severity_level

	if [ -n "$sev_level" ]; then
		# value 1 of severity compare corresponds to data model
		# and system default which is EqualorHigher
		config_get sev_compare $section severity_compare 1
		# value 0 of severity action corresponds to data model
		# and system default that is log
		config_get sev_action $section severity_action 0

		generate_severity_regex $sev_level $sev_compare $sev_action
	fi
	echo "};" >> ${TMP_CONF_FILE}
}

handle_filter_ref() {
	local filter_name="$1"
	config_foreach handle_filter_conf filter "$filter_name"
}

handle_log_file() {
	local section="$1" # out_file section
	local match="$2"
	local filter="$3"
	local action_ref

	config_get action_ref $section action
	if [ "$action_ref" != "$match" ]; then
		return
	fi

	local enabled
	config_get enabled $section enable
	if [ "$enabled" == 0 ]; then
		return
	fi

	local file
	config_get file $section file
	if [ -z "$file" ]; then
		return
	fi


	echo -e "destination file_$match {" >> ${TMP_CONF_FILE}
	echo -e "\tfile("$file");" >> ${TMP_CONF_FILE}
	echo -e "};" >> ${TMP_CONF_FILE}

	# now generate the log section for each action section to bring into effect
	# the filter, destination, source sections create above
	echo -e "log {" >> ${TMP_CONF_FILE}
	echo -e "\tsource($tag);" >> ${TMP_CONF_FILE}
	if [ -n "$filter" ]; then
		IFS=" "
		for finst in $filter; do
			echo -e "\tfilter($finst);" >> ${TMP_CONF_FILE}
		done
	fi
	echo -e "\tdestination(file_$match);" >> ${TMP_CONF_FILE} # log_file
	echo -e "};" >> ${TMP_CONF_FILE} # close log section
}

handle_log_remote() {
	local section="$1"
	local match="$2"
	local filter="$3"
	local action_ref

	config_get action_ref $section action
	if [ "$action_ref" != "$match" ]; then
		return
	fi

	local enabled
	config_get enabled $section enable
	if [ "$enabled" == 0 ]; then
		return
	fi


	local address
	config_get address $section log_ip
	if [ -z "$address" ]; then
		return
	fi

	echo -e "destination remote_$match {" >> ${TMP_CONF_FILE}
	echo -e "\tsyslog(" >> ${TMP_CONF_FILE}
	echo -e "\t\t"$address"" >> ${TMP_CONF_FILE}

	local proto # holds value tcp or udp
	config_get proto $section proto
	if [ -n "$proto" ]; then
		echo -e "\t\ttransport($proto)" >> ${TMP_CONF_FILE}
	fi

	local port
	config_get port $section port
	if [ -n "$port" ]; then
		echo -e "\t\tport($port)" >> ${TMP_CONF_FILE}
	fi

	local cert
	local peer_verify
	config_get cert $section cert
	if [ -n "$cert" ]; then
		echo -e "\t\ttls(" >> ${TMP_CONF_FILE}
		echo -e "\t\t\tcert-file($cert)" >> ${TMP_CONF_FILE}

		config_get peer_verify $section peer_verify
		if [ "$peer_verify" == "1" ]; then
			echo -e "\t\t\tpeer-verify(required-trusted)" >> ${TMP_CONF_FILE}
		fi
		echo -e "\t\t)" >> ${TMP_CONF_FILE} # close tls section
	fi
	echo -e "\t);" >> ${TMP_CONF_FILE} # close syslog section
	echo -e "};" >> ${TMP_CONF_FILE} # close destination section

	# now generate the log section for each action section to bring into effect
	# the filter, destination, source sections create above
	echo -e "log {" >> ${TMP_CONF_FILE}
	echo -e "\tsource($tag);" >> ${TMP_CONF_FILE}
	if [ -n "$filter" ]; then
		IFS=" "
		for finst in $filter; do
			echo -e "\tfilter($finst);" >> ${TMP_CONF_FILE}
		done
	fi
	echo -e "\tdestination(remote_$match);" >> ${TMP_CONF_FILE} # log_file
	echo -e "};" >> ${TMP_CONF_FILE} # close log section
}

handle_action() {
	local section="$1"

	local filter
	config_get filter $section filter

	# use config action option name as tag for input
	local tag
	config_get tag $section name
	if [ -z "$tag" ]; then
		return
	fi

	create_input_section $tag
	if [ -n "$filter" ]; then
		IFS=" "
		for finst in $filter; do
			handle_filter_ref $finst
		done
	fi

	# handle output, each action can be associated with a out_log and out_syslog
	# section so figure out if any out_log or out_syslog section is associated
	# with this and action and setup output accordingly.
	config_foreach handle_log_file log_file "$tag" "$filter"
	config_foreach handle_log_remote log_remote "$tag" "$filter"
}

handle_action_section() {
	config_foreach handle_action action
}

apply_config_file() {
	echo -e '@include "/etc/syslog-ng.d/"' >> ${TMP_CONF_FILE}
	cp ${TMP_CONF_FILE} ${CONF_FILE}
}

logmngr_init() {
	create_config_file

	config_load logmngr
	local enabled
	config_get enabled globals enable

	if [ "$enabled" == "0" ]; then
		return
	fi

	create_option_section
	handle_action_section
	apply_config_file

	if [ -f /lib/logmngr/logrotate.sh ]; then
		logrotate_init
	fi

	if procd_running 'syslog-ng'; then
		/etc/init.d/syslog-ng reload
	else
		/etc/init.d/syslog-ng start
	fi
}
