#!/bin/bash

# 读取设置文件
function get_config(){
	while [[ "$*" != "" ]]; do
		eval ${1}='`uci get wechatpush.config.$1`' 2>/dev/null
		shift
	done
}

# 后台读取 json 中的变量
read_json() {
	local json_key="$1"
	local json_path="$2"
	local output_file="$output_dir/${json_key}"
	jq -r ."$json_key" "$json_path" > "$output_file" &
}

# 遍历输出目录，将文件内容保存到对应的变量
wait_and_cat() {
	[ $(ls -A "$output_dir" | wc -l) -eq 0 ] && return
	wait
	for file in "$output_dir"/*; do
		local variable_name=$(basename "$file")
		local variable_value=$(cat "$file")
		eval "${variable_name}='${variable_value}'"
	done
	rm "$output_dir"/*
}

# 初始化设置信息
function read_config(){
	get_config \
	"enable" "lite_enable" "device_name" "sleeptime" "oui_data" "reset_regularly" "debuglevel" \
	"jsonpath" "sckey" "corpid" "userid" "agentid" "corpsecret" "mediapath" "wxpusher_apptoken" "wxpusher_uids" "wxpusher_topicIds" "pushplus_token" "tg_token" "chat_id" \
	"get_ipv4_mode" "ipv4_interface" "get_ipv6_mode" "ipv6_interface" "auto_update_ip_list" \
	"device_notification" "cpu_notification" "cpu_load_threshold" "temperature_threshold" \
	"client_usage" "client_usage_max" "client_usage_disturb" "client_usage_whitelist" \
	"login_notification" "login_max_num" "login_web_black" "login_ip_black_timeout" "login_ip_white_list" "port_knocking_enable" "login_ip_white_timeout" "login_port_white" "login_port_forward_list" \
	"crontab_regular_time" "crontab_interval_time" \
	"do_not_disturb_mode" "do_not_disturb_starttime" "do_not_disturb_endtime" "up_down_push_whitelist" "up_down_push_blacklist" "up_down_push_interface" "mac_online_list" "mac_offline_list" "login_disturb" "login_notification_delay" "login_log_enable" \
	"up_timeout" "down_timeout" "timeout_retry_count" "only_timeout_push" "passive_mode" "thread_num" "soc_code" "server_host" "server_port" \
	"unattended_enable" "zerotier_helper" "unattended_only_on_disturb_time" "unattended_device_aliases" "network_disconnect_event" "unattended_autoreboot_mode" "autoreboot_system_uptime" "autoreboot_network_uptime" \
	"device_info_helper" "gateway_host_url" "gateway_info_url" "gateway_logout_url" "gateway_username_id" "gateway_password_id" "gateway_username" "gateway_password" "scan_ip_range" "device_info_helper_sleeptime"

	( echo "$device_notification"|grep -q "online" ) && notification_online="true"
	( echo "$device_notification"|grep -q "offline" ) && notification_offline="true"
	( echo "$cpu_notification"|grep -q "load" ) && notification_load="true"
	( echo "$cpu_notification"|grep -q "temp" ) && notification_temp="true"
	( echo "$login_notification"|grep -q "web_logged" ) && web_logged="true"
	( echo "$login_notification"|grep -q "ssh_logged" ) && ssh_logged="true"
	( echo "$login_notification"|grep -q "web_login_failed" ) && web_login_failed="true"
	( echo "$login_notification"|grep -q "ssh_login_failed" ) && ssh_login_failed="true"
	( echo "$device_info_helper"|grep -q "gateway_info" ) && gateway_info_enable="true"
	for str_version in "wrtbwmon" "iputils-arping" "curl" "iw"; do
		eval `echo ${str_version:0:2}"_version"`=`opkg list-installed|grep -w ^${str_version}|awk '{print $3}'` 2>/dev/null
	done
	( opkg list-installed|grep -w -q ^firewall4 ) && nftables_version="true"
	dir="/tmp/wechatpush/" && mkdir -p ${dir} && mkdir -p ${dir}/client
	tempjsonpath="${dir}temp.json"
	ip_blacklist_path="/usr/share/wechatpush/api/ip_blacklist"
	oui_base="${dir}oui_base.txt"
	debuglevel=`echo "$debuglevel"` && [ -z "$debuglevel" ] && logfile="/dev/null" || logfile="${dir}wechatpush.log"
	login_port_forward_list=`echo "$login_port_forward_list"|sed 's/ /\n/g'` 2>/dev/null
	up_down_push_blacklist=`echo "$up_down_push_blacklist"|sed 's/ /\n/g'` 2>/dev/null
	up_down_push_whitelist=`echo "$up_down_push_whitelist"|sed 's/ /\n/g'` 2>/dev/null
	device_aliases=`cat /usr/share/wechatpush/api/device_aliases.list` 2>/dev/null
	unattended_device_aliases=`echo "$unattended_device_aliases"|sed 's/ /\n/g'` 2>/dev/null
	client_usage_whitelist=`echo "$client_usage_whitelist"|sed 's/ /\n/g'` 2>/dev/null
	login_ip_white_list=`echo "$login_ip_white_list"|sed 's/ /\n/g'` 2>/dev/null
	mark_mac_list="${mac_online_list} ${mac_offline_list}"
	mark_mac_list=`echo "$mark_mac_list"|sed 's/ /\n/g'|sed 's/-/ /'` 2>/dev/null
	ipv4_urllist=`cat /usr/share/wechatpush/api/ipv4.list` 2>/dev/null
	ipv6_urllist=`cat /usr/share/wechatpush/api/ipv6.list` 2>/dev/null
	User_Agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.58"
	[ -z "$get_ipv4_mode" ] && get_ipv4_mode=0
	[ -z "$get_ipv6_mode" ] && get_ipv6_mode=0
	[ -z "$sleeptime" ] && sleeptime="60"
	[ -z "$login_ip_black_timeout" ] && login_ip_black_timeout="86400"
	[ -z "$login_ip_white_timeout" ] && login_ip_white_timeout="600"
	[ "$iw_version" ] && wlan_interface=`iw dev 2>/dev/null|grep Interface|awk '{print $2}'` >/dev/null 2>&1
	[ -z "$server_port" ] && server_port="22"
	output_dir="${dir}json_output"
	mkdir -p "$output_dir"
	if ( echo "$lite_enable"|grep -q "content" ); then
		str_title_start="" && str_title_end="" && str_splitline="" && str_linefeed="" && str_tab=""
	else
		read_json "str_title_start" "$jsonpath"
		read_json "str_title_end" "$jsonpath"
		read_json "str_linefeed" "$jsonpath"
		read_json "str_splitline" "$jsonpath"
		read_json "str_space" "$jsonpath"
		read_json "str_tab" "$jsonpath"
		read_json "_api" "$jsonpath"
	fi
	wait_and_cat
	disturb_text=$_api
	deltemp
	cron
}

# 初始化
function init(){
	enable_detection
	echo "---------------------------------------------------------------------------------------" >> ${logfile}
	echo "`date "+%Y-%m-%d %H:%M:%S"` 【初始化】start running..." >> ${logfile}
	if [ -f "/usr/share/wechatpush/errlog" ]; then
		cat /usr/share/wechatpush/errlog > ${logfile}
		echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】载入上次重启前日志" >> ${logfile}
	fi
	/usr/libexec/wechatpush-call "down_oui"

	rm -f ${dir}fd1 ${dir}sheep_usage ${dir}old_sheep_usage ${dir}client_usage_aliases ${dir}old_client_usage_aliases /usr/share/wechatpush/errlog >/dev/null 2>&1
	[ ! -f "/usr/sbin/wrtbwmon" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【info】未安装 wrtbwmon ，流量统计不可用" >> ${logfile}
	[ -z "$ip_version" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】无法获取依赖项 iputils-arping 版本号，请确认插件是否正常运行" >> ${logfile}
	[ -z "$cu_version" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】无法获取依赖项 curl 版本号，请确认插件是否正常运行" >> ${logfile}
	[ -z "${sckey}${tg_token}${pushplus_token}${corpid}${wxpusher_apptoken}${wxpusher_uids}${wxpusher_topicIds}" -a "${jsonpath}" != "/usr/share/wechatpush/api/diy.json" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】请填写正确的 key " >> ${logfile} && return 1
	local interfacelist=`getinterfacelist` && [ -z "$interfacelist" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】无法获取接口在线时间等信息，可能存在多个接口或配置错误，请确认插件是否正常运行" >> ${logfile}
	[ -n "$notification_temp" ] && [ -n "$temperature_threshold" ] && local cpu_temp=`soc_temp` || local cpu_temp="null"
	[ -z "$cpu_temp" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】无法读取设备温度，请检查命令" >> ${logfile}
	[ -n "$notification_load" ] && [ -n "$cpu_load_threshold" ] && local cpu_fuzai=`cat /proc/loadavg|awk '{print $1}'` 2>/dev/null || local cpu_fuzai="null"
	[ -z "$cpu_fuzai" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】无法读取设备负载，请检查命令" >> ${logfile}

	[ -n "$login_web_black" ] && [ "$login_web_black" -eq "1" ] && init_ip_black "ipv4"
	[ -n "$login_web_black" ] && [ "$login_web_black" -eq "1" ] && init_ip_black "ipv6"
	[ -n "$port_knocking_enable" ] && [ "$port_knocking_enable" -eq "1" ] && init_ip_white "ipv4"
	[ -n "$port_knocking_enable" ] && [ "$port_knocking_enable" -eq "1" ] && init_ip_white "ipv6"

	tmp_ip_list=`echo "$login_ip_white_list"|grep -v "^$"|sort -u`
	while IFS= read -r tmp_ip; do
		[ -n "$tmp_ip" ] && add_ip_white "$tmp_ip" "0"
	done <<< "$tmp_ip_list"
	set_ip_black
	return 0
}

# 推送
function diy_send(){
	( ! echo "$lite_enable"|grep -q "content" ) && ( ! echo "$lite_enable"|grep -q "nowtime" ) && local nowtime=`date "+%Y-%m-%d %H:%M:%S"`
	! jq -r '.' ${3} >/dev/null 2>&1 && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】json 文件格式错误，这不是一个标准的 json 文件，请检查 ${3} 文件是否有特殊符号未转义或语法错误" >> ${logfile} && return 1
	local diyurl=`jq -r .url ${3}` && local diyurl=`eval echo ${diyurl}`
	local type=`jq -r '.type' ${3}` && local type=`eval echo ${type}`
	local data=`jq -r '.data' ${3}` && local data=`eval echo ${data}`
	local content_type=`jq -r '.content_type' ${3}`
	! jq "$type" ${3} > ${tempjsonpath} && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】type:{ } 字段转义变量后格式错误，请检查 type:{ } 字段内是否有特殊符号未转义或语法错误" >> ${logfile} && return 1

	[ $4 ] && echo '{"url":"'${diyurl}'","content_type":"'${content_type}'","type":'`jq "$type" ${3}`'}' > ${dir}debug_send_json
	[ $4 ] && echo -e "${send_title}" "${send_content}" > ${dir}debug_send_content
	[ $4 ] && cat ${tempjsonpath} > ${dir}debug_send_data
	[ $4 ] && ! jq -r '.' ${dir}debug_send_json && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】转义变量后格式错误，请检查 ${dir}debug_send_json 字段内是否有特殊符号未转义或语法错误" >> ${logfile}
	[ $4 ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【debug】json 文件已保存至：${dir}debug_send_json"  >> ${logfile}
	[ $4 ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【debug】推送内容预览文件保存至：${dir}debug_send_content" >> ${logfile}
	[ $4 ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【debug】如果收不到信息，请检查 ${dir}debug_send_data 文件，或使用下列命令手动测试返回值 (可能需要关闭日志自动刷新方便选中)" >> ${logfile}
	[ $4 ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【debug】"'curl -X POST -H "'$content_type'" -d "@'${dir}debug_send_data'" "'${diyurl}'"  ' >> ${logfile}

	curl --connect-timeout 30 -m 60 -X POST -H "$content_type" -d "$data" "${diyurl}"
	local RETVAL=$?
	[ $RETVAL -ne "0" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】网络错误或 URL 错误，推送失败，curl 返回值为 ${RETVAL}" >> ${logfile} && return 1 || return 0
}

# 清理临时文件
function deltemp(){
	unset title	content ipAddress_logrow online_list online_mac mac_online_status gatewayinfo gateway_iplist
	rm -f ${dir}title ${dir}content ${dir}tmp_downlist ${dir}send_enable.lock ${tempjsonpath} ${dir}cookies.txt ${dir}tmp_sort_file >/dev/null 2>&1
	[ ! -f ${dir}ipAddress ] && rm -f ${dir}client/* >/dev/null 2>&1
	LockFile unlock
	[ -f ${logfile} ] && local logrow=$(grep -c "" ${logfile}) || local logrow="0"
	[ $logrow -gt 500 ] && sed -i '1,100d' ${logfile} && echo "`date "+%Y-%m-%d %H:%M:%S"`  【清理】日志超出上限，删除前 100 条" >> ${logfile}
}

# 检测程序开关
function enable_detection(){
	[ ! "$1" ] && local time_n=1
	for i in `seq 1 $time_n`; do
		get_config enable;[ -z "$enable" ] || [ "$enable" -eq "0" ] && exit || sleep 1
	done
}

# 获取 ip
function getip(){
	[ ! "$1" ] && return

	# 从接口获取 IPv4
	if [ $1 == "wanipv4" ] ;then
		[ ! -z "$ipv4_interface" ] && local wanIP=$(/sbin/ifconfig ${ipv4_interface}|awk '/inet addr/ {print $2}'|awk -F: '{print $2}'|grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
		[ -z "$ipv4_interface" ] && local wanIP=$(getinterfacelist|grep '\"address\"'|grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
		echo "$wanIP"

	# 从 URL 获取 IPv4
	elif [ $1 == "hostipv4" ] ;then
		local url_number=`echo "$ipv4_urllist"|wc -l`
		local rand_number=`rand 1 $url_number`
		function get_hostipv4()
		{
			local ipv4_URL=`echo "$ipv4_urllist"| sed -n "${1}p"|sed -e 's/\r//g'`
			[ ! -z "$ipv4_interface" ] && local tmp_hostIP=$(eval "curl -k -s -4 --interface ${ipv4_interface} -m 5 ${ipv4_URL}") || local tmp_hostIP=$(eval "curl -k -s -4 -m 5 ${ipv4_URL}")
			[ -z "$tmp_hostIP" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【info】IP 获取失败，当前使用的 API 为 $ipv4_URL，接口为：${ipv4_interface}" >> ${logfile}
			local tmp_hostIP=`echo $tmp_hostIP|grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'|head -n1`
			echo "{\"IP\":\"${tmp_hostIP}\", \"URL\":\"${ipv4_URL}\"}"
		}
		local hostIP=`get_hostipv4 ${rand_number}`
		[ -z `echo $hostIP|jq -r '.IP'` ] && local rand_number=`expr $rand_number + 1` && [ $rand_number -gt $url_number ] && local rand_number=1;[ -z `echo $hostIP|jq -r '.IP'` ] && local hostIP=`get_hostipv4 ${rand_number}`
		[ -z `echo $hostIP|jq -r '.IP'` ] && local rand_number=`expr $rand_number + 1` && [ $rand_number -gt $url_number ] && local rand_number=1;[ -z `echo $hostIP|jq -r '.IP'` ] && local hostIP=`get_hostipv4 ${rand_number}`
		[ -n "$list_auto_up" ] && [ "$list_auto_up" -eq "1" ] && [ -z `echo $hostIP|jq -r '.IP'` ] && /usr/libexec/wechatpush-call "auto_update_ip_list" "ipv4"
		[ -z `echo $hostIP|jq -r '.IP'` ] && ipv4_urllist=`cat /usr/share/wechatpush/api/ipv4.list` 2>/dev/null
		echo $hostIP

	# 从接口获取 IPv6
	elif [ $1 == "wanipv6" ] ;then
		[ ! -z "$ipv6_interface" ] && local wanIPv6=$(ip addr show ${ipv6_interface}|grep -v deprecated|grep -A1 'inet6 [^f:]'|sed -nr ':a;N;s#^ +inet6 ([a-f0-9:]+)/.+? scope global .*? valid_lft ([0-9]+sec) .*#\2 \1#p;ta'|sort -nr|head -n1|awk '{print $2}')
		[ -z "$ipv6_interface" ] && local wanIPv6=$(ip addr show|grep -v deprecated|grep -A1 'inet6 [^f:]'|sed -nr ':a;N;s#^ +inet6 ([a-f0-9:]+)/.+? scope global .*? valid_lft ([0-9]+sec) .*#\2 \1#p;ta'|sort -nr|head -n1|awk '{print $2}')
		echo "$wanIPv6"

	# 从 URL 获取 IPv6
	elif [ $1 == "hostipv6" ] ;then
		local urlv6_number=`echo "$ipv6_urllist"|wc -l`
		local rand_numberv6=`rand 1 $urlv6_number`
		function get_hostipv6()
		{
			local ipv6_URL=`echo "$ipv6_urllist"| sed -n "${1}p"|sed -e 's/\r//g'`
			[ ! -z "$ipv6_interface" ] && local tmp_hostIPv6=$(eval "curl -k -s -6 --interface ${ipv6_interface} -m 5 ${ipv6_URL}") || local tmp_hostIPv6=$(eval "curl -k -s -6 -m 5 ${ipv6_URL}")
			[ -z "$tmp_hostIPv6" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【info】IP 获取失败，当前使用的 API 为 $ipv6_URL，接口为：${ipv6_interface}" >> ${logfile}
			local tmp_hostIPv6=`echo $tmp_hostIPv6|grep -oE "([\da-fA-F0-9]{1,4}(:{1,2})){1,15}[\da-fA-F0-9]{1,4}"|head -n1`
			echo "{\"IP\":\"${tmp_hostIPv6}\", \"URL\":\"${ipv6_URL}\"}"
		}
		local hostIPv6=`get_hostipv6 ${rand_numberv6}`
		[ -z `echo $hostIPv6|jq -r '.IP'` ] && local rand_numberv6=`expr $rand_numberv6 + 1` && [ $rand_numberv6 -gt $urlv6_number ] && local rand_numberv6=1;[ -z `echo $hostIPv6|jq -r '.IP'` ] && local hostIPv6=`get_hostipv6 ${rand_numberv6}`
		[ -z `echo $hostIPv6|jq -r '.IP'` ] && local rand_numberv6=`expr $rand_numberv6 + 1` && [ $rand_numberv6 -gt $urlv6_number ] && local rand_numberv6=1;[ -z `echo $hostIPv6|jq -r '.IP'` ] && local hostIPv6=`get_hostipv6 ${rand_numberv6}`
		[ -n "$list_auto_up" ] && [ "$list_auto_up" -eq "1" ] && [ -z `echo $hostIP|jq -r '.IP'` ] && /usr/libexec/wechatpush-call "auto_update_ip_list" "ipv6"
		[ -z `echo $hostIPv6|jq -r '.IP'` ] && ipv4_urllist=`cat /usr/share/wechatpush/api/ipv6.list` 2>/dev/null
		echo $hostIPv6
	fi
}

# 获取接口信息
function getinterfacelist(){
	[ `ubus list|grep -w -i "network.interface.wan"|wc -l` -ge "1" ] && ubus call network.interface.wan status && return
	local ubuslist=`ubus list|grep -i "network.interface."|grep -v "loopback"|grep -v -i "wan6"|grep -v -i "lan6"|grep -v -i "ipsec.*"|grep -v -i "VPN.*"|grep -v -i "DOCKER.*"`
	[ `echo "${ubuslist}" |wc -l` -eq "1" ] && ubus call ${ubuslist} status && return
}

# 获取接口在线时间
function getinterfaceuptime(){
	getinterfacelist|awk -F'\"uptime\": ' '/uptime/ { gsub(/,/, "", $2); print $2 }'
}

# 查询 MAC 地址
function getmac(){
	# 已保存的 MAC
	[ -f "${dir}ipAddress" ] && local tmp_mac=`cat ${dir}ipAddress|grep -w ${1}|awk '{print $2}'|grep -v "^$"`
	( echo "$tmp_mac"|grep -q "unknown" ) && unset tmp_mac # 为 unknown 时重新读取
	[ -n "$tmp_mac" ] && [ "$(grep -w -i "${tmp_mac}" "${dir}ipAddress" | wc -l)" -gt "1" ] && unset tmp_mac # 某些路由器中继模式，会进行 MAC 克隆，重复值重新读取
	[ -f "${dir}tmp_downlist" ] && [ -z "$tmp_mac" ] && local tmp_mac=`cat ${dir}tmp_downlist|grep -w ${1}|awk '{print $2}'|grep -v "^$"|sort -u|head -n1`
	# DHCP
	( echo "$tmp_mac"|grep -q "unknown" ) && unset tmp_mac # 为 unknown 时重新读取
	[ -f "/tmp/dhcp.leases" ] && [ -z "$tmp_mac" ] && local tmp_mac=`cat /tmp/dhcp.leases|grep -w ${1}|awk '{print $2}'|grep -v "^$"|sort -u|head -n1`
	# arp
	[ -z "$tmp_mac" ] && local tmp_mac=`cat /proc/net/arp|grep "0x2\|0x6"|grep -w ${1}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`

	[ -z "$tmp_mac" ] && local tmp_mac="unknown"
	echo $tmp_mac |tr -d '\n\r'
}

# 查询主机名
function getname(){
	# 自定义备注
	local tmp_name=`echo "$device_aliases"|grep -i -w "^${1}\|^${2}"|awk '{ for(i=2; i<=NF; i++) printf $i " "; print "" }'|grep -v "^$"|sort -u|head -n1`
	[ -n "$tmp_name" ] && echo "$tmp_name" | tr -d '\n\r' | awk '$1=$1' | sed 's/_/ /g' | sort -u | head -n1 && return
	echo "$2" | grep -q -w "unknown\|*" && echo "unknown" && return # 当 MAC 获取失败时先不要尝试获取主机名
	# 已保存的 主机名
	[ -f "${dir}ipAddress" ] && [ -z "$tmp_name" ] && local tmp_name=`cat ${dir}ipAddress|grep -w ${1}|awk '{print $3}'|grep -v "^$"|sort -u|head -n1`
	echo "$tmp_name" | grep -q -w "unknown\|*" && unset tmp_name # 为unknown时重新读取
	[ -z "$tmp_name" ] && [ -f "${dir}tmp_downlist" ] && local tmp_name=`cat ${dir}tmp_downlist|grep -w ${1}|awk '{print $3}'|grep -v "^$"|sort -u|head -n1`
	# 静态地址备注名
	echo "$tmp_name" | grep -q -w "unknown\|*" && unset tmp_name # 为unknown时重新读取
	[ -z "$tmp_name" ] && dhcp_config=`uci show dhcp|grep "ip\|mac\|name"`
	if [ -n "$dhcp_config" ]; then
		dhcp_ip_n=$(echo "$dhcp_config" | grep -w ^dhcp.@${dhcp_config_str}.*ip=.${1} | sed -nr 's#^dhcp.(.*).ip.*#\1#gp' 2>/dev/null)
		[ ! -z "$dhcp_ip_n" ] && [ -z "$tmp_name" ] && tmp_name=$(uci get dhcp.${dhcp_ip_n}.name 2>/dev/null)
		[ -z "$tmp_name" ] && dhcp_mac_n=$(echo "$dhcp_config" | grep -i ^dhcp.@${dhcp_config_str}.*mac=.${2} | sed -nr 's#^dhcp.(.*).mac.*#\1#gp' 2>/dev/null)
		[ ! -z "$dhcp_mac_n" ] && [ -z "$tmp_name" ] && tmp_name=$(uci get dhcp.${dhcp_mac_n}.name 2>/dev/null)
	fi
	# DHCP
	echo "$tmp_name" | grep -q -w "unknown\|*" && unset tmp_name # 为unknown时重新读取
	[ -z "$tmp_name" ] && [ -f "/tmp/dhcp.leases" ] && local tmp_name=`cat /tmp/dhcp.leases|grep -w ${1}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`
	# 光猫
	echo "$tmp_name" | grep -q -w "unknown\|*" && unset tmp_name # 为unknown时重新读取
	[ -z "$tmp_name" ] && local	tmp_name=$(cut_str "$(echo "$gatewayinfo"|grep -w ${1}|awk '{print $2}'|sort -u|head -n1)" "30")
	# MAC设备信息数据库
	echo "$tmp_name" | grep -q -w "unknown\|*" && unset tmp_name # 为unknown时重新读取
	[ -z "$tmp_name" ] && [ -f "$oui_base" ] && local tmp_name=$(cat $oui_base|grep -i $(echo "$2"|cut -c 1,2,4,5,7,8)|sed -nr 's#^.*16)..(.*)#\1#gp')
	[ -z "$tmp_name" ] && [ ! -z "$oui_data" ] && [ "$oui_data" -eq "4" ] && local tmp_name=$(curl -sS "https://standards-oui.ieee.org/oui/oui.txt"|grep -i $(echo "$2"|cut -c 1,2,4,5,7,8)|sed -nr 's#^.*16)..(.*)#\1#gp')

	[ -z "$tmp_name" ] && local tmp_name="unknown"
	echo "$tmp_name" | tr -d '\n\r' | awk '$1=$1' | sed 's/_/ /g' | sort -u | head -n1
}

# 从光猫处获取设备信息
function getgateway(){
	[ -z "$gateway_info_enable" ] && return
	last_getgateway_time=$(date -r ${dir}gateway_info +%s 2>/dev/null) || last_getgateway_time=0
	[ "$1" ] && [ "$1" == "reboot" ] && last_getgateway_time=0
	if [ `expr $(date +%s) - $last_getgateway_time` -gt "$device_info_helper_sleeptime" ]; then
		# 登录
		local loginfo=`curl -s -L "${gateway_host_url}" -c ${dir}cookies.txt -d "${gateway_username_id}=${gateway_username}&${gateway_password_id}=${gateway_password}"` 2>/dev/null
		[ ! -z "$loginfo" ] && local mytoken=$(echo $loginfo |sed 's/{/\n/g' | grep token |awk '/realRestart/{print $2}'| sed $'s/\'//g')
		# 获取
		[ ! -z "$mytoken" ] && local get_gateway=`curl -s -b ${dir}cookies.txt "${gateway_info_url}" -d 'token='$mytoken | jq '.[] | iterables| "\(.ip) \(.devName) \(.model)"'|sed 's/unknown//g'|sed 's/  / /g'|sed 's/ /_/g'|sed 's/_/ /'|sed 's/\"//g'`
		# 重启
		[ "$1" ] && [ "$1" == "reboot" ] && curl -s -b ${dir}/cookies.txt "${gateway_host_url}/admin/reboot" -d "token=$mytoken" >/dev/null 2>&1
		# 注销
		[ ! -z "$get_gateway" ] && [ ! -z "$gateway_logout_url" ] && curl -s -b ${dir}cookies.txt "${gateway_logout_url}" -d 'token='$mytoken 2>/dev/null
		[ -z "$get_gateway" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【info】获取光猫信息失败，可能当前用户未注销或设置错误" >> ${logfile}
	fi
	[ ! -z "$get_gateway" ] && echo "$get_gateway" > ${dir}gateway_info
}

# 扫描范围内 IP
function scanlocalip(){
	[ -z "$scan_ip_range" ] && return
	[ -z "$last_scan_ip_time" ] && last_scan_ip_time=0
	if [ `expr $(date +%s) - $last_scan_ip_time` -gt "$device_info_helper_sleeptime" ]; then
		start_ip=$(echo "$scan_ip_range" | cut -d "-" -f 1)
		end_ip=$(echo "$scan_ip_range" | cut -d "-" -f 2)

		i=$(echo "$start_ip" | awk -F '.' '{print $NF}')
		end_i=$(echo "$end_ip" | awk -F '.' '{print $NF}')
		while [ "$i" -le "$end_i" ]; do
			ping "${start_ip%.*}.$i" -c 1 >> /dev/null 2>&1 &
			i=$((i + 1))
		done
	fi
}

# 查询设备接口
function getinterface(){
	[ -z "${1}" ] && return
	[ "${1}" == "unknown" ] && return

	[ -f "${dir}ipAddress" ] && local ip_interface=`cat ${dir}ipAddress|grep -w ${1}|awk '{print $5}'|grep -v "^$"|sort -u|head -n1`
	[ -f "${dir}tmp_downlist" ] && [ -z "$ip_interface" ] && local ip_interface=`cat ${dir}tmp_downlist|grep -w ${1}|awk '{print $5}'|grep -v "^$"|sort -u|head -n1`
	if [ -z "$ip_interface" ] && [ ! -z "$wlan_interface" ]; then
		for interface in $wlan_interface; do
			local ip_interface=`iw dev $interface station dump 2>/dev/null|grep Station|grep -i -w ${1}|sed -nr 's#^.*on (.*))#\1#gp'` >/dev/null 2>&1
			[ ! -z "$ip_interface" ] && echo "$ip_interface" && return
		done
	fi
	[ -z "$ip_interface" ] && local ip_interface=`cat /proc/net/arp|grep "0x2\|0x6"|grep -i -w ${1}|awk '{print $6}'|grep -v "^$"|sort -u|head -n1`
	echo $ip_interface |tr -d '\n\r'
}

# ping
function getping(){
	ip_interface=`getinterface ${2}`
	[ "$iw_version" ] && [ "$ip_interface" ] && wlan_online=`iw dev ${ip_interface} station dump 2>/dev/null|grep -i -w ${2}|grep Station` >/dev/null 2>&1
	[ "$wlan_online" ] && return 0
	arplist=$(cat /proc/net/arp)
	for i in `seq 1 ${4}`; do
		[ "$(echo "$arplist"|grep -i -w "${2}"|wc -l)" -eq 1 ] && interface=$(echo "$arplist"|grep -w ${1}|awk '{print $6}'|grep -v "^$"|sort -u|head -n1) && [ ! -z "$interface" ] && ip_ms=`arping -I ${interface} -c 20 -f -w ${3} ${1}` 2>/dev/null
		( ! echo "$ip_ms"|grep -q "ms" ) && ip_ms=`ping -c 5 -w ${3} ${1}|grep -v '100% packet loss'` 2>/dev/null
		( ! echo "$ip_ms"|grep -q "ms" ) && sleep 1
	done
	echo "$ip_ms"|grep -q "ms"
}

# CPU 占用率
function getcpu(){
	local AT=$(cat /proc/stat|grep "^cpu "|awk '{print $2+$3+$4+$5+$6+$7+$8 " " $2+$3+$4+$7+$8}')
	sleep 1
	local BT=$(cat /proc/stat|grep "^cpu "|awk '{print $2+$3+$4+$5+$6+$7+$8 " " $2+$3+$4+$7+$8}')
	printf "%.01f%%" $(echo ${AT} ${BT}|awk '{print (($4-$2)/($3-$1))*100}')
}

# 获取SOC温度 （取所有传感器温度最大值）
function soc_temp(){
	[ ! -z "$soc_code" ] && eval `echo "$soc_code"` 2>/dev/null && return 0
	getsensors() {
		# Intel
		local sensor_field1='["coretemp-isa-0000"]["Package id 0"]["temp1_input"]'
		# AMD
		local sensor_field2='["zenpower-pci-00c3"]["Tctl"]["temp1_input"]'
		local sensor_field3='["k10temp-pci-00c3"]["Tctl"]["temp1_input"]'
		eval "${1} sensors -j 2>/dev/null" | jq -r "
		if .${sensor_field1} != null then
		  .${sensor_field1}
		elif .${sensor_field2} != null then
		  .${sensor_field2}
		elif .${sensor_field3} != null then
		  .${sensor_field3}
		else
		  null
		end // \"\"
		"
	}

	[ ! -z "$server_host" ] && ssh_command="ssh -o StrictHostKeyChecking=yes -o BatchMode=yes -i /root/.ssh/id_rsa root@${server_host} -p ${server_port}"
	temperature=$(getsensors "$ssh_command" 2>/dev/null)
	# 通用（只能取最高温度，不一定是 CPU，特殊设备自行修改）
	# 将 grep °C 改为温度所在行的特别字符串，如 grep Core 0 等，就可以指定设备了
	[ -z "$temperature" ] && temperature=$(sensors 2>/dev/null|grep °C|sed -nr 's#^.*:.*\+(.*)°C .*#\1#gp'|sort -nr|head -n1)
	# 将 thermal_zone* 改为 thermal_zone0 thermal_zone1 等，就可以指定设备了
	[ -z "$temperature" ] && temperature=$(cat /sys/class/thermal/thermal_zone*/temp 2>/dev/null|sort -nr|head -n1|cut -c-2)
	printf "%.1f" "$temperature"
}
# 流量数据
function usage(){
	[ ! -f "/usr/sbin/wrtbwmon" ] || [ ! "$1" ] && return
	# 更新
	if [ $1 == "update" ] ;then
		function version_le() { test "$(echo "$@"|tr " " "\n"|sort -n|head -n 1)" == "$1"; }
		function version_ge() { test "$(echo "$@"|tr " " "\n"|sort -r|head -n 1)" == "$1"; }
		[ ! -z "$wr_version" ] && ( version_ge "${wr_version}" "1.2.0" ) && wrtbwmon -f ${dir}usage.db 2>/dev/null && return
		[ ! -z "$wr_version" ] && ( version_le "${wr_version}" "1.0.0" ) || [ -z "$wr_version" ] && wrtbwmon update ${dir}usage.db 2>/dev/null && return
	# 获取
	elif [ $1 == "get" ] ;then
		[ ! -f "${dir}usage.db" ] && [ ! "$3" ] && echo `bytes_for_humans 0` && return
		[ ! -f "${dir}usage.db" ] && [ "$3" ] && echo 0 && return
		[ -z "$total_n" ] && total_n=`cat ${dir}usage.db|head -n1|grep "total"|sed 's/,/\n/g'|awk '/total/{print NR}'` 2>/dev/null
		[ -z "$total_n" ] && total_n="6"
		[ "$2" ] && local tmptotal=`cat ${dir}usage.db|sed 's/,,,/,0,0,/g'|sed 's/,,/,0,/g'|sed 's/,/ /g'|grep -i -w ${2}|awk "{print "'$'$total_n"}"|grep -v "^$"|sort -u|head -n1` 2>/dev/null
		[ -z "$tmptotal" ] && local tmptotal="0"
		[ ! "$3" ] && echo `bytes_for_humans ${tmptotal}` || echo $tmptotal
	# 剔除
	elif [ $1 == "down" ] ;then
		[ "$2" ] && sed -i "/,${2},/d" ${dir}usage.db 2>/dev/null
	fi
}

