#!/bin/sh /etc/rc.common

START=99
STOP=02
USE_PROCD=1

PROG=/usr/sbin/obuspa
CONFIGURATION=obuspa

ENV_PROFILE="/root/.profile"
KEEP_FILE="/lib/upgrade/keep.d/obuspa"

RESET_FILE="/tmp/obuspa/fw_defaults"
SQL_DB_FILE="/tmp/obuspa/usp.db"
DB_DUMP="/tmp/obuspa/usp.dump_$(date +%s)"

BASEPATH=""
INSTANCE_COUNT=0

. /lib/functions/network.sh
. /usr/share/libubox/jshn.sh
. /etc/obuspa/usp_utils.sh

global_init()
{
	BASEPATH=""
	INSTANCE_COUNT=0
}

log()
{
	echo "$*"|logger -t obuspa.init -p debug
}

db_set_reset_file()
{
	local param value

	param="${1}"
	shift
	value="$*"

	if [ -n "${param}" ]; then
		echo "${param} \"${value}\"">>${RESET_FILE}
	else
		echo >>${RESET_FILE}
	fi
}

db_set_sql()
{
	local param value

	param="${1}"
	shift
	value="$*"

	if [ -n "${param}" ] && [ -n "${value}" ]; then
		if grep -q "${param} " ${DB_DUMP}; then
			value="${value//\//\\/}"
			sed -i "s/${param} .*/${param} \"${value}\"/g" ${DB_DUMP}
		else
			echo "${param} \"${value}\"" >> ${DB_DUMP}
		fi
	fi
}

db_set()
{
	# if sql db dump file present, update it
	if [ -f "${DB_DUMP}" ]; then
		db_set_sql "$@"
	else
		db_set_reset_file "$@"
	fi
}

dump_db()
{
	${PROG} -v0 -f ${SQL_DB_FILE} -c show database |grep "^Internal.\|^Device."|sed '{s/=> /"/g;s/$/"/g}' | sort  > ${DB_DUMP}
}

