├── .gitattributes ├── LICENSE ├── Makefile ├── README.md ├── files ├── luci │ ├── controller │ │ └── xlnetacc.lua │ ├── i18n │ │ ├── xlnetacc.zh-cn.lmo │ │ └── xlnetacc.zh-cn.po │ ├── model │ │ └── cbi │ │ │ └── xlnetacc.lua │ └── view │ │ └── xlnetacc │ │ ├── logview.htm │ │ └── status.htm └── root │ ├── etc │ ├── config │ │ └── xlnetacc │ ├── hotplug.d │ │ └── iface │ │ │ └── 95-xlnetacc │ ├── init.d │ │ └── xlnetacc │ └── uci-defaults │ │ └── luci-xlnetacc │ └── usr │ └── bin │ └── xlnetacc.sh └── tools └── po2lmo ├── Makefile └── src ├── po2lmo.c ├── template_lmo.c └── template_lmo.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 2018 Sense 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include $(TOPDIR)/rules.mk 2 | 3 | PKG_NAME:=luci-app-xlnetacc 4 | PKG_VERSION:=1.0.5 5 | PKG_RELEASE:=1 6 | 7 | PKG_LICENSE:=GPLv2 8 | PKG_MAINTAINER:=Sense 9 | 10 | include $(INCLUDE_DIR)/package.mk 11 | 12 | define Package/$(PKG_NAME) 13 | SECTION:=luci 14 | CATEGORY:=LuCI 15 | SUBMENU:=3. Applications 16 | TITLE:=LuCI Support for XLNetAcc 17 | PKGARCH:=all 18 | DEPENDS:=+jshn +wget +openssl-util 19 | endef 20 | 21 | define Package/$(PKG_NAME)/description 22 | LuCI Support for XLNetAcc. 23 | endef 24 | 25 | define Build/Prepare 26 | $(foreach po,$(wildcard ${CURDIR}/files/luci/i18n/*.po), \ 27 | po2lmo $(po) $(PKG_BUILD_DIR)/$(patsubst %.po,%.lmo,$(notdir $(po)));) 28 | endef 29 | 30 | define Build/Configure 31 | endef 32 | 33 | define Build/Compile 34 | endef 35 | 36 | define Package/$(PKG_NAME)/postinst 37 | #!/bin/sh 38 | if [ -z "$${IPKG_INSTROOT}" ]; then 39 | ( . /etc/uci-defaults/luci-xlnetacc ) && rm -f /etc/uci-defaults/luci-xlnetacc 40 | fi 41 | exit 0 42 | endef 43 | 44 | define Package/$(PKG_NAME)/conffiles 45 | /etc/config/xlnetacc 46 | endef 47 | 48 | define Package/$(PKG_NAME)/install 49 | $(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n 50 | $(INSTALL_DATA) $(PKG_BUILD_DIR)/xlnetacc.*.lmo $(1)/usr/lib/lua/luci/i18n/ 51 | $(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller 52 | $(INSTALL_DATA) ./files/luci/controller/*.lua $(1)/usr/lib/lua/luci/controller/ 53 | $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi 54 | $(INSTALL_DATA) ./files/luci/model/cbi/*.lua $(1)/usr/lib/lua/luci/model/cbi/ 55 | $(INSTALL_DIR) $(1)/usr/lib/lua/luci/view/xlnetacc 56 | $(INSTALL_DATA) ./files/luci/view/xlnetacc/*.htm $(1)/usr/lib/lua/luci/view/xlnetacc/ 57 | $(INSTALL_DIR) $(1)/etc/config 58 | $(INSTALL_CONF) ./files/root/etc/config/xlnetacc $(1)/etc/config/xlnetacc 59 | $(INSTALL_DIR) $(1)/etc/init.d 60 | $(INSTALL_BIN) ./files/root/etc/init.d/xlnetacc $(1)/etc/init.d/xlnetacc 61 | $(INSTALL_DIR) $(1)/etc/hotplug.d/iface 62 | $(INSTALL_BIN) ./files/root/etc/hotplug.d/iface/95-xlnetacc $(1)/etc/hotplug.d/iface/95-xlnetacc 63 | $(INSTALL_DIR) $(1)/etc/uci-defaults 64 | $(INSTALL_BIN) ./files/root/etc/uci-defaults/luci-xlnetacc $(1)/etc/uci-defaults/luci-xlnetacc 65 | $(INSTALL_DIR) $(1)/usr/bin 66 | $(INSTALL_BIN) ./files/root/usr/bin/xlnetacc.sh $(1)/usr/bin/xlnetacc.sh 67 | endef 68 | 69 | $(eval $(call BuildPackage,$(PKG_NAME))) 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # luci-app-xlnetacc 2 | 适用于 OpenWRT/LEDE 纯Shell实现的迅雷快鸟客户端 3 | 4 | 依赖: wget openssl-util 5 | 6 | 7 | 更新到支持快鸟新协议 300 8 | 9 | 详情见恩山论坛介绍帖 [依然是改良作品,这次的目标是 -- 迅雷快鸟](http://www.right.com.cn/forum/thread-267641-1-1.html) 10 | -------------------------------------------------------------------------------- /files/luci/controller/xlnetacc.lua: -------------------------------------------------------------------------------- 1 | module("luci.controller.xlnetacc", package.seeall) 2 | 3 | function index() 4 | if not nixio.fs.access("/etc/config/xlnetacc") then 5 | return 6 | end 7 | 8 | entry({"admin", "services", "xlnetacc"}, 9 | firstchild(), _("XLNetAcc")).dependent = false 10 | 11 | entry({"admin", "services", "xlnetacc", "general"}, 12 | cbi("xlnetacc"), _("Settings"), 1) 13 | 14 | entry({"admin", "services", "xlnetacc", "log"}, 15 | template("xlnetacc/logview"), _("Log"), 2) 16 | 17 | entry({"admin", "services", "xlnetacc", "status"}, call("action_status")) 18 | entry({"admin", "services", "xlnetacc", "logdata"}, call("action_log")) 19 | end 20 | 21 | local function is_running(name) 22 | return luci.sys.call("pidof %s >/dev/null" %{name}) == 0 23 | end 24 | 25 | function action_status() 26 | luci.http.prepare_content("application/json") 27 | luci.http.write_json({ 28 | run_state = is_running("xlnetacc.sh"), 29 | down_state = nixio.fs.readfile("/var/state/xlnetacc_down_state") or "", 30 | up_state = nixio.fs.readfile("/var/state/xlnetacc_up_state") or "" 31 | }) 32 | end 33 | 34 | function action_log() 35 | local uci = require "luci.model.uci".cursor() 36 | local util = require "luci.util" 37 | local log_data = { } 38 | 39 | log_data.syslog = util.trim(util.exec("logread | grep xlnetacc")) 40 | if uci:get("xlnetacc", "general", "logging") ~= "0" then 41 | log_data.client = nixio.fs.readfile("/var/log/xlnetacc.log") or "" 42 | end 43 | uci:unload("xlnetacc") 44 | 45 | luci.http.prepare_content("application/json") 46 | luci.http.write_json(log_data) 47 | end 48 | -------------------------------------------------------------------------------- /files/luci/i18n/xlnetacc.zh-cn.lmo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sensec/luci-app-xlnetacc/efafda569bd6f6c8bd8780af89fdc8da6202664d/files/luci/i18n/xlnetacc.zh-cn.lmo -------------------------------------------------------------------------------- /files/luci/i18n/xlnetacc.zh-cn.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "Content-Type: text/plain; charset=UTF-8\n" 3 | 4 | msgid "XLNetAcc" 5 | msgstr "迅雷快鸟" 6 | 7 | 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." 8 | msgstr "迅雷快鸟是迅雷联合宽带运营商推出的一款致力于帮助用户解决宽带低、网速慢、上网体验差的专业级宽带加速软件。" 9 | 10 | msgid "Settings" 11 | msgstr "设置" 12 | 13 | msgid "Log" 14 | msgstr "日志" 15 | 16 | msgid "Running Status" 17 | msgstr "运行状态" 18 | 19 | msgid "XLNetAcc Running Status" 20 | msgstr "快鸟运行状态" 21 | 22 | msgid "DownLink Upgrade Status" 23 | msgstr "下行提速状态" 24 | 25 | msgid "UpLink Upgrade Status" 26 | msgstr "上行提速状态" 27 | 28 | msgid "RUNNING" 29 | msgstr "运行中" 30 | 31 | msgid "NOT RUNNING" 32 | msgstr "未运行" 33 | 34 | msgid "No upgrade information" 35 | msgstr "暂无提速信息" 36 | 37 | msgid "General Settings" 38 | msgstr "基本设置" 39 | 40 | msgid "Enabled" 41 | msgstr "启用" 42 | 43 | msgid "Enable DownLink Upgrade" 44 | msgstr "开启下行提速" 45 | 46 | msgid "Enable UpLink Upgrade" 47 | msgstr "开启上行提速" 48 | 49 | msgid "Enable Logging" 50 | msgstr "启用日志记录" 51 | 52 | msgid "Enable verbose logging" 53 | msgstr "启用详细日志" 54 | 55 | msgid "Upgrade interface" 56 | msgstr "指定提速接口" 57 | 58 | msgid "Keepalive interval" 59 | msgstr "保持连接周期" 60 | 61 | msgid "Account relogin" 62 | msgstr "帐号重新登录" 63 | 64 | msgid "Not enabled" 65 | msgstr "未启用" 66 | 67 | msgid "minutes" 68 | msgstr "分钟" 69 | 70 | msgid "hours" 71 | msgstr "小时" 72 | 73 | msgid "XLNetAcc account" 74 | msgstr "迅雷快鸟帐号" 75 | 76 | msgid "XLNetAcc password" 77 | msgstr "迅雷快鸟密码" 78 | 79 | msgid "Does not store the plaintext password, automatically emptied after start." 80 | msgstr "不存储明文密码,启动后自动清空。" 81 | 82 | msgid "Encrypted password" 83 | msgstr "加密后的密码" 84 | 85 | msgid "Auto-generate in accordance with the plaintext password, do not modify it!" 86 | msgstr "根据明文密码自动生成,请勿修改!" 87 | 88 | msgid "Log Data" 89 | msgstr "日志数据" 90 | 91 | msgid "Loading..." 92 | msgstr "正在加载..." 93 | 94 | msgid "Refresh every 5 seconds." 95 | msgstr "每 5 秒刷新。" 96 | 97 | msgid "syslog:" 98 | msgstr "系统日志:" 99 | 100 | msgid "log file:" 101 | msgstr "日志文件:" 102 | 103 | msgid "No log data." 104 | msgstr "无日志数据。" 105 | 106 | msgid "Error get log data." 107 | msgstr "获取日志数据失败。" 108 | -------------------------------------------------------------------------------- /files/luci/model/cbi/xlnetacc.lua: -------------------------------------------------------------------------------- 1 | local m, s, o 2 | local uci = luci.model.uci.cursor() 3 | 4 | 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.")) 5 | m:append(Template("xlnetacc/status")) 6 | 7 | s = m:section(NamedSection, "general", "general", translate("General Settings")) 8 | s.anonymous = true 9 | s.addremove = false 10 | 11 | o = s:option(Flag, "enabled", translate("Enabled")) 12 | o.rmempty = false 13 | 14 | o = s:option(Flag, "down_acc", translate("Enable DownLink Upgrade")) 15 | 16 | o = s:option(Flag, "up_acc", translate("Enable UpLink Upgrade")) 17 | 18 | o = s:option(Flag, "logging", translate("Enable Logging")) 19 | o.default = "1" 20 | 21 | o = s:option(Flag, "verbose", translate("Enable verbose logging")) 22 | o:depends("logging", "1") 23 | 24 | o = s:option(ListValue, "network", translate("Upgrade interface")) 25 | uci:foreach("network", "interface", function(section) 26 | if section[".name"] ~= "loopback" then 27 | o:value(section[".name"]) 28 | end 29 | end) 30 | 31 | o = s:option(Value, "keepalive", translate("Keepalive interval"), "5-60 " .. translate("minutes")) 32 | for _, v in ipairs({5, 10, 20, 30, 60}) do 33 | o:value(v, v .. " " .. translate("minutes")) 34 | end 35 | o.datatype = "range(5, 60)" 36 | o.default = 10 37 | 38 | o = s:option(Value, "relogin", translate("Account relogin"), "1-48 " .. translate("hours")) 39 | o:value(0, translate("Not enabled")) 40 | for _, v in ipairs({3, 12, 18, 24, 30}) do 41 | o:value(v, v .. " " .. translate("hours")) 42 | end 43 | o.datatype = "max(48)" 44 | o.default = 0 45 | 46 | o = s:option(Value, "account", translate("XLNetAcc account")) 47 | 48 | o = s:option(Value, "password", translate("XLNetAcc password")) 49 | o.password = true 50 | 51 | return m 52 | -------------------------------------------------------------------------------- /files/luci/view/xlnetacc/logview.htm: -------------------------------------------------------------------------------- 1 | <% css = [[ 2 | #log_text { 3 | padding: 10px; 4 | text-align: left; 5 | height: 500px; 6 | overflow: auto; 7 | } 8 | #log_text pre { 9 | word-break: break-all; 10 | margin: 0; 11 | } 12 | .description { 13 | color: #ffffff; 14 | background-color: #0099ff; 15 | } 16 | ]] 17 | %> 18 | 19 | <%+header%> 20 | 21 |
22 |

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

23 |
24 |
25 |
<%:Loading...%><%:Collecting data...%>
26 |
<%:Refresh every 5 seconds.%>
27 |
28 |
29 |
30 | 31 | 32 | 48 | 49 | <%+footer%> 50 | -------------------------------------------------------------------------------- /files/luci/view/xlnetacc/status.htm: -------------------------------------------------------------------------------- 1 |
2 | <%:Running Status%> 3 | 4 | 5 | 6 | 7 |
<%:XLNetAcc Running Status%><%:Collecting data...%>
<%:DownLink Upgrade Status%><%:Collecting data...%>
<%:UpLink Upgrade Status%><%:Collecting data...%>
8 |
9 | 10 | 22 | -------------------------------------------------------------------------------- /files/root/etc/config/xlnetacc: -------------------------------------------------------------------------------- 1 | 2 | config general 'general' 3 | option enabled '0' 4 | option network 'wan' 5 | 6 | -------------------------------------------------------------------------------- /files/root/etc/hotplug.d/iface/95-xlnetacc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | /etc/init.d/xlnetacc enabled || exit 0 4 | [ "$INTERFACE" != "$(uci get xlnetacc.general.network)" ] && exit 0 5 | 6 | case "$ACTION" in 7 | ifup) 8 | /etc/init.d/xlnetacc start 9 | ;; 10 | ifdown) 11 | /etc/init.d/xlnetacc stop 12 | ;; 13 | esac 14 | -------------------------------------------------------------------------------- /files/root/etc/init.d/xlnetacc: -------------------------------------------------------------------------------- 1 | #!/bin/sh /etc/rc.common 2 | 3 | START=95 4 | STOP=10 5 | SERVICE_DAEMONIZE=1 6 | 7 | NAME=xlnetacc 8 | 9 | start() { 10 | local retry=1 11 | while pidof "${NAME}.sh" >/dev/null 2>&1; do 12 | [ $retry -ge 10 ] && return 1 || let retry++ 13 | sleep 1 14 | done 15 | 16 | config_load "$NAME" 17 | config_get_bool enabled "general" "enabled" 0 18 | config_get_bool down_acc "general" "down_acc" 0 19 | config_get_bool up_acc "general" "up_acc" 0 20 | config_get network "general" "network" 21 | config_get username "general" "account" 22 | config_get password "general" "password" 23 | ( [ $enabled -eq 0 ] || [ $down_acc -eq 0 -a $up_acc -eq 0 ] || [ -z "$username" -o -z "$password" -o -z "$network" ] ) && return 2 24 | 25 | logger -p "daemon.notice" -t "$NAME" "XLNetAcc is starting ..." 26 | service_start /usr/bin/${NAME}.sh --start 27 | } 28 | 29 | stop() { 30 | pidof "${NAME}.sh" >/dev/null 2>&1 || return 1 31 | 32 | local pid spid 33 | for pid in $(pidof "${NAME}.sh"); do 34 | echo "Stop XLNetAcc process PID: $pid" 35 | kill $pid >/dev/null 2>&1 36 | for spid in $(pgrep -P $pid "sleep"); do 37 | echo "Stop XLNetAcc process SPID: $spid" 38 | kill $spid >/dev/null 2>&1 39 | done 40 | done 41 | logger -p "daemon.notice" -t "$NAME" "XLNetAcc has stoped." 42 | return 0 43 | } 44 | 45 | restart() { 46 | stop && sleep 1 47 | start 48 | } 49 | -------------------------------------------------------------------------------- /files/root/etc/uci-defaults/luci-xlnetacc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | uci -q batch <<-EOF >/dev/null 4 | delete ucitrack.@xlnetacc[-1] 5 | add ucitrack xlnetacc 6 | set ucitrack.@xlnetacc[-1].init=xlnetacc 7 | commit ucitrack 8 | EOF 9 | 10 | general=$(uci -q get xlnetacc.@general[-1]) 11 | if [ -z "$general" ]; then 12 | uci -q add xlnetacc general 13 | fi 14 | if [ "$general"x != "general"x ]; then 15 | uci -q batch <<-EOF >/dev/null 16 | rename xlnetacc.@general[-1]="general" 17 | commit xlnetacc 18 | EOF 19 | fi 20 | 21 | rm -rf /tmp/luci-indexcache /tmp/luci-modulecache 22 | exit 0 23 | -------------------------------------------------------------------------------- /files/root/usr/bin/xlnetacc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 声明常量 4 | readonly packageName='com.xunlei.vip.swjsq' 5 | readonly protocolVersion=300 6 | readonly businessType=68 7 | readonly sdkVersion='3.1.2.185150' 8 | readonly clientVersion='2.7.2.0' 9 | readonly agent_xl="android-ok-http-client/xl-acc-sdk/version-$sdkVersion" 10 | readonly agent_down='okhttp/3.9.1' 11 | readonly agent_up='android-async-http/xl-acc-sdk/version-1.0.0.1' 12 | readonly client_type_down='android-swjsq' 13 | readonly client_type_up='android-uplink' 14 | 15 | # 声明全局变量 16 | _bind_ip= 17 | _http_cmd= 18 | _peerid= 19 | _devicesign= 20 | _userid= 21 | _loginkey= 22 | _sessionid= 23 | _portal_down= 24 | _portal_up= 25 | _dial_account= 26 | access_url= 27 | http_args= 28 | user_agent= 29 | link_cn= 30 | lasterr= 31 | sequence_xl=1000000 32 | sequence_down=$(( $(date +%s) / 6 )) 33 | sequence_up=$sequence_down 34 | 35 | # 包含用于解析 JSON 格式返回值的函数 36 | . /usr/share/libubox/jshn.sh 37 | 38 | # 读取 UCI 设置相关函数 39 | uci_get_by_name() { 40 | local ret=$(uci get $NAME.$1.$2 2> /dev/null) 41 | echo -n ${ret:=$3} 42 | } 43 | uci_get_by_type() { 44 | local ret=$(uci get $NAME.@$1[-1].$2 2> /dev/null) 45 | echo -n ${ret:=$3} 46 | } 47 | uci_get_by_bool() { 48 | case $(uci_get_by_name "$1" "$2" "$3") in 49 | 1|on|true|yes|enabled) echo -n 1;; 50 | *) echo -n 0;; 51 | esac 52 | } 53 | 54 | # 日志和状态栏输出。1 日志文件, 2 系统日志, 4 详细模式, 8 下行状态栏, 16 上行状态栏, 32 失败状态 55 | _log() { 56 | local msg=$1 flag=$2 timestamp=$(date +'%Y/%m/%d %H:%M:%S') 57 | [ -z "$msg" ] && return 58 | [ -z "$flag" ] && flag=1 59 | 60 | [ $logging -eq 0 -a $(( $flag & 1 )) -ne 0 ] && flag=$(( $flag ^ 1 )) 61 | if [ $verbose -eq 0 -a $(( $flag & 4 )) -ne 0 ]; then 62 | [ $(( $flag & 1 )) -ne 0 ] && flag=$(( $flag ^ 1 )) 63 | [ $(( $flag & 2 )) -ne 0 ] && flag=$(( $flag ^ 2 )) 64 | fi 65 | if [ $down_acc -eq 0 -a $(( $flag & 8 )) -ne 0 ]; then 66 | flag=$(( $flag ^ 8 )) 67 | [ $up_acc -ne 0 ] && flag=$(( $flag | 16 )) 68 | fi 69 | if [ $up_acc -eq 0 -a $(( $flag & 16 )) -ne 0 ]; then 70 | flag=$(( $flag ^ 16 )) 71 | [ $down_acc -ne 0 ] && flag=$(( $flag | 8 )) 72 | fi 73 | 74 | [ $(( $flag & 1 )) -ne 0 ] && echo "$timestamp $msg" >> $LOGFILE 2> /dev/null 75 | [ $(( $flag & 2 )) -ne 0 ] && logger -p "daemon.info" -t "$NAME" "$msg" 76 | 77 | [ $(( $flag & 32 )) -eq 0 ] && local color="green" || local color="red" 78 | [ $(( $flag & 8 )) -ne 0 ] && echo -n "$timestamp $msg" > $down_state_file 2> /dev/null 79 | [ $(( $flag & 16 )) -ne 0 ] && echo -n "$timestamp $msg" > $up_state_file 2> /dev/null 80 | } 81 | 82 | # 清理日志 83 | clean_log() { 84 | [ $logging -eq 1 -a -f "$LOGFILE" ] || return 85 | [ $(wc -l "$LOGFILE" | awk '{print $1}') -le 800 ] && return 86 | _log "清理日志文件" 87 | local logdata=$(tail -n 500 "$LOGFILE") 88 | echo "$logdata" > $LOGFILE 2> /dev/null 89 | unset logdata 90 | } 91 | 92 | # 获取接口IP地址 93 | get_bind_ip() { 94 | json_cleanup; json_load "$(ubus call network.interface.$network status 2> /dev/null)" >/dev/null 2>&1 95 | json_select "ipv4-address" >/dev/null 2>&1; json_select 1 >/dev/null 2>&1 96 | json_get_var _bind_ip "address" 97 | if [ -z "$_bind_ip" -o "$_bind_ip"x == "0.0.0.0"x ]; then 98 | _log "获取网络 $network IP地址失败" 99 | return 1 100 | else 101 | _log "绑定IP地址: $_bind_ip" 102 | return 0 103 | fi 104 | } 105 | 106 | # 定义基本 HTTP 命令和参数 107 | gen_http_cmd() { 108 | _http_cmd="wget-ssl -nv -t 1 -T 5 -O - --no-check-certificate" 109 | _http_cmd="$_http_cmd --bind-address=$_bind_ip" 110 | } 111 | 112 | # 生成设备标识 113 | gen_device_sign() { 114 | local ifname macaddr 115 | while : ; do 116 | ifname=$(uci get "network.$network.ifname" 2> /dev/null) 117 | [ "${ifname:0:1}" == "@" ] && network="${ifname:1}" || break 118 | done 119 | [ -z "$ifname" ] && { _log "获取网络 $network 信息出错"; return; } 120 | json_cleanup; json_load "$(ubus call network.device status {\"name\":\"$ifname\"} 2> /dev/null)" >/dev/null 2>&1 121 | json_get_var macaddr "macaddr" 122 | [ -z "$macaddr" ] && { _log "获取网络 $network MAC地址出错"; return; } 123 | macaddr=$(echo -n "$macaddr" | awk '{print toupper($0)}') 124 | 125 | # 计算peerID 126 | local fake_peerid=$(awk -F- '{print toupper($5)}' '/proc/sys/kernel/random/uuid') 127 | readonly _peerid="${fake_peerid}004V" 128 | _log "_peerid is $_peerid" $(( 1 | 4 )) 129 | 130 | # 计算devicesign 131 | # sign = div.10?.device_id + md5(sha1(packageName + businessType + md5(a protocolVersion specific GUID))) 132 | local fake_device_id=$(echo -n "${macaddr//:/}" | openssl dgst -md5 | awk '{print $2}') 133 | local fake_device_sign=$(echo -n "${fake_device_id}${packageName}${businessType}c7f21687eed3cdb400ca11fc2263c998" \ 134 | | openssl dgst -sha1 | awk '{print $2}') 135 | readonly _devicesign="div101.${fake_device_id}"$(echo -n "$fake_device_sign" | openssl dgst -md5 | awk '{print $2}') 136 | _log "_devicesign is $_devicesign" $(( 1 | 4 )) 137 | } 138 | 139 | # 快鸟帐号通用参数 140 | swjsq_json() { 141 | let sequence_xl++ 142 | # 生成POST数据 143 | json_init 144 | json_add_string protocolVersion "$protocolVersion" 145 | json_add_string sequenceNo "$sequence_xl" 146 | json_add_string platformVersion '10' 147 | json_add_string isCompressed '0' 148 | json_add_string appid "$businessType" 149 | json_add_string clientVersion "$clientVersion" 150 | json_add_string peerID "$_peerid" 151 | json_add_string appName "ANDROID-$packageName" 152 | json_add_string sdkVersion "${sdkVersion##*.}" 153 | json_add_string devicesign "$_devicesign" 154 | json_add_string netWorkType 'WIFI' 155 | json_add_string providerName 'OTHER' 156 | json_add_string deviceModel 'MI' 157 | json_add_string deviceName 'Xiaomi Mi' 158 | json_add_string OSVersion "7.1.1" 159 | } 160 | 161 | # 帐号登录 162 | swjsq_login() { 163 | swjsq_json 164 | if [ -z "$_userid" -o -z "$_loginkey" ]; then 165 | access_url='https://mobile-login.xunlei.com/login' 166 | json_add_string userName "$username" 167 | json_add_string passWord "$password" 168 | json_add_string verifyKey 169 | json_add_string verifyCode 170 | json_add_string isMd5Pwd '0' 171 | else 172 | access_url='https://mobile-login.xunlei.com/loginkey' 173 | json_add_string userName "$_userid" 174 | json_add_string loginKey "$_loginkey" 175 | fi 176 | json_close_object 177 | 178 | local ret=$($_http_cmd --user-agent="$agent_xl" "$access_url" --post-data="$(json_dump)") 179 | case $? in 180 | 0) 181 | _log "login is $ret" $(( 1 | 4 )) 182 | json_cleanup; json_load "$ret" >/dev/null 2>&1 183 | json_get_var lasterr "errorCode" 184 | ;; 185 | 2) lasterr=-2;; 186 | 4) lasterr=-3;; 187 | *) lasterr=-1;; 188 | esac 189 | 190 | case ${lasterr:=-1} in 191 | 0) 192 | json_get_var _userid "userID" 193 | json_get_var _loginkey "loginKey" 194 | json_get_var _sessionid "sessionID" 195 | _log "_sessionid is $_sessionid" $(( 1 | 4 )) 196 | local outmsg="帐号登录成功"; _log "$outmsg" $(( 1 | 8 )) 197 | ;; 198 | 15) # 身份信息已失效 199 | _userid=; _loginkey=;; 200 | -1) 201 | local outmsg="帐号登录失败。迅雷服务器未响应,请稍候"; _log "$outmsg";; 202 | -2) 203 | local outmsg="Wget 参数解析错误,请更新 GNU Wget"; _log "$outmsg" $(( 1 | 8 | 32 ));; 204 | -3) 205 | local outmsg="Wget 网络通信失败,请稍候"; _log "$outmsg";; 206 | *) 207 | local errorDesc; json_get_var errorDesc "errorDesc" 208 | local outmsg="帐号登录失败。错误代码: ${lasterr}"; \ 209 | [ -n "$errorDesc" ] && outmsg="${outmsg},原因: $errorDesc"; _log "$outmsg" $(( 1 | 8 | 32 ));; 210 | esac 211 | 212 | [ $lasterr -eq 0 ] && return 0 || return 1 213 | } 214 | 215 | # 帐号注销 216 | swjsq_logout() { 217 | swjsq_json 218 | json_add_string userID "$_userid" 219 | json_add_string sessionID "$_sessionid" 220 | json_close_object 221 | 222 | local ret=$($_http_cmd --user-agent="$agent_xl" 'https://mobile-login.xunlei.com/logout' --post-data="$(json_dump)") 223 | _log "logout is $ret" $(( 1 | 4 )) 224 | json_cleanup; json_load "$ret" >/dev/null 2>&1 225 | json_get_var lasterr "errorCode" 226 | 227 | case ${lasterr:=-1} in 228 | 0) 229 | _sessionid= 230 | local outmsg="帐号注销成功"; _log "$outmsg" $(( 1 | 8 ));; 231 | -1) 232 | local outmsg="帐号注销失败。迅雷服务器未响应,请稍候"; _log "$outmsg";; 233 | *) 234 | local errorDesc; json_get_var errorDesc "errorDesc" 235 | local outmsg="帐号注销失败。错误代码: ${lasterr}"; \ 236 | [ -n "$errorDesc" ] && outmsg="${outmsg},原因: $errorDesc"; _log "$outmsg" $(( 1 | 8 | 32 ));; 237 | esac 238 | 239 | [ $lasterr -eq 0 ] && return 0 || return 1 240 | } 241 | 242 | # 获取用户信息 243 | swjsq_getuserinfo() { 244 | local _vasid vasid_down=14 vasid_up=33 outmsg 245 | [ $down_acc -ne 0 ] && _vasid="${_vasid}${vasid_down},"; [ $up_acc -ne 0 ] && _vasid="${_vasid}${vasid_up}," 246 | swjsq_json 247 | json_add_string userID "$_userid" 248 | json_add_string sessionID "$_sessionid" 249 | json_add_string vasid "$_vasid" 250 | json_close_object 251 | 252 | local ret=$($_http_cmd --user-agent="$agent_xl" 'https://mobile-login.xunlei.com/getuserinfo' --post-data="$(json_dump)") 253 | _log "getuserinfo is $ret" $(( 1 | 4 )) 254 | json_cleanup; json_load "$ret" >/dev/null 2>&1 255 | json_get_var lasterr "errorCode" 256 | 257 | case ${lasterr:=-1} in 258 | 0) 259 | local index=1 can_down=0 vasid isVip isYear expireDate 260 | json_select "vipList" >/dev/null 2>&1 261 | while : ; do 262 | json_select $index >/dev/null 2>&1 263 | [ $? -ne 0 ] && break 264 | json_get_var vasid "vasid" 265 | json_get_var isVip "isVip" 266 | json_get_var isYear "isYear" 267 | json_get_var expireDate "expireDate" 268 | json_select ".." >/dev/null 2>&1 269 | let index++ 270 | case ${vasid:-0} in 271 | 2) [ $down_acc -ne 0 ] && outmsg="迅雷超级会员" || continue;; 272 | $vasid_down) outmsg="迅雷快鸟会员";; 273 | $vasid_up) outmsg="上行提速会员";; 274 | *) continue;; 275 | esac 276 | if [ ${isVip:-0} -eq 1 -o ${isYear:-0} -eq 1 ]; then 277 | outmsg="${outmsg}有效。会员到期时间:${expireDate:0:4}-${expireDate:4:2}-${expireDate:6:2}" 278 | [ $vasid -eq $vasid_up ] && _log "$outmsg" $(( 1 | 16 )) || _log "$outmsg" $(( 1 | 8 )) 279 | [ $vasid -ne $vasid_up ] && can_down=$(( $can_down | 1 )) 280 | else 281 | if [ ${#expireDate} -ge 8 ]; then 282 | outmsg="${outmsg}已到期。会员到期时间:${expireDate:0:4}-${expireDate:4:2}-${expireDate:6:2}" 283 | else 284 | outmsg="${outmsg}无效" 285 | fi 286 | [ $vasid -eq $vasid_up ] && _log "$outmsg" $(( 1 | 16 | 32 )) || _log "$outmsg" $(( 1 | 8 | 32 )) 287 | [ $vasid -eq $vasid_up ] && up_acc=0 288 | fi 289 | done 290 | [ $can_down -eq 0 ] && down_acc=0 291 | ;; 292 | -1) 293 | outmsg="获取迅雷会员信息失败。迅雷服务器未响应,请稍候"; _log "$outmsg";; 294 | *) 295 | local errorDesc; json_get_var errorDesc "errorDesc" 296 | outmsg="获取迅雷会员信息失败。错误代码: ${lasterr}"; \ 297 | [ -n "$errorDesc" ] && outmsg="${outmsg},原因: $errorDesc"; _log "$outmsg" $(( 1 | 8 | 32 ));; 298 | esac 299 | 300 | [ $lasterr -eq 0 ] && return 0 || return 1 301 | } 302 | 303 | # 登录时间更新 304 | swjsq_renewal() { 305 | xlnetacc_var 1 306 | local limitdate=$(date +%Y%m%d -d "1970.01.01-00:00:$(( $(date +%s) + 30 * 24 * 60 * 60 ))") 307 | 308 | access_url='http://api.ext.swjsq.vip.xunlei.com' 309 | local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/renewal?${http_args%&dial_account=*}&limitdate=$limitdate") 310 | _log "renewal is $ret" $(( 1 | 4 )) 311 | json_cleanup; json_load "$ret" >/dev/null 2>&1 312 | json_get_var lasterr "errno" 313 | 314 | case ${lasterr:=-1} in 315 | 0) 316 | local outmsg="更新登录时间成功。帐号登录展期:${limitdate:0:4}-${limitdate:4:2}-${limitdate:6:2}"; _log "$outmsg";; 317 | -1) 318 | local outmsg="更新登录时间失败。迅雷服务器未响应,请稍候"; _log "$outmsg";; 319 | *) 320 | local message; json_get_var message "richmessage" 321 | local outmsg="更新登录时间失败。错误代码: ${lasterr}"; \ 322 | [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | 8 | 32 ));; 323 | esac 324 | 325 | [ $lasterr -eq 0 ] && return 0 || return 1 326 | } 327 | 328 | # 获取提速入口 329 | swjsq_portal() { 330 | xlnetacc_var $1 331 | 332 | [ $1 -eq 1 ] && access_url='http://api.portal.swjsq.vip.xunlei.com:81/v2/queryportal' || \ 333 | access_url='http://api.upportal.swjsq.vip.xunlei.com/v2/queryportal' 334 | local ret=$($_http_cmd --user-agent="$user_agent" "$access_url") 335 | _log "portal $1 is $ret" $(( 1 | 4 )) 336 | json_cleanup; json_load "$ret" >/dev/null 2>&1 337 | json_get_var lasterr "errno" 338 | 339 | case ${lasterr:=-1} in 340 | 0) 341 | local interface_ip interface_port province sp 342 | json_get_var interface_ip "interface_ip" 343 | json_get_var interface_port "interface_port" 344 | json_get_var province "province_name" 345 | json_get_var sp "sp_name" 346 | if [ $1 -eq 1 ]; then 347 | _portal_down="http://$interface_ip:$interface_port/v2" 348 | _log "_portal_down is $_portal_down" $(( 1 | 4 )) 349 | else 350 | _portal_up="http://$interface_ip:$interface_port/v2" 351 | _log "_portal_up is $_portal_up" $(( 1 | 4 )) 352 | fi 353 | local outmsg="获取${link_cn}提速入口成功"; \ 354 | [ -n "$province" -a -n "$sp" ] && outmsg="${outmsg}。运营商:${province}${sp}"; _log "$outmsg" $(( 1 | $1 * 8 )) 355 | ;; 356 | -1) 357 | local outmsg="获取${link_cn}提速入口失败。迅雷服务器未响应,请稍候"; _log "$outmsg";; 358 | *) 359 | local message; json_get_var message "message" 360 | local outmsg="获取${link_cn}提速入口失败。错误代码: ${lasterr}"; \ 361 | [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; 362 | esac 363 | 364 | [ $lasterr -eq 0 ] && return 0 || return 1 365 | } 366 | 367 | # 获取网络带宽信息 368 | isp_bandwidth() { 369 | xlnetacc_var $1 370 | 371 | local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/bandwidth?${http_args%&dial_account=*}") 372 | _log "bandwidth $1 is $ret" $(( 1 | 4 )) 373 | json_cleanup; json_load "$ret" >/dev/null 2>&1 374 | json_get_var lasterr "errno" 375 | 376 | case ${lasterr:=-1} in 377 | 0) 378 | # 获取带宽数据 379 | local can_upgrade bind_dial_account dial_account stream cur_bandwidth max_bandwidth 380 | [ $1 -eq 1 ] && stream="downstream" || stream="upstream" 381 | json_get_var can_upgrade "can_upgrade" 382 | json_get_var bind_dial_account "bind_dial_account" 383 | json_get_var dial_account "dial_account" 384 | json_select; json_select "bandwidth" >/dev/null 2>&1 385 | json_get_var cur_bandwidth "$stream" 386 | json_select; json_select "max_bandwidth" >/dev/null 2>&1 387 | json_get_var max_bandwidth "$stream" 388 | json_select 389 | cur_bandwidth=$(( ${cur_bandwidth:-0} / 1024 )) 390 | max_bandwidth=$(( ${max_bandwidth:-0} / 1024 )) 391 | 392 | if [ -n "$bind_dial_account" -a "$bind_dial_account" != "$dial_account" ]; then 393 | local outmsg="绑定宽带账号 $bind_dial_account 与当前宽带账号 $dial_account 不一致,请联系迅雷客服解绑(每月仅一次)"; \ 394 | _log "$outmsg" $(( 1 | 8 | 32 )) 395 | down_acc=0; up_acc=0 396 | elif [ $can_upgrade -eq 0 ]; then 397 | local message; json_get_var message "richmessage"; [ -z "$message" ] && json_get_var message "message" 398 | local outmsg="${link_cn}无法提速"; \ 399 | [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 )) 400 | [ $1 -eq 1 ] && down_acc=0 || up_acc=0 401 | elif [ $cur_bandwidth -ge $max_bandwidth ]; then 402 | local outmsg="${link_cn}无需提速。当前带宽 ${cur_bandwidth}M,超过最大可提升带宽 ${max_bandwidth}M"; \ 403 | _log "$outmsg" $(( 1 | $1 * 8 )) 404 | [ $1 -eq 1 ] && down_acc=0 || up_acc=0 405 | else 406 | if [ -z "$_dial_account" -a -n "$dial_account" ]; then 407 | _dial_account=$dial_account 408 | _log "_dial_account is $_dial_account" $(( 1 | 4 )) 409 | fi 410 | local outmsg="${link_cn}可以提速。当前带宽 ${cur_bandwidth}M,可提升至 ${max_bandwidth}M"; _log "$outmsg" $(( 1 | $1 * 8 )) 411 | fi 412 | ;; 413 | 724) # 724 账号存在异常 414 | lasterr=-2 415 | local outmsg="获取${link_cn}网络带宽信息失败。原因: 您的账号存在异常,请联系迅雷客服反馈"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; 416 | 3103) # 3103 线路暂不支持 417 | lasterr=0 418 | local province sp 419 | json_get_var province "province_name"; json_get_var sp "sp_name" 420 | local outmsg="${link_cn}无法提速。原因: ${province}${sp}线路暂不支持"; _log "$outmsg" $(( 1 | $1 * 8 | 32 )) 421 | [ $1 -eq 1 ] && down_acc=0 || up_acc=0 422 | ;; 423 | -1) 424 | local outmsg="获取${link_cn}网络带宽信息失败。运营商服务器未响应,请稍候"; _log "$outmsg";; 425 | *) 426 | local message; json_get_var message "richmessage"; [ -z "$message" ] && json_get_var message "message" 427 | local outmsg="获取${link_cn}网络带宽信息失败。错误代码: ${lasterr}"; \ 428 | [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; 429 | esac 430 | 431 | [ $lasterr -eq 0 ] && return 0 || return 1 432 | } 433 | 434 | # 发送带宽提速信号 435 | isp_upgrade() { 436 | xlnetacc_var $1 437 | 438 | local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/upgrade?$http_args") 439 | _log "upgrade $1 is $ret" $(( 1 | 4 )) 440 | json_cleanup; json_load "$ret" >/dev/null 2>&1 441 | json_get_var lasterr "errno" 442 | 443 | case ${lasterr:=-1} in 444 | 0) 445 | local bandwidth 446 | json_select "bandwidth" >/dev/null 2>&1 447 | json_get_var bandwidth "downstream" 448 | bandwidth=$(( ${bandwidth:-0} / 1024 )) 449 | local outmsg="${link_cn}提速成功,带宽已提升到 ${bandwidth}M"; _log "$outmsg" $(( 1 | $1 * 8 )) 450 | [ $1 -eq 1 ] && down_acc=2 || up_acc=2 451 | ;; 452 | 812) # 812 已处于提速状态 453 | lasterr=0 454 | local outmsg="${link_cn}提速成功,当前宽带已处于提速状态"; _log "$outmsg" $(( 1 | $1 * 8 )) 455 | [ $1 -eq 1 ] && down_acc=2 || up_acc=2 456 | ;; 457 | 724) # 724 账号存在异常 458 | lasterr=-2 459 | local outmsg="${link_cn}提速失败。原因: 您的账号存在异常,请联系迅雷客服反馈"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; 460 | -1) 461 | local outmsg="${link_cn}提速失败。运营商服务器未响应,请稍候"; _log "$outmsg";; 462 | *) 463 | local message; json_get_var message "richmessage"; [ -z "$message" ] && json_get_var message "message" 464 | local outmsg="${link_cn}提速失败。错误代码: ${lasterr}"; \ 465 | [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; 466 | esac 467 | 468 | [ $lasterr -eq 0 ] && return 0 || return 1 469 | } 470 | 471 | # 发送提速心跳信号 472 | isp_keepalive() { 473 | xlnetacc_var $1 474 | 475 | local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/keepalive?$http_args") 476 | _log "keepalive $1 is $ret" $(( 1 | 4 )) 477 | json_cleanup; json_load "$ret" >/dev/null 2>&1 478 | json_get_var lasterr "errno" 479 | 480 | case ${lasterr:=-1} in 481 | 0) 482 | local outmsg="${link_cn}心跳信号返回正常"; _log "$outmsg";; 483 | 513) # 513 提速通道不存在 484 | lasterr=-2 485 | local outmsg="${link_cn}提速超时,提速通道不存在"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; 486 | -1) 487 | local outmsg="${link_cn}心跳信号发送失败。运营商服务器未响应,请稍候"; _log "$outmsg";; 488 | *) 489 | local message; json_get_var message "richmessage"; [ -z "$message" ] && json_get_var message "message" 490 | local outmsg="${link_cn}提速失效。错误代码: ${lasterr}"; \ 491 | [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; 492 | esac 493 | 494 | [ $lasterr -eq 0 ] && return 0 || return 1 495 | } 496 | 497 | # 发送带宽恢复信号 498 | isp_recover() { 499 | xlnetacc_var $1 500 | 501 | local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/recover?$http_args") 502 | _log "recover $1 is $ret" $(( 1 | 4 )) 503 | json_cleanup; json_load "$ret" >/dev/null 2>&1 504 | json_get_var lasterr "errno" 505 | 506 | case ${lasterr:=-1} in 507 | 0) 508 | local outmsg="${link_cn}带宽已恢复"; _log "$outmsg" $(( 1 | $1 * 8 )) 509 | [ $1 -eq 1 ] && down_acc=1 || up_acc=1;; 510 | -1) 511 | local outmsg="${link_cn}带宽恢复失败。运营商服务器未响应,请稍候"; _log "$outmsg";; 512 | *) 513 | local message; json_get_var message "richmessage"; [ -z "$message" ] && json_get_var message "message" 514 | local outmsg="${link_cn}带宽恢复失败。错误代码: ${lasterr}"; \ 515 | [ -n "$message" ] && outmsg="${outmsg},原因: $message"; _log "$outmsg" $(( 1 | $1 * 8 | 32 ));; 516 | esac 517 | 518 | [ $lasterr -eq 0 ] && return 0 || return 1 519 | } 520 | 521 | # 查询提速信息,未使用 522 | isp_query() { 523 | xlnetacc_var $1 524 | 525 | local ret=$($_http_cmd --user-agent="$user_agent" "$access_url/query_try_info?$http_args") 526 | _log "query_try_info $1 is $ret" $(( 1 | 4 )) 527 | json_cleanup; json_load "$ret" >/dev/null 2>&1 528 | json_get_var lasterr "errno" 529 | 530 | [ $lasterr -eq 0 ] && return 0 || return 1 531 | } 532 | 533 | # 设置参数变量 534 | xlnetacc_var() { 535 | if [ $1 -eq 1 ]; then 536 | let sequence_down++ 537 | access_url=$_portal_down 538 | 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" 539 | user_agent=$agent_down 540 | link_cn="下行" 541 | else 542 | let sequence_up++ 543 | access_url=$_portal_up 544 | http_args="sequence=${sequence_up}&client_type=${client_type_up}-${clientVersion}&client_version=${client_type_up//-/}-${clientVersion}" 545 | user_agent=$agent_down 546 | link_cn="上行" 547 | fi 548 | http_args="${http_args}&peerid=${_peerid}&userid=${_userid}&sessionid=${_sessionid}&user_type=1&os=android-7.1.1" 549 | [ -n "$_dial_account" ] && http_args="${http_args}&dial_account=${_dial_account}" 550 | } 551 | 552 | # 重试循环 553 | xlnetacc_retry() { 554 | if [ $# -ge 3 -a $3 -ne 0 ]; then 555 | [ $2 -eq 1 -a $down_acc -ne $3 ] && return 0 556 | [ $2 -eq 2 -a $up_acc -ne $3 ] && return 0 557 | fi 558 | 559 | local retry=1 560 | while : ; do 561 | lasterr= 562 | eval $1 $2 && break # 成功 563 | [ $# -ge 4 -a $retry -ge $4 ] && break || let retry++ # 重试超时 564 | case $lasterr in 565 | -1) sleep 5s;; # 服务器未响应 566 | -2) break;; # 严重错误 567 | *) sleep 3s;; # 其它错误 568 | esac 569 | done 570 | 571 | [ ${lasterr:-0} -eq 0 ] && return 0 || return 1 572 | } 573 | 574 | # 注销已登录帐号 575 | xlnetacc_logout() { 576 | [ -z "$_sessionid" ] && return 2 577 | [ $# -ge 1 ] && local retry=$1 || local retry=1 578 | 579 | xlnetacc_retry 'isp_recover' 1 2 $retry 580 | xlnetacc_retry 'isp_recover' 2 2 $retry 581 | xlnetacc_retry 'swjsq_logout' 0 0 $retry 582 | [ $down_acc -ne 0 ] && down_acc=1; [ $up_acc -ne 0 ] && up_acc=1 583 | _sessionid=; _dial_account= 584 | 585 | [ $lasterr -eq 0 ] && return 0 || return 1 586 | } 587 | 588 | # 中止信号处理 589 | sigterm() { 590 | _log "trap sigterm, exit" $(( 1 | 4 )) 591 | xlnetacc_logout 592 | rm -f "$down_state_file" "$up_state_file" 593 | exit 0 594 | } 595 | 596 | # 初始化 597 | xlnetacc_init() { 598 | [ "$1" != "--start" ] && return 1 599 | 600 | # 防止重复启动 601 | local pid 602 | for pid in $(pidof "${0##*/}"); do 603 | [ $pid -ne $$ ] && return 1 604 | done 605 | 606 | # 读取设置 607 | readonly NAME=xlnetacc 608 | readonly LOGFILE=/var/log/${NAME}.log 609 | readonly down_state_file=/var/state/${NAME}_down_state 610 | readonly up_state_file=/var/state/${NAME}_up_state 611 | down_acc=$(uci_get_by_bool "general" "down_acc" 0) 612 | up_acc=$(uci_get_by_bool "general" "up_acc" 0) 613 | readonly logging=$(uci_get_by_bool "general" "logging" 1) 614 | readonly verbose=$(uci_get_by_bool "general" "verbose" 0) 615 | network=$(uci_get_by_name "general" "network" "wan") 616 | keepalive=$(uci_get_by_name "general" "keepalive" 10) 617 | relogin=$(uci_get_by_name "general" "relogin" 0) 618 | readonly username=$(uci_get_by_name "general" "account") 619 | readonly password=$(uci_get_by_name "general" "password") 620 | local enabled=$(uci_get_by_bool "general" "enabled" 0) 621 | ([ $enabled -eq 0 ] || [ $down_acc -eq 0 -a $up_acc -eq 0 ] || [ -z "$username" -o -z "$password" -o -z "$network" ]) && return 2 622 | ([ -z "$keepalive" -o -n "${keepalive//[0-9]/}" ] || [ $keepalive -lt 5 -o $keepalive -gt 60 ]) && keepalive=10 623 | readonly keepalive=$(( $keepalive )) 624 | ([ -z "$relogin" -o -n "${relogin//[0-9]/}" ] || [ $relogin -gt 48 ]) && relogin=0 625 | readonly relogin=$(( $relogin * 60 * 60 )) 626 | 627 | [ $logging -eq 1 ] && [ ! -d /var/log ] && mkdir -p /var/log 628 | [ -f "$LOGFILE" ] && _log "------------------------------" 629 | _log "迅雷快鸟正在启动..." 630 | 631 | # 检查外部调用工具 632 | command -v wget-ssl >/dev/null || { _log "GNU Wget 未安装"; return 3; } 633 | local opensslchk=$(echo -n 'openssl' | openssl dgst -sha1 | awk '{print $2}') 634 | [ "$opensslchk" != 'c898fa1e7226427010e329971e82c669f8d8abb4' ] && { _log "openssl-util 未安装或计算错误"; return 3; } 635 | 636 | # 捕获中止信号 637 | trap 'sigterm' INT # Ctrl-C 638 | trap 'sigterm' QUIT # Ctrl-\ 639 | trap 'sigterm' TERM # kill 640 | 641 | # 生成设备标识 642 | gen_device_sign 643 | [ ${#_peerid} -ne 16 -o ${#_devicesign} -ne 71 ] && return 4 644 | 645 | clean_log 646 | [ -d /var/state ] || mkdir -p /var/state 647 | rm -f "$down_state_file" "$up_state_file" 648 | return 0 649 | } 650 | 651 | # 程序主体 652 | xlnetacc_main() { 653 | while : ; do 654 | # 获取外网IP地址 655 | xlnetacc_retry 'get_bind_ip' 656 | gen_http_cmd 657 | 658 | # 注销快鸟帐号 659 | xlnetacc_logout 3 && sleep 3s 660 | 661 | # 登录快鸟帐号 662 | while : ; do 663 | lasterr= 664 | swjsq_login 665 | case $lasterr in 666 | 0) break;; # 登录成功 667 | -1) sleep 5s;; # 服务器未响应 668 | -2) return 7;; # Wget 参数解析错误 669 | -3) sleep 3s;; # Wget 网络通信失败 670 | 6) sleep 130m;; # 需要输入验证码 671 | 8) sleep 3m;; # 服务器系统维护 672 | 15) sleep 1s;; # 身份信息已失效 673 | *) return 5;; # 登录失败 674 | esac 675 | done 676 | 677 | # 获取用户信息 678 | xlnetacc_retry 'swjsq_getuserinfo' 679 | [ $down_acc -eq 0 -a $up_acc -eq 0 ] && break 680 | # 登录时间更新 681 | xlnetacc_retry 'swjsq_renewal' 682 | # 获取提速入口 683 | xlnetacc_retry 'swjsq_portal' 1 1 684 | xlnetacc_retry 'swjsq_portal' 2 1 685 | # 获取带宽信息 686 | xlnetacc_retry 'isp_bandwidth' 1 1 10 || { sleep 3m; continue; } 687 | xlnetacc_retry 'isp_bandwidth' 2 1 10 || { sleep 3m; continue; } 688 | [ $down_acc -eq 0 -a $up_acc -eq 0 ] && break 689 | # 带宽提速 690 | xlnetacc_retry 'isp_upgrade' 1 1 10 || { sleep 3m; continue; } 691 | xlnetacc_retry 'isp_upgrade' 2 1 10 || { sleep 3m; continue; } 692 | 693 | # 心跳保持 694 | local timer=$(date +%s) 695 | while : ; do 696 | clean_log # 清理日志 697 | sleep ${keepalive}m 698 | [ $relogin -ne 0 -a $(( $(date +%s) - $timer )) -ge $relogin ] && break # 登录超时 699 | xlnetacc_retry 'isp_keepalive' 1 2 5 || break 700 | xlnetacc_retry 'isp_keepalive' 2 2 5 || break 701 | done 702 | done 703 | xlnetacc_logout 704 | _log "无法提速,迅雷快鸟已停止。" 705 | return 6 706 | } 707 | 708 | # 程序入口 709 | xlnetacc_init "$@" && xlnetacc_main 710 | exit $? 711 | -------------------------------------------------------------------------------- /tools/po2lmo/Makefile: -------------------------------------------------------------------------------- 1 | 2 | INSTALL = install 3 | PREFIX = /usr/bin 4 | 5 | po2lmo: src/po2lmo.o src/template_lmo.o 6 | $(CC) $(LDFLAGS) -o src/po2lmo src/po2lmo.o src/template_lmo.o 7 | 8 | install: 9 | $(INSTALL) -m 755 src/po2lmo $(PREFIX) 10 | 11 | clean: 12 | $(RM) src/po2lmo src/*.o 13 | -------------------------------------------------------------------------------- /tools/po2lmo/src/po2lmo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * lmo - Lua Machine Objects - PO to LMO conversion tool 3 | * 4 | * Copyright (C) 2009-2012 Jo-Philipp Wich 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "template_lmo.h" 20 | 21 | static void die(const char *msg) 22 | { 23 | fprintf(stderr, "Error: %s\n", msg); 24 | exit(1); 25 | } 26 | 27 | static void usage(const char *name) 28 | { 29 | fprintf(stderr, "Usage: %s input.po output.lmo\n", name); 30 | exit(1); 31 | } 32 | 33 | static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream) 34 | { 35 | if( fwrite(ptr, size, nmemb, stream) == 0 ) 36 | die("Failed to write stdout"); 37 | } 38 | 39 | static int extract_string(const char *src, char *dest, int len) 40 | { 41 | int pos = 0; 42 | int esc = 0; 43 | int off = -1; 44 | 45 | for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ ) 46 | { 47 | if( (off == -1) && (src[pos] == '"') ) 48 | { 49 | off = pos + 1; 50 | } 51 | else if( off >= 0 ) 52 | { 53 | if( esc == 1 ) 54 | { 55 | switch (src[pos]) 56 | { 57 | case '"': 58 | case '\\': 59 | off++; 60 | break; 61 | } 62 | dest[pos-off] = src[pos]; 63 | esc = 0; 64 | } 65 | else if( src[pos] == '\\' ) 66 | { 67 | dest[pos-off] = src[pos]; 68 | esc = 1; 69 | } 70 | else if( src[pos] != '"' ) 71 | { 72 | dest[pos-off] = src[pos]; 73 | } 74 | else 75 | { 76 | dest[pos-off] = '\0'; 77 | break; 78 | } 79 | } 80 | } 81 | 82 | return (off > -1) ? strlen(dest) : -1; 83 | } 84 | 85 | static int cmp_index(const void *a, const void *b) 86 | { 87 | uint32_t x = ((const lmo_entry_t *)a)->key_id; 88 | uint32_t y = ((const lmo_entry_t *)b)->key_id; 89 | 90 | if (x < y) 91 | return -1; 92 | else if (x > y) 93 | return 1; 94 | 95 | return 0; 96 | } 97 | 98 | static void print_uint32(uint32_t x, FILE *out) 99 | { 100 | uint32_t y = htonl(x); 101 | print(&y, sizeof(uint32_t), 1, out); 102 | } 103 | 104 | static void print_index(void *array, int n, FILE *out) 105 | { 106 | lmo_entry_t *e; 107 | 108 | qsort(array, n, sizeof(*e), cmp_index); 109 | 110 | for (e = array; n > 0; n--, e++) 111 | { 112 | print_uint32(e->key_id, out); 113 | print_uint32(e->val_id, out); 114 | print_uint32(e->offset, out); 115 | print_uint32(e->length, out); 116 | } 117 | } 118 | 119 | int main(int argc, char *argv[]) 120 | { 121 | char line[4096]; 122 | char key[4096]; 123 | char val[4096]; 124 | char tmp[4096]; 125 | int state = 0; 126 | int offset = 0; 127 | int length = 0; 128 | int n_entries = 0; 129 | void *array = NULL; 130 | lmo_entry_t *entry = NULL; 131 | uint32_t key_id, val_id; 132 | 133 | FILE *in; 134 | FILE *out; 135 | 136 | if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) ) 137 | usage(argv[0]); 138 | 139 | memset(line, 0, sizeof(key)); 140 | memset(key, 0, sizeof(val)); 141 | memset(val, 0, sizeof(val)); 142 | 143 | while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) ) 144 | { 145 | if( state == 0 && strstr(line, "msgid \"") == line ) 146 | { 147 | switch(extract_string(line, key, sizeof(key))) 148 | { 149 | case -1: 150 | die("Syntax error in msgid"); 151 | case 0: 152 | state = 1; 153 | break; 154 | default: 155 | state = 2; 156 | } 157 | } 158 | else if( state == 1 || state == 2 ) 159 | { 160 | if( strstr(line, "msgstr \"") == line || state == 2 ) 161 | { 162 | switch(extract_string(line, val, sizeof(val))) 163 | { 164 | case -1: 165 | state = 4; 166 | break; 167 | default: 168 | state = 3; 169 | } 170 | } 171 | else 172 | { 173 | switch(extract_string(line, tmp, sizeof(tmp))) 174 | { 175 | case -1: 176 | state = 2; 177 | break; 178 | default: 179 | strcat(key, tmp); 180 | } 181 | } 182 | } 183 | else if( state == 3 ) 184 | { 185 | switch(extract_string(line, tmp, sizeof(tmp))) 186 | { 187 | case -1: 188 | state = 4; 189 | break; 190 | default: 191 | strcat(val, tmp); 192 | } 193 | } 194 | 195 | if( state == 4 ) 196 | { 197 | if( strlen(key) > 0 && strlen(val) > 0 ) 198 | { 199 | key_id = sfh_hash(key, strlen(key)); 200 | val_id = sfh_hash(val, strlen(val)); 201 | 202 | if( key_id != val_id ) 203 | { 204 | n_entries++; 205 | array = realloc(array, n_entries * sizeof(lmo_entry_t)); 206 | entry = (lmo_entry_t *)array + n_entries - 1; 207 | 208 | if (!array) 209 | die("Out of memory"); 210 | 211 | entry->key_id = key_id; 212 | entry->val_id = val_id; 213 | entry->offset = offset; 214 | entry->length = strlen(val); 215 | 216 | length = strlen(val) + ((4 - (strlen(val) % 4)) % 4); 217 | 218 | print(val, length, 1, out); 219 | offset += length; 220 | } 221 | } 222 | 223 | state = 0; 224 | memset(key, 0, sizeof(key)); 225 | memset(val, 0, sizeof(val)); 226 | } 227 | 228 | memset(line, 0, sizeof(line)); 229 | } 230 | 231 | print_index(array, n_entries, out); 232 | 233 | if( offset > 0 ) 234 | { 235 | print_uint32(offset, out); 236 | fsync(fileno(out)); 237 | fclose(out); 238 | } 239 | else 240 | { 241 | fclose(out); 242 | unlink(argv[2]); 243 | } 244 | 245 | fclose(in); 246 | return(0); 247 | } 248 | -------------------------------------------------------------------------------- /tools/po2lmo/src/template_lmo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * lmo - Lua Machine Objects - Base functions 3 | * 4 | * Copyright (C) 2009-2010 Jo-Philipp Wich 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include "template_lmo.h" 20 | 21 | /* 22 | * Hash function from http://www.azillionmonkeys.com/qed/hash.html 23 | * Copyright (C) 2004-2008 by Paul Hsieh 24 | */ 25 | 26 | uint32_t sfh_hash(const char *data, int len) 27 | { 28 | uint32_t hash = len, tmp; 29 | int rem; 30 | 31 | if (len <= 0 || data == NULL) return 0; 32 | 33 | rem = len & 3; 34 | len >>= 2; 35 | 36 | /* Main loop */ 37 | for (;len > 0; len--) { 38 | hash += sfh_get16(data); 39 | tmp = (sfh_get16(data+2) << 11) ^ hash; 40 | hash = (hash << 16) ^ tmp; 41 | data += 2*sizeof(uint16_t); 42 | hash += hash >> 11; 43 | } 44 | 45 | /* Handle end cases */ 46 | switch (rem) { 47 | case 3: hash += sfh_get16(data); 48 | hash ^= hash << 16; 49 | hash ^= data[sizeof(uint16_t)] << 18; 50 | hash += hash >> 11; 51 | break; 52 | case 2: hash += sfh_get16(data); 53 | hash ^= hash << 11; 54 | hash += hash >> 17; 55 | break; 56 | case 1: hash += *data; 57 | hash ^= hash << 10; 58 | hash += hash >> 1; 59 | } 60 | 61 | /* Force "avalanching" of final 127 bits */ 62 | hash ^= hash << 3; 63 | hash += hash >> 5; 64 | hash ^= hash << 4; 65 | hash += hash >> 17; 66 | hash ^= hash << 25; 67 | hash += hash >> 6; 68 | 69 | return hash; 70 | } 71 | 72 | uint32_t lmo_canon_hash(const char *str, int len) 73 | { 74 | char res[4096]; 75 | char *ptr, prev; 76 | int off; 77 | 78 | if (!str || len >= sizeof(res)) 79 | return 0; 80 | 81 | for (prev = ' ', ptr = res, off = 0; off < len; prev = *str, off++, str++) 82 | { 83 | if (isspace(*str)) 84 | { 85 | if (!isspace(prev)) 86 | *ptr++ = ' '; 87 | } 88 | else 89 | { 90 | *ptr++ = *str; 91 | } 92 | } 93 | 94 | if ((ptr > res) && isspace(*(ptr-1))) 95 | ptr--; 96 | 97 | return sfh_hash(res, ptr - res); 98 | } 99 | 100 | lmo_archive_t * lmo_open(const char *file) 101 | { 102 | int in = -1; 103 | uint32_t idx_offset = 0; 104 | struct stat s; 105 | 106 | lmo_archive_t *ar = NULL; 107 | 108 | if (stat(file, &s) == -1) 109 | goto err; 110 | 111 | if ((in = open(file, O_RDONLY)) == -1) 112 | goto err; 113 | 114 | if ((ar = (lmo_archive_t *)malloc(sizeof(*ar))) != NULL) 115 | { 116 | memset(ar, 0, sizeof(*ar)); 117 | 118 | ar->fd = in; 119 | ar->size = s.st_size; 120 | 121 | fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC); 122 | 123 | if ((ar->mmap = mmap(NULL, ar->size, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED) 124 | goto err; 125 | 126 | idx_offset = ntohl(*((const uint32_t *) 127 | (ar->mmap + ar->size - sizeof(uint32_t)))); 128 | 129 | if (idx_offset >= ar->size) 130 | goto err; 131 | 132 | ar->index = (lmo_entry_t *)(ar->mmap + idx_offset); 133 | ar->length = (ar->size - idx_offset - sizeof(uint32_t)) / sizeof(lmo_entry_t); 134 | ar->end = ar->mmap + ar->size; 135 | 136 | return ar; 137 | } 138 | 139 | err: 140 | if (in > -1) 141 | close(in); 142 | 143 | if (ar != NULL) 144 | { 145 | if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED)) 146 | munmap(ar->mmap, ar->size); 147 | 148 | free(ar); 149 | } 150 | 151 | return NULL; 152 | } 153 | 154 | void lmo_close(lmo_archive_t *ar) 155 | { 156 | if (ar != NULL) 157 | { 158 | if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED)) 159 | munmap(ar->mmap, ar->size); 160 | 161 | close(ar->fd); 162 | free(ar); 163 | 164 | ar = NULL; 165 | } 166 | } 167 | 168 | 169 | lmo_catalog_t *_lmo_catalogs = NULL; 170 | lmo_catalog_t *_lmo_active_catalog = NULL; 171 | 172 | int lmo_load_catalog(const char *lang, const char *dir) 173 | { 174 | DIR *dh = NULL; 175 | char pattern[16]; 176 | char path[PATH_MAX]; 177 | struct dirent *de = NULL; 178 | 179 | lmo_archive_t *ar = NULL; 180 | lmo_catalog_t *cat = NULL; 181 | 182 | if (!lmo_change_catalog(lang)) 183 | return 0; 184 | 185 | if (!dir || !(dh = opendir(dir))) 186 | goto err; 187 | 188 | if (!(cat = malloc(sizeof(*cat)))) 189 | goto err; 190 | 191 | memset(cat, 0, sizeof(*cat)); 192 | 193 | snprintf(cat->lang, sizeof(cat->lang), "%s", lang); 194 | snprintf(pattern, sizeof(pattern), "*.%s.lmo", lang); 195 | 196 | while ((de = readdir(dh)) != NULL) 197 | { 198 | if (!fnmatch(pattern, de->d_name, 0)) 199 | { 200 | snprintf(path, sizeof(path), "%s/%s", dir, de->d_name); 201 | ar = lmo_open(path); 202 | 203 | if (ar) 204 | { 205 | ar->next = cat->archives; 206 | cat->archives = ar; 207 | } 208 | } 209 | } 210 | 211 | closedir(dh); 212 | 213 | cat->next = _lmo_catalogs; 214 | _lmo_catalogs = cat; 215 | 216 | if (!_lmo_active_catalog) 217 | _lmo_active_catalog = cat; 218 | 219 | return 0; 220 | 221 | err: 222 | if (dh) closedir(dh); 223 | if (cat) free(cat); 224 | 225 | return -1; 226 | } 227 | 228 | int lmo_change_catalog(const char *lang) 229 | { 230 | lmo_catalog_t *cat; 231 | 232 | for (cat = _lmo_catalogs; cat; cat = cat->next) 233 | { 234 | if (!strncmp(cat->lang, lang, sizeof(cat->lang))) 235 | { 236 | _lmo_active_catalog = cat; 237 | return 0; 238 | } 239 | } 240 | 241 | return -1; 242 | } 243 | 244 | static lmo_entry_t * lmo_find_entry(lmo_archive_t *ar, uint32_t hash) 245 | { 246 | unsigned int m, l, r; 247 | uint32_t k; 248 | 249 | l = 0; 250 | r = ar->length - 1; 251 | 252 | while (1) 253 | { 254 | m = l + ((r - l) / 2); 255 | 256 | if (r < l) 257 | break; 258 | 259 | k = ntohl(ar->index[m].key_id); 260 | 261 | if (k == hash) 262 | return &ar->index[m]; 263 | 264 | if (k > hash) 265 | { 266 | if (!m) 267 | break; 268 | 269 | r = m - 1; 270 | } 271 | else 272 | { 273 | l = m + 1; 274 | } 275 | } 276 | 277 | return NULL; 278 | } 279 | 280 | int lmo_translate(const char *key, int keylen, char **out, int *outlen) 281 | { 282 | uint32_t hash; 283 | lmo_entry_t *e; 284 | lmo_archive_t *ar; 285 | 286 | if (!key || !_lmo_active_catalog) 287 | return -2; 288 | 289 | hash = lmo_canon_hash(key, keylen); 290 | 291 | for (ar = _lmo_active_catalog->archives; ar; ar = ar->next) 292 | { 293 | if ((e = lmo_find_entry(ar, hash)) != NULL) 294 | { 295 | *out = ar->mmap + ntohl(e->offset); 296 | *outlen = ntohl(e->length); 297 | return 0; 298 | } 299 | } 300 | 301 | return -1; 302 | } 303 | 304 | void lmo_close_catalog(const char *lang) 305 | { 306 | lmo_archive_t *ar, *next; 307 | lmo_catalog_t *cat, *prev; 308 | 309 | for (prev = NULL, cat = _lmo_catalogs; cat; prev = cat, cat = cat->next) 310 | { 311 | if (!strncmp(cat->lang, lang, sizeof(cat->lang))) 312 | { 313 | if (prev) 314 | prev->next = cat->next; 315 | else 316 | _lmo_catalogs = cat->next; 317 | 318 | for (ar = cat->archives; ar; ar = next) 319 | { 320 | next = ar->next; 321 | lmo_close(ar); 322 | } 323 | 324 | free(cat); 325 | break; 326 | } 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /tools/po2lmo/src/template_lmo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * lmo - Lua Machine Objects - General header 3 | * 4 | * Copyright (C) 2009-2012 Jo-Philipp Wich 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef _TEMPLATE_LMO_H_ 20 | #define _TEMPLATE_LMO_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #if (defined(__GNUC__) && defined(__i386__)) 38 | #define sfh_get16(d) (*((const uint16_t *) (d))) 39 | #else 40 | #define sfh_get16(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ 41 | +(uint32_t)(((const uint8_t *)(d))[0]) ) 42 | #endif 43 | 44 | 45 | struct lmo_entry { 46 | uint32_t key_id; 47 | uint32_t val_id; 48 | uint32_t offset; 49 | uint32_t length; 50 | } __attribute__((packed)); 51 | 52 | typedef struct lmo_entry lmo_entry_t; 53 | 54 | 55 | struct lmo_archive { 56 | int fd; 57 | int length; 58 | uint32_t size; 59 | lmo_entry_t *index; 60 | char *mmap; 61 | char *end; 62 | struct lmo_archive *next; 63 | }; 64 | 65 | typedef struct lmo_archive lmo_archive_t; 66 | 67 | 68 | struct lmo_catalog { 69 | char lang[6]; 70 | struct lmo_archive *archives; 71 | struct lmo_catalog *next; 72 | }; 73 | 74 | typedef struct lmo_catalog lmo_catalog_t; 75 | 76 | 77 | uint32_t sfh_hash(const char *data, int len); 78 | uint32_t lmo_canon_hash(const char *data, int len); 79 | 80 | lmo_archive_t * lmo_open(const char *file); 81 | void lmo_close(lmo_archive_t *ar); 82 | 83 | 84 | extern lmo_catalog_t *_lmo_catalogs; 85 | extern lmo_catalog_t *_lmo_active_catalog; 86 | 87 | int lmo_load_catalog(const char *lang, const char *dir); 88 | int lmo_change_catalog(const char *lang); 89 | int lmo_translate(const char *key, int keylen, char **out, int *outlen); 90 | void lmo_close_catalog(const char *lang); 91 | 92 | #endif 93 | --------------------------------------------------------------------------------