# 流量数据单位换算
function bytes_for_humans {
	[ ! "$1" ] && return
	[ "$1" -gt 1073741824 ] && echo "`awk 'BEGIN{printf "%.2f\n",'$1'/'1073741824'}'` GB" && return
	[ "$1" -gt 1048576 ] && echo "`awk 'BEGIN{printf "%.2f\n",'$1'/'1048576'}'` MB" && return
	[ "$1" -gt 1024 ] && echo "`awk 'BEGIN{printf "%.2f\n",'$1'/'1024'}'` KB" && return
	echo "${1} bytes"
}

# 设备异常流量检测
function get_client_usage(){
	[ -z "$client_usage" ] && return
	[ "$client_usage" -ne "1" ] && return
	[ -z "$client_usage_max" ] && return

	[ -z "$get_client_usage_time" ] && get_client_usage_time=`date +%s`
	( echo $client_usage_max|sed -r 's/.*(.)$/\1/'|grep -q "K\|k" ) && client_usage_max=`expr ${client_usage_max%?} \* 1024`
	( echo $client_usage_max|sed -r 's/.*(.)$/\1/'|grep -q "M\|m" ) && client_usage_max=`expr ${client_usage_max%?} \* 1048576`
	( echo $client_usage_max|sed -r 's/.*(.)$/\1/'|grep -q "G\|g" ) && client_usage_max=`expr ${client_usage_max%?} \* 1073741824`
	[ -z "$client_usage_disturb" ] && client_usage_disturb="0"
	[ "$client_usage_disturb" -eq "0" ] && [ -f "${dir}ipAddress" ] && local MACLIST=`cat ${dir}ipAddress|awk '{print $2}'|grep -v "^$"|sort -u`
	[ "$client_usage_disturb" -eq "1" ] && [ ! -z "$client_usage_whitelist" ] && local MACLIST=`echo "$client_usage_whitelist"`
	[ -z "$MACLIST" ] && return

	if [ "$((`date +%s`-$get_client_usage_time))" -ge "60" ]; then
		> ${dir}client_usage_aliases
		for mac in $MACLIST; do
			( ! cat ${dir}ipAddress|grep -q -i -w $mac|grep -v "^$"|sort -u|head -n1 ) && continue
			echo "$mac" `usage get ${mac} bytes` >> ${dir}client_usage_aliases
			[ -f "${dir}old_client_usage_aliases" ] && get_client_usage_bytes=`cat ${dir}old_client_usage_aliases|grep -i -w $mac|awk '{print $2}'|grep -v "^$"|sort -u|head -n1` || continue
			[ -z "$get_client_usage_bytes" ] && get_client_usage_bytes="0"
			if [ "$((`usage get ${mac} bytes`-$get_client_usage_bytes))" -ge "$client_usage_max" ]; then
				local ip=`cat ${dir}ipAddress|grep -i -w $mac|awk '{print $1}'|grep -v "^$"|sort -u|head -n1`
				local ip_name=`getname ${ip} ${mac}`
				local tmp_usage=$(bytes_for_humans $(expr `usage get ${mac} bytes` - ${get_client_usage_bytes}))
				local time_up=`cat ${dir}ipAddress|grep -w ${ip}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`
				local ip_total=`usage get $mac` && [ ! -z "$ip_total" ] && local ip_total="${str_linefeed}${str_tab}总计流量： ${str_space}${str_space}${str_space}${str_space}${ip_total}"
				local time1=`date +%s`
				local time1=$(time_for_humans `expr ${time1} - ${time_up}`)
				if [ -z "$title" ]; then
					title="${ip_name} 流量异常"
					content="${content}${str_splitline}${str_title_start} 设备流量异常${str_title_end}${str_linefeed}${str_tab}客户端名：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP： ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC：${str_space}${str_space}${str_space}${str_space}${mac}$ip_total${str_linefeed}${str_tab}一分钟内流量： ${str_space}${str_space}${tmp_usage}${str_linefeed}${str_tab}在线时间： ${str_space}${str_space}${str_space}${str_space}${time1}"
				elif ( echo "$title"|grep -q "流量异常" ); then
					title="${ip_name} ${title}"
					content="${content}${str_splitline}${str_tab}客户端名：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP： ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC：${str_space}${str_space}${str_space}${str_space}${mac}$ip_total${str_linefeed}${str_tab}一分钟内流量： ${str_space}${str_space}${str_space}${tmp_usage}${str_linefeed}${str_tab}在线时间： ${str_space}${str_space}${str_space}${str_space}${time1}"
				else
					title="设备状态变化"
					content="${content}${str_splitline}${str_title_start} 设备流量异常${str_title_end}${str_linefeed}${str_tab}客户端名：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP： ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC：${str_space}${str_space}${str_space}${str_space}${mac}$ip_total${str_linefeed}${str_tab}一分钟内流量： ${str_space}${str_space}${str_space}${tmp_usage}${str_linefeed}${str_tab}在线时间： ${str_space}${str_space}${str_space}${str_space}${time1}"
				fi
			fi
		done
		cat ${dir}client_usage_aliases > ${dir}old_client_usage_aliases
		get_client_usage_time=`date +%s`
	fi
}

