From 0ca811631230b0b0a41b73d292883c6368aea16b Mon Sep 17 00:00:00 2001 From: coolsnowwolf Date: Tue, 9 Oct 2018 18:42:55 +0800 Subject: [PATCH] re-add Xunlei Fast Dick package --- package/lean/luci-app-xlnetacc/Makefile | 69 ++ .../files/luci/controller/xlnetacc.lua | 47 ++ .../files/luci/i18n/xlnetacc.zh-cn.lmo | Bin 0 -> 1188 bytes .../files/luci/i18n/xlnetacc.zh-cn.po | 92 +++ .../files/luci/model/cbi/xlnetacc.lua | 36 + .../files/luci/view/xlnetacc/logview.htm | 49 ++ .../files/luci/view/xlnetacc/status.htm | 21 + .../files/root/etc/config/xlnetacc | 5 + .../root/etc/hotplug.d/iface/95-xlnetacc | 13 + .../files/root/etc/init.d/xlnetacc | 49 ++ .../files/root/etc/uci-defaults/luci-xlnetacc | 22 + .../files/root/usr/bin/xlnetacc.sh | 670 ++++++++++++++++++ .../luci-app-xlnetacc/tools/po2lmo/Makefile | 12 + .../tools/po2lmo/src/po2lmo.c | 247 +++++++ .../tools/po2lmo/src/template_lmo.c | 328 +++++++++ .../tools/po2lmo/src/template_lmo.h | 92 +++ 16 files changed, 1752 insertions(+) create mode 100644 package/lean/luci-app-xlnetacc/Makefile create mode 100644 package/lean/luci-app-xlnetacc/files/luci/controller/xlnetacc.lua create mode 100644 package/lean/luci-app-xlnetacc/files/luci/i18n/xlnetacc.zh-cn.lmo create mode 100644 package/lean/luci-app-xlnetacc/files/luci/i18n/xlnetacc.zh-cn.po create mode 100644 package/lean/luci-app-xlnetacc/files/luci/model/cbi/xlnetacc.lua create mode 100644 package/lean/luci-app-xlnetacc/files/luci/view/xlnetacc/logview.htm create mode 100644 package/lean/luci-app-xlnetacc/files/luci/view/xlnetacc/status.htm create mode 100644 package/lean/luci-app-xlnetacc/files/root/etc/config/xlnetacc create mode 100644 package/lean/luci-app-xlnetacc/files/root/etc/hotplug.d/iface/95-xlnetacc create mode 100644 package/lean/luci-app-xlnetacc/files/root/etc/init.d/xlnetacc create mode 100644 package/lean/luci-app-xlnetacc/files/root/etc/uci-defaults/luci-xlnetacc create mode 100644 package/lean/luci-app-xlnetacc/files/root/usr/bin/xlnetacc.sh create mode 100644 package/lean/luci-app-xlnetacc/tools/po2lmo/Makefile create mode 100644 package/lean/luci-app-xlnetacc/tools/po2lmo/src/po2lmo.c create mode 100644 package/lean/luci-app-xlnetacc/tools/po2lmo/src/template_lmo.c create mode 100644 package/lean/luci-app-xlnetacc/tools/po2lmo/src/template_lmo.h diff --git a/package/lean/luci-app-xlnetacc/Makefile b/package/lean/luci-app-xlnetacc/Makefile new file mode 100644 index 000000000..d863c3592 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/Makefile @@ -0,0 +1,69 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-xlnetacc +PKG_VERSION:=1.0.3 +PKG_RELEASE:=8 + +PKG_LICENSE:=GPLv2 +PKG_MAINTAINER:=Sense + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=luci + CATEGORY:=LuCI + SUBMENU:=3. Applications + TITLE:=LuCI Support for XLNetAcc + PKGARCH:=all + DEPENDS:=+jshn +wget +openssl-util +endef + +define Package/$(PKG_NAME)/description + LuCI Support for XLNetAcc. +endef + +define Build/Prepare + $(foreach po,$(wildcard ${CURDIR}/files/luci/i18n/*.po), \ + po2lmo $(po) $(PKG_BUILD_DIR)/$(patsubst %.po,%.lmo,$(notdir $(po)));) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/$(PKG_NAME)/postinst +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + ( . /etc/uci-defaults/luci-xlnetacc ) && rm -f /etc/uci-defaults/luci-xlnetacc +fi +exit 0 +endef + +define Package/$(PKG_NAME)/conffiles + /etc/config/xlnetacc +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n + $(INSTALL_DATA) $(PKG_BUILD_DIR)/xlnetacc.*.lmo $(1)/usr/lib/lua/luci/i18n/ + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller + $(INSTALL_DATA) ./files/luci/controller/*.lua $(1)/usr/lib/lua/luci/controller/ + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi + $(INSTALL_DATA) ./files/luci/model/cbi/*.lua $(1)/usr/lib/lua/luci/model/cbi/ + $(INSTALL_DIR) $(1)/usr/lib/lua/luci/view/xlnetacc + $(INSTALL_DATA) ./files/luci/view/xlnetacc/*.htm $(1)/usr/lib/lua/luci/view/xlnetacc/ + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/root/etc/config/xlnetacc $(1)/etc/config/xlnetacc + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/root/etc/init.d/xlnetacc $(1)/etc/init.d/xlnetacc + $(INSTALL_DIR) $(1)/etc/hotplug.d/iface + $(INSTALL_BIN) ./files/root/etc/hotplug.d/iface/95-xlnetacc $(1)/etc/hotplug.d/iface/95-xlnetacc + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_BIN) ./files/root/etc/uci-defaults/luci-xlnetacc $(1)/etc/uci-defaults/luci-xlnetacc + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) ./files/root/usr/bin/xlnetacc.sh $(1)/usr/bin/xlnetacc.sh +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/package/lean/luci-app-xlnetacc/files/luci/controller/xlnetacc.lua b/package/lean/luci-app-xlnetacc/files/luci/controller/xlnetacc.lua new file mode 100644 index 000000000..ab9d92947 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/files/luci/controller/xlnetacc.lua @@ -0,0 +1,47 @@ +module("luci.controller.xlnetacc", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/xlnetacc") then + return + end + + entry({"admin", "services", "xlnetacc"}, + firstchild(), _("XLNetAcc")).dependent = false + + entry({"admin", "services", "xlnetacc", "general"}, + cbi("xlnetacc"), _("Settings"), 1) + + entry({"admin", "services", "xlnetacc", "log"}, + template("xlnetacc/logview"), _("Log"), 2) + + entry({"admin", "services", "xlnetacc", "status"}, call("action_status")) + entry({"admin", "services", "xlnetacc", "logdata"}, call("action_log")) +end + +local function is_running() + return luci.sys.call("(ps | grep xlnetacc.sh | grep -v 'grep') >/dev/null" ) == 0 +end + +function action_status() + luci.http.prepare_content("application/json") + luci.http.write_json({ + run_state = is_running(), + down_state = nixio.fs.readfile("/var/state/xlnetacc_down_state") or "", + up_state = nixio.fs.readfile("/var/state/xlnetacc_up_state") or "" + }) +end + +function action_log() + local uci = require "luci.model.uci".cursor() + local util = require "luci.util" + local log_data = { } + + log_data.syslog = util.trim(util.exec("logread | grep xlnetacc")) + if uci:get("xlnetacc", "general", "logging") ~= "0" then + log_data.client = nixio.fs.readfile("/var/log/xlnetacc.log") or "" + end + uci:unload("xlnetacc") + + luci.http.prepare_content("application/json") + luci.http.write_json(log_data) +end diff --git a/package/lean/luci-app-xlnetacc/files/luci/i18n/xlnetacc.zh-cn.lmo b/package/lean/luci-app-xlnetacc/files/luci/i18n/xlnetacc.zh-cn.lmo new file mode 100644 index 0000000000000000000000000000000000000000..3c0764141954a380428348ea22eea4117de48497 GIT binary patch literal 1188 zcmZWnZD>_uHo!VT}TvJ>Ht3?qfXqlVRd(OS>w1px1V-9>yuBAZ(hdj^wJnz>z z*T}g?ThlamX;g_C1(>zSCN*3kD*C9TQl-PliH4YeSm%zQ1^&RjAfG@4;;m(5A2C}T~;vQEIlZd0+TZiwam=JbY? zqH5D*%#b_uKF{P{tiemAh}oC<6EqO#yH33kRYV#{e-M*Bdd$W5Yoy&Rv@Xe7{4DIH z`S3)x0lle^q@v&Ob^$QOtzXRGPI1NXAdcHN&DcA3oi$2@1vLL8 zVxj93S(iCCYfAB~?l^5rqN<^)Wo2cA$${c;iuKO3)R$)A6gm>3U+L5PqGr}aHuC;G zF)g0ij-zkxl_*MZM=6a_aN>p%As^b6eo*|p`F z+U$4{bSKvrl}~r|4z5}Wy%gMD@^9={wP;}l_zG}qsdZ%OkF~FA;jaX@uNOP26N|#1 zgNxvfomHv9mopzY;ODwycd&Y_V$wUe-TD2r-7Og&EKRQF_c_G<_l7+Sgs~@I z0YAoZ{PD$_Uy7IAEP;-liR0clY0h|1kJ${P({DxSm*C literal 0 HcmV?d00001 diff --git a/package/lean/luci-app-xlnetacc/files/luci/i18n/xlnetacc.zh-cn.po b/package/lean/luci-app-xlnetacc/files/luci/i18n/xlnetacc.zh-cn.po new file mode 100644 index 000000000..80c6b9d23 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/files/luci/i18n/xlnetacc.zh-cn.po @@ -0,0 +1,92 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8\n" + +msgid "XLNetAcc" +msgstr "迅雷快鸟" + +msgid "XLNetAcc is a Thunder joint broadband operators launched a commitment to help users solve the low broadband, slow Internet access, poor Internet experience of professional-grade broadband upgrade software." +msgstr "迅雷快鸟是迅雷联合宽带运营商推出的一款致力于帮助用户解决宽带低、网速慢、上网体验差的专业级宽带加速软件。" + +msgid "Settings" +msgstr "设置" + +msgid "Log" +msgstr "日志" + +msgid "Running Status" +msgstr "运行状态" + +msgid "XLNetAcc Running Status" +msgstr "快鸟运行状态" + +msgid "DownLink Upgrade Status" +msgstr "下行提速状态" + +msgid "UpLink Upgrade Status" +msgstr "上行提速状态" + +msgid "RUNNING" +msgstr "运行中" + +msgid "NOT RUNNING" +msgstr "未运行" + +msgid "No upgrade information" +msgstr "暂无提速信息" + +msgid "General Settings" +msgstr "基本设置" + +msgid "Enabled" +msgstr "启用" + +msgid "Enable DownLink Upgrade" +msgstr "开启下行提速" + +msgid "Enable UpLink Upgrade" +msgstr "开启上行提速" + +msgid "Enable Logging" +msgstr "启用日志记录" + +msgid "Enable verbose logging" +msgstr "启用详细日志" + +msgid "Upgrade interface" +msgstr "指定提速接口" + +msgid "XLNetAcc account" +msgstr "迅雷快鸟帐号" + +msgid "XLNetAcc password" +msgstr "迅雷快鸟密码" + +msgid "Does not store the plaintext password, automatically emptied after start." +msgstr "不存储明文密码,启动后自动清空。" + +msgid "Encrypted password" +msgstr "加密后的密码" + +msgid "Auto-generate in accordance with the plaintext password, do not modify it!" +msgstr "根据明文密码自动生成,请勿修改!" + +msgid "Log Data" +msgstr "日志数据" + +msgid "Loading..." +msgstr "正在加载..." + +msgid "Refresh every 5 seconds." +msgstr "每 5 秒刷新。" + +msgid "syslog:" +msgstr "系统日志:" + +msgid "log file:" +msgstr "日志文件:" + +msgid "No log data." +msgstr "无日志数据。" + +msgid "Error get log data." +msgstr "获取日志数据失败。" diff --git a/package/lean/luci-app-xlnetacc/files/luci/model/cbi/xlnetacc.lua b/package/lean/luci-app-xlnetacc/files/luci/model/cbi/xlnetacc.lua new file mode 100644 index 000000000..9bef249ce --- /dev/null +++ b/package/lean/luci-app-xlnetacc/files/luci/model/cbi/xlnetacc.lua @@ -0,0 +1,36 @@ +local m, s, o +local uci = luci.model.uci.cursor() + +m = Map("xlnetacc", "%s - %s" %{translate("XLNetAcc"), translate("Settings")}, translate("XLNetAcc is a Thunder joint broadband operators launched a commitment to help users solve the low broadband, slow Internet access, poor Internet experience of professional-grade broadband upgrade software.")) +m:append(Template("xlnetacc/status")) + +s = m:section(NamedSection, "general", "general", translate("General Settings")) +s.anonymous = true +s.addremove = false + +o = s:option(Flag, "enabled", translate("Enabled")) +o.rmempty = false + +o = s:option(Flag, "down_acc", translate("Enable DownLink Upgrade")) + +o = s:option(Flag, "up_acc", translate("Enable UpLink Upgrade")) + +o = s:option(Flag, "logging", translate("Enable Logging")) +o.default = "1" + +o = s:option(Flag, "verbose", translate("Enable verbose logging")) +o:depends("logging", "1") + +o = s:option(ListValue, "network", translate("Upgrade interface")) +uci:foreach("network", "interface", function(section) + if section[".name"] ~= "loopback" then + o:value(section[".name"]) + end +end) + +o = s:option(Value, "account", translate("XLNetAcc account")) + +o = s:option(Value, "password", translate("XLNetAcc password")) +o.password = true + +return m diff --git a/package/lean/luci-app-xlnetacc/files/luci/view/xlnetacc/logview.htm b/package/lean/luci-app-xlnetacc/files/luci/view/xlnetacc/logview.htm new file mode 100644 index 000000000..a07a27112 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/files/luci/view/xlnetacc/logview.htm @@ -0,0 +1,49 @@ +<% css = [[ + #log_text { + padding: 10px; + text-align: left; + height: 500px; + overflow: auto; + } + #log_text pre { + word-break: break-all; + margin: 0; + } + .description { + color: #ffffff; + background-color: #0099ff; + } +]] +%> + +<%+header%> + +
+

<%:XLNetAcc%> - <%:Log Data%>

+
+
+
<%:Loading...%><%:Collecting data...%>
+
<%:Refresh every 5 seconds.%>
+
+
+
+ + + + +<%+footer%> diff --git a/package/lean/luci-app-xlnetacc/files/luci/view/xlnetacc/status.htm b/package/lean/luci-app-xlnetacc/files/luci/view/xlnetacc/status.htm new file mode 100644 index 000000000..3da9c4422 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/files/luci/view/xlnetacc/status.htm @@ -0,0 +1,21 @@ +
+ <%:Running Status%> + + + + +
<%:XLNetAcc Running Status%><%:Collecting data...%>
<%:DownLink Upgrade Status%><%:Collecting data...%>
<%:UpLink Upgrade Status%><%:Collecting data...%>
+
+ + diff --git a/package/lean/luci-app-xlnetacc/files/root/etc/config/xlnetacc b/package/lean/luci-app-xlnetacc/files/root/etc/config/xlnetacc new file mode 100644 index 000000000..4345070c4 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/files/root/etc/config/xlnetacc @@ -0,0 +1,5 @@ + +config general 'general' + option enabled '0' + option network 'wan' + diff --git a/package/lean/luci-app-xlnetacc/files/root/etc/hotplug.d/iface/95-xlnetacc b/package/lean/luci-app-xlnetacc/files/root/etc/hotplug.d/iface/95-xlnetacc new file mode 100644 index 000000000..be0271ad8 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/files/root/etc/hotplug.d/iface/95-xlnetacc @@ -0,0 +1,13 @@ +#!/bin/sh + +/etc/init.d/xlnetacc enabled || exit 0 +[ "$INTERFACE" != "$(uci get xlnetacc.general.network)" ] && exit 0 + +case "$ACTION" in + ifup) + /etc/init.d/xlnetacc start + ;; + ifdown) + /etc/init.d/xlnetacc stop + ;; +esac diff --git a/package/lean/luci-app-xlnetacc/files/root/etc/init.d/xlnetacc b/package/lean/luci-app-xlnetacc/files/root/etc/init.d/xlnetacc new file mode 100644 index 000000000..d15628113 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/files/root/etc/init.d/xlnetacc @@ -0,0 +1,49 @@ +#!/bin/sh /etc/rc.common + +START=95 +STOP=10 +SERVICE_DAEMONIZE=1 + +NAME=xlnetacc + +start() { + local retry=1 + while pidof "${NAME}.sh" >/dev/null 2>&1; do + [ $retry -ge 10 ] && return 1 || let retry++ + sleep 1 + done + + config_load "$NAME" + config_get_bool enabled "general" "enabled" 0 + config_get_bool down_acc "general" "down_acc" 0 + config_get_bool up_acc "general" "up_acc" 0 + config_get network "general" "network" + config_get username "general" "account" + config_get password "general" "password" + ( [ $enabled -eq 0 ] || [ $down_acc -eq 0 -a $up_acc -eq 0 ] || [ -z "$username" -o -z "$password" -o -z "$network" ] ) && return 2 + + logger -p "daemon.notice" -t "$NAME" "XLNetAcc is starting ..." + service_start /usr/bin/${NAME}.sh --start +} + +stop() { + ps | grep xlnetacc.sh | grep -v 'grep' >/dev/null 2>&1 || return 1 + + local pid spid + for pid in $(ps | grep xlnetacc.sh | grep -v 'grep' | awk '{print $1}'); do + echo "Stop XLNetAcc process PID: $pid" + kill -9 $pid >/dev/null 2>&1 + for spid in $(pgrep -P $pid "sleep"); do + echo "Stop XLNetAcc process SPID: $spid" + kill -9 $spid >/dev/null 2>&1 + done + done + logger -p "daemon.notice" -t "$NAME" "XLNetAcc has stoped." + return 0 +} + +restart() { + rm -rf /tmp/state/xlnetacc* + stop && sleep 1 + start +} diff --git a/package/lean/luci-app-xlnetacc/files/root/etc/uci-defaults/luci-xlnetacc b/package/lean/luci-app-xlnetacc/files/root/etc/uci-defaults/luci-xlnetacc new file mode 100644 index 000000000..632c02678 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/files/root/etc/uci-defaults/luci-xlnetacc @@ -0,0 +1,22 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@xlnetacc[-1] + add ucitrack xlnetacc + set ucitrack.@xlnetacc[-1].init=xlnetacc + commit ucitrack +EOF + +general=$(uci -q get xlnetacc.@general[-1]) +if [ -z "$general" ]; then + uci -q add xlnetacc general +fi +if [ "$general"x != "general"x ]; then + uci -q batch <<-EOF >/dev/null + rename xlnetacc.@general[-1]="general" + commit xlnetacc + EOF +fi + +rm -rf /tmp/luci-indexcache /tmp/luci-modulecache +exit 0 diff --git a/package/lean/luci-app-xlnetacc/files/root/usr/bin/xlnetacc.sh b/package/lean/luci-app-xlnetacc/files/root/usr/bin/xlnetacc.sh new file mode 100644 index 000000000..e4c18ef81 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/files/root/usr/bin/xlnetacc.sh @@ -0,0 +1,670 @@ +#!/bin/sh + +# 声明常量 +readonly packageName='com.xunlei.vip.swjsq' +readonly protocolVersion=200 +readonly businessType=68 +readonly sdkVersion='2.1.1.177662' +readonly clientVersion='2.4.1.3' +readonly agent_xl="android-async-http/xl-acc-sdk/version-$sdkVersion" +readonly agent_down='okhttp/3.4.1' +readonly agent_up='android-async-http/xl-acc-sdk/version-1.0.0.1' +readonly client_type_down='android-swjsq' +readonly client_type_up='android-uplink' + +# 声明全局变量 +_bind_ip= +_http_cmd= +_peerid= +_devicesign= +_userid= +_loginkey= +_sessionid= +_portal_down= +_portal_up= +_dial_account= +access_url= +http_args= +user_agent= +link_cn= +lasterr= +sequence_xl=1000000 +sequence_down=$(( $(date +%s) / 6 )) +sequence_up=$sequence_down + +# 包含用于解析 JSON 格式返回值的函数 +. /usr/share/libubox/jshn.sh + +# 读取 UCI 设置相关函数 +uci_get_by_name() { + local ret=$(uci get $NAME.$1.$2 2> /dev/null) + echo -n ${ret:=$3} +} +uci_get_by_type() { + local ret=$(uci get $NAME.@$1[-1].$2 2> /dev/null) + echo -n ${ret:=$3} +} +uci_get_by_bool() { + case $(uci_get_by_name "$1" "$2" "$3") in + 1|on|true|yes|enabled) echo -n 1;; + *) echo -n 0;; + esac +} + +# 日志和状态栏输出。1 日志文件, 2 系统日志, 4 详细模式, 8 下行状态栏, 16 上行状态栏, 32 失败状态 +_log() { + local msg=$1 + local flag=$2 + [ -z "$msg" ] && return + [ -z "$flag" ] && flag=1 + local timestamp=$(date +'%Y/%m/%d %H:%M:%S') + + [ $logging -eq 0 -a $(( $flag & 1 )) -ne 0 ] && flag=$(( $flag ^ 1 )) + if [ $verbose -eq 0 -a $(( $flag & 4 )) -ne 0 ]; then + [ $(( $flag & 1 )) -ne 0 ] && flag=$(( $flag ^ 1 )) + [ $(( $flag & 2 )) -ne 0 ] && flag=$(( $flag ^ 2 )) + fi + if [ $down_acc -eq 0 -a $(( $flag & 8 )) -ne 0 ]; then + flag=$(( $flag ^ 8 )) + [ $up_acc -ne 0 ] && flag=$(( $flag | 16 )) + fi + if [ $up_acc -eq 0 -a $(( $flag & 16 )) -ne 0 ]; then + flag=$(( $flag ^ 16 )) + [ $down_acc -ne 0 ] && flag=$(( $flag | 8 )) + fi + + [ $(( $flag & 1 )) -ne 0 ] && echo "$timestamp $msg" >> $LOGFILE 2> /dev/null + [ $(( $flag & 2 )) -ne 0 ] && logger -p "daemon.info" -t "$NAME" "$msg" + + [ $(( $flag & 32 )) -eq 0 ] && local color="green" || local color="red" + [ $(( $flag & 8 )) -ne 0 ] && echo -n "$timestamp $msg" > $down_state_file 2> /dev/null + [ $(( $flag & 16 )) -ne 0 ] && echo -n "$timestamp $msg" > $up_state_file 2> /dev/null +} + +# 清理日志 +clean_log() { + [ $logging -eq 1 -a -f "$LOGFILE" ] || return + [ $(wc -l "$LOGFILE" | awk '{print $1}') -le 800 ] && return + _log "清理日志文件" + local logdata=$(tail -n 500 "$LOGFILE") + echo "$logdata" > $LOGFILE 2> /dev/null + unset logdata +} + +# 获取接口IP地址 +get_bind_ip() { + json_cleanup; json_load "$(ubus call network.interface.$network status 2> /dev/null)" >/dev/null 2>&1 + json_select "ipv4-address" >/dev/null 2>&1; json_select 1 >/dev/null 2>&1 + json_get_var _bind_ip "address" + if [ -z "$_bind_ip" -o "$_bind_ip"x == "0.0.0.0"x ]; then + _log "获取网络 $network IP地址失败" + return 1 + else + _log "绑定IP地址: $_bind_ip" + return 0 + fi +} + +# 定义基本 HTTP 命令和参数 +gen_http_cmd() { + _http_cmd="wget-ssl -nv -t 1 -T 5 -O - --no-check-certificate" + _http_cmd="$_http_cmd --bind-address=$_bind_ip" +} + +# 生成设备标识 +gen_device_sign() { + local ifname macaddr + while : ; do + ifname=$(uci get "network.$network.ifname" 2> /dev/null) + [ "${ifname:0:1}" == "@" ] && network="${ifname:1}" || break + done + [ -z "$ifname" ] && { _log "获取网络 $network 信息出错"; return; } + json_cleanup; json_load "$(ubus call network.device status {\"name\":\"$ifname\"} 2> /dev/null)" >/dev/null 2>&1 + json_get_var macaddr "macaddr" + [ -z "$macaddr" ] && { _log "获取网络 $network MAC地址出错"; return; } + macaddr=$(echo -n "$macaddr" | awk '{print toupper($0)}') + + # 计算peerID + local fake_peerid=$(awk -F- '{print toupper($5)}' '/proc/sys/kernel/random/uuid') + readonly _peerid="${fake_peerid}004V" + _log "_peerid is $_peerid" $(( 1 | 4 )) + + # 计算devicesign + # sign = div.10?.device_id + md5(sha1(packageName + businessType + md5(a protocolVersion specific GUID))) + local fake_device_id=$(echo -n "${macaddr//:/}" | openssl dgst -md5 | awk '{print $2}') + local fake_device_sign=$(echo -n "${fake_device_id}${packageName}${businessType}c7f21687eed3cdb400ca11fc2263c998" \ + | openssl dgst -sha1 | awk '{print $2}') + readonly _devicesign="div101.${fake_device_id}"$(echo -n "$fake_device_sign" | openssl dgst -md5 | awk '{print $2}') + _log "_devicesign is $_devicesign" $(( 1 | 4 )) +} + +# 快鸟帐号通用参数 +swjsq_json() { + let sequence_xl++ + # 生成POST数据 + json_init + json_add_string protocolVersion "$protocolVersion" + json_add_string sequenceNo "$sequence_xl" + json_add_string platformVersion '2' + json_add_string isCompressed '0' + json_add_string businessType "$businessType" + json_add_string clientVersion "$clientVersion" + json_add_string peerID "$_peerid" + json_add_string appName "ANDROID-$packageName" + json_add_string sdkVersion "${sdkVersion##*.}" + json_add_string devicesign "$_devicesign" + json_add_string deviceModel 'MI' + json_add_string deviceName 'Xiaomi Mi' + json_add_string OSVersion "7.1.1" +} + +# 帐号登录 +swjsq_login() { + swjsq_json + if [ -z "$_userid" -o -z "$_loginkey" ]; then + access_url='https://mobile-login.xunlei.com/login' + json_add_string userName "$username" + json_add_string passWord "$password" + json_add_string verifyKey + json_add_string verifyCode + else + access_url='https://mobile-login.xunlei.com/loginkey' + json_add_string userName "$_userid" + json_add_string loginKey "$_loginkey" + fi + json_close_object + + local ret=$($_http_cmd --user-agent="$agent_xl" "$access_url" --post-data="$(json_dump)") + case $? in + 0) + _log "login is $ret" $(( 1 | 4 )) + json_cleanup; json_load "$ret" >/dev/null 2>&1 + json_get_var lasterr "errorCode" + ;; + 2) lasterr=-2;; + 4) lasterr=-3;; + *) lasterr=-1;; + esac + + case ${lasterr:=-1} in + 0) + json_get_var _userid "userID" + json_get_var _loginkey "loginKey" + json_get_var _sessionid "sessionID" + _log "_sessionid is $_sessionid" $(( 1 | 4 )) + local outmsg="帐号登录成功"; _log "$outmsg" $(( 1 | 8 )) + ;; + 15) # 身份信息已失效 + _userid=; _loginkey=;; + -1) + local outmsg="帐号登录失败。迅雷服务器未响应,请稍候"; _log "$outmsg";; + -2) + local outmsg="Wget 参数解析错误,请更新 GNU Wget"; _log "$outmsg" $(( 1 | 8 | 32 ));; + -3) + local outmsg="Wget 网络通信失败,请稍候"; _log "$outmsg";; + *) + local errorDesc; json_get_var errorDesc "errorDesc" + local outmsg="帐号登录失败。错误代码: ${lasterr}"; \ + [ -n "$errorDesc" ] && outmsg="${outmsg},原因: $errorDesc"; _log "$outmsg" $(( 1 | 8 | 32 ));; + esac + + [ $lasterr -eq 0 ] && return 0 || return 1 +} + +# 帐号注销 +swjsq_logout() { + swjsq_json + json_add_string userID "$_userid" + json_add_string sessionID "$_sessionid" + json_close_object + + local ret=$($_http_cmd --user-agent="$agent_xl" 'https://mobile-login.xunlei.com/logout' --post-data="$(json_dump)") + _log "logout is $ret" $(( 1 | 4 )) + json_cleanup; json_load "$ret" >/dev/null 2>&1 + json_get_var lasterr "errorCode" + + case ${lasterr:=-1} in + 0) + _sessionid= + local outmsg="帐号注销成功"; _log "$outmsg" $(( 1 | 8 ));; + -1) + local outmsg="帐号注销失败。迅雷服务器未响应,请稍候"; _log "$outmsg";; + *) + local errorDesc; json_get_var errorDesc "errorDesc" + local outmsg="帐号注销失败。错误代码: ${lasterr}"; \ + [ -n "$errorDesc" ] && outmsg="${outmsg},原因: $errorDesc"; _log "$outmsg" $(( 1 | 8 | 32 ));; + esac + + [ $lasterr -eq 0 ] && return 0 || return 1 +} + +# 获取用户信息 +swjsq_getuserinfo() { + [ $1 -eq 1 ] && local _vasid=14 || local _vasid=33 + swjsq_json + json_add_string userID "$_userid" + json_add_string sessionID "$_sessionid" + json_add_string vasid "$_vasid" + json_close_object + + local ret=$($_http_cmd --user-agent="$agent_xl" 'https://mobile-login.xunlei.com/getuserinfo' --post-data="$(json_dump)") + _log "getuserinfo $1 is $ret" $(( 1 | 4 )) + json_cleanup; json_load "$ret" >/dev/null 2>&1 + json_get_var lasterr "errorCode" + + [ $1 -eq 1 ] && local outmsg="下行提速会员" || local outmsg="上行提速会员" + case ${lasterr:=-1} in + 0) + local index vasid isVip isYear expireDate can_upgrade + json_select "vipList" >/dev/null 2>&1 + while : ; do + json_select ${index:=1} >/dev/null 2>&1 + [ $? -ne 0 ] && break + json_get_var vasid "vasid" + json_get_var isVip "isVip" + json_get_var isYear "isYear" + json_get_var expireDate "expireDate" + json_select ".." >/dev/null 2>&1 + let index++ + ([ $1 -eq 1 -a ${vasid:-0} -eq 2 ] || [ ${vasid:-0} -eq $_vasid ]) && \ + [ ${isVip:-0} -eq 1 -o ${isYear:-0} -eq 1 ] && { can_upgrade=1; break; } + done + if [ ${can_upgrade:-0} -eq 1 ]; then + outmsg="获取${outmsg}信息成功。会员到期时间:${expireDate:0:4}-${expireDate:4:2}-${expireDate:6:2}"; \ + _log "$outmsg" $(( 1 | $1 * 8 )) + else + if [ ${#expireDate} -ge 8 ]; then + outmsg="${outmsg}已到期。会员到期时间:${expireDate:0:4}-${expireDate:4:2}-${expireDate:6:2}" + else + outmsg="${outmsg}无效" + fi + _log "$outmsg" $(( 1 | $1 * 8 | 32 )) + [ $1 -eq 1 ] && down_acc=0 || up_acc=0 + fi + ;; + -1) + outmsg="获取${outmsg}信息失败。迅雷服务器未响应,请稍候"; _log "$outmsg";; + *) + local errorDesc; json_get_var errorDesc "errorDesc" + outmsg="获取${outmsg}信息失败。错误代码: ${lasterr}"; \ + [ -n "$errorDesc" ] && outmsg="${outmsg},原因: $errorDesc"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; + esac + + [ $lasterr -eq 0 ] && return 0 || return 1 +} + +# 获取提速入口 +swjsq_portal() { + xlnetacc_var $1 + + [ $1 -eq 1 ] && access_url='http://api.portal.swjsq.vip.xunlei.com:81/v2/queryportal' || \ + access_url='http://api.upportal.swjsq.vip.xunlei.com/v2/queryportal' + local ret=$($_http_cmd --user-agent="$user_agent" "$access_url") + _log "portal $1 is $ret" $(( 1 | 4 )) + json_cleanup; json_load "$ret" >/dev/null 2>&1 + json_get_var lasterr "errno" + + case ${lasterr:=-1} in + 0) + local interface_ip interface_port province sp + json_get_var interface_ip "interface_ip" + json_get_var interface_port "interface_port" + json_get_var province "province_name" + json_get_var sp "sp_name" + if [ $1 -eq 1 ]; then + _portal_down="http://$interface_ip:$interface_port/v2" + _log "_portal_down is $_portal_down" $(( 1 | 4 )) + else + _portal_up="http://$interface_ip:$interface_port/v2" + _log "_portal_up is $_portal_up" $(( 1 | 4 )) + fi + local outmsg="获取${link_cn}提速入口成功"; \ + [ -n "$province" -a -n "$sp" ] && outmsg="${outmsg}。运营商:${province}${sp}"; _log "$outmsg" $(( 1 | $1 * 8 )) + ;; + -1) + local outmsg="获取${link_cn}提速入口失败。迅雷服务器未响应,请稍候"; _log "$outmsg";; + *) + local message; json_get_var message "message" + local outmsg="获取${link_cn}提速入口失败。错误代码: ${lasterr}"; \ + [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; + esac + + [ $lasterr -eq 0 ] && return 0 || return 1 +} + +# 获取网络带宽信息 +isp_bandwidth() { + xlnetacc_var $1 + + local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/bandwidth?${http_args%&dial_account=*}") + _log "bandwidth $1 is $ret" $(( 1 | 4 )) + json_cleanup; json_load "$ret" >/dev/null 2>&1 + json_get_var lasterr "errno" + + case ${lasterr:=-1} in + 0) + # 获取带宽数据 + local can_upgrade bind_dial_account dial_account stream cur_bandwidth max_bandwidth + [ $1 -eq 1 ] && stream="downstream" || stream="upstream" + json_get_var can_upgrade "can_upgrade" + json_get_var bind_dial_account "bind_dial_account" + json_get_var dial_account "dial_account" + json_select; json_select "bandwidth" >/dev/null 2>&1 + json_get_var cur_bandwidth "$stream" + json_select; json_select "max_bandwidth" >/dev/null 2>&1 + json_get_var max_bandwidth "$stream" + json_select + cur_bandwidth=$(expr ${cur_bandwidth:-0} / 1024) + max_bandwidth=$(expr ${max_bandwidth:-0} / 1024) + + if [ -n "$bind_dial_account" -a "$bind_dial_account" != "$dial_account" ]; then + local outmsg="绑定宽带账号 $bind_dial_account 与当前宽带账号 $dial_account 不一致,请联系迅雷客服解绑(每月仅一次)"; \ + _log "$outmsg" $(( 1 | 8 | 32 )) + down_acc=0; up_acc=0 + elif [ $can_upgrade -eq 0 ]; then + local message; json_get_var message "richmessage"; [ -z "$message" ] && json_get_var message "message" + local outmsg="${link_cn}无法提速"; \ + [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 )) + [ $1 -eq 1 ] && down_acc=0 || up_acc=0 + elif [ $cur_bandwidth -ge $max_bandwidth ]; then + local outmsg="${link_cn}无需提速。当前带宽 ${cur_bandwidth}M,超过最大可提升带宽 ${max_bandwidth}M"; \ + _log "$outmsg" $(( 1 | $1 * 8 )) + [ $1 -eq 1 ] && down_acc=0 || up_acc=0 + else + if [ -z "$_dial_account" -a -n "$dial_account" ]; then + _dial_account=$dial_account + _log "_dial_account is $_dial_account" $(( 1 | 4 )) + fi + local outmsg="${link_cn}可以提速。当前带宽 ${cur_bandwidth}M,可提升至 ${max_bandwidth}M"; _log "$outmsg" $(( 1 | $1 * 8 )) + fi + ;; + 724) # 724 账号存在异常 + lasterr=-2 + local outmsg="获取${link_cn}网络带宽信息失败。原因: 您的账号存在异常,请联系迅雷客服反馈"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; + 3103) # 3103 线路暂不支持 + lasterr=0 + local province sp + json_get_var province "province_name"; json_get_var sp "sp_name" + local outmsg="${link_cn}无法提速。原因: ${province}${sp}线路暂不支持"; _log "$outmsg" $(( 1 | $1 * 8 | 32 )) + [ $1 -eq 1 ] && down_acc=0 || up_acc=0 + ;; + -1) + local outmsg="获取${link_cn}网络带宽信息失败。运营商服务器未响应,请稍候"; _log "$outmsg";; + *) + local message; json_get_var message "richmessage"; [ -z "$message" ] && json_get_var message "message" + local outmsg="获取${link_cn}网络带宽信息失败。错误代码: ${lasterr}"; \ + [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; + esac + + [ $lasterr -eq 0 ] && return 0 || return 1 +} + +# 发送带宽提速信号 +isp_upgrade() { + xlnetacc_var $1 + + local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/upgrade?$http_args") + _log "upgrade $1 is $ret" $(( 1 | 4 )) + json_cleanup; json_load "$ret" >/dev/null 2>&1 + json_get_var lasterr "errno" + + case ${lasterr:=-1} in + 0) + local bandwidth + json_select "bandwidth" >/dev/null 2>&1 + json_get_var bandwidth "downstream" + bandwidth=$(expr ${bandwidth:-0} / 1024) + local outmsg="${link_cn}提速成功,带宽已提升到 ${bandwidth}M"; _log "$outmsg" $(( 1 | $1 * 8 )) + [ $1 -eq 1 ] && down_acc=2 || up_acc=2 + ;; + 812) # 812 已处于提速状态 + lasterr=0 + local outmsg="${link_cn}提速成功,当前宽带已处于提速状态"; _log "$outmsg" $(( 1 | $1 * 8 )) + [ $1 -eq 1 ] && down_acc=2 || up_acc=2 + ;; + 724) # 724 账号存在异常 + lasterr=-2 + local outmsg="${link_cn}提速失败。原因: 您的账号存在异常,请联系迅雷客服反馈"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; + -1) + local outmsg="${link_cn}提速失败。运营商服务器未响应,请稍候"; _log "$outmsg";; + *) + local message; json_get_var message "richmessage"; [ -z "$message" ] && json_get_var message "message" + local outmsg="${link_cn}提速失败。错误代码: ${lasterr}"; \ + [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; + esac + + [ $lasterr -eq 0 ] && return 0 || return 1 +} + +# 发送提速心跳信号 +isp_keepalive() { + xlnetacc_var $1 + + local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/keepalive?$http_args") + _log "keepalive $1 is $ret" $(( 1 | 4 )) + json_cleanup; json_load "$ret" >/dev/null 2>&1 + json_get_var lasterr "errno" + + case ${lasterr:=-1} in + 0) + local outmsg="${link_cn}心跳信号返回正常"; _log "$outmsg";; + 513) # 513 提速通道不存在 + lasterr=-2 + local outmsg="${link_cn}提速超时,提速通道不存在"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; + -1) + local outmsg="${link_cn}心跳信号发送失败。运营商服务器未响应,请稍候"; _log "$outmsg";; + *) + local message; json_get_var message "richmessage"; [ -z "$message" ] && json_get_var message "message" + local outmsg="${link_cn}提速失效。错误代码: ${lasterr}"; \ + [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; + esac + + [ $lasterr -eq 0 ] && return 0 || return 1 +} + +# 发送带宽恢复信号 +isp_recover() { + xlnetacc_var $1 + + local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/recover?$http_args") + _log "recover $1 is $ret" $(( 1 | 4 )) + json_cleanup; json_load "$ret" >/dev/null 2>&1 + json_get_var lasterr "errno" + + case ${lasterr:=-1} in + 0) + local outmsg="${link_cn}带宽已恢复"; _log "$outmsg" $(( 1 | $1 * 8 )) + [ $1 -eq 1 ] && down_acc=1 || up_acc=1;; + -1) + local outmsg="${link_cn}带宽恢复失败。运营商服务器未响应,请稍候"; _log "$outmsg";; + *) + local message; json_get_var message "richmessage"; [ -z "$message" ] && json_get_var message "message" + local outmsg="${link_cn}带宽恢复失败。错误代码: ${lasterr}"; \ + [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; + esac + + [ $lasterr -eq 0 ] && return 0 || return 1 +} + +# 查询提速信息,未使用 +isp_query() { + xlnetacc_var $1 + + local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/query_try_info?$http_args") + _log "query_try_info $1 is $ret" $(( 1 | 4 )) + json_cleanup; json_load "$ret" >/dev/null 2>&1 + json_get_var lasterr "errno" + + [ $lasterr -eq 0 ] && return 0 || return 1 +} + +# 设置参数变量 +xlnetacc_var() { + if [ $1 -eq 1 ]; then + let sequence_down++ + access_url=$_portal_down + http_args="sequence=${sequence_down}&client_type=${client_type_down}-${clientVersion}&client_version=${client_type_down//-/}-${clientVersion}&chanel=umeng-10900011&time_and=$(date +%s)000" + user_agent=$agent_down + link_cn="下行" + else + let sequence_up++ + access_url=$_portal_up + http_args="sequence=${sequence_up}&client_type=${client_type_up}-${clientVersion}&client_version=${client_type_up//-/}-${clientVersion}" + user_agent=$agent_up + link_cn="上行" + fi + http_args="${http_args}&peerid=${_peerid}&userid=${_userid}&sessionid=${_sessionid}&user_type=1&os=android-7.1.1" + [ -n "$_dial_account" ] && http_args="${http_args}&dial_account=${_dial_account}" +} + +# 重试循环 +xlnetacc_retry() { + if [ $# -ge 3 -a $3 -ne 0 ]; then + [ $2 -eq 1 -a $down_acc -ne $3 ] && return 0 + [ $2 -eq 2 -a $up_acc -ne $3 ] && return 0 + fi + + local retry=1 + while : ; do + lasterr= + eval $1 $2 && break # 成功 + [ $# -ge 4 -a $retry -ge $4 ] && break || let retry++ # 重试超时 + case $lasterr in + -1) sleep 5s;; # 服务器未响应 + -2) break;; # 严重错误 + *) sleep 3s;; # 其它错误 + esac + done + + [ ${lasterr:-0} -eq 0 ] && return 0 || return 1 +} + +# 注销已登录帐号 +xlnetacc_logout() { + [ -z "$_sessionid" ] && return 2 + [ $# -ge 1 ] && local retry=$1 || local retry=1 + + xlnetacc_retry 'isp_recover' 1 2 $retry + xlnetacc_retry 'isp_recover' 2 2 $retry + xlnetacc_retry 'swjsq_logout' 0 0 $retry + [ $down_acc -ne 0 ] && down_acc=1; [ $up_acc -ne 0 ] && up_acc=1 + _sessionid=; _dial_account= + + [ $lasterr -eq 0 ] && return 0 || return 1 +} + +# 中止信号处理 +sigterm() { + _log "trap sigterm, exit" $(( 1 | 4 )) + xlnetacc_logout + rm -f "$down_state_file" "$up_state_file" + exit 0 +} + +# 初始化 +xlnetacc_init() { + [ "$1" != "--start" ] && return 1 + + # 防止重复启动 + local pid + for pid in $(pidof "${0##*/}"); do + [ $pid -ne $$ ] && return 1 + done + + # 读取设置 + readonly NAME=xlnetacc + readonly LOGFILE=/var/log/${NAME}.log + readonly down_state_file=/var/state/${NAME}_down_state + readonly up_state_file=/var/state/${NAME}_up_state + down_acc=$(uci_get_by_bool "general" "down_acc" 0) + up_acc=$(uci_get_by_bool "general" "up_acc" 0) + readonly logging=$(uci_get_by_bool "general" "logging" 1) + readonly verbose=$(uci_get_by_bool "general" "verbose" 0) + network=$(uci_get_by_name "general" "network" "wan") + readonly username=$(uci_get_by_name "general" "account") + readonly password=$(uci_get_by_name "general" "password") + local enabled=$(uci_get_by_bool "general" "enabled" 0) + ([ $enabled -eq 0 ] || [ $down_acc -eq 0 -a $up_acc -eq 0 ] || [ -z "$username" -o -z "$password" -o -z "$network" ]) && return 2 + + [ $logging -eq 1 ] && [ ! -d /var/log ] && mkdir -p /var/log + [ -f "$LOGFILE" ] && _log "------------------------------" + _log "迅雷快鸟正在启动..." + + # 检查外部调用工具 + command -v wget-ssl >/dev/null || { _log "GNU Wget 未安装"; return 3; } + local opensslchk=$(echo -n 'openssl' | openssl dgst -sha1 | awk '{print $2}') + [ "$opensslchk" != 'c898fa1e7226427010e329971e82c669f8d8abb4' ] && { _log "openssl-util 未安装或计算错误"; return 3; } + + # 捕获中止信号 + trap 'sigterm' INT # Ctrl-C + trap 'sigterm' QUIT # Ctrl-\ + trap 'sigterm' TERM # kill + + # 生成设备标识 + gen_device_sign + [ ${#_peerid} -ne 16 -o ${#_devicesign} -ne 71 ] && return 4 + + clean_log + [ -d /var/state ] || mkdir -p /var/state + return 0 +} + +# 程序主体 +xlnetacc_main() { + while : ; do + # 获取外网IP地址 + xlnetacc_retry 'get_bind_ip' + gen_http_cmd + + # 注销快鸟帐号 + xlnetacc_logout 3 && sleep 3s + + # 登录快鸟帐号 + while : ; do + lasterr= + swjsq_login + case $lasterr in + 0) break;; # 登录成功 + -1) sleep 5s;; # 服务器未响应 + -2) return 7;; # Wget 参数解析错误 + -3) sleep 3s;; # Wget 网络通信失败 + 6) sleep 130m;; # 需要输入验证码 + 8) sleep 3m;; # 服务器系统维护 + 15) sleep 1s;; # 身份信息已失效 + *) return 5;; # 登录失败 + esac + done + + # 获取用户信息 + xlnetacc_retry 'swjsq_getuserinfo' 1 1 + xlnetacc_retry 'swjsq_getuserinfo' 2 1 + [ $down_acc -eq 0 -a $up_acc -eq 0 ] && break + # 获取提速入口 + xlnetacc_retry 'swjsq_portal' 1 1 + xlnetacc_retry 'swjsq_portal' 2 1 + # 获取带宽信息 + xlnetacc_retry 'isp_bandwidth' 1 1 10 || { sleep 3m; continue; } + xlnetacc_retry 'isp_bandwidth' 2 1 10 || { sleep 3m; continue; } + [ $down_acc -eq 0 -a $up_acc -eq 0 ] && break + # 带宽提速 + xlnetacc_retry 'isp_upgrade' 1 1 10 || { sleep 3m; continue; } + xlnetacc_retry 'isp_upgrade' 2 1 10 || { sleep 3m; continue; } + + # 心跳保持 +# local retry=1 + while : ; do + clean_log # 清理日志 + sleep 10m +# [ $retry -ge 144 ] && break || let retry++ # 心跳最多保持24小时,144=24*60/10 + xlnetacc_retry 'isp_keepalive' 1 2 5 || break + xlnetacc_retry 'isp_keepalive' 2 2 5 || break + done + done + xlnetacc_logout + _log "无法提速,迅雷快鸟已停止。" + return 6 +} + +# 程序入口 +xlnetacc_init "$@" && xlnetacc_main +exit $? diff --git a/package/lean/luci-app-xlnetacc/tools/po2lmo/Makefile b/package/lean/luci-app-xlnetacc/tools/po2lmo/Makefile new file mode 100644 index 000000000..ad2c13320 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/tools/po2lmo/Makefile @@ -0,0 +1,12 @@ + +INSTALL = install +PREFIX = /usr/bin + +po2lmo: src/po2lmo.o src/template_lmo.o + $(CC) $(LDFLAGS) -o src/po2lmo src/po2lmo.o src/template_lmo.o + +install: + $(INSTALL) -m 755 src/po2lmo $(PREFIX) + +clean: + $(RM) src/po2lmo src/*.o diff --git a/package/lean/luci-app-xlnetacc/tools/po2lmo/src/po2lmo.c b/package/lean/luci-app-xlnetacc/tools/po2lmo/src/po2lmo.c new file mode 100644 index 000000000..0da792b68 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/tools/po2lmo/src/po2lmo.c @@ -0,0 +1,247 @@ +/* + * lmo - Lua Machine Objects - PO to LMO conversion tool + * + * Copyright (C) 2009-2012 Jo-Philipp Wich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "template_lmo.h" + +static void die(const char *msg) +{ + fprintf(stderr, "Error: %s\n", msg); + exit(1); +} + +static void usage(const char *name) +{ + fprintf(stderr, "Usage: %s input.po output.lmo\n", name); + exit(1); +} + +static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + if( fwrite(ptr, size, nmemb, stream) == 0 ) + die("Failed to write stdout"); +} + +static int extract_string(const char *src, char *dest, int len) +{ + int pos = 0; + int esc = 0; + int off = -1; + + for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ ) + { + if( (off == -1) && (src[pos] == '"') ) + { + off = pos + 1; + } + else if( off >= 0 ) + { + if( esc == 1 ) + { + switch (src[pos]) + { + case '"': + case '\\': + off++; + break; + } + dest[pos-off] = src[pos]; + esc = 0; + } + else if( src[pos] == '\\' ) + { + dest[pos-off] = src[pos]; + esc = 1; + } + else if( src[pos] != '"' ) + { + dest[pos-off] = src[pos]; + } + else + { + dest[pos-off] = '\0'; + break; + } + } + } + + return (off > -1) ? strlen(dest) : -1; +} + +static int cmp_index(const void *a, const void *b) +{ + uint32_t x = ((const lmo_entry_t *)a)->key_id; + uint32_t y = ((const lmo_entry_t *)b)->key_id; + + if (x < y) + return -1; + else if (x > y) + return 1; + + return 0; +} + +static void print_uint32(uint32_t x, FILE *out) +{ + uint32_t y = htonl(x); + print(&y, sizeof(uint32_t), 1, out); +} + +static void print_index(void *array, int n, FILE *out) +{ + lmo_entry_t *e; + + qsort(array, n, sizeof(*e), cmp_index); + + for (e = array; n > 0; n--, e++) + { + print_uint32(e->key_id, out); + print_uint32(e->val_id, out); + print_uint32(e->offset, out); + print_uint32(e->length, out); + } +} + +int main(int argc, char *argv[]) +{ + char line[4096]; + char key[4096]; + char val[4096]; + char tmp[4096]; + int state = 0; + int offset = 0; + int length = 0; + int n_entries = 0; + void *array = NULL; + lmo_entry_t *entry = NULL; + uint32_t key_id, val_id; + + FILE *in; + FILE *out; + + if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) ) + usage(argv[0]); + + memset(line, 0, sizeof(key)); + memset(key, 0, sizeof(val)); + memset(val, 0, sizeof(val)); + + while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) ) + { + if( state == 0 && strstr(line, "msgid \"") == line ) + { + switch(extract_string(line, key, sizeof(key))) + { + case -1: + die("Syntax error in msgid"); + case 0: + state = 1; + break; + default: + state = 2; + } + } + else if( state == 1 || state == 2 ) + { + if( strstr(line, "msgstr \"") == line || state == 2 ) + { + switch(extract_string(line, val, sizeof(val))) + { + case -1: + state = 4; + break; + default: + state = 3; + } + } + else + { + switch(extract_string(line, tmp, sizeof(tmp))) + { + case -1: + state = 2; + break; + default: + strcat(key, tmp); + } + } + } + else if( state == 3 ) + { + switch(extract_string(line, tmp, sizeof(tmp))) + { + case -1: + state = 4; + break; + default: + strcat(val, tmp); + } + } + + if( state == 4 ) + { + if( strlen(key) > 0 && strlen(val) > 0 ) + { + key_id = sfh_hash(key, strlen(key)); + val_id = sfh_hash(val, strlen(val)); + + if( key_id != val_id ) + { + n_entries++; + array = realloc(array, n_entries * sizeof(lmo_entry_t)); + entry = (lmo_entry_t *)array + n_entries - 1; + + if (!array) + die("Out of memory"); + + entry->key_id = key_id; + entry->val_id = val_id; + entry->offset = offset; + entry->length = strlen(val); + + length = strlen(val) + ((4 - (strlen(val) % 4)) % 4); + + print(val, length, 1, out); + offset += length; + } + } + + state = 0; + memset(key, 0, sizeof(key)); + memset(val, 0, sizeof(val)); + } + + memset(line, 0, sizeof(line)); + } + + print_index(array, n_entries, out); + + if( offset > 0 ) + { + print_uint32(offset, out); + fsync(fileno(out)); + fclose(out); + } + else + { + fclose(out); + unlink(argv[2]); + } + + fclose(in); + return(0); +} diff --git a/package/lean/luci-app-xlnetacc/tools/po2lmo/src/template_lmo.c b/package/lean/luci-app-xlnetacc/tools/po2lmo/src/template_lmo.c new file mode 100644 index 000000000..27205a722 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/tools/po2lmo/src/template_lmo.c @@ -0,0 +1,328 @@ +/* + * lmo - Lua Machine Objects - Base functions + * + * Copyright (C) 2009-2010 Jo-Philipp Wich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "template_lmo.h" + +/* + * Hash function from http://www.azillionmonkeys.com/qed/hash.html + * Copyright (C) 2004-2008 by Paul Hsieh + */ + +uint32_t sfh_hash(const char *data, int len) +{ + uint32_t hash = len, tmp; + int rem; + + if (len <= 0 || data == NULL) return 0; + + rem = len & 3; + len >>= 2; + + /* Main loop */ + for (;len > 0; len--) { + hash += sfh_get16(data); + tmp = (sfh_get16(data+2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2*sizeof(uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) { + case 3: hash += sfh_get16(data); + hash ^= hash << 16; + hash ^= data[sizeof(uint16_t)] << 18; + hash += hash >> 11; + break; + case 2: hash += sfh_get16(data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: hash += *data; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + +uint32_t lmo_canon_hash(const char *str, int len) +{ + char res[4096]; + char *ptr, prev; + int off; + + if (!str || len >= sizeof(res)) + return 0; + + for (prev = ' ', ptr = res, off = 0; off < len; prev = *str, off++, str++) + { + if (isspace(*str)) + { + if (!isspace(prev)) + *ptr++ = ' '; + } + else + { + *ptr++ = *str; + } + } + + if ((ptr > res) && isspace(*(ptr-1))) + ptr--; + + return sfh_hash(res, ptr - res); +} + +lmo_archive_t * lmo_open(const char *file) +{ + int in = -1; + uint32_t idx_offset = 0; + struct stat s; + + lmo_archive_t *ar = NULL; + + if (stat(file, &s) == -1) + goto err; + + if ((in = open(file, O_RDONLY)) == -1) + goto err; + + if ((ar = (lmo_archive_t *)malloc(sizeof(*ar))) != NULL) + { + memset(ar, 0, sizeof(*ar)); + + ar->fd = in; + ar->size = s.st_size; + + fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC); + + if ((ar->mmap = mmap(NULL, ar->size, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED) + goto err; + + idx_offset = ntohl(*((const uint32_t *) + (ar->mmap + ar->size - sizeof(uint32_t)))); + + if (idx_offset >= ar->size) + goto err; + + ar->index = (lmo_entry_t *)(ar->mmap + idx_offset); + ar->length = (ar->size - idx_offset - sizeof(uint32_t)) / sizeof(lmo_entry_t); + ar->end = ar->mmap + ar->size; + + return ar; + } + +err: + if (in > -1) + close(in); + + if (ar != NULL) + { + if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED)) + munmap(ar->mmap, ar->size); + + free(ar); + } + + return NULL; +} + +void lmo_close(lmo_archive_t *ar) +{ + if (ar != NULL) + { + if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED)) + munmap(ar->mmap, ar->size); + + close(ar->fd); + free(ar); + + ar = NULL; + } +} + + +lmo_catalog_t *_lmo_catalogs = NULL; +lmo_catalog_t *_lmo_active_catalog = NULL; + +int lmo_load_catalog(const char *lang, const char *dir) +{ + DIR *dh = NULL; + char pattern[16]; + char path[PATH_MAX]; + struct dirent *de = NULL; + + lmo_archive_t *ar = NULL; + lmo_catalog_t *cat = NULL; + + if (!lmo_change_catalog(lang)) + return 0; + + if (!dir || !(dh = opendir(dir))) + goto err; + + if (!(cat = malloc(sizeof(*cat)))) + goto err; + + memset(cat, 0, sizeof(*cat)); + + snprintf(cat->lang, sizeof(cat->lang), "%s", lang); + snprintf(pattern, sizeof(pattern), "*.%s.lmo", lang); + + while ((de = readdir(dh)) != NULL) + { + if (!fnmatch(pattern, de->d_name, 0)) + { + snprintf(path, sizeof(path), "%s/%s", dir, de->d_name); + ar = lmo_open(path); + + if (ar) + { + ar->next = cat->archives; + cat->archives = ar; + } + } + } + + closedir(dh); + + cat->next = _lmo_catalogs; + _lmo_catalogs = cat; + + if (!_lmo_active_catalog) + _lmo_active_catalog = cat; + + return 0; + +err: + if (dh) closedir(dh); + if (cat) free(cat); + + return -1; +} + +int lmo_change_catalog(const char *lang) +{ + lmo_catalog_t *cat; + + for (cat = _lmo_catalogs; cat; cat = cat->next) + { + if (!strncmp(cat->lang, lang, sizeof(cat->lang))) + { + _lmo_active_catalog = cat; + return 0; + } + } + + return -1; +} + +static lmo_entry_t * lmo_find_entry(lmo_archive_t *ar, uint32_t hash) +{ + unsigned int m, l, r; + uint32_t k; + + l = 0; + r = ar->length - 1; + + while (1) + { + m = l + ((r - l) / 2); + + if (r < l) + break; + + k = ntohl(ar->index[m].key_id); + + if (k == hash) + return &ar->index[m]; + + if (k > hash) + { + if (!m) + break; + + r = m - 1; + } + else + { + l = m + 1; + } + } + + return NULL; +} + +int lmo_translate(const char *key, int keylen, char **out, int *outlen) +{ + uint32_t hash; + lmo_entry_t *e; + lmo_archive_t *ar; + + if (!key || !_lmo_active_catalog) + return -2; + + hash = lmo_canon_hash(key, keylen); + + for (ar = _lmo_active_catalog->archives; ar; ar = ar->next) + { + if ((e = lmo_find_entry(ar, hash)) != NULL) + { + *out = ar->mmap + ntohl(e->offset); + *outlen = ntohl(e->length); + return 0; + } + } + + return -1; +} + +void lmo_close_catalog(const char *lang) +{ + lmo_archive_t *ar, *next; + lmo_catalog_t *cat, *prev; + + for (prev = NULL, cat = _lmo_catalogs; cat; prev = cat, cat = cat->next) + { + if (!strncmp(cat->lang, lang, sizeof(cat->lang))) + { + if (prev) + prev->next = cat->next; + else + _lmo_catalogs = cat->next; + + for (ar = cat->archives; ar; ar = next) + { + next = ar->next; + lmo_close(ar); + } + + free(cat); + break; + } + } +} diff --git a/package/lean/luci-app-xlnetacc/tools/po2lmo/src/template_lmo.h b/package/lean/luci-app-xlnetacc/tools/po2lmo/src/template_lmo.h new file mode 100644 index 000000000..57f59aa56 --- /dev/null +++ b/package/lean/luci-app-xlnetacc/tools/po2lmo/src/template_lmo.h @@ -0,0 +1,92 @@ +/* + * lmo - Lua Machine Objects - General header + * + * Copyright (C) 2009-2012 Jo-Philipp Wich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _TEMPLATE_LMO_H_ +#define _TEMPLATE_LMO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (defined(__GNUC__) && defined(__i386__)) +#define sfh_get16(d) (*((const uint16_t *) (d))) +#else +#define sfh_get16(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif + + +struct lmo_entry { + uint32_t key_id; + uint32_t val_id; + uint32_t offset; + uint32_t length; +} __attribute__((packed)); + +typedef struct lmo_entry lmo_entry_t; + + +struct lmo_archive { + int fd; + int length; + uint32_t size; + lmo_entry_t *index; + char *mmap; + char *end; + struct lmo_archive *next; +}; + +typedef struct lmo_archive lmo_archive_t; + + +struct lmo_catalog { + char lang[6]; + struct lmo_archive *archives; + struct lmo_catalog *next; +}; + +typedef struct lmo_catalog lmo_catalog_t; + + +uint32_t sfh_hash(const char *data, int len); +uint32_t lmo_canon_hash(const char *data, int len); + +lmo_archive_t * lmo_open(const char *file); +void lmo_close(lmo_archive_t *ar); + + +extern lmo_catalog_t *_lmo_catalogs; +extern lmo_catalog_t *_lmo_active_catalog; + +int lmo_load_catalog(const char *lang, const char *dir); +int lmo_change_catalog(const char *lang); +int lmo_translate(const char *key, int keylen, char **out, int *outlen); +void lmo_close_catalog(const char *lang); + +#endif