# if db present then check if it matches with existing instances
# fallback to max instance present + 1
# In case of no db get the count
get_base_path()
{
	local refpath value path count

	refpath="${1}"
	value="${2}"
	path=""
	count=0

	if [ -f "${DB_DUMP}" ]; then
		path=$(grep -E "${refpath}\d+.Alias \"${value}\"" ${DB_DUMP})
		path=${path%.*}
		if [ -z "${path}" ]; then
			path=$(grep -oE "${refpath}\d+" ${DB_DUMP} |sort -r|head -n 1)
			if [ -n "${path}" ]; then
				count=${path##*.}
				count=$(( count + 1 ))
			else
				count=1
			fi
			path="${refpath}${count}"
		fi
	fi

	if [ -z "${path}" ]; then
		INSTANCE_COUNT=$(( INSTANCE_COUNT + 1 ))
		path="${refpath}${INSTANCE_COUNT}"
	fi
	BASEPATH="${path}"
}

get_refrence_path()
{
	local dmref value path

	dmref="${1}"
	value="${2}"
	path=""

	if [ -f "${DB_DUMP}" ]; then
		path=$(grep -E "${dmref}\d+.Alias " ${DB_DUMP}|grep -w "${value}")
	elif [ -f "${RESET_FILE}" ]; then
		path=$(grep -E "${dmref}\d+.Alias " ${RESET_FILE}|grep -w "${value}")
	fi
	path=${path%.*}
	echo "${path}"
}

update_keep()
{
	file=${1}

	if [ -z "${file}" ]; then
		return;
	fi

	if [ ! -f "${KEEP_FILE}" ]; then
		touch "${KEEP_FILE}"
	fi

	if ! grep -q "${file}" ${KEEP_FILE}; then
		echo "${file}" >> ${KEEP_FILE}
	fi
}

validate_obuspa_section()
{
	uci_validate_section ${CONFIGURATION} obuspa "${1}" \
		'enabled:bool:1' \
		'trust_cert:file' \
		'client_cert:file' \
		'interface:string' \
		'ifname:string' \
		'prototrace:bool:0' \
		'log_level:uinteger' \
		'min_num_to_group:uinteger' \
		'max_group_sep:uinteger' \
		'max_cache_time:uinteger' \
		'ipc_timeout:uinteger' \
		'log_dest:string' \
		'db_file:string'
}

validate_localagent_section()
{
	uci_validate_section ${CONFIGURATION} localagent "${1}" \
		'EndpointID:string'
}

validate_controller_section()
{
	uci_validate_section ${CONFIGURATION} controller "${1}" \
		'Enable:bool:1' \
		'EndpointID:string' \
		'assigned_role_name:string' \
		'Protocol:or("STOMP","CoAP","MQTT", "WebSocket")' \
		'Destination:string' \
		'Topic:string' \
		'ParameterName:list(string)' \
		'mqtt:string' \
		'stomp:string' \
		'Host:string' \
		'Port:port' \
		'Path:string' \
		'EnableEncryption:bool' \
		'PeriodicNotifInterval:uinteger' \
		'SessionMode:string' \
		'ProvisioningCode:string'
}

validate_subscription_section()
{
	uci_validate_section ${CONFIGURATION} subscription "${1}" \
		'Enable:bool:1' \
		'NotifType:or("ValueChange","ObjectCreation","ObjectDeletion","OperationComplete","Event")' \
		'ReferenceList:list(string)' \
		'Recipient:string' \
		'controller:string'
}

validate_mtp_section()
{
	uci_validate_section ${CONFIGURATION} mtp "${1}" \
		'Enable:bool:1' \
		'Protocol:or("STOMP","CoAP","MQTT", "WebSocket")' \
		'ResponseTopicConfigured:string' \
		'Destination:string' \
		'Port:port' \
		'Path:string' \
		'mqtt:string' \
		'stomp:string' \
		'PublishQoS:uinteger' \
		'EnableEncryption:bool'
}

validate_stomp_connection_section()
{
	uci_validate_section ${CONFIGURATION} stomp "${1}" \
		'Enable:bool:1' \
		'Host:string' \
		'Port:port:61613' \
		'Username:string' \
		'Password:string' \
		'EnableEncryption:bool:1' \
		'EnableHeartbeats:bool:1' \
		'VirtualHost:string:/'
}

validate_mqtt_client_section()
{
	uci_validate_section ${CONFIGURATION} mqtt "${1}" \
		'Enable:bool:1' \
		'BrokerAddress:string' \
		'BrokerPort:port:1883' \
		'Username:string' \
		'Password:string' \
		'ProtocolVersion:or("3.1", "3.1.1","5.0"):5.0' \
		'TransportProtocol:or("TCP/IP","TLS"):TCP/IP' \
		'ClientID:string' \
		'RequestResponseInfo:bool:1'
}

validate_challenge_section()
{
	uci_validate_section ${CONFIGURATION} challenge "${1}" \
		'Enable:bool:1' \
		'Description:string' \
		'role_name:string' \
		'Role:string' \
		'Value:string' \
		'Retries:uinteger:3' \
		'LockoutPeriod:uinteger:0'
}

configure_localagent()
{
	local EndpointID

	validate_localagent_section "${1}" || {
		log "Validation of localagent section failed"
		return 0;
	}

	db_set Device.LocalAgent.EndpointID "${EndpointID}"
}

update_reset_reason()
{
	[ -f "/tmp/reset_reason" ] || return 0;

	if grep -qwi "defaultreset" /tmp/reset_reason; then
		db_set Internal.Reboot.Cause "FactoryReset"
	fi
}

update_dual_stack_pref()
{
	db_set Internal.DualStackPreference "${1}"
}

get_role_index()
{
	local name drole

	name="${1}"
	drole="Device.LocalAgent.ControllerTrust.Role.2"
	if [ -z "${name}" ]; then
		log "No role name provided, use Untrusted role index 2"
		echo "${drole}"
		return 0
	fi

	if [ "${name}" = "full_access" ] || [ "${name}" = "Full Access" ]; then
		echo "Device.LocalAgent.ControllerTrust.Role.1"
		return 0
	fi

	if [ "${name}" = "Untrusted" ]; then
		echo "Device.LocalAgent.ControllerTrust.Role.1"
		return 0
	fi

	# Get if from CTRUST file first if present, then from dbdump and then use default Untrusted role
	if [ -f "${CTRUST_RESET_FILE}" ]; then
		val="$(grep "Device.LocalAgent.ControllerTrust.Role.\d.Name" ${CTRUST_RESET_FILE} |grep $name)"
		val="$(echo ${val/.Name /,}|cut -d, -f 1)"
		echo "$val"
	elif [ -f "${DB_DUMP}" ]; then
		val="$(grep "Device.LocalAgent.ControllerTrust.Role.\d.Name" ${DB_DUMP} |grep $name)"
		val="$(echo ${val/.Name /,}|cut -d, -f 1)"
		echo "$val"
	else
		log "Not able to get role ${name}, use Untrusted role"
		echo "${drole}"
	fi
}

configure_controller()
{
	local EndpointID Enable 
	local Protocol Destination
	local Topic mqtt stomp assigned_role_name AssignedRole ParameterName ProvisioningCode
	local Host Port Path EnableEncryption PeriodicNotifInterval
	local dm_ref sec

	sec="${1}"
	validate_controller_section "${1}" || {
		log "Validation of controller section failed"
		return 1;
	}

	sec="${sec/controller_/cpe-}"
	get_base_path "Device.LocalAgent.Controller." "${sec}"
	if [ -z "${BASEPATH}" ]; then
		log "Failed to get path [$BASEPATH]"
		return 1;
	fi

	if [ -z "${Protocol}" ]; then
		log "controller:: Protocol cannot be empty"
		return 1;
	fi

	dm_ref=""
	if [ "${Protocol}" = "STOMP" ]; then
		stomp="${stomp/stomp_/cpe-}"
		dm_ref=$(get_refrence_path "Device.STOMP.Connection." "${stomp}")
	elif [ "${Protocol}" = "MQTT" ]; then
		mqtt="${mqtt/mqtt_/cpe-}"
		dm_ref=$(get_refrence_path "Device.MQTT.Client." "${mqtt}")
	fi

	db_set "${BASEPATH}.Alias" "${sec}"
	db_set "${BASEPATH}.Enable" "${Enable}"
	db_set "${BASEPATH}.EndpointID" "${EndpointID}"

	if [ -n "${ProvisioningCode}" ]; then
		db_set "${BASEPATH}.ProvisioningCode" "${ProvisioningCode}"
	fi

	if [ -n "${PeriodicNotifInterval}" ]; then
		db_set "${BASEPATH}.PeriodicNotifInterval" "${PeriodicNotifInterval}"
	fi

	if [ -n "${SessionMode}" ]; then
		db_set "${BASEPATH}.E2ESession.SessionMode" "${SessionMode}"
	fi

	if [ -n "${assigned_role_name}" ]; then
		AssignedRole=$(get_role_index "${assigned_role_name}")
		if [ -n "${AssignedRole}" ]; then
			db_set "${BASEPATH}.AssignedRole" "${AssignedRole}"
		fi
	fi

	db_set "${BASEPATH}.MTP.1.Alias" "${sec}"
	db_set "${BASEPATH}.MTP.1.Enable" "${Enable}"
	db_set "${BASEPATH}.MTP.1.Protocol" "${Protocol}"
	# only support configuration of one mtp path per controller using uci
	if [ "${Protocol}" = "MQTT" ]; then
		# Cleanup
		db_set "${BASEPATH}.MTP.1.WebSocket.Host" ""
		db_set "${BASEPATH}.MTP.1.WebSocket.Path" ""
		db_set "${BASEPATH}.MTP.1.STOMP.Reference" ""
		db_set "${BASEPATH}.MTP.1.STOMP.Destination" ""

		db_set "${BASEPATH}.MTP.1.MQTT.Reference" "${dm_ref}"
		db_set "${BASEPATH}.MTP.1.MQTT.Topic" "${Topic}"
	elif [ "${Protocol}" = "STOMP" ]; then
		# Cleanup
		db_set "${BASEPATH}.MTP.1.WebSocket.Host" ""
		db_set "${BASEPATH}.MTP.1.WebSocket.Path" ""
		db_set "${BASEPATH}.MTP.1.MQTT.Reference" ""
		db_set "${BASEPATH}.MTP.1.MQTT.Topic" ""

		db_set "${BASEPATH}.MTP.1.STOMP.Reference" "${dm_ref}"
		db_set "${BASEPATH}.MTP.1.STOMP.Destination" "${Destination}"
	elif [ "${Protocol}" = "CoAP" ]; then
		db_set "${BASEPATH}.MTP.1.CoAP.Host" "${Host}"
		db_set "${BASEPATH}.MTP.1.CoAP.Path" "${Path}"
		db_set "${BASEPATH}.MTP.1.CoAP.Port" "${Port}"
		db_set "${BASEPATH}.MTP.1.CoAP.EnableEncryption" "${EnableEncryption}"
	elif [ "${Protocol}" = "WebSocket" ]; then
		# Cleanup
		db_set "${BASEPATH}.MTP.1.STOMP.Reference" ""
		db_set "${BASEPATH}.MTP.1.STOMP.Destination" ""
		db_set "${BASEPATH}.MTP.1.MQTT.Reference" ""
		db_set "${BASEPATH}.MTP.1.MQTT.Topic" ""

		db_set "${BASEPATH}.MTP.1.WebSocket.Host" "${Host}"
		db_set "${BASEPATH}.MTP.1.WebSocket.Port" "${Port}"
		db_set "${BASEPATH}.MTP.1.WebSocket.Path" "${Path}"
		db_set "${BASEPATH}.MTP.1.WebSocket.EnableEncryption" "${EnableEncryption}"
	fi

	local param
	local _pnum=1

	for param in ${ParameterName}
	do
		db_set "${BASEPATH}.BootParameter.${_pnum}.Alias" "${sec}_boot_${_pnum}"
		db_set "${BASEPATH}.BootParameter.${_pnum}.Enable" "${Enable}"
		db_set "${BASEPATH}.BootParameter.${_pnum}.ParameterName" "${param}"
		_pnum=$(( _pnum + 1 ))
	done
}

configure_subscription()
{
	local Enable NotifType ReferenceList controller
	local dm_ref
	local sec

	sec="${1}"
	validate_subscription_section "${1}" || {
		log "Validation of subscription section failed"
		return 1;
	}

	sec="${sec/sub_/cpe-}"
	get_base_path "Device.LocalAgent.Subscription." "sub_${1}"
	if [ -z "${BASEPATH}" ]; then
		log "Failed to get path [$BASEPATH]"
		return 1;
	fi

	if [ -n "${controller}" ]; then
		controller="${controller/controller_/cpe-}"
		dm_ref=$(get_refrence_path "Device.LocalAgent.Controller." "${controller}")
	fi

	db_set "${BASEPATH}.Alias" "${sec}"
	db_set "${BASEPATH}.ID" "uci-${1}"
	db_set "${BASEPATH}.CreationDate" "$(date -I'seconds')"
	db_set "${BASEPATH}.Enable" "${Enable}"
	db_set "${BASEPATH}.NotifType" "${NotifType}"
	if [ -n "${ReferenceList}" ]; then
		ReferenceList=${ReferenceList// /,}
		db_set "${BASEPATH}.ReferenceList" "${ReferenceList}"
	fi
	db_set "${BASEPATH}.Persistent" "1"
	db_set "${BASEPATH}.Recipient" "${dm_ref}"
	# Entry updated in db, remove uci entry
	uci_remove obuspa "${1}"
}

configure_challenges()
{
	local Enable Description role_name Role Value Retries LockoutPeriod
	local sec

	sec="${1}"
	validate_challenge_section "${1}" || {
		log "Validation of challenge section failed"
	}

	sec="${sec/challenge_/cpe-}"
	get_base_path "Device.LocalAgent.ControllerTrust.Challenge." "${sec}"
	if [ -z "${BASEPATH}" ]; then
		log "Failed to get path [$BASEPATH]"
		return 1;
	fi

	if [ -z "${role_name}" ] && [ -z "${Role}" ]; then
		log "Either role_name or Role must defined for a challenge";
		return 1;
	fi

	db_set "${BASEPATH}.Alias" "${sec}"
	db_set "${BASEPATH}.Enable" "${Enable}"
	db_set "${BASEPATH}.Description" "${Description}"

	if [ -z "${Role}" ]; then
		Role=$(get_role_index "${role_name}")
	fi

	db_set "${BASEPATH}.Role" "${Role}"
	db_set "${BASEPATH}.Value" "${Value}"
	db_set "${BASEPATH}.Retries" "${Retries}"
	db_set "${BASEPATH}.LockoutPeriod" "${LockoutPeriod}"
	# Entry updated in db, remove uci entry
	uci_remove obuspa "${1}"
}

configure_mtp() {
	local Enable Protocol ResponseTopicConfigured
	local Path Port EnableEncryption PublishQoS
	local stomp mqtt dm_ref sec

	sec="${1}"
	validate_mtp_section "${1}" || {
		log "Validation of mtp section failed"
		return 1;
	}
	sec="${sec/mtp_/cpe-}"
	get_base_path "Device.LocalAgent.MTP." "${sec}"
	if [ -z "${BASEPATH}" ]; then
		log "Failed to get path [$BASEPATH]"
		return 1;
	fi

	if [ -z "${Protocol}" ]; then
		log "Protocol not defined for the mtp[${1}] section"
		return 1;
	fi

	dm_ref=""
	if [ "${Protocol}" = "STOMP" ]; then
		stomp="${stomp/stomp_/cpe-}"
		dm_ref=$(get_refrence_path "Device.STOMP.Connection." "${stomp}")
	elif [ "${Protocol}" = "MQTT" ]; then
		mqtt="${mqtt/mqtt_/cpe-}"
		dm_ref=$(get_refrence_path "Device.MQTT.Client." "${mqtt}")
	fi

	db_set "${BASEPATH}.Alias" "${sec}"
	db_set "${BASEPATH}.Enable" "${Enable}"
	db_set "${BASEPATH}.Protocol" "${Protocol}"
	if [ "${Protocol}" = "MQTT" ]; then
		# cleanup
		db_set "${BASEPATH}.WebSocket.Path" ""
		db_set "${BASEPATH}.STOMP.Reference" ""
		db_set "${BASEPATH}.STOMP.Destination" ""

		db_set "${BASEPATH}.MQTT.Reference" "${dm_ref}"
		db_set "${BASEPATH}.MQTT.ResponseTopicConfigured" "${ResponseTopicConfigured}"
		if [ -n "${PublishQoS}" ]; then
			db_set "${BASEPATH}.MQTT.PublishQoS" "${PublishQoS}"
		fi
	elif [ "${Protocol}" = "STOMP" ]; then
		# cleanup
		db_set "${BASEPATH}.WebSocket.Path" ""
		db_set "${BASEPATH}.MQTT.Reference" ""
		db_set "${BASEPATH}.MQTT.ResponseTopicConfigured" ""

		db_set "${BASEPATH}.STOMP.Reference" "${dm_ref}"
		db_set "${BASEPATH}.STOMP.Destination" "${Destination}"
	elif [ "${Protocol}" = "CoAP" ]; then
		db_set "${BASEPATH}.CoAP.Path" "${Path}"
		db_set "${BASEPATH}.CoAP.Port" "${Port}"
	elif [ "${Protocol}" = "WebSocket" ]; then
		# cleanup
		db_set "${BASEPATH}.MQTT.Reference" ""
		db_set "${BASEPATH}.MQTT.ResponseTopicConfigured" ""
		db_set "${BASEPATH}.STOMP.Reference" ""
		db_set "${BASEPATH}.STOMP.Destination" ""

		db_set "${BASEPATH}.WebSocket.Path" "${Path}"
		db_set "${BASEPATH}.WebSocket.Port" "${Port}"
		db_set "${BASEPATH}.WebSocket.EnableEncryption" "${EnableEncryption}"
	fi
}

configure_stomp_connection() {
	local Host Username Password Enable Port VirtualHost
	local EnableEncryption EnableHeartbeats
	local sec

	sec="${1}"
	validate_stomp_connection_section "${1}" || {
		log "Validation of stomp section failed"
		return 1;
	}

	sec="${sec/stomp_/cpe-}"
	get_base_path "Device.STOMP.Connection." "${sec}"
	if [ -z "${BASEPATH}" ]; then
		log "Failed to get path [$BASEPATH]"
		return 1;
	fi

	db_set "${BASEPATH}.Alias" "${sec}"
	db_set "${BASEPATH}.Host" "${Host}"
	db_set "${BASEPATH}.Username" "${Username}"
	db_set "${BASEPATH}.Password" "${Password}"

	db_set "${BASEPATH}.Enable" "${Enable}"
	db_set "${BASEPATH}.Port" "${Port}"
	db_set "${BASEPATH}.EnableEncryption" "${EnableEncryption}"
	db_set "${BASEPATH}.EnableHeartbeats" "${EnableHeartbeats}"
	db_set "${BASEPATH}.VirtualHost" "${VirtualHost}"
}

configure_mqtt_client() {
	local BrokerAddress BrokerPort Enable Username Password ProtocolVersion
	local TransportProtocol ClientID RequestResponseInfo
	local sec

	sec="${1}"
	validate_mqtt_client_section "${1}" || {
		log "Validation of mqtt section failed"
		return 1;
	}

	sec="${sec/mqtt_/cpe-}"
	get_base_path "Device.MQTT.Client." "${sec}"
	if [ -z "${BASEPATH}" ]; then
		log "Failed to get path [$BASEPATH]"
		return 1;
	fi

	db_set "${BASEPATH}.Alias" "${sec}"
	db_set "${BASEPATH}.Enable" "${Enable}"
	db_set "${BASEPATH}.BrokerAddress" "${BrokerAddress}"
	db_set "${BASEPATH}.BrokerPort" "${BrokerPort}"
	db_set "${BASEPATH}.Username" "${Username}"
	db_set "${BASEPATH}.Password" "${Password}"
	db_set "${BASEPATH}.ProtocolVersion" "${ProtocolVersion}"
	db_set "${BASEPATH}.TransportProtocol" "${TransportProtocol}"
	db_set "${BASEPATH}.ClientID" "${ClientID}"
	db_set "${BASEPATH}.RequestResponseInfo" "${RequestResponseInfo}"
}


configure_obuspa() {
	local enabled trust_cert ifname interface prototrace log_level db_file log_dest
	local client_cert

	validate_obuspa_section "global"

	if [ "${prototrace}" -eq 1 ]; then
		procd_append_param command -p
	fi

	if [ -n "${log_level}" ]; then
		procd_append_param command -v "${log_level}"
	fi

	if [ -n "${log_dest}" ]; then
		procd_append_param command -l "${log_dest}"
	fi

	if [ -n "${interface}" ]; then
		network_get_physdev ifname "${interface}"
	fi

	if [ -n "${ifname}" ]; then
		procd_set_param env USP_BOARD_IFNAME="${ifname}"
	fi

	if [ -z "${ifname}" ] || ! grep -F -q "export USP_BOARD_IFNAME=${ifname}" "${ENV_PROFILE}"; then
		if [ -f "${ENV_PROFILE}" ]; then
			sed -i "/export USP_BOARD_IFNAME/d" "${ENV_PROFILE}"
		fi

		if [ -n "${ifname}" ]; then
			# Set this variable for root user and obuspa -c tool
			echo "export USP_BOARD_IFNAME=${ifname}" >> "${ENV_PROFILE}"
		fi
	fi

	if [ -n "${db_file}" ]; then
		update_keep "${db_file}"
		procd_append_param command -f "${SQL_DB_FILE}"
	fi

	if [ -f "${RESET_FILE}" ]; then
		if [ -f "${SQL_DB_FILE}" ]; then
			mv ${SQL_DB_FILE} ${SQL_DB_FILE}.old
		fi
		procd_append_param command -r ${RESET_FILE}
	fi

	if [ -n "${trust_cert}" ]; then
		update_keep "${trust_cert}"
		if [ -f "${trust_cert}" ]; then
			procd_append_param command -t "${trust_cert}"
		fi
	fi

	if [ -n "${client_cert}" ]; then
		update_keep "${client_cert}"
		if [ -f "${client_cert}" ]; then
			procd_append_param command -a "${client_cert}"
		fi
	fi
}

get_instances_from_db_dump()
{
	local obj inst

	obj="${1}\d+"
	if [ ! -f "${DB_DUMP}" ]; then
		echo ""
		return 0;
	fi

	inst="$(grep -oE "${obj}" "${DB_DUMP}"|uniq)"
	echo "$inst"
}

get_param_value_from_dump()
{
	local param value

	param="${1}"

	if [ -z "${param}" ] || [ ! -f "${DB_DUMP}" ]; then
		log "error getting param"
		echo ""
		return 0
	fi

	value="$(grep "^${param} " ${DB_DUMP}|awk '{print $2}')"

	echo "${value//\"/}"
}

update_uci_sec()
{
	local sec tmp

	sec="${1}"
	stype="${2}"
	if [ -z "$sec" ] || [ -z "$stype" ]; then
		log "No section name, error"
		return 0
	fi

	tmp="$(uci_get obuspa "${sec}")"
	if [ "$tmp" != "$stype" ]; then
		uci_add obuspa "${stype}" "${sec}"
	fi
}

sync_db_controller()
{
	local cntrs copts sec pvalue protocol

	copts="Enable EndpointID PeriodicNotifInterval"
	popts="Destination Topic Host Port Path EnableEncryption"

	cntrs="$(get_instances_from_db_dump Device.LocalAgent.Controller.)"
	for cntr in $cntrs; do
		sec="$(get_param_value_from_dump "${cntr}".Alias)"
		sec="${sec/cpe-/controller_}"
		sec="${sec/-/_}"

		update_uci_sec "${sec}" controller
		for param in ${copts}; do
			pvalue="$(get_param_value_from_dump "${cntr}"."${param}")"
			uci_set obuspa "${sec}" "${param}" "${pvalue}"
		done
		uci_set obuspa "${sec}" "_sync" "1"

		protocol="$(get_param_value_from_dump "${cntr}".MTP.1.Protocol)"
		if [ -z "${protocol}" ]; then
			break;
		fi
		uci_set obuspa "${sec}" "Protocol" "${protocol}"
		for param in ${popts}; do
			pvalue="$(get_param_value_from_dump "${cntr}".MTP.1."${protocol}"."${param}")"
			uci_set obuspa "${sec}" "${param}" "${pvalue}"
		done
	done
}

sync_db_localagent_mtp()
{
	local mtps opts popts sec pvalue protocol

	opts="Enable"
	popts="ResponseTopicConfigured Destination Port Path EnableEncryption PublishQoS"

	mtps="$(get_instances_from_db_dump Device.LocalAgent.MTP.)"
	for inst in $mtps; do
		sec="$(get_param_value_from_dump "${inst}".Alias)"
		sec="${sec/cpe-/mtp_}"
		sec="${sec/-/_}"
		update_uci_sec "${sec}" mtp
		for param in ${opts}; do
			pvalue="$(get_param_value_from_dump "${inst}"."${param}")"
			uci_set obuspa "${sec}" "${param}" "${pvalue}"
		done
		uci_set obuspa "${sec}" "_sync" "1"

		protocol="$(get_param_value_from_dump "${inst}".Protocol)"
		if [ -z "${protocol}" ]; then
			break;
		fi
		uci_set obuspa "${sec}" "Protocol" "${protocol}"
		for param in ${popts}; do
			pvalue="$(get_param_value_from_dump "${inst}"."${protocol}"."${param}")"
			uci_set obuspa "${sec}" "${param}" "${pvalue}"
		done
	done
}


sync_db_mqtt_client()
{
	local mtps copts sec pvalue protocol

	opts="Enable BrokerAddress BrokerPort Username ProtocolVersion TransportProtocol ClientID"

	mtps="$(get_instances_from_db_dump Device.MQTT.Client.)"
	for inst in $mtps; do
		sec="$(get_param_value_from_dump "${inst}".Alias)"
		sec="${sec/cpe-/mqtt_}"
		sec="${sec/-/_}"
		update_uci_sec "${sec}" mqtt
		for param in ${opts}; do
			pvalue="$(get_param_value_from_dump "${inst}"."${param}")"
			uci_set obuspa "${sec}" "${param}" "${pvalue}"
		done
		uci_set obuspa "${sec}" "_sync" "1"
	done
}

sync_db_stomp_connection()
{
	local mtps copts sec pvalue protocol

	opts="Enable Host Port Username EnableEncryption EnableHeartbeats VirtualHost"

	mtps="$(get_instances_from_db_dump Device.STOMP.Connection.)"
	for inst in $mtps; do
		sec="$(get_param_value_from_dump "${inst}".Alias)"
		sec="${sec/cpe-/stomp_}"
		sec="${sec/-/_}"
		update_uci_sec "${sec}" stomp
		for param in ${opts}; do
			pvalue="$(get_param_value_from_dump "${inst}"."${param}")"
			uci_set obuspa "${sec}" "${param}" "${pvalue}"
		done
		uci_set obuspa "${sec}" "_sync" "1"
	done
}

sync_update_sec()
{
	local _sync
	config_get _sync "${1}" _sync ""
	if [ -z "${_sync}" ]; then
		uci_remove obuspa "${1}"
		log "Deleting obuspa.${1} section ..."
	else
		uci_remove obuspa "${1}" _sync
	fi
}

sync_uci_with_db()
{
	if [ ! -f "${DB_DUMP}" ]; then
		return 0;
	fi

	config_load obuspa
	sync_db_controller
	sync_db_localagent_mtp
	sync_db_mqtt_client
	sync_db_stomp_connection
	uci_commit obuspa

	config_load obuspa
	config_foreach sync_update_sec controller
	config_foreach sync_update_sec mtp
	config_foreach sync_update_sec mqtt
	config_foreach sync_update_sec stomp
	uci_commit obuspa
}

delete_sql_db_entry_with_pattern()
{
	local params pattern

	pattern="${1}"
	if [ ! -f "${DB_DUMP}" ]; then
		return 0;
	fi

	if [ "${#pattern}" -lt 7 ]; then
		return 0;
	fi

	#log "Deleting with pattern [${pattern}] from ${DB_DUMP}"
	sed -i "/${pattern}/d" ${DB_DUMP}
}

check_n_delete_db()
{
	local sec t r path

	sec="${1}"
	if uci -q get obuspa."${sec}" >/dev/null 2>&1; then
		return 0
	fi

	t="${2}"
	r="${3}"
	sec="${sec/${t}_/cpe-}"

	path=$(grep -E "${r}\d+.Alias \"${sec}\"" ${DB_DUMP})
	path=${path%.*}

	delete_sql_db_entry_with_pattern "${path}"
}

workaround_remove_download_pattern()
{
	local inst

	inst="$(cat ${DB_DUMP} |grep -E "Device.DeviceInfo.FirmwareImage.\d.Download()"|grep -oE "Device.LocalAgent.Request.\d.")"

	if [ -n "${inst}" ]; then
		log "Workaround to remove the old download Request [$inst]"
		delete_sql_db_entry_with_pattern "${inst}"
	fi
}

reverse_update_db_with_uci()
{
	if [ ! -f "${DB_DUMP}" ]; then
		return 0;
	fi

	export UCI_CONFIG_DIR="/tmp/obuspa"
	config_load obuspa
	config_foreach check_n_delete_db controller controller "Device.LocalAgent.Controller."
	config_foreach check_n_delete_db mtp mtp "Device.LocalAgent.MTP."
	config_foreach check_n_delete_db mqtt mqtt "Device.MQTT.Client."
	config_foreach check_n_delete_db stomp stomp "Device.STOMP.Connection."
	unset UCI_CONFIG_DIR
}

# Create factory reset file
db_init()
{
	local reason role_file

	reason="${1}"
	mkdir -p /tmp/obuspa/

	# Load configuration
	config_load $CONFIGURATION
	config_get SQL_DB_FILE global db_file "/tmp/obuspa/usp.db"
	config_get role_file global role_file ""

	if [ -f "${SQL_DB_FILE}.old" ] && [ ! -f "${SQL_DB_FILE}" ]; then
		log "Copying old db, since new db not present ..."
		mv ${SQL_DB_FILE}.old ${SQL_DB_FILE}
	fi

	# Dump datamodel parameters from DB
	if [ -f "${SQL_DB_FILE}" ]; then
		dump_db
	fi

	# In case of Reboot or service restart update the uci
        # from usp.db file
	if [ -f "${DB_DUMP}" ] && [ "${reason}" != "update" ]; then
		# Only do this if db have reasonable data
		val="$(awk 'END{print NR}' ${DB_DUMP})"
		if [ "$val" -gt 15 ]; then
			log "Syncing obuspa uci with usp.db ...."
			sync_uci_with_db
		fi
	fi

	# remove entries from db if deleted from uci, only in case of reload
	if [ -f "${DB_DUMP}" ] && [ "${reason}" = "update" ] && [ -f "/tmp/obuspa/obuspa" ]; then
		log "Deleting entries from usp.db if uci not present ...."
		reverse_update_db_with_uci
	fi

	# Remove reset file if present
	[ -f "${RESET_FILE}" ] && mv ${RESET_FILE} ${RESET_FILE}.old

	#log "Create reset file ...."
	config_load $CONFIGURATION
	config_get dualstack_pref global dualstack_pref "IPv6"

	global_init
	config_foreach configure_localagent localagent
	global_init
	config_foreach configure_stomp_connection stomp
	global_init
	config_foreach configure_mqtt_client mqtt
	global_init
	config_foreach configure_mtp mtp
	global_init
	config_foreach configure_controller controller
	global_init
	config_foreach configure_subscription subscription
	global_init
	config_foreach configure_challenges challenge

	update_reset_reason
	update_dual_stack_pref "${dualstack_pref}"

	uci_commit ${CONFIGURATION}

	cp /etc/config/obuspa /tmp/obuspa/
	if [ -f "${DB_DUMP}" ]; then
		workaround_remove_download_pattern
		mv ${DB_DUMP} ${RESET_FILE}
	fi

	if [ -f "${CTRUST_RESET_FILE}" ]; then
		cat ${CTRUST_RESET_FILE} >> ${RESET_FILE}
		rm ${CTRUST_RESET_FILE}
	fi
}

start_service() {
	local enabled

	mkdir -p /tmp/obuspa/
	config_load obuspa
	config_get_bool enabled global enabled 0

	procd_open_instance ${CONFIGURATION}
	if [ "${enabled}" -eq 1 ]; then
		db_init "${1}"
		procd_set_param command ${PROG}
		configure_obuspa
		procd_set_param respawn \
			"${respawn_threshold:-10}" \
			"${respawn_timeout:-10}" "${respawn_retry:-5}"
		#procd_set_param limits core="unlimited"
	fi
	procd_close_instance ${CONFIGURATION}
}

stop_service() {
	if command -v timeout >/dev/null 2>&1; then
		timeout 5 ${PROG} -c stop
	fi
}

reload_service() {
	stop
	start update
}

service_triggers() {
	procd_add_reload_trigger "obuspa"
}