# 时间单位换算
function time_for_humans {
	[ ! "$1" ] && return

	if [ "$1" -lt 60 ]; then
		echo "${1} 秒"
	elif [ "$1" -lt 3600 ]; then
		local usetime_min=`expr $1 / 60`
		local usetime_sec=`expr $usetime_min \* 60`
		local usetime_sec=`expr $1 - $usetime_sec`
		echo "${usetime_min} 分 ${usetime_sec} 秒"
	elif [ "$1" -lt 86400 ]; then
		local usetime_hour=`expr $1 / 3600`
		local usetime_min=`expr $usetime_hour \* 3600`
		local usetime_min=`expr $1 - $usetime_min`
		local usetime_min=`expr $usetime_min / 60`
		echo "${usetime_hour} 小时 ${usetime_min} 分"
	else
		local usetime_day=`expr $1 / 86400`
		local usetime_hour=`expr $usetime_day \* 86400`
		local usetime_hour=`expr $1 - $usetime_hour`
		local usetime_hour=`expr $usetime_hour / 3600`
		echo "${usetime_day} 天 ${usetime_hour} 小时"
	fi
}

# 计算字符显示宽度
function length_str {
	[ ! "$1" ] && return

	local length_zh=`echo "$1"|awk '{print gensub(/[\u4e00-\u9FA5A-Za-z0-9_]/,"","g",$0)}'|awk -F "" '{print NF}'`
	local length_en=`echo "$1"|awk '{print gensub(/[^\u4e00-\u9FA5A-Za-z0-9_]/,"","g",$0)}'|awk -F "" '{print NF}'`

	echo $((length_zh / 3 * 2 + length_en))
}

