This commit is contained in:
ling 2023-04-01 10:00:13 +08:00
parent e65679b443
commit 5500a26278
793 changed files with 76153 additions and 0 deletions

View File

@ -0,0 +1,33 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=ext-command
PKG_VERSION:=4.500
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/ext-command
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Basic Applications
TITLE:=support for Command
PKGARCH:=all
endef
define Package/ext-command/description
Helper scripts to enable command
endef
define Build/Compile
endef
define Package/ext-command/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,ext-command))

View File

@ -0,0 +1,296 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2012 Jo-Philipp Wich <jow@openwrt.org>
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
]]--
module("luci.controller.commands", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0"
local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0"
if (multilock == "0") or (multilock == "1" and rootlock == "1") then
entry({"admin", "system", "commands"}, firstchild(), _(translate("Custom Commands")), 80)
entry({"admin", "system", "commands", "dashboard"}, template("commands"), _(translate("Dashboard")), 1)
entry({"admin", "system", "commands", "config"}, cbi("commands"), _(translate("Configure")), 2)
entry({"admin", "system", "commands", "script"}, template("cmdedit"), _(translate("Scripts")), 3)
entry({"admin", "system", "commands", "run"}, call("action_run"), nil, 3).leaf = true
entry({"admin", "system", "commands", "download"}, call("action_download"), nil, 3).leaf = true
end
entry({"admin", "system", "load_script"}, call("action_load_script"))
entry({"admin", "system", "save_script"}, call("action_save_script"))
entry({"admin", "system", "del_script"}, call("action_del_script"))
entry({"command"}, call("action_public"), nil, 1).leaf = true
end
--- Decode a given string into arguments following shell quoting rules
--- [[abc \def "foo\"bar" abc'def']] -> [[abc def]] [[foo"bar]] [[abcdef]]
local function parse_args(str)
local args = { }
local function isspace(c)
if c == 9 or c == 10 or c == 11 or c == 12 or c == 13 or c == 32 then
return c
end
end
local function isquote(c)
if c == 34 or c == 39 or c == 96 then
return c
end
end
local function isescape(c)
if c == 92 then
return c
end
end
local function ismeta(c)
if c == 36 or c == 92 or c == 96 then
return c
end
end
--- Convert given table of byte values into a Lua string and append it to
--- the "args" table. Segment byte value sequence into chunks of 256 values
--- to not trip over the parameter limit for string.char()
local function putstr(bytes)
local chunks = { }
local csz = 256
local upk = unpack
local chr = string.char
local min = math.min
local len = #bytes
local off
for off = 1, len, csz do
chunks[#chunks+1] = chr(upk(bytes, off, min(off + csz - 1, len)))
end
args[#args+1] = table.concat(chunks)
end
--- Scan substring defined by the indexes [s, e] of the string "str",
--- perform unquoting and de-escaping on the fly and store the result in
--- a table of byte values which is passed to putstr()
local function unquote(s, e)
local off, esc, quote
local res = { }
for off = s, e do
local byte = str:byte(off)
local q = isquote(byte)
local e = isescape(byte)
local m = ismeta(byte)
if e then
esc = true
elseif esc then
if m then res[#res+1] = 92 end
res[#res+1] = byte
esc = false
elseif q and quote and q == quote then
quote = nil
elseif q and not quote then
quote = q
else
if m then res[#res+1] = 92 end
res[#res+1] = byte
end
end
putstr(res)
end
--- Find substring boundaries in "str". Ignore escaped or quoted
--- whitespace, pass found start- and end-index for each substring
--- to unquote()
local off, esc, start, quote
for off = 1, #str + 1 do
local byte = str:byte(off)
local q = isquote(byte)
local s = isspace(byte) or (off > #str)
local e = isescape(byte)
if esc then
esc = false
elseif e then
esc = true
elseif q and quote and q == quote then
quote = nil
elseif q and not quote then
start = start or off
quote = q
elseif s and not quote then
if start then
unquote(start, off - 1)
start = nil
end
else
start = start or off
end
end
--- If the "quote" is still set we encountered an unfinished string
if quote then
unquote(start, #str)
end
return args
end
local function parse_cmdline(cmdid, args)
local uci = require "luci.model.uci".cursor()
if uci:get("luci", cmdid) == "command" then
local cmd = uci:get_all("luci", cmdid)
local argv = parse_args(cmd.command)
local i, v
if cmd.param == "1" and args then
for i, v in ipairs(parse_args(luci.http.urldecode(args))) do
argv[#argv+1] = v
end
end
for i, v in ipairs(argv) do
if v:match("[^%w%.%-i/]") then
argv[i] = '"%s"' % v:gsub('"', '\\"')
end
end
return argv
end
end
function action_run(...)
local fs = require "nixio.fs"
local argv = parse_cmdline(...)
if argv then
local outfile = os.tmpname()
local errfile = os.tmpname()
local rv = os.execute(table.concat(argv, " ") .. " >%s 2>%s" %{ outfile, errfile })
local stdout = fs.readfile(outfile, 1024 * 512) or ""
local stderr = fs.readfile(errfile, 1024 * 512) or ""
fs.unlink(outfile)
fs.unlink(errfile)
local binary = not not (stdout:match("[%z\1-\8\14-\31]"))
luci.http.prepare_content("application/json")
luci.http.write_json({
command = table.concat(argv, " "),
stdout = not binary and stdout,
stderr = stderr,
exitcode = rv,
binary = binary
})
else
luci.http.status(404, translate("No such command"))
end
end
function action_download(...)
local fs = require "nixio.fs"
local argv = parse_cmdline(...)
if argv then
local fd = io.popen(table.concat(argv, " ") .. " 2>/dev/null")
if fd then
local chunk = fd:read(4096) or ""
local name
if chunk:match("[%z\1-\8\14-\31]") then
luci.http.header("Content-Disposition", "attachment; filename=%s"
% fs.basename(argv[1]):gsub("%W+", ".") .. ".bin")
luci.http.prepare_content("application/octet-stream")
else
luci.http.header("Content-Disposition", "attachment; filename=%s"
% fs.basename(argv[1]):gsub("%W+", ".") .. ".txt")
luci.http.prepare_content("text/plain")
end
while chunk do
luci.http.write(chunk)
chunk = fd:read(4096)
end
fd:close()
else
luci.http.status(500, translate("Failed to execute command"))
end
else
luci.http.status(404, "No such command")
end
end
function action_public(cmdid, args)
local uci = require "luci.model.uci".cursor()
if cmdid and
uci:get("luci", cmdid) == "command" and
uci:get("luci", cmdid, "public") == "1"
then
action_download(cmdid, args)
else
luci.http.status(403, translate("Access to command denied"))
end
end
function action_load_script()
local set = luci.http.formvalue("set")
local rv ={}
local file
file = io.open(set, "r")
if file ~= nil then
local tmp = file:read("*all")
rv["text"] = tmp
file:close()
else
rv["text"] = translate("No file found")
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end
function action_save_script()
local line = luci.http.formvalue("set")
local rv ={}
local file
s, e = line:find("|")
name = line:sub(1,s-1)
text = line:sub(e+1)
file = io.open(name, "w")
file:write(text)
file:close()
os.execute("chmod 777 " .. name)
rv["name"] = name
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end
function action_del_script()
local name = luci.http.formvalue("set")
local rv ={}
os.remove(name)
rv["name"] = name
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end

View File

@ -0,0 +1,37 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2012 Jo-Philipp Wich <jow@openwrt.org>
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
]]--
local m, s
m = Map("luci", translate("Custom Commands"),
translate("This page allows you to configure custom shell commands which can be easily invoked from the web interface."))
s = m:section(TypedSection, "command", "")
s.template = "cbi/tblsection"
s.anonymous = true
s.addremove = true
s:option(Value, "name", translate("Description"),
translate("A short textual description of the configured command"))
s:option(Value, "command", translate("Command"),
translate("Command line to execute"))
s:option(Flag, "param", translate("Custom arguments"),
translate("Allow the user to provide additional command line arguments"))
s:option(Flag, "public", translate("Public access"),
translate("Allow executing the command and downloading its output without prior authentication"))
return m

View File

@ -0,0 +1,186 @@
<%+header%>
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>
<script type="text/javascript">//<![CDATA[
function savescript(btn)
{
var t = document.getElementById("script").value;
if ( t.length == 0 )
{
alert("No script name!!");
return false;
}
var tp = document.getElementById("path").value;
if ( t.length == 0 )
{
alert("No script path!!");
return false;
}
var txt = document.getElementById("txt").value;
if ( txt.length == 0 )
{
alert("Script is blank!!");
return false;
}
var length = tp.length;
if ( tp.substr(length-1) != "/" )
{
tp = tp.concat("/");
}
var s = tp.concat(t);
s = s.concat("|");
s = s.concat(txt);
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "save_script")%>',
{ set: s },
function(x, rv)
{
name = rv.name;
text = name.concat(" has been saved.")
alert(text);
}
);
return false;
}
function delscript(btn)
{
var t = document.getElementById("script").value;
if ( t.length == 0 )
{
alert("No script name!!");
return false;
}
var tp = document.getElementById("path").value;
if ( t.length == 0 )
{
alert("No script path!!");
return false;
}
var length = tp.length;
if ( tp.substr(length-1) != "/" )
{
tp = tp.concat("/");
}
var s = tp.concat(t);
var del = "Delete ";
del = del.concat(s);
del = del.concat(" ?");
var r=confirm(del);
if (r==false)
{
return false;
}
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "del_script")%>',
{ set: s },
function(x, rv)
{
name = rv.name;
text = name.concat(" has been deleted.")
alert(text);
document.getElementById("path").value="/usr/lib/scripts";
document.getElementById("txt").value="";
document.getElementById("script").value="";
}
);
return false;
}
function newscript(btn)
{
document.getElementById("path").value="/usr/lib/scripts";
document.getElementById("txt").value="";
document.getElementById("script").value="";
return false;
}
function loadscript(btn)
{
var t = document.getElementById("script").value;
if ( t.length == 0 )
{
alert("No script name!!");
return false;
}
var tp = document.getElementById("path").value;
if ( t.length == 0 )
{
alert("No script path!!");
return false;
}
document.getElementById("txt").value="";
var length = tp.length;
if ( tp.substr(length-1) != "/" )
{
tp = tp.concat("/");
}
var s = tp.concat(t);
XHR.get('<%=luci.dispatcher.build_url("admin", "system", "load_script")%>',
{ set: s },
function(x, rv)
{
document.getElementById("txt").value=rv.text;
}
);
return false;
}
function initial(btn)
{
document.getElementById("path").value="/usr/lib/scripts";
document.getElementById("txt").value="";
document.getElementById("script").value="";
return false;
}
window.onload=initial;
//]]></script>
<form method="post" action="<%=REQUEST_URI%>">
<div class="cbi-map" id="cbi-sms">
<h2><a id="content" name="content"><%:Script Editing%></a></h2>
<div class="cbi-map-descr"><%:Create, Edit and Save Scripts%></div>
<fieldset class="cbi-section" id="cbi-read">
<table id="sendmsg" width="600" border="0" style="display:table;">
<tr>
<td width="15%"><div align="left"><strong><%:Script Name :%></strong></div></td>
<td width="70%"><input type="text" name="script" id="script" maxlength="50"></input></td>
<td width="15%">&nbsp;</td>
</tr>
</table>
<table id="sendmsg" width="600" border="0" style="display:table;">
<tr>
<td width="15%"><div align="left"><strong><%:Path to Script :%></strong></div></td>
<td width="70%"><input type="text" name="path" id="path" maxlength="100"></input></td>
<td width="15%">&nbsp;</td>
</tr>
</table>
<table id="sendtxt" width="700" border="0" style="display:table;">
<tr>
<td width="100%">
<textarea name="txt" id="txt" rows="6" style="width: 600px;" maxlength="10000"></textarea>
</td>
</tr>
</table>
<table id="sendbtn" width="550" border="0" style="display:table;">
<tr>
<td width="5%"><input type="button" id="newbtn" class="cbi-button cbi-button-apply" value="<%:New%>" onclick="return newscript()" /></td>
<td width="5%"><input type="button" id="loadbtn" class="cbi-button cbi-button-apply" value="<%:Load%>" onclick="return loadscript()" /></td>
<td width="5%"><input type="button" id="savebtn" class="cbi-button cbi-button-apply" value="<%:Save%>" onclick="return savescript()" /></td>
<td width="5%"><input type="button" id="delbtn" class="cbi-button cbi-button-apply" value="<%:Delete%>" onclick="return delscript()" /></td>
<td width="80%">&nbsp;</td>
</tr>
</table>
</fieldset>
</div>
</form>
<%+footer%>

View File

@ -0,0 +1,176 @@
<%#
LuCI - Lua Configuration Interface
Copyright 2012 Jo-Philipp Wich <jow@openwrt.org>
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
-%>
<% css = [[
.commandbox {
height: 12em;
width: 30%;
float: left;
height: 12em;
margin: 5px;
position: relative;
}
.commandbox h3 {
font-size: 1.5em !important;
line-height: 2em !important;
margin: 0 !important;
}
.commandbox input[type="text"] {
width: 50% !important;
}
.commandbox div {
position: absolute;
left: 0;
bottom: 1.5em;
}
]] -%>
<%+header%>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript">//<![CDATA[
var stxhr = new XHR();
function command_run(id)
{
var args;
var field = document.getElementById(id);
if (field)
args = encodeURIComponent(field.value);
var legend = document.getElementById('command-rc-legend');
var output = document.getElementById('command-rc-output');
if (legend && output)
{
output.innerHTML =
'<img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /> ' +
'<%:Waiting for command to complete...%>'
;
legend.parentNode.style.display = 'block';
legend.style.display = 'inline';
stxhr.get('<%=luci.dispatcher.build_url("admin", "system", "commands", "run")%>/' + id + (args ? '/' + args : ''), null,
function(x, st)
{
if (st)
{
if (st.binary)
st.stdout = '[<%:Binary data not displayed, download instead.%>]';
legend.style.display = 'none';
output.innerHTML = String.format(
'<pre><strong># %h\n</strong>%h<span style="color:red">%h</span></pre>' +
'<div class="alert-message warning">%s (<%:Code:%> %d)</div>',
st.command, st.stdout, st.stderr,
(st.exitcode == 0) ? '<%:Command successful%>' : '<%:Command failed%>',
st.exitcode);
}
else
{
legend.style.display = 'none';
output.innerHTML = '<span class="error"><%:Failed to execute command!%></span>';
}
location.hash = '#output';
}
);
}
}
function command_download(id)
{
var args;
var field = document.getElementById(id);
if (field)
args = encodeURIComponent(field.value);
location.href = '<%=luci.dispatcher.build_url("admin", "system", "commands", "download")%>/' + id + (args ? '/' + args : '');
}
function command_link(id)
{
var legend = document.getElementById('command-rc-legend');
var output = document.getElementById('command-rc-output');
var args;
var field = document.getElementById(id);
if (field)
args = encodeURIComponent(field.value);
if (legend && output)
{
var link = location.protocol + '//' + location.hostname +
(location.port ? ':' + location.port : '') +
location.pathname.split(';')[0] + 'command/' +
id + (args ? '/' + args : '');
legend.style.display = 'none';
output.parentNode.style.display = 'block';
output.innerHTML = String.format(
'<div class="alert-message"><%:Access command with%> <a href="%s">%s</a></div>',
link, link
);
location.hash = '#output';
}
}
//]]></script>
<%
local uci = require "luci.model.uci".cursor()
local commands = { }
uci:foreach("luci", "command", function(s) commands[#commands+1] = s end)
%>
<form method="get" action="<%=pcdata(luci.http.getenv("REQUEST_URI"))%>">
<div class="cbi-map">
<h2><a id="content" name="content"><%:Custom Commands%></a></h2>
<fieldset class="cbi-section">
<% local _, command; for _, command in ipairs(commands) do %>
<div class="commandbox">
<h3><%=pcdata(command.name)%></h3>
<p><%:Command:%> <code><%=pcdata(command.command)%></code></p>
<% if command.param == "1" then %>
<p><%:Arguments:%> <input type="text" id="<%=command['.name']%>" /></p>
<% end %>
<div>
<input type="button" value="<%:Run%>" class="cbi-button cbi-button-apply" onclick="command_run('<%=command['.name']%>')" />
<input type="button" value="<%:Download%>" class="cbi-button cbi-button-download" onclick="command_download('<%=command['.name']%>')" />
<% if command.public == "1" then %>
<input type="button" value="<%:Link%>" class="cbi-button cbi-button-link" onclick="command_link('<%=command['.name']%>')" />
<% end %>
</div>
</div>
<% end %>
<br style="clear:both" /><br />
<a name="output"></a>
</fieldset>
</div>
<fieldset class="cbi-section" style="display:none">
<legend id="command-rc-legend"><%:Collecting data...%></legend>
<span id="command-rc-output"></span>
</fieldset>
</form>
<%+footer%>

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,35 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=ext-extra
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/ext-extra
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Basic Applications
TITLE:=Add Scheduled Reboot
PKGARCH:=all
endef
define Package/ext-extra/description
Helper scripts to install Scheduled Reboot
endef
define Build/Compile
endef
define Package/ext-extra/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,ext-extra))

View File

@ -0,0 +1,7 @@
config reboot 'reboot'
option enable '0'
config timezone 'timezone'
option zonename 'UTC'

View File

@ -0,0 +1,13 @@
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.schedule", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local page
page = entry({"admin", "services", "schedule"}, cbi("schedule"), _(translate("Scheduled Reboot")), 61)
page.dependent = true
end

View File

@ -0,0 +1,29 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Copyright 2008-2013 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local cronfile = "/etc/cronuser"
f = SimpleForm("crontab", translate("Scheduled Tasks"), translate("This is the system crontab in which scheduled tasks can be defined."))
t = f:field(TextValue, "crons")
t.rmempty = true
t.rows = 10
function t.cfgvalue()
return fs.readfile(cronfile) or ""
end
function f.handle(self, state, data)
if state == FORM_VALID then
if data.crons then
fs.writefile(cronfile, data.crons:gsub("\r\n", "\n"))
else
fs.writefile(cronfile, "")
end
luci.sys.call("/usr/lib/rooter/luci/croncat.sh")
end
return true
end
return f

View File

@ -0,0 +1,133 @@
local utl = require "luci.util"
local sys = require "luci.sys"
local zones = require "luci.sys.zoneinfo"
local fs = require "nixio.fs"
local conf = require "luci.config"
os.execute("/usr/lib/rooter/luci/reboot.sh 0")
m = Map("schedule", translate("Scheduled Reboot"), translate("Schedule a Router Reboot at a Specified Time"))
m.on_after_save = function(self)
luci.sys.call("/usr/lib/rooter/luci/reboot.sh 1 &")
end
d1 = m:section(TypedSection, "timezone", " ")
--o1 = d1:option(DummyValue, "_systime", translate("Local Time : "))
--o1.template = "admin_system/clock_status"
o = d1:option(DummyValue, "zonename", translate("Timezone : "), translate("Be sure to set your Timezone correctly in System->System"))
d = m:section(TypedSection, "reboot", " ")
c1 = d:option(ListValue, "enable", " ");
c1:value("0", translate("Disabled"))
c1:value("1", translate("Enabled"))
c1.default=0
sdhour = d:option(ListValue, "sdhour", translate("Reboot Time :"))
sdhour.rmempty = true
sdhour:value("0", "12:00 AM")
sdhour:value("1", "12:15 AM")
sdhour:value("2", "12:30 AM")
sdhour:value("3", "12:45 AM")
sdhour:value("4", "01:00 AM")
sdhour:value("5", "01:15 AM")
sdhour:value("6", "01:30 AM")
sdhour:value("7", "01:45 AM")
sdhour:value("8", "02:00 AM")
sdhour:value("9", "02:15 AM")
sdhour:value("10", "02:30 AM")
sdhour:value("11", "02:45 AM")
sdhour:value("12", "03:00 AM")
sdhour:value("13", "03:15 AM")
sdhour:value("14", "03:30 AM")
sdhour:value("15", "03:45 AM")
sdhour:value("16", "04:00 AM")
sdhour:value("17", "04:15 AM")
sdhour:value("18", "04:30 AM")
sdhour:value("19", "04:45 AM")
sdhour:value("20", "05:00 AM")
sdhour:value("21", "05:15 AM")
sdhour:value("22", "05:30 AM")
sdhour:value("23", "05:45 AM")
sdhour:value("24", "06:00 AM")
sdhour:value("25", "06:15 AM")
sdhour:value("26", "06:30 AM")
sdhour:value("27", "06:45 AM")
sdhour:value("28", "07:00 AM")
sdhour:value("29", "07:15 AM")
sdhour:value("30", "07:30 AM")
sdhour:value("31", "07:45 AM")
sdhour:value("32", "08:00 AM")
sdhour:value("33", "08:15 AM")
sdhour:value("34", "08:30 AM")
sdhour:value("35", "08:45 AM")
sdhour:value("36", "09:00 AM")
sdhour:value("37", "09:15 AM")
sdhour:value("38", "09:30 AM")
sdhour:value("39", "09:45 AM")
sdhour:value("40", "10:00 AM")
sdhour:value("41", "10:15 AM")
sdhour:value("42", "10:30 AM")
sdhour:value("43", "10:45 AM")
sdhour:value("44", "11:00 AM")
sdhour:value("45", "11:15 AM")
sdhour:value("46", "11:30 AM")
sdhour:value("47", "11:45 AM")
sdhour:value("48", "12:00 PM")
sdhour:value("49", "12:15 PM")
sdhour:value("50", "12:30 PM")
sdhour:value("51", "12:45 PM")
sdhour:value("52", "01:00 PM")
sdhour:value("53", "01:15 PM")
sdhour:value("54", "01:30 PM")
sdhour:value("55", "01:45 PM")
sdhour:value("56", "02:00 PM")
sdhour:value("57", "02:15 PM")
sdhour:value("58", "02:30 PM")
sdhour:value("59", "02:45 PM")
sdhour:value("60", "03:00 PM")
sdhour:value("61", "03:15 PM")
sdhour:value("62", "03:30 PM")
sdhour:value("63", "03:45 PM")
sdhour:value("64", "04:00 PM")
sdhour:value("65", "04:15 PM")
sdhour:value("66", "04:30 PM")
sdhour:value("67", "04:45 PM")
sdhour:value("68", "05:00 PM")
sdhour:value("69", "05:15 PM")
sdhour:value("70", "05:30 PM")
sdhour:value("71", "05:45 PM")
sdhour:value("72", "06:00 PM")
sdhour:value("73", "06:15 PM")
sdhour:value("74", "06:30 PM")
sdhour:value("75", "06:45 PM")
sdhour:value("76", "07:00 PM")
sdhour:value("77", "07:15 PM")
sdhour:value("78", "07:30 PM")
sdhour:value("79", "07:45 PM")
sdhour:value("80", "08:00 PM")
sdhour:value("81", "08:15 PM")
sdhour:value("82", "08:30 PM")
sdhour:value("83", "08:45 PM")
sdhour:value("84", "09:00 PM")
sdhour:value("85", "09:15 PM")
sdhour:value("86", "09:30 PM")
sdhour:value("87", "09:45 PM")
sdhour:value("88", "10:00 PM")
sdhour:value("89", "10:15 PM")
sdhour:value("90", "10:30 PM")
sdhour:value("91", "10:45 PM")
sdhour:value("92", "11:00 PM")
sdhour:value("93", "11:15 PM")
sdhour:value("94", "11:30 PM")
sdhour:value("95", "11:45 PM")
sdhour:depends("enable", "1")
sdhour.default = "0"
return m

View File

@ -0,0 +1,36 @@
#!/bin/sh
log() {
logger -t "Croncat" "$@"
}
> /tmp/crontmp
if [ -e /etc/crontabs/root ]; then
while read -r line; do
if [ -n "$line" ]; then
if [ ${line: -1} == ";" ]; then
echo "$line" >> /tmp/crontmp
fi
fi
done < /etc/crontabs/root
fi
if [ -f /etc/cronuser ]; then
if [ -f /etc/cronbase ]; then
cat /etc/cronbase /etc/cronuser > /etc/crontabs/root
else
cp /etc/cronuser /etc/crontabs/root
fi
else
if [ -f /etc/cronbase ]; then
cp /etc/cronbase /etc/crontabs/root
else
> /etc/crontabs/root
fi
fi
cat /tmp/crontmp /etc/crontabs/root > /tmp/cronroot
cp /tmp/cronroot /etc/crontabs/root
rm /tmp/crontmp
rm /tmp/cronroot
/etc/init.d/cron restart

View File

@ -0,0 +1,32 @@
#!/bin/sh
log() {
logger -t "Schedule Reboot" "$@"
}
PARM=$1
if [ $PARM = "0" ]; then
HO=$(uci get system.@system[-1].zonename)
if [ -z $HO ]; then
HO="UTC"
fi
uci set schedule.timezone.zonename="$HO"
uci commit schedule
fi
if [ $PARM = "1" ]; then
sleep 5
EN=$(uci get schedule.reboot.enable)
if [ $EN = "1" ]; then
SDHOUR=$(uci get schedule.reboot.sdhour)
HOUR=`expr $SDHOUR / 4`
let "TH = $HOUR * 4"
let "TMP1 = $SDHOUR - $TH"
let "MIN = $TMP1 * 15"
echo "$MIN $HOUR * * * sleep 70 && touch /etc/banner && reboot -f" > /etc/cronbase
else
rm -f /etc/cronbase
fi
/usr/lib/rooter/luci/croncat.sh
fi

View File

@ -0,0 +1,36 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=ext-p910nd
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/ext-p910nd
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Basic Applications
DEPENDS:=+p910nd +kmod-usb-printer +kmod-usb-ohci
TITLE:=Install Print Server
PKGARCH:=all
endef
define Package/ext-p910nd/description
Helper scripts to install print Server
endef
define Build/Compile
endef
define Package/ext-p910nd/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,ext-p910nd))

View File

@ -0,0 +1,11 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@p910nd[-1]
add ucitrack p910nd
set ucitrack.@p910nd[-1].init=p910nd
commit ucitrack
EOF
rm -f /tmp/luci-indexcache
exit 0

View File

@ -0,0 +1,18 @@
-- Copyright 2008 Yanira <forum-2008@email.de>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.p910ndx", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
if not nixio.fs.access("/etc/config/p910nd") then
return
end
local page
page = entry({"admin", "services", "p910ndx"}, cbi("p910ndx"), _(translate("Print Server")), 60)
page.dependent = true
end

View File

@ -0,0 +1,59 @@
--[[
LuCI p910nd
(c) 2008 Yanira <forum-2008@email.de>
(c) 2012 Jo-Philipp Wich <jow@openwrt.org>
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
]]--
local uci = luci.model.uci.cursor_state()
local net = require "luci.model.network"
local m, s, p, b
m = Map("p910nd", translate("Print Server"),
translatef("Support for USB Printers."))
net = net.init(m.uci)
s = m:section(TypedSection, "p910nd", translate("Settings"))
s.addremove = true
s.anonymous = true
s:option(Flag, "enabled", translate("enable"))
s:option(Value, "device", translate("Device")).rmempty = true
b = s:option(Value, "bind", translate("Interface"), translate("Specifies the interface to listen on."))
b.template = "cbi/network_netlist"
b.nocreate = true
b.unspecified = true
function b.cfgvalue(...)
local v = Value.cfgvalue(...)
if v then
return (net:get_status_by_address(v))
end
end
function b.write(self, section, value)
local n = net:get_network(value)
if n and n:ipaddr() then
Value.write(self, section, n:ipaddr())
end
end
p = s:option(ListValue, "port", translate("Port"), translate("TCP listener port."))
p.rmempty = true
for i=0,9 do
p:value(i, 9100+i)
end
s:option(Flag, "bidirectional", translate("Bidirectional mode"))
return m

View File

@ -0,0 +1,38 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=usb-storage
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/usb-storage
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Basic Applications
DEPENDS:= +ntfs-3g +fdisk +kmod-usb-storage \
+kmod-fs-ext4 +kmod-fs-vfat +kmod-nls-cp437 +kmod-nls-iso8859-1 +kmod-nls-utf8 \
+block-mount +kmod-fs-exfat +kmod-fs-hfs +hd-idle
TITLE:=Install USB Storage
PKGARCH:=all
endef
define Package/usb-storage/description
Helper scripts to install USB Storage
endef
define Build/Compile
endef
define Package/usb-storage/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,usb-storage))

View File

@ -0,0 +1,2 @@
config umount 'umount'
option drive ''

View File

@ -0,0 +1,68 @@
#!/bin/sh /etc/rc.common
. /lib/functions.sh
log() {
logger -t "20-mount" "$@"
}
blkdev=`dirname $DEVPATH`
if [ `basename $blkdev` != "block" ]; then
device=`basename $DEVPATH`
if echo $device | grep -q "mtdblock"; then
exit 0
fi
if [ -e /etc/sda_drop ]; then
source /etc/sda_drop
if echo $device | grep -q "$SDA"; then
exit 0
fi
fi
if [ ! -e /usr/lib/sdcard/sdcard.sh ]; then
/usr/lib/sdcard/sdcard.sh detect
source /tmp/detect.file
if [ $detect = "1" ]; then
if echo $device | grep -q "mmcblk"; then
exit 0
fi
fi
fi
if echo $device | grep -q "mmcblk"; then
device1="SDCard"${device:8:2}
else
device1=$device
fi
case "$ACTION" in
add)
mkdir -p /mnt/$device1
# vfat & ntfs-3g check
if [ `which fdisk` ]; then
isntfs=`fdisk -l | grep $device | grep NTFS`
isvfat=`fdisk -l | grep $device | grep FAT`
isfuse=`lsmod | grep fuse`
isntfs3g=`which ntfs-3g`
else
isntfs=""
isvfat=""
fi
# mount with ntfs-3g if possible, else with default mount
if [ "$isntfs" -a "$isfuse" -a "$isntfs3g" ]; then
ntfs-3g -o nls=utf8 /dev/$device /mnt/$device1
log "Mount /mnt/$device as NTFS"
elif [ "$isvfat" ]; then
mount -o rw,sync,umask=002,codepage=437,iocharset=iso8859-1 /dev/$device /mnt/$device1
log "Mount /mnt/$device as FAT"
else
mount -o rw,sync /dev/$device /mnt/$device1
log "Mount /mnt/$device as other"
fi
chmod 777 /mnt/$device1
chown nobody /mnt/$device1
if [ -e /usr/lib/sdcard/sdcard.sh ]; then
/usr/lib/sdcard/sdcard.sh add
fi
;;
esac
fi

View File

@ -0,0 +1,88 @@
#!/bin/sh /etc/rc.common
. /lib/functions.sh
# Copyright (C) 2011 OpenWrt.org
log() {
logger -t "30-mount" "$@"
}
sanitize() {
sed -e 's/[[:space:]]\+$//; s/[[:space:]]\+/_/g' "$@"
}
blkdev=`dirname $DEVPATH`
if [ `basename $blkdev` != "block" ]; then
device=`basename $DEVPATH`
if echo $device | grep -q "mtdblock"; then
exit 0
fi
if [ ! -e /usr/lib/sdcard/sdcard.sh ]; then
/usr/lib/sdcard/sdcard.sh detect
source /tmp/detect.file
if [ $detect = "1" ]; then
if echo $device | grep -q "mmcblk"; then
exit 0
fi
fi
fi
if echo $device | grep -q "mmcblk"; then
device1="SDCard"${device:8:2}
else
device1=$device
fi
if [ -e /etc/sda_drop ]; then
source /etc/sda_drop
if echo $device | grep -q "$SDA"; then
exit 0
fi
fi
case "$ACTION" in
add)
MT=$(cat /proc/mounts | grep "$device")
if [ -z $MT ]; then
exit 0
fi
DEVN=${DEVNAME:0:3}
MODEL=$(sanitize "/sys/block/$DEVN/device/model")
if [ -d /etc/ksmbd ]; then
uci delete ksmbd.$device1
uci set ksmbd.$device1=share
uci set ksmbd.$device1.name=$device1
uci set ksmbd.$device1.path=/mnt/$device1
uci set ksmbd.$device1.read_only=no
uci set ksmbd.$device1.guest_ok=yes
uci set ksmbd.$device1.create_mask='0666'
uci set ksmbd.$device1.dir_mask='0777'
uci commit ksmbd
/etc/init.d/ksmbd restart
log "/mnt/$device1 shared as $device1"
else
if [ -d /etc/samba ]; then
uci delete samba.$device1
uci set samba.$device1=sambashare
uci set samba.$device1.name=$device1
uci set samba.$device1.path=/mnt/$device1
uci set samba.$device1.read_only=no
uci set samba.$device1.guest_ok=yes
uci commit samba
/etc/init.d/samba restart
log "/mnt/$device1 shared as $device1"
fi
fi
;;
remove)
log "remove /mnt/$device1"
if [ -d /etc/ksmbd ]; then
uci delete ksmbd.$device1
uci commit ksmbd
else
if [ -d /etc/samba ]; then
uci delete samba.$device1
uci commit samba
fi
fi
;;
esac
fi