function cut_str {
	[ ! "$1" ] && return
	[ ! "$2" ] && return

	if [ $(length_str "$1") -le "$2" ]; then
		echo "$1"
		return
	fi

	local columns=$(echo "$1" | awk '{print NF}')
	if [ "$columns" -gt 1 ]; then
		local max_length=0
		local max_column=1
		for i in $(seq 1 $columns); do
			local length=$(echo "$1"|awk '{print gensub(/[\u4e00-\u9FA5A-Za-z0-9_]/,"","g",$0)}'|awk -F "" '{print NF}')
			if [ "$length" -gt "$max_length" ]; then
				max_length=$length
				max_column=$i
			fi
		done
		local text=$(echo -n "$1" | cut -d ' ' -f $max_column)
		if [ $(length_str "$text") -le "$2" ]; then
			echo "$text"
			return
		fi
	fi

	local temp_length=$2
	while [ $(length_str "$(echo -n "$1" | cut -c -$temp_length)") -lt "$2" ]; do
		temp_length=$(expr $temp_length + 1)
	done
	while [ $(printf "%d" \'$(echo -n "$1" | cut -c $temp_length)) -ge "128" ] && [ $(printf "%d" \'$(echo -n "$1" | cut -c $temp_length)) -lt "224" ]; do
		temp_length=$(expr $temp_length + 1)
	done
	temp_length=$(expr $temp_length - 1)

	echo "$(echo -n "$1" | cut -c -$temp_length)"..
}



# 随机数
function rand(){
	local min=$1
	local max=$(($2- $min + 1))
	local num=$(date +%s%N)
	echo $(($num % $max + $min))
}

# 在线设备列表
function first(){
	[ -f "${dir}ipAddress" ] && local IPLIST_ipAddress=`cat ${dir}ipAddress|awk '{print $1}'|grep -v "^$"|sort -u`
	getgateway
	scanlocalip;last_scan_ip_time=$(date +%s)
	for ip in $IPLIST_ipAddress; do
		[ ! -z "$passive_mode" ] && [ "$passive_mode" -eq "1" ] && break
		read -u 5
		{
			down $ip
			echo "" >&5
		}&
	done
	wait

	local IPLIST=`cat /proc/net/arp|grep "0x2\|0x6"|awk '{print $1}'|grep -v "^169.254."|grep -v "^$"|sort -u|grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'`
	[ -f "${dir}gateway_info" ] && gatewayinfo=`cat ${dir}gateway_info`
	local gateway_iplist=`echo "${gatewayinfo}"|awk '{print $1}'`
	[ ! -z "$gateway_iplist" ] && local IPLIST=`echo -e "${IPLIST}\n${gateway_iplist}"|grep -v "^$"|sort -u`
	for ip in $IPLIST; do
		[ ! -z "$passive_mode" ] && [ "$passive_mode" -eq "1" ] && break
		read -u 5
		{
			up $ip
			echo "" >&5
		}&
	done
	wait

	[ -z "$passive_mode" ] && return
	[ "$passive_mode" -ne "1" ] && return
	for ip in $IPLIST; do
		if ( ! echo "$IPLIST_ipAddress"|grep -q -i -w $ip ); then
			ip_mac=`getmac $ip`
			ip_name=`getname ${ip} ${ip_mac}`
			ip_interface=`getinterface ${ip_mac}`
			echo "{'ip': '${ip}','mac': '${ip_mac}','name': '${ip_name}','uptime': '0秒','interface': '${ip_interface}','usage': ''}" > ${dir}client/${ip}
			usage down ${ip}
			echo "${ip} ${ip_mac} ${ip_name// /_} `date +%s` ${ip_interface}" >> ${dir}ipAddress
		fi
	done
	for ip in $IPLIST_ipAddress; do
		if ( echo "$IPLIST"|grep -q -i -w $ip ); then
			ip_mac=`getmac $ip`
			ip_name=`getname ${ip} ${ip_mac}`
			ip_interface=`getinterface ${ip_mac}`
			time_up=`cat ${dir}ipAddress|grep -w ${ip}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`
			time1=`date +%s`
			time1=$(time_for_humans `expr ${time1} - ${time_up}`)
			echo "{'ip': '${ip}','mac': '${ip_mac}','name': '${ip_name}','uptime': '${time1}','interface': '${ip_interface}','usage': '`usage get $ip_mac`'}" > ${dir}client/${ip}
		else
			sed -i "/^${ip} /d" ${dir}ipAddress
			rm -f ${dir}client/${ip} >/dev/null 2>&1
		fi
	done
}

# 创建计划任务
function cron(){
	function del_cron(){
		( echo `crontab -l 2>/dev/null`|grep -q "wechatpush" ) && crontab -l > conf && sed -i "/wechatpush/d" conf && crontab conf && rm -f conf >/dev/null 2>&1
	}
	function re_cron(){
		/etc/init.d/cron stop
		/etc/init.d/cron start
	}
	del_cron
	if [ -z "$enable" ]; then
		re_cron
		return
	fi

	# 重置流量
	if [ ! -z "$reset_regularly" ] && [ "$reset_regularly" -eq "1" ]; then
		crontab -l 2>/dev/null > conf && echo -e "0 0 * * * rm ${dir}usage.db >/dev/null 2>&1" >> conf && crontab conf && rm -f conf >/dev/null 2>&1
		crontab -l 2>/dev/null > conf && echo -e "0 0 * * * rm ${dir}usage6.db >/dev/null 2>&1" >> conf && crontab conf && rm -f conf >/dev/null 2>&1
	fi

	# 定时发送
	if [ -n "$crontab_regular_time" ]; then
		crontab_regular_time=`echo $crontab_regular_time|sed 's/ /,/g'` 2>/dev/null
		crontab -l 2>/dev/null > conf && echo -e "0 $crontab_regular_time * * * /usr/share/wechatpush/wechatpush send &" >> conf && crontab conf && rm -f conf >/dev/null 2>&1
	# 间隔发送
	elif [ -n "$crontab_interval_time" ]; then
		crontab -l 2>/dev/null > conf && echo -e "0 */$crontab_interval_time * * * /usr/share/wechatpush/wechatpush send &" >> conf && crontab conf && rm -f conf >/dev/null 2>&1
	fi

	re_cron
}

# 免打扰检测
function disturb(){
	[ -z "$do_not_disturb_mode" ] || [ -z "$do_not_disturb_starttime" ] || [ -z "$do_not_disturb_endtime" ] && return 0

	# 非免打扰时间
	if [ `date +%H` -ge $do_not_disturb_endtime -a $do_not_disturb_starttime -lt $do_not_disturb_endtime ] || [ `date +%H` -lt $do_not_disturb_starttime -a $do_not_disturb_starttime -lt $do_not_disturb_endtime ] || [ `date +%H` -lt $do_not_disturb_starttime -a `date +%H` -ge $do_not_disturb_endtime -a $do_not_disturb_starttime -gt $do_not_disturb_endtime ]; then
		unset sheep_starttime
		rm -f ${dir}sheep_usage ${dir}old_sheep_usage  2>/dev/null
		disturb_text=`jq -r '._api' ${jsonpath}`
		return 0
	# 免打扰
	else
		[ -z "$sheep_starttime" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【免打扰】夜深了，该休息了" >> ${logfile} && sheep_starttime=`date +%s`
		# 挂起
		if [ "$do_not_disturb_mode" -eq "1" ] ;then
			while [ `date +%H` -lt "$do_not_disturb_endtime" ]; do
				enable_detection
				sleep $sleeptime
			done
		# 静默
		elif [ "$do_not_disturb_mode" -eq "2" ] ;then
			disturb_text="【免打扰】"
			return 1
		fi
	fi
}

# 文件锁
function LockFile(){
	if [ $1 = "lock" ] ;then
		[ ! -f "${dir}wechatpush.lock" ] && > ${dir}wechatpush.lock && return
		while [ -f "${dir}wechatpush.lock" ]; do
			enable_detection 1
		done
		LockFile lock
	fi
	[ $1 = "unlock" ] && rm -f ${dir}wechatpush.lock >/dev/null 2>&1
	return 0
}

# 检测黑白名单
function blackwhitelist(){
	[ ! "$1" ] && return 1

	[ -z "$up_down_push_whitelist" ] && [ -z "$up_down_push_blacklist" ] && [ -z "$up_down_push_interface" ] && [ -z "$mac_online_list" ] && [ -z "$mac_offline_list" ] && return 0
	[ ! -z "$up_down_push_whitelist" ] && ( echo "$up_down_push_whitelist"|grep -q -i -w $1 ) && return 1
	[ ! -z "$up_down_push_blacklist" ] && ( ! echo "$up_down_push_blacklist"|grep -q -i -w $1 ) && return 1
	[ ! -z "$up_down_push_interface" ] && ( ! echo `getinterface ${1}`|grep -q -i -w $up_down_push_interface ) && return 1
	[ ! -z "$mac_online_list" ] && [ ! -z "$mac_online_status" ] && return 1
	[ ! -z "$mac_online_list" ] && ( echo "$mac_online_list"|grep -q -i -w $1 ) && return 1
	[ ! -z "$mac_offline_list" ] && [ -z "$mac_online_status" ] && return 1

	return 0
}

# 重启网络服务
function network_restart(){
cat>${dir}network_restart<<EOF
#!/bin/sh
/etc/init.d/network restart >/dev/null 2>&1 &
/etc/init.d/firewall restart >/dev/null 2>&1 &
/etc/init.d/dnsmasq restart >/dev/null 2>&1 &
EOF
	chmod 0755 ${dir}network_restart && ${dir}network_restart
	rm -f ${dir}network_restart >/dev/null 2>&1
}

# 查看无人值守任务设备是否在线
function geterrdevicealiases(){
	[ -z "$unattended_device_aliases" ] && return
	[ -f ${dir}ipAddress ] && local logrow=$(grep -c "" ${dir}ipAddress) || local logrow="0";[ $logrow -eq "0" ] && return

	local MACLIST=`cat ${dir}ipAddress|awk '{print $2}'|grep -v "^$"|sort -u`
	for mac in $MACLIST; do
		[ -z "$unattended_mac" ] && [ ! -z "$mac" ] && local unattended_mac=`echo "$unattended_device_aliases"|grep -i $mac|grep -v "^$"|sort -u|head -n1`
	done
	# 进入免打扰时间已经超过一小时
	if [ ! -z "$sheep_starttime" ] && [ "$((`date +%s`-$sheep_starttime))" -ge "3600" ]; then
		> ${dir}sheep_usage
		local MACLIST=`echo "$unattended_device_aliases"|grep -v "^$"|sort -u`
		while IFS= read -r mac; do
			[ ! -z "$mac" ] && local tmptotal=`usage get ${mac} bytes`
			[ ! -z "$tmptotal" ] && awk 'BEGIN{printf "%.0f\n",'$tmptotal'/'204800'}' 2>/dev/null >> ${dir}sheep_usage
		done <<< "$MACLIST"
		old_sheep_usage=`cat ${dir}old_sheep_usage` 2>/dev/null
		sheep_usage=`cat ${dir}sheep_usage` 2>/dev/null
		[ "$old_sheep_usage" == "$sheep_usage" ] && [ -z "$sheep_nousage_starttime" ] && sheep_nousage_starttime=`date +%s`
		[ "$old_sheep_usage" != "$sheep_usage" ] && unset sheep_nousage_starttime && cat ${dir}sheep_usage 2>/dev/null > ${dir}old_sheep_usage
		[ ! -z "$sheep_nousage_starttime" ] && [ "$((`date +%s`-$sheep_nousage_starttime))" -ge "300" ] && unset unattended_mac
	fi
	[ -z "$unattended_mac" ]
}

# 无人值守任务
function unattended(){
	[ -z "$unattended_enable" ] || [ "$unattended_enable" -ne "1" ] && return
	[ ! -z "$unattended_only_on_disturb_time" ] && [ "$unattended_only_on_disturb_time" -eq "1" ] && [ -z "$sheep_starttime" ] && return
	geterrdevicealiases;[ $? -eq "1" ] && return

	if [ ! -z "$unattended_autoreboot_mode" ]; then
		local interfaceuptime=`getinterfaceuptime`
		if [ ! -z "$autoreboot_system_uptime" ] && [ `cat /proc/uptime|awk -F. '{run_hour=$1/3600;printf("%d",run_hour)}'` -ge "$autoreboot_system_uptime" ] && [ "$unattended_autoreboot_mode" -eq "1" ]; then
			echo "`date "+%Y-%m-%d %H:%M:%S"` 【无人值守任务】重启路由器咯" >> ${logfile}
			cat ${logfile} > /usr/share/wechatpush/errlog
			sleep 2 && reboot && exit
		elif [ ! -z "$autoreboot_network_uptime" ] && [ ! -z "$interfaceuptime" ] && [ `echo "$interfaceuptime"|awk -F. '{run_hour=$1/3600;printf("%d",run_hour)}'` -ge "$autoreboot_network_uptime" ] && [ "$unattended_autoreboot_mode" -eq "2" ]; then
			echo "`date "+%Y-%m-%d %H:%M:%S"` 【无人值守任务】重新拨号咯" >> ${logfile}
			ifup wan >/dev/null 2>&1
			sleep 60
		fi
	fi
}

# 检测网络状态
function rand_geturl(){
	# 获取网络状态
	function getcheck(){
		local urllist="https://www.163.com https://www.qq.com https://www.baidu.com https://www.qidian.com https://www.douban.com"
		local url_number=`expr $(echo "$urllist"|grep -o ' '|wc -l) + 1`
		local url_str=`echo "$urllist"|awk -v i=$(rand 1 $url_number) '{print $i}'`
		echo `curl -k -s -w "%{http_code}" -m 5 ${url_str} -A "${User_Agent}" -o /dev/null`
	}
	local check=`getcheck`
	while [ -z "$check" ] || [[ $check -ne 200 && $check -ne 301 && $check -ne 302 ]]; do
		local check=`getcheck`
		if [ ! -z "$check" ] && [[ $check -eq 200 || $check -eq 301 || $check -eq 302 ]]; then
			[ ! -z "$network_enable" ] && [ "$network_enable" -eq "404" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【网络状态】网络恢复正常.." >> ${logfile}
			local network_enable="200"
		else
			[ -z "$network_enable" ] || [ "$network_enable" -eq "200" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！！】当前网络不通！停止检测！ " >> ${logfile}
			local network_enable="404"
			# 无人值守、待弃用或改进
			[ -z "$network_unattended_time" ] && network_unattended_time=`date +%s`
			if [ ! -z "$network_disconnect_event" ] && [ "$((`date +%s`-$network_unattended_time))" -ge "600" ]; then
				> ${dir}send_enable.lock && first && deltemp
				geterrdevicealiases
				if [ "$?" -eq "0" ]; then
					[ -f /usr/share/wechatpush/autoreboot_count ] && retry_count=`cat /usr/share/wechatpush/autoreboot_count` && rm -f /usr/share/wechatpush/autoreboot_count >/dev/null 2>&1
					[ ! -z "${retry_count}" ] && retry_count=0;retry_count=`expr $retry_count + 1`
					if [ "$network_disconnect_event" -eq "1" ] ;then
						if [ "$retry_count" -lt "3" ] ;then
							echo "$retry_count" > /usr/share/wechatpush/autoreboot_count
							echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！！】正在尝试重启路由，当前第 $retry_count 次 " >> ${logfile}
							cat ${logfile} > /usr/share/wechatpush/errlog
							getgateway "reboot"
							sleep 2 && reboot && exit
						fi
						[ "$retry_count" -eq "3" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！！】已经重启路由2次，修复失败，请主人自行修复哦" >> ${logfile}
					elif [ "$network_disconnect_event" -eq "2" ] ;then
						[ "$retry_count" -lt "3" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！！】正在尝试重启网络，当前第 $retry_count 次 " >> ${logfile} && ifup wan >/dev/null 2>&1
						[ "$retry_count" -eq "3" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！！】已经重启网络2次，修复失败，请主人自行修复哦 " >> ${logfile}
					fi
				fi
			elif [ -f /usr/share/wechatpush/autoreboot_count ]; then
				network_unattended_time=`expr $network_unattended_time - 600` && sleep 60
			fi
			enable_detection
			sleep $sleeptime
		fi
	continue
	done
	rm -f /usr/share/wechatpush/autoreboot_count >/dev/null 2>&1
}

# 检测 ip 状况
function ip_changes(){
	[ "$get_ipv4_mode" -eq "1" ] && local IPv4=`getip wanipv4` && local IPv4_URL="网络接口"
	[ "$get_ipv4_mode" -eq "2" ] && local IPv4=`getip hostipv4` && local IPv4_URL=`echo ${IPv4}|jq -r '.URL'` && local IPv4=`echo ${IPv4}|jq -r '.IP'`
	[ "$get_ipv6_mode" -eq "1" ] && local IPv6=`getip wanipv6` && local IPv6_URL="网络接口"
	[ "$get_ipv6_mode" -eq "2" ] && local IPv6=`getip hostipv6` && local IPv6_URL=`echo ${IPv6}|jq -r '.URL'` && local IPv6=`echo ${IPv6}|jq -r '.IP'`

	# 存在临时文件
	if [ -f ${dir}ip ]; then
		local last_IPv4=$(cat "${dir}ip"|grep IPv4|awk '{print $2}'|grep -v "^$"|sort -u|head -n1)
		local last_IPv6=$(cat "${dir}ip"|grep IPv6|awk '{print $2}'|grep -v "^$"|sort -u|head -n1)
		if [ "$get_ipv4_mode" -ne "0" ] && [ ! -z "$IPv4" ] && ( ! echo ${IPv4}|grep -w -q ${last_IPv4} ); then
			echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}当前 IP：${IPv4}    from：${IPv4_URL}" >> ${logfile}
			echo IPv4 $IPv4 > ${dir}ip && echo -e IPv6 $last_IPv6 >> ${dir}ip
			title="IP 地址变化"
			content="${content}${str_splitline}${str_title_start} IP 地址变化${str_title_end}${str_linefeed}${str_tab}当前 IP：${IPv4}"
		fi

		if [ "$get_ipv6_mode" -ne "0" ] && [ ! -z "$IPv6" ] && ( ! echo "$IPv6"|grep -w -q ${last_IPv6} ); then
			echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}当前 IPv6：${IPv6}    from：${IPv6_URL}" >> ${logfile}
			echo IPv4 $IPv4 > ${dir}ip && echo -e IPv6 $IPv6 >> ${dir}ip
			[ -z "$title" ] && title="IPv6 地址变化"
			[ ! -z "$title" ] && title="IP 地址变化"
			content="${content}${str_splitline}${str_title_start} IPv6 地址变化${str_title_end}${str_linefeed}${str_tab}当前 IPv6：${IPv6}"
		fi

	# 临时文件目录为空
	else
		echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}路由器已经重启!" >> ${logfile}
		[ "$get_ipv4_mode" -ne "0" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}当前 IP: ${IPv4}    from：${IPv4_URL}" >> ${logfile}
		[ "$get_ipv6_mode" -ne "0" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}当前 IPv6: ${IPv6}    from：${IPv6_URL}" >> ${logfile}
		echo IPv4 $IPv4 > ${dir}ip && echo -e IPv6 $IPv6 >> ${dir}ip
		title="路由器重新启动"
		content="${content}${str_splitline}${str_title_start} 路由器重新启动${str_title_end}"
		[ "$get_ipv4_mode" -ne "0" ] && content="${content}${str_linefeed}${str_tab}当前IP：${IPv4}"
		[ "$get_ipv6_mode" -ne "0" ] && content="${content}${str_linefeed}${str_tab}当前IPv6：${IPv6}"
	fi

	# IP 变化，悄咪咪的重启 zerotier
	if [ ! -z "$content" ] && [ -n "$zerotier_helper" ] && [ "$zerotier_helper" -eq "1" ];then
		[ -z "$zerotier_enabled" ] && zerotier_enabled=$(uci get zerotier.sample_config.enabled)
		if [ ! -z "$zerotier_enabled" ] && [ $zerotier_enabled -eq "1" ] ; then
			/etc/init.d/zerotier restart >/dev/null 2>&1
		fi
	fi
}

# 检测设备上线
function up(){
	[ -f ${dir}ipAddress ] && ( cat ${dir}ipAddress|grep -q -w $1 ) && return

	local ip_mac=`getmac $1`
	local ip_name=`getname ${1} ${ip_mac}`
	local ip_interface=`getinterface ${ip_mac}`
	getping ${1} ${ip_mac} ${up_timeout} "1";local ping_online=$?

	# 连通
	if [ "$ping_online" -eq "0" ]; then
		LockFile lock
		[ ! -z "$up_down_push_blacklist" ] && local tmp_mac=`echo "${up_down_push_blacklist}"|grep -w -i ${ip_mac}`
		[ ! -z "$up_down_push_whitelist" ] && local tmp_mac=`echo "${up_down_push_whitelist}"|grep -w -i ${ip_mac}`
		echo "{'ip': '${1}','mac': '${ip_mac}','name': '${ip_name}','uptime': '0秒','interface': '${ip_interface}','usage': ''}" > ${dir}client/${1}
		# ？？？
		if [ ! -z "$tmp_mac" ] && ( cat ${dir}ipAddress|grep -q -w -i ${tmp_mac} ); then
			usage down ${1}
			echo "${1} ${ip_mac} ${ip_name// /_} `date +%s` ${ip_interface}" >> ${dir}ipAddress
			LockFile unlock && return
		# ？？？
		elif [ ! -z "$tmp_mac" ] && [ -f "${dir}tmp_downlist" ] && ( cat ${dir}tmp_downip|grep -q -w -i ${tmp_mac} ); then
			local tmp_downip=`cat ${dir}tmp_downlist|grep -w -i ${tmp_mac}|awk '{print $1}'|grep -v "^$"|sort -u|head -n1`
			usage down $tmp_downip
			sed -i "/^${tmp_downip} /d" ${dir}tmp_downlist
			LockFile unlock && return
		fi
		# 从离线二次验证区恢复信息
		[ -f "${dir}tmp_downlist" ] && local tmp_downip=`cat ${dir}tmp_downlist|grep -w ${1}|grep -v "^$"|sort -u|head -n1`
		if [ ! -z "$tmp_downip" ]; then
			cat ${dir}tmp_downlist|grep -w ${1}|grep -v "^$"|sort -u|head -n1 >> ${dir}ipAddress
			sed -i "/^${1} /d" ${dir}tmp_downlist
		# up
		else
			usage down $1
			echo "$1 ${ip_mac} ${ip_name// /_} `date +%s` ${ip_interface}" >> ${dir}ipAddress
			blackwhitelist ${ip_mac};local ip_blackwhite=$?
			[ -f "${dir}send_enable.lock" ] || [ -z "$notification_online" ] || [ -z "$ip_blackwhite" ] && LockFile unlock && return
			[ -z "$ip_blackwhite" ] || [ "$ip_blackwhite" -ne "0" ] && LockFile unlock && return

			[ -f "${dir}title" ] && local title=`cat ${dir}title`
			[ -f "${dir}content" ] && local content=`cat ${dir}content`
			if [ -z "$title" ]; then
				local title="$ip_name 连接了你的路由器"
				local content="${str_splitline}${str_title_start} 新设备连接${str_title_end}${str_linefeed}${str_tab}客户端名：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP： ${str_space}${str_space}${str_space}${str_space}${1}${str_linefeed}${str_tab}客户端MAC：${str_space}${str_space}${str_space}${str_space}${ip_mac}${str_linefeed}${str_tab}网络接口：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_interface}"
			elif ( echo ${title}|grep -q "连接了你的路由器" ); then
				local title="${ip_name} ${title}"
				local content="${str_splitline}${str_tab}客户端名：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP： ${str_space}${str_space}${str_space}${str_space}${1}${str_linefeed}${str_tab}客户端MAC：${str_space}${str_space}${str_space}${str_space}${ip_mac}${str_linefeed}${str_tab}网络接口：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_interface}"
			else
				local title="设备状态变化"
				local content="${str_splitline}${str_title_start} 新设备连接${str_title_end}${str_linefeed}${str_tab}客户端名：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP： ${str_space}${str_space}${str_space}${str_space}${1}${str_linefeed}${str_tab}客户端MAC：${str_space}${str_space}${str_space}${str_space}${ip_mac}${str_linefeed}${str_tab}网络接口：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_interface}"
			fi
			echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}新设备 ${ip_name} ${1} 连接了">> ${logfile}
			#[ ! -z "$up_down_push_blacklist" ] && local title="你偷偷关注的设备上线了"
			[ ! -z "$title" ] && echo "$title" >${dir}title
			[ ! -z "$content" ] && echo -n "$content" >>${dir}content
		fi
	fi
	LockFile unlock
}

# 检测设备离线
function down(){
	local ip_mac=`getmac $1`
	local ip_name=`getname ${1} ${ip_mac}`
	local ip_interface=`getinterface ${ip_mac}`

	tmp_timeout=$down_timeout && tmp_retry_count=$timeout_retry_count
	[ -n "$only_timeout_push" ] && blackwhitelist ${ip_mac};local ip_blackwhite=$? && [ "$ip_blackwhite" -ne "0" ] && tmp_timeout=10 && tmp_retry_count=2
	getping ${1} ${ip_mac} ${tmp_timeout} ${tmp_retry_count};local ping_online=$?
	# 离线，置入二次验证区
	if [ "$ping_online" -eq "1" ]; then
		LockFile lock
		[ ! -f "${dir}send_enable.lock" ] && cat ${dir}ipAddress|grep -w ${1}|grep -v "^$"|sort -u|head -n1 >> ${dir}tmp_downlist
		sed -i "/^${1} /d" ${dir}ipAddress
		sed -i "/^${1} /d" ${dir}gateway_info
		rm -f ${dir}client/${1} >/dev/null 2>&1
		LockFile unlock
	# 更新主机名或 MAC
	else
		local tmp_name=`cat ${dir}ipAddress|grep -w ${1}|awk '{print $3}'|grep -v "^$"|sort -u|head -n1`
		local tmp_mac=`cat ${dir}ipAddress|grep -w ${1}|awk '{print $2}'|grep -v "^$"|sort -u|head -n1`
		if [ ${ip_name// /_} != ${tmp_name} ] || [ ${ip_mac} != ${tmp_mac} ]; then
			LockFile lock
			olduptime=$(cat ${dir}ipAddress|grep -w ${1}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1)
			sed -i "/^${1} /d" ${dir}ipAddress
			[ ${ip_mac} != ${tmp_mac} ] && ip_name="unknown" # MAC 变化时应删除主机名重新获取
			echo "$1  ${ip_mac} ${ip_name// /_} ${olduptime} ${ip_interface}" >> ${dir}ipAddress
			LockFile unlock
		fi
		local time_up=`cat ${dir}ipAddress|grep -w ${1}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`
		local time1=`date +%s`
		local time1=$(time_for_humans `expr ${time1} - ${time_up}`)
		echo "{'ip': '${1}','mac': '${ip_mac}','name': '${ip_name}','uptime': '${time1}','interface': '${ip_interface}','usage': '`usage get $ip_mac`'}" > ${dir}client/${1}
	fi
}

# 设备离线通知
function down_send(){
	[ ! -f "${dir}tmp_downlist" ] && return

	local IPLIST=`cat ${dir}tmp_downlist|awk '{print $1}'`
	for ip in $IPLIST; do
		local ip_mac=`getmac ${ip}`
		blackwhitelist ${ip_mac};local ip_blackwhite=$?
		[ -z "$notification_offline" ] || [ -z "$ip_blackwhite" ] && continue
		[ -z "$ip_blackwhite" ] || [ "$ip_blackwhite" -ne "0" ] && continue
		[ ! -z "$up_down_push_blacklist" ] && local tmp_mac=`echo "${up_down_push_blacklist}"|grep -w -i ${ip_mac}`
		[ ! -z "$up_down_push_whitelist" ] && local tmp_mac=`echo "${up_down_push_whitelist}"|grep -w -i ${ip_mac}`
		[ ! -z "$tmp_mac" ] && ( cat ${dir}ipAddress|grep -q -w -i ${tmp_mac} ) && continue

		local ip_name=`getname ${ip} ${ip_mac}`
		local time_up=`cat ${dir}tmp_downlist|grep -w ${ip}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`
		local ip_total=`usage get $ip_mac` && [ ! -z "$ip_total" ] && local ip_total="${str_linefeed}${str_tab}总计流量： ${str_space}${str_space}${str_space}${str_space}${ip_total}"
		local time1=`date +%s`
		local time1=$(time_for_humans `expr ${time1} - ${time_up}`)
		if [ -z "$title" ]; then
			title="${ip_name} 断开连接"
			content="${content}${str_splitline}${str_title_start} 设备断开连接${str_title_end}${str_linefeed}${str_tab}客户端名：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP： ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC：${str_space}${str_space}${str_space}${str_space}${ip_mac}$ip_total${str_linefeed}${str_tab}在线时间： ${str_space}${str_space}${str_space}${str_space}${time1}"
		elif ( echo "$title"|grep -q "断开连接" ); then
			title="${ip_name} ${title}"
			content="${content}${str_splitline}${str_tab}客户端名：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP： ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC：${str_space}${str_space}${str_space}${str_space}${ip_mac}$ip_total${str_linefeed}${str_tab}在线时间： ${str_space}${str_space}${str_space}${str_space}${time1}"
		else
			title="设备状态变化"
			content="${content}${str_splitline}${str_title_start} 设备断开连接${str_title_end}${str_linefeed}${str_tab}客户端名：${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP： ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC：${str_space}${str_space}${str_space}${str_space}${ip_mac}$ip_total${str_linefeed}${str_tab}在线时间： ${str_space}${str_space}${str_space}${str_space}${time1}"
		fi
		echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}设备 ${ip_name} ${ip} 断开连接 " >> ${logfile}
	done

	rm -f ${dir}tmp_downlist >/dev/null 2>&1
}

# 当前设备列表
function current_device(){
	( echo "$lite_enable"|grep -q "content" ) || ( echo "$lite_enable"|grep -q "device" ) && return
	[ -f ${dir}ipAddress ] && local logrow=$(grep -c "" ${dir}ipAddress) || local logrow="0";[ $logrow -eq "0" ] && return

	[ -f ${dir}usage.db ] && local ip_total_db="总计流量${str_space}${str_space}${str_space}${str_space}"
	content="${content}${str_splitline}${str_title_start} 现有在线设备 ${logrow} 台，具体如下${str_title_end}${str_linefeed}${str_tab}IP 地址${str_space}${str_space}${str_space}${str_space}${str_space}${str_space}${str_space}${str_space}${str_space}${ip_total_db}客户端名"
	local IPLIST=`cat ${dir}ipAddress|awk '{print $1}'`
	for ip in $IPLIST; do
		local ip_mac=`getmac ${ip}`
		local ip_total=`usage get ${ip_mac}`
		local ip_name=`getname ${ip} ${ip_mac}`
		local ip_name=`cut_str "$ip_name" "15"`
		if [ "${#ip}" -lt "15" ]; then
			local n=`expr 15 - ${#ip}`
			for i in `seq 1 $n`; do
				local ip="${ip}${str_space}"
			done
			unset i n
		fi
		if [ ! -z "$ip_total" ]; then
			local n=`expr 11 - ${#ip_total}`
			for i in `seq 1 $n`; do
				local ip_total="${ip_total}${str_space}"
			done
		fi
		content="${content}${str_linefeed}${str_tab}${ip}${ip_total}${ip_name}"
		unset i n ip_total ip_mac ip_name
	done
}

# 检测 cpu 状态
function cpu_load(){
	if [ -n "$notification_temp" ] && [ -n "$temperature_threshold" ]; then
		[ -z "$temp_last_overload_time" ] && temp_last_overload_time=`date +%s`
		local cpu_temp=`soc_temp`;

		if [ ! -z "$cpu_temp" ] && [ `expr $cpu_temp \> $temperature_threshold` -eq "1" ]; then
			echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！警报！！】 CPU 温度过高: ${cpu_temp}" >> ${logfile}
		else
			temp_last_overload_time=`date +%s`
		fi

		if [ ! -z "$cpu_temp" ] && [ "$((`date +%s`-$temp_last_overload_time))" -ge "300" ] && [ -z "$temperaturecd_time" ]; then
			title="CPU 温度过高！"
			temperaturecd_time=`date +%s`
			echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text} CPU 温 度过高: ${cpu_temp}" >> ${logfile}
			content="${content}${str_splitline}${str_title_start} CPU 温度过高${str_title_end}${str_linefeed}${str_tab}CPU 温度已连续五分钟超过预设${str_linefeed}${str_tab}接下来一小 时不再提示${str_linefeed}${str_tab}当前温度：${cpu_temp}℃"
		elif [ ! -z "$temperaturecd_time" ] && [ "$((`date +%s`-$temperaturecd_time))" -ge "3300" ] ;then
			unset temperaturecd_time
		fi
	fi

	if [ -n "$notification_load" ] && [ -n "$cpu_load_threshold" ]; then
		[ -z "$cpu_last_overload_time" ] && cpu_last_overload_time=`date +%s`
		local cpu_fuzai=`cat /proc/loadavg|awk '{print $1}'` 2>/dev/null

		if [ ! -z "$cpu_fuzai" ] && [ `expr $cpu_fuzai \> $cpu_load_threshold` -eq "1" ]; then
			echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！警报！！】 CPU 负载过高: ${cpu_fuzai}" >> ${logfile}
			cputop log
		elif [ ! -z "$cpu_fuzai" ]; then
			cpu_last_overload_time=`date +%s`
		fi

		if [ ! -z "$cpu_fuzai" ] && [ "$((`date +%s`-$cpu_last_overload_time))" -ge "300" ] && [ -z "$cpucd_time" ]; then
			unset getlogtop
			if [ ! -z "$title" ] && ( echo "$title"|grep -q "过高" ); then
				title="设备报警！"
			else
				title="CPU 负载过高！"
			fi
			cpucd_time=`date +%s`
			echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text} CPU 负 载过高: ${cpu_fuzai}" >> ${logfile}
			content="${content}${str_splitline}${str_title_start} CPU 负载过高${str_title_end}${str_linefeed}${str_tab}CPU 负载已连续五分钟超过预设${str_linefeed}${str_tab}接下来一小 时不再提示${str_linefeed}${str_tab}当前负载：${cpu_fuzai}"
			cputop
		elif [ ! -z "$cpucd_time" ] && [ "$((`date +%s`-$cpucd_time))" -ge "3300" ] ;then
			unset cpucd_time
		fi
	fi
}

# CPU 占用前三
function cputop(){
	[ -z "$1" ] && content="${content}${str_splitline}${str_title_start} 当前 CPU 占用前三的进程${str_title_end}"
	local gettop=`top -bn 1|grep -v "top -bn 1"`
	for i in `seq 5 7`; do
		local top_name=`echo "${gettop}"|awk 'NR=='${i}|awk '{print ($8 ~ /\/bin\/sh|\/bin\/bash/) ? $9 : $8}'`
		local top_load=`echo "${gettop}"|awk 'NR=='${i}|awk '{print $7}'`
		local temp_top="${top_name} ${top_load}"
		[ ! -z "$1" ] && local logtop="$logtop  $temp_top"
		[ -z "$1" ] && content="${content}${str_linefeed}${str_tab}${temp_top}"
	done
	unset i
	[ ! -z "$1" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！警报！！】 CPU 占用前三: ${logtop}" >> ${logfile}
}

# 检测硬盘状态
function get_disk() {
	mkdir -p "${dir}disk_info"
	local_disk_names=()
	pve_disk_names=()

	# 查询本地硬盘名
	local_disk_names=($(lsblk | awk '$NF=="disk" {print $1}' | sort -u))
	local_disk_tags=($(for _ in "${local_disk_names[@]}"; do echo "local"; done))

	# 查询远程硬盘名
	if [ -n "$server_host" ]; then
		ssh_command="ssh -o StrictHostKeyChecking=yes -o BatchMode=yes -i /root/.ssh/id_rsa root@${server_host} -p ${server_port}"
		pve_disk_names=($(eval ${ssh_command} lsblk | awk '$NF=="disk" {print $1}' | sort -u))
		pve_disk_tags=($(for _ in "${pve_disk_names[@]}"; do echo "pve"; done))
	fi

	# 合并本地和远程硬盘名及标记
	all_disk_names=("${local_disk_names[@]}" "${pve_disk_names[@]}")
	all_disk_tags=("${local_disk_tags[@]}" "${pve_disk_tags[@]}")

	for i in "${!all_disk_names[@]}"; do
		tmp_name=${all_disk_names[i]}
		tmp_tag=${all_disk_tags[i]}
		error_pattern="No such device|Unable to detect device type|Unknown USB bridge|QEMU HARDDISK"
		unset tmp_command disk_type disk_err

		# 判断硬盘类型
		if [ "$tmp_tag" == "pve" ]; then
			tmp_command="$ssh_command"
			disk_type="_pve"
		fi
		file_path="${dir}disk_info/${tmp_name}${disk_type}"

		# 如果不能获取值，使用分区名重试（因为不清楚是 OpenWrt 的原因还是 smartctl 版本的原因，使用出错重试的方式）
		eval ${tmp_command} smartctl -i -n standby "/dev/${tmp_name}" | grep -qE "$error_pattern" && {
			tmp_name=$(df -h | awk "/^\\/dev\\/${tmp_name}/ {print \$1}" | awk -F '/' '{print $NF}' | head -n1)
			[ -z "$tmp_name" ] && continue
		}

		# 手上的硬盘不能休眠，不确定命令是否会唤醒硬盘，每天只运行一次
		last_disk_time=$(date -r "${file_path}" +%s 2>/dev/null) || last_disk_time=0

		if [ $(( $(date +%s) - $last_disk_time )) -gt 86000 ]; then
			disk_info=$(eval ${tmp_command} smartctl -i -n standby "/dev/${tmp_name}")
			echo "$disk_info" | grep -qE "$error_pattern" && {
				continue
			} || \
			echo "$disk_info" | grep -q "STANDBY" && {
				echo "$disk_info" > "${file_path}"
			} || \
			eval ${tmp_command} smartctl -a -j /dev/${tmp_name} > ${file_path}
		fi

		# 硬盘状态
		if [ -f "${file_path}" ] && ( ! cat "${file_path}" | grep -q -v "STANDBY" ); then
			disk_name=$(awk '/Device Model/{print $NF}' "$file_path")
			[[ -n $disk_name && $disk_name != null && $disk_name != 0 ]] && {
				disk_name=$(cut_str "$disk_name" "20")
				disk_name="${disk_name}_$(eval ${tmp_command} lsblk -o NAME,SIZE | awk "/^${all_disk_names[i]}/ {print \$NF}")"
			}
			printf "${str_linefeed}${str_title_start} 硬盘名称：${disk_name}${disk_type}${str_title_end}${str_linefeed}${str_tab}硬盘休眠中" >> "$output_dir/get_disk"
		elif [ -f "${file_path}" ]; then
			# 硬盘名称
			disk_name=$(jq -r .model_name ${file_path})
			[[ -n $disk_name && $disk_name != null && $disk_name != 0 ]] && {
				disk_name=$(cut_str "$disk_name" "20")
				disk_name="${disk_name}_$(eval ${tmp_command} lsblk -o NAME,SIZE | awk "/^${all_disk_names[i]}/ {print \$NF}")"
			}
			printf "${str_linefeed}${str_title_start} 硬盘名称：${disk_name}${disk_type}${str_title_end}" >> "$output_dir/get_disk"
			# 硬盘温度
			disk_temp=$(jq -r .temperature.current ${file_path})
			[[ -n $disk_temp && $disk_temp != null && $disk_temp != 0 ]] && printf "${str_linefeed}${str_tab}硬盘温度：${disk_temp}℃" >> "$output_dir/get_disk"
			# 通电时间
			disk_time=$(jq -r .power_on_time.hours ${file_path})
			[[ -n $disk_time && $disk_time != null ]] && printf "${str_linefeed}${str_tab}通电时间：${disk_time}h" >> "$output_dir/get_disk"
			# 空间使用
			disk_use=$(eval ${tmp_command} lsblk -o NAME,FSUSE%,TYPE | awk -v part_name="${all_disk_names[i]}" '$NF == "part" && $1 ~ part_name && NF > 2 {sub(".*" part_name, part_name, $1); printf "%s: %s  ", $1, $2} END {print ""}')
			[ -n "$disk_use" ] && [ -n "${disk_use// }" ] && echo -e -n "${str_linefeed}${str_tab}空间使用：${disk_use}" >> "$output_dir/get_disk"
			# 寿命使用
			disk_health=$(jq -r .nvme_smart_health_information_log.percentage_used ${file_path})
			[[ -n $disk_health && $disk_health != null ]] && echo -e -n "${str_linefeed}${str_tab}寿命使用：${disk_health}%" >> "$output_dir/get_disk"
			# 错误日志
			disk_log_err=$(jq -r .ata_smart_error_log.summary.count ${file_path})
			[[ -n $disk_log_err && $disk_log_err != null && $disk_log_err != 0 ]] && disk_err="true" && printf "${str_linefeed}${str_tab}错误日志：${disk_log_err}" >> "$output_dir/get_disk"
			# 自检错误
			disk_test_err=$(jq -r .ata_smart_self_test_log.standard.error_count_total ${file_path})
			[[ -n $disk_test_err && $disk_test_err != null && $disk_test_err != 0 ]] && disk_err="true" && printf "${str_linefeed}${str_tab}自检错误：${disk_test_err}" >> "$output_dir/get_disk"
			# 0E 错误
			disk_0e_err=$(jq -r .nvme_smart_health_information_log.media_errors ${file_path})
			[[ -n $disk_0e_err && $disk_0e_err != null && $disk_0e_err != 0 ]] && disk_err="true" && printf "${str_linefeed}${str_tab}0E 错误：${disk_0e_err}" >> "$output_dir/get_disk"
			# 整体健康
			smart_status=$(jq -r .smart_status.passed ${file_path})
			[[ -n $smart_status && $smart_status != null && $smart_status != "true" ]] && {
				echo -e -n "${str_linefeed}${str_tab}${str_title_start}硬盘整体健康评估不通过!!!${str_title_end}" >> "$output_dir/get_disk"
				disk_err="true"
			}
			[ -n "$disk_err" ] && echo -e -n "${str_linefeed}${str_tab}${str_title_start}硬盘存在错误，请及时备份数据!!!${str_title_end}" >> "$output_dir/get_disk"
		fi
	done
}


# 查询 IP 归属地
function get_ip_attribution(){
	ip="$1"
	[ -f ${dir}ipAddress ] && ( cat ${dir}ipAddress|grep -q -w -i "$ip" ) && echo "本地网络" && return
	ip_attribution_urls=$(cat /usr/share/wechatpush/api/ip_attribution.list)
	while IFS= read -r ip_attribution_command; do
		login_ip_attribution=$(eval "$ip_attribution_command" 2>/dev/null)
		[ "$login_ip_attribution" == "null" ] && unset login_ip_attribution
		[ -n "$login_ip_attribution" ] && break
	done <<< "$ip_attribution_urls"
	echo "$login_ip_attribution"
}

# 登录提醒通知
function login_send(){
	[ -n "$login_web_black" ] && [ "$login_web_black" -eq "1" ] && init_ip_black "ipv4"
	[ -n "$login_web_black" ] && [ "$login_web_black" -eq "1" ] && init_ip_black "ipv6"
	[ -n "$port_knocking_enable" ] && [ "$port_knocking_enable" -eq "1" ] && init_ip_white "ipv4"
	[ -n "$port_knocking_enable" ] && [ "$port_knocking_enable" -eq "1" ] && init_ip_white "ipv6"
	tmp_ip_list=`echo "$login_ip_white_list"|grep -v "^$"|sort -u`
	while IFS= read -r tmp_ip; do
		[ -n "$tmp_ip" ] && add_ip_white "$tmp_ip" "0"
	done <<< "$tmp_ip_list"
	[ -z "$web_logged" ] && [ -z "$ssh_logged" ] && [ -z "$web_login_failed" ] && [ -z "$ssh_login_failed" ] && return
	set_ip_black
	sys_log=$(logread notice)

	# Web 登录提醒
	[ -f ${dir}web_login ] && for login_ip in `cat ${dir}web_login | sort -u`; do
		[ -z "$login_ip" ] && continue
		local login_time=$(echo "$sys_log" | grep -w ${login_ip} | awk '{print $4}' | tail -n 1)
		local login_mode=$(echo "$sys_log" | grep -w ${login_ip} | awk '{print $13}' | tail -n 1)
		unset log_only content_attribution content_mode
		echo "$login_ip_white_list" | grep -w -q "$login_ip" && log_only="1" && [ -n "$login_log_enable" ] && continue
		if [ -z "$log_only" ] && [ ! -z "$login_disturb" ] && [ "$login_disturb" -eq "2" ]; then
			[ -f "$logfile" ] && login_log=$(grep -w "$login_ip" "$logfile" | grep -v "\【info\】" | tail -n 1)
			[ ! -z "$login_log" ] && log_timestamp=$(date -d "$(echo "$login_log" | awk '{print $1, $2}')" +%s) || log_timestamp=0
			[ $(($(date +%s) - log_timestamp)) -lt $login_notification_delay ] && log_only="1" && [ -n "$login_log_enable" ] && continue
		fi
		[ -n "$log_only" ] && echo "`date "+%Y-%m-%d"` ${login_time} 【info】设备 ${login_ip} 通过 Web ${login_mode} 登录了路由器 " >> ${logfile} && continue

		login_ip_attribution=$(get_ip_attribution ${login_ip})
		[ -n "$login_ip_attribution" ] && content_attribution="${str_linefeed}${str_tab}IP 归属地： ${str_space}${str_space}${str_space}${str_space}${login_ip_attribution}"
		[ -n "$login_mode" ] && content_mode="${str_linefeed}${str_tab}登录方式： ${str_space}${str_space}${str_space}${str_space}${login_mode}"
		if { [ -z "$login_disturb" ] || [ "$login_disturb" -ne "1" ]; }; then
			if [ -z "$title" ]; then
				title="${login_ip} 通过 Web 登录了路由器"
				content="${content}${str_splitline}${str_title_start} 登录信息${str_title_end}${str_linefeed}${str_tab}时间：${str_space}${str_space}${str_space}${str_space}${str_space}${login_time}${str_linefeed}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}${content_mode}"
			elif ( echo "$title"|grep -q "登录了路由器" ); then
				title="${login_ip} ${title}"
				content="${content}${str_splitline}${str_tab}时间：${str_space}${str_space}${str_space}${str_space}${str_space}${login_time}${str_linefeed}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}${content_mode}"
			else
				title="${login_ip} 通过 Web 登录了路由器"
				content="${content}${str_splitline}${str_title_start} 登录信息${str_title_end}${str_linefeed}${str_tab}时间：${str_space}${str_space}${str_space}${str_space}${str_space}${login_time}${str_linefeed}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}${content_mode}"
			fi
		fi
		echo "`date "+%Y-%m-%d"` ${login_time} ${disturb_text}设备 ${login_ip} (${login_ip_attribution}) 通过 Web ${login_mode} 登录了路由器 " >> ${logfile}
	done
	rm -f ${dir}web_login >/dev/null 2>&1
	unset login_ip login_time login_mode
	# SSH 登录提醒
	[ -f ${dir}ssh_login ] && for login_ip in `cat ${dir}ssh_login | sort -u`; do
		[ -z "$login_ip" ] && continue
		local login_time=$(echo "$sys_log" | grep -w ${login_ip} | awk '{print $4}' | tail -n 1)
		local login_mode=$(echo "$sys_log" | grep -w ${login_ip} | awk '{print $8}' | tail -n 1)
		unset log_only content_attribution content_mode
		echo "$login_ip_white_list"|grep -w -q "$login_ip" && log_only="1" && [ -n "$login_log_enable" ] && continue
		if [ -z "$log_only" ] && [ ! -z "$login_disturb" ] && [ "$login_disturb" -eq "2" ]; then
			[ -f "$logfile" ] && login_log=$(grep -w "$login_ip" "$logfile" | grep -v "\【info\】" | tail -n 1)
			[ ! -z "$login_log" ] && log_timestamp=$(date -d "$(echo "$login_log" | awk '{print $1, $2}')" +%s) || log_timestamp=0
			[ $(($(date +%s) - log_timestamp)) -lt $login_notification_delay ] && log_only="1" && [ -n "$login_log_enable" ] && continue
		fi
		[ -n "$log_only" ] && echo "`date "+%Y-%m-%d"` ${login_time} 【info】设备 ${login_ip} 通过 SSH ${login_mode} 登录了路由器 " >> ${logfile} && continue

		login_ip_attribution=$(get_ip_attribution ${login_ip})
		[ -n "$login_ip_attribution" ] && content_attribution="${str_linefeed}${str_tab}IP 归属地： ${str_space}${str_space}${str_space}${str_space}${login_ip_attribution}"
		[ ! -z "$login_mode" ] && content_mode="${str_linefeed}${str_tab}登录方式： ${str_space}${str_space}${str_space}${str_space}${login_mode}"
		if { [ -z "$login_disturb" ] || [ "$login_disturb" -ne "1" ]; }; then
			if [ -z "$title" ]; then
				title="${login_ip} 通过 SSH 登录了路由器"
				content="${content}${str_splitline}${str_title_start} 登录信息${str_title_end}${str_linefeed}${str_tab}时间：${str_space}${str_space}${str_space}${str_space}${str_space}${login_time}${str_linefeed}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}${content_mode}"
			elif ( echo "$title"|grep -q "登录了路由器" ); then
				title="${login_ip} ${title}"
				content="${content}${str_splitline}${str_tab}时间：${str_space}${str_space}${str_space}${str_space}${str_space}${login_time}${str_linefeed}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}${content_mode}"
			else
				title="${login_ip} 通过 SSH 登录了路由器"
				content="${content}${str_splitline}${str_title_start} 登录信息${str_title_end}${str_linefeed}${str_tab}时间：${str_space}${str_space}${str_space}${str_space}${str_space}${login_time}${str_linefeed}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}${content_mode}"
			fi
		fi
		echo "`date "+%Y-%m-%d"` ${login_time} ${disturb_text}设备 ${login_ip} (${login_ip_attribution}) 通过 SSH ${login_mode} 登录了路由器 " >> ${logfile}
	done
	rm -f ${dir}ssh_login >/dev/null 2>&1
	unset login_ip login_time login_mode
	# Web 非法登录
	[ -f ${dir}web_failed ] && for login_ip in `cat ${dir}web_failed | sort -u`; do
		[ -z "$login_ip" ] && continue
		login_ip_attribution=$(get_ip_attribution ${login_ip})
		[ -n "$login_ip_attribution" ] && content_attribution="${str_linefeed}${str_tab}IP 归属地： ${str_space}${str_space}${str_space}${str_space}${login_ip_attribution}" || unset content_attribution
		echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】设备 ${login_ip} (${login_ip_attribution}) 通过 Web 频繁尝试登录" >> ${logfile}
		[ -n "$login_disturb" ] && [ "$login_disturb" -eq "1" ] && continue
		if [ -z "$title" ]; then
			title="${login_ip} 通过 Web 频繁尝试登录"
			content="${content}${str_splitline}${str_title_start} 登录信息${str_title_end}${str_linefeed}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}"
		elif ( echo "$title"|grep -q "频繁尝试登录" ); then
			title="${login_ip} ${title}"
			content="${content}${str_splitline}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}"
		else
			title="设备状态变化"
			content="${content}${str_splitline}${str_title_start} 登录信息${str_title_end}${str_linefeed}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}"
		fi
	done
	rm -f ${dir}web_failed >/dev/null 2>&1
	unset login_ip
	# SSH 非法登录
	[ -f ${dir}ssh_failed ] && for login_ip in `cat ${dir}ssh_failed | sort -u`; do
		[ -z "$login_ip" ] && continue
		login_ip_attribution=$(get_ip_attribution ${login_ip})
		[ -n "$login_ip_attribution" ] && content_attribution="${str_linefeed}${str_tab}IP 归属地： ${str_space}${str_space}${str_space}${str_space}${login_ip_attribution}" || unset content_attribution
		echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】设备 ${login_ip} (${login_ip_attribution}) 通过 SSH 频繁尝试登录" >> ${logfile}
		[ -n "$login_disturb" ] && [ "$login_disturb" -eq "1" ] && continue
		if [ -z "$title" ]; then
			title="${login_ip} 通过 SSH 频繁尝试登录"
			content="${content}${str_splitline}${str_title_start} 登录信息${str_title_end}${str_linefeed}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}"
		elif ( echo "$title"|grep -q "频繁尝试登录" ); then
			title="${login_ip} ${title}"
			content="${content}${str_splitline}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}"
		else
			title="设备状态变化"
			content="${content}${str_splitline}${str_title_start} 登录信息${str_title_end}${str_linefeed}${str_tab}设备 IP： ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_attribution}"
		fi
	done
	rm -f ${dir}ssh_failed >/dev/null 2>&1
	unset login_ip
}

# 添加白名单，懒得写删除项和信息显示了，纯粹就是懒
function add_ip_white() {
	[ -n "$port_knocking_enable" ] && [ "$port_knocking_enable" -eq "1" ] || return
	[ -z "$2" ] && timeout=$login_ip_white_timeout || timeout=$2
	# 检查 IP 版本
	( echo "$1"|grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$' ) && local ipset_name="wechatpush_whitelist"
	( echo "$1"|grep -Eq '^([\da-fA-F0-9]{1,4}(:{1,2})){1,15}[\da-fA-F0-9]{1,4}$' ) && local ipset_name="wechatpush_whitelistv6"
	[ -z "$ipset_name" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】白名单添加失败，IP 格式错误" >> ${logfile} && return

	[ -n "$nftables_version" ] && nft delete element inet fw4 $ipset_name { $1 } >/dev/null 2>&1
	[ -n "$nftables_version" ] && nft add element inet fw4 $ipset_name { $1 expires ${timeout}s } && return #没找到刷新时间的命令，删除再添加
	ipset -exist add $ipset_name $1 timeout $timeout
}

# 初始化白名单
function init_ip_white() {
	[ -n "$port_knocking_enable" ] && [ "$port_knocking_enable" -eq "1" ] || return
	# 设置 IP 版本变量
	if [ $1 == "ipv4" ]; then
		ipset_name="wechatpush_whitelist"
		ip_version="ip"
	elif [ $1 == "ipv6" ]; then
		ipset_name="wechatpush_whitelistv6"
		ip_version="ip6"
		nat_table_cmd="family inet6"
	fi

	if [ -n "$nftables_version" ]; then
		! nft list set inet fw4 $ipset_name >/dev/null 2>&1 && nft add set inet fw4 $ipset_name { type ${1}_addr\; flags timeout\; timeout ${login_ip_white_timeout}s\; }
		nft -- add chain inet fw4 wechatpush_dstnat { type nat hook prerouting priority -100 \; }
		nft add chain inet fw4 wechatpush_srcnat { type nat hook postrouting priority 100 \; }
	else
		! ipset list $ipset_name >/dev/null 2>&1 && ipset create $ipset_name hash:ip timeout $login_ip_white_timeout $nat_table_cmd >/dev/null 2>&1
	fi

	# 端口放行
	if [ ! -z "$login_port_white" ]; then
		local login_port_white=`echo "$login_port_white"|sed 's/ //g'|sed 's/,/, /g'` 2>/dev/null
		if [ -n "$nftables_version" ]; then
			local count_accept_rules=`nft list ruleset | grep -c "tcp dport.* ${login_port_white}.* $ip_version saddr @${ipset_name} counter packets .* accept comment \"\!wechatpush Accept rule\""`
			if [ $count_accept_rules -eq 0 ]; then
				nft insert rule inet fw4 input tcp dport { $login_port_white } $ip_version saddr @$ipset_name counter accept comment \"\!wechatpush Accept rule\" >/dev/null 2>&1
			elif [ $count_accept_rules -ne 1 ]; then
				local i=0
				local handles=`nft --handle list ruleset | grep "\!wechatpush Accept rule" | grep -v "tcp dport.* ${login_port_white}.* $ip_version saddr @${ipset_name} counter packets .* accept comment \"\!wechatpush Accept rule\"" | awk '{print $NF}'`
				for handle in $handles; do
					[ $i -eq 0 ] && i=1 && continue
					nft delete rule $handle
				done
			fi
		else
			${ip_version}tables -C INPUT -m set --match-set $ipset_name src -p tcp -m multiport --dport $login_port_white -j ACCEPT >/dev/null 2>&1 || ${ip_version}tables -I INPUT -m set --match-set $ipset_name src -p tcp -m multiport --dport $login_port_white -j ACCEPT >/dev/null 2>&1
		fi
	fi
	unset handle
	# 端口转发
	while IFS= read -r port_forward; do
		port_forward=`echo "$port_forward"|sed 's/,/ /g'` 2>/dev/null
		[ `echo $port_forward| awk -F" " '{print NF}'` -ne "4" ] && continue
		local src_ip=`echo ${port_forward}|awk '{print $1}'`
		local src_port=`echo ${port_forward}|awk '{print $2}'`
		local dst_ip=`echo ${port_forward}|awk '{print $3}'`
		local dst_port=`echo ${port_forward}|awk '{print $4}'`
		if [ -n "$nftables_version" ]; then
			! nft list ruleset|grep "$ip_version saddr @${ipset_name} tcp dport $src_port counter .* dnat $ip_version to $dst_ip:$dst_port comment \"\!wechatpush DNAT rule\"" >/dev/null 2>&1 && nft insert rule inet fw4 wechatpush_dstnat meta nfproto $1 $ip_version saddr @${ipset_name} tcp dport $src_port counter dnat to "$dst_ip:$dst_port" comment \"\!wechatpush DNAT rule\" >/dev/null 2>&1
			! nft list ruleset|grep "$ip_version daddr $dst_ip tcp dport $dst_port counter .* snat $ip_version to $src_ip comment \"\!wechatpush SNAT rule\"" >/dev/null 2>&1 && nft insert rule inet fw4 wechatpush_srcnat $ip_version daddr $dst_ip tcp dport $dst_port counter snat to $src_ip comment \"\!wechatpush SNAT rule\" >/dev/null 2>&1
		else
			${ip_version}tables -t nat -C PREROUTING -m set --match-set $ipset_name src -p tcp --dport $src_port -j DNAT --to-destination "$dst_ip:$dst_port" >/dev/null 2>&1 || ${ip_version}tables -t nat -I PREROUTING -m set --match-set $ipset_name src -p tcp --dport $src_port -j DNAT --to-destination "$dst_ip:$dst_port" >/dev/null 2>&1
			${ip_version}tables -t nat -C POSTROUTING -m set --match-set $ipset_name src -p tcp -d $dst_ip --dport $dst_port -j SNAT --to-source $src_ip >/dev/null 2>&1 || ${ip_version}tables -t nat -I POSTROUTING -m set --match-set $ipset_name src -p tcp -d $dst_ip --dport $dst_port -j SNAT --to-source $src_ip >/dev/null 2>&1
		fi
	done <<< "$login_port_forward_list"
	unset port_forward
}

# 初始化黑名单规则
function init_ip_black(){
	[ -n "$login_web_black" ] && [ "$login_web_black" -eq "1" ] || return
	# 设置 IP 版本变量
	if [ $1 == "ipv4" ]; then
		ipset_name="wechatpush_blacklist"
		ip_version="ip"
	elif [ $1 == "ipv6" ]; then
		ipset_name="wechatpush_blacklistv6"
		ip_version="ip6"
		nat_table_cmd="family inet6"
	fi

	if [ -n "$nftables_version" ]; then
		! nft list set inet fw4 ${ipset_name} >/dev/null 2>&1 && nft add set inet fw4 ${ipset_name} { type ${1}_addr\; flags timeout\; timeout ${login_ip_black_timeout}s\; }
		! nft list ruleset|grep "$ip_version saddr @${ipset_name} counter .* comment \"\!wechatpush Drop rule\"" >/dev/null 2>&1 && nft insert rule inet fw4 input $ip_version saddr @${ipset_name} counter drop comment \"\!wechatpush Drop rule\" >/dev/null 2>&1
	else
		ipset list $ipset_name >/dev/null 2>&1 || ipset create ${ipset_name} hash:ip timeout ${login_ip_black_timeout} ${nat_table_cmd} >/dev/null 2>&1
		${ip_version}tables -C INPUT -m set --match-set ${ipset_name} src -j DROP >/dev/null 2>&1 || ${ip_version}tables -I INPUT -m set --match-set ${ipset_name} src -j DROP >/dev/null 2>&1
	fi
}

# 添加黑名单
function add_ip_black(){
	[ ! "$1" ] && return
	echo "$login_ip_white_list"|grep -w -q "$1" && return
	# 检查 IP 版本
	( echo "$1"|grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$' ) && ipset_name="wechatpush_blacklist"
	( echo "$1"|grep -Eq '^([\da-fA-F0-9]{1,4}(:{1,2})){1,15}[\da-fA-F0-9]{1,4}$' ) && ipset_name="wechatpush_blacklistv6"
	[ -z "$ipset_name" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】黑名单添加失败，IP 格式错误" >> ${logfile} && return

	! cat ${ip_blacklist_path}|grep -q -w -i ${1} && echo "$1 timeout ${login_ip_black_timeout}" >> ${ip_blacklist_path}

	[ -n "$nftables_version" ] && nft add element inet fw4 ${ipset_name} { $1 expires ${login_ip_black_timeout}s } >/dev/null 2>&1
	[ -n "$nftables_version" ] && return

	ipset -exist add $ipset_name ${1} timeout ${login_ip_black_timeout}
}

# 移出黑名单
function del_ip_black(){
	[ ! "$1" ] && return
	sed -i "/^${1}/d" ${ip_blacklist_path}

	# 检查 IP 版本
	( echo "$1"|grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$' ) && ipset_name="wechatpush_blacklist"
	( echo "$1"|grep -Eq '^([\da-fA-F0-9]{1,4}(:{1,2})){1,15}[\da-fA-F0-9]{1,4}$' ) && ipset_name="wechatpush_blacklistv6"
	[ -z "$ipset_name" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】黑名单删除失败，IP 格式错误" >> ${logfile} && return

	[ -n "$nftables_version" ] && nft delete element inet fw4 ${ipset_name} { $1 } >/dev/null 2>&1
	[ -n "$nftables_version" ] && return
	ipset list ${ipset_name} >/dev/null 2>&1 && ipset -! del ${ipset_name} ${1}
}

# 设置防火墙列表
function set_ip_black(){
	# 检查换行，避免出错
	[ `tail -n1 "${ip_blacklist_path}" | wc -l` -eq "0" ] && echo -e >> ${ip_blacklist_path}

	# 从 ip_blacklist 文件逐行添加黑名单，add_ip_black() 处验证是否重复
	for ip_black in `cat ${ip_blacklist_path}|awk '{print $1}'`; do
		add_ip_black ${ip_black}
	done
	# 当 ip_blacklist 文件清除 IP 时，从集合中清除 IP
	[ -n "$nftables_version" ] && fw_info_blacklist=$(nft list set inet fw4 wechatpush_blacklist | tr -d '\n' | grep -oE 'elements = \{[^}]*\}' | grep -oE '[^{}]+ expires [^,}]+[,\}]' | tr ',}' '\n' | tr -s ' ' | sed -e 's/^[[:space:]]*//')
	[ -n "$nftables_version" ] && fw_info_blacklistv6=$(nft list set inet fw4 wechatpush_blacklistv6 | tr -d '\n' | grep -oE 'elements = \{[^}]*\}' | grep -oE '[^{}]+ expires [^,}]+[,\}]' | tr ',}' '\n' | tr -s ' ' | sed -e 's/^[[:space:]]*//')
	[ -z "$nftables_version" ] && fw_info_blacklist=$(ipset list wechatpush_blacklist | grep "timeout" 2>/dev/null)
	[ -z "$nftables_version" ] && fw_info_blacklistv6=$(ipset list wechatpush_blacklistv6 | grep "timeout" 2>/dev/null)

	fw_info_blacklist="${fw_info_blacklist}\n${fw_info_blacklistv6}"
	while IFS= read -r ip_black_info; do
		ip_black=$(echo "$ip_black_info"|grep -Eo "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}")
		[ -z "$ip_black" ] && ip_black=$(echo "$ip_black_info"|grep -Eo "([\da-fA-F0-9]{1,4}(:{1,2})){1,15}[\da-fA-F0-9]{1,4}")
		[ -z "$ip_black" ] && continue
		cat ${ip_blacklist_path}|grep -q -w -i ${ip_black} && sed -i "/^${ip_black}/d" ${ip_blacklist_path} && echo ${ip_black_info} >> ${ip_blacklist_path} || del_ip_black ${ip_black}
	done <<< "$fw_info_blacklist"
}

# 发送定时数据
function send(){
	echo "`date "+%Y-%m-%d %H:%M:%S"` 【定时数据】创建定时任务" >> ${logfile}
	disturb;local send_disturb=$?
	get_config "send_title" "send_notification"

	cpuload=`getcpu`
	service_status=$(ubus call service list '{"name": "wechatpush"}' | grep -o '"running": true')
	[ -z "$1" ] && ( echo "$send_notification"|grep -q "client_list" ) && > ${dir}send_enable.lock && [ -z "$service_status" ] && first &
	if [ -z "$1" ] && ( echo "$send_notification"|grep -q "router_status" ); then
		cat /proc/loadavg|awk '{print $1" "$2" "$3}' > "$output_dir/systemload" &
		free -m|sed -n '2p'|awk '{printf "%.2f%%\n",($3/$2)*100}' > "$output_dir/ramload" &
		curl -o /dev/null --connect-timeout 5 -s -w %{http_code} www.google.com > "$output_dir/Qwai" &
		cat /proc/uptime|awk -F. '{run_days=$1 / 86400;run_hour=($1 % 86400)/3600;run_minute=($1 % 3600)/60;run_second=$1 % 60;printf("运行时间：%d天%d时%d分%d秒",run_days,run_hour,run_minute,run_second)}' > "$output_dir/systemstatustime" &
		systeminfo_enable="1"
	fi
	[ -z "$1" ] && ( echo "$send_notification"|grep -q "router_temp" ) && soc_temp > "$output_dir/cputemp" &

	if [ -z "$1" ] && ( echo "$send_notification"|grep -q "wan_info" ); then
		getip wanipv4 > "$output_dir/send_wanIP" &
		getip hostipv4|jq -r '.IP' > "$output_dir/send_hostIP" &
		waninfo_enable="1"
		if [ "$get_ipv6_mode" -ne "0" ]; then
			getip wanipv6 > "$output_dir/send_wanIPv6" &
			getip hostipv6|jq -r '.IP' > "$output_dir/send_hostIPv6" &
			ipv6_enable="1"
		fi
		getinterfaceuptime > "$output_dir/interfaceuptime" &
	fi

	#[ -z "$1" ] && ( echo "$send_notification"|grep -q "disk_info" ) && get_disk &
	[ -z "$1" ] && get_disk &

	[ -z "$send_title" ] && send_title="路由状态："
	[ ! -z "$1" ] && send_title="发送测试：" && send_content="${str_splitline}${str_title_start}内容1${str_title_end}${str_linefeed}${str_tab}设备1${str_linefeed}${str_tab}设备2${str_splitline}${str_title_start}内容2${str_title_end}${str_linefeed}${str_tab}设备3${str_linefeed}${str_tab}设备4"

	wait_and_cat
	if [ -n "$systeminfo_enable" ]; then
		[[ $Qwai -eq 200 || $Qwai -eq 301 || $Qwai -eq 302 ]] && Qwai_status="已连通！" || Qwai_status="已断开！"
		send_content="${send_content}${str_splitline}${str_title_start} 系统运行状态${str_title_end}"
		send_content="${send_content}${str_linefeed}${str_tab}平均负载：${systemload}"
		send_content="${send_content}${str_linefeed}${str_tab}CPU占用：${cpuload}"
		send_content="${send_content}${str_linefeed}${str_tab}内存占用：${ramload}"
		send_content="${send_content}${str_linefeed}${str_tab}全球互联：${Qwai_status}"
		send_content="${send_content}${str_linefeed}${str_tab}${systemstatustime}"
	fi

	if [ -z "$1" ] && ( echo "$send_notification"|grep -q "router_temp" ); then
		[ ! -z "$cputemp" ] && send_content="${send_content}${str_splitline}${str_title_start} 设备温度${str_title_end}${str_linefeed}${str_tab}CPU：${cputemp}℃"
		[ -z "$cputemp" ] && send_content="${send_content}${str_splitline}${str_title_start} 设备温度${str_title_end}${str_linefeed}${str_tab}无法获取设备温度"
	fi

	#if [ -z "$1" ] && ( echo "$send_notification"|grep -q "disk_info" ); then
	if [ -z "$1" ]; then
		send_content="${send_content}${get_disk}"
	fi

	if [ -n "$waninfo_enable" ]; then
		send_content="${send_content}${str_splitline}${str_title_start} WAN 口信息${str_title_end}"
		if [ "$send_wanIP" == "$send_hostIP" ]; then
			send_content="${send_content}${str_linefeed}${str_tab}IPv4: ${send_wanIP}"
		elif [ "$get_ipv4_mode" -eq "1" ]; then
			send_content="${send_content}${str_linefeed}${str_tab}接口 IPv4: ${send_wanIP}"
			[ -n "$send_hostIP" ] && send_content="${send_content}${str_linefeed}${str_tab}外网 IPv4: ${send_hostIP}"
		elif [ "$get_ipv4_mode" -eq "2" ]; then
			[ -n "$send_wanIP" ] && send_content="${send_content}${str_linefeed}${str_tab}接口 IPv4: ${send_wanIP}"
			send_content="${send_content}${str_linefeed}${str_tab}外网 IPv4: ${send_hostIP}"
		fi
		if [ -n "$ipv6_enable" ]; then
			if [ "$send_wanIPv6" == "$send_hostIPv6" ]; then
				send_content="${send_content}${str_linefeed}${str_tab}IPv6: ${send_wanIPv6}"
			elif [ "$get_ipv6_mode" -eq "1" ]; then
				send_content="${send_content}${str_linefeed}${str_tab}接口 IPv6: ${send_wanIPv6}"
				[ -n "$send_hostIPv6" ] && send_content="${send_content}${str_linefeed}${str_tab}外网 IPv6: ${send_hostIPv6}"
			elif [ "$get_ipv6_mode" -eq "2" ]; then
				[ -n "$send_wanIPv6" ] && send_content="${send_content}${str_linefeed}${str_tab}接口 IPv6: ${send_wanIPv6}"
				send_content="${send_content}${str_linefeed}${str_tab}外网 IPv6: ${send_hostIPv6}"
			fi
		fi
		interfaceuptime=`getinterfaceuptime`
		[ ! -z "$interfaceuptime" ] && wanstatustime=$(printf "在线时间：%d天%d时%d分%d秒" $((interfaceuptime / 86400)) $(((interfaceuptime % 86400) / 3600)) $(((interfaceuptime % 3600) / 60)) $((interfaceuptime % 60)))
		send_content="${send_content}${str_linefeed}${str_tab}${wanstatustime}"
	fi

	if [ -z "$1" ] && ( echo "$send_notification"|grep -q "client_list" ); then
		wait
		awk '{ lines[i++] = $0 } END { for (j = i-1; j >= 0; j--) print lines[j] }' "${dir}ipAddress" > "${dir}tmp_sort_file"
		logrow=$(awk 'END {print NR}' ${dir}ipAddress)
		send_content="${send_content}${str_splitline}${str_title_start} 现有在线设备 ${logrow} 台${str_title_end}"
		[ "$logrow" -eq "0" ] && send_content="${send_content}${str_splitline}${str_title_start} 当前无在线设备${str_title_end}"
		time_now=$(date +%s)
		while read -r tmp_ip tmp_mac tmp_name time_up _; do
			tmp_name=${tmp_name//_/ }
			tmp_name=$(cut_str "$tmp_name" "20")
			time_online=$(time_for_humans $((time_now - time_up)))
			ip_total=$(usage get "$tmp_mac")
			[ -n "$ip_total" ] && ip_total="总计流量：${ip_total}  "
			send_content="${send_content}${str_linefeed}【${tmp_name}】  ${ip_total}${str_linefeed}${str_tab}${tmp_ip}    在线 ${time_online}"
		done < "${dir}tmp_sort_file"
	fi

	[ ! -z "$device_name" ] && send_title="【$device_name】${send_title}"
	[ -z "$send_content" ] && send_content="${str_splitline}${str_title_start} 我遇到了一个难题${str_title_end}${str_linefeed}${str_tab}定时发送选项错误，你没有选择需要发送的项目，该怎 么办呢${str_splitline}"
	[ "$send_disturb" -eq "0" ] && diy_send "${send_title}" "${send_content}" "${jsonpath}" "$1" >/dev/null 2>&1
	RETVAL=$?
	[ $RETVAL -eq 1 ] && [ "$send_disturb" -eq "0" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】定时推送失败，请检查网络或设置信息" >> ${logfile} || echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}定时推送任务完成" >> ${logfile}
	deltemp
	return $RETVAL
}

# 初始化
if [ "$1" ] ;then
	[ $1 == "soc" ] && get_config "soc_code" "server_host" "server_port"
	[ $1 == "soc" ] && soc_temp && exit $?
	read_config
	[ $1 == "send" ] && send && exit $?
	[ $1 == "test" ] && send test && exit $?
	[ $1 == "t1" ] && thread_num=1 || exit
else
	read_config
fi

# 限制并发进程
[ -z "$thread_num" ] || [ "$thread_num" -eq "0" ] && thread_num=5
[ -e ${dir}fd1 ] || mkfifo ${dir}fd1
exec 5<>${dir}fd1
rm -f ${dir}fd1 >/dev/null 2>&1
for i in `seq 1 $thread_num`; do
	echo >&5
done
unset i

process_login() {
	local login_ip=$1
	local -n login_counts=$2

	if [ -z "${login_counts["$login_ip"]}" ]; then
		login_counts["$login_ip"]=0
	fi
	login_counts["$login_ip"]=$((login_counts["$login_ip"]+1))
	local count=${login_counts["$login_ip"]}
	login_log=$(logread notice | grep -w -i "$login_ip" | tail -n 1)

	if [[ $count -eq $login_max_num && ( "$2" == "web_failed_counts" || "$2" == "ssh_failed_counts" ) ]]; then
		add_ip_black ${login_ip}
		unset login_counts["$login_ip"]
		[ "$2" == "web_failed_counts" ] && echo "${login_ip}" >> ${dir}web_failed
		[ "$2" == "ssh_failed_counts" ] && echo "${login_ip}" >> ${dir}ssh_failed
	fi

	if [[ "$2" == "web_login_counts" || "$2" == "ssh_login_counts" ]]; then
		add_ip_white ${login_ip}
		unset web_failed_counts["$login_ip"]
		unset ssh_failed_counts["$login_ip"]
		unset login_counts["$login_ip"]
		[ "$2" == "web_login_counts" ] && echo "${login_ip}" >> ${dir}web_login
		[ "$2" == "ssh_login_counts" ] && echo "${login_ip}" >> ${dir}ssh_login
		[ "${#login_counts[@]}" -gt "100" ] && login_counts=("${login_counts[@]: -100}")
	fi
}

# 监听登录事件
if [ -n "$web_logged" ] || [ -n "$ssh_logged" ] || [ -n "$web_login_failed" ] || [ -n "$ssh_login_failed" ]; then
	declare -A web_login_counts
	declare -A ssh_login_counts
	declare -A web_failed_counts
	declare -A ssh_failed_counts
	[ -f ${dir}child_pid ] && child_pid=$(cat ${dir}child_pid)
	[ -n "$child_pid" ] && kill $child_pid >/dev/null 2>&1
	(
	logread -f -p notice | while IFS= read -r line; do
		[ -n "$web_logged" ] && {
			web_login_ip=$(echo "$line" | grep -i "accepted login" | awk '{print $NF}')
			[ -n "$web_login_ip" ] && process_login "$web_login_ip" web_login_counts
		}

		[ -n "$ssh_logged" ] && {
			ssh_login_ip=$(echo "$line" | grep -i "Password auth succeeded\|Pubkey auth succeeded" | awk '{print $NF}' | sed -nr 's#^(.*):.[0-9]{1,5}#\1#gp' | sed -e 's/%.*//')
			[ -n "$ssh_login_ip" ] && process_login "$ssh_login_ip" ssh_login_counts
		}

		[ -n "$web_login_failed" ] && {
			web_failed_ip=$(echo "$line" | grep -i "failed login"|awk '{print $NF}')
			[ -n "$web_failed_ip" ] && process_login "$web_failed_ip" web_failed_counts
		}

		[ -n "$ssh_login_failed" ] && {
			ssh_failed_ip=$(echo "$line" | grep -i "Bad password attempt\|Login attempt for nonexistent user from" | awk '{print $NF}' | sed -nr 's#^(.*):.[0-9]{1,5}#\1#gp' | sed -e 's/%.*//')
			[ -z "$ssh_failed_ip" ] && ssh_failed_num=$(echo "$line" | sed -n 's/.*authpriv\.warn dropbear\[\([0-9]\+\)\]: Login attempt for nonexistent user/\1/p') && [ -n "$ssh_failed_num" ] && ssh_failed_ip=$(logread notice | grep "authpriv\.info dropbear\[${failed_user_id}\].*Child connection from" | awk '{print $NF}' | sed -nr 's#^(.*):.[0-9]{1,5}#\1#gp' | sed -e 's/%.*//')
			[ -n "$ssh_failed_ip" ] && process_login "$ssh_failed_ip" ssh_failed_counts
		}
	done
	) &
	# 分离子shell，避免影响 wait
	child_pid=$!
	sleep 1
	disown "$child_pid"
	echo $child_pid > ${dir}child_pid
fi

# 载入在线设备
init;[ $? -eq 1 ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【！！！】读取设置出错，请检查设置项 " >> ${logfile} && exit
echo "`date "+%Y-%m-%d %H:%M:%S"` 【初始化】载入在线设备..." >> ${logfile}
> ${dir}send_enable.lock && first && deltemp
echo "`date "+%Y-%m-%d %H:%M:%S"` 【初始化】初始化完成" >> ${logfile}

# 循环
while [ "$enable" -eq "1" ]; do
	deltemp
	usage update
	disturb;disturb=$?
	device_aliases=`cat /usr/share/wechatpush/api/device_aliases.list` 2>/dev/null

	[ -f ${dir}ipAddress ] && ipAddress_logrow=$(grep -c "" ${dir}ipAddress) || ipAddress_logrow="0";
	if [ $ipAddress_logrow -ne "0" ]; then
		online_list=`cat ${dir}ipAddress|awk '{print $2}'|grep -v "^$"|sort -u`
		for online_mac in $online_list; do
			[ ! -z "$online_mac" ] && mac_online_status="`echo "$mark_mac_list"|grep -i $online_mac|grep -v "^$"|sort -u|head -n1`${mac_online_status}"
		done
	fi

	# 网络状态与 IP 变动
	if [ "$get_ipv4_mode" -ne "0" ] || [ "$get_ipv6_mode" -ne "0" ]; then
		rand_geturl
		ip_changes
	fi

	# 设备列表
	if [ ! -f "${dir}send_enable.lock" ]; then
		[ ! -z "$title" ] && echo "$title" > ${dir}title
		[ ! -z "$content" ] && echo "$content" > ${dir}content
		first
		[ -f "${dir}title" ] && title=`cat ${dir}title` && rm -f ${dir}title >/dev/null 2>&1
		[ -f "${dir}content" ] && content=`cat ${dir}content` && rm -f ${dir}content >/dev/null 2>&1
	fi

	# 离线二次验证区推送
	[ ! -f "${dir}send_enable.lock" ] && down_send

	# 当前设备列表
	[ ! -z "$content" ] && [ ! -f "${dir}send_enable.lock" ] && current_device

	# 无人值守任务
	[ ! -f "${dir}send_enable.lock" ] && unattended

	# CPU 检测
	[ ! -f "${dir}send_enable.lock" ] && cpu_load

	# 硬盘检测
	#[ ! -f "${dir}send_enable.lock" ] && get_disk

	# 异常流量检测
	[ ! -f "${dir}send_enable.lock" ] && get_client_usage

	# 登录提醒通知
	[ ! -f "${dir}send_enable.lock" ] && login_send

	# 推送
	if [ ! -f "${dir}send_enable.lock" ] && [ ! -z "$title" ] && [ ! -z "$content" ]; then
		[ ! -z "$device_name" ] && title="【$device_name】$title"
		( echo "$lite_enable"|grep -q "content" ) && content="$title"
		[ "$disturb" -eq "0" ] && diy_send "${title}" "${content}" "${jsonpath}" >/dev/null 2>&1
	fi

	# 等待定时任务推送完成
	while [ -f "${dir}send_enable.lock" ]; do
		sleep $sleeptime
	done

	sleep $sleeptime
done