View File

@ -0,0 +1,41 @@
#!/bin/sh /etc/rc.common
. /lib/functions.sh
log() {
logger -t "99-mount" "$@"
}
blkdev=`dirname $DEVPATH`
if [ `basename $blkdev` != "block" ]; then
device=`basename $DEVPATH`
if echo $device | grep -q "mtdblock"; then
exit 0
fi
if [ ! -e /usr/lib/sdcard/sdcard.sh ]; then
/usr/lib/sdcard/sdcard.sh detect
source /tmp/detect.file
if [ $detect = "1" ]; then
if echo $device | grep -q "mmcblk"; then
exit 0
fi
fi
fi
if echo $device | grep -q "mmcblk"; then
device1="SDCard"${device:8:2}
else
device1=$device
fi
case "$ACTION" in
remove)
log "remove /mnt/$device1"
umount -l /mnt/$device1
rm -rf /mnt/$device1
if [ -e /usr/lib/sdcard/sdcard.sh ]; then
/usr/lib/sdcard/sdcard.sh remove
fi
;;
esac
fi

View File

@ -0,0 +1,11 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@hd-idle[-1]
add ucitrack hd-idle
set ucitrack.@hd-idle[-1].init=hd-idle
commit ucitrack
EOF
rm -f /tmp/luci-indexcache
exit 0

View File

@ -0,0 +1,18 @@
#!/bin/sh
log() {
logger -t "Umount" "$@"
}
sleep 5
DRV=$(uci get umount.umount.drive)
if [ -z $DRV ]; then
exit 0
fi
umount -l /mnt/$DRV
rm -rf /mnt/$DRV
uci set umount.umount.drive=''
uci commit umount

View File

@ -0,0 +1,17 @@
-- Copyright 2008 Yanira <forum-2008@email.de>
-- Licensed to the public under the Apache License 2.0.
module("luci.controller.hd_idle", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
if not nixio.fs.access("/etc/config/hd-idle") then
return
end
local page
page = entry({"admin", "services", "hd_idle"}, cbi("hd_idle"), _(translate("Hard Drive Idle")), 60)
page.dependent = true
end

View File

@ -0,0 +1,11 @@
module("luci.controller.umount", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local page
page = entry({"admin", "services", "umount"}, cbi("umount", {hidesavebtn=true, hideresetbtn=true}), translate("Safely Eject Drive"), 25)
page.dependent = true
end

View File

@ -0,0 +1,28 @@
-- Copyright 2008 Yanira <forum-2008@email.de>
-- Licensed to the public under the Apache License 2.0.
require("nixio.fs")
m = Map("hd-idle", "Hard Drive Idle",
translate("This is a utility program for spinning-down external disks after a period of idle time."))
s = m:section(TypedSection, "hd-idle", translate("Settings"))
s.anonymous = true
s:option(Flag, "enabled", translate("Enable"))
disk = s:option(Value, "disk", translate("Disk"))
disk.rmempty = true
for dev in nixio.fs.glob("/dev/[sh]d[a-z]") do
disk:value(nixio.fs.basename(dev))
end
s:option(Value, "idle_time_interval", translate("Idle-time")).default = 10
s.rmempty = true
unit = s:option(ListValue, "idle_time_unit", translate("Idle-time unit"))
unit.default = "minutes"
unit:value("minutes", translate("min"))
unit:value("hours", translate("h"))
unit.rmempty = true
return m

View File

@ -0,0 +1,20 @@
require("nixio.fs")
m = Map("umount", "Safely Eject a Drive",
translate("Safely eject a drive from the router"))
m.on_after_save = function(self)
luci.sys.call("/etc/umount &")
end
drv = m:section(TypedSection, "umount", translate("Currently Mounted Drives"))
drv.anonymous = true
disk = drv:option(Value, "drive", translate(" "), translate("Click Save and Apply to eject drive"))
disk.rmempty = true
for dev in nixio.fs.glob("/mnt/[sh]d[a-z][1-9]") do
dv = nixio.fs.basename(dev)
disk:value(nixio.fs.basename(dev))
end
return m

View File

@ -0,0 +1,88 @@
#!/bin/sh
log() {
logger -t "sdcard" "$@"
}
h721() {
if [ $1 = "add" ]; then
echo "17" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio17/direction
echo 0 > /sys/class/gpio/gpio17/value
else
echo "17" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio17/direction
echo 1 > /sys/class/gpio/gpio17/value
fi
}
wg1608() {
if [ $1 = "add" ]; then
echo timer > /sys/class/leds/zbt-wg3526:green:signal/trigger
echo 1000 > /sys/class/leds/zbt-wg3526:green:signal/delay_on
echo 0 > /sys/class/leds/zbt-wg3526:green:signal/delay_off
else
echo timer > /sys/class/leds/zbt-wg3526:green:signal/trigger
echo 0 > /sys/class/leds/zbt-wg3526:green:signal/delay_on
echo 1000 > /sys/class/leds/zbt-wg3526:green:signal/delay_off
fi
}
ws7915() {
if [ $1 = "add" ]; then
echo timer > /sys/class/leds/sys/trigger
echo 1000 > /sys/class/leds/sys/delay_on
echo 0 > /sys/class/leds/sys/delay_off
else
echo timer > /sys/class/leds/sys/trigger
echo 0 > /sys/class/leds/sys/delay_on
echo 1000 > /sys/class/leds/sys/delay_off
fi
}
ws1688() {
if [ $1 = "add" ]; then
echo timer > /sys/class/leds/usb/trigger
echo 1000 > /sys/class/leds/usb/delay_on
echo 0 > /sys/class/leds/usb/delay_off
else
echo timer > /sys/class/leds/usb/trigger
echo 0 > /sys/class/leds/usb/delay_on
echo 1000 > /sys/class/leds/usb/delay_off
fi
}
ACTION=$1
model=$(cat /tmp/sysinfo/model)
case $ACTION in
"add"|"remove" )
mod=$(echo $model | grep "H721")
if [ $mod ]; then
h721 $ACTION
fi
mod=$(echo $model | grep "WG1608")
if [ $mod ]; then
wg1608 $ACTION
fi
mod=$(echo $model | grep "WS7915")
if [ $mod ]; then
ws7915 $ACTION
fi
mod=$(echo $model | grep "WS1688")
if [ $mod ]; then
ws1688 $ACTION
fi
;;
"detect" )
mod=$(echo $model | grep "Raspberry")
if [ $mod ]; then
echo 'detect="'"1"'"' > /tmp/detect.file
else
echo 'detect="'"0"'"' > /tmp/detect.file
fi
;;
esac

View File

@ -0,0 +1,35 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=ext-buttons
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/ext-buttons
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Basic Support
TITLE:=Install button support
PKGARCH:=all
endef
define Package/ext-buttons/description
Helper scripts to install button support
endef
define Build/Compile
endef
define Package/ext-buttons/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,ext-buttons))

View File

@ -0,0 +1,56 @@
#!/bin/sh
FUNC=$1
reset_short() {
passwd -d root
reboot -f
}
reset_long() {
mtd -r erase rootfs_data
}
wifi() {
STATEFILE="/tmp/wifionoff.state"
if [ $# -eq 1 ]; then
case $1 in
"up"|"on")
STATE=off
;;
"down"|"off")
STATE=on
;;
esac
else
if [ ! -e ${STATEFILE} ]; then
STATE=on
else
. ${STATEFILE}
fi
fi
if [ -z ${STATE} ]; then
STATE=on
fi
if [ ${STATE} == "on" ]; then
/sbin/wifi down
STATE=off
else
/sbin/wifi up
STATE=on
fi
echo "STATE=${STATE}" > ${STATEFILE}
}
if [ $FUNC = "reset_short" ]; then
reset_short
fi
if [ $FUNC = "reset_long" ]; then
reset_long
fi
if [ $FUNC = "wifi" ]; then
wifi $2
fi

View File

@ -0,0 +1,26 @@
#!/bin/sh
. /lib/functions.sh
do_button () {
local button
local action
local handler
local min
local max
config_get button $1 button
config_get action $1 action
config_get handler $1 handler
config_get min $1 min
config_get max $1 max
[ "$ACTION" = "$action" -a "$BUTTON" = "$button" -a -n "$handler" ] && {
[ -z "$min" -o -z "$max" ] && eval $handler
[ -n "$min" -a -n "$max" ] && {
[ $min -le $SEEN -a $max -ge $SEEN ] && eval $handler
}
}
}
config_load system
config_foreach do_button button

View File

@ -0,0 +1,10 @@
#!/bin/sh
log() {
logger -t "Button Checker " "$@"
}
log "Button Name : $BUTTON Action : $ACTION"
log "$ACTION $SEEN"

View File

@ -0,0 +1,16 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2006 OpenWrt.org
log() {
logger -t "Buttons" "$@"
}
START=98
start() {
local BTN=$(uci -q get system.@button[-1].button)
}
stop() {
log "Stopping Buttons"
}

View File

@ -0,0 +1,14 @@
module("luci.controller.buttons", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local page
local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0"
local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0"
if (multilock == "0") or (multilock == "1" and rootlock == "1") then
page = entry({"admin", "system", "buttons"}, cbi("buttons/buttons"), _(translate("Buttons")), 65)
page.dependent = true
end
end

View File

@ -0,0 +1,44 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2008 Steven Barth <steven@midlink.org>
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
$Id$
]]--
m = Map("system", translate("Buttons"),
translate("This page allows the configuration of custom button actions"))
s = m:section(TypedSection, "button", "")
s.anonymous = true
s.addremove = true
s:option(Value, "button", translate("Name"))
act = s:option(ListValue, "action",
translate("Action"),
translate("Specifies the button state to handle"))
act:value("released")
act:value("pressed")
act.default = "released"
s:option(Value, "handler",
translate("Handler"),
translate("Path to executable which handles the button event"))
min = s:option(Value, "min", translate("Minimum hold time"))
min.rmempty = true
min:depends("action", "released")
max = s:option(Value, "max", translate("Maximum hold time"))
max.rmempty = true
max:depends("action", "released")
return m

View File

@ -0,0 +1,35 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=ext-sms
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/ext-sms
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Basic Support
TITLE:=Install SMS support
PKGARCH:=all
endef
define Package/ext-sms/description
Helper scripts to install SMS on ROOter
endef
define Build/Compile
endef
define Package/ext-sms/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,ext-sms))

View File

@ -0,0 +1,160 @@
module("luci.controller.sms", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local fs = require "nixio.fs"
if not fs.stat("/etc/nosms") then
local page
page = entry({"admin", "modem", "sms"}, template("rooter/sms"), translate("短信功能"), 35)
page.dependent = true
end
entry({"admin", "modem", "check_read"}, call("action_check_read"))
entry({"admin", "modem", "del_sms"}, call("action_del_sms"))
entry({"admin", "modem", "send_sms"}, call("action_send_sms"))
entry({"admin", "modem", "change_sms"}, call("action_change_sms"))
entry({"admin", "modem", "change_smsdn"}, call("action_change_smsdn"))
entry({"admin", "modem", "change_smsflag"}, call("action_change_smsflag"))
end
function trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function action_send_sms()
if package.path:find(";/usr/lib/sms/?.lua") == nil then
package.path = package.path .. ";/usr/lib/sms/?.lua"
end
smsnum = luci.model.uci.cursor():get("modem", "general", "smsnum")
local set = luci.http.formvalue("set")
local number = trim(string.sub(set, 1, 20))
local txt = string.sub(set, 21)
local utf8togsm = require "utf8togsm"
utf8togsm.chktxt(txt)
local msg = utf8togsm["msg"]
local dcs = utf8togsm["dcs"]
txt = utf8togsm["txt"]
local rv = {}
local file = nil
local k = 1
local status
local rfname = "/tmp/smssendstatus0000"
if msg == nil then
os.execute("if [ -e " .. rfname .. " ]; then rm " ..rfname .. "; fi")
os.execute("lua /usr/lib/sms/sendsms.lua " .. smsnum .. " " .. number .. " " .. dcs .. " " .. txt .. " 0000")
os.execute("sleep 3")
repeat
file = io.open(rfname, "r")
if file == nil then
os.execute("sleep 1")
end
k = k + 1
until k > 25 or file ~=nil
if file == nil then
status = translate('Sending attempt timed out (fail)')
else
status = file:read("*line")
file:close()
os.remove (rfname)
end
else
status = msg
end
rv["status"] = status
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end
function action_del_sms()
local set = tonumber(luci.http.formvalue("set"))
if set ~= nil and set > 0 then
set = set - 1;
smsnum = luci.model.uci.cursor():get("modem", "general", "smsnum")
os.execute("/usr/lib/sms/delsms.sh " .. smsnum .. " " .. set)
os.execute("touch /tmp/smswakeup" .. smsnum)
end
end
function action_check_read()
local rv ={}
local file
local line
smsnum = luci.model.uci.cursor():get("modem", "general", "smsnum")
conn = "Modem #" .. smsnum
rv["conntype"] = conn
support = luci.model.uci.cursor():get("modem", "modem" .. smsnum, "sms")
rv["ready"] = "0"
rv["menable"] = "0"
rv["mslots"] = "0"
if support == "1" then
rv["ready"] = "1"
result = "/tmp/smsresult" .. smsnum .. ".at"
file = io.open(result, "r")
if file ~= nil then
file:close()
file = io.open("/tmp/smstext" .. smsnum, "r")
if file == nil then
rv["ready"] = "3"
else
rv["menable"] = luci.model.uci.cursor():get("modem", "sms", "menable")
rv["mslots"] = luci.model.uci.cursor():get("modem", "sms", "slots")
rv["ready"] = "2"
local tmp = file:read("*line")
rv["used"] = tmp
tmp = file:read("*line")
rv["max"] = tmp
full = nil
repeat
for j = 1, 4 do
line = file:read("*line")
if line ~= nil then
if j == 3 then
full = full .. string.char(29)
local i = tonumber(line)
for k = 1, i do
line = file:read("*line")
full = full .. line
if k < i then
full = full .. '<br />'
end
end
else
if full == nil then
full = line
else
full = full .. string.char(29) .. line
end
end
end
end
until line == nil
file:close()
rv["line"] = full
end
end
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end
function action_change_sms()
os.execute("/usr/lib/rooter/luci/modemchge.sh sms 1")
end
function action_change_smsdn()
os.execute("/usr/lib/rooter/luci/modemchge.sh sms 0")
end
function action_change_smsflag()
local set = tonumber(luci.http.formvalue("set"))
os.execute("/usr/lib/sms/toggle.sh " .. set)
end

View File

@ -0,0 +1,525 @@
<%+header%>
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>
<script type="text/javascript">//<![CDATA[
reading = 0;
init = 0;
indx = -1;
index = [];
recread = [];
number = [];
tdate = [];
ttime = [];
ttext =[];
selectline = -1;
XHR.poll(20, '<%=luci.dispatcher.build_url("admin", "modem", "check_read")%>', null,
function(x, rv)
{
var ss = rv.ready;
document.getElementById('conntype').innerHTML=rv.conntype;
if ( ss == "0" )
{
clearListBox("smsList");
document.getElementById('message').innerHTML="";
document.getElementById('total').innerHTML="";
document.getElementById('used').innerHTML="";
document.getElementById('mslots').innerHTML="";
document.getElementById('menb').checked=false;
document.getElementById('supported').innerHTML="<%:模块未适配短信支持/未连接到模块%>";
}
if ( ss == "1" )
{
clearListBox("smsList");
document.getElementById('message').innerHTML="";
document.getElementById('total').innerHTML="";
document.getElementById('used').innerHTML="";
document.getElementById('mslots').innerHTML="";
document.getElementById('menb').checked=false;
document.getElementById('supported').innerHTML="<%:您有未读的短信,请前往查看%>";
}
if ( ss == "3" )
{
document.getElementById('supported').innerHTML="<%:消息读取有问题%>";
}
if ( ss == "2" )
{
document.getElementById('supported').innerHTML="<%:存在的短信%>";
clearListBox("smsList");
document.getElementById('total').innerHTML=rv.max;
document.getElementById('used').innerHTML=rv.used;
if ( parseInt(rv.used) == parseInt(rv.max) )
{
alternateColor('red','total');
alternateColor('red','used');
}
else
{
document.getElementById('total').style.color = "default";
document.getElementById('used').style.color = "default";
}
document.getElementById('mslots').innerHTML=rv.mslots;
if ( init == 0 )
{
var me = rv.menable;
if ( me == "0" )
{
document.getElementById('menb').checked=false;
}
else
{
document.getElementById('menb').checked=true;
}
init = 1;
}
if (rv.used == "0")
{
document.getElementById('supported').innerHTML="<%:SIM卡上没有短信%>";
}
else
{
var line=rv.line;
var arr=(line.split("\x1D"));
var len = arr.length;
indx = 0;
var i;
for(i=0;i<len;i++)
{
index[indx] = parseInt(arr[i]);
number[indx] = arr[i+1];
ttext[indx] = arr[i+2];
var txtline = arr[i+3];
txtline = txtline.replace(/ /g,"\240");
var select = document.getElementById("smsList");
select.options[select.options.length] = new Option(txtline, indx);
i = i + 3;
indx = indx + 1;
}
if ( indx != -1 )
{
if ( selectline == -1 )
{
select.value = 0;
document.getElementById('message').innerHTML=ttext[0];
selectline = 0;
}
else
{
if ( selectline > indx-1 )
{
selectline = indx -1 ;
}
select.value = selectline;
document.getElementById('message').innerHTML=ttext[selectline];
}
}
}
}
}
);
document.getElementById('message').innerHTML=" ";
document.getElementById('total').innerHTML="0";
document.getElementById('used').innerHTML="0";
document.getElementById('mslots').innerHTML="0";
function alternateColor(color, textId, myInterval)
{
if(!myInterval)
{
myInterval = 500;
}
var colors = ['grey', color];
var currentColor = 1;
document.getElementById(textId).style.color = colors[0];
setInterval(function()
{
if ( document.getElementById(textId).style.color == 'default' )
{
return;
}
document.getElementById(textId).style.color = colors[currentColor];
if (currentColor < colors.length-1) {
++currentColor;
} else {
currentColor = 0;
}
}, myInterval);
}
function clearListBox(listboxID)
{
var mylistbox = document.getElementById(listboxID);
if(mylistbox == null)
{
return 1;
}
while(mylistbox.length > 0)
{
mylistbox.remove(0);
}
return 1;
}
function changetxt()
{
var s = document.getElementById("smsList").value;
selectline = s;
document.getElementById('message').innerHTML=ttext[s];
}
function sendsms()
{
if ( reading > 0 )
{
return false;
}
var s = document.getElementById("sendto").value;
//document.getElementById('rding').innerHTML=s.length;
if ( s.length == 0 )
{
alert("<%:请输入电话号码!!%>");
return false;
}
s = s.trim();
if ( isNaN(s) == true )
{
alert("<%:错误的电话号码!!%>");
return false;
}
var num = s.concat(" ");
num = num.substr(0, 20);
var t = document.getElementById("txtmessage").value;
if ( t.length == 0 )
{
alert("<%:Message is blank!!%>");
return false;
}
if ( t.length > 160 )
{
t = t.substr(0, 160);
}
num = num.concat(t);
alert("<%:SMS will be queued for processing.\nA status update will follow.%>");
document.getElementById("sstat").innerHTML="<%:状态 :消息正在发送%>";
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "send_sms")%>',
{ set: num },
function(x, rv)
{
var status = rv.status;
alert(status);
document.getElementById("sstat").innerHTML="";
}
);
}
function delsms()
{
if ( selectline == -1 )
{
return false;
}
var r=confirm("<%:确认删除选中消息 %>");
if (r==false)
{
return false;
}
var s = document.getElementById("smsList").value;
var dx = index[s];
dx = dx + 1;
clearListBox("smsList");
document.getElementById('message').style.color = "red";
document.getElementById('message').innerHTML="<%:短信将被删除,同步到列表可能会很久(反复提交删除申请一样很久)%>";
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "del_sms")%>',
{ set: dx },
function()
{
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "check_read")%>', null,
function(x, rv)
{
var ss = rv.ready;
document.getElementById('message').style.color = "initial";
document.getElementById('conntype').innerHTML=rv.conntype;
if ( ss == "1" )
{
clearListBox("smsList");
document.getElementById('message').innerHTML="";
document.getElementById('total').innerHTML="";
document.getElementById('used').innerHTML="";
document.getElementById('supported').innerHTML="<%:您有未读的短信,请前往查看%>";
}
if ( ss == "3" )
{
document.getElementById('supported').innerHTML="<%:消息读取有问题%>";
}
if ( ss == "2" )
{
document.getElementById('supported').innerHTML="<%:存在短信%>";
clearListBox("smsList");
document.getElementById('total').innerHTML=rv.max;
document.getElementById('used').innerHTML=rv.used;
var line=rv.line;
var arr=(line.split("\x1D"));
var len = arr.length;
indx = 0;
var i;
for(i=0;i<len;i++)
{
index[indx] = parseInt(arr[i]);
number[indx] = arr[i+1];
ttext[indx] = arr[i+2];
var txtline = arr[i+3];
txtline = txtline.replace(/ /g,"\240");
var select = document.getElementById("smsList");
select.options[select.options.length] = new Option(txtline, indx);
i = i + 3;
indx = indx + 1;
}
if ( indx != -1 )
{
if ( selectline == -1 )
{
select.value = 0;
document.getElementById('message').innerHTML=ttext[0];
selectline = 0;
}
else
{
if ( selectline > indx-1 )
{
selectline = indx -1 ;
}
select.value = selectline;
document.getElementById('message').innerHTML=ttext[selectline];
}
}
}
}
);
}
);
}
function replysms()
{
if ( reading > 0 )
{
return false;
}
var s = document.getElementById("smsList").value;
if ( selectline == -1 )
{
return false;
}
else
{
document.getElementById('sendmsg').style.display="table";
document.getElementById('sendtxt').style.display="table";
document.getElementById('sendbtn').style.display="table";
document.getElementById('sendtitle').style.display="block";
document.getElementById("sendto").value=number[s];
document.getElementById("txtmessage").value="";
}
return false;
}
function newsms()
{
if ( reading > 0 )
{
return false;
}
document.getElementById('sendmsg').style.display="table";
document.getElementById('sendtxt').style.display="table";
document.getElementById('sendbtn').style.display="table";
document.getElementById('sendtitle').style.display="block";
document.getElementById("sendto").value="";
document.getElementById("txtmessage").value="";
return false;
}
function modemtoggle(btn)
{
btn.disabled = true;
btn.value = '<%:Changing...%>';
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "change_sms")%>',
null,
function(x, rv)
{
btn.disabled = false;
btn.value = '<%:下一个模块%>';
}
);
return false;
}
function modemtoggledn(btn)
{
btn.disabled = true;
btn.value = '<%:Changing...%>';
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "change_smsdn")%>',
null,
function(x, rv)
{
btn.disabled = false;
btn.value = '<%:Prev Modem%>';
}
);
return false;
}
function memenable(btn)
{
dx = 0;
if ( btn.checked == true )
{
dx = 1;
}
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "change_smsflag")%>',
{ set: dx },
function()
{
}
);
return false;
}
//]]></script>
<form method="post" action="<%=REQUEST_URI%>">
<div class="cbi-map" id="cbi-sms">
<h2><a id="content" name="content"><%:短信收发页面%></a></h2>
<div class="cbi-map-descr"><%:通过模块发送和接收文本消息%></div>
<fieldset class="cbi-section" id="cbi-read">
<legend><%:通信模块信息%></legend>
<table width="550" border="0">
<tr>
<td width="40%"><ul id="supported"></ul></td>
<td width="17%"><strong id="conntype"></strong></td>
<td width="12%">
<input type="button" class="cbi-button cbi-button-apply" value="<%:上一个模块%>" onclick="return modemtoggledn(this)" />
</td>
<td width="31%">
<input type="button" class="cbi-button cbi-button-apply" value="<%:下一个模块%>" onclick="return modemtoggle(this)" />
</td>
</tr>
</table>
<legend><%:收到的短信%></legend>
<table width="550" border="0">
<tr>
<td width="18%"><div align="center"><strong><%:SIM可存放的短信空间 (条)%></strong></div></td>
<td width="18%"><div align="center"><strong><%:已使用的SIM短信空间 (条)%></strong></div></td>
<td width="34%">&nbsp;</td>
</tr>
<tr>
<td><div align="center"><ul id="total"></ul></div></td>
<td><div align="center"><ul id="used"></ul></div></td>
<td>&nbsp;</td>
</tr>
</table>
<table width="550" border="0">
<tr>
<td width="3%">&nbsp;</td>
<td width="20%"><div align="left"><%:启用模块到SIM卡的短信传输%></div></td>
<td width="8%">
<input type="checkbox" id="menb" onclick="memenable(this)" />
</td>
<td width="16%"><div align="left"><strong><u><%:模块上的未读信息数量%></u></strong></div></td>
<td width="34%">&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td><div align="center"><ul id="mslots"></ul></div></td>
<td>&nbsp;</td>
</tr>
</table>
<table width="700" border="0">
<tr>
<td width="4%"><div align="center"><strong><u><%:已读状态%></u></strong></div></td>
<td width="18%"><div align="left"><strong><u><%:发件人%></u></strong></div></td>
<td width="8%"><div align="left"><strong><u><%:Date%></u></strong></div></td>
<td width="11%"><div align="left"><strong><u><%:时间%></u></strong></div></td>
<td width="35%"><div align="left"><strong><u><%:短信%></u></strong></div></td>
<td width="24%"><div align="left"> </div></td>
</tr>
</table>
<table width="700" border="0">
<tr>
<td width="100%">
<select name="smslist" id="smsList" size="5" style="width: 700px; font-size:15px; font-family:monospace; line-height:27px; float:left; height:130px;" onchange="changetxt()">
</select>
</td>
</tr>
</table>
<table width="550" border="0">
<tr>
<td width="15%"><div align="left"><strong><%:短信内容 :%></strong></div></td>
<td width="70%"><ul id="message"></ul></td>
<td width="15%">&nbsp;</td>
</tr>
</table>
<table width="550" border="0">
<tr>
<td width="17%"><input type="button" id="delbtn" class="cbi-button cbi-button-apply" value="<%:删除短信%>" onclick="return delsms()" /></td>
<td width="17%"><input type="button" id="replybtn" class="cbi-button cbi-button-apply" value="<%:回复短信%>" onclick="return replysms()" /></td>
<td width="17%"><input type="button" id="newbtn" class="cbi-button cbi-button-apply" value="<%:新建短信%>" onclick="return newsms()" /></td>
<td width="49%">&nbsp;</td>
</tr>
</table>
<legend id="sendtitle" style="display:block;"><%:短信会话%></legend>
<table id="sendmsg" width="600" border="0" style="display:table;">
<tr>
<td width="15%"><div align="left"><strong><%:收件人 :%></strong></div></td>
<td width="70%"><input name="sendto" id="sendto" maxlength="20"></input></td>
<td width="15%">&nbsp;</td>
</tr>
</table>
<table id="sendtxt" width="700" border="0" style="display:table;">
<tr>
<td width="100%">
<textarea name="txtmessage" id="txtmessage" rows="6" style="width: 600px;" maxlength="160"></textarea>
</td>
</tr>
</table>
<table id="sendbtn" width="550" border="0" style="display:table;">
<tr>
<td width="17%"><input type="button" id="sendbtn" class="cbi-button cbi-button-apply" value="<%:Send%>" onclick="return sendsms()" /></td>
<td width="13%">&nbsp;</td>
<td width="70%">&nbsp;</td>
</tr>
</table>
<table width="550" border="0">
<tr>
<td width="15%"><div align="left"><strong><%:短信发送状态 :%></strong></div></td>
<td width="70%"><ul style="color:red" id="sstat"></ul></td>
<td width="15%">&nbsp;</td>
</tr>
</table>
</fieldset>
</div>
</form>
<%+footer%>

View File

@ -0,0 +1,41 @@
#!/bin/sh
ROOTER=/usr/lib/rooter
log() {
logger -t "Delete SMS" "$@"
}
CURRMODEM=$1
shift 1
SLOTS="$@"
COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport)
SMSLOC=$(uci -q get modem.modem$CURRMODEM.smsloc)
LOCKDIR="/tmp/smslock$CURRMODEM"
PIDFILE="${LOCKDIR}/PID"
while [ 1 -lt 6 ]; do
if mkdir "${LOCKDIR}" &>/dev/null; then
echo "$$" > "${PIDFILE}"
for SLOT in $SLOTS
do
ATCMDD="AT+CPMS=\"$SMSLOC\";+CMGD=$SLOT"
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
done
uci set modem.modem$CURRMODEM.smsnum=999
uci commit modem
break
else
OTHERPID="$(cat "${PIDFILE}")"
if [ $? = 0 ]; then
if ! kill -0 $OTHERPID &>/dev/null; then
rm -rf "${LOCKDIR}"
fi
fi
sleep 1
fi
done
rm -rf "${LOCKDIR}"

View File

@ -0,0 +1,79 @@
local pack7bit = {}
function hasbit(x, p)
return x % (p + p) >= p
end
function bitand(x, y)
local p = 1; local z = 0; local limit = x > y and x or y
while p <= limit do
if hasbit(x, p) and hasbit(y, p) then
z = z + p
end
p = p + p
end
return z
end
function bitor(x, y)
local p = 1; local z = 0; local limit = x > y and x or y
while p <= limit do
if hasbit(x, p) or hasbit(y, p) then
z = z + p
end
p = p + p
end
return z
end
function bitright(x, y)
return math.floor(x / 2 ^ y)
end
function bitleft(x, y)
return x * 2 ^ y
end
function pack7bit.pack(udl, txt)
maxb = math.ceil((tonumber(udl, 16) / 8) * 7)
udtab = {}
ii = 1
jj = 1
kk = 0
repeat
ch = tonumber(txt:sub(jj, jj + 1), 16)
if ii == 1 then
udtab[kk + 1] = ch
elseif ii == 2 then
udtab[kk] = bitor(bitleft(bitand(ch, 1), 7), udtab[kk])
udtab[kk + 1] = bitright(bitand(ch, 126), 1)
elseif ii == 3 then
udtab[kk] = bitor(bitleft(bitand(ch, 3), 6), udtab[kk])
udtab[kk + 1] = bitright(bitand(ch, 124), 2)
elseif ii == 4 then
udtab[kk] = bitor(bitleft(bitand(ch, 7), 5), udtab[kk])
udtab[kk + 1] = bitright(bitand(ch, 120), 3)
elseif ii == 5 then
udtab[kk] = bitor(bitleft((bitand(ch, 15)), 4), udtab[kk])
udtab[kk + 1] = bitright(bitand(ch, 112), 4)
elseif ii == 6 then
udtab[kk] = bitor(bitleft(bitand(ch, 31), 3), udtab[kk])
udtab[kk + 1] = bitright(bitand(ch, 96), 5)
elseif ii == 7 then
udtab[kk] = bitor(bitleft(bitand(ch, 63), 2), udtab[kk])
udtab[kk + 1] = bitright(bitand(ch, 64), 6)
else
udtab[kk] = bitor(bitleft(ch, 1), udtab[kk])
ii = 0
kk = kk - 1
end
ii = ii + 1
jj = jj + 2
kk = kk + 1
until jj > #txt
for jj = 1, maxb do
udtab[jj] = string.format("%02X", udtab[jj])
end
pack7bit["pdu"] = table.concat(udtab)
end
return pack7bit

View File

@ -0,0 +1,168 @@
#!/bin/sh
ROOTER=/usr/lib/rooter
log() {
logger -t "sms process" "$@"
}
CURRMODEM=$1
log "SMS Supported Modem$CURRMODEM"
COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport)
LOCKDIR="/tmp/smslock$CURRMODEM"
PIDFILE="${LOCKDIR}/PID"
rm -rf "${LOCKDIR}"
idV=$(uci -q get modem.modem$CURRMODEM.idV)
idP=$(uci -q get modem.modem$CURRMODEM.idP)
MODEMID="$idV${idP:0:3}"
ATCMDD="AT+CMGF=0"
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
sleep 1
ATCMDD="AT+CPMS=\"SM\",\"SM\",\"SM\""
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
MAXED=$(echo "$OX" | cut -d, -f2 | grep -o "[0-9]\{1,3\}")
if [ "$MAXED" == "0" -a "$MODEMID" != "119968a" ]; then
ATCMDD="AT+CPMS=\"ME\",\"ME\",\"ME\""
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
uci set modem.modem$CURRMODEM.smsloc="ME"
SMSLOC="ME"
MEM3="ME"
else
uci set modem.modem$CURRMODEM.smsloc="SM"
SMSLOC="SM"
MEM3="SM"
fi
sleep 1
uci set modem.modem$CURRMODEM.smsnum=999
uci commit modem
ATCMDD="AT+CPMS=\"ME\""
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
MESC=$(echo "$OX" | grep -o "+CPMS:.*" | awk -F, '{print $1}' | grep -o "[0-9]\{1,3\}")
METC=$(echo "$OX" | grep -o "+CPMS:.*" | awk -F, '{print $2}' | grep -o "[0-9]\{1,3\}")
MESLOT="0"
MESCc=""
if [ "x$MESC" = "x" ]; then
MESC="0"
fi
if [ "x$METC" = "x" ]; then
METC="0"
MESC="0"
SMSLOC="SM"
fi
uci set modem.sms.slots=$MESC
uci commit modem
sleep 1
rm -f /tmp/smsresult$CURRMODEM".at"
> /tmp/smsslots$CURRMODEM
HH=$(date +%H)
while true; do
SLEEP="20"
while true; do
if mkdir "${LOCKDIR}" &>/dev/null; then
echo "$$" > "${PIDFILE}"
if [ "$METC" != "0" ]; then
ATCMDD="AT+CPMS=\"ME\",\"$SMSLOC\",\"$MEM3\""
SX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
USED=$(echo "$SX" | cut -d, -f1 | grep -o "[0-9]\{1,3\}")
MESCc="$USED"
MAXED=$(echo "$SX" | cut -d, -f2 | grep -o "[0-9]\{1,3\}")
fi
if [ $SMSLOC == "SM" ]; then
ATCMDD="AT+CPMS=\"SM\",\"$SMSLOC\",\"$MEM3\""
SX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
USED=$(echo "$SX" | cut -d, -f1 | grep -o "[0-9]\{1,3\}")
MAXED=$(echo "$SX" | cut -d, -f2 | grep -o "[0-9]\{1,3\}")
if [ -n "$MESCc" -a "$MESCc" != "$MESC" ]; then
MESC=$MESCc
uci set modem.sms.slots=$MESC
uci commit modem
fi
if [ $USED == $MAXED -a $MEM3 == "SM" ]; then
ATCMDD="AT+CPMS=\"SM\",\"SM\",\"ME\""
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
MEM3="ME"
else
if [ $USED != $MAXED -a $MEM3 == "ME" ]; then
ATCMDD="AT+CPMS=\"SM\",\"SM\",\"SM\""
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
MEM3="SM"
fi
fi
fi
if [ $MAXED -eq 0 ]; then
SLEEP="900"
fi
if [ $USED -eq $(uci get modem.modem$CURRMODEM.smsnum) ] && [ $HH -eq $(date +%H) ]; then
if [ $MEM3 == "SM" -a $USED -lt $MAXED -a $MESC -gt 0 -a $(uci -q get modem.sms.menable) == 1 ]; then
ATCMDD="AT+CPMS=\"ME\";+CMGR=$MESLOT;+CPMS=\"SM\""
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
Rstat=$(echo "$OX" | grep -o "+CMGR:[^,]\+" | grep -o "[0-3]")
PDU=$(echo "$OX" | grep -o "[0-9A-F]\{30,\}")
PDUL=$(echo "$OX" | grep -o "+CMGR:.*" | grep -o ",[0-9]\{1,\}" | grep -o "[0-9]\{1,3\}")
if [ -n "$PDU" -a -n "$PDUL" -a -n "$Rstat" ]; then
if [ ${#PDUL} -eq 2 ]; then
PDUL="0$PDUL"
fi
ATCMDD="$PDUL,SM,$Rstat,$PDU"
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "smswrite.gcom" "$CURRMODEM" "$ATCMDD")
MREF=$(echo "$OX" | grep -o "[0-9]\{1,3\}")
if [ ${#MREF} -gt 0 ]; then
echo "$MREF" >> /tmp/smsslots$CURRMODEM
ATCMDD="AT+CPMS=\"ME\";+CMGD=$MESLOT;+CPMS=\"SM\""
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
fi
MESC=$(($MESC - 1))
uci set modem.sms.slots=$MESC
uci commit modem
SLEEP="5"
fi
MESLOT=$(($MESLOT + 1))
if [ $MESLOT -gt $METC -o $MESC == "0" ]; then
MESLOT="0"
fi
fi
else
log "Reread SMS Messages on Modem $CURRMODEM"
echo "$SX" > /tmp/smstemp$CURRMODEM
ATCMDD="AT+CMGL=4"
SX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
SX=$(echo "$SX" | sed -e "s/+CMGL:/+CMGL: /g")
echo "$SX" >> /tmp/smstemp$CURRMODEM
uci set modem.modem$CURRMODEM.smsnum=$USED
uci commit modem
mv /tmp/smstemp$CURRMODEM /tmp/smsresult$CURRMODEM.at
lua /usr/lib/sms/smsread.lua $CURRMODEM
HH=$(date +%H)
SLEEP="5"
fi
break
else
OTHERPID="$(cat "${PIDFILE}")"
if [ $? = 0 ]; then
if ! kill -0 $OTHERPID &>/dev/null; then
rm -rf "${LOCKDIR}"
fi
fi
sleep 1
fi
done
rm -rf "${LOCKDIR}"
n=1
until [ $n -ge $SLEEP ]
do
sleep 1
if [ -e /tmp/smswakeup$CURRMODEM ]; then
rm /tmp/smswakeup$CURRMODEM
n=$(( $n + $SLEEP ))
else
n=$(( $n + 1 ))
fi
done
done

View File

@ -0,0 +1,41 @@
#!/usr/bin/lua
modem = arg[1]
addr = arg[2]
dcs = arg[3]
txt = arg[4]
suffix = arg[5]
if package.path:find(";/usr/lib/sms/?.lua") == nil then
package.path = package.path .. ";/usr/lib/sms/?.lua"
end
local pack7bit = require "pack7bit"
udl = string.format("%02X", math.floor(#txt / 2))
da = "81"
if addr:sub(1, 1) == "+" then
da = "91"
addr = addr:sub(2)
elseif addr:sub(1, 1) == "-" then
addr = addr:sub(2)
end
da = string.format("%02X", #addr) .. da
if (#addr % 2) > 0 then
addr = addr .. "F"
end
k = #addr
j = 1
repeat
da = da .. addr:sub(j + 1, j + 1) .. addr:sub(j, j)
j = j + 2
until j > k
if dcs == "00" then
pack7bit.pack(udl, txt)
ud = pack7bit["pdu"]
else
ud = txt
end
pdu = "001100" .. da .. "00" .. dcs .. "AD" .. udl .. ud
pdul = string.format("%03d", (math.floor(#pdu / 2) - 1))
os.execute("/usr/lib/sms/sendsms.sh " .. modem .. " " .. pdul .. "," .. suffix .. "," .. pdu .. " &")

View File

@ -0,0 +1,10 @@
#!/bin/sh
ROOTER=/usr/lib/rooter
CURRMODEM=$1
ATCMDD=$2
COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport)
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "sendsms-at.gcom" "$CURRMODEM" "$ATCMDD")

View File

@ -0,0 +1,24 @@
#!/usr/bin/lua
local modem = arg[1]
local dest = arg[2]
local txt = arg[3]
local pid = arg[4]
local rfname = "/tmp/smssendstatus" .. pid
if package.path:find(";/usr/lib/sms/?.lua") == nil then
package.path = package.path .. ";/usr/lib/sms/?.lua"
end
local utf8togsm = require "utf8togsm"
utf8togsm.chktxt(txt)
local msg = utf8togsm["msg"]
local dcs = utf8togsm["dcs"]
txt = utf8togsm["txt"]
if msg == nil then
os.execute("if [ -e " .. rfname .. " ]; then rm " ..rfname .. "; fi")
os.execute("lua /usr/lib/sms/sendsms.lua " .. modem .. " " .. dest .. " " .. dcs .. " " .. txt .. " " .. pid)
else
os.execute('echo "SMS sending failed - text is too long" > ' .. rfname)
end

View File

@ -0,0 +1,38 @@
#!/bin/sh
ROOTER=/usr/lib/rooter
log() {
logger -t "sms process" "$@"
}
CURRMODEM=$(uci get modem.general.smsnum)
DEST="$1"
shift 1
TXT="$@"
MYPID=$(printf "%05d" $$)
MYPID=$(printf "${MYPID:1:4}")
RESFILE="/tmp/smssendstatus"$MYPID
lua /usr/lib/sms/smsout.lua $CURRMODEM $DEST "$TXT" $MYPID
sleep 5
COUNT=0
XSTATUS=1
RES="SMS sending failed, timeout reading result"
while [ $COUNT -lt 15 ]; do
if [ -e $RESFILE ]; then
read RES < $RESFILE
if [ "${RES:0:9}" = "SMS sent," ]; then
XSTATUS=0
fi
COUNT=999
rm $RESFILE
else
sleep 2
fi
COUNT=$(($COUNT + 1))
done
log "$RES"
echo "$RES"
exit $XSTATUS

View File

@ -0,0 +1,862 @@
#!/usr/bin/lua
senders2delete = {}
deletebinaries = false
modemn = arg[1]
local smsresult = "/tmp/smsresult" .. modemn .. ".at"
local smsslots = "/tmp/smsslots" .. modemn
local smstime = "/tmp/smstime" .. modemn
local t = {}
local tptr
local m_pdu_ptr
local m_pdu
local m_smsc
local m_with_udh
local m_report
local m_number
local m_replace
local m_alphabet
local m_dcs
local m_flash
local m_date
local m_time
local m_text
local m_concat
local m_read
local m_index
local g_table1 = {}
local g_table2 = {}
local max_smsc = 64
local max_number = 64
local max_udh_data = 512
surrogate = 0
function reset()
m_smsc = nil
m_with_udh = 0
m_report = 0
m_number = nil
m_replace = 0
m_alphabet = -1
m_flash = 0
m_date = nil
m_time = nil
m_text = nil
m_concat = nil
end
function hasbit(x, p)
return x % (p + p) >= p
end
function bitor(x, y)
local p = 1; local z = 0; local limit = x > y and x or y
while p <= limit do
if hasbit(x, p) or hasbit(y, p) then
z = z + p
end
p = p + p
end
return z
end
function bitand(x, y)
local p = 1; local z = 0; local limit = x > y and x or y
while p <= limit do
if hasbit(x, p) and hasbit(y, p) then
z = z + p
end
p = p + p
end
return z
end
function bitright(x, y)
return math.floor(x / 2 ^ y)
end
function bitleft(x, y)
return x * 2 ^ y
end
function ocount(x, y)
local j = 0
local i = x:find(y, 0)
while i ~= nil do
i = x:find(y, i + 1)
j = j + 1
end
return j
end
printf = function(s,...)
if echo == 0 then
io.write(s:format(...))
else
ss = s:format(...)
os.execute("/usr/lib/rooter/logprint.sh " .. ss)
end
end
function isxdigit(digit)
if digit == nil then
return 0
end
if digit >= 48 and digit <= 57 then
return 1
end
if digit >= 97 and digit <= 102 then
return 1
end
if digit >= 65 and digit <= 70 then
return 1
end
return 0
end
function isdigit(digit)
if digit >= 48 and digit <= 57 then
return 1
end
return 0
end
function octet2bin(octet)
result = 0
if octet:byte(1) > 57 then
result = result + octet:byte(1) - 55
else
result = result + octet:byte(1) - 48
end
result = result * 16
if octet:byte(2) > 57 then
result = result + octet:byte(2) - 55
else
result = result + octet:byte(2) - 48
end
return result
end
function octet2bin_check(octet)
if octet:byte(1) == 0 then
return -1
end
if octet:byte(2) == 0 then
return -2
end
if isxdigit(octet:byte(1)) == 0 then
return -3
end
if isxdigit(octet:byte(2)) == 0 then
return -4
end
return octet2bin(octet)
end
function swapchars(sstring)
local length = sstring:len()
local xstring = nil
local i = 1
while i < length do
c1 = sstring:sub(i, i)
c2 = sstring:sub(i+1, i+1)
if xstring == nil then
xstring = c2 .. c1
else
xstring = xstring .. c2 .. c1
end
i = i + 2
end
return xstring
end
function parseSMSC()
m_pdu_ptr = m_pdu
local length = octet2bin_check(m_pdu_ptr)
if length < 0 then
return -1
end
if length == 0 then
m_smsc = ""
m_pdu_ptr = m_pdu_ptr:sub(3)
return 1
end
if length < 2 or length > max_smsc then
return -1
end
length = (length * 2) - 2
local mlen = m_pdu:len()
if mlen < (length + 4) then
return -1
end
m_pdu_ptr = m_pdu_ptr:sub(3)
local addr_type = octet2bin_check(m_pdu_ptr)
if addr_type < 0 then
return -1
end
if addr_type < 0x80 then
return -1
end
m_pdu_ptr = m_pdu_ptr:sub(3)
m_smsc = m_pdu_ptr:sub(0, length)
m_smsc = swapchars(m_smsc)
if addr_type < 0x90 then
for j=1, length do
if isxdigit(m_smsc:byte(j)) == 0 then
return -1
end
end
else
if m_smsc:byte(length) == 70 then
m_smsc = m_smsc:sub(1, length-1)
end
local leng = m_smsc:len()
for j=1,leng do
if isdigit(m_smsc:byte(j)) == 0 then
return -1
end
end
end
m_pdu_ptr = m_pdu_ptr:sub(length + 1)
return 1
end
function explainAddressType(octet_char, octet_int)
local result
if octet_char ~= nil then
result = octet2bin_check(octet_char)
else
result = octet_int
end
return result
end
function concatinfo(x)
while #x > 9 do
if x:sub(1, 4) == '0003' then
if x:sub(7, 10) ~= '0101' then
m_concat = 'Msg# ' .. tonumber(x:sub(5, 6), 16)
m_concat = m_concat .. ',' .. tonumber(x:sub(9, 10), 16)
m_concat = m_concat .. '/' .. tonumber(x:sub(7, 8), 16)
end
x = ""
elseif x:sub(1, 4) == '0804' then
if x:sub(9, 12) ~= '0101' then
m_concat = 'Msg# ' .. tonumber(x:sub(5, 8), 16)
m_concat = m_concat .. ',' .. tonumber(x:sub(11, 12), 16)
m_concat = m_concat .. '/' .. tonumber(x:sub(9, 10), 16)
end
x = ""
else
local iel = tonumber(x:sub(3, 4), 16)
x = x:sub(5 + iel * 2)
end
end
end
function pdu2binary(pdu, with_udh)
local skip_octets = 0
local octetcounter
m_text = ''
local octets = octet2bin_check(pdu)
local last_i = 0
if octets < 0 then
return -1
end
if with_udh > 0 then
local pdu2 = pdu:sub(3)
local udhl = tonumber(pdu2:sub(1, 2), 16)
concatinfo(pdu2:sub(3, (udhl + 1) * 2))
local udhsize = octet2bin_check(pdu2)
if udhsize < 0 then
return -1
end
skip_octets = udhsize + 1
end
for octetcounter = 0, (octets - skip_octets - 1) do
local pdu2 = pdu:sub((octetcounter * 2) + 3 + (skip_octets * 2))
local i = octet2bin_check(pdu2)
if i < 0 then
return -1
end
if m_alphabet == 2 then
if (2 + octetcounter) % 2 == 0 then
last_i = i
else
m_text = word2utf8(bitor(bitleft(last_i, 8), i), m_text)
end
else
if i < 32 or i > 127 then
i = 0x25A1
end
m_text = word2utf8(i, m_text)
end
end
return (octets - skip_octets)
end
function pdu2text(pdu, with_udh)
local result
local octetcounter
local skip_characters = 0
local binary = 0
m_text = ''
local septets = octet2bin_check(pdu)
if septets < 0 then
return -1
end
if with_udh > 0 then
local pdu2 = pdu:sub(3)
local udhl = tonumber(pdu2:sub(1, 2), 16)
concatinfo(pdu2:sub(3, (udhl + 1) * 2))
local udhsize = octet2bin_check(pdu2)
skip_characters = math.floor((((udhsize+1)*8)+6)/7)
end
local octets = math.floor((septets * 7 + 7) / 8)
local bitposition = 0
local byteposition
local byteoffset
local i
local g_table_nbr = 1
octetcounter = 0
for charcounter=0,septets-1 do
local c = 0
for bitcounter=0,6 do
byteposition = math.floor(bitposition / 8)
byteoffset = bitposition % 8
while (byteposition >= octetcounter) and (octetcounter < octets) do
local pdu2 = pdu:sub((octetcounter * 2) + 3)
i = octet2bin_check(pdu2)
if i < 0 then
return -2
end
binary = i
octetcounter = octetcounter + 1
end
if bitand(binary, (2^byteoffset)) > 0 then
c = bitor(c, 128)
end
bitposition = bitposition + 1
c = bitand(math.floor(c / 2), 127)
end
c = gsm2byte(c)
if charcounter >= skip_characters and c ~= 27 then
m_text = word2utf8(c, m_text)
end
end
return 1
end
function gsm2byte(ch)
if g_table_nbr == 2 then
if g_table2[ch] == nil then
ch = 63
else
ch = g_table2[ch]
end
g_table_nbr = 1
else
if ch == 27 then
g_table_nbr = 2
else
if g_table1[ch] ~= nil then
ch = g_table1[ch]
end
end
end
return ch
end
function word2utf8(i, txt)
if surrogate > 0 then
if i >= 0xDC00 and i <= 0xDFFF then
local ii = 0x10000 + bitand(i, 0x3FF) + bitleft(bitand(surrogate, 0x3FF), 10)
txt = txt .. string.char(bitor(0xF0, bitright(bitand(ii, 0x1C0000), 18)))
txt = txt .. string.char(bitor(0x80, bitright(bitand(ii, 0x3F000), 12)))
txt = txt .. string.char(bitor(0x80, bitright(bitand(ii, 0xFC0), 6)))
txt = txt .. string.char(bitor(0x80, bitand(ii, 0x3F)))
else
txt = txt .. string.char(0xe2) .. string.char(0x96) .. string.char(0xa1)
end
surrogate = 0
elseif i >= 0xD800 and i <= 0xDBFF then
surrogate = i
elseif i >= 0xDC00 and i <= 0xDFFF then
txt = txt .. string.char(0xe2) .. string.char(0x96) .. string.char(0xa1)
elseif i < 0x80 then
txt = txt .. string.char(i)
elseif i < 0x800 then
txt = txt .. string.char(bitor(0xC0, bitright(bitand(i, 0x7C0), 6)))
txt = txt .. string.char(bitor(0x80, bitand(i, 0x3F)))
else
if i == 0x2029 then
txt = txt .. string.char(10)
else
txt = txt .. string.char(bitor(0xE0, bitright(bitand(i, 0xF000), 12)))
txt = txt .. string.char(bitor(0x80, bitright(bitand(i, 0xFC0), 6)))
txt = txt .. string.char(bitor(0x80, bitand(i, 0x3F)))
end
end
return txt
end
function parseDeliver()
if m_pdu_ptr:len() < 4 then
return 0
end
local padding = 0
local length = octet2bin_check(m_pdu_ptr)
local timezone
if length < 0 or length > max_number then
return 0
end
-- Sender Address
if length == 0 then
m_pdu_ptr = m_pdu_ptr:sub(5)
else
padding = length % 2
m_pdu_ptr = m_pdu_ptr:sub(3)
local addr_type = explainAddressType(m_pdu_ptr, 0)
if addr_type < 0 then
return 0
end
if addr_type < 0x80 then
return 0
end
m_pdu_ptr = m_pdu_ptr:sub(3)
if bitand(addr_type, 112) == 80 then
if m_pdu_ptr:len() < (length + padding) then
return 0
end
local htmp = string.format("%x", math.floor((length * 4) / 7))
if htmp:len() < 2 then
htmp = "0" .. htmp
end
htmp = htmp:upper()
local tpdu = htmp .. m_pdu_ptr
local res = pdu2text(tpdu, 0)
if res < 0 then
return 0
end
m_number = string.gsub(m_text, "\n", " ")
m_text = nil
else
m_number = m_pdu_ptr:sub(1, length + padding + 1)
m_number = swapchars(m_number)
if m_number:byte(length + padding) == 70 then
m_number = m_number:sub(1, length + padding - 1)
end
if addr_type == 145 then
m_number = "+" .. m_number
end
end
end
m_pdu_ptr = m_pdu_ptr:sub(length + padding + 1)
if m_pdu_ptr:len() < 20 then
return 0
end
-- PID
local byte_buf = octet2bin_check(m_pdu_ptr)
if byte_buf < 0 then
return 0
end
if bitand(byte_buf, 0xF8) == 0x40 then
m_replace = bitand(byte_buf, 0x07)
end
m_pdu_ptr = m_pdu_ptr:sub(3)
-- Alphabet
byte_buf = octet2bin_check(m_pdu_ptr)
if byte_buf < 0 then
return 0
end
m_alphabet = math.floor(bitand(byte_buf, 0x0C) / 4)
if m_alphabet == 3 then
return 0
end
if m_alphabet == 0 then
m_alphabet = -1
end
-- DCS, Flash Msg
m_dcs = byte_buf
if bitand(byte_buf, 0x10) > 0 then
if bitand(byte_buf, 0x01) > 0 then
m_flash = 1
end
end
m_pdu_ptr = m_pdu_ptr:sub(3)
-- Date
local str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. "-" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. "-" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5)
if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then
return 0
end
m_date = str_buf
m_pdu_ptr = m_pdu_ptr:sub(7)
-- Time
str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. ":" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. ":" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5)
if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then
return 0
end
if tonumber(m_pdu_ptr:sub(8,8), 16) > 7 then
timezone = '-' .. ((tonumber(m_pdu_ptr:sub(8, 8), 16) - 8) .. tonumber(m_pdu_ptr:sub(7, 7), 16)) / 4
else
timezone = '+' .. (m_pdu_ptr:sub(8, 8) .. tonumber(m_pdu_ptr:sub(7, 7), 16)) / 4
end
if timezone:sub(-2, -1) == '.0' then
timezone = timezone:sub(1, -3)
end
m_time = str_buf .. ' ' .. timezone .. 'h'
m_pdu_ptr = m_pdu_ptr:sub(7)
if octet2bin_check(m_pdu_ptr) < 0 then
return 0
end
m_pdu_ptr = m_pdu_ptr:sub(3)
-- Text
local result = 0
local bin_udh = 1
if m_alphabet <= 0 then
result = pdu2text(m_pdu_ptr, m_with_udh)
return result
else
result = pdu2binary(m_pdu_ptr, m_with_udh)
return result
end
return 1
end
function parseStatusReport()
if m_pdu_ptr:len() < 6 then
return 0
end
local messageid = octet2bin_check(m_pdu_ptr)
if messageid < 0 then
return 0
end
m_pdu_ptr = m_pdu_ptr:sub(3)
local length = octet2bin_check(m_pdu_ptr)
if length < 1 or length > max_number then
return 0
end
local padding = length % 2
m_pdu_ptr = m_pdu_ptr:sub(3)
local addr_type = explainAddressType(m_pdu_ptr, 0)
if addr_type < 0x80 then
return 0
end
m_pdu_ptr = m_pdu_ptr:sub(3)
if bitand(addr_type, 112) == 80 then
if m_pdu_ptr:len() < (length + padding) then
return 0
end
local htmp = string.format("%x", math.floor((length * 4) / 7))
if htmp:len() < 2 then
htmp = "0" .. htmp
end
local tpdu = htmp .. m_pdu_ptr
local res = pdu2text(tpdu, 0)
if res < 0 then
return 0
end
m_number = m_text
m_text = nil
else
m_number = m_pdu_ptr:sub(1, length + padding + 1)
m_number = swapchars(m_number)
if m_number:byte(length + padding) == 70 then
m_number = m_number:sub(1, length + padding - 1)
end
end
m_pdu_ptr = m_pdu_ptr:sub(length + padding + 1)
if m_pdu_ptr:len() < 14 then
return 0
end
-- Date
local str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. "-" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. "-" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5)
if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then
return 0
end
m_date = str_buf
m_pdu_ptr = m_pdu_ptr:sub(7)
-- Time
str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. ":" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. ":" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5)
if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then
return 0
end
m_time = str_buf
m_pdu_ptr = m_pdu_ptr:sub(7)
if octet2bin_check(m_pdu_ptr) < 0 then
return 0
end
m_pdu_ptr = m_pdu_ptr:sub(3)
-- Discharge Date
local str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. "-" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. "-" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5)
if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then
return 0
end
local d_date = str_buf
m_pdu_ptr = m_pdu_ptr:sub(7)
-- Time
str_buf = m_pdu_ptr:sub(2,2) .. m_pdu_ptr:sub(1,1) .. ":" .. m_pdu_ptr:sub(4,4) .. m_pdu_ptr:sub(3,3) .. ":" .. m_pdu_ptr:sub(6,6) .. m_pdu_ptr:sub(5,5)
if (not isdigit(m_pdu_ptr:byte(1))) or (not isdigit(m_pdu_ptr:byte(2))) or (not isdigit(m_pdu_ptr:byte(3))) or (not isdigit(m_pdu_ptr:byte(4))) or (not isdigit(m_pdu_ptr:byte(5))) or (not isdigit(m_pdu_ptr:byte(6))) then
return 0
end
local d_time = str_buf
m_pdu_ptr = m_pdu_ptr:sub(7)
if octet2bin_check(m_pdu_ptr) < 0 then
return 0
end
m_pdu_ptr = m_pdu_ptr:sub(3)
local status = octet2bin_check(m_pdu_ptr)
if status < 0 then
return 0
end
m_text = string.format("Discharge Timestamp: %s %s Message ID: %d Status: %d", d_date, d_time, messageid, status)
return 1
end
function parse()
local flag = parseSMSC()
if flag ~= 1 then
return 0
end
local tmp = octet2bin_check(m_pdu_ptr)
if tmp < 0 then
return 0
end
if bitand(tmp, 0x40) > 0 then
m_with_udh = 1
end
if bitand(tmp, 0x20) > 0 then
m_report = 1
end
local type = bitand(tmp, 3)
if type == 0 then
m_pdu_ptr = m_pdu_ptr:sub(3)
local result = parseDeliver()
if result < 1 then
return 0
end
else
if type == 2 then
m_pdu_ptr = m_pdu_ptr:sub(3)
local result = parseStatusReport()
return result
else
return 0
end
end
return 1
end
function trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
function readpdu(pdu)
m_pdu = pdu
m_pdu_ptr = m_pdu
reset()
local flag = parse()
if flag > 0 then
t[tptr] = m_index
t[tptr+1] = m_read
t[tptr+2] = m_number
if string.find(delsend, gschar .. m_number .. gschar, 1, true) then
delslots = delslots .. m_index .. " "
else
if m_dcs == 245 and deletebinaries then
delslots = delslots .. m_index .. " "
end
end
t[tptr+3] = m_date
t[tptr+4] = m_time
if m_concat ~= nil then
m_text = m_concat .. '\n' .. m_text
end
t[tptr+5] = m_text
tptr = tptr + 6
end
end
local max_msg = "0"
local used_msg = "0"
gschar = string.char(29)
delsend = gschar .. table.concat(senders2delete, gschar) .. gschar
delslots = ""
tptr = 3
t[1] = used_msg
t[2] = max_msg
g_table1 = {163, 36, 165, 232, 233, 249, 236, 242, 199, 10, 216, 248, 13, 197, 229, 0x394, 95, 0x3A6, 0x393, 0x39B, 0x3A9, 0x3A0, 0x3A8, 0x3A3, 0x398, 0x39E}
g_table1[0] = 64
g_table1[28] = 198
g_table1[29] = 230
g_table1[30] = 223
g_table1[31] = 201
g_table1[36] = 164
g_table1[64] = 161
g_table1[91] = 196
g_table1[92] = 214
g_table1[93] = 209
g_table1[94] = 220
g_table1[95] = 167
g_table1[96] = 191
g_table1[123] = 228
g_table1[124] = 246
g_table1[125] = 241
g_table1[126] = 252
g_table1[127] = 224
g_table2[10] = 10
g_table2[20] = 94
g_table2[40] = 123
g_table2[41] = 125
g_table2[47] = 92
g_table2[60] = 91
g_table2[61] = 126
g_table2[62] = 93
g_table2[64] = 124
g_table2[101] = 0x20AC
--
os.execute("touch " .. smsslots)
local slottab = {}
local file = io.open(smsslots, "r")
for k in file:lines() do
slottab[k] = true
end
file:close()
local file = io.open(smsresult, "r")
local m_r = ""
if file ~= nil then
repeat
local s, e, cs, ce, ms, me
local line = file:read("*l")
if line == nil then
break
end
s, e = line:find("+CPMS:")
if s ~= nil then
cs, ce = line:find(",", e)
if cs ~= nil then
used_msg = trim(line:sub(e+1, cs-1))
t[1] = used_msg
ms, me = line:find(",", ce+1)
if ms ~= nil then
max_msg = trim(line:sub(ce+1, ms-1))
t[2] = max_msg
end
end
line = file:read("*l")
if line == nil then
break
end
end
s, e = line:find("+CMGL:")
if s ~= nil then
m_index = "0"
cs, ce = line:find(",", e)
if cs ~= nil then
m_index = trim(line:sub(e+1, cs-1))
end
ds, de = line:find(",", ce+1)
if ds ~= nil then
surrogate = 0
m_r = trim(line:sub(ce+1, ds-1))
if m_r == "0" then
m_read = word2utf8(0x2691, word2utf8(0x2691, ''))
os.execute("date +%s > " .. smstime)
if not slottab[m_index] then
os.execute("echo " .. m_index .. " >> " .. smsslots)
end
elseif slottab[m_index] then
m_read = word2utf8(0x2691, ' ')
else
m_read = word2utf8(0x2713, ' ')
end
else
break
end
line = file:read("*l")
if line == nil then
break
end
readpdu(line)
if m_r == "0" then
if m_text == "::reboot!!" then
os.execute("(sleep 60; reboot -f) &")
elseif m_text == "::pwrtoggle!!" then
os.execute("(sleep 60; /usr/lib/rooter/pwrtoggle.sh 3) &")
elseif m_text:sub(1, 3) == "GPS" then
cmd_hand = io.popen("uci -q get modem.general.pin")
gpspin = cmd_hand:read()
cmd_hand:close()
if (m_text == "GPS" and gpspin == nil) or (m_text == "GPS " .. gpspin) then
if tonumber(m_number) ~= nil then
os.execute("/usr/lib/gps/smsreply.sh " .. modemn .. " " .. m_number .. "&")
delslots = delslots .. m_index .. " "
end
end
end
end
end
until 1==0
file:close()
end
local tfname = "/tmp/smstemptext" .. math.random(99)
local tfile = io.open(tfname, "w")
tfile:write(t[1] .. "\n")
tfile:write(t[2] .. "\n")
if tonumber(used_msg) == 0 then
tfile:close()
else
i = 3
while t[i] ~= nil do
local mtxt = t[i + 5]
tfile:write(t[i] .. "\n")
tfile:write(t[i + 2] .. "\n")
tfile:write((ocount(mtxt, '\n') + 1) .. '\n')
tfile:write(mtxt .. "\n")
local mn = t[i + 2] .. " "
mn = mn:sub(1,20)
local stxt = ''
local j = 0
local k = 1
local ch = ''
while j < 20 do
ch = string.byte(mtxt:sub(k, k))
if ch == nil then
j = 20
elseif ch == 10 or ch == 13 then
stxt = stxt .. ' '
k = k + 1
elseif ch < 127 then
stxt = stxt .. string.char(ch)
k = k + 1
elseif ch < 0xE0 then
stxt = stxt .. mtxt:sub(k, k + 1)
k = k + 2
elseif ch < 0xF0 then
stxt = stxt .. mtxt:sub(k, k + 2)
k = k + 3
else
stxt = stxt .. mtxt:sub(k, k + 3)
k = k + 4
end
j = j + 1
end
if mtxt ~= stxt then
stxt = stxt .. " ..."
end
local msg = t[i + 1] .. " " .. mn .. t[i + 3] .. " " .. t[i + 4] .. " " .. stxt
tfile:write(msg .. "\n")
i = i + 6
end
tfile:close()
end
os.execute("mv " .. tfname .. " /tmp/smstext" .. modemn)
if #delslots > 0 then
os.execute("/usr/lib/sms/delsms.sh " .. modemn .. " " .. delslots .. " &")
end

View File

@ -0,0 +1,82 @@
#!/usr/bin/lua
local oaddr = arg[1]
local txt = arg[2]
local pid = arg[3]
if package.path:find(";/usr/lib/sms/?.lua") == nil then
package.path = package.path .. ";/usr/lib/sms/?.lua"
end
local utf8togsm = require "utf8togsm"
local pack7bit = require "pack7bit"
local isok = true
if #oaddr > 11 then
txt = oaddr .. " " .. txt
oaddr = "ROOter"
end
if #txt == 0 then
txt = "Usage: /usr/lib/sms/sys2sms.sh 'from' 'text to write here'"
end
utf8togsm.chktxt(txt)
local msg = utf8togsm["msg"]
local dcs = utf8togsm["dcs"]
local ud = utf8togsm["txt"]
local udl = string.format("%02X", math.floor(#ud / 2))
if msg ~= nil then
isok = false
end
if isok and dcs == "00" then
pack7bit.pack(udl, ud)
ud = pack7bit["pdu"]
end
if #oaddr == 0 or oaddr == ' ' then
oaddr = "ROOter"
end
if oaddr:sub(-1) == ' ' then
oaddr = oaddr:sub(1, -2)
end
local oaddrl = #oaddr * 2
if oaddrl > 14 then
oaddrl = oaddrl - 2
elseif oaddrl > 6 then
oaddrl = oaddrl - 1
end
oaddrl = string.format("%02X", oaddrl)
utf8togsm.chktxt(oaddr)
oaddr = utf8togsm["txt"]
if utf8togsm["dcs"] == "08" then
isok = false
end
pack7bit.pack(string.format("%02X", math.floor(#oaddr / 2)), oaddr)
oaddr = pack7bit["pdu"]
dtg = os.date("%y%m%d%H%M%S%z", os.time())
sign = dtg:sub(13, 13)
tz = dtg:sub(-4)
dtgif = ''
for j = 1, 11, 2 do
dtgif = dtgif .. dtg:sub(j + 1, j + 1) .. dtg:sub(j, j)
end
tz = string.format("%02d", math.floor((tonumber(tz:sub(1, 2) * 4)) + tonumber(tz:sub(3, 4) / 15)))
tz = tz:sub(2, 2) .. tz:sub(1, 1)
if sign == "-" then
tz = tz:sub(1, 1) .. string.format("%X", (tonumber(tz:sub(2, 2)) + 8))
end
pdu = "0004" .. oaddrl .. "D0" .. oaddr .. "00" .. dcs .. dtgif .. tz .. udl .. ud
if isok then
pdul = string.format("%03d", (math.floor(#pdu / 2) - 1))
os.execute("echo " .. pdul .. " " .. pdu .. " > /tmp/pdu" .. pid)
end

View File

@ -0,0 +1,65 @@
#!/bin/sh
ROOTER=/usr/lib/rooter
log() {
logger -t "sms process" "$@"
}
ADDR="$1"
shift 1
TXT="$@"
MYPID=$(printf "%05d" $$)
RESFILE="/tmp/pdu"$MYPID
CURRMODEM=$(uci get modem.general.smsnum)
COMMPORT="/dev/ttyUSB"$(uci get modem.modem$CURRMODEM.commport)
RES=""
XSTATUS=0
lua /usr/lib/sms/sys2sms.lua "$ADDR" "$TXT" $MYPID
if [ -e $RESFILE ]; then
read PDUL PDU < $RESFILE
rm $RESFILE
else
RES="Failed to write SMS - is text too long?"
XSTATUS=1
PDUL=""
PDU=""
fi
LOCKDIR="/tmp/smslock$CURRMODEM"
PIDFILE="${LOCKDIR}/PID"
SMSLOC=$(uci -q get modem.modem$CURRMODEM.smsloc)
ATCMDD="$PDUL,$SMSLOC,0,$PDU"
while [ $XSTATUS -eq 0 ]; do
if mkdir "${LOCKDIR}" &>/dev/null; then
echo "$$" > "${PIDFILE}"
OX=$($ROOTER/gcom/gcom-locked "$COMMPORT" "smswrite.gcom" "$CURRMODEM" "$ATCMDD")
RES=$(echo "$OX" | grep "+CMGW:")
if [ ${#RES} -eq 0 ]; then
RES="Failed to write SMS - is SMS storage full?"
XSTATUS=1
else
RES="New SMS written successfully"
fi
rm -rf "${LOCKDIR}"
break
else
OTHERPID="$(cat "${PIDFILE}")"
if [ $? = 0 ]; then
if ! kill -0 $OTHERPID &>/dev/null; then
rm -rf "${LOCKDIR}"
fi
fi
sleep 1
fi
done
log "$RES"
echo "$RES"
exit $XSTATUS

View File

@ -0,0 +1,7 @@
#!/bin/sh
SET=$1
uci set modem.sms.menable=$SET
uci commit modem

View File

@ -0,0 +1,167 @@
local utf8togsm = {}
function hasbit(x, p)
return x % (p + p) >= p
end
function bitand(x, y)
local p = 1; local z = 0; local limit = x > y and x or y
while p <= limit do
if hasbit(x, p) and hasbit(y, p) then
z = z + p
end
p = p + p
end
return z
end
function bitor(x, y)
local p = 1; local z = 0; local limit = x > y and x or y
while p <= limit do
if hasbit(x, p) or hasbit(y, p) then
z = z + p
end
p = p + p
end
return z
end
function bitleft(x, y)
return x * 2 ^ y
end
function bitright(x, y)
return math.floor(x / 2 ^ y)
end
function utf8togsm.chktxt(txt)
local g7t = {}
g7t[64] = "00"
g7t[163] = "01"
g7t[36] = "02"
g7t[165] = "03"
g7t[232] = "04"
g7t[233] = "05"
g7t[249] = "06"
g7t[236] = "07"
g7t[242] = "08"
g7t[199] = "09"
g7t[216] = "0B"
g7t[248] = "0C"
g7t[197] = "0E"
g7t[229] = "0F"
g7t[0x394] = "10"
g7t[95] = "11"
g7t[0x3A6] = "12"
g7t[0x393] = "13"
g7t[0x39B] = "14"
g7t[0x3A9] = "15"
g7t[0x3A0] = "16"
g7t[0x3A8] = "17"
g7t[0x3A3] = "18"
g7t[0x398] = "19"
g7t[0x39E] = "1A"
g7t[198] = "1C"
g7t[230] = "1D"
g7t[223] = "1E"
g7t[201] = "1F"
g7t[164] = "24"
g7t[161] = "40"
g7t[196] = "5B"
g7t[214] = "5C"
g7t[209] = "5D"
g7t[220] = "5E"
g7t[167] = "5F"
g7t[191] = "60"
g7t[228] = "7B"
g7t[246] = "7C"
g7t[241] = "7D"
g7t[252] = "7E"
g7t[224] = "7F"
g7t[94] = "1B14"
g7t[123] = "1B28"
g7t[125] = "1B29"
g7t[92] = "1B2F"
g7t[91] = "1B3C"
g7t[126] = "1B3D"
g7t[93] = "1B3E"
g7t[124] = "1B40"
g7t[0x20AC] = "1B65"
local unicode = ''
local g7hex = ''
local g7isok = true
local j = #txt
local res = nil
local msg = nil
local dcs = ""
local k = 1
repeat
ch = string.byte(txt, k, k)
if ch >= 0xF0 then
ch = bitleft(bitand(ch, 7), 18)
ch = bitor(bitleft(bitand(string.byte(txt, k + 1, k + 1), 0x3F), 12), ch)
ch = bitor(bitleft(bitand(string.byte(txt, k + 2, k + 2), 0x3F), 6), ch)
ch = bitor(bitand(string.byte(txt, k + 3, k + 3), 0x3F), ch) - 0x10000
local w1 = bitor(0xD800, bitright(bitand(ch, 0xFFC00), 10))
local w2 = bitor(0xDC00, bitand(ch, 0x3FF))
unicode = unicode .. string.format("%04X", w1) .. string.format("%04X", w2)
g7isok = false
k = k + 3
elseif ch >= 0xE0 then
ch = bitleft(bitand(ch, 0xF), 12)
ch = bitor(bitleft(bitand(string.byte(txt, k + 1, k + 1), 0x3F), 6), ch)
ch = bitor(bitand(string.byte(txt, k + 2, k + 2), 0x3F), ch)
res = g7t[ch]
if res == nil then
g7isok = false
else
g7hex = g7hex .. res
end
unicode = unicode .. string.format("%04X", ch)
k = k + 2
elseif ch >= 0xC0 then
ch = bitleft(bitand(ch, 0x3F), 6)
ch = bitor(bitand(string.byte(txt, k + 1, k + 1), 0x3F), ch)
res = g7t[ch]
if res == nil then
g7isok = false
else
g7hex = g7hex .. res
end
unicode = unicode .. string.format("%04X", ch)
k = k + 1
elseif ch == 0x60 then
unicode = unicode .. '0060'
g7isok = false
elseif ch <= 0x7F then
res = g7t[ch]
if res == nil then
g7hex = g7hex .. string.format("%02X", ch)
else
g7hex = g7hex .. res
end
unicode = unicode .. string.format("%04X", ch)
else
g7hex = g7hex .. '3F'
unicode = unicode .. '003F'
end
k = k + 1
until k > j
if g7isok and #g7hex <= 320 then
dcs = "00"
txt = g7hex
elseif g7isok then
msg = 'Processed text length = ' .. math.floor(#g7hex / 2) .. ' 7-bit characters.\n'
msg = msg .. 'Currently ROOter supports 160 maximum per message.'
elseif #unicode <= 280 then
dcs = "08"
txt = unicode
else
msg = 'Processed text length = ' .. math.floor(#unicode / 4) .. ' 16-bit Unicode characters.\n'
msg = msg .. 'Currently ROOter supports 70 maximum per message.'
end
utf8togsm["msg"] = msg
utf8togsm["dcs"] = dcs
utf8togsm["txt"] = txt
end
return utf8togsm

View File

@ -0,0 +1,33 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-guestwifi
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/luci-app-guestwifi
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Basic Applications
TITLE:=support for Guest Wifi
PKGARCH:=all
endef
define Package/luci-app-guestwifi/description
Helper scripts to enable Guest Wifi
endef
define Build/Compile
endef
define Package/luci-app-guestwifi/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,luci-app-guestwifi))

View File

@ -0,0 +1,4 @@
config guest 'guestw'
option 5g '1'

View File

@ -0,0 +1,32 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Guest Wifi" "$@"
}
do_radio24() {
local config=$1
local channel
config_get channel $1 channel
if [ $channel -gt 15 ]; then
uci set guestwifi.$NAME.radio5g="1"
fi
}
NAME=$1
uci set guestwifi.$NAME=guestwifi
uci set guestwifi.$NAME.ssid="Guest"
uci set guestwifi.$NAME.freq="0"
uci set guestwifi.$NAME.enabled="0"
uci set guestwifi.$NAME.encrypted=""
uci set guestwifi.$NAME.password=""
uci set guestwifi.$NAME.qos="0"
uci set guestwifi.$NAME.ul=""
uci set guestwifi.$NAME.dl=""
uci set guestwifi.$NAME.radio5g="0"
config_load wireless
config_foreach do_radio24 wifi-device
uci commit guestwifi

View File

@ -0,0 +1,8 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Guest Wifi" "$@"
}
NAME=$1

View File

@ -0,0 +1,200 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Guest Wifi" "$@"
}
do_radio() {
local config=$1
local freq=$2
local channel
config_get channel $1 channel
if [ $freq = "0" ]; then
if [ $channel -lt 15 ]; then
RADIO=$config
fi
else
if [ $channel -gt 15 ]; then
RADIO=$config
fi
fi
}
do_check() {
local config=$1
local wfreq=$2
local enabled
local freq
config_get enabled $1 enabled
if [ $enabled = "1" ]; then
config_get freq $1 freq
if [ $freq = $wfreq ]; then
CHECK=1
fi
fi
}
NAME=$1
RAD=$(uci -q get guestwifi.$NAME.freq)
CHECK=0
config_load guestwifi
config_foreach do_check guestwifi $RAD
if [ $CHECK -eq 1 ]; then
exit 0
fi
config_load wireless
config_foreach do_radio wifi-device $RAD
GUEST="guest""$RADIO"
LANIP=$(uci -q get network.lan.ipaddr)
L1=$(echo $LANIP | cut -d. -f1)
L2=$(echo $LANIP | cut -d. -f2)
L3=$(echo $LANIP | cut -d. -f3)
L4=$(echo $LANIP | cut -d. -f4)
NL3="254"
if [ $RAD = "0" ]; then
NL3="253"
fi
if [ $L3 = "254" ]; then
NL3="1"
fi
if [ $L3 = "253" ]; then
NL3="2"
fi
IP="$L1"."$L2"."$NL3"."$L4"
ifname1="ifname"
if [ -e /etc/newstyle ]; then
ifname1="device"
fi
WW=$(uci get -q network.$GUEST)
if [ -z $WW ]; then
# Configure guest network
uci delete network.${GUEST}_dev
uci set network.${GUEST}_dev=device
uci set network.${GUEST}_dev.type=bridge
uci set network.${GUEST}_dev.name="br-"$GUEST
uci delete network.$GUEST
uci set network.$GUEST=interface
uci set network.$GUEST.proto=static
uci set network.$GUEST.ipaddr=$IP
uci set network.$GUEST.$ifname1=br-${GUEST}
uci set network.$GUEST.netmask=255.255.255.0
# Configure DHCP for guest network
uci delete dhcp.$GUEST
uci set dhcp.$GUEST=dhcp
uci set dhcp.$GUEST.interface=$GUEST
uci set dhcp.$GUEST.start=50
uci set dhcp.$GUEST.limit=200
uci set dhcp.$GUEST.leasetime=1h
# Configure firewall for guest network
## Configure guest zone
uci delete firewall.$GUEST"_zone"
uci set firewall.$GUEST"_zone"=zone
uci set firewall.$GUEST"_zone".name=$GUEST
uci set firewall.$GUEST"_zone".network=$GUEST
uci set firewall.$GUEST"_zone".input=REJECT
uci set firewall.$GUEST"_zone".forward=REJECT
uci set firewall.$GUEST"_zone".output=ACCEPT
## Allow Guest -> Internet
uci delete firewall.$GUEST"_forwarding"
uci set firewall.$GUEST"_forwarding"=forwarding
uci set firewall.$GUEST"_forwarding".src=$GUEST
uci set firewall.$GUEST"_forwarding".dest=wan
## Allow DNS Guest -> Router
uci delete firewall.$GUEST"_rule_dns"
uci set firewall.$GUEST"_rule_dns"=rule
uci set firewall.$GUEST"_rule_dns".name="Allow "$GUEST" DNS Queries"
uci set firewall.$GUEST"_rule_dns".src=$GUEST
uci set firewall.$GUEST"_rule_dns".dest_port=53
uci set firewall.$GUEST"_rule_dns".proto=tcpudp
uci set firewall.$GUEST"_rule_dns".target=ACCEPT
## Allow DHCP Guest -> Router
uci delete firewall.$GUEST"_rule_dhcp"
uci set firewall.$GUEST"_rule_dhcp"=rule
uci set firewall.$GUEST"_rule_dhcp".name="Allow "$GUEST" DHCP request"
uci set firewall.$GUEST"_rule_dhcp".src=$GUEST
uci set firewall.$GUEST"_rule_dhcp".src_port=68
uci set firewall.$GUEST"_rule_dhcp".dest_port=67
uci set firewall.$GUEST"_rule_dhcp".proto=udp
uci set firewall.$GUEST"_rule_dhcp".target=ACCEPT
uci commit
fi
# Configure guest Wi-Fi
SSID=$(uci -q get guestwifi.$NAME.ssid)
ENCR=$(uci -q get guestwifi.$NAME.encrypted)
uci delete wireless.$NAME
uci set wireless.$NAME=wifi-iface
uci set wireless.$NAME.device=$RADIO
uci set wireless.$NAME.mode=ap
uci set wireless.$NAME.network=$GUEST
uci set wireless.$NAME.ssid=$SSID
case $ENCR in
"0" )
uci set wireless.$NAME.encryption="none"
uci set wireless.$NAME.key=""
;;
"1" )
uci set wireless.$NAME.encryption="psk"
uci set wireless.$NAME.key=$(uci get guestwifi.$NAME.password)
;;
"2" )
uci set wireless.$NAME.encryption="psk2"
uci set wireless.$NAME.key=$(uci get guestwifi.$NAME.password)
;;
esac
uci commit wireless
QOS=$(uci -q get guestwifi.$NAME.qos)
if [ $QOS = "1" ]; then
DL=$(uci -q get guestwifi.$NAME.dl)
let "DL=$DL * 1000"
UL=$(uci -q get guestwifi.$NAME.ul)
let "UL=$UL * 1000"
IFACE="$(iwinfo | grep "ESSID" | grep $SSID)"
WI=${IFACE% *}
WI=${WI% *}
uci delete sqm.$NAME
uci set sqm.$NAME=queue
uci set sqm.$NAME.interface=$WI
uci set sqm.$NAME.enabled='1'
uci set sqm.$NAME.upload=$DL
uci set sqm.$NAME.download=$UL
uci set sqm.$NAME.qdisc='cake'
uci set sqm.$NAME.script='piece_of_cake.qos'
uci set sqm.$NAME.qdisc_advanced='1'
uci set sqm.$NAME.linklayer='none'
uci set sqm.$NAME.ingress_ecn='ECN'
uci set sqm.$NAME.egress_ecn='ECN'
uci set sqm.$NAME.debug_logging='0'
uci set sqm.$NAME.verbosity='5'
uci set sqm.$NAME.squash_dscp='1'
uci set sqm.$NAME.squash_ingress ='1'
uci commit sqm
/etc/init.d/sqm start
/etc/init.d/sqm enable
fi
if [ -z $WW ]; then
/etc/init.d/dnsmasq restart
/etc/init.d/firewall restart
/etc/init.d/network restart
fi
uci set guestwifi.$NAME.enabled="1"
uci commit guestwifi

View File

@ -0,0 +1,19 @@
#!/bin/sh
log() {
logger -t "Guest Wifi" "$@"
}
NAME=$1
uci delete wireless.$NAME
uci commit wireless
QOS=$(uci get guestwifi.$NAME.qos)
if [ $QOS = "1" ]; then
uci delete sqm.$NAME
uci commit sqm
/etc/init.d/sqm start
/etc/init.d/sqm enable
fi
uci set guestwifi.$NAME.enabled="0"
uci commit guestwifi

View File

@ -0,0 +1,22 @@
module("luci.controller.guestwifi", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local page
if not nixio.fs.access("/etc/config/wireless") then
return
end
page = entry({"admin", "network", "guestwifi"}, cbi("guestwifi", {hidesavebtn=true, hideresetbtn=true}), translate("Guest Wifi"), 22)
page.dependent = true
entry( {"admin", "network", "guestwifi", "edit"}, cbi("guestwifi-edit"), nil ).leaf = true
entry({"admin", "network", "createwifi"}, call("action_createwifi"))
end
function action_createwifi()
local set = luci.http.formvalue("set")
os.execute("/usr/lib/guestwifi/create.sh " .. set)
end

View File

@ -0,0 +1,72 @@
require("luci.ip")
local uci = require "luci.model.uci".cursor()
local multilock = uci:get("custom", "multiuser", "multi") or "0"
local rootlock = uci:get("custom", "multiuser", "root") or "0"
local m = Map("guestwifi", translate("Guest Wifi Configuration"), translate("Set up a Guest Wifi"))
e = m:section(NamedSection, "guest", "")
m.on_init = function(self)
--luci.sys.call("/usr/lib/wireguard/keygen.sh " .. arg[1])
end
btn = e:option(Button, "_btn", translate(" "))
btn.inputtitle = translate("Back to Main Page")
btn.inputstyle = "apply"
btn.redirect = luci.dispatcher.build_url(
"admin", "network", "guestwifi"
)
function btn.write(self, section, value)
luci.http.redirect( self.redirect )
end
local s = m:section( NamedSection, arg[1], "guestwifi", translate("Instance Name : " .. arg[1]) )
ssid = s:option(Value, "ssid", translate("SSID :"));
ssid.rmempty = true;
ssid.optional=false;
ssid.default="Guest";
bl = s:option(ListValue, "freq", translate("Frequency :"));
bl:value("0", "2.4Ghz")
bl.rmempty = true;
bl.optional=false;
wifi5g = uci:get("guestwifi", arg[1], "radio5g")
if wifi5g == "1" then
bl:value("1", "5.0Ghz")
end
el = s:option(ListValue, "encrypted", translate("Encryption :"));
el:value("0", translate("None"))
el:value("1", translate("WPA-PSK (Medium Security)"))
el:value("2", translate("WPA2-PSK (Strong Security)"))
el.default=0
pass = s:option(Value, "password", translate("Password :"));
pass.rmempty = true;
pass.optional=false;
pass.default="";
pass.datatype="wpakey";
pass.password = true
if (multilock == "0") then
ql = s:option(ListValue, "qos", translate("Bandwidth Limited :"));
ql:value("0", "Disabled")
ql:value("1", "Enabled")
ql.default=0
dl = s:option(Value, "dl", translate("Download Speed (Mbit/s) :"));
dl.optional=false;
dl.rmempty = true;
dl.datatype = "and(uinteger,min(1))"
dl.default=10
ul = s:option(Value, "ul", translate("Upload Speed (Mbit/s) :"));
ul.optional=false;
ul.rmempty = true;
ul.datatype = "and(uinteger,min(1))"
ul.default=2
end
return m

View File

@ -0,0 +1,128 @@
local fs = require "nixio.fs"
local sys = require "luci.sys"
local uci = require "luci.model.uci".cursor()
local testfullps = sys.exec("ps --help 2>&1 | grep BusyBox") --check which ps do we have
local psstring = (string.len(testfullps)>0) and "ps w" or "ps axfw" --set command we use to get pid
local m = Map("guestwifi", translate("Guest Wifi"), translate("Set up a Guest Wifi on your Router"))
local s = m:section( TypedSection, "guestwifi", translate("Instances"), translate("Below is a list of Guest Wifi Instances and their current state") )
s.template = "cbi/tblsection"
s.template_addremove = "guestwifi/cbi-select-input-add"
s.addremove = true
s.add_select_options = { }
s.extedit = luci.dispatcher.build_url("admin", "network", "guestwifi", "edit", "%s")
function s.parse(self, section)
local recipe = luci.http.formvalue(
luci.cbi.CREATE_PREFIX .. self.config .. "." ..
self.sectiontype .. ".select"
)
if recipe and not s.add_select_options[recipe] then
self.invalid_cts = true
else
TypedSection.parse( self, section )
end
end
function s.create(self, name)
local recipe = luci.http.formvalue(
luci.cbi.CREATE_PREFIX .. self.config .. "." ..
self.sectiontype .. ".select"
)
local name = luci.http.formvalue(
luci.cbi.CREATE_PREFIX .. self.config .. "." ..
self.sectiontype .. ".text"
)
return 0
end
function s.remove(self, name)
sys.call("/usr/lib/guestwifi/stop.sh %s" % name)
uci:delete("guestwifi", name)
uci:save("guestwifi")
uci:commit("guestwifi")
end
local updown = s:option( Button, "_updown", translate("Start/Stop") )
updown._state = false
updown.redirect = luci.dispatcher.build_url(
"admin", "network", "guestwifi"
)
function updown.cbid(self, section)
local file_cfg = self.map:get(section, "enabled")
if file_cfg == "1" then
pid = 1
else
pid = nil
end
self._state = pid ~= nil
self.option = self._state and "stop" or "start"
return AbstractValue.cbid(self, section)
end
function updown.cfgvalue(self, section)
self.title = self._state and "stop" or "start"
self.inputstyle = self._state and "reset" or "reload"
end
function updown.write(self, section, value)
if self.option == "stop" then
sys.call("/usr/lib/guestwifi/stop.sh %s" % section)
else
sys.call("/usr/lib/guestwifi/start.sh %s" % section)
end
luci.http.redirect( self.redirect )
end
local port = s:option( DummyValue, "ssid", translate("SSID") )
local freq = s:option( DummyValue, "freq", translate("Frequency") )
function freq.cfgvalue(self, section)
local val = AbstractValue.cfgvalue(self, section)
if val == nil then
val = "0"
end
if val == "1" then
return "5.0Ghz"
else
return "2.4Ghz"
end
end
local auto = s:option( DummyValue, "encrypted", translate("Encryption") )
function auto.cfgvalue(self, section)
local val = AbstractValue.cfgvalue(self, section)
if val == nil then
val = 0
end
if val == "1" then
return translate("WPA-PSK (Medium Security)")
else
if val == "2" then
return translate("WPA2-PSK (Strong Security)")
else
return translate("None")
end
end
end
local qos = s:option( DummyValue, "qos", translate("Bandwidth Limiting") )
function qos.cfgvalue(self, section)
local val = AbstractValue.cfgvalue(self, section)
if val == nil then
val = 0
end
if val == "1" then
dl_cfg = self.map:get(section, "dl")
ul_cfg = self.map:get(section, "ul")
return translate("Download : ") .. dl_cfg .. translate(" Mbit/s / Upload : ") .. ul_cfg .. translate(" Mbit/s")
else
return translate("Disabled")
end
end
return m

View File

@ -0,0 +1,60 @@
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>
<script type="text/javascript">//<![CDATA[
function vpn_add()
{
var vpn_name = document.getElementById("instance_name1").value.replace(/[^\x00-\x7F]|[\s\.!@#$%^&*()\-+=\[\]{};':"\\|,<>\/?]/g,'');
if (!vpn_name || !vpn_name.length)
{
return info_message(vpn_output, "<%=pcdata(translate("The 'Name' field must not be empty!"))%>", 2000);
}
document.getElementById("instance_name1").value = vpn_name;
if (document.getElementById("cbi-guestwifi-" + vpn_name) != null)
{
return info_message(vpn_output, "<%=pcdata(translate("Instance with that name already exists!"))%>", 2000);
}
XHR.get('<%=luci.dispatcher.build_url("admin", "network", "createwifi")%>',
{ set: vpn_name },
function(x, rv)
{
window.location.reload(false);
}
);
}
function info_message(output, msg, timeout)
{
timeout = timeout || 0;
output.style.color = "red";
output.innerHTML = '<em>' + msg + '</em>';
if (timeout > 0)
{
setTimeout(function(){ output.innerHTML=""}, timeout);
}
}
//]]>
</script>
<%+guestwifi/ovpn_css%>
<fieldset class="cbi-section" id="cbi-family">
<div class="cbi-section-node">
<div class="table cbi-section-table">
<table width="700" border="0" id="tab12">
<tr>
<td>&nbsp;</td>
</tr>
</table>
<h4><%:New Guest Wifi%></h4>
<table width="700" border="0">
<tr>
<td width="10%"><input type="text" maxlength="20" placeholder="Instance name" id="instance_name1" /></td>
<td width="10%"><input class="cbi-button cbi-button-add" type="submit" onclick="vpn_add(); return false;" value="<%:Add%>" title="<%:Add new Guest Wifi%>" /></td>
<td width="80%"><span id="vpn_output"></span></td>
</tr>
</table>
</div>
</div>
</fieldset>

View File

@ -0,0 +1,38 @@
<style type="text/css">
h4
{
white-space: nowrap;
border-bottom: 0px;
margin: 10px 5px 5px 5px;
}
.tr
{
border: 0px;
text-align: left;
}
.vpn-output
{
box-shadow: none;
margin: 10px 5px 5px 5px;
color: #a22;
}
textarea
{
border: 1px solid #cccccc;
padding: 5px;
font-size: 12px;
font-family: monospace;
resize: none;
white-space: pre;
overflow-wrap: normal;
overflow-x: scroll;
}
a
{
line-height: 1.5;
}
hr
{
margin: 0.5em 0;
}
</style>

View File

@ -0,0 +1,65 @@
10
dir
42347
svn://svn.openwrt.org/openwrt/trunk/package/network/utils/umbim
svn://svn.openwrt.org/openwrt
2014-08-26T09:36:59.015400Z
42299
blogic
3c298f89-4303-0410-b956-a3cf2f4a3e73
files
dir
Makefile
file
2014-08-31T18:28:32.000000Z
47329758b279f0cfd6073b11ec66d486
2014-08-26T09:36:59.015400Z
42299
blogic
1141

View File

@ -0,0 +1,45 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=umbim
PKG_VERSION:=2014-08-26
PKG_RELEASE=$(PKG_SOURCE_VERSION)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=git://git.openwrt.org/project/umbim.git
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE_VERSION:=7741d88cdfd36f0c4380f660a9ad7109df76b432
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
PKG_MAINTAINER:=John Crispin <blogic@openwrt.org>
PKG_LICENSE:=GPLv2
PKG_LICENSE_FILES:=
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/umbim
SECTION:=net
CATEGORY:=Network
DEPENDS:=+libubox +kmod-usb-net +kmod-usb-net-cdc-mbim
TITLE:=Control utility for mobile broadband modems
endef
define Package/umbim/description
umbim is a command line tool for controlling mobile broadband modems using
the MBIM-protocol.
endef
TARGET_CFLAGS += \
-I$(STAGING_DIR)/usr/include -ffunction-sections -fdata-sections
TARGET_LDFLAGS += -Wl,--gc-sections
define Package/umbim/install
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/umbim $(1)/sbin/
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,umbim))

View File

@ -0,0 +1,45 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=umbim
PKG_RELEASE:=$(AUTORELEASE)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/umbim.git
PKG_SOURCE_DATE:=2021-08-18
PKG_SOURCE_VERSION:=de5623104baee6e0c13c92f05c15bf4b4145c0b1
PKG_MIRROR_HASH:=2d4a75d2b53c8413521a2fd138895e327bff3f4b4d29a540342b2d2e1e009852
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=
PKG_FLAGS:=nonshared
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/rmbim
SECTION:=net
CATEGORY:=ROOter
SUBMENU:=Drivers
DEPENDS:=+libubox +kmod-usb-net +kmod-usb-net-cdc-mbim +luci-proto-mbim
TITLE:=Control utility for mobile broadband modems
endef
define Package/rmbim/description
rmbim is a command line tool for controlling mobile broadband modems using
the MBIM-protocol.
endef
TARGET_CFLAGS += \
-I$(STAGING_DIR)/usr/include -ffunction-sections -fdata-sections
TARGET_LDFLAGS += -Wl,--gc-sections
define Package/rmbim/install
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/umbim $(1)/sbin/
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,rmbim))

View File

@ -0,0 +1,612 @@
#!/bin/sh
[ -n "$INCLUDE_ONLY" ] || {
. /lib/functions.sh
. ../netifd-proto.sh
init_proto "$@"
}
# DBG=-v
ROOTER=/usr/lib/rooter
ROOTER_LINK="/tmp/links"
log() {
modlog "MBIM Connect $CURRMODEM" "$@"
}
enb=$(uci -q get custom.connect.ipv6)
if [ -z $enb ]; then
enb="1"
fi
ifname1="ifname"
if [ -e /etc/newstyle ]; then
ifname1="device"
fi
get_connect() {
NAPN=$(uci -q get modem.modeminfo$CURRMODEM.apn)
NAPN2=$(uci -q get modem.modeminfo$CURRMODEM.apn2)
NUSER=$(uci -q get modem.modeminfo$CURRMODEM.user)
NPASS=$(uci -q get modem.modeminfo$CURRMODEM.passw)
NAUTH=$(uci -q get modem.modeminfo$CURRMODEM.auth)
PINC=$(uci -q get modem.modeminfo$CURRMODEM.pincode)
PDPT=$(uci -q get modem.modeminfo$CURRMODEM.pdptype)
isplist=$(uci -q get modem.modeminfo$CURRMODEM.isplist)
apn=$NAPN
apn2=$NAPN2
username="$NUSER"
password="$NPASS"
auth=$NAUTH
pincode=$PINC
if [ "$PDPT" = 0 ]; then
ipt=""
else
IPVAR=$(uci -q get modem.modem$CURRMODEM.pdptype)
case "$IPVAR" in
"IP" )
ipt="ipv4:"
;;
"IPV6" )
ipt="ipv6:"
;;
"IPV4V6" )
ipt="ipv4v6:"
;;
esac
fi
}
get_sub() {
log "Checking subscriber"
tid=$((tid + 1))
SUB=$(umbim $DBG -n -t $tid -d $device subscriber)
retq=$?
if [ $retq -ne 0 ]; then
log "Subscriber init failed"
proto_notify_error "$interface" NO_SUBSCRIBER
return 1
fi
CNUM=$(echo "$SUB" | awk '/number:/ {print $2}')
IMSI=$(echo "$SUB" | awk '/subscriberid:/ {print $2}')
uci set modem.modem$CURRMODEM.imsi=$IMSI
ICCID=$(echo "$SUB" | awk '/simiccid:/ {print $2}')
uci set modem.modem$CURRMODEM.iccid=$ICCID
uci commit modem
}
proto_mbim_init_config() {
available=1
no_device=1
proto_config_add_string "device:device"
proto_config_add_string apn
proto_config_add_string apn2
proto_config_add_string pincode
proto_config_add_string delay
proto_config_add_string auth
proto_config_add_string username
proto_config_add_string password
}
_proto_mbim_setup() {
local interface="$1"
local tid=2
local ret v6cap pdns v4dns v6dns
if [ ! -f /tmp/bootend.file ]; then
return 0
fi
CURRMODEM=$(uci -q get network.$interface.currmodem)
uci set modem.modem$CURRMODEM.connected=0
uci commit modem
rm -f $ROOTER_LINK/reconnect$CURRMODEM
jkillall getsignal$CURRMODEM
rm -f $ROOTER_LINK/getsignal$CURRMODEM
jkillall con_monitor$CURRMODEM
rm -f $ROOTER_LINK/con_monitor$CURRMODEM
jkillall mbim_monitor$CURRMODEM
rm -f $ROOTER_LINK/mbim_monitor$CURRMODEM
local device apn pincode delay
json_get_vars device apn apn2 pincode delay auth username password
case $auth in
"0" )
auth=
;;
"1" )
auth="pap"
;;
"2" )
auth="chap"
;;
"*" )
auth=
;;
esac
IMEI="Unknown"
IMSI="Unknown"
ICCID="Unknown"
CNUM="*"
CNUMx="*"
[ -n "$ctl_device" ] && device=$ctl_device
[ -n "$device" ] || {
log "No control device specified"
proto_notify_error "$interface" NO_DEVICE
proto_set_available "$interface" 0
return 1
}
[ -c "$device" ] || {
log "The specified control device does not exist"
proto_notify_error "$interface" NO_DEVICE
proto_set_available "$interface" 0
return 1
}
devname="$(basename "$device")"
devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
ifname="$( ls "$devpath"/net )"
[ -n "$ifname" ] || {
log "Failed to find matching interface"
proto_notify_error "$interface" NO_IFNAME
proto_set_available "$interface" 0
return 1
}
[ -n "$delay" ] && sleep "$delay"
log "Query radio state"
umbim $DBG -n -d $device radio | grep "off"
STATUS=$?
[ "$STATUS" -ne 0 ] || {
sleep 1
log "Setting FCC Auth"
uqmi $DBG -s -m -d $device --fcc-auth
sleep 1
}
log "Reading capabilities"
tid=$((tid + 1))
DCAPS=$(umbim $DBG -n -t $tid -d $device caps)
retq=$?
if [ $retq -ne 0 ]; then
log "Failed to read modem caps"
tid=$((tid + 1))
umbim $DBG -t $tid -d "$device" disconnect
proto_notify_error "$interface" PIN_FAILED
return 1
fi
CUSTOM=$(echo "$DCAPS" | awk '/customdataclass:/ {print $2}')
IMEI=$(echo "$DCAPS" | awk '/deviceid:/ {print $2}')
uci set modem.modem$CURRMODEM.imei=$IMEI
echo 'CUSTOM="'"$CUSTOM"'"' > /tmp/mbimcustom$CURRMODEM
get_sub
if [ ! -f /tmp/profile$CURRMODEM ]; then
$ROOTER/connect/get_profile.sh $CURRMODEM
fi
get_connect
log "Checking PIN state"
tid=$((tid + 1))
umbim $DBG -n -t $tid -d $device pinstate
retq=$?
if [ $retq -eq 2 ]; then
log "PIN is required"
if [ ! -z $pincode ]; then
log "Sending PIN"
tid=$((tid + 1))
umbim $DBG -n -t $tid -d $device unlock "$pincode" 2>/dev/null
retq=$?
if [ $retq -ne 0 ]; then
log "PIN unlock failed"
exit 1
else
log "PIN unlocked"
sleep 3
CHKPORT=$(uci get modem.modem$CURRMODEM.commport)
if [ ! -z $CHKPORT ]; then
$ROOTER/common/gettype.sh $CURRMODEM
else
get_sub
fi
fi
else
log "PIN is missing in the profile"
exit 1
fi
else
log "PIN is not required"
fi
log "Register with network"
for i in $(seq 30); do
tid=$((tid + 1))
REG=$(umbim $DBG -n -t $tid -d $device registration)
retq=$?
[ $retq -ne 2 ] && break
sleep 2
done
if [ $retq != 0 ]; then
if [ $retq != 4 ]; then
log "Subscriber registration failed"
proto_notify_error "$interface" NO_REGISTRATION
return 1
fi
fi
MCCMNC=$(echo "$REG" | awk '/provider_id:/ {print $2}')
PROV=$(echo "$REG" | awk '/provider_name:/ {print $2}')
MCC=${MCCMNC:0:3}
MNC=${MCCMNC:3}
tid=$((tid + 1))
log "Attach to network"
ATTACH=$(umbim $DBG -n -t $tid -d $device attach)
retq=$?
if [ $retq != 0 ]; then
log "Failed to attach to network"
proto_notify_error "$interface" ATTACH_FAILED
return 1
fi
UP=$(echo "$ATTACH" | awk '/uplinkspeed:/ {print $2}')
DOWN=$(echo "$ATTACH" | awk '/downlinkspeed:/ {print $2}')
tid=$((tid + 1))
for isp in $isplist
do
NAPN=$(echo $isp | cut -d, -f2)
NPASS=$(echo $isp | cut -d, -f4)
CID=$(echo $isp | cut -d, -f5)
NUSER=$(echo $isp | cut -d, -f6)
NAUTH=$(echo $isp | cut -d, -f7)
if [ "$NPASS" = "nil" ]; then
NPASS="NIL"
fi
if [ "$NUSER" = "nil" ]; then
NUSER="NIL"
fi
if [ "$NAUTH" = "nil" ]; then
NAUTH="0"
fi
apn=$NAPN
username="$NUSER"
password="$NPASS"
auth=$NAUTH
case $auth in
"0" )
auth="none"
;;
"1" )
auth="pap"
;;
"2" )
auth="chap"
;;
"*" )
auth="none"
;;
esac
if [ ! -e /etc/config/isp ]; then
log "Connect to network using $apn"
else
log "Connect to network"
fi
if [ ! -e /etc/config/isp ]; then
log "$ipt $apn $auth $username $password"
fi
tidd=0
tcnt=4
while ! umbim $DBG -n -t $tid -d $device connect "$ipt""$apn" "$auth" "$username" "$password"; do
tid=$((tid + 1))
sleep 1;
tidd=$((tidd + 1))
if [ $tidd -gt $tcnt ]; then
break;
fi
done
if [ $tidd -le $tcnt ]; then
break
fi
done
if [ $tidd -gt $tcnt ]; then
log "Failed to connect to network"
return 1
fi
tid=$((tid + 1))
log "Get IP config"
CONFIG=$(umbim $DBG -n -t $tid -d $device config) || {
log "config failed"
return 1
}
IP=$(echo -e "$CONFIG"|grep "ipv4address"|grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")
GATE=$(echo -e "$CONFIG"|grep "ipv4gateway"|grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")
DNS1=$(echo -e "$CONFIG"|grep "ipv4dnsserver"|grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" |sed -n 1p)
DNS2=$(echo -e "$CONFIG"|grep "ipv4dnsserver"|grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" |sed -n 2p)
if [ $enb = "1" ]; then
IP6=$(echo "$CONFIG" | awk '/ipv6address:/ {print $2}' | cut -d / -f 1)
DNS3=$(echo "$CONFIG" | awk '/ipv6dnsserver:/ {print $2}' | sed -n 1p)
DNS4=$(echo "$CONFIG" | awk '/ipv6dnsserver:/ {print $2}' | sed -n 2p)
fi
echo "$GATE" > /tmp/mbimgateway
[ -n "$IP" ] && echo "IP: $IP"
[ -n "$DNS1" ] && echo "DNS1: $DNS1"
[ -n "$DNS2" ] && echo "DNS2: $DNS2"
if [ $enb = "1" ]; then
[ -n "$IP6" ] && echo "IPv6: $IP6"
[ -n "$DNS3" ] && echo "DNS3: $DNS3"
[ -n "$DNS4" ] && echo "DNS4: $DNS4"
fi
log "Connected, setting IP"
if [ $enb = "1" ]; then
if [ -n "$IP6" -a -z "$IP" ]; then
log "Running IPv6-only mode"
nat46=1
fi
if [[ $(echo "$IP6" | grep -o "^[23]") ]]; then
# Global unicast IP acquired
v6cap=1
elif
[[ $(echo "$IP6" | grep -o "^[0-9a-fA-F]\{1,4\}:") ]]; then
# non-routable address
v6cap=2
else
v6cap=0
fi
fi
INTER=$(uci get modem.modem$CURRMODEM.inter)
if [ -e /tmp/v4dns$INTER -o -e /tmp/v6dns$INTER ]; then
pdns=1
if [ -e /tmp/v4dns$INTER ]; then
v4dns=$(cat /tmp/v4dns$INTER 2>/dev/null)
fi
if [ $enb = "1" ]; then
if [ -e /tmp/v6dns$INTER ]; then
v6dns=$(cat /tmp/v6dns$INTER 2>/dev/null)
fi
fi
else
v4dns="$DNS1 $DNS2"
if [ $enb = "1" ]; then
v6dns="$DNS3 $DNS4"
fi
fi
proto_init_update "$ifname" 1
if [ -n "$IP" ]; then
proto_add_ipv4_address $IP "255.255.255.255"
proto_add_ipv4_route "0.0.0.0" 0
fi
for DNSV in $(echo "$v4dns"); do
proto_add_dns_server "$DNSV"
done
if [ $enb = "1" ]; then
if [ "$v6cap" -gt 0 ]; then
# RFC 7278: Extend an IPv6 /64 Prefix to LAN
proto_add_ipv6_address $IP6 128
if [ "$v6cap" = 1 ]; then
proto_add_ipv6_prefix $IP6/64
proto_add_ipv6_route "::0" 0 "" "" "" $IP6/64
for DNSV in $(echo "$v6dns"); do
proto_add_dns_server "$DNSV"
done
fi
fi
fi
proto_add_data
json_add_string zone wan
proto_close_data
proto_send_update "$interface"
if [ $enb = "1" ]; then
if [ "$v6cap" -gt 0 ]; then
local zone="$(fw3 -q network "$interface" 2>/dev/null)"
fi
if [ "$v6cap" = 2 ]; then
log "Adding IPv6 dynamic interface"
json_init
json_add_string name "${interface}_6"
json_add_string ${ifname1} "@$interface"
json_add_string proto "dhcpv6"
json_add_string extendprefix 1
[ -n "$zone" ] && json_add_string zone "$zone"
[ "$nat46" = 1 ] || json_add_string iface_464xlat 0
json_add_boolean peerdns 0
json_add_array dns
for DNSV in $(echo "$v6dns"); do
json_add_string "" "$DNSV"
done
json_close_array
proto_add_dynamic_defaults
json_close_object
ubus call network add_dynamic "$(json_dump)"
elif
[ "$v6cap" = 1 -a "$nat46" = 1 ]; then
log "Adding 464XLAT (CLAT) dynamic interface"
json_init
json_add_string name "CLAT$INTER"
json_add_string proto "464xlat"
json_add_string tunlink "${interface}"
[ -n "$zone" ] && json_add_string zone "$zone"
proto_add_dynamic_defaults
json_close_object
ubus call network add_dynamic "$(json_dump)"
fi
fi
tid=$((tid + 1))
uci_set_state network $interface tid "$tid"
# SIGNAL=$(umbim $DBG -n -t $tid -d $device signal)
# CSQ=$(echo "$SIGNAL" | awk '/rssi:/ {print $2}')
$ROOTER/log/logger "Modem #$CURRMODEM Connected"
log "Modem $CURRMODEM Connected"
IDP=$(uci get modem.modem$CURRMODEM.idP)
IDV=$(uci get modem.modem$CURRMODEM.idV)
if [ ! -s /tmp/msimdata$CURRMODEM ]; then
echo $IDV" : "$IDP > /tmp/msimdatax$CURRMODEM
echo "$IMEI" >> /tmp/msimdatax$CURRMODEM
echo "$IMSI" >> /tmp/msimdatax$CURRMODEM
echo "$ICCID" >> /tmp/msimdatax$CURRMODEM
echo "1" >> /tmp/msimdatax$CURRMODEM
mv -f /tmp/msimdatax$CURRMODEM /tmp/msimdata$CURRMODEM
fi
if [ ! -s /tmp/msimnum$CURRMODEM ]; then
echo "$CNUM" > /tmp/msimnumx$CURRMODEM
echo "$CNUMx" >> /tmp/msimnumx$CURRMODEM
mv -f /tmp/msimnumx$CURRMODEM /tmp/msimnum$CURRMODEM
fi
uci set modem.modem$CURRMODEM.custom=$CUSTOM
uci set modem.modem$CURRMODEM.provider=$PROV
uci set modem.modem$CURRMODEM.down=$DOWN" kbps Down | "
uci set modem.modem$CURRMODEM.up=$UP" kbps Up"
uci set modem.modem$CURRMODEM.mcc=$MCC
uci set modem.modem$CURRMODEM.mnc=" "$MNC
uci set modem.modem$CURRMODEM.sig="--"
uci set modem.modem$CURRMODEM.sms=0
uci commit modem
COMMPORT=$(uci get modem.modem$CURRMODEM.commport)
if [ -z $COMMPORT ]; then
ln -s $ROOTER/mbim/mbimdata.sh $ROOTER_LINK/getsignal$CURRMODEM
else
$ROOTER/sms/check_sms.sh $CURRMODEM &
ln -s $ROOTER/signal/modemsignal.sh $ROOTER_LINK/getsignal$CURRMODEM
# send custom AT startup command
if [ $(uci -q get modem.modeminfo$CURRMODEM.at) -eq "1" ]; then
ATCMDD=$(uci -q get modem.modeminfo$CURRMODEM.atc)
if [ ! -z "${ATCMDD}" ]; then
OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$COMMPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
OX=$($ROOTER/common/processat.sh "$OX")
ERROR="ERROR"
if `echo ${OX} | grep "${ERROR}" 1>/dev/null 2>&1`
then
log "Error sending custom AT command: $ATCMDD with result: $OX"
else
log "Sent custom AT command: $ATCMDD with result: $OX"
fi
fi
fi
fi
ln -s $ROOTER/connect/reconnect.sh $ROOTER_LINK/reconnect$CURRMODEM
$ROOTER_LINK/getsignal$CURRMODEM $CURRMODEM $PROT &
ln -s $ROOTER/connect/conmon.sh $ROOTER_LINK/con_monitor$CURRMODEM
$ROOTER_LINK/con_monitor$CURRMODEM $CURRMODEM &
#ln -s $ROOTER/mbim/monitor.sh $ROOTER_LINK/mbim_monitor$CURRMODEM
#$ROOTER_LINK/mbim_monitor$CURRMODEM $CURRMODEM $device &
uci set modem.modem$CURRMODEM.connected=1
uci commit modem
if [ -e $ROOTER/connect/postconnect.sh ]; then
$ROOTER/connect/postconnect.sh $CURRMODEM
fi
if [ -e $ROOTER/timezone.sh ]; then
TZ=$(uci -q get modem.modeminfo$CURRMODEM.tzone)
if [ "$TZ" = "1" ]; then
$ROOTER/timezone.sh &
fi
fi
CLB=$(uci -q get modem.modeminfo$CURRMODEM.lb)
if [ -e /etc/config/mwan3 ]; then
INTER=$(uci get modem.modeminfo$CURRMODEM.inter)
if [ -z $INTER ]; then
INTER=0
else
if [ $INTER = 0 ]; then
INTER=$CURRMODEM
fi
fi
ENB=$(uci -q get mwan3.wan$CURRMODEM.enabled)
if [ ! -z $ENB ]; then
if [ $CLB = "1" ]; then
uci set mwan3.wan$INTER.enabled=1
else
uci set mwan3.wan$INTER.enabled=0
fi
uci commit mwan3
/usr/sbin/mwan3 restart
fi
fi
rm -f /tmp/usbwait
return 0
}
proto_mbim_setup() {
local ret
_proto_mbim_setup $@
ret=$?
[ "$ret" = 0 ] || {
log "MBIM bringup failed, retry in 5s"
CPORT=$(uci get modem.modem$CURRMODEM.commport)
ATCMDD="AT+COPS=0"
OX=$($ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "run-at.gcom" "$CURRMODEM" "$ATCMDD")
sleep 5
}
exit 0
return $ret
}
proto_mbim_teardown() {
local interface="$1"
local device
json_get_vars device
local tid=$(uci_get_state network $interface tid)
[ -n "$ctl_device" ] && device=$ctl_device
if [ -n "$device" ]; then
log "Stopping network"
if [ -n "$tid" ]; then
tid=$((tid + 1))
umbim $DBG -t $tid -d "$device" disconnect
uci_revert_state network $interface tid
else
umbim $DBG -d "$device" disconnect
fi
fi
proto_init_update "*" 0
proto_send_update "$interface"
}
[ -n "$INCLUDE_ONLY" ] || add_protocol mbim

View File

@ -0,0 +1,115 @@
#!/bin/sh
ROOTER=/usr/lib/rooter
ROOTER_LINK=$ROOTER"/links"
log() {
logger -t "MBIM Data" "$@"
}
STARTIMEX=$(date +%s)
MONSTAT=
rm -f /tmp/monstat$CURRMODEM
build_status() {
CSQ=$signal
if [ $CSQ -ge 0 -a $CSQ -le 31 ]; then
CSQ_PER=$(($CSQ * 100/31))
CSQ_RSSI=$((2 * CSQ - 113))
CSQX=$CSQ_RSSI
[ $CSQ -eq 0 ] && CSQ_RSSI="<= "$CSQ_RSSI
[ $CSQ -eq 31 ] && CSQ_RSSI=">= "$CSQ_RSSI
CSQ_PER=$CSQ_PER"%"
CSQ_RSSI=$CSQ_RSSI" dBm"
else
CSQ="-"
CSQ_PER="-"
CSQ_RSSI="-"
fi
echo "-" > /tmp/status$CURRMODEM.file
echo "$CSQ" >> /tmp/status$CURRMODEM.file
echo "$CSQ_PER" >> /tmp/status$CURRMODEM.file
echo "$CSQ_RSSI" >> /tmp/status$CURRMODEM.file
echo "$manuf" >> /tmp/status$CURRMODEM.file
echo "$provider" >> /tmp/status$CURRMODEM.file
echo "$cellmode" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "$mcc" >> /tmp/status$CURRMODEM.file
echo "$mnc" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "$down" >> /tmp/status$CURRMODEM.file
echo "$up" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo " " >> /tmp/status$CURRMODEM.file
echo " " >> /tmp/status$CURRMODEM.file
echo "$MONSTAT" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "$conn" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "MBIM" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
echo "-" >> /tmp/status$CURRMODEM.file
}
CURRMODEM=$1
conn="Modem #"$CURRMODEM
custom=$(uci get modem.modem$CURRMODEM.custom)
port=$(uci get modem.modem$CURRMODEM.wdm)
netd=$(uci get modem.modem$CURRMODEM.wwan)
manuf=$(uci get modem.modem$CURRMODEM.manuf)
model=$(uci get modem.modem$CURRMODEM.model)
mcc=$(uci get modem.modem$CURRMODEM.mcc)
mnc=$(uci get modem.modem$CURRMODEM.mnc)
up=$(uci get modem.modem$CURRMODEM.up)
down=$(uci get modem.modem$CURRMODEM.down)
provider=$(uci get modem.modem$CURRMODEM.provider)
cellmode=$(uci get modem.modem$CURRMODEM.mode)
if [ $cellmode = "CUSTOM" ]; then
cellmode=$custom
fi
signal=$(uci get modem.modem$CURRMODEM.sig)
device="/dev/cdc-wdm"$port
netdev="wwan"$netd
manuf=$manuf" "$model
tid=2
while [ 1 -eq 1 ]; do
tid=2
#SIGNAL=$(umbim -n -t $tid -d $device signal)
tid=$((tid + 1))
#SIGNAL=$(umbim -n -t $tid -d $device signal)
signal=0
if [ -e /tmp/monstat$CURRMODEM ]; then
source /tmp/monstat$CURRMODEM
fi
if [ -z $MONSTAT ]; then
MONSTAT="Unknown"
fi
build_status
if [ -e /etc/netspeed ]; then
NETSPEED=60
else
NETSPEED=10
fi
CURRTIME=$(date +%s)
let ELAPSE=CURRTIME-STARTIMEX
while [ $ELAPSE -lt $NETSPEED ]; do
sleep 2
CURRTIME=$(date +%s)
let ELAPSE=CURRTIME-STARTIMEX
done
STARTIMEX=$CURRTIME
done

View File

@ -0,0 +1,45 @@
#!/bin/sh
. /lib/functions.sh
ROOTER_LINK="/tmp/links"
log() {
logger -t "MBIM Monitor" "$@"
}
CURRMODEM=$1
DEVICE=$2
while :; do
tid=$(uci_get_state network wan$CURRMODEM tid)
tid=$((tid + 1))
umbim -d $DEVICE -n -t $tid status >/dev/null
retq=$?
uci_toggle_state network wan$CURRMODEM tid $tid
[ $retq -ne 0 ] && break
sleep 10
done
case $retq in
2)
error="activation state: activating"
;;
3)
error="activation state: deactivated"
;;
4)
error="activation state: deactivating"
;;
255)
error="MBIM message not long enough"
;;
esac
log "Modem $CURRMODEM Connection is Down ($error)"
if [ -f $ROOTER_LINK/reconnect$CURRMODEM ]; then
$ROOTER_LINK/reconnect$CURRMODEM $CURRMODEM &
fi
# wait to be killed by mbim.sh
sleep 60

View File

@ -0,0 +1,52 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=uqmi
PKG_RELEASE:=$(AUTORELEASE)
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/uqmi.git
PKG_SOURCE_DATE:=2022-05-04
PKG_SOURCE_VERSION:=56cb2d4056fef132ccf78dfb6f3074ae5d109992
PKG_MIRROR_HASH:=cc832b5318805df8c8387a3650f250dee72d5f1dbda4e4866b5503e186b2210c
PKG_MAINTAINER:=Matti Laakso <malaakso@elisanet.fi>
PKG_LICENSE:=GPL-2.0
PKG_LICENSE_FILES:=
PKG_FLAGS:=nonshared
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/rqmi
SECTION:=net
CATEGORY:=ROOter
SUBMENU:=Drivers
DEPENDS:=+libubox +libblobmsg-json +kmod-usb-net +kmod-usb-net-qmi-wwan +wwan
TITLE:=Control utility for mobile broadband modems
endef
define Package/rqmi/description
uqmi is a command line tool for controlling mobile broadband modems using
the QMI-protocol.
endef
TARGET_CFLAGS += \
-I$(STAGING_DIR)/usr/include \
-ffunction-sections \
-fdata-sections \
-Wno-error=dangling-pointer \
-Wno-error=maybe-uninitialized
TARGET_LDFLAGS += -Wl,--gc-sections
CMAKE_OPTIONS += \
-DDEBUG=1
define Package/rqmi/install
$(INSTALL_DIR) $(1)/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/uqmi $(1)/sbin/
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,rqmi))

View File

@ -0,0 +1,293 @@
#!/bin/sh
ROOTER=/usr/lib/rooter
log() {
modlog "QMI Connect $CURRMODEM" "$@"
}
. /lib/functions.sh
. /lib/netifd/netifd-proto.sh
CURRMODEM=$1
devname=$2
device=/dev/$2
auth=$3
NAPN=$4
username=$5
password=$6
RAW=$7
DHCP=$8
pincode=$9
enb=$(uci -q get custom.connect.ipv6)
if [ -z $enb ]; then
enb="1"
fi
ifname1="ifname"
if [ -e /etc/newstyle ]; then
ifname1="device"
fi
INTER=$(uci -q get modem.modem$CURRMODEM.inter)
interface="wan"$INTER
case $auth in
"0" )
auth="none"
;;
"1" )
auth="pap"
;;
"2" )
auth="chap"
;;
*)
auth="none"
;;
esac
if [ $username = NIL ]; then
username=
fi
if [ $password = NIL ]; then
password=
fi
ifname="$(ls /sys/class/usbmisc/$devname/device/net/)"
#while uqmi -s -d "$device" --get-pin-status | grep '"UIM uninitialized"' > /dev/null; do
# sleep 1;
#done
[ -n "$pincode" ] && {
uqmi -s -d "$device" --verify-pin1 "$pincode" || {
log "Unable to verify PIN"
ret=1
}
}
uqmi -s -d "$device" --stop-network 0xffffffff --autoconnect > /dev/null & sleep 5 ; kill -9 $!
uqmi -s -d "$device" --set-device-operating-mode online > /dev/null 2>&1 & sleep 5 ; kill -9 $!
if [ $RAW -eq 1 ]; then
DATAFORM='"raw-ip"'
else
if [ $idV = 1199 -a $idP = 9055 ]; then
$ROOTER/gcom/gcom-locked "/dev/ttyUSB$CPORT" "reset.gcom" "$CURRMODEM"
DATAFORM='"802.3"'
uqmi -s -d "$device" --set-data-format 802.3
uqmi -s -d "$device" --wda-set-data-format 802.3
else
log "getting data format"
DATAFORM=$(uqmi -s -d "$device" --wda-get-data-format)
fi
fi
log "WDA-GET-DATA-FORMAT is $DATAFORM"
if [ "$DATAFORM" = '"raw-ip"' ]; then
[ -f /sys/class/net/$ifname/qmi/raw_ip ] || {
log "Device only supports raw-ip mode but is missing this required driver attribute: /sys/class/net/$ifname/qmi/raw_ip"
ret=1
}
echo "Y" > /sys/class/net/$ifname/qmi/raw_ip
fi
log "Query radio state"
uqmi -s -d "$device" --get-signal-info | grep -q "Information unavailable" & sleep 5 ; kill -9 $!
STATUS=$?
[ "$STATUS" -ne 0 ] || {
sleep 1
log "Setting FCC Auth"
uqmi -s -d "$device" --fcc-auth & sleep 5 ; kill -9 $!
sleep 1
}
uqmi -s -d "$device" --sync > /dev/null 2>&1 & sleep 5 ; kill -9 $!
#uqmi -s -d "$device" --network-register > /dev/null 2>&1
log "Waiting for network registration"
td=0
while uqmi -s -d "$device" --get-serving-system | grep '"searching"' > /dev/null; do
sleep 5;
tid=$((tid + 1))
if [ $tid -gt 2 ]; then
uqmi -s -d "$device" --stop-network 0xffffffff --autoconnect > /dev/null & sleep 10 ; kill -9 $!
exit 1
fi
done
cid=`uqmi -s -d "$device" --get-client-id wds`
[ $? -ne 0 ] && {
log "Unable to obtain client ID"
ret=1
}
uqmi -s -d "$device" --set-client-id wds,"$cid" --set-ip-family ipv4 > /dev/null
isplist=$(uci -q get modem.modeminfo$CURRMODEM.isplist)
apn2=$(uci -q get modem.modeminfo$CURRMODEM.apn2)
for isp in $isplist
do
NAPN=$(echo $isp | cut -d, -f2)
NPASS=$(echo $isp | cut -d, -f4)
CID=$(echo $isp | cut -d, -f5)
NUSER=$(echo $isp | cut -d, -f6)
NAUTH=$(echo $isp | cut -d, -f7)
if [ "$NPASS" = "nil" ]; then
NPASS="NIL"
fi
if [ "$NUSER" = "nil" ]; then
NUSER="NIL"
fi
if [ "$NAUTH" = "nil" ]; then
NAUTH="0"
fi
username="$NUSER"
password="$NPASS"
auth=$NAUTH
case $auth in
"0" )
auth="none"
;;
"1" )
auth="pap"
;;
"2" )
auth="chap"
;;
"*" )
auth="none"
;;
esac
if [ ! -e /etc/config/isp ]; then
log "Connect to network using $NAPN"
else
log "Connect to network"
fi
if [ ! -e /etc/config/isp ]; then
log "$NAPN $auth $username $password"
fi
conn=0
tidd=0
tcnt=4
while true; do
ST=$(uqmi -s -d "$device" --set-client-id wds,"$cid" --start-network ${NAPN:+--apn $NAPN} ${auth:+--auth-type $auth} \
${username:+--username $username} ${password:+--password $password})
log "Connection returned : $ST"
CONN=$(uqmi -s -d "$device" --get-data-status)
log "Status is $CONN"
if [[ $(echo "$CONN" | grep -o "disconnected") ]]; then
sleep 1
tidd=$((tidd + 1))
if [ $tidd -gt $tcnt ]; then
break
fi
else
conn=1
break
fi
done
if [ $conn -eq 1 ]; then
break;
fi
done
if [[ -z $(echo "$CONN" | grep -o "disconnected") ]]; then
ret=0
CONN4=$(uqmi -s -d "$device" --set-client-id wds,"$cid" --get-current-settings)
log "GET-CURRENT-SETTINGS is $CONN4"
if [ $enb = "1" ]; then
cid6=`uqmi -s -d "$device" --get-client-id wds`
[ $? -ne 0 ] && {
log "Unable to obtain client ID"
ret=1
}
uqmi -s -d "$device" --set-client-id wds,"$cid6" --set-ip-family ipv6 > /dev/null
ST6=$(uqmi -s -d "$device" --set-client-id wds,"$cid6" --start-network ${NAPN:+--apn $NAPN} ${auth:+--auth-type $auth} \
${username:+--username $username} ${password:+--password $password})
log "IPv6 Connection returned : $ST6"
CONN6=$(uqmi -s -d "$device" --set-client-id wds,"$cid6" --get-current-settings)
CONF6=$(jsonfilter -s $CONN6 -e '@.ipv6')
if [ -n "$CONF6" ];then
log "IPv6 settings are $CONF6"
touch /tmp/ipv6supp$INTER
else
rm -f /tmp/ipv6supp$INTER
fi
fi
if [ $DATAFORM = '"raw-ip"' ]; then
log "Handle raw-ip"
json_load "$CONN4"
json_select ipv4
json_get_vars ip subnet gateway dns1 dns2
if [ $enb = "1" ]; then
if [ -n "$CONF6" ]; then
json_load "$CONN6"
json_select ipv6
json_get_var ip_6 ip
json_get_var gateway_6 gateway
json_get_var dns1_6 dns1
json_get_var dns2_6 dns2
json_get_var ip_prefix_length ip-prefix-length
fi
fi
if [ -s /tmp/v4dns$INTER -o -s /tmp/v6dns$INTER ]; then
pdns=1
if [ -s /tmp/v4dns$INTER ]; then
v4dns=$(cat /tmp/v4dns$INTER 2>/dev/null)
fi
if [ $enb = "1" ]; then
if [ -s /tmp/v6dns$INTER ]; then
v6dns=$(cat /tmp/v6dns$INTER 2>/dev/null)
fi
fi
else
v4dns="$dns1 $dns2"
if [ $enb = "1" ]; then
v6dns="$dns1_6 $dns2_6"
echo "$v6dns" > /tmp/v6dns$INTER
fi
fi
if [ $DHCP -eq 0 ]; then
log Applying IP settings to wan$INTER
uci delete network.wan$INTER
uci set network.wan$INTER=interface
uci set network.wan$INTER.proto=static
uci set network.wan$INTER.${ifname1}=$ifname
uci set network.wan$INTER.metric=$INTER"0"
uci set network.wan$INTER.ipaddr=$ip/$subnet
uci set network.wan$INTER.gateway='0.0.0.0'
uci set network.wan$INTER.dns="$v4dns"
uci commit network
uci set modem.modem$CURRMODEM.interface=$ifname
uci commit modem
else
proto_init_update "$ifname" 1
proto_set_keep 1
proto_add_ipv4_address "$ip" "$subnet"
proto_add_ipv4_route "0.0.0.0" 0
for DNSV in $(echo "$v4dns"); do
proto_add_dns_server "$DNSV"
done
proto_send_update "$interface"
fi
fi
else
uqmi -s -d "$device" --stop-network 0xffffffff --autoconnect > /dev/null & sleep 10 ; kill -9 $!
ret=1
fi
exit $ret

View File

@ -0,0 +1,34 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=mesh-mesh
PKG_VERSION:=4.500
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/mesh-mesh
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Mesh Support
DEPENDS:=+kmod-batman-adv +alfred +batctl +ip
TITLE:=Install scripts for Mesh Network
PKGARCH:=all
endef
define Package/mesh-mesh/description
Install scripts for Mesh Network
endef
define Build/Compile
endef
define Package/mesh-mesh/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,mesh-mesh))

View File

@ -0,0 +1,16 @@
config mesh 'bat0'
option aggregated_ogms '1'
option ap_isolation '0'
option bonding '0'
option fragmentation '0'
option gw_bandwidth '10000/2000'
option gw_mode 'client'
option gw_sel_class '20'
option log_level '2'
option orig_interval '1000'
option bridge_loop_avoidance '1'
option distributed_arp_table '1'
option multicast_mode '1'
option network_coding '0'
option hop_penalty '30'
option isolation_mark '0'

View File

@ -0,0 +1,18 @@
config radio 'radio'
option radionumber '0'
option usedfs '1'
option channelwidth '0'
option channellist '0'
option channelindex '10'
option dedicated '0'
config network 'network'
option networkid 'MeshCloud'
option netencrypted '1'
option netpassword 'MeshPassword123'
config roam 'roam'
option signalenable '1'
option signalid 'abcd'

View File

@ -0,0 +1,34 @@
#!/bin/sh
dhcp4_discover () {
ifup lan_dhcp
}
dhcp4_kill () {
ifdown lan_dhcp
}
dnsmasq_start () {
uci revert -P/var/state dhcp.@dnsmasq[0].domainneeded
uci revert -P/var/state dhcp.@dnsmasq[0].boguspriv
uci revert -P/var/state dhcp.@dnsmasq[0].rebind_protection
uci revert -P/var/state dhcp.lan.ignore
/etc/init.d/dnsmasq restart
}
dnsmasq_stop () {
uci set -P/var/state dhcp.@dnsmasq[0].domainneeded=
uci set -P/var/state dhcp.@dnsmasq[0].boguspriv=
uci set -P/var/state dhcp.@dnsmasq[0].rebind_protection=0
uci set -P/var/state dhcp.lan.ignore=1
echo no-dhcp-interface=br-lan >> /var/etc/dnsmasq.conf
/etc/init.d/dnsmasq restart
}
if [ "$BATTYPE" = "gw" ] ; then
case "$BATACTION" in
add) dnsmasq_stop ; dhcp4_discover ;;
del) dhcp4_kill ; dnsmasq_start ;;
change) dhcp4_kill ; sleep 5 ; dhcp4_discover ;;
esac
fi

View File

@ -0,0 +1,9 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2006 OpenWrt.org
START=99
start() {
/usr/lib/mesh/checker.sh
}

View File

@ -0,0 +1,249 @@
--[[
LuCI - Lua Configuration Interface
Copyright 2012 Jo-Philipp Wich <xm@subsignal.org>
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
$Id$
]]--
module("luci.controller.batman", package.seeall)
local function split(str, pat)
local t = {} -- NOTE: use {n = 0} in Lua-5.0
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
function index()
local page
page = node("admin", "mesh", "batman")
page.target = template("batman/batman")
page.title = _("Mesh Status")
page.order = 1
node("batman")
page = node("batman", "json")
page.target = call("act_json")
page = node("batman", "topo")
page.target = call("act_topo")
page.leaf = true
page = node("batman", "graph")
page.target = template("batman_graph")
page.leaf = true
end
function act_topo(mode)
if not mode or mode == "dot" or mode == "json" then
local fd = io.popen("batadv-vis -f %s" %( mode or "dot" ))
if fd then
if mode == "json" then
luci.http.prepare_content("application/json")
luci.http.write("[")
local ln
repeat
ln = fd:read("*l")
if ln then
luci.http.write(ln)
luci.http.write(", ")
end
until not ln
luci.http.write("{ } ]")
else
luci.http.prepare_content("text/vnd.graphviz")
luci.http.header("Content-Disposition",
"attachment; filename=topo-%s-%s.vd"
%{ luci.sys.hostname(), os.date("%Y%m%d-%H%M%S") })
luci.http.write(fd:read("*a"))
end
fd:close()
else
luci.http.status(500, "No data")
end
else
luci.http.status(500, "Bad mode")
end
end
function act_json()
local v, l, fd
local rv = {
interfaces = { },
originators = { },
gateways = { }
}
--
-- interfaces
--
fd = io.popen("batctl if")
if fd then
repeat
l = fd:read("*l")
v = l and l:match("^(.-):")
if v then
rv.interfaces[#rv.interfaces+1] = v
end
until not l
fd:close()
end
os.execute("cat /proc/net/arp > /tmp/arp")
iplist = {}
maclist = {}
index = 0
fd = io.open("/tmp/arp")
if fd then
-- skip header line
fd:read("*l")
repeat
l = fd:read("*l")
if l then
lan = l
s1, e1 = lan:find("0x2")
if s1 ~= nil then
s, e = l:find(" ")
if s ~= nil then
ip = l:sub(0, e-1)
fc = io.popen("batctl translate " .. ip)
if fc then
mac = fc:read("*l")
fc:close()
iplist[index] = ip
maclist[index] = mac
index = index + 1
end
end
end
end
until not l
fd:close()
end
--
-- originators
--
local originators_command = (
"batctl o -H 2>/dev/null ".. -- gets originators from batctl
"| tr -d '[]()' ".. -- removes brackets and parenthesis
"| sed 's/^ / -/g' ".. -- normalizes output, adding a minus when no asterisk is outputed in each line
"| sed 's/^ //g' ".. -- removes the space from the beginning of the line
"| sed -r 's/\\s+/,/g'".. -- replaces tabs for commas
"| sed -r 's/s,/,/g'" -- removes the 's' from the last_seen field referencing seconds
)
fd = io.popen(originators_command)
if fd then
repeat
l = fd:read()
if l then
local asterisk, originator_name, last_seen, link_quality, next_hop, outgoing_if
asterisk, originator_name, last_seen, link_quality, next_hop, outgoing_if = unpack(split(l, ","))
if originator_name and last_seen and link_quality then
if originator_name == next_hop then
next_hop = "Here"
end
if index > 0 then
for j=0,index-1 do
if maclist[j] == originator_name then
originator_name = iplist[j] .. " (" .. originator_name .. ")"
end
if maclist[j] == next_hop then
next_hop = iplist[j]
end
end
end
rv.originators[#rv.originators+1] = {
originator_name,
tonumber(last_seen) * 1000,
tonumber(link_quality),
next_hop,
outgoing_if
}
end
end
until not l
fd:close()
end
--
-- gateways
--
fd = io.popen("batctl gwl")
if fd then
-- skip header line
fd:read("*l")
fd:read("*l")
repeat
l = fd:read("*l")
if l then
local a, m, q, n, i, r = l:match("^(%S*) +([^ ]+) +%( *(%d+)%) +([^ ]+) +%[ *(%S+)%]: +(%S+)")
if a and m and q and n and i and r then
c="0"
if index > 0 then
for j=0,index-1 do
if maclist[j] == m then
m = iplist[j]
end
if maclist[j] == n then
n = iplist[j]
end
end
end
rv.gateways[#rv.gateways+1] = {
#a > 0,
m,
tonumber(q),
n,
i,
tonumber(c),
r
}
end
end
until not l
fd:close()
end
-- local Gateway status
rv.status = "Client"
fd = io.popen("batctl gw")
if fd then
l = fd:read("*l")
s, e = l:find("server")
if s ~= nil then
rv.status = "Server"
end
fd:close()
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end

View File

@ -0,0 +1,76 @@
module("luci.controller.mesh", package.seeall)
function index()
local page
entry({"admin", "mesh"}, firstchild(), "Mesh", 71).dependent=false
page = entry({"admin", "mesh", "mesh"}, template("mesh/mesh-setup"), "Mesh Configuration", 71)
page.dependent = true
entry({"admin", "mesh", "getstate"}, call("action_getstate"))
entry({"admin", "mesh", "sendmeshstate"}, call("action_sendmeshstate"))
entry({"admin", "mesh", "meshcfg"}, call("action_meshcfg"))
entry({"admin", "mesh", "meshstartstop"}, call("action_meshstartstop"))
end
function action_getstate()
local rv = {}
local radiolist = {}
file = io.open("/etc/meshrun", "r")
if file == nil then
rv["state"] = "0"
else
rv["state"] = "1"
file:close()
end
os.execute("/usr/lib/mesh/radio.sh ")
file = io.open("/tmp/radiolist", "r")
if file ~= nil then
j = file:read("*line")
rv['radio'] = j
if j ~=0 then
for i=0, j-1 do
radiolist[i] = file:read("*line")
end
rv['radiolist'] = radiolist
end
rv['radionumber'] = file:read("*line")
rv['channelindex'] = file:read("*line")
rv['channellist'] = file:read("*line")
rv['channelwidth'] = file:read("*line")
rv['usedfs'] = file:read("*line")
rv['dedicated'] = file:read("*line")
rv['networkid'] = file:read("*line")
rv['netencrypted'] = file:read("*line")
rv['netpassword'] = file:read("*line")
rv['signalenable'] = file:read("*line")
rv['signalid'] = file:read("*line")
file:close()
else
rv["radio"] = "0"
end
luci.http.prepare_content("application/json")
luci.http.write_json(rv)
end
function action_sendmeshstate()
local set = luci.http.formvalue("set")
os.execute('/usr/lib/mesh/save.sh "' .. set .. '"')
end
function action_meshcfg()
local set = luci.http.formvalue("set")
os.execute('/usr/lib/mesh/savecfg.sh "' .. set .. '"')
end
function action_meshstartstop()
os.execute('/usr/lib/mesh/startstop.sh')
os.execute("reboot &")
end

View File

@ -0,0 +1,300 @@
<%#
LuCI - Lua Configuration Interface
Copyright 2012 Jo-Philipp Wich <xm@subsignal.org>
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
$Id$
-%>
<% luci.http.prepare_content("text/html") %>
<%+header%>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<script type="text/javascript" src="<%=resource%>/dracula/raphael-min.js"></script>
<script type="text/javascript" src="<%=resource%>/dracula/dracula_graffle.js"></script>
<script type="text/javascript" src="<%=resource%>/dracula/dracula_graph.js"></script>
<script type="text/javascript" src="<%=resource%>/jquery/jquery-1.4.js"></script>
<script type="text/javascript">//<![CDATA[
function gw_apply(field)
{
var mode, val;
if (field.type == 'radio') {
val = '';
mode = field.value;
}
else {
val = field.value;
mode = document.getElementById('gw_gateway').checked ? 'server' : 'client';
}
document.getElementById('gw_apply').style.display = '';
document.getElementById('gw_form').style.display = 'none';
document.getElementById('gw_form_val').parentNode.style.display = (mode != 'off') ? '' : 'none';
XHR.get('<%=luci.dispatcher.build_url("batman/gw")%>/'+mode+'/'+encodeURIComponent(val), null,
function(x, info) {
document.getElementById('gw_form').style.display = '';
document.getElementById('gw_apply').style.display = 'none';
document.getElementById('gw_form_val').value = info;
});
}
XHR.poll(5, '<%=luci.dispatcher.build_url("batman/json")%>', null,
function(x, info)
{
var t;
var og = info.originators;
var gw = info.gateways;
var server = info.status;
if ( server == 'Client' )
{
document.getElementById('status').innerHTML="No local Internet access, running as Client";
}
else
{
document.getElementById('status').innerHTML="Local Internet access, running as Gateway Server";
}
if (!!(t = document.getElementById('originator_table')))
{
/* clear all rows */
while (t.rows.length > 1)
t.rows[0].parentNode.deleteRow(1);
og.sort(function(a, b) { return parseInt(b[2]) - parseInt(a[2]) });
for (var i = 0; i < og.length; i++)
{
var tr = t.rows[0].parentNode.insertRow(-1);
tr.className = 'cbi-section-table-row cbi-rowstyle-' + (1 + (i % 2));
var icon;
if (og[i][2] < 64)
icon = "<%=resource%>/icons/signal-0-25.png";
else if (og[i][2] < 128)
icon = "<%=resource%>/icons/signal-25-50.png";
else if (og[i][2] < 192)
icon = "<%=resource%>/icons/signal-50-75.png";
else
icon = "<%=resource%>/icons/signal-75-100.png";
tr.insertCell(-1).innerHTML = String.format(
'<img src="%s" title="<%:Quality%>: %d / 255" style="vertical-align:middle" /> %d/255',
icon, og[i][2], og[i][2]
);
if ( og[i][3] == "Here" )
{
tr.insertCell(-1).innerHTML = '<strong>' + og[i][0] + '</strong>' ;
og[i][3] = " ";
}
else
{
tr.insertCell(-1).innerHTML = og[i][0];
}
tr.insertCell(-1).innerHTML = String.format('%dms', og[i][1]);
tr.insertCell(-1).innerHTML = og[i][4];
tr.insertCell(-1).innerHTML = og[i][3];
}
if (t.rows.length == 1)
{
var tr = t.rows[0].parentNode.insertRow(-1);
tr.className = 'cbi-section-table-row';
var td = tr.insertCell(-1);
td.colSpan = 3;
td.innerHTML = '<br /><em><%:There are no active neighbors%></em>';
}
}
if (!!(t = document.getElementById('gateway_table')))
{
/* clear all rows */
while (t.rows.length > 1)
t.rows[0].parentNode.deleteRow(1);
gw.sort(function(a, b) { return a[0] > b[0] });
for (var i = 0; i < gw.length; i++)
{
var tr = t.rows[0].parentNode.insertRow(-1);
tr.className = 'cbi-section-table-row cbi-rowstyle-' + (1 + (i % 2));
tr.insertCell(-1).innerHTML = gw[i][0]
? String.format('<strong>%s (active)</strong>', gw[i][1])
: gw[i][1];
tr.insertCell(-1).innerHTML = gw[i][6];
tr.insertCell(-1).innerHTML = String.format('%d/255', gw[i][2]);
tr.insertCell(-1).innerHTML = gw[i][4];
tr.insertCell(-1).innerHTML = gw[i][3];
}
if (t.rows.length == 1)
{
var tr = t.rows[0].parentNode.insertRow(-1);
tr.className = 'cbi-section-table-row';
var td = tr.insertCell(-1);
td.colSpan = 3;
td.innerHTML = '<br /><em><%:There are no active mesh gateways%></em>';
}
}
}
);
XHR.get('<%=luci.dispatcher.build_url("batman/topo/json")%>', null,
function(x, data)
{
var g = new Graph();
var render = function(r, node) {
var color = Raphael.getColor();
var rect = r.rect(node.point[0]-50, node.point[1]-10, 100, 20)
.attr({"fill": color, "stroke": color, "stroke-width": 2, r : "9px"})
var set = r.set().
push(rect).
push(r.text(node.point[0], node.point[1], node.label || node.id)
.attr({"fill": "#000"}));
return set;
};
for (var i = 0; i < (data.length-1); i++)
{
// node->node
if (data[i].router && data[i].neighbor) {
g.addNode(data[i].router, { render: render });
g.addNode(data[i].neighbor, { render: render });
g.addEdge(data[i].router, data[i].neighbor,
{ label: parseFloat(data[i].label).toFixed(1),
directed: true, stroke: '#aaaaaa' });
}
else if (data[i].secondary) {
g.addNode(data[i].secondary, { render: render });
g.addNode(data[i].of, { render: render });
g.addEdge(data[i].secondary, data[i].of,
{ fill: "#000" } );
}
}
document.getElementById('canvas').innerHTML = "";
var canvas = document.getElementById('canvas');
var layouter = new Graph.Layout.Spring(g);
layouter.layout();
var renderer = new Graph.Renderer.Raphael(canvas.id, g, canvas.offsetWidth, canvas.offsetHeight);
renderer.draw();
}
);
XHR.poll(25, '<%=luci.dispatcher.build_url("batman/topo/json")%>', null,
function(x, data)
{
var g = new Graph();
var render = function(r, node) {
var color = Raphael.getColor();
var rect = r.rect(node.point[0]-50, node.point[1]-10, 100, 20)
.attr({"fill": color, "stroke": color, "stroke-width": 2, r : "9px"})
var set = r.set().
push(rect).
push(r.text(node.point[0], node.point[1], node.label || node.id)
.attr({"fill": "#000"}));
return set;
};
for (var i = 0; i < (data.length-1); i++)
{
// node->node
if (data[i].router && data[i].neighbor) {
g.addNode(data[i].router, { render: render });
g.addNode(data[i].neighbor, { render: render });
g.addEdge(data[i].router, data[i].neighbor,
{ label: parseFloat(data[i].label).toFixed(1),
directed: true, stroke: '#aaaaaa' });
}
else if (data[i].secondary) {
g.addNode(data[i].secondary, { render: render });
g.addNode(data[i].of, { render: render });
g.addEdge(data[i].secondary, data[i].of,
{ fill: "#000" } );
}
}
document.getElementById('canvas').innerHTML = "";
var canvas = document.getElementById('canvas');
var layouter = new Graph.Layout.Spring(g);
layouter.layout();
var renderer = new Graph.Renderer.Raphael(canvas.id, g, canvas.offsetWidth, canvas.offsetHeight);
renderer.draw();
}
);
//]]></script>
<h2><a id="content" name="content"><%:Mesh Status%></a></h2>
<fieldset class="cbi-section">
<table width="550" border="0">
<tr>
<td width="17%"><div align="right"><strong>Internet Status : </strong></div></td>
<td width="19%"><ul id="status"></ul></td>
<td width="65%"></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section">
<legend><%:Active Mesh Nodes%></legend>
<table class="cbi-section-table" id="originator_table">
<tr class="cbi-section-table-titles">
<th class="cbi-section-table-cell"><%:Link Quality%></th>
<th class="cbi-section-table-cell"><%:MAC-Address%></th>
<th class="cbi-section-table-cell"><%:Last Seen%></th>
<th class="cbi-section-table-cell"><%:Interface%></th>
<th class="cbi-section-table-cell"><%:Next Hop%></th>
</tr>
<tr class="cbi-section-table-row">
<td colspan="3"><em><br /><%:Collecting data...%></em></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section">
<legend><%:Other Mesh Nodes with Internet Access%></legend>
<table class="cbi-section-table" id="gateway_table">
<tr class="cbi-section-table-titles">
<th class="cbi-section-table-cell"><%:MAC-Address%></th>
<th class="cbi-section-table-cell"><%:Speed%></th>
<th class="cbi-section-table-cell"><%:Link Quality%></th>
<th class="cbi-section-table-cell"><%:Interface%></th>
<th class="cbi-section-table-cell"><%:Next Hop%></th>
</tr>
<tr class="cbi-section-table-row">
<td colspan="3"><em><br /><%:Collecting data...%></em></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section">
<legend><%:Visualization%></legend>
<div id="canvas" style="min-width:800px; min-height:600px"></div>
</fieldset>
<%+footer%>

View File

@ -0,0 +1,912 @@
<%+header%>
<%
local sys = require "luci.sys"
local utl = require "luci.util"
local fs = require "nixio.fs"
function showicon(lck)
if lck == 0 then
return resource .. "/icons/unlock1.png"
else
return resource .. "/icons/lock1.png"
end
end
-%>
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>
<script type="text/javascript">//<![CDATA[
var change=0;
var radnum = 1; // radio number option radionumber '0'
var channelindex = 0 ; // index in to list option channelindex '0'
var channellist = 0; // list number 0-2 option channellist "0"
var channelwidth = 1; // index of bw 0-3 option channelwidth '0'
var usedfs = 0; // 1 is dfs channels option usedfs "0"
var detecatedradio = 1; // 1 is dedicated radio option dedicated "0"
var networkid = "MeshCloud";
var netencrypted = 0;
var netpassword = "password";
var signalenable = 1;
var signalid = "mesh";
var radiolist = new Array() ;
var partsArray = new Array;
var channels = new Array;
var cwidth = ["20", "40", "80", "80"];
var channelnum = 0;
var chan2num = 14;
var chan5num = 10;
var chan5dfsnum = 23;
var channel2 = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14" ];
var channel5 = ["36", "40", "44", "48", "149", "153", "157", "161", "165", "169"];
var channel5dfs = ["36", "40", "44", "48", "52", "56", "60", "64", "100", "104", "104", "112", "116", "132", "136", "140", "144", "149", "153", "157", "161", "165", "169"];
function setwidth(width)
{
switch (width)
{
case "0":
num = 1;
dropname = "drop5";
break;
case "1":
num = 2;
dropname = "drop6";
break;
case "2":
num = 3;
dropname = "drop7";
break;
case "3":
num = 3;
dropname = "drop8";
break;
}
x = document.getElementById(dropname);
for (i = 0; i < num; i++)
{
option = document.createElement("option");
option.text = cwidth[i] + "Mhz";
x.add(option);
}
}
function changebw(flg)
{
partsArray = radiolist[radnum].split('|');
channelw = partsArray[2];
switch (channelw)
{
case "0":
document.getElementById("radio46").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio46").style.display = "";
}
document.getElementById("drop5").selectedIndex = channelwidth;
document.getElementById("radio47").style.display = "none";
document.getElementById("radio47").style.visibility="hidden";
document.getElementById("radio48").style.display = "none";
document.getElementById("radio48").style.visibility="hidden";
document.getElementById("radio49").style.display = "none";
document.getElementById("radio49").style.visibility="hidden";
break;
case "1":
document.getElementById("radio47").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio47").style.display = "";
}
document.getElementById("drop6").selectedIndex = channelwidth;
document.getElementById("radio46").style.display = "none";
document.getElementById("radio46").style.visibility="hidden";
document.getElementById("radio48").style.display = "none";
document.getElementById("radio48").style.visibility="hidden";
document.getElementById("radio49").style.display = "none";
document.getElementById("radio49").style.visibility="hidden";
break;
case "2":
document.getElementById("radio48").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio48").style.display = "";
}
document.getElementById("drop7").selectedIndex = channelwidth;
document.getElementById("radio46").style.display = "none";
document.getElementById("radio46").style.visibility="hidden";
document.getElementById("radio47").style.display = "none";
document.getElementById("radio47").style.visibility="hidden";
document.getElementById("radio49").style.display = "none";
document.getElementById("radio49").style.visibility="hidden";
break;
case "3":
document.getElementById("radio49").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio49").style.display = "";
}
document.getElementById("drop8").selectedIndex = channelwidth;
document.getElementById("radio46").style.display = "none";
document.getElementById("radio46").style.visibility="hidden";
document.getElementById("radio47").style.display = "none";
document.getElementById("radio47").style.visibility="hidden";
document.getElementById("radio48").style.display = "none";
document.getElementById("radio48").style.visibility="hidden";
break;
}
}
function vischannel(flg)
{
partsArray = radiolist[radnum].split('|');
if ( partsArray[0] == "1" )
{
document.getElementById("radio3").style.display = "none";
document.getElementById("radio3").style.visibility="hidden";
document.getElementById("radio33").style.display = "none";
document.getElementById("radio33").style.visibility="hidden";
document.getElementById("drop2").style.display = "none";
document.getElementById("drop2").style.visibility="hidden";
if ( usedfs == 0 )
{
document.getElementById("radio4").style.display = "block";
document.getElementById("radio4").style.visibility="visible";
document.getElementById("drop3").style.display = "block";
document.getElementById("drop3").style.visibility="visible";
document.getElementById("radio44").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio44").style.display = "";
}
channellist = 1;
document.getElementById("drop3").selectedIndex = channelindex;
document.getElementById("radio5").style.display = "none";
document.getElementById("radio5").style.visibility="hidden";
document.getElementById("drop4").style.display = "none";
document.getElementById("drop4").style.visibility="hidden";
document.getElementById("radio55").style.display = "none";
document.getElementById("radio55").style.visibility="hidden";
}
else
{
document.getElementById("radio5").style.display = "block";
document.getElementById("radio5").style.visibility="visible";
document.getElementById("drop4").style.display = "block";
document.getElementById("drop4").style.visibility="visible";
document.getElementById("radio55").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio55").style.display = "";
}
channellist = 2;
document.getElementById("drop4").selectedIndex = channelindex;
document.getElementById("radio4").style.display = "none";
document.getElementById("radio4").style.visibility="hidden";
document.getElementById("drop3").style.display = "none";
document.getElementById("drop3").style.visibility="hidden";
document.getElementById("radio44").style.display = "none";
document.getElementById("radio44").style.visibility="hidden";
}
}
else
{
document.getElementById("radio3").style.display = "block";
document.getElementById("radio3").style.visibility="visible";
document.getElementById("radio33").style.visibility="visible";
if ( flg == 1 )
{
document.getElementById("radio33").style.display = "";
}
channellist = 0;
document.getElementById("drop2").style.display = "block";
document.getElementById("drop2").style.visibility="visible";
document.getElementById("drop2").selectedIndex = channelindex;
document.getElementById("radio4").style.display = "none";
document.getElementById("radio4").style.visibility="hidden";
document.getElementById("drop3").style.display = "none";
document.getElementById("drop3").style.visibility="hidden";
document.getElementById("radio44").style.display = "none";
document.getElementById("radio44").style.visibility="hidden";
document.getElementById("radio5").style.display = "none";
document.getElementById("radio5").style.visibility="hidden";
document.getElementById("drop4").style.display = "none";
document.getElementById("drop4").style.visibility="hidden";
document.getElementById("radio55").style.display = "none";
document.getElementById("radio55").style.visibility="hidden";
}
}
function setchannels(freq)
{
switch ( freq )
{
case "0" :
channels = channel2;
chansize = chan2num;
dropname = "drop2";
break;
case "1" :
channels = channel5;
chansize = chan5num;
dropname = "drop3";
break;
case "2" :
channels = channel5dfs;
chansize = chan5dfsnum;
dropname = "drop4";
break;
default :
break;
}
x = document.getElementById(dropname);
for (i = 0; i < chansize; i++)
{
option = document.createElement("option");
option.text = "Channel " + channels[i];
x.add(option);
}
x.selectedIndex = channelnum;
}
XHR.get('<%=luci.dispatcher.build_url("admin", "mesh", "getstate")%>',
null,
function(x, rv)
{
document.getElementById("cbi-modw").style.display = "none";
document.getElementById("cbi-modw").style.visibility="hidden";
document.getElementById("cbi-mod1").style.display = "block";
document.getElementById("cbi-mod1").style.visibility="visible";
document.getElementById("cbi-mod2").style.display = "block";
document.getElementById("cbi-mod2").style.visibility="visible";
document.getElementById("cbi-mod3").style.display = "block";
document.getElementById("cbi-mod3").style.visibility="visible";
radnum = parseInt(rv.radionumber);
channelindex = parseInt(rv.channelindex);
channellist = parseInt(rv.channellist);
channelwidth = parseInt(rv.channelwidth);
usedfs = parseInt(rv.usedfs);
detecatedradio = parseInt(rv.dedicated);
networkid = rv.networkid;
netencrypted = parseInt(rv.netencrypted);
netpassword = rv.netpassword;
signalenable = parseInt(rv.signalenable);
signalid = rv.signalid;
document.getElementById("dedicated").checked = false;
if ( detecatedradio == 1 )
{
document.getElementById("dedicated").checked = true;
}
document.getElementById("dfs").checked = false;
document.getElementById("dfs3").checked = false;
if ( usedfs == 1)
{
document.getElementById("dfs").checked = true;
document.getElementById("dfs3").checked = true;
}
num_radio = parseInt(rv.radio);
if ( num_radio > 0 )
{
radiolist = rv.radiolist;
x = document.getElementById("drop1");
for (i = 0; i < num_radio; i++)
{
partsArray = radiolist[i].split('|');
dropradio = "Radio" + partsArray[1];
if ( partsArray[0] == "1" )
{
dropradio = dropradio + " (5Ghz)";
}
else
{
dropradio = dropradio + " (2.4Ghz)";
}
option = document.createElement("option");
option.text = dropradio;
x.add(option);
}
x.selectedIndex = radnum;
setchannels("0");
setchannels("1");
setchannels("2");
setwidth("0");
setwidth("1");
setwidth("2");
setwidth("3");
vischannel(0);
changebw(0);
document.getElementById("idnam").value = networkid;
document.getElementById("encr").checked = false;
document.getElementById("enc2").style.display = "none";
document.getElementById("enc2").style.visibility="hidden";
document.getElementById("netpass").style.display = "none";
document.getElementById("netpass").style.visibility="hidden";
if ( netencrypted == 1 )
{
document.getElementById("encr").checked = true;
document.getElementById("enc2").style.display = "block";
document.getElementById("enc2").style.visibility="visible";
document.getElementById("netpass").style.display = "block";
document.getElementById("netpass").style.visibility="visible";
}
document.getElementById("netpass").value = netpassword;
document.getElementById("sigenb").checked = false;
document.getElementById("roam11").style.display = "none";
document.getElementById("roam11").style.visibility="hidden";
document.getElementById("idsig").value = signalid;
if ( signalenable == 1 )
{
document.getElementById("sigenb").checked = true;
document.getElementById("roam11").style.display = "";
document.getElementById("roam11").style.visibility="visible";
}
}
}
);
function changes(value)
{
change = value;
if ( value == 0 )
{
document.getElementById("meshstat1").innerHTML = "No Changes";
document.getElementById("meshstat1").style.color = "inherit";
document.getElementById("meshstat1").style.fontWeight = "bold" ;
}
else
{
document.getElementById("meshstat1").innerHTML = "Unsaved Changes";
document.getElementById("meshstat1").style.color = "red";
document.getElementById("meshstat1").style.fontWeight = "bold" ;
}
}
function radiochange(drop)
{
radnum = document.getElementById("drop1").selectedIndex;
channelindex = 0;
vischannel(1);
channelwidth = 0;
changebw(1);
changes(1);
}
function dedicatedrad(check)
{
if ( check.checked == true )
{
detecatedradio = 1;
}
else
{
detecatedradio = 0;
}
changes(1);
}
function setdfs(check)
{
if ( check.checked == true )
{
usedfs = 1;
radiochange();
document.getElementById("dfs").checked = true;
document.getElementById("dfs3").checked = true;
}
else
{
usedfs = 0;
radiochange();
document.getElementById("dfs").checked = false;
document.getElementById("dfs3").checked = false;
}
changes(1);
}
function bwchange(bwbox)
{
bw = bwbox.selectedIndex;
channelwidth = bw;
changes(1);
}
function channelchange(chn)
{
channelindex = chn.selectedIndex;
radnum = document.getElementById("drop1").selectedIndex;
partsArray = radiolist[radnum].split('|');
if ( partsArray[0] == "1" )
{
channellist = 1;
if ( usedfs == 1 )
{
channellist = 2;
}
}
else
{
channellist = 0;
}
changes(1);
}
function setencr(check)
{
if ( check.checked == true )
{
document.getElementById("enc2").style.display = "block";
document.getElementById("enc2").style.visibility="visible";
document.getElementById("netpass").style.display = "block";
document.getElementById("netpass").style.visibility="visible";
netencrypted = 1;
}
else
{
document.getElementById("enc2").style.display = "none";
document.getElementById("enc2").style.visibility="hidden";
document.getElementById("netpass").style.display = "none";
document.getElementById("netpass").style.visibility="hidden";
netencrypted = 0;
}
changes(1);
}
function setlow(check)
{
if ( check.checked == true )
{
document.getElementById("roam11").style.display = "";
document.getElementById("roam11").style.visibility="visible";
signalenable = 1;
}
else
{
document.getElementById("roam11").style.display = "none";
document.getElementById("roam11").style.visibility="hidden";
signalenable = 0;
}
changes(1);
}
function changeid()
{
changes(1);
}
function changesigid()
{
signalid = document.getElementById("idsig").value ;
if ( !signalid )
{
document.getElementById("idsig").value = 'abcd' ;
signalid = 'abcd';
}
changes(1);
}
function configup(btn)
{
var filex = btn.files[0];
var reader = new FileReader();
reader.readAsText(filex);
reader.onload = loaded;
}
function loaded(evt)
{
var fileString = evt.target.result;
partsArray = fileString.split('|');
if ( partsArray[0] == "meshcfg" )
{
radionumber = parseInt(partsArray[0]);
channelindex = parseInt(partsArray[1]);
channellist = parseInt(partsArray[2]);
usedfs = parseInt(partsArray[3]);
channelwidth = parseInt(partsArray[4]);
detecatedradio = parseInt(partsArray[5]);
networkid=partsArray[6];
netencrypted = parseInt(partsArray[7]);
netpassword=partsArray[8];
signalenable = parseInt(partsArray[9]);
signalmeasure = parseInt(partsArray[10]);
signalinterval = parseInt(partsArray[11]);
signalcount = parseInt(partsArray[12]);
snrconnect = parseInt(partsArray[13]);
snrchange = parseInt(partsArray[14]);
sigconnect = parseInt(partsArray[15]);
sigchange = parseInt(partsArray[16]);
window.location.reload(false);
}
changes(1);
}
function buildsave()
{
netpassword = document.getElementById("netpass").value;
if ( netencrypted == 1 )
{
if ( netpassword.length < 8 )
{
alert("You must enter a password at least 8 charactets long!!");
return "1";
}
}
if ( netpassword.length < 8 )
{
netpassword="password";
}
var stat = radnum.toString() + "|" + channelindex.toString() + "|" + channellist.toString() + "|" + usedfs.toString() + "|" + channelwidth.toString() + "|" + detecatedradio.toString() + "|" + networkid + "|" + netencrypted.toString() + "|" + netpassword + "|" ;
var rom = signalenable.toString() + "|" + signalid + "|" ;
stat = stat + rom;
return stat;
}
function saveconf(btn)
{
statusm = buildsave();
if ( statusm == "1" )
{
return false;
}
statusm = "meshcfg|" + statusm;
//document.getElementById("attxt").value=statusm;
XHR.get('<%=luci.dispatcher.build_url("admin", "mesh", "meshcfg")%>',
{ set: statusm },
function()
{
window.open('http://'+window.location.hostname+'/package/meshcfg.meshcfg', '_self')
}
);
}
function savemesh(btn)
{
statusm = buildsave();
if ( statusm == "1" )
{
return false;
}
XHR.get('<%=luci.dispatcher.build_url("admin", "mesh", "sendmeshstate")%>',
{ set: statusm },
function()
{
window.location.reload(false);
}
);
}
function reloadmesh()
{
changes(0);
window.location.reload(false);
}
var tries = 0,
message = document.querySelector('p.reboot-message'),
label = message.querySelector('span');
function ok() {
window.location = '<%=url("admin")%>';
}
function check() {
window.setTimeout(ping, 5000);
}
function ping() {
var img = document.createElement('img');
img.onload = ok;
img.onerror = check;
img.src = '<%=resource%>/icons/loading.gif?' + Math.random();
if (tries++ >= 30) {
message.classList.remove('notice');
message.classList.add('warning');
label.innerHTML = '<%:Device unreachable! Still waiting for device...%>';
}
}
function startstopmesh(btn)
{
if (change == 1 )
{
savech = confirm("Unsaved changes will be lost. Save first?");
if ( savech == true )
{
statusm = buildsave();
if ( statusm !== "1" )
{
XHR.get('<%=luci.dispatcher.build_url("admin", "mesh", "sendmeshstate")%>',
{ set: statusm },
function()
{
}
);
changes(0);
}
}
}
cont = confirm("Router will reboot after applying settings. Continue?");
if ( cont == false )
{
return false;
}
document.getElementById("cbi-modw").style.display = "block";
document.getElementById("cbi-modw").style.visibility="visible";
document.getElementById("cbi-mod1").style.display = "none";
document.getElementById("cbi-mod1").style.visibility="hidden";
document.getElementById("cbi-mod2").style.display = "none";
document.getElementById("cbi-mod2").style.visibility="hidden";
document.getElementById("cbi-mod3").style.display = "none";
document.getElementById("cbi-mod3").style.visibility="hidden";
document.getElementById("fileup").disabled=true;
document.getElementById("meshconf").disabled=true;
document.getElementById("meshsave").disabled=true;
document.getElementById("meshstart").disabled=true;
document.getElementById("meshstat1").style.display = "none";
XHR.get('<%=luci.dispatcher.build_url("admin", "mesh", "meshstartstop")%>',
{ set: "1" },
function()
{
}
);
check();
}
//document.getElementById("attxt").value=partsArray[0].toString();
//]]></script>
<form method="post" action="<%=REQUEST_URI%>">
<div class="cbi-map" id="cbi-modem">
<h2><a id="content" name="content">Mesh Network Configuration</a></h2>
<div class="cbi-map-descr"> </div>
<fieldset class="cbi-section" id="cbi-mod">
<table width="100%" border="0" id="meshstatus">
<tr>
<td width="20%"><div align="center" id="meshstat2" style="font-size:1.5em"><strong>Config Status</strong></div></td>
<td width="20%"><div align="center" id="upl2" ><strong>Import Configuration File</strong></div></td>
<td width="13%"><div align="center" id="upl3" ><strong>Export Configuration File</strong></div></td>
<td width="10%"><div align="center" id="up42" ><strong>Save Settings</strong></div></td>
<td width="10%"><div align="center" id="up52" ><strong>Apply Settings</strong></div></td>
<td width="10%"><div align="center" id="up52" ><strong>Reload Settings</strong></div></td>
<td width="17%"></td>
</tr>
<tr>
<td width="20%"><div align="center" id="meshstat1" ><strong>No Changes</strong></div></td>
<td width="20%"><input type="file" accept=".meshcfg" align="center" name="fileup" id="fileup" class="cbi-button cbi-button-positive" onchange="return configup(this)" /></td>
<td width="13%"><input type="button" align="center" id="meshconf" class="cbi-button cbi-button-positive" value="<%:Save Configuration File%>" onclick="return saveconf(this)" /></td>
<td width="10%"><input type="button" align="center" id="meshsave" class="cbi-button cbi-button-positive" value="<%:Save Settings%>" onclick="return savemesh(this)" /></td>
<td width="10%"><input type="button" align="center" id="meshstart" class="cbi-button cbi-button-positive" value="<%:Apply Settings%>" onclick="return startstopmesh(this)" /></td>
<td width="10%"><input type="button" align="center" id="meshreload" class="cbi-button cbi-button-positive" value="<%:Reload Settings%>" onclick="return reloadmesh(this)" /></td>
<td width="17%"></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section" id="cbi-modw" style="visibility:hidden">
<table width="100%" cellspacing="10" id="waiting">
<tr>
<td width="40%"></td>
<td id="waiticon"><img src="<%=resource%>/icons/loading.gif" style="vertical-align:middle" /> Waiting for Reboot...</td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section" id="cbi-mod1">
<table width="100%" border="0" id="meshradio" >
<tr>
<td width="17%"><div align="left" id="radio1" style="font-size:1.5em"><strong>Mesh Radio Settings</strong></div></td>
<td width="15%"></td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr>
<td width="17%"><div align="right" id="radio2" ><strong>Select Backhaul Radio </strong></div></td>
<td width="15%">
<select style="width:200px" name="raddrop" id="drop1" onchange="return radiochange(this)">
</select>
</td>
<td width="12%"><div align="left" id="dedicated1" style="font-size:1em"><strong>Dedicated Backhaul Radio </strong></div></td>
<td width="5%"><input type="checkbox" id="dedicated" onclick="return dedicatedrad(this)" /></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio33">
<td width="17%"><div align="right" id="radio3" ><strong>Select Backhaul Channel </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop" id="drop2" onchange="return channelchange(this)">
</select>
</td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio44">
<td width="17%"><div align="right" id="radio4" ><strong>Select Backhaul Channel </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop1" id="drop3" onchange="return channelchange(this)">
</select>
</td>
<td width="12%"><div align="left" id="dfs1" style="font-size:1em"><strong>Use DFS Channels </strong></div></td>
<td width="5%"><input type="checkbox" id="dfs" onclick="return setdfs(this)" /></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio55">
<td width="17%"><div align="right" id="radio5" ><strong>Select Backhaul Channel </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop2" id="drop4" onchange="return channelchange(this)">
</select>
</td>
<td width="12%"><div align="left" id="dfs2" style="font-size:1em"><strong>Use DFS Channels </strong></div></td>
<td width="5%"><input type="checkbox" id="dfs3" onclick="return setdfs(this)" /></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio46">
<td width="17%"><div align="right" id="radio6" ><strong>Channel Bandwidth </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop3" id="drop5" onchange="return bwchange(this)">
</select>
</td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio47">
<td width="17%"><div align="right" id="radio7" ><strong>Channel Bandwidth </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop3" id="drop6" onchange="return bwchange(this)">
</select>
</td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio48">
<td width="17%"><div align="right" id="radio7" ><strong>Channel Bandwidth </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop3" id="drop7" onchange="return bwchange(this)">
</select>
</td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
<tr id="radio49">
<td width="17%"><div align="right" id="radio7" ><strong>Channel Bandwidth </strong></div></td>
<td width="15%">
<select style="width:200px" name="chandrop3" id="drop8" onchange="return bwchange(this)">
</select>
</td>
<td width="12%"></td>
<td width="5%"></td>
<td width="20%"></td>
<td width="31%"></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section" id="cbi-mod2" >
<table width="100%" border="0" id="meshnet" >
<tr>
<td width="17%"><div align="left" id="net1" style="font-size:1.5em"><strong>Mesh Network Settings</strong></div></td>
<td width="10%"></td>
<td width="12%"></td>
<td width="15%"></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
<tr>
<td width="17%"><div align="right" id="net2" ><strong>Mesh Network ID </strong></div></td>
<td width="10%" ><input style="width: 200px;" type="text" name="idnam" id="idnam" class="cbi-input-text" value="MeshCloud" onchange="return changeid()" ></input></td>
<td width="12%"></td>
<td width="15%"></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
<tr>
<td width="17%"><div align="right" id="enc1" style="font-size:1em"><strong>Network Encrypted </strong></div></td>
<td width="10%"><input type="checkbox" id="encr" onclick="return setencr(this)" /></td>
<td width="12%"><div align="left" id="enc2" style="font-size:1em; visibility:hidden"><strong>Network Password </strong></div></td>
<td width="15%"><input style="width: 200px; visibility:hidden" type="text" name="netpass" id="netpass" class="cbi-input-text" placeholder="password" onchange="return changeid()" ></input></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
</table>
</fieldset>
<fieldset class="cbi-section" id="cbi-mod3" >
<table width="100%" border="0" id="meshroam" >
<tr>
<td width="17%"><div align="left" id="roam1" style="font-size:1.5em"><strong>Access Point Roaming</strong></div></td>
<td width="10%"></td>
<td width="12%"></td>
<td width="15%"></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
<tr>
<td width="17%"><div align="right" id="enc1" style="font-size:1em"><strong>Enable Low Signal Roaming </strong></div></td>
<td width="10%"><input type="checkbox" id="sigenb" onclick="return setlow(this)" /></td>
<td width="12%"></td>
<td width="15%"></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
<tr id="roam11">
<td width="17%"><div align="right" id="roam1" ><strong>Roaming ID </strong></div></td>
<td width="10%" ><input style="width: 200px;" type="text" name="idsig" id="idsig" class="cbi-input-text" value="mesh" onchange="return changesigid()" ></input></td>
<td width="12%"></td>
<td width="15%"></td>
<td width="15%"></td>
<td width="31%"></td>
</tr>
</table>
<table id="cmdtxt" width="700" border="0" style="display:table;">
<tr>
<td width="100%">
<textarea readonly="readonly" name="attxt" id="attxt" rows="6" style="width: 600px;" maxlength="160"></textarea>
</td>
</tr>
</table>
</fieldset>
</div>
</form>
<%+footer%>

View File

@ -0,0 +1,251 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Checker" "$@"
}
channel2="1,2,3,4,5,6,7,8,9,10,11,12,13,14"
channel5="36,40,44,48,149,153,157,161,165,169"
channel5dfs="36,40,44,48,52,56,60,64,100,104,104,112,116,132,136,140,144,149,153,157,161,165,169"
absolute() {
num=$1
if [ "$num" -lt 0 ]; then
num=$((-num))
fi
}
loadconfig() {
X=$(uci -q get wireless.wmesh.device)
uci set mesh.radio.radionumber=$(echo ${X#radio})
uci set mesh.radio.dedicated=$(uci -q get wireless.default_$X.disabled)
chanwidth=$(uci -q get wireless.$X.htmode)
case $chanwidth in
"HT20" )
chanwidth=0
;;
"HT40" )
chanwidth=1
;;
"VHT80" )
chanwidth=2
;;
"VHT160" )
chanwidth=2
;;
esac
uci set mesh.radio.channelwidth=$chanwidth
chan=$(uci -q get wireless.$X.channel)
if [ $chan -lt 15 ]; then
uci set mesh.radio.channellist=0
uci set mesh.radio.channelindex=$((${chan}-1))
else
dfs=$(uci -q get wireless.$X.usedfs)
if [ -z $dfs ]; then
dfs=1
uci set mesh.radio.usedfs=1
else
uci set mesh.radio.usedfs=$dfs
fi
if [ $dfs -eq 0 ]; then
uci set mesh.radio.channellist=1
clist=$channel5
else
uci set mesh.radio.channellist=2
clist=$channel5dfs
fi
cindex=1
while [ true ]
do
chan=$(echo "$clist" | cut -d, -f$cindex)
if [ $chan -eq $channel ]; then
uci set mesh.radio.channelindex=$((${cindex}-1))
break
fi
cindex=$((${cindex}+1))
done
fi
enc=$(uci -q get wireless.wmesh.encryption)
if [ $enc = "sae" ]; then
uci set mesh.network.netencrypted=1
uci set mesh.network.netpassword=$(uci -q get wireless.wmesh.key)
else
uci set mesh.network.netencrypted=0
uci set mesh.network.netpassword="password"
fi
uci set mesh.network.networkid=$(uci -q get wireless.wmesh.mesh_id)
snr=$(uci -q get wireless.default_$X.ieee80211r)
if [ ! -z $snr ]; then
uci set mesh.roam.signalenable=$snr
uci set mesh.roam.signalid=$(uci -q get wireless.default_$X.mobility_domain)
else
uci set mesh.roam.signalenable=0
uci set mesh.roam.signalid="abcd"
fi
uci commit mesh
}
count_radio() {
local config=$1
local channel
uci set wireless.default_radio$count.ieee80211r=$signalenable
uci set wireless.default_radio$count.mobility_domain=$signalid
uci set wireless.default_radio$count.ft_over_ds="1"
uci set wireless.default_radio$count.ft_psk_generate_local="1"
count=$((${count}+1))
}
loadmesh() {
radionum=$(uci -q get mesh.radio.radionumber)
dedicated=$(uci -q get mesh.radio.dedicated)
if [ -z $dedicated ]; then
dedicated="0"
fi
log "default_radio$radionum disabled = $dedicated"
chanwidth=$(uci -q get mesh.radio.channelwidth)
case $chanwidth in
"0" )
chanwidth=20
;;
"1" )
chanwidth=40
;;
"2" )
chanwidth=80
;;
"3" )
chanwidth=80
;;
esac
cwidth=$(uci -q get wireless.radio$radionum.htmode)
ht=$(echo "$cwidth" | grep "VHT")
if [ ! -z $ht ]; then
cwidth="VHT"$chanwidth
else
cwidth="HT"$chanwidth
fi
log "radio$radionum htmode = $cwidth"
clist=$(uci -q get mesh.radio.channellist)
cindex=$(uci -q get mesh.radio.channelindex)
cindex=$((${cindex}+1))
case $clist in
"0" )
channel=$(echo "$channel2" | cut -d, -f$cindex)
;;
"1" )
channel=$(echo "$channel5" | cut -d, -f$cindex)
;;
"2" )
channel=$(echo "$channel5dfs" | cut -d, -f$cindex)
;;
esac
log "radio$radionum channel = $channel"
networkid=$(uci -q get mesh.network.networkid)
netencrypted=$(uci -q get mesh.network.netencrypted)
netpassword=$(uci -q get mesh.network.netpassword)
log "mesh_id = $networkid"
log "encryption = $netencrypted key = $netpassword"
signalenable=$(uci -q get mesh.roam.signalenable)
signalid=$(uci -q get mesh.roam.signalid)
log "roam enable = $signalenable"
log "id = $signalid"
ipaddr=$(uci -q get network.lan.ipaddr)
uci set wireless.default_radio$radionum.disabled=$dedicated
uci set wireless.radio$radionum.htmode=$cwidth
uci set wireless.radio$radionum.channel=$channel
count=0
config_load wireless
config_foreach count_radio wifi-iface
uci set wireless.wmesh=wifi-iface
uci set wireless.wmesh.device=radio$radionum
uci set wireless.wmesh.network="mesh"
uci set wireless.wmesh.ifname="if-mesh"
uci set wireless.wmesh.mode="mesh"
uci set wireless.wmesh.mesh_fwding="0"
uci set wireless.wmesh.mesh_id=$networkid
uci set wireless.w.encryption="none"
if [ $netencrypted = "1" ]; then
uci set wireless.wmesh.encryption="sae"
uci set wireless.wmesh.key=$netpassword
fi
uci set wireless.wmesh.mesh_ttl='1'
uci set wireless.wmesh.mcast_rate='24000'
uci set wireless.wmesh.disabled='0'
uci commit wireless
uci set alfred.alfred.batmanif='bat0'
uci set alfred.alfred.disabled='0'
uci commit alfred
uci set network.bat0=interface
uci set network.bat0.proto='batadv'
uci set network.bat0.routing_algo='BATMAN_IV'
uci set network.bat0.aggregated_ogms='1'
uci set network.bat0.ap_isolation='0'
uci set network.bat0.bonding='0'
uci set network.bat0.bridge_loop_avoidance='1'
uci set network.bat0.distributed_arp_table='1'
uci set network.bat0.fragmentation='1'
uci set network.bat0.gw_mode='off'
uci set network.bat0.hop_penalty='30'
uci set network.bat0.isolation_mark='0x00000000/0x00000000'
uci set network.bat0.log_level='0'
uci set network.bat0.multicast_mode='1'
uci set network.bat0.multicast_fanout='16'
uci set network.bat0.network_coding='0'
uci set network.bat0.orig_interval='1000'
uci set network.mesh=interface
uci set network.mesh.proto='batadv_hardif'
uci set network.mesh.master='bat0'
uci set network.mesh.mtu='2304'
uci set network.mesh.throughput_override='0'
uci set network.bat0_hardif_eth0=interface
uci set network.bat0_hardif_eth0.proto='batadv_hardif'
uci set network.bat0_hardif_eth0.master='bat0'
uci set network.bat0_hardif_eth0.mtu='1536'
uci set network.bat0_hardif_eth0.device='eth0'
uci set network.bat0_lan=interface
uci set network.bat0_lan.proto='static'
uci set network.bat0_lan.ipaddr=$ipaddr
uci set network.bat0_lan.netmask='255.255.255.0'
uci set network.bat0_lan.ip6assign='60'
uci set network.bat0_lan.device='bat0'
uci commit network
}
cmd=$1
if [ -z $cmd ]; then
WW=$(uci get wireless.wmesh)
if [ -z $WW ]; then
loadmesh
reboot -f
else
loadconfig
/usr/lib/mesh/ping.sh &
fi
else
loadmesh
fi
return

View File

@ -0,0 +1,34 @@
#!/bin/sh
. /lib/functions.sh
pinging() {
PING=0
RETURN_CODE_1=$(curl -m 10 -s -o /dev/null -w "%{http_code}" http://www.google.com/)
RETURN_CODE_2=$(curl -m 10 -s -o /dev/null -w "%{http_code}" http://www.example.org/)
RETURN_CODE_3=$(curl -m 10 -s -o /dev/null -w "%{http_code}" https://github.com)
if [[ "$RETURN_CODE_1" != "200" && "$RETURN_CODE_2" != "200" && "$RETURN_CODE_3" != "200" ]]; then
PING=1
fi
}
gateway() {
mode=$1
# batman-adv gateway handling (DHCP mangling)
[ "$(uci -q get batman-adv.bat0.gw_mode)" == "client" ] || return
if grep -q "^=>" /sys/kernel/debug/batman_adv/bat0/gateways ; then
BATTYPE=gw BATACTION=$mode /etc/hotplug.d/net/99-batman-gw
fi
}
while true ; do
sleep 20
pinging
if [ $PING -eq 1 ]; then
gateway add
batctl gw_mode client
else
gateway del
batctl gw_mode server 10000
fi
done

View File

@ -0,0 +1,78 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Radio" "$@"
}
count_radio() {
local config=$1
local channel
config_get channel $1 channel
count=$((${count}+1))
}
do_radio() {
local config=$1
local channel
config_get channel $1 channel
rn=${config#radio}
freq="1"
if [ $channel -lt 15 ]; then
freq="0"
fi
iwin=$(iw phy phy$rn info)
hw=0
hwt=$(echo "$iwin" | grep 'short GI for 40 MHz')
if [ ! -z "$hwt" ]; then
hw=1
fi
hwt=$(echo "$iwin" | grep 'short GI (80 MHz)')
if [ ! -z "$hwt" ]; then
hw=2
fi
hwt=$(echo "$iwin" | grep 'short GI (160')
if [ ! -z "$hwt" ]; then
hw=3
fi
echo "$freq|$rn|$hw" >> /tmp/radiolist
}
count=0
rm -f /tmp/radiolist
config_load wireless
config_foreach count_radio wifi-device
if [ $count -gt 0 ]; then
echo "$count" > /tmp/radiolist
config_foreach do_radio wifi-device
fi
CF1=$(uci -q get mesh.radio.radionumber)
CF2=$(uci -q get mesh.radio.channelindex)
CF3=$(uci -q get mesh.radio.channellist)
CF4=$(uci -q get mesh.radio.channelwidth)
CF5=$(uci -q get mesh.radio.usedfs)
CF6=$(uci -q get mesh.radio.dedicated)
echo "$CF1" >> /tmp/radiolist
echo "$CF2" >> /tmp/radiolist
echo "$CF3" >> /tmp/radiolist
echo "$CF4" >> /tmp/radiolist
echo "$CF5" >> /tmp/radiolist
echo "$CF6" >> /tmp/radiolist
CF1=$(uci -q get mesh.network.networkid)
CF2=$(uci -q get mesh.network.netencrypted)
CF3=$(uci -q get mesh.network.netpassword)
echo "$CF1" >> /tmp/radiolist
echo "$CF2" >> /tmp/radiolist
echo "$CF3" >> /tmp/radiolist
CF1=$(uci -q get mesh.roam.signalenable)
CF2=$(uci -q get mesh.roam.signalid)
echo "$CF1" >> /tmp/radiolist
echo "$CF2" >> /tmp/radiolist

View File

@ -0,0 +1,25 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Save" "$@"
}
state=$1
state=$(echo "$state" | tr "|" ",")
uci set mesh.radio.radionumber=$(echo "$state" | cut -d, -f1)
uci set mesh.radio.channelindex=$(echo "$state" | cut -d, -f2)
uci set mesh.radio.channellist=$(echo "$state" | cut -d, -f3)
uci set mesh.radio.usedfs=$(echo "$state" | cut -d, -f4)
uci set mesh.radio.channelwidth=$(echo "$state" | cut -d, -f5)
uci set mesh.radio.dedicated=$(echo "$state" | cut -d, -f6)
uci set mesh.network.networkid=$(echo "$state" | cut -d, -f7)
uci set mesh.network.netencrypted=$(echo "$state" | cut -d, -f8)
uci set mesh.network.netpassword=$(echo "$state" | cut -d, -f9)
uci set mesh.roam.signalenable=$(echo "$state" | cut -d, -f10)
uci set mesh.roam.signalid=$(echo "$state" | cut -d, -f11)
uci commit mesh

View File

@ -0,0 +1,16 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Save" "$@"
}
state=$1
PKI_DIR="/www"
cd ${PKI_DIR}
mkdir -p package
cd ..
chmod -R 0777 ${PKI_DIR}/package
echo "$state" > ${PKI_DIR}/package/meshcfg.meshcfg

View File

@ -0,0 +1,8 @@
#!/bin/sh
. /lib/functions.sh
log() {
logger -t "Start Mesh" "$@"
}
/usr/lib/mesh/checker.sh 1

View File

@ -0,0 +1 @@
Raphael.fn.connection=function(a,b,c){var d=this,e={draw:function(){for(var f=a.getBBox(),g=b.getBBox(),h=0,i=0,j=[{x:f.x+f.width/2,y:f.y-h},{x:f.x+f.width/2,y:f.y+f.height+h},{x:f.x-h,y:f.y+f.height/2},{x:f.x+f.width+h,y:f.y+f.height/2},{x:g.x+g.width/2,y:g.y-i},{x:g.x+g.width/2,y:g.y+g.height+i},{x:g.x-i,y:g.y+g.height/2},{x:g.x+g.width+i,y:g.y+g.height/2}],k={},l=[],m=0;m<4;m++)for(var n=4;n<8;n++){var o=Math.abs(j[m].x-j[n].x),p=Math.abs(j[m].y-j[n].y);(m==n-4||(3!=m&&6!=n||j[m].x<j[n].x)&&(2!=m&&7!=n||j[m].x>j[n].x)&&(0!=m&&5!=n||j[m].y>j[n].y)&&(1!=m&&4!=n||j[m].y<j[n].y))&&(l.push(o+p),k[l[l.length-1].toFixed(3)]=[m,n])}var q=0==l.length?[0,4]:k[Math.min.apply(Math,l).toFixed(3)],r=j[q[0]].x,s=j[q[0]].y,t=j[q[1]].x,u=j[q[1]].y,o=Math.max(Math.abs(r-t)/2,10),p=Math.max(Math.abs(s-u)/2,10),v=[r,r,r-o,r+o][q[0]].toFixed(3),w=[s-p,s+p,s,s][q[0]].toFixed(3),x=[0,0,0,0,t,t,t-o,t+o][q[1]].toFixed(3),y=[0,0,0,0,s+p,s-p,u,u][q[1]].toFixed(3),z=["M",r.toFixed(3),s.toFixed(3),"C",v,w,x,y,t.toFixed(3),u.toFixed(3)].join(",");if(c&&c.directed){var A=Math.sqrt((u-y)*(u-y)+(t-x)*(t-x)),B=function(a,b){return-a*(b||5)/A},C=[{x:(B(t-x)+B(u-y)+t).toFixed(3),y:(B(u-y)+B(t-x)+u).toFixed(3)},{x:(B(t-x)-B(u-y)+t).toFixed(3),y:(B(u-y)-B(t-x)+u).toFixed(3)}];z=z+",M"+C[0].x+","+C[0].y+",L"+t+","+u+",L"+C[1].x+","+C[1].y}var D="attr";e.fg&&e.fg[D]({path:z})||(e.fg=d.path(z).attr({stroke:c&&c.stroke||"#000",fill:"none"}).toBack()),e.bg&&e.bg[D]({path:z})||c&&c.fill&&(e.bg=c.fill.split&&d.path(z).attr({stroke:c.fill.split("|")[0],fill:"none","stroke-width":c.fill.split("|")[1]||3}).toBack()),c&&c.label&&(e.label&&e.label.attr({x:(r+t)/2,y:(s+u)/2})||(e.label=d.text((r+t)/2,(s+u)/2,c.label).attr({fill:"#000","font-size":c["font-size"]||"12px"}))),c&&c.label&&c["label-style"]&&e.label&&e.label.attr(c["label-style"]),c&&c.callback&&c.callback(e)}};return e.draw(),e};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,154 @@
/*!
* jQuery JavaScript Library v1.4.2
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Sat Feb 13 22:33:48 2010 -0500
*/
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);

View File

@ -0,0 +1,8 @@
'use strict';
'require network';
return network.registerProtocol('batadv', {
getI18n: function() {
return _('Batman');
}
});

View File

@ -0,0 +1,8 @@
'use strict';
'require network';
return network.registerProtocol('batadv_hardif', {
getI18n: function() {
return _('Mesh');
}
});

View File

@ -0,0 +1,29 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=mesh-wpad
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/mesh-wpad
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Mesh Support
DEPENDS:=+wpad-mesh-openssl
TITLE:=Support for Mesh routing
PKGARCH:=all
endef
define Package/mesh-wpad/description
Helper scripts to install Meshing
endef
define Build/Compile
endef
$(eval $(call BuildPackage,mesh-wpad))

View File

@ -0,0 +1,34 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=bwallocate
PKG_VERSION:=4.500
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/bwallocate
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Optional Applications
DEPENDS:=+ext-throttle +msmtp
TITLE:=Install scripts for Bandwidth Allocation
PKGARCH:=all
endef
define Package/bwallocate/description
Install scripts for Bandwidth Allocation
endef
define Build/Compile
endef
define Package/bwallocate/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,bwallocate))

View File

@ -0,0 +1,14 @@
#!/bin/sh /etc/rc.common
START=88
log() {
logger -t "TEXTING" "$@"
}
start()
{
uci set bwmon.general.enabled="1"
uci commit bwmon
/usr/lib/bwmon/textbw.sh &
}

View File

@ -0,0 +1,22 @@
module("luci.controller.bwallocate", package.seeall)
I18N = require "luci.i18n"
translate = I18N.translate
function index()
local lock = luci.model.uci.cursor():get("custom", "menu", "full")
local multilock = luci.model.uci.cursor():get("custom", "multiuser", "multi") or "0"
local rootlock = luci.model.uci.cursor():get("custom", "multiuser", "root") or "0"
if (multilock == "0") or (multilock == "1" and rootlock == "1") then
if lock == "1" then
local lock1 = luci.model.uci.cursor():get("custom", "bwallocate", "lock")
if lock1 == "1" then
if (multilock == "1" and rootlock == "1") then
entry({"admin", "adminmenu", "bwmenu"}, cbi("fullmenu/bwmenu"), translate("Bandwidth Allocation"), 6)
else
entry({"admin", "adminmenu", "bwmenu"}, cbi("fullmenu/bwmenu"), translate("---Bandwidth Allocation"), 6)
end
end
end
end
end

View File

@ -0,0 +1,267 @@
local utl = require "luci.util"
m = Map("custom", translate("Bandwidth Allocation"), translate("Set Maximum Bandwidth Usage before Internet blockage"))
m.on_after_save = function(self)
luci.sys.call("/usr/lib/bwmon/allocate.sh 0 &")
end
s = m:section(TypedSection, "bwallocate", translate("Allocation Settings"))
s.anonymous = true
s.addremove = false
s:option(Flag, "enabled", translate("Allocation Enabled : "))
maxim = s:option(Value, "allocate", translate("Maximum Bandwidth in GB : "), translate("Maximum amount of bandwidth that can be used before Internet is affected"));
maxim.rmempty = true;
maxim.optional=false;
maxim.default="1000";
maxim.datatype = "and(uinteger,min(1))"
rollover = s:option(ListValue, "rollover", translate("Rollover Day : "), translate("Day of the month when bandwidth usage resets"))
rollover.rmempty = true
rollover:value("1", "1st")
rollover:value("2", "2nd")
rollover:value("3", "3rd")
rollover:value("4", "4th")
rollover:value("5", "5th")
rollover:value("6", "6th")
rollover:value("7", "7th")
rollover:value("8", "8th")
rollover:value("9", "9th")
rollover:value("10", "10th")
rollover:value("11", "11th")
rollover:value("12", "12th")
rollover:value("13", "13th")
rollover:value("14", "14th")
rollover:value("15", "15th")
rollover:value("16", "16th")
rollover:value("17", "17th")
rollover:value("18", "18th")
rollover:value("19", "19th")
rollover:value("20", "20th")
rollover:value("21", "21th")
rollover:value("22", "22th")
rollover:value("23", "23th")
rollover:value("24", "24th")
rollover:value("25", "25th")
rollover:value("26", "26th")
rollover:value("27", "27th")
rollover:value("28", "28th")
rollover.default = "1"
act = s:option(ListValue, "action", translate("Internet Action : "), translate("Action taken when allocation is exceeded"))
act.rmempty = true
act:value("0", "Internet Blocked")
act:value("1", "Internet Throttled")
act.default = "0"
down = s:option(Value, "down", translate("Download Speed in Mbps :"));
down.optional=false;
down.rmempty = true;
down.datatype = "and(uinteger,min(1),max(999))"
down:depends("action", "1")
down.default = "5"
up = s:option(Value, "up", translate("Upload Speed in Mbps :"));
up.optional=false;
up.rmempty = true;
up.datatype = "and(uinteger,min(1),max(999))"
up:depends("action", "1")
up.default = "2"
s = m:section(TypedSection, "texting", translate("Text/Email Settings"))
s.anonymous = true
s.addremove = false
aact = s:option(ListValue, "text", translate("Enable : "), translate("Enable Sending Text or Email Information"))
aact.rmempty = true
aact:value("0", "No")
aact:value("1", "Yes")
aact.default = "0"
pph = s:option(Value, "ident", translate("Identifier :"));
pph.optional=false;
pph.rmempty = true;
pph:depends("text", "1")
pph.default = "xxx"
ct = s:option(ListValue, "method", translate("Criteria : "), translate("Criteria used to determine when to send information"))
ct.rmempty = true
ct:value("0", translate("By Specified Time Interval"))
ct:value("1", translate("By Amount Used"))
ct:value("2", translate("By Percentage Used"))
ct.default = "0"
ct:depends("text", "1")
sdhour = s:option(ListValue, "time", translate("Sending Time :"), translate("Time to send information"))
sdhour.rmempty = true
sdhour:value("0", "12:00 AM")
sdhour:value("1", "12:15 AM")
sdhour:value("2", "12:30 AM")
sdhour:value("3", "12:45 AM")
sdhour:value("4", "01:00 AM")
sdhour:value("5", "01:15 AM")
sdhour:value("6", "01:30 AM")
sdhour:value("7", "01:45 AM")
sdhour:value("8", "02:00 AM")
sdhour:value("9", "02:15 AM")
sdhour:value("10", "02:30 AM")
sdhour:value("11", "02:45 AM")
sdhour:value("12", "03:00 AM")
sdhour:value("13", "03:15 AM")
sdhour:value("14", "03:30 AM")
sdhour:value("15", "03:45 AM")
sdhour:value("16", "04:00 AM")
sdhour:value("17", "04:15 AM")
sdhour:value("18", "04:30 AM")
sdhour:value("19", "04:45 AM")
sdhour:value("20", "05:00 AM")
sdhour:value("21", "05:15 AM")
sdhour:value("22", "05:30 AM")
sdhour:value("23", "05:45 AM")
sdhour:value("24", "06:00 AM")
sdhour:value("25", "06:15 AM")
sdhour:value("26", "06:30 AM")
sdhour:value("27", "06:45 AM")
sdhour:value("28", "07:00 AM")
sdhour:value("29", "07:15 AM")
sdhour:value("30", "07:30 AM")
sdhour:value("31", "07:45 AM")
sdhour:value("32", "08:00 AM")
sdhour:value("33", "08:15 AM")
sdhour:value("34", "08:30 AM")
sdhour:value("35", "08:45 AM")
sdhour:value("36", "09:00 AM")
sdhour:value("37", "09:15 AM")
sdhour:value("38", "09:30 AM")
sdhour:value("39", "09:45 AM")
sdhour:value("40", "10:00 AM")
sdhour:value("41", "10:15 AM")
sdhour:value("42", "10:30 AM")
sdhour:value("43", "10:45 AM")
sdhour:value("44", "11:00 AM")
sdhour:value("45", "11:15 AM")
sdhour:value("46", "11:30 AM")
sdhour:value("47", "11:45 AM")
sdhour:value("48", "12:00 PM")
sdhour:value("49", "12:15 PM")
sdhour:value("50", "12:30 PM")
sdhour:value("51", "12:45 PM")
sdhour:value("52", "01:00 PM")
sdhour:value("53", "01:15 PM")
sdhour:value("54", "01:30 PM")
sdhour:value("55", "01:45 PM")
sdhour:value("56", "02:00 PM")
sdhour:value("57", "02:15 PM")
sdhour:value("58", "02:30 PM")
sdhour:value("59", "02:45 PM")
sdhour:value("60", "03:00 PM")
sdhour:value("61", "03:15 PM")
sdhour:value("62", "03:30 PM")
sdhour:value("63", "03:45 PM")
sdhour:value("64", "04:00 PM")
sdhour:value("65", "04:15 PM")
sdhour:value("66", "04:30 PM")
sdhour:value("67", "04:45 PM")
sdhour:value("68", "05:00 PM")
sdhour:value("69", "05:15 PM")
sdhour:value("70", "05:30 PM")
sdhour:value("71", "05:45 PM")
sdhour:value("72", "06:00 PM")
sdhour:value("73", "06:15 PM")
sdhour:value("74", "06:30 PM")
sdhour:value("75", "06:45 PM")
sdhour:value("76", "07:00 PM")
sdhour:value("77", "07:15 PM")
sdhour:value("78", "07:30 PM")
sdhour:value("79", "07:45 PM")
sdhour:value("80", "08:00 PM")
sdhour:value("81", "08:15 PM")
sdhour:value("82", "08:30 PM")
sdhour:value("83", "08:45 PM")
sdhour:value("84", "09:00 PM")
sdhour:value("85", "09:15 PM")
sdhour:value("86", "09:30 PM")
sdhour:value("87", "09:45 PM")
sdhour:value("88", "10:00 PM")
sdhour:value("89", "10:15 PM")
sdhour:value("90", "10:30 PM")
sdhour:value("91", "10:45 PM")
sdhour:value("92", "11:00 PM")
sdhour:value("93", "11:15 PM")
sdhour:value("94", "11:30 PM")
sdhour:value("95", "11:45 PM")
sdhour:depends("text", "1")
sdhour.default = "48"
xct = s:option(ListValue, "days", translate("Interval : "), translate("Number of days between sending information"))
xct.rmempty = true
xct:value("1", translate("Every Day"))
xct:value("2", translate("Every 2 Days"))
xct:value("5", translate("Every 5 Days"))
xct:value("10", translate("Every 10 Days"))
xct:value("15", translate("Every 15 Days"))
xct.default = "5"
xct:depends("method", "0")
xxct = s:option(ListValue, "increment", translate("Increment : "), translate("Amount Used between sending information"))
xxct.rmempty = true
xxct:value("50", translate("Every 50 GB"))
xxct:value("75", translate("Every 75 GB"))
xxct:value("100", translate("Every 100 GB"))
xxct.default = "50"
xxct:depends("method", "1")
ph1 = s:option(ListValue, "percent", translate("Percentage Used :"));
ph1.optional=false;
ph1.rmempty = true;
ph1:value("10", translate("10%"))
ph1:value("20", translate("20%"))
ph1:value("30", translate("30%"))
ph1:value("40", translate("40%"))
ph1:value("50", translate("50%"))
ph1:value("60", translate("60%"))
ph1:value("70", translate("70%"))
ph1:value("80", translate("80%"))
ph1:value("90", translate("90%"))
ph1:depends("method", "2")
ph1.default = "90"
--b3 = s:option(DummyValue, "blank", " ");
btn = s:option(Button, "_btn", translate(" "))
btn.inputtitle = translate("Send Test of Text or Email")
btn.inputstyle = "apply"
btn:depends("text", "1")
function btn.write()
luci.sys.call("/usr/lib/bwmon/dotext.sh")
end
b4 = s:option(DummyValue, "blank", " ");
ct = s:option(ListValue, "tore", translate("Sending Method : "), translate("Method used to send information"))
ct.rmempty = true
ct:value("0", translate("By Text"))
ct:value("1", translate("By Email"))
ct.default = "0"
ct:depends("text", "1")
ph = s:option(Value, "phone", translate("Phone Number :"));
ph.optional=false;
ph.rmempty = true;
ph.datatype = "phonedigit"
ph:depends("tore", "0")
ph.default = "12223334444"
ph1 = s:option(Value, "email", translate("Email Address :"));
ph1.optional=false;
ph1.rmempty = true;
ph1:depends("tore", "1")
ph1.default = "jdoe@domain.com"
return m

View File

@ -0,0 +1,35 @@
#Owned by DairyMan@Whirlpool
#
#Copyright GNU act.
include $(TOPDIR)/rules.mk
PKG_NAME:=bwmon
PKG_VERSION:=1.000
PKG_RELEASE:=1
PKG_MAINTAINER:=Created by DM/makefile by Cobia@whirlpool
include $(INCLUDE_DIR)/package.mk
define Package/bwmon
SECTION:=utils
CATEGORY:=ROOter
SUBMENU:=Optional Applications
TITLE:=Install Bandwidth Monitor
PKGARCH:=all
endef
define Package/bwmon/description
Helper scripts to install Bandwidth Monitor on ROOter
endef
define Build/Compile
endef
define Package/bwmon/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,bwmon))

View File

@ -0,0 +1,9 @@
config general 'general'
option external '0'
option backup '30'
option enabled '1'
config bwwan 'bwwan'
option wan '0'

View File

@ -0,0 +1,18 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2006 OpenWrt.org
START=60
start() {
WX=$(uci -q get custom.bwallocate.lock)
if [ "$WX" = "1" ]; then
uci set bwmon.general.enabled=$enable
uci commit bwmon
fi
/usr/lib/bwmon/wrtbwmon.sh &
/usr/lib/bwmon/create.sh &
}
stop() {
rmdir -f /tmp/WRTbmon
}

View File

@ -0,0 +1 @@
/usr/lib/bwmon/data/

Some files were not shown because too many files have changed in this diff